@co0ontty/wand 4.59.1 → 4.60.0-beta.gc0ff8cc
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/build-info.json +4 -4
- package/dist/server-session-routes.d.ts +1 -18
- package/dist/server-session-routes.js +71 -228
- package/dist/server-task-routes.js +15 -5
- package/dist/server.js +1 -1
- package/dist/web-ui/content/scripts.js +40 -40
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.js +2 -2
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"commit": "
|
|
3
|
-
"builtAt": "2026-09-
|
|
4
|
-
"version": "4.
|
|
5
|
-
"channel": "
|
|
2
|
+
"commit": "c0ff8ccee9e2b9591db65e5f14d45626e7a07fa9",
|
|
3
|
+
"builtAt": "2026-09-12T12:30:38.170Z",
|
|
4
|
+
"version": "4.60.0-beta.gc0ff8cc",
|
|
5
|
+
"channel": "beta"
|
|
6
6
|
}
|
|
@@ -22,16 +22,6 @@ type SessionDeletionStructured = Pick<StructuredSessionManager, "get" | "delete"
|
|
|
22
22
|
* immediately reappear as a "non-Wand" session after the Wand row is removed.
|
|
23
23
|
*/
|
|
24
24
|
export declare function deleteSessionWithProviderHistory(processes: SessionDeletionProcesses, structured: SessionDeletionStructured, storage: Pick<WandStorage, "getConfigValue" | "setConfigValue">, id: string): void;
|
|
25
|
-
type ProviderHistorySession = {
|
|
26
|
-
claudeSessionId: string;
|
|
27
|
-
cwd: string;
|
|
28
|
-
firstUserMessage: string;
|
|
29
|
-
timestamp: string;
|
|
30
|
-
mtimeMs: number;
|
|
31
|
-
hasConversation: boolean;
|
|
32
|
-
managedByWand: boolean;
|
|
33
|
-
provider?: "claude" | "codex" | "opencode" | "qoder";
|
|
34
|
-
};
|
|
35
25
|
type SessionListPageEntry = {
|
|
36
26
|
type: "managed";
|
|
37
27
|
key: string;
|
|
@@ -55,13 +45,6 @@ export interface SessionDirectoryTreeResponse {
|
|
|
55
45
|
}
|
|
56
46
|
export declare function buildSessionListPage(sessions: SessionSnapshot[], offset: number, limit: number): SessionListPage;
|
|
57
47
|
export declare function buildSessionDirectoryTree(sessions: SessionSnapshot[], customNames?: ReadonlyMap<string, string>): SessionDirectoryTreeResponse;
|
|
58
|
-
/**
|
|
59
|
-
* Provider history is scanned by ProcessManager, but structured sessions live
|
|
60
|
-
* in StructuredSessionManager. Annotate against the combined session list so a
|
|
61
|
-
* structured conversation is not also exposed as a recoverable native history
|
|
62
|
-
* entry. Return copies for matches because ProcessManager caches scan results.
|
|
63
|
-
*/
|
|
64
|
-
export declare function markManagedProviderHistory<T extends ProviderHistorySession>(history: T[], sessions: SessionSnapshot[], provider: "claude" | "codex" | "opencode" | "qoder"): T[];
|
|
65
48
|
export declare function registerSessionRoutes(app: Express, processes: ProcessManager, structured: StructuredSessionManager, storage: WandStorage, defaultMode: ExecutionMode, config: WandConfig, sessions: SessionRegistry, onSessionCreated?: (cwd: string | undefined | null) => void): void;
|
|
66
|
-
export declare function registerClaudeHistoryRoutes(app: Express, processes: ProcessManager,
|
|
49
|
+
export declare function registerClaudeHistoryRoutes(app: Express, processes: ProcessManager, storage: WandStorage): void;
|
|
67
50
|
export {};
|
|
@@ -265,33 +265,6 @@ function directoryTreeContainsPath(nodes, directoryPath) {
|
|
|
265
265
|
return nodes.some((node) => ((!node.synthetic && node.path === directoryPath)
|
|
266
266
|
|| directoryTreeContainsPath(node.children, directoryPath)));
|
|
267
267
|
}
|
|
268
|
-
/**
|
|
269
|
-
* Provider history is scanned by ProcessManager, but structured sessions live
|
|
270
|
-
* in StructuredSessionManager. Annotate against the combined session list so a
|
|
271
|
-
* structured conversation is not also exposed as a recoverable native history
|
|
272
|
-
* entry. Return copies for matches because ProcessManager caches scan results.
|
|
273
|
-
*/
|
|
274
|
-
export function markManagedProviderHistory(history, sessions, provider) {
|
|
275
|
-
const managedIds = new Set();
|
|
276
|
-
for (const session of sessions) {
|
|
277
|
-
const sessionProvider = session.provider
|
|
278
|
-
?? session.structuredState?.provider
|
|
279
|
-
?? (/^codex\b/i.test(session.command.trim())
|
|
280
|
-
? "codex"
|
|
281
|
-
: /^opencode\b/i.test(session.command.trim())
|
|
282
|
-
? "opencode"
|
|
283
|
-
: /^qodercli\b/i.test(session.command.trim())
|
|
284
|
-
? "qoder"
|
|
285
|
-
: "claude");
|
|
286
|
-
const providerSessionId = session.claudeSessionId?.trim();
|
|
287
|
-
if (sessionProvider === provider && providerSessionId) {
|
|
288
|
-
managedIds.add(providerSessionId);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
return history.map((entry) => (entry.managedByWand || !managedIds.has(entry.claudeSessionId)
|
|
292
|
-
? entry
|
|
293
|
-
: { ...entry, managedByWand: true }));
|
|
294
|
-
}
|
|
295
268
|
function requireWorktreeSession(snapshot) {
|
|
296
269
|
if (!snapshot) {
|
|
297
270
|
throw new Error("未找到该会话。");
|
|
@@ -1484,230 +1457,100 @@ export function registerSessionRoutes(app, processes, structured, storage, defau
|
|
|
1484
1457
|
}
|
|
1485
1458
|
});
|
|
1486
1459
|
}
|
|
1487
|
-
export function registerClaudeHistoryRoutes(app, processes,
|
|
1488
|
-
//
|
|
1489
|
-
//
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
}
|
|
1512
|
-
res.json({ ok: true });
|
|
1513
|
-
});
|
|
1514
|
-
app.delete("/api/claude-history", (req, res) => {
|
|
1515
|
-
const cwd = typeof req.query.cwd === "string" ? req.query.cwd.trim() : "";
|
|
1516
|
-
if (!cwd) {
|
|
1517
|
-
res.status(400).json({ error: "目录不能为空。" });
|
|
1518
|
-
return;
|
|
1519
|
-
}
|
|
1520
|
-
try {
|
|
1521
|
-
const sessions = processes.listClaudeHistorySessions();
|
|
1522
|
-
const toDelete = [];
|
|
1523
|
-
for (const session of sessions) {
|
|
1524
|
-
if (session.claudeSessionId && session.cwd === cwd) {
|
|
1525
|
-
toDelete.push({ claudeSessionId: session.claudeSessionId, cwd: session.cwd });
|
|
1526
|
-
}
|
|
1527
|
-
}
|
|
1528
|
-
const deleted = processes.deleteClaudeHistoryFiles(toDelete);
|
|
1529
|
-
removeFromHiddenClaudeSessionIds(storage, toDelete.map((s) => s.claudeSessionId));
|
|
1530
|
-
res.json({ ok: true, deleted });
|
|
1531
|
-
}
|
|
1532
|
-
catch (error) {
|
|
1533
|
-
res.status(500).json({ error: getErrorMessage(error, "无法删除该目录下的历史会话。") });
|
|
1534
|
-
}
|
|
1535
|
-
});
|
|
1536
|
-
app.post("/api/claude-history/batch-delete", (req, res) => {
|
|
1537
|
-
const claudeSessionIds = Array.isArray(req.body?.claudeSessionIds)
|
|
1538
|
-
? req.body.claudeSessionIds.filter((value) => typeof value === "string" && value.trim().length > 0)
|
|
1539
|
-
: [];
|
|
1540
|
-
if (claudeSessionIds.length === 0) {
|
|
1541
|
-
res.status(400).json({ error: "至少提供一个历史会话 ID。" });
|
|
1542
|
-
return;
|
|
1543
|
-
}
|
|
1544
|
-
try {
|
|
1545
|
-
const allSessions = processes.listClaudeHistorySessions();
|
|
1546
|
-
const sessionMap = new Map();
|
|
1547
|
-
for (const s of allSessions) {
|
|
1548
|
-
if (s.claudeSessionId)
|
|
1549
|
-
sessionMap.set(s.claudeSessionId, s.cwd);
|
|
1550
|
-
}
|
|
1551
|
-
const toDelete = [];
|
|
1552
|
-
const toHide = [];
|
|
1553
|
-
for (const id of claudeSessionIds) {
|
|
1554
|
-
const cwd = sessionMap.get(id);
|
|
1555
|
-
if (cwd) {
|
|
1556
|
-
toDelete.push({ claudeSessionId: id, cwd });
|
|
1557
|
-
}
|
|
1558
|
-
else {
|
|
1559
|
-
toHide.push(id);
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
const deleted = processes.deleteClaudeHistoryFiles(toDelete);
|
|
1563
|
-
removeFromHiddenClaudeSessionIds(storage, toDelete.map((s) => s.claudeSessionId));
|
|
1564
|
-
if (toHide.length > 0) {
|
|
1565
|
-
const hidden = getHiddenClaudeSessionIds(storage);
|
|
1566
|
-
let added = 0;
|
|
1567
|
-
for (const id of toHide) {
|
|
1568
|
-
if (!hidden.has(id)) {
|
|
1569
|
-
hidden.add(id);
|
|
1570
|
-
added++;
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
if (added > 0)
|
|
1574
|
-
saveHiddenClaudeSessionIds(storage, hidden);
|
|
1575
|
-
}
|
|
1576
|
-
res.json({ ok: true, deleted: deleted + toHide.length });
|
|
1577
|
-
}
|
|
1578
|
-
catch (error) {
|
|
1579
|
-
res.status(500).json({ error: getErrorMessage(error, "无法批量删除历史会话。") });
|
|
1580
|
-
}
|
|
1581
|
-
});
|
|
1582
|
-
// ── Codex history(~/.codex/sessions/ 扫描,对齐 Claude 历史区) ──
|
|
1583
|
-
// codex 历史的"恢复"是新建一个结构化 codex 会话并预填 thread id(存进 claudeSessionId
|
|
1584
|
-
// 字段),用户发第一条消息时 buildCodexArgs 自动拼 `codex exec ... resume <thread_id>`。
|
|
1585
|
-
// hidden 集合与 claude 共用(id 全局唯一,不会冲突)。
|
|
1586
|
-
app.get("/api/codex-history", (_req, res) => {
|
|
1587
|
-
res.json([]);
|
|
1588
|
-
});
|
|
1589
|
-
app.delete("/api/codex-history/:threadId", (req, res) => {
|
|
1590
|
-
const threadId = req.params.threadId?.trim();
|
|
1591
|
-
if (!threadId) {
|
|
1592
|
-
res.status(400).json({ error: "会话 ID 不能为空。" });
|
|
1593
|
-
return;
|
|
1594
|
-
}
|
|
1595
|
-
const exists = processes.listCodexHistorySessions().some((s) => s.claudeSessionId === threadId);
|
|
1596
|
-
if (exists) {
|
|
1597
|
-
processes.deleteCodexHistoryFiles([threadId]);
|
|
1598
|
-
removeFromHiddenClaudeSessionIds(storage, [threadId]);
|
|
1599
|
-
}
|
|
1600
|
-
else {
|
|
1601
|
-
const hidden = getHiddenClaudeSessionIds(storage);
|
|
1602
|
-
if (!hidden.has(threadId)) {
|
|
1603
|
-
hidden.add(threadId);
|
|
1604
|
-
saveHiddenClaudeSessionIds(storage, hidden);
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
res.json({ ok: true });
|
|
1608
|
-
});
|
|
1609
|
-
app.post("/api/codex-history/batch-delete", (req, res) => {
|
|
1610
|
-
const threadIds = Array.isArray(req.body?.claudeSessionIds)
|
|
1611
|
-
? req.body.claudeSessionIds.filter((value) => typeof value === "string" && value.trim().length > 0)
|
|
1612
|
-
: [];
|
|
1613
|
-
if (threadIds.length === 0) {
|
|
1614
|
-
res.status(400).json({ error: "至少提供一个历史会话 ID。" });
|
|
1615
|
-
return;
|
|
1616
|
-
}
|
|
1617
|
-
try {
|
|
1618
|
-
const existing = new Set(processes.listCodexHistorySessions().map((s) => s.claudeSessionId));
|
|
1619
|
-
const toDelete = [];
|
|
1620
|
-
const toHide = [];
|
|
1621
|
-
for (const id of threadIds) {
|
|
1622
|
-
if (existing.has(id))
|
|
1623
|
-
toDelete.push(id);
|
|
1624
|
-
else
|
|
1625
|
-
toHide.push(id);
|
|
1626
|
-
}
|
|
1627
|
-
const deleted = processes.deleteCodexHistoryFiles(toDelete);
|
|
1628
|
-
removeFromHiddenClaudeSessionIds(storage, toDelete);
|
|
1629
|
-
if (toHide.length > 0) {
|
|
1630
|
-
const hidden = getHiddenClaudeSessionIds(storage);
|
|
1631
|
-
let added = 0;
|
|
1632
|
-
for (const id of toHide) {
|
|
1633
|
-
if (!hidden.has(id)) {
|
|
1634
|
-
hidden.add(id);
|
|
1635
|
-
added++;
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
if (added > 0)
|
|
1639
|
-
saveHiddenClaudeSessionIds(storage, hidden);
|
|
1640
|
-
}
|
|
1641
|
-
res.json({ ok: true, deleted: deleted + toHide.length });
|
|
1642
|
-
}
|
|
1643
|
-
catch (error) {
|
|
1644
|
-
res.status(500).json({ error: getErrorMessage(error, "无法批量删除历史会话。") });
|
|
1645
|
-
}
|
|
1646
|
-
});
|
|
1647
|
-
const externalHistoryProviders = [
|
|
1648
|
-
{
|
|
1649
|
-
provider: "opencode",
|
|
1650
|
-
label: "OpenCode",
|
|
1460
|
+
export function registerClaudeHistoryRoutes(app, processes, storage) {
|
|
1461
|
+
// Older clients still GET these endpoints. Wand no longer imports provider-native
|
|
1462
|
+
// history into its session list, so the supported list response stays empty.
|
|
1463
|
+
for (const provider of ["claude", "codex", "opencode", "qoder", "grok", "pi"]) {
|
|
1464
|
+
app.get(`/api/${provider}-history`, (_req, res) => {
|
|
1465
|
+
res.json([]);
|
|
1466
|
+
});
|
|
1467
|
+
}
|
|
1468
|
+
const historyFiles = {
|
|
1469
|
+
claude: {
|
|
1470
|
+
list: () => processes.listClaudeHistorySessions(),
|
|
1471
|
+
remove: (ids) => {
|
|
1472
|
+
const cwdById = new Map(processes.listClaudeHistorySessions().map((session) => [session.claudeSessionId, session.cwd]));
|
|
1473
|
+
return processes.deleteClaudeHistoryFiles(ids.flatMap((id) => {
|
|
1474
|
+
const cwd = cwdById.get(id);
|
|
1475
|
+
return cwd ? [{ claudeSessionId: id, cwd }] : [];
|
|
1476
|
+
}));
|
|
1477
|
+
},
|
|
1478
|
+
},
|
|
1479
|
+
codex: {
|
|
1480
|
+
list: () => processes.listCodexHistorySessions(),
|
|
1481
|
+
remove: (ids) => processes.deleteCodexHistoryFiles(ids),
|
|
1482
|
+
},
|
|
1483
|
+
opencode: {
|
|
1651
1484
|
list: () => processes.listOpenCodeHistorySessions(),
|
|
1652
1485
|
remove: (ids) => processes.deleteOpenCodeHistorySessions(ids),
|
|
1653
1486
|
},
|
|
1654
|
-
{
|
|
1655
|
-
provider: "qoder",
|
|
1656
|
-
label: "Qoder",
|
|
1487
|
+
qoder: {
|
|
1657
1488
|
list: () => processes.listQoderHistorySessions(),
|
|
1658
1489
|
remove: (ids) => processes.deleteQoderHistoryFiles(ids),
|
|
1659
1490
|
},
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1491
|
+
};
|
|
1492
|
+
const deleteHistory = (provider, ids) => {
|
|
1493
|
+
const existing = new Set(historyFiles[provider].list()
|
|
1494
|
+
.map((session) => session.claudeSessionId)
|
|
1495
|
+
.filter((id) => Boolean(id)));
|
|
1496
|
+
const toDelete = ids.filter((id) => existing.has(id));
|
|
1497
|
+
const toHide = ids.filter((id) => !existing.has(id));
|
|
1498
|
+
const deleted = historyFiles[provider].remove(toDelete);
|
|
1499
|
+
removeFromHiddenClaudeSessionIds(storage, toDelete);
|
|
1500
|
+
addToHiddenClaudeSessionIds(storage, toHide);
|
|
1501
|
+
return deleted + toHide.length;
|
|
1502
|
+
};
|
|
1503
|
+
const registerHistoryMutations = (provider, param, label) => {
|
|
1504
|
+
app.delete(`/api/${provider}-history/:${param}`, (req, res) => {
|
|
1505
|
+
const id = req.params[param]?.trim();
|
|
1506
|
+
if (!id) {
|
|
1673
1507
|
res.status(400).json({ error: "会话 ID 不能为空。" });
|
|
1674
1508
|
return;
|
|
1675
1509
|
}
|
|
1676
1510
|
try {
|
|
1677
|
-
|
|
1678
|
-
if (exists) {
|
|
1679
|
-
config.remove([sessionId]);
|
|
1680
|
-
removeFromHiddenClaudeSessionIds(storage, [sessionId]);
|
|
1681
|
-
}
|
|
1682
|
-
else {
|
|
1683
|
-
addToHiddenClaudeSessionIds(storage, [sessionId]);
|
|
1684
|
-
}
|
|
1511
|
+
deleteHistory(provider, [id]);
|
|
1685
1512
|
res.json({ ok: true });
|
|
1686
1513
|
}
|
|
1687
1514
|
catch (error) {
|
|
1688
|
-
res.status(500).json({ error: getErrorMessage(error, `无法删除 ${
|
|
1515
|
+
res.status(500).json({ error: getErrorMessage(error, `无法删除 ${label} 历史会话。`) });
|
|
1689
1516
|
}
|
|
1690
1517
|
});
|
|
1691
|
-
app.post(`/api/${
|
|
1692
|
-
const
|
|
1518
|
+
app.post(`/api/${provider}-history/batch-delete`, (req, res) => {
|
|
1519
|
+
const ids = Array.isArray(req.body?.claudeSessionIds)
|
|
1693
1520
|
? req.body.claudeSessionIds.filter((value) => typeof value === "string" && value.trim().length > 0)
|
|
1694
1521
|
: [];
|
|
1695
|
-
if (
|
|
1522
|
+
if (ids.length === 0) {
|
|
1696
1523
|
res.status(400).json({ error: "至少提供一个历史会话 ID。" });
|
|
1697
1524
|
return;
|
|
1698
1525
|
}
|
|
1699
1526
|
try {
|
|
1700
|
-
|
|
1701
|
-
const toDelete = sessionIds.filter((id) => existing.has(id));
|
|
1702
|
-
const toHide = sessionIds.filter((id) => !existing.has(id));
|
|
1703
|
-
const deleted = config.remove(toDelete);
|
|
1704
|
-
removeFromHiddenClaudeSessionIds(storage, toDelete);
|
|
1705
|
-
addToHiddenClaudeSessionIds(storage, toHide);
|
|
1706
|
-
res.json({ ok: true, deleted: deleted + toHide.length });
|
|
1527
|
+
res.json({ ok: true, deleted: deleteHistory(provider, ids) });
|
|
1707
1528
|
}
|
|
1708
1529
|
catch (error) {
|
|
1709
|
-
res.status(500).json({ error: getErrorMessage(error, `无法批量删除 ${
|
|
1530
|
+
res.status(500).json({ error: getErrorMessage(error, `无法批量删除 ${label} 历史会话。`) });
|
|
1710
1531
|
}
|
|
1711
1532
|
});
|
|
1712
|
-
}
|
|
1533
|
+
};
|
|
1534
|
+
registerHistoryMutations("claude", "claudeSessionId", "Claude");
|
|
1535
|
+
app.delete("/api/claude-history", (req, res) => {
|
|
1536
|
+
const cwd = typeof req.query.cwd === "string" ? req.query.cwd.trim() : "";
|
|
1537
|
+
if (!cwd) {
|
|
1538
|
+
res.status(400).json({ error: "目录不能为空。" });
|
|
1539
|
+
return;
|
|
1540
|
+
}
|
|
1541
|
+
try {
|
|
1542
|
+
const toDelete = processes.listClaudeHistorySessions()
|
|
1543
|
+
.filter((session) => session.claudeSessionId && session.cwd === cwd)
|
|
1544
|
+
.map((session) => ({ claudeSessionId: session.claudeSessionId, cwd: session.cwd }));
|
|
1545
|
+
const deleted = processes.deleteClaudeHistoryFiles(toDelete);
|
|
1546
|
+
removeFromHiddenClaudeSessionIds(storage, toDelete.map((session) => session.claudeSessionId));
|
|
1547
|
+
res.json({ ok: true, deleted });
|
|
1548
|
+
}
|
|
1549
|
+
catch (error) {
|
|
1550
|
+
res.status(500).json({ error: getErrorMessage(error, "无法删除该目录下的历史会话。") });
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
registerHistoryMutations("codex", "threadId", "Codex");
|
|
1554
|
+
registerHistoryMutations("opencode", "sessionId", "OpenCode");
|
|
1555
|
+
registerHistoryMutations("qoder", "sessionId", "Qoder");
|
|
1713
1556
|
}
|
|
@@ -308,12 +308,12 @@ export function registerTaskRoutes(app, deps, sessionsLegacy, requireAdminLegacy
|
|
|
308
308
|
res.json({ ok: true });
|
|
309
309
|
});
|
|
310
310
|
/**
|
|
311
|
-
*
|
|
312
|
-
*
|
|
311
|
+
* 用选定的 CLI 工具开一个结构化会话,把这次派发的 prompt 作为首条消息,
|
|
312
|
+
* 并把会话绑定回该任务。cwd 取任务所属项目目录;未指定项目时用全局默认目录。
|
|
313
313
|
*/
|
|
314
314
|
app.post("/api/wand-tasks/:id/dispatch", guard, asyncRoute(async (req, res) => {
|
|
315
315
|
try {
|
|
316
|
-
|
|
316
|
+
let task = storage.getWandTask(req.params.id);
|
|
317
317
|
if (!task) {
|
|
318
318
|
res.status(404).json({ error: "未找到该任务。" });
|
|
319
319
|
return;
|
|
@@ -327,10 +327,21 @@ export function registerTaskRoutes(app, deps, sessionsLegacy, requireAdminLegacy
|
|
|
327
327
|
if (!agent)
|
|
328
328
|
throw new Error("请先为该任务选择 CLI 工具。");
|
|
329
329
|
writeTaskBoardLastAgent(storage, agent);
|
|
330
|
+
if (body.workspaceId !== undefined) {
|
|
331
|
+
const workspaceId = body.workspaceId === null ? null : text(body.workspaceId) || null;
|
|
332
|
+
if (workspaceId && !storage.getWorkspace(workspaceId))
|
|
333
|
+
throw new Error("项目不存在。");
|
|
334
|
+
task = storage.updateWandTask(task.id, { workspaceId }) ?? task;
|
|
335
|
+
}
|
|
330
336
|
const workspace = task.workspaceId ? storage.getWorkspace(task.workspaceId) : null;
|
|
331
337
|
if (task.workspaceId && !workspace)
|
|
332
338
|
throw new Error("任务所属项目已被删除,请重新指定。");
|
|
333
339
|
const cwd = workspace?.cwd || config.defaultCwd;
|
|
340
|
+
const requestedPrompt = text(body.prompt);
|
|
341
|
+
const existingSessions = storage.listWandTaskSessionIds(task.id).length;
|
|
342
|
+
if (existingSessions > 0 && !requestedPrompt)
|
|
343
|
+
throw new Error("请输入提示词。");
|
|
344
|
+
const prompt = requestedPrompt || task.description.trim() || task.title || "执行此任务";
|
|
334
345
|
const model = agent.model === "default" ? "" : agent.model;
|
|
335
346
|
const session = structured.createSession({
|
|
336
347
|
cwd,
|
|
@@ -346,8 +357,7 @@ export function registerTaskRoutes(app, deps, sessionsLegacy, requireAdminLegacy
|
|
|
346
357
|
});
|
|
347
358
|
storage.updateWandTask(task.id, { agent, status: task.status === "todo" ? "doing" : task.status });
|
|
348
359
|
storage.bindWandTaskSession(task.id, session.id);
|
|
349
|
-
const
|
|
350
|
-
const completion = structured.sendMessage(session.id, prompt || task.title || "执行此任务");
|
|
360
|
+
const completion = structured.sendMessage(session.id, prompt);
|
|
351
361
|
completion.catch((error) => console.error(`[WandTask] Agent dispatch failed for ${task.id}:`, error));
|
|
352
362
|
res.status(202).json({
|
|
353
363
|
ok: true,
|
package/dist/server.js
CHANGED
|
@@ -1004,7 +1004,7 @@ export async function startServer(config, configPath, options = {}) {
|
|
|
1004
1004
|
registerSessionRoutes(app, processes, structuredSessions, storage, config.defaultMode, config, sessionRegistry, (cwd) => {
|
|
1005
1005
|
recordRecentPath(storage, cwd);
|
|
1006
1006
|
});
|
|
1007
|
-
registerClaudeHistoryRoutes(app, processes,
|
|
1007
|
+
registerClaudeHistoryRoutes(app, processes, storage);
|
|
1008
1008
|
registerWorkspaceRoutes(app, storage, sessionRegistry);
|
|
1009
1009
|
registerMissionRoutes(app, missions);
|
|
1010
1010
|
registerUploadRoutes(app, processes);
|