stashes 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +115 -24
- package/dist/mcp.js +115 -24
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -62,13 +62,14 @@ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
|
62
62
|
// ../core/dist/generation.js
|
|
63
63
|
import { readFileSync as readFileSync2, existsSync as existsSync6 } from "fs";
|
|
64
64
|
import { join as join6 } from "path";
|
|
65
|
-
var {spawn:
|
|
65
|
+
var {spawn: spawn3 } = globalThis.Bun;
|
|
66
66
|
import simpleGit3 from "simple-git";
|
|
67
67
|
|
|
68
68
|
// ../core/dist/worktree.js
|
|
69
69
|
import simpleGit from "simple-git";
|
|
70
70
|
import { join as join2 } from "path";
|
|
71
71
|
import { existsSync as existsSync2, rmSync, symlinkSync } from "fs";
|
|
72
|
+
var {spawn } = globalThis.Bun;
|
|
72
73
|
|
|
73
74
|
// ../core/dist/logger.js
|
|
74
75
|
import { appendFileSync, mkdirSync, existsSync } from "fs";
|
|
@@ -128,6 +129,32 @@ var logger = {
|
|
|
128
129
|
};
|
|
129
130
|
|
|
130
131
|
// ../core/dist/worktree.js
|
|
132
|
+
async function prepareWorktreeDeps(worktreePath, projectPath) {
|
|
133
|
+
let pm = "npm";
|
|
134
|
+
if (existsSync2(join2(projectPath, "pnpm-lock.yaml")))
|
|
135
|
+
pm = "pnpm";
|
|
136
|
+
else if (existsSync2(join2(projectPath, "bun.lock")) || existsSync2(join2(projectPath, "bun.lockb")))
|
|
137
|
+
pm = "bun";
|
|
138
|
+
else if (existsSync2(join2(projectPath, "yarn.lock")))
|
|
139
|
+
pm = "yarn";
|
|
140
|
+
if (pm === "npm")
|
|
141
|
+
return;
|
|
142
|
+
const cmd = pm === "pnpm" ? ["pnpm", "install", "--frozen-lockfile", "--prefer-offline"] : pm === "bun" ? ["bun", "install", "--frozen-lockfile"] : ["yarn", "install", "--frozen-lockfile"];
|
|
143
|
+
logger.info("worktree", `installing deps (${pm})`, { worktreePath: worktreePath.split("/").slice(-2).join("/") });
|
|
144
|
+
const proc = spawn({
|
|
145
|
+
cmd,
|
|
146
|
+
cwd: worktreePath,
|
|
147
|
+
stdin: "ignore",
|
|
148
|
+
stdout: "pipe",
|
|
149
|
+
stderr: "pipe",
|
|
150
|
+
env: { ...process.env }
|
|
151
|
+
});
|
|
152
|
+
const exitCode = await proc.exited;
|
|
153
|
+
if (exitCode !== 0) {
|
|
154
|
+
const stderr = await new Response(proc.stderr).text();
|
|
155
|
+
logger.warn("worktree", `${pm} install exited ${exitCode}`, { stderr: stderr.substring(0, 300) });
|
|
156
|
+
}
|
|
157
|
+
}
|
|
131
158
|
var PREVIEW_PORT = STASH_PORT_START;
|
|
132
159
|
|
|
133
160
|
class WorktreeManager {
|
|
@@ -140,6 +167,9 @@ class WorktreeManager {
|
|
|
140
167
|
this.git = simpleGit(projectPath);
|
|
141
168
|
this.cleanupStaleWorktrees();
|
|
142
169
|
}
|
|
170
|
+
getProjectPath() {
|
|
171
|
+
return this.projectPath;
|
|
172
|
+
}
|
|
143
173
|
async cleanupStaleWorktrees() {
|
|
144
174
|
const worktreesDir = join2(this.projectPath, ".stashes", "worktrees");
|
|
145
175
|
if (!existsSync2(worktreesDir))
|
|
@@ -704,7 +734,7 @@ import { mkdirSync as mkdirSync4, existsSync as existsSync5 } from "fs";
|
|
|
704
734
|
import simpleGit2 from "simple-git";
|
|
705
735
|
|
|
706
736
|
// ../core/dist/screenshot.js
|
|
707
|
-
var {spawn } = globalThis.Bun;
|
|
737
|
+
var {spawn: spawn2 } = globalThis.Bun;
|
|
708
738
|
import { join as join4 } from "path";
|
|
709
739
|
import { mkdirSync as mkdirSync3, existsSync as existsSync4 } from "fs";
|
|
710
740
|
var SCREENSHOTS_DIR = ".stashes/screenshots";
|
|
@@ -743,7 +773,7 @@ async function captureScreenshot(portOrOpts, projectPath, stashId) {
|
|
|
743
773
|
await browser.close();
|
|
744
774
|
})();
|
|
745
775
|
`;
|
|
746
|
-
const proc =
|
|
776
|
+
const proc = spawn2({
|
|
747
777
|
cmd: ["node", "-e", playwrightScript],
|
|
748
778
|
stdin: "ignore",
|
|
749
779
|
stdout: "pipe",
|
|
@@ -1132,8 +1162,9 @@ async function generate(opts) {
|
|
|
1132
1162
|
const screenshotWorktree = await worktreeManager.createForGeneration(`screenshot-${stashId}`);
|
|
1133
1163
|
const screenshotGit = simpleGit3(screenshotWorktree.path);
|
|
1134
1164
|
await screenshotGit.checkout(["--detach", stash.branch]);
|
|
1135
|
-
|
|
1136
|
-
|
|
1165
|
+
await prepareWorktreeDeps(screenshotWorktree.path, projectPath);
|
|
1166
|
+
const devServer = spawn3({
|
|
1167
|
+
cmd: ["npm", "run", "dev", "--", "--port", String(port)],
|
|
1137
1168
|
cwd: screenshotWorktree.path,
|
|
1138
1169
|
stdin: "ignore",
|
|
1139
1170
|
stdout: "pipe",
|
|
@@ -1185,7 +1216,7 @@ async function generate(opts) {
|
|
|
1185
1216
|
return completedStashes;
|
|
1186
1217
|
}
|
|
1187
1218
|
// ../core/dist/vary.js
|
|
1188
|
-
var {spawn:
|
|
1219
|
+
var {spawn: spawn4 } = globalThis.Bun;
|
|
1189
1220
|
import simpleGit4 from "simple-git";
|
|
1190
1221
|
function emit2(onProgress, event) {
|
|
1191
1222
|
if (onProgress)
|
|
@@ -1303,8 +1334,9 @@ ${context}` : `The user wants to vary the current UI. Apply this change: ${promp
|
|
|
1303
1334
|
const screenshotWorktree = await worktreeManager.createForGeneration(`screenshot-${stashId}`);
|
|
1304
1335
|
const screenshotGit = simpleGit4(screenshotWorktree.path);
|
|
1305
1336
|
await screenshotGit.checkout(["--detach", stash.branch]);
|
|
1306
|
-
|
|
1307
|
-
|
|
1337
|
+
await prepareWorktreeDeps(screenshotWorktree.path, projectPath);
|
|
1338
|
+
const devServer = spawn4({
|
|
1339
|
+
cmd: ["npm", "run", "dev", "--", "--port", String(port)],
|
|
1308
1340
|
cwd: screenshotWorktree.path,
|
|
1309
1341
|
stdin: "ignore",
|
|
1310
1342
|
stdout: "pipe",
|
|
@@ -1398,7 +1430,7 @@ import { query as query2, tool, createSdkMcpServer } from "@anthropic-ai/claude-
|
|
|
1398
1430
|
import { z } from "zod/v4";
|
|
1399
1431
|
|
|
1400
1432
|
// ../server/dist/services/app-proxy.js
|
|
1401
|
-
import { spawn as
|
|
1433
|
+
import { spawn as spawn5 } from "child_process";
|
|
1402
1434
|
function startAppProxy(userDevPort, proxyPort, injectOverlay) {
|
|
1403
1435
|
const overlayScript = injectOverlay("", userDevPort, proxyPort);
|
|
1404
1436
|
const overlayEscaped = JSON.stringify(overlayScript);
|
|
@@ -1473,7 +1505,7 @@ server.listen(${proxyPort}, () => {
|
|
|
1473
1505
|
if (process.send) process.send('ready');
|
|
1474
1506
|
});
|
|
1475
1507
|
`;
|
|
1476
|
-
const child =
|
|
1508
|
+
const child = spawn5("node", ["-e", proxyScript], {
|
|
1477
1509
|
stdio: ["ignore", "inherit", "inherit", "ipc"]
|
|
1478
1510
|
});
|
|
1479
1511
|
child.on("error", (err) => {
|
|
@@ -1716,8 +1748,9 @@ class PreviewPool {
|
|
|
1716
1748
|
this.usedPorts.add(proxyPort);
|
|
1717
1749
|
const devPort = proxyPort + DEV_PORT_OFFSET;
|
|
1718
1750
|
const worktreePath = await this.worktreeManager.createPreviewForPool(stashId);
|
|
1751
|
+
await prepareWorktreeDeps(worktreePath, this.worktreeManager.getProjectPath());
|
|
1719
1752
|
const process2 = Bun.spawn({
|
|
1720
|
-
cmd: ["npm", "run", "dev"],
|
|
1753
|
+
cmd: ["npm", "run", "dev", "--", "--port", String(devPort)],
|
|
1721
1754
|
cwd: worktreePath,
|
|
1722
1755
|
stdin: "ignore",
|
|
1723
1756
|
stdout: "pipe",
|
|
@@ -2218,11 +2251,44 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2218
2251
|
mcpServers: {
|
|
2219
2252
|
"stashes-chat": stashServer
|
|
2220
2253
|
},
|
|
2254
|
+
disallowedTools: [
|
|
2255
|
+
"Write",
|
|
2256
|
+
"Edit",
|
|
2257
|
+
"Bash",
|
|
2258
|
+
"NotebookEdit",
|
|
2259
|
+
"LSP",
|
|
2260
|
+
"Agent",
|
|
2261
|
+
"TodoWrite",
|
|
2262
|
+
"TaskCreate",
|
|
2263
|
+
"TaskUpdate",
|
|
2264
|
+
"TaskList",
|
|
2265
|
+
"TaskGet",
|
|
2266
|
+
"Skill",
|
|
2267
|
+
"ToolSearch",
|
|
2268
|
+
"EnterPlanMode",
|
|
2269
|
+
"ExitPlanMode",
|
|
2270
|
+
"WebSearch",
|
|
2271
|
+
"WebFetch"
|
|
2272
|
+
],
|
|
2221
2273
|
permissionMode: "bypassPermissions",
|
|
2222
2274
|
allowDangerouslySkipPermissions: true,
|
|
2223
2275
|
includePartialMessages: true
|
|
2224
2276
|
}
|
|
2225
2277
|
});
|
|
2278
|
+
const VISIBLE_TOOLS = new Set([
|
|
2279
|
+
"generate_stashes",
|
|
2280
|
+
"vary_stash",
|
|
2281
|
+
"show_stash",
|
|
2282
|
+
"stashes_generate",
|
|
2283
|
+
"stashes_vary",
|
|
2284
|
+
"stashes_show",
|
|
2285
|
+
"stashes_list",
|
|
2286
|
+
"stashes_apply",
|
|
2287
|
+
"stashes_remove",
|
|
2288
|
+
"stashes_browse"
|
|
2289
|
+
]);
|
|
2290
|
+
const hiddenToolIds = new Set;
|
|
2291
|
+
let insideHiddenTool = false;
|
|
2226
2292
|
for await (const sdkMessage of queryIter) {
|
|
2227
2293
|
if (sdkMessage.type === "system" && "subtype" in sdkMessage && sdkMessage.subtype === "init") {
|
|
2228
2294
|
const sessionId = "session_id" in sdkMessage ? sdkMessage.session_id : "";
|
|
@@ -2236,14 +2302,16 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2236
2302
|
if (event.type === "content_block_delta") {
|
|
2237
2303
|
const delta = event.delta;
|
|
2238
2304
|
if (delta.type === "text_delta" && delta.text) {
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2305
|
+
if (!insideHiddenTool) {
|
|
2306
|
+
flushThinking();
|
|
2307
|
+
textBuf += delta.text;
|
|
2308
|
+
this.broadcast({
|
|
2309
|
+
type: "ai_stream",
|
|
2310
|
+
content: delta.text,
|
|
2311
|
+
streamType: "text",
|
|
2312
|
+
source: "chat"
|
|
2313
|
+
});
|
|
2314
|
+
}
|
|
2247
2315
|
} else if (delta.type === "thinking_delta" && delta.thinking) {
|
|
2248
2316
|
thinkingBuf += delta.thinking;
|
|
2249
2317
|
this.broadcast({
|
|
@@ -2260,12 +2328,19 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2260
2328
|
const msg = sdkMessage.message;
|
|
2261
2329
|
for (const block of msg.content || []) {
|
|
2262
2330
|
if (block.type === "tool_use") {
|
|
2263
|
-
flushThinking();
|
|
2264
|
-
flushText();
|
|
2265
2331
|
const toolId = block.id;
|
|
2266
2332
|
const toolName = block.name;
|
|
2267
2333
|
const toolParams = block.input ?? {};
|
|
2268
2334
|
toolNameMap.set(toolId, toolName);
|
|
2335
|
+
const isVisible = VISIBLE_TOOLS.has(toolName);
|
|
2336
|
+
if (!isVisible) {
|
|
2337
|
+
hiddenToolIds.add(toolId);
|
|
2338
|
+
insideHiddenTool = true;
|
|
2339
|
+
continue;
|
|
2340
|
+
}
|
|
2341
|
+
insideHiddenTool = false;
|
|
2342
|
+
flushThinking();
|
|
2343
|
+
flushText();
|
|
2269
2344
|
save({
|
|
2270
2345
|
id: crypto.randomUUID(),
|
|
2271
2346
|
role: "assistant",
|
|
@@ -2301,6 +2376,12 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2301
2376
|
const toolUseId = b.tool_use_id;
|
|
2302
2377
|
const isError = b.is_error || false;
|
|
2303
2378
|
const endToolName = toolNameMap.get(toolUseId) || "unknown";
|
|
2379
|
+
if (hiddenToolIds.has(toolUseId)) {
|
|
2380
|
+
hiddenToolIds.delete(toolUseId);
|
|
2381
|
+
insideHiddenTool = false;
|
|
2382
|
+
continue;
|
|
2383
|
+
}
|
|
2384
|
+
insideHiddenTool = false;
|
|
2304
2385
|
if (endToolName.includes("generate_stashes") || endToolName.includes("stashes_generate") || endToolName.includes("vary_stash") || endToolName.includes("stashes_vary")) {
|
|
2305
2386
|
this.stopStashPoll();
|
|
2306
2387
|
}
|
|
@@ -2469,9 +2550,19 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2469
2550
|
case "error":
|
|
2470
2551
|
this.broadcast({ type: "stash:error", stashId: event.stashId, error: event.error });
|
|
2471
2552
|
break;
|
|
2472
|
-
case "ai_stream":
|
|
2473
|
-
|
|
2474
|
-
|
|
2553
|
+
case "ai_stream":
|
|
2554
|
+
break;
|
|
2555
|
+
case "activity": {
|
|
2556
|
+
const activityEvent = {
|
|
2557
|
+
stashId: event.stashId,
|
|
2558
|
+
action: event.action,
|
|
2559
|
+
file: event.file,
|
|
2560
|
+
lines: event.lines,
|
|
2561
|
+
content: event.content,
|
|
2562
|
+
timestamp: event.timestamp
|
|
2563
|
+
};
|
|
2564
|
+
this.activityStore.append(activityEvent);
|
|
2565
|
+
this.broadcast({ type: "stash:activity", stashId: event.stashId, event: activityEvent });
|
|
2475
2566
|
break;
|
|
2476
2567
|
}
|
|
2477
2568
|
}
|
package/dist/mcp.js
CHANGED
|
@@ -28,7 +28,7 @@ import { z } from "zod";
|
|
|
28
28
|
// ../core/dist/generation.js
|
|
29
29
|
import { readFileSync as readFileSync2, existsSync as existsSync6 } from "fs";
|
|
30
30
|
import { join as join6 } from "path";
|
|
31
|
-
var {spawn:
|
|
31
|
+
var {spawn: spawn3 } = globalThis.Bun;
|
|
32
32
|
import simpleGit3 from "simple-git";
|
|
33
33
|
// ../shared/dist/constants/index.js
|
|
34
34
|
var STASHES_PORT = 4000;
|
|
@@ -54,6 +54,7 @@ var DEFAULT_DIRECTIVES = [
|
|
|
54
54
|
import simpleGit from "simple-git";
|
|
55
55
|
import { join as join2 } from "path";
|
|
56
56
|
import { existsSync as existsSync2, rmSync, symlinkSync } from "fs";
|
|
57
|
+
var {spawn } = globalThis.Bun;
|
|
57
58
|
|
|
58
59
|
// ../core/dist/logger.js
|
|
59
60
|
import { appendFileSync, mkdirSync, existsSync } from "fs";
|
|
@@ -113,6 +114,32 @@ var logger = {
|
|
|
113
114
|
};
|
|
114
115
|
|
|
115
116
|
// ../core/dist/worktree.js
|
|
117
|
+
async function prepareWorktreeDeps(worktreePath, projectPath) {
|
|
118
|
+
let pm = "npm";
|
|
119
|
+
if (existsSync2(join2(projectPath, "pnpm-lock.yaml")))
|
|
120
|
+
pm = "pnpm";
|
|
121
|
+
else if (existsSync2(join2(projectPath, "bun.lock")) || existsSync2(join2(projectPath, "bun.lockb")))
|
|
122
|
+
pm = "bun";
|
|
123
|
+
else if (existsSync2(join2(projectPath, "yarn.lock")))
|
|
124
|
+
pm = "yarn";
|
|
125
|
+
if (pm === "npm")
|
|
126
|
+
return;
|
|
127
|
+
const cmd = pm === "pnpm" ? ["pnpm", "install", "--frozen-lockfile", "--prefer-offline"] : pm === "bun" ? ["bun", "install", "--frozen-lockfile"] : ["yarn", "install", "--frozen-lockfile"];
|
|
128
|
+
logger.info("worktree", `installing deps (${pm})`, { worktreePath: worktreePath.split("/").slice(-2).join("/") });
|
|
129
|
+
const proc = spawn({
|
|
130
|
+
cmd,
|
|
131
|
+
cwd: worktreePath,
|
|
132
|
+
stdin: "ignore",
|
|
133
|
+
stdout: "pipe",
|
|
134
|
+
stderr: "pipe",
|
|
135
|
+
env: { ...process.env }
|
|
136
|
+
});
|
|
137
|
+
const exitCode = await proc.exited;
|
|
138
|
+
if (exitCode !== 0) {
|
|
139
|
+
const stderr = await new Response(proc.stderr).text();
|
|
140
|
+
logger.warn("worktree", `${pm} install exited ${exitCode}`, { stderr: stderr.substring(0, 300) });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
116
143
|
var PREVIEW_PORT = STASH_PORT_START;
|
|
117
144
|
|
|
118
145
|
class WorktreeManager {
|
|
@@ -125,6 +152,9 @@ class WorktreeManager {
|
|
|
125
152
|
this.git = simpleGit(projectPath);
|
|
126
153
|
this.cleanupStaleWorktrees();
|
|
127
154
|
}
|
|
155
|
+
getProjectPath() {
|
|
156
|
+
return this.projectPath;
|
|
157
|
+
}
|
|
128
158
|
async cleanupStaleWorktrees() {
|
|
129
159
|
const worktreesDir = join2(this.projectPath, ".stashes", "worktrees");
|
|
130
160
|
if (!existsSync2(worktreesDir))
|
|
@@ -689,7 +719,7 @@ import { mkdirSync as mkdirSync4, existsSync as existsSync5 } from "fs";
|
|
|
689
719
|
import simpleGit2 from "simple-git";
|
|
690
720
|
|
|
691
721
|
// ../core/dist/screenshot.js
|
|
692
|
-
var {spawn } = globalThis.Bun;
|
|
722
|
+
var {spawn: spawn2 } = globalThis.Bun;
|
|
693
723
|
import { join as join4 } from "path";
|
|
694
724
|
import { mkdirSync as mkdirSync3, existsSync as existsSync4 } from "fs";
|
|
695
725
|
var SCREENSHOTS_DIR = ".stashes/screenshots";
|
|
@@ -728,7 +758,7 @@ async function captureScreenshot(portOrOpts, projectPath, stashId) {
|
|
|
728
758
|
await browser.close();
|
|
729
759
|
})();
|
|
730
760
|
`;
|
|
731
|
-
const proc =
|
|
761
|
+
const proc = spawn2({
|
|
732
762
|
cmd: ["node", "-e", playwrightScript],
|
|
733
763
|
stdin: "ignore",
|
|
734
764
|
stdout: "pipe",
|
|
@@ -1117,8 +1147,9 @@ async function generate(opts) {
|
|
|
1117
1147
|
const screenshotWorktree = await worktreeManager.createForGeneration(`screenshot-${stashId}`);
|
|
1118
1148
|
const screenshotGit = simpleGit3(screenshotWorktree.path);
|
|
1119
1149
|
await screenshotGit.checkout(["--detach", stash.branch]);
|
|
1120
|
-
|
|
1121
|
-
|
|
1150
|
+
await prepareWorktreeDeps(screenshotWorktree.path, projectPath);
|
|
1151
|
+
const devServer = spawn3({
|
|
1152
|
+
cmd: ["npm", "run", "dev", "--", "--port", String(port)],
|
|
1122
1153
|
cwd: screenshotWorktree.path,
|
|
1123
1154
|
stdin: "ignore",
|
|
1124
1155
|
stdout: "pipe",
|
|
@@ -1170,7 +1201,7 @@ async function generate(opts) {
|
|
|
1170
1201
|
return completedStashes;
|
|
1171
1202
|
}
|
|
1172
1203
|
// ../core/dist/vary.js
|
|
1173
|
-
var {spawn:
|
|
1204
|
+
var {spawn: spawn4 } = globalThis.Bun;
|
|
1174
1205
|
import simpleGit4 from "simple-git";
|
|
1175
1206
|
function emit2(onProgress, event) {
|
|
1176
1207
|
if (onProgress)
|
|
@@ -1288,8 +1319,9 @@ ${context}` : `The user wants to vary the current UI. Apply this change: ${promp
|
|
|
1288
1319
|
const screenshotWorktree = await worktreeManager.createForGeneration(`screenshot-${stashId}`);
|
|
1289
1320
|
const screenshotGit = simpleGit4(screenshotWorktree.path);
|
|
1290
1321
|
await screenshotGit.checkout(["--detach", stash.branch]);
|
|
1291
|
-
|
|
1292
|
-
|
|
1322
|
+
await prepareWorktreeDeps(screenshotWorktree.path, projectPath);
|
|
1323
|
+
const devServer = spawn4({
|
|
1324
|
+
cmd: ["npm", "run", "dev", "--", "--port", String(port)],
|
|
1293
1325
|
cwd: screenshotWorktree.path,
|
|
1294
1326
|
stdin: "ignore",
|
|
1295
1327
|
stdout: "pipe",
|
|
@@ -1622,7 +1654,7 @@ import { query as query2, tool, createSdkMcpServer } from "@anthropic-ai/claude-
|
|
|
1622
1654
|
import { z as z6 } from "zod/v4";
|
|
1623
1655
|
|
|
1624
1656
|
// ../server/dist/services/app-proxy.js
|
|
1625
|
-
import { spawn as
|
|
1657
|
+
import { spawn as spawn5 } from "child_process";
|
|
1626
1658
|
function startAppProxy(userDevPort, proxyPort, injectOverlay) {
|
|
1627
1659
|
const overlayScript = injectOverlay("", userDevPort, proxyPort);
|
|
1628
1660
|
const overlayEscaped = JSON.stringify(overlayScript);
|
|
@@ -1697,7 +1729,7 @@ server.listen(${proxyPort}, () => {
|
|
|
1697
1729
|
if (process.send) process.send('ready');
|
|
1698
1730
|
});
|
|
1699
1731
|
`;
|
|
1700
|
-
const child =
|
|
1732
|
+
const child = spawn5("node", ["-e", proxyScript], {
|
|
1701
1733
|
stdio: ["ignore", "inherit", "inherit", "ipc"]
|
|
1702
1734
|
});
|
|
1703
1735
|
child.on("error", (err) => {
|
|
@@ -1940,8 +1972,9 @@ class PreviewPool {
|
|
|
1940
1972
|
this.usedPorts.add(proxyPort);
|
|
1941
1973
|
const devPort = proxyPort + DEV_PORT_OFFSET;
|
|
1942
1974
|
const worktreePath = await this.worktreeManager.createPreviewForPool(stashId);
|
|
1975
|
+
await prepareWorktreeDeps(worktreePath, this.worktreeManager.getProjectPath());
|
|
1943
1976
|
const process2 = Bun.spawn({
|
|
1944
|
-
cmd: ["npm", "run", "dev"],
|
|
1977
|
+
cmd: ["npm", "run", "dev", "--", "--port", String(devPort)],
|
|
1945
1978
|
cwd: worktreePath,
|
|
1946
1979
|
stdin: "ignore",
|
|
1947
1980
|
stdout: "pipe",
|
|
@@ -2442,11 +2475,44 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2442
2475
|
mcpServers: {
|
|
2443
2476
|
"stashes-chat": stashServer
|
|
2444
2477
|
},
|
|
2478
|
+
disallowedTools: [
|
|
2479
|
+
"Write",
|
|
2480
|
+
"Edit",
|
|
2481
|
+
"Bash",
|
|
2482
|
+
"NotebookEdit",
|
|
2483
|
+
"LSP",
|
|
2484
|
+
"Agent",
|
|
2485
|
+
"TodoWrite",
|
|
2486
|
+
"TaskCreate",
|
|
2487
|
+
"TaskUpdate",
|
|
2488
|
+
"TaskList",
|
|
2489
|
+
"TaskGet",
|
|
2490
|
+
"Skill",
|
|
2491
|
+
"ToolSearch",
|
|
2492
|
+
"EnterPlanMode",
|
|
2493
|
+
"ExitPlanMode",
|
|
2494
|
+
"WebSearch",
|
|
2495
|
+
"WebFetch"
|
|
2496
|
+
],
|
|
2445
2497
|
permissionMode: "bypassPermissions",
|
|
2446
2498
|
allowDangerouslySkipPermissions: true,
|
|
2447
2499
|
includePartialMessages: true
|
|
2448
2500
|
}
|
|
2449
2501
|
});
|
|
2502
|
+
const VISIBLE_TOOLS = new Set([
|
|
2503
|
+
"generate_stashes",
|
|
2504
|
+
"vary_stash",
|
|
2505
|
+
"show_stash",
|
|
2506
|
+
"stashes_generate",
|
|
2507
|
+
"stashes_vary",
|
|
2508
|
+
"stashes_show",
|
|
2509
|
+
"stashes_list",
|
|
2510
|
+
"stashes_apply",
|
|
2511
|
+
"stashes_remove",
|
|
2512
|
+
"stashes_browse"
|
|
2513
|
+
]);
|
|
2514
|
+
const hiddenToolIds = new Set;
|
|
2515
|
+
let insideHiddenTool = false;
|
|
2450
2516
|
for await (const sdkMessage of queryIter) {
|
|
2451
2517
|
if (sdkMessage.type === "system" && "subtype" in sdkMessage && sdkMessage.subtype === "init") {
|
|
2452
2518
|
const sessionId = "session_id" in sdkMessage ? sdkMessage.session_id : "";
|
|
@@ -2460,14 +2526,16 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2460
2526
|
if (event.type === "content_block_delta") {
|
|
2461
2527
|
const delta = event.delta;
|
|
2462
2528
|
if (delta.type === "text_delta" && delta.text) {
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2529
|
+
if (!insideHiddenTool) {
|
|
2530
|
+
flushThinking();
|
|
2531
|
+
textBuf += delta.text;
|
|
2532
|
+
this.broadcast({
|
|
2533
|
+
type: "ai_stream",
|
|
2534
|
+
content: delta.text,
|
|
2535
|
+
streamType: "text",
|
|
2536
|
+
source: "chat"
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2471
2539
|
} else if (delta.type === "thinking_delta" && delta.thinking) {
|
|
2472
2540
|
thinkingBuf += delta.thinking;
|
|
2473
2541
|
this.broadcast({
|
|
@@ -2484,12 +2552,19 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2484
2552
|
const msg = sdkMessage.message;
|
|
2485
2553
|
for (const block of msg.content || []) {
|
|
2486
2554
|
if (block.type === "tool_use") {
|
|
2487
|
-
flushThinking();
|
|
2488
|
-
flushText();
|
|
2489
2555
|
const toolId = block.id;
|
|
2490
2556
|
const toolName = block.name;
|
|
2491
2557
|
const toolParams = block.input ?? {};
|
|
2492
2558
|
toolNameMap.set(toolId, toolName);
|
|
2559
|
+
const isVisible = VISIBLE_TOOLS.has(toolName);
|
|
2560
|
+
if (!isVisible) {
|
|
2561
|
+
hiddenToolIds.add(toolId);
|
|
2562
|
+
insideHiddenTool = true;
|
|
2563
|
+
continue;
|
|
2564
|
+
}
|
|
2565
|
+
insideHiddenTool = false;
|
|
2566
|
+
flushThinking();
|
|
2567
|
+
flushText();
|
|
2493
2568
|
save({
|
|
2494
2569
|
id: crypto.randomUUID(),
|
|
2495
2570
|
role: "assistant",
|
|
@@ -2525,6 +2600,12 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2525
2600
|
const toolUseId = b.tool_use_id;
|
|
2526
2601
|
const isError = b.is_error || false;
|
|
2527
2602
|
const endToolName = toolNameMap.get(toolUseId) || "unknown";
|
|
2603
|
+
if (hiddenToolIds.has(toolUseId)) {
|
|
2604
|
+
hiddenToolIds.delete(toolUseId);
|
|
2605
|
+
insideHiddenTool = false;
|
|
2606
|
+
continue;
|
|
2607
|
+
}
|
|
2608
|
+
insideHiddenTool = false;
|
|
2528
2609
|
if (endToolName.includes("generate_stashes") || endToolName.includes("stashes_generate") || endToolName.includes("vary_stash") || endToolName.includes("stashes_vary")) {
|
|
2529
2610
|
this.stopStashPoll();
|
|
2530
2611
|
}
|
|
@@ -2693,9 +2774,19 @@ ${sourceCode.substring(0, 3000)}
|
|
|
2693
2774
|
case "error":
|
|
2694
2775
|
this.broadcast({ type: "stash:error", stashId: event.stashId, error: event.error });
|
|
2695
2776
|
break;
|
|
2696
|
-
case "ai_stream":
|
|
2697
|
-
|
|
2698
|
-
|
|
2777
|
+
case "ai_stream":
|
|
2778
|
+
break;
|
|
2779
|
+
case "activity": {
|
|
2780
|
+
const activityEvent = {
|
|
2781
|
+
stashId: event.stashId,
|
|
2782
|
+
action: event.action,
|
|
2783
|
+
file: event.file,
|
|
2784
|
+
lines: event.lines,
|
|
2785
|
+
content: event.content,
|
|
2786
|
+
timestamp: event.timestamp
|
|
2787
|
+
};
|
|
2788
|
+
this.activityStore.append(activityEvent);
|
|
2789
|
+
this.broadcast({ type: "stash:activity", stashId: event.stashId, event: activityEvent });
|
|
2699
2790
|
break;
|
|
2700
2791
|
}
|
|
2701
2792
|
}
|