agent-conveyor 0.1.5 → 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",
|
|
@@ -502,6 +566,7 @@ function parseRuntimeArgs(args, env) {
|
|
|
502
566
|
managerObjective: null,
|
|
503
567
|
managerPermissionsJson: null,
|
|
504
568
|
managerPermit: [],
|
|
569
|
+
managerRecipe: null,
|
|
505
570
|
managerReference: [],
|
|
506
571
|
managerRequireAcks: false,
|
|
507
572
|
managerTool: [],
|
|
@@ -1421,6 +1486,17 @@ function parseRuntimeArgs(args, env) {
|
|
|
1421
1486
|
flags.managerMode = value.value;
|
|
1422
1487
|
index += 1;
|
|
1423
1488
|
}
|
|
1489
|
+
else if (arg === "--manager-recipe") {
|
|
1490
|
+
if (command !== "pair") {
|
|
1491
|
+
return { command, enabled, error: "Unsupported TypeScript runtime option: --manager-recipe", explicit, flags, task };
|
|
1492
|
+
}
|
|
1493
|
+
const value = valueAfter(queue, index, arg);
|
|
1494
|
+
if (value.error) {
|
|
1495
|
+
return { command, enabled, error: value.error, explicit, flags, task };
|
|
1496
|
+
}
|
|
1497
|
+
flags.managerRecipe = value.value;
|
|
1498
|
+
index += 1;
|
|
1499
|
+
}
|
|
1424
1500
|
else if (arg === "--manager-objective") {
|
|
1425
1501
|
if (command !== "pair") {
|
|
1426
1502
|
return { command, enabled, error: "Unsupported TypeScript runtime option: --manager-objective", explicit, flags, task };
|
|
@@ -1555,6 +1631,17 @@ function parseRuntimeArgs(args, env) {
|
|
|
1555
1631
|
flags.managerObjective = value.value;
|
|
1556
1632
|
index += 1;
|
|
1557
1633
|
}
|
|
1634
|
+
else if (arg === "--recipe") {
|
|
1635
|
+
if (command !== "manager-config") {
|
|
1636
|
+
return { command, enabled, error: "Unsupported TypeScript runtime option: --recipe", explicit, flags, task };
|
|
1637
|
+
}
|
|
1638
|
+
const value = valueAfter(queue, index, arg);
|
|
1639
|
+
if (value.error) {
|
|
1640
|
+
return { command, enabled, error: value.error, explicit, flags, task };
|
|
1641
|
+
}
|
|
1642
|
+
flags.managerRecipe = value.value;
|
|
1643
|
+
index += 1;
|
|
1644
|
+
}
|
|
1558
1645
|
else if (arg === "--guideline") {
|
|
1559
1646
|
if (command !== "manager-config") {
|
|
1560
1647
|
return { command, enabled, error: "Unsupported TypeScript runtime option: --guideline", explicit, flags, task };
|
|
@@ -5371,6 +5458,7 @@ function runStartSessionCommand(parsed, options, role) {
|
|
|
5371
5458
|
const initialPrompt = role === "manager"
|
|
5372
5459
|
? startManagerBootstrapPrompt(database, {
|
|
5373
5460
|
cwd,
|
|
5461
|
+
dbPath: runtimeDbPath(parsed, options),
|
|
5374
5462
|
managerName: name,
|
|
5375
5463
|
taskGoal: parsed.flags.taskGoal,
|
|
5376
5464
|
taskName: parsed.flags.taskName,
|
|
@@ -5697,7 +5785,7 @@ function runPairCommand(parsed, options) {
|
|
|
5697
5785
|
return unsupportedRuntimeResult(parsed, "pair requires --task, --worker-name, and --manager-name.");
|
|
5698
5786
|
}
|
|
5699
5787
|
const dbPath = runtimeDbPath(parsed, options);
|
|
5700
|
-
const dispatch = pairDispatchPayload(parsed, dbPath);
|
|
5788
|
+
const dispatch = pairDispatchPayload(parsed, dbPath, options);
|
|
5701
5789
|
const packageRoot = packageRootFromRuntimeModule();
|
|
5702
5790
|
if (parsed.flags.dryRun) {
|
|
5703
5791
|
return jsonResult({
|
|
@@ -5708,6 +5796,18 @@ function runPairCommand(parsed, options) {
|
|
|
5708
5796
|
worker: workerName,
|
|
5709
5797
|
});
|
|
5710
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
|
+
}
|
|
5711
5811
|
const cwd = parsed.flags.cwd ?? options.cwd ?? process.cwd();
|
|
5712
5812
|
const database = openRuntimeDatabase(parsed, options);
|
|
5713
5813
|
let taskId = null;
|
|
@@ -5774,6 +5874,7 @@ function runPairCommand(parsed, options) {
|
|
|
5774
5874
|
managerObjective: parsed.flags.managerObjective,
|
|
5775
5875
|
managerPermissionsJson: parsed.flags.managerPermissionsJson,
|
|
5776
5876
|
managerPermit: parsed.flags.managerPermit,
|
|
5877
|
+
managerRecipe: parsed.flags.managerRecipe,
|
|
5777
5878
|
managerReference: parsed.flags.managerReference,
|
|
5778
5879
|
managerRequireAcks: parsed.flags.managerRequireAcks,
|
|
5779
5880
|
managerTool: parsed.flags.managerTool,
|
|
@@ -5824,7 +5925,7 @@ function runPairCommand(parsed, options) {
|
|
|
5824
5925
|
acceptTrust: parsed.flags.acceptTrust,
|
|
5825
5926
|
askForApproval: startup.askForApproval,
|
|
5826
5927
|
cwd,
|
|
5827
|
-
initialPrompt: workerAckTaskPrompt(taskName, parsed.flags.taskPrompt),
|
|
5928
|
+
initialPrompt: workerAckTaskPrompt(taskName, parsed.flags.taskPrompt, dbPath),
|
|
5828
5929
|
name: workerName,
|
|
5829
5930
|
role: "worker",
|
|
5830
5931
|
sandbox: startup.sandbox,
|
|
@@ -5852,6 +5953,7 @@ function runPairCommand(parsed, options) {
|
|
|
5852
5953
|
cwd,
|
|
5853
5954
|
initialPrompt: startManagerBootstrapPrompt(database, {
|
|
5854
5955
|
cwd,
|
|
5956
|
+
dbPath,
|
|
5855
5957
|
managerName,
|
|
5856
5958
|
taskGoal: task.goal,
|
|
5857
5959
|
taskName,
|
|
@@ -6011,14 +6113,13 @@ function taskRowForPair(database, taskName) {
|
|
|
6011
6113
|
`).get(taskName, taskName);
|
|
6012
6114
|
return row ?? null;
|
|
6013
6115
|
}
|
|
6014
|
-
function pairDispatchPayload(parsed, dbPath) {
|
|
6116
|
+
function pairDispatchPayload(parsed, dbPath, options) {
|
|
6015
6117
|
const dispatcherId = parsed.flags.dispatcherId;
|
|
6016
6118
|
const ensureDispatch = dispatcherId !== null && !parsed.flags.noDispatch;
|
|
6017
|
-
const packageRoot = packageRootFromRuntimeModule();
|
|
6018
6119
|
return {
|
|
6019
6120
|
dispatchCommand: ensureDispatch
|
|
6020
6121
|
? [
|
|
6021
|
-
|
|
6122
|
+
workerctlDispatchExecutable(options),
|
|
6022
6123
|
"dispatch",
|
|
6023
6124
|
"--watch",
|
|
6024
6125
|
"--dispatcher-id",
|
|
@@ -6030,6 +6131,17 @@ function pairDispatchPayload(parsed, dbPath) {
|
|
|
6030
6131
|
ensureDispatch,
|
|
6031
6132
|
};
|
|
6032
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
|
+
}
|
|
6033
6145
|
function emitPairTelemetry(database, options) {
|
|
6034
6146
|
emitTelemetrySync(database, {
|
|
6035
6147
|
actor: "workerctl",
|
|
@@ -6053,6 +6165,7 @@ function emitPairTelemetry(database, options) {
|
|
|
6053
6165
|
function ensurePairManagerConfig(database, options) {
|
|
6054
6166
|
const existing = managerConfigSync(database, options.taskId);
|
|
6055
6167
|
const requested = options.managerMode !== null
|
|
6168
|
+
|| options.managerRecipe !== null
|
|
6056
6169
|
|| options.managerObjective !== null
|
|
6057
6170
|
|| options.managerGuideline.length > 0
|
|
6058
6171
|
|| options.managerAcceptance.length > 0
|
|
@@ -6073,6 +6186,7 @@ function ensurePairManagerConfig(database, options) {
|
|
|
6073
6186
|
if (supervisionMode !== "light" && supervisionMode !== "guided" && supervisionMode !== "strict") {
|
|
6074
6187
|
throw new Error("manager_mode must be light, guided, or strict");
|
|
6075
6188
|
}
|
|
6189
|
+
const recipeName = cleanManagerRecipeName(options.managerRecipe, existing?.recipe_name ?? (existing === null ? "custom" : null));
|
|
6076
6190
|
const objective = options.managerObjective !== null ? options.managerObjective : existing?.objective ?? null;
|
|
6077
6191
|
const guidelines = options.managerGuideline.length > 0 ? options.managerGuideline : existing?.guidelines ?? [];
|
|
6078
6192
|
const acceptanceCriteria = options.managerAcceptance.length > 0
|
|
@@ -6093,13 +6207,14 @@ function ensurePairManagerConfig(database, options) {
|
|
|
6093
6207
|
const requireAcks = options.managerRequireAcks || (existing?.require_acks ?? false);
|
|
6094
6208
|
database.prepare(`
|
|
6095
6209
|
insert into manager_configs(
|
|
6096
|
-
task_id, supervision_mode, objective, guidelines_json,
|
|
6210
|
+
task_id, recipe_name, supervision_mode, objective, guidelines_json,
|
|
6097
6211
|
acceptance_criteria_json, reference_paths_json, permissions_json,
|
|
6098
6212
|
tools_json, epilogues_json, nudge_on_completion, require_acks,
|
|
6099
6213
|
revision, created_at, updated_at
|
|
6100
6214
|
)
|
|
6101
|
-
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
6215
|
+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
6102
6216
|
on conflict(task_id) do update set
|
|
6217
|
+
recipe_name = excluded.recipe_name,
|
|
6103
6218
|
supervision_mode = excluded.supervision_mode,
|
|
6104
6219
|
objective = excluded.objective,
|
|
6105
6220
|
guidelines_json = excluded.guidelines_json,
|
|
@@ -6111,6 +6226,7 @@ function ensurePairManagerConfig(database, options) {
|
|
|
6111
6226
|
nudge_on_completion = excluded.nudge_on_completion,
|
|
6112
6227
|
require_acks = excluded.require_acks,
|
|
6113
6228
|
revision = case when
|
|
6229
|
+
manager_configs.recipe_name is not excluded.recipe_name or
|
|
6114
6230
|
manager_configs.supervision_mode is not excluded.supervision_mode or
|
|
6115
6231
|
manager_configs.objective is not excluded.objective or
|
|
6116
6232
|
manager_configs.guidelines_json is not excluded.guidelines_json or
|
|
@@ -6123,7 +6239,7 @@ function ensurePairManagerConfig(database, options) {
|
|
|
6123
6239
|
manager_configs.require_acks is not excluded.require_acks
|
|
6124
6240
|
then manager_configs.revision + 1 else manager_configs.revision end,
|
|
6125
6241
|
updated_at = excluded.updated_at
|
|
6126
|
-
`).run(options.taskId, supervisionMode, objective, stableJson(guidelines), stableJson(acceptanceCriteria), stableJson(referencePaths), stableJson(permissions), stableJson(tools), stableJson(epilogues), nudgeOnCompletion, requireAcks ? 1 : 0, options.timestamp, options.timestamp);
|
|
6242
|
+
`).run(options.taskId, recipeName, supervisionMode, objective, stableJson(guidelines), stableJson(acceptanceCriteria), stableJson(referencePaths), stableJson(permissions), stableJson(tools), stableJson(epilogues), nudgeOnCompletion, requireAcks ? 1 : 0, options.timestamp, options.timestamp);
|
|
6127
6243
|
const config = managerConfigSync(database, options.taskId);
|
|
6128
6244
|
if (config === null) {
|
|
6129
6245
|
throw new Error(`manager config was not recorded for task ${options.taskId}`);
|
|
@@ -6379,20 +6495,24 @@ function spawnCodexAndRegisterPairSession(database, parsed, options, params) {
|
|
|
6379
6495
|
tmux_session: registered.tmux_session,
|
|
6380
6496
|
};
|
|
6381
6497
|
}
|
|
6382
|
-
function workerAckTaskPrompt(taskName, taskPrompt) {
|
|
6498
|
+
function workerAckTaskPrompt(taskName, taskPrompt, dbPath) {
|
|
6383
6499
|
if (taskPrompt === null) {
|
|
6384
6500
|
return null;
|
|
6385
6501
|
}
|
|
6386
6502
|
const taskRef = taskName ?? "<task>";
|
|
6503
|
+
const pathSuffix = commandPathSuffix(dbPath);
|
|
6387
6504
|
return [
|
|
6388
6505
|
taskPrompt,
|
|
6389
6506
|
"",
|
|
6390
6507
|
"Before editing files or running implementation work, acknowledge the task contract:",
|
|
6391
6508
|
"",
|
|
6392
|
-
`conveyor worker-ack ${taskRef} --from-stdin`,
|
|
6509
|
+
`conveyor worker-ack ${taskRef} --from-stdin${pathSuffix}`,
|
|
6510
|
+
"",
|
|
6511
|
+
"Use a JSON object like:",
|
|
6512
|
+
"",
|
|
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}`,
|
|
6393
6514
|
"",
|
|
6394
|
-
"
|
|
6395
|
-
"open_questions, and ready_to_start.",
|
|
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.",
|
|
6396
6516
|
].join("\n");
|
|
6397
6517
|
}
|
|
6398
6518
|
function createPairRunSync(database, options) {
|
|
@@ -11842,6 +11962,7 @@ function insertCompatEventSync(database, options) {
|
|
|
11842
11962
|
}
|
|
11843
11963
|
function managerConfigMutationRequested(parsed) {
|
|
11844
11964
|
return parsed.flags.managerMode !== null
|
|
11965
|
+
|| parsed.flags.managerRecipe !== null
|
|
11845
11966
|
|| parsed.flags.managerObjective !== null
|
|
11846
11967
|
|| parsed.flags.managerGuideline.length > 0
|
|
11847
11968
|
|| parsed.flags.managerAcceptance.length > 0
|
|
@@ -11860,6 +11981,7 @@ function upsertManagerConfigFromParsed(database, options) {
|
|
|
11860
11981
|
const parsed = options.parsed;
|
|
11861
11982
|
const existing = options.existing;
|
|
11862
11983
|
const supervisionMode = parsed.flags.managerMode ?? existing?.supervision_mode ?? "guided";
|
|
11984
|
+
const recipeName = cleanManagerRecipeName(parsed.flags.managerRecipe, existing?.recipe_name ?? null);
|
|
11863
11985
|
const objective = parsed.flags.managerObjective !== null ? parsed.flags.managerObjective : existing?.objective ?? null;
|
|
11864
11986
|
const guidelines = parsed.flags.managerGuideline.length > 0 ? parsed.flags.managerGuideline : existing?.guidelines ?? [];
|
|
11865
11987
|
const acceptanceCriteria = parsed.flags.managerAcceptance.length > 0
|
|
@@ -11880,13 +12002,14 @@ function upsertManagerConfigFromParsed(database, options) {
|
|
|
11880
12002
|
const requireAcks = parsed.flags.managerRequireAcks || (existing?.require_acks ?? false);
|
|
11881
12003
|
database.prepare(`
|
|
11882
12004
|
insert into manager_configs(
|
|
11883
|
-
task_id, supervision_mode, objective, guidelines_json,
|
|
12005
|
+
task_id, recipe_name, supervision_mode, objective, guidelines_json,
|
|
11884
12006
|
acceptance_criteria_json, reference_paths_json, permissions_json,
|
|
11885
12007
|
tools_json, epilogues_json, nudge_on_completion, require_acks,
|
|
11886
12008
|
revision, created_at, updated_at
|
|
11887
12009
|
)
|
|
11888
|
-
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
12010
|
+
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
|
|
11889
12011
|
on conflict(task_id) do update set
|
|
12012
|
+
recipe_name = excluded.recipe_name,
|
|
11890
12013
|
supervision_mode = excluded.supervision_mode,
|
|
11891
12014
|
objective = excluded.objective,
|
|
11892
12015
|
guidelines_json = excluded.guidelines_json,
|
|
@@ -11898,6 +12021,7 @@ function upsertManagerConfigFromParsed(database, options) {
|
|
|
11898
12021
|
nudge_on_completion = excluded.nudge_on_completion,
|
|
11899
12022
|
require_acks = excluded.require_acks,
|
|
11900
12023
|
revision = case when
|
|
12024
|
+
manager_configs.recipe_name is not excluded.recipe_name or
|
|
11901
12025
|
manager_configs.supervision_mode is not excluded.supervision_mode or
|
|
11902
12026
|
manager_configs.objective is not excluded.objective or
|
|
11903
12027
|
manager_configs.guidelines_json is not excluded.guidelines_json or
|
|
@@ -11910,7 +12034,7 @@ function upsertManagerConfigFromParsed(database, options) {
|
|
|
11910
12034
|
manager_configs.require_acks is not excluded.require_acks
|
|
11911
12035
|
then manager_configs.revision + 1 else manager_configs.revision end,
|
|
11912
12036
|
updated_at = excluded.updated_at
|
|
11913
|
-
`).run(options.taskId, supervisionMode, objective, stableJson(guidelines), stableJson(acceptanceCriteria), stableJson(referencePaths), stableJson(permissions), stableJson(tools), stableJson(epilogues), nudgeOnCompletion, requireAcks ? 1 : 0, options.timestamp, options.timestamp);
|
|
12037
|
+
`).run(options.taskId, recipeName, supervisionMode, objective, stableJson(guidelines), stableJson(acceptanceCriteria), stableJson(referencePaths), stableJson(permissions), stableJson(tools), stableJson(epilogues), nudgeOnCompletion, requireAcks ? 1 : 0, options.timestamp, options.timestamp);
|
|
11914
12038
|
const config = managerConfigSync(database, options.taskId);
|
|
11915
12039
|
if (config === null) {
|
|
11916
12040
|
throw new Error(`manager config was not recorded for task ${options.taskId}`);
|
|
@@ -11933,6 +12057,16 @@ function cleanManagerNudgeOnCompletion(value) {
|
|
|
11933
12057
|
}
|
|
11934
12058
|
return value;
|
|
11935
12059
|
}
|
|
12060
|
+
function cleanManagerRecipeName(value, existing) {
|
|
12061
|
+
if (value === null) {
|
|
12062
|
+
return existing;
|
|
12063
|
+
}
|
|
12064
|
+
const normalized = normalizeManagerRecipeName(value);
|
|
12065
|
+
if (normalized === "custom") {
|
|
12066
|
+
return null;
|
|
12067
|
+
}
|
|
12068
|
+
return managerRecipeDefinition(normalized).name;
|
|
12069
|
+
}
|
|
11936
12070
|
function managerPermissionWarnings(permissions) {
|
|
11937
12071
|
const warnings = [];
|
|
11938
12072
|
for (const [key, value] of Object.entries(permissions ?? {})) {
|
|
@@ -16618,16 +16752,20 @@ function startManagerBootstrapPrompt(database, options) {
|
|
|
16618
16752
|
const goalLine = options.taskGoal ?? context?.goal ?? "No task goal supplied yet.";
|
|
16619
16753
|
const workerLine = options.workerName ?? "No worker session supplied yet.";
|
|
16620
16754
|
const workerctl = "conveyor";
|
|
16755
|
+
const pathSuffix = commandPathSuffix(options.dbPath);
|
|
16621
16756
|
const setupCommand = options.taskName
|
|
16622
|
-
? `${workerctl} manager-config ${taskLine} --questions`
|
|
16623
|
-
: `${workerctl} manager-config <task> --questions`;
|
|
16624
|
-
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}`;
|
|
16625
16760
|
const managerAckCommand = options.taskName
|
|
16626
|
-
? `${workerctl} manager-ack ${taskLine} --from-stdin`
|
|
16627
|
-
: `${workerctl} manager-ack <task> --from-stdin`;
|
|
16761
|
+
? `${workerctl} manager-ack ${taskLine} --from-stdin${pathSuffix}`
|
|
16762
|
+
: `${workerctl} manager-ack <task> --from-stdin${pathSuffix}`;
|
|
16628
16763
|
const workerAckCommand = options.taskName
|
|
16629
|
-
? `${workerctl} worker-ack ${taskLine} --json`
|
|
16630
|
-
: `${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}`;
|
|
16631
16769
|
const config = context ? managerConfigSync(database, context.id) : null;
|
|
16632
16770
|
const initialSetup = config
|
|
16633
16771
|
? seededManagerConfigSetup({ config, cycleCommand, managerAckCommand, workerAckCommand })
|
|
@@ -16635,11 +16773,12 @@ function startManagerBootstrapPrompt(database, options) {
|
|
|
16635
16773
|
"Initial setup:",
|
|
16636
16774
|
`1. Run \`${setupCommand}\`.`,
|
|
16637
16775
|
"2. Ask the user the returned setup questions in this manager Codex chat.",
|
|
16638
|
-
`3. Persist the answers with \`${workerctl} manager-config\`.`,
|
|
16776
|
+
`3. Persist the answers with \`${workerctl} manager-config${pathSuffix}\`.`,
|
|
16639
16777
|
"4. Use `conveyor manager-config --interactive` only when a human is directly running conveyor in a terminal.",
|
|
16640
16778
|
"",
|
|
16641
16779
|
"Acknowledgement:",
|
|
16642
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}`,
|
|
16643
16782
|
`- Before nudging or finishing, inspect the worker acknowledgement with \`${workerAckCommand}\` when available.`,
|
|
16644
16783
|
].join("\n");
|
|
16645
16784
|
return [
|
|
@@ -16662,7 +16801,8 @@ function startManagerBootstrapPrompt(database, options) {
|
|
|
16662
16801
|
"- Inspect `manager_context.acceptance_criteria` each cycle.",
|
|
16663
16802
|
"- If worker progress reveals new edge cases, tests, polish, or scope boundaries, ask the worker to propose must-have vs follow-up criteria.",
|
|
16664
16803
|
"- Before finishing, compare worker receipts/verification against accepted open criteria.",
|
|
16665
|
-
`-
|
|
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}\`.`,
|
|
16666
16806
|
"- Communicate with the worker only through conveyor session/task commands.",
|
|
16667
16807
|
"- Do not edit project files unless the user explicitly asks this manager session to change Agent Conveyor itself.",
|
|
16668
16808
|
].join("\n");
|
|
@@ -16677,7 +16817,7 @@ function seededManagerConfigSetup(options) {
|
|
|
16677
16817
|
if (options.config.tools.length > 0) {
|
|
16678
16818
|
lines.push(`Expected tools: ${options.config.tools.join(", ")}.`);
|
|
16679
16819
|
}
|
|
16680
|
-
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.`);
|
|
16681
16821
|
return lines.join("\n");
|
|
16682
16822
|
}
|
|
16683
16823
|
function startManagerTaskContext(database, taskName) {
|
|
@@ -16691,6 +16831,9 @@ function startManagerTaskContext(database, taskName) {
|
|
|
16691
16831
|
function shellQuote(value) {
|
|
16692
16832
|
return `'${value.replace(/'/g, "'\"'\"'")}'`;
|
|
16693
16833
|
}
|
|
16834
|
+
function commandPathSuffix(dbPath) {
|
|
16835
|
+
return dbPath ? ` --path ${shellQuote(dbPath)}` : "";
|
|
16836
|
+
}
|
|
16694
16837
|
function emitTelemetrySync(database, options) {
|
|
16695
16838
|
const eventId = `telemetry-${randomUUID()}`;
|
|
16696
16839
|
const attributesJson = stableJson(options.attributes);
|
|
@@ -18149,9 +18292,8 @@ The supported manager/worker setup is session-based:
|
|
|
18149
18292
|
|
|
18150
18293
|
${workerctl} worker-ack <task-name> --from-stdin
|
|
18151
18294
|
|
|
18152
|
-
|
|
18153
|
-
expected_tools,
|
|
18154
|
-
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}
|
|
18155
18297
|
|
|
18156
18298
|
Required fields:
|
|
18157
18299
|
- worker name
|
|
@@ -18238,6 +18380,14 @@ function ensureTmuxAvailable(runner) {
|
|
|
18238
18380
|
const detail = (result.stderr || result.stdout || `exit code ${result.status}`).trim();
|
|
18239
18381
|
return lifecycleWorkerErrorResult(tmuxCommandFailureMessage(["tmux", "-V"], detail));
|
|
18240
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
|
+
}
|
|
18241
18391
|
const CONTENT_KEYS = new Set(["content", "message", "output", "segment_text", "text"]);
|
|
18242
18392
|
function redactPayload(value) {
|
|
18243
18393
|
if (Array.isArray(value)) {
|