@moretea-labs/forge 1.7.0 → 1.7.2

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 (175) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +26 -0
  3. package/CLAUDE.md +2 -0
  4. package/THIRD_PARTY_NOTICES.md +1 -1
  5. package/agents/openai.yaml +1 -1
  6. package/assets/partials-agents/02-operating-mode.partial.md +2 -0
  7. package/assets/plugin-registry.v1.json +3 -3
  8. package/assets/skill-version.json +2 -2
  9. package/assets/templates/helpers/check-architecture-sync.sh +17 -0
  10. package/assets/templates/helpers/inspect-project-state.ts +8 -6
  11. package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
  12. package/assets/templates/helpers/workflow-contract.ts +5 -1
  13. package/docs/architecture/CURRENT.md +12 -4
  14. package/docs/forge-plugin-management.md +1 -1
  15. package/docs/operations/controller-performance-and-502.md +19 -0
  16. package/docs/operations/homebrew.md +2 -2
  17. package/package.json +5 -2
  18. package/scripts/architecture-event.ts +2 -820
  19. package/scripts/architecture-queue.sh +2 -645
  20. package/scripts/archive-architecture-request.sh +2 -242
  21. package/scripts/archive-workflow.sh +1 -291
  22. package/scripts/benchmark-work-efficiency.ts +0 -0
  23. package/scripts/capability-config.ts +2 -392
  24. package/scripts/capability-resolver.ts +2 -503
  25. package/scripts/capture-plan.sh +1 -332
  26. package/scripts/check-agent-tooling.sh +2 -1531
  27. package/scripts/check-architecture-sync.sh +2 -302
  28. package/scripts/check-brain-manifest.sh +2 -253
  29. package/scripts/check-context-files.sh +2 -47
  30. package/scripts/check-deploy-sql-order.sh +2 -115
  31. package/scripts/check-runtime-architecture.mjs +243 -16
  32. package/scripts/check-skill-version.ts +3 -191
  33. package/scripts/check-source-duplication.mjs +61 -0
  34. package/scripts/check-stable-baseline.ts +0 -0
  35. package/scripts/check-task-sync.sh +2 -63
  36. package/scripts/check-task-workflow.sh +2 -1000
  37. package/scripts/codex-handoff-resume.sh +2 -267
  38. package/scripts/context-contract-sync.sh +2 -514
  39. package/scripts/contract-run.ts +2 -463
  40. package/scripts/contract-worktree.sh +1 -702
  41. package/scripts/ensure-task-workflow.sh +1 -1192
  42. package/scripts/inspect-project-state.ts +4 -279
  43. package/scripts/lib/project-init-lib.sh +7 -2
  44. package/scripts/lib/run-forge-helper.sh +19 -0
  45. package/scripts/lib/run-forge-helper.ts +26 -0
  46. package/scripts/migrate-project-template.sh +1 -33
  47. package/scripts/migrate-workflow-docs.ts +4 -412
  48. package/scripts/new-plan.sh +1 -180
  49. package/scripts/new-spec.sh +1 -47
  50. package/scripts/new-sprint.sh +1 -46
  51. package/scripts/plan-to-todo.sh +1 -771
  52. package/scripts/prepare-codex-handoff.sh +2 -201
  53. package/scripts/prepare-handoff.sh +1 -78
  54. package/scripts/refresh-current-status.sh +2 -467
  55. package/scripts/run-governed-gate.ts +3 -0
  56. package/scripts/select-agent-context-blocks.sh +2 -64
  57. package/scripts/ship-worktrees.sh +1 -531
  58. package/scripts/sprint-backlog.sh +1 -834
  59. package/scripts/stage-runtime-release.ts +2 -1
  60. package/scripts/summarize-failures.sh +2 -123
  61. package/scripts/switch-plan.sh +1 -150
  62. package/scripts/sync-brain-docs.sh +2 -379
  63. package/scripts/sync-generated-authority.mjs +175 -0
  64. package/scripts/verify-contract.sh +2 -593
  65. package/scripts/verify-sprint.sh +1 -500
  66. package/scripts/workflow-contract.ts +4 -201
  67. package/scripts/workstream-sync.sh +2 -261
  68. package/src/cli/agent-jobs/executor-health.ts +1 -1
  69. package/src/cli/commands/plugin.ts +12 -3
  70. package/src/cli/controller/check-runner.ts +7 -2
  71. package/src/cli/controller/context-pack.ts +46 -21
  72. package/src/cli/github/contracts.ts +16 -0
  73. package/src/cli/github/github.ts +2 -16
  74. package/src/cli/github/session.ts +2 -1
  75. package/src/cli/local-bridge/facade-api.ts +37 -47
  76. package/src/cli/local-bridge/server.ts +2 -2
  77. package/src/cli/mcp/legacy-tool-service.ts +10 -33
  78. package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
  79. package/src/cli/mcp/repository-tools.ts +125 -101
  80. package/src/cli/mcp/server.ts +57 -13
  81. package/src/cli/mcp/tool-contract.ts +14 -0
  82. package/src/cli/mcp/toolset.ts +2 -2
  83. package/src/cli/mcp/transports/http.ts +23 -0
  84. package/src/cli/repositories/command-classifier.ts +2 -2
  85. package/src/cli/repositories/command-executor.ts +24 -6
  86. package/src/cli/repositories/repository-snapshot.ts +5 -2
  87. package/src/cli/repositories/structured-git.ts +57 -3
  88. package/src/cli/repository/inspector.ts +11 -3
  89. package/src/runtime/context/generic-lsp-provider.ts +1 -1
  90. package/src/runtime/context/semantic-navigation-contract.ts +61 -0
  91. package/src/runtime/context/semantic-navigation.ts +9 -61
  92. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +69 -29
  93. package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
  94. package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
  95. package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
  96. package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
  97. package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
  98. package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
  99. package/src/runtime/control-plane/execution/work-handle-authority.ts +150 -0
  100. package/src/runtime/control-plane/execution/work-handle-store.ts +1 -1
  101. package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
  102. package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
  103. package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
  104. package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
  105. package/src/runtime/control-plane/execution/work-task-receipt.ts +4 -43
  106. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +13 -3
  107. package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
  108. package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
  109. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  110. package/src/runtime/control-plane/facade/controller-round-relay.ts +164 -37
  111. package/src/runtime/control-plane/facade/controller-session-store.ts +183 -24
  112. package/src/runtime/control-plane/facade/goal-workloop-access.ts +15 -1
  113. package/src/runtime/control-plane/facade/goal-workloop.ts +329 -148
  114. package/src/runtime/control-plane/facade/index.ts +2 -0
  115. package/src/runtime/control-plane/facade/plan-contract-store.ts +90 -22
  116. package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
  117. package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
  118. package/src/runtime/control-plane/facade/types.ts +68 -5
  119. package/src/runtime/control-plane/facade/work-contract-store.ts +3 -209
  120. package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
  121. package/src/runtime/control-plane/global-scheduler/maintenance.ts +14 -7
  122. package/src/runtime/control-plane/global-scheduler/scheduler.ts +5 -1
  123. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +13 -0
  124. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +15 -6
  125. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +54 -5
  126. package/src/runtime/control-plane/launcher/thin-launcher.ts +56 -7
  127. package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
  128. package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
  129. package/src/runtime/control-plane/routing/route-policy.ts +18 -6
  130. package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
  131. package/src/runtime/evidence/process-check-execution.ts +18 -0
  132. package/src/runtime/execution/jobs/child-reference.ts +6 -2
  133. package/src/runtime/execution/process-runtime/check-result.ts +53 -18
  134. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
  135. package/src/runtime/execution/process-runtime/command-facade.ts +39 -17
  136. package/src/runtime/execution/process-runtime/lightweight-managed.ts +20 -3
  137. package/src/runtime/execution/process-runtime/persisted-check.ts +4 -1
  138. package/src/runtime/execution/process-runtime/runtime.ts +10 -0
  139. package/src/runtime/execution/process-runtime/types.ts +2 -12
  140. package/src/runtime/execution/work-activity.ts +21 -0
  141. package/src/runtime/execution/workers/executor.ts +18 -13
  142. package/src/runtime/gateway/mcp/execution-tools.ts +35 -2930
  143. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
  144. package/src/runtime/gateway/mcp/router.ts +2 -2
  145. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +21 -2
  146. package/src/runtime/gateway/mcp/runtime-tools.ts +815 -1015
  147. package/src/runtime/plugins/app-store-connect-adapter.ts +93 -28
  148. package/src/runtime/plugins/browser-adapter.ts +256 -1083
  149. package/src/runtime/plugins/browser-handoff-host.ts +2 -25
  150. package/src/runtime/plugins/browser-handoff.ts +18 -3
  151. package/src/runtime/plugins/browser-macos-bridge.ts +121 -16
  152. package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
  153. package/src/runtime/plugins/browser-native-session-service.ts +222 -0
  154. package/src/runtime/plugins/browser-runtime-contract.ts +2 -0
  155. package/src/runtime/plugins/browser-runtime.ts +10 -0
  156. package/src/runtime/plugins/browser-session-store.ts +121 -0
  157. package/src/runtime/plugins/browser-session-types.ts +98 -0
  158. package/src/runtime/plugins/desktop-operator-registration.ts +4 -4
  159. package/src/runtime/plugins/external-adapter.ts +92 -58
  160. package/src/runtime/plugins/macos-capability-broker.ts +0 -8
  161. package/src/runtime/plugins/store.ts +66 -9
  162. package/src/runtime/plugins/types.ts +3 -1
  163. package/src/runtime/recovery/maintenance-executor.ts +61 -25
  164. package/src/runtime/root/package-connector-service.ts +46 -4
  165. package/src/runtime/root/package-runtime-release.ts +3 -2
  166. package/src/runtime/root/package-runtime-service.ts +48 -3
  167. package/src/runtime/root/release-manifest.ts +137 -16
  168. package/src/runtime/root/release-materialize.ts +109 -35
  169. package/src/runtime/root/types.ts +10 -0
  170. package/src/runtime/standalone-recovery/core.ts +425 -194
  171. package/src/runtime/standalone-recovery/entry.ts +1 -1
  172. package/src/runtime/standalone-recovery/installer.ts +1 -1
  173. package/src/runtime/workflow/schedules/engine.ts +113 -87
  174. package/src/runtime/workflow/schedules/settlement.ts +26 -23
  175. package/src/runtime/workflow/schedules/store.ts +79 -10
@@ -1,394 +1,4 @@
1
1
  #!/usr/bin/env bun
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
3
- import { dirname, resolve } from "path";
4
- import { spawnSync } from "child_process";
2
+ import { runTrackedForgeHelper } from "./lib/run-forge-helper";
5
3
 
6
- type ContractFiles = {
7
- agents: string;
8
- claude: string;
9
- };
10
-
11
- type Capability = {
12
- id: string;
13
- domain: string;
14
- name: string;
15
- prefixes: string[];
16
- contract_files: ContractFiles;
17
- architecture_module: string;
18
- workstream_dir: string;
19
- lsp_profile: string;
20
- verification_hints: string[];
21
- };
22
-
23
- type Registry = {
24
- version: number;
25
- capabilities: Capability[];
26
- };
27
-
28
- type Format = "text" | "json";
29
-
30
- type Args = {
31
- command: "add" | "";
32
- repo: string;
33
- prefix: string;
34
- id: string;
35
- domain: string;
36
- name: string;
37
- agents: string;
38
- claude: string;
39
- architectureModule: string;
40
- workstreamDir: string;
41
- lspProfile: string;
42
- verificationHints: string[];
43
- createPrefix: boolean;
44
- createArchitectureModule: boolean;
45
- createWorkstream: boolean;
46
- syncContracts: boolean;
47
- dryRun: boolean;
48
- format: Format;
49
- };
50
-
51
- const REGISTRY_PATH = ".ai/context/capabilities.json";
52
-
53
- function usage(): never {
54
- console.error(
55
- [
56
- "Usage:",
57
- " scripts/capability-config.ts add --prefix <path> [options]",
58
- "",
59
- "Options:",
60
- " --repo <path> Target repo (default: .)",
61
- " --id <id> Capability ID (default derived from prefix)",
62
- " --domain <domain> Architecture domain (default derived from prefix)",
63
- " --name <name> Capability name (default derived from prefix)",
64
- " --agents <path> AGENTS.md path (default: <prefix>/AGENTS.md)",
65
- " --claude <path> CLAUDE.md path (default: <prefix>/CLAUDE.md)",
66
- " --architecture-module <path> Architecture module path",
67
- " --workstream-dir <path> Workstream directory path",
68
- " --lsp-profile <profile> LSP/tooling profile (default: typescript-lsp)",
69
- " --verification-hint <command> Repeatable local verification hint",
70
- " --create-prefix Create the prefix directory when missing",
71
- " --create-architecture-module Create a minimal architecture module when missing",
72
- " --create-workstream Create a durable workstream ledger",
73
- " --no-sync-contracts Only update the registry",
74
- " --dry-run Print planned changes without writing",
75
- " --format text|json Output format (default: text)",
76
- ].join("\n")
77
- );
78
- process.exit(2);
79
- }
80
-
81
- function parseArgs(argv: string[]): Args {
82
- const args: Args = {
83
- command: (argv[0] as Args["command"]) || "",
84
- repo: ".",
85
- prefix: "",
86
- id: "",
87
- domain: "",
88
- name: "",
89
- agents: "",
90
- claude: "",
91
- architectureModule: "",
92
- workstreamDir: "",
93
- lspProfile: "typescript-lsp",
94
- verificationHints: [],
95
- createPrefix: false,
96
- createArchitectureModule: false,
97
- createWorkstream: false,
98
- syncContracts: true,
99
- dryRun: false,
100
- format: "text",
101
- };
102
-
103
- for (let index = 1; index < argv.length; index += 1) {
104
- const arg = argv[index];
105
- switch (arg) {
106
- case "--repo":
107
- args.repo = argv[++index] || usage();
108
- break;
109
- case "--prefix":
110
- args.prefix = argv[++index] || usage();
111
- break;
112
- case "--id":
113
- args.id = argv[++index] || usage();
114
- break;
115
- case "--domain":
116
- args.domain = argv[++index] || usage();
117
- break;
118
- case "--name":
119
- args.name = argv[++index] || usage();
120
- break;
121
- case "--agents":
122
- args.agents = argv[++index] || usage();
123
- break;
124
- case "--claude":
125
- args.claude = argv[++index] || usage();
126
- break;
127
- case "--architecture-module":
128
- args.architectureModule = argv[++index] || usage();
129
- break;
130
- case "--workstream-dir":
131
- args.workstreamDir = argv[++index] || usage();
132
- break;
133
- case "--lsp-profile":
134
- args.lspProfile = argv[++index] || usage();
135
- break;
136
- case "--verification-hint":
137
- args.verificationHints.push(argv[++index] || usage());
138
- break;
139
- case "--create-prefix":
140
- args.createPrefix = true;
141
- break;
142
- case "--create-architecture-module":
143
- args.createArchitectureModule = true;
144
- break;
145
- case "--create-workstream":
146
- args.createWorkstream = true;
147
- break;
148
- case "--no-sync-contracts":
149
- args.syncContracts = false;
150
- break;
151
- case "--dry-run":
152
- args.dryRun = true;
153
- break;
154
- case "--format": {
155
- const format = argv[++index] as Format;
156
- if (!["text", "json"].includes(format)) usage();
157
- args.format = format;
158
- break;
159
- }
160
- case "--help":
161
- case "-h":
162
- usage();
163
- break;
164
- default:
165
- console.error(`capability-config: unknown argument: ${arg}`);
166
- usage();
167
- }
168
- }
169
-
170
- if (args.command !== "add" || !args.prefix) usage();
171
- return args;
172
- }
173
-
174
- function repoRoot(input: string): string {
175
- const cwd = resolve(input);
176
- const result = spawnSync("git", ["rev-parse", "--show-toplevel"], {
177
- cwd,
178
- encoding: "utf-8",
179
- });
180
- if (result.status === 0 && result.stdout.trim()) return resolve(result.stdout.trim());
181
- return cwd;
182
- }
183
-
184
- function normalizeRepoPath(value: string, repo: string): string {
185
- let next = value.trim().replace(/^file:\/\//, "").replaceAll("\\", "/");
186
- const normalizedRepo = repo.replaceAll("\\", "/");
187
-
188
- if (next.startsWith(`${normalizedRepo}/`)) {
189
- next = next.slice(normalizedRepo.length + 1);
190
- } else if (next.startsWith("/")) {
191
- throw new Error(`absolute path is outside repo: ${value}`);
192
- }
193
-
194
- next = next.replace(/^\.\//, "").replace(/\/+$/, "");
195
- const parts = next.split("/").filter(Boolean);
196
- if (parts.length === 0) throw new Error("path must not be empty");
197
- if (parts.some((part) => part === "." || part === "..")) {
198
- throw new Error(`path must not contain traversal: ${value}`);
199
- }
200
- return parts.join("/");
201
- }
202
-
203
- function safeToken(value: string, fallback = "capability"): string {
204
- const token = value
205
- .toLowerCase()
206
- .replace(/[^a-z0-9]+/g, "-")
207
- .replace(/^-+|-+$/g, "")
208
- .replace(/-{2,}/g, "-");
209
- return token || fallback;
210
- }
211
-
212
- function defaultParts(prefix: string) {
213
- const parts = prefix.split("/");
214
- const domain =
215
- parts.length >= 2 ? safeToken(`${parts[0]}-${parts[1]}`, safeToken(prefix)) : safeToken(prefix);
216
- const name = parts.length > 2 ? safeToken(parts[parts.length - 1]) : safeToken(parts[parts.length - 1] || domain);
217
- const id = parts.length > 2 ? `${domain}-${name}` : domain;
218
- return { id, domain, name };
219
- }
220
-
221
- function buildCapability(args: Args, repo: string): Capability {
222
- const prefix = normalizeRepoPath(args.prefix, repo);
223
- const defaults = defaultParts(prefix);
224
- const domain = safeToken(args.domain || defaults.domain);
225
- const name = safeToken(args.name || defaults.name);
226
- const id = safeToken(args.id || defaults.id);
227
-
228
- return {
229
- id,
230
- domain,
231
- name,
232
- prefixes: [prefix],
233
- contract_files: {
234
- agents: normalizeRepoPath(args.agents || `${prefix}/AGENTS.md`, repo),
235
- claude: normalizeRepoPath(args.claude || `${prefix}/CLAUDE.md`, repo),
236
- },
237
- architecture_module: normalizeRepoPath(
238
- args.architectureModule || `docs/architecture/modules/${domain}/${name}.md`,
239
- repo
240
- ),
241
- workstream_dir: normalizeRepoPath(args.workstreamDir || `tasks/workstreams/${domain}/${name}`, repo),
242
- lsp_profile: args.lspProfile,
243
- verification_hints:
244
- args.verificationHints.length > 0 ? args.verificationHints : ["record local commands here before implementation"],
245
- };
246
- }
247
-
248
- function readRegistry(repo: string): Registry {
249
- const registryPath = resolve(repo, REGISTRY_PATH);
250
- if (!existsSync(registryPath)) return { version: 1, capabilities: [] };
251
- const parsed = JSON.parse(readFileSync(registryPath, "utf-8")) as Partial<Registry>;
252
- return {
253
- version: parsed.version ?? 1,
254
- capabilities: Array.isArray(parsed.capabilities) ? parsed.capabilities : [],
255
- };
256
- }
257
-
258
- function writeRegistry(repo: string, registry: Registry): void {
259
- const registryPath = resolve(repo, REGISTRY_PATH);
260
- mkdirSync(dirname(registryPath), { recursive: true });
261
- writeFileSync(registryPath, `${JSON.stringify(registry, null, 2)}\n`);
262
- }
263
-
264
- function upsertCapability(registry: Registry, capability: Capability): { status: "added" | "existing"; capability: Capability } {
265
- const prefix = capability.prefixes[0];
266
- const existingById = registry.capabilities.find((entry) => entry.id === capability.id);
267
- const existingByPrefix = registry.capabilities.find((entry) => (entry.prefixes || []).includes(prefix));
268
-
269
- if (existingById && existingById !== existingByPrefix) {
270
- throw new Error(`capability id already exists with different prefix: ${capability.id}`);
271
- }
272
- if (existingByPrefix && existingByPrefix.id !== capability.id) {
273
- throw new Error(`capability prefix already belongs to ${existingByPrefix.id}: ${prefix}`);
274
- }
275
- if (existingById) return { status: "existing", capability: existingById };
276
-
277
- registry.capabilities.push(capability);
278
- return { status: "added", capability };
279
- }
280
-
281
- function runChecked(repo: string, command: string, args: string[]): string {
282
- const result = spawnSync(command, args, {
283
- cwd: repo,
284
- encoding: "utf-8",
285
- });
286
- if (result.status !== 0) {
287
- throw new Error([`${command} ${args.join(" ")} failed`, result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n"));
288
- }
289
- return result.stdout.trim();
290
- }
291
-
292
- function validateRegistry(repo: string): void {
293
- runChecked(repo, process.execPath, ["scripts/capability-resolver.ts", "validate", "--repo", repo, "--format", "text"]);
294
- }
295
-
296
- function syncContracts(repo: string, capability: Capability): void {
297
- const event = {
298
- ts: new Date().toISOString(),
299
- file_path: capability.prefixes[0],
300
- severity: "medium",
301
- functional_block: capability.prefixes[0],
302
- capability_id: capability.id,
303
- matched_prefix: capability.prefixes[0],
304
- architecture_domain: capability.domain,
305
- architecture_capability: capability.name,
306
- architecture_module: capability.architecture_module,
307
- workstream_dir: capability.workstream_dir,
308
- contract_agents: capability.contract_files.agents,
309
- contract_claude: capability.contract_files.claude,
310
- lsp_profile: capability.lsp_profile,
311
- change_type: "capability-config",
312
- request_file: "none",
313
- spawn_recommended: false,
314
- contract_sync_required: true,
315
- };
316
-
317
- runChecked(repo, "bash", ["scripts/context-contract-sync.sh", "sync-event", "--json", JSON.stringify(event)]);
318
- }
319
-
320
- function createArchitectureModule(repo: string, capability: Capability): void {
321
- const path = resolve(repo, capability.architecture_module);
322
- if (existsSync(path)) return;
323
- mkdirSync(dirname(path), { recursive: true });
324
- writeFileSync(
325
- path,
326
- [
327
- `# Architecture Module: ${capability.domain}/${capability.name}`,
328
- "",
329
- `> **Capability ID**: \`${capability.id}\``,
330
- `> **Source**: \`${REGISTRY_PATH}\``,
331
- "",
332
- "## Responsibility",
333
- "",
334
- `Record stable boundaries, entrypoints, runtime paths, dependency rules, and verification hints for \`${capability.id}\`.`,
335
- "",
336
- "## Entrypoints",
337
- "",
338
- `- \`${capability.prefixes[0]}\``,
339
- "",
340
- ].join("\n")
341
- );
342
- }
343
-
344
- function createWorkstream(repo: string, capability: Capability): void {
345
- runChecked(repo, "bash", ["scripts/workstream-sync.sh", "ensure", "--block", capability.prefixes[0]]);
346
- }
347
-
348
- function main(): void {
349
- const args = parseArgs(process.argv.slice(2));
350
- const repo = repoRoot(args.repo);
351
- const requestedCapability = buildCapability(args, repo);
352
- const prefixPath = resolve(repo, requestedCapability.prefixes[0]);
353
- const registry = readRegistry(repo);
354
- const actions: string[] = [];
355
-
356
- if (!existsSync(prefixPath)) {
357
- if (!args.createPrefix) {
358
- throw new Error(`capability prefix does not exist: ${requestedCapability.prefixes[0]} (use --create-prefix to create it)`);
359
- }
360
- actions.push(`create-prefix:${requestedCapability.prefixes[0]}`);
361
- if (!args.dryRun) mkdirSync(prefixPath, { recursive: true });
362
- }
363
-
364
- const { status, capability } = upsertCapability(registry, requestedCapability);
365
- actions.push(`${status}:${capability.id}`);
366
-
367
- if (args.syncContracts) actions.push(`sync-contracts:${capability.contract_files.agents},${capability.contract_files.claude}`);
368
- if (args.createArchitectureModule) actions.push(`create-architecture-module:${capability.architecture_module}`);
369
- if (args.createWorkstream) actions.push(`create-workstream:${capability.workstream_dir}`);
370
- actions.push("validate:capability-registry");
371
-
372
- if (!args.dryRun) {
373
- if (status === "added") writeRegistry(repo, registry);
374
- if (args.syncContracts) syncContracts(repo, capability);
375
- if (args.createArchitectureModule) createArchitectureModule(repo, capability);
376
- if (args.createWorkstream) createWorkstream(repo, capability);
377
- validateRegistry(repo);
378
- }
379
-
380
- if (args.format === "json") {
381
- console.log(JSON.stringify({ repo, status, capability, actions, dry_run: args.dryRun }, null, 2));
382
- return;
383
- }
384
-
385
- console.log(`[CapabilityConfig] ${status === "added" ? "Added" : "Found existing"} ${capability.id} -> ${capability.prefixes[0]}`);
386
- for (const action of actions) console.log(`[CapabilityConfig] ${args.dryRun ? "Would " : ""}${action}`);
387
- }
388
-
389
- try {
390
- main();
391
- } catch (error) {
392
- console.error(`capability-config: ${(error as Error).message}`);
393
- process.exit(1);
394
- }
4
+ if (import.meta.main) runTrackedForgeHelper("capability-config.ts");