@ludecker/aaac 1.1.6 → 1.2.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.
Files changed (79) hide show
  1. package/package.json +9 -9
  2. package/src/cli.mjs +0 -0
  3. package/src/run-engine/debug-run.mjs +0 -0
  4. package/src/run-engine/log-dump.mjs +0 -0
  5. package/src/run-engine/log-trace.mjs +0 -0
  6. package/templates/cursor/aaac/enforcement.json +84 -3
  7. package/templates/cursor/aaac/graph.project.yaml +28 -0
  8. package/templates/cursor/aaac/lifecycle/lifecycle.json +14 -0
  9. package/templates/cursor/aaac/lifecycle/phases.json +7 -1
  10. package/templates/cursor/aaac/ontology.json +1 -0
  11. package/templates/cursor/aaac/project.config.json +36 -0
  12. package/templates/cursor/aaac/scripts/remediation/auto-check-swarm-synthesis.mjs +75 -0
  13. package/templates/cursor/aaac/scripts/remediation/auto-dispatch-queue-from-health.mjs +78 -0
  14. package/templates/cursor/aaac/scripts/remediation/bootstrap-autonomous.mjs +113 -0
  15. package/templates/cursor/aaac/scripts/remediation/capture-verify-baseline.mjs +66 -0
  16. package/templates/cursor/aaac/scripts/remediation/capture-wave-snapshot.mjs +79 -0
  17. package/templates/cursor/aaac/scripts/remediation/check-swarm-raw.template.json +26 -0
  18. package/templates/cursor/aaac/scripts/remediation/classify-fallow-issues.mjs +77 -0
  19. package/templates/cursor/aaac/scripts/remediation/classify-verify-failure.mjs +176 -0
  20. package/templates/cursor/aaac/scripts/remediation/compute-satisfaction.mjs +344 -0
  21. package/templates/cursor/aaac/scripts/remediation/debt-sweep-gate.mjs +202 -0
  22. package/templates/cursor/aaac/scripts/remediation/dispatch-rules.json +44 -0
  23. package/templates/cursor/aaac/scripts/remediation/fallow-fp-rules.json +87 -0
  24. package/templates/cursor/aaac/scripts/remediation/fallow-scan.mjs +219 -0
  25. package/templates/cursor/aaac/scripts/remediation/handle-yield.mjs +240 -0
  26. package/templates/cursor/aaac/scripts/remediation/init-campaign.mjs +211 -0
  27. package/templates/cursor/aaac/scripts/remediation/lib/autonomous-mode.mjs +63 -0
  28. package/templates/cursor/aaac/scripts/remediation/lib/campaign-focus.mjs +87 -0
  29. package/templates/cursor/aaac/scripts/remediation/lib/fallow-classifier.mjs +190 -0
  30. package/templates/cursor/aaac/scripts/remediation/lib/fallow-health-targets.mjs +56 -0
  31. package/templates/cursor/aaac/scripts/remediation/lib/fallow-metrics.mjs +119 -0
  32. package/templates/cursor/aaac/scripts/remediation/lib/invoke-cursor-agent.mjs +51 -0
  33. package/templates/cursor/aaac/scripts/remediation/lib/reconcile-run-manifest.mjs +41 -0
  34. package/templates/cursor/aaac/scripts/remediation/lib/regression-analysis.mjs +55 -0
  35. package/templates/cursor/aaac/scripts/remediation/lib/remediation-config.mjs +69 -0
  36. package/templates/cursor/aaac/scripts/remediation/lib/remediation-progress.mjs +58 -0
  37. package/templates/cursor/aaac/scripts/remediation/lib/remediation-watch-loop.mjs +168 -0
  38. package/templates/cursor/aaac/scripts/remediation/lib/runner-exec.mjs +156 -0
  39. package/templates/cursor/aaac/scripts/remediation/lib/runner-state.mjs +145 -0
  40. package/templates/cursor/aaac/scripts/remediation/lib/verify-metrics.mjs +205 -0
  41. package/templates/cursor/aaac/scripts/remediation/merge-check-swarm.mjs +257 -0
  42. package/templates/cursor/aaac/scripts/remediation/plan-waves-from-queue.mjs +85 -0
  43. package/templates/cursor/aaac/scripts/remediation/prepare-check-context.mjs +148 -0
  44. package/templates/cursor/aaac/scripts/remediation/record-fallow-fp.mjs +107 -0
  45. package/templates/cursor/aaac/scripts/remediation/record-iteration-step.mjs +56 -0
  46. package/templates/cursor/aaac/scripts/remediation/remediation-cli.mjs +157 -0
  47. package/templates/cursor/aaac/scripts/remediation/remediation-cursor-watch.sh +10 -0
  48. package/templates/cursor/aaac/scripts/remediation/remediation-runner-daemon.sh +13 -0
  49. package/templates/cursor/aaac/scripts/remediation/remediation-runner.mjs +748 -0
  50. package/templates/cursor/aaac/scripts/remediation/remediation-yield-watcher.mjs +40 -0
  51. package/templates/cursor/aaac/scripts/remediation/remediator-gate.mjs +405 -0
  52. package/templates/cursor/aaac/scripts/remediation/repair-fallow-start-baseline.mjs +118 -0
  53. package/templates/cursor/aaac/scripts/remediation/runner-health-check.mjs +164 -0
  54. package/templates/cursor/aaac/scripts/remediation/satisfaction-loop-gate.mjs +286 -0
  55. package/templates/cursor/aaac/scripts/remediation/validate-campaign-complete.mjs +191 -0
  56. package/templates/cursor/aaac/scripts/remediation/verify-remediation-iteration.mjs +112 -0
  57. package/templates/cursor/aaac/scripts/run-engine/debug-run.mjs +0 -0
  58. package/templates/cursor/aaac/scripts/run-engine/log-dump.mjs +0 -0
  59. package/templates/cursor/aaac/scripts/run-engine/log-trace.mjs +0 -0
  60. package/templates/cursor/agents/remediation-check-app-inventory.md +32 -0
  61. package/templates/cursor/agents/remediation-check-app-ssot.md +24 -0
  62. package/templates/cursor/agents/remediation-check-app-trace.md +29 -0
  63. package/templates/cursor/agents/remediation-check-architecture-boundaries.md +21 -0
  64. package/templates/cursor/agents/remediation-check-architecture-decomposition.md +25 -0
  65. package/templates/cursor/agents/remediation-check-architecture-deps.md +23 -0
  66. package/templates/cursor/agents/remediation-check-risk.md +37 -0
  67. package/templates/cursor/agents/remediation-e2e-gate.md +30 -0
  68. package/templates/cursor/agents/remediation-remediator.md +69 -0
  69. package/templates/cursor/commands/remediate-app.md +212 -0
  70. package/templates/cursor/hooks/aaac-before-submit.sh +0 -0
  71. package/templates/cursor/hooks/aaac-pre-tool.sh +0 -0
  72. package/templates/cursor/hooks/aaac-stop.sh +0 -0
  73. package/templates/cursor/hooks/aaac-subagent-start.sh +0 -0
  74. package/templates/cursor/skills/shared/remediation/SKILL.md +51 -0
  75. package/templates/cursor/skills/shared/remediation/babysit/SKILL.md +223 -0
  76. package/templates/cursor/skills/shared/remediation/check-swarm/SKILL.md +114 -0
  77. package/templates/cursor/skills/shared/remediation/orchestrator/SKILL.md +275 -0
  78. package/templates/cursor/skills/shared/remediation/orchestrator/contract.yaml +116 -0
  79. package/templates/docs/agentic_architecture.md +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ludecker/aaac",
3
- "version": "1.1.6",
3
+ "version": "1.2.0",
4
4
  "description": "Agentic Architecture as Code (AAAC) — installable Cursor agent framework",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -29,6 +29,13 @@
29
29
  "src/",
30
30
  "templates/"
31
31
  ],
32
+ "scripts": {
33
+ "test": "vitest run",
34
+ "test:watch": "vitest",
35
+ "test:node": "node --test tests/log.test.mjs",
36
+ "test:e2e": "pnpm exec playwright test",
37
+ "test:e2e:ui": "pnpm exec playwright test --ui"
38
+ },
32
39
  "devDependencies": {
33
40
  "@playwright/test": "^1.52.0",
34
41
  "vitest": "^3.2.4",
@@ -39,12 +46,5 @@
39
46
  },
40
47
  "publishConfig": {
41
48
  "access": "public"
42
- },
43
- "scripts": {
44
- "test": "vitest run",
45
- "test:watch": "vitest",
46
- "test:node": "node --test tests/log.test.mjs",
47
- "test:e2e": "pnpm exec playwright test",
48
- "test:e2e:ui": "pnpm exec playwright test --ui"
49
49
  }
50
- }
50
+ }
package/src/cli.mjs CHANGED
File without changes
File without changes
File without changes
File without changes
@@ -1,8 +1,23 @@
1
1
  {
2
2
  "version": 3,
3
3
  "description": "AAAC runtime enforcement — SSOT for hooks and run engine",
4
- "edit_phases": ["execute", "test_execute", "sync_inventory", "persist", "write"],
5
- "artifact_write_phases": ["plan", "report"],
4
+ "edit_phases": [
5
+ "execute",
6
+ "debt_sweep",
7
+ "test_execute",
8
+ "sync_inventory",
9
+ "persist",
10
+ "write"
11
+ ],
12
+ "artifact_write_phases": [
13
+ "plan",
14
+ "report",
15
+ "campaign_init",
16
+ "scan",
17
+ "check_swarm",
18
+ "plan_waves",
19
+ "satisfaction_gate"
20
+ ],
6
21
  "mutating_verbs": ["create", "update", "fix"],
7
22
  "phase_edit_scopes": {
8
23
  "execute": { "deny_test_paths": true },
@@ -19,6 +34,11 @@
19
34
  "verify_fix": 3,
20
35
  "review_swarm": 3
21
36
  },
37
+ "swarm_min_agents_by_command": {
38
+ "remediate-app": {
39
+ "check_swarm": 7
40
+ }
41
+ },
22
42
  "phase_artifacts": {
23
43
  "investigate_swarm": ["artifacts/investigation.md"],
24
44
  "root_cause": ["artifacts/root_cause.yaml"],
@@ -35,7 +55,68 @@
35
55
  },
36
56
  "allowed_path_prefixes": {
37
57
  "run_artifacts": [".cursor/aaac/state/runs/", "aaac/state/runs/"],
38
- "write_article": [".cursor/write-article-runs/"]
58
+ "campaign_artifacts": [".cursor/aaac/state/campaigns/", "aaac/state/campaigns/"]
59
+ },
60
+ "remediation_gate": {
61
+ "script": "verify-remediation-iteration.mjs",
62
+ "remediator_gate_script": "remediator-gate.mjs",
63
+ "debt_sweep_script": "debt-sweep-gate.mjs",
64
+ "satisfaction_loop_script": "satisfaction-loop-gate.mjs",
65
+ "repair_fallow_start_script": "repair-fallow-start-baseline.mjs",
66
+ "bootstrap_autonomous_script": "bootstrap-autonomous.mjs",
67
+ "runner_script": "remediation-runner.mjs",
68
+ "runner_daemon_script": "remediation-runner-daemon.sh",
69
+ "runner_health_script": "runner-health-check.mjs",
70
+ "plan_waves_script": "plan-waves-from-queue.mjs",
71
+ "validate_script": "validate-campaign-complete.mjs",
72
+ "baseline_script": "capture-verify-baseline.mjs",
73
+ "wave_snapshot_script": "capture-wave-snapshot.mjs",
74
+ "classify_fallow_script": "classify-fallow-issues.mjs",
75
+ "record_fallow_fp_script": "record-fallow-fp.mjs",
76
+ "fallow_fp_rules": "fallow-fp-rules.json",
77
+ "classify_script": "classify-verify-failure.mjs",
78
+ "dispatch_rules": "dispatch-rules.json",
79
+ "wave_mode": "wave",
80
+ "debt_mode": "debt",
81
+ "wave_gate_mode": "regression",
82
+ "debt_gate_mode": "strict",
83
+ "campaign_artifact": "artifacts/campaign.json",
84
+ "exit_codes": {
85
+ "promote": 0,
86
+ "block": 1,
87
+ "runtime_error": 2,
88
+ "remediate": 3
89
+ },
90
+ "invariants": {
91
+ "exit_3_is_continue": true,
92
+ "never_block_campaign_on_wave_exit_3": true,
93
+ "satisfaction_exit_3_is_continue_loop": true,
94
+ "fallow_start_baseline_immutable": true,
95
+ "validate_before_report": true
96
+ }
97
+ },
98
+ "phase_artifacts_remediate": {
99
+ "campaign_init": ["artifacts/campaign.json", "artifacts/verify_baseline.json"],
100
+ "scan": [
101
+ "artifacts/fallow_scan.json",
102
+ "artifacts/fallow_dupes.json",
103
+ "artifacts/fallow_health.json",
104
+ "artifacts/fallow_scan_bundle.json",
105
+ "artifacts/fallow_classification.json"
106
+ ],
107
+ "check_swarm": [
108
+ "artifacts/check_synthesis.md",
109
+ "artifacts/dispatch-queue.yaml",
110
+ "artifacts/check_app_validate.yaml",
111
+ "artifacts/check_architecture_fitness.yaml",
112
+ "artifacts/protected_paths.yaml",
113
+ "artifacts/check_swarm_merge.json"
114
+ ],
115
+ "plan_waves": ["artifacts/plan_waves.yaml"],
116
+ "execute": ["artifacts/execute_waves.yaml"],
117
+ "debt_sweep": ["artifacts/debt_sweep.json", "artifacts/verify_debt.json"],
118
+ "satisfaction_gate": ["artifacts/satisfaction.json", "artifacts/satisfaction_loop_gate.json"],
119
+ "report": ["artifacts/report.md"]
39
120
  },
40
121
  "fix_commands": ["fix-module", "fix-bug", "module-fix", "bug-fix"]
41
122
  }
@@ -31,6 +31,12 @@ orchestrators:
31
31
  path: skills/shared/platform-release/orchestrator
32
32
  requires: [testing, verification, execution, reporting]
33
33
 
34
+ remediate-app:
35
+ path: skills/shared/remediation/orchestrator
36
+ requires: [remediation, discovery, check, execution, testing, verification, reporting]
37
+ check_swarm_skill: skills/shared/remediation/check-swarm
38
+ phases: [campaign_init, scan, check_swarm, plan_waves, execute, debt_sweep, satisfaction_gate, report]
39
+
34
40
  verb-create:
35
41
  path: skills/shared/verbs/create/orchestrator
36
42
  requires: [discovery, investigation-lite, planning, validation, impact-analysis, dependency-graph, fitness-functions, rollback, execution, testing, verification, reporting, module-authoring]
@@ -143,6 +149,10 @@ skills:
143
149
  path: skills/shared/module-authoring
144
150
  platform-release:
145
151
  path: skills/shared/platform-release
152
+ remediation:
153
+ path: skills/shared/remediation
154
+ remediation-check-swarm:
155
+ path: skills/shared/remediation/check-swarm
146
156
  governance/implementation:
147
157
  path: skills/shared/governance/implementation
148
158
 
@@ -199,6 +209,24 @@ agents:
199
209
  path: agents/release-git.md
200
210
  wave: 1
201
211
  blocking: true
212
+ remediation-check-app-inventory:
213
+ path: agents/remediation-check-app-inventory.md
214
+ remediation-check-app-ssot:
215
+ path: agents/remediation-check-app-ssot.md
216
+ remediation-check-app-trace:
217
+ path: agents/remediation-check-app-trace.md
218
+ remediation-check-architecture-boundaries:
219
+ path: agents/remediation-check-architecture-boundaries.md
220
+ remediation-check-architecture-deps:
221
+ path: agents/remediation-check-architecture-deps.md
222
+ remediation-check-architecture-decomposition:
223
+ path: agents/remediation-check-architecture-decomposition.md
224
+ remediation-check-risk:
225
+ path: agents/remediation-check-risk.md
226
+ remediation-remediator:
227
+ path: agents/remediation-remediator.md
228
+ remediation-e2e-gate:
229
+ path: agents/remediation-e2e-gate.md
202
230
 
203
231
  policies:
204
232
  - policies/master-rules.md
@@ -125,6 +125,20 @@
125
125
  "report"
126
126
  ],
127
127
  "gate_stack": "pre_execute"
128
+ },
129
+ "remediate-app": {
130
+ "description": "Long-running remediation campaign — Fallow scan, check swarm, fix waves, debt sweep, satisfaction loop",
131
+ "work_phases": [
132
+ "campaign_init",
133
+ "scan",
134
+ "check_swarm",
135
+ "plan_waves",
136
+ "execute",
137
+ "debt_sweep",
138
+ "satisfaction_gate",
139
+ "report"
140
+ ],
141
+ "gate_stack": null
128
142
  }
129
143
  }
130
144
  }
@@ -17,6 +17,12 @@
17
17
  "test_execute": { "skill": "test-authoring" },
18
18
  "verify": { "skills": ["testing", "verification"] },
19
19
  "review_swarm": { "skill": "implementation-review", "readonly": true },
20
- "report": { "skill": "reporting" }
20
+ "report": { "skill": "reporting" },
21
+ "campaign_init": { "skill": "remediation", "readonly": true },
22
+ "scan": { "skill": "remediation", "readonly": true },
23
+ "check_swarm": { "skill": "check", "readonly": true },
24
+ "plan_waves": { "skill": "planning", "readonly": true },
25
+ "debt_sweep": { "skill": "remediation" },
26
+ "satisfaction_gate": { "skill": "remediation", "readonly": true }
21
27
  }
22
28
  }
@@ -180,6 +180,7 @@
180
180
  "review-incident": { "orchestrator": "review-incident" },
181
181
  "test-function": { "orchestrator": "test-function" },
182
182
  "release-app": { "orchestrator": "release-app" },
183
+ "remediate-app": { "orchestrator": "remediate-app", "object": "app" },
183
184
  "module-update": { "alias": "update-module" },
184
185
  "update-doc": { "alias": "update-architecture" },
185
186
  "architecture": { "alias": "update-architecture" },
@@ -2,5 +2,41 @@
2
2
  "manual_commands": [],
3
3
  "verify": {
4
4
  "enabled": false
5
+ },
6
+ "remediation": {
7
+ "fallow_cwd": ".",
8
+ "scan_root": ".",
9
+ "verify": {
10
+ "layers": [
11
+ {
12
+ "id": "typecheck",
13
+ "command": "npm",
14
+ "args": ["run", "typecheck"],
15
+ "cwd": ".",
16
+ "optional": true
17
+ },
18
+ {
19
+ "id": "vitest",
20
+ "command": "npm",
21
+ "args": ["test"],
22
+ "cwd": ".",
23
+ "optional": true
24
+ },
25
+ {
26
+ "id": "build",
27
+ "command": "npm",
28
+ "args": ["run", "build"],
29
+ "cwd": ".",
30
+ "optional": true
31
+ }
32
+ ],
33
+ "playwright": {
34
+ "enabled": false
35
+ },
36
+ "dev_server": {
37
+ "url": "http://localhost:3000",
38
+ "launch_hint": "Start your dev server before debt sweep / Playwright gates."
39
+ }
40
+ }
5
41
  }
6
42
  }
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Synthesize check-swarm-raw.json from Fallow health targets (scriptable check_swarm).
4
+ */
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import { isoNow } from "../run-engine/lib.mjs";
8
+ import { campaignDir, iterDir } from "./lib/runner-state.mjs";
9
+ import { loadCampaignContext } from "./lib/campaign-focus.mjs";
10
+ import {
11
+ fetchHealthTargets,
12
+ filterTargetsForWaves,
13
+ } from "./lib/fallow-health-targets.mjs";
14
+
15
+ const AGENT_IDS = [
16
+ "remediation-check-app-inventory",
17
+ "remediation-check-app-ssot",
18
+ "remediation-check-app-trace",
19
+ "remediation-check-architecture-boundaries",
20
+ "remediation-check-architecture-deps",
21
+ "remediation-check-architecture-decomposition",
22
+ "remediation-check-risk",
23
+ ];
24
+
25
+ function parseArgs(argv) {
26
+ const out = { campaignId: null, iteration: 0 };
27
+ for (let i = 0; i < argv.length; i++) {
28
+ if (argv[i] === "--campaign-id") out.campaignId = argv[++i];
29
+ else if (argv[i] === "--iteration") out.iteration = Number(argv[++i]);
30
+ }
31
+ return out;
32
+ }
33
+
34
+ const args = parseArgs(process.argv.slice(2));
35
+ if (!args.campaignId) {
36
+ console.error("--campaign-id required");
37
+ process.exit(2);
38
+ }
39
+
40
+ const ctx = loadCampaignContext(args.campaignId);
41
+ const { targets, score } = fetchHealthTargets({ scope: ctx.scope, limit: 15 });
42
+ const filtered = filterTargetsForWaves(targets, {
43
+ protected_paths: ctx.protected_paths,
44
+ defer_high_fan_in: ctx.focus.defer_high_fan_in,
45
+ });
46
+
47
+ const safeToFix = filtered.slice(0, 8).map((t) => ({
48
+ path: t.path,
49
+ category: "health_decompose",
50
+ evidence: t.recommendation ?? null,
51
+ }));
52
+
53
+ const baseFinding = `health ${score ?? "?"}; focus=${ctx.focus.health_functions_above_60_loc ? "functions>60LOC" : "general"}`;
54
+
55
+ const agents = AGENT_IDS.map((agent_id) => ({
56
+ agent_id,
57
+ command_mirror: agent_id.includes("risk") ? "check-risk" : agent_id.includes("architecture") ? "check-architecture" : "check-app",
58
+ answer: "partial",
59
+ confidence: "high",
60
+ false_positives: [],
61
+ protected_paths: ctx.protected_paths,
62
+ do_not_delete: ctx.protected_paths.map((p) => ({ path: p, reason: "protected" })),
63
+ safe_to_fix: safeToFix,
64
+ findings: [baseFinding, `auto-synthesis iter ${args.iteration}`],
65
+ gaps: [],
66
+ }));
67
+
68
+ const outPath = path.join(iterDir(args.campaignId, args.iteration), "check-swarm-raw.json");
69
+ fs.mkdirSync(path.dirname(outPath), { recursive: true });
70
+ fs.writeFileSync(
71
+ outPath,
72
+ JSON.stringify({ merged_at: isoNow(), iteration: args.iteration, focus: ctx.focus, agents }, null, 2),
73
+ );
74
+
75
+ console.log(JSON.stringify({ ok: true, path: outPath, agents: agents.length, safe_to_fix: safeToFix.length }));
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Build dispatch-queue.yaml from Fallow health targets + campaign focus.
4
+ */
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import { campaignDir, loadCampaign } from "./lib/runner-state.mjs";
8
+ import { loadCampaignContext, normalizeRepoPath } from "./lib/campaign-focus.mjs";
9
+ import {
10
+ fetchHealthTargets,
11
+ filterTargetsForWaves,
12
+ targetToWaveIntent,
13
+ } from "./lib/fallow-health-targets.mjs";
14
+ import { journal } from "./lib/runner-exec.mjs";
15
+
16
+ function parseArgs(argv) {
17
+ const out = { campaignId: null, iteration: null };
18
+ for (let i = 0; i < argv.length; i++) {
19
+ if (argv[i] === "--campaign-id") out.campaignId = argv[++i];
20
+ else if (argv[i] === "--iteration") out.iteration = Number(argv[++i]);
21
+ }
22
+ return out;
23
+ }
24
+
25
+ const args = parseArgs(process.argv.slice(2));
26
+ if (!args.campaignId) {
27
+ console.error("--campaign-id required");
28
+ process.exit(2);
29
+ }
30
+
31
+ const ctx = loadCampaignContext(args.campaignId);
32
+ const campaign = ctx.campaign;
33
+ const iteration = args.iteration ?? campaign.iteration ?? 0;
34
+ const maxWaves = campaign.config?.max_waves_per_iteration ?? 3;
35
+
36
+ const { targets } = fetchHealthTargets({ scope: ctx.scope, limit: 20 });
37
+ const filtered = filterTargetsForWaves(targets, {
38
+ protected_paths: ctx.protected_paths,
39
+ defer_high_fan_in: ctx.focus.defer_high_fan_in,
40
+ }).slice(0, maxWaves);
41
+
42
+ if (filtered.length === 0) {
43
+ console.error("No health targets available for waves");
44
+ process.exit(2);
45
+ }
46
+
47
+ const lines = [
48
+ `# iteration ${iteration} health waves — auto from Fallow targets`,
49
+ `iteration: ${iteration}`,
50
+ `campaign_id: ${args.campaignId}`,
51
+ `scope: ${ctx.scope}`,
52
+ `intent_focus: health`,
53
+ "",
54
+ "protected_paths:",
55
+ ...ctx.protected_paths.map((p) => ` - ${p}`),
56
+ "",
57
+ "waves:",
58
+ ];
59
+
60
+ for (let i = 0; i < filtered.length; i++) {
61
+ const t = filtered[i];
62
+ const risk = t.effort === "high" ? "medium" : "low";
63
+ lines.push(`- priority: ${i + 1}`);
64
+ lines.push(` command: fix-module`);
65
+ lines.push(` intent: ${targetToWaveIntent(t)}`);
66
+ lines.push(` risk: ${risk}`);
67
+ }
68
+
69
+ const yaml = `${lines.join("\n")}\n`;
70
+ const dest = path.join(campaignDir(args.campaignId), "dispatch-queue.yaml");
71
+ const artifact = path.join(campaignDir(args.campaignId), "artifacts", "dispatch-queue.yaml");
72
+ fs.writeFileSync(dest, yaml);
73
+ fs.mkdirSync(path.dirname(artifact), { recursive: true });
74
+ fs.writeFileSync(artifact, yaml);
75
+
76
+ journal(args.campaignId, `- **Auto dispatch-queue** iter ${iteration}: ${filtered.length} health wave(s)`);
77
+
78
+ console.log(JSON.stringify({ ok: true, waves: filtered.length, paths: filtered.map((t) => t.path) }));
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Write run + campaign artifacts when autonomous mode is active.
4
+ * Called from init-campaign.mjs — orchestrator MUST follow bootstrap.next_action.
5
+ *
6
+ * Usage:
7
+ * node bootstrap-autonomous.mjs --run-id <id> --campaign-id <id>
8
+ */
9
+ import fs from "fs";
10
+ import path from "path";
11
+ import { REPO_ROOT, isoNow, readJson, runDir, writeJson } from "../run-engine/lib.mjs";
12
+ import {
13
+ autonomousBootstrapCommands,
14
+ BABYSIT_SKILL,
15
+ } from "./lib/autonomous-mode.mjs";
16
+ import { loadRunnerState, loadYield, runnerStatePath, yieldArtifactPath } from "./lib/runner-state.mjs";
17
+
18
+ function parseArgs(argv) {
19
+ const out = { runId: null, campaignId: null };
20
+ for (let i = 0; i < argv.length; i++) {
21
+ const a = argv[i];
22
+ if (a === "--run-id") out.runId = argv[++i];
23
+ else if (a === "--campaign-id") out.campaignId = argv[++i];
24
+ }
25
+ return out;
26
+ }
27
+
28
+ const args = parseArgs(process.argv.slice(2));
29
+ if (!args.runId || !args.campaignId) {
30
+ console.error("bootstrap-autonomous: --run-id and --campaign-id required");
31
+ process.exit(2);
32
+ }
33
+
34
+ const campaignPath = path.join(
35
+ REPO_ROOT,
36
+ ".cursor/aaac/state/campaigns",
37
+ args.campaignId,
38
+ "campaign.json",
39
+ );
40
+ const campaign = readJson(campaignPath, null);
41
+ if (!campaign?.config?.autonomous) {
42
+ console.log(JSON.stringify({ ok: true, autonomous: false, skipped: true }));
43
+ process.exit(0);
44
+ }
45
+
46
+ const commands = autonomousBootstrapCommands(args.runId, args.campaignId);
47
+ const runnerState = loadRunnerState(args.campaignId);
48
+ const yieldPayload = loadYield(args.campaignId);
49
+
50
+ const bootstrap = {
51
+ ok: true,
52
+ autonomous: true,
53
+ autonomous_reason: campaign.config.autonomous_reason,
54
+ campaign_id: args.campaignId,
55
+ run_id: args.runId,
56
+ iteration: campaign.iteration,
57
+ satisfaction_threshold: campaign.config.satisfaction_threshold,
58
+ orchestrator_mode: "shell_runner_yield_watcher",
59
+ skill_required: BABYSIT_SKILL,
60
+ orchestrator_must_not: [
61
+ "walk_phases_manually_in_chat",
62
+ "end_turn_before_runner_exit_0",
63
+ "report_when_satisfaction_below_threshold",
64
+ ],
65
+ loop: [
66
+ "read_babysit_skill",
67
+ "runner_health_check",
68
+ "remediation_yield_watcher",
69
+ "if_exit_3_handle_yield_then_ack_yield",
70
+ "repeat_until_exit_0",
71
+ ],
72
+ commands,
73
+ runner_state_path: runnerStatePath(args.campaignId),
74
+ yield_path: yieldArtifactPath(args.campaignId),
75
+ current_runner: runnerState,
76
+ pending_yield: yieldPayload,
77
+ next_action: yieldPayload
78
+ ? {
79
+ type: "handle_yield",
80
+ yield_type: yieldPayload.type,
81
+ ack_command: `node .cursor/aaac/scripts/remediation/remediation-runner.mjs --run-id ${args.runId} --campaign-id ${args.campaignId} --ack-yield ${yieldPayload.type}`,
82
+ }
83
+ : {
84
+ type: "run_until_yield",
85
+ command: commands.runner_until_yield,
86
+ },
87
+ at: isoNow(),
88
+ };
89
+
90
+ const runArtifact = path.join(runDir(args.runId), "artifacts", "autonomous_bootstrap.json");
91
+ writeJson(runArtifact, bootstrap);
92
+
93
+ const campaignArtifact = path.join(
94
+ REPO_ROOT,
95
+ ".cursor/aaac/state/campaigns",
96
+ args.campaignId,
97
+ "autonomous-bootstrap.json",
98
+ );
99
+ writeJson(campaignArtifact, bootstrap);
100
+
101
+ appendJournal(args.campaignId, `- **Autonomous mode** — ${campaign.config.autonomous_reason}; bootstrap written`);
102
+
103
+ console.log(JSON.stringify(bootstrap));
104
+
105
+ function appendJournal(campaignId, line) {
106
+ const journalPath = path.join(
107
+ REPO_ROOT,
108
+ ".cursor/aaac/state/campaigns",
109
+ campaignId,
110
+ "journal.md",
111
+ );
112
+ fs.appendFileSync(journalPath, `\n${line}\n`);
113
+ }
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Capture campaign verify baseline at start (before any waves).
4
+ *
5
+ * Usage:
6
+ * node capture-verify-baseline.mjs --campaign-id <id> [--run-id <run_id>]
7
+ */
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import { REPO_ROOT, isoNow, readJson, writeJson, runDir } from "../run-engine/lib.mjs";
11
+ import {
12
+ runVerifySteps,
13
+ writeVerifyLogs,
14
+ summarizeMetrics,
15
+ } from "./lib/verify-metrics.mjs";
16
+
17
+ const CAMPAIGNS_ROOT = path.join(REPO_ROOT, ".cursor/aaac/state/campaigns");
18
+
19
+ function parseArgs(argv) {
20
+ const out = { campaignId: null, runId: null };
21
+ for (let i = 0; i < argv.length; i++) {
22
+ if (argv[i] === "--campaign-id") out.campaignId = argv[++i];
23
+ else if (argv[i] === "--run-id") out.runId = argv[++i];
24
+ }
25
+ return out;
26
+ }
27
+
28
+ const args = parseArgs(process.argv.slice(2));
29
+ if (!args.campaignId) {
30
+ console.error("capture-verify-baseline: --campaign-id required");
31
+ process.exit(2);
32
+ }
33
+
34
+ const campaignDir = path.join(CAMPAIGNS_ROOT, args.campaignId);
35
+ const baselineDir = path.join(campaignDir, "baseline");
36
+ fs.mkdirSync(baselineDir, { recursive: true });
37
+
38
+ const report = await runVerifySteps("wave");
39
+ writeVerifyLogs(report, baselineDir, "baseline");
40
+
41
+ const snapshot = {
42
+ captured_at: isoNow(),
43
+ kind: "campaign_verify_baseline",
44
+ summary: summarizeMetrics(report),
45
+ metrics: report.metrics,
46
+ report_path: path.join(baselineDir, "verify-baseline.json"),
47
+ };
48
+
49
+ writeJson(snapshot.report_path, report);
50
+ writeJson(path.join(campaignDir, "verify-baseline.json"), snapshot);
51
+
52
+ const campaign = readJson(path.join(campaignDir, "campaign.json"), {});
53
+ if (campaign) {
54
+ campaign.verify_baseline = snapshot.summary;
55
+ campaign.updated_at = isoNow();
56
+ writeJson(path.join(campaignDir, "campaign.json"), campaign);
57
+ }
58
+
59
+ if (args.runId) {
60
+ writeJson(path.join(runDir(args.runId), "artifacts", "verify_baseline.json"), snapshot);
61
+ }
62
+
63
+ const journal = `\n- **Verify baseline captured** — total_errors=${snapshot.summary.total_errors} (typecheck ${snapshot.summary.layers.typecheck.error_count}, vitest ${snapshot.summary.layers.vitest.error_count})\n`;
64
+ fs.appendFileSync(path.join(campaignDir, "journal.md"), journal);
65
+
66
+ console.log(JSON.stringify({ ok: true, baseline: snapshot }));