machine-bridge-mcp 2.0.0 → 3.0.0-beta.102

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 (473) hide show
  1. package/CHANGELOG.md +1142 -0
  2. package/CONTRIBUTING.md +23 -25
  3. package/GOVERNANCE.md +2 -2
  4. package/README.md +58 -20
  5. package/SECURITY.md +161 -120
  6. package/SUPPORT.md +1 -1
  7. package/browser-extension/broker-auth.js +83 -0
  8. package/browser-extension/broker-liveness.js +35 -0
  9. package/browser-extension/browser-error-boundary.js +96 -0
  10. package/browser-extension/browser-operations.js +1456 -101
  11. package/browser-extension/devtools-input.js +195 -34
  12. package/browser-extension/devtools-observation.js +429 -0
  13. package/browser-extension/devtools-session.js +48 -0
  14. package/browser-extension/manifest.json +4 -3
  15. package/browser-extension/page-automation.js +578 -118
  16. package/browser-extension/pairing-bootstrap.js +42 -0
  17. package/browser-extension/pairing.js +28 -12
  18. package/browser-extension/service-worker.js +126 -106
  19. package/docs/AGENT_CONTEXT.md +13 -10
  20. package/docs/ARCHITECTURE.md +159 -67
  21. package/docs/AUDIT.md +1302 -4
  22. package/docs/CLIENTS.md +19 -6
  23. package/docs/COMPUTER_USE.md +297 -0
  24. package/docs/ENGINEERING.md +72 -13
  25. package/docs/GETTING_STARTED.md +18 -20
  26. package/docs/LOCAL_AUTHORIZATION.md +115 -72
  27. package/docs/LOCAL_AUTOMATION.md +27 -21
  28. package/docs/LOGGING.md +40 -19
  29. package/docs/MANAGED_JOBS.md +37 -34
  30. package/docs/MULTI_ACCOUNT.md +98 -37
  31. package/docs/OPERATIONS.md +145 -51
  32. package/docs/OVERVIEW.md +14 -11
  33. package/docs/POLICY_REFERENCE.md +71 -3
  34. package/docs/PRIVACY.md +41 -2
  35. package/docs/PROJECT_STANDARDS.md +29 -6
  36. package/docs/RELEASING.md +238 -64
  37. package/docs/TESTING.md +150 -39
  38. package/docs/THREAT_MODEL.md +164 -67
  39. package/docs/TOOL_REFERENCE.md +653 -60
  40. package/docs/UPGRADING.md +78 -18
  41. package/native/macos/MachineBridgeBackgroundInput.swift +1051 -0
  42. package/native/macos/MachineBridgeBackgroundInputSmokeFixture.swift +295 -0
  43. package/native/macos/MachineBridgeTrustBroker.swift +233 -0
  44. package/package.json +94 -16
  45. package/scripts/accepted-candidate-tarball.mjs +77 -0
  46. package/scripts/candidate-runtime-store.mjs +93 -0
  47. package/scripts/check-plan.mjs +73 -3
  48. package/scripts/check-runner.mjs +129 -17
  49. package/scripts/commit-message-check.mjs +5 -2
  50. package/scripts/consumer-package-security.mjs +293 -0
  51. package/scripts/coverage-check.mjs +251 -15
  52. package/scripts/coverage-generation.mjs +41 -0
  53. package/scripts/coverage-range-merge.mjs +41 -0
  54. package/scripts/foreground-daemon-recovery.mjs +88 -0
  55. package/scripts/generate-policy-reference.mjs +28 -5
  56. package/scripts/generate-tool-reference.mjs +1 -1
  57. package/scripts/generate-worker-types.mjs +21 -11
  58. package/scripts/github-backlog.mjs +11 -10
  59. package/scripts/github-push.mjs +62 -16
  60. package/scripts/github-release-asset.mjs +58 -0
  61. package/scripts/github-release.mjs +241 -132
  62. package/scripts/global-package-installation.mjs +68 -0
  63. package/scripts/hardened-npm-session.mjs +42 -0
  64. package/scripts/install-published-prerelease.mjs +198 -0
  65. package/scripts/local-release-acceptance.mjs +103 -45
  66. package/scripts/macos-background-input-smoke.mjs +515 -0
  67. package/scripts/network-retry.mjs +8 -1
  68. package/scripts/npm-global-prefix.mjs +27 -0
  69. package/scripts/npm-publication-policy.mjs +17 -0
  70. package/scripts/official-mcp-conformance.mjs +267 -0
  71. package/scripts/persistent-activation-process.mjs +101 -0
  72. package/scripts/prepare-pinned-npm.mjs +12 -69
  73. package/scripts/prerelease-activation.mjs +160 -0
  74. package/scripts/privacy-check.mjs +14 -6
  75. package/scripts/promotion-digest.mjs +128 -0
  76. package/scripts/publish-npm.mjs +260 -0
  77. package/scripts/published-release.mjs +132 -0
  78. package/scripts/release-acceptance.mjs +62 -54
  79. package/scripts/release-browser-extension-store.mjs +172 -0
  80. package/scripts/release-candidate-manifest.mjs +52 -0
  81. package/scripts/release-channel.mjs +106 -0
  82. package/scripts/release-diagnostic.mjs +41 -0
  83. package/scripts/release-impact-check.mjs +12 -22
  84. package/scripts/release-oauth-canary-core.mjs +325 -0
  85. package/scripts/release-oauth-canary-evidence.mjs +100 -0
  86. package/scripts/release-oauth-canary.mjs +127 -0
  87. package/scripts/release-publication-guard.mjs +67 -0
  88. package/scripts/release-soak.mjs +284 -0
  89. package/scripts/release-state.mjs +1 -1
  90. package/scripts/run-checks.mjs +44 -7
  91. package/scripts/run-worker-dry-run.mjs +21 -0
  92. package/scripts/sarif-security-gate.mjs +2 -1
  93. package/scripts/sbom-check.mjs +106 -0
  94. package/scripts/start-release-candidate.mjs +267 -44
  95. package/scripts/syntax-check.mjs +36 -14
  96. package/scripts/verification-generation-guard.mjs +15 -0
  97. package/scripts/verification-idle-sleep-guard.mjs +37 -0
  98. package/scripts/verification-state.mjs +108 -0
  99. package/scripts/wrangler-command-lifecycle.mjs +115 -0
  100. package/src/local/account-access.mjs +13 -1
  101. package/src/local/account-admin-response.mjs +92 -0
  102. package/src/local/account-admin.mjs +52 -19
  103. package/src/local/agent-context-projection.mjs +26 -7
  104. package/src/local/agent-context.mjs +88 -49
  105. package/src/local/agent-skill-discovery.mjs +16 -5
  106. package/src/local/app-automation-macos-jxa.mjs +350 -0
  107. package/src/local/app-automation.mjs +873 -163
  108. package/src/local/application-capability-projection.mjs +24 -0
  109. package/src/local/authority-context.mjs +106 -0
  110. package/src/local/autostart-log-maintenance.mjs +36 -0
  111. package/src/local/browser-bridge-http.mjs +5 -3
  112. package/src/local/browser-bridge.mjs +109 -31
  113. package/src/local/browser-broker-auth-http.mjs +67 -0
  114. package/src/local/browser-broker-auth.mjs +98 -0
  115. package/src/local/browser-broker-routes.mjs +63 -20
  116. package/src/local/browser-broker-server.mjs +17 -7
  117. package/src/local/browser-command.mjs +79 -30
  118. package/src/local/browser-computer-observation-service.mjs +266 -0
  119. package/src/local/browser-extension-identity.mjs +50 -0
  120. package/src/local/browser-extension-path.mjs +22 -0
  121. package/src/local/browser-extension-protocol.mjs +50 -11
  122. package/src/local/browser-operation-service.mjs +147 -117
  123. package/src/local/browser-pairing-grant.mjs +109 -0
  124. package/src/local/browser-pairing-http.mjs +36 -0
  125. package/src/local/browser-pairing-launch.mjs +58 -0
  126. package/src/local/browser-pairing-store.mjs +85 -48
  127. package/src/local/browser-request-registry.mjs +40 -14
  128. package/src/local/browser-request-settlement.mjs +78 -0
  129. package/src/local/browser-resource-input.mjs +74 -0
  130. package/src/local/browser-trusted-input-health.mjs +63 -0
  131. package/src/local/call-authority.mjs +21 -0
  132. package/src/local/call-capacity.mjs +45 -0
  133. package/src/local/call-registry-drain.mjs +54 -0
  134. package/src/local/call-registry.mjs +30 -15
  135. package/src/local/capability-observer.mjs +5 -0
  136. package/src/local/capability-ranking.mjs +3 -2
  137. package/src/local/child-process-settlement.mjs +132 -0
  138. package/src/local/cli-account-admin.mjs +40 -6
  139. package/src/local/cli-activate.mjs +162 -0
  140. package/src/local/cli-local-admin.mjs +20 -45
  141. package/src/local/cli-options.mjs +12 -13
  142. package/src/local/cli-ready-output.mjs +52 -0
  143. package/src/local/cli-service.mjs +91 -11
  144. package/src/local/cli.mjs +232 -150
  145. package/src/local/computer-use-application-observation.mjs +224 -0
  146. package/src/local/computer-use-arguments.mjs +270 -0
  147. package/src/local/computer-use-deadline.mjs +50 -0
  148. package/src/local/computer-use-dispatch-settlement.mjs +40 -0
  149. package/src/local/computer-use-expectation.mjs +171 -0
  150. package/src/local/computer-use-observation.mjs +769 -0
  151. package/src/local/computer-use-recovery.mjs +82 -0
  152. package/src/local/computer-use-result-budget.mjs +145 -0
  153. package/src/local/computer-use-snapshot-store.mjs +67 -0
  154. package/src/local/computer-use.mjs +2255 -0
  155. package/src/local/daemon-http-relay-auth.mjs +26 -0
  156. package/src/local/daemon-http-relay-connection.mjs +298 -0
  157. package/src/local/daemon-http-relay-request.mjs +64 -0
  158. package/src/local/daemon-http-relay-sequence.mjs +49 -0
  159. package/src/local/daemon-process.mjs +40 -7
  160. package/src/local/delegated-process-sandbox.mjs +148 -0
  161. package/src/local/device-identity.mjs +156 -49
  162. package/src/local/device-root-provider.mjs +81 -0
  163. package/src/local/directory-metadata.mjs +47 -0
  164. package/src/local/doctor-reporting.mjs +23 -0
  165. package/src/local/durable-process-spec.mjs +80 -0
  166. package/src/local/errors.mjs +25 -15
  167. package/src/local/exclusive-file.mjs +74 -26
  168. package/src/local/execution-limits.mjs +9 -0
  169. package/src/local/execution-routing.mjs +276 -0
  170. package/src/local/execution-surface.mjs +23 -0
  171. package/src/local/file-mutation-coordinator.mjs +47 -0
  172. package/src/local/file-snapshot-preservation.mjs +24 -0
  173. package/src/local/filesystem-identity.mjs +54 -0
  174. package/src/local/fixed-process-environment.mjs +21 -0
  175. package/src/local/full-access-test.mjs +31 -13
  176. package/src/local/git-commit.mjs +69 -0
  177. package/src/local/git-config-safety.mjs +55 -0
  178. package/src/local/git-log-parser.mjs +41 -0
  179. package/src/local/git-metadata-boundary.mjs +77 -0
  180. package/src/local/git-metadata-tree-safety.mjs +59 -0
  181. package/src/local/git-operation-state.mjs +19 -0
  182. package/src/local/git-service.mjs +165 -30
  183. package/src/local/hardened-npm-download-timeout.mjs +46 -0
  184. package/src/local/hardened-npm-download.mjs +109 -0
  185. package/src/local/hardened-npm-extract.mjs +20 -0
  186. package/src/local/hardened-npm-verification.mjs +104 -0
  187. package/src/local/hardened-npm.mjs +199 -0
  188. package/src/local/job-runner.mjs +244 -89
  189. package/src/local/lifecycle.mjs +6 -0
  190. package/src/local/log.mjs +19 -45
  191. package/src/local/macos-background-input.mjs +398 -0
  192. package/src/local/macos-idle-sleep-assertion.mjs +65 -0
  193. package/src/local/macos-trust-broker.mjs +404 -0
  194. package/src/local/managed-job-cancellation.mjs +42 -0
  195. package/src/local/managed-job-capacity.mjs +16 -0
  196. package/src/local/managed-job-directory-generation.mjs +60 -0
  197. package/src/local/managed-job-directory.mjs +75 -0
  198. package/src/local/managed-job-durable-process.mjs +49 -0
  199. package/src/local/managed-job-lock.mjs +46 -14
  200. package/src/local/managed-job-plan.mjs +38 -14
  201. package/src/local/managed-job-projection.mjs +23 -15
  202. package/src/local/managed-job-retention.mjs +128 -0
  203. package/src/local/managed-job-runner-claim.mjs +70 -0
  204. package/src/local/managed-job-runner.mjs +35 -10
  205. package/src/local/managed-job-storage.mjs +22 -6
  206. package/src/local/managed-job-terminal-maintenance.mjs +40 -0
  207. package/src/local/managed-job-terminal.mjs +150 -0
  208. package/src/local/managed-jobs.mjs +424 -287
  209. package/src/local/npm-cli.mjs +42 -0
  210. package/src/local/npm-environment.mjs +37 -0
  211. package/src/local/operation-authorization.mjs +68 -324
  212. package/src/local/operation-risk.mjs +51 -4
  213. package/src/local/owner-state-lock.mjs +118 -0
  214. package/src/local/package-identity.mjs +9 -0
  215. package/src/local/patch.mjs +20 -18
  216. package/src/local/path-inspection.mjs +23 -0
  217. package/src/local/policy.mjs +19 -0
  218. package/src/local/private-toolchain-integrity.mjs +54 -0
  219. package/src/local/process-execution.mjs +87 -75
  220. package/src/local/process-foreground-timeout.mjs +50 -0
  221. package/src/local/process-identity.mjs +41 -7
  222. package/src/local/process-nonreplayable-settlement.mjs +50 -0
  223. package/src/local/process-result-projection.mjs +22 -0
  224. package/src/local/process-session-events.mjs +47 -0
  225. package/src/local/process-session-remote-activity.mjs +10 -0
  226. package/src/local/process-session-termination.mjs +73 -0
  227. package/src/local/process-sessions.mjs +144 -112
  228. package/src/local/process-tracker.mjs +140 -13
  229. package/src/local/process-tree-ownership-types.d.ts +37 -0
  230. package/src/local/process-tree-ownership.mjs +57 -0
  231. package/src/local/process-tree-signal.mjs +34 -0
  232. package/src/local/process-tree-snapshot.mjs +77 -0
  233. package/src/local/process-tree-supervisor.mjs +69 -0
  234. package/src/local/process-tree.mjs +11 -53
  235. package/src/local/project-metadata.mjs +19 -6
  236. package/src/local/relay-call-recovery.mjs +58 -38
  237. package/src/local/relay-connection-classification.mjs +131 -0
  238. package/src/local/relay-connection-support.mjs +91 -0
  239. package/src/local/relay-connection.mjs +179 -272
  240. package/src/local/relay-diagnostics.mjs +91 -0
  241. package/src/local/relay-heartbeat.mjs +119 -0
  242. package/src/local/relay-liveness.mjs +109 -0
  243. package/src/local/relay-peer-diagnostics.mjs +29 -0
  244. package/src/local/release-runtime-lock.mjs +18 -0
  245. package/src/local/remote-activity-idle-sleep-guard.mjs +77 -0
  246. package/src/local/remote-configuration.mjs +48 -0
  247. package/src/local/resilient-relay-connection.mjs +178 -0
  248. package/src/local/resource-admission-diagnostics.mjs +52 -0
  249. package/src/local/resource-admission-policy.mjs +115 -0
  250. package/src/local/resource-admission.mjs +339 -0
  251. package/src/local/resource-build-root.mjs +83 -0
  252. package/src/local/resource-cargo-concurrency.mjs +38 -0
  253. package/src/local/resource-cmake-concurrency.mjs +42 -0
  254. package/src/local/resource-command-concurrency.mjs +37 -0
  255. package/src/local/resource-command-profile.mjs +176 -0
  256. package/src/local/resource-coordinator-accounting.mjs +21 -0
  257. package/src/local/resource-cpu-window.mjs +20 -0
  258. package/src/local/resource-disk-headroom.mjs +13 -0
  259. package/src/local/resource-elastic-memory.mjs +19 -0
  260. package/src/local/resource-elastic-request.mjs +36 -0
  261. package/src/local/resource-foreground-wait.mjs +29 -0
  262. package/src/local/resource-go-concurrency.mjs +43 -0
  263. package/src/local/resource-gradle-concurrency.mjs +57 -0
  264. package/src/local/resource-host-cache.mjs +39 -0
  265. package/src/local/resource-host-darwin.mjs +54 -0
  266. package/src/local/resource-host-linux.mjs +35 -0
  267. package/src/local/resource-host-sample-file.mjs +23 -0
  268. package/src/local/resource-host-snapshot.mjs +99 -0
  269. package/src/local/resource-lease-accounting.mjs +119 -0
  270. package/src/local/resource-light-command.mjs +6 -0
  271. package/src/local/resource-make-concurrency.mjs +42 -0
  272. package/src/local/resource-maven-concurrency.mjs +38 -0
  273. package/src/local/resource-ninja-command-concurrency.mjs +20 -0
  274. package/src/local/resource-ninja-concurrency.mjs +28 -0
  275. package/src/local/resource-operations.mjs +26 -10
  276. package/src/local/resource-pressure.mjs +67 -0
  277. package/src/local/resource-probe-command.mjs +35 -0
  278. package/src/local/resource-process-admission.mjs +59 -0
  279. package/src/local/resource-process-ancestry-cache.mjs +43 -0
  280. package/src/local/resource-process-ancestry.mjs +32 -0
  281. package/src/local/resource-process-priority.mjs +15 -0
  282. package/src/local/resource-project-key.mjs +53 -0
  283. package/src/local/resource-pytest-concurrency.mjs +33 -0
  284. package/src/local/resource-release-control-classification.mjs +14 -0
  285. package/src/local/resource-release-control-executable.mjs +70 -0
  286. package/src/local/resource-release-control-workspace.mjs +41 -0
  287. package/src/local/resource-request-contract.mjs +30 -0
  288. package/src/local/resource-script-classification.mjs +44 -0
  289. package/src/local/resource-shell-analysis.mjs +58 -0
  290. package/src/local/resource-staging-recovery.mjs +97 -0
  291. package/src/local/resource-swift-concurrency.mjs +31 -0
  292. package/src/local/resource-transaction-lock.mjs +189 -0
  293. package/src/local/resource-wait.mjs +48 -0
  294. package/src/local/resource-waiters.mjs +139 -0
  295. package/src/local/resource-xcode-command.mjs +7 -0
  296. package/src/local/resource-xcode-concurrency.mjs +34 -0
  297. package/src/local/resource-xcode-non-build.mjs +19 -0
  298. package/src/local/runtime-activation.mjs +700 -0
  299. package/src/local/runtime-activity-projection.mjs +48 -0
  300. package/src/local/runtime-capabilities.mjs +48 -15
  301. package/src/local/runtime-diagnostic-state.mjs +14 -0
  302. package/src/local/runtime-diagnostics.mjs +40 -13
  303. package/src/local/runtime-info-projection.mjs +60 -0
  304. package/src/local/runtime-info-relay-projection.mjs +21 -0
  305. package/src/local/runtime-paths.mjs +2 -1
  306. package/src/local/runtime-process-routing.mjs +33 -0
  307. package/src/local/runtime-relay-connection-options.mjs +44 -0
  308. package/src/local/runtime-relay-control.mjs +98 -0
  309. package/src/local/runtime-relay.mjs +26 -50
  310. package/src/local/runtime-reporting.mjs +37 -21
  311. package/src/local/runtime-resource-service.mjs +77 -0
  312. package/src/local/runtime-tool-handlers.mjs +13 -10
  313. package/src/local/runtime.mjs +244 -208
  314. package/src/local/secure-file.mjs +73 -20
  315. package/src/local/security-audit-dispatch.mjs +35 -0
  316. package/src/local/security-audit-log.mjs +215 -0
  317. package/src/local/security-audit-state.mjs +139 -0
  318. package/src/local/security-audit-storage.mjs +135 -0
  319. package/src/local/security-audit-warning.mjs +31 -0
  320. package/src/local/security-audit-worker.mjs +87 -0
  321. package/src/local/service-convergence.mjs +42 -1
  322. package/src/local/service-definition.mjs +24 -0
  323. package/src/local/service-environment.mjs +18 -10
  324. package/src/local/service-owner.mjs +146 -0
  325. package/src/local/service-ownership.mjs +17 -0
  326. package/src/local/service-restart-handoff.mjs +64 -0
  327. package/src/local/service-restart-scheduler.mjs +49 -0
  328. package/src/local/service-runtime-convergence.mjs +52 -0
  329. package/src/local/service-runtime.mjs +105 -0
  330. package/src/local/service-status.mjs +60 -0
  331. package/src/local/service.mjs +385 -92
  332. package/src/local/shell.mjs +39 -19
  333. package/src/local/ssh-key.mjs +158 -42
  334. package/src/local/state-inventory.mjs +50 -24
  335. package/src/local/state-owner-lock-inventory.mjs +23 -0
  336. package/src/local/state-root-owned-namespaces.mjs +83 -0
  337. package/src/local/state-root-retirement.mjs +89 -0
  338. package/src/local/state.mjs +386 -96
  339. package/src/local/stdio.mjs +96 -66
  340. package/src/local/support-state-projection.mjs +30 -0
  341. package/src/local/system-network-route.mjs +76 -0
  342. package/src/local/systemd-removal.mjs +20 -0
  343. package/src/local/tool-executor.mjs +85 -20
  344. package/src/local/tool-result-boundary.mjs +51 -0
  345. package/src/local/toolchain-operation-lock.mjs +41 -0
  346. package/src/local/tools.mjs +7 -5
  347. package/src/local/trusted-executable.mjs +53 -0
  348. package/src/local/trusted-git-executable.mjs +34 -0
  349. package/src/local/trusted-github-cli.mjs +24 -0
  350. package/src/local/windows-service-convergence.mjs +49 -0
  351. package/src/local/windows-service.mjs +52 -45
  352. package/src/local/worker-deployment-fingerprint.mjs +102 -0
  353. package/src/local/worker-deployment.mjs +48 -60
  354. package/src/local/worker-health.mjs +12 -4
  355. package/src/local/worker-secret-file.mjs +37 -17
  356. package/src/local/workspace-file-service.mjs +156 -239
  357. package/src/local/workspace-file-transaction.mjs +189 -0
  358. package/src/local/workspace-search.mjs +55 -0
  359. package/src/local/wrangler-toolchain/package-lock.json +1505 -0
  360. package/src/local/wrangler-toolchain/package.json +23 -0
  361. package/src/local/wrangler-toolchain-verification.mjs +135 -0
  362. package/src/local/wrangler-toolchain.mjs +188 -0
  363. package/src/shared/access-contract.json +7 -1
  364. package/src/shared/activation-recovery.mjs +49 -0
  365. package/src/shared/admin-auth.d.mts +2 -1
  366. package/src/shared/admin-auth.mjs +3 -3
  367. package/src/shared/authority-revocation.d.mts +9 -0
  368. package/src/shared/authority-revocation.mjs +28 -0
  369. package/src/shared/daemon-auth.d.mts +11 -0
  370. package/src/shared/daemon-auth.mjs +17 -0
  371. package/src/shared/device-session-auth.d.mts +20 -0
  372. package/src/shared/device-session-auth.mjs +51 -0
  373. package/src/shared/foreground-timeout.d.mts +15 -0
  374. package/src/shared/foreground-timeout.mjs +70 -0
  375. package/src/shared/log-redaction.d.mts +9 -0
  376. package/src/shared/log-redaction.mjs +51 -0
  377. package/src/shared/mcp-protocol.d.mts +27 -0
  378. package/src/shared/mcp-protocol.mjs +275 -0
  379. package/src/shared/project-overview-projection.d.mts +4 -0
  380. package/src/shared/project-overview-projection.mjs +96 -0
  381. package/src/shared/relay-contract.json +28 -0
  382. package/src/shared/result-projection.d.mts +2 -1
  383. package/src/shared/result-projection.mjs +13 -2
  384. package/src/shared/server-metadata.json +15 -9
  385. package/src/shared/tool-argument-validation.d.mts +17 -0
  386. package/src/shared/tool-argument-validation.mjs +325 -0
  387. package/src/shared/tool-call-capacity.d.mts +41 -0
  388. package/src/shared/tool-call-capacity.mjs +59 -0
  389. package/src/shared/tool-catalog.json +626 -57
  390. package/src/worker/access.ts +12 -0
  391. package/src/worker/account-admin.ts +55 -33
  392. package/src/worker/authority-revocations.ts +174 -0
  393. package/src/worker/authority.ts +52 -6
  394. package/src/worker/daemon-auth.ts +49 -68
  395. package/src/worker/daemon-channel.ts +36 -0
  396. package/src/worker/daemon-http-auth.ts +63 -0
  397. package/src/worker/daemon-http-channel.ts +120 -0
  398. package/src/worker/daemon-http-controller.ts +163 -0
  399. package/src/worker/daemon-http-protocol.ts +62 -0
  400. package/src/worker/daemon-http-registry.ts +82 -0
  401. package/src/worker/daemon-last-observation.ts +30 -0
  402. package/src/worker/daemon-liveness.ts +8 -6
  403. package/src/worker/daemon-ready-dispatch.ts +17 -0
  404. package/src/worker/daemon-ready-messages.ts +73 -0
  405. package/src/worker/daemon-ready-waiters.ts +79 -0
  406. package/src/worker/daemon-recovery-budget.ts +13 -0
  407. package/src/worker/daemon-registry.ts +58 -0
  408. package/src/worker/daemon-relay-diagnostics.ts +127 -0
  409. package/src/worker/daemon-socket-attachment.ts +55 -0
  410. package/src/worker/daemon-sockets.ts +72 -62
  411. package/src/worker/daemon-status.ts +38 -0
  412. package/src/worker/device-session-verifier.ts +129 -0
  413. package/src/worker/dpop.ts +157 -0
  414. package/src/worker/durable-process-timeout.ts +29 -0
  415. package/src/worker/errors.ts +57 -0
  416. package/src/worker/http.ts +112 -26
  417. package/src/worker/index.ts +446 -440
  418. package/src/worker/mcp-access.ts +57 -0
  419. package/src/worker/mcp-controller.ts +188 -0
  420. package/src/worker/mcp-http-accept.ts +11 -0
  421. package/src/worker/mcp-http-contract.ts +322 -0
  422. package/src/worker/mcp-initialization-compat.ts +141 -0
  423. package/src/worker/mcp-jsonrpc.ts +11 -29
  424. package/src/worker/mcp-removed-protocol.ts +17 -0
  425. package/src/worker/mcp-response-proxy.ts +135 -0
  426. package/src/worker/mcp-response-stream.ts +65 -0
  427. package/src/worker/mcp-stale-schema-compat.ts +57 -0
  428. package/src/worker/mcp-stream-proxy-contract.ts +48 -0
  429. package/src/worker/mcp-tool-call-input.ts +23 -0
  430. package/src/worker/nonce-store.ts +33 -35
  431. package/src/worker/oauth-authorization-page.ts +21 -1
  432. package/src/worker/oauth-client-admin.ts +52 -0
  433. package/src/worker/oauth-client-contract.ts +38 -0
  434. package/src/worker/oauth-controller.ts +107 -47
  435. package/src/worker/oauth-field-contract.ts +31 -0
  436. package/src/worker/oauth-record-contract.ts +7 -0
  437. package/src/worker/oauth-refresh-authority.ts +27 -0
  438. package/src/worker/oauth-refresh-exchange.ts +162 -0
  439. package/src/worker/oauth-refresh-families.ts +130 -27
  440. package/src/worker/oauth-refresh-persistence.ts +116 -0
  441. package/src/worker/oauth-state.ts +33 -18
  442. package/src/worker/oauth-store-validation.ts +131 -0
  443. package/src/worker/oauth-token-derivation.ts +33 -0
  444. package/src/worker/oauth-token-issuance.ts +119 -0
  445. package/src/worker/oauth-tokens.ts +56 -190
  446. package/src/worker/observability.ts +38 -5
  447. package/src/worker/pending-admission.ts +15 -0
  448. package/src/worker/pending-call-capacity.ts +108 -0
  449. package/src/worker/pending-call-contract.ts +42 -5
  450. package/src/worker/pending-call-deadlines.ts +75 -0
  451. package/src/worker/pending-calls.ts +131 -125
  452. package/src/worker/runtime-alarm-storage.ts +37 -0
  453. package/src/worker/runtime-alarm.ts +136 -0
  454. package/src/worker/server-info-activity.ts +36 -0
  455. package/src/worker/server-info-tool-delivery.ts +15 -0
  456. package/src/worker/server-info.ts +168 -0
  457. package/src/worker/tool-catalog.ts +47 -1
  458. package/src/worker/tool-timeout.ts +75 -14
  459. package/src/worker/websocket-protocol.ts +26 -2
  460. package/src/worker/worker-edge-guard.ts +90 -0
  461. package/src/worker/worker-edge-log.ts +65 -0
  462. package/src/worker/worker-entry.ts +52 -0
  463. package/src/worker/worker-mcp-config.ts +23 -0
  464. package/src/worker/worker-metadata.ts +48 -0
  465. package/src/worker/worker-rate-limit-key.ts +30 -0
  466. package/src/worker/worker-runtime-config.ts +20 -0
  467. package/src/worker/worker-static-routes.ts +54 -0
  468. package/src/worker/worker-task-lifetime.ts +18 -0
  469. package/tsconfig.local.json +17 -1
  470. package/wrangler.jsonc +13 -0
  471. package/src/local/cli-approval.mjs +0 -117
  472. package/src/local/operation-state-lock.mjs +0 -92
  473. package/src/worker/mcp-session.ts +0 -72
@@ -0,0 +1,115 @@
1
+ import { spawn } from "node:child_process";
2
+ import process from "node:process";
3
+
4
+ const DEFAULT_TIMEOUT_MS = 120_000;
5
+ const DEFAULT_COMPLETION_EXIT_GRACE_MS = 500;
6
+ const DEFAULT_TERMINATION_GRACE_MS = 2_000;
7
+
8
+ export async function runCompletedWranglerCommand(options = {}) {
9
+ const cwd = requiredString(options.cwd, "cwd");
10
+ const wranglerPath = requiredString(options.wranglerPath, "wranglerPath");
11
+ const args = Array.isArray(options.args) ? options.args.map(String) : [];
12
+ const label = requiredString(options.label, "label");
13
+ const completionMarker = requiredString(options.completionMarker, "completionMarker");
14
+ const completionCheck = typeof options.completionCheck === "function" ? options.completionCheck : () => true;
15
+ const timeoutMs = positiveInteger(options.timeoutMs, DEFAULT_TIMEOUT_MS, "timeoutMs");
16
+ const completionExitGraceMs = positiveInteger(options.completionExitGraceMs, DEFAULT_COMPLETION_EXIT_GRACE_MS, "completionExitGraceMs");
17
+ const terminationGraceMs = positiveInteger(options.terminationGraceMs, DEFAULT_TERMINATION_GRACE_MS, "terminationGraceMs");
18
+ const stdout = options.stdout || process.stdout;
19
+ const stderr = options.stderr || process.stderr;
20
+ const env = options.env || process.env;
21
+ const killChild = typeof options.killChild === "function" ? options.killChild : null;
22
+ const child = spawn(process.execPath, [wranglerPath, ...args], {
23
+ cwd,
24
+ env,
25
+ stdio: ["ignore", "pipe", "pipe"],
26
+ windowsHide: true,
27
+ });
28
+
29
+ await new Promise((resolvePromise, rejectPromise) => {
30
+ let completionObserved = false;
31
+ let cleanupRequested = false;
32
+ let forceKillUsed = false;
33
+ let hardTimedOut = false;
34
+ let outputTail = "";
35
+ let completionTimer;
36
+ let forceTimer;
37
+ let settled = false;
38
+
39
+ const hardTimer = setTimeout(() => {
40
+ hardTimedOut = true;
41
+ requestTermination();
42
+ }, timeoutMs);
43
+ const clearTimers = () => {
44
+ clearTimeout(hardTimer);
45
+ clearTimeout(completionTimer);
46
+ clearTimeout(forceTimer);
47
+ };
48
+ const finish = (error) => {
49
+ if (settled) return;
50
+ settled = true;
51
+ clearTimers();
52
+ if (error) rejectPromise(error);
53
+ else resolvePromise();
54
+ };
55
+ const requestTermination = () => {
56
+ if (cleanupRequested) return;
57
+ cleanupRequested = true;
58
+ try {
59
+ if (killChild) killChild(child, "SIGTERM");
60
+ else child.kill("SIGTERM");
61
+ }
62
+ catch (error) { finish(new Error(`${label} could not request graceful cleanup`, { cause: error })); return; }
63
+ forceTimer = setTimeout(() => {
64
+ if (child.exitCode !== null || child.signalCode !== null) return;
65
+ forceKillUsed = true;
66
+ try {
67
+ const killed = killChild ? killChild(child, "SIGKILL") : child.kill("SIGKILL");
68
+ if (killed !== true) finish(new Error(`${label} could not force cleanup`));
69
+ } catch (error) { finish(new Error(`${label} could not force cleanup`, { cause: error })); }
70
+ }, terminationGraceMs);
71
+ };
72
+ const observeOutput = (destination, chunk) => {
73
+ destination.write(chunk);
74
+ outputTail = `${outputTail}${String(chunk)}`.slice(-4096);
75
+ if (completionObserved || !outputTail.includes(completionMarker)) return;
76
+ completionObserved = true;
77
+ completionTimer = setTimeout(() => {
78
+ if (child.exitCode === null && child.signalCode === null) requestTermination();
79
+ }, completionExitGraceMs);
80
+ };
81
+ const completionIsValid = () => {
82
+ try { return completionCheck() === true; }
83
+ catch (error) { finish(error); return false; }
84
+ };
85
+
86
+ child.stdout.on("data", (chunk) => observeOutput(stdout, chunk));
87
+ child.stderr.on("data", (chunk) => observeOutput(stderr, chunk));
88
+ child.once("error", finish);
89
+ child.once("close", (code, signal) => {
90
+ if (hardTimedOut) { finish(new Error(`${label} timed out after ${timeoutMs}ms`)); return; }
91
+ if (forceKillUsed) { finish(new Error(`${label} completed but did not terminate after graceful cleanup`)); return; }
92
+ if (code === 0 && completionIsValid()) { finish(); return; }
93
+ if (cleanupRequested && completionObserved && signal === "SIGTERM" && completionIsValid()) {
94
+ stderr.write(`${label} completed but did not exit; terminated the completed CLI after a bounded grace period\n`);
95
+ finish();
96
+ return;
97
+ }
98
+ if (settled) return;
99
+ const status = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
100
+ finish(new Error(`${label} failed with ${status}`));
101
+ });
102
+ });
103
+ }
104
+
105
+ function requiredString(value, name) {
106
+ const text = String(value || "");
107
+ if (!text) throw new TypeError(`${name} must be a non-empty string`);
108
+ return text;
109
+ }
110
+
111
+ function positiveInteger(value, fallback, name) {
112
+ if (value === undefined) return fallback;
113
+ if (!Number.isSafeInteger(value) || value <= 0) throw new TypeError(`${name} must be a positive integer`);
114
+ return value;
115
+ }
@@ -1,8 +1,10 @@
1
1
  import accessContract from "../shared/access-contract.json" with { type: "json" };
2
2
  import { BridgeError } from "./errors.mjs";
3
+ import { buildAuthorityContext } from "./authority-context.mjs";
3
4
  import { policyProfile, toolNamesForPolicy, assertToolAllowed } from "./policy.mjs";
4
5
 
5
6
  export const ACCOUNT_ACCESS_REVISION = Number(accessContract.revision);
7
+ const OWNER_ONLY_TOOLS = new Set((accessContract.ownerOnlyTools || []).map(String));
6
8
  const ACCOUNT_ROLE_ENTRIES = Object.entries(accessContract.roles)
7
9
  .map(([name, value]) => [name, Object.freeze({ ...value })]);
8
10
  const ACCOUNT_ROLE_BY_NAME = new Map(ACCOUNT_ROLE_ENTRIES);
@@ -22,16 +24,26 @@ export function accountRolePolicy(role) {
22
24
  }
23
25
 
24
26
  export function accountRoleToolNames(role) {
25
- return toolNamesForPolicy(accountRolePolicy(role));
27
+ const normalized = normalizeAccountRole(role);
28
+ const names = toolNamesForPolicy(accountRolePolicy(normalized));
29
+ return normalized === OWNER_ACCOUNT_ROLE ? names : names.filter((name) => !OWNER_ONLY_TOOLS.has(name));
26
30
  }
27
31
 
28
32
  export class AccountAccessGate {
29
33
  assert(role, tool) {
30
34
  const normalized = normalizeAccountRole(role);
35
+ if (normalized !== OWNER_ACCOUNT_ROLE && OWNER_ONLY_TOOLS.has(String(tool || ""))) {
36
+ throw new BridgeError("authorization_denied", `tool is reserved for the owner account: ${String(tool || "")}`);
37
+ }
31
38
  assertToolAllowed(accountRolePolicy(normalized), tool);
32
39
  return normalized;
33
40
  }
34
41
 
42
+ authority(authorization, daemonPolicy, origin = "relay") {
43
+ const role = origin === "relay" ? normalizeAccountRole(authorization?.role) : "owner";
44
+ return buildAuthorityContext({ authorization: { ...authorization, role }, daemonPolicy, origin });
45
+ }
46
+
35
47
  names(role) {
36
48
  return accountRoleToolNames(role);
37
49
  }
@@ -0,0 +1,92 @@
1
+ import { BridgeError } from "./errors.mjs";
2
+
3
+ const MAX_ADMIN_RESPONSE_BYTES = 1024 * 1024;
4
+ const MAX_ADMIN_ERROR_CHARS = 2_000;
5
+
6
+ export function isReadOnlyAdminMethod(method) { return method === "GET" || method === "HEAD"; }
7
+
8
+ export async function validateAdminResponseStatus(response, method, pathname) {
9
+ const expectedStatus = method === "DELETE" && pathname === "/admin/accounts" ? 204
10
+ : method === "POST" && pathname === "/admin/accounts" ? 201 : 200;
11
+ if (!response.ok || response.status === expectedStatus) return;
12
+ await cancelResponseBody(response.body);
13
+ throw adminResponseProtocolError(response, method, "account administration response used an unexpected success status");
14
+ }
15
+
16
+ export function boundedRemoteAdminMessage(payload, status) {
17
+ const fallback = `account administration failed (${status})`;
18
+ const candidate = typeof payload?.message === "string" ? payload.message : typeof payload?.error === "string" ? payload.error : fallback;
19
+ const normalized = candidate.replace(/[\u0000-\u001f\u007f\u200B-\u200F\u202A-\u202E\u2066-\u2069\uFEFF]/g, " ").replace(/\s+/g, " ").trim();
20
+ return (normalized || fallback).slice(0, MAX_ADMIN_ERROR_CHARS);
21
+ }
22
+
23
+ export async function readAdminJsonResponse(response, method) {
24
+ const declared = Number(response.headers.get("content-length") || "0");
25
+ if (Number.isFinite(declared) && declared > MAX_ADMIN_RESPONSE_BYTES) {
26
+ await cancelResponseBody(response.body);
27
+ throw adminResponseProtocolError(response, method, "account administration response exceeded the size limit");
28
+ }
29
+ if (!response.body) {
30
+ if (response.ok) throw adminResponseProtocolError(response, method, "account administration response was empty");
31
+ return {};
32
+ }
33
+ const reader = response.body.getReader();
34
+ const chunks = [];
35
+ let bytes = 0;
36
+ try {
37
+ for (;;) {
38
+ const { done, value } = await reader.read();
39
+ if (done) break;
40
+ if (!value) continue;
41
+ bytes += value.byteLength;
42
+ if (bytes > MAX_ADMIN_RESPONSE_BYTES) {
43
+ await cancelReader(reader);
44
+ throw adminResponseProtocolError(response, method, "account administration response exceeded the size limit");
45
+ }
46
+ chunks.push(value);
47
+ }
48
+ } finally {
49
+ reader.releaseLock();
50
+ }
51
+ let payload;
52
+ try {
53
+ const text = new TextDecoder("utf-8", { fatal: true }).decode(concatBytes(chunks, bytes));
54
+ payload = JSON.parse(text);
55
+ } catch (cause) {
56
+ if (response.ok) throw adminResponseProtocolError(response, method, "account administration response was not valid JSON", cause);
57
+ return {};
58
+ }
59
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
60
+ if (response.ok) throw adminResponseProtocolError(response, method, "account administration response was not a JSON object");
61
+ return {};
62
+ }
63
+ return payload;
64
+ }
65
+
66
+ function adminResponseProtocolError(response, method, message, cause) {
67
+ const mutation = response.ok && !isReadOnlyAdminMethod(method);
68
+ return new BridgeError("protocol_error", message, {
69
+ ...(cause ? { cause } : {}),
70
+ ...(mutation ? { retryable: false, details: { request_delivery: "sent", effect_settlement: "unknown" } } : {}),
71
+ });
72
+ }
73
+
74
+ async function cancelResponseBody(body) {
75
+ if (!body) return;
76
+ const reader = body.getReader();
77
+ try { await cancelReader(reader); } finally { reader.releaseLock(); }
78
+ }
79
+
80
+ async function cancelReader(reader) {
81
+ try { await reader.cancel("response size limit reached"); } catch { /* cleanup only */ }
82
+ }
83
+
84
+ function concatBytes(chunks, bytes) {
85
+ const output = new Uint8Array(bytes);
86
+ let offset = 0;
87
+ for (const chunk of chunks) {
88
+ output.set(chunk, offset);
89
+ offset += chunk.byteLength;
90
+ }
91
+ return output;
92
+ }
@@ -1,6 +1,8 @@
1
- import { createHash, createHmac, randomBytes } from "node:crypto";
1
+ import { createHash, randomBytes } from "node:crypto";
2
2
  import { ADMIN_AUTH_SCHEME, adminAuthTranscript } from "../shared/admin-auth.mjs";
3
3
  import { ACCOUNT_ROLES, normalizeAccountRole } from "./account-access.mjs";
4
+ import { boundedRemoteAdminMessage, isReadOnlyAdminMethod, readAdminJsonResponse, validateAdminResponseStatus } from "./account-admin-response.mjs";
5
+ import { encodeDeviceSessionCertificate, signWithDeviceSessionIdentity, validateDeviceSessionIdentity } from "./device-identity.mjs";
4
6
  import { BridgeError } from "./errors.mjs";
5
7
 
6
8
  const REQUEST_TIMEOUT_MS = 15_000;
@@ -10,15 +12,18 @@ export function generateAccountPassword() {
10
12
  }
11
13
 
12
14
  export class AccountAdminClient {
13
- constructor({ workerUrl, adminSecret, fetchImpl = fetch }) {
15
+ constructor({ workerUrl, sessionIdentity, fetchImpl = fetch }) {
14
16
  this.workerUrl = normalizeWorkerUrl(workerUrl);
15
- if (typeof adminSecret !== "string" || adminSecret.length < 24) throw new BridgeError("invalid_request", "account administration secret is missing");
16
- this.adminSecret = adminSecret;
17
+ this.sessionIdentity = validateDeviceSessionIdentity(sessionIdentity);
17
18
  this.fetchImpl = fetchImpl;
18
19
  }
19
20
 
20
- list() {
21
- return this.request("GET", "/admin/accounts");
21
+ list() { return this.request("GET", "/admin/accounts"); }
22
+ listClients() { return this.request("GET", "/admin/clients"); }
23
+
24
+ removeClient({ clientId }) {
25
+ if (!/^mcp_client_[A-Za-z0-9_-]{43}$/.test(String(clientId || ""))) throw new BridgeError("invalid_request", "OAuth client id is invalid");
26
+ return this.request("DELETE", "/admin/clients", { client_id: clientId });
22
27
  }
23
28
 
24
29
  create({ name, role, password, displayName = "" }) {
@@ -61,7 +66,7 @@ export class AccountAdminClient {
61
66
  async request(method, pathname, body) {
62
67
  const serializedBody = body === undefined ? "" : JSON.stringify(body);
63
68
  const headers = accountAdminRequestHeaders({
64
- secret: this.adminSecret,
69
+ sessionIdentity: this.sessionIdentity,
65
70
  origin: this.workerUrl,
66
71
  method,
67
72
  pathname,
@@ -74,40 +79,68 @@ export class AccountAdminClient {
74
79
  ...(body === undefined ? {} : { "content-type": "application/json" }),
75
80
  },
76
81
  body: body === undefined ? undefined : serializedBody,
82
+ redirect: "error",
77
83
  signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
78
84
  cache: "no-store",
79
85
  }).catch((error) => {
80
- throw new BridgeError("network_error", "account administration request failed", { cause: error, retryable: true });
86
+ const retryable = isReadOnlyAdminMethod(method);
87
+ throw new BridgeError("network_error", "account administration request failed", {
88
+ cause: error,
89
+ retryable,
90
+ ...(retryable ? {} : { details: { request_delivery: "unknown", effect_settlement: "unknown" } }),
91
+ });
81
92
  });
93
+ await validateAdminResponseStatus(response, method, pathname);
82
94
  if (response.status === 204) return { removed: true };
83
- const payload = await response.json().catch(() => ({}));
95
+ const payload = await readAdminJsonResponse(response, method);
84
96
  if (!response.ok) {
85
- const message = typeof payload.message === "string" ? payload.message : typeof payload.error === "string" ? payload.error : `account administration failed (${response.status})`;
97
+ const message = boundedRemoteAdminMessage(payload, response.status);
98
+ if (response.status >= 500) {
99
+ const retryable = isReadOnlyAdminMethod(method);
100
+ throw new BridgeError("unavailable", message, {
101
+ retryable,
102
+ ...(retryable ? {} : { details: { request_delivery: "sent", effect_settlement: "unknown" } }),
103
+ });
104
+ }
86
105
  throw new BridgeError(response.status === 404 ? "not_found" : response.status === 409 ? "conflict" : response.status === 401 ? "authentication_failed" : "invalid_request", message);
87
106
  }
88
107
  return payload;
89
108
  }
90
109
  }
91
110
 
92
-
93
- export function accountAdminRequestHeaders({ secret, origin, method, pathname, body = "", now = Date.now(), nonce = randomBytes(24).toString("base64url") }) {
94
- if (typeof secret !== "string" || secret.length < 24) throw new BridgeError("invalid_request", "account administration secret is missing");
111
+ export function accountAdminRequestHeaders({
112
+ sessionIdentity,
113
+ origin,
114
+ method,
115
+ pathname,
116
+ body = "",
117
+ now = Date.now(),
118
+ nonce = randomBytes(24).toString("base64url"),
119
+ }) {
120
+ validateDeviceSessionIdentity(sessionIdentity, now);
95
121
  const issuedAt = Math.floor(Number(now) / 1000);
96
122
  const bodyHash = createHash("sha256").update(String(body)).digest("hex");
97
- const transcript = adminAuthTranscript({ origin, method: String(method).toUpperCase(), pathname, bodyHash, issuedAt, nonce });
98
- const signature = createHmac("sha256", secret).update(transcript).digest("base64url");
123
+ const transcript = adminAuthTranscript({
124
+ origin,
125
+ method: String(method).toUpperCase(),
126
+ pathname,
127
+ bodyHash,
128
+ keyId: sessionIdentity.keyId,
129
+ issuedAt,
130
+ nonce,
131
+ });
99
132
  return {
100
133
  "X-Bridge-Admin-Scheme": ADMIN_AUTH_SCHEME,
101
134
  "X-Bridge-Admin-Time": String(issuedAt),
102
135
  "X-Bridge-Admin-Nonce": nonce,
103
136
  "X-Bridge-Admin-Body-SHA256": bodyHash,
104
- "X-Bridge-Admin-Signature": signature,
137
+ "X-Bridge-Admin-Key": sessionIdentity.keyId,
138
+ "X-Bridge-Admin-Signature": signWithDeviceSessionIdentity(sessionIdentity, transcript),
139
+ "X-Bridge-Device-Certificate": encodeDeviceSessionCertificate(sessionIdentity),
105
140
  };
106
141
  }
107
142
 
108
- export function accountRoleNames() {
109
- return Object.keys(ACCOUNT_ROLES);
110
- }
143
+ export function accountRoleNames() { return Object.keys(ACCOUNT_ROLES); }
111
144
 
112
145
  function normalizeWorkerUrl(value) {
113
146
  const url = new URL(String(value || ""));
@@ -36,6 +36,9 @@ import { createHash } from "node:crypto";
36
36
  */
37
37
  /**
38
38
  * @typedef {object} ProjectionState
39
+ * @property {string} target
40
+ * @property {string} targetDir
41
+ * @property {string} scopeRoot
39
42
  * @property {string[]} configFiles
40
43
  * @property {InstructionItem | null} builtinInstructions
41
44
  * @property {InstructionItem | null} automaticProjectContext
@@ -47,18 +50,34 @@ import { createHash } from "node:crypto";
47
50
  /** @param {ProjectionState} state @param {SkillSummary[]} skills */
48
51
  export function capabilityFingerprint(state, skills) {
49
52
  return sha256(JSON.stringify({
50
- configs: state.configFiles,
53
+ target: state.target,
54
+ target_dir: state.targetDir,
55
+ scope_root: state.scopeRoot,
56
+ configs: [...state.configFiles],
51
57
  instructions: [
52
- state.builtinInstructions?.sha256 || "",
53
- state.automaticProjectContext?.sha256 || "",
54
- state.modelInstructions?.sha256 || "",
55
- ...state.instructions.map((item) => item.sha256),
58
+ instructionFingerprintItem(state.builtinInstructions),
59
+ instructionFingerprintItem(state.automaticProjectContext),
60
+ instructionFingerprintItem(state.modelInstructions),
61
+ ...state.instructions.map(instructionFingerprintItem),
56
62
  ],
57
- skills: skills.map((skill) => [skill.id, skill.sha256]),
58
- commands: [...state.commands.values()].map((command) => [command.name, command.argv]),
63
+ skills: skills
64
+ .map((skill) => [skill.id, skill.name, skill.entrypoint, skill.sourceRoot, skill.sha256])
65
+ .sort((left, right) => String(left[0]).localeCompare(String(right[0]))),
66
+ commands: [...state.commands.values()]
67
+ .map((command) => [
68
+ command.name, command.description, command.argv, command.cwd, command.timeoutSeconds,
69
+ command.allowExtraArgs, command.source, command.sourceType || "", command.script || "",
70
+ ])
71
+ .sort((left, right) => String(left[0]).localeCompare(String(right[0]))),
59
72
  }));
60
73
  }
61
74
 
75
+ /** @param {InstructionItem | null | undefined} item */
76
+ function instructionFingerprintItem(item) {
77
+ if (!item) return null;
78
+ return [item.source || "", item.path || "", item.scope, item.sha256, item.precedence, item.bytes];
79
+ }
80
+
62
81
  /** @param {SkillSummary} skill @param {DisplayPath} displayPath */
63
82
  export function publicSkill(skill, displayPath) {
64
83
  return {