toolroll 0.5.0

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 (626) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1113 -0
  3. package/THIRD_PARTY_NOTICES.md +449 -0
  4. package/dist/accent-colors.d.ts +48 -0
  5. package/dist/accent-colors.js +122 -0
  6. package/dist/action-ledger.d.ts +26 -0
  7. package/dist/action-ledger.js +75 -0
  8. package/dist/agent-fence.d.ts +42 -0
  9. package/dist/agent-fence.js +183 -0
  10. package/dist/agentconfig.d.ts +216 -0
  11. package/dist/agentconfig.js +454 -0
  12. package/dist/api-tokens.d.ts +16 -0
  13. package/dist/api-tokens.js +27 -0
  14. package/dist/approval-policy.d.ts +69 -0
  15. package/dist/approval-policy.js +137 -0
  16. package/dist/approval-rules-ui.d.ts +25 -0
  17. package/dist/approval-rules-ui.js +39 -0
  18. package/dist/assignment-adapters.d.ts +180 -0
  19. package/dist/assignment-adapters.js +239 -0
  20. package/dist/assignment-brief.d.ts +71 -0
  21. package/dist/assignment-brief.js +129 -0
  22. package/dist/assignment-delivery.d.ts +56 -0
  23. package/dist/assignment-delivery.js +160 -0
  24. package/dist/assignment-presentation.d.ts +26 -0
  25. package/dist/assignment-presentation.js +80 -0
  26. package/dist/assignment-status.d.ts +62 -0
  27. package/dist/assignment-status.js +152 -0
  28. package/dist/assignment-ui.d.ts +71 -0
  29. package/dist/assignment-ui.js +103 -0
  30. package/dist/assignment.d.ts +222 -0
  31. package/dist/assignment.js +399 -0
  32. package/dist/attest.d.ts +56 -0
  33. package/dist/attest.js +153 -0
  34. package/dist/backend.d.ts +97 -0
  35. package/dist/backend.js +166 -0
  36. package/dist/backup-ui.d.ts +22 -0
  37. package/dist/backup-ui.js +59 -0
  38. package/dist/backup.d.ts +84 -0
  39. package/dist/backup.js +421 -0
  40. package/dist/beads.d.ts +34 -0
  41. package/dist/beads.js +135 -0
  42. package/dist/bin.d.ts +2 -0
  43. package/dist/bin.js +22 -0
  44. package/dist/board.d.ts +150 -0
  45. package/dist/board.js +210 -0
  46. package/dist/boot-identity.d.ts +63 -0
  47. package/dist/boot-identity.js +99 -0
  48. package/dist/browser/THIRD_PARTY_NOTICES.txt +2295 -0
  49. package/dist/browser/workspace.css +4 -0
  50. package/dist/browser/workspace.js +225 -0
  51. package/dist/browser-crew.d.ts +11 -0
  52. package/dist/browser-crew.js +50 -0
  53. package/dist/browser-shell.d.ts +8 -0
  54. package/dist/browser-shell.js +60 -0
  55. package/dist/browser-workspace.d.ts +780 -0
  56. package/dist/browser-workspace.js +47 -0
  57. package/dist/budget-alerts.d.ts +19 -0
  58. package/dist/budget-alerts.js +46 -0
  59. package/dist/builder.d.ts +370 -0
  60. package/dist/builder.js +3262 -0
  61. package/dist/capscan.d.ts +35 -0
  62. package/dist/capscan.js +113 -0
  63. package/dist/chat-acceptance.d.ts +71 -0
  64. package/dist/chat-acceptance.js +120 -0
  65. package/dist/chat-actions.d.ts +265 -0
  66. package/dist/chat-actions.js +1273 -0
  67. package/dist/chat-channel.d.ts +109 -0
  68. package/dist/chat-channel.js +652 -0
  69. package/dist/chat-continuity.d.ts +32 -0
  70. package/dist/chat-continuity.js +317 -0
  71. package/dist/chat-controls.d.ts +113 -0
  72. package/dist/chat-controls.js +53 -0
  73. package/dist/chat-delivery-state.d.ts +159 -0
  74. package/dist/chat-delivery-state.js +309 -0
  75. package/dist/chat-delivery.d.ts +38 -0
  76. package/dist/chat-delivery.js +693 -0
  77. package/dist/chat-display.d.ts +1 -0
  78. package/dist/chat-display.js +18 -0
  79. package/dist/chat-evidence.d.ts +123 -0
  80. package/dist/chat-evidence.js +207 -0
  81. package/dist/chat-flow.d.ts +44 -0
  82. package/dist/chat-flow.js +215 -0
  83. package/dist/chat-inbox.d.ts +57 -0
  84. package/dist/chat-inbox.js +123 -0
  85. package/dist/chat-polish.d.ts +16 -0
  86. package/dist/chat-polish.js +135 -0
  87. package/dist/chat-review.d.ts +46 -0
  88. package/dist/chat-review.js +98 -0
  89. package/dist/chat-rooms.d.ts +123 -0
  90. package/dist/chat-rooms.js +216 -0
  91. package/dist/chat-task-actions.d.ts +44 -0
  92. package/dist/chat-task-actions.js +79 -0
  93. package/dist/check-progress.d.ts +51 -0
  94. package/dist/check-progress.js +290 -0
  95. package/dist/child-database.d.ts +12 -0
  96. package/dist/child-database.js +30 -0
  97. package/dist/claim.d.ts +688 -0
  98. package/dist/claim.js +1740 -0
  99. package/dist/cli.d.ts +137 -0
  100. package/dist/cli.js +1461 -0
  101. package/dist/codex-limits.d.ts +15 -0
  102. package/dist/codex-limits.js +145 -0
  103. package/dist/coding-context.d.ts +55 -0
  104. package/dist/coding-context.js +92 -0
  105. package/dist/coding-handoff.d.ts +57 -0
  106. package/dist/coding-handoff.js +277 -0
  107. package/dist/coding-provider.d.ts +72 -0
  108. package/dist/coding-provider.js +424 -0
  109. package/dist/coding-shipping-ui.d.ts +4 -0
  110. package/dist/coding-shipping-ui.js +12 -0
  111. package/dist/coding-types.d.ts +62 -0
  112. package/dist/coding-types.js +1 -0
  113. package/dist/coding-ui.d.ts +17 -0
  114. package/dist/coding-ui.js +364 -0
  115. package/dist/coding-update.d.ts +15 -0
  116. package/dist/coding-update.js +149 -0
  117. package/dist/coding-workspace.d.ts +124 -0
  118. package/dist/coding-workspace.js +768 -0
  119. package/dist/container-state.d.ts +5 -0
  120. package/dist/container-state.js +62 -0
  121. package/dist/containment.d.ts +197 -0
  122. package/dist/containment.js +559 -0
  123. package/dist/contest.d.ts +318 -0
  124. package/dist/contest.js +753 -0
  125. package/dist/control-setup.d.ts +35 -0
  126. package/dist/control-setup.js +40 -0
  127. package/dist/control-ui.d.ts +29 -0
  128. package/dist/control-ui.js +53 -0
  129. package/dist/controller-service.d.ts +1 -0
  130. package/dist/controller-service.js +19 -0
  131. package/dist/controller-supervisor.d.ts +30 -0
  132. package/dist/controller-supervisor.js +104 -0
  133. package/dist/converse.d.ts +304 -0
  134. package/dist/converse.js +849 -0
  135. package/dist/coordinator-proposals.d.ts +29 -0
  136. package/dist/coordinator-proposals.js +137 -0
  137. package/dist/coordinator.d.ts +186 -0
  138. package/dist/coordinator.js +447 -0
  139. package/dist/credentials-ui.d.ts +25 -0
  140. package/dist/credentials-ui.js +48 -0
  141. package/dist/daemon.d.ts +209 -0
  142. package/dist/daemon.js +604 -0
  143. package/dist/decision.d.ts +120 -0
  144. package/dist/decision.js +388 -0
  145. package/dist/demo.d.ts +55 -0
  146. package/dist/demo.js +992 -0
  147. package/dist/desktop-access.d.ts +28 -0
  148. package/dist/desktop-access.js +88 -0
  149. package/dist/desktop-bundle.d.ts +16 -0
  150. package/dist/desktop-bundle.js +74 -0
  151. package/dist/desktop-host.d.ts +54 -0
  152. package/dist/desktop-host.js +508 -0
  153. package/dist/desktop-update-gate.d.ts +12 -0
  154. package/dist/desktop-update-gate.js +91 -0
  155. package/dist/desktop-update-recovery.d.ts +14 -0
  156. package/dist/desktop-update-recovery.js +243 -0
  157. package/dist/desktop-update.d.ts +110 -0
  158. package/dist/desktop-update.js +740 -0
  159. package/dist/discord-api.d.ts +20 -0
  160. package/dist/discord-api.js +138 -0
  161. package/dist/discord-chat.d.ts +16 -0
  162. package/dist/discord-chat.js +381 -0
  163. package/dist/discord-settings.d.ts +7 -0
  164. package/dist/discord-settings.js +75 -0
  165. package/dist/discord.d.ts +10 -0
  166. package/dist/discord.js +169 -0
  167. package/dist/discover.d.ts +75 -0
  168. package/dist/discover.js +150 -0
  169. package/dist/dispatch.d.ts +100 -0
  170. package/dist/dispatch.js +311 -0
  171. package/dist/dispose.d.ts +161 -0
  172. package/dist/dispose.js +803 -0
  173. package/dist/email-settings.d.ts +34 -0
  174. package/dist/email-settings.js +50 -0
  175. package/dist/envelope.d.ts +47 -0
  176. package/dist/envelope.js +105 -0
  177. package/dist/evidence-pack.d.ts +185 -0
  178. package/dist/evidence-pack.js +258 -0
  179. package/dist/evidence.d.ts +345 -0
  180. package/dist/evidence.js +782 -0
  181. package/dist/exec.d.ts +285 -0
  182. package/dist/exec.js +1841 -0
  183. package/dist/exhaustion.d.ts +85 -0
  184. package/dist/exhaustion.js +141 -0
  185. package/dist/export-ui.d.ts +4 -0
  186. package/dist/export-ui.js +17 -0
  187. package/dist/export.d.ts +48 -0
  188. package/dist/export.js +305 -0
  189. package/dist/flow-actions.d.ts +77 -0
  190. package/dist/flow-actions.js +203 -0
  191. package/dist/flow-code.d.ts +50 -0
  192. package/dist/flow-code.js +159 -0
  193. package/dist/flow-draft.d.ts +38 -0
  194. package/dist/flow-draft.js +80 -0
  195. package/dist/flow-engine.d.ts +66 -0
  196. package/dist/flow-engine.js +416 -0
  197. package/dist/flow-insights.d.ts +95 -0
  198. package/dist/flow-insights.js +149 -0
  199. package/dist/flow-live.d.ts +24 -0
  200. package/dist/flow-live.js +150 -0
  201. package/dist/flow-people.d.ts +24 -0
  202. package/dist/flow-people.js +91 -0
  203. package/dist/flow-replies.d.ts +48 -0
  204. package/dist/flow-replies.js +113 -0
  205. package/dist/flow-scripts.d.ts +38 -0
  206. package/dist/flow-scripts.js +73 -0
  207. package/dist/flow-secrets.d.ts +13 -0
  208. package/dist/flow-secrets.js +45 -0
  209. package/dist/flow-sort.d.ts +82 -0
  210. package/dist/flow-sort.js +153 -0
  211. package/dist/flow-steps.d.ts +40 -0
  212. package/dist/flow-steps.js +408 -0
  213. package/dist/flow-triggers.d.ts +244 -0
  214. package/dist/flow-triggers.js +959 -0
  215. package/dist/flows-ui.d.ts +20 -0
  216. package/dist/flows-ui.js +175 -0
  217. package/dist/flows.d.ts +229 -0
  218. package/dist/flows.js +968 -0
  219. package/dist/fonts.d.ts +19 -0
  220. package/dist/fonts.js +19 -0
  221. package/dist/gaps.d.ts +35 -0
  222. package/dist/gaps.js +101 -0
  223. package/dist/gate-failure.d.ts +40 -0
  224. package/dist/gate-failure.js +66 -0
  225. package/dist/git.d.ts +54 -0
  226. package/dist/git.js +94 -0
  227. package/dist/google-mail.d.ts +58 -0
  228. package/dist/google-mail.js +151 -0
  229. package/dist/grant.d.ts +136 -0
  230. package/dist/grant.js +238 -0
  231. package/dist/graph.d.ts +164 -0
  232. package/dist/graph.js +383 -0
  233. package/dist/guides.d.ts +22 -0
  234. package/dist/guides.js +363 -0
  235. package/dist/held.d.ts +150 -0
  236. package/dist/held.js +799 -0
  237. package/dist/invoke.d.ts +112 -0
  238. package/dist/invoke.js +780 -0
  239. package/dist/issues.d.ts +41 -0
  240. package/dist/issues.js +131 -0
  241. package/dist/job-object-helper.ps1 +252 -0
  242. package/dist/jsonl-discriminants.d.ts +11 -0
  243. package/dist/jsonl-discriminants.js +93 -0
  244. package/dist/keys.d.ts +104 -0
  245. package/dist/keys.js +229 -0
  246. package/dist/kits-ui.d.ts +17 -0
  247. package/dist/kits-ui.js +46 -0
  248. package/dist/kits.d.ts +86 -0
  249. package/dist/kits.js +215 -0
  250. package/dist/knowledge-cli.d.ts +101 -0
  251. package/dist/knowledge-cli.js +92 -0
  252. package/dist/knowledge-ui.d.ts +24 -0
  253. package/dist/knowledge-ui.js +40 -0
  254. package/dist/lead-context.d.ts +8 -0
  255. package/dist/lead-context.js +56 -0
  256. package/dist/lead-follow.d.ts +22 -0
  257. package/dist/lead-follow.js +167 -0
  258. package/dist/lead-status.d.ts +75 -0
  259. package/dist/lead-status.js +285 -0
  260. package/dist/ledger-chain.d.ts +46 -0
  261. package/dist/ledger-chain.js +187 -0
  262. package/dist/ledger-csv.d.ts +4 -0
  263. package/dist/ledger-csv.js +11 -0
  264. package/dist/ledger-view.d.ts +24 -0
  265. package/dist/ledger-view.js +58 -0
  266. package/dist/limits-ui.d.ts +26 -0
  267. package/dist/limits-ui.js +67 -0
  268. package/dist/link.d.ts +72 -0
  269. package/dist/link.js +217 -0
  270. package/dist/live.d.ts +96 -0
  271. package/dist/live.js +366 -0
  272. package/dist/liveness.d.ts +30 -0
  273. package/dist/liveness.js +42 -0
  274. package/dist/log.d.ts +7 -0
  275. package/dist/log.js +25 -0
  276. package/dist/mailbox.d.ts +57 -0
  277. package/dist/mailbox.js +150 -0
  278. package/dist/maintenance.d.ts +11 -0
  279. package/dist/maintenance.js +35 -0
  280. package/dist/mate-cli.d.ts +52 -0
  281. package/dist/mate-cli.js +345 -0
  282. package/dist/mate-contract.d.ts +10 -0
  283. package/dist/mate-contract.js +30 -0
  284. package/dist/mate-doors.d.ts +69 -0
  285. package/dist/mate-doors.js +548 -0
  286. package/dist/mate-progress.d.ts +29 -0
  287. package/dist/mate-progress.js +121 -0
  288. package/dist/mate-tools.d.ts +94 -0
  289. package/dist/mate-tools.js +1878 -0
  290. package/dist/mate.d.ts +92 -0
  291. package/dist/mate.js +435 -0
  292. package/dist/mcp-connect.d.ts +103 -0
  293. package/dist/mcp-connect.js +252 -0
  294. package/dist/mcp.d.ts +27 -0
  295. package/dist/mcp.js +651 -0
  296. package/dist/memory-cli.d.ts +466 -0
  297. package/dist/memory-cli.js +111 -0
  298. package/dist/memory-pass.d.ts +160 -0
  299. package/dist/memory-pass.js +409 -0
  300. package/dist/metrics.d.ts +3 -0
  301. package/dist/metrics.js +56 -0
  302. package/dist/mobile-viewport.d.ts +3 -0
  303. package/dist/mobile-viewport.js +37 -0
  304. package/dist/model-catalog.d.ts +118 -0
  305. package/dist/model-catalog.js +376 -0
  306. package/dist/models-cli.d.ts +102 -0
  307. package/dist/models-cli.js +66 -0
  308. package/dist/models-ui.d.ts +34 -0
  309. package/dist/models-ui.js +68 -0
  310. package/dist/modes.d.ts +80 -0
  311. package/dist/modes.js +182 -0
  312. package/dist/monitoring-settings.d.ts +44 -0
  313. package/dist/monitoring-settings.js +173 -0
  314. package/dist/monitoring-ui.d.ts +20 -0
  315. package/dist/monitoring-ui.js +51 -0
  316. package/dist/monitoring.d.ts +34 -0
  317. package/dist/monitoring.js +221 -0
  318. package/dist/names.d.ts +67 -0
  319. package/dist/names.js +102 -0
  320. package/dist/observations.d.ts +40 -0
  321. package/dist/observations.js +211 -0
  322. package/dist/oidc.d.ts +71 -0
  323. package/dist/oidc.js +182 -0
  324. package/dist/onboard.d.ts +108 -0
  325. package/dist/onboard.js +325 -0
  326. package/dist/openrouter-models.d.ts +30 -0
  327. package/dist/openrouter-models.js +120 -0
  328. package/dist/operate.d.ts +118 -0
  329. package/dist/operate.js +11321 -0
  330. package/dist/peek-cli.d.ts +97 -0
  331. package/dist/peek-cli.js +215 -0
  332. package/dist/peek.d.ts +134 -0
  333. package/dist/peek.js +578 -0
  334. package/dist/phase-routing.d.ts +307 -0
  335. package/dist/phase-routing.js +658 -0
  336. package/dist/plan-auto.d.ts +14 -0
  337. package/dist/plan-auto.js +92 -0
  338. package/dist/plan.d.ts +186 -0
  339. package/dist/plan.js +401 -0
  340. package/dist/planner-source.d.ts +251 -0
  341. package/dist/planner-source.js +460 -0
  342. package/dist/planner.d.ts +75 -0
  343. package/dist/planner.js +992 -0
  344. package/dist/policy-ui.d.ts +20 -0
  345. package/dist/policy-ui.js +41 -0
  346. package/dist/policy.d.ts +111 -0
  347. package/dist/policy.js +231 -0
  348. package/dist/prepared-evidence.d.ts +16 -0
  349. package/dist/prepared-evidence.js +96 -0
  350. package/dist/pricing.d.ts +45 -0
  351. package/dist/pricing.js +77 -0
  352. package/dist/principal.d.ts +42 -0
  353. package/dist/principal.js +82 -0
  354. package/dist/probe.d.ts +46 -0
  355. package/dist/probe.js +79 -0
  356. package/dist/process-custody.d.ts +17 -0
  357. package/dist/process-custody.js +91 -0
  358. package/dist/process-liveness.d.ts +10 -0
  359. package/dist/process-liveness.js +81 -0
  360. package/dist/process-recovery-anchor.d.ts +75 -0
  361. package/dist/process-recovery-anchor.js +188 -0
  362. package/dist/process-recovery-coalition.d.ts +25 -0
  363. package/dist/process-recovery-coalition.js +105 -0
  364. package/dist/process-recovery-eligibility.d.ts +178 -0
  365. package/dist/process-recovery-eligibility.js +170 -0
  366. package/dist/process-recovery-native.d.ts +172 -0
  367. package/dist/process-recovery-native.js +592 -0
  368. package/dist/process-recovery-provenance.d.ts +163 -0
  369. package/dist/process-recovery-provenance.js +292 -0
  370. package/dist/process-recovery-services.d.ts +56 -0
  371. package/dist/process-recovery-services.js +191 -0
  372. package/dist/process-recovery-settlement.d.ts +32 -0
  373. package/dist/process-recovery-settlement.js +132 -0
  374. package/dist/process-recovery.d.ts +41 -0
  375. package/dist/process-recovery.js +91 -0
  376. package/dist/process-tree.d.ts +41 -0
  377. package/dist/process-tree.js +264 -0
  378. package/dist/project-access.d.ts +14 -0
  379. package/dist/project-access.js +34 -0
  380. package/dist/project-cli.d.ts +18 -0
  381. package/dist/project-cli.js +104 -0
  382. package/dist/project-delete-ui.d.ts +22 -0
  383. package/dist/project-delete-ui.js +48 -0
  384. package/dist/project-delete.d.ts +55 -0
  385. package/dist/project-delete.js +413 -0
  386. package/dist/project-knowledge.d.ts +111 -0
  387. package/dist/project-knowledge.js +241 -0
  388. package/dist/project-learning.d.ts +100 -0
  389. package/dist/project-learning.js +438 -0
  390. package/dist/project-memory.d.ts +81 -0
  391. package/dist/project-memory.js +264 -0
  392. package/dist/project-skills.d.ts +152 -0
  393. package/dist/project-skills.js +660 -0
  394. package/dist/project-tools.d.ts +219 -0
  395. package/dist/project-tools.js +796 -0
  396. package/dist/project.d.ts +61 -0
  397. package/dist/project.js +125 -0
  398. package/dist/prompt.d.ts +22 -0
  399. package/dist/prompt.js +72 -0
  400. package/dist/proof.d.ts +513 -0
  401. package/dist/proof.js +1140 -0
  402. package/dist/proposal.d.ts +82 -0
  403. package/dist/proposal.js +210 -0
  404. package/dist/provider-connection.d.ts +22 -0
  405. package/dist/provider-connection.js +98 -0
  406. package/dist/provider-limits.d.ts +35 -0
  407. package/dist/provider-limits.js +95 -0
  408. package/dist/provider.d.ts +279 -0
  409. package/dist/provider.js +935 -0
  410. package/dist/publish.d.ts +107 -0
  411. package/dist/publish.js +650 -0
  412. package/dist/pulls.d.ts +118 -0
  413. package/dist/pulls.js +240 -0
  414. package/dist/push.d.ts +95 -0
  415. package/dist/push.js +353 -0
  416. package/dist/quality.d.ts +8 -0
  417. package/dist/quality.js +6 -0
  418. package/dist/recipe-ui.d.ts +18 -0
  419. package/dist/recipe-ui.js +152 -0
  420. package/dist/recipes.d.ts +81 -0
  421. package/dist/recipes.js +332 -0
  422. package/dist/remote.d.ts +67 -0
  423. package/dist/remote.js +122 -0
  424. package/dist/render.d.ts +64 -0
  425. package/dist/render.js +587 -0
  426. package/dist/report-summary.d.ts +13 -0
  427. package/dist/report-summary.js +15 -0
  428. package/dist/repos.d.ts +65 -0
  429. package/dist/repos.js +277 -0
  430. package/dist/repository-context-ui.d.ts +2 -0
  431. package/dist/repository-context-ui.js +10 -0
  432. package/dist/repository-context.d.ts +67 -0
  433. package/dist/repository-context.js +376 -0
  434. package/dist/restart-certification.d.ts +134 -0
  435. package/dist/restart-certification.js +226 -0
  436. package/dist/result-actions.d.ts +28 -0
  437. package/dist/result-actions.js +270 -0
  438. package/dist/result-completion.d.ts +18 -0
  439. package/dist/result-completion.js +66 -0
  440. package/dist/result-review.d.ts +213 -0
  441. package/dist/result-review.js +430 -0
  442. package/dist/retention-ui.d.ts +12 -0
  443. package/dist/retention-ui.js +39 -0
  444. package/dist/retention.d.ts +72 -0
  445. package/dist/retention.js +288 -0
  446. package/dist/review-context.d.ts +243 -0
  447. package/dist/review-context.js +1043 -0
  448. package/dist/review-evidence.d.ts +33 -0
  449. package/dist/review-evidence.js +56 -0
  450. package/dist/reviewer.d.ts +97 -0
  451. package/dist/reviewer.js +202 -0
  452. package/dist/routine.d.ts +228 -0
  453. package/dist/routine.js +764 -0
  454. package/dist/runner.d.ts +266 -0
  455. package/dist/runner.js +399 -0
  456. package/dist/scan.d.ts +32 -0
  457. package/dist/scan.js +92 -0
  458. package/dist/scope.d.ts +695 -0
  459. package/dist/scope.js +1176 -0
  460. package/dist/scout-report.d.ts +42 -0
  461. package/dist/scout-report.js +108 -0
  462. package/dist/scout.d.ts +69 -0
  463. package/dist/scout.js +351 -0
  464. package/dist/serve.d.ts +313 -0
  465. package/dist/serve.js +21776 -0
  466. package/dist/session-brief.d.ts +8 -0
  467. package/dist/session-brief.js +24 -0
  468. package/dist/session-cli.d.ts +13 -0
  469. package/dist/session-cli.js +284 -0
  470. package/dist/session-contract.d.ts +183 -0
  471. package/dist/session-contract.js +122 -0
  472. package/dist/session-http.d.ts +19 -0
  473. package/dist/session-http.js +154 -0
  474. package/dist/session-server.d.ts +12 -0
  475. package/dist/session-server.js +37 -0
  476. package/dist/session-service.d.ts +22 -0
  477. package/dist/session-service.js +157 -0
  478. package/dist/setup-guide.d.ts +39 -0
  479. package/dist/setup-guide.js +93 -0
  480. package/dist/sign-in-guard.d.ts +45 -0
  481. package/dist/sign-in-guard.js +74 -0
  482. package/dist/skills-ui.d.ts +11 -0
  483. package/dist/skills-ui.js +58 -0
  484. package/dist/skills.d.ts +97 -0
  485. package/dist/skills.js +276 -0
  486. package/dist/slack-api.d.ts +55 -0
  487. package/dist/slack-api.js +229 -0
  488. package/dist/slack-chat.d.ts +28 -0
  489. package/dist/slack-chat.js +413 -0
  490. package/dist/slack-settings.d.ts +7 -0
  491. package/dist/slack-settings.js +75 -0
  492. package/dist/slack-state.d.ts +13 -0
  493. package/dist/slack-state.js +9 -0
  494. package/dist/slack.d.ts +13 -0
  495. package/dist/slack.js +167 -0
  496. package/dist/spend-ui.d.ts +28 -0
  497. package/dist/spend-ui.js +95 -0
  498. package/dist/spend.d.ts +142 -0
  499. package/dist/spend.js +313 -0
  500. package/dist/sqlite-runtime.d.ts +3 -0
  501. package/dist/sqlite-runtime.js +6 -0
  502. package/dist/sso-settings.d.ts +33 -0
  503. package/dist/sso-settings.js +103 -0
  504. package/dist/sso-ui.d.ts +22 -0
  505. package/dist/sso-ui.js +39 -0
  506. package/dist/storage.d.ts +15 -0
  507. package/dist/storage.js +84 -0
  508. package/dist/store.d.ts +7754 -0
  509. package/dist/store.js +23279 -0
  510. package/dist/structured-output.d.ts +58 -0
  511. package/dist/structured-output.js +103 -0
  512. package/dist/style-asset.d.ts +7 -0
  513. package/dist/style-asset.js +41 -0
  514. package/dist/subscription-chat.d.ts +46 -0
  515. package/dist/subscription-chat.js +275 -0
  516. package/dist/summary.d.ts +33 -0
  517. package/dist/summary.js +71 -0
  518. package/dist/supervisor.mjs +297 -0
  519. package/dist/surface.d.ts +63 -0
  520. package/dist/surface.js +352 -0
  521. package/dist/sync.d.ts +94 -0
  522. package/dist/sync.js +279 -0
  523. package/dist/task-composer.d.ts +13 -0
  524. package/dist/task-composer.js +52 -0
  525. package/dist/task-control.d.ts +165 -0
  526. package/dist/task-control.js +214 -0
  527. package/dist/task-outcome-cli.d.ts +10 -0
  528. package/dist/task-outcome-cli.js +92 -0
  529. package/dist/task-text.d.ts +30 -0
  530. package/dist/task-text.js +41 -0
  531. package/dist/team-cli.d.ts +15 -0
  532. package/dist/team-cli.js +618 -0
  533. package/dist/team-contract.d.ts +92 -0
  534. package/dist/team-contract.js +1 -0
  535. package/dist/team-http.d.ts +17 -0
  536. package/dist/team-http.js +144 -0
  537. package/dist/team-leads.d.ts +81 -0
  538. package/dist/team-leads.js +565 -0
  539. package/dist/team-runtime.d.ts +27 -0
  540. package/dist/team-runtime.js +264 -0
  541. package/dist/team-ui.d.ts +3 -0
  542. package/dist/team-ui.js +9 -0
  543. package/dist/team-updates.d.ts +8 -0
  544. package/dist/team-updates.js +57 -0
  545. package/dist/teammate-admin.d.ts +53 -0
  546. package/dist/teammate-admin.js +111 -0
  547. package/dist/teammate-desk.d.ts +60 -0
  548. package/dist/teammate-desk.js +154 -0
  549. package/dist/teammate-memory.d.ts +64 -0
  550. package/dist/teammate-memory.js +196 -0
  551. package/dist/teammate-question.d.ts +59 -0
  552. package/dist/teammate-question.js +175 -0
  553. package/dist/teammate-tools.d.ts +108 -0
  554. package/dist/teammate-tools.js +271 -0
  555. package/dist/teammate-week.d.ts +68 -0
  556. package/dist/teammate-week.js +132 -0
  557. package/dist/teammate-work.d.ts +76 -0
  558. package/dist/teammate-work.js +280 -0
  559. package/dist/teammates-ui.d.ts +20 -0
  560. package/dist/teammates-ui.js +166 -0
  561. package/dist/teammates.d.ts +180 -0
  562. package/dist/teammates.js +253 -0
  563. package/dist/teams-api.d.ts +33 -0
  564. package/dist/teams-api.js +204 -0
  565. package/dist/teams-chat.d.ts +26 -0
  566. package/dist/teams-chat.js +215 -0
  567. package/dist/teams-settings.d.ts +12 -0
  568. package/dist/teams-settings.js +57 -0
  569. package/dist/teams.d.ts +21 -0
  570. package/dist/teams.js +124 -0
  571. package/dist/telegram-flow.d.ts +49 -0
  572. package/dist/telegram-flow.js +110 -0
  573. package/dist/telegram-mate.d.ts +137 -0
  574. package/dist/telegram-mate.js +707 -0
  575. package/dist/telegram-progress.d.ts +14 -0
  576. package/dist/telegram-progress.js +129 -0
  577. package/dist/telegram-settings.d.ts +9 -0
  578. package/dist/telegram-settings.js +36 -0
  579. package/dist/telegram-status.d.ts +75 -0
  580. package/dist/telegram-status.js +265 -0
  581. package/dist/telegram-team.d.ts +85 -0
  582. package/dist/telegram-team.js +359 -0
  583. package/dist/telegram.d.ts +230 -0
  584. package/dist/telegram.js +1931 -0
  585. package/dist/templates.d.ts +65 -0
  586. package/dist/templates.js +118 -0
  587. package/dist/tool-launcher.d.ts +1 -0
  588. package/dist/tool-launcher.js +101 -0
  589. package/dist/tools-ui.d.ts +30 -0
  590. package/dist/tools-ui.js +40 -0
  591. package/dist/transitions-recipes.d.ts +1 -0
  592. package/dist/transitions-recipes.js +203 -0
  593. package/dist/tree-proof.d.ts +34 -0
  594. package/dist/tree-proof.js +58 -0
  595. package/dist/verification-evidence.d.ts +44 -0
  596. package/dist/verification-evidence.js +238 -0
  597. package/dist/version.d.ts +2 -0
  598. package/dist/version.js +10 -0
  599. package/dist/webhooks.d.ts +91 -0
  600. package/dist/webhooks.js +283 -0
  601. package/dist/work-index.d.ts +68 -0
  602. package/dist/work-index.js +384 -0
  603. package/dist/work-summary.d.ts +57 -0
  604. package/dist/work-summary.js +116 -0
  605. package/dist/workspace-motion.d.ts +4 -0
  606. package/dist/workspace-motion.js +133 -0
  607. package/dist/workspace-revision.d.ts +19 -0
  608. package/dist/workspace-revision.js +92 -0
  609. package/dist/workspace-ui.d.ts +204 -0
  610. package/dist/workspace-ui.js +411 -0
  611. package/dist/worktree-notices.d.ts +13 -0
  612. package/dist/worktree-notices.js +17 -0
  613. package/dist/worktree.d.ts +249 -0
  614. package/dist/worktree.js +720 -0
  615. package/package.json +122 -0
  616. package/scripts/canary-assertions.mjs +42 -0
  617. package/scripts/crash-canary.mjs +253 -0
  618. package/scripts/fixtures/crash-process.mjs +74 -0
  619. package/scripts/fixtures/pilot-scenarios.mjs +85 -0
  620. package/scripts/fixtures/restart-service.mjs +27 -0
  621. package/scripts/launchd-certification.mjs +143 -0
  622. package/scripts/pilot.mjs +121 -0
  623. package/scripts/proof-preflight.mjs +140 -0
  624. package/scripts/provider-canary.mjs +379 -0
  625. package/scripts/recovery-canary.mjs +135 -0
  626. package/scripts/restart-certification.mjs +98 -0
package/dist/mcp.js ADDED
@@ -0,0 +1,651 @@
1
+ import { TASK_SCOPE_TEXT_SCHEMA } from "./task-text.js";
2
+ import { dirname, join } from 'node:path';
3
+ import { repositoryContextRead } from './repository-context.js';
4
+ import { ASSIGNMENT_TOOLS, assignmentForCoordinator } from "./assignment-adapters.js";
5
+ /**
6
+ * `toolroll mcp` — the MCP stdio server (MCP gateway spec v6).
7
+ *
8
+ * Zero-dep JSON-RPC 2.0 over stdio, newline-delimited; stdout carries
9
+ * protocol bytes ONLY (logs go to stderr); clean EOF is clean shutdown.
10
+ * Two pinned protocol revisions:
11
+ *
12
+ * - modern `2026-07-28`: stateless; every request carries its version in
13
+ * `_meta`; `server/discover` describes the server; successful results
14
+ * are schema-complete (`resultType: "complete"`, and tools/list +
15
+ * discover carry `ttlMs: 0` with the narrowest `cacheScope`).
16
+ * - legacy `2025-11-25`: the initialize era — a client asking for an
17
+ * unsupported version is answered WITH this one (negotiation, not
18
+ * refusal); `notifications/initialized` is received and ignored. The
19
+ * eras never cross: initialize never counter-offers the modern one.
20
+ *
21
+ * No JSON-RPC batching in either era (arrays reject). A cancellation is a
22
+ * notification: the server stops work on that id and suppresses its
23
+ * response entirely. Limits: request ≤ 256 KiB, JSON depth ≤ 32.
24
+ *
25
+ * EVERY tool call authenticates the coordinator credential; the schema
26
+ * version is re-read per call (a concurrent migration refuses in words
27
+ * and the server exits). Protocol errors are JSON-RPC errors; tool-level
28
+ * refusals are successful `tools/call` results with `isError: true`.
29
+ */
30
+ import { PACKAGE_VERSION } from "./version.js";
31
+ import { authenticateCoordinator, fileCoordinatorProposal, statusFor, listTasksFor, taskDetailFor, } from "./coordinator.js";
32
+ import { ISO_STAMP_RULE, decisionOver, decisionsOver, labelRepos, queueOver, recapOver } from "./mate-tools.js";
33
+ import { proposeAsCoordinator } from "./coordinator-proposals.js";
34
+ export const MODERN = "2026-07-28";
35
+ export const LEGACY = "2025-11-25";
36
+ /** The modern revision namespaces its per-request metadata. */
37
+ export const META_VERSION = "io.modelcontextprotocol/protocolVersion";
38
+ export const META_SERVER = "io.modelcontextprotocol/serverInfo";
39
+ export const META_CAPABILITIES = "io.modelcontextprotocol/clientCapabilities";
40
+ /** The revision's own error code for an unsupported protocol version. */
41
+ export const UNSUPPORTED_VERSION = -32022;
42
+ const MAX_REQUEST = 256 * 1024;
43
+ const MAX_DEPTH = 32;
44
+ function depthOf(value) {
45
+ // The byte cap bounds the work list. Neither nesting nor array width
46
+ // becomes a JavaScript call stack or a spread argument list.
47
+ const pending = [{ value, depth: 0 }];
48
+ let maximum = 0;
49
+ while (pending.length > 0) {
50
+ const current = pending.pop();
51
+ if (current.depth > MAX_DEPTH)
52
+ return current.depth;
53
+ maximum = Math.max(maximum, current.depth);
54
+ if (current.value !== null && typeof current.value === "object") {
55
+ const children = Array.isArray(current.value) ? current.value : Object.values(current.value);
56
+ for (const child of children)
57
+ pending.push({ value: child, depth: current.depth + 1 });
58
+ }
59
+ }
60
+ return maximum;
61
+ }
62
+ const CONTRACT_GUIDE = [
63
+ "Toolroll MCP contract.",
64
+ "You hold a coordinator credential: you may read inside your repo allowlist, file proposals, and record assignment ownership and receipt checks. Ownership and receipt checks grant no execution or approval authority.",
65
+ "A filed proposal is an ordinary unapproved task: it is quarantined from planning, claiming, and running until the operator signs its scope in a password ceremony that shows them who asked. Modes never auto-admit coordinator filings.",
66
+ "file_proposal requires an idempotency_key (8-64 printable chars, unique per request): replaying the same key+request returns the original task; the same key with a different request refuses. deliverable 'report' files a scout task: a read-only investigation whose only output is a report on the task page, never a branch.",
67
+ "You are rate-limited per hour and capped on outstanding unapproved filings. Refusals say the limit and the road in words.",
68
+ "recap, list_decisions, get_decision, and queue are the plane's own read queries (shared with the operator's mate). get_decision shows each option's consequence, never the builder's recommendation.",
69
+ "propose_next, propose_reserve, propose_hold, propose_unhold, propose_scope, propose_cancel, and propose_answer write a PROPOSAL row and nothing else: an approver confirms it on the console or the CLI, and a stale one refuses there. Proposals share your hourly filing rate and hold at most 20 pending per credential; they expire after seven days.",
70
+ "Approve, steer, answer, pick, mint, configure, merge: those verbs do not exist on this surface, by construction.",
71
+ "Claim one assignment, then follow list_assignment_updates with a saved cursor; inspect get_assignment when a current result or decision needs attention. claim_assignment records its lead; acknowledge_assignment records that lead's check of an exact ready receipt. Neither operation grants authority, accepts proof, answers decisions, approves work, publishes, or deploys.",
72
+ ].join("\n");
73
+ /** The descriptor's inputSchema IS the runtime parser (review finding 2):
74
+ * unknown fields, bad types, bad enums, and bound violations are protocol
75
+ * errors (InvalidParams), never tool refusals. Small on purpose — it
76
+ * covers exactly the schema features the descriptors use. */
77
+ function invalidArgs(schema, args) {
78
+ const shape = schema;
79
+ const properties = shape.properties ?? {};
80
+ for (const key of Object.keys(args)) {
81
+ if (properties[key] === undefined)
82
+ return "unknown argument `" + key + "`";
83
+ }
84
+ for (const key of shape.required ?? []) {
85
+ if (args[key] === undefined)
86
+ return "missing required argument `" + key + "`";
87
+ }
88
+ for (const [key, rule] of Object.entries(properties)) {
89
+ const value = args[key];
90
+ if (value === undefined)
91
+ continue;
92
+ // A union type (`["string","null"]`) admits null or its other member;
93
+ // an array checks its items and its cap (v3 review, finding 8).
94
+ if (Array.isArray(rule["type"])) {
95
+ const types = rule["type"];
96
+ if (value === null) {
97
+ if (!types.includes("null"))
98
+ return "`" + key + "` must not be null";
99
+ continue;
100
+ }
101
+ const member = types.find(one => one !== "null");
102
+ const problem = invalidArgs({ type: "object", properties: { [key]: { ...rule, type: member ?? "string" } } }, { [key]: value });
103
+ if (problem !== null)
104
+ return problem;
105
+ continue;
106
+ }
107
+ if (rule["type"] === "array") {
108
+ if (!Array.isArray(value))
109
+ return "`" + key + "` must be an array";
110
+ const maxItems = rule["maxItems"];
111
+ if (typeof maxItems === "number" && value.length > maxItems)
112
+ return "`" + key + "` has more than " + String(maxItems) + " items";
113
+ const items = rule["items"];
114
+ if (items !== undefined) {
115
+ for (const one of value) {
116
+ const problem = invalidArgs({ type: "object", properties: { item: items } }, { item: one });
117
+ if (problem !== null)
118
+ return "`" + key + "`: " + problem.replace("`item`", "an item");
119
+ }
120
+ }
121
+ continue;
122
+ }
123
+ if (rule["type"] === "boolean" && typeof value !== "boolean")
124
+ return "`" + key + "` must be a boolean";
125
+ if (rule["type"] === "string") {
126
+ if (typeof value !== "string")
127
+ return "`" + key + "` must be a string";
128
+ const min = rule["minLength"];
129
+ const max = rule["maxLength"];
130
+ if (typeof min === "number" && value.length < min)
131
+ return "`" + key + "` is shorter than " + String(min);
132
+ if (typeof max === "number" && value.length > max)
133
+ return "`" + key + "` is longer than " + String(max);
134
+ const pattern = rule["pattern"];
135
+ if (typeof pattern === "string" && !new RegExp(pattern).test(value))
136
+ return "`" + key + "` does not match its required format";
137
+ const allowed = rule["enum"];
138
+ if (Array.isArray(allowed) && !allowed.includes(value))
139
+ return "`" + key + "` must be one of " + allowed.join(", ");
140
+ }
141
+ if (rule["type"] === "integer") {
142
+ if (typeof value !== "number" || !Number.isInteger(value))
143
+ return "`" + key + "` must be an integer";
144
+ const min = rule["minimum"];
145
+ const max = rule["maximum"];
146
+ if (typeof min === "number" && value < min)
147
+ return "`" + key + "` is below " + String(min);
148
+ if (typeof max === "number" && value > max)
149
+ return "`" + key + "` is above " + String(max);
150
+ }
151
+ }
152
+ return null;
153
+ }
154
+ function str(args, name, max) {
155
+ const value = args[name];
156
+ if (typeof value !== "string" || value.length === 0 || value.length > max)
157
+ return null;
158
+ return value;
159
+ }
160
+ const TOOLS = [
161
+ {
162
+ name: 'get_project_context', description: 'Read bounded source excerpts or advisory static import impact in an admitted project. Falls back to text search without an index.',
163
+ inputSchema: { type: 'object', properties: { repo: { type: 'string', minLength: 1, maxLength: 4096 }, query: { type: 'string', minLength: 1, maxLength: 1000 }, mode: { type: 'string', enum: ['search', 'impact'] } }, required: ['repo', 'query'], additionalProperties: false },
164
+ handle: (ctx, args) => {
165
+ const repo = String(args['repo']);
166
+ if (!ctx.who.repos.includes(repo) || ctx.enrolled !== null && !ctx.enrolled.includes(repo))
167
+ return { ok: false, message: 'That project is outside your access.' };
168
+ return { ok: true, body: repositoryContextRead({ repo, query: String(args['query']), mode: args['mode'] === 'impact' ? 'impact' : 'search', audience: 'lead',
169
+ ...(ctx.evidenceRoot === undefined ? {} : { cacheRoot: join(dirname(ctx.evidenceRoot), 'repository-context') }) }) };
170
+ },
171
+ },
172
+ ...ASSIGNMENT_TOOLS.map(spec => ({
173
+ name: spec.name, description: spec.description, inputSchema: spec.inputSchema,
174
+ handle: (ctx, args) => {
175
+ const result = assignmentForCoordinator(ctx.store, ctx.token, spec.operation, args, ctx.now, ctx.evidenceRoot);
176
+ return result.ok ? { ok: true, body: result.body } : { ok: false, message: `${result.reason}: ${result.message}` };
177
+ },
178
+ })),
179
+ {
180
+ name: "status",
181
+ description: "The plane's liveness facts over your repo allowlist: what waits on the operator, what runs, what finished in the last 24h.",
182
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
183
+ handle: ctx => ({ ok: true, body: statusFor(ctx.store, ctx.who, ctx.now) }),
184
+ },
185
+ {
186
+ name: "list_tasks",
187
+ description: "Tasks in your repo allowlist. Filter by state and repo; cursor-paginated, stable order.",
188
+ inputSchema: {
189
+ type: "object",
190
+ properties: {
191
+ state: { type: "string", enum: ["queued", "running", "done", "failed", "cancelled"] },
192
+ repo: { type: "string", maxLength: 800 },
193
+ cursor: { type: "integer", minimum: 0 },
194
+ limit: { type: "integer", minimum: 1, maximum: 50 },
195
+ },
196
+ additionalProperties: false,
197
+ },
198
+ handle: (ctx, args) => {
199
+ const filter = {};
200
+ if (typeof args["state"] === "string")
201
+ filter.state = args["state"];
202
+ if (typeof args["repo"] === "string")
203
+ filter.repo = args["repo"];
204
+ if (typeof args["cursor"] === "number")
205
+ filter.cursor = args["cursor"];
206
+ if (typeof args["limit"] === "number")
207
+ filter.limit = args["limit"];
208
+ return { ok: true, body: listTasksFor(ctx.store, ctx.who, filter, ctx.now) };
209
+ },
210
+ },
211
+ {
212
+ name: "get_task",
213
+ description: "One task's deliverable (branch or report), scope standing, filer provenance, attempt ledger, and — for a finished scout — the report's title, summary, and follow-ups. A ref outside your allowlist answers not-found.",
214
+ inputSchema: {
215
+ type: "object",
216
+ properties: { ref: { type: "string", minLength: 1, maxLength: 64 } },
217
+ required: ["ref"],
218
+ additionalProperties: false,
219
+ },
220
+ handle: (ctx, args) => {
221
+ const ref = str(args, "ref", 64);
222
+ if (ref === null)
223
+ return { ok: false, message: "ref is a task id, 1-64 characters" };
224
+ const detail = taskDetailFor(ctx.store, ctx.who, ref, ctx.evidenceRoot, ctx.now);
225
+ if (detail === null)
226
+ return { ok: false, message: `not-found: no task \`${ref}\` in your repositories` };
227
+ return { ok: true, body: detail };
228
+ },
229
+ },
230
+ {
231
+ name: "list_repos",
232
+ description: "The repositories your credential may see and file into, with their operating-mode standing.",
233
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
234
+ handle: ctx => {
235
+ // FAIL CLOSED when the project registry cannot be read (round-2
236
+ // finding 4): answering the full allowlist would claim enrollment
237
+ // nobody proved.
238
+ if (ctx.enrolled === null) {
239
+ return { ok: false, message: "the project registry could not be read — the enrolled set is unknown, so nothing lists" };
240
+ }
241
+ return {
242
+ ok: true,
243
+ body: {
244
+ repos: ctx.who.repos
245
+ .filter(repo => ctx.enrolled !== null && ctx.enrolled.includes(repo))
246
+ .map(repo => {
247
+ const mode = ctx.store.activeMode(repo, ctx.now);
248
+ return { repo, mode: mode === null ? "no operating mode — every act is a ceremony" : `mode ${mode.name} signed until ${mode.absoluteExpiry}` };
249
+ }),
250
+ },
251
+ };
252
+ },
253
+ },
254
+ {
255
+ name: "recap",
256
+ description: "How things stand per repository in your allowlist, counts and ids: what waits on the operator (decisions, incidents, scopes awaiting approval), what runs, what is queued, finished, failed. Pass `since` (an ISO timestamp) to count only decisions, incidents, and attempts newer than it, to the hour; queued work and scopes awaiting approval always count.",
257
+ inputSchema: { type: "object", properties: { since: { type: "string", maxLength: 30 } }, additionalProperties: false },
258
+ handle: (ctx, args) => {
259
+ const since = args["since"];
260
+ if (since !== undefined && (typeof since !== "string" || !ISO_STAMP_RULE.test(since) || Number.isNaN(Date.parse(since)))) {
261
+ return { ok: false, message: "since is an ISO timestamp like 2026-09-02T12:00:00Z" };
262
+ }
263
+ return { ok: true, body: labelRepos(recapOver(ctx.store, ctx.who.repos, ctx.now, typeof since === "string" ? since : null), index => ctx.who.repos[index] ?? "") };
264
+ },
265
+ },
266
+ {
267
+ name: "list_decisions",
268
+ description: "Open decisions in your allowlist: id, task, question, options (id, label, reversible), age in hours. Never consequences or recommendations; the operator answers them.",
269
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
270
+ handle: ctx => ({ ok: true, body: labelRepos(decisionsOver(ctx.store, ctx.who.repos, ctx.now), index => ctx.who.repos[index] ?? "") }),
271
+ },
272
+ {
273
+ name: "queue",
274
+ description: "One repository's queue by column — the shared column, then each worker's reserved column — each in dispatch order.",
275
+ inputSchema: { type: "object", properties: { repo: { type: "string", minLength: 1, maxLength: 800 } }, required: ["repo"], additionalProperties: false },
276
+ handle: (ctx, args) => {
277
+ const repo = str(args, "repo", 800);
278
+ if (repo === null || !ctx.who.repos.includes(repo))
279
+ return { ok: false, message: "not-found: that repository is not in your allowlist" };
280
+ // The installation-wide revision stays home (slice-2 review, finding
281
+ // 12): a coordinator cannot move queues, and the counter would tell it
282
+ // about repos it may not see.
283
+ const { queueRevision: _revision, ...columns } = queueOver(ctx.store, repo, ctx.now);
284
+ return { ok: true, body: { repo, ...columns } };
285
+ },
286
+ },
287
+ {
288
+ name: "get_decision",
289
+ description: "One open decision in your allowlist in full: question, options with id, label, reversible, and consequence. Never the builder's recommendation.",
290
+ inputSchema: { type: "object", properties: { decision: { type: "integer", minimum: 1 } }, required: ["decision"], additionalProperties: false },
291
+ handle: (ctx, args) => {
292
+ const found = decisionOver(ctx.store, ctx.who.repos, Number(args["decision"]), ctx.now);
293
+ if (found === null)
294
+ return { ok: false, message: "not-found: no such decision in your repositories" };
295
+ ctx.readDecisions.add(Number(args["decision"]));
296
+ return { ok: true, body: labelRepos(found, index => ctx.who.repos[index] ?? "") };
297
+ },
298
+ },
299
+ ...proposeTools(),
300
+ {
301
+ name: "get_contract",
302
+ description: "This surface's contract: what a coordinator may do, the proposal lifecycle, and the admission promise.",
303
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
304
+ handle: () => ({ ok: true, body: { contract: CONTRACT_GUIDE } }),
305
+ },
306
+ {
307
+ name: "file_proposal",
308
+ description: "File a task proposal into one of your repositories. It stays quarantined until the operator signs its scope.",
309
+ inputSchema: {
310
+ type: "object",
311
+ properties: {
312
+ repo: { type: "string", minLength: 1, maxLength: 800 },
313
+ title: { type: "string", minLength: 1, maxLength: 200 },
314
+ intent: TASK_SCOPE_TEXT_SCHEMA,
315
+ idempotency_key: { type: "string", minLength: 8, maxLength: 64 },
316
+ deliverable: { type: "string", enum: ["branch", "report"] },
317
+ },
318
+ required: ["repo", "title", "idempotency_key"],
319
+ additionalProperties: false,
320
+ },
321
+ handle: (ctx, args) => {
322
+ const repo = str(args, "repo", 800);
323
+ const title = str(args, "title", 200);
324
+ const key = str(args, "idempotency_key", 64);
325
+ const intent = typeof args["intent"] === "string" ? args["intent"] : undefined;
326
+ const deliverable = args["deliverable"] === "report" ? "report" : args["deliverable"] === "branch" ? "branch" : undefined;
327
+ if (repo === null || title === null || key === null) {
328
+ return { ok: false, message: "file_proposal needs repo, title, and idempotency_key (8-64 chars)" };
329
+ }
330
+ // The token, not the pre-verified identity: filing re-authenticates
331
+ // INSIDE its own transaction (the session's `who` is a courtesy).
332
+ const outcome = fileCoordinatorProposal(ctx.store, ctx.token, { repo, title, ...(intent === undefined ? {} : { intent }), ...(deliverable === undefined ? {} : { deliverable }), idempotencyKey: key }, ctx.now);
333
+ if (!outcome.ok)
334
+ return { ok: false, message: outcome.message };
335
+ return {
336
+ ok: true,
337
+ body: {
338
+ ref: outcome.id,
339
+ replayed: outcome.replayed,
340
+ admission: "quarantined until the operator signs its scope — the ceremony shows them your name",
341
+ },
342
+ };
343
+ },
344
+ },
345
+ ];
346
+ /** The propose_* tools: each writes one proposal row through the coordinator door. */
347
+ function proposeTools() {
348
+ const ref = { type: "string", minLength: 1, maxLength: 64 };
349
+ const make = (kind, description, properties, required) => ({
350
+ name: `propose_${kind}`,
351
+ description,
352
+ inputSchema: { type: "object", properties, required, additionalProperties: false },
353
+ handle: (ctx, args) => {
354
+ const outcome = proposeAsCoordinator(ctx.store, ctx.token, kind, args, ctx.now, { readDecisions: ctx.readDecisions });
355
+ if (!outcome.ok)
356
+ return { ok: false, message: outcome.message };
357
+ return { ok: true, body: { proposal: outcome.id, kind: outcome.kind, awaiting: outcome.awaiting } };
358
+ },
359
+ });
360
+ return [
361
+ make("next", "Propose moving a queued task to the front of its column. An approver confirms; a queue that moved meanwhile refuses.", { ref }, ["ref"]),
362
+ make("reserve", "Propose reserving a queued task for one worker, or releasing it to the shared queue with worker null.", { ref, worker: { type: ["string", "null"], maxLength: 60 } }, ["ref", "worker"]),
363
+ make("hold", "Propose holding a task's next attempt, with a reason. A running attempt is never interrupted.", { ref, reason: { type: "string", maxLength: 200 } }, ["ref", "reason"]),
364
+ make("unhold", "Propose lifting the operator's own hold on a task.", { ref }, ["ref"]),
365
+ make("scope", "Propose rewriting a task's scope. An approver confirms the rewrite, then approves it with a password — a scope you wrote never seals under a mode.", { ref, goal: TASK_SCOPE_TEXT_SCHEMA, not: TASK_SCOPE_TEXT_SCHEMA, touches: { type: "array", items: { type: "string", maxLength: 200 }, maxItems: 50 } }, ["ref", "goal"]),
366
+ make("cancel", "Propose cancelling a task, with a reason. The approver arms and confirms it on the task itself.", { ref, reason: { type: "string", maxLength: 200 } }, ["ref", "reason"]),
367
+ make("answer", "Propose an answer to an open decision you read with get_decision, with a rationale. The approver confirms where every consequence and the builder's recommendation are shown; an irreversible option needs their explicit confirmation.", { decision: { type: "integer", minimum: 1 }, option: { type: "string", minLength: 1, maxLength: 64 }, rationale: { type: "string", maxLength: 400 } }, ["decision", "option", "rationale"]),
368
+ ];
369
+ }
370
+ /** Serve until EOF. The store is already open through the non-migrating
371
+ * door; the token was startup-verified by the caller (and dies here again
372
+ * if it does not hold). */
373
+ export function serveMcp(store, token, io, clock = () => new Date(), enrolled = null, evidenceRoot) {
374
+ /** Per connection: which decisions this credential read in full (v3). */
375
+ const readDecisions = new Set();
376
+ const auth = authenticateCoordinator(store, token);
377
+ if (!auth.ok) {
378
+ return {
379
+ ok: false,
380
+ reason: auth.reason === "revoked" || auth.reason === "expired" ? "revoked" : "unauthenticated",
381
+ message: auth.reason === "revoked" ? "this coordinator credential was revoked — mint a new one"
382
+ : auth.reason === "expired" ? "this coordinator credential expired — mint a new one"
383
+ : "no live coordinator credential matches this token",
384
+ };
385
+ }
386
+ // Cancellation semantics on a SERIAL server (round-2 finding 2, stated
387
+ // rather than pretended): every request completes before the next line
388
+ // is read, so no cancellation can arrive while its target is genuinely
389
+ // in flight — and the revision permits ignoring cancellations for
390
+ // completed requests. The registry exists so any future asynchronous
391
+ // tool inherits correct suppression, and so a pre-cancelled FUTURE id
392
+ // can never be blacklisted (the in-flight check).
393
+ const cancelled = new Set();
394
+ const inFlight = new Set();
395
+ // Legacy lifecycle state (review finding 2): initialize must come first
396
+ // in the handshake era; the modern era is stateless by design.
397
+ let initializeSeen = false;
398
+ let legacyReady = false;
399
+ // Stdio pins ONE era per connection (round-2 finding 2): the first
400
+ // era-classified request decides, and the other era's metadata refuses.
401
+ let pinnedEra = null;
402
+ const error = (id, code, message) => io.write(JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } }));
403
+ const respond = (id, era, result, cacheable) => {
404
+ if (id !== null && cancelled.has(JSON.stringify(id)))
405
+ return; // suppressed entirely
406
+ const complete = era === "modern"
407
+ ? { ...result, resultType: "complete", ...(cacheable ? { ttlMs: 0, cacheScope: "private" } : {}) }
408
+ : result;
409
+ io.write(JSON.stringify({ jsonrpc: "2.0", id, result: complete }));
410
+ };
411
+ const toolsPayload = () => ({
412
+ // No outputSchema: MCP output schemas describe structuredContent, and
413
+ // these tools return text content only (round-2 finding 1).
414
+ tools: TOOLS.map(tool => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema })),
415
+ });
416
+ const callTool = (id, era, params) => {
417
+ // ONE snapshot per call (review finding 3): the version check, the
418
+ // credential re-read, and every data read share a transaction, so a
419
+ // concurrent migration cannot slip between them; filing's own
420
+ // BEGIN IMMEDIATE reenters this one. A moved schema refuses in words
421
+ // and the server exits clean.
422
+ store.transact(() => {
423
+ if (!store.schemaCurrent()) {
424
+ error(id, -32000, "the database schema moved underneath this server — restart it");
425
+ io.exit(0);
426
+ return;
427
+ }
428
+ const name = typeof params["name"] === "string" ? params["name"] : "";
429
+ const tool = TOOLS.find(one => one.name === name);
430
+ if (tool === undefined) {
431
+ error(id, -32602, `no tool \`${name}\``);
432
+ return;
433
+ }
434
+ // tools/list visibility is presentation — authorization happens HERE,
435
+ // on every call, against the live credential row.
436
+ const session = authenticateCoordinator(store, token);
437
+ if (!session.ok) {
438
+ error(id, -32000, "this credential no longer stands — the server exits");
439
+ io.exit(0);
440
+ return;
441
+ }
442
+ // Only an ABSENT `arguments` defaults to empty (round-3 finding 2): an
443
+ // explicit null is not the optional-object shape MCP defines.
444
+ const rawArgs = params["arguments"] === undefined ? {} : params["arguments"];
445
+ if (typeof rawArgs !== "object" || rawArgs === null || Array.isArray(rawArgs)) {
446
+ // The root of `arguments` is an object BEFORE any schema applies
447
+ // (round-2 finding 2): 42 or false never passes an empty schema.
448
+ error(id, -32602, "arguments must be an object");
449
+ return;
450
+ }
451
+ const args = rawArgs;
452
+ const invalid = invalidArgs(tool.inputSchema, args);
453
+ if (invalid !== null) {
454
+ error(id, -32602, invalid);
455
+ return;
456
+ }
457
+ const answered = tool.handle({ store, who: session.who, token, enrolled, now: clock(), readDecisions, ...(evidenceRoot === undefined ? {} : { evidenceRoot }) }, args);
458
+ if (!answered.ok) {
459
+ respond(id, era, { content: [{ type: "text", text: answered.message }], isError: true }, false);
460
+ return;
461
+ }
462
+ respond(id, era, { content: [{ type: "text", text: JSON.stringify(answered.body) }] }, false);
463
+ });
464
+ };
465
+ io.onLine(line => {
466
+ if (line.trim() === "")
467
+ return;
468
+ if (Buffer.byteLength(line, "utf8") > MAX_REQUEST) {
469
+ error(null, -32600, "request over 256 KiB");
470
+ return;
471
+ }
472
+ let message;
473
+ try {
474
+ message = JSON.parse(line);
475
+ }
476
+ catch {
477
+ error(null, -32700, "parse error");
478
+ return;
479
+ }
480
+ if (Array.isArray(message)) {
481
+ // Batching left MCP in 2025-06-18 — neither pinned era accepts it.
482
+ error(null, -32600, "JSON-RPC batching is not part of MCP — send one request per line");
483
+ return;
484
+ }
485
+ if (message === null || typeof message !== "object" || depthOf(message) > MAX_DEPTH) {
486
+ error(null, -32600, "invalid request");
487
+ return;
488
+ }
489
+ const request = message;
490
+ if (request["jsonrpc"] !== "2.0") {
491
+ error(null, -32600, 'jsonrpc must be "2.0"');
492
+ return;
493
+ }
494
+ // A notification is the message that carries NO id — the method name
495
+ // never decides (round-3 finding 3): notifications/initialized WITH an
496
+ // id is a malformed message, not a quiet notification. MCP RequestId is
497
+ // a string or an INTEGER (round-2 finding 2): floats, null, and object
498
+ // shapes refuse wherever an id appears.
499
+ const hasId = "id" in request;
500
+ const rawId = request["id"];
501
+ if (hasId && (rawId === null || (typeof rawId !== "string" && !(typeof rawId === "number" && Number.isInteger(rawId))))) {
502
+ error(null, -32600, "id must be a string or an integer");
503
+ return;
504
+ }
505
+ const method = typeof request["method"] === "string" ? request["method"] : "";
506
+ if (method.startsWith("notifications/")) {
507
+ if (hasId) {
508
+ error(rawId, -32600, "a notification carries no id");
509
+ return;
510
+ }
511
+ }
512
+ else if (!hasId) {
513
+ error(null, -32600, "a request carries an id — a string or an integer");
514
+ return;
515
+ }
516
+ const id = (rawId ?? null);
517
+ const params = (request["params"] ?? {});
518
+ const meta = (params["_meta"] ?? {});
519
+ // Every method — lifecycle included — refuses on a moved schema
520
+ // (review finding 3): a server that answers discover from one world
521
+ // and tools from another is lying to somebody.
522
+ if (!store.schemaCurrent()) {
523
+ error(id, -32000, "the database schema moved underneath this server — restart it");
524
+ io.exit(0);
525
+ return;
526
+ }
527
+ if (method === "notifications/cancelled") {
528
+ // Cancellation touches IN-FLIGHT work only (review finding 2): an id
529
+ // never seen, already answered, or yet to arrive is not cancellable —
530
+ // pre-cancelling the future would let a peer suppress request ids
531
+ // forever.
532
+ const target = params["requestId"];
533
+ if (target !== undefined && inFlight.has(JSON.stringify(target))) {
534
+ cancelled.add(JSON.stringify(target));
535
+ }
536
+ return; // a notification — no reply of any kind
537
+ }
538
+ if (method === "notifications/initialized") {
539
+ // Only a handshake that actually happened completes (round-2 f2).
540
+ if (initializeSeen)
541
+ legacyReady = true;
542
+ return;
543
+ }
544
+ if (method.startsWith("notifications/"))
545
+ return; // unknown notification: silence, never an error
546
+ // An unsupported protocol version refuses -32022 with the revision's
547
+ // OWN shape for EVERY request — server/discover included (round-3
548
+ // finding 4): the ask precedes any per-method branch.
549
+ const declared = typeof meta[META_VERSION] === "string" ? meta[META_VERSION] : null;
550
+ if (declared !== null && declared !== MODERN && declared !== LEGACY) {
551
+ io.write(JSON.stringify({
552
+ jsonrpc: "2.0",
553
+ id,
554
+ error: {
555
+ code: UNSUPPORTED_VERSION,
556
+ message: `unsupported protocol version \`${declared}\``,
557
+ data: { supported: [MODERN, LEGACY], requested: declared },
558
+ },
559
+ }));
560
+ return;
561
+ }
562
+ // ClientCapabilities is an OBJECT shape (round-3 finding 5): an array
563
+ // is not a capabilities declaration.
564
+ const capabilitiesShape = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
565
+ if (method === "initialize") {
566
+ if (pinnedEra === "modern") {
567
+ error(id, -32600, "this connection speaks the modern era — initialize belongs to the handshake era");
568
+ return;
569
+ }
570
+ pinnedEra = "legacy";
571
+ initializeSeen = true;
572
+ // The handshake era can only negotiate ITSELF: an unsupported ask is
573
+ // answered WITH the legacy version, never the modern one.
574
+ respond(id, "legacy", {
575
+ protocolVersion: LEGACY,
576
+ capabilities: { tools: {} },
577
+ serverInfo: { name: "toolroll", version: PACKAGE_VERSION },
578
+ }, false);
579
+ return;
580
+ }
581
+ if (method === "server/discover") {
582
+ if (pinnedEra === "legacy") {
583
+ error(id, -32600, "this connection speaks the handshake era — server/discover belongs to the modern one");
584
+ return;
585
+ }
586
+ if (declared !== MODERN || !capabilitiesShape(meta[META_CAPABILITIES])) {
587
+ // The modern era's requests carry BOTH namespaced keys (round-2
588
+ // finding 1) — a bare discover is not a modern request.
589
+ error(id, -32600, `server/discover requires _meta["${META_VERSION}"] = "${MODERN}" and _meta["${META_CAPABILITIES}"]`);
590
+ return;
591
+ }
592
+ pinnedEra = "modern";
593
+ respond(id, "modern", {
594
+ protocolVersion: MODERN,
595
+ supportedVersions: [MODERN, LEGACY],
596
+ capabilities: { tools: {} },
597
+ _meta: { [META_SERVER]: { name: "toolroll", version: PACKAGE_VERSION } },
598
+ ...toolsPayload(),
599
+ }, true);
600
+ return;
601
+ }
602
+ // Era classification precedes every remaining method — ping and unknown
603
+ // methods included (round-3 finding 1): a refused modern ping still pins
604
+ // the modern era, and a cross-era unknown method refuses on the pin
605
+ // instead of slipping past it.
606
+ const era = declared === MODERN ? "modern" : "legacy";
607
+ if (era === "modern" && !capabilitiesShape(meta[META_CAPABILITIES])) {
608
+ error(id, -32600, `a ${MODERN} request carries _meta["${META_CAPABILITIES}"]`);
609
+ return;
610
+ }
611
+ if (pinnedEra !== null && era !== pinnedEra) {
612
+ error(id, -32600, `this connection is pinned to the ${pinnedEra} era`);
613
+ return;
614
+ }
615
+ pinnedEra = era;
616
+ if (method === "ping") {
617
+ // ping left the protocol in 2026-07-28 — only the handshake era has it.
618
+ if (era === "modern") {
619
+ error(id, -32601, "ping is not part of the modern revision");
620
+ return;
621
+ }
622
+ respond(id, "legacy", {}, false);
623
+ return;
624
+ }
625
+ // The handshake era operates only after its lifecycle completed; the
626
+ // modern era is stateless and needs no handshake.
627
+ if (era === "legacy" && !legacyReady && (method === "tools/list" || method === "tools/call")) {
628
+ error(id, -32002, "not initialized — the handshake era requires initialize and notifications/initialized first");
629
+ return;
630
+ }
631
+ if (method === "tools/list") {
632
+ respond(id, era, toolsPayload(), true);
633
+ return;
634
+ }
635
+ if (method === "tools/call") {
636
+ const key = JSON.stringify(id);
637
+ inFlight.add(key);
638
+ try {
639
+ callTool(id, era, params);
640
+ }
641
+ finally {
642
+ inFlight.delete(key);
643
+ cancelled.delete(key);
644
+ }
645
+ return;
646
+ }
647
+ error(id, -32601, `unknown method \`${method}\``);
648
+ });
649
+ io.onEof(() => io.exit(0));
650
+ return { ok: true };
651
+ }