@moretea-labs/forge 1.7.0 → 1.7.1

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 +13 -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 +85 -89
  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 +18 -25
  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 +96 -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 +805 -1009
  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 +1 -1
  166. package/src/runtime/root/package-runtime-service.ts +33 -2
  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,280 +1,5 @@
1
- import { existsSync, readFileSync, readdirSync } from "fs";
2
- import { join, resolve } from "path";
3
- import { loadWorkflowContract, resolveWorkflowContractForRepo } from "./workflow-contract.ts";
1
+ #!/usr/bin/env bun
2
+ export * from "../assets/templates/helpers/inspect-project-state";
3
+ import { runTrackedForgeHelper } from "./lib/run-forge-helper";
4
4
 
5
- type Mode = "initialize" | "migrate" | "audit" | "repair";
6
-
7
- type InspectionResult = {
8
- repo: string;
9
- mode: Mode;
10
- legacy_contract_version: string;
11
- drift_signals: string[];
12
- required_decisions: string[];
13
- safe_defaults: string[];
14
- detected_paths: string[];
15
- upgrade_plan: UpgradePlanItem[];
16
- };
17
-
18
- type UpgradePlanItem = {
19
- id: string;
20
- signal: string;
21
- action: string;
22
- risk: string;
23
- ownership: string;
24
- paths: string[];
25
- target_paths?: string[];
26
- summary: string;
27
- };
28
-
29
- function parseArgs(argv: string[]) {
30
- let repo = process.cwd();
31
- let format: "json" | "text" = "json";
32
-
33
- for (let i = 0; i < argv.length; i += 1) {
34
- const arg = argv[i];
35
- if (arg === "--repo") {
36
- repo = argv[i + 1] ? resolve(argv[i + 1]) : repo;
37
- i += 1;
38
- continue;
39
- }
40
- if (arg === "--format") {
41
- format = argv[i + 1] === "text" ? "text" : "json";
42
- i += 1;
43
- }
44
- }
45
-
46
- return { repo, format };
47
- }
48
-
49
- function fileHasContent(path: string, pattern: RegExp): boolean {
50
- if (!existsSync(path)) return false;
51
- return pattern.test(readFileSync(path, "utf-8"));
52
- }
53
-
54
- function jsonPathExists(path: string, keys: string[]): boolean {
55
- if (!existsSync(path)) return false;
56
- try {
57
- let value: unknown = JSON.parse(readFileSync(path, "utf-8"));
58
- for (const key of keys) {
59
- if (!value || typeof value !== "object" || !(key in value)) return false;
60
- value = (value as Record<string, unknown>)[key];
61
- }
62
- return true;
63
- } catch {
64
- return false;
65
- }
66
- }
67
-
68
- function hasAnyPath(repo: string, relPaths: string[]): boolean {
69
- return relPaths.some((relPath) => existsSync(join(repo, relPath)));
70
- }
71
-
72
- function hasCustomClaudeHooks(repo: string): boolean {
73
- const hooksDir = join(repo, ".claude", "hooks");
74
- if (!existsSync(hooksDir)) return false;
75
- try {
76
- return readdirSync(hooksDir).some((entry) => /^custom-.*\.sh$/.test(entry));
77
- } catch {
78
- return false;
79
- }
80
- }
81
-
82
- function detectMode(repo: string): Mode {
83
- const hasTasks = existsSync(join(repo, "tasks"));
84
- const hasPlan = existsSync(join(repo, "plans"));
85
- const hasLegacyDocs =
86
- existsSync(join(repo, "docs", "plan.md")) || existsSync(join(repo, "docs", "TODO.md"));
87
- const hasLegacySkillFactory =
88
- existsSync(join(repo, ".claude", "skill-factory")) ||
89
- existsSync(join(repo, "scripts", "skill-factory-check.sh")) ||
90
- existsSync(join(repo, "scripts", "skill-factory-create.sh")) ||
91
- existsSync(join(repo, ".ai", "hooks", "memory-intake.sh")) ||
92
- existsSync(join(repo, ".ai", "hooks", "skill-factory-session-end.sh"));
93
-
94
- if (hasTasks && hasPlan) return "audit";
95
- if (hasLegacyDocs || hasLegacySkillFactory) return "migrate";
96
- if (!hasTasks && !hasPlan && !hasLegacyDocs) return "initialize";
97
- return "repair";
98
- }
99
-
100
- export function inspectRepo(repo: string): InspectionResult {
101
- const contract = loadWorkflowContract(resolveWorkflowContractForRepo(repo));
102
- const latestContract = loadWorkflowContract();
103
- const upgradeActions = latestContract.migrations.upgrade?.actions ?? contract.migrations.upgrade?.actions ?? [];
104
- const detectedPathSet = new Set(
105
- [...new Set([...contract.migrations.legacyPaths, ...latestContract.migrations.legacyPaths])]
106
- .map((relPath) => relPath)
107
- .filter((relPath) => existsSync(join(repo, relPath)))
108
- );
109
- const driftSignals: string[] = [];
110
- const requiredDecisions: string[] = [];
111
- const safeDefaults = [
112
- "Preserve repo-local tasks-first workflow",
113
- "Archive uncertain legacy content instead of overwriting it",
114
- "Delete only manifest-owned known_generated legacy files",
115
- "Distill repeated corrections into tasks/lessons.md and hidden contracts into docs/researches/",
116
- ];
117
-
118
- const runtimeManifest = join(repo, contract.artifacts.runtimeManifest);
119
- const todoFile = join(repo, contract.documents.deferredGoalLedger ?? contract.documents.taskChecklist ?? "tasks/todos.md");
120
- const legacySingularTodoFile = join(repo, "tasks", "todo.md");
121
- const legacyTaskSprintDir = join(repo, "tasks", "sprints");
122
- const policyFile = join(repo, ".ai", "harness", "policy.json");
123
- const generatedClaudeHookPaths = [
124
- ".claude/hooks/run-hook.sh",
125
- ".claude/hooks/finalize-handoff.sh",
126
- ".claude/hooks/session-start-context.sh",
127
- ".claude/hooks/hook-input.sh",
128
- ".claude/hooks/lib/workflow-state.sh",
129
- ".claude/hooks/lib/session-state.sh",
130
- ];
131
- const ignoredReferenceOrSecretPaths = [
132
- "_ref",
133
- "_ops",
134
- ];
135
-
136
- if (!existsSync(runtimeManifest)) {
137
- driftSignals.push("missing-runtime-contract-manifest");
138
- }
139
- if (existsSync(policyFile) && !jsonPathExists(policyFile, ["upgrade", "strategy_version"])) {
140
- driftSignals.push("policy-missing-upgrade-strategy");
141
- }
142
- if (existsSync(join(repo, "docs", "plan.md"))) {
143
- driftSignals.push("legacy-docs-plan");
144
- }
145
- if (existsSync(join(repo, "docs", "TODO.md"))) {
146
- driftSignals.push("legacy-docs-todo");
147
- }
148
- if (existsSync(legacySingularTodoFile) && legacySingularTodoFile !== todoFile) {
149
- driftSignals.push("legacy-singular-todo-file");
150
- }
151
- if (existsSync(legacyTaskSprintDir)) {
152
- driftSignals.push("legacy-task-sprint-prds");
153
- }
154
- if (
155
- existsSync(join(repo, ".claude", "skill-factory")) ||
156
- existsSync(join(repo, "scripts", "skill-factory-check.sh")) ||
157
- existsSync(join(repo, "scripts", "skill-factory-create.sh")) ||
158
- existsSync(join(repo, ".ai", "hooks", "memory-intake.sh")) ||
159
- existsSync(join(repo, ".ai", "hooks", "skill-factory-session-end.sh"))
160
- ) {
161
- driftSignals.push("legacy-skill-factory-surface");
162
- }
163
- if (existsSync(join(repo, "docs", "PROGRESS.md"))) {
164
- driftSignals.push("legacy-docs-progress");
165
- }
166
- if (
167
- existsSync(todoFile) &&
168
- (
169
- !fileHasContent(todoFile, /^# Deferred Goal Ledger\s*$/m) ||
170
- !fileHasContent(todoFile, /^\> \*\*Status\*\*:\s*Backlog\s*$/m)
171
- )
172
- ) {
173
- driftSignals.push("legacy-task-checklist-format");
174
- }
175
- if (hasAnyPath(repo, generatedClaudeHookPaths)) {
176
- driftSignals.push("stale-generated-claude-hook-shims");
177
- }
178
-
179
- if (driftSignals.includes("missing-runtime-contract-manifest")) {
180
- requiredDecisions.push("Install runtime workflow contract manifest");
181
- }
182
- if (driftSignals.includes("policy-missing-upgrade-strategy")) {
183
- requiredDecisions.push("Merge versioned upgrade strategy into harness policy");
184
- }
185
- if (driftSignals.includes("legacy-docs-plan") || driftSignals.includes("legacy-docs-todo")) {
186
- requiredDecisions.push("Run legacy document migration before template refresh");
187
- }
188
- if (driftSignals.includes("legacy-singular-todo-file")) {
189
- requiredDecisions.push("Migrate legacy tasks/todo.md into tasks/todos.md");
190
- }
191
- if (driftSignals.includes("legacy-task-sprint-prds")) {
192
- requiredDecisions.push("Move legacy tasks/sprints/*.sprint.md into plans/sprints/*.sprint.md");
193
- }
194
- if (driftSignals.includes("legacy-docs-progress")) {
195
- requiredDecisions.push("Archive legacy docs/PROGRESS.md into research report or changelog surfaces");
196
- }
197
- if (driftSignals.includes("legacy-skill-factory-surface")) {
198
- requiredDecisions.push("Remove repo-local Skill Factory and auto-memory surfaces");
199
- }
200
- if (driftSignals.includes("stale-generated-claude-hook-shims")) {
201
- requiredDecisions.push("Remove manifest-owned generated .claude/hooks shims and keep .ai/hooks as source of truth");
202
- }
203
-
204
- const upgradeSignals = new Set(driftSignals);
205
- if (hasCustomClaudeHooks(repo)) {
206
- upgradeSignals.add("custom-claude-hooks");
207
- }
208
- if (hasAnyPath(repo, ignoredReferenceOrSecretPaths)) {
209
- upgradeSignals.add("ignored-reference-or-secret-surfaces");
210
- }
211
- const upgradePlan = upgradeActions
212
- .filter((action) => upgradeSignals.has(action.signal))
213
- .map((action) => {
214
- for (const relPath of action.paths) {
215
- if (!relPath.includes("*") && existsSync(join(repo, relPath))) {
216
- detectedPathSet.add(relPath);
217
- }
218
- }
219
- return {
220
- id: action.id,
221
- signal: action.signal,
222
- action: action.action,
223
- risk: action.risk,
224
- ownership: action.ownership,
225
- paths: action.paths,
226
- target_paths: action.targetPaths,
227
- summary: action.summary,
228
- };
229
- });
230
-
231
- let legacyContractVersion = "current-v1";
232
- if (driftSignals.includes("legacy-docs-plan") || driftSignals.includes("legacy-docs-todo")) {
233
- legacyContractVersion = "pre-tasks-first";
234
- } else if (driftSignals.includes("missing-runtime-contract-manifest")) {
235
- legacyContractVersion = "tasks-first-without-contract-manifest";
236
- }
237
-
238
- return {
239
- repo,
240
- mode: detectMode(repo),
241
- legacy_contract_version: legacyContractVersion,
242
- drift_signals: driftSignals,
243
- required_decisions: requiredDecisions,
244
- safe_defaults: safeDefaults,
245
- detected_paths: [...detectedPathSet].sort(),
246
- upgrade_plan: upgradePlan,
247
- };
248
- }
249
-
250
- function renderText(result: InspectionResult): string {
251
- const lines = [
252
- `repo: ${result.repo}`,
253
- `mode: ${result.mode}`,
254
- `legacy_contract_version: ${result.legacy_contract_version}`,
255
- `drift_signals: ${result.drift_signals.join(", ") || "(none)"}`,
256
- `required_decisions: ${result.required_decisions.join(" | ") || "(none)"}`,
257
- `safe_defaults: ${result.safe_defaults.join(" | ")}`,
258
- `upgrade_plan:`,
259
- ];
260
- if (result.upgrade_plan.length === 0) {
261
- lines.push("- (none)");
262
- } else {
263
- for (const item of result.upgrade_plan) {
264
- const target = item.target_paths?.length ? ` -> ${item.target_paths.join(", ")}` : "";
265
- lines.push(
266
- `- ${item.action} ${item.id} [${item.risk}, ${item.ownership}]: ${item.paths.join(", ")}${target}`
267
- );
268
- }
269
- }
270
- return lines.join("\n");
271
- }
272
-
273
- const { repo, format } = parseArgs(process.argv.slice(2));
274
- const result = inspectRepo(repo);
275
-
276
- if (format === "text") {
277
- console.log(renderText(result));
278
- } else {
279
- console.log(JSON.stringify(result, null, 2));
280
- }
5
+ if (import.meta.main) runTrackedForgeHelper("inspect-project-state.ts");
@@ -1055,7 +1055,9 @@ pi_install_helpers() {
1055
1055
  fi
1056
1056
 
1057
1057
  if [[ "$mode" != "apply" ]]; then
1058
- if [[ "$source_repo_target" -eq 1 || "$(pi_repo_pins_helper_source "$target_dir" && printf yes || true)" == "yes" ]]; then
1058
+ if [[ "$source_repo_target" -eq 1 ]]; then
1059
+ echo "[dry-run] preserve tracked source helper compatibility surfaces in $scripts_dir"
1060
+ elif [[ "$(pi_repo_pins_helper_source "$target_dir" && printf yes || true)" == "yes" ]]; then
1059
1061
  echo "[dry-run] install source helpers into $scripts_dir"
1060
1062
  else
1061
1063
  echo "[dry-run] install helper compatibility wrappers in $scripts_dir; package runtime dispatches through forge run"
@@ -1083,7 +1085,10 @@ pi_install_helpers() {
1083
1085
  fi
1084
1086
  fi
1085
1087
  if [[ "$source_repo_target" -eq 1 ]]; then
1086
- cp "$helpers_dir/$helper_name" "$scripts_dir/$helper_name"
1088
+ # Self-host source helpers are tracked compatibility surfaces. Their
1089
+ # implementation authority lives in assets/templates/helpers; never
1090
+ # copy the full runtime implementation back into scripts/.
1091
+ continue
1087
1092
  elif pi_repo_pins_helper_source "$target_dir"; then
1088
1093
  cp "$helpers_dir/$helper_name" "$runtime_dir/$helper_name"
1089
1094
  pi_normalize_installed_helper "$runtime_dir/$helper_name"
@@ -0,0 +1,19 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ SOURCE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
6
+ HELPER_NAME="${1:?helper filename is required}"
7
+ shift
8
+ HELPER_ID="${HELPER_NAME%.*}"
9
+
10
+ if command -v bun >/dev/null 2>&1 && [[ -f "$SOURCE_ROOT/src/cli/index.ts" && -f "$SOURCE_ROOT/assets/templates/helpers/$HELPER_NAME" ]]; then
11
+ exec bun "$SOURCE_ROOT/src/cli/index.ts" run "$HELPER_ID" "$@"
12
+ fi
13
+
14
+ if command -v forge >/dev/null 2>&1; then
15
+ exec forge run "$HELPER_ID" "$@"
16
+ fi
17
+
18
+ echo "Missing Forge runtime for helper $HELPER_ID" >&2
19
+ exit 1
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bun
2
+ import { spawnSync } from "node:child_process";
3
+ import { existsSync } from "node:fs";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ export function runTrackedForgeHelper(helperName: string, args = process.argv.slice(2)): never {
8
+ const helperId = helperName.replace(/\.[^.]+$/, "");
9
+ const scriptDir = dirname(fileURLToPath(import.meta.url));
10
+ const sourceRoot = resolve(scriptDir, "..", "..");
11
+ const sourceCli = join(sourceRoot, "src", "cli", "index.ts");
12
+ const canonicalHelper = join(sourceRoot, "assets", "templates", "helpers", helperName);
13
+ const command = existsSync(sourceCli) && existsSync(canonicalHelper)
14
+ ? ["bun", sourceCli, "run", helperId]
15
+ : ["forge", "run", helperId];
16
+ const result = spawnSync(command[0], [...command.slice(1), ...args], {
17
+ cwd: process.cwd(),
18
+ env: process.env,
19
+ stdio: "inherit",
20
+ });
21
+ if (result.error) {
22
+ console.error(`Missing Forge runtime for helper ${helperId}: ${result.error.message}`);
23
+ process.exit(1);
24
+ }
25
+ process.exit(result.status ?? 1);
26
+ }
@@ -1,36 +1,4 @@
1
1
  #!/bin/bash
2
- # Run the canonical Forge adoption path without guessing a developer checkout.
3
- #
4
- # The self-host repository invokes this script directly, so delegating to a
5
- # discovered copy of this same filename used to recurse. Installed helper
6
- # copies use an explicit source root when one is supplied, otherwise the
7
- # installed `forge` CLI.
8
-
9
2
  set -euo pipefail
10
-
11
3
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
12
- SELF_SOURCE_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
13
- SOURCE_ROOT="${FORGE_SOURCE_ROOT:-${AGENTIC_DEV_ROOT:-${AGENTIC_DEV_SKILL_ROOT:-}}}"
14
-
15
- run_source_root() {
16
- local root="$1"
17
- shift
18
- [[ -f "$root/src/cli/index.ts" ]] || return 1
19
- command -v bun >/dev/null 2>&1 || {
20
- echo "[migrate] bun is required to run Forge from source: $root" >&2
21
- exit 1
22
- }
23
- exec bun "$root/src/cli/index.ts" adopt "$@" --no-codegraph --no-verify
24
- }
25
-
26
- run_source_root "$SELF_SOURCE_ROOT" "$@"
27
- if [[ -n "$SOURCE_ROOT" ]]; then
28
- run_source_root "$SOURCE_ROOT" "$@"
29
- fi
30
-
31
- if command -v forge >/dev/null 2>&1; then
32
- exec forge adopt "$@" --no-codegraph --no-verify
33
- fi
34
-
35
- echo "[migrate] Missing Forge CLI; set FORGE_SOURCE_ROOT to a Forge source checkout." >&2
36
- exit 1
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "migrate-project-template.sh" "$@"