@ai-setting/roy-task-plugin 0.5.0 → 0.6.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/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/dist/cli.js +470 -74
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roy-task",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Roy — task-as-first-class-citizen harness for Claude Code. Ships the roy agent, slash commands for the task lifecycle, and an MCP server exposing the task tools natively.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "dongzhaokun",
|
package/dist/cli.js
CHANGED
|
@@ -137,6 +137,199 @@ function isMissingBinary(err) {
|
|
|
137
137
|
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
// ../../../packages/cli/src/daemon/task-created.ts
|
|
141
|
+
var CREATED_LINE = /Task created(?:\s+successfully)?\s*:\s*#(\d+)/;
|
|
142
|
+
function extractCreatedTask(text, titleHint) {
|
|
143
|
+
if (!text)
|
|
144
|
+
return;
|
|
145
|
+
return fromJson(text) ?? fromSuccessLine(text, titleHint) ?? fromEmbeddedTaskObject(text) ?? fromTaskObjectBlob(text);
|
|
146
|
+
}
|
|
147
|
+
function uniqueTaskId(text) {
|
|
148
|
+
let id;
|
|
149
|
+
for (const m of text.matchAll(/"taskId"\s*:\s*(\d+)/g)) {
|
|
150
|
+
const n = Number(m[1]);
|
|
151
|
+
if (!Number.isInteger(n) || n <= 0)
|
|
152
|
+
return;
|
|
153
|
+
if (id === undefined)
|
|
154
|
+
id = n;
|
|
155
|
+
else if (id !== n)
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
return id;
|
|
159
|
+
}
|
|
160
|
+
function fromJson(text) {
|
|
161
|
+
const trimmed = text.trim();
|
|
162
|
+
if (!trimmed.startsWith("{"))
|
|
163
|
+
return;
|
|
164
|
+
let parsed;
|
|
165
|
+
try {
|
|
166
|
+
parsed = JSON.parse(trimmed);
|
|
167
|
+
} catch {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
171
|
+
return;
|
|
172
|
+
const obj = parsed;
|
|
173
|
+
const id = obj["id"];
|
|
174
|
+
const title = obj["title"];
|
|
175
|
+
if (typeof id !== "number" || !Number.isInteger(id) || id <= 0)
|
|
176
|
+
return;
|
|
177
|
+
if (typeof title !== "string" || title.trim() === "")
|
|
178
|
+
return;
|
|
179
|
+
return { id, title: title.trim() };
|
|
180
|
+
}
|
|
181
|
+
function fromTaskObjectBlob(text) {
|
|
182
|
+
if (!BLOB_GATE.every((marker) => text.includes(marker)))
|
|
183
|
+
return;
|
|
184
|
+
const id = uniqueTaskId(text);
|
|
185
|
+
if (id === undefined)
|
|
186
|
+
return;
|
|
187
|
+
const title = titleFromCreatedActionTitle(text);
|
|
188
|
+
if (title === undefined)
|
|
189
|
+
return;
|
|
190
|
+
return { id, title };
|
|
191
|
+
}
|
|
192
|
+
function titleFromCreatedActionTitle(text) {
|
|
193
|
+
const m = /"actionTitle"\s*:\s*"Task created:\s*([^"]*)"/.exec(text);
|
|
194
|
+
const title = m?.[1]?.trim();
|
|
195
|
+
if (!title || title.length > 200)
|
|
196
|
+
return;
|
|
197
|
+
return title;
|
|
198
|
+
}
|
|
199
|
+
var BLOB_GATE = ['"taskId"', '"actionTitle"', "Task created:"];
|
|
200
|
+
function fromEmbeddedTaskObject(text) {
|
|
201
|
+
let found;
|
|
202
|
+
for (const task of taskCandidates(text, jsonTree(text))) {
|
|
203
|
+
if (found === undefined)
|
|
204
|
+
found = task;
|
|
205
|
+
else if (found.id !== task.id)
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
return found;
|
|
209
|
+
}
|
|
210
|
+
function looksLikeArrayStart(text, at) {
|
|
211
|
+
for (let i = at + 1;i < text.length; i++) {
|
|
212
|
+
const ch = text[i];
|
|
213
|
+
if (ch === " " || ch === "\t" || ch === `
|
|
214
|
+
` || ch === "\r")
|
|
215
|
+
continue;
|
|
216
|
+
return ch === "{" || ch === "[" || ch === '"' || ch === "]";
|
|
217
|
+
}
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
function taskCandidates(text, roots) {
|
|
221
|
+
const out = [];
|
|
222
|
+
const pending = [...roots].reverse();
|
|
223
|
+
while (pending.length > 0) {
|
|
224
|
+
const node = pending.pop();
|
|
225
|
+
if (node.end < 0) {
|
|
226
|
+
if (node.ch === "[" && looksLikeArrayStart(text, node.start))
|
|
227
|
+
continue;
|
|
228
|
+
pushChildren(pending, node);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (node.ch === "[")
|
|
232
|
+
continue;
|
|
233
|
+
const parsed = parseObject(text, node);
|
|
234
|
+
const task = parsed ? taskFromObject(parsed) : undefined;
|
|
235
|
+
if (task)
|
|
236
|
+
out.push(task);
|
|
237
|
+
}
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
function pushChildren(pending, node) {
|
|
241
|
+
for (let i = node.children.length - 1;i >= 0; i--)
|
|
242
|
+
pending.push(node.children[i]);
|
|
243
|
+
}
|
|
244
|
+
function parseObject(text, node) {
|
|
245
|
+
try {
|
|
246
|
+
const parsed = JSON.parse(text.slice(node.start, node.end + 1));
|
|
247
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
248
|
+
return parsed;
|
|
249
|
+
}
|
|
250
|
+
} catch {}
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
function taskFromObject(obj) {
|
|
254
|
+
const id = obj["id"];
|
|
255
|
+
const title = obj["title"];
|
|
256
|
+
if (typeof id !== "number" || !Number.isInteger(id) || id <= 0)
|
|
257
|
+
return;
|
|
258
|
+
if (typeof title !== "string" || title.trim() === "")
|
|
259
|
+
return;
|
|
260
|
+
return { id, title: title.trim() };
|
|
261
|
+
}
|
|
262
|
+
function jsonTree(text) {
|
|
263
|
+
const roots = [];
|
|
264
|
+
const stack = [];
|
|
265
|
+
let inString = false;
|
|
266
|
+
let escaped = false;
|
|
267
|
+
const open = (ch, at) => {
|
|
268
|
+
const node = { ch, start: at, end: -1, children: [] };
|
|
269
|
+
const parent = stack[stack.length - 1];
|
|
270
|
+
(parent ? parent.children : roots).push(node);
|
|
271
|
+
stack.push(node);
|
|
272
|
+
};
|
|
273
|
+
const close = (ch, at) => {
|
|
274
|
+
const want = ch === "}" ? "{" : "[";
|
|
275
|
+
let k = stack.length - 1;
|
|
276
|
+
while (k >= 0 && stack[k].ch !== want)
|
|
277
|
+
k--;
|
|
278
|
+
if (k < 0)
|
|
279
|
+
return;
|
|
280
|
+
stack.length = k + 1;
|
|
281
|
+
const node = stack.pop();
|
|
282
|
+
node.end = at;
|
|
283
|
+
};
|
|
284
|
+
for (let i = 0;i < text.length; i++) {
|
|
285
|
+
const ch = text[i];
|
|
286
|
+
if (inString) {
|
|
287
|
+
if (ch === `
|
|
288
|
+
`) {
|
|
289
|
+
inString = false;
|
|
290
|
+
escaped = false;
|
|
291
|
+
} else if (escaped)
|
|
292
|
+
escaped = false;
|
|
293
|
+
else if (ch === "\\")
|
|
294
|
+
escaped = true;
|
|
295
|
+
else if (ch === '"')
|
|
296
|
+
inString = false;
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
if (ch === '"')
|
|
300
|
+
inString = true;
|
|
301
|
+
else if (ch === "{" || ch === "[")
|
|
302
|
+
open(ch, i);
|
|
303
|
+
else if (ch === "}" || ch === "]")
|
|
304
|
+
close(ch, i);
|
|
305
|
+
}
|
|
306
|
+
return roots;
|
|
307
|
+
}
|
|
308
|
+
function fromSuccessLine(text, titleHint) {
|
|
309
|
+
const m = CREATED_LINE.exec(text);
|
|
310
|
+
if (!m)
|
|
311
|
+
return;
|
|
312
|
+
const id = Number(m[1]);
|
|
313
|
+
if (!Number.isInteger(id) || id <= 0)
|
|
314
|
+
return;
|
|
315
|
+
const title = titleFromCliSummary(text) || titleHint?.trim();
|
|
316
|
+
return title ? { id, title } : { id };
|
|
317
|
+
}
|
|
318
|
+
function titleFromCliSummary(text) {
|
|
319
|
+
const at = CREATED_LINE.exec(text);
|
|
320
|
+
if (!at)
|
|
321
|
+
return;
|
|
322
|
+
const rest = text.slice(at.index + at[0].length);
|
|
323
|
+
const m = /^\s*Title:\s*(.+)$/m.exec(rest);
|
|
324
|
+
const title = m?.[1]?.trim();
|
|
325
|
+
if (!title || title.length > 200)
|
|
326
|
+
return;
|
|
327
|
+
return title;
|
|
328
|
+
}
|
|
329
|
+
function isTaskCreateTool(name) {
|
|
330
|
+
return /(^|__)task_create$/.test(name);
|
|
331
|
+
}
|
|
332
|
+
|
|
140
333
|
// ../../../packages/cli/src/daemon/ndjson.ts
|
|
141
334
|
class LineSplitter {
|
|
142
335
|
tail = "";
|
|
@@ -169,6 +362,7 @@ class NdjsonAssembler {
|
|
|
169
362
|
toolCalls = 0;
|
|
170
363
|
sessionId;
|
|
171
364
|
tools = [];
|
|
365
|
+
createdTask;
|
|
172
366
|
pushChunk(chunk) {
|
|
173
367
|
this.tail += chunk;
|
|
174
368
|
let idx = this.tail.indexOf(`
|
|
@@ -209,6 +403,14 @@ class NdjsonAssembler {
|
|
|
209
403
|
if (typeof name === "string" && name) {
|
|
210
404
|
this.tools.push(name);
|
|
211
405
|
}
|
|
406
|
+
if (this.createdTask === undefined && typeof name === "string") {
|
|
407
|
+
const part = parsed.part;
|
|
408
|
+
const output = part?.state?.output;
|
|
409
|
+
const title = part?.state?.input?.["title"];
|
|
410
|
+
if (isTaskCreateTool(name) && typeof output === "string") {
|
|
411
|
+
this.createdTask = extractCreatedTask(output, typeof title === "string" ? title : undefined);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
212
414
|
return;
|
|
213
415
|
}
|
|
214
416
|
if (parsed.type === "error") {
|
|
@@ -228,7 +430,8 @@ class NdjsonAssembler {
|
|
|
228
430
|
error: this.error,
|
|
229
431
|
toolCalls: this.toolCalls,
|
|
230
432
|
sessionId: this.sessionId,
|
|
231
|
-
tools: this.tools
|
|
433
|
+
tools: this.tools,
|
|
434
|
+
createdTask: this.createdTask
|
|
232
435
|
};
|
|
233
436
|
}
|
|
234
437
|
}
|
|
@@ -279,10 +482,10 @@ class CodexStreamDecoder {
|
|
|
279
482
|
return;
|
|
280
483
|
}
|
|
281
484
|
if (ev.type === "item.started" || ev.type === "item.completed") {
|
|
282
|
-
this.consumeItem(ev.item);
|
|
485
|
+
this.consumeItem(ev.item, ev.type === "item.completed");
|
|
283
486
|
}
|
|
284
487
|
}
|
|
285
|
-
consumeItem(raw) {
|
|
488
|
+
consumeItem(raw, completed) {
|
|
286
489
|
if (typeof raw !== "object" || raw === null)
|
|
287
490
|
return;
|
|
288
491
|
const item = raw;
|
|
@@ -300,9 +503,12 @@ class CodexStreamDecoder {
|
|
|
300
503
|
}
|
|
301
504
|
if (item.type === CODEX_ITEM_TYPES.COMMAND_EXECUTION) {
|
|
302
505
|
const id = item.id;
|
|
303
|
-
if (typeof id === "string" && id && this.state.tools.includes(id))
|
|
304
|
-
|
|
305
|
-
|
|
506
|
+
if (typeof id === "string" && id && this.state.tools.includes(id)) {} else {
|
|
507
|
+
this.state.tools.push(typeof id === "string" ? id : `cmd-${this.state.tools.length}`);
|
|
508
|
+
}
|
|
509
|
+
if (completed && this.state.createdTask === undefined) {
|
|
510
|
+
this.state.createdTask = extractCreatedTask(item.aggregated_output);
|
|
511
|
+
}
|
|
306
512
|
}
|
|
307
513
|
}
|
|
308
514
|
toResult() {
|
|
@@ -313,6 +519,8 @@ class CodexStreamDecoder {
|
|
|
313
519
|
result.sessionId = this.state.sessionId;
|
|
314
520
|
if (this.state.tools.length > 0)
|
|
315
521
|
result.toolCalls = this.state.tools.length;
|
|
522
|
+
if (this.state.createdTask)
|
|
523
|
+
result.createdTask = this.state.createdTask;
|
|
316
524
|
return result;
|
|
317
525
|
}
|
|
318
526
|
}
|
|
@@ -417,6 +625,7 @@ function makeCodexRunner(opts = {}) {
|
|
|
417
625
|
text: "",
|
|
418
626
|
toolCalls: result.toolCalls,
|
|
419
627
|
tools: result.tools,
|
|
628
|
+
createdTask: result.createdTask,
|
|
420
629
|
error: `codex exited ${code}: ${(stderr || "no stderr").trim().slice(0, 1000)}`
|
|
421
630
|
};
|
|
422
631
|
}
|
|
@@ -434,13 +643,38 @@ var DEFAULT_PROFILE = "default";
|
|
|
434
643
|
var DEFAULT_AGENT = "roy";
|
|
435
644
|
var DEFAULT_EVENT_KEY = "im.message.receive_v1";
|
|
436
645
|
var DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
646
|
+
function findSubcommand(argv) {
|
|
647
|
+
for (let i = 0;i < argv.length; i++) {
|
|
648
|
+
const raw = argv[i];
|
|
649
|
+
if (raw.startsWith("-")) {
|
|
650
|
+
if (!raw.includes("=") && VALUE_FLAGS.has(raw))
|
|
651
|
+
i++;
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
return raw;
|
|
655
|
+
}
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
var VALUE_FLAGS = new Set([
|
|
659
|
+
"--profile",
|
|
660
|
+
"--agent",
|
|
661
|
+
"--event-key",
|
|
662
|
+
"--runtime",
|
|
663
|
+
"--command",
|
|
664
|
+
"--runtime-bin",
|
|
665
|
+
"--opencode-bin",
|
|
666
|
+
"--codex-model",
|
|
667
|
+
"--codex-sandbox",
|
|
668
|
+
"--max-concurrency",
|
|
669
|
+
"--timeout-ms"
|
|
670
|
+
]);
|
|
437
671
|
var SUBCOMMANDS = new Set(["serve", "status", "help", "version"]);
|
|
438
672
|
function parseArgs(argv) {
|
|
439
673
|
if (argv.includes("--help") || argv.includes("-h"))
|
|
440
674
|
return { command: "help" };
|
|
441
675
|
if (argv.includes("--version") || argv.includes("-v"))
|
|
442
676
|
return { command: "version" };
|
|
443
|
-
const head = argv
|
|
677
|
+
const head = findSubcommand(argv);
|
|
444
678
|
const command = head ?? "serve";
|
|
445
679
|
if (!SUBCOMMANDS.has(command)) {
|
|
446
680
|
return { command: "unknown", error: `unknown command "${command}"` };
|
|
@@ -523,6 +757,13 @@ function parseServe(argv) {
|
|
|
523
757
|
serve.runtime = v;
|
|
524
758
|
break;
|
|
525
759
|
}
|
|
760
|
+
case "--command": {
|
|
761
|
+
const v = take();
|
|
762
|
+
if (v instanceof Error)
|
|
763
|
+
return { command: "unknown", error: v.message };
|
|
764
|
+
serve.command = v;
|
|
765
|
+
break;
|
|
766
|
+
}
|
|
526
767
|
case "--runtime-bin": {
|
|
527
768
|
const v = take();
|
|
528
769
|
if (v instanceof Error)
|
|
@@ -626,6 +867,8 @@ function readValue(argv, flag) {
|
|
|
626
867
|
return;
|
|
627
868
|
}
|
|
628
869
|
function resolveRuntimeBin(options) {
|
|
870
|
+
if (options.command !== undefined)
|
|
871
|
+
return options.command;
|
|
629
872
|
if (options.runtimeBin !== undefined)
|
|
630
873
|
return options.runtimeBin;
|
|
631
874
|
if (options.runtime === "opencode" && options.opencodeBin !== "opencode") {
|
|
@@ -653,8 +896,11 @@ SERVE OPTIONS
|
|
|
653
896
|
--agent <name> agent to dispatch to (default: ${DEFAULT_AGENT})
|
|
654
897
|
--runtime <name> which harness runs the agent (default: ${DEFAULT_RUNTIME})
|
|
655
898
|
one of: ${RUNTIMES.join(" | ")}
|
|
656
|
-
--
|
|
657
|
-
|
|
899
|
+
--command <name|path> executable to spawn, whatever the dialect
|
|
900
|
+
is (default: the runtime's own binary).
|
|
901
|
+
e.g. --runtime claude --command claude-minimax
|
|
902
|
+
--runtime-bin <path> DEPRECATED alias for --command
|
|
903
|
+
--opencode-bin <path> DEPRECATED alias for --command
|
|
658
904
|
(only applies when --runtime opencode)
|
|
659
905
|
--codex-model <name> model for codex exec --model (default: codex config)
|
|
660
906
|
--codex-sandbox <mode> codex exec -s policy (default: read-only)
|
|
@@ -673,6 +919,12 @@ SERVE OPTIONS
|
|
|
673
919
|
never block the text reply.
|
|
674
920
|
|
|
675
921
|
NOTES
|
|
922
|
+
• --runtime vs --command: --runtime picks the *dialect* (which flags and
|
|
923
|
+
which stream decoder), --command picks the *executable* that speaks it.
|
|
924
|
+
So \`--runtime claude --command claude-minimax\` keeps every claude flag
|
|
925
|
+
(--print / --output-format stream-json / --agents / --resume <uuid>) and
|
|
926
|
+
merely spawns the wrapper instead of the bare binary. Use this whenever
|
|
927
|
+
the default binary is not the one that actually works on your machine.
|
|
676
928
|
• stdin is forced to EOF for the agent child (stdio[0]="ignore"). Without it
|
|
677
929
|
both \`opencode run\` and \`claude --print\` wait for EOF on a socket and the
|
|
678
930
|
run hangs forever.
|
|
@@ -826,6 +1078,24 @@ function buildDispatchPrompt(input) {
|
|
|
826
1078
|
"3. 需要落任务就用 `task_*` 工具(task_create / task_update / …),",
|
|
827
1079
|
" 这是你的主要职责;不要只在回答里“描述”你打算做什么。",
|
|
828
1080
|
"",
|
|
1081
|
+
"## 什么时候该建任务(Task #4433)",
|
|
1082
|
+
"",
|
|
1083
|
+
"任务由**你**决定建不建,守护进程不会替你建。判断标准:",
|
|
1084
|
+
"",
|
|
1085
|
+
"- **该建**:需要多步操作、要动文件/跑命令、要调研并产出结论、",
|
|
1086
|
+
" 耗时预计超过一两分钟、或用户明确要求「跟踪 / 建个任务 / 后续跟进」。",
|
|
1087
|
+
" → 用 `task_create` 建任务,**然后**再开始干活(先立任务,再动手)。",
|
|
1088
|
+
"- **不必建**:寒暄、谢谢、纯问答(「今天几号」「这个参数叫啥」)、",
|
|
1089
|
+
" 一两句话就能答完且不需要任何工具的问题。",
|
|
1090
|
+
" → 直接回答,不要为了「显得勤快」而建一个空任务。",
|
|
1091
|
+
"- **建完要更新**:动手过程中用 `task_update` 推进度 / 改 current_status,",
|
|
1092
|
+
" 干完用 `task_complete` 收尾。建了任务却从不更新,比不建更糟——",
|
|
1093
|
+
" 看板上会留下一个卡住的任务。",
|
|
1094
|
+
"",
|
|
1095
|
+
"⚠️ **卡片与任务一一对应**:只有你建了任务,用户才会收到一张进展卡片;",
|
|
1096
|
+
"没建任务就只有文字回复。所以**不要**为了「想要一张卡片」而去建任务,",
|
|
1097
|
+
"也不要建了任务又不用它——卡片上显示的就是你建的那个任务的真 id 和标题。",
|
|
1098
|
+
"",
|
|
829
1099
|
"## 环境事实(必须使用下面这些值,不要自己猜)",
|
|
830
1100
|
"",
|
|
831
1101
|
`- lark-cli profile:\`${profile}\`(飞书 openId 是 per-app 隔离的,换 profile 会失败)`,
|
|
@@ -904,6 +1174,7 @@ function createRoyAgentCardPort(options = {}) {
|
|
|
904
1174
|
return inFlight;
|
|
905
1175
|
};
|
|
906
1176
|
return {
|
|
1177
|
+
enabled: true,
|
|
907
1178
|
async start(input) {
|
|
908
1179
|
const n = await withTimeout("load", getNotifier(), opTimeoutMs);
|
|
909
1180
|
return withTimeout("start", n.startTask({
|
|
@@ -942,6 +1213,7 @@ function createRoyAgentCardPort(options = {}) {
|
|
|
942
1213
|
}
|
|
943
1214
|
function createNoopCardPort() {
|
|
944
1215
|
return {
|
|
1216
|
+
enabled: false,
|
|
945
1217
|
async start() {
|
|
946
1218
|
return { messageId: "", pinned: false };
|
|
947
1219
|
},
|
|
@@ -949,21 +1221,14 @@ function createNoopCardPort() {
|
|
|
949
1221
|
async finish() {}
|
|
950
1222
|
};
|
|
951
1223
|
}
|
|
952
|
-
function
|
|
953
|
-
const maxTitle = input.maxTitleChars ?? 60;
|
|
954
|
-
const normalized = input.text.replace(/\r\n/g, `
|
|
955
|
-
`).trim();
|
|
956
|
-
const lines = normalized.split(`
|
|
957
|
-
`).map((l) => l.trim()).filter(Boolean);
|
|
958
|
-
const first = lines[0] ?? "(非文本消息)";
|
|
959
|
-
const rest = lines.slice(1).join(`
|
|
960
|
-
`);
|
|
961
|
-
const title = first.length > maxTitle ? `${first.slice(0, maxTitle - 1)}…` : first;
|
|
1224
|
+
function buildCardMeta(input) {
|
|
962
1225
|
return {
|
|
963
|
-
id:
|
|
964
|
-
title
|
|
965
|
-
description:
|
|
966
|
-
|
|
1226
|
+
id: input.task.id,
|
|
1227
|
+
title: input.task.title ?? `Task #${input.task.id}`,
|
|
1228
|
+
description: input.description ?? `由 roy-task 派发,触发消息 ${input.messageId}`,
|
|
1229
|
+
type: "normal",
|
|
1230
|
+
priority: "high",
|
|
1231
|
+
currentStatus: "由 agent 处理中"
|
|
967
1232
|
};
|
|
968
1233
|
}
|
|
969
1234
|
var TOOL_LABELS = {
|
|
@@ -997,8 +1262,15 @@ function cardReport(handle) {
|
|
|
997
1262
|
out.cardMessageId = handle.messageId;
|
|
998
1263
|
if (handle.error)
|
|
999
1264
|
out.cardError = handle.error;
|
|
1265
|
+
if (handle.cardWantedButNoTask && !handle.messageId && !handle.error)
|
|
1266
|
+
out.cardExpected = true;
|
|
1267
|
+
if (handle.meta && typeof handle.meta.id === "number")
|
|
1268
|
+
out.taskId = handle.meta.id;
|
|
1000
1269
|
return out;
|
|
1001
1270
|
}
|
|
1271
|
+
function createdTaskReport(createdTask) {
|
|
1272
|
+
return createdTask ? { taskId: createdTask.id } : {};
|
|
1273
|
+
}
|
|
1002
1274
|
function errorMessage(err) {
|
|
1003
1275
|
return err instanceof Error ? err.message : String(err);
|
|
1004
1276
|
}
|
|
@@ -1093,13 +1365,18 @@ class Dispatcher {
|
|
|
1093
1365
|
return { status: "dry-run", plan };
|
|
1094
1366
|
}
|
|
1095
1367
|
const run = async () => {
|
|
1096
|
-
const cardPromise = this.openCard({ chatId, messageId, profile, raw });
|
|
1097
1368
|
const result = await this.deps.runAgent({
|
|
1098
1369
|
prompt: plan.prompt,
|
|
1099
1370
|
agent: plan.agent,
|
|
1100
1371
|
sessionId: plan.sessionId
|
|
1101
1372
|
});
|
|
1102
|
-
const card = await
|
|
1373
|
+
const card = await this.openCard({
|
|
1374
|
+
chatId,
|
|
1375
|
+
messageId,
|
|
1376
|
+
profile,
|
|
1377
|
+
createdTask: result.createdTask,
|
|
1378
|
+
requestText: extractUserText(raw)
|
|
1379
|
+
});
|
|
1103
1380
|
if (card.messageId) {
|
|
1104
1381
|
await this.patchCard(card, {
|
|
1105
1382
|
chatId,
|
|
@@ -1115,7 +1392,13 @@ class Dispatcher {
|
|
|
1115
1392
|
status: "failed",
|
|
1116
1393
|
finalStep: `agent 报错:${result.error}`
|
|
1117
1394
|
});
|
|
1118
|
-
return {
|
|
1395
|
+
return {
|
|
1396
|
+
status: "agent-error",
|
|
1397
|
+
plan,
|
|
1398
|
+
error: result.error,
|
|
1399
|
+
...createdTaskReport(result.createdTask),
|
|
1400
|
+
...cardReport(card)
|
|
1401
|
+
};
|
|
1119
1402
|
}
|
|
1120
1403
|
if (!result.text.trim()) {
|
|
1121
1404
|
await this.closeCard(card, {
|
|
@@ -1128,6 +1411,7 @@ class Dispatcher {
|
|
|
1128
1411
|
status: "no-output",
|
|
1129
1412
|
plan,
|
|
1130
1413
|
toolCalls: result.toolCalls ?? 0,
|
|
1414
|
+
...createdTaskReport(result.createdTask),
|
|
1131
1415
|
...cardReport(card)
|
|
1132
1416
|
};
|
|
1133
1417
|
}
|
|
@@ -1138,7 +1422,13 @@ class Dispatcher {
|
|
|
1138
1422
|
status: "completed",
|
|
1139
1423
|
finalStep: "--no-reply:agent 已完成,未发送回复"
|
|
1140
1424
|
});
|
|
1141
|
-
return {
|
|
1425
|
+
return {
|
|
1426
|
+
status: "no-reply",
|
|
1427
|
+
plan,
|
|
1428
|
+
text: result.text,
|
|
1429
|
+
...createdTaskReport(result.createdTask),
|
|
1430
|
+
...cardReport(card)
|
|
1431
|
+
};
|
|
1142
1432
|
}
|
|
1143
1433
|
const sent = await this.deps.reply({
|
|
1144
1434
|
messageId,
|
|
@@ -1159,6 +1449,7 @@ class Dispatcher {
|
|
|
1159
1449
|
plan,
|
|
1160
1450
|
error: sent.error ?? "unknown",
|
|
1161
1451
|
text: result.text,
|
|
1452
|
+
...createdTaskReport(result.createdTask),
|
|
1162
1453
|
...cardReport(card)
|
|
1163
1454
|
};
|
|
1164
1455
|
}
|
|
@@ -1173,6 +1464,7 @@ class Dispatcher {
|
|
|
1173
1464
|
plan,
|
|
1174
1465
|
replyMessageId: sent.messageId,
|
|
1175
1466
|
text: result.text,
|
|
1467
|
+
...createdTaskReport(result.createdTask),
|
|
1176
1468
|
...cardReport(card)
|
|
1177
1469
|
};
|
|
1178
1470
|
};
|
|
@@ -1182,23 +1474,20 @@ class Dispatcher {
|
|
|
1182
1474
|
const handle = { messageId: "" };
|
|
1183
1475
|
if (!this.deps.card)
|
|
1184
1476
|
return handle;
|
|
1477
|
+
if (!input.createdTask) {
|
|
1478
|
+
handle.cardWantedButNoTask = this.deps.card.enabled === true;
|
|
1479
|
+
return handle;
|
|
1480
|
+
}
|
|
1481
|
+
const meta = buildCardMeta({
|
|
1482
|
+
task: input.createdTask,
|
|
1483
|
+
messageId: input.messageId,
|
|
1484
|
+
...input.requestText ? { description: input.requestText } : {}
|
|
1485
|
+
});
|
|
1185
1486
|
try {
|
|
1186
|
-
const identity = buildCardIdentity({
|
|
1187
|
-
messageId: input.messageId,
|
|
1188
|
-
text: extractUserText(input.raw)
|
|
1189
|
-
});
|
|
1190
1487
|
const started = await this.deps.card.start({
|
|
1191
1488
|
chatId: input.chatId,
|
|
1192
1489
|
profile: input.profile,
|
|
1193
|
-
meta
|
|
1194
|
-
id: identity.id,
|
|
1195
|
-
title: identity.title,
|
|
1196
|
-
description: identity.description,
|
|
1197
|
-
goals: identity.goals,
|
|
1198
|
-
type: "normal",
|
|
1199
|
-
priority: "high",
|
|
1200
|
-
currentStatus: "已收到消息,正在处理"
|
|
1201
|
-
},
|
|
1490
|
+
meta,
|
|
1202
1491
|
milestones: [
|
|
1203
1492
|
{
|
|
1204
1493
|
title: "收到消息",
|
|
@@ -1209,6 +1498,7 @@ class Dispatcher {
|
|
|
1209
1498
|
});
|
|
1210
1499
|
handle.messageId = started.messageId;
|
|
1211
1500
|
handle.pinned = started.pinned;
|
|
1501
|
+
handle.meta = meta;
|
|
1212
1502
|
} catch (err) {
|
|
1213
1503
|
handle.error = errorMessage(err);
|
|
1214
1504
|
}
|
|
@@ -1226,6 +1516,7 @@ class Dispatcher {
|
|
|
1226
1516
|
chatId: input.chatId,
|
|
1227
1517
|
profile: input.profile,
|
|
1228
1518
|
status: input.status,
|
|
1519
|
+
...handle.meta ? { meta: handle.meta } : {},
|
|
1229
1520
|
processSteps: tools.map(describeToolUse)
|
|
1230
1521
|
});
|
|
1231
1522
|
} catch (err) {
|
|
@@ -1242,7 +1533,8 @@ class Dispatcher {
|
|
|
1242
1533
|
profile: input.profile,
|
|
1243
1534
|
status: input.status,
|
|
1244
1535
|
finalStep: input.finalStep,
|
|
1245
|
-
progress: input.status === "completed" ? 100 : undefined
|
|
1536
|
+
progress: input.status === "completed" ? 100 : undefined,
|
|
1537
|
+
...handle.meta ? { meta: handle.meta } : {}
|
|
1246
1538
|
});
|
|
1247
1539
|
} catch (err) {
|
|
1248
1540
|
handle.error ??= errorMessage(err);
|
|
@@ -1309,6 +1601,7 @@ function createEventListener(config) {
|
|
|
1309
1601
|
|
|
1310
1602
|
// ../../../packages/cli/src/daemon/runners/claude.ts
|
|
1311
1603
|
import { createHash as createHash2 } from "node:crypto";
|
|
1604
|
+
import { appendFileSync } from "node:fs";
|
|
1312
1605
|
|
|
1313
1606
|
// ../../../packages/cli/src/daemon/runners/claude-agents.ts
|
|
1314
1607
|
var CLAUDE_ROY_AGENT_NAME = "roy";
|
|
@@ -1459,9 +1752,45 @@ function createClaudeSessionRegistry() {
|
|
|
1459
1752
|
}
|
|
1460
1753
|
|
|
1461
1754
|
// ../../../packages/cli/src/daemon/runners/claude-stream.ts
|
|
1755
|
+
function errorDetail(result) {
|
|
1756
|
+
if (typeof result.result === "string" && result.result.trim() !== "") {
|
|
1757
|
+
return result.result.trim();
|
|
1758
|
+
}
|
|
1759
|
+
if (Array.isArray(result.errors)) {
|
|
1760
|
+
const parts = result.errors.map((e) => typeof e === "string" ? e.trim() : "").filter((e) => e !== "");
|
|
1761
|
+
if (parts.length > 0)
|
|
1762
|
+
return parts.join("; ");
|
|
1763
|
+
}
|
|
1764
|
+
return result.subtype === undefined ? "claude reported is_error" : `claude reported ${result.subtype}`;
|
|
1765
|
+
}
|
|
1766
|
+
function flattenToolResult(content) {
|
|
1767
|
+
if (typeof content === "string")
|
|
1768
|
+
return content;
|
|
1769
|
+
if (!Array.isArray(content))
|
|
1770
|
+
return "";
|
|
1771
|
+
const parts = [];
|
|
1772
|
+
for (const block of content) {
|
|
1773
|
+
if (typeof block === "string") {
|
|
1774
|
+
parts.push(block);
|
|
1775
|
+
continue;
|
|
1776
|
+
}
|
|
1777
|
+
if (typeof block === "object" && block !== null) {
|
|
1778
|
+
const t = block.text;
|
|
1779
|
+
if (typeof t === "string")
|
|
1780
|
+
parts.push(t);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
return parts.join(`
|
|
1784
|
+
`);
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1462
1787
|
class ClaudeStreamDecoder {
|
|
1463
1788
|
lines = new LineSplitter;
|
|
1464
|
-
state = {
|
|
1789
|
+
state = {
|
|
1790
|
+
assistantText: [],
|
|
1791
|
+
tools: [],
|
|
1792
|
+
pendingCreates: new Map
|
|
1793
|
+
};
|
|
1465
1794
|
pushChunk(chunk) {
|
|
1466
1795
|
for (const line of this.lines.pushChunk(chunk))
|
|
1467
1796
|
this.consume(line);
|
|
@@ -1494,10 +1823,38 @@ class ClaudeStreamDecoder {
|
|
|
1494
1823
|
this.consumeAssistant(ev);
|
|
1495
1824
|
return;
|
|
1496
1825
|
}
|
|
1826
|
+
if (ev.type === "user") {
|
|
1827
|
+
this.consumeUser(ev);
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1497
1830
|
if (ev.type === "result") {
|
|
1498
1831
|
this.state.result = ev;
|
|
1499
1832
|
}
|
|
1500
1833
|
}
|
|
1834
|
+
consumeUser(ev) {
|
|
1835
|
+
const message = ev.message;
|
|
1836
|
+
const content = message?.content;
|
|
1837
|
+
if (!Array.isArray(content))
|
|
1838
|
+
return;
|
|
1839
|
+
for (const block of content) {
|
|
1840
|
+
if (typeof block !== "object" || block === null)
|
|
1841
|
+
continue;
|
|
1842
|
+
const b = block;
|
|
1843
|
+
if (b.type !== "tool_result")
|
|
1844
|
+
continue;
|
|
1845
|
+
const id = typeof b.tool_use_id === "string" ? b.tool_use_id : undefined;
|
|
1846
|
+
const pending = id ? this.state.pendingCreates.get(id) : undefined;
|
|
1847
|
+
const text = flattenToolResult(b.content);
|
|
1848
|
+
if (this.state.createdTask !== undefined)
|
|
1849
|
+
continue;
|
|
1850
|
+
if (pending) {
|
|
1851
|
+
this.state.pendingCreates.delete(id);
|
|
1852
|
+
this.state.createdTask = extractCreatedTask(text, pending.titleHint);
|
|
1853
|
+
continue;
|
|
1854
|
+
}
|
|
1855
|
+
this.state.createdTask = extractCreatedTask(text);
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1501
1858
|
consumeAssistant(ev) {
|
|
1502
1859
|
const message = ev.message;
|
|
1503
1860
|
const content = message?.content;
|
|
@@ -1510,8 +1867,17 @@ class ClaudeStreamDecoder {
|
|
|
1510
1867
|
if (b.type === "text" && typeof b.text === "string") {
|
|
1511
1868
|
this.state.assistantText.push(b.text);
|
|
1512
1869
|
} else if (b.type === "tool_use") {
|
|
1513
|
-
if (typeof b.name === "string")
|
|
1870
|
+
if (typeof b.name === "string") {
|
|
1514
1871
|
this.state.tools.push(b.name);
|
|
1872
|
+
if (isTaskCreateTool(b.name) && typeof b.id === "string") {
|
|
1873
|
+
const input = b.input;
|
|
1874
|
+
const title = input?.["title"];
|
|
1875
|
+
this.state.pendingCreates.set(b.id, {
|
|
1876
|
+
tool: b.name,
|
|
1877
|
+
titleHint: typeof title === "string" ? title : undefined
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1515
1881
|
}
|
|
1516
1882
|
}
|
|
1517
1883
|
}
|
|
@@ -1519,15 +1885,23 @@ class ClaudeStreamDecoder {
|
|
|
1519
1885
|
const { result } = this.state;
|
|
1520
1886
|
const toolCalls = this.state.tools.length > 0 ? this.state.tools.length : undefined;
|
|
1521
1887
|
const tools = this.state.tools.length > 0 ? [...this.state.tools] : undefined;
|
|
1888
|
+
const createdTask = this.state.createdTask;
|
|
1522
1889
|
if (result?.is_error) {
|
|
1523
|
-
const detail =
|
|
1524
|
-
return {
|
|
1890
|
+
const detail = errorDetail(result);
|
|
1891
|
+
return {
|
|
1892
|
+
text: "",
|
|
1893
|
+
sessionId: this.state.sessionId,
|
|
1894
|
+
toolCalls,
|
|
1895
|
+
tools,
|
|
1896
|
+
createdTask,
|
|
1897
|
+
error: detail.slice(0, 1000)
|
|
1898
|
+
};
|
|
1525
1899
|
}
|
|
1526
1900
|
if (typeof result?.result === "string" && result.result.trim() !== "") {
|
|
1527
|
-
return { text: result.result.trim(), sessionId: this.state.sessionId, toolCalls, tools };
|
|
1901
|
+
return { text: result.result.trim(), sessionId: this.state.sessionId, toolCalls, tools, createdTask };
|
|
1528
1902
|
}
|
|
1529
1903
|
const fallback = this.state.assistantText.join("").trim();
|
|
1530
|
-
return { text: fallback, sessionId: this.state.sessionId, toolCalls, tools };
|
|
1904
|
+
return { text: fallback, sessionId: this.state.sessionId, toolCalls, tools, createdTask };
|
|
1531
1905
|
}
|
|
1532
1906
|
}
|
|
1533
1907
|
|
|
@@ -1588,7 +1962,14 @@ function makeClaudeRunner(opts = {}) {
|
|
|
1588
1962
|
stdin: CLAUDE_STDIO[0],
|
|
1589
1963
|
env: { ...process.env, NO_COLOR: "1" },
|
|
1590
1964
|
timeoutMs,
|
|
1591
|
-
onStdout: (chunk) =>
|
|
1965
|
+
onStdout: (chunk) => {
|
|
1966
|
+
decoder.pushChunk(chunk);
|
|
1967
|
+
if (process.env["ROY_TASK_DUMP_STREAM"]) {
|
|
1968
|
+
try {
|
|
1969
|
+
appendFileSync(process.env["ROY_TASK_DUMP_STREAM"], chunk);
|
|
1970
|
+
} catch {}
|
|
1971
|
+
}
|
|
1972
|
+
},
|
|
1592
1973
|
onStderr: (chunk) => {
|
|
1593
1974
|
if (stderr.length < 64 * 1024)
|
|
1594
1975
|
stderr += chunk;
|
|
@@ -1607,29 +1988,37 @@ function makeClaudeRunner(opts = {}) {
|
|
|
1607
1988
|
return { text: "", error: errMsg2(err) };
|
|
1608
1989
|
}
|
|
1609
1990
|
const result = decoder.finish();
|
|
1610
|
-
|
|
1611
|
-
|
|
1991
|
+
const stderrText = stderr.trim();
|
|
1992
|
+
const combined = result.error ? stderrText && !result.error.includes(stderrText) ? `${result.error} | ${stderrText}` : result.error : undefined;
|
|
1993
|
+
const effective = combined ? { ...result, error: combined.slice(0, 1000) } : result;
|
|
1994
|
+
if (input.sessionId && effective.sessionId) {
|
|
1995
|
+
sessions.set(input.sessionId, effective.sessionId);
|
|
1612
1996
|
}
|
|
1613
1997
|
if (code === 124) {
|
|
1614
|
-
return { ...
|
|
1998
|
+
return { ...effective, error: `claude timed out after ${timeoutMs}ms` };
|
|
1615
1999
|
}
|
|
1616
|
-
if (
|
|
1617
|
-
if (input.sessionId &&
|
|
2000
|
+
if (effective.error) {
|
|
2001
|
+
if (input.sessionId && STALE_SESSION_RE.test(effective.error)) {
|
|
1618
2002
|
sessions.delete(input.sessionId);
|
|
1619
2003
|
}
|
|
1620
|
-
return
|
|
2004
|
+
return effective;
|
|
1621
2005
|
}
|
|
1622
|
-
if (code !== 0 && !
|
|
2006
|
+
if (code !== 0 && !effective.text) {
|
|
2007
|
+
const error = `claude exited ${code}: ${(stderr || "no stderr").trim().slice(0, 1000)}`;
|
|
2008
|
+
if (input.sessionId && STALE_SESSION_RE.test(error)) {
|
|
2009
|
+
sessions.delete(input.sessionId);
|
|
2010
|
+
}
|
|
1623
2011
|
return {
|
|
1624
2012
|
text: "",
|
|
1625
|
-
toolCalls:
|
|
1626
|
-
tools:
|
|
1627
|
-
error
|
|
2013
|
+
toolCalls: effective.toolCalls,
|
|
2014
|
+
tools: effective.tools,
|
|
2015
|
+
error
|
|
1628
2016
|
};
|
|
1629
2017
|
}
|
|
1630
|
-
return
|
|
2018
|
+
return effective;
|
|
1631
2019
|
};
|
|
1632
2020
|
}
|
|
2021
|
+
var STALE_SESSION_RE = /No conversation found|not a UUID|session title/i;
|
|
1633
2022
|
function errMsg2(err) {
|
|
1634
2023
|
if (err instanceof Error)
|
|
1635
2024
|
return err.message;
|
|
@@ -1680,7 +2069,8 @@ function makeOpencodeRunner(opts = {}) {
|
|
|
1680
2069
|
error: `opencode timed out after ${timeoutMs}ms`,
|
|
1681
2070
|
sessionId: result.sessionId,
|
|
1682
2071
|
toolCalls: result.toolCalls,
|
|
1683
|
-
tools: result.tools
|
|
2072
|
+
tools: result.tools,
|
|
2073
|
+
createdTask: result.createdTask
|
|
1684
2074
|
};
|
|
1685
2075
|
}
|
|
1686
2076
|
if (result.error) {
|
|
@@ -1689,7 +2079,8 @@ function makeOpencodeRunner(opts = {}) {
|
|
|
1689
2079
|
error: result.error,
|
|
1690
2080
|
sessionId: result.sessionId,
|
|
1691
2081
|
toolCalls: result.toolCalls,
|
|
1692
|
-
tools: result.tools
|
|
2082
|
+
tools: result.tools,
|
|
2083
|
+
createdTask: result.createdTask
|
|
1693
2084
|
};
|
|
1694
2085
|
}
|
|
1695
2086
|
if (code !== 0 && !result.text) {
|
|
@@ -1697,14 +2088,16 @@ function makeOpencodeRunner(opts = {}) {
|
|
|
1697
2088
|
text: "",
|
|
1698
2089
|
error: `opencode exited ${code}: ${(stderr || "no stderr").trim().slice(0, 1000)}`,
|
|
1699
2090
|
toolCalls: result.toolCalls,
|
|
1700
|
-
tools: result.tools
|
|
2091
|
+
tools: result.tools,
|
|
2092
|
+
createdTask: result.createdTask
|
|
1701
2093
|
};
|
|
1702
2094
|
}
|
|
1703
2095
|
return {
|
|
1704
2096
|
text: result.text,
|
|
1705
2097
|
sessionId: result.sessionId,
|
|
1706
2098
|
toolCalls: result.toolCalls,
|
|
1707
|
-
tools: result.tools
|
|
2099
|
+
tools: result.tools,
|
|
2100
|
+
createdTask: result.createdTask
|
|
1708
2101
|
};
|
|
1709
2102
|
};
|
|
1710
2103
|
}
|
|
@@ -1916,7 +2309,7 @@ function formatBanner(options, commands, maxConcurrency) {
|
|
|
1916
2309
|
` profile : ${options.profile}`,
|
|
1917
2310
|
` agent : ${options.agent}`,
|
|
1918
2311
|
` runtime : ${options.runtime}`,
|
|
1919
|
-
|
|
2312
|
+
" command : " + (resolveRuntimeBin(options) ?? "(default: " + options.runtime + ")"),
|
|
1920
2313
|
...options.runtime === "codex" ? [
|
|
1921
2314
|
` codex model : ${options.codexModel ?? "(codex config)"}`,
|
|
1922
2315
|
` codex sandbox : ${options.codexSandbox ?? "read-only"}`
|
|
@@ -1935,29 +2328,32 @@ function formatBanner(options, commands, maxConcurrency) {
|
|
|
1935
2328
|
`);
|
|
1936
2329
|
}
|
|
1937
2330
|
function cardSuffix(result) {
|
|
1938
|
-
if (
|
|
1939
|
-
return "";
|
|
1940
|
-
if (result.cardError)
|
|
2331
|
+
if ("cardError" in result && result.cardError)
|
|
1941
2332
|
return ` card=FAILED(${result.cardError})`;
|
|
1942
|
-
|
|
2333
|
+
if ("cardMessageId" in result && result.cardMessageId)
|
|
2334
|
+
return ` card=${result.cardMessageId}`;
|
|
2335
|
+
return result.cardExpected ? " card=none(no task created)" : "";
|
|
2336
|
+
}
|
|
2337
|
+
function taskSuffix(result) {
|
|
2338
|
+
return result.taskId === undefined ? "" : ` task=${result.taskId}`;
|
|
1943
2339
|
}
|
|
1944
2340
|
function formatResult(label, result) {
|
|
1945
2341
|
const card = cardSuffix(result);
|
|
1946
2342
|
switch (result.status) {
|
|
1947
2343
|
case "dispatched":
|
|
1948
|
-
return `[roy-task] ${label} dispatched chat=${result.plan.chatId} session=${result.plan.sessionId} ` + `reply=${result.replyMessageId ?? "(no id)"} chars=${result.text.length}${card}`;
|
|
2344
|
+
return `[roy-task] ${label} dispatched chat=${result.plan.chatId} session=${result.plan.sessionId} ` + `reply=${result.replyMessageId ?? "(no id)"} chars=${result.text.length}` + ` task=${result.taskId ?? "(none)"}${card}`;
|
|
1949
2345
|
case "dry-run":
|
|
1950
2346
|
return `[roy-task] ${label} DRY-RUN would run agent=${result.plan.agent} ` + `session=${result.plan.sessionId} chat=${result.plan.chatId} prompt=${result.plan.prompt.length}chars`;
|
|
1951
2347
|
case "duplicate":
|
|
1952
2348
|
return `[roy-task] ${label} duplicate dropped key=${result.key ?? "(unknown)"}`;
|
|
1953
2349
|
case "no-output":
|
|
1954
|
-
return `[roy-task] ${label} no-output (agent produced no text; not replying) ` + `toolCalls=${result.toolCalls}${card}`;
|
|
2350
|
+
return `[roy-task] ${label} no-output (agent produced no text; not replying) ` + `toolCalls=${result.toolCalls}${taskSuffix(result)}${card}`;
|
|
1955
2351
|
case "no-reply":
|
|
1956
|
-
return `[roy-task] ${label} no-reply (reply disabled) chars=${result.text.length}${card}`;
|
|
2352
|
+
return `[roy-task] ${label} no-reply (reply disabled) chars=${result.text.length}${taskSuffix(result)}${card}`;
|
|
1957
2353
|
case "agent-error":
|
|
1958
|
-
return `[roy-task] ${label} agent-error: ${result.error}${card}`;
|
|
2354
|
+
return `[roy-task] ${label} agent-error: ${result.error}${taskSuffix(result)}${card}`;
|
|
1959
2355
|
case "reply-failed":
|
|
1960
|
-
return `[roy-task] ${label} reply-failed: ${result.error}${card}`;
|
|
2356
|
+
return `[roy-task] ${label} reply-failed: ${result.error}${taskSuffix(result)}${card}`;
|
|
1961
2357
|
case "no-target":
|
|
1962
2358
|
return `[roy-task] ${label} skipped: ${result.reason}`;
|
|
1963
2359
|
}
|
|
@@ -2087,7 +2483,7 @@ function formatStatus(report) {
|
|
|
2087
2483
|
}
|
|
2088
2484
|
|
|
2089
2485
|
// ../../../packages/cli/src/main.ts
|
|
2090
|
-
var VERSION = "0.
|
|
2486
|
+
var VERSION = "0.6.1";
|
|
2091
2487
|
async function main(argv) {
|
|
2092
2488
|
const parsed = parseArgs(argv);
|
|
2093
2489
|
switch (parsed.command) {
|