stashes 0.1.19 → 0.1.20
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 +165 -30
- package/dist/commands/setup.d.ts +13 -0
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +3 -3
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +115 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +125 -27
- package/dist/web/assets/{index-_bKtJYAZ.js → index-CMBT005S.js} +1 -1
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -538,6 +538,7 @@ function killAiProcess(id) {
|
|
|
538
538
|
}
|
|
539
539
|
return false;
|
|
540
540
|
}
|
|
541
|
+
var toolNameMap = new Map;
|
|
541
542
|
async function* parseClaudeStream(proc) {
|
|
542
543
|
const stdout = proc.stdout;
|
|
543
544
|
if (!stdout || typeof stdout === "number") {
|
|
@@ -574,15 +575,58 @@ async function* parseClaudeStream(proc) {
|
|
|
574
575
|
} else if (block.type === "thinking" && block.thinking) {
|
|
575
576
|
yield { type: "thinking", content: block.thinking };
|
|
576
577
|
} else if (block.type === "tool_use") {
|
|
577
|
-
|
|
578
|
-
|
|
578
|
+
const toolId = block.id;
|
|
579
|
+
const toolName = block.name;
|
|
580
|
+
toolNameMap.set(toolId, toolName);
|
|
581
|
+
logger.debug("claude", `tool_use: ${toolName}`);
|
|
582
|
+
yield {
|
|
583
|
+
type: "tool_use",
|
|
584
|
+
content: JSON.stringify({ tool: toolName, input: block.input }),
|
|
585
|
+
toolName,
|
|
586
|
+
toolInput: block.input,
|
|
587
|
+
toolUseId: toolId
|
|
588
|
+
};
|
|
579
589
|
}
|
|
580
590
|
}
|
|
581
591
|
}
|
|
592
|
+
if (parsed.type === "user" && parsed.message) {
|
|
593
|
+
const message = parsed.message;
|
|
594
|
+
for (const block of message.content || []) {
|
|
595
|
+
if (block.type === "tool_result") {
|
|
596
|
+
const toolUseId = block.tool_use_id;
|
|
597
|
+
const isError = block.is_error || false;
|
|
598
|
+
const toolName = toolNameMap.get(toolUseId) || "unknown";
|
|
599
|
+
let resultContent;
|
|
600
|
+
if (typeof block.content === "string") {
|
|
601
|
+
resultContent = block.content;
|
|
602
|
+
} else if (Array.isArray(block.content)) {
|
|
603
|
+
resultContent = block.content.filter((c) => c.type === "text").map((c) => c.text).join(`
|
|
604
|
+
`);
|
|
605
|
+
} else {
|
|
606
|
+
resultContent = "";
|
|
607
|
+
}
|
|
608
|
+
yield {
|
|
609
|
+
type: "tool_result",
|
|
610
|
+
content: resultContent.substring(0, 500),
|
|
611
|
+
toolName,
|
|
612
|
+
toolUseId,
|
|
613
|
+
isError
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (parsed.type === "result") {
|
|
619
|
+
yield {
|
|
620
|
+
type: "result",
|
|
621
|
+
content: "",
|
|
622
|
+
resultSubtype: parsed.subtype
|
|
623
|
+
};
|
|
624
|
+
}
|
|
582
625
|
}
|
|
583
626
|
}
|
|
584
627
|
} finally {
|
|
585
628
|
logger.debug("claude", `stream ended`, { totalChunks: chunkCount });
|
|
629
|
+
toolNameMap.clear();
|
|
586
630
|
reader.releaseLock();
|
|
587
631
|
}
|
|
588
632
|
}
|
|
@@ -964,6 +1008,34 @@ async function remove(projectPath, stashId) {
|
|
|
964
1008
|
} catch {}
|
|
965
1009
|
logger.info("manage", `removed stash: ${stashId}`);
|
|
966
1010
|
}
|
|
1011
|
+
async function show(projectPath, stashId) {
|
|
1012
|
+
const persistence = new PersistenceService(projectPath);
|
|
1013
|
+
let found;
|
|
1014
|
+
for (const project of persistence.listProjects()) {
|
|
1015
|
+
found = persistence.getStash(project.id, stashId);
|
|
1016
|
+
if (found)
|
|
1017
|
+
break;
|
|
1018
|
+
}
|
|
1019
|
+
if (!found)
|
|
1020
|
+
return null;
|
|
1021
|
+
const git = simpleGit4(projectPath);
|
|
1022
|
+
const branch = found.branch || `stashes/${stashId}`;
|
|
1023
|
+
let diff = "";
|
|
1024
|
+
let files = [];
|
|
1025
|
+
try {
|
|
1026
|
+
const base = await git.raw(["merge-base", "HEAD", branch]);
|
|
1027
|
+
diff = await git.raw(["diff", base.trim(), branch, "--stat"]);
|
|
1028
|
+
const fullDiff = await git.raw(["diff", base.trim(), branch]);
|
|
1029
|
+
diff = fullDiff.length > 8000 ? fullDiff.substring(0, 8000) + `
|
|
1030
|
+
... (truncated)` : fullDiff;
|
|
1031
|
+
const fileList = await git.raw(["diff", "--name-only", base.trim(), branch]);
|
|
1032
|
+
files = fileList.trim().split(`
|
|
1033
|
+
`).filter(Boolean);
|
|
1034
|
+
} catch {
|
|
1035
|
+
diff = "(branch not found or no diff available)";
|
|
1036
|
+
}
|
|
1037
|
+
return { stash: found, diff, files };
|
|
1038
|
+
}
|
|
967
1039
|
// ../mcp/src/tools/generate.ts
|
|
968
1040
|
var generateParams = {
|
|
969
1041
|
prompt: z.string().describe('What UI changes to generate (e.g. "make the hero section bolder")'),
|
|
@@ -1088,10 +1160,48 @@ async function handleVary(args, projectPath) {
|
|
|
1088
1160
|
};
|
|
1089
1161
|
}
|
|
1090
1162
|
|
|
1091
|
-
// ../mcp/src/tools/
|
|
1163
|
+
// ../mcp/src/tools/show.ts
|
|
1092
1164
|
import { z as z4 } from "zod";
|
|
1165
|
+
var showParams = {
|
|
1166
|
+
stashId: z4.string().describe('The stash ID to inspect (e.g. "stash_a1b2c3d4")')
|
|
1167
|
+
};
|
|
1168
|
+
async function handleShow(args, projectPath) {
|
|
1169
|
+
const { stashId } = args;
|
|
1170
|
+
initLogFile(projectPath);
|
|
1171
|
+
const result = await show(projectPath, stashId);
|
|
1172
|
+
if (!result) {
|
|
1173
|
+
return {
|
|
1174
|
+
content: [{
|
|
1175
|
+
type: "text",
|
|
1176
|
+
text: `No stash found with ID "${stashId}".`
|
|
1177
|
+
}]
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
const { stash, diff, files } = result;
|
|
1181
|
+
return {
|
|
1182
|
+
content: [{
|
|
1183
|
+
type: "text",
|
|
1184
|
+
text: JSON.stringify({
|
|
1185
|
+
id: stash.id,
|
|
1186
|
+
number: stash.number,
|
|
1187
|
+
prompt: stash.prompt,
|
|
1188
|
+
status: stash.status,
|
|
1189
|
+
branch: stash.branch,
|
|
1190
|
+
componentPath: stash.componentPath ?? null,
|
|
1191
|
+
screenshotPath: stash.screenshotUrl,
|
|
1192
|
+
relatedTo: stash.relatedTo,
|
|
1193
|
+
createdAt: stash.createdAt,
|
|
1194
|
+
filesChanged: files,
|
|
1195
|
+
diff
|
|
1196
|
+
}, null, 2)
|
|
1197
|
+
}]
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
// ../mcp/src/tools/remove.ts
|
|
1202
|
+
import { z as z5 } from "zod";
|
|
1093
1203
|
var removeParams = {
|
|
1094
|
-
stashId:
|
|
1204
|
+
stashId: z5.string().describe("The stash ID to remove")
|
|
1095
1205
|
};
|
|
1096
1206
|
async function handleRemove(args, projectPath) {
|
|
1097
1207
|
const { stashId } = args;
|
|
@@ -1482,9 +1592,12 @@ ${refs.join(`
|
|
|
1482
1592
|
}
|
|
1483
1593
|
const chatPrompt = [
|
|
1484
1594
|
"You are helping the user explore UI design variations for their project.",
|
|
1485
|
-
"You have access to stashes MCP tools to generate, list, browse, vary, and apply stashes.",
|
|
1595
|
+
"You have access to stashes MCP tools to generate, list, show, browse, vary, and apply stashes.",
|
|
1486
1596
|
"If the user asks you to generate, create, or make variations, use the stashes_generate tool.",
|
|
1487
1597
|
"If the user asks to vary an existing stash, use the stashes_vary tool.",
|
|
1598
|
+
"If the user asks about what a stash changed, its diff, or its contents, use stashes_show to inspect it.",
|
|
1599
|
+
'IMPORTANT: NEVER call stashes_apply unless the user explicitly asks to "apply" or "merge" a stash.',
|
|
1600
|
+
'IMPORTANT: NEVER call stashes_remove unless the user explicitly asks to "delete" or "remove" a stash.',
|
|
1488
1601
|
"Otherwise, respond conversationally about their project and stashes.",
|
|
1489
1602
|
"",
|
|
1490
1603
|
component ? `Component: ${component.name}` : "",
|
|
@@ -1519,40 +1632,24 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1519
1632
|
source: "chat"
|
|
1520
1633
|
});
|
|
1521
1634
|
} else if (chunk.type === "tool_use") {
|
|
1522
|
-
let toolName = "unknown";
|
|
1523
|
-
let toolParams = {};
|
|
1524
|
-
try {
|
|
1525
|
-
const parsed = JSON.parse(chunk.content);
|
|
1526
|
-
toolName = parsed.tool || parsed.name || "unknown";
|
|
1527
|
-
toolParams = parsed.input || parsed.params || {};
|
|
1528
|
-
} catch {}
|
|
1529
1635
|
this.broadcast({
|
|
1530
1636
|
type: "ai_stream",
|
|
1531
1637
|
content: chunk.content,
|
|
1532
1638
|
streamType: "tool_start",
|
|
1533
1639
|
source: "chat",
|
|
1534
|
-
toolName,
|
|
1535
|
-
toolParams,
|
|
1640
|
+
toolName: chunk.toolName ?? "unknown",
|
|
1641
|
+
toolParams: chunk.toolInput ?? {},
|
|
1536
1642
|
toolStatus: "running"
|
|
1537
1643
|
});
|
|
1538
1644
|
} else if (chunk.type === "tool_result") {
|
|
1539
|
-
let toolName = "unknown";
|
|
1540
|
-
let toolResult = "";
|
|
1541
|
-
try {
|
|
1542
|
-
const parsed = JSON.parse(chunk.content);
|
|
1543
|
-
toolName = parsed.tool || parsed.name || "unknown";
|
|
1544
|
-
toolResult = typeof parsed.result === "string" ? parsed.result.substring(0, 200) : JSON.stringify(parsed.result).substring(0, 200);
|
|
1545
|
-
} catch {
|
|
1546
|
-
toolResult = chunk.content.substring(0, 200);
|
|
1547
|
-
}
|
|
1548
1645
|
this.broadcast({
|
|
1549
1646
|
type: "ai_stream",
|
|
1550
1647
|
content: chunk.content,
|
|
1551
1648
|
streamType: "tool_end",
|
|
1552
1649
|
source: "chat",
|
|
1553
|
-
toolName,
|
|
1554
|
-
toolStatus: "completed",
|
|
1555
|
-
toolResult
|
|
1650
|
+
toolName: chunk.toolName ?? "unknown",
|
|
1651
|
+
toolStatus: chunk.isError ? "error" : "completed",
|
|
1652
|
+
toolResult: chunk.content.substring(0, 300)
|
|
1556
1653
|
});
|
|
1557
1654
|
}
|
|
1558
1655
|
}
|
|
@@ -2196,7 +2293,8 @@ var server = new McpServer({
|
|
|
2196
2293
|
});
|
|
2197
2294
|
server.tool("stashes_generate", "Generate multiple AI-powered UI design explorations (stashes) for a given prompt. Each stash applies a different creative direction.", generateParams, async (args) => handleGenerate(args, projectPath));
|
|
2198
2295
|
server.tool("stashes_list", "List all existing stashes in the current project. Shows ID, prompt, status, branch, and screenshot path.", listParams, async (args) => handleList(args, projectPath));
|
|
2199
|
-
server.tool("
|
|
2296
|
+
server.tool("stashes_show", "Show detailed information about a specific stash including its git diff, changed files, prompt, and metadata. Use this to inspect what a stash changed without applying it.", showParams, async (args) => handleShow(args, projectPath));
|
|
2297
|
+
server.tool("stashes_apply", "Merge a stash branch into the current git branch. Applies the AI-generated UI changes and cleans up all worktrees. ONLY use when the user explicitly asks to apply or merge.", applyParams, async (args) => handleApply(args, projectPath));
|
|
2200
2298
|
server.tool("stashes_vary", "Create a variation of an existing stash by applying additional changes on top of it.", varyParams, async (args) => handleVary(args, projectPath));
|
|
2201
2299
|
server.tool("stashes_remove", "Delete a stash \u2014 removes its persistence entry and git branch.", removeParams, async (args) => handleRemove(args, projectPath));
|
|
2202
2300
|
server.tool("stashes_browse", "Start the Stashes web server and open the browser for interactive browsing of generated stashes.", browseParams, async (args) => handleBrowse(args, projectPath));
|