agent-conveyor 0.1.6 → 0.1.7
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.
|
@@ -76,7 +76,7 @@ export function runTypescriptRuntimeCommand(options) {
|
|
|
76
76
|
return errorResult(`unknown command: ${parsed.command}`);
|
|
77
77
|
}
|
|
78
78
|
if (parsed.flags.help) {
|
|
79
|
-
return textResult(
|
|
79
|
+
return textResult(commandHelpText(program, parsed.command));
|
|
80
80
|
}
|
|
81
81
|
if (parsed.error) {
|
|
82
82
|
return errorResult(parsed.error);
|
|
@@ -337,6 +337,70 @@ export function runTypescriptRuntimeCommand(options) {
|
|
|
337
337
|
return errorResult(error instanceof Error ? error.message : String(error));
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
|
+
function commandHelpText(program, command) {
|
|
341
|
+
const path = "[--path <workerctl.db>]";
|
|
342
|
+
const linesByCommand = {
|
|
343
|
+
criteria: [
|
|
344
|
+
`usage: ${program} criteria <task> [--list|--add --criterion <text> --source <source>|--accept ID|--satisfy ID|--defer ID|--reject ID] ${path} [--json]`,
|
|
345
|
+
"",
|
|
346
|
+
"Examples:",
|
|
347
|
+
` ${program} criteria my-task --list --json --path /tmp/work/workerctl.db`,
|
|
348
|
+
` ${program} criteria my-task --add --criterion "Note file exists" --source manager_inferred --status accepted --path /tmp/work/workerctl.db`,
|
|
349
|
+
` ${program} criteria my-task --satisfy 1 --proof "File exists" --evidence-json '{"artifact":{"path":"docs/note.md"}}' --path /tmp/work/workerctl.db`,
|
|
350
|
+
],
|
|
351
|
+
"finish-task": [
|
|
352
|
+
`usage: ${program} finish-task <task> --reason <reason> [--require-criteria-audit] ${path}`,
|
|
353
|
+
"",
|
|
354
|
+
"Examples:",
|
|
355
|
+
` ${program} finish-task my-task --reason "Accepted criteria satisfied" --require-criteria-audit --path /tmp/work/workerctl.db`,
|
|
356
|
+
],
|
|
357
|
+
"manager-ack": [
|
|
358
|
+
`usage: ${program} manager-ack <task> --from-stdin ${path}`,
|
|
359
|
+
`usage: ${program} manager-ack <task> --json ${path}`,
|
|
360
|
+
"",
|
|
361
|
+
"Example JSON:",
|
|
362
|
+
` {"task":"my-task","manager_session":"mgr","supervision_contract":"I will supervise through Conveyor and verify criteria before finishing.","will_not_edit_project_files":true}`,
|
|
363
|
+
],
|
|
364
|
+
nudge: [
|
|
365
|
+
`usage: ${program} nudge <worker-or-session> <message> ${path} [--dry-run]`,
|
|
366
|
+
`usage: ${program} session-nudge <session> <message> ${path} [--dry-run]`,
|
|
367
|
+
"",
|
|
368
|
+
"For task-routed delivery, prefer enqueue-nudge-worker plus dispatch:",
|
|
369
|
+
` ${program} enqueue-nudge-worker my-task --message "Status and evidence?" --path /tmp/work/workerctl.db`,
|
|
370
|
+
` ${program} dispatch --once --type nudge_worker --path /tmp/work/workerctl.db`,
|
|
371
|
+
],
|
|
372
|
+
pair: [
|
|
373
|
+
`usage: ${program} pair --task <task> --worker-name <worker> --manager-name <manager> [options] ${path}`,
|
|
374
|
+
"",
|
|
375
|
+
"Options:",
|
|
376
|
+
" --task-goal <text> Task goal stored in Conveyor state.",
|
|
377
|
+
" --task-prompt <text> Initial worker prompt; defaults to task goal when omitted.",
|
|
378
|
+
" --manager-recipe <recipe> Seed a manager recipe, for example goalbuddy-conveyor.",
|
|
379
|
+
" --manager-acceptance <text> Seed an accepted manager criterion; repeat for multiple criteria.",
|
|
380
|
+
" --manager-tool <tool> Seed an expected manager/worker tool; repeat for multiple tools.",
|
|
381
|
+
" --manager-reference <path> Seed a manager reference path; repeat for multiple references.",
|
|
382
|
+
" --manager-question <text> Seed a manager setup question; repeat for multiple questions.",
|
|
383
|
+
" --manager-guideline <text> Seed a manager guideline; repeat for multiple guidelines.",
|
|
384
|
+
" --cwd <dir> Working directory for both Codex sessions.",
|
|
385
|
+
" --accept-trust Auto-accept the Codex trust prompt for the chosen cwd.",
|
|
386
|
+
" --no-dispatch Do not start Dispatch after launching the pair.",
|
|
387
|
+
" --dry-run Print the launch plan without creating sessions.",
|
|
388
|
+
" --json Emit JSON output.",
|
|
389
|
+
"",
|
|
390
|
+
"Examples:",
|
|
391
|
+
` ${program} pair --task dogfood --worker-name dogfood-worker --manager-name dogfood-manager --task-goal "Create docs/note.md" --task-prompt "Create docs/note.md" --manager-recipe goalbuddy-conveyor --manager-acceptance "docs/note.md exists" --cwd /tmp/work --path /tmp/work/workerctl.db --accept-trust`,
|
|
392
|
+
` ${program} pair --task dogfood --worker-name dogfood-worker --manager-name dogfood-manager --path /tmp/work/workerctl.db --dry-run --json`,
|
|
393
|
+
],
|
|
394
|
+
"worker-ack": [
|
|
395
|
+
`usage: ${program} worker-ack <task> --from-stdin ${path}`,
|
|
396
|
+
`usage: ${program} worker-ack <task> --json ${path}`,
|
|
397
|
+
"",
|
|
398
|
+
"Example JSON:",
|
|
399
|
+
` {"goal_restatement":"Create docs/dogfood-note.md","proposed_criteria":{"must_have":["note file exists"],"follow_up":[]},"expected_tools":["shell"],"open_questions":[],"ready_to_start":true}`,
|
|
400
|
+
],
|
|
401
|
+
};
|
|
402
|
+
return linesByCommand[command] ?? [`usage: ${program} ${command} [-h] [options]`];
|
|
403
|
+
}
|
|
340
404
|
function parseRuntimeArgs(args, env) {
|
|
341
405
|
const flags = {
|
|
342
406
|
format: "timeline",
|
|
@@ -5394,6 +5458,7 @@ function runStartSessionCommand(parsed, options, role) {
|
|
|
5394
5458
|
const initialPrompt = role === "manager"
|
|
5395
5459
|
? startManagerBootstrapPrompt(database, {
|
|
5396
5460
|
cwd,
|
|
5461
|
+
dbPath: runtimeDbPath(parsed, options),
|
|
5397
5462
|
managerName: name,
|
|
5398
5463
|
taskGoal: parsed.flags.taskGoal,
|
|
5399
5464
|
taskName: parsed.flags.taskName,
|
|
@@ -5720,7 +5785,7 @@ function runPairCommand(parsed, options) {
|
|
|
5720
5785
|
return unsupportedRuntimeResult(parsed, "pair requires --task, --worker-name, and --manager-name.");
|
|
5721
5786
|
}
|
|
5722
5787
|
const dbPath = runtimeDbPath(parsed, options);
|
|
5723
|
-
const dispatch = pairDispatchPayload(parsed, dbPath);
|
|
5788
|
+
const dispatch = pairDispatchPayload(parsed, dbPath, options);
|
|
5724
5789
|
const packageRoot = packageRootFromRuntimeModule();
|
|
5725
5790
|
if (parsed.flags.dryRun) {
|
|
5726
5791
|
return jsonResult({
|
|
@@ -5731,6 +5796,18 @@ function runPairCommand(parsed, options) {
|
|
|
5731
5796
|
worker: workerName,
|
|
5732
5797
|
});
|
|
5733
5798
|
}
|
|
5799
|
+
const codexPreflight = ensureRequiredTool("codex", options);
|
|
5800
|
+
if (codexPreflight) {
|
|
5801
|
+
return codexPreflight;
|
|
5802
|
+
}
|
|
5803
|
+
const tmuxPreflight = ensureTmuxAvailable(options.tmuxRunner ?? defaultTmuxRunner);
|
|
5804
|
+
if (tmuxPreflight) {
|
|
5805
|
+
return tmuxPreflight;
|
|
5806
|
+
}
|
|
5807
|
+
const tmuxAccessPreflight = ensureTmuxServerAccessible(options.tmuxRunner ?? defaultTmuxRunner);
|
|
5808
|
+
if (tmuxAccessPreflight) {
|
|
5809
|
+
return tmuxAccessPreflight;
|
|
5810
|
+
}
|
|
5734
5811
|
const cwd = parsed.flags.cwd ?? options.cwd ?? process.cwd();
|
|
5735
5812
|
const database = openRuntimeDatabase(parsed, options);
|
|
5736
5813
|
let taskId = null;
|
|
@@ -5848,7 +5925,7 @@ function runPairCommand(parsed, options) {
|
|
|
5848
5925
|
acceptTrust: parsed.flags.acceptTrust,
|
|
5849
5926
|
askForApproval: startup.askForApproval,
|
|
5850
5927
|
cwd,
|
|
5851
|
-
initialPrompt: workerAckTaskPrompt(taskName, parsed.flags.taskPrompt),
|
|
5928
|
+
initialPrompt: workerAckTaskPrompt(taskName, parsed.flags.taskPrompt, dbPath),
|
|
5852
5929
|
name: workerName,
|
|
5853
5930
|
role: "worker",
|
|
5854
5931
|
sandbox: startup.sandbox,
|
|
@@ -5876,6 +5953,7 @@ function runPairCommand(parsed, options) {
|
|
|
5876
5953
|
cwd,
|
|
5877
5954
|
initialPrompt: startManagerBootstrapPrompt(database, {
|
|
5878
5955
|
cwd,
|
|
5956
|
+
dbPath,
|
|
5879
5957
|
managerName,
|
|
5880
5958
|
taskGoal: task.goal,
|
|
5881
5959
|
taskName,
|
|
@@ -6035,14 +6113,13 @@ function taskRowForPair(database, taskName) {
|
|
|
6035
6113
|
`).get(taskName, taskName);
|
|
6036
6114
|
return row ?? null;
|
|
6037
6115
|
}
|
|
6038
|
-
function pairDispatchPayload(parsed, dbPath) {
|
|
6116
|
+
function pairDispatchPayload(parsed, dbPath, options) {
|
|
6039
6117
|
const dispatcherId = parsed.flags.dispatcherId;
|
|
6040
6118
|
const ensureDispatch = dispatcherId !== null && !parsed.flags.noDispatch;
|
|
6041
|
-
const packageRoot = packageRootFromRuntimeModule();
|
|
6042
6119
|
return {
|
|
6043
6120
|
dispatchCommand: ensureDispatch
|
|
6044
6121
|
? [
|
|
6045
|
-
|
|
6122
|
+
workerctlDispatchExecutable(options),
|
|
6046
6123
|
"dispatch",
|
|
6047
6124
|
"--watch",
|
|
6048
6125
|
"--dispatcher-id",
|
|
@@ -6054,6 +6131,17 @@ function pairDispatchPayload(parsed, dbPath) {
|
|
|
6054
6131
|
ensureDispatch,
|
|
6055
6132
|
};
|
|
6056
6133
|
}
|
|
6134
|
+
function workerctlDispatchExecutable(options) {
|
|
6135
|
+
const workerctlPath = commandPath("workerctl", options);
|
|
6136
|
+
if (workerctlPath) {
|
|
6137
|
+
return workerctlPath;
|
|
6138
|
+
}
|
|
6139
|
+
const workerctlScript = join(packageRootFromRuntimeModule(), "scripts", "workerctl");
|
|
6140
|
+
if (pathIsExecutable(workerctlScript)) {
|
|
6141
|
+
return workerctlScript;
|
|
6142
|
+
}
|
|
6143
|
+
throw new Error(`Cannot start Dispatch: workerctl is not on PATH and ${workerctlScript} is not executable.`);
|
|
6144
|
+
}
|
|
6057
6145
|
function emitPairTelemetry(database, options) {
|
|
6058
6146
|
emitTelemetrySync(database, {
|
|
6059
6147
|
actor: "workerctl",
|
|
@@ -6407,20 +6495,24 @@ function spawnCodexAndRegisterPairSession(database, parsed, options, params) {
|
|
|
6407
6495
|
tmux_session: registered.tmux_session,
|
|
6408
6496
|
};
|
|
6409
6497
|
}
|
|
6410
|
-
function workerAckTaskPrompt(taskName, taskPrompt) {
|
|
6498
|
+
function workerAckTaskPrompt(taskName, taskPrompt, dbPath) {
|
|
6411
6499
|
if (taskPrompt === null) {
|
|
6412
6500
|
return null;
|
|
6413
6501
|
}
|
|
6414
6502
|
const taskRef = taskName ?? "<task>";
|
|
6503
|
+
const pathSuffix = commandPathSuffix(dbPath);
|
|
6415
6504
|
return [
|
|
6416
6505
|
taskPrompt,
|
|
6417
6506
|
"",
|
|
6418
6507
|
"Before editing files or running implementation work, acknowledge the task contract:",
|
|
6419
6508
|
"",
|
|
6420
|
-
`conveyor worker-ack ${taskRef} --from-stdin`,
|
|
6509
|
+
`conveyor worker-ack ${taskRef} --from-stdin${pathSuffix}`,
|
|
6510
|
+
"",
|
|
6511
|
+
"Use a JSON object like:",
|
|
6421
6512
|
"",
|
|
6422
|
-
"
|
|
6423
|
-
"
|
|
6513
|
+
`{"goal_restatement":"Restate the assigned task.","proposed_criteria":{"must_have":["Current-task proof"],"follow_up":[]},"expected_tools":["shell"],"open_questions":[],"ready_to_start":true}`,
|
|
6514
|
+
"",
|
|
6515
|
+
"When your implementation is complete, leave a concise final reply with the files changed and verification you ran. Do not call `conveyor finish-task`; the manager owns criteria satisfaction and audited task closeout.",
|
|
6424
6516
|
].join("\n");
|
|
6425
6517
|
}
|
|
6426
6518
|
function createPairRunSync(database, options) {
|
|
@@ -16660,16 +16752,20 @@ function startManagerBootstrapPrompt(database, options) {
|
|
|
16660
16752
|
const goalLine = options.taskGoal ?? context?.goal ?? "No task goal supplied yet.";
|
|
16661
16753
|
const workerLine = options.workerName ?? "No worker session supplied yet.";
|
|
16662
16754
|
const workerctl = "conveyor";
|
|
16755
|
+
const pathSuffix = commandPathSuffix(options.dbPath);
|
|
16663
16756
|
const setupCommand = options.taskName
|
|
16664
|
-
? `${workerctl} manager-config ${taskLine} --questions`
|
|
16665
|
-
: `${workerctl} manager-config <task> --questions`;
|
|
16666
|
-
const cycleCommand = options.taskName ? `${workerctl} cycle ${taskLine}` : `${workerctl} cycle <task
|
|
16757
|
+
? `${workerctl} manager-config ${taskLine} --questions${pathSuffix}`
|
|
16758
|
+
: `${workerctl} manager-config <task> --questions${pathSuffix}`;
|
|
16759
|
+
const cycleCommand = options.taskName ? `${workerctl} cycle ${taskLine}${pathSuffix}` : `${workerctl} cycle <task>${pathSuffix}`;
|
|
16667
16760
|
const managerAckCommand = options.taskName
|
|
16668
|
-
? `${workerctl} manager-ack ${taskLine} --from-stdin`
|
|
16669
|
-
: `${workerctl} manager-ack <task> --from-stdin`;
|
|
16761
|
+
? `${workerctl} manager-ack ${taskLine} --from-stdin${pathSuffix}`
|
|
16762
|
+
: `${workerctl} manager-ack <task> --from-stdin${pathSuffix}`;
|
|
16670
16763
|
const workerAckCommand = options.taskName
|
|
16671
|
-
? `${workerctl} worker-ack ${taskLine} --json`
|
|
16672
|
-
: `${workerctl} worker-ack <task> --json`;
|
|
16764
|
+
? `${workerctl} worker-ack ${taskLine} --json${pathSuffix}`
|
|
16765
|
+
: `${workerctl} worker-ack <task> --json${pathSuffix}`;
|
|
16766
|
+
const satisfyCriterionCommand = options.taskName
|
|
16767
|
+
? `${workerctl} criteria ${taskLine} --satisfy <id> --proof "<proof>" --evidence-json '{"status":"pass","command":"<command>","summary":"<what this proved>"}'${pathSuffix}`
|
|
16768
|
+
: `${workerctl} criteria <task> --satisfy <id> --proof "<proof>" --evidence-json '{"status":"pass","command":"<command>","summary":"<what this proved>"}'${pathSuffix}`;
|
|
16673
16769
|
const config = context ? managerConfigSync(database, context.id) : null;
|
|
16674
16770
|
const initialSetup = config
|
|
16675
16771
|
? seededManagerConfigSetup({ config, cycleCommand, managerAckCommand, workerAckCommand })
|
|
@@ -16677,11 +16773,12 @@ function startManagerBootstrapPrompt(database, options) {
|
|
|
16677
16773
|
"Initial setup:",
|
|
16678
16774
|
`1. Run \`${setupCommand}\`.`,
|
|
16679
16775
|
"2. Ask the user the returned setup questions in this manager Codex chat.",
|
|
16680
|
-
`3. Persist the answers with \`${workerctl} manager-config\`.`,
|
|
16776
|
+
`3. Persist the answers with \`${workerctl} manager-config${pathSuffix}\`.`,
|
|
16681
16777
|
"4. Use `conveyor manager-config --interactive` only when a human is directly running conveyor in a terminal.",
|
|
16682
16778
|
"",
|
|
16683
16779
|
"Acknowledgement:",
|
|
16684
16780
|
`- Before your first cycle, record the supervision contract you are committing to with \`${managerAckCommand}\`.`,
|
|
16781
|
+
` Example JSON: {"task":"${taskLine}","manager_session":"${options.managerName}","supervision_contract":"I will supervise through Conveyor and verify criteria before finishing.","will_not_edit_project_files":true}`,
|
|
16685
16782
|
`- Before nudging or finishing, inspect the worker acknowledgement with \`${workerAckCommand}\` when available.`,
|
|
16686
16783
|
].join("\n");
|
|
16687
16784
|
return [
|
|
@@ -16704,7 +16801,8 @@ function startManagerBootstrapPrompt(database, options) {
|
|
|
16704
16801
|
"- Inspect `manager_context.acceptance_criteria` each cycle.",
|
|
16705
16802
|
"- If worker progress reveals new edge cases, tests, polish, or scope boundaries, ask the worker to propose must-have vs follow-up criteria.",
|
|
16706
16803
|
"- Before finishing, compare worker receipts/verification against accepted open criteria.",
|
|
16707
|
-
`-
|
|
16804
|
+
`- For each accepted criterion that is proven, record evidence with \`${satisfyCriterionCommand}\`.`,
|
|
16805
|
+
`- When all accepted criteria are satisfied, deferred, or rejected, finish the task with \`${workerctl} finish-task ${taskLine} --reason "Accepted criteria satisfied" --require-criteria-audit${pathSuffix}\`.`,
|
|
16708
16806
|
"- Communicate with the worker only through conveyor session/task commands.",
|
|
16709
16807
|
"- Do not edit project files unless the user explicitly asks this manager session to change Agent Conveyor itself.",
|
|
16710
16808
|
].join("\n");
|
|
@@ -16719,7 +16817,7 @@ function seededManagerConfigSetup(options) {
|
|
|
16719
16817
|
if (options.config.tools.length > 0) {
|
|
16720
16818
|
lines.push(`Expected tools: ${options.config.tools.join(", ")}.`);
|
|
16721
16819
|
}
|
|
16722
|
-
lines.push("", "Acknowledgement:", `- Before your first cycle, record the supervision contract you are committing to with \`${options.managerAckCommand}\`.`, `- Before nudging or finishing, inspect the worker acknowledgement with \`${options.workerAckCommand}\` when available.`);
|
|
16820
|
+
lines.push("", "Acknowledgement:", `- Before your first cycle, record the supervision contract you are committing to with \`${options.managerAckCommand}\`.`, ` Example JSON: {"task":"${options.config.task_id}","supervision_contract":"I will supervise through Conveyor and verify criteria before finishing.","will_not_edit_project_files":true}`, `- Before nudging or finishing, inspect the worker acknowledgement with \`${options.workerAckCommand}\` when available.`);
|
|
16723
16821
|
return lines.join("\n");
|
|
16724
16822
|
}
|
|
16725
16823
|
function startManagerTaskContext(database, taskName) {
|
|
@@ -16733,6 +16831,9 @@ function startManagerTaskContext(database, taskName) {
|
|
|
16733
16831
|
function shellQuote(value) {
|
|
16734
16832
|
return `'${value.replace(/'/g, "'\"'\"'")}'`;
|
|
16735
16833
|
}
|
|
16834
|
+
function commandPathSuffix(dbPath) {
|
|
16835
|
+
return dbPath ? ` --path ${shellQuote(dbPath)}` : "";
|
|
16836
|
+
}
|
|
16736
16837
|
function emitTelemetrySync(database, options) {
|
|
16737
16838
|
const eventId = `telemetry-${randomUUID()}`;
|
|
16738
16839
|
const attributesJson = stableJson(options.attributes);
|
|
@@ -18191,9 +18292,8 @@ The supported manager/worker setup is session-based:
|
|
|
18191
18292
|
|
|
18192
18293
|
${workerctl} worker-ack <task-name> --from-stdin
|
|
18193
18294
|
|
|
18194
|
-
|
|
18195
|
-
expected_tools,
|
|
18196
|
-
separate must-have and follow-up criteria.
|
|
18295
|
+
Example JSON:
|
|
18296
|
+
{"goal_restatement":"Restate the assigned task.","proposed_criteria":{"must_have":["Current-task proof"],"follow_up":[]},"expected_tools":["shell"],"open_questions":[],"ready_to_start":true}
|
|
18197
18297
|
|
|
18198
18298
|
Required fields:
|
|
18199
18299
|
- worker name
|
|
@@ -18280,6 +18380,14 @@ function ensureTmuxAvailable(runner) {
|
|
|
18280
18380
|
const detail = (result.stderr || result.stdout || `exit code ${result.status}`).trim();
|
|
18281
18381
|
return lifecycleWorkerErrorResult(tmuxCommandFailureMessage(["tmux", "-V"], detail));
|
|
18282
18382
|
}
|
|
18383
|
+
function ensureTmuxServerAccessible(runner) {
|
|
18384
|
+
const result = runner(["tmux", "start-server"], { check: false });
|
|
18385
|
+
if (result.status === 0) {
|
|
18386
|
+
return null;
|
|
18387
|
+
}
|
|
18388
|
+
const detail = (result.stderr || result.stdout || `exit code ${result.status}`).trim();
|
|
18389
|
+
return lifecycleWorkerErrorResult(tmuxCommandFailureMessage(["tmux", "start-server"], detail));
|
|
18390
|
+
}
|
|
18283
18391
|
const CONTENT_KEYS = new Set(["content", "message", "output", "segment_text", "text"]);
|
|
18284
18392
|
function redactPayload(value) {
|
|
18285
18393
|
if (Array.isArray(value)) {
|