@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
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env bash
2
+ # Install the one Controller-owned physical-iPhone HID Python toolchain.
3
+ # Execute only with an authorized ForgeInstance host process:exec grant.
4
+ set -euo pipefail
5
+
6
+ if [[ $# -ne 1 || ! -d "$1" ]]; then
7
+ echo "Usage: $0 <existing-controller-home>" >&2
8
+ exit 2
9
+ fi
10
+ if [[ "$(uname -s)" != "Darwin" ]]; then
11
+ echo "The CoreDevice HID toolchain requires macOS." >&2
12
+ exit 2
13
+ fi
14
+
15
+ repo_root="$(cd "$(dirname "$0")/.." && pwd -P)"
16
+ controller_home="$(cd "$1" && pwd -P)"
17
+ version="11.24.0"
18
+ # The provider source is the sole runtime version authority. Refuse a stale installer.
19
+ if ! grep -Fq "export const IOS_HID_TOOLCHAIN_VERSION = '$version';" \
20
+ "$repo_root/src/runtime/plugins/ios/remote-xpc-hid.ts"; then
21
+ echo "Installer version no longer matches the RemoteXPC provider pin." >&2
22
+ exit 2
23
+ fi
24
+
25
+ toolchains="$controller_home/toolchains"
26
+ mkdir -p "$toolchains"
27
+ target="$toolchains/pymobiledevice3-$version"
28
+ lock="$toolchains/.pymobiledevice3-$version-install.lock"
29
+ if ! mkdir "$lock" 2>/dev/null; then
30
+ echo "The pinned HID toolchain is already being installed; no parallel writer." >&2
31
+ exit 1
32
+ fi
33
+
34
+ created=false
35
+ completed=false
36
+ cleanup() {
37
+ if [[ "$created" == true && "$completed" != true ]]; then
38
+ rm -rf -- "$target"
39
+ fi
40
+ rmdir "$lock" 2>/dev/null || true
41
+ }
42
+ trap cleanup EXIT
43
+
44
+ verify() {
45
+ "$1" -c "from importlib.metadata import version; from pymobiledevice3.remote.remote_service_discovery import RemoteServiceDiscoveryService; from pymobiledevice3.remote.core_device.pasteboard_service import PasteboardService; from pymobiledevice3.remote.core_device.hid_service import UniversalHIDServiceService, touch_session; actual=version('pymobiledevice3'); assert actual == '$version', (actual, '$version'); print('pymobiledevice3 ' + actual + ' verified')"
46
+ }
47
+
48
+ if [[ -e "$target" ]]; then
49
+ verify "$target/bin/python"
50
+ completed=true
51
+ exit 0
52
+ fi
53
+
54
+ # A newly created target is owned by this invocation. Never alter an old toolchain.
55
+ created=true
56
+ python3 -m venv "$target"
57
+ "$target/bin/python" -m pip install --disable-pip-version-check --no-input "pymobiledevice3==$version"
58
+ verify "$target/bin/python"
59
+ completed=true
60
+ printf 'Installed Controller-owned HID toolchain: %s\n' "$target"
@@ -2,7 +2,7 @@ import { createHash } from 'crypto';
2
2
  import { isAbsolute, join, resolve } from 'path';
3
3
  import { hostname } from 'os';
4
4
  import { systemdUserUnitName } from '../src/cli/controller/systemd-user';
5
- import { openAiSecureTunnelConnectArgs } from '../src/cli/mcp/openai-secure-tunnel';
5
+ import { openAiSecureTunnelConnectArgs } from '../adapters/mcp/tunnels/openai-secure-tunnel';
6
6
  import type { OpenAiSecureTunnelServiceConfig, PrimaryConnectorServiceConfig, PublicTunnelServiceConfig, RecoveryTunnelServiceConfig } from '../src/runtime/standalone-recovery/core';
7
7
  import { installStandaloneRecovery } from '../src/runtime/standalone-recovery/installer';
8
8
 
@@ -1029,7 +1029,7 @@ pi_install_helpers() {
1029
1029
  local target_dir="$1"
1030
1030
  local helpers_dir="$2"
1031
1031
  local mode="${3:-apply}"
1032
- local helper_names="${4:-new-spec.sh new-sprint.sh new-plan.sh capture-plan.sh plan-to-todo.sh contract-run.ts contract-worktree.sh ship-worktrees.sh archive-workflow.sh refresh-current-status.sh prepare-handoff.sh verify-contract.sh summarize-failures.sh verify-sprint.sh sprint-backlog.sh check-task-sync.sh check-deploy-sql-order.sh check-architecture-sync.sh check-agent-tooling.sh check-context-files.sh check-brain-manifest.sh sync-brain-docs.sh check-skill-version.ts select-agent-context-blocks.sh ensure-task-workflow.sh check-task-workflow.sh switch-plan.sh workflow-contract.ts inspect-project-state.ts migrate-workflow-docs.ts migrate-project-template.sh capability-resolver.ts architecture-event.ts capability-config.ts architecture-queue.sh context-contract-sync.sh workstream-sync.sh prepare-codex-handoff.sh codex-handoff-resume.sh}"
1032
+ local helper_names="${4:-new-spec.sh new-sprint.sh new-plan.sh capture-plan.sh plan-to-todo.sh contract-run.ts contract-worktree.sh ship-worktrees.sh archive-workflow.sh refresh-current-status.sh prepare-handoff.sh verify-contract.sh summarize-failures.sh verify-sprint.sh sprint-backlog.sh check-task-sync.sh check-deploy-sql-order.sh check-architecture-sync.sh check-agent-tooling.sh check-context-files.sh check-brain-manifest.sh sync-brain-docs.sh select-agent-context-blocks.sh ensure-task-workflow.sh check-task-workflow.sh switch-plan.sh workflow-contract.ts inspect-project-state.ts migrate-workflow-docs.ts migrate-project-template.sh capability-resolver.ts architecture-event.ts capability-config.ts architecture-queue.sh context-contract-sync.sh workstream-sync.sh prepare-codex-handoff.sh codex-handoff-resume.sh}"
1033
1033
  local scripts_dir="$target_dir/scripts"
1034
1034
  local runtime_dir="$target_dir/.ai/harness/scripts"
1035
1035
  local helper_name
@@ -1283,7 +1283,7 @@ pi_external_tooling_defaults_summary() {
1283
1283
  - Mode: optional-enhancements
1284
1284
  - Detection: setup/readiness only
1285
1285
  - Waza/gstack/gbrain/Mermaid: optional host enhancements; never required for Forge correctness
1286
- - CodeGraph: Forge bundled structural backend; global CLI/MCP is optional host integration
1286
+ - Code location: ripgrep lexical source search with explicit language-service definition/reference navigation; no managed graph index
1287
1287
  - Auto-actions: never install, upgrade, serve, sync, or enable unrelated third-party tooling automatically
1288
1288
  EOF_EXTERNAL_TOOLING_DEFAULTS
1289
1289
  }
@@ -1424,7 +1424,7 @@ pi_forge_version_for_refs() {
1424
1424
  printf '%s\n' "unknown"
1425
1425
  return 0
1426
1426
  fi
1427
- local version_file="$root_dir/assets/skill-version.json"
1427
+ local version_file="$root_dir/package.json"
1428
1428
 
1429
1429
  if [[ -f "$version_file" ]]; then
1430
1430
  sed -n 's/^[[:space:]]*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$version_file" | head -n 1
@@ -12,6 +12,7 @@ import {
12
12
  import { homedir } from 'os';
13
13
  import { basename, dirname, join, resolve } from 'path';
14
14
  import { spawnSync } from 'child_process';
15
+ import { assertRuntimeReleaseExecutionCanaries } from '../src/runtime/root/release-execution-canary';
15
16
  import { stageRuntimeRelease } from '../src/runtime/root/release-materialize';
16
17
  import { publishRuntimeRelease } from '../src/runtime/root/release-store';
17
18
 
@@ -254,6 +255,7 @@ try {
254
255
  // the clean source checkout before any canonical unit starts.
255
256
  preserveLegacyReleaseAuthority(destination, timestamp);
256
257
  const stagedRelease = stageRuntimeRelease({ controllerHome: destination, sourceRoot });
258
+ assertRuntimeReleaseExecutionCanaries(stagedRelease.manifestPath, destination);
257
259
  publishRuntimeRelease(destination, stagedRelease.manifestPath, `windows-wsl-controller-home-migration-${timestamp}`);
258
260
  const release = readActiveRelease(destination);
259
261
  atomicWrite(unitPath(units.canonicalRuntime), renderRuntimeUnit(destination, units.canonicalRuntime, release), 0o644);
@@ -17,7 +17,6 @@ tests/readme-dx.test.ts
17
17
 
18
18
  # Runtime proxy bypass intentionally includes Tailscale's standardized CGNAT CIDR.
19
19
  adapters/mcp/proxy-env.ts
20
- src/cli/mcp/proxy-env.ts
21
20
 
22
21
  # Scanner / redaction implementations intentionally embed pattern samples.
23
22
  scripts/public-release.ts
@@ -27,6 +27,8 @@ export function stepsFor(gate: Gate): Step[] {
27
27
  ];
28
28
  if (gate === 'main') return [
29
29
  { label: 'focused task receipt', gate: 'task' },
30
+ { label: 'frozen MCP tool contract', command: 'bun', args: ['run', 'check:mcp-compatibility'], timeoutMs: 2 * 60_000 },
31
+ { label: 'quality harness benchmark', command: 'bun', args: ['run', 'check:quality-harness'], timeoutMs: 2 * 60_000 },
30
32
  { label: 'core regression', command: 'bun', args: ['run', 'test:core'], timeoutMs: 20 * 60_000 },
31
33
  { label: 'runtime smoke', command: 'bun', args: ['run', 'check:smoke'], timeoutMs: 10 * 60_000 },
32
34
  ];
@@ -1,6 +1,7 @@
1
- import { existsSync } from 'fs';
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { createHash } from 'crypto';
2
3
  import { spawnSync } from 'child_process';
3
- import { executeIosPluginAction } from '../src/runtime/plugins/ios-adapter';
4
+ import { computerPluginAdapter } from '../src/runtime/plugins/computer-registration';
4
5
  import { resolveRepoPreferredControllerHome } from '../src/cli/repositories/controller-home';
5
6
 
6
7
  const repoRoot = process.cwd();
@@ -29,12 +30,12 @@ const common = {
29
30
  controllerHome,
30
31
  repoId,
31
32
  repoRoot,
32
- pluginId: 'ios',
33
+ pluginId: 'computer',
33
34
  origin: { surface: 'local-ui' as const, actor: 'physical-ios-live-smoke' },
34
35
  };
35
36
 
36
37
  async function invoke(actionId: string, args: Record<string, unknown>) {
37
- return executeIosPluginAction({
38
+ return computerPluginAdapter.executeAction({
38
39
  ...common,
39
40
  actionId,
40
41
  args,
@@ -43,6 +44,7 @@ async function invoke(actionId: string, args: Record<string, unknown>) {
43
44
  }
44
45
 
45
46
  let interactionId: string | undefined;
47
+ let reusedSession = false;
46
48
  try {
47
49
  const listed = await invoke('physical_device_list', {});
48
50
  const devices = Array.isArray(listed.devices) ? listed.devices as Array<Record<string, unknown>> : [];
@@ -50,6 +52,9 @@ try {
50
52
  entry.identifier === deviceSelector || entry.udid === deviceSelector || entry.name === deviceSelector);
51
53
  if (matches.length !== 1) throw new Error(`Expected exactly one physical iPhone for selector ${deviceSelector}; found ${matches.length}.`);
52
54
  const device = matches[0]!;
55
+ if (device.connected !== true || device.screenshotAvailable !== true) {
56
+ throw new Error(`The selected iPhone ${deviceSelector} has no connected CoreDevice screenshot transport. No app inspection or activation was attempted.`);
57
+ }
53
58
  const info = await invoke('physical_device_info', { device: device.identifier });
54
59
  const apps = await invoke('physical_device_apps', { device: device.identifier, bundle_id: bundleId });
55
60
  const installed = Array.isArray(apps.apps) ? apps.apps as Array<Record<string, unknown>> : [];
@@ -58,11 +63,15 @@ try {
58
63
  const opened = await invoke('physical_device_open', {
59
64
  device: device.identifier,
60
65
  bundle_id: bundleId,
61
- relaunch: true,
66
+ relaunch: false,
67
+ observe_after_open: true,
68
+ // This is a one-shot open/capture receipt; do not retain a HID worker.
69
+ prewarm_input: false,
62
70
  });
63
71
  const interaction = opened.interaction as Record<string, unknown> | undefined;
64
72
  interactionId = typeof interaction?.interactionId === 'string' ? interaction.interactionId : undefined;
65
73
  if (!interactionId) throw new Error('The physical provider did not return an interaction id.');
74
+ reusedSession = opened.reusedSession === true;
66
75
 
67
76
  const screenshot = await invoke('physical_device_screenshot', {
68
77
  interaction_id: interactionId,
@@ -71,17 +80,29 @@ try {
71
80
  const artifacts = Array.isArray(screenshot.artifactCandidates)
72
81
  ? screenshot.artifactCandidates as Array<Record<string, unknown>>
73
82
  : [];
74
- const path = typeof artifacts[0]?.path === 'string' ? artifacts[0].path : '';
83
+ const artifact = artifacts[0];
84
+ const path = typeof artifact?.path === 'string' ? artifact.path : '';
75
85
  if (!path || !existsSync(path)) throw new Error('The physical provider did not create a screenshot artifact.');
86
+ // Bind the local evidence to this exact CoreDevice observation without
87
+ // claiming what App, SKU or checkout price is actually visible.
88
+ const observation = screenshot.observation as Record<string, unknown> | undefined;
89
+ const image = readFileSync(path);
90
+ const screenshotSha256 = createHash('sha256').update(image).digest('hex');
91
+ const observationId = typeof observation?.observationId === 'string' ? observation.observationId : undefined;
92
+ if (!observationId || artifact?.sha256 !== screenshotSha256 || artifact?.bytes !== image.length
93
+ || observation?.screenshotSha256 !== screenshotSha256 || observation?.screenshotBytes !== image.length) {
94
+ throw new Error('The screenshot file and CoreDevice observation receipts do not match.');
95
+ }
76
96
  const metadata = spawnSync('sips', ['-g', 'pixelWidth', '-g', 'pixelHeight', '-g', 'format', path], { encoding: 'utf8' }).stdout;
77
97
  const width = metadata.match(/pixelWidth:\s*(\d+)/)?.[1];
78
98
  const height = metadata.match(/pixelHeight:\s*(\d+)/)?.[1];
79
99
  const format = metadata.match(/format:\s*(\S+)/)?.[1];
80
100
 
81
- const closed = await invoke('physical_device_close', { interaction_id: interactionId });
101
+ const closed = reusedSession ? undefined : await invoke('physical_device_close', { interaction_id: interactionId });
82
102
  interactionId = undefined;
83
103
  const app = installed[0]!;
84
104
  console.log(JSON.stringify({
105
+ verificationLevel: 'source_computer_adapter_open_and_capture_only',
85
106
  device: {
86
107
  name: device.name,
87
108
  model: device.model,
@@ -97,20 +118,27 @@ try {
97
118
  version: app.version,
98
119
  },
99
120
  launchStatus: interaction?.status,
121
+ reusedSession,
100
122
  controlPlane: opened.controlPlane,
101
123
  coreDeviceCapabilities: info.capabilities,
102
124
  screenViewingURLAvailable: typeof info.screenViewingURL === 'string',
103
125
  screenshot: {
104
126
  created: true,
127
+ path,
128
+ sha256: screenshotSha256,
129
+ bytes: image.length,
130
+ observationId,
131
+ observedAt: observation?.observedAt,
132
+ semanticPriceVerified: false,
105
133
  width: width ? Number(width) : undefined,
106
134
  height: height ? Number(height) : undefined,
107
135
  format,
108
136
  },
109
- closeStatus: (closed.interaction as Record<string, unknown> | undefined)?.status,
110
- deviceUnmodified: closed.deviceUnmodified === true,
137
+ closeStatus: (closed?.interaction as Record<string, unknown> | undefined)?.status,
138
+ deviceUnmodified: closed?.deviceUnmodified === true,
111
139
  }, null, 2));
112
140
  } finally {
113
- if (interactionId) {
141
+ if (interactionId && !reusedSession) {
114
142
  try { await invoke('physical_device_close', { interaction_id: interactionId }); } catch {}
115
143
  }
116
144
  }
@@ -6,13 +6,12 @@ import { join } from 'path';
6
6
  import { registerRepository } from '../src/cli/repositories/registry';
7
7
  import { readForgeRuntimeStatus } from '../src/runtime/control-plane/runtime-status-client';
8
8
  import { FORGE_TOOL_SURFACE } from '../src/cli/controller/runtime-config';
9
- import { CORE_CONTROLLER_TOOL_NAMES } from '../src/cli/mcp/toolset';
9
+ import { controllerExposureSnapshot } from '../adapters/mcp/toolset';
10
10
  import { writeMcpServiceLocalConfig } from '../adapters/mcp/auth';
11
- import { buildMcpToolDefinitions } from '../src/cli/mcp/tools';
12
- import { runtimePolicy } from '../src/cli/mcp/multi-repository';
13
- import { resolveControllerToolsetSelection } from '../src/cli/mcp/toolset-selection';
11
+ import { buildMcpToolDefinitions } from '../adapters/mcp/tool-mapping/tools';
12
+ import { runtimePolicy } from '../adapters/mcp/multi-repository';
14
13
  import { RUNTIME_WRITE_CLAIM_ENV } from '../src/runtime/root/write-fence';
15
- import { createMcpToolContext, readCanonicalRuntimeToolSchema } from '../src/cli/mcp/server';
14
+ import { createMcpToolContext, readCanonicalRuntimeToolSchema } from '../adapters/mcp/server';
16
15
 
17
16
  const root = mkdtempSync(join(tmpdir(), 'forge-mcp-http-smoke-'));
18
17
  const repoRoot = join(root, 'repo');
@@ -160,8 +159,8 @@ try {
160
159
  enableDevRunner: true,
161
160
  devRunnerAgents: 'codex,claude',
162
161
  });
163
- // Unmarked Controller startup intentionally preserves the Advanced compatibility label.
164
- const expectedToolset = resolveControllerToolsetSelection(null).toolset;
162
+ // Every Controller session exposes the same complete capability registry.
163
+ const expectedToolset = 'full';
165
164
  if (health.body.toolset !== expectedToolset) throw new Error(`TOOLSET_CHANGED: ${String(health.body.toolset)}`);
166
165
  if (health.body.toolSurface !== FORGE_TOOL_SURFACE) throw new Error(`TOOL_SURFACE_CHANGED: ${String(health.body.toolSurface)}`);
167
166
  const expectedCompatibilityToolCount = buildMcpToolDefinitions(expectedPolicy).length;
@@ -184,7 +183,7 @@ try {
184
183
  devRunnerAgents: 'codex,claude',
185
184
  });
186
185
  const runtimeSchema = await readCanonicalRuntimeToolSchema(runtimeContext);
187
- const expectedRuntimeNames = [...CORE_CONTROLLER_TOOL_NAMES].sort();
186
+ const expectedRuntimeNames = [...controllerExposureSnapshot(runtimeContext).actualToolNames].sort();
188
187
  if (JSON.stringify(runtimeSchema.toolNames) !== JSON.stringify(expectedRuntimeNames)) {
189
188
  throw new Error(`RUNTIME_TOOL_SCHEMA_CHANGED: ${JSON.stringify(runtimeSchema.toolNames)}`);
190
189
  }
@@ -3,27 +3,34 @@
3
3
  * Focused smoke: local MCP tool surface + connector freshness semantics.
4
4
  * Does not require a live ChatGPT connector session.
5
5
  */
6
- import { getMcpPolicy } from '../src/cli/mcp/policy';
7
- import { controllerExpectedToolNames } from '../src/cli/mcp/legacy-tool-service';
6
+ import { getMcpPolicy } from '../adapters/mcp/policy';
8
7
  import {
9
- ADVANCED_CONTROLLER_TOOL_NAMES,
10
- DEFAULT_CONTROLLER_TOOL_NAMES,
8
+ PREFERRED_CONTROLLER_TOOL_NAMES,
11
9
  PREFERRED_FACADE_TOOL_NAMES,
12
10
  exposedControllerToolDefinitions,
13
- } from '../src/cli/mcp/toolset';
11
+ } from '../adapters/mcp/toolset';
14
12
  import {
15
13
  EXPECTED_FACADE_TOOLS,
16
14
  OPTIONAL_INTERACTIVE_DEVELOPMENT_TOOLS,
17
15
  evaluateConnectorFreshness,
18
16
  } from '../src/cli/local-bridge/connector-freshness';
19
- import type { MultiRepositoryMcpToolContext } from '../src/cli/mcp/multi-repository';
17
+ import type { MultiRepositoryMcpToolContext } from '../adapters/mcp/multi-repository';
20
18
 
21
19
  function assert(condition: unknown, message: string): asserts condition {
22
20
  if (!condition) throw new Error(`SMOKE_FAIL: ${message}`);
23
21
  }
24
22
 
25
23
  const policy = getMcpPolicy('controller');
26
- const expected = controllerExpectedToolNames(policy);
24
+ const fullCtx = {
25
+ policy,
26
+ toolset: 'full' as const,
27
+ controllerHome: process.cwd(),
28
+ repoRoot: process.cwd(),
29
+ enableChatgptBrowser: false,
30
+ audit: () => undefined,
31
+ } as unknown as MultiRepositoryMcpToolContext;
32
+ const fullExposed = exposedControllerToolDefinitions(fullCtx).map((tool) => tool.name);
33
+ const expected = fullExposed;
27
34
 
28
35
  assert(
29
36
  JSON.stringify([...PREFERRED_FACADE_TOOL_NAMES]) === JSON.stringify([...EXPECTED_FACADE_TOOLS]),
@@ -32,7 +39,7 @@ assert(
32
39
 
33
40
  for (const name of EXPECTED_FACADE_TOOLS) {
34
41
  assert(
35
- (DEFAULT_CONTROLLER_TOOL_NAMES as readonly string[]).includes(name),
42
+ (PREFERRED_CONTROLLER_TOOL_NAMES as readonly string[]).includes(name),
36
43
  `default exposure missing ${name}`,
37
44
  );
38
45
  assert(expected.includes(name), `expectedTools missing ${name}`);
@@ -40,41 +47,21 @@ for (const name of EXPECTED_FACADE_TOOLS) {
40
47
 
41
48
  for (const name of OPTIONAL_INTERACTIVE_DEVELOPMENT_TOOLS) {
42
49
  assert(
43
- (ADVANCED_CONTROLLER_TOOL_NAMES as readonly string[]).includes(name),
44
- `interactive tool ${name} missing from ADVANCED_CONTROLLER_TOOL_NAMES`,
50
+ (PREFERRED_CONTROLLER_TOOL_NAMES as readonly string[]).includes(name),
51
+ `interactive tool ${name} missing from the preferred capability list`,
45
52
  );
46
53
  assert(
47
- (DEFAULT_CONTROLLER_TOOL_NAMES as readonly string[]).includes(name),
48
- `interactive tool ${name} missing from the stable default tools/list`,
54
+ (PREFERRED_CONTROLLER_TOOL_NAMES as readonly string[]).includes(name),
55
+ `interactive tool ${name} missing from the preferred routing list`,
49
56
  );
50
57
  }
51
58
 
52
- const coreCtx = {
53
- policy,
54
- toolset: 'core' as const,
55
- enableChatgptBrowser: false,
56
- audit: () => undefined,
57
- } as unknown as MultiRepositoryMcpToolContext;
58
- const advancedCtx = { ...coreCtx, toolset: 'advanced' as const };
59
-
60
- const coreExposed = exposedControllerToolDefinitions(coreCtx).map((tool) => tool.name);
61
- const advancedExposed = exposedControllerToolDefinitions(advancedCtx).map((tool) => tool.name);
62
- for (const name of EXPECTED_FACADE_TOOLS) {
63
- assert(coreExposed.includes(name), `exposed core tools missing ${name}`);
64
- }
65
- assert(coreExposed.includes('repository_list'), 'default surface missing repository_list');
66
- assert(!coreExposed.includes('repository_bootstrap_local_project'), 'default stable surface must not expose legacy bootstrap tool');
67
- assert(!advancedExposed.includes('repository_bootstrap_local_project'), 'advanced stable alias must not expose legacy bootstrap tool');
68
- assert(coreExposed.length === DEFAULT_CONTROLLER_TOOL_NAMES.length, `core stable tool count changed: ${coreExposed.length}`);
69
- assert(advancedExposed.length === DEFAULT_CONTROLLER_TOOL_NAMES.length, `advanced stable tool count changed: ${advancedExposed.length}`);
70
- assert(
71
- JSON.stringify(coreExposed) === JSON.stringify(advancedExposed),
72
- 'Core and Advanced must remain schema-stable aliases of the same bounded tool surface',
73
- );
74
- for (const name of OPTIONAL_INTERACTIVE_DEVELOPMENT_TOOLS) {
75
- assert(coreExposed.includes(name), `stable surface missing interactive ${name}`);
76
- assert(advancedExposed.includes(name), `advanced alias missing interactive ${name}`);
59
+ for (const name of PREFERRED_CONTROLLER_TOOL_NAMES) {
60
+ assert(fullExposed.includes(name), `complete registry missing preferred capability ${name}`);
77
61
  }
62
+ assert(fullExposed.includes('repository_bootstrap_local_project'), 'complete registry missing repository bootstrap');
63
+ assert(fullExposed.includes('git_commit_paths'), 'complete registry missing canonical Git operation');
64
+ assert(fullExposed.length > PREFERRED_CONTROLLER_TOOL_NAMES.length, 'complete registry must include every registered operation');
78
65
 
79
66
  const unable = evaluateConnectorFreshness({ localToolNames: expected });
80
67
  assert(unable.status === 'unable_to_verify_chatgpt_snapshot', `expected unable_to_verify, got ${unable.status}`);
@@ -103,11 +90,10 @@ console.log(JSON.stringify({
103
90
  ok: true,
104
91
  expectedFacadeTools: EXPECTED_FACADE_TOOLS,
105
92
  preferredTools: PREFERRED_FACADE_TOOL_NAMES,
106
- defaultToolCount: coreExposed.length,
107
- advancedToolCount: advancedExposed.length,
93
+ exposedToolCount: fullExposed.length,
94
+ preferredToolCount: PREFERRED_CONTROLLER_TOOL_NAMES.length,
108
95
  expectedToolsHasFacade: EXPECTED_FACADE_TOOLS.every((name) => expected.includes(name)),
109
- advancedHasInteractive: OPTIONAL_INTERACTIVE_DEVELOPMENT_TOOLS.every((name) =>
110
- (ADVANCED_CONTROLLER_TOOL_NAMES as readonly string[]).includes(name)),
96
+ fullHasInteractive: OPTIONAL_INTERACTIVE_DEVELOPMENT_TOOLS.every((name) => fullExposed.includes(name)),
111
97
  states: {
112
98
  unable: unable.status,
113
99
  missingSnap: missingSnap.status,
@@ -73,10 +73,13 @@ try {
73
73
  assert.equal(browserCore.parseConversation(conversationUrl)?.conversationId, conversationId);
74
74
  assert.equal(browserCore.parseConversation(`https://example.com/c/${conversationId}`), null);
75
75
  const extensionManifest = JSON.parse(readFileSync(resolve('adapters/computer/chrome-extension/manifest.json'), 'utf8')) as { permissions?: string[] };
76
- assert.equal(extensionManifest.permissions?.includes('storage'), false);
76
+ assert.equal(extensionManifest.permissions?.includes('storage'), true);
77
77
  const backgroundSource = readFileSync(resolve('adapters/computer/chrome-extension/background.js'), 'utf8');
78
- assert.ok(backgroundSource.includes('const PROVIDER_INSTANCE_ID = randomId()'));
79
- assert.equal(backgroundSource.includes('chrome.storage'), false);
78
+ assert.ok(backgroundSource.includes("chrome.storage.local.get('forgeComputerProviderInstanceId')"));
79
+ assert.ok(backgroundSource.includes('const instanceId = await providerInstanceId();'));
80
+ assert.ok(backgroundSource.includes('source: `chrome-extension:${instanceId}`'));
81
+ assert.equal(backgroundSource.includes('PROVIDER_INSTANCE_ID'), false);
82
+ assert.ok(backgroundSource.includes('chrome.storage.local.set({ forgeComputerProviderInstanceId: instanceId })'));
80
83
  assert.ok(backgroundSource.includes("nativeRpc('computer_extension_heartbeat'"));
81
84
  assert.ok(backgroundSource.includes('providerInstanceId: instanceId'));
82
85
  assert.ok(backgroundSource.includes("nativeRpc('computer_extension_claim', { provider_instance_id: instanceId })"));
@@ -92,7 +92,6 @@ function shellCompatibilityWrapper(name) {
92
92
  }
93
93
 
94
94
  const MODULE_HELPERS = new Set([
95
- 'check-skill-version.ts',
96
95
  'workflow-contract.ts',
97
96
  'inspect-project-state.ts',
98
97
  'migrate-workflow-docs.ts',
@@ -1,5 +1,5 @@
1
1
  import type { GitHubStatus } from "../github/contracts";
2
- import type { McpAgentRunnerName } from "../mcp/types";
2
+ import type { McpAgentRunnerName } from "../../../adapters/mcp/types";
3
3
  import type { ControllerAgent } from "../controller/types";
4
4
 
5
5
  export type ExecutorHealthStatus =
@@ -13,8 +13,8 @@ import {
13
13
  type EditOperation,
14
14
  type EditSession,
15
15
  } from "../editing/edit-session";
16
- import { resolveMcpPath } from "../mcp/paths";
17
- import type { McpPolicy } from "../mcp/types";
16
+ import { resolveMcpPath } from "../../../adapters/mcp/paths";
17
+ import type { McpPolicy } from "../../../adapters/mcp/types";
18
18
  import { getAgentJob, markAgentJobClosure, markAgentJobIntegrated, markAgentJobIntegrationReview } from "./job-manager";
19
19
  import type { AgentJobMeta, AgentJobPreservationReason } from "./types";
20
20
  import { assertRuntimeMayWriteOrThrow, isRuntimeWriteFenceError } from "../../runtime/root/write-fence";
@@ -1,8 +1,8 @@
1
1
  import { createHash } from 'crypto';
2
2
  import { existsSync, readFileSync, statSync } from 'fs';
3
3
  import { isAbsolute, resolve } from 'path';
4
- import { resolveMcpPath } from '../mcp/paths';
5
- import type { McpPolicy } from '../mcp/types';
4
+ import { resolveMcpPath } from '../../../adapters/mcp/paths';
5
+ import type { McpPolicy } from '../../../adapters/mcp/types';
6
6
  import type { BrowserWriteOutputPolicy, PromptBundleFile } from './types';
7
7
 
8
8
  const READ_ALLOW_GLOBS = [
@@ -2,7 +2,7 @@
2
2
  * `forge doctor` — read-only readiness diagnostics.
3
3
  *
4
4
  * Built-in checks: PATH resolution, CLI version, per-host install detection,
5
- * Codex user-level trust state count, and target-aware CodeGraph readiness.
5
+ * Codex user-level trust state count, and current-source tool readiness.
6
6
  * Never mutates.
7
7
  */
8
8
 
@@ -11,7 +11,6 @@ import * as os from 'os';
11
11
  import * as path from 'path';
12
12
  import { spawnSync } from 'child_process';
13
13
  import { ALL_TARGETS } from '../installer/targets/registry';
14
- import { checkCodegraph, type CodegraphCheckResult } from '../tools/codegraph';
15
14
  import { CLI_VERSION } from './status';
16
15
  import { runSecurityScan, type SecurityScanReport } from './security';
17
16
  import { isOptIn, resolveHooksDir, resolveRepoRoot } from '../hook/runtime';
@@ -225,142 +224,6 @@ function checkCodexTrustState(): DoctorCheckResult {
225
224
  }
226
225
  }
227
226
 
228
- function doctorStatusForCodegraph(status: CodegraphCheckResult['status']): CheckStatus {
229
- if (status === 'present') return 'ok';
230
- if (status === 'missing') return 'fail';
231
- return 'warn';
232
- }
233
-
234
- function formatCodegraphDetail(result: CodegraphCheckResult): string {
235
- const raw = result.raw as Record<string, any>;
236
- const indexStatus = raw.project_index?.status ?? 'unknown';
237
- const codexMcpStatus = raw.mcp_hosts?.codex?.status ?? 'unknown';
238
- const claudeMcpStatus = raw.mcp_hosts?.claude?.status ?? 'unknown';
239
- const bits = [
240
- result.reason,
241
- `source=${result.resolution.source}`,
242
- `version=${result.resolution.version ?? 'unknown'}`,
243
- `codex-mcp=${codexMcpStatus}`,
244
- `claude-mcp=${claudeMcpStatus}`,
245
- `index=${indexStatus}`,
246
- ];
247
- if (result.resolution.globalFallbackUsed) bits.push('global-fallback=true');
248
- const remediation = codegraphRemediation(result);
249
- if (remediation) bits.push(`remediation=${remediation}`);
250
- return bits.join('; ');
251
- }
252
-
253
- function codegraphRemediation(result: CodegraphCheckResult): string | null {
254
- if (result.status === 'present') return null;
255
-
256
- const raw = result.raw as Record<string, any>;
257
- if (result.resolution.source === 'missing') {
258
- return String(raw.install_command ?? 'bash scripts/ensure-codegraph.sh');
259
- }
260
- if (result.resolution.globalFallbackUsed) {
261
- return String(raw.install_command ?? 'bun install');
262
- }
263
- if (raw.mcp_hosts?.codex?.status !== 'configured' || raw.mcp_hosts?.claude?.status !== 'configured') {
264
- return String(raw.mcp_install_command ?? 'forge tools configure codegraph --target both --location global');
265
- }
266
- if (raw.project_index?.status === 'not-initialized') {
267
- return String(raw.init_command ?? 'bash scripts/ensure-codegraph.sh --init');
268
- }
269
- if (raw.project_index?.status === 'stale') {
270
- return String(raw.sync_command ?? 'bash scripts/ensure-codegraph.sh --sync');
271
- }
272
- return String(raw.ensure_command ?? raw.sync_command ?? 'bash scripts/ensure-codegraph.sh --check');
273
- }
274
-
275
- interface CodegraphProbe {
276
- result?: CodegraphCheckResult;
277
- error?: Error;
278
- }
279
-
280
- function probeCodegraph(cwd: string): CodegraphProbe {
281
- try {
282
- return { result: checkCodegraph({ repoRoot: cwd, host: 'both' }) };
283
- } catch (err) {
284
- return { error: err as Error };
285
- }
286
- }
287
-
288
- function checkCodegraphReadiness(probe: CodegraphProbe): DoctorCheckResult {
289
- const id = 'codegraph-readiness';
290
- const describe = 'CodeGraph CLI, MCP, and project index readiness';
291
- if (probe.result) {
292
- return {
293
- id,
294
- describe,
295
- status: doctorStatusForCodegraph(probe.result.status),
296
- detail: formatCodegraphDetail(probe.result),
297
- };
298
- }
299
- return {
300
- id,
301
- describe,
302
- status: 'fail',
303
- detail: `error checking CodeGraph readiness: ${probe.error?.message ?? 'unknown error'}`,
304
- };
305
- }
306
-
307
- function checkCodegraphMcpHost(probe: CodegraphProbe, host: 'codex' | 'claude'): DoctorCheckResult {
308
- const id = `${host}-codegraph-mcp`;
309
- const describe = `${host === 'codex' ? 'Codex' : 'Claude Code'} CodeGraph MCP config`;
310
- if (!probe.result) {
311
- return {
312
- id,
313
- describe,
314
- status: 'fail',
315
- detail: `error checking CodeGraph MCP config: ${probe.error?.message ?? 'unknown error'}`,
316
- };
317
- }
318
-
319
- const raw = probe.result.raw as Record<string, any>;
320
- const entry = raw.mcp_hosts?.[host];
321
- if (entry?.status === 'configured') {
322
- return { id, describe, status: 'ok', detail: entry.reason ?? 'configured' };
323
- }
324
- return {
325
- id,
326
- describe,
327
- status: 'warn',
328
- detail: `${entry?.reason ?? 'missing'}; remediation=forge tools configure codegraph --target ${host} --location global`,
329
- };
330
- }
331
-
332
- function checkCodegraphIndex(probe: CodegraphProbe): DoctorCheckResult {
333
- const id = 'codegraph-index';
334
- const describe = 'CodeGraph project index';
335
- if (!probe.result) {
336
- return {
337
- id,
338
- describe,
339
- status: 'fail',
340
- detail: `error checking CodeGraph index: ${probe.error?.message ?? 'unknown error'}`,
341
- };
342
- }
343
-
344
- const raw = probe.result.raw as Record<string, any>;
345
- const indexStatus = raw.project_index?.status ?? 'unknown';
346
- const status: CheckStatus = indexStatus === 'up-to-date'
347
- ? 'ok'
348
- : indexStatus === 'stale' || indexStatus === 'unknown'
349
- ? 'warn'
350
- : 'fail';
351
- const remediation = indexStatus === 'not-initialized'
352
- ? raw.init_command
353
- : indexStatus === 'stale'
354
- ? raw.sync_command
355
- : raw.ensure_command;
356
- return {
357
- id,
358
- describe,
359
- status,
360
- detail: `index=${indexStatus}${remediation ? `; remediation=${remediation}` : ''}`,
361
- };
362
- }
363
-
364
227
  function checkSecurityConfig(report: SecurityScanReport): DoctorCheckResult {
365
228
  const id = 'security-config';
366
229
  const describe = 'Local hook and VS Code automatic task security scan';
@@ -451,7 +314,6 @@ function checkHookScriptDrift(cwd: string): DoctorCheckResult {
451
314
 
452
315
  export function runDoctor(cwd: string = process.cwd()): DoctorReport {
453
316
  const checks: DoctorCheckResult[] = [];
454
- const codegraphProbe = probeCodegraph(cwd);
455
317
  const securityReport = runSecurityScan({ cwd });
456
318
  checks.push(checkPath());
457
319
  checks.push(checkVersion());
@@ -462,10 +324,6 @@ export function runDoctor(cwd: string = process.cwd()): DoctorReport {
462
324
  }
463
325
  }
464
326
  checks.push(checkCodexTrustState());
465
- checks.push(checkCodegraphReadiness(codegraphProbe));
466
- checks.push(checkCodegraphMcpHost(codegraphProbe, 'codex'));
467
- checks.push(checkCodegraphMcpHost(codegraphProbe, 'claude'));
468
- checks.push(checkCodegraphIndex(codegraphProbe));
469
327
  checks.push(checkSecurityConfig(securityReport));
470
328
  checks.push(checkHookScriptDrift(cwd));
471
329
  checks.push(checkBootstrapLifecycle());