@moretea-labs/forge 1.8.0 → 1.8.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 (528) hide show
  1. package/AGENTS.md +70 -7
  2. package/CHANGELOG.md +14 -0
  3. package/CLAUDE.md +17 -2
  4. package/CONTRIBUTING.md +3 -2
  5. package/THIRD_PARTY_NOTICES.md +1 -1
  6. package/adapters/chatgpt/browser-delivery-host.ts +7 -1
  7. package/adapters/chatgpt/browser-delivery-runtime.ts +529 -56
  8. package/adapters/chatgpt/controller-binding-store.ts +101 -22
  9. package/adapters/chatgpt/controller-round-host.ts +15 -25
  10. package/adapters/chatgpt/controller-round-settlement-store.ts +58 -4
  11. package/adapters/chatgpt/provider-delivery.ts +228 -1
  12. package/adapters/chatgpt/work-conversation-binding-store.ts +79 -53
  13. package/adapters/computer/chatgpt-extension-target.ts +463 -0
  14. package/adapters/computer/chatgpt-target-router.ts +103 -0
  15. package/adapters/computer/chrome-extension/background.js +385 -0
  16. package/adapters/computer/chrome-extension/content.js +378 -0
  17. package/adapters/computer/chrome-extension/core.js +24 -0
  18. package/adapters/computer/chrome-extension/manifest.json +30 -0
  19. package/adapters/computer/desktop-operator-discovery.ts +11 -31
  20. package/adapters/computer/interaction-target-authority.ts +142 -18
  21. package/adapters/mcp/auth.ts +0 -1
  22. package/adapters/mcp/instructions.ts +5 -4
  23. package/adapters/mcp/multi-repository.ts +3 -19
  24. package/adapters/mcp/oauth.ts +73 -0
  25. package/adapters/mcp/paths.ts +4 -1
  26. package/adapters/mcp/runtime-gateway/automation-receipt-adapter.ts +87 -0
  27. package/adapters/mcp/runtime-gateway/bounded-result-runtime.ts +62 -0
  28. package/adapters/mcp/runtime-gateway/cognition-settlement.ts +201 -0
  29. package/adapters/mcp/runtime-gateway/context-adapter.ts +411 -73
  30. package/adapters/mcp/runtime-gateway/context-pack-sidecar.ts +91 -0
  31. package/adapters/mcp/runtime-gateway/controller-authority-adapter.ts +20 -5
  32. package/adapters/mcp/runtime-gateway/core-capability-adapter.ts +258 -0
  33. package/adapters/mcp/runtime-gateway/engineering-preconditions.ts +10 -27
  34. package/adapters/mcp/runtime-gateway/engineering-tool-contract.ts +15 -0
  35. package/adapters/mcp/runtime-gateway/execution-tools.ts +8 -42
  36. package/adapters/mcp/runtime-gateway/gateway-execution-adapter.ts +2 -1
  37. package/adapters/mcp/runtime-gateway/plugin-adapter.ts +117 -45
  38. package/adapters/mcp/runtime-gateway/process-tools.ts +190 -22
  39. package/adapters/mcp/runtime-gateway/protected-computer-adapter.ts +16 -4
  40. package/adapters/mcp/runtime-gateway/recovery-adapter.ts +69 -52
  41. package/adapters/mcp/runtime-gateway/repository-compat-adapter.ts +4 -35
  42. package/adapters/mcp/runtime-gateway/result-adapter.ts +10 -4
  43. package/adapters/mcp/runtime-gateway/router.ts +18 -504
  44. package/adapters/mcp/runtime-gateway/routing-policy.ts +499 -0
  45. package/adapters/mcp/runtime-gateway/runtime-observation-adapter.ts +14 -65
  46. package/adapters/mcp/runtime-gateway/runtime-readiness-observation.ts +218 -0
  47. package/adapters/mcp/runtime-gateway/runtime-tool-definitions.ts +113 -173
  48. package/adapters/mcp/runtime-gateway/runtime-tools.ts +15 -5
  49. package/adapters/mcp/runtime-gateway/scheduler-adapter.ts +1 -0
  50. package/adapters/mcp/runtime-gateway/shared-adapter.ts +20 -0
  51. package/adapters/mcp/runtime-gateway/status-inbox-adapter.ts +358 -266
  52. package/adapters/mcp/runtime-gateway/typescript-navigation-sidecar.ts +136 -0
  53. package/adapters/mcp/runtime-gateway/work-adapter.ts +261 -3122
  54. package/adapters/mcp/runtime-gateway/work-controller-operations.ts +257 -0
  55. package/adapters/mcp/runtime-gateway/work-detail-projection.ts +60 -0
  56. package/adapters/mcp/runtime-gateway/work-input-wire-migration.ts +246 -0
  57. package/adapters/mcp/runtime-gateway/work-learning-operations.ts +145 -0
  58. package/adapters/mcp/runtime-gateway/work-list-projection.ts +38 -0
  59. package/adapters/mcp/runtime-gateway/work-plan-operations.ts +382 -0
  60. package/adapters/mcp/runtime-gateway/work-repair-adapter.ts +308 -0
  61. package/adapters/mcp/runtime-gateway/work-requirement-operations.ts +148 -0
  62. package/adapters/mcp/runtime-gateway/work-semantic-operations.ts +263 -0
  63. package/adapters/mcp/runtime-gateway/work-workflow-operations.ts +113 -0
  64. package/adapters/mcp/runtime-gateway/workflow-supervisor-adapter.ts +156 -0
  65. package/adapters/mcp/server.ts +67 -23
  66. package/adapters/mcp/setup.ts +1 -3
  67. package/adapters/mcp/tool-mapping/legacy-tool-service.ts +44 -170
  68. package/adapters/mcp/tool-mapping/post-finalize-work-attribution.ts +4 -9
  69. package/adapters/mcp/tool-mapping/repository-tools.ts +133 -142
  70. package/adapters/mcp/toolset-names.ts +5 -0
  71. package/adapters/mcp/toolset.ts +6 -5
  72. package/adapters/mcp/transports/http-observation.ts +365 -0
  73. package/adapters/mcp/transports/http.ts +154 -677
  74. package/adapters/mcp/transports/oauth-http.ts +322 -0
  75. package/adapters/mcp/transports/session-registry.ts +6 -0
  76. package/adapters/mcp/tunnels/openai-secure-tunnel.ts +89 -5
  77. package/assets/plugin-registry.v1.json +6 -4
  78. package/assets/reference-configs/agentic-development-flow.md +25 -0
  79. package/assets/reference-configs/global-working-rules.md +19 -0
  80. package/assets/skill-version.json +2 -2
  81. package/docs/architecture/CURRENT.md +111 -41
  82. package/docs/architecture/decisions/20260803-release-identity-binding-and-exit-policy.md +14 -5
  83. package/docs/architecture/decisions/20260823-immediate-controller-relay.md +6 -3
  84. package/docs/architecture/decisions/20260907-assistant-learning-loop.md +2 -0
  85. package/docs/architecture/decisions/20260907-controller-round-transition-policy.md +19 -4
  86. package/docs/architecture/decisions/20260916-workflow-supervisor-authority.md +249 -0
  87. package/docs/architecture/decisions/20260917-cognitive-memory-foundation.md +82 -0
  88. package/docs/architecture/decisions/20260918-stable-candidate-release-lifecycle.md +221 -0
  89. package/docs/architecture/decisions/20260919-autonomous-work-liveness.md +62 -0
  90. package/docs/architecture/decisions/20260924-thin-semantic-working-context.md +72 -0
  91. package/docs/architecture/decisions/20261001-supervisor-turn-authority.md +237 -0
  92. package/docs/architecture/decisions/20261005-forge-v3-desktop-client-boundary.md +77 -0
  93. package/docs/architecture/domains/verification.md +1 -0
  94. package/docs/architecture/domains/workflow-engine.md +6 -0
  95. package/docs/architecture/modules/controller-runtime/transport-lifecycle.md +1 -1
  96. package/docs/forge-plugin-management.md +2 -2
  97. package/docs/operations/controller-performance-and-502.md +17 -0
  98. package/docs/operations/controller-reliability-runbook.md +2 -2
  99. package/docs/operations/features.md +1 -1
  100. package/docs/operations/features.zh-CN.md +1 -1
  101. package/docs/operations/homebrew.md +2 -2
  102. package/docs/operations/mcp-tool-exposure.md +2 -0
  103. package/docs/operations/releasing.md +2 -0
  104. package/docs/operations/standalone-disaster-recovery.md +14 -6
  105. package/docs/wiki/Implementation.md +1 -1
  106. package/package.json +25 -14
  107. package/packages/kernel/cognition/api/index.ts +6 -0
  108. package/packages/kernel/cognition/application/activation-service.ts +451 -0
  109. package/packages/kernel/cognition/application/consolidation-service.ts +185 -0
  110. package/packages/kernel/cognition/application/legacy-experience-adapter.ts +38 -0
  111. package/packages/kernel/cognition/application/memory-service.ts +64 -0
  112. package/packages/kernel/cognition/domain/learning.ts +106 -0
  113. package/packages/kernel/cognition/domain/memory.ts +254 -0
  114. package/packages/kernel/controller/api/index.ts +1 -0
  115. package/packages/kernel/controller/application/continuation-service.ts +281 -0
  116. package/packages/kernel/controller/application/controller-round-service.ts +12 -0
  117. package/packages/kernel/controller/domain/controller-round-transition-policy.ts +242 -21
  118. package/packages/kernel/controller/domain/controller-round.ts +4 -1
  119. package/packages/kernel/controller/domain/execution-quality.ts +3 -1
  120. package/packages/kernel/controller/infrastructure/controller-round-store.ts +689 -103
  121. package/packages/kernel/controller/infrastructure/controller-session-store.ts +297 -71
  122. package/packages/kernel/controller/ports/controller-host.ts +2 -0
  123. package/packages/kernel/identity/api/index.ts +10 -0
  124. package/packages/kernel/identity/domain/activity-projection.ts +43 -0
  125. package/packages/kernel/identity/domain/capability-broker.ts +60 -0
  126. package/packages/kernel/identity/domain/grant.ts +72 -0
  127. package/packages/kernel/identity/domain/owned-resource.ts +116 -0
  128. package/packages/kernel/identity/domain/user-request.ts +93 -0
  129. package/packages/kernel/identity/infrastructure/activity-projection-store.ts +77 -0
  130. package/packages/kernel/identity/infrastructure/capability-broker.ts +81 -0
  131. package/packages/kernel/identity/infrastructure/grant-store.ts +284 -0
  132. package/packages/kernel/identity/infrastructure/owned-resource-store.ts +259 -0
  133. package/packages/kernel/identity/infrastructure/user-request-store.ts +182 -0
  134. package/packages/kernel/scheduler/api/index.ts +0 -2
  135. package/packages/kernel/scheduler/application/schedule-service.ts +3 -0
  136. package/packages/kernel/scheduler/application/settlement.ts +0 -15
  137. package/packages/kernel/scheduler/domain/schedule.ts +87 -0
  138. package/packages/kernel/scheduler/infrastructure/schedule-store.ts +153 -133
  139. package/packages/kernel/work/api/index.ts +3 -2
  140. package/packages/kernel/work/application/work-service.ts +17 -42
  141. package/packages/kernel/work/domain/current-task-lineage.ts +104 -0
  142. package/packages/kernel/work/domain/engineering-design.ts +10 -5
  143. package/packages/kernel/work/domain/engineering-profile.ts +8 -12
  144. package/packages/kernel/work/domain/evaluation-promotion-receipt.ts +186 -0
  145. package/packages/kernel/work/domain/execution-concurrency.ts +19 -26
  146. package/packages/kernel/work/domain/execution-snapshot.ts +0 -31
  147. package/packages/kernel/work/domain/implementation-review.ts +14 -331
  148. package/packages/kernel/work/domain/objective-graph.ts +119 -0
  149. package/packages/kernel/work/domain/project-engineering-contract.ts +23 -1
  150. package/packages/kernel/work/domain/repository-completion-receipt.ts +1 -1
  151. package/packages/kernel/work/domain/state-machine.ts +25 -63
  152. package/packages/kernel/work/domain/types.ts +57 -51
  153. package/packages/kernel/work/infrastructure/work-contract-store.ts +819 -728
  154. package/packages/kernel/work/ports/work-contract-store.ts +5 -2
  155. package/packages/plugin-runtime/browser/session-authority.ts +2 -1
  156. package/packages/plugin-runtime/computer/chatgpt-identity.ts +24 -0
  157. package/packages/plugin-runtime/computer/conversation-target.ts +143 -0
  158. package/packages/plugin-runtime/computer/index.ts +2 -0
  159. package/packages/plugin-runtime/computer/target-authority.ts +26 -1
  160. package/packages/plugin-runtime/external/unix-jsonl-transport.ts +142 -18
  161. package/packages/protocols/computer/contract.ts +27 -1
  162. package/scripts/activate-source-baseline.ts +7 -9
  163. package/scripts/canary-controller-semantic-wait.ts +12 -24
  164. package/scripts/check-mcp-compatibility.ts +48 -136
  165. package/scripts/check-runtime-architecture.mjs +622 -217
  166. package/scripts/forge-local-recovery-helper.mjs +93 -15
  167. package/scripts/lib/project-init-lib.sh +3 -0
  168. package/scripts/open-source-audit-allowlist.txt +1 -2
  169. package/scripts/run-bounded-command.mjs +5 -0
  170. package/scripts/run-governed-gate.ts +0 -1
  171. package/scripts/run-mobile-monitor-bridge.ts +0 -1
  172. package/scripts/smoke-control-plane-failure-domain.ts +94 -0
  173. package/scripts/smoke-mcp-http-runtime.ts +5 -0
  174. package/scripts/smoke-runtime-recovery.ts +12 -43
  175. package/scripts/smoke-schedule-engine.ts +23 -15
  176. package/scripts/smoke-unattended-transport-recovery.ts +223 -0
  177. package/scripts/smoke-user-request-continuation-restart.ts +232 -0
  178. package/scripts/smoke-workflow-supervisor-chrome-adapter.ts +92 -0
  179. package/scripts/smoke-workflow-supervisor-process-restart.ts +276 -0
  180. package/scripts/smoke-workflow-supervisor-restart-recovery.ts +150 -0
  181. package/scripts/smoke-workflow-supervisor.ts +103 -0
  182. package/scripts/verify-forge-runtime.sh +2 -1
  183. package/src/cli/agent-jobs/executor-health.ts +11 -34
  184. package/src/cli/agent-jobs/integration.ts +18 -49
  185. package/src/cli/agent-jobs/job-manager.ts +7 -3
  186. package/src/cli/commands/brain-assistant.ts +27 -13
  187. package/src/cli/commands/brain.ts +13 -15
  188. package/src/cli/commands/chatgpt.ts +1 -163
  189. package/src/cli/commands/recovery.ts +135 -121
  190. package/src/cli/commands/runtime.ts +3 -3
  191. package/src/cli/commands/setup-profile.ts +8 -0
  192. package/src/cli/controller/check-runner.ts +13 -2
  193. package/src/cli/controller/completion-backlog.ts +3 -3
  194. package/src/cli/controller/completion-orchestrator.ts +4 -43
  195. package/src/cli/controller/completion-target.ts +3 -72
  196. package/src/cli/controller/context/source-materializer.ts +81 -100
  197. package/src/cli/controller/context-pack.ts +10 -8
  198. package/src/cli/controller/execution-completion.ts +4 -7
  199. package/src/cli/controller/execution-policy.ts +36 -153
  200. package/src/cli/controller/governance.ts +2 -3
  201. package/src/cli/controller/issue-store.ts +4 -99
  202. package/src/cli/controller/launch-agents.ts +59 -18
  203. package/src/cli/controller/operational-plan.ts +24 -51
  204. package/src/cli/controller/runtime-config.ts +5 -1
  205. package/src/cli/controller/stuck-state-migration.ts +2 -3
  206. package/src/cli/controller/systemd-user.ts +39 -1
  207. package/src/cli/editing/edit-session.ts +1 -7
  208. package/src/cli/local-bridge/console-automations.ts +18 -13
  209. package/src/cli/local-bridge/console-view-models.ts +3 -12
  210. package/src/cli/local-bridge/facade-api.ts +64 -191
  211. package/src/cli/local-bridge/server.ts +24 -147
  212. package/src/cli/local-bridge/types.ts +0 -1
  213. package/src/cli/mcp/oauth-client-retirement.ts +74 -0
  214. package/src/cli/repositories/command-executor.ts +29 -23
  215. package/src/cli/repositories/command-scope.ts +35 -16
  216. package/src/cli/repositories/controller-home.ts +48 -0
  217. package/src/cli/repositories/ephemeral-workspace.ts +20 -30
  218. package/src/cli/repositories/git-command-executor.ts +2 -2
  219. package/src/cli/repositories/registry.ts +77 -11
  220. package/src/cli/repositories/structured-git.ts +62 -2
  221. package/src/cli/repository/session-cache.ts +92 -6
  222. package/src/runtime/context/assistant-context.ts +20 -7
  223. package/src/runtime/context/assistant-work-context.ts +89 -27
  224. package/src/runtime/context/automatic-learning.ts +565 -0
  225. package/src/runtime/context/cognitive-attention.ts +173 -0
  226. package/src/runtime/context/cognitive-skill-canary.ts +158 -0
  227. package/src/runtime/context/context-closure.ts +46 -9
  228. package/src/runtime/context/context-pack-process.ts +103 -0
  229. package/src/runtime/context/context-plane.ts +1 -9
  230. package/src/runtime/context/direct-controller-learning.ts +298 -0
  231. package/src/runtime/context/semantic-navigation-contract.ts +9 -0
  232. package/src/runtime/context/semantic-navigation.ts +6 -34
  233. package/src/runtime/context/typescript-navigation-process.ts +145 -0
  234. package/src/runtime/context/typescript-navigation.ts +89 -3
  235. package/src/runtime/control-plane/cleanup-artifact-retention.ts +212 -9
  236. package/src/runtime/control-plane/concurrency/work-execution-concurrency.ts +9 -47
  237. package/src/runtime/control-plane/execution/controller-authority-recovery.ts +34 -4
  238. package/src/runtime/control-plane/execution/edit-validation-coordinator.ts +29 -20
  239. package/src/runtime/control-plane/execution/execution-identity.ts +23 -3
  240. package/src/runtime/control-plane/execution/repository-work-attribution.ts +7 -30
  241. package/src/runtime/control-plane/execution/retained-work-resume.ts +206 -199
  242. package/src/runtime/control-plane/execution/session-store.ts +31 -1
  243. package/src/runtime/control-plane/execution/validation.ts +6 -8
  244. package/src/runtime/control-plane/execution/work-authority-reconciler.ts +13 -42
  245. package/src/runtime/control-plane/execution/work-check-evidence.ts +137 -0
  246. package/src/runtime/control-plane/execution/work-completion-authority.ts +30 -85
  247. package/src/runtime/control-plane/execution/work-delivery-service.ts +497 -0
  248. package/src/runtime/control-plane/execution/work-evidence-policy.ts +12 -50
  249. package/src/runtime/control-plane/execution/work-execution-support.ts +50 -149
  250. package/src/runtime/control-plane/execution/work-handle-authority.ts +188 -109
  251. package/src/runtime/control-plane/execution/work-handle-store.ts +19 -43
  252. package/src/runtime/control-plane/execution/work-head-settlement.ts +53 -20
  253. package/src/runtime/control-plane/execution/work-lifecycle-audit.ts +52 -29
  254. package/src/runtime/control-plane/execution/work-operation-service.ts +43 -27
  255. package/src/runtime/control-plane/execution/work-preparation-service.ts +126 -266
  256. package/src/runtime/control-plane/execution/work-remote-delivery.ts +2 -3
  257. package/src/runtime/control-plane/execution/work-revision-diff.ts +39 -0
  258. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +173 -186
  259. package/src/runtime/control-plane/execution/work-validation-reconciler.ts +28 -84
  260. package/src/runtime/control-plane/execution/work-verification-service.ts +406 -50
  261. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  262. package/src/runtime/control-plane/facade/capability-registry.ts +362 -37
  263. package/src/runtime/control-plane/facade/check-normalization.ts +3 -9
  264. package/src/runtime/control-plane/facade/codex-delegation.ts +10 -11
  265. package/src/runtime/control-plane/facade/controller-connection.ts +135 -0
  266. package/src/runtime/control-plane/facade/goal-workloop-access.ts +1 -20
  267. package/src/runtime/control-plane/facade/goal-workloop.ts +281 -1753
  268. package/src/runtime/control-plane/facade/handoff-inbox-application.ts +12 -25
  269. package/src/runtime/control-plane/facade/handoff-inbox-store.ts +256 -52
  270. package/src/runtime/control-plane/facade/index.ts +0 -1
  271. package/src/runtime/control-plane/facade/operation-digest.ts +12 -15
  272. package/src/runtime/control-plane/facade/plan-contract-store.ts +451 -991
  273. package/src/runtime/control-plane/facade/policy-gate.ts +0 -23
  274. package/src/runtime/control-plane/facade/repository-work-admission.ts +12 -22
  275. package/src/runtime/control-plane/facade/requirement-authority.ts +102 -199
  276. package/src/runtime/control-plane/facade/requirement-board.ts +3 -3
  277. package/src/runtime/control-plane/facade/rh-work-operation-contract.ts +51 -14
  278. package/src/runtime/control-plane/facade/self-healing-loop.ts +18 -53
  279. package/src/runtime/control-plane/facade/suggested-actions.ts +15 -18
  280. package/src/runtime/control-plane/facade/types.ts +49 -108
  281. package/src/runtime/control-plane/facade/work-continuation.ts +8 -8
  282. package/src/runtime/control-plane/generated-cache-retention.ts +97 -1
  283. package/src/runtime/control-plane/global-scheduler/autonomous-continuation.ts +248 -0
  284. package/src/runtime/control-plane/global-scheduler/durable-admission.ts +1 -1
  285. package/src/runtime/control-plane/global-scheduler/maintenance.ts +239 -112
  286. package/src/runtime/control-plane/global-scheduler/reconciliation.ts +2 -1
  287. package/src/runtime/control-plane/global-scheduler/scheduler.ts +66 -40
  288. package/src/runtime/control-plane/global-scheduler/wake-signal.ts +42 -2
  289. package/src/runtime/control-plane/governance/access-policy.ts +19 -2
  290. package/src/runtime/control-plane/governance/authorization.ts +20 -3
  291. package/src/runtime/control-plane/launcher/chatgpt-round-continuation.ts +63 -300
  292. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +28 -300
  293. package/src/runtime/control-plane/launcher/local-conversation-controller.ts +238 -0
  294. package/src/runtime/control-plane/launcher/provider-mcp-bootstrap.ts +5 -2
  295. package/src/runtime/control-plane/launcher/thin-launcher.ts +96 -240
  296. package/src/runtime/control-plane/persistence/cognition-store.ts +820 -0
  297. package/src/runtime/control-plane/persistence/experience-store.ts +162 -29
  298. package/src/runtime/control-plane/persistence/requirement-store.ts +216 -74
  299. package/src/runtime/control-plane/persistence/sqlite-store.ts +113 -6
  300. package/src/runtime/control-plane/release-retention.ts +135 -47
  301. package/src/runtime/control-plane/repository-namespace-retention.ts +2 -2
  302. package/src/runtime/control-plane/runtime-cleanup.ts +290 -21
  303. package/src/runtime/control-plane/workspace/project-onboarding.ts +80 -0
  304. package/src/runtime/control-plane/workspace/semantic-sync-service.ts +19 -5
  305. package/src/runtime/control-plane/workspace/workspace-store.ts +169 -0
  306. package/src/runtime/diagnostics/incident-repair.ts +313 -146
  307. package/src/runtime/diagnostics/mcp-timing.ts +114 -0
  308. package/src/runtime/evidence/artifact-store.ts +158 -40
  309. package/src/runtime/evidence/evidence-store.ts +112 -8
  310. package/src/runtime/evidence/output-handle-index.ts +225 -0
  311. package/src/runtime/evidence/result-store.ts +158 -44
  312. package/src/runtime/execution/jobs/store.ts +3 -4
  313. package/src/runtime/execution/managed-workspace.ts +57 -0
  314. package/src/runtime/execution/process-runtime/check-facade.ts +1 -1
  315. package/src/runtime/execution/process-runtime/check-result-retention.ts +2 -2
  316. package/src/runtime/execution/process-runtime/check-result.ts +105 -1
  317. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +18 -8
  318. package/src/runtime/execution/process-runtime/command-facade.ts +79 -27
  319. package/src/runtime/execution/process-runtime/gc.ts +15 -2
  320. package/src/runtime/execution/process-runtime/handle-index.ts +176 -0
  321. package/src/runtime/execution/process-runtime/host-command-lane.ts +139 -0
  322. package/src/runtime/execution/process-runtime/index.ts +3 -0
  323. package/src/runtime/execution/process-runtime/lightweight-managed.ts +251 -72
  324. package/src/runtime/execution/process-runtime/persisted-check.ts +3 -3
  325. package/src/runtime/execution/process-runtime/process-runner-entry.ts +47 -5
  326. package/src/runtime/execution/process-runtime/process-scope.ts +160 -0
  327. package/src/runtime/execution/process-runtime/resource-claims.ts +65 -61
  328. package/src/runtime/execution/process-runtime/runtime.ts +35 -2
  329. package/src/runtime/execution/process-runtime/store.ts +30 -2
  330. package/src/runtime/execution/process-runtime/types.ts +6 -1
  331. package/src/runtime/execution/workers/executor.ts +2 -6
  332. package/src/runtime/platform/service-inventory.ts +130 -0
  333. package/src/runtime/platform/service-manager.ts +8 -0
  334. package/src/runtime/plugins/action-application.ts +85 -28
  335. package/src/runtime/plugins/app-store-connect-adapter.ts +38 -14
  336. package/src/runtime/plugins/browser-adapter.ts +757 -34
  337. package/src/runtime/plugins/browser-automation-service.ts +23 -3
  338. package/src/runtime/plugins/browser-macos-bridge.ts +321 -29
  339. package/src/runtime/plugins/browser-manifest-surface.ts +45 -11
  340. package/src/runtime/plugins/browser-native-session-service.ts +63 -13
  341. package/src/runtime/plugins/browser-registration.ts +16 -0
  342. package/src/runtime/plugins/browser-runtime.ts +14 -1
  343. package/src/runtime/plugins/browser-session-authority.ts +2 -2
  344. package/src/runtime/plugins/browser-session-store.ts +46 -76
  345. package/src/runtime/plugins/capability-authorization-grants.ts +258 -62
  346. package/src/runtime/plugins/computer-chatgpt-browser-adapter-installer.ts +219 -0
  347. package/src/runtime/plugins/computer-chatgpt-macos-target.ts +891 -0
  348. package/src/runtime/plugins/computer-registration.ts +222 -11
  349. package/src/runtime/plugins/desktop-operator-external-policy.ts +36 -4
  350. package/src/runtime/plugins/desktop-operator-registration.ts +12 -4
  351. package/src/runtime/plugins/external-adapter.ts +42 -6
  352. package/src/runtime/plugins/external-registration.ts +21 -1
  353. package/src/runtime/plugins/gmail-adapter.ts +23 -2
  354. package/src/runtime/plugins/google-calendar-adapter.ts +2 -2
  355. package/src/runtime/plugins/google-shared.ts +14 -7
  356. package/src/runtime/plugins/google-tasks-adapter.ts +2 -2
  357. package/src/runtime/plugins/ios-adapter.ts +1 -1
  358. package/src/runtime/plugins/lightweight-action.ts +208 -2
  359. package/src/runtime/plugins/local-system-adapter.ts +12 -2
  360. package/src/runtime/plugins/managed-process-adapter.ts +12 -5
  361. package/src/runtime/plugins/plugin-action-sidecar.ts +17 -13
  362. package/src/runtime/plugins/plugin-management-adapter.ts +1 -1
  363. package/src/runtime/plugins/store.ts +602 -428
  364. package/src/runtime/plugins/types.ts +20 -0
  365. package/src/runtime/plugins/xiaohongshu-publish.ts +16 -0
  366. package/src/runtime/projections/invalidation.ts +7 -3
  367. package/src/runtime/projections/materialized-view.ts +80 -36
  368. package/src/runtime/recovery/actions.ts +3 -3
  369. package/src/runtime/recovery/capability-action-application.ts +46 -45
  370. package/src/runtime/recovery/lifecycle-inventory.ts +29 -29
  371. package/src/runtime/recovery/maintenance-executor.ts +374 -123
  372. package/src/runtime/recovery/store.ts +29 -11
  373. package/src/runtime/release/release-coordinator.ts +296 -0
  374. package/src/runtime/release/release-session.ts +716 -0
  375. package/src/runtime/release/release-state-migration.ts +25 -0
  376. package/src/runtime/resources/leases/store.ts +56 -25
  377. package/src/runtime/root/computer-composition.ts +191 -6
  378. package/src/runtime/root/controller-progression-composition.ts +192 -0
  379. package/src/runtime/root/controller-round-composition.ts +20 -1
  380. package/src/runtime/root/deployment-topology.ts +106 -0
  381. package/src/runtime/root/entry.ts +4 -3
  382. package/src/runtime/root/known-good-recovery.ts +184 -0
  383. package/src/runtime/root/local-bridge.ts +0 -1
  384. package/src/runtime/root/mcp-transport.ts +111 -18
  385. package/src/runtime/root/ownership.ts +261 -9
  386. package/src/runtime/root/package-connector-service.ts +105 -19
  387. package/src/runtime/root/package-runtime-release.ts +117 -18
  388. package/src/runtime/root/package-runtime-service.ts +17 -11
  389. package/src/runtime/root/release-execution-canary.ts +44 -12
  390. package/src/runtime/root/release-loader.ts +90 -8
  391. package/src/runtime/root/release-manifest.ts +80 -6
  392. package/src/runtime/root/release-materialize.ts +372 -28
  393. package/src/runtime/root/release-store.ts +395 -36
  394. package/src/runtime/root/runtime-lane.ts +191 -0
  395. package/src/runtime/root/runtime.ts +159 -27
  396. package/src/runtime/root/scheduled-controller-composition.ts +28 -3
  397. package/src/runtime/root/service-runner.ts +2 -2
  398. package/src/runtime/root/service.ts +36 -33
  399. package/src/runtime/root/status.ts +48 -0
  400. package/src/runtime/root/types.ts +32 -3
  401. package/src/runtime/root/workflow-supervisor-composition.ts +493 -0
  402. package/src/runtime/root/workflow-supervisor-runtime.ts +209 -0
  403. package/src/runtime/root/write-fence.ts +50 -2
  404. package/src/runtime/safe-tooling/google-credential-store.ts +76 -21
  405. package/src/runtime/safe-tooling/google-oauth-broker.ts +25 -7
  406. package/src/runtime/safe-tooling/workspace-auth.ts +1 -1
  407. package/src/runtime/shared/bounded-child-supervisor.ts +9 -1
  408. package/src/runtime/shared/process-environment.ts +20 -9
  409. package/src/runtime/shared/response-budget.ts +1 -3
  410. package/src/runtime/standalone-recovery/controller-home-migration.ts +16 -24
  411. package/src/runtime/standalone-recovery/core.ts +3702 -342
  412. package/src/runtime/standalone-recovery/entry.ts +469 -39
  413. package/src/runtime/standalone-recovery/installer.ts +262 -148
  414. package/src/runtime/standalone-recovery/mcp-server.ts +29 -193
  415. package/src/runtime/standalone-recovery/operation-lock.ts +1 -1
  416. package/src/runtime/standalone-recovery/performance.ts +54 -16
  417. package/src/runtime/standalone-recovery/release.ts +53 -5
  418. package/src/runtime/standalone-recovery/service-labels.ts +5 -2
  419. package/src/runtime/standalone-recovery/watchdog-heartbeat.ts +5 -2
  420. package/src/runtime/workflow/schedules/browser-probe.ts +17 -6
  421. package/src/runtime/workflow/schedules/chatgpt-automation-migration.ts +10 -3
  422. package/src/runtime/workflow/schedules/engine.ts +138 -172
  423. package/src/runtime/workflow/schedules/work-continuation.ts +44 -5
  424. package/src/runtime/workflows/runtime.ts +15 -19
  425. package/src/testing/test-governance.ts +5 -1
  426. package/supervisor/chatgpt-conversation.ts +23 -0
  427. package/supervisor/client.ts +201 -0
  428. package/supervisor/control-plane.ts +868 -0
  429. package/supervisor/entry.ts +15 -0
  430. package/supervisor/forge-validators.ts +80 -0
  431. package/supervisor/index.ts +5 -0
  432. package/supervisor/native-browser-adapter.ts +786 -0
  433. package/supervisor/native-messaging/host.ts +39 -0
  434. package/supervisor/native-messaging/manifest.ts +26 -0
  435. package/supervisor/native-messaging/protocol.ts +27 -0
  436. package/supervisor/paths.ts +18 -0
  437. package/supervisor/protocol.ts +202 -0
  438. package/supervisor/server.ts +404 -0
  439. package/supervisor/store.ts +1451 -0
  440. package/supervisor/tsconfig.json +8 -0
  441. package/supervisor/types.ts +255 -0
  442. package/adapters/chatgpt/controller-host.ts +0 -119
  443. package/adapters/mcp/controller-round-compatibility.ts +0 -184
  444. package/adapters/mcp/frozen-client-semantic-compatibility.ts +0 -292
  445. package/adapters/mcp/runtime-gateway/work-compat-adapter.ts +0 -502
  446. package/packages/kernel/progression/api/index.ts +0 -2
  447. package/packages/kernel/progression/application/projector.ts +0 -211
  448. package/packages/kernel/progression/domain/types.ts +0 -116
  449. package/packages/kernel/progression/index.ts +0 -1
  450. package/packages/kernel/scheduler/application/continuation-service.ts +0 -212
  451. package/packages/kernel/scheduler/domain/continuation.ts +0 -38
  452. package/packages/kernel/scheduler/infrastructure/continuation-dispatch-store.ts +0 -38
  453. package/packages/kernel/work/domain/admission-policy.ts +0 -34
  454. package/scripts/benchmark-background-check-overlap.ts +0 -228
  455. package/scripts/benchmark-computer-hotpath.ts +0 -255
  456. package/scripts/benchmark-controller-hotpath.ts +0 -212
  457. package/scripts/benchmark-controller-round2.ts +0 -191
  458. package/scripts/benchmark-ios-agent-device.ts +0 -511
  459. package/scripts/benchmark-mcp-host.sh +0 -117
  460. package/scripts/benchmark-mcp-transport.ts +0 -169
  461. package/scripts/benchmark-operational-memory-activation.ts +0 -235
  462. package/scripts/benchmark-operational-shadow.ts +0 -28
  463. package/scripts/benchmark-quality-harness.ts +0 -146
  464. package/scripts/benchmark-route-session-concurrency.ts +0 -915
  465. package/scripts/benchmark-thin-harness-gateway-ab.ts +0 -632
  466. package/scripts/benchmark-thin-harness-mcp-e2e.ts +0 -498
  467. package/scripts/benchmark-thin-harness.ts +0 -251
  468. package/scripts/benchmark-typescript-navigation.ts +0 -186
  469. package/scripts/benchmark-work-efficiency.ts +0 -334
  470. package/scripts/build-controller-ui.ts +0 -28
  471. package/scripts/check-npm-release.sh +0 -32
  472. package/scripts/check-public-release-surface.sh +0 -19
  473. package/scripts/check-release-published.sh +0 -57
  474. package/scripts/check-release-readiness.sh +0 -37
  475. package/scripts/check-release-version.mjs +0 -74
  476. package/scripts/check-tarball-install-smoke.sh +0 -150
  477. package/scripts/package-source-archive.sh +0 -147
  478. package/scripts/public-release-files.txt +0 -39
  479. package/scripts/public-release.ts +0 -174
  480. package/scripts/publish-release-tarball.sh +0 -27
  481. package/scripts/route-nl-vs-ts-eval.ts +0 -679
  482. package/scripts/stage-runtime-release.ts +0 -44
  483. package/src/cli/controller/progress.ts +0 -656
  484. package/src/cli/controller/work-mode.ts +0 -181
  485. package/src/cli/local-bridge/console-assets.ts +0 -17
  486. package/src/cli/local-bridge/dashboard.ts +0 -17
  487. package/src/cli/local-bridge/frontend/src/App.tsx +0 -10
  488. package/src/cli/local-bridge/frontend/src/components/Button.tsx +0 -1
  489. package/src/cli/local-bridge/frontend/src/components/DetailPane.tsx +0 -3
  490. package/src/cli/local-bridge/frontend/src/components/SearchField.tsx +0 -1
  491. package/src/cli/local-bridge/frontend/src/components/SectionHeader.tsx +0 -1
  492. package/src/cli/local-bridge/frontend/src/components/Segmented.tsx +0 -1
  493. package/src/cli/local-bridge/frontend/src/components/StatusText.tsx +0 -3
  494. package/src/cli/local-bridge/frontend/src/design/icons.tsx +0 -11
  495. package/src/cli/local-bridge/frontend/src/design/tokens.css +0 -8
  496. package/src/cli/local-bridge/frontend/src/features/automations/AutomationsView.tsx +0 -153
  497. package/src/cli/local-bridge/frontend/src/features/capabilities/CapabilitiesView.tsx +0 -37
  498. package/src/cli/local-bridge/frontend/src/features/overview/OverviewView.tsx +0 -183
  499. package/src/cli/local-bridge/frontend/src/features/repositories/RepositoriesView.tsx +0 -2
  500. package/src/cli/local-bridge/frontend/src/features/system/SystemView.tsx +0 -2
  501. package/src/cli/local-bridge/frontend/src/features/work/WorkView.tsx +0 -4
  502. package/src/cli/local-bridge/frontend/src/lib/api.ts +0 -30
  503. package/src/cli/local-bridge/frontend/src/lib/format.ts +0 -4
  504. package/src/cli/local-bridge/frontend/src/lib/routes.ts +0 -7
  505. package/src/cli/local-bridge/frontend/src/main.tsx +0 -1
  506. package/src/cli/local-bridge/frontend/src/shell/AppShell.tsx +0 -1
  507. package/src/cli/local-bridge/frontend/src/shell/CommandBar.tsx +0 -2
  508. package/src/cli/local-bridge/frontend/src/shell/Sidebar.tsx +0 -4
  509. package/src/cli/local-bridge/frontend/src/styles.css +0 -28
  510. package/src/cli/local-bridge/frontend/src/types.ts +0 -15
  511. package/src/cli/local-bridge/frontend/src/vite-env.d.ts +0 -1
  512. package/src/cli/local-bridge/frontend/vite.config.ts +0 -27
  513. package/src/cli/local-bridge/ui-dist/app.css +0 -1
  514. package/src/cli/local-bridge/ui-dist/app.js +0 -11228
  515. package/src/runtime/control-plane/execution/content-equivalent-commit-authority.ts +0 -169
  516. package/src/runtime/control-plane/execution/direct-canonical-work-reconciliation.ts +0 -85
  517. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +0 -655
  518. package/src/runtime/control-plane/execution/work-finalization-service.ts +0 -2850
  519. package/src/runtime/control-plane/execution/work-path-scope.ts +0 -37
  520. package/src/runtime/control-plane/execution/work-task-receipt.ts +0 -468
  521. package/src/runtime/control-plane/facade/controller-round-relay.ts +0 -3
  522. package/src/runtime/control-plane/facade/work-admission-policy.ts +0 -142
  523. package/src/runtime/control-plane/facade/work-implementation-review.ts +0 -2
  524. package/src/runtime/control-plane/facade/work-state-machine.ts +0 -2
  525. package/src/runtime/control-plane/facade/work-task-projection.ts +0 -66
  526. package/src/runtime/control-plane/routing/index.ts +0 -1
  527. package/src/runtime/control-plane/routing/route-policy.ts +0 -401
  528. package/src/runtime/control-plane/routing/workspace-admission.ts +0 -70
@@ -0,0 +1,298 @@
1
+ import { createHash } from 'crypto';
2
+ import {
3
+ memoryAddressKey,
4
+ parseMemoryAddressKey,
5
+ memoryDraftFromLearningSignal,
6
+ recordCognitiveMemory,
7
+ type CognitiveWriteAuthorityPort,
8
+ type LearningSignal,
9
+ type MemoryUnit,
10
+ } from '../../../packages/kernel/cognition/api/index';
11
+ import { readForgeInstanceIdentity, type ScopeRef } from '../../../packages/kernel/identity/api/index';
12
+ import { FORGE_INSTANCE_SCOPE_KEY } from '../../cli/repositories/controller-home';
13
+ import type { RepositoryRecord } from '../../cli/repositories/types';
14
+ import { cognitionMemoryStore, cognitionReadPort, recordCognitiveUsageObservation, type CognitiveUsageRejectionKind } from '../control-plane/persistence/cognition-store';
15
+ import { resolveProjectForRepositoryPlacement } from '../control-plane/workspace/workspace-store';
16
+ import { getWorkContract } from '../../../packages/kernel/work/api/index';
17
+ import { cognitiveScopesForWork } from '../control-plane/persistence/experience-store';
18
+ import { findPluginActionReceipt } from '../plugins/store';
19
+ import {
20
+ associateStoredMemories,
21
+ consolidateAffectedMemories,
22
+ CONTROLLER_LEARNING_SIGNAL_ENVELOPE_MAX_ITEMS,
23
+ type ControllerLearningSignalDraft,
24
+ } from './automatic-learning';
25
+
26
+ export interface DirectControllerLearningResult {
27
+ storedMemoryIds: string[];
28
+ associatedEdgeCount: number;
29
+ consolidatedMemoryIds: string[];
30
+ scopes: ScopeRef[];
31
+ }
32
+
33
+ function sameScope(left: ScopeRef, right: ScopeRef): boolean {
34
+ return left.kind === right.kind && left.id === right.id;
35
+ }
36
+
37
+ export function directLearningScopes(
38
+ controllerHome: string,
39
+ repository: Pick<RepositoryRecord, 'repoId' | 'activeCheckoutId'>,
40
+ workId?: string,
41
+ ): ScopeRef[] {
42
+ if (workId) {
43
+ const work = getWorkContract({ controllerHome, repoId: repository.repoId }, workId);
44
+ if (!work) throw new Error(`WORK_NOT_FOUND: ${workId}`);
45
+ return cognitiveScopesForWork(work, controllerHome);
46
+ }
47
+ const instance = readForgeInstanceIdentity(controllerHome);
48
+ if (!instance) throw new Error('COGNITION_DIRECT_LEARNING_FORGE_INSTANCE_REQUIRED');
49
+ const project = resolveProjectForRepositoryPlacement({
50
+ controllerHome,
51
+ forgeInstanceId: instance.instanceId,
52
+ repositoryId: repository.repoId,
53
+ checkoutId: repository.activeCheckoutId,
54
+ });
55
+ if (!project) throw new Error('COGNITION_DIRECT_LEARNING_PROJECT_PLACEMENT_REQUIRED');
56
+ return [
57
+ { schemaVersion: 1, kind: 'project', id: project.projectId },
58
+ { schemaVersion: 1, kind: 'workspace', id: project.workspaceId },
59
+ ];
60
+ }
61
+
62
+ function semanticSignalId(signal: ControllerLearningSignalDraft, scope: ScopeRef): string {
63
+ const concepts = [...new Set(signal.concepts.map(value => value.trim()).filter(Boolean))].sort();
64
+ const identity = JSON.stringify({
65
+ scope: `${scope.kind}:${scope.id}`,
66
+ kind: signal.kind,
67
+ valence: signal.valence,
68
+ summary: signal.summary,
69
+ concepts,
70
+ admissionSource: signal.admissionSource,
71
+ portability: signal.portability,
72
+ });
73
+ return createHash('sha256').update(identity).digest('hex').slice(0, 32);
74
+ }
75
+
76
+ function directSourceId(input: {
77
+ principalId?: string;
78
+ sessionId?: string;
79
+ controllerInstanceId?: string;
80
+ controllerType?: string;
81
+ }): string {
82
+ const identity = [
83
+ input.principalId?.trim() ?? '',
84
+ input.controllerType?.trim() ?? '',
85
+ input.controllerInstanceId?.trim() ?? '',
86
+ input.sessionId?.trim() ?? '',
87
+ ].join(':');
88
+ return `mcp-learning:${createHash('sha256').update(identity || 'anonymous-controller').digest('hex').slice(0, 24)}`;
89
+ }
90
+
91
+ function directLearningAuthority(input: {
92
+ controllerHome: string;
93
+ repository: Pick<RepositoryRecord, 'repoId'>;
94
+ scopes: readonly ScopeRef[];
95
+ principalId?: string;
96
+ sourceId: string;
97
+ sourceWorkId?: string;
98
+ }): CognitiveWriteAuthorityPort {
99
+ const scopeAllowed = (scope: ScopeRef) => input.scopes.some(candidate => sameScope(candidate, scope));
100
+ return {
101
+ assertMemoryWrite(memory: MemoryUnit) {
102
+ if (!scopeAllowed(memory.scope)
103
+ || memory.provenance.sourceKind !== 'controller'
104
+ || memory.provenance.sourceId !== input.sourceId
105
+ || memory.provenance.sourceWorkId !== input.sourceWorkId
106
+ || memory.provenance.sourceRoundId) {
107
+ throw new Error('COGNITION_DIRECT_LEARNING_AUTHORITY_INVALID');
108
+ }
109
+ if (memory.scope.kind === 'workspace' && !memory.facets.includes('portability.portable')) {
110
+ throw new Error('COGNITION_DIRECT_LEARNING_WORKSPACE_PORTABILITY_REQUIRED');
111
+ }
112
+ },
113
+ assertEdgeWrite() {
114
+ throw new Error('COGNITION_DIRECT_LEARNING_EDGE_NOT_ALLOWED');
115
+ },
116
+ evidenceAvailable(ref, scope) {
117
+ if (!scopeAllowed(scope)) return false;
118
+ const receipt = findPluginActionReceipt(input.controllerHome, ref);
119
+ if (!receipt) return false;
120
+ if (receipt.repoId === input.repository.repoId || receipt.workRepoId === input.repository.repoId) return true;
121
+ const principal = input.principalId?.trim();
122
+ return receipt.scopeKey === FORGE_INSTANCE_SCOPE_KEY
123
+ && Boolean(principal)
124
+ && receipt.origin?.actor === principal;
125
+ },
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Persist semantic learning selected by the model without creating a learning lifecycle.
131
+ *
132
+ * The caller supplies meaning plus an optional already-existing Work identity. Forge derives
133
+ * reachable semantic scope, source identity and time. Work provenance never fabricates a
134
+ * ControllerRound; ControllerRound authority remains intentionally absent.
135
+ */
136
+ export interface DirectControllerLearningFeedbackDraft {
137
+ memoryAddress: string;
138
+ decision: 'used' | 'rejected';
139
+ reason: string;
140
+ rejectionKind?: CognitiveUsageRejectionKind;
141
+ }
142
+
143
+ export interface DirectControllerLearningFeedbackResult {
144
+ observationIds: string[];
145
+ scopes: ScopeRef[];
146
+ }
147
+
148
+ export function recordDirectControllerLearningFeedback(input: {
149
+ controllerHome: string;
150
+ repository: Pick<RepositoryRecord, 'repoId' | 'activeCheckoutId'>;
151
+ feedback: readonly DirectControllerLearningFeedbackDraft[];
152
+ principalId?: string;
153
+ sessionId?: string;
154
+ controllerInstanceId?: string;
155
+ now?: string;
156
+ workId?: string;
157
+ }): DirectControllerLearningFeedbackResult {
158
+ if (!input.feedback.length || input.feedback.length > 32) throw new Error('COGNITION_DIRECT_FEEDBACK_ITEMS_INVALID');
159
+ const principalId = input.principalId?.trim();
160
+ if (!principalId) throw new Error('COGNITION_DIRECT_FEEDBACK_PRINCIPAL_REQUIRED');
161
+ const interactionId = input.sessionId?.trim() || input.controllerInstanceId?.trim();
162
+ if (!interactionId) throw new Error('COGNITION_DIRECT_FEEDBACK_SESSION_REQUIRED');
163
+ const scopes = directLearningScopes(input.controllerHome, input.repository, input.workId);
164
+ const allowedScopes = new Set(scopes.map(scope => `${scope.kind}:${scope.id}`));
165
+ const now = input.now ?? new Date().toISOString();
166
+ const read = cognitionReadPort(input.controllerHome);
167
+ const observations = input.feedback.map((draft, index) => {
168
+ const address = parseMemoryAddressKey(draft.memoryAddress);
169
+ if (!address || !allowedScopes.has(`${address.scope.kind}:${address.scope.id}`)) {
170
+ throw new Error(`COGNITION_DIRECT_FEEDBACK_MEMORY_SCOPE_INVALID: ${index}`);
171
+ }
172
+ if (!read.readByAddresses([address]).length) {
173
+ throw new Error(`COGNITION_DIRECT_FEEDBACK_MEMORY_NOT_FOUND: ${index}`);
174
+ }
175
+ const reason = draft.reason.trim();
176
+ if (!reason || reason.length > 1_000) throw new Error(`COGNITION_DIRECT_FEEDBACK_REASON_INVALID: ${index}`);
177
+ if (draft.decision === 'rejected' && !draft.rejectionKind) {
178
+ throw new Error(`COGNITION_DIRECT_FEEDBACK_REJECTION_KIND_REQUIRED: ${index}`);
179
+ }
180
+ if (draft.decision === 'used' && draft.rejectionKind) {
181
+ throw new Error(`COGNITION_DIRECT_FEEDBACK_REJECTION_KIND_UNEXPECTED: ${index}`);
182
+ }
183
+ const observationId = `usage:${createHash('sha256')
184
+ .update(JSON.stringify({
185
+ actor: principalId,
186
+ interaction: interactionId,
187
+ address: memoryAddressKey(address),
188
+ decision: draft.decision,
189
+ rejectionKind: draft.rejectionKind ?? '',
190
+ reason,
191
+ }))
192
+ .digest('hex').slice(0, 32)}`;
193
+ return recordCognitiveUsageObservation(input.controllerHome, {
194
+ observationId,
195
+ address,
196
+ actorId: principalId,
197
+ decision: draft.decision,
198
+ reason,
199
+ ...(draft.rejectionKind ? { rejectionKind: draft.rejectionKind } : {}),
200
+ observedAt: now,
201
+ });
202
+ });
203
+ return { observationIds: observations.map(item => item.observationId), scopes };
204
+ }
205
+
206
+ export function persistDirectControllerLearning(input: {
207
+ controllerHome: string;
208
+ repository: Pick<RepositoryRecord, 'repoId' | 'activeCheckoutId'>;
209
+ signals: readonly ControllerLearningSignalDraft[];
210
+ principalId?: string;
211
+ sessionId?: string;
212
+ controllerInstanceId?: string;
213
+ controllerType?: string;
214
+ workId?: string;
215
+ now?: string;
216
+ }): DirectControllerLearningResult {
217
+ if (!input.signals.length || input.signals.length > CONTROLLER_LEARNING_SIGNAL_ENVELOPE_MAX_ITEMS) {
218
+ throw new Error('COGNITION_DIRECT_LEARNING_SIGNALS_INVALID');
219
+ }
220
+ const scopes = directLearningScopes(input.controllerHome, input.repository, input.workId);
221
+ const observedAt = input.now ?? new Date().toISOString();
222
+ const sourceId = directSourceId(input);
223
+ const projectScope = scopes.find(scope => scope.kind === 'project')!;
224
+ const workspaceScope = scopes.find(scope => scope.kind === 'workspace')!;
225
+ const store = cognitionMemoryStore(input.controllerHome);
226
+ const authority = directLearningAuthority({
227
+ controllerHome: input.controllerHome,
228
+ repository: input.repository,
229
+ scopes,
230
+ principalId: input.principalId,
231
+ sourceId,
232
+ sourceWorkId: input.workId,
233
+ });
234
+
235
+ const drafts = input.signals.map(signal => {
236
+ const scope = scopes.find(candidate => candidate.kind === signal.scopeKind)
237
+ ?? (signal.scopeKind === 'project' ? projectScope : signal.scopeKind === 'workspace' ? workspaceScope : undefined);
238
+ if (!scope) {
239
+ throw new Error(`COGNITION_LEARNING_SCOPE_UNREACHABLE: ${signal.scopeKind}`);
240
+ }
241
+ const id = semanticSignalId(signal, scope);
242
+ const learning: LearningSignal = {
243
+ schemaVersion: 1,
244
+ id: `direct:${id}`,
245
+ scope,
246
+ kind: signal.kind,
247
+ valence: signal.valence,
248
+ summary: signal.summary,
249
+ concepts: [...new Set(signal.concepts.map(value => value.trim()).filter(Boolean))],
250
+ facets: [...new Set(signal.facets.map(value => value.trim()).filter(Boolean))],
251
+ admissionSource: signal.admissionSource,
252
+ portability: signal.portability,
253
+ salience: signal.salience,
254
+ confidence: signal.confidence,
255
+ utility: signal.utility,
256
+ sourceKind: 'controller',
257
+ sourceId,
258
+ observedAt,
259
+ evidenceRefs: [...new Set(signal.evidenceRefs)],
260
+ counterEvidenceRefs: [...new Set(signal.counterEvidenceRefs)],
261
+ ...(signal.expiresAt ? { expiresAt: signal.expiresAt } : {}),
262
+ };
263
+ const draft = memoryDraftFromLearningSignal(learning);
264
+ return input.workId ? {
265
+ ...draft,
266
+ provenance: {
267
+ ...draft.provenance,
268
+ sourceWorkId: input.workId,
269
+ },
270
+ } : draft;
271
+ });
272
+
273
+ // Validate all evidence before any write so a multi-signal call cannot partially commit.
274
+ for (const draft of drafts) {
275
+ authority.assertMemoryWrite({ ...draft, schemaVersion: 1, revision: 1 });
276
+ for (const ref of [...draft.provenance.evidenceRefs, ...draft.counterEvidenceRefs]) {
277
+ if (!authority.evidenceAvailable(ref, draft.scope)) {
278
+ throw new Error(`COGNITION_DIRECT_LEARNING_EVIDENCE_UNAVAILABLE: ${ref}`);
279
+ }
280
+ }
281
+ }
282
+
283
+ const stored = store.transaction(() => drafts.map(draft =>
284
+ recordCognitiveMemory(store, authority, draft)));
285
+ const associatedEdgeCount = associateStoredMemories({
286
+ controllerHome: input.controllerHome,
287
+ memories: stored,
288
+ now: observedAt,
289
+ });
290
+ const consolidatedMemoryIds = scopes.flatMap(scope =>
291
+ consolidateAffectedMemories(input.controllerHome, scope, stored, observedAt).map(candidate => candidate.memory.id));
292
+ return {
293
+ storedMemoryIds: stored.map(memory => memory.id),
294
+ associatedEdgeCount,
295
+ consolidatedMemoryIds: [...new Set(consolidatedMemoryIds)],
296
+ scopes,
297
+ };
298
+ }
@@ -32,10 +32,19 @@ export type SemanticNavigationOutcome =
32
32
  | { ok: true; result: SemanticNavigationResult }
33
33
  | { ok: false; code: string; message: string };
34
34
 
35
+ export interface SemanticNavigationReadPolicy {
36
+ profile: string;
37
+ readGlobs: readonly string[];
38
+ denyGlobs: readonly string[];
39
+ maxFileBytes: number;
40
+ }
41
+
35
42
  export interface SemanticNavigationAccess {
36
43
  cacheScope: string;
37
44
  sourceIdentity?: string;
38
45
  profile: string;
46
+ /** Serializable policy used by disposable semantic sidecars. */
47
+ readPolicy?: SemanticNavigationReadPolicy;
39
48
  allowRepositoryPath(relativePath: string): boolean;
40
49
  }
41
50
 
@@ -1,5 +1,5 @@
1
1
  import { extname } from 'path';
2
- import { navigateTypeScriptSymbol } from './typescript-navigation';
2
+ import { navigateTypeScriptInSidecar } from './typescript-navigation-process';
3
3
  import { navigateSwiftSymbols } from './swift-navigation';
4
4
  import { GenericLspSemanticProvider, type GenericLspProviderDescriptor } from './generic-lsp-provider';
5
5
 
@@ -25,39 +25,11 @@ const typeScriptProvider: SemanticNavigationProvider = {
25
25
  return extensionSupported && (!request.language || request.language.toLowerCase() === 'typescript');
26
26
  },
27
27
  async navigate(repoRoot, requests, access) {
28
- return requests.map((request) => {
29
- let policyDeniedReads = 0;
30
- try {
31
- const result = navigateTypeScriptSymbol(repoRoot, {
32
- navigation: request.navigation,
33
- path: request.path,
34
- line: request.line,
35
- column: request.column,
36
- tsconfigPath: request.tsconfigPath,
37
- }, {
38
- cacheScope: access.cacheScope,
39
- sourceIdentity: access.sourceIdentity,
40
- allowRepositoryPath: (relativePath) => {
41
- const allowed = access.allowRepositoryPath(relativePath);
42
- if (!allowed) policyDeniedReads += 1;
43
- return allowed;
44
- },
45
- });
46
- return {
47
- ok: true,
48
- result: {
49
- providerId: 'typescript-language-service',
50
- language: 'typescript',
51
- navigation: result.navigation,
52
- target: result.target,
53
- locations: result.locations,
54
- policyDeniedReads,
55
- },
56
- } satisfies SemanticNavigationOutcome;
57
- } catch (error) {
58
- return { ok: false, code: 'SEMANTIC_NAVIGATION_FAILED', message: error instanceof Error ? error.message : String(error) } satisfies SemanticNavigationOutcome;
59
- }
60
- });
28
+ // A Forge-sized TypeScript LanguageService can return its live heap after
29
+ // dispose() while JSC/WebKit keeps the expanded allocator resident. Keep
30
+ // that allocator lifetime out of the canonical Runtime: one bounded batch
31
+ // runs in one short-lived sidecar and the OS reclaims it on process exit.
32
+ return navigateTypeScriptInSidecar(repoRoot, requests, access);
61
33
  },
62
34
  };
63
35
 
@@ -0,0 +1,145 @@
1
+ import { existsSync, lstatSync, readFileSync } from 'fs';
2
+ import { dirname, join, resolve } from 'path';
3
+ import { runProcess } from '../../effects/process-runner';
4
+ import { resolveBunExecutable } from '../shared/process-environment';
5
+ import type {
6
+ SemanticNavigationAccess,
7
+ SemanticNavigationOutcome,
8
+ SemanticNavigationRequest,
9
+ } from './semantic-navigation-contract';
10
+
11
+ const TYPESCRIPT_NAVIGATION_SIDECAR_ENTRYPOINT = 'forge-typescript-navigation' as const;
12
+ const TYPESCRIPT_NAVIGATION_TIMEOUT_MS = 60_000;
13
+ const TYPESCRIPT_NAVIGATION_MAX_OUTPUT_BYTES = 4 * 1024 * 1024;
14
+
15
+ interface SidecarResponse {
16
+ schemaVersion: 1;
17
+ outcomes: SemanticNavigationOutcome[];
18
+ }
19
+
20
+ interface SourceSymbolsSidecarResponse {
21
+ schemaVersion: 1;
22
+ symbols: Array<{ startLine: number; endLine: number; kind: string; name?: string; enclosing?: string }>;
23
+ }
24
+
25
+ interface SidecarManifestRecord {
26
+ typescriptNavigationEntrypoint?: unknown;
27
+ typescriptNavigationArtifactIdentity?: unknown;
28
+ }
29
+
30
+ function releaseManifestArgument(argv: readonly string[]): string | undefined {
31
+ const index = argv.indexOf('--release-manifest');
32
+ const value = index >= 0 ? argv[index + 1]?.trim() : undefined;
33
+ return value ? resolve(value) : undefined;
34
+ }
35
+
36
+ export function resolveTypeScriptNavigationSidecarCommand(
37
+ argv: readonly string[] = process.argv,
38
+ ): { executable: string; args: string[]; cwd?: string } {
39
+ const manifestPath = releaseManifestArgument(argv);
40
+ if (manifestPath) {
41
+ const parsed = JSON.parse(readFileSync(manifestPath, 'utf8')) as SidecarManifestRecord;
42
+ if (parsed.typescriptNavigationEntrypoint !== TYPESCRIPT_NAVIGATION_SIDECAR_ENTRYPOINT) {
43
+ throw new Error('TYPESCRIPT_NAVIGATION_SIDECAR_MANIFEST_MISSING');
44
+ }
45
+ const identity = typeof parsed.typescriptNavigationArtifactIdentity === 'string'
46
+ ? parsed.typescriptNavigationArtifactIdentity.trim()
47
+ : '';
48
+ if (!/^sha256:[a-f0-9]{64}$/i.test(identity)) {
49
+ throw new Error('TYPESCRIPT_NAVIGATION_SIDECAR_IDENTITY_INVALID');
50
+ }
51
+ const executable = join(dirname(manifestPath), TYPESCRIPT_NAVIGATION_SIDECAR_ENTRYPOINT);
52
+ if (!existsSync(executable)) throw new Error('TYPESCRIPT_NAVIGATION_SIDECAR_MISSING');
53
+ const status = lstatSync(executable);
54
+ if (status.isSymbolicLink() || !status.isFile() || (status.mode & 0o111) === 0) {
55
+ throw new Error('TYPESCRIPT_NAVIGATION_SIDECAR_NOT_EXECUTABLE');
56
+ }
57
+ return { executable, args: [], cwd: dirname(manifestPath) };
58
+ }
59
+
60
+ // Construct the development-only path at runtime. A literal new URL() to the
61
+ // .ts sidecar makes Bun bundle that file as an asset and drags the TypeScript
62
+ // compiler graph back into the long-lived Runtime.
63
+ const entry = resolve(process.cwd(), 'adapters', 'mcp', 'runtime-gateway', 'typescript-navigation-sidecar.ts');
64
+ if (!existsSync(entry)) throw new Error('TYPESCRIPT_NAVIGATION_SOURCE_SIDECAR_MISSING');
65
+ return {
66
+ executable: resolveBunExecutable(process.execPath, process.env),
67
+ args: [entry],
68
+ cwd: dirname(entry),
69
+ };
70
+ }
71
+
72
+ function failedOutcomes(requests: readonly SemanticNavigationRequest[], code: string, message: string): SemanticNavigationOutcome[] {
73
+ return requests.map(() => ({ ok: false as const, code, message }));
74
+ }
75
+
76
+ export function extractTypeScriptSourceSymbolsInSidecar(
77
+ path: string,
78
+ source: string,
79
+ ): SourceSymbolsSidecarResponse['symbols'] {
80
+ const command = resolveTypeScriptNavigationSidecarCommand();
81
+ const executed = runProcess(command.executable, command.args, {
82
+ cwd: command.cwd ?? process.cwd(),
83
+ input: JSON.stringify({ schemaVersion: 1, operation: 'source_symbols', path, source }),
84
+ timeoutMs: TYPESCRIPT_NAVIGATION_TIMEOUT_MS,
85
+ maxOutputBytes: TYPESCRIPT_NAVIGATION_MAX_OUTPUT_BYTES,
86
+ });
87
+ if (!executed.ok) {
88
+ throw new Error(`TYPESCRIPT_SOURCE_SYMBOL_SIDECAR_FAILED: ${(executed.stderr || executed.stdout || executed.error || 'unknown failure').trim().slice(0, 2_000)}`);
89
+ }
90
+ const response = JSON.parse(executed.stdout) as SourceSymbolsSidecarResponse;
91
+ if (response.schemaVersion !== 1 || !Array.isArray(response.symbols)) {
92
+ throw new Error('TYPESCRIPT_SOURCE_SYMBOL_SIDECAR_RESPONSE_INVALID');
93
+ }
94
+ return response.symbols;
95
+ }
96
+
97
+ export function navigateTypeScriptInSidecar(
98
+ repoRoot: string,
99
+ requests: SemanticNavigationRequest[],
100
+ access: SemanticNavigationAccess,
101
+ ): SemanticNavigationOutcome[] {
102
+ if (!access.readPolicy) {
103
+ return failedOutcomes(requests, 'SEMANTIC_READ_POLICY_REQUIRED', 'TypeScript semantic navigation requires a serializable repository read policy.');
104
+ }
105
+
106
+ let command: ReturnType<typeof resolveTypeScriptNavigationSidecarCommand>;
107
+ try {
108
+ command = resolveTypeScriptNavigationSidecarCommand();
109
+ } catch (error) {
110
+ return failedOutcomes(requests, 'TYPESCRIPT_NAVIGATION_SIDECAR_UNAVAILABLE', error instanceof Error ? error.message : String(error));
111
+ }
112
+
113
+ const envelope = {
114
+ schemaVersion: 1,
115
+ operation: 'navigation',
116
+ repoRoot: resolve(repoRoot),
117
+ requests,
118
+ access: {
119
+ cacheScope: access.cacheScope,
120
+ ...(access.sourceIdentity ? { sourceIdentity: access.sourceIdentity } : {}),
121
+ profile: access.profile,
122
+ readPolicy: access.readPolicy,
123
+ },
124
+ };
125
+ const executed = runProcess(command.executable, command.args, {
126
+ cwd: command.cwd ?? repoRoot,
127
+ input: JSON.stringify(envelope),
128
+ timeoutMs: TYPESCRIPT_NAVIGATION_TIMEOUT_MS,
129
+ maxOutputBytes: TYPESCRIPT_NAVIGATION_MAX_OUTPUT_BYTES,
130
+ });
131
+ if (!executed.ok) {
132
+ const detail = (executed.stderr || executed.stdout || executed.error || 'TypeScript navigation sidecar failed').trim();
133
+ return failedOutcomes(requests, 'TYPESCRIPT_NAVIGATION_SIDECAR_FAILED', detail.slice(0, 2_000));
134
+ }
135
+
136
+ try {
137
+ const response = JSON.parse(executed.stdout) as SidecarResponse;
138
+ if (response.schemaVersion !== 1 || !Array.isArray(response.outcomes) || response.outcomes.length !== requests.length) {
139
+ throw new Error('invalid sidecar response shape');
140
+ }
141
+ return response.outcomes;
142
+ } catch (error) {
143
+ return failedOutcomes(requests, 'TYPESCRIPT_NAVIGATION_SIDECAR_RESPONSE_INVALID', error instanceof Error ? error.message : String(error));
144
+ }
145
+ }
@@ -26,6 +26,14 @@ export interface TypeScriptNavigationResult {
26
26
  locations: TypeScriptNavigationLocation[];
27
27
  }
28
28
 
29
+ export interface TypeScriptSourceSymbolRange {
30
+ startLine: number;
31
+ endLine: number;
32
+ kind: string;
33
+ name?: string;
34
+ enclosing?: string;
35
+ }
36
+
29
37
  export interface TypeScriptNavigationAccess {
30
38
  /** Stable identity for one read-policy scope. Restricted and unrestricted projects must never share a Language Service. */
31
39
  cacheScope: string;
@@ -38,11 +46,13 @@ export interface TypeScriptNavigationAccess {
38
46
  interface CachedProject {
39
47
  repoRoot: string;
40
48
  configPath: string;
49
+ configVersion: string;
50
+ sourceIdentity: string;
41
51
  service: ts.LanguageService;
42
52
  }
43
53
 
44
54
  const projects = new Map<string, CachedProject>();
45
- const MAX_CACHED_TYPESCRIPT_PROJECTS = 32;
55
+ const MAX_CACHED_TYPESCRIPT_PROJECTS = 1;
46
56
 
47
57
  function normalizePath(path: string): string {
48
58
  return path.replace(/\\/g, '/');
@@ -71,13 +81,19 @@ function loadProject(repoRoot: string, tsconfigPath = 'tsconfig.json', access?:
71
81
  if (access && !access.allowRepositoryPath(configRelative)) {
72
82
  throw new Error(`TypeScript navigation tsconfig is denied by read policy: ${configRelative}.`);
73
83
  }
74
- const cacheKey = `${root}\0${configPath}\0${scriptVersion(configPath)}\0${access?.cacheScope ?? 'unrestricted'}\0${access?.sourceIdentity ?? 'unbound-source'}`;
84
+ const configVersion = scriptVersion(configPath);
85
+ const sourceIdentity = access?.sourceIdentity ?? 'unbound-source';
86
+ const cacheKey = `${root}\0${configPath}\0${access?.cacheScope ?? 'unrestricted'}`;
75
87
  const cached = projects.get(cacheKey);
76
- if (cached) {
88
+ if (cached && cached.configVersion === configVersion && cached.sourceIdentity === sourceIdentity) {
77
89
  projects.delete(cacheKey);
78
90
  projects.set(cacheKey, cached);
79
91
  return cached;
80
92
  }
93
+ if (cached) {
94
+ projects.delete(cacheKey);
95
+ cached.service.dispose();
96
+ }
81
97
 
82
98
  const canReadAbsolute = (fileName: string): boolean => {
83
99
  if (!access) return true;
@@ -129,6 +145,8 @@ function loadProject(repoRoot: string, tsconfigPath = 'tsconfig.json', access?:
129
145
  const project = {
130
146
  repoRoot: root,
131
147
  configPath,
148
+ configVersion,
149
+ sourceIdentity,
132
150
  service: ts.createLanguageService(host, ts.createDocumentRegistry()),
133
151
  };
134
152
  projects.set(cacheKey, project);
@@ -176,6 +194,70 @@ function location(
176
194
  };
177
195
  }
178
196
 
197
+ function sourceScriptKind(path: string): ts.ScriptKind | undefined {
198
+ if (/\.tsx$/i.test(path)) return ts.ScriptKind.TSX;
199
+ if (/\.jsx$/i.test(path)) return ts.ScriptKind.JSX;
200
+ if (/\.(?:mts|cts|ts)$/i.test(path)) return ts.ScriptKind.TS;
201
+ if (/\.(?:mjs|cjs|js)$/i.test(path)) return ts.ScriptKind.JS;
202
+ return undefined;
203
+ }
204
+
205
+ function sourceDeclarationName(node: ts.Node): string | undefined {
206
+ const named = node as ts.Node & { name?: ts.Node };
207
+ return named.name ? named.name.getText().slice(0, 200) : undefined;
208
+ }
209
+
210
+ function sourceDeclarationKind(node: ts.Node): string | undefined {
211
+ if (ts.isFunctionDeclaration(node)) return 'function';
212
+ if (ts.isMethodDeclaration(node)) return 'method';
213
+ if (ts.isConstructorDeclaration(node)) return 'constructor';
214
+ if (ts.isGetAccessorDeclaration(node)) return 'getter';
215
+ if (ts.isSetAccessorDeclaration(node)) return 'setter';
216
+ if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) return 'class';
217
+ if (ts.isInterfaceDeclaration(node)) return 'interface';
218
+ if (ts.isTypeAliasDeclaration(node)) return 'type';
219
+ if (ts.isEnumDeclaration(node)) return 'enum';
220
+ if (ts.isModuleDeclaration(node)) return 'module';
221
+ if (ts.isVariableStatement(node) && node.declarationList.declarations.some((declaration) =>
222
+ declaration.initializer && (ts.isArrowFunction(declaration.initializer) || ts.isFunctionExpression(declaration.initializer)))) return 'function-variable';
223
+ return undefined;
224
+ }
225
+
226
+ function sourceEnclosingName(node: ts.Node): string | undefined {
227
+ let current = node.parent;
228
+ while (current) {
229
+ if (ts.isClassDeclaration(current) || ts.isClassExpression(current) || ts.isInterfaceDeclaration(current) || ts.isModuleDeclaration(current)) {
230
+ const kind = sourceDeclarationKind(current) ?? 'container';
231
+ const name = sourceDeclarationName(current);
232
+ return name ? `${kind}:${name}` : kind;
233
+ }
234
+ current = current.parent;
235
+ }
236
+ return undefined;
237
+ }
238
+
239
+ export function extractTypeScriptSourceSymbols(path: string, source: string): TypeScriptSourceSymbolRange[] {
240
+ const kind = sourceScriptKind(path);
241
+ if (kind === undefined) return [];
242
+ const sourceFile = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true, kind);
243
+ const declarations: TypeScriptSourceSymbolRange[] = [];
244
+ const visit = (node: ts.Node): void => {
245
+ const declarationKind = sourceDeclarationKind(node);
246
+ if (declarationKind) {
247
+ declarations.push({
248
+ startLine: sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1,
249
+ endLine: sourceFile.getLineAndCharacterOfPosition(node.end).line + 1,
250
+ kind: declarationKind,
251
+ ...(sourceDeclarationName(node) ? { name: sourceDeclarationName(node) } : {}),
252
+ ...(sourceEnclosingName(node) ? { enclosing: sourceEnclosingName(node) } : {}),
253
+ });
254
+ }
255
+ ts.forEachChild(node, visit);
256
+ };
257
+ visit(sourceFile);
258
+ return declarations;
259
+ }
260
+
179
261
  function dedupe(locations: TypeScriptNavigationLocation[]): TypeScriptNavigationLocation[] {
180
262
  const seen = new Set<string>();
181
263
  return locations.filter((entry) => {
@@ -220,6 +302,10 @@ export function navigateTypeScriptSymbol(
220
302
  };
221
303
  }
222
304
 
305
+ export function typeScriptNavigationCachedProjectCount(): number {
306
+ return projects.size;
307
+ }
308
+
223
309
  export function clearTypeScriptNavigationCache(): void {
224
310
  for (const project of projects.values()) project.service.dispose();
225
311
  projects.clear();