@co0ontty/wand 4.57.0 → 4.58.0
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 +3 -3
- package/dist/ensure-node-pty-helper.d.ts +0 -1
- package/dist/ensure-node-pty-helper.js +0 -5
- package/dist/git-quick-commit.js +18 -19
- package/dist/github-connector.d.ts +11 -5
- package/dist/github-connector.js +105 -33
- package/dist/missions.d.ts +1 -1
- package/dist/missions.js +17 -4
- package/dist/server-file-routes.js +43 -2
- package/dist/server-github-routes.js +50 -53
- package/dist/server-mission-routes.js +11 -10
- package/dist/server-task-routes.d.ts +14 -2
- package/dist/server-task-routes.js +248 -84
- package/dist/server-workspace-routes.js +90 -16
- package/dist/server.js +2 -20
- package/dist/storage.d.ts +23 -6
- package/dist/storage.js +130 -53
- package/dist/structured-exec-host.d.ts +13 -2
- package/dist/structured-exec-host.js +71 -36
- package/dist/structured-exec-pump.d.ts +1 -1
- package/dist/structured-exec-pump.js +14 -8
- package/dist/task-types.d.ts +15 -0
- package/dist/terminal-daemon-client.d.ts +2 -0
- package/dist/terminal-daemon-client.js +7 -1
- package/dist/terminal-daemon-server.js +17 -18
- package/dist/tui/ipc-server.js +3 -1
- package/dist/types.d.ts +1 -0
- package/dist/wand-task-sync.d.ts +9 -0
- package/dist/wand-task-sync.js +50 -0
- package/dist/web-ui/content/scripts.js +85 -85
- package/dist/web-ui/content/styles.css +1 -1
- package/dist/web-ui/embedded-assets.js +2 -2
- package/dist/ws-broadcast.js +5 -1
- package/package.json +2 -3
- package/dist/taskboard-bridge.d.ts +0 -11
- package/dist/taskboard-bridge.js +0 -371
- package/vendor/codex-taskboard/LICENSE +0 -201
- package/vendor/codex-taskboard/dist/web/assets/AiChat-BNn4VJ5a.js +0 -12
- package/vendor/codex-taskboard/dist/web/assets/GanttView-D8wnfGrG.css +0 -1
- package/vendor/codex-taskboard/dist/web/assets/GanttView-rGWhuEX9.js +0 -39
- package/vendor/codex-taskboard/dist/web/assets/abnfDiagram-N423BO3Z-DbFG6lbA.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/arc-BjSQqbzd.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/architecture-TIHT7OUA-C9-t8p4o.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/architectureDiagram-T3A2C74G-Db4kJZwO.js +0 -36
- package/vendor/codex-taskboard/dist/web/assets/array-BifhSqXX.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/blockDiagram-VBNYF7ZC-C-BywuWV.js +0 -132
- package/vendor/codex-taskboard/dist/web/assets/c4Diagram-5PPSVZJV-Dq-80rjP.js +0 -10
- package/vendor/codex-taskboard/dist/web/assets/channel-C7mnz8Xc.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-2GRJ4B5K-B2G57us9.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-2Q5K7J3B-C1jixKkw.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-3NCLNEKW-DVGIRib_.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-4I5QYGJK-kNoGFqr0.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-5RXB4S5H-4iv6-xM6.js +0 -231
- package/vendor/codex-taskboard/dist/web/assets/chunk-5VM5RSS4-ZNzvKenW.js +0 -15
- package/vendor/codex-taskboard/dist/web/assets/chunk-6Q2QTUOP-1J34vxHr.js +0 -88
- package/vendor/codex-taskboard/dist/web/assets/chunk-7BUUIJ7U-Bb538aSH.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-7Z6QIM7H-CDQpQlxX.js +0 -10
- package/vendor/codex-taskboard/dist/web/assets/chunk-GF5L2VYU-Dg92oHHl.js +0 -206
- package/vendor/codex-taskboard/dist/web/assets/chunk-I66GZJ75-Bk8_gFs2.js +0 -125
- package/vendor/codex-taskboard/dist/web/assets/chunk-J7OUQ5F2-CJRcenlr.js +0 -2
- package/vendor/codex-taskboard/dist/web/assets/chunk-JQJVKLGR-BLBV_Sus.js +0 -156
- package/vendor/codex-taskboard/dist/web/assets/chunk-JWPE2WC7-DVXcaiue.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-KBJHAD2P-Da9Yjz0p.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-KEIR6QF5-Dj-OpFgW.js +0 -161
- package/vendor/codex-taskboard/dist/web/assets/chunk-NSK5VX7P-Cb56tnGK.js +0 -2
- package/vendor/codex-taskboard/dist/web/assets/chunk-QR6OTTB3-BwoszTxn.js +0 -62
- package/vendor/codex-taskboard/dist/web/assets/chunk-RYQCIY6F-D_L2RdcQ.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-UBXNYLIW-YX5mN8cl.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-W5SLKNZC-DlOLhhDO.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-WRU74C26-B7SBmP0K.js +0 -70
- package/vendor/codex-taskboard/dist/web/assets/chunk-XXDRQBXY-BuE3VzE_.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/chunk-ZIRB5QZD-C6fEPe3t.js +0 -32
- package/vendor/codex-taskboard/dist/web/assets/classDiagram-JCYQIIEL-KIdCVvbA.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/classDiagram-v2-OCEON4UE-KIdCVvbA.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/cose-bilkent-JH36ORCC-BzQvy5TC.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/cynefin-VYW2F7L2-D1_5O1XR.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/cynefinDiagram-MW4NZA55-DOW_U5QN.js +0 -62
- package/vendor/codex-taskboard/dist/web/assets/cytoscape.esm-DnGd5Fuo.js +0 -321
- package/vendor/codex-taskboard/dist/web/assets/dagre-VZM6K2ZE-0Dntc3NT.js +0 -4
- package/vendor/codex-taskboard/dist/web/assets/dagre-dpRSp0QF.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/defaultLocale-C8Fc0cco.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/diagram-7IWD3JNH-D7GleYAM.js +0 -30
- package/vendor/codex-taskboard/dist/web/assets/diagram-B4RE2ZJO-DCXTe6q5.js +0 -3
- package/vendor/codex-taskboard/dist/web/assets/diagram-LBJQPF4R-ZFJyXEXl.js +0 -24
- package/vendor/codex-taskboard/dist/web/assets/diagram-Q27KOJAE-DUGCuGd9.js +0 -24
- package/vendor/codex-taskboard/dist/web/assets/diagram-UB23O5K3-DRmp4Nng.js +0 -41
- package/vendor/codex-taskboard/dist/web/assets/dist-D9sYb5Oa.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/ebnfDiagram-BXEA7PRR-CkKoaf7T.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/erDiagram-JOGREHBK-nBX5z4R4.js +0 -85
- package/vendor/codex-taskboard/dist/web/assets/eventmodeling-45OFAUF4-pexmK65N.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/flowDiagram-UKHOOZJN-aroohRbL.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/ganttDiagram-PKOTCBZU-BOJWUTXa.js +0 -292
- package/vendor/codex-taskboard/dist/web/assets/gitGraph-TEB2WS4Q-DxnuhSZU.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/gitGraphDiagram-DS77QQ5N-Cte975TC.js +0 -106
- package/vendor/codex-taskboard/dist/web/assets/graphlib-DS17s2tU.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/index-Docmx4uQ.css +0 -1
- package/vendor/codex-taskboard/dist/web/assets/index-Du07lEGz.js +0 -121
- package/vendor/codex-taskboard/dist/web/assets/info-DKCQHKI2-DOTjgYxk.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/infoDiagram-6WML65LV-SpyV9UJd.js +0 -2
- package/vendor/codex-taskboard/dist/web/assets/init-D6jRqBbL.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/ishikawaDiagram-WSZJBQD7-T0PZwoUZ.js +0 -70
- package/vendor/codex-taskboard/dist/web/assets/journeyDiagram-NVQOT4AX-B88b8UgX.js +0 -139
- package/vendor/codex-taskboard/dist/web/assets/kanban-definition-27J2QSJJ-CIlfNnl_.js +0 -89
- package/vendor/codex-taskboard/dist/web/assets/katex-B7rAX3Vi.js +0 -257
- package/vendor/codex-taskboard/dist/web/assets/line-fWrwPZhB.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/linear-B7l8qgEw.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/map-BaFkSB1l.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/mermaid-parser.core-C5gls2nC.js +0 -7
- package/vendor/codex-taskboard/dist/web/assets/mermaid.core-POz2Xcvr.js +0 -11
- package/vendor/codex-taskboard/dist/web/assets/mindmap-definition-FAOFIHXS-BM0-egZ5.js +0 -96
- package/vendor/codex-taskboard/dist/web/assets/ordinal-hYBb2elL.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/packet-7NZHBO7P-DQZzyVos.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/path-BWPyau1x.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/pegDiagram-VL7TDLO6-B8aEwl-7.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/pie-RZYD4A2V-DRUflilR.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/pieDiagram-7S7Q4E2Y-0cDDxlua.js +0 -39
- package/vendor/codex-taskboard/dist/web/assets/purify.es-Bwt4ulIK.js +0 -3
- package/vendor/codex-taskboard/dist/web/assets/quadrantDiagram-CIZ2JOQS-CBgb0YZ0.js +0 -7
- package/vendor/codex-taskboard/dist/web/assets/radar-I7S5WNFK-tRocoKxq.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/railroad-3IZDKUUU-DaS4ZlX_.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/railroad-abnf-AHOZXSZD-BN1T5dBT.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/railroad-ebnf-EBAXGLYW-Cuf8qyKs.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/railroad-peg-LSFZ7HO6-B511_EYq.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/railroadDiagram-AXF67PYL-QtPo-JZb.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/requirementDiagram-LRYGKXZP-CuBIF85r.js +0 -84
- package/vendor/codex-taskboard/dist/web/assets/rolldown-runtime-QTnfLwEv.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/rough.esm-CSKSodPl.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/sankeyDiagram-W5VNT64P-CRA-b_za.js +0 -40
- package/vendor/codex-taskboard/dist/web/assets/sequenceDiagram-SI44F4Z6-CoddVWwY.js +0 -162
- package/vendor/codex-taskboard/dist/web/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/src-_wZywoZs.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/stateDiagram-OKZ733FA-D8DMM2ln.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/stateDiagram-v2-UEYNNEHI-CVp0eYAS.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/swimlanes-SLNWSIFB-C1fC7EFu.js +0 -2
- package/vendor/codex-taskboard/dist/web/assets/swimlanesDiagram-ULZ7WXOC-CPd58Xso.js +0 -8
- package/vendor/codex-taskboard/dist/web/assets/timeline-definition-Z64GVDOM-BUBv8aKP.js +0 -120
- package/vendor/codex-taskboard/dist/web/assets/treeView-QDETBFTQ-C-Bve2kY.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/treemap-6X3UGDF4-BcphHDdV.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/vennDiagram-T6HMQDX7-0wQnwAyA.js +0 -34
- package/vendor/codex-taskboard/dist/web/assets/wardley-OPB4EBWU-CJZ4BevB.js +0 -1
- package/vendor/codex-taskboard/dist/web/assets/wardleyDiagram-T6FBY63Y-U9nwPrkN.js +0 -78
- package/vendor/codex-taskboard/dist/web/assets/xychartDiagram-ELKLHX3M-CyCqnzgE.js +0 -7
- package/vendor/codex-taskboard/dist/web/codex-agent-logo.png +0 -0
- package/vendor/codex-taskboard/dist/web/codex-app-icon.png +0 -0
- package/vendor/codex-taskboard/dist/web/favicon.svg +0 -7
- package/vendor/codex-taskboard/dist/web/index.html +0 -20
- package/vendor/codex-taskboard/server/ai-chat-catalog.mjs +0 -1031
- package/vendor/codex-taskboard/server/ai-chat-process.mjs +0 -462
- package/vendor/codex-taskboard/server/ai-chat.mjs +0 -1237
- package/vendor/codex-taskboard/server/ai-turn-owner.mjs +0 -39
- package/vendor/codex-taskboard/server/app.mjs +0 -3211
- package/vendor/codex-taskboard/server/cloud-config.mjs +0 -188
- package/vendor/codex-taskboard/server/cloud-proxy.mjs +0 -310
- package/vendor/codex-taskboard/server/codex-app-server.mjs +0 -376
- package/vendor/codex-taskboard/server/codex-slash-commands-0.139.0.json +0 -62
- package/vendor/codex-taskboard/server/database.mjs +0 -2845
- package/vendor/codex-taskboard/server/index.mjs +0 -41
- package/vendor/codex-taskboard/server/jira-config.mjs +0 -181
- package/vendor/codex-taskboard/server/jira-integration.mjs +0 -487
- package/vendor/codex-taskboard/server/project-summary.mjs +0 -159
- package/vendor/codex-taskboard/shared/api-fields.mjs +0 -163
- package/vendor/codex-taskboard/shared/codex-environment.mjs +0 -5
- package/vendor/codex-taskboard/shared/codex-executable.mjs +0 -77
- package/vendor/codex-taskboard/shared/codex-permissions.mjs +0 -9
- package/vendor/codex-taskboard/shared/composer-reference.d.mts +0 -19
- package/vendor/codex-taskboard/shared/composer-reference.mjs +0 -90
- package/vendor/codex-taskboard/shared/domain.mjs +0 -34
- package/vendor/codex-taskboard/shared/executable-command.mjs +0 -13
- package/vendor/codex-taskboard/shared/process-tree.mjs +0 -27
- package/vendor/codex-taskboard/shared/task-input.mjs +0 -308
- package/vendor/codex-taskboard/shared/task-records.mjs +0 -199
- package/vendor/codex-taskboard/shared/task-relations.mjs +0 -55
- package/vendor/codex-taskboard/shared/taskboard-automation.mjs +0 -277
- package/vendor/codex-taskboard/skills/manage-taskboard/SKILL.md +0 -45
- package/vendor/codex-taskboard/skills/manage-taskboard/agents/openai.yaml +0 -4
- package/vendor/codex-taskboard/skills/manage-taskboard/references/cli.md +0 -211
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { StringDecoder } from "node:string_decoder";
|
|
3
4
|
/**
|
|
4
5
|
* Ownership seam for structured CLI runs, mirroring TerminalHost for PTYs.
|
|
5
6
|
* Persistent adapters (terminald) outlive web restarts; the in-process adapter
|
|
@@ -7,6 +8,26 @@ import { randomUUID } from "node:crypto";
|
|
|
7
8
|
*/
|
|
8
9
|
/** Per-stream replay log cap inside the daemon. Reducers need full history. */
|
|
9
10
|
export const STRUCTURED_RUN_LOG_MAX_CHARS = 8 * 1024 * 1024;
|
|
11
|
+
export function createUtf8TextDecoder() {
|
|
12
|
+
const decoder = new StringDecoder("utf8");
|
|
13
|
+
let ended = false;
|
|
14
|
+
return {
|
|
15
|
+
write(chunk) {
|
|
16
|
+
if (ended)
|
|
17
|
+
return "";
|
|
18
|
+
if (typeof chunk === "string")
|
|
19
|
+
return chunk;
|
|
20
|
+
return decoder.write(chunk);
|
|
21
|
+
},
|
|
22
|
+
end() {
|
|
23
|
+
if (ended)
|
|
24
|
+
return "";
|
|
25
|
+
ended = true;
|
|
26
|
+
decoder.end();
|
|
27
|
+
return "";
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
10
31
|
/** Resolve a stable daemon-side key for a session's active structured run. */
|
|
11
32
|
export function structuredRunId(sessionId) {
|
|
12
33
|
return `structured:${sessionId}`;
|
|
@@ -17,9 +38,46 @@ class InProcessStructuredExecProcess {
|
|
|
17
38
|
incarnationId = randomUUID();
|
|
18
39
|
stdoutSeq = 0;
|
|
19
40
|
stderrSeq = 0;
|
|
41
|
+
stdoutDecoder = createUtf8TextDecoder();
|
|
42
|
+
stderrDecoder = createUtf8TextDecoder();
|
|
43
|
+
streamEvents = [];
|
|
44
|
+
streamListeners = new Set();
|
|
45
|
+
exitListeners = new Set();
|
|
46
|
+
exitEvent = null;
|
|
20
47
|
constructor(runId, child) {
|
|
21
48
|
this.runId = runId;
|
|
22
49
|
this.child = child;
|
|
50
|
+
const emit = (stream, data) => {
|
|
51
|
+
if (!data)
|
|
52
|
+
return;
|
|
53
|
+
const event = {
|
|
54
|
+
stream,
|
|
55
|
+
data,
|
|
56
|
+
seq: stream === "stdout" ? ++this.stdoutSeq : ++this.stderrSeq,
|
|
57
|
+
};
|
|
58
|
+
this.streamEvents.push(event);
|
|
59
|
+
for (const listener of this.streamListeners)
|
|
60
|
+
listener(event);
|
|
61
|
+
};
|
|
62
|
+
this.child.stdout?.on("data", (chunk) => emit("stdout", this.stdoutDecoder.write(chunk)));
|
|
63
|
+
this.child.stderr?.on("data", (chunk) => emit("stderr", this.stderrDecoder.write(chunk)));
|
|
64
|
+
const settleExit = (event) => {
|
|
65
|
+
if (this.exitEvent)
|
|
66
|
+
return;
|
|
67
|
+
// Flush pending bytes before announcing exit; decoders no-op once ended.
|
|
68
|
+
emit("stdout", this.stdoutDecoder.end());
|
|
69
|
+
emit("stderr", this.stderrDecoder.end());
|
|
70
|
+
this.exitEvent = event;
|
|
71
|
+
for (const listener of this.exitListeners)
|
|
72
|
+
listener(event);
|
|
73
|
+
};
|
|
74
|
+
this.child.on("close", (code, signal) => {
|
|
75
|
+
settleExit({
|
|
76
|
+
exitCode: code,
|
|
77
|
+
signal: signal === null || signal === undefined ? null : osSignalNumber(signal),
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
this.child.on("error", () => settleExit({ exitCode: null, signal: null }));
|
|
23
81
|
}
|
|
24
82
|
get pid() {
|
|
25
83
|
return this.child.pid ?? -1;
|
|
@@ -31,39 +89,18 @@ class InProcessStructuredExecProcess {
|
|
|
31
89
|
catch { /* best-effort */ }
|
|
32
90
|
}
|
|
33
91
|
onStream(listener) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
this.
|
|
37
|
-
this.
|
|
38
|
-
return {
|
|
39
|
-
dispose: () => {
|
|
40
|
-
this.child.stdout?.off("data", stdoutHandler);
|
|
41
|
-
this.child.stderr?.off("data", stderrHandler);
|
|
42
|
-
},
|
|
43
|
-
};
|
|
92
|
+
for (const event of this.streamEvents)
|
|
93
|
+
listener(event);
|
|
94
|
+
this.streamListeners.add(listener);
|
|
95
|
+
return { dispose: () => { this.streamListeners.delete(listener); } };
|
|
44
96
|
}
|
|
45
97
|
onExit(listener) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
};
|
|
53
|
-
const errorHandler = () => {
|
|
54
|
-
if (settled)
|
|
55
|
-
return;
|
|
56
|
-
settled = true;
|
|
57
|
-
listener({ exitCode: null, signal: null });
|
|
58
|
-
};
|
|
59
|
-
this.child.on("close", closeHandler);
|
|
60
|
-
this.child.on("error", errorHandler);
|
|
61
|
-
return {
|
|
62
|
-
dispose: () => {
|
|
63
|
-
this.child.off("close", closeHandler);
|
|
64
|
-
this.child.off("error", errorHandler);
|
|
65
|
-
},
|
|
66
|
-
};
|
|
98
|
+
if (this.exitEvent) {
|
|
99
|
+
listener(this.exitEvent);
|
|
100
|
+
return { dispose: () => { } };
|
|
101
|
+
}
|
|
102
|
+
this.exitListeners.add(listener);
|
|
103
|
+
return { dispose: () => { this.exitListeners.delete(listener); } };
|
|
67
104
|
}
|
|
68
105
|
}
|
|
69
106
|
/** Legacy/local adapter and deterministic test adapter for the structured seam. */
|
|
@@ -83,16 +120,14 @@ export class InProcessStructuredExecHost {
|
|
|
83
120
|
if (wantsStdin)
|
|
84
121
|
child.stdin?.end(request.stdinData);
|
|
85
122
|
const wrapped = new InProcessStructuredExecProcess(request.runId, child);
|
|
123
|
+
// Keep exited records until forgetRun so a late attach can still answer.
|
|
86
124
|
this.processes.set(request.runId, wrapped);
|
|
87
|
-
wrapped.onExit(() => {
|
|
88
|
-
// Keep exited records until forgetRun so attachRun can still answer.
|
|
89
|
-
});
|
|
90
125
|
return wrapped;
|
|
91
126
|
}
|
|
92
|
-
async attachRun() {
|
|
127
|
+
async attachRun(_runId) {
|
|
93
128
|
return null;
|
|
94
129
|
}
|
|
95
|
-
async adoptRun() {
|
|
130
|
+
async adoptRun(_runId) {
|
|
96
131
|
return null;
|
|
97
132
|
}
|
|
98
133
|
async listRuns() {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import type
|
|
2
|
+
import { type StructuredExecHost } from "./structured-exec-host.js";
|
|
3
3
|
import type { StructuredRunnerExecution, StructuredRunnerObserver, StructuredRunnerResult, StructuredRunnerTurnState } from "./structured-runner.js";
|
|
4
4
|
/**
|
|
5
5
|
* Shared pump for CLI-backed structured runners. One implementation drives both
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { createUtf8TextDecoder, } from "./structured-exec-host.js";
|
|
2
3
|
export function startStructuredCli(options) {
|
|
3
4
|
const spawnedAt = new Date().toISOString();
|
|
4
5
|
const observer = options.observer;
|
|
@@ -26,7 +27,7 @@ export function startStructuredCli(options) {
|
|
|
26
27
|
resolveCompletion(options.finalize(ctx, exitCode, signal, spawnError));
|
|
27
28
|
};
|
|
28
29
|
const handleStdoutText = (text) => {
|
|
29
|
-
if (!observer.isActive())
|
|
30
|
+
if (!text || !observer.isActive())
|
|
30
31
|
return;
|
|
31
32
|
observer.onStdout?.(text);
|
|
32
33
|
options.onStdoutText?.(text);
|
|
@@ -37,14 +38,13 @@ export function startStructuredCli(options) {
|
|
|
37
38
|
options.processLine(line, ctx);
|
|
38
39
|
};
|
|
39
40
|
const handleStderrText = (text) => {
|
|
40
|
-
if (!observer.isActive())
|
|
41
|
+
if (!text || !observer.isActive())
|
|
41
42
|
return;
|
|
42
43
|
observer.onStderr?.(text);
|
|
43
44
|
ctx.stderr += text;
|
|
44
45
|
};
|
|
45
|
-
const
|
|
46
|
-
if (
|
|
47
|
-
const host = options.execHost;
|
|
46
|
+
const host = options.execHost;
|
|
47
|
+
if (host?.persistent) {
|
|
48
48
|
const request = {
|
|
49
49
|
runId: `structured:${options.sessionId}`,
|
|
50
50
|
file: options.file,
|
|
@@ -82,10 +82,16 @@ export function startStructuredCli(options) {
|
|
|
82
82
|
if (wantsStdin)
|
|
83
83
|
child.stdin?.end(options.stdinData);
|
|
84
84
|
source = { pid: child.pid ?? null, interrupt: () => child.kill("SIGTERM") };
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
const stdoutDecoder = createUtf8TextDecoder();
|
|
86
|
+
const stderrDecoder = createUtf8TextDecoder();
|
|
87
|
+
child.stdout?.on("data", (chunk) => handleStdoutText(stdoutDecoder.write(chunk)));
|
|
88
|
+
child.stderr?.on("data", (chunk) => handleStderrText(stderrDecoder.write(chunk)));
|
|
87
89
|
child.on("error", (error) => finish(null, null, error));
|
|
88
|
-
child.on("close", (exitCode, signalName) =>
|
|
90
|
+
child.on("close", (exitCode, signalName) => {
|
|
91
|
+
handleStdoutText(stdoutDecoder.end());
|
|
92
|
+
handleStderrText(stderrDecoder.end());
|
|
93
|
+
finish(exitCode, signalName === null || signalName === undefined ? null : signalName);
|
|
94
|
+
});
|
|
89
95
|
sourceReady = Promise.resolve();
|
|
90
96
|
}
|
|
91
97
|
return {
|
package/dist/task-types.d.ts
CHANGED
|
@@ -1,8 +1,21 @@
|
|
|
1
1
|
export type WandTaskStatus = "todo" | "doing" | "done";
|
|
2
2
|
export type WandTaskPriority = "none" | "low" | "medium" | "high" | "urgent";
|
|
3
|
+
/** 任务派发时选择的 CLI 工具;空串表示尚未指定。 */
|
|
4
|
+
export type WandTaskAgentProvider = "claude" | "codex" | "opencode" | "grok" | "qoder" | "pi";
|
|
5
|
+
export type WandTaskAgentModel = string;
|
|
6
|
+
export type WandTaskAgentEffort = "off" | "standard" | "deep" | "max";
|
|
7
|
+
/** 任务上的默认派发配置:先选工具 / 模型 / 思考深度,再一键交给 Agent。 */
|
|
8
|
+
export interface WandTaskAgent {
|
|
9
|
+
provider: WandTaskAgentProvider;
|
|
10
|
+
/** 具体模型 ID;"default" 表示跟随服务端为该 provider 选择的默认模型。 */
|
|
11
|
+
model: WandTaskAgentModel;
|
|
12
|
+
thinkingEffort: WandTaskAgentEffort;
|
|
13
|
+
}
|
|
3
14
|
export interface WandTask {
|
|
4
15
|
id: string;
|
|
5
16
|
workspaceId: string | null;
|
|
17
|
+
/** 关联的侧栏工作任务;归档/新建时用来对账,不随 WorkspaceTask 删除而消失。 */
|
|
18
|
+
workspaceTaskId: string | null;
|
|
6
19
|
identifier: string;
|
|
7
20
|
title: string;
|
|
8
21
|
description: string;
|
|
@@ -11,6 +24,8 @@ export interface WandTask {
|
|
|
11
24
|
labels: string[];
|
|
12
25
|
dueDate: string | null;
|
|
13
26
|
sortOrder: number;
|
|
27
|
+
/** 该任务绑定的执行 Agent;null 表示还没指定。 */
|
|
28
|
+
agent: WandTaskAgent | null;
|
|
14
29
|
createdAt: string;
|
|
15
30
|
updatedAt: string;
|
|
16
31
|
}
|
|
@@ -7,6 +7,8 @@ export declare class TerminalDaemonClient implements TerminalHost, StructuredExe
|
|
|
7
7
|
readonly persistent = true;
|
|
8
8
|
private socket;
|
|
9
9
|
private buffer;
|
|
10
|
+
/** Decodes daemon NDJSON frames without splitting multi-byte chars. */
|
|
11
|
+
private decoder;
|
|
10
12
|
private nextRequestId;
|
|
11
13
|
private readonly pending;
|
|
12
14
|
private readonly inventory;
|
|
@@ -2,6 +2,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
2
2
|
import net from "node:net";
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import process from "node:process";
|
|
5
|
+
import { StringDecoder } from "node:string_decoder";
|
|
5
6
|
import { TERMINAL_DAEMON_PROTOCOL_VERSION, terminalDaemonPaths, } from "./terminal-daemon-protocol.js";
|
|
6
7
|
import { appendTerminalChunkWindow, InProcessTerminalHost, } from "./terminal-host.js";
|
|
7
8
|
import { STRUCTURED_RUN_LOG_MAX_CHARS, } from "./structured-exec-host.js";
|
|
@@ -223,6 +224,8 @@ export class TerminalDaemonClient {
|
|
|
223
224
|
persistent = true;
|
|
224
225
|
socket = null;
|
|
225
226
|
buffer = "";
|
|
227
|
+
/** Decodes daemon NDJSON frames without splitting multi-byte chars. */
|
|
228
|
+
decoder = new StringDecoder("utf8");
|
|
226
229
|
nextRequestId = 1;
|
|
227
230
|
pending = new Map();
|
|
228
231
|
inventory = new Map();
|
|
@@ -257,7 +260,10 @@ export class TerminalDaemonClient {
|
|
|
257
260
|
socket.once("connect", onConnect);
|
|
258
261
|
socket.once("error", onError);
|
|
259
262
|
});
|
|
260
|
-
socket
|
|
263
|
+
// Each socket decodes from a clean slate; a half-written character from a
|
|
264
|
+
// previous connection must not leak into the next frame.
|
|
265
|
+
this.decoder = new StringDecoder("utf8");
|
|
266
|
+
socket.on("data", (data) => this.consume(this.decoder.write(data)));
|
|
261
267
|
socket.on("close", () => this.handleDisconnect());
|
|
262
268
|
socket.on("error", (error) => {
|
|
263
269
|
this.rejectPending(error instanceof Error ? error : new Error(String(error)));
|
|
@@ -3,9 +3,10 @@ import { spawn as nodeSpawn } from "node:child_process";
|
|
|
3
3
|
import { chmodSync, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
4
|
import net from "node:net";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import { StringDecoder } from "node:string_decoder";
|
|
6
7
|
import pty from "node-pty";
|
|
7
8
|
import { ensureNodePtyHelperExecutable } from "./ensure-node-pty-helper.js";
|
|
8
|
-
import { STRUCTURED_RUN_LOG_MAX_CHARS, } from "./structured-exec-host.js";
|
|
9
|
+
import { STRUCTURED_RUN_LOG_MAX_CHARS, createUtf8TextDecoder, } from "./structured-exec-host.js";
|
|
9
10
|
import { TERMINAL_DAEMON_PROTOCOL_VERSION, terminalDaemonPaths, } from "./terminal-daemon-protocol.js";
|
|
10
11
|
import { appendTerminalChunkWindow, } from "./terminal-host.js";
|
|
11
12
|
import { PtyTerminalState } from "./pty-terminal-state.js";
|
|
@@ -213,34 +214,30 @@ export async function runTerminalDaemon(configPath) {
|
|
|
213
214
|
stderrLog: "",
|
|
214
215
|
stdoutTruncated: false,
|
|
215
216
|
stderrTruncated: false,
|
|
217
|
+
stdoutDecoder: createUtf8TextDecoder(),
|
|
218
|
+
stderrDecoder: createUtf8TextDecoder(),
|
|
216
219
|
};
|
|
217
220
|
structuredRuns.set(request.runId, run);
|
|
218
221
|
evictStaleStructuredRuns();
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
+
const emitDecoded = (stream, text) => {
|
|
223
|
+
if (!text)
|
|
224
|
+
return;
|
|
225
|
+
const seq = appendRunLog(run, stream, text);
|
|
222
226
|
broadcast({
|
|
223
227
|
kind: "event",
|
|
224
228
|
event: "sdata",
|
|
225
229
|
sessionId: run.request.runId,
|
|
226
230
|
incarnationId: run.incarnationId,
|
|
227
|
-
stream
|
|
231
|
+
stream,
|
|
228
232
|
data: text,
|
|
229
233
|
seq,
|
|
230
234
|
});
|
|
235
|
+
};
|
|
236
|
+
child.stdout?.on("data", (chunk) => {
|
|
237
|
+
emitDecoded("stdout", run.stdoutDecoder.write(chunk));
|
|
231
238
|
});
|
|
232
239
|
child.stderr?.on("data", (chunk) => {
|
|
233
|
-
|
|
234
|
-
const seq = appendRunLog(run, "stderr", text);
|
|
235
|
-
broadcast({
|
|
236
|
-
kind: "event",
|
|
237
|
-
event: "sdata",
|
|
238
|
-
sessionId: run.request.runId,
|
|
239
|
-
incarnationId: run.incarnationId,
|
|
240
|
-
stream: "stderr",
|
|
241
|
-
data: text,
|
|
242
|
-
seq,
|
|
243
|
-
});
|
|
240
|
+
emitDecoded("stderr", run.stderrDecoder.write(chunk));
|
|
244
241
|
});
|
|
245
242
|
child.on("error", () => {
|
|
246
243
|
// Spawn failures surface via close with no exit code; keep the record so
|
|
@@ -249,6 +246,8 @@ export async function runTerminalDaemon(configPath) {
|
|
|
249
246
|
child.on("close", (code, signalName) => {
|
|
250
247
|
if (structuredRuns.get(run.request.runId) !== run || run.child !== child)
|
|
251
248
|
return;
|
|
249
|
+
emitDecoded("stdout", run.stdoutDecoder.end());
|
|
250
|
+
emitDecoded("stderr", run.stderrDecoder.end());
|
|
252
251
|
run.child = null;
|
|
253
252
|
run.status = "exited";
|
|
254
253
|
run.exitCode = code;
|
|
@@ -380,11 +379,11 @@ export async function runTerminalDaemon(configPath) {
|
|
|
380
379
|
}
|
|
381
380
|
};
|
|
382
381
|
const server = net.createServer((socket) => {
|
|
383
|
-
const client = { socket, authenticated: false, buffer: "" };
|
|
382
|
+
const client = { socket, authenticated: false, buffer: "", decoder: new StringDecoder("utf8") };
|
|
384
383
|
clients.add(client);
|
|
385
384
|
socket.setNoDelay(true);
|
|
386
385
|
socket.on("data", (data) => {
|
|
387
|
-
client.buffer +=
|
|
386
|
+
client.buffer += client.decoder.write(data);
|
|
388
387
|
if (client.buffer.length > MAX_REQUEST_BUFFER) {
|
|
389
388
|
socket.destroy();
|
|
390
389
|
return;
|
package/dist/tui/ipc-server.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import net from "node:net";
|
|
7
7
|
import { chmodSync, chownSync, existsSync, statSync, unlinkSync } from "node:fs";
|
|
8
|
+
import { StringDecoder } from "node:string_decoder";
|
|
8
9
|
import path from "node:path";
|
|
9
10
|
import { getErrorMessage } from "../error-utils.js";
|
|
10
11
|
export function startIpcServer(deps) {
|
|
@@ -19,8 +20,9 @@ export function startIpcServer(deps) {
|
|
|
19
20
|
}
|
|
20
21
|
const server = net.createServer((conn) => {
|
|
21
22
|
let buf = "";
|
|
23
|
+
const decoder = new StringDecoder("utf8");
|
|
22
24
|
conn.on("data", (chunk) => {
|
|
23
|
-
buf +=
|
|
25
|
+
buf += decoder.write(chunk);
|
|
24
26
|
let idx;
|
|
25
27
|
while ((idx = buf.indexOf("\n")) >= 0) {
|
|
26
28
|
const line = buf.slice(0, idx).trim();
|
package/dist/types.d.ts
CHANGED
|
@@ -685,6 +685,7 @@ export interface WorkspaceTask {
|
|
|
685
685
|
status: WorkspaceTaskStatus;
|
|
686
686
|
createdAt: string;
|
|
687
687
|
lastOpenedAt: string | null;
|
|
688
|
+
layoutRevision?: number;
|
|
688
689
|
}
|
|
689
690
|
/** Unified event type emitted by ClaudePtyBridge for WebSocket broadcast */
|
|
690
691
|
type SessionEventType = "output.raw" | "output.chat" | "chat.turn" | "permission.prompt" | "permission.resolved" | "session.id" | "task" | "ended";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { WandStorage } from "./storage.js";
|
|
2
|
+
import type { WandTask } from "./task-types.js";
|
|
3
|
+
import type { Workspace, WorkspaceTask } from "./types.js";
|
|
4
|
+
/** 侧栏工作任务与看板卡片对账:已关联则复用,同项目同名未关联则挂上,否则新建。 */
|
|
5
|
+
export declare function ensureBoardTaskForWorkspaceTask(storage: WandStorage, task: WorkspaceTask, workspace: Workspace): WandTask;
|
|
6
|
+
/** 看板归档:卡片进入已完成,并同步把关联的侧栏工作任务标成 done(不删会话)。 */
|
|
7
|
+
export declare function archiveBoardTask(storage: WandStorage, id: string): WandTask | null;
|
|
8
|
+
/** 侧栏工作任务完成/删除时,把对应看板卡片标成已完成。 */
|
|
9
|
+
export declare function archiveBoardTaskForWorkspaceTask(storage: WandStorage, workspaceTaskId: string): void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
function boardDescriptionFor(task, workspace) {
|
|
2
|
+
const lines = [`项目:${workspace.name}`];
|
|
3
|
+
const cwd = task.worktree?.path || task.cwd || workspace.cwd;
|
|
4
|
+
if (cwd)
|
|
5
|
+
lines.push(`目录:${cwd}`);
|
|
6
|
+
if (task.worktree?.branch)
|
|
7
|
+
lines.push(`分支:${task.worktree.branch}`);
|
|
8
|
+
return lines.join("\n");
|
|
9
|
+
}
|
|
10
|
+
/** 侧栏工作任务与看板卡片对账:已关联则复用,同项目同名未关联则挂上,否则新建。 */
|
|
11
|
+
export function ensureBoardTaskForWorkspaceTask(storage, task, workspace) {
|
|
12
|
+
const linked = storage.getWandTaskByWorkspaceTaskId(task.id);
|
|
13
|
+
if (linked)
|
|
14
|
+
return linked;
|
|
15
|
+
const reusable = storage.findUnlinkedWandTask(workspace.id, task.name);
|
|
16
|
+
if (reusable) {
|
|
17
|
+
return storage.updateWandTask(reusable.id, {
|
|
18
|
+
workspaceTaskId: task.id,
|
|
19
|
+
workspaceId: workspace.id,
|
|
20
|
+
}) ?? reusable;
|
|
21
|
+
}
|
|
22
|
+
return storage.createWandTask({
|
|
23
|
+
workspaceId: workspace.id,
|
|
24
|
+
workspaceTaskId: task.id,
|
|
25
|
+
title: task.name,
|
|
26
|
+
description: boardDescriptionFor(task, workspace),
|
|
27
|
+
status: task.status === "done" ? "done" : "todo",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/** 看板归档:卡片进入已完成,并同步把关联的侧栏工作任务标成 done(不删会话)。 */
|
|
31
|
+
export function archiveBoardTask(storage, id) {
|
|
32
|
+
const current = storage.getWandTask(id);
|
|
33
|
+
if (!current)
|
|
34
|
+
return null;
|
|
35
|
+
const archived = storage.updateWandTask(id, { status: "done" });
|
|
36
|
+
if (current.workspaceTaskId) {
|
|
37
|
+
const workspaceTask = storage.getWorkspaceTask(current.workspaceTaskId);
|
|
38
|
+
if (workspaceTask && workspaceTask.status !== "done") {
|
|
39
|
+
storage.updateWorkspaceTask(workspaceTask.id, { status: "done" });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return archived;
|
|
43
|
+
}
|
|
44
|
+
/** 侧栏工作任务完成/删除时,把对应看板卡片标成已完成。 */
|
|
45
|
+
export function archiveBoardTaskForWorkspaceTask(storage, workspaceTaskId) {
|
|
46
|
+
const linked = storage.getWandTaskByWorkspaceTaskId(workspaceTaskId);
|
|
47
|
+
if (!linked || linked.status === "done")
|
|
48
|
+
return;
|
|
49
|
+
storage.updateWandTask(linked.id, { status: "done" });
|
|
50
|
+
}
|