@moretea-labs/forge 1.8.1 → 1.8.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 (328) hide show
  1. package/AGENTS.md +5 -2
  2. package/CHANGELOG.md +20 -0
  3. package/README.en.md +24 -3
  4. package/README.md +10 -6
  5. package/README.zh-CN.md +5 -3
  6. package/THIRD_PARTY_NOTICES.md +1 -2
  7. package/adapters/chatgpt/browser-delivery-runtime.ts +5 -3
  8. package/adapters/chatgpt/provider-delivery.ts +1 -1
  9. package/adapters/chatgpt/work-conversation-binding-store.ts +20 -1
  10. package/adapters/computer/chatgpt-extension-target.ts +295 -50
  11. package/adapters/computer/chrome-extension/background.js +227 -71
  12. package/adapters/computer/chrome-extension/content.js +181 -157
  13. package/adapters/computer/chrome-extension/manifest.json +3 -1
  14. package/adapters/computer/desktop-operator-provider.ts +18 -6
  15. package/adapters/computer/interaction-target-authority.ts +39 -9
  16. package/adapters/mcp/access-mode.ts +18 -39
  17. package/adapters/mcp/auth.ts +2 -6
  18. package/adapters/mcp/instructions.ts +2 -2
  19. package/adapters/mcp/multi-repository.ts +7 -28
  20. package/adapters/mcp/runtime-gateway/context-adapter.ts +79 -40
  21. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +7 -15
  22. package/adapters/mcp/runtime-gateway/execution-tools.ts +7 -13
  23. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +16 -3
  24. package/adapters/mcp/runtime-gateway/process-tools.ts +3 -21
  25. package/adapters/mcp/runtime-gateway/router.ts +3 -5
  26. package/adapters/mcp/runtime-gateway/routing-policy.ts +17 -10
  27. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +1 -1
  28. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +14 -9
  29. package/adapters/mcp/runtime-gateway/runtime-tools.ts +1 -5
  30. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +36 -1
  31. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +58 -4
  32. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +7 -3
  33. package/adapters/mcp/runtime-gateway/work-adapter.ts +16 -16
  34. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +0 -17
  35. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +69 -12
  36. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +26 -2
  37. package/adapters/mcp/server.ts +24 -3
  38. package/adapters/mcp/setup.ts +4 -10
  39. package/adapters/mcp/tool-mapping/access-tools.ts +0 -6
  40. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +672 -2935
  41. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +1 -1
  42. package/adapters/mcp/tool-mapping/repository-tools.ts +52 -86
  43. package/adapters/mcp/toolset-names.ts +11 -42
  44. package/adapters/mcp/toolset.ts +16 -90
  45. package/{src/cli → adapters}/mcp/transports/AGENTS.md +5 -5
  46. package/{src/cli → adapters}/mcp/transports/CLAUDE.md +5 -5
  47. package/adapters/mcp/transports/http-observation.ts +18 -6
  48. package/adapters/mcp/transports/http-post-lifecycle.ts +19 -0
  49. package/adapters/mcp/transports/http.ts +54 -14
  50. package/adapters/mcp/types.ts +0 -6
  51. package/assets/hooks/lib/session-state.sh +0 -38
  52. package/assets/hooks/post-bash.sh +1 -1
  53. package/assets/hooks/post-tool-observer.sh +0 -5
  54. package/assets/hooks/prompt-guard.sh +0 -55
  55. package/assets/partials/04-project-structure.partial.md +1 -1
  56. package/assets/partials/07-footer.partial.md +1 -1
  57. package/assets/partials-agents/02-operating-mode.partial.md +1 -1
  58. package/assets/partials-agents/08-deep-docs.partial.md +1 -1
  59. package/assets/reference-configs/agentic-development-flow.md +1 -1
  60. package/assets/reference-configs/external-tooling.md +0 -76
  61. package/assets/reference-configs/release-deploy.md +1 -1
  62. package/assets/templates/helpers/architecture-queue.sh +1 -1
  63. package/assets/templates/helpers/check-agent-tooling.sh +1 -327
  64. package/assets/templates/helpers/check-task-workflow.sh +1 -1
  65. package/assets/templates/helpers/ensure-task-workflow.sh +0 -14
  66. package/assets/templates/helpers/migrate-project-template.sh +2 -2
  67. package/assets/workflow-contract.v1.json +0 -2
  68. package/docs/README.md +5 -2
  69. package/docs/architecture/CURRENT.md +114 -30
  70. package/docs/architecture/decisions/20260904-ios-device-migration-baseline.md +42 -0
  71. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +15 -2
  72. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +4 -2
  73. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +109 -4
  74. package/docs/architecture/decisions/20261009-exact-code-context-discovery.md +19 -0
  75. package/docs/architecture/decisions/20261009-generated-xcode-cache-retention.md +37 -0
  76. package/docs/architecture/decisions/20261011-autonomous-continuation-convergence.md +597 -0
  77. package/docs/architecture/decisions/20261017-edit-session-finalization-reconciliation.md +17 -0
  78. package/docs/architecture/decisions/20261019-retire-host-skills.md +16 -0
  79. package/docs/architecture/diagrams/agentic-dev-plugin-architecture.html +1 -1
  80. package/docs/architecture/domains/public-surface.md +3 -5
  81. package/docs/architecture/domains/verification.md +5 -5
  82. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +2 -2
  83. package/docs/architecture/requests/2026-09-04-computer-plugin-workflow-taxonomy.md +4 -4
  84. package/docs/architecture/reviews/20261015-code-search-runtime-acceptance.md +75 -0
  85. package/docs/forge-plugin-management.md +14 -2
  86. package/docs/operations/controller-browser-plugin.md +23 -0
  87. package/docs/operations/features.md +6 -7
  88. package/docs/operations/features.zh-CN.md +1 -1
  89. package/docs/operations/github-repository.md +4 -4
  90. package/docs/operations/github-semantic-release-projection.md +20 -0
  91. package/docs/operations/homebrew.md +2 -2
  92. package/docs/operations/mcp-tool-exposure.md +13 -54
  93. package/docs/operations/runtime-performance-diagnostics.md +8 -0
  94. package/docs/operations/standalone-disaster-recovery.md +1 -1
  95. package/docs/tutorials/01-install-and-start.zh-CN.md +1 -1
  96. package/docs/tutorials/03-first-repository-task.md +2 -0
  97. package/docs/wiki/Computer-and-Plugins.md +78 -0
  98. package/docs/wiki/Computer-and-Plugins.zh-CN.md +88 -0
  99. package/docs/wiki/Home.md +16 -2
  100. package/docs/wiki/Implementation.md +24 -12
  101. package/docs/wiki/Installation.md +28 -32
  102. package/docs/wiki/Integrations.md +4 -0
  103. package/docs/wiki/Quick-Start.md +35 -22
  104. package/docs/wiki/Releases-and-Upgrades.md +15 -25
  105. package/docs/wiki/_Sidebar.md +5 -1
  106. package/package.json +1 -12
  107. package/packages/kernel/controller/infrastructure/controller-session-store.ts +63 -38
  108. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +10 -0
  109. package/packages/kernel/scheduler/application/eligibility.ts +4 -1
  110. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +13 -10
  111. package/packages/kernel/work/application/work-service.ts +1 -0
  112. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  113. package/packages/kernel/work/domain/state-machine.ts +9 -2
  114. package/packages/kernel/work/infrastructure/work-contract-store.ts +28 -1
  115. package/packages/plugin-runtime/browser/provider-registry.ts +12 -36
  116. package/packages/plugin-runtime/computer/conversation-target.ts +17 -7
  117. package/scripts/assemble-template.ts +11 -72
  118. package/scripts/check-mcp-compatibility.ts +55 -74
  119. package/scripts/check-package-identity.mjs +0 -5
  120. package/scripts/check-runtime-architecture.mjs +305 -28
  121. package/scripts/init-project.sh +0 -46
  122. package/scripts/install-ios-hid-toolchain.sh +60 -0
  123. package/scripts/install-standalone-recovery.ts +1 -1
  124. package/scripts/lib/project-init-lib.sh +3 -3
  125. package/scripts/migrate-windows-wsl-controller-home.ts +2 -0
  126. package/scripts/open-source-audit-allowlist.txt +0 -1
  127. package/scripts/run-governed-gate.ts +2 -0
  128. package/scripts/smoke-ios-physical-device.ts +38 -10
  129. package/scripts/smoke-mcp-http-runtime.ts +7 -8
  130. package/scripts/smoke-mcp-tool-surface.ts +27 -41
  131. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +6 -3
  132. package/scripts/sync-generated-authority.mjs +0 -1
  133. package/src/cli/agent-jobs/executor-health.ts +1 -1
  134. package/src/cli/agent-jobs/integration.ts +2 -2
  135. package/src/cli/chatgpt-browser/file-policy.ts +2 -2
  136. package/src/cli/commands/doctor.ts +1 -143
  137. package/src/cli/commands/global-runtime.ts +3 -196
  138. package/src/cli/commands/init-hook.ts +6 -23
  139. package/src/cli/commands/init.ts +3 -252
  140. package/src/cli/commands/mcp.ts +0 -5
  141. package/src/cli/commands/prompt-guard-decision.ts +0 -2
  142. package/src/cli/commands/recovery.ts +2 -14
  143. package/src/cli/commands/repository.ts +17 -1
  144. package/src/cli/commands/setup-execution.ts +41 -0
  145. package/src/cli/controller/completion-orchestrator.ts +1 -1
  146. package/src/cli/controller/composite-operations.ts +1 -1
  147. package/src/cli/controller/context/instruction-context.ts +1 -1
  148. package/src/cli/controller/context/known-paths.ts +2 -2
  149. package/src/cli/controller/context/query-planning.ts +11 -4
  150. package/src/cli/controller/context/rule-resolution.ts +2 -2
  151. package/src/cli/controller/context/source-materializer.ts +2 -2
  152. package/src/cli/controller/context/structural-provider.ts +84 -0
  153. package/src/cli/controller/context/structural.ts +6 -6
  154. package/src/cli/controller/context/types.ts +8 -9
  155. package/src/cli/controller/context-pack.ts +97 -76
  156. package/src/cli/controller/operational-plan.ts +1 -1
  157. package/src/cli/controller/systemd-user.ts +4 -10
  158. package/src/cli/editing/edit-session.ts +17 -5
  159. package/src/cli/github/github.ts +4 -4
  160. package/src/cli/github/semantic-projection.ts +174 -0
  161. package/src/cli/hook/prompt-intents.ts +0 -9
  162. package/src/cli/index.ts +1 -43
  163. package/src/cli/local-bridge/connector-freshness.ts +1 -12
  164. package/src/cli/local-bridge/console-automations.ts +1 -1
  165. package/src/cli/local-bridge/console-view-models.ts +1 -1
  166. package/src/cli/local-bridge/facade-api.ts +0 -2
  167. package/src/cli/repositories/command-classifier.ts +0 -9
  168. package/src/cli/repositories/command-scope.ts +2 -2
  169. package/src/cli/repositories/locks.ts +20 -0
  170. package/src/cli/repositories/registry.ts +2 -1
  171. package/src/cli/repositories/safe-patch.ts +2 -12
  172. package/src/cli/repositories/structured-git.ts +39 -3
  173. package/src/cli/repository/inspector.ts +185 -343
  174. package/src/effects/process-runner.ts +17 -1
  175. package/src/runtime/context/generic-lsp-provider.ts +1 -1
  176. package/src/runtime/context/semantic-navigation-contract.ts +7 -0
  177. package/src/runtime/context/semantic-navigation.ts +1 -1
  178. package/src/runtime/control-plane/cleanup-artifact-retention.ts +4 -4
  179. package/src/runtime/control-plane/execution/work-delivery-service.ts +150 -31
  180. package/src/runtime/control-plane/execution/work-handle-authority.ts +12 -4
  181. package/src/runtime/control-plane/execution/work-handle-store.ts +53 -1
  182. package/src/runtime/control-plane/execution/work-operation-service.ts +20 -10
  183. package/src/runtime/control-plane/execution/work-preparation-service.ts +108 -4
  184. package/src/runtime/control-plane/execution/work-process-evidence.ts +2 -2
  185. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +28 -13
  186. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +5 -1
  187. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +1 -1
  188. package/src/runtime/control-plane/facade/capability-registry.ts +2 -0
  189. package/src/runtime/control-plane/facade/work-continuation.ts +1 -1
  190. package/src/runtime/control-plane/generated-cache-retention.ts +114 -63
  191. package/src/runtime/control-plane/global-scheduler/maintenance.ts +20 -8
  192. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +1 -11
  193. package/src/runtime/control-plane/governance/external-effects.ts +1 -1
  194. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +1 -0
  195. package/src/runtime/control-plane/runtime-cleanup.ts +12 -93
  196. package/src/runtime/evidence/sensitive-output.ts +22 -2
  197. package/src/runtime/execution/jobs/child-reference.ts +11 -0
  198. package/src/runtime/execution/jobs/receipt-recovery.ts +1 -11
  199. package/src/runtime/execution/process-runtime/command-facade.ts +3 -3
  200. package/src/runtime/execution/process-runtime/runtime.ts +20 -16
  201. package/src/runtime/execution/thin-harness/execution-router.ts +16 -16
  202. package/src/runtime/execution/thin-harness/fast-executor.ts +2 -2
  203. package/src/runtime/execution/thin-harness/search-worker.ts +2 -2
  204. package/src/runtime/execution/workers/executor.ts +1 -2
  205. package/src/runtime/maintenance/cleanup.ts +41 -5
  206. package/src/runtime/plugins/action-application.ts +12 -1
  207. package/src/runtime/plugins/app-store-connect-adapter.ts +252 -4
  208. package/src/runtime/plugins/browser-adapter.ts +381 -313
  209. package/src/runtime/plugins/browser-macos-bridge.ts +114 -112
  210. package/src/runtime/plugins/browser-manifest-surface.ts +2 -1
  211. package/src/runtime/plugins/browser-registration.ts +2 -0
  212. package/src/runtime/plugins/browser-runtime.ts +26 -35
  213. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +11 -2
  214. package/src/runtime/plugins/computer-registration.ts +76 -9
  215. package/src/runtime/plugins/github-adapter.ts +30 -3
  216. package/src/runtime/plugins/gmail-adapter.ts +166 -1
  217. package/src/runtime/plugins/google-shared.ts +10 -5
  218. package/src/runtime/plugins/ios/remote-xpc-hid.ts +70 -30
  219. package/src/runtime/plugins/ios-adapter.ts +45 -40
  220. package/src/runtime/plugins/ios-agent-device.ts +54 -4
  221. package/src/runtime/plugins/ios-device-ownership.ts +103 -0
  222. package/src/runtime/plugins/ios-physical-device.ts +497 -79
  223. package/src/runtime/plugins/local-system-adapter.ts +1 -99
  224. package/src/runtime/plugins/store.ts +80 -7
  225. package/src/runtime/plugins/types.ts +4 -0
  226. package/src/runtime/projections/git-status-sampler.ts +2 -19
  227. package/src/runtime/recovery/actions.ts +1 -1
  228. package/src/runtime/recovery/lifecycle-inventory.ts +1 -11
  229. package/src/runtime/recovery/probe.ts +2 -2
  230. package/src/runtime/release/release-coordinator.ts +20 -4
  231. package/src/runtime/root/controller-progression-composition.ts +67 -5
  232. package/src/runtime/root/package-connector-service.ts +123 -11
  233. package/src/runtime/root/package-runtime-release.ts +6 -18
  234. package/src/runtime/root/package-runtime-service.ts +7 -13
  235. package/src/runtime/root/release-execution-canary.ts +18 -5
  236. package/src/runtime/root/release-manifest.ts +0 -34
  237. package/src/runtime/root/release-materialize.ts +0 -78
  238. package/src/runtime/root/runtime.ts +1 -2
  239. package/src/runtime/root/scheduled-controller-composition.ts +2 -1
  240. package/src/runtime/root/service.ts +90 -11
  241. package/src/runtime/root/types.ts +0 -6
  242. package/src/runtime/root/workflow-supervisor-composition.ts +207 -19
  243. package/src/runtime/root/workflow-supervisor-runtime.ts +365 -10
  244. package/src/runtime/safe-tooling/google-credential-store.ts +1 -11
  245. package/src/runtime/safe-tooling/ios-development.ts +22 -8
  246. package/src/runtime/safe-tooling/job-summary.ts +1 -1
  247. package/src/runtime/safe-tooling/workspace-auth.ts +4 -1
  248. package/src/runtime/shared/atomic-text-file.ts +21 -0
  249. package/src/runtime/shared/json-files.ts +8 -3
  250. package/src/runtime/standalone-recovery/core.ts +189 -174
  251. package/src/runtime/standalone-recovery/entry.ts +62 -30
  252. package/src/runtime/standalone-recovery/operation-lock.ts +11 -1
  253. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +1 -0
  254. package/src/runtime/workflow/schedules/engine.ts +36 -14
  255. package/src/runtime/workflow/schedules/pending-activation.ts +11 -4
  256. package/src/runtime/workflow/schedules/work-continuation.ts +51 -6
  257. package/supervisor/client.ts +31 -14
  258. package/supervisor/control-plane.ts +210 -115
  259. package/supervisor/forge-validators.ts +88 -21
  260. package/supervisor/native-browser-adapter.ts +393 -28
  261. package/supervisor/native-messaging/host.ts +21 -2
  262. package/supervisor/protocol.ts +74 -26
  263. package/supervisor/server.ts +16 -8
  264. package/supervisor/store.ts +476 -57
  265. package/supervisor/types.ts +19 -13
  266. package/SKILL.md +0 -427
  267. package/adapters/computer/chatgpt-target-router.ts +0 -103
  268. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +0 -87
  269. package/adapters/mcp/runtime-gateway/work-validation-reconciler.ts +0 -1
  270. package/adapters/mcp/toolset-selection.ts +0 -41
  271. package/agents/openai.yaml +0 -4
  272. package/assets/skill-hooks.json +0 -41
  273. package/assets/skill-version.json +0 -189
  274. package/assets/skills/claude-review/SKILL.md +0 -231
  275. package/assets/skills/codex-review/SKILL.md +0 -103
  276. package/assets/templates/helpers/check-skill-version.ts +0 -193
  277. package/scripts/check-skill-version.ts +0 -5
  278. package/scripts/ensure-codegraph.sh +0 -16
  279. package/scripts/run-skill-hook.ts +0 -244
  280. package/scripts/sync-codex-installed-copies.sh +0 -182
  281. package/src/cli/commands/tools.ts +0 -167
  282. package/src/cli/mcp/access-mode.ts +0 -2
  283. package/src/cli/mcp/access-tools.ts +0 -2
  284. package/src/cli/mcp/audit.ts +0 -2
  285. package/src/cli/mcp/auth.ts +0 -2
  286. package/src/cli/mcp/instructions.ts +0 -2
  287. package/src/cli/mcp/legacy-context.ts +0 -2
  288. package/src/cli/mcp/legacy-tool-service.ts +0 -2
  289. package/src/cli/mcp/multi-repository.ts +0 -2
  290. package/src/cli/mcp/oauth.ts +0 -2
  291. package/src/cli/mcp/openai-secure-tunnel.ts +0 -2
  292. package/src/cli/mcp/paths.ts +0 -2
  293. package/src/cli/mcp/policy.ts +0 -2
  294. package/src/cli/mcp/post-finalize-work-attribution.ts +0 -2
  295. package/src/cli/mcp/proxy-env.ts +0 -2
  296. package/src/cli/mcp/readiness-projection.ts +0 -2
  297. package/src/cli/mcp/redaction.ts +0 -2
  298. package/src/cli/mcp/repo.ts +0 -2
  299. package/src/cli/mcp/repository-tools.ts +0 -2
  300. package/src/cli/mcp/server.ts +0 -2
  301. package/src/cli/mcp/setup.ts +0 -2
  302. package/src/cli/mcp/tool-capability-cache.ts +0 -2
  303. package/src/cli/mcp/tool-contract.ts +0 -2
  304. package/src/cli/mcp/tools.ts +0 -2
  305. package/src/cli/mcp/toolset-names.ts +0 -2
  306. package/src/cli/mcp/toolset-selection.ts +0 -2
  307. package/src/cli/mcp/toolset.ts +0 -2
  308. package/src/cli/mcp/transports/http.ts +0 -2
  309. package/src/cli/mcp/transports/session-registry.ts +0 -2
  310. package/src/cli/mcp/transports/stdio.ts +0 -2
  311. package/src/cli/mcp/types.ts +0 -2
  312. package/src/cli/mcp/umbrella-tools.ts +0 -2
  313. package/src/cli/tools/codegraph.ts +0 -695
  314. package/src/core/adoption/helper-wrapper-plan.ts +0 -159
  315. package/src/runtime/context/codegraph-cache-boundary.ts +0 -255
  316. package/src/runtime/context/codegraph-read-provider.ts +0 -611
  317. package/src/runtime/context/codegraph-sidecar.cjs +0 -248
  318. package/src/runtime/control-plane/codegraph-cache-retention.ts +0 -164
  319. package/src/runtime/gateway/mcp/execution-tools.ts +0 -2
  320. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +0 -2
  321. package/src/runtime/gateway/mcp/persisted-check-process.ts +0 -2
  322. package/src/runtime/gateway/mcp/process-tools.ts +0 -2
  323. package/src/runtime/gateway/mcp/router.ts +0 -2
  324. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +0 -2
  325. package/src/runtime/gateway/mcp/runtime-tools.ts +0 -2
  326. package/src/runtime/gateway/mcp/work-validation-reconciler.ts +0 -2
  327. package/src/runtime/plugins/browser-provider-registry.ts +0 -2
  328. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +0 -891
@@ -1,159 +0,0 @@
1
- import { existsSync, readFileSync } from "fs";
2
- import { basename, resolve } from "path";
3
- import type { AdoptionMode } from "./modes";
4
- import type { WriteFileOperation } from "./operations";
5
- import { makeOperationId } from "./operations";
6
- import { loadWorkflowContractAsset, WORKFLOW_CONTRACT_ASSET_PATH } from "./workflow-contract-asset";
7
-
8
- const EXECUTABLE_MODE = 0o755;
9
-
10
- interface WorkflowContractForHelperWrappers {
11
- readonly helpers: {
12
- readonly compatibilityDirectory?: string;
13
- readonly scripts: readonly string[];
14
- };
15
- }
16
-
17
- function repoPinsHelperSource(repoRoot: string): boolean {
18
- if (process.env.FORGE_HELPER_SOURCE === "repo") return true;
19
- const policyPath = resolve(repoRoot, ".ai/harness/policy.json");
20
- if (!existsSync(policyPath)) return false;
21
- try {
22
- const policy = JSON.parse(readFileSync(policyPath, "utf-8")) as { harness?: { helper_source?: string } };
23
- return policy.harness?.helper_source === "repo";
24
- } catch {
25
- return false;
26
- }
27
- }
28
-
29
- function isSelfHostSourceRepo(repoRoot: string): boolean {
30
- const targetHelpers = resolve(repoRoot, "assets/templates/helpers");
31
- const assetHelpers = resolve(WORKFLOW_CONTRACT_ASSET_PATH, "..", "templates", "helpers");
32
- return existsSync(targetHelpers) && targetHelpers === assetHelpers;
33
- }
34
-
35
- function assertHelperName(helperName: string): void {
36
- if (helperName !== basename(helperName) || helperName.includes("..") || helperName.startsWith(".")) {
37
- throw new Error(`unsafe helper wrapper name: ${helperName}`);
38
- }
39
- }
40
-
41
- function helperId(helperName: string): string {
42
- return helperName.replace(/\.[^.]+$/, "");
43
- }
44
-
45
- function shellWrapper(helperName: string): string {
46
- const id = helperId(helperName);
47
- return [
48
- "#!/bin/bash",
49
- "set -euo pipefail",
50
- "",
51
- 'SOURCE_ROOT="${FORGE_SOURCE_ROOT:-${AGENTIC_DEV_ROOT:-${AGENTIC_DEV_SKILL_ROOT:-}}}"',
52
- "",
53
- 'if [[ -n "$SOURCE_ROOT" && -f "$SOURCE_ROOT/src/cli/index.ts" ]]; then',
54
- " if command -v bun >/dev/null 2>&1; then",
55
- ` exec bun "$SOURCE_ROOT/src/cli/index.ts" run ${id} "$@"`,
56
- " fi",
57
- "fi",
58
- "",
59
- "if command -v forge >/dev/null 2>&1; then",
60
- ` exec forge run ${id} "$@"`,
61
- "fi",
62
- "",
63
- `echo "Missing forge CLI for helper ${id}" >&2`,
64
- "exit 1",
65
- "",
66
- ].join("\n");
67
- }
68
-
69
- function typescriptWrapper(helperName: string): string {
70
- const id = helperId(helperName);
71
- return [
72
- "#!/usr/bin/env bun",
73
- 'import { spawnSync } from "node:child_process";',
74
- 'import { existsSync } from "node:fs";',
75
- 'import { join } from "node:path";',
76
- "",
77
- `const helperId = "${id}";`,
78
- "const DEFAULT_TIMEOUT_MS = 120_000;",
79
- "const configuredTimeoutMs = Number.parseInt(",
80
- ' process.env.FORGE_HELPER_TIMEOUT_MS ?? String(DEFAULT_TIMEOUT_MS),',
81
- " 10,",
82
- ");",
83
- "const timeoutMs = Number.isFinite(configuredTimeoutMs) && configuredTimeoutMs > 0",
84
- " ? configuredTimeoutMs",
85
- " : DEFAULT_TIMEOUT_MS;",
86
- "",
87
- "const sourceRoot =",
88
- " process.env.FORGE_SOURCE_ROOT ||",
89
- " process.env.AGENTIC_DEV_ROOT ||",
90
- " process.env.AGENTIC_DEV_SKILL_ROOT;",
91
- 'const command = sourceRoot && existsSync(join(sourceRoot, "src", "cli", "index.ts"))',
92
- ` ? ["bun", join(sourceRoot, "src", "cli", "index.ts"), "run", "${id}"]`,
93
- ` : ["forge", "run", "${id}"];`,
94
- "",
95
- "const result = spawnSync(command[0], [...command.slice(1), ...process.argv.slice(2)], {",
96
- " cwd: process.cwd(),",
97
- " env: process.env,",
98
- ' stdio: "inherit",',
99
- " timeout: timeoutMs,",
100
- "});",
101
- "",
102
- "if (result.error) {",
103
- ' const code = "code" in result.error ? String(result.error.code ?? "") : "";',
104
- ' const prefix = code === "ETIMEDOUT"',
105
- " ? `forge helper ${helperId} timed out after ${timeoutMs}ms`",
106
- " : `Missing forge CLI for helper ${helperId}`;",
107
- " console.error(`${prefix}: ${result.error.message}`);",
108
- " process.exit(1);",
109
- "}",
110
- "",
111
- "process.exit(result.status ?? 1);",
112
- "",
113
- ].join("\n");
114
- }
115
-
116
- export function helperWrapperContent(helperName: string): string {
117
- assertHelperName(helperName);
118
- return helperName.endsWith(".ts") ? typescriptWrapper(helperName) : shellWrapper(helperName);
119
- }
120
-
121
- function helperWrapperStatus(repoRoot: string, path: string): WriteFileOperation["status"] {
122
- return existsSync(resolve(repoRoot, path)) ? "skipped" : "planned";
123
- }
124
-
125
- function shouldPlanHelperWrappers(repoRoot: string, mode: AdoptionMode): boolean {
126
- return mode === "standard" && !isSelfHostSourceRepo(repoRoot) && !repoPinsHelperSource(repoRoot);
127
- }
128
-
129
- export function helperWrapperGitignoreContent(repoRoot: string, mode: AdoptionMode): string {
130
- if (!shouldPlanHelperWrappers(repoRoot, mode)) return "";
131
- const contract = loadWorkflowContractAsset<WorkflowContractForHelperWrappers>();
132
- const directory = contract.helpers.compatibilityDirectory ?? "scripts";
133
- const paths = contract.helpers.scripts.map((helperName) => {
134
- assertHelperName(helperName);
135
- return `${directory}/${helperName}`;
136
- });
137
- return ["# forge generated helper wrappers", ...paths, `${directory}/forge/`].join("\n");
138
- }
139
-
140
- export function helperWrapperOperations(repoRoot: string, mode: AdoptionMode): WriteFileOperation[] {
141
- if (!shouldPlanHelperWrappers(repoRoot, mode)) return [];
142
- const contract = loadWorkflowContractAsset<WorkflowContractForHelperWrappers>();
143
- const directory = contract.helpers.compatibilityDirectory ?? "scripts";
144
- return contract.helpers.scripts.map((helperName) => {
145
- assertHelperName(helperName);
146
- const path = `${directory}/${helperName}`;
147
- return {
148
- id: makeOperationId("writeFile", path, "helper-wrapper"),
149
- kind: "writeFile",
150
- path,
151
- content: helperWrapperContent(helperName),
152
- ifMissing: true,
153
- mode: EXECUTABLE_MODE,
154
- reason: "Install forge helper compatibility wrapper",
155
- risk: "low",
156
- status: helperWrapperStatus(repoRoot, path),
157
- };
158
- });
159
- }
@@ -1,255 +0,0 @@
1
- import { randomBytes, createHash } from 'crypto';
2
- import {
3
- cpSync,
4
- existsSync,
5
- lstatSync,
6
- mkdirSync,
7
- readdirSync,
8
- readlinkSync,
9
- rmSync,
10
- symlinkSync,
11
- utimesSync,
12
- } from 'fs';
13
- import { dirname, join, resolve } from 'path';
14
- import { withControllerLock } from '../../cli/repositories/locks';
15
-
16
- export const CODEGRAPH_LEGACY_CACHE_DIR = '.codegraph';
17
- export const CODEGRAPH_LOCATOR_PREFIX = '.codegraph-forge-';
18
- const CODEGRAPH_LOCATOR_SCAN_BUDGET = 128;
19
-
20
- /** Stable identity for Forge-owned CodeGraph cache placement. */
21
- export function codegraphCacheIdentity(repoRoot: string): string {
22
- return createHash('sha256').update(resolve(repoRoot)).digest('hex').slice(0, 24);
23
- }
24
-
25
- export function codegraphCacheRoot(controllerHome: string): string {
26
- return join(resolve(controllerHome), 'tool-cache', 'codegraph');
27
- }
28
-
29
- export function codegraphRepositoryCacheRoot(controllerHome: string, repoRoot: string): string {
30
- return join(codegraphCacheRoot(controllerHome), codegraphCacheIdentity(repoRoot));
31
- }
32
-
33
- function absoluteLinkTarget(linkPath: string): string {
34
- const target = readlinkSync(linkPath);
35
- return resolve(dirname(linkPath), target);
36
- }
37
-
38
- function samePath(left: string, right: string): boolean {
39
- return resolve(left) === resolve(right);
40
- }
41
-
42
- function processAlive(pid: number): boolean {
43
- if (!Number.isInteger(pid) || pid <= 0) return false;
44
- try {
45
- process.kill(pid, 0);
46
- return true;
47
- } catch (error) {
48
- return (error as NodeJS.ErrnoException).code === 'EPERM';
49
- }
50
- }
51
-
52
- function touchCacheRoot(path: string): void {
53
- try {
54
- const at = new Date();
55
- utimesSync(path, at, at);
56
- } catch {
57
- // Cache recency is advisory. A failed touch must never make the index an authority.
58
- }
59
- }
60
-
61
- /**
62
- * Explicit migration boundary for the retired repo-local `.codegraph` cache.
63
- * A legacy Forge compatibility symlink is simply retired. A real directory is
64
- * copied only when the Controller Home target is empty; conflicting dual cache
65
- * state fails closed instead of guessing which index is newer.
66
- */
67
- export function migrateLegacyCodegraphCache(repoRoot: string, controllerHome: string): string {
68
- const canonicalRepo = resolve(repoRoot);
69
- const targetRoot = codegraphRepositoryCacheRoot(controllerHome, canonicalRepo);
70
- const legacyRoot = join(canonicalRepo, CODEGRAPH_LEGACY_CACHE_DIR);
71
- return withControllerLock(
72
- controllerHome,
73
- { scope: 'global', resource: `codegraph-migration:${codegraphCacheIdentity(canonicalRepo)}` },
74
- `codegraph-migration:${codegraphCacheIdentity(canonicalRepo)}`,
75
- () => {
76
- mkdirSync(targetRoot, { recursive: true });
77
- if (!existsSync(legacyRoot)) return targetRoot;
78
-
79
- const stat = lstatSync(legacyRoot);
80
- if (stat.isSymbolicLink()) {
81
- if (!samePath(absoluteLinkTarget(legacyRoot), targetRoot)) {
82
- throw new Error(`CODEGRAPH_CACHE_LINK_MISMATCH: ${legacyRoot} -> ${readlinkSync(legacyRoot)}`);
83
- }
84
- rmSync(legacyRoot, { force: true });
85
- touchCacheRoot(targetRoot);
86
- return targetRoot;
87
- }
88
- if (!stat.isDirectory()) throw new Error(`CODEGRAPH_CACHE_PATH_INVALID: ${legacyRoot}`);
89
- if (readdirSync(targetRoot).length > 0) {
90
- throw new Error(`CODEGRAPH_CACHE_MIGRATION_CONFLICT: both ${legacyRoot} and ${targetRoot} contain cache state`);
91
- }
92
- cpSync(legacyRoot, targetRoot, {
93
- recursive: true,
94
- dereference: false,
95
- preserveTimestamps: true,
96
- force: false,
97
- errorOnExist: true,
98
- });
99
- rmSync(legacyRoot, { recursive: true, force: true });
100
- touchCacheRoot(targetRoot);
101
- return targetRoot;
102
- },
103
- );
104
- }
105
-
106
- export interface CodegraphLocatorCleanupReport {
107
- inspected: number;
108
- eligible: number;
109
- attempted: number;
110
- removed: string[];
111
- active: string[];
112
- skippedByReason: Record<string, number>;
113
- errors: string[];
114
- budgetExhausted: boolean;
115
- }
116
-
117
- function increment(counts: Record<string, number>, reason: string): void {
118
- counts[reason] = (counts[reason] ?? 0) + 1;
119
- }
120
-
121
- /**
122
- * Remove only dead-process locator symlinks that still point at this repo's
123
- * exact Forge cache. Live PIDs and unproven paths are preserved fail-closed.
124
- */
125
- export function cleanupStaleCodegraphLocators(
126
- repoRoot: string,
127
- controllerHome: string,
128
- maxEntries = CODEGRAPH_LOCATOR_SCAN_BUDGET,
129
- maxRemovals = 16,
130
- ): CodegraphLocatorCleanupReport {
131
- const canonicalRepo = resolve(repoRoot);
132
- const targetRoot = codegraphRepositoryCacheRoot(controllerHome, canonicalRepo);
133
- const removalLimit = Math.max(0, Math.floor(maxRemovals));
134
- const report: CodegraphLocatorCleanupReport = {
135
- inspected: 0,
136
- eligible: 0,
137
- attempted: 0,
138
- removed: [],
139
- active: [],
140
- skippedByReason: {},
141
- errors: [],
142
- budgetExhausted: false,
143
- };
144
- let entries;
145
- try {
146
- entries = readdirSync(canonicalRepo, { withFileTypes: true })
147
- .filter((entry) => String(entry.name).startsWith(CODEGRAPH_LOCATOR_PREFIX));
148
- } catch (error) {
149
- report.errors.push(error instanceof Error ? error.message : String(error));
150
- return report;
151
- }
152
- if (entries.length > maxEntries) report.budgetExhausted = true;
153
- for (const entry of entries.slice(0, Math.max(1, maxEntries))) {
154
- report.inspected += 1;
155
- const name = String(entry.name);
156
- const path = join(canonicalRepo, name);
157
- try {
158
- const stat = lstatSync(path);
159
- if (!stat.isSymbolicLink()) {
160
- increment(report.skippedByReason, 'locator_not_symlink');
161
- continue;
162
- }
163
- if (!samePath(absoluteLinkTarget(path), targetRoot)) {
164
- increment(report.skippedByReason, 'locator_target_unproven');
165
- continue;
166
- }
167
- const match = /^\.codegraph-forge-(\d+)-[a-f0-9]+$/.exec(name);
168
- if (!match) {
169
- increment(report.skippedByReason, 'locator_identity_unproven');
170
- continue;
171
- }
172
- const pid = Number(match[1]);
173
- if (processAlive(pid)) {
174
- report.active.push(name);
175
- increment(report.skippedByReason, 'active_locator');
176
- continue;
177
- }
178
- report.eligible += 1;
179
- if (report.attempted >= removalLimit) {
180
- report.budgetExhausted = true;
181
- increment(report.skippedByReason, 'cleanup_budget_exhausted');
182
- continue;
183
- }
184
- report.attempted += 1;
185
- rmSync(path, { force: true });
186
- report.removed.push(name);
187
- } catch (error) {
188
- report.errors.push(`${name}: ${error instanceof Error ? error.message : String(error)}`);
189
- }
190
- }
191
- report.active.sort();
192
- report.removed.sort();
193
- report.errors.sort();
194
- return report;
195
- }
196
-
197
- export interface CodegraphCacheLocator {
198
- name: string;
199
- path: string;
200
- targetRoot: string;
201
- release(): void;
202
- }
203
-
204
- export interface CodegraphCacheLocatorOptions {
205
- migrateLegacy?: boolean;
206
- createTarget?: boolean;
207
- }
208
-
209
- /**
210
- * Create a process-scoped CODEGRAPH_DIR locator. The source tree contains only
211
- * a short-lived symlink; durable cache bytes remain in Controller Home.
212
- */
213
- export function createCodegraphCacheLocator(
214
- repoRoot: string,
215
- controllerHome: string,
216
- options: CodegraphCacheLocatorOptions = {},
217
- ): CodegraphCacheLocator | null {
218
- const canonicalRepo = resolve(repoRoot);
219
- const targetRoot = codegraphRepositoryCacheRoot(controllerHome, canonicalRepo);
220
- if (options.migrateLegacy === true) migrateLegacyCodegraphCache(canonicalRepo, controllerHome);
221
- if (!existsSync(targetRoot)) {
222
- if (options.createTarget === false) return null;
223
- mkdirSync(targetRoot, { recursive: true });
224
- }
225
- cleanupStaleCodegraphLocators(canonicalRepo, controllerHome);
226
-
227
- let name = '';
228
- let path = '';
229
- for (let attempt = 0; attempt < 16; attempt += 1) {
230
- name = `${CODEGRAPH_LOCATOR_PREFIX}${process.pid}-${randomBytes(6).toString('hex')}`;
231
- path = join(canonicalRepo, name);
232
- if (!existsSync(path)) break;
233
- name = '';
234
- }
235
- if (!name || !path) throw new Error('CODEGRAPH_LOCATOR_ID_EXHAUSTED');
236
- symlinkSync(targetRoot, path, process.platform === 'win32' ? 'junction' : 'dir');
237
- touchCacheRoot(targetRoot);
238
- let released = false;
239
- return {
240
- name,
241
- path,
242
- targetRoot,
243
- release(): void {
244
- if (released) return;
245
- released = true;
246
- try {
247
- if (existsSync(path) && lstatSync(path).isSymbolicLink() && samePath(absoluteLinkTarget(path), targetRoot)) {
248
- rmSync(path, { force: true });
249
- }
250
- } finally {
251
- touchCacheRoot(targetRoot);
252
- }
253
- },
254
- };
255
- }