@ludecker/aaac 1.0.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 (110) hide show
  1. package/README.md +60 -0
  2. package/package.json +38 -0
  3. package/src/cli.mjs +138 -0
  4. package/src/generators/generate-commands.mjs +165 -0
  5. package/src/generators/generate-graph-commands.mjs +63 -0
  6. package/src/generators/generate-graph.mjs +242 -0
  7. package/src/lib/copy.mjs +36 -0
  8. package/src/lib/install.mjs +76 -0
  9. package/src/lib/paths.mjs +54 -0
  10. package/templates/cursor/aaac/capabilities/registry.json +106 -0
  11. package/templates/cursor/aaac/contract-schema.md +66 -0
  12. package/templates/cursor/aaac/contracts/commands/create-module.yaml +28 -0
  13. package/templates/cursor/aaac/contracts/commands/fix-bug.yaml +32 -0
  14. package/templates/cursor/aaac/contracts/commands/update-module.yaml +28 -0
  15. package/templates/cursor/aaac/contracts/skills/impact-analysis.yaml +17 -0
  16. package/templates/cursor/aaac/contracts/skills/investigation-lite.yaml +17 -0
  17. package/templates/cursor/aaac/contracts/skills/investigation.yaml +17 -0
  18. package/templates/cursor/aaac/contracts/skills/validation.yaml +14 -0
  19. package/templates/cursor/aaac/dependencies.yaml +14 -0
  20. package/templates/cursor/aaac/dispatch.md +135 -0
  21. package/templates/cursor/aaac/fitness-functions.yaml +34 -0
  22. package/templates/cursor/aaac/governance/gates.json +39 -0
  23. package/templates/cursor/aaac/graph.project.yaml +161 -0
  24. package/templates/cursor/aaac/layers.md +93 -0
  25. package/templates/cursor/aaac/lifecycle/lifecycle.json +78 -0
  26. package/templates/cursor/aaac/lifecycle/phases.json +19 -0
  27. package/templates/cursor/aaac/ontology.json +219 -0
  28. package/templates/cursor/aaac/ontology.md +90 -0
  29. package/templates/cursor/aaac/project.config.json +3 -0
  30. package/templates/cursor/aaac/run/RUN.md +72 -0
  31. package/templates/cursor/aaac/run/schema.json +83 -0
  32. package/templates/cursor/aaac/state/checkpoints/README.md +20 -0
  33. package/templates/cursor/agents/boundary-review.md +11 -0
  34. package/templates/cursor/agents/check-capability-trace.md +18 -0
  35. package/templates/cursor/agents/dependency-analysis.md +11 -0
  36. package/templates/cursor/agents/discovery-boundaries.md +11 -0
  37. package/templates/cursor/agents/discovery-inventory.md +14 -0
  38. package/templates/cursor/agents/discovery-ssot.md +11 -0
  39. package/templates/cursor/agents/fallow-check-changed.md +9 -0
  40. package/templates/cursor/agents/impact-analysis.md +22 -0
  41. package/templates/cursor/agents/plan-layer-map.md +11 -0
  42. package/templates/cursor/agents/plan-state-machines.md +11 -0
  43. package/templates/cursor/agents/release-git.md +36 -0
  44. package/templates/cursor/agents/system-decomposition.md +11 -0
  45. package/templates/cursor/agents/unit-test-run.md +19 -0
  46. package/templates/cursor/policies/implementation.md +8 -0
  47. package/templates/cursor/policies/master-rules.md +7 -0
  48. package/templates/cursor/skills/shared/api/SKILL.md +26 -0
  49. package/templates/cursor/skills/shared/architecture/SKILL.md +25 -0
  50. package/templates/cursor/skills/shared/architecture/orchestrator/SKILL.md +21 -0
  51. package/templates/cursor/skills/shared/architecture/refactor-analysis.md +302 -0
  52. package/templates/cursor/skills/shared/check/SKILL.md +47 -0
  53. package/templates/cursor/skills/shared/component/SKILL.md +24 -0
  54. package/templates/cursor/skills/shared/dependency-graph/SKILL.md +38 -0
  55. package/templates/cursor/skills/shared/discovery/SKILL.md +29 -0
  56. package/templates/cursor/skills/shared/documentation/SKILL.md +21 -0
  57. package/templates/cursor/skills/shared/documentation/orchestrator/SKILL.md +26 -0
  58. package/templates/cursor/skills/shared/documentation/orchestrator/contract.yaml +20 -0
  59. package/templates/cursor/skills/shared/documentation/write-arch-doc.md +168 -0
  60. package/templates/cursor/skills/shared/domain/SKILL.md +24 -0
  61. package/templates/cursor/skills/shared/execution/SKILL.md +34 -0
  62. package/templates/cursor/skills/shared/fitness-functions/SKILL.md +42 -0
  63. package/templates/cursor/skills/shared/governance/implementation/SKILL.md +424 -0
  64. package/templates/cursor/skills/shared/impact-analysis/SKILL.md +44 -0
  65. package/templates/cursor/skills/shared/integration/SKILL.md +22 -0
  66. package/templates/cursor/skills/shared/investigation/SKILL.md +46 -0
  67. package/templates/cursor/skills/shared/investigation/orchestrator/SKILL.md +22 -0
  68. package/templates/cursor/skills/shared/investigation-lite/SKILL.md +38 -0
  69. package/templates/cursor/skills/shared/migration/SKILL.md +22 -0
  70. package/templates/cursor/skills/shared/model/SKILL.md +22 -0
  71. package/templates/cursor/skills/shared/module-authoring/SKILL.md +29 -0
  72. package/templates/cursor/skills/shared/module-authoring/authoring-template.md +9 -0
  73. package/templates/cursor/skills/shared/planning/SKILL.md +30 -0
  74. package/templates/cursor/skills/shared/platform-release/SKILL.md +46 -0
  75. package/templates/cursor/skills/shared/platform-release/orchestrator/SKILL.md +51 -0
  76. package/templates/cursor/skills/shared/platform-release/orchestrator/contract.yaml +29 -0
  77. package/templates/cursor/skills/shared/platform-release/ship-procedure.md +31 -0
  78. package/templates/cursor/skills/shared/remove/SKILL.md +28 -0
  79. package/templates/cursor/skills/shared/reporting/SKILL.md +43 -0
  80. package/templates/cursor/skills/shared/rollback/SKILL.md +46 -0
  81. package/templates/cursor/skills/shared/root-cause/SKILL.md +24 -0
  82. package/templates/cursor/skills/shared/run/SKILL.md +64 -0
  83. package/templates/cursor/skills/shared/schema/SKILL.md +24 -0
  84. package/templates/cursor/skills/shared/testing/SKILL.md +24 -0
  85. package/templates/cursor/skills/shared/testing/orchestrator/SKILL.md +22 -0
  86. package/templates/cursor/skills/shared/validation/SKILL.md +56 -0
  87. package/templates/cursor/skills/shared/verbs/_dispatch-utils.md +90 -0
  88. package/templates/cursor/skills/shared/verbs/_lifecycle.md +87 -0
  89. package/templates/cursor/skills/shared/verbs/_object-skills.md +60 -0
  90. package/templates/cursor/skills/shared/verbs/check/orchestrator/SKILL.md +22 -0
  91. package/templates/cursor/skills/shared/verbs/check/orchestrator/contract.yaml +24 -0
  92. package/templates/cursor/skills/shared/verbs/create/orchestrator/SKILL.md +39 -0
  93. package/templates/cursor/skills/shared/verbs/create/orchestrator/contract.yaml +34 -0
  94. package/templates/cursor/skills/shared/verbs/fix/orchestrator/SKILL.md +33 -0
  95. package/templates/cursor/skills/shared/verbs/fix/orchestrator/contract.yaml +38 -0
  96. package/templates/cursor/skills/shared/verbs/release/orchestrator/SKILL.md +29 -0
  97. package/templates/cursor/skills/shared/verbs/release/orchestrator/contract.yaml +25 -0
  98. package/templates/cursor/skills/shared/verbs/remove/orchestrator/SKILL.md +25 -0
  99. package/templates/cursor/skills/shared/verbs/remove/orchestrator/contract.yaml +32 -0
  100. package/templates/cursor/skills/shared/verbs/review/orchestrator/SKILL.md +24 -0
  101. package/templates/cursor/skills/shared/verbs/review/orchestrator/contract.yaml +25 -0
  102. package/templates/cursor/skills/shared/verbs/test/orchestrator/SKILL.md +24 -0
  103. package/templates/cursor/skills/shared/verbs/test/orchestrator/contract.yaml +25 -0
  104. package/templates/cursor/skills/shared/verbs/update/orchestrator/SKILL.md +34 -0
  105. package/templates/cursor/skills/shared/verbs/update/orchestrator/contract.yaml +34 -0
  106. package/templates/cursor/skills/shared/verification/SKILL.md +28 -0
  107. package/templates/cursor/skills/shared/workflow/SKILL.md +25 -0
  108. package/templates/docs/agentic_architecture.md +131 -0
  109. package/templates/docs/architecture.md +5 -0
  110. package/templates/docs/master_rules.md +5 -0
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # @ludecker/aaac
2
+
3
+ **Agentic Architecture as Code (AAAC)** — a complete agentic architecture framework for Cursor.
4
+
5
+ > Commands are the public API. Skills, agents, and orchestrators are private implementation.
6
+
7
+ ## Install
8
+
9
+ No `npm` CLI required. Use `npx` or `pnpm dlx`:
10
+
11
+ ```bash
12
+ npx @ludecker/aaac@latest init
13
+ ```
14
+
15
+ ```bash
16
+ pnpm dlx @ludecker/aaac@latest init
17
+ ```
18
+
19
+ Non-interactive:
20
+
21
+ ```bash
22
+ npx @ludecker/aaac@latest init --yes --dir /path/to/your/repo
23
+ ```
24
+
25
+ ## What you get
26
+
27
+ - `.cursor/aaac/` — ontology, graph, lifecycle, run model, generators config
28
+ - `.cursor/skills/shared/` — full pipeline (discovery → execute → verify → report)
29
+ - `.cursor/agents/` — 13 generic subagent specs
30
+ - `.cursor/commands/` — ~130 generated slash commands
31
+ - `docs/agentic_architecture.md` — user + maintainer guide
32
+
33
+ Add project-specific **domains** under `.cursor/domains/<slug>/` (see maintainer appendix).
34
+
35
+ ## Regenerate
36
+
37
+ After editing `ontology.json` or `graph.project.yaml`:
38
+
39
+ ```bash
40
+ npx @ludecker/aaac@latest generate
41
+ pnpm dlx @ludecker/aaac@latest generate
42
+ ```
43
+
44
+ ## Links
45
+
46
+ - [Install guide](https://ludecker.com/guide/install-aaac)
47
+ - [Package on npm](https://www.npmjs.com/package/@ludecker/aaac)
48
+ - [Lüdecker](https://ludecker.com) — reference implementation
49
+
50
+ ## Publish (maintainers)
51
+
52
+ Authenticate with a registry token in `.npmrc` (used by pnpm, not the `npm` CLI):
53
+
54
+ ```bash
55
+ pnpm --filter @ludecker/aaac publish --access public --no-git-checks
56
+ git tag aaac-v1.0.0
57
+ git push origin aaac-v1.0.0
58
+ ```
59
+
60
+ CI publishes on `aaac-v*` tags via `.github/workflows/publish-aaac.yml` (`NPM_TOKEN` secret).
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@ludecker/aaac",
3
+ "version": "1.0.0",
4
+ "description": "Agentic Architecture as Code (AAAC) — installable Cursor agent framework",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Hans-Erik Lydecker",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/eriklydecker/ludecker.git",
11
+ "directory": "packages/aaac"
12
+ },
13
+ "homepage": "https://ludecker.com/guide/install-aaac",
14
+ "bugs": {
15
+ "url": "https://github.com/eriklydecker/ludecker/issues"
16
+ },
17
+ "keywords": [
18
+ "aaac",
19
+ "agentic-architecture",
20
+ "cursor",
21
+ "ai-agents",
22
+ "skills",
23
+ "commands"
24
+ ],
25
+ "bin": {
26
+ "aaac": "./src/cli.mjs"
27
+ },
28
+ "files": [
29
+ "src/",
30
+ "templates/"
31
+ ],
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ }
38
+ }
package/src/cli.mjs ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ import readline from "readline";
3
+ import path from "path";
4
+ import { parseArgs } from "./lib/paths.mjs";
5
+ import { installAaac, runGenerators } from "./lib/install.mjs";
6
+ import { resolveCursorRoot } from "./lib/paths.mjs";
7
+
8
+ function printHelp() {
9
+ console.log(`@ludecker/aaac — Agentic Architecture as Code
10
+
11
+ Usage:
12
+ npx @ludecker/aaac@latest init [options]
13
+ pnpm dlx @ludecker/aaac@latest init [options]
14
+ aaac generate [options]
15
+
16
+ Commands:
17
+ init Copy AAAC kernel into .cursor/ and docs/ (default)
18
+ generate Regenerate graph.yaml and commands from ontology
19
+
20
+ Options:
21
+ --dir <path> Target project directory (default: cwd)
22
+ --yes, -y Non-interactive defaults
23
+ --force Backup existing .cursor/ and replace
24
+
25
+ Install (no npm CLI required):
26
+ npx @ludecker/aaac@latest init
27
+ pnpm dlx @ludecker/aaac@latest init
28
+
29
+ Docs: https://ludecker.com/guide/install-aaac
30
+ Package: https://www.npmjs.com/package/@ludecker/aaac
31
+ `);
32
+ }
33
+
34
+ function ask(question, defaultValue) {
35
+ const rl = readline.createInterface({
36
+ input: process.stdin,
37
+ output: process.stdout,
38
+ });
39
+ const prompt = defaultValue
40
+ ? `${question} [${defaultValue}]: `
41
+ : `${question}: `;
42
+ return new Promise((resolve) => {
43
+ rl.question(prompt, (answer) => {
44
+ rl.close();
45
+ const trimmed = answer.trim();
46
+ resolve(trimmed || defaultValue || "");
47
+ });
48
+ });
49
+ }
50
+
51
+ async function promptInitOptions(args) {
52
+ if (args.yes) {
53
+ const dir = args.dir ? path.resolve(args.dir) : process.cwd();
54
+ const base = path.basename(dir);
55
+ return {
56
+ targetDir: dir,
57
+ projectName: base || "my-project",
58
+ docsRoot: "docs",
59
+ };
60
+ }
61
+
62
+ const targetDir = args.dir
63
+ ? path.resolve(args.dir)
64
+ : await ask("Project directory", process.cwd());
65
+ const projectName = await ask(
66
+ "Project name",
67
+ path.basename(targetDir) || "my-project",
68
+ );
69
+ const docsRoot = await ask("Docs folder (relative to project)", "docs");
70
+
71
+ return { targetDir, projectName, docsRoot };
72
+ }
73
+
74
+ async function cmdInit(args) {
75
+ const options = await promptInitOptions(args);
76
+ console.log(`\nInstalling AAAC into ${options.targetDir}...\n`);
77
+
78
+ const { cursorDest, docsDest } = installAaac({
79
+ targetDir: options.targetDir,
80
+ projectName: options.projectName,
81
+ docsRoot: options.docsRoot,
82
+ force: args.force,
83
+ });
84
+
85
+ console.log(`
86
+ AAAC installed.
87
+
88
+ .cursor/ → ${cursorDest}
89
+ docs/ → ${docsDest}
90
+
91
+ Next steps:
92
+ 1. Open the project in Cursor
93
+ 2. Create ${options.docsRoot}/master_rules.md and ${options.docsRoot}/architecture.md if missing
94
+ 3. Try /review-architecture or /check-architecture
95
+ 4. Read ${options.docsRoot}/agentic_architecture.md — Part 2 for adding domains
96
+
97
+ Regenerate after ontology changes:
98
+ pnpm dlx @ludecker/aaac@latest generate
99
+ npx @ludecker/aaac@latest generate
100
+ `);
101
+ }
102
+
103
+ function cmdGenerate(args) {
104
+ const targetDir = args.dir ? path.resolve(args.dir) : process.cwd();
105
+ const cursorRoot = resolveCursorRoot(path.join(targetDir, ".cursor"));
106
+ console.log(`Regenerating AAAC graph at ${cursorRoot}...`);
107
+ runGenerators(cursorRoot);
108
+ console.log("Done.");
109
+ }
110
+
111
+ async function main() {
112
+ const argv = process.argv.slice(2);
113
+ if (argv.includes("--help") || argv.includes("-h")) {
114
+ printHelp();
115
+ return;
116
+ }
117
+
118
+ const args = parseArgs(process.argv);
119
+ const sub = argv.find((a) => !a.startsWith("-")) ?? "init";
120
+
121
+ if (sub === "init") {
122
+ await cmdInit(args);
123
+ return;
124
+ }
125
+ if (sub === "generate") {
126
+ cmdGenerate(args);
127
+ return;
128
+ }
129
+
130
+ console.error(`Unknown command: ${sub}`);
131
+ printHelp();
132
+ process.exit(1);
133
+ }
134
+
135
+ main().catch((err) => {
136
+ console.error(err.message ?? err);
137
+ process.exit(1);
138
+ });
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Regenerates .cursor/commands/<verb>-<object>.md from ontology.json
4
+ * Prunes stale command files. manual_commands from aaac/project.config.json
5
+ */
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import { aaacDir, parseArgs, resolveCursorRoot } from "../lib/paths.mjs";
9
+
10
+ const args = parseArgs(process.argv);
11
+ const cursorRoot = resolveCursorRoot(args.root);
12
+ const aaac = aaacDir(cursorRoot);
13
+ const commandsDir = path.join(cursorRoot, "commands");
14
+ fs.mkdirSync(commandsDir, { recursive: true });
15
+
16
+ const data = JSON.parse(
17
+ fs.readFileSync(path.join(aaac, "ontology.json"), "utf8"),
18
+ );
19
+
20
+ const projectConfigPath = path.join(aaac, "project.config.json");
21
+ const projectConfig = fs.existsSync(projectConfigPath)
22
+ ? JSON.parse(fs.readFileSync(projectConfigPath, "utf8"))
23
+ : { manual_commands: [] };
24
+
25
+ const {
26
+ verbs,
27
+ objects,
28
+ invalid_pairs,
29
+ command_overrides,
30
+ command_aliases,
31
+ } = data;
32
+
33
+ const invalid = new Set(invalid_pairs.map(([v, o]) => `${v}-${o}`));
34
+
35
+ const KEEP_EXTRA = new Set(projectConfig.manual_commands ?? []);
36
+
37
+ const EXCEPTION_CMD = {
38
+ "fix-bug": {
39
+ layer: "product",
40
+ description: "defect repair (resolver; not in 12-object matrix)",
41
+ },
42
+ "review-incident": {
43
+ layer: "system",
44
+ description: "production incident investigation",
45
+ },
46
+ };
47
+
48
+ function objectMeta(object, cmd) {
49
+ if (EXCEPTION_CMD[cmd]) return EXCEPTION_CMD[cmd];
50
+ const o = objects[object];
51
+ if (!o) return { layer: null, description: object };
52
+ if (typeof o === "string") return { layer: null, description: o };
53
+ return { layer: o.layer ?? null, description: o.description ?? object };
54
+ }
55
+
56
+ function cap(s) {
57
+ return s.charAt(0).toUpperCase() + s.slice(1);
58
+ }
59
+
60
+ function orchestratorHint(cmd, entry) {
61
+ if (entry?.alias) return `alias → \`${entry.alias}\``;
62
+ if (entry?.resolver) {
63
+ const fallback =
64
+ cmd === "fix-bug"
65
+ ? " — unknown slug → `verb-fix` + object `feature`"
66
+ : "";
67
+ return `resolver \`${entry.resolver}\`${fallback}`;
68
+ }
69
+ const verb = cmd.split("-")[0];
70
+ const orch = entry?.orchestrator;
71
+ const dedicated = new Set([
72
+ "update-doc",
73
+ "review-module",
74
+ "review-incident",
75
+ "test-function",
76
+ "release-app",
77
+ "write-article",
78
+ ]);
79
+ if (cmd === "update-architecture" || (orch && dedicated.has(orch))) {
80
+ const id = cmd === "update-architecture" ? "update-doc" : orch;
81
+ return `orchestrator \`${id}\` (see graph \`orchestrators.${id}.path\`)`;
82
+ }
83
+ const object = cmd.split("-").slice(1).join("-");
84
+ return `[skills/shared/verbs/${verb}/orchestrator/SKILL.md](../skills/shared/verbs/${verb}/orchestrator/SKILL.md) (object: \`${object}\`)`;
85
+ }
86
+
87
+ function domainLine(cmd) {
88
+ if (cmd === "review-incident" || cmd.endsWith("-function")) {
89
+ return "Domain optional.";
90
+ }
91
+ if (cmd.endsWith("-domain") || cmd.endsWith("-module")) {
92
+ return "Domain slug required (bounded context).";
93
+ }
94
+ return "Domain slug recommended.";
95
+ }
96
+
97
+ function writeCmd(cmd, entry = null) {
98
+ const parts = cmd.split("-");
99
+ const verb = parts[0];
100
+ let object = parts.slice(1).join("-");
101
+ const vDesc = verbs[verb] ?? verb;
102
+ if (entry?.alias) {
103
+ const canonParts = entry.alias.split("-");
104
+ object = canonParts.slice(1).join("-");
105
+ }
106
+ const { layer, description } = objectMeta(object, entry?.alias ?? cmd);
107
+ const aliasNote = entry?.alias
108
+ ? ` (alias \`${cmd}\` → \`${entry.alias}\`)`
109
+ : "";
110
+ const domainArg =
111
+ cmd === "review-incident" || cmd.endsWith("-function") ? "" : " <domain>";
112
+ const layerLine = layer ? `**Layer:** ${layer} \n` : "";
113
+ const body = `# ${cmd}
114
+
115
+ AAAC: \`/${cmd}${domainArg} "<intent>"\`
116
+
117
+ ${layerLine}**${cap(vDesc)}** a **${object}**${aliasNote} — ${description}.
118
+
119
+ ## Dispatch
120
+
121
+ 1. [.cursor/aaac/dispatch.md](../aaac/dispatch.md)
122
+ 2. [.cursor/aaac/graph.yaml](../aaac/graph.yaml) — **\`${cmd}\`**
123
+ 3. ${orchestratorHint(cmd, entry ?? {})}
124
+
125
+ ${domainLine(cmd)}
126
+ `;
127
+ fs.writeFileSync(path.join(commandsDir, `${cmd}.md`), body);
128
+ }
129
+
130
+ const written = new Set();
131
+
132
+ for (const [cmd, entry] of Object.entries(command_overrides)) {
133
+ writeCmd(cmd, entry);
134
+ written.add(cmd);
135
+ }
136
+
137
+ for (const [alias, canonical] of Object.entries(command_aliases ?? {})) {
138
+ if (written.has(alias)) continue;
139
+ writeCmd(alias, { alias: canonical });
140
+ written.add(alias);
141
+ }
142
+
143
+ for (const verb of Object.keys(verbs)) {
144
+ for (const object of Object.keys(objects)) {
145
+ const cmd = `${verb}-${object}`;
146
+ if (invalid.has(cmd) || written.has(cmd)) continue;
147
+ writeCmd(cmd, { orchestrator: `verb-${verb}`, object });
148
+ written.add(cmd);
149
+ }
150
+ }
151
+
152
+ let pruned = 0;
153
+ if (fs.existsSync(commandsDir)) {
154
+ for (const file of fs.readdirSync(commandsDir)) {
155
+ if (!file.endsWith(".md") || KEEP_EXTRA.has(file)) continue;
156
+ if (!written.has(file.replace(/\.md$/, ""))) {
157
+ fs.unlinkSync(path.join(commandsDir, file));
158
+ pruned++;
159
+ }
160
+ }
161
+ } else {
162
+ fs.mkdirSync(commandsDir, { recursive: true });
163
+ }
164
+
165
+ console.log(`Wrote ${written.size} command files, pruned ${pruned} stale.`);
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ /** Prints graph.yaml `commands:` block from ontology.json */
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { aaacDir, parseArgs, resolveCursorRoot } from "../lib/paths.mjs";
6
+
7
+ const args = parseArgs(process.argv);
8
+ const cursorRoot = resolveCursorRoot(args.root);
9
+ const aaac = aaacDir(cursorRoot);
10
+
11
+ const data = JSON.parse(
12
+ fs.readFileSync(path.join(aaac, "ontology.json"), "utf8"),
13
+ );
14
+ const { verbs, objects, invalid_pairs, command_overrides, command_aliases } =
15
+ data;
16
+ const invalid = new Set(invalid_pairs.map(([v, o]) => `${v}-${o}`));
17
+
18
+ const lines = ["commands:"];
19
+ const done = new Set();
20
+
21
+ function emit(cmd, entry) {
22
+ done.add(cmd);
23
+ if (entry.alias) {
24
+ lines.push(` ${cmd}:`);
25
+ lines.push(` alias: ${entry.alias}`);
26
+ return;
27
+ }
28
+ if (entry.resolver) {
29
+ lines.push(` ${cmd}:`);
30
+ lines.push(` resolver: ${entry.resolver}`);
31
+ return;
32
+ }
33
+ if (entry.orchestrator) {
34
+ lines.push(` ${cmd}:`);
35
+ lines.push(` orchestrator: ${entry.orchestrator}`);
36
+ if (entry.object) lines.push(` object: ${entry.object}`);
37
+ }
38
+ }
39
+
40
+ for (const [cmd, entry] of Object.entries(command_overrides)) {
41
+ emit(cmd, entry);
42
+ }
43
+
44
+ for (const verb of Object.keys(verbs)) {
45
+ for (const object of Object.keys(objects)) {
46
+ const cmd = `${verb}-${object}`;
47
+ if (invalid.has(cmd) || done.has(cmd)) continue;
48
+ done.add(cmd);
49
+ const orch = verb === "check" ? "verb-check" : `verb-${verb}`;
50
+ lines.push(` ${cmd}:`);
51
+ lines.push(` orchestrator: ${orch}`);
52
+ lines.push(` object: ${object}`);
53
+ }
54
+ }
55
+
56
+ for (const [alias, canonical] of Object.entries(command_aliases ?? {})) {
57
+ if (done.has(alias) || alias === canonical) continue;
58
+ done.add(alias);
59
+ lines.push(` ${alias}:`);
60
+ lines.push(` alias: ${canonical}`);
61
+ }
62
+
63
+ console.log(lines.join("\n"));
@@ -0,0 +1,242 @@
1
+ #!/usr/bin/env node
2
+ /** Writes .cursor/aaac/graph.yaml from ontology + lifecycle + graph.project.yaml */
3
+ import fs from "fs";
4
+ import path from "path";
5
+ import { execSync } from "child_process";
6
+ import { fileURLToPath } from "url";
7
+ import {
8
+ aaacDir,
9
+ parseArgs,
10
+ resolveCursorRoot,
11
+ packageGeneratorsDir,
12
+ } from "../lib/paths.mjs";
13
+
14
+ const INJECT_MARKER = "{{INJECT_OBJECT_BLOCKS}}";
15
+
16
+ const args = parseArgs(process.argv);
17
+ const cursorRoot = resolveCursorRoot(args.root);
18
+ const aaac = aaacDir(cursorRoot);
19
+ const generatorsDir = packageGeneratorsDir();
20
+
21
+ const commandsBlock = execSync(
22
+ `node "${path.join(generatorsDir, "generate-graph-commands.mjs")}" --root "${cursorRoot}"`,
23
+ { encoding: "utf8" },
24
+ );
25
+
26
+ const data = JSON.parse(
27
+ fs.readFileSync(path.join(aaac, "ontology.json"), "utf8"),
28
+ );
29
+
30
+ const lifecycle = JSON.parse(
31
+ fs.readFileSync(path.join(aaac, "lifecycle/lifecycle.json"), "utf8"),
32
+ );
33
+
34
+ const gates = JSON.parse(
35
+ fs.readFileSync(path.join(aaac, "governance/gates.json"), "utf8"),
36
+ );
37
+
38
+ const capabilityRegistry = JSON.parse(
39
+ fs.readFileSync(path.join(aaac, "capabilities/registry.json"), "utf8"),
40
+ );
41
+
42
+ const projectTail = fs.readFileSync(
43
+ path.join(aaac, "graph.project.yaml"),
44
+ "utf8",
45
+ );
46
+
47
+ function providerSkillId(provider) {
48
+ if (typeof provider === "string") return provider;
49
+ if (provider.type === "skill") return provider.id;
50
+ return null;
51
+ }
52
+
53
+ function resolveCapabilities(capIds) {
54
+ const skills = new Set();
55
+ for (const id of capIds ?? []) {
56
+ const cap = capabilityRegistry.capabilities[id];
57
+ if (!cap) throw new Error(`Unknown capability in ontology: ${id}`);
58
+ for (const provider of cap.providers) {
59
+ const skillId = providerSkillId(provider);
60
+ if (skillId) skills.add(skillId);
61
+ }
62
+ }
63
+ return [...skills];
64
+ }
65
+
66
+ function composeRuntimePhases(verbDef) {
67
+ const work = verbDef.work_phases ?? [];
68
+ if (!verbDef.gate_stack) return work;
69
+ const gatePhases = gates.stacks[verbDef.gate_stack] ?? [];
70
+ const executeIdx = work.indexOf("execute");
71
+ if (executeIdx === -1) {
72
+ const reportIdx = work.indexOf("report");
73
+ if (reportIdx <= 0) {
74
+ return work.length <= 1
75
+ ? [...work, ...gatePhases]
76
+ : [...work.slice(0, -1), ...gatePhases, work[work.length - 1]];
77
+ }
78
+ return [...work.slice(0, reportIdx), ...gatePhases, ...work.slice(reportIdx)];
79
+ }
80
+ return [...work.slice(0, executeIdx), ...gatePhases, ...work.slice(executeIdx)];
81
+ }
82
+
83
+ const resolvedObjectSkills = Object.fromEntries(
84
+ Object.entries(data.object_capabilities ?? {}).map(([object, caps]) => [
85
+ object,
86
+ resolveCapabilities(caps),
87
+ ]),
88
+ );
89
+
90
+ const resolvedObjectSkillVerbs = Object.fromEntries(
91
+ Object.entries(data.object_capability_verbs ?? {}).map(([object, verbs]) => [
92
+ object,
93
+ Object.fromEntries(
94
+ Object.entries(verbs).map(([verb, caps]) => [
95
+ verb,
96
+ resolveCapabilities(caps),
97
+ ]),
98
+ ),
99
+ ]),
100
+ );
101
+
102
+ const objectCapabilitiesBlock = Object.entries(data.object_capabilities ?? {})
103
+ .map(([object, caps]) =>
104
+ caps.length ? ` ${object}: [${caps.join(", ")}]` : ` ${object}: []`,
105
+ )
106
+ .join("\n");
107
+
108
+ const objectSkillsBlock = Object.entries(resolvedObjectSkills)
109
+ .map(([object, skills]) =>
110
+ skills.length ? ` ${object}: [${skills.join(", ")}]` : ` ${object}: []`,
111
+ )
112
+ .join("\n");
113
+
114
+ const objectSkillVerbsBlock = Object.entries(resolvedObjectSkillVerbs)
115
+ .map(([object, verbs]) => {
116
+ const inner = Object.entries(verbs)
117
+ .map(([verb, skills]) =>
118
+ skills.length
119
+ ? ` ${verb}: [${skills.join(", ")}]`
120
+ : ` ${verb}: []`,
121
+ )
122
+ .join("\n");
123
+ return ` ${object}:\n${inner}`;
124
+ })
125
+ .join("\n");
126
+
127
+ const verbWorkPhasesBlock = Object.entries(lifecycle.verbs ?? {})
128
+ .map(
129
+ ([verb, def]) => ` ${verb}: [${(def.work_phases ?? []).join(", ")}]`,
130
+ )
131
+ .join("\n");
132
+
133
+ const verbGateStackBlock = Object.entries(lifecycle.verbs ?? {})
134
+ .map(
135
+ ([verb, def]) =>
136
+ ` ${verb}: ${def.gate_stack ?? "null"}`,
137
+ )
138
+ .join("\n");
139
+
140
+ const verbRuntimeBlock = Object.entries(lifecycle.verbs ?? {})
141
+ .map(([verb, def]) => {
142
+ const phases = Array.isArray(def) ? def : composeRuntimePhases(def);
143
+ return ` ${verb}: [${phases.join(", ")}]`;
144
+ })
145
+ .join("\n");
146
+
147
+ const governanceGateStacksBlock = Object.entries(gates.stacks ?? {})
148
+ .map(([name, phases]) => ` ${name}: [${phases.join(", ")}]`)
149
+ .join("\n");
150
+
151
+ const layerComment = Object.entries(data.layers ?? {})
152
+ .sort((a, b) => a[1].order - b[1].order)
153
+ .map(([name, L]) => `# ${name}: ${L.objects.join(", ")}`)
154
+ .join("\n");
155
+
156
+ const confidenceBlock = Object.entries(data.confidence ?? {})
157
+ .map(([k, v]) => ` ${k}: ${v}`)
158
+ .join("\n");
159
+
160
+ const objectMaturityBlock = Object.entries(data.object_maturity ?? {})
161
+ .map(([object, level]) => ` ${object}: ${level}`)
162
+ .join("\n");
163
+
164
+ const maturityRulesBlock = Object.entries(data.maturity_rules ?? {})
165
+ .map(([level, rule]) => {
166
+ const phases = (rule.requires_phases ?? [])
167
+ .map((p) => ` - ${p}`)
168
+ .join("\n");
169
+ return ` ${level}:\n requires_phases:\n${phases || " []"}\n investigation: ${rule.investigation ?? "lite_on_create_update_deep_on_fix"}`;
170
+ })
171
+ .join("\n");
172
+
173
+ const injectBlock = `object_capabilities:
174
+ ${objectCapabilitiesBlock}
175
+
176
+ object_skills:
177
+ ${objectSkillsBlock}
178
+
179
+ object_skill_verbs:
180
+ ${objectSkillVerbsBlock}
181
+ `;
182
+
183
+ const header = `version: 1
184
+
185
+ # AAAC execution graph — SSOT for command → orchestrator → skills → agents.
186
+ # Regenerate: pnpm aaac:generate (or npx @ludecker/aaac generate)
187
+ # Path convention: agents/, policies/, skills/, domains/ are relative to .cursor/
188
+ # Ontology: .cursor/aaac/ontology.json — layers (code → data → product → system):
189
+ ${layerComment}
190
+
191
+ verbs: [${Object.keys(data.verbs).join(", ")}]
192
+ objects: [${Object.keys(data.objects).join(", ")}]
193
+
194
+ invalid_pairs:
195
+ ${data.invalid_pairs.map(([v, o]) => ` - [${v}, ${o}]`).join("\n")}
196
+
197
+ verb_work_phases:
198
+ ${verbWorkPhasesBlock}
199
+
200
+ verb_gate_stack:
201
+ ${verbGateStackBlock}
202
+
203
+ governance_gate_stacks:
204
+ ${governanceGateStacksBlock}
205
+
206
+ # Composed runtime: work through plan + gate stack + execute onward (see lifecycle.json runtime_compose)
207
+ verb_runtime:
208
+ ${verbRuntimeBlock}
209
+
210
+ confidence:
211
+ ${confidenceBlock}
212
+
213
+ object_maturity:
214
+ ${objectMaturityBlock}
215
+
216
+ maturity_rules:
217
+ ${maturityRulesBlock}
218
+
219
+ # Layer SSOT refs (see aaac/layers.md)
220
+ lifecycle: aaac/lifecycle/lifecycle.json
221
+ lifecycle_phases: aaac/lifecycle/phases.json
222
+ governance_gates: aaac/governance/gates.json
223
+ run: aaac/run/schema.json
224
+ capabilities: aaac/capabilities/registry.json
225
+ dependencies: aaac/dependencies.yaml
226
+ fitness_functions: aaac/fitness-functions.yaml
227
+ state: aaac/state/runs/
228
+ observability: aaac/run/schema.json
229
+ contracts: aaac/contracts/
230
+
231
+ `;
232
+
233
+ let tail = projectTail.trim();
234
+ if (tail.includes(INJECT_MARKER)) {
235
+ tail = tail.replace(INJECT_MARKER, injectBlock.trim());
236
+ } else {
237
+ tail = `${tail}\n\n${injectBlock.trim()}`;
238
+ }
239
+
240
+ const out = `${header}${commandsBlock}\n\n${tail}\n`;
241
+ fs.writeFileSync(path.join(aaac, "graph.yaml"), out);
242
+ console.log("Wrote graph.yaml");