@ai-setting/roy-plugin-task-show 2.4.2 → 2.5.1
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/chat-output-parser.d.ts +26 -0
- package/dist/chat-output-parser.d.ts.map +1 -0
- package/dist/chat-output-parser.js +36 -0
- package/dist/chat-output-parser.js.map +1 -0
- package/dist/chat-panel-html.d.ts +76 -0
- package/dist/chat-panel-html.d.ts.map +1 -0
- package/dist/chat-panel-html.js +117 -0
- package/dist/chat-panel-html.js.map +1 -0
- package/dist/chat-process-manager.d.ts +93 -0
- package/dist/chat-process-manager.d.ts.map +1 -0
- package/dist/chat-process-manager.js +197 -0
- package/dist/chat-process-manager.js.map +1 -0
- package/dist/server.d.ts +55 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +408 -4
- package/dist/server.js.map +1 -1
- package/dist/task-chat-context-builder.d.ts +94 -0
- package/dist/task-chat-context-builder.d.ts.map +1 -0
- package/dist/task-chat-context-builder.js +130 -0
- package/dist/task-chat-context-builder.js.map +1 -0
- package/dist/task-session-store.d.ts.map +1 -1
- package/dist/task-session-store.js +5 -0
- package/dist/task-session-store.js.map +1 -1
- package/package.json +4 -2
- package/plugin.json +1 -1
- package/public/chat-panel.js +565 -0
- package/public/dompurify.min.js +3 -0
- package/public/index.html +11 -0
- package/public/markdown-renderer.js +176 -0
- package/public/marked.min.js +6 -0
- package/public/style.css +316 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Output parser for `roy-agent act` subprocess stdout.
|
|
3
|
+
*
|
|
4
|
+
* `roy-agent act -s <sessionId> <message>` writes human-friendly text to
|
|
5
|
+
* stdout with a leading/trailing sentinel pair:
|
|
6
|
+
*
|
|
7
|
+
* [TaskEventHandler] Started
|
|
8
|
+
* ... LLM streaming text ...
|
|
9
|
+
* [TaskEventHandler] Stopped
|
|
10
|
+
*
|
|
11
|
+
* We do not want the sentinel lines to leak into the chat UI, and we want
|
|
12
|
+
* to strip ANSI colour codes that the CLI uses to highlight text. This
|
|
13
|
+
* module is the single place that knows about that format — every other
|
|
14
|
+
* layer treats output as an opaque byte stream.
|
|
15
|
+
*
|
|
16
|
+
* v2.5.0: kept tiny so we can unit-test the contract in isolation.
|
|
17
|
+
*/
|
|
18
|
+
export declare const SENTINEL_START = "[TaskEventHandler] Started";
|
|
19
|
+
export declare const SENTINEL_STOP = "[TaskEventHandler] Stopped";
|
|
20
|
+
/** Strip CSI / SGR ANSI colour codes from a chunk of stdout. */
|
|
21
|
+
export declare function stripAnsi(input: string): string;
|
|
22
|
+
/** Strip the literal sentinel lines (start + stop). Case-sensitive. */
|
|
23
|
+
export declare function stripSentinels(input: string): string;
|
|
24
|
+
/** Convenience: strip ANSI + sentinels + trim trailing newline. */
|
|
25
|
+
export declare function cleanStdout(raw: string): string;
|
|
26
|
+
//# sourceMappingURL=chat-output-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-output-parser.d.ts","sourceRoot":"","sources":["../src/chat-output-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,eAAO,MAAM,cAAc,+BAA+B,CAAC;AAC3D,eAAO,MAAM,aAAa,+BAA+B,CAAC;AAE1D,gEAAgE;AAChE,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,uEAAuE;AACvE,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKpD;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE/C"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Output parser for `roy-agent act` subprocess stdout.
|
|
3
|
+
*
|
|
4
|
+
* `roy-agent act -s <sessionId> <message>` writes human-friendly text to
|
|
5
|
+
* stdout with a leading/trailing sentinel pair:
|
|
6
|
+
*
|
|
7
|
+
* [TaskEventHandler] Started
|
|
8
|
+
* ... LLM streaming text ...
|
|
9
|
+
* [TaskEventHandler] Stopped
|
|
10
|
+
*
|
|
11
|
+
* We do not want the sentinel lines to leak into the chat UI, and we want
|
|
12
|
+
* to strip ANSI colour codes that the CLI uses to highlight text. This
|
|
13
|
+
* module is the single place that knows about that format — every other
|
|
14
|
+
* layer treats output as an opaque byte stream.
|
|
15
|
+
*
|
|
16
|
+
* v2.5.0: kept tiny so we can unit-test the contract in isolation.
|
|
17
|
+
*/
|
|
18
|
+
const ANSI_RE = /\x1B\[[0-9;?]*[A-Za-z]/g;
|
|
19
|
+
export const SENTINEL_START = "[TaskEventHandler] Started";
|
|
20
|
+
export const SENTINEL_STOP = "[TaskEventHandler] Stopped";
|
|
21
|
+
/** Strip CSI / SGR ANSI colour codes from a chunk of stdout. */
|
|
22
|
+
export function stripAnsi(input) {
|
|
23
|
+
return input.replace(ANSI_RE, "");
|
|
24
|
+
}
|
|
25
|
+
/** Strip the literal sentinel lines (start + stop). Case-sensitive. */
|
|
26
|
+
export function stripSentinels(input) {
|
|
27
|
+
return input
|
|
28
|
+
.split(/\r?\n/)
|
|
29
|
+
.filter((line) => line.trim() !== SENTINEL_START && line.trim() !== SENTINEL_STOP)
|
|
30
|
+
.join("\n");
|
|
31
|
+
}
|
|
32
|
+
/** Convenience: strip ANSI + sentinels + trim trailing newline. */
|
|
33
|
+
export function cleanStdout(raw) {
|
|
34
|
+
return stripSentinels(stripAnsi(raw)).replace(/\n+$/, "");
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=chat-output-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-output-parser.js","sourceRoot":"","sources":["../src/chat-output-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,OAAO,GAAG,yBAAyB,CAAC;AAE1C,MAAM,CAAC,MAAM,cAAc,GAAG,4BAA4B,CAAC;AAC3D,MAAM,CAAC,MAAM,aAAa,GAAG,4BAA4B,CAAC;AAE1D,gEAAgE;AAChE,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACpC,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,KAAK;SACT,KAAK,CAAC,OAAO,CAAC;SACd,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,cAAc,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,aAAa,CAAC;SACjF,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,OAAO,cAAc,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Chat panel HTML — extracted v2.5.1 for cross-page reuse.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this module exists (v2.5.1 REQ-2 fix + v2.5 REQ-3 extension)
|
|
5
|
+
*
|
|
6
|
+
* v2.5.0 introduced the home-page chat panel via `renderChatPanel()`
|
|
7
|
+
* defined inside `src/server.ts`. Only `renderIndexPage` (the legacy
|
|
8
|
+
* home page, hit when no `TaskSessionStore` is configured) actually
|
|
9
|
+
* called it. The plugin always wires a `TaskSessionStore`, so the
|
|
10
|
+
* production home page (`renderSessionForestPage` in
|
|
11
|
+
* `src/task-session-store.ts`) shipped **without** the chat panel.
|
|
12
|
+
*
|
|
13
|
+
* The pre-existing `home-chat-v25.test.ts` constructed a server
|
|
14
|
+
* WITHOUT `sessionStore`, so the green test exercised the legacy
|
|
15
|
+
* path and the v2.5.0 bug slipped through.
|
|
16
|
+
*
|
|
17
|
+
* The v2.5.1 fix:
|
|
18
|
+
* 1. Extract `renderChatPanel()` into this shared module.
|
|
19
|
+
* 2. Have BOTH `renderIndexPage` (legacy) AND
|
|
20
|
+
* `_renderSessionForestPageImpl` (production home) import it.
|
|
21
|
+
* 3. Both pages also need `<script src="/static/chat-panel.js"
|
|
22
|
+
* defer></script>` for the JS to actually wire up the form.
|
|
23
|
+
*
|
|
24
|
+
* v2.5 REQ-3 extends `renderChatPanel()` to accept an `opts` bag
|
|
25
|
+
* with `scope` ("home" | "task") and `taskId` (when scope=task).
|
|
26
|
+
* The HTML carries `data-chat-scope` and `data-task-id` hooks that
|
|
27
|
+
* the chat-panel.js factory picks up to route to `/api/chat/...`
|
|
28
|
+
* vs `/api/task-chat/...` and to select the right localStorage key.
|
|
29
|
+
*
|
|
30
|
+
* Extracting to a dedicated module avoids a circular import between
|
|
31
|
+
* `server.ts` ↔ `task-session-store.ts` (server already imports from
|
|
32
|
+
* task-session-store, and task-session-store previously imported
|
|
33
|
+
* nothing from server, but future plugin evolution may want
|
|
34
|
+
* session-store to depend on other server-side types — keeping
|
|
35
|
+
* chat-panel-html a leaf module is a safer contract).
|
|
36
|
+
*
|
|
37
|
+
* The asset contract pinned by `test/home-chat-v25.test.ts`,
|
|
38
|
+
* `test/chat-panel-session-forest-v251.test.ts` and
|
|
39
|
+
* `test/task-chat-v25.test.ts`:
|
|
40
|
+
* • `data-chat-shell` — the section root
|
|
41
|
+
* • `data-chat-scope` — "home" | "task" (read by the JS factory)
|
|
42
|
+
* • `data-task-id` — task id when scope=task
|
|
43
|
+
* • `data-chat-input` — the text input
|
|
44
|
+
* • `data-chat-send` — the submit button
|
|
45
|
+
* • `data-chat-form` — the `<form>` (used by the JS to bind Enter)
|
|
46
|
+
* • `data-chat-messages` — the message log container
|
|
47
|
+
* • `<script src="/static/chat-panel.js" defer></script>` — must
|
|
48
|
+
* follow the markup on the same page (defer is fine because the
|
|
49
|
+
* JS module polls for the DOM on load).
|
|
50
|
+
*
|
|
51
|
+
* Disabled gracefully: when the host didn't pass
|
|
52
|
+
* `chatOptions.enabled` we render the empty section so SSR layout
|
|
53
|
+
* stays predictable; the JS short-circuits and the `/api/chat/*`
|
|
54
|
+
* endpoints return 503.
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* Render the home-page chat panel markup.
|
|
58
|
+
*
|
|
59
|
+
* Markup is intentionally minimal — the heavy lifting (EventSource
|
|
60
|
+
* handling, message rendering, sessionId persistence) lives in
|
|
61
|
+
* `public/chat-panel.js`. The HTML below carries `data-*` hooks that
|
|
62
|
+
* the JS module targets; the contracts are pinned by
|
|
63
|
+
* `test/home-chat-v25.test.ts`,
|
|
64
|
+
* `test/chat-panel-session-forest-v251.test.ts` and
|
|
65
|
+
* `test/task-chat-v25.test.ts`.
|
|
66
|
+
*
|
|
67
|
+
* @param opts.scope "home" (default) | "task" — controls the
|
|
68
|
+
* API endpoint the JS targets and the UI badge.
|
|
69
|
+
* @param opts.taskId Required when scope === "task". Used to label
|
|
70
|
+
* the panel and bind `data-task-id`.
|
|
71
|
+
*/
|
|
72
|
+
export declare function renderChatPanel(opts?: {
|
|
73
|
+
scope?: "home" | "task";
|
|
74
|
+
taskId?: number;
|
|
75
|
+
}): string;
|
|
76
|
+
//# sourceMappingURL=chat-panel-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-panel-html.d.ts","sourceRoot":"","sources":["../src/chat-panel-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CA6C/F"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Chat panel HTML — extracted v2.5.1 for cross-page reuse.
|
|
3
|
+
*
|
|
4
|
+
* ## Why this module exists (v2.5.1 REQ-2 fix + v2.5 REQ-3 extension)
|
|
5
|
+
*
|
|
6
|
+
* v2.5.0 introduced the home-page chat panel via `renderChatPanel()`
|
|
7
|
+
* defined inside `src/server.ts`. Only `renderIndexPage` (the legacy
|
|
8
|
+
* home page, hit when no `TaskSessionStore` is configured) actually
|
|
9
|
+
* called it. The plugin always wires a `TaskSessionStore`, so the
|
|
10
|
+
* production home page (`renderSessionForestPage` in
|
|
11
|
+
* `src/task-session-store.ts`) shipped **without** the chat panel.
|
|
12
|
+
*
|
|
13
|
+
* The pre-existing `home-chat-v25.test.ts` constructed a server
|
|
14
|
+
* WITHOUT `sessionStore`, so the green test exercised the legacy
|
|
15
|
+
* path and the v2.5.0 bug slipped through.
|
|
16
|
+
*
|
|
17
|
+
* The v2.5.1 fix:
|
|
18
|
+
* 1. Extract `renderChatPanel()` into this shared module.
|
|
19
|
+
* 2. Have BOTH `renderIndexPage` (legacy) AND
|
|
20
|
+
* `_renderSessionForestPageImpl` (production home) import it.
|
|
21
|
+
* 3. Both pages also need `<script src="/static/chat-panel.js"
|
|
22
|
+
* defer></script>` for the JS to actually wire up the form.
|
|
23
|
+
*
|
|
24
|
+
* v2.5 REQ-3 extends `renderChatPanel()` to accept an `opts` bag
|
|
25
|
+
* with `scope` ("home" | "task") and `taskId` (when scope=task).
|
|
26
|
+
* The HTML carries `data-chat-scope` and `data-task-id` hooks that
|
|
27
|
+
* the chat-panel.js factory picks up to route to `/api/chat/...`
|
|
28
|
+
* vs `/api/task-chat/...` and to select the right localStorage key.
|
|
29
|
+
*
|
|
30
|
+
* Extracting to a dedicated module avoids a circular import between
|
|
31
|
+
* `server.ts` ↔ `task-session-store.ts` (server already imports from
|
|
32
|
+
* task-session-store, and task-session-store previously imported
|
|
33
|
+
* nothing from server, but future plugin evolution may want
|
|
34
|
+
* session-store to depend on other server-side types — keeping
|
|
35
|
+
* chat-panel-html a leaf module is a safer contract).
|
|
36
|
+
*
|
|
37
|
+
* The asset contract pinned by `test/home-chat-v25.test.ts`,
|
|
38
|
+
* `test/chat-panel-session-forest-v251.test.ts` and
|
|
39
|
+
* `test/task-chat-v25.test.ts`:
|
|
40
|
+
* • `data-chat-shell` — the section root
|
|
41
|
+
* • `data-chat-scope` — "home" | "task" (read by the JS factory)
|
|
42
|
+
* • `data-task-id` — task id when scope=task
|
|
43
|
+
* • `data-chat-input` — the text input
|
|
44
|
+
* • `data-chat-send` — the submit button
|
|
45
|
+
* • `data-chat-form` — the `<form>` (used by the JS to bind Enter)
|
|
46
|
+
* • `data-chat-messages` — the message log container
|
|
47
|
+
* • `<script src="/static/chat-panel.js" defer></script>` — must
|
|
48
|
+
* follow the markup on the same page (defer is fine because the
|
|
49
|
+
* JS module polls for the DOM on load).
|
|
50
|
+
*
|
|
51
|
+
* Disabled gracefully: when the host didn't pass
|
|
52
|
+
* `chatOptions.enabled` we render the empty section so SSR layout
|
|
53
|
+
* stays predictable; the JS short-circuits and the `/api/chat/*`
|
|
54
|
+
* endpoints return 503.
|
|
55
|
+
*/
|
|
56
|
+
/**
|
|
57
|
+
* Render the home-page chat panel markup.
|
|
58
|
+
*
|
|
59
|
+
* Markup is intentionally minimal — the heavy lifting (EventSource
|
|
60
|
+
* handling, message rendering, sessionId persistence) lives in
|
|
61
|
+
* `public/chat-panel.js`. The HTML below carries `data-*` hooks that
|
|
62
|
+
* the JS module targets; the contracts are pinned by
|
|
63
|
+
* `test/home-chat-v25.test.ts`,
|
|
64
|
+
* `test/chat-panel-session-forest-v251.test.ts` and
|
|
65
|
+
* `test/task-chat-v25.test.ts`.
|
|
66
|
+
*
|
|
67
|
+
* @param opts.scope "home" (default) | "task" — controls the
|
|
68
|
+
* API endpoint the JS targets and the UI badge.
|
|
69
|
+
* @param opts.taskId Required when scope === "task". Used to label
|
|
70
|
+
* the panel and bind `data-task-id`.
|
|
71
|
+
*/
|
|
72
|
+
export function renderChatPanel(opts = {}) {
|
|
73
|
+
const scope = opts.scope ?? "home";
|
|
74
|
+
const taskId = opts.taskId;
|
|
75
|
+
const isTask = scope === "task" && typeof taskId === "number";
|
|
76
|
+
const ariaLabel = isTask ? `Task #${taskId} chat panel` : "Home chat panel";
|
|
77
|
+
const heading = isTask ? "💬 Task chat" : "💬 roy-agent chat";
|
|
78
|
+
const badge = isTask
|
|
79
|
+
? `<span class="chat-scope-badge" data-chat-scope-badge>Connected to task #${taskId}</span>`
|
|
80
|
+
: "";
|
|
81
|
+
const subline = isTask
|
|
82
|
+
? `Multi-turn conversation powered by <code>roy-agent act -s task-${taskId}</code>. The task context (title, status, recent operations) is auto-injected into every message.`
|
|
83
|
+
: `Multi-turn conversation powered by <code>roy-agent act -s <sessionId></code>.`;
|
|
84
|
+
const placeholder = isTask ? `Ask anything about task #${taskId}…` : "Type a message and press Enter…";
|
|
85
|
+
// Scope + taskId hooks the JS factory reads to pick the right
|
|
86
|
+
// endpoint and the right localStorage key.
|
|
87
|
+
const scopeAttrs = isTask
|
|
88
|
+
? ` data-chat-scope="task" data-task-id="${taskId}"`
|
|
89
|
+
: ` data-chat-scope="home"`;
|
|
90
|
+
const extraClass = isTask ? " chat-panel--task" : "";
|
|
91
|
+
return `
|
|
92
|
+
<section class="panel chat-panel${extraClass}"${scopeAttrs} data-chat-shell aria-label="${ariaLabel}">
|
|
93
|
+
<header class="chat-panel-header">
|
|
94
|
+
<h2>${heading} ${badge}</h2>
|
|
95
|
+
<p class="meta chat-panel-meta">${subline}</p>
|
|
96
|
+
</header>
|
|
97
|
+
<div class="chat-messages" data-chat-messages role="log" aria-live="polite" aria-relevant="additions">
|
|
98
|
+
<p class="chat-empty">No messages yet — ask away!</p>
|
|
99
|
+
</div>
|
|
100
|
+
<form class="chat-form" data-chat-form autocomplete="off">
|
|
101
|
+
<label class="visually-hidden" for="chat-input">Message</label>
|
|
102
|
+
<input
|
|
103
|
+
id="chat-input"
|
|
104
|
+
type="text"
|
|
105
|
+
class="chat-input"
|
|
106
|
+
data-chat-input
|
|
107
|
+
placeholder="${placeholder}"
|
|
108
|
+
autocomplete="off"
|
|
109
|
+
/>
|
|
110
|
+
<button type="submit" class="chat-send" data-chat-send aria-label="Send message">
|
|
111
|
+
Send
|
|
112
|
+
</button>
|
|
113
|
+
</form>
|
|
114
|
+
</section>
|
|
115
|
+
`;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=chat-panel-html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-panel-html.js","sourceRoot":"","sources":["../src/chat-panel-html.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAAC,OAAqD,EAAE;IACrF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,MAAM,MAAM,GAAG,KAAK,KAAK,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC;IAC9D,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,SAAS,MAAM,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC;IAC5E,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAC9D,MAAM,KAAK,GAAG,MAAM;QAClB,CAAC,CAAC,2EAA2E,MAAM,SAAS;QAC5F,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,OAAO,GAAG,MAAM;QACpB,CAAC,CAAC,kEAAkE,MAAM,mGAAmG;QAC7K,CAAC,CAAC,qFAAqF,CAAC;IAC1F,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,4BAA4B,MAAM,GAAG,CAAC,CAAC,CAAC,iCAAiC,CAAC;IACvG,8DAA8D;IAC9D,2CAA2C;IAC3C,MAAM,UAAU,GAAG,MAAM;QACvB,CAAC,CAAC,yCAAyC,MAAM,GAAG;QACpD,CAAC,CAAC,yBAAyB,CAAC;IAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;IAErD,OAAO;oCAC2B,UAAU,IAAI,UAAU,gCAAgC,SAAS;;YAEzF,OAAO,IAAI,KAAK;wCACY,OAAO;;;;;;;;;;;;uBAYxB,WAAW;;;;;;;;CAQjC,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ChatProcessManager — spawn wrapper for `roy-agent act`.
|
|
3
|
+
*
|
|
4
|
+
* v2.5.0: encapsulates the user-decided integration strategy documented in
|
|
5
|
+
* /tmp/task-show-v2.5-spawn-plan.md. We do NOT depend on the roy-agent
|
|
6
|
+
* SDK; instead we shell out to `node <roy-agent.js> act -s <sessionId>
|
|
7
|
+
<message>` per query and stream the subprocess stdout back to the
|
|
8
|
+
* consumer.
|
|
9
|
+
*
|
|
10
|
+
* Concurrency: a FIFO queue caps the number of in-flight subprocesses at
|
|
11
|
+
* `maxConcurrent`. Excess calls `await` until a slot frees up.
|
|
12
|
+
*
|
|
13
|
+
* Lifecycle: every `sendStream` call spawns exactly ONE short-lived
|
|
14
|
+
* subprocess. The subprocess is SIGTERM'd (then SIGKILL after 5s) on
|
|
15
|
+
* `abort()`. The slot is released in the `exit` handler so a failure
|
|
16
|
+
* cannot leak concurrency.
|
|
17
|
+
*
|
|
18
|
+
* Output parsing: each line written by the subprocess is classified into
|
|
19
|
+
* a `ChatChunk` (see type below). Sentinels and ANSI codes are stripped
|
|
20
|
+
* before classification — see `chat-output-parser.ts`.
|
|
21
|
+
*/
|
|
22
|
+
/** One unit of output emitted by `roy-agent act`. */
|
|
23
|
+
export type ChatChunkType = "start" | "text" | "reasoning" | "done" | "error";
|
|
24
|
+
export interface ChatChunk {
|
|
25
|
+
type: ChatChunkType;
|
|
26
|
+
/** Plain text payload (already ANSI-stripped). */
|
|
27
|
+
text?: string;
|
|
28
|
+
/** Final metadata attached to start/done chunks. */
|
|
29
|
+
meta?: {
|
|
30
|
+
sessionId: string;
|
|
31
|
+
latencyMs?: number;
|
|
32
|
+
exitCode?: number;
|
|
33
|
+
};
|
|
34
|
+
/** Error info attached to error chunks. */
|
|
35
|
+
error?: {
|
|
36
|
+
message: string;
|
|
37
|
+
code?: string;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export interface SendOptions {
|
|
41
|
+
/** Hard timeout (default = constructor `defaultTimeoutMs`). */
|
|
42
|
+
timeoutMs?: number;
|
|
43
|
+
/** Working dir for the subprocess (default = process.cwd()). */
|
|
44
|
+
cwd?: string;
|
|
45
|
+
/** Extra args appended AFTER `--tool-calls=false`. Used by tests. */
|
|
46
|
+
extraArgs?: string[];
|
|
47
|
+
}
|
|
48
|
+
export interface ChatProcessManagerOptions {
|
|
49
|
+
/** Absolute path to the roy-agent CLI entry. */
|
|
50
|
+
cliPath: string;
|
|
51
|
+
/** Maximum concurrent subprocesses (default 4). */
|
|
52
|
+
maxConcurrent?: number;
|
|
53
|
+
/** Default timeout per query (default 300_000 ms). */
|
|
54
|
+
defaultTimeoutMs?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface SendResult {
|
|
57
|
+
exitCode: number;
|
|
58
|
+
durationMs: number;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Manager — single instance per task-show process. Stateless beyond the
|
|
62
|
+
* concurrency queue + abort map.
|
|
63
|
+
*/
|
|
64
|
+
export declare class ChatProcessManager {
|
|
65
|
+
private readonly cliPath;
|
|
66
|
+
private readonly maxConcurrent;
|
|
67
|
+
private readonly defaultTimeoutMs;
|
|
68
|
+
private active;
|
|
69
|
+
private queue;
|
|
70
|
+
private abortFlags;
|
|
71
|
+
private totalCompleted;
|
|
72
|
+
constructor(opts: ChatProcessManagerOptions);
|
|
73
|
+
/** Block until a concurrency slot is available. */
|
|
74
|
+
private acquire;
|
|
75
|
+
/** Release a slot; wake the next waiter if any. */
|
|
76
|
+
private release;
|
|
77
|
+
/**
|
|
78
|
+
* Stream a chat turn. The callback receives ChatChunk objects in the
|
|
79
|
+
* order they are classified; the returned promise resolves with the
|
|
80
|
+
* subprocess exit metadata.
|
|
81
|
+
*/
|
|
82
|
+
sendStream(sessionId: string, message: string, onChunk: (chunk: ChatChunk) => void, opts?: SendOptions): Promise<SendResult>;
|
|
83
|
+
private emitLine;
|
|
84
|
+
/** Abort an in-flight query (best-effort SIGTERM). */
|
|
85
|
+
abort(sessionId: string): void;
|
|
86
|
+
/** Stats for monitoring / health endpoints. */
|
|
87
|
+
stats(): {
|
|
88
|
+
active: number;
|
|
89
|
+
queued: number;
|
|
90
|
+
totalCompleted: number;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=chat-process-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-process-manager.d.ts","sourceRoot":"","sources":["../src/chat-process-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAKH,qDAAqD;AACrD,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,MAAM,GACN,WAAW,GACX,MAAM,GACN,OAAO,CAAC;AAEZ,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,aAAa,CAAC;IACpB,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,IAAI,CAAC,EAAE;QACL,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,2CAA2C;IAC3C,KAAK,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAED,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACxC,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAID;;;GAGG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,UAAU,CAAsC;IACxD,OAAO,CAAC,cAAc,CAAK;gBAEf,IAAI,EAAE,yBAAyB;IAS3C,mDAAmD;YACrC,OAAO;IASrB,mDAAmD;IACnD,OAAO,CAAC,OAAO;IAMf;;;;OAIG;IACG,UAAU,CACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,EACnC,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,UAAU,CAAC;IAiHtB,OAAO,CAAC,QAAQ;IAoBhB,sDAAsD;IACtD,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK9B,+CAA+C;IAC/C,KAAK,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE;CAOpE"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ChatProcessManager — spawn wrapper for `roy-agent act`.
|
|
3
|
+
*
|
|
4
|
+
* v2.5.0: encapsulates the user-decided integration strategy documented in
|
|
5
|
+
* /tmp/task-show-v2.5-spawn-plan.md. We do NOT depend on the roy-agent
|
|
6
|
+
* SDK; instead we shell out to `node <roy-agent.js> act -s <sessionId>
|
|
7
|
+
<message>` per query and stream the subprocess stdout back to the
|
|
8
|
+
* consumer.
|
|
9
|
+
*
|
|
10
|
+
* Concurrency: a FIFO queue caps the number of in-flight subprocesses at
|
|
11
|
+
* `maxConcurrent`. Excess calls `await` until a slot frees up.
|
|
12
|
+
*
|
|
13
|
+
* Lifecycle: every `sendStream` call spawns exactly ONE short-lived
|
|
14
|
+
* subprocess. The subprocess is SIGTERM'd (then SIGKILL after 5s) on
|
|
15
|
+
* `abort()`. The slot is released in the `exit` handler so a failure
|
|
16
|
+
* cannot leak concurrency.
|
|
17
|
+
*
|
|
18
|
+
* Output parsing: each line written by the subprocess is classified into
|
|
19
|
+
* a `ChatChunk` (see type below). Sentinels and ANSI codes are stripped
|
|
20
|
+
* before classification — see `chat-output-parser.ts`.
|
|
21
|
+
*/
|
|
22
|
+
import { spawn } from "node:child_process";
|
|
23
|
+
import { stripAnsi } from "./chat-output-parser.js";
|
|
24
|
+
const REASONING_OPEN = "<think>";
|
|
25
|
+
/**
|
|
26
|
+
* Manager — single instance per task-show process. Stateless beyond the
|
|
27
|
+
* concurrency queue + abort map.
|
|
28
|
+
*/
|
|
29
|
+
export class ChatProcessManager {
|
|
30
|
+
cliPath;
|
|
31
|
+
maxConcurrent;
|
|
32
|
+
defaultTimeoutMs;
|
|
33
|
+
active = 0;
|
|
34
|
+
queue = [];
|
|
35
|
+
abortFlags = new Map();
|
|
36
|
+
totalCompleted = 0;
|
|
37
|
+
constructor(opts) {
|
|
38
|
+
if (!opts || typeof opts.cliPath !== "string" || opts.cliPath.length === 0) {
|
|
39
|
+
throw new Error("ChatProcessManager: cliPath is required");
|
|
40
|
+
}
|
|
41
|
+
this.cliPath = opts.cliPath;
|
|
42
|
+
this.maxConcurrent = Math.max(1, opts.maxConcurrent ?? 4);
|
|
43
|
+
this.defaultTimeoutMs = opts.defaultTimeoutMs ?? 300_000;
|
|
44
|
+
}
|
|
45
|
+
/** Block until a concurrency slot is available. */
|
|
46
|
+
async acquire() {
|
|
47
|
+
if (this.active < this.maxConcurrent) {
|
|
48
|
+
this.active++;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
await new Promise((resolve) => this.queue.push(resolve));
|
|
52
|
+
this.active++;
|
|
53
|
+
}
|
|
54
|
+
/** Release a slot; wake the next waiter if any. */
|
|
55
|
+
release() {
|
|
56
|
+
this.active = Math.max(0, this.active - 1);
|
|
57
|
+
const next = this.queue.shift();
|
|
58
|
+
if (next)
|
|
59
|
+
next();
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Stream a chat turn. The callback receives ChatChunk objects in the
|
|
63
|
+
* order they are classified; the returned promise resolves with the
|
|
64
|
+
* subprocess exit metadata.
|
|
65
|
+
*/
|
|
66
|
+
async sendStream(sessionId, message, onChunk, opts = {}) {
|
|
67
|
+
if (typeof sessionId !== "string" || sessionId.length === 0) {
|
|
68
|
+
throw new Error("ChatProcessManager: sessionId is required");
|
|
69
|
+
}
|
|
70
|
+
if (typeof message !== "string") {
|
|
71
|
+
throw new Error("ChatProcessManager: message must be a string");
|
|
72
|
+
}
|
|
73
|
+
await this.acquire();
|
|
74
|
+
const ctrl = new AbortController();
|
|
75
|
+
this.abortFlags.set(sessionId, ctrl);
|
|
76
|
+
const args = [
|
|
77
|
+
this.cliPath,
|
|
78
|
+
"act",
|
|
79
|
+
"-s",
|
|
80
|
+
sessionId,
|
|
81
|
+
message,
|
|
82
|
+
"--reasoning=false",
|
|
83
|
+
"--tool-calls=false",
|
|
84
|
+
...(opts.extraArgs ?? []),
|
|
85
|
+
];
|
|
86
|
+
const startedAt = Date.now();
|
|
87
|
+
const timeoutMs = opts.timeoutMs ?? this.defaultTimeoutMs;
|
|
88
|
+
let proc;
|
|
89
|
+
try {
|
|
90
|
+
proc = spawn("node", args, {
|
|
91
|
+
cwd: opts.cwd ?? process.cwd(),
|
|
92
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
93
|
+
signal: ctrl.signal,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
this.abortFlags.delete(sessionId);
|
|
98
|
+
this.release();
|
|
99
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
100
|
+
onChunk({ type: "error", error: { message: msg, code: "spawn_failed" } });
|
|
101
|
+
onChunk({
|
|
102
|
+
type: "done",
|
|
103
|
+
meta: { sessionId, exitCode: -1, latencyMs: Date.now() - startedAt },
|
|
104
|
+
});
|
|
105
|
+
return { exitCode: -1, durationMs: Date.now() - startedAt };
|
|
106
|
+
}
|
|
107
|
+
onChunk({ type: "start", meta: { sessionId } });
|
|
108
|
+
// Force-kill watchdog so a stuck subprocess cannot pin a slot.
|
|
109
|
+
const killTimer = setTimeout(() => {
|
|
110
|
+
try {
|
|
111
|
+
proc.kill("SIGKILL");
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
/* ignore */
|
|
115
|
+
}
|
|
116
|
+
}, timeoutMs);
|
|
117
|
+
killTimer.unref?.();
|
|
118
|
+
let stdoutBuf = "";
|
|
119
|
+
proc.stdout.setEncoding("utf-8");
|
|
120
|
+
proc.stdout.on("data", (raw) => {
|
|
121
|
+
stdoutBuf += typeof raw === "string" ? raw : raw.toString("utf-8");
|
|
122
|
+
let nlIdx = stdoutBuf.indexOf("\n");
|
|
123
|
+
while (nlIdx >= 0) {
|
|
124
|
+
const lineRaw = stdoutBuf.slice(0, nlIdx);
|
|
125
|
+
stdoutBuf = stdoutBuf.slice(nlIdx + 1);
|
|
126
|
+
this.emitLine(lineRaw, sessionId, onChunk);
|
|
127
|
+
nlIdx = stdoutBuf.indexOf("\n");
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
proc.stdout.on("end", () => {
|
|
131
|
+
if (stdoutBuf.length > 0) {
|
|
132
|
+
this.emitLine(stdoutBuf, sessionId, onChunk);
|
|
133
|
+
stdoutBuf = "";
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
// stderr is best-effort diagnostics; we surface it as a single error
|
|
137
|
+
// chunk only if the process exits non-zero.
|
|
138
|
+
let stderrBuf = "";
|
|
139
|
+
proc.stderr.setEncoding("utf-8");
|
|
140
|
+
proc.stderr.on("data", (raw) => {
|
|
141
|
+
stderrBuf += typeof raw === "string" ? raw : raw.toString("utf-8");
|
|
142
|
+
});
|
|
143
|
+
const exitCode = await new Promise((resolve) => {
|
|
144
|
+
proc.on("exit", (code) => resolve(typeof code === "number" ? code : -1));
|
|
145
|
+
proc.on("error", () => resolve(-1));
|
|
146
|
+
});
|
|
147
|
+
clearTimeout(killTimer);
|
|
148
|
+
const durationMs = Date.now() - startedAt;
|
|
149
|
+
this.abortFlags.delete(sessionId);
|
|
150
|
+
this.release();
|
|
151
|
+
this.totalCompleted++;
|
|
152
|
+
if (exitCode === 0) {
|
|
153
|
+
onChunk({ type: "done", meta: { sessionId, exitCode, latencyMs: durationMs } });
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
const tail = stderrBuf.trim().split(/\r?\n/).slice(-3).join(" | ");
|
|
157
|
+
onChunk({
|
|
158
|
+
type: "error",
|
|
159
|
+
error: {
|
|
160
|
+
message: tail || `roy-agent act exited with code ${exitCode}`,
|
|
161
|
+
code: `exit_${exitCode}`,
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
onChunk({ type: "done", meta: { sessionId, exitCode, latencyMs: durationMs } });
|
|
165
|
+
}
|
|
166
|
+
return { exitCode, durationMs };
|
|
167
|
+
}
|
|
168
|
+
emitLine(line, _sessionId, onChunk) {
|
|
169
|
+
const trimmed = stripAnsi(line).replace(/\s+$/, "");
|
|
170
|
+
if (trimmed.length === 0)
|
|
171
|
+
return;
|
|
172
|
+
if (trimmed === "[TaskEventHandler] Started" ||
|
|
173
|
+
trimmed === "[TaskEventHandler] Stopped") {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (trimmed.startsWith(REASONING_OPEN)) {
|
|
177
|
+
onChunk({ type: "reasoning", text: trimmed });
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
onChunk({ type: "text", text: trimmed });
|
|
181
|
+
}
|
|
182
|
+
/** Abort an in-flight query (best-effort SIGTERM). */
|
|
183
|
+
abort(sessionId) {
|
|
184
|
+
const ctrl = this.abortFlags.get(sessionId);
|
|
185
|
+
if (ctrl)
|
|
186
|
+
ctrl.abort();
|
|
187
|
+
}
|
|
188
|
+
/** Stats for monitoring / health endpoints. */
|
|
189
|
+
stats() {
|
|
190
|
+
return {
|
|
191
|
+
active: this.active,
|
|
192
|
+
queued: this.queue.length,
|
|
193
|
+
totalCompleted: this.totalCompleted,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=chat-process-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-process-manager.js","sourceRoot":"","sources":["../src/chat-process-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -94,6 +94,8 @@ export declare class TaskShowServer {
|
|
|
94
94
|
/** v0.9.0+: optional session-scoped task store. When set, GET / renders the
|
|
95
95
|
* session forest; otherwise the legacy cross-host tree view is used. */
|
|
96
96
|
private readonly sessionStore;
|
|
97
|
+
/** v2.5.0+: ChatProcessManager singleton (null when chat is disabled). */
|
|
98
|
+
private readonly chatManager;
|
|
97
99
|
constructor(opts: {
|
|
98
100
|
cfg: TaskShowConfig;
|
|
99
101
|
collector: ToolCallCollector;
|
|
@@ -115,6 +117,19 @@ export declare class TaskShowServer {
|
|
|
115
117
|
sessionStore?: TaskSessionStore;
|
|
116
118
|
/** v1.1.0+: plugin version stamped on every SSE event we broadcast. */
|
|
117
119
|
pluginVersion?: string;
|
|
120
|
+
/**
|
|
121
|
+
* v2.5.0+: chat feature config. When `chatOptions.enabled` is true
|
|
122
|
+
* (default), the server mounts `/api/chat/*` routes and renders the
|
|
123
|
+
* home chat panel. When false, the chat UI is hidden and the API
|
|
124
|
+
* endpoints return 503 — useful for environments without a built
|
|
125
|
+
* `roy-agent` CLI on disk.
|
|
126
|
+
*/
|
|
127
|
+
chatOptions?: {
|
|
128
|
+
cliPath: string;
|
|
129
|
+
maxConcurrent?: number;
|
|
130
|
+
defaultTimeoutMs?: number;
|
|
131
|
+
enabled?: boolean;
|
|
132
|
+
};
|
|
118
133
|
});
|
|
119
134
|
/**
|
|
120
135
|
* Get the SSE event bus (for tests / health checks).
|
|
@@ -171,6 +186,46 @@ export declare class TaskShowServer {
|
|
|
171
186
|
* directories (defaults to cwd + $HOME; configurable via
|
|
172
187
|
* `ts.config.fileSandboxPaths`).
|
|
173
188
|
*/
|
|
189
|
+
/**
|
|
190
|
+
* Allocate a fresh chat sessionId. The id is just a string — the
|
|
191
|
+
* underlying SQLite store lives inside the `roy-agent act` subprocess
|
|
192
|
+
* (we never persist anything ourselves; on the next `act -s <id>` call
|
|
193
|
+
* the CLI resurrects the session from disk if it still exists).
|
|
194
|
+
*/
|
|
195
|
+
private handleChatStart;
|
|
196
|
+
/**
|
|
197
|
+
* SSE endpoint. Accepts `application/json` POST body and emits a series
|
|
198
|
+
* of SSE frames: `event: chunk` for every ChatChunk, then
|
|
199
|
+
* `event: done` once the subprocess exits (or `event: error` on
|
|
200
|
+
* failure).
|
|
201
|
+
*/
|
|
202
|
+
private handleChatMessage;
|
|
203
|
+
/** Abort an in-flight chat query for the given session. */
|
|
204
|
+
private handleChatAbort;
|
|
205
|
+
/**
|
|
206
|
+
* v2.5.0+ REQ-3: task-aware chat endpoint.
|
|
207
|
+
*
|
|
208
|
+
* Resolves the task by id (from the collector session OR the
|
|
209
|
+
* operations cache), builds an additionInfo block from the task
|
|
210
|
+
* context, wraps the user's message, and forwards it to the same
|
|
211
|
+
* ChatProcessManager REQ-2 already plumbs. The sessionId is the
|
|
212
|
+
* deterministic `task-${taskId}` so reloads land on the same
|
|
213
|
+
* SQLite-backed conversation.
|
|
214
|
+
*
|
|
215
|
+
* Returns 404 when the task is unknown — we deliberately do NOT
|
|
216
|
+
* answer off-topic questions for tasks that don't exist (which is
|
|
217
|
+
* the same behaviour REQ-2 already shows for unknown chat
|
|
218
|
+
* sessions, just gated by a task id instead of a random uuid).
|
|
219
|
+
*/
|
|
220
|
+
private handleTaskChatMessage;
|
|
221
|
+
/**
|
|
222
|
+
* Resolve the task context for a chat turn. Returns the
|
|
223
|
+
* TaskChatContextBuilder input or null when the task is unknown.
|
|
224
|
+
* Prefers the live collector session (rich `context.worktree` +
|
|
225
|
+
* current status); falls back to the operations cache envelope
|
|
226
|
+
* for tasks that have already been finalized.
|
|
227
|
+
*/
|
|
228
|
+
private resolveTaskChatContext;
|
|
174
229
|
private handleFileContent;
|
|
175
230
|
/**
|
|
176
231
|
* v2.0.0: GET /api/task/:id/file-tree — returns the git-tracked
|