@love-moon/conductor-cli 0.7.6 → 0.8.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/CHANGELOG.md +42 -0
- package/bin/conductor-task.js +124 -0
- package/bin/conductor.js +3 -2
- package/package.json +5 -5
- package/src/daemon.js +1126 -64
- package/src/entity-helpers.js +27 -2
- package/src/handoff-log-mask.js +43 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,47 @@
|
|
|
1
1
|
# @love-moon/conductor-cli
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 959dd1d: Add project-configured worker and reviewer task groups, task-group discovery in
|
|
8
|
+
the SDK and `conductor task group`, and a lightweight daemon protocol for
|
|
9
|
+
refreshing the project agent registry.
|
|
10
|
+
- fe76139: Add `conductor task create` for creating app tasks with title, prompt, backend,
|
|
11
|
+
project resolution, and optional parent task-card grouping. App tasks now
|
|
12
|
+
require an online compatible daemon, and grouping results are exposed to
|
|
13
|
+
callers so partial success is visible without retrying task creation.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [959dd1d]
|
|
18
|
+
- Updated dependencies [fe76139]
|
|
19
|
+
- @love-moon/conductor-sdk@0.8.0
|
|
20
|
+
- @love-moon/ai-sdk@0.8.0
|
|
21
|
+
|
|
22
|
+
## 0.7.7
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- 400f3a7: Report a terminal task status when a stop request finds no active process, so a
|
|
27
|
+
task whose Fire already died converges instead of sitting in `killing` forever.
|
|
28
|
+
|
|
29
|
+
Drop queued terminal status events before an in-place restart reuses a working
|
|
30
|
+
directory. The durable upstream outbox lives inside that directory, so an
|
|
31
|
+
undelivered `KILLED` from the previous run was flushed on startup and killed the
|
|
32
|
+
task that had just finished resuming.
|
|
33
|
+
|
|
34
|
+
- 67498dc: Report a Fire that dies inside its tmux session instead of leaving the task
|
|
35
|
+
hanging. In tmux mode the daemon's child is the short-lived `tmux new-session`
|
|
36
|
+
client, not the Fire, so an abnormal death (crash, OOM, SIGKILL) went unreported
|
|
37
|
+
and the task sat at `running` until reconcile relabelled it as a user stop. The
|
|
38
|
+
Fire now records its own exit code into its log under a per-launch nonce, and the
|
|
39
|
+
liveness reaper classifies the death from that marker and publishes a terminal
|
|
40
|
+
status with the real cause.
|
|
41
|
+
- Updated dependencies [400f3a7]
|
|
42
|
+
- @love-moon/conductor-sdk@0.7.7
|
|
43
|
+
- @love-moon/ai-sdk@0.7.7
|
|
44
|
+
|
|
3
45
|
## 0.7.6
|
|
4
46
|
|
|
5
47
|
### Patch Changes
|
package/bin/conductor-task.js
CHANGED
|
@@ -5,7 +5,10 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Subcommands:
|
|
7
7
|
* list [--project ...] [--issue <id>] [--status ...]
|
|
8
|
+
* create --title <title> [--prompt <prompt>] [--backend <backend>]
|
|
9
|
+
* [--parent-task-id <id>] [--project ...]
|
|
8
10
|
* show <id>
|
|
11
|
+
* group [<id>]
|
|
9
12
|
* send <id> [<message>] [--stdin] [--from-file FILE] [--metadata-json '{...}']
|
|
10
13
|
* insert <id> [<message>] [--stdin] [--from-file FILE] [--target-reply-to <msg-id>]
|
|
11
14
|
* messages <id> [--limit N] [--before <msg-id>]
|
|
@@ -63,6 +66,7 @@ function taskAsObject(task) {
|
|
|
63
66
|
sessionId: task.sessionId,
|
|
64
67
|
createdAt: task.createdAt,
|
|
65
68
|
updatedAt: task.updatedAt,
|
|
69
|
+
grouping: task.grouping ?? undefined,
|
|
66
70
|
};
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -243,6 +247,54 @@ async function handleList(argv, deps) {
|
|
|
243
247
|
return EXIT.OK;
|
|
244
248
|
}
|
|
245
249
|
|
|
250
|
+
async function handleCreate(argv, deps) {
|
|
251
|
+
const apis = await buildApis(deps);
|
|
252
|
+
const project = await resolveProject(apis, {
|
|
253
|
+
env: deps.env,
|
|
254
|
+
cwd: deps.cwd,
|
|
255
|
+
project: argv.project,
|
|
256
|
+
});
|
|
257
|
+
const title = String(argv.title ?? "").trim();
|
|
258
|
+
if (!title) {
|
|
259
|
+
const err = new Error("--title must not be empty");
|
|
260
|
+
err.code = "ARGS";
|
|
261
|
+
throw err;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const body = {
|
|
265
|
+
projectId: project.id,
|
|
266
|
+
title,
|
|
267
|
+
taskType: "ai_task",
|
|
268
|
+
...(argv.prompt !== undefined ? { initialContent: String(argv.prompt) } : {}),
|
|
269
|
+
...(argv.backend ? { backendType: String(argv.backend) } : {}),
|
|
270
|
+
...(argv.parentTaskId ? { parentTaskId: String(argv.parentTaskId) } : {}),
|
|
271
|
+
metadata: buildAuditMetadata(deps.env),
|
|
272
|
+
};
|
|
273
|
+
if (argv.dryRun) {
|
|
274
|
+
emitDryRun(
|
|
275
|
+
deps.stdout,
|
|
276
|
+
argv.json,
|
|
277
|
+
makeDryRunPayload("POST", `${buildBaseUrl(apis.config)}/api/tasks`, body),
|
|
278
|
+
);
|
|
279
|
+
return EXIT.OK;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const created = await apis.tasks.createTask(body);
|
|
283
|
+
const obj = taskAsObject(created);
|
|
284
|
+
if (argv.json) {
|
|
285
|
+
printJson(deps.stdout, obj);
|
|
286
|
+
return EXIT.OK;
|
|
287
|
+
}
|
|
288
|
+
printPretty(deps.stdout, `Created app task ${obj.id}: ${obj.title}`);
|
|
289
|
+
if (obj.grouping?.grouped === false) {
|
|
290
|
+
printPretty(
|
|
291
|
+
deps.stderr,
|
|
292
|
+
`Warning: ${obj.grouping.warning || `task was not grouped with ${obj.grouping.parentTaskId}`}. The task itself was created successfully.`,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
return EXIT.OK;
|
|
296
|
+
}
|
|
297
|
+
|
|
246
298
|
async function handleShow(argv, deps) {
|
|
247
299
|
const apis = await buildApis(deps);
|
|
248
300
|
const task = await apis.tasks.getTask(argv.id);
|
|
@@ -267,6 +319,45 @@ async function handleShow(argv, deps) {
|
|
|
267
319
|
return EXIT.OK;
|
|
268
320
|
}
|
|
269
321
|
|
|
322
|
+
async function handleGroup(argv, deps) {
|
|
323
|
+
const apis = await buildApis(deps);
|
|
324
|
+
const taskId =
|
|
325
|
+
(argv.id && String(argv.id).trim()) ||
|
|
326
|
+
(deps.env.CONDUCTOR_TASK_ID && String(deps.env.CONDUCTOR_TASK_ID).trim());
|
|
327
|
+
if (!taskId) {
|
|
328
|
+
const err = new Error(
|
|
329
|
+
"No task id: pass <id> or run inside a task (CONDUCTOR_TASK_ID)",
|
|
330
|
+
);
|
|
331
|
+
err.statusCode = 400;
|
|
332
|
+
throw err;
|
|
333
|
+
}
|
|
334
|
+
const group = await apis.tasks.getTaskGroup(taskId);
|
|
335
|
+
if (argv.json) {
|
|
336
|
+
printJson(deps.stdout, group);
|
|
337
|
+
return EXIT.OK;
|
|
338
|
+
}
|
|
339
|
+
if (!group.groupId) {
|
|
340
|
+
printPretty(deps.stdout, "(task is not in a group)");
|
|
341
|
+
return EXIT.OK;
|
|
342
|
+
}
|
|
343
|
+
printPretty(deps.stdout, `group ${group.groupId}`);
|
|
344
|
+
printPretty(
|
|
345
|
+
deps.stdout,
|
|
346
|
+
`${pad("ROLE", 10)} ${pad("TASK ID", 24)} ${pad("AGENT", 20)} STATUS`,
|
|
347
|
+
);
|
|
348
|
+
for (const member of group.members) {
|
|
349
|
+
const selfMark = member.isSelf ? " (you)" : "";
|
|
350
|
+
printPretty(
|
|
351
|
+
deps.stdout,
|
|
352
|
+
`${pad(member.role || "?", 10)} ${pad(member.taskId, 24)} ${pad(
|
|
353
|
+
member.agent || "-",
|
|
354
|
+
20,
|
|
355
|
+
)} ${member.status || ""}${selfMark}`,
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
return EXIT.OK;
|
|
359
|
+
}
|
|
360
|
+
|
|
270
361
|
async function handleSend(argv, deps) {
|
|
271
362
|
const apis = await buildApis(deps);
|
|
272
363
|
const content = readMessageInput({
|
|
@@ -485,6 +576,31 @@ export async function main(argvInput = hideBin(process.argv), deps = {}) {
|
|
|
485
576
|
exitCode = await handleList(argv, { ...handlerDeps, configFile: argv.configFile });
|
|
486
577
|
},
|
|
487
578
|
)
|
|
579
|
+
.command(
|
|
580
|
+
"create",
|
|
581
|
+
"Create a new app task through the frontend task pipeline",
|
|
582
|
+
(cmd) => cmd
|
|
583
|
+
.option("title", {
|
|
584
|
+
type: "string",
|
|
585
|
+
demandOption: true,
|
|
586
|
+
describe: "Task title",
|
|
587
|
+
})
|
|
588
|
+
.option("prompt", {
|
|
589
|
+
type: "string",
|
|
590
|
+
describe: "Initial user prompt",
|
|
591
|
+
})
|
|
592
|
+
.option("backend", {
|
|
593
|
+
type: "string",
|
|
594
|
+
describe: "AI backend type, for example codex or claude",
|
|
595
|
+
})
|
|
596
|
+
.option("parent-task-id", {
|
|
597
|
+
type: "string",
|
|
598
|
+
describe: "Display the new task in the same task-card group as this task",
|
|
599
|
+
}),
|
|
600
|
+
async (argv) => {
|
|
601
|
+
exitCode = await handleCreate(argv, { ...handlerDeps, configFile: argv.configFile });
|
|
602
|
+
},
|
|
603
|
+
)
|
|
488
604
|
.command(
|
|
489
605
|
"show <id>",
|
|
490
606
|
"Show one task's detail",
|
|
@@ -493,6 +609,14 @@ export async function main(argvInput = hideBin(process.argv), deps = {}) {
|
|
|
493
609
|
exitCode = await handleShow(argv, { ...handlerDeps, configFile: argv.configFile });
|
|
494
610
|
},
|
|
495
611
|
)
|
|
612
|
+
.command(
|
|
613
|
+
"group [id]",
|
|
614
|
+
"Show the multi-agent group a task belongs to (defaults to $CONDUCTOR_TASK_ID)",
|
|
615
|
+
(cmd) => cmd.positional("id", { type: "string" }),
|
|
616
|
+
async (argv) => {
|
|
617
|
+
exitCode = await handleGroup(argv, { ...handlerDeps, configFile: argv.configFile });
|
|
618
|
+
},
|
|
619
|
+
)
|
|
496
620
|
.command(
|
|
497
621
|
"send <id> [message]",
|
|
498
622
|
"Send a user message into a running task",
|
package/bin/conductor.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* serve-ai - Start an OpenAI-compatible local AI server
|
|
15
15
|
* project - Manage Conductor projects (list/show/create/...)
|
|
16
16
|
* issue - Manage issues (list/show/create/update/start/done)
|
|
17
|
-
* task - Manage tasks (list/show/send/messages/schedule)
|
|
17
|
+
* task - Manage tasks (create/list/show/send/messages/schedule)
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -134,7 +134,7 @@ Subcommands:
|
|
|
134
134
|
serve-ai Start an OpenAI-compatible local AI server
|
|
135
135
|
project Manage Conductor projects (list/show/create/...)
|
|
136
136
|
issue Manage issues (list/show/create/update/start/done)
|
|
137
|
-
task Manage tasks (list/show/send/messages/schedule)
|
|
137
|
+
task Manage tasks (create/list/show/send/messages/schedule)
|
|
138
138
|
|
|
139
139
|
Options:
|
|
140
140
|
-h, --help Show this help message
|
|
@@ -156,6 +156,7 @@ Examples:
|
|
|
156
156
|
conductor update
|
|
157
157
|
conductor project list
|
|
158
158
|
conductor issue create --title "Refactor module" --priority P2
|
|
159
|
+
conductor task create --title "Refactor module" --prompt "Extract the parser" --backend codex
|
|
159
160
|
conductor task send <task-id> "please add a unit test"
|
|
160
161
|
conductor task schedule create <task-id> "follow up" --delay 10m
|
|
161
162
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@love-moon/conductor-cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"gitCommitId": "
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"gitCommitId": "04d4f62",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/lovemoon-ai/conductor.git"
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"test": "node --test test/*.test.js"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@love-moon/ai-sdk": "0.
|
|
28
|
-
"@love-moon/conductor-sdk": "0.
|
|
27
|
+
"@love-moon/ai-sdk": "0.8.0",
|
|
28
|
+
"@love-moon/conductor-sdk": "0.8.0",
|
|
29
29
|
"@github/copilot-sdk": "^0.3.0",
|
|
30
30
|
"chrome-launcher": "^1.2.1",
|
|
31
31
|
"chrome-remote-interface": "^0.33.0",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"optionalDependencies": {
|
|
40
40
|
"@roamhq/wrtc": "^0.10.0",
|
|
41
|
-
"@love-moon/chat-web": "0.
|
|
41
|
+
"@love-moon/chat-web": "0.8.0"
|
|
42
42
|
},
|
|
43
43
|
"pnpm": {
|
|
44
44
|
"onlyBuiltDependencies": [
|