@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
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Snapshot verify metrics immediately before a cleanup wave executes.
4
+ *
5
+ * Usage:
6
+ * node capture-wave-snapshot.mjs --campaign-id <id> --iteration <n> --wave-index <w>
7
+ */
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import { spawnSync } from "child_process";
11
+ import { fileURLToPath } from "url";
12
+ import { REPO_ROOT, isoNow, writeJson } from "../run-engine/lib.mjs";
13
+ import { summarizeMetrics } from "./lib/verify-metrics.mjs";
14
+
15
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
+ const CAMPAIGNS_ROOT = path.join(REPO_ROOT, ".cursor/aaac/state/campaigns");
17
+ const VERIFY_SCRIPT = path.join(__dirname, "verify-remediation-iteration.mjs");
18
+
19
+ function parseArgs(argv) {
20
+ const out = { campaignId: null, iteration: 0, waveIndex: 0 };
21
+ for (let i = 0; i < argv.length; i++) {
22
+ if (argv[i] === "--campaign-id") out.campaignId = argv[++i];
23
+ else if (argv[i] === "--iteration") out.iteration = Number(argv[++i]);
24
+ else if (argv[i] === "--wave-index") out.waveIndex = Number(argv[++i]);
25
+ }
26
+ return out;
27
+ }
28
+
29
+ const args = parseArgs(process.argv.slice(2));
30
+ if (!args.campaignId) {
31
+ console.error("capture-wave-snapshot: --campaign-id required");
32
+ process.exit(2);
33
+ }
34
+
35
+ spawnSync(
36
+ process.execPath,
37
+ [
38
+ VERIFY_SCRIPT,
39
+ "--campaign-id",
40
+ args.campaignId,
41
+ "--iteration",
42
+ String(args.iteration),
43
+ "--mode",
44
+ "wave",
45
+ "--label",
46
+ `pre-wave-${args.waveIndex}`,
47
+ ],
48
+ { encoding: "utf8" },
49
+ );
50
+
51
+ const iterDir = path.join(
52
+ CAMPAIGNS_ROOT,
53
+ args.campaignId,
54
+ "iterations",
55
+ String(args.iteration),
56
+ );
57
+ const prePath = path.join(iterDir, `wave-${args.waveIndex}-pre.json`);
58
+ const verifyPath = path.join(iterDir, "verify-wave.json");
59
+
60
+ let report = null;
61
+ try {
62
+ report = JSON.parse(fs.readFileSync(verifyPath, "utf8"));
63
+ } catch {
64
+ console.error("capture-wave-snapshot: missing verify-wave.json");
65
+ process.exit(2);
66
+ }
67
+
68
+ const snapshot = {
69
+ captured_at: isoNow(),
70
+ kind: "pre_wave",
71
+ wave_index: args.waveIndex,
72
+ iteration: args.iteration,
73
+ summary: summarizeMetrics(report),
74
+ metrics: report.metrics,
75
+ };
76
+ writeJson(prePath, snapshot);
77
+ fs.copyFileSync(verifyPath, path.join(iterDir, `wave-${args.waveIndex}-pre-verify.json`));
78
+
79
+ console.log(JSON.stringify({ ok: true, snapshot_path: prePath, summary: snapshot.summary }));
@@ -0,0 +1,26 @@
1
+ {
2
+ "campaign_id": "campaign_EXAMPLE",
3
+ "iteration": 0,
4
+ "collected_at": "ISO8601",
5
+ "agents": [
6
+ {
7
+ "agent_id": "remediation-check-app-inventory",
8
+ "command_mirror": "check-app",
9
+ "answer": "partial",
10
+ "confidence": "high",
11
+ "false_positives": [
12
+ {
13
+ "path": "src/hooks/useCryptoPriceWorker.ts",
14
+ "export_name": null,
15
+ "reason": "worker_hook_runtime",
16
+ "evidence": "src/hooks/useCryptoPriceWorker.ts:1"
17
+ }
18
+ ],
19
+ "protected_paths": ["src/hooks/useCryptoPriceWorker.ts"],
20
+ "do_not_delete": [],
21
+ "safe_to_fix": [],
22
+ "findings": [],
23
+ "gaps": []
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,77 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Classify Fallow scan findings and persist actionable vs false-positive SSOT.
4
+ *
5
+ * Usage:
6
+ * node classify-fallow-issues.mjs --campaign-id <id> --iteration <n> [--save-actionable-baseline]
7
+ */
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import { REPO_ROOT, isoNow, readJson, writeJson } from "../run-engine/lib.mjs";
11
+ import { classifyFallowScan, loadFpRules } from "./lib/fallow-classifier.mjs";
12
+
13
+ const CAMPAIGNS_ROOT = path.join(REPO_ROOT, ".cursor/aaac/state/campaigns");
14
+
15
+ function parseArgs(argv) {
16
+ const out = { campaignId: null, iteration: 0, saveActionableBaseline: false };
17
+ for (let i = 0; i < argv.length; i++) {
18
+ const a = argv[i];
19
+ if (a === "--campaign-id") out.campaignId = argv[++i];
20
+ else if (a === "--iteration") out.iteration = Number(argv[++i]);
21
+ else if (a === "--save-actionable-baseline") out.saveActionableBaseline = true;
22
+ }
23
+ return out;
24
+ }
25
+
26
+ const args = parseArgs(process.argv.slice(2));
27
+ if (!args.campaignId) {
28
+ console.error("classify-fallow-issues: --campaign-id required");
29
+ process.exit(2);
30
+ }
31
+
32
+ const campaignDir = path.join(CAMPAIGNS_ROOT, args.campaignId);
33
+ const iterDir = path.join(campaignDir, "iterations", String(args.iteration));
34
+ const scanPath = path.join(iterDir, "fallow-scan.json");
35
+ const scan = readJson(scanPath, null);
36
+
37
+ if (!scan) {
38
+ console.error(`classify-fallow-issues: missing ${scanPath}`);
39
+ process.exit(2);
40
+ }
41
+
42
+ const classification = classifyFallowScan({
43
+ scan,
44
+ campaignDir,
45
+ rules: loadFpRules(),
46
+ });
47
+
48
+ const outPath = path.join(iterDir, "fallow-classification.json");
49
+ writeJson(outPath, classification);
50
+
51
+ const actionableBaselinePath = path.join(campaignDir, "fallow-start-actionable-baseline.json");
52
+ if (args.saveActionableBaseline && !fs.existsSync(actionableBaselinePath)) {
53
+ writeJson(actionableBaselinePath, {
54
+ actionable_total: classification.summary.actionable_total,
55
+ raw_total: classification.summary.raw_total,
56
+ false_positive_total: classification.summary.false_positive_total,
57
+ recorded_at: isoNow(),
58
+ immutable: true,
59
+ source: "classify-fallow-issues",
60
+ iteration: args.iteration,
61
+ });
62
+ }
63
+
64
+ const campaign = readJson(path.join(campaignDir, "campaign.json"), null);
65
+ if (campaign) {
66
+ campaign.current = campaign.current ?? {};
67
+ campaign.current.fallow_raw_total = classification.summary.raw_total;
68
+ campaign.current.fallow_actionable_total = classification.summary.actionable_total;
69
+ campaign.current.fallow_false_positive_total = classification.summary.false_positive_total;
70
+ campaign.updated_at = isoNow();
71
+ writeJson(path.join(campaignDir, "campaign.json"), campaign);
72
+ }
73
+
74
+ const journal = `\n- **Fallow classified** iter ${args.iteration}: raw=${classification.summary.raw_total}, actionable=${classification.summary.actionable_total}, false_positive=${classification.summary.false_positive_total}, review=${classification.summary.review_total}\n`;
75
+ fs.appendFileSync(path.join(campaignDir, "journal.md"), journal);
76
+
77
+ console.log(JSON.stringify({ ok: true, classification: classification.summary, path: outPath }));
@@ -0,0 +1,176 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Classify verify-remediation report failures → fix-module / fix-bug handoffs.
4
+ *
5
+ * Usage:
6
+ * node classify-verify-failure.mjs --report <path> --campaign-id <id> [--iteration n] [--wave-index n] [--attempt n]
7
+ */
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import { fileURLToPath } from "url";
11
+ import { REPO_ROOT, readJson } from "../run-engine/lib.mjs";
12
+
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+ const RULES_PATH = path.join(__dirname, "dispatch-rules.json");
15
+
16
+ function parseArgs(argv) {
17
+ const out = {
18
+ reportPath: null,
19
+ campaignId: "",
20
+ iteration: 0,
21
+ waveIndex: null,
22
+ attempt: 1,
23
+ };
24
+ for (let i = 0; i < argv.length; i++) {
25
+ const a = argv[i];
26
+ if (a === "--report") out.reportPath = argv[++i];
27
+ else if (a === "--campaign-id") out.campaignId = argv[++i];
28
+ else if (a === "--iteration") out.iteration = Number(argv[++i]);
29
+ else if (a === "--wave-index") out.waveIndex = Number(argv[++i]);
30
+ else if (a === "--attempt") out.attempt = Number(argv[++i]);
31
+ }
32
+ return out;
33
+ }
34
+
35
+ function loadRules() {
36
+ return readJson(RULES_PATH, { layers: {}, evidence_priority: [] });
37
+ }
38
+
39
+ function readLogFile(logPath) {
40
+ if (!logPath || !fs.existsSync(logPath)) return "";
41
+ try {
42
+ return fs.readFileSync(logPath, "utf8");
43
+ } catch {
44
+ return "";
45
+ }
46
+ }
47
+
48
+ function evidenceText(step) {
49
+ if (!step) return "";
50
+ const fromLog = readLogFile(step.log_path);
51
+ if (fromLog) return fromLog;
52
+ return [
53
+ step.stdout_full,
54
+ step.stderr_full,
55
+ step.stderr_tail,
56
+ step.stdout_tail,
57
+ step.detail,
58
+ ]
59
+ .filter(Boolean)
60
+ .join("\n");
61
+ }
62
+
63
+ function extractFilePaths(text) {
64
+ const paths = new Set();
65
+ const patterns = [
66
+ /(?:frontend|backend)\/[^\s:'"]+\.(?:tsx?|jsx?|go)/g,
67
+ /src\/[^\s:'"]+\.(?:tsx?|jsx?)/g,
68
+ /internal\/[^\s:'"]+\.go/g,
69
+ /[^\s('"]+\.(?:test|spec)\.(?:tsx?|jsx?)/g,
70
+ ];
71
+ for (const re of patterns) {
72
+ for (const m of text.matchAll(re)) {
73
+ paths.add(m[0].replace(/^[('"]+/, ""));
74
+ }
75
+ }
76
+ return [...paths];
77
+ }
78
+
79
+ function inferDomain(layer, evidence, ruleDomain) {
80
+ const paths = extractFilePaths(evidence);
81
+ if (paths.some((p) => p.startsWith("backend/") || p.includes("/internal/") || p.endsWith(".go"))) {
82
+ return "backend";
83
+ }
84
+ if (paths.some((p) => p.startsWith("frontend/") || p.startsWith("src/"))) {
85
+ return "frontend";
86
+ }
87
+ return ruleDomain ?? "frontend";
88
+ }
89
+
90
+ function pickCommand(layer, rule, evidence) {
91
+ if (layer === "playwright" && /frontend not reachable|launch via/i.test(evidence)) {
92
+ return { command: null, level: "infrastructure", handoff: rule.layers?.playwright_infra?.handoff ?? "/launch-se100" };
93
+ }
94
+ if (layer === "playwright" && /does not provide an export|Failed to fetch dynamically imported module|Cannot find module/i.test(evidence)) {
95
+ return { command: rule.module_import_command ?? "fix-module", level: "code" };
96
+ }
97
+ if (layer === "vitest" && /\.(test|spec)\.(tsx?|jsx?)/.test(evidence) && !/src\/(?!.*\.test\.)/.test(evidence.split("\n")[0] ?? "")) {
98
+ return { command: rule.test_file_command ?? rule.command, level: "test" };
99
+ }
100
+ return { command: rule.command, level: rule.level ?? "code" };
101
+ }
102
+
103
+ function fillTemplate(template, vars) {
104
+ return template.replace(/\{(\w+)\}/g, (_, key) => String(vars[key] ?? ""));
105
+ }
106
+
107
+ function classifyReport(report, ctx) {
108
+ const rules = loadRules();
109
+ const failedLayers = rules.evidence_priority.filter((layer) => report[layer]?.status === "fail");
110
+ const handoffs = [];
111
+
112
+ for (const layer of failedLayers) {
113
+ const rule = rules.layers[layer];
114
+ if (!rule) continue;
115
+ const evidence = evidenceText(report[layer]);
116
+ const picked = pickCommand(layer, rule, evidence);
117
+ if (picked.level === "infrastructure") {
118
+ handoffs.push({
119
+ layer,
120
+ level: "infrastructure",
121
+ command: null,
122
+ domain: null,
123
+ intent: null,
124
+ handoff: picked.handoff,
125
+ evidence: evidence.slice(0, 16000),
126
+ evidence_truncated: evidence.length > 16000,
127
+ log_path: report[layer]?.log_path ?? null,
128
+ file_paths: extractFilePaths(evidence),
129
+ });
130
+ continue;
131
+ }
132
+ const domain = inferDomain(layer, evidence, rule.domain);
133
+ const intent = fillTemplate(rule.intent_template, {
134
+ campaign_id: ctx.campaignId,
135
+ iteration: ctx.iteration,
136
+ wave_index: ctx.waveIndex ?? "n/a",
137
+ attempt: ctx.attempt,
138
+ evidence: evidence.slice(0, 16000),
139
+ });
140
+ handoffs.push({
141
+ layer,
142
+ level: picked.level,
143
+ command: picked.command,
144
+ domain,
145
+ intent,
146
+ slash_command: `/${picked.command} ${domain} "${intent.replace(/"/g, '\\"').slice(0, 500)}…"`,
147
+ evidence: evidence.slice(0, 16000),
148
+ evidence_truncated: evidence.length > 16000,
149
+ log_path: report[layer]?.log_path ?? null,
150
+ file_paths: extractFilePaths(evidence),
151
+ });
152
+ }
153
+
154
+ return {
155
+ status: handoffs.length ? "fail" : "pass",
156
+ failed_layers: failedLayers,
157
+ handoffs,
158
+ primary: handoffs.find((h) => h.command) ?? handoffs[0] ?? null,
159
+ };
160
+ }
161
+
162
+ const args = parseArgs(process.argv.slice(2));
163
+ if (!args.reportPath) {
164
+ console.error("classify-verify-failure: --report required");
165
+ process.exit(2);
166
+ }
167
+
168
+ const report = readJson(args.reportPath, null);
169
+ if (!report) {
170
+ console.error(`classify-verify-failure: cannot read report ${args.reportPath}`);
171
+ process.exit(2);
172
+ }
173
+
174
+ const classification = classifyReport(report, args);
175
+ console.log(JSON.stringify({ ok: true, classification }));
176
+ process.exit(classification.status === "pass" ? 0 : 1);