agent-conveyor 0.1.3 → 0.1.5
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/README.md +22 -0
- package/dist/cli/main.js +3 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/typescript-runtime.js +269 -1
- package/dist/cli/typescript-runtime.js.map +1 -1
- package/dist/runtime/manager-config.d.ts +1 -0
- package/dist/runtime/manager-config.js +2 -1
- package/dist/runtime/manager-config.js.map +1 -1
- package/dist/state/database.js +2 -2
- package/dist/state/schema-v23.d.ts +1 -0
- package/dist/state/{schema-v22.js → schema-v23.js} +3 -2
- package/dist/state/{schema-v22.js.map → schema-v23.js.map} +1 -1
- package/dist/state/sqlite-contract.d.ts +1 -1
- package/dist/state/sqlite-contract.js +1 -1
- package/docs/landing-page.html +702 -0
- package/docs/manager-recipes.md +303 -0
- package/package.json +5 -1
- package/scripts/serve-landing-page.mjs +39 -0
- package/skills/manage-codex-workers/SKILL.md +33 -0
- package/dist/state/schema-v22.d.ts +0 -1
package/README.md
CHANGED
|
@@ -132,6 +132,19 @@ command exits 0 and the JSON result reports `"ok": true`.
|
|
|
132
132
|
Before publishing `agent-conveyor` to npm, use
|
|
133
133
|
[`docs/package-release.md`](docs/package-release.md).
|
|
134
134
|
|
|
135
|
+
For common manager setups, start with
|
|
136
|
+
[`docs/manager-recipes.md`](docs/manager-recipes.md). It maps natural-language
|
|
137
|
+
requests such as GoalBuddy conveyor runs, test coverage loops, UX polish loops,
|
|
138
|
+
what-next nudging, and PR/CI/merge Ralph loops to concrete `manager-config`
|
|
139
|
+
settings, permissions, evidence gates, cleanup behavior, and example
|
|
140
|
+
manager/Dispatch/worker interactions. Use `conveyor manager-recipes --list`
|
|
141
|
+
or `conveyor manager-recipes --show goalbuddy-conveyor --json` for a
|
|
142
|
+
machine-readable setup preview.
|
|
143
|
+
For a package-facing overview of these modes, open
|
|
144
|
+
[`docs/landing-page.html`](docs/landing-page.html) locally or host it as a
|
|
145
|
+
static landing page. From the repo, `npm run docs:landing` serves it at
|
|
146
|
+
`http://127.0.0.1:8765/`.
|
|
147
|
+
|
|
135
148
|
After install, the intended Codex app entry point is natural language. Open a
|
|
136
149
|
new Codex app session in the target repo and say:
|
|
137
150
|
|
|
@@ -163,6 +176,10 @@ Use `conveyor qa-plan adversarial-triggers` to verify natural-language
|
|
|
163
176
|
manager prompts activate Ralph-loop adversarial gates.
|
|
164
177
|
Use `conveyor qa-plan goalbuddy-conveyor` when a broad request should become
|
|
165
178
|
sequential GoalBuddy child boards with PR/CI/merge receipts.
|
|
179
|
+
Before cutting a manager loose, have it resolve the freeform setup request to a
|
|
180
|
+
named recipe from `docs/manager-recipes.md` or an explicit `custom` setup, then
|
|
181
|
+
show the saved mode, permissions, evidence gates, cleanup policy, and disallowed
|
|
182
|
+
actions.
|
|
166
183
|
For manual QA, launch the dashboard with Dispatch enforcement so the page can
|
|
167
184
|
show live proof:
|
|
168
185
|
|
|
@@ -411,6 +428,11 @@ tmux attach -t codex-live-test
|
|
|
411
428
|
Use `--require` when a manager command should fail closed. Use
|
|
412
429
|
`--require-handoff` before worker compact/clear style instructions so visible
|
|
413
430
|
context is persisted first.
|
|
431
|
+
- `manager-recipes --list|--show RECIPE [--json]` — List or show built-in
|
|
432
|
+
manager setup recipes. Recipe JSON includes the supervision mode,
|
|
433
|
+
permissions, expected tools, epilogues, evidence gates, cleanup behavior,
|
|
434
|
+
disallowed actions, locked setup summary template, and suggested
|
|
435
|
+
`manager-config` command. Use this before cutting a manager loose.
|
|
414
436
|
- `worker-ack <task> --from-stdin|--json [--correlation-id ID]` /
|
|
415
437
|
`manager-ack <task> --from-stdin|--json [--correlation-id ID]` — Persist or
|
|
416
438
|
read the latest structured acknowledgement from the worker or manager. Acks
|
package/dist/cli/main.js
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
2
3
|
import { programNameFromArgv } from "./program-name.js";
|
|
3
4
|
import { runTypescriptRuntimeCommand } from "./typescript-runtime.js";
|
|
4
5
|
const args = process.argv.slice(2);
|
|
5
6
|
const program = programNameFromArgv(process.argv, process.env);
|
|
7
|
+
const stdin = args.includes("--from-stdin") ? readFileSync(0, "utf8") : undefined;
|
|
6
8
|
const typescriptRuntime = runTypescriptRuntimeCommand({
|
|
7
9
|
args,
|
|
8
10
|
cwd: process.cwd(),
|
|
9
11
|
env: process.env,
|
|
10
12
|
program,
|
|
13
|
+
stdin,
|
|
11
14
|
});
|
|
12
15
|
if (typescriptRuntime.stdout) {
|
|
13
16
|
process.stdout.write(typescriptRuntime.stdout);
|
package/dist/cli/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;AAC/D,MAAM,iBAAiB,GAAG,2BAA2B,CAAC;IACpD,IAAI;IACJ,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;IAClB,GAAG,EAAE,OAAO,CAAC,GAAG;IAChB,OAAO;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,mBAAmB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;AAC/D,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClF,MAAM,iBAAiB,GAAG,2BAA2B,CAAC;IACpD,IAAI;IACJ,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;IAClB,GAAG,EAAE,OAAO,CAAC,GAAG;IAChB,OAAO;IACP,KAAK;CACN,CAAC,CAAC;AAEH,IAAI,iBAAiB,CAAC,MAAM,EAAE,CAAC;IAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AACD,IAAI,iBAAiB,CAAC,MAAM,EAAE,CAAC;IAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;AACjD,CAAC;AACD,OAAO,CAAC,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC"}
|
|
@@ -109,6 +109,9 @@ export function runTypescriptRuntimeCommand(options) {
|
|
|
109
109
|
if (parsed.command === "ralph-loop-presets") {
|
|
110
110
|
return runRalphLoopPresetsCommand(parsed, options);
|
|
111
111
|
}
|
|
112
|
+
if (parsed.command === "manager-recipes") {
|
|
113
|
+
return runManagerRecipesCommand(parsed);
|
|
114
|
+
}
|
|
112
115
|
if (parsed.command === "loop-triggers") {
|
|
113
116
|
return runLoopTriggersCommand(parsed, options);
|
|
114
117
|
}
|
|
@@ -593,6 +596,7 @@ function parseRuntimeArgs(args, env) {
|
|
|
593
596
|
&& command !== "runs"
|
|
594
597
|
&& command !== "loop-templates"
|
|
595
598
|
&& command !== "ralph-loop-presets"
|
|
599
|
+
&& command !== "manager-recipes"
|
|
596
600
|
&& command !== "loop-triggers"
|
|
597
601
|
&& command !== "manager-permission"
|
|
598
602
|
&& command !== "continuation"
|
|
@@ -946,7 +950,7 @@ function parseRuntimeArgs(args, env) {
|
|
|
946
950
|
index += 1;
|
|
947
951
|
}
|
|
948
952
|
else if (arg === "--show") {
|
|
949
|
-
if (command !== "runs" && command !== "loop-templates" && command !== "ralph-loop-presets") {
|
|
953
|
+
if (command !== "runs" && command !== "loop-templates" && command !== "ralph-loop-presets" && command !== "manager-recipes") {
|
|
950
954
|
return { command, enabled, error: "Unsupported TypeScript runtime option: --show", explicit, flags, task };
|
|
951
955
|
}
|
|
952
956
|
const value = valueAfter(queue, index, arg);
|
|
@@ -3110,6 +3114,43 @@ function runRalphLoopPresetsCommand(parsed, options) {
|
|
|
3110
3114
|
database.close();
|
|
3111
3115
|
}
|
|
3112
3116
|
}
|
|
3117
|
+
function runManagerRecipesCommand(parsed) {
|
|
3118
|
+
const unsupportedOptions = unsupportedLoopCommandOptions(parsed, {
|
|
3119
|
+
allowedFlags: new Set(["json", "list", "show"]),
|
|
3120
|
+
commandName: "manager-recipes",
|
|
3121
|
+
});
|
|
3122
|
+
if (unsupportedOptions) {
|
|
3123
|
+
return unsupportedRuntimeResult(parsed, unsupportedOptions);
|
|
3124
|
+
}
|
|
3125
|
+
const actionCount = [parsed.flags.list, parsed.flags.show !== null].filter(Boolean).length;
|
|
3126
|
+
if (actionCount !== 1) {
|
|
3127
|
+
return errorResult("Choose one of --list or --show");
|
|
3128
|
+
}
|
|
3129
|
+
if (parsed.flags.list) {
|
|
3130
|
+
const recipes = listManagerRecipes();
|
|
3131
|
+
if (parsed.flags.json) {
|
|
3132
|
+
return jsonResult({ recipes });
|
|
3133
|
+
}
|
|
3134
|
+
return textResult(recipes.map((recipe) => {
|
|
3135
|
+
const loop = recipe.loop_template ? ` loop=${recipe.loop_template}` : "";
|
|
3136
|
+
return `${recipe.name}\tmode=${recipe.mode}${loop}\t${recipe.description}`;
|
|
3137
|
+
}));
|
|
3138
|
+
}
|
|
3139
|
+
const recipe = managerRecipeSummary(parsed.flags.show ?? "");
|
|
3140
|
+
if (parsed.flags.json) {
|
|
3141
|
+
return jsonResult({ recipe });
|
|
3142
|
+
}
|
|
3143
|
+
const lines = [
|
|
3144
|
+
String(recipe.locked_summary_template),
|
|
3145
|
+
"",
|
|
3146
|
+
"manager config command:",
|
|
3147
|
+
` ${recipe.manager_config_command.map(shellQuote).join(" ")}`,
|
|
3148
|
+
];
|
|
3149
|
+
if (recipe.loop_template) {
|
|
3150
|
+
lines.push("", `loop template: ${recipe.loop_template}`);
|
|
3151
|
+
}
|
|
3152
|
+
return textResult(lines);
|
|
3153
|
+
}
|
|
3113
3154
|
function runLoopTriggersCommand(parsed, _options) {
|
|
3114
3155
|
const unsupported = unsupportedMigratedProofCliOptions(parsed);
|
|
3115
3156
|
if (unsupported) {
|
|
@@ -13418,6 +13459,7 @@ function isDefaultRuntimeCommand(command) {
|
|
|
13418
13459
|
|| command === "loop-templates"
|
|
13419
13460
|
|| command === "loop-triggers"
|
|
13420
13461
|
|| command === "ralph-loop-presets"
|
|
13462
|
+
|| command === "manager-recipes"
|
|
13421
13463
|
|| command === "qa-plan"
|
|
13422
13464
|
|| command === "qa-run"
|
|
13423
13465
|
|| command === "start"
|
|
@@ -15170,6 +15212,232 @@ function ralphLoopPresetMetadata(name, options) {
|
|
|
15170
15212
|
ralphLoopPreset(name);
|
|
15171
15213
|
return loopTemplateMetadata(name, options);
|
|
15172
15214
|
}
|
|
15215
|
+
const MANAGER_RECIPES = {
|
|
15216
|
+
"goalbuddy-conveyor": {
|
|
15217
|
+
acceptance: [
|
|
15218
|
+
"Every child board has PR/CI/merge, satisfied_on_main, or blocker proof.",
|
|
15219
|
+
"Parent state records final status for every child.",
|
|
15220
|
+
],
|
|
15221
|
+
cleanup: "compact between child boards after saved handoff",
|
|
15222
|
+
description: "Run broad work as one parent GoalBuddy board with one active child board at a time.",
|
|
15223
|
+
disallowedActions: [
|
|
15224
|
+
"Do not run two child boards at once.",
|
|
15225
|
+
"Do not merge without green CI.",
|
|
15226
|
+
"Do not compact or clear before a saved handoff.",
|
|
15227
|
+
],
|
|
15228
|
+
displayName: "GoalBuddy Conveyor",
|
|
15229
|
+
epilogues: ["draft-pr", "record-handoff"],
|
|
15230
|
+
evidenceGates: [
|
|
15231
|
+
"child receipt with focused verification",
|
|
15232
|
+
"adversarial review",
|
|
15233
|
+
"PR/CI/merge or satisfied_on_main proof",
|
|
15234
|
+
"parent receipt update before the next child",
|
|
15235
|
+
],
|
|
15236
|
+
guidelines: [
|
|
15237
|
+
"Keep exactly one child board active at a time.",
|
|
15238
|
+
"Before activating the next child, update the parent receipt.",
|
|
15239
|
+
],
|
|
15240
|
+
loopTemplate: null,
|
|
15241
|
+
mode: "strict",
|
|
15242
|
+
name: "goalbuddy-conveyor",
|
|
15243
|
+
objective: "Run a one-child-at-a-time GoalBuddy conveyor until every child is merged, proven satisfied, or blocked with evidence.",
|
|
15244
|
+
permissions: ["repo.open_pr", "repo.merge_green_pr", "worker_session.compact", "worker_session.clear"],
|
|
15245
|
+
supportPatterns: ["Inbox / No-Tmux App Loop", "Recovery / Resume / Handoff"],
|
|
15246
|
+
tools: ["verification.run_tests", "context.fetch_prs"],
|
|
15247
|
+
},
|
|
15248
|
+
"nudge-whats-next": {
|
|
15249
|
+
acceptance: [
|
|
15250
|
+
"Accepted criteria are satisfied or explicitly deferred.",
|
|
15251
|
+
"The final summary names commands run, changed files, and residual risk.",
|
|
15252
|
+
],
|
|
15253
|
+
cleanup: "off by default",
|
|
15254
|
+
description: "Observe, ask useful status questions, negotiate criteria, and keep permissions minimal.",
|
|
15255
|
+
disallowedActions: ["Do not grant repo or worker-session mutation permissions by default."],
|
|
15256
|
+
displayName: "Nudge / What's Next Manager",
|
|
15257
|
+
epilogues: [],
|
|
15258
|
+
evidenceGates: ["manager decision", "worker receipt", "accepted criteria closure"],
|
|
15259
|
+
guidelines: [
|
|
15260
|
+
"Prefer wait over nudge while the worker is active.",
|
|
15261
|
+
"Ask for must-have current-task criteria versus follow-ups when scope changes.",
|
|
15262
|
+
],
|
|
15263
|
+
loopTemplate: null,
|
|
15264
|
+
mode: "guided",
|
|
15265
|
+
name: "nudge-whats-next",
|
|
15266
|
+
objective: "Observe the worker, ask useful status and next-step questions, and finish only with evidence.",
|
|
15267
|
+
permissions: [],
|
|
15268
|
+
supportPatterns: ["Inbox / No-Tmux App Loop", "Recovery / Resume / Handoff"],
|
|
15269
|
+
tools: [],
|
|
15270
|
+
},
|
|
15271
|
+
"pr-ci-merge-ralph-loop": {
|
|
15272
|
+
acceptance: [
|
|
15273
|
+
"PR URL, green CI, merge receipt, and adversarial proof are recorded.",
|
|
15274
|
+
"Worker handoff exists before compact or clear.",
|
|
15275
|
+
],
|
|
15276
|
+
cleanup: "clear after saved handoff",
|
|
15277
|
+
description: "Drive delivery through PR readiness, CI, merge, handoff, and worker clear receipts.",
|
|
15278
|
+
disallowedActions: [
|
|
15279
|
+
"Do not open PRs before repo.open_pr is permitted.",
|
|
15280
|
+
"Do not merge before repo.merge_green_pr is permitted and CI is green.",
|
|
15281
|
+
"Do not clear before a saved handoff.",
|
|
15282
|
+
],
|
|
15283
|
+
displayName: "PR/CI/Merge Ralph Loop",
|
|
15284
|
+
epilogues: ["draft-pr", "record-handoff"],
|
|
15285
|
+
evidenceGates: ["pr_url", "ci_green", "merge", "adversarial_check"],
|
|
15286
|
+
guidelines: ["Merge only after green CI and recorded manager decision evidence."],
|
|
15287
|
+
loopTemplate: "pr_ci_merge_loop",
|
|
15288
|
+
mode: "strict",
|
|
15289
|
+
name: "pr-ci-merge-ralph-loop",
|
|
15290
|
+
objective: "Drive the worker through PR readiness, CI, merge, handoff, and clear receipts.",
|
|
15291
|
+
permissions: ["repo.open_pr", "repo.merge_green_pr", "worker_session.compact", "worker_session.clear"],
|
|
15292
|
+
supportPatterns: ["Inbox / No-Tmux App Loop", "Recovery / Resume / Handoff"],
|
|
15293
|
+
tools: ["verification.run_tests", "context.fetch_prs"],
|
|
15294
|
+
},
|
|
15295
|
+
"test-coverage-loop": {
|
|
15296
|
+
acceptance: [
|
|
15297
|
+
"Coverage or targeted test evidence is recorded before another worker pass.",
|
|
15298
|
+
"Structured adversarial proof names the strongest realistic failure mode.",
|
|
15299
|
+
],
|
|
15300
|
+
cleanup: "clear by default",
|
|
15301
|
+
description: "Improve or prove test confidence with coverage evidence before another pass.",
|
|
15302
|
+
disallowedActions: ["Do not continue after only generic tests-passed text."],
|
|
15303
|
+
displayName: "Test Coverage Loop",
|
|
15304
|
+
epilogues: [],
|
|
15305
|
+
evidenceGates: ["test_coverage", "adversarial_check"],
|
|
15306
|
+
guidelines: ["Record coverage evidence before asking for another worker pass."],
|
|
15307
|
+
loopTemplate: "test_coverage_loop",
|
|
15308
|
+
mode: "strict",
|
|
15309
|
+
name: "test-coverage-loop",
|
|
15310
|
+
objective: "Improve or prove test coverage for the requested behavior.",
|
|
15311
|
+
permissions: ["worker_session.compact", "worker_session.clear"],
|
|
15312
|
+
supportPatterns: ["Inbox / No-Tmux App Loop", "Recovery / Resume / Handoff"],
|
|
15313
|
+
tools: ["verification.run_tests"],
|
|
15314
|
+
},
|
|
15315
|
+
"ux-polish-loop": {
|
|
15316
|
+
acceptance: [
|
|
15317
|
+
"Reference artifact, candidate screenshot, visual diff report, and below-threshold evidence are recorded.",
|
|
15318
|
+
"Structured adversarial proof is recorded before another visual pass.",
|
|
15319
|
+
],
|
|
15320
|
+
cleanup: "compact by default",
|
|
15321
|
+
description: "Iterate on visible UI quality using browser, screenshot, and visual-diff evidence.",
|
|
15322
|
+
disallowedActions: ["Do not approve a visual pass without screenshot or browser evidence."],
|
|
15323
|
+
displayName: "UX Polish Loop",
|
|
15324
|
+
epilogues: [],
|
|
15325
|
+
evidenceGates: [
|
|
15326
|
+
"reference_artifact",
|
|
15327
|
+
"candidate_screenshot",
|
|
15328
|
+
"visual_diff_report",
|
|
15329
|
+
"diff_below_threshold",
|
|
15330
|
+
"adversarial_check",
|
|
15331
|
+
],
|
|
15332
|
+
guidelines: ["Compare visible output against references before requesting another pass."],
|
|
15333
|
+
loopTemplate: "visual_diff_loop",
|
|
15334
|
+
mode: "guided",
|
|
15335
|
+
name: "ux-polish-loop",
|
|
15336
|
+
objective: "Iterate on visible UI quality using browser and screenshot evidence.",
|
|
15337
|
+
permissions: ["worker_session.compact", "worker_session.clear"],
|
|
15338
|
+
supportPatterns: ["Inbox / No-Tmux App Loop", "Recovery / Resume / Handoff"],
|
|
15339
|
+
tools: ["verification.run_playwright"],
|
|
15340
|
+
},
|
|
15341
|
+
};
|
|
15342
|
+
const MANAGER_RECIPE_ALIASES = {
|
|
15343
|
+
"goalbuddy conveyor": "goalbuddy-conveyor",
|
|
15344
|
+
goalbuddy: "goalbuddy-conveyor",
|
|
15345
|
+
"nudge / what's next manager": "nudge-whats-next",
|
|
15346
|
+
"nudge whats next": "nudge-whats-next",
|
|
15347
|
+
"pr ci merge ralph loop": "pr-ci-merge-ralph-loop",
|
|
15348
|
+
"pr/ci/merge ralph loop": "pr-ci-merge-ralph-loop",
|
|
15349
|
+
"ralph loop": "pr-ci-merge-ralph-loop",
|
|
15350
|
+
"test coverage": "test-coverage-loop",
|
|
15351
|
+
"test coverage loop": "test-coverage-loop",
|
|
15352
|
+
"ux polish": "ux-polish-loop",
|
|
15353
|
+
"ux polish loop": "ux-polish-loop",
|
|
15354
|
+
"visual polish": "ux-polish-loop",
|
|
15355
|
+
"what's next": "nudge-whats-next",
|
|
15356
|
+
"whats next": "nudge-whats-next",
|
|
15357
|
+
};
|
|
15358
|
+
function listManagerRecipes() {
|
|
15359
|
+
return Object.keys(MANAGER_RECIPES).sort().map((name) => managerRecipeSummary(name));
|
|
15360
|
+
}
|
|
15361
|
+
function managerRecipeDefinition(name) {
|
|
15362
|
+
const key = normalizeManagerRecipeName(name);
|
|
15363
|
+
const recipe = MANAGER_RECIPES[key];
|
|
15364
|
+
if (!recipe) {
|
|
15365
|
+
throw new Error(`Unknown manager recipe: ${name}; expected one of: ${Object.keys(MANAGER_RECIPES).sort().join(", ")}`);
|
|
15366
|
+
}
|
|
15367
|
+
return recipe;
|
|
15368
|
+
}
|
|
15369
|
+
function normalizeManagerRecipeName(name) {
|
|
15370
|
+
const normalized = name.trim().toLowerCase().split(/\s+/).join(" ");
|
|
15371
|
+
return MANAGER_RECIPE_ALIASES[normalized] ?? normalized.replace(/_/g, "-").replace(/ /g, "-");
|
|
15372
|
+
}
|
|
15373
|
+
function managerRecipeSummary(name) {
|
|
15374
|
+
const recipe = managerRecipeDefinition(name);
|
|
15375
|
+
return {
|
|
15376
|
+
acceptance: [...recipe.acceptance],
|
|
15377
|
+
cleanup: recipe.cleanup,
|
|
15378
|
+
description: recipe.description,
|
|
15379
|
+
disallowed_actions: [...recipe.disallowedActions],
|
|
15380
|
+
display_name: recipe.displayName,
|
|
15381
|
+
epilogues: [...recipe.epilogues],
|
|
15382
|
+
evidence_gates: [...recipe.evidenceGates],
|
|
15383
|
+
guidelines: [...recipe.guidelines],
|
|
15384
|
+
locked_summary_template: lockedManagerRecipeSummary(recipe),
|
|
15385
|
+
loop_template: recipe.loopTemplate,
|
|
15386
|
+
manager_config_command: managerRecipeConfigCommand(recipe),
|
|
15387
|
+
mode: recipe.mode,
|
|
15388
|
+
name: recipe.name,
|
|
15389
|
+
objective: recipe.objective,
|
|
15390
|
+
permissions: [...recipe.permissions],
|
|
15391
|
+
support_patterns: [...recipe.supportPatterns],
|
|
15392
|
+
tools: [...recipe.tools],
|
|
15393
|
+
};
|
|
15394
|
+
}
|
|
15395
|
+
function managerRecipeConfigCommand(recipe, taskPlaceholder = "<task>") {
|
|
15396
|
+
const command = ["conveyor", "manager-config", taskPlaceholder, "--mode", recipe.mode, "--objective", recipe.objective];
|
|
15397
|
+
for (const guideline of recipe.guidelines) {
|
|
15398
|
+
command.push("--guideline", guideline);
|
|
15399
|
+
}
|
|
15400
|
+
for (const acceptance of recipe.acceptance) {
|
|
15401
|
+
command.push("--acceptance", acceptance);
|
|
15402
|
+
}
|
|
15403
|
+
const permissions = new Set(recipe.permissions);
|
|
15404
|
+
if (permissions.has("worker_session.compact") && permissions.has("worker_session.clear")) {
|
|
15405
|
+
command.push("--allow-worker-compact-clear");
|
|
15406
|
+
permissions.delete("worker_session.compact");
|
|
15407
|
+
permissions.delete("worker_session.clear");
|
|
15408
|
+
}
|
|
15409
|
+
if (permissions.has("repo.open_pr")) {
|
|
15410
|
+
command.push("--allow-pr");
|
|
15411
|
+
permissions.delete("repo.open_pr");
|
|
15412
|
+
}
|
|
15413
|
+
if (permissions.has("repo.merge_green_pr")) {
|
|
15414
|
+
command.push("--allow-merge-green");
|
|
15415
|
+
permissions.delete("repo.merge_green_pr");
|
|
15416
|
+
}
|
|
15417
|
+
for (const permission of [...permissions].sort()) {
|
|
15418
|
+
command.push("--permit", permission);
|
|
15419
|
+
}
|
|
15420
|
+
for (const tool of recipe.tools) {
|
|
15421
|
+
command.push("--tool", tool);
|
|
15422
|
+
}
|
|
15423
|
+
for (const epilogue of recipe.epilogues) {
|
|
15424
|
+
command.push("--epilogue", epilogue);
|
|
15425
|
+
}
|
|
15426
|
+
return command;
|
|
15427
|
+
}
|
|
15428
|
+
function lockedManagerRecipeSummary(recipe) {
|
|
15429
|
+
return [
|
|
15430
|
+
`Selected recipe: ${recipe.displayName}`,
|
|
15431
|
+
`Mode: ${recipe.mode}`,
|
|
15432
|
+
`Permissions: ${recipe.permissions.length > 0 ? recipe.permissions.join(", ") : "none"}`,
|
|
15433
|
+
`Tools: ${recipe.tools.length > 0 ? recipe.tools.join(", ") : "none"}`,
|
|
15434
|
+
`Epilogues: ${recipe.epilogues.length > 0 ? recipe.epilogues.join(", ") : "none"}`,
|
|
15435
|
+
`Cleanup: ${recipe.cleanup}`,
|
|
15436
|
+
`Evidence gates: ${recipe.evidenceGates.length > 0 ? recipe.evidenceGates.join(", ") : "manager-reviewed evidence"}`,
|
|
15437
|
+
`Not allowed: ${recipe.disallowedActions.length > 0 ? recipe.disallowedActions.join("; ") : "unconfirmed custom actions"}`,
|
|
15438
|
+
"User confirmed: <yes|no>",
|
|
15439
|
+
].join("\n");
|
|
15440
|
+
}
|
|
15173
15441
|
const LOOP_TRIGGERS = [
|
|
15174
15442
|
{
|
|
15175
15443
|
acceptance: "Create or reuse a loop policy whose required_before_continue includes adversarial_check.",
|