stashes 0.1.21 → 0.1.22
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
CHANGED
|
@@ -622,15 +622,20 @@ class PersistenceService {
|
|
|
622
622
|
var {spawn } = globalThis.Bun;
|
|
623
623
|
var CLAUDE_BIN = "/opt/homebrew/bin/claude";
|
|
624
624
|
var processes = new Map;
|
|
625
|
-
function startAiProcess(id, prompt, cwd) {
|
|
625
|
+
function startAiProcess(id, prompt, cwd, resumeSessionId) {
|
|
626
626
|
killAiProcess(id);
|
|
627
627
|
logger.info("claude", `spawning process: ${id}`, {
|
|
628
628
|
cwd,
|
|
629
629
|
promptLength: prompt.length,
|
|
630
|
-
promptPreview: prompt.substring(0, 100)
|
|
630
|
+
promptPreview: prompt.substring(0, 100),
|
|
631
|
+
resumeSessionId
|
|
631
632
|
});
|
|
633
|
+
const cmd = [CLAUDE_BIN, "-p", prompt, "--output-format=stream-json", "--verbose", "--dangerously-skip-permissions"];
|
|
634
|
+
if (resumeSessionId) {
|
|
635
|
+
cmd.push("--resume", resumeSessionId);
|
|
636
|
+
}
|
|
632
637
|
const proc = spawn({
|
|
633
|
-
cmd
|
|
638
|
+
cmd,
|
|
634
639
|
stdin: "ignore",
|
|
635
640
|
stdout: "pipe",
|
|
636
641
|
stderr: "pipe",
|
|
@@ -684,6 +689,9 @@ async function* parseClaudeStream(proc) {
|
|
|
684
689
|
} catch {
|
|
685
690
|
continue;
|
|
686
691
|
}
|
|
692
|
+
if (parsed.type === "system" && parsed.subtype === "init" && parsed.session_id) {
|
|
693
|
+
yield { type: "session_id", content: "", sessionId: parsed.session_id };
|
|
694
|
+
}
|
|
687
695
|
if (parsed.type === "assistant" && parsed.message) {
|
|
688
696
|
const message = parsed.message;
|
|
689
697
|
for (const block of message.content || []) {
|
|
@@ -1323,6 +1331,9 @@ class StashService {
|
|
|
1323
1331
|
broadcast;
|
|
1324
1332
|
previewPool;
|
|
1325
1333
|
selectedComponent = null;
|
|
1334
|
+
messageQueue = [];
|
|
1335
|
+
isProcessingMessage = false;
|
|
1336
|
+
chatSessions = new Map;
|
|
1326
1337
|
constructor(projectPath, worktreeManager, persistence, broadcast) {
|
|
1327
1338
|
this.projectPath = projectPath;
|
|
1328
1339
|
this.worktreeManager = worktreeManager;
|
|
@@ -1375,6 +1386,20 @@ class StashService {
|
|
|
1375
1386
|
}
|
|
1376
1387
|
}
|
|
1377
1388
|
async message(projectId, chatId, message, referenceStashIds, componentContext) {
|
|
1389
|
+
this.messageQueue.push({ projectId, chatId, message, referenceStashIds, componentContext });
|
|
1390
|
+
if (!this.isProcessingMessage) {
|
|
1391
|
+
await this.processMessageQueue();
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
async processMessageQueue() {
|
|
1395
|
+
this.isProcessingMessage = true;
|
|
1396
|
+
while (this.messageQueue.length > 0) {
|
|
1397
|
+
const msg = this.messageQueue.shift();
|
|
1398
|
+
await this.processMessage(msg.projectId, msg.chatId, msg.message, msg.referenceStashIds, msg.componentContext);
|
|
1399
|
+
}
|
|
1400
|
+
this.isProcessingMessage = false;
|
|
1401
|
+
}
|
|
1402
|
+
async processMessage(projectId, chatId, message, referenceStashIds, componentContext) {
|
|
1378
1403
|
const component = componentContext ? { name: componentContext.name, filePath: this.selectedComponent?.filePath || "" } : this.selectedComponent;
|
|
1379
1404
|
let sourceCode = "";
|
|
1380
1405
|
const filePath = component?.filePath || "";
|
|
@@ -1394,29 +1419,41 @@ ${refs.join(`
|
|
|
1394
1419
|
`)}`;
|
|
1395
1420
|
}
|
|
1396
1421
|
}
|
|
1397
|
-
const
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1422
|
+
const existingSessionId = this.chatSessions.get(chatId);
|
|
1423
|
+
let chatPrompt;
|
|
1424
|
+
if (existingSessionId) {
|
|
1425
|
+
const parts = [message];
|
|
1426
|
+
if (stashContext)
|
|
1427
|
+
parts.push(stashContext);
|
|
1428
|
+
if (component && !existingSessionId)
|
|
1429
|
+
parts.push(`Component: ${component.name}`);
|
|
1430
|
+
chatPrompt = parts.join(`
|
|
1431
|
+
`);
|
|
1432
|
+
} else {
|
|
1433
|
+
chatPrompt = [
|
|
1434
|
+
"You are helping the user explore UI design variations for their project.",
|
|
1435
|
+
"You have access to stashes MCP tools to generate, list, show, browse, vary, and apply stashes.",
|
|
1436
|
+
"If the user asks you to generate, create, or make variations, use the stashes_generate tool.",
|
|
1437
|
+
"If the user asks to vary an existing stash, use the stashes_vary tool.",
|
|
1438
|
+
"If the user asks about what a stash changed, its diff, or its contents, use stashes_show to inspect it.",
|
|
1439
|
+
'IMPORTANT: NEVER call stashes_apply unless the user explicitly asks to "apply" or "merge" a stash.',
|
|
1440
|
+
'IMPORTANT: NEVER call stashes_remove unless the user explicitly asks to "delete" or "remove" a stash.',
|
|
1441
|
+
"Otherwise, respond conversationally about their project and stashes.",
|
|
1442
|
+
"",
|
|
1443
|
+
component ? `Component: ${component.name}` : "",
|
|
1444
|
+
filePath !== "auto-detect" ? `File: ${filePath}` : "",
|
|
1445
|
+
sourceCode ? `
|
|
1410
1446
|
Source:
|
|
1411
1447
|
\`\`\`
|
|
1412
1448
|
${sourceCode.substring(0, 3000)}
|
|
1413
1449
|
\`\`\`` : "",
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1450
|
+
stashContext,
|
|
1451
|
+
"",
|
|
1452
|
+
`User: ${message}`
|
|
1453
|
+
].filter(Boolean).join(`
|
|
1418
1454
|
`);
|
|
1419
|
-
|
|
1455
|
+
}
|
|
1456
|
+
const aiProcess = startAiProcess("chat", chatPrompt, this.projectPath, existingSessionId);
|
|
1420
1457
|
let thinkingBuf = "";
|
|
1421
1458
|
let textBuf = "";
|
|
1422
1459
|
const pendingMessages = [];
|
|
@@ -1435,6 +1472,10 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1435
1472
|
}
|
|
1436
1473
|
try {
|
|
1437
1474
|
for await (const chunk of parseClaudeStream(aiProcess.process)) {
|
|
1475
|
+
if (chunk.type === "session_id" && chunk.sessionId) {
|
|
1476
|
+
this.chatSessions.set(chatId, chunk.sessionId);
|
|
1477
|
+
continue;
|
|
1478
|
+
}
|
|
1438
1479
|
if (chunk.type === "text") {
|
|
1439
1480
|
flushThinking();
|
|
1440
1481
|
textBuf += chunk.content;
|
package/dist/mcp.js
CHANGED
|
@@ -504,15 +504,20 @@ class PersistenceService {
|
|
|
504
504
|
var {spawn } = globalThis.Bun;
|
|
505
505
|
var CLAUDE_BIN = "/opt/homebrew/bin/claude";
|
|
506
506
|
var processes = new Map;
|
|
507
|
-
function startAiProcess(id, prompt, cwd) {
|
|
507
|
+
function startAiProcess(id, prompt, cwd, resumeSessionId) {
|
|
508
508
|
killAiProcess(id);
|
|
509
509
|
logger.info("claude", `spawning process: ${id}`, {
|
|
510
510
|
cwd,
|
|
511
511
|
promptLength: prompt.length,
|
|
512
|
-
promptPreview: prompt.substring(0, 100)
|
|
512
|
+
promptPreview: prompt.substring(0, 100),
|
|
513
|
+
resumeSessionId
|
|
513
514
|
});
|
|
515
|
+
const cmd = [CLAUDE_BIN, "-p", prompt, "--output-format=stream-json", "--verbose", "--dangerously-skip-permissions"];
|
|
516
|
+
if (resumeSessionId) {
|
|
517
|
+
cmd.push("--resume", resumeSessionId);
|
|
518
|
+
}
|
|
514
519
|
const proc = spawn({
|
|
515
|
-
cmd
|
|
520
|
+
cmd,
|
|
516
521
|
stdin: "ignore",
|
|
517
522
|
stdout: "pipe",
|
|
518
523
|
stderr: "pipe",
|
|
@@ -566,6 +571,9 @@ async function* parseClaudeStream(proc) {
|
|
|
566
571
|
} catch {
|
|
567
572
|
continue;
|
|
568
573
|
}
|
|
574
|
+
if (parsed.type === "system" && parsed.subtype === "init" && parsed.session_id) {
|
|
575
|
+
yield { type: "session_id", content: "", sessionId: parsed.session_id };
|
|
576
|
+
}
|
|
569
577
|
if (parsed.type === "assistant" && parsed.message) {
|
|
570
578
|
const message = parsed.message;
|
|
571
579
|
for (const block of message.content || []) {
|
|
@@ -1519,6 +1527,9 @@ class StashService {
|
|
|
1519
1527
|
broadcast;
|
|
1520
1528
|
previewPool;
|
|
1521
1529
|
selectedComponent = null;
|
|
1530
|
+
messageQueue = [];
|
|
1531
|
+
isProcessingMessage = false;
|
|
1532
|
+
chatSessions = new Map;
|
|
1522
1533
|
constructor(projectPath, worktreeManager, persistence, broadcast) {
|
|
1523
1534
|
this.projectPath = projectPath;
|
|
1524
1535
|
this.worktreeManager = worktreeManager;
|
|
@@ -1571,6 +1582,20 @@ class StashService {
|
|
|
1571
1582
|
}
|
|
1572
1583
|
}
|
|
1573
1584
|
async message(projectId, chatId, message, referenceStashIds, componentContext) {
|
|
1585
|
+
this.messageQueue.push({ projectId, chatId, message, referenceStashIds, componentContext });
|
|
1586
|
+
if (!this.isProcessingMessage) {
|
|
1587
|
+
await this.processMessageQueue();
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
async processMessageQueue() {
|
|
1591
|
+
this.isProcessingMessage = true;
|
|
1592
|
+
while (this.messageQueue.length > 0) {
|
|
1593
|
+
const msg = this.messageQueue.shift();
|
|
1594
|
+
await this.processMessage(msg.projectId, msg.chatId, msg.message, msg.referenceStashIds, msg.componentContext);
|
|
1595
|
+
}
|
|
1596
|
+
this.isProcessingMessage = false;
|
|
1597
|
+
}
|
|
1598
|
+
async processMessage(projectId, chatId, message, referenceStashIds, componentContext) {
|
|
1574
1599
|
const component = componentContext ? { name: componentContext.name, filePath: this.selectedComponent?.filePath || "" } : this.selectedComponent;
|
|
1575
1600
|
let sourceCode = "";
|
|
1576
1601
|
const filePath = component?.filePath || "";
|
|
@@ -1590,29 +1615,41 @@ ${refs.join(`
|
|
|
1590
1615
|
`)}`;
|
|
1591
1616
|
}
|
|
1592
1617
|
}
|
|
1593
|
-
const
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1618
|
+
const existingSessionId = this.chatSessions.get(chatId);
|
|
1619
|
+
let chatPrompt;
|
|
1620
|
+
if (existingSessionId) {
|
|
1621
|
+
const parts = [message];
|
|
1622
|
+
if (stashContext)
|
|
1623
|
+
parts.push(stashContext);
|
|
1624
|
+
if (component && !existingSessionId)
|
|
1625
|
+
parts.push(`Component: ${component.name}`);
|
|
1626
|
+
chatPrompt = parts.join(`
|
|
1627
|
+
`);
|
|
1628
|
+
} else {
|
|
1629
|
+
chatPrompt = [
|
|
1630
|
+
"You are helping the user explore UI design variations for their project.",
|
|
1631
|
+
"You have access to stashes MCP tools to generate, list, show, browse, vary, and apply stashes.",
|
|
1632
|
+
"If the user asks you to generate, create, or make variations, use the stashes_generate tool.",
|
|
1633
|
+
"If the user asks to vary an existing stash, use the stashes_vary tool.",
|
|
1634
|
+
"If the user asks about what a stash changed, its diff, or its contents, use stashes_show to inspect it.",
|
|
1635
|
+
'IMPORTANT: NEVER call stashes_apply unless the user explicitly asks to "apply" or "merge" a stash.',
|
|
1636
|
+
'IMPORTANT: NEVER call stashes_remove unless the user explicitly asks to "delete" or "remove" a stash.',
|
|
1637
|
+
"Otherwise, respond conversationally about their project and stashes.",
|
|
1638
|
+
"",
|
|
1639
|
+
component ? `Component: ${component.name}` : "",
|
|
1640
|
+
filePath !== "auto-detect" ? `File: ${filePath}` : "",
|
|
1641
|
+
sourceCode ? `
|
|
1606
1642
|
Source:
|
|
1607
1643
|
\`\`\`
|
|
1608
1644
|
${sourceCode.substring(0, 3000)}
|
|
1609
1645
|
\`\`\`` : "",
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1646
|
+
stashContext,
|
|
1647
|
+
"",
|
|
1648
|
+
`User: ${message}`
|
|
1649
|
+
].filter(Boolean).join(`
|
|
1614
1650
|
`);
|
|
1615
|
-
|
|
1651
|
+
}
|
|
1652
|
+
const aiProcess = startAiProcess("chat", chatPrompt, this.projectPath, existingSessionId);
|
|
1616
1653
|
let thinkingBuf = "";
|
|
1617
1654
|
let textBuf = "";
|
|
1618
1655
|
const pendingMessages = [];
|
|
@@ -1631,6 +1668,10 @@ ${sourceCode.substring(0, 3000)}
|
|
|
1631
1668
|
}
|
|
1632
1669
|
try {
|
|
1633
1670
|
for await (const chunk of parseClaudeStream(aiProcess.process)) {
|
|
1671
|
+
if (chunk.type === "session_id" && chunk.sessionId) {
|
|
1672
|
+
this.chatSessions.set(chatId, chunk.sessionId);
|
|
1673
|
+
continue;
|
|
1674
|
+
}
|
|
1634
1675
|
if (chunk.type === "text") {
|
|
1635
1676
|
flushThinking();
|
|
1636
1677
|
textBuf += chunk.content;
|