@intentic/sandbox-contract 1.247.0 → 1.249.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 (883) hide show
  1. package/README.md +18 -15
  2. package/dist/chores/chores.d.ts.map +1 -1
  3. package/dist/chores/chores.js.map +1 -1
  4. package/dist/chores/digest.d.ts.map +1 -1
  5. package/dist/chores/digest.js.map +1 -1
  6. package/dist/chores/extension-update.d.ts.map +1 -1
  7. package/dist/chores/extension-update.js.map +1 -1
  8. package/dist/chores/fix-deps.d.ts.map +1 -1
  9. package/dist/chores/fix-deps.js.map +1 -1
  10. package/dist/chores/index.d.ts +2 -2
  11. package/dist/chores/index.d.ts.map +1 -1
  12. package/dist/chores/index.js +1 -1
  13. package/dist/chores/index.js.map +1 -1
  14. package/dist/chores/probes.d.ts.map +1 -1
  15. package/dist/chores/probes.js.map +1 -1
  16. package/dist/chores/prompt.d.ts.map +1 -1
  17. package/dist/chores/prompt.js.map +1 -1
  18. package/dist/chores/stack.d.ts.map +1 -1
  19. package/dist/chores/stack.js.map +1 -1
  20. package/dist/chores/verdict.d.ts +7 -1
  21. package/dist/chores/verdict.d.ts.map +1 -1
  22. package/dist/chores/verdict.js +8 -0
  23. package/dist/chores/verdict.js.map +1 -1
  24. package/dist/contracts/accounts.contract.d.ts.map +1 -1
  25. package/dist/contracts/accounts.contract.js.map +1 -1
  26. package/dist/contracts/activity.contract.d.ts +1 -0
  27. package/dist/contracts/activity.contract.d.ts.map +1 -1
  28. package/dist/contracts/agent.contract.d.ts +13 -205
  29. package/dist/contracts/agent.contract.d.ts.map +1 -1
  30. package/dist/contracts/agent.contract.js +2 -1
  31. package/dist/contracts/agent.contract.js.map +1 -1
  32. package/dist/contracts/agents.contract.d.ts +228 -54
  33. package/dist/contracts/agents.contract.d.ts.map +1 -1
  34. package/dist/contracts/agents.contract.js +11 -2
  35. package/dist/contracts/agents.contract.js.map +1 -1
  36. package/dist/contracts/automations.contract.d.ts +35 -17
  37. package/dist/contracts/automations.contract.d.ts.map +1 -1
  38. package/dist/contracts/automations.contract.js +10 -1
  39. package/dist/contracts/automations.contract.js.map +1 -1
  40. package/dist/contracts/capabilities.contract.d.ts +0 -12
  41. package/dist/contracts/capabilities.contract.d.ts.map +1 -1
  42. package/dist/contracts/capabilities.contract.js +1 -1
  43. package/dist/contracts/capabilities.contract.js.map +1 -1
  44. package/dist/contracts/chores.contract.d.ts.map +1 -1
  45. package/dist/contracts/chores.contract.js.map +1 -1
  46. package/dist/contracts/ci.contract.d.ts +9 -0
  47. package/dist/contracts/ci.contract.d.ts.map +1 -1
  48. package/dist/contracts/endpoints.contract.d.ts.map +1 -1
  49. package/dist/contracts/endpoints.contract.js.map +1 -1
  50. package/dist/contracts/exit.contract.d.ts.map +1 -1
  51. package/dist/contracts/exit.contract.js +1 -1
  52. package/dist/contracts/exit.contract.js.map +1 -1
  53. package/dist/contracts/extensions.contract.d.ts.map +1 -1
  54. package/dist/contracts/extensions.contract.js.map +1 -1
  55. package/dist/contracts/git.contract.d.ts +45 -6
  56. package/dist/contracts/git.contract.d.ts.map +1 -1
  57. package/dist/contracts/git.contract.js +9 -9
  58. package/dist/contracts/git.contract.js.map +1 -1
  59. package/dist/contracts/host.contract.d.ts +2 -0
  60. package/dist/contracts/host.contract.d.ts.map +1 -1
  61. package/dist/contracts/host.contract.js.map +1 -1
  62. package/dist/contracts/intentic.contract.js +1 -1
  63. package/dist/contracts/intentic.contract.js.map +1 -1
  64. package/dist/contracts/logs.contract.d.ts.map +1 -1
  65. package/dist/contracts/logs.contract.js.map +1 -1
  66. package/dist/contracts/loops.contract.d.ts.map +1 -1
  67. package/dist/contracts/loops.contract.js.map +1 -1
  68. package/dist/contracts/personas.contract.d.ts +39 -4
  69. package/dist/contracts/personas.contract.d.ts.map +1 -1
  70. package/dist/contracts/personas.contract.js +10 -1
  71. package/dist/contracts/personas.contract.js.map +1 -1
  72. package/dist/contracts/providers.contract.d.ts.map +1 -1
  73. package/dist/contracts/providers.contract.js.map +1 -1
  74. package/dist/contracts/runner.contract.d.ts +6 -80
  75. package/dist/contracts/runner.contract.d.ts.map +1 -1
  76. package/dist/contracts/runner.contract.js +2 -2
  77. package/dist/contracts/runner.contract.js.map +1 -1
  78. package/dist/contracts/safety.contract.d.ts.map +1 -1
  79. package/dist/contracts/safety.contract.js +1 -1
  80. package/dist/contracts/safety.contract.js.map +1 -1
  81. package/dist/contracts/secrets.contract.d.ts.map +1 -1
  82. package/dist/contracts/secrets.contract.js.map +1 -1
  83. package/dist/contracts/sessions.contract.d.ts +2 -41
  84. package/dist/contracts/sessions.contract.d.ts.map +1 -1
  85. package/dist/contracts/sessions.contract.js +1 -1
  86. package/dist/contracts/sessions.contract.js.map +1 -1
  87. package/dist/contracts/settings.contract.d.ts +10 -10
  88. package/dist/contracts/settings.contract.d.ts.map +1 -1
  89. package/dist/contracts/settings.contract.js.map +1 -1
  90. package/dist/contracts/share.contract.d.ts.map +1 -1
  91. package/dist/contracts/share.contract.js.map +1 -1
  92. package/dist/contracts/skills.contract.d.ts.map +1 -1
  93. package/dist/contracts/skills.contract.js.map +1 -1
  94. package/dist/contracts/system.contract.d.ts +49 -73
  95. package/dist/contracts/system.contract.d.ts.map +1 -1
  96. package/dist/contracts/system.contract.js +12 -2
  97. package/dist/contracts/system.contract.js.map +1 -1
  98. package/dist/contracts/usage.contract.d.ts.map +1 -1
  99. package/dist/contracts/usage.contract.js.map +1 -1
  100. package/dist/contracts/vpn.contract.d.ts.map +1 -1
  101. package/dist/contracts/vpn.contract.js +1 -1
  102. package/dist/contracts/vpn.contract.js.map +1 -1
  103. package/dist/contracts/webext.contract.d.ts.map +1 -1
  104. package/dist/contracts/webext.contract.js.map +1 -1
  105. package/dist/contracts/workflows.contract.d.ts +7 -6
  106. package/dist/contracts/workflows.contract.d.ts.map +1 -1
  107. package/dist/contracts/workflows.contract.js +12 -3
  108. package/dist/contracts/workflows.contract.js.map +1 -1
  109. package/dist/contracts/workspace.contract.d.ts.map +1 -1
  110. package/dist/contracts/workspace.contract.js.map +1 -1
  111. package/dist/events/agent-events.d.ts +1237 -0
  112. package/dist/events/agent-events.d.ts.map +1 -0
  113. package/dist/events/agent-events.js +226 -0
  114. package/dist/events/agent-events.js.map +1 -0
  115. package/dist/events/cards.d.ts +404 -0
  116. package/dist/events/cards.d.ts.map +1 -0
  117. package/dist/events/cards.js +179 -0
  118. package/dist/events/cards.js.map +1 -0
  119. package/dist/events/resume.d.ts +23 -0
  120. package/dist/events/resume.d.ts.map +1 -0
  121. package/dist/events/resume.js +31 -0
  122. package/dist/events/resume.js.map +1 -0
  123. package/dist/events/system-events.d.ts +615 -0
  124. package/dist/events/system-events.d.ts.map +1 -0
  125. package/dist/events/system-events.js +64 -0
  126. package/dist/events/system-events.js.map +1 -0
  127. package/dist/events/transcript.d.ts +1755 -0
  128. package/dist/events/transcript.d.ts.map +1 -0
  129. package/dist/events/transcript.js +205 -0
  130. package/dist/events/transcript.js.map +1 -0
  131. package/dist/ids/conversation-ids.d.ts +8 -0
  132. package/dist/ids/conversation-ids.d.ts.map +1 -0
  133. package/dist/{conversation-ids.js → ids/conversation-ids.js} +13 -0
  134. package/dist/ids/conversation-ids.js.map +1 -0
  135. package/dist/ids/hostnames.d.ts.map +1 -0
  136. package/dist/ids/hostnames.js.map +1 -0
  137. package/dist/ids/session-names.d.ts.map +1 -0
  138. package/dist/ids/session-names.js.map +1 -0
  139. package/dist/ids/share-paths.d.ts.map +1 -0
  140. package/dist/ids/share-paths.js.map +1 -0
  141. package/dist/{tunnel-ids.d.ts → ids/tunnel-ids.d.ts} +1 -0
  142. package/dist/ids/tunnel-ids.d.ts.map +1 -0
  143. package/dist/{tunnel-ids.js → ids/tunnel-ids.js} +1 -0
  144. package/dist/ids/tunnel-ids.js.map +1 -0
  145. package/dist/index.d.ts +464 -447
  146. package/dist/index.d.ts.map +1 -1
  147. package/dist/index.js +54 -47
  148. package/dist/index.js.map +1 -1
  149. package/dist/{agent-catalog.d.ts → models/agent-catalog.d.ts} +2 -2
  150. package/dist/models/agent-catalog.d.ts.map +1 -0
  151. package/dist/models/agent-catalog.js.map +1 -0
  152. package/dist/models/agent-runtimes.d.ts.map +1 -0
  153. package/dist/models/agent-runtimes.js.map +1 -0
  154. package/dist/{fast-tier.d.ts → models/fast-tier.d.ts} +1 -1
  155. package/dist/models/fast-tier.d.ts.map +1 -0
  156. package/dist/models/fast-tier.js.map +1 -0
  157. package/dist/models/model-order.d.ts.map +1 -0
  158. package/dist/models/model-order.js.map +1 -0
  159. package/dist/{model-pins.d.ts → models/model-pins.d.ts} +2 -4
  160. package/dist/models/model-pins.d.ts.map +1 -0
  161. package/dist/models/model-pins.js +22 -0
  162. package/dist/models/model-pins.js.map +1 -0
  163. package/dist/{model-roles.d.ts → models/model-roles.d.ts} +25 -30
  164. package/dist/models/model-roles.d.ts.map +1 -0
  165. package/dist/{model-roles.js → models/model-roles.js} +30 -27
  166. package/dist/models/model-roles.js.map +1 -0
  167. package/dist/{plan-pools.d.ts → models/plan-pools.d.ts} +1 -1
  168. package/dist/models/plan-pools.d.ts.map +1 -0
  169. package/dist/models/plan-pools.js.map +1 -0
  170. package/dist/models/prompt-complexity.d.ts.map +1 -0
  171. package/dist/models/prompt-complexity.js.map +1 -0
  172. package/dist/models/provider-specs.d.ts.map +1 -0
  173. package/dist/models/provider-specs.js.map +1 -0
  174. package/dist/policy/approvals-execution.d.ts.map +1 -0
  175. package/dist/policy/approvals-execution.js.map +1 -0
  176. package/dist/{batch-runs.d.ts → policy/batch-runs.d.ts} +5 -1
  177. package/dist/policy/batch-runs.d.ts.map +1 -0
  178. package/dist/{batch-runs.js → policy/batch-runs.js} +10 -7
  179. package/dist/policy/batch-runs.js.map +1 -0
  180. package/dist/policy/capability-env.d.ts.map +1 -0
  181. package/dist/policy/capability-env.js.map +1 -0
  182. package/dist/policy/capability-secrets.d.ts.map +1 -0
  183. package/dist/policy/capability-secrets.js.map +1 -0
  184. package/dist/{card-status.d.ts → policy/card-status.d.ts} +2 -2
  185. package/dist/policy/card-status.d.ts.map +1 -0
  186. package/dist/{card-status.js → policy/card-status.js} +1 -5
  187. package/dist/policy/card-status.js.map +1 -0
  188. package/dist/{command-classes.d.ts → policy/command-classes.d.ts} +6 -2
  189. package/dist/policy/command-classes.d.ts.map +1 -0
  190. package/dist/{command-classes.js → policy/command-classes.js} +48 -11
  191. package/dist/policy/command-classes.js.map +1 -0
  192. package/dist/{command-run.d.ts → policy/command-run.d.ts} +1 -1
  193. package/dist/policy/command-run.d.ts.map +1 -0
  194. package/dist/policy/command-run.js.map +1 -0
  195. package/dist/policy/control-scopes.d.ts +16 -0
  196. package/dist/policy/control-scopes.d.ts.map +1 -0
  197. package/dist/policy/control-scopes.js +26 -0
  198. package/dist/policy/control-scopes.js.map +1 -0
  199. package/dist/policy/credential-material.d.ts.map +1 -0
  200. package/dist/policy/credential-material.js.map +1 -0
  201. package/dist/policy/needs-action.d.ts.map +1 -0
  202. package/dist/policy/needs-action.js.map +1 -0
  203. package/dist/policy/output-fields.d.ts.map +1 -0
  204. package/dist/policy/output-fields.js.map +1 -0
  205. package/dist/policy/overlay-lint.d.ts.map +1 -0
  206. package/dist/policy/overlay-lint.js.map +1 -0
  207. package/dist/policy/owner-ticket.d.ts.map +1 -0
  208. package/dist/{owner-ticket.js → policy/owner-ticket.js} +1 -1
  209. package/dist/policy/owner-ticket.js.map +1 -0
  210. package/dist/{safety-policy.d.ts → policy/safety-policy.d.ts} +6 -5
  211. package/dist/policy/safety-policy.d.ts.map +1 -0
  212. package/dist/{safety-policy.js → policy/safety-policy.js} +12 -12
  213. package/dist/policy/safety-policy.js.map +1 -0
  214. package/dist/policy/search-globs.d.ts.map +1 -0
  215. package/dist/policy/search-globs.js.map +1 -0
  216. package/dist/protocol/container-requirements.d.ts +20 -0
  217. package/dist/protocol/container-requirements.d.ts.map +1 -0
  218. package/dist/protocol/container-requirements.js +23 -0
  219. package/dist/protocol/container-requirements.js.map +1 -0
  220. package/dist/{host-protocol.d.ts → protocol/host-protocol.d.ts} +1 -0
  221. package/dist/protocol/host-protocol.d.ts.map +1 -0
  222. package/dist/{host-protocol.js → protocol/host-protocol.js} +1 -0
  223. package/dist/protocol/host-protocol.js.map +1 -0
  224. package/dist/protocol/ingress-contract.d.ts.map +1 -0
  225. package/dist/{ingress-contract.js → protocol/ingress-contract.js} +1 -1
  226. package/dist/protocol/ingress-contract.js.map +1 -0
  227. package/dist/protocol/ingress-protocol.d.ts.map +1 -0
  228. package/dist/protocol/ingress-protocol.js.map +1 -0
  229. package/dist/protocol/listener-protocol.d.ts.map +1 -0
  230. package/dist/{listener-protocol.js → protocol/listener-protocol.js} +1 -1
  231. package/dist/protocol/listener-protocol.js.map +1 -0
  232. package/dist/{peer-dial.d.ts → protocol/peer-dial.d.ts} +4 -1
  233. package/dist/protocol/peer-dial.d.ts.map +1 -0
  234. package/dist/{peer-dial.js → protocol/peer-dial.js} +51 -10
  235. package/dist/protocol/peer-dial.js.map +1 -0
  236. package/dist/protocol/peer-mcp-server.d.ts.map +1 -0
  237. package/dist/protocol/peer-mcp-server.js.map +1 -0
  238. package/dist/protocol/request-id.d.ts.map +1 -0
  239. package/dist/protocol/request-id.js.map +1 -0
  240. package/dist/protocol/routes.d.ts.map +1 -0
  241. package/dist/protocol/routes.js.map +1 -0
  242. package/dist/{runner-protocol.d.ts → protocol/runner-protocol.d.ts} +1 -0
  243. package/dist/protocol/runner-protocol.d.ts.map +1 -0
  244. package/dist/{runner-protocol.js → protocol/runner-protocol.js} +2 -1
  245. package/dist/protocol/runner-protocol.js.map +1 -0
  246. package/dist/protocol/sse.d.ts.map +1 -0
  247. package/dist/protocol/sse.js.map +1 -0
  248. package/dist/{terminal-protocol.d.ts → protocol/terminal-protocol.d.ts} +1 -3
  249. package/dist/protocol/terminal-protocol.d.ts.map +1 -0
  250. package/dist/protocol/terminal-protocol.js.map +1 -0
  251. package/dist/protocol/webext-links.d.ts.map +1 -0
  252. package/dist/protocol/webext-links.js.map +1 -0
  253. package/dist/{webext-protocol.d.ts → protocol/webext-protocol.d.ts} +1 -0
  254. package/dist/protocol/webext-protocol.d.ts.map +1 -0
  255. package/dist/{webext-protocol.js → protocol/webext-protocol.js} +1 -0
  256. package/dist/protocol/webext-protocol.js.map +1 -0
  257. package/dist/schemas/activity.d.ts +2 -0
  258. package/dist/schemas/activity.d.ts.map +1 -1
  259. package/dist/schemas/activity.js +4 -0
  260. package/dist/schemas/activity.js.map +1 -1
  261. package/dist/schemas/agent.d.ts +17 -4
  262. package/dist/schemas/agent.d.ts.map +1 -1
  263. package/dist/schemas/agent.js +21 -4
  264. package/dist/schemas/agent.js.map +1 -1
  265. package/dist/schemas/agents.d.ts +17 -4
  266. package/dist/schemas/agents.d.ts.map +1 -1
  267. package/dist/schemas/agents.js +15 -4
  268. package/dist/schemas/agents.js.map +1 -1
  269. package/dist/schemas/approvals.d.ts.map +1 -1
  270. package/dist/schemas/approvals.js.map +1 -1
  271. package/dist/schemas/automations.d.ts +54 -28
  272. package/dist/schemas/automations.d.ts.map +1 -1
  273. package/dist/schemas/automations.js +26 -8
  274. package/dist/schemas/automations.js.map +1 -1
  275. package/dist/schemas/capabilities.d.ts +0 -8
  276. package/dist/schemas/capabilities.d.ts.map +1 -1
  277. package/dist/schemas/capabilities.js +0 -4
  278. package/dist/schemas/capabilities.js.map +1 -1
  279. package/dist/schemas/ci.d.ts +10 -0
  280. package/dist/schemas/ci.d.ts.map +1 -1
  281. package/dist/schemas/ci.js +9 -1
  282. package/dist/schemas/ci.js.map +1 -1
  283. package/dist/schemas/codebase-health.d.ts.map +1 -1
  284. package/dist/schemas/codebase-health.js.map +1 -1
  285. package/dist/schemas/devices.d.ts +90 -0
  286. package/dist/schemas/devices.d.ts.map +1 -1
  287. package/dist/schemas/devices.js +10 -1
  288. package/dist/schemas/devices.js.map +1 -1
  289. package/dist/schemas/engines.d.ts.map +1 -1
  290. package/dist/schemas/engines.js.map +1 -1
  291. package/dist/schemas/environment.d.ts.map +1 -1
  292. package/dist/schemas/environment.js.map +1 -1
  293. package/dist/schemas/exit.d.ts.map +1 -1
  294. package/dist/schemas/exit.js.map +1 -1
  295. package/dist/schemas/extension-updates.d.ts.map +1 -1
  296. package/dist/schemas/extension-updates.js.map +1 -1
  297. package/dist/schemas/git-history.d.ts.map +1 -1
  298. package/dist/schemas/git-history.js.map +1 -1
  299. package/dist/schemas/git.d.ts +80 -16
  300. package/dist/schemas/git.d.ts.map +1 -1
  301. package/dist/schemas/git.js +37 -25
  302. package/dist/schemas/git.js.map +1 -1
  303. package/dist/schemas/history.d.ts.map +1 -1
  304. package/dist/schemas/history.js.map +1 -1
  305. package/dist/schemas/hosts.d.ts.map +1 -1
  306. package/dist/schemas/hosts.js.map +1 -1
  307. package/dist/schemas/inventory.d.ts.map +1 -1
  308. package/dist/schemas/inventory.js.map +1 -1
  309. package/dist/schemas/issues.d.ts +0 -1
  310. package/dist/schemas/issues.d.ts.map +1 -1
  311. package/dist/schemas/issues.js +0 -1
  312. package/dist/schemas/issues.js.map +1 -1
  313. package/dist/schemas/logs.d.ts.map +1 -1
  314. package/dist/schemas/logs.js.map +1 -1
  315. package/dist/schemas/loops.d.ts.map +1 -1
  316. package/dist/schemas/loops.js +1 -1
  317. package/dist/schemas/loops.js.map +1 -1
  318. package/dist/schemas/maintenance.d.ts.map +1 -1
  319. package/dist/schemas/maintenance.js.map +1 -1
  320. package/dist/schemas/marketplace.d.ts +0 -4
  321. package/dist/schemas/marketplace.d.ts.map +1 -1
  322. package/dist/schemas/panels.d.ts.map +1 -1
  323. package/dist/schemas/panels.js.map +1 -1
  324. package/dist/schemas/personas.d.ts +49 -4
  325. package/dist/schemas/personas.d.ts.map +1 -1
  326. package/dist/schemas/personas.js +32 -5
  327. package/dist/schemas/personas.js.map +1 -1
  328. package/dist/schemas/plan-limits.d.ts +2 -4
  329. package/dist/schemas/plan-limits.d.ts.map +1 -1
  330. package/dist/schemas/plan-limits.js +5 -8
  331. package/dist/schemas/plan-limits.js.map +1 -1
  332. package/dist/schemas/ports.d.ts.map +1 -1
  333. package/dist/schemas/ports.js.map +1 -1
  334. package/dist/schemas/provider-oauth.d.ts.map +1 -1
  335. package/dist/schemas/provider-oauth.js.map +1 -1
  336. package/dist/schemas/provider-subscriptions.d.ts +1 -1
  337. package/dist/schemas/provider-subscriptions.d.ts.map +1 -1
  338. package/dist/schemas/provider-subscriptions.js +1 -1
  339. package/dist/schemas/provider-subscriptions.js.map +1 -1
  340. package/dist/schemas/public.d.ts.map +1 -1
  341. package/dist/schemas/public.js.map +1 -1
  342. package/dist/schemas/push.d.ts.map +1 -1
  343. package/dist/schemas/push.js.map +1 -1
  344. package/dist/schemas/secrets.d.ts.map +1 -1
  345. package/dist/schemas/secrets.js.map +1 -1
  346. package/dist/schemas/settings.d.ts +7 -5
  347. package/dist/schemas/settings.d.ts.map +1 -1
  348. package/dist/schemas/settings.js +18 -8
  349. package/dist/schemas/settings.js.map +1 -1
  350. package/dist/schemas/share.d.ts.map +1 -1
  351. package/dist/schemas/share.js.map +1 -1
  352. package/dist/schemas/shared.d.ts +4 -0
  353. package/dist/schemas/shared.d.ts.map +1 -1
  354. package/dist/schemas/shared.js +3 -0
  355. package/dist/schemas/shared.js.map +1 -1
  356. package/dist/schemas/system.d.ts +6 -0
  357. package/dist/schemas/system.d.ts.map +1 -1
  358. package/dist/schemas/system.js +10 -0
  359. package/dist/schemas/system.js.map +1 -1
  360. package/dist/schemas/terminal.d.ts.map +1 -1
  361. package/dist/schemas/terminal.js.map +1 -1
  362. package/dist/schemas/usage.d.ts.map +1 -1
  363. package/dist/schemas/usage.js.map +1 -1
  364. package/dist/schemas/vpn.d.ts.map +1 -1
  365. package/dist/schemas/vpn.js.map +1 -1
  366. package/dist/schemas/webext.d.ts.map +1 -1
  367. package/dist/schemas/webext.js.map +1 -1
  368. package/dist/schemas/workflows.d.ts +66 -9
  369. package/dist/schemas/workflows.d.ts.map +1 -1
  370. package/dist/schemas/workflows.js +6 -5
  371. package/dist/schemas/workflows.js.map +1 -1
  372. package/dist/schemas/workspace-repos.d.ts.map +1 -1
  373. package/dist/schemas/workspace-repos.js.map +1 -1
  374. package/dist/schemas/workspace-search.d.ts.map +1 -1
  375. package/dist/schemas/workspace-search.js.map +1 -1
  376. package/dist/schemas/workspace-setup.d.ts.map +1 -1
  377. package/dist/schemas/workspace-setup.js.map +1 -1
  378. package/dist/schemas/workspace-tree.d.ts.map +1 -1
  379. package/dist/schemas/workspace-tree.js.map +1 -1
  380. package/dist/state/arrival.d.ts.map +1 -0
  381. package/dist/{arrival.js → state/arrival.js} +1 -1
  382. package/dist/state/arrival.js.map +1 -0
  383. package/dist/state/contract-lock.d.ts.map +1 -0
  384. package/dist/{contract-lock.js → state/contract-lock.js} +1 -1
  385. package/dist/state/contract-lock.js.map +1 -0
  386. package/dist/{definition.d.ts → state/definition.d.ts} +21 -17
  387. package/dist/state/definition.d.ts.map +1 -0
  388. package/dist/{definition.js → state/definition.js} +4 -4
  389. package/dist/state/definition.js.map +1 -0
  390. package/dist/state/history-state.d.ts.map +1 -0
  391. package/dist/{history-state.js → state/history-state.js} +1 -0
  392. package/dist/state/history-state.js.map +1 -0
  393. package/dist/state/runtime-state.d.ts.map +1 -0
  394. package/dist/state/runtime-state.js.map +1 -0
  395. package/dist/state/starter.d.ts.map +1 -0
  396. package/dist/state/starter.js.map +1 -0
  397. package/dist/state/state-portability.d.ts.map +1 -0
  398. package/dist/state/state-portability.js.map +1 -0
  399. package/dist/state/versions.d.ts.map +1 -0
  400. package/dist/state/versions.js.map +1 -0
  401. package/dist/{workspace-state.d.ts → state/workspace-state.d.ts} +8 -5
  402. package/dist/state/workspace-state.d.ts.map +1 -0
  403. package/dist/{workspace-state.js → state/workspace-state.js} +25 -1
  404. package/dist/state/workspace-state.js.map +1 -0
  405. package/dist/{documents.d.ts → text/documents.d.ts} +1 -1
  406. package/dist/text/documents.d.ts.map +1 -0
  407. package/dist/{documents.js → text/documents.js} +1 -1
  408. package/dist/text/documents.js.map +1 -0
  409. package/dist/text/embed.d.ts.map +1 -0
  410. package/dist/text/embed.js.map +1 -0
  411. package/dist/text/mentions.d.ts.map +1 -0
  412. package/dist/text/mentions.js.map +1 -0
  413. package/dist/text/model-answer.d.ts +3 -0
  414. package/dist/text/model-answer.d.ts.map +1 -0
  415. package/dist/text/model-answer.js +3 -0
  416. package/dist/text/model-answer.js.map +1 -0
  417. package/dist/text/path-refs.d.ts.map +1 -0
  418. package/dist/text/path-refs.js.map +1 -0
  419. package/dist/{shell-regions.d.ts → text/shell-regions.d.ts} +1 -1
  420. package/dist/text/shell-regions.d.ts.map +1 -0
  421. package/dist/text/shell-regions.js.map +1 -0
  422. package/dist/text/title.d.ts.map +1 -0
  423. package/dist/text/title.js.map +1 -0
  424. package/dist/{transcript-fold.d.ts → text/transcript-fold.d.ts} +2 -1
  425. package/dist/text/transcript-fold.d.ts.map +1 -0
  426. package/dist/{transcript-fold.js → text/transcript-fold.js} +2 -16
  427. package/dist/text/transcript-fold.js.map +1 -0
  428. package/dist/text/whisper.d.ts +3 -0
  429. package/dist/text/whisper.d.ts.map +1 -0
  430. package/dist/text/whisper.js +11 -0
  431. package/dist/text/whisper.js.map +1 -0
  432. package/dist/{workflow-faults.d.ts → text/workflow-faults.d.ts} +1 -1
  433. package/dist/text/workflow-faults.d.ts.map +1 -0
  434. package/dist/{workflow-faults.js → text/workflow-faults.js} +1 -1
  435. package/dist/text/workflow-faults.js.map +1 -0
  436. package/package.json +70 -70
  437. package/src/chores/chores.test.ts +4 -10
  438. package/src/chores/chores.ts +148 -392
  439. package/src/chores/digest.ts +8 -28
  440. package/src/chores/extension-update.ts +3 -8
  441. package/src/chores/fix-deps.ts +4 -18
  442. package/src/chores/index.ts +2 -2
  443. package/src/chores/probes.test.ts +7 -43
  444. package/src/chores/probes.ts +62 -167
  445. package/src/chores/prompt.ts +10 -34
  446. package/src/chores/stack.test.ts +6 -45
  447. package/src/chores/stack.ts +27 -118
  448. package/src/chores/verdict.test.ts +101 -80
  449. package/src/chores/verdict.ts +54 -99
  450. package/src/contracts/accounts.contract.ts +4 -19
  451. package/src/contracts/agent.contract.ts +7 -22
  452. package/src/contracts/agents.contract.ts +25 -71
  453. package/src/contracts/automations.contract.ts +14 -30
  454. package/src/contracts/capabilities.contract.ts +8 -35
  455. package/src/contracts/chores.contract.ts +4 -15
  456. package/src/contracts/endpoints.contract.ts +5 -22
  457. package/src/contracts/exit.contract.ts +7 -30
  458. package/src/contracts/extensions.contract.ts +8 -30
  459. package/src/contracts/git.contract.ts +25 -49
  460. package/src/contracts/host.contract.ts +9 -44
  461. package/src/contracts/intentic.contract.ts +1 -1
  462. package/src/contracts/logs.contract.ts +3 -13
  463. package/src/contracts/loops.contract.ts +9 -40
  464. package/src/contracts/personas.contract.ts +22 -30
  465. package/src/contracts/providers.contract.ts +4 -17
  466. package/src/contracts/runner.contract.ts +12 -39
  467. package/src/contracts/safety.contract.ts +5 -14
  468. package/src/contracts/secrets.contract.ts +4 -22
  469. package/src/contracts/sessions.contract.ts +1 -1
  470. package/src/contracts/settings.contract.ts +4 -10
  471. package/src/contracts/share.contract.ts +3 -9
  472. package/src/contracts/skills.contract.ts +4 -15
  473. package/src/contracts/system.contract.ts +26 -52
  474. package/src/contracts/usage.contract.ts +7 -21
  475. package/src/contracts/vpn.contract.ts +9 -16
  476. package/src/contracts/webext.contract.ts +9 -25
  477. package/src/contracts/workflows.contract.ts +34 -58
  478. package/src/contracts/workspace.contract.ts +19 -50
  479. package/src/events/agent-events.ts +345 -0
  480. package/src/events/cards.ts +286 -0
  481. package/src/{events.test.ts → events/resume.test.ts} +4 -19
  482. package/src/events/resume.ts +60 -0
  483. package/src/events/system-events.ts +139 -0
  484. package/src/events/transcript.ts +320 -0
  485. package/src/{conversation-ids.test.ts → ids/conversation-ids.test.ts} +25 -13
  486. package/src/ids/conversation-ids.ts +178 -0
  487. package/src/ids/hostnames.ts +129 -0
  488. package/src/ids/session-names.ts +29 -0
  489. package/src/ids/share-paths.ts +43 -0
  490. package/src/{tunnel-ids.test.ts → ids/tunnel-ids.test.ts} +1 -14
  491. package/src/ids/tunnel-ids.ts +29 -0
  492. package/src/index.ts +71 -88
  493. package/src/{agent-catalog.test.ts → models/agent-catalog.test.ts} +19 -93
  494. package/src/models/agent-catalog.ts +174 -0
  495. package/src/models/agent-runtimes.ts +201 -0
  496. package/src/models/capability-ledger.test.ts +84 -0
  497. package/src/{fast-tier.test.ts → models/fast-tier.test.ts} +7 -18
  498. package/src/models/fast-tier.ts +36 -0
  499. package/src/{model-order.test.ts → models/model-order.test.ts} +19 -40
  500. package/src/models/model-order.ts +163 -0
  501. package/src/models/model-pins.test.ts +87 -0
  502. package/src/models/model-pins.ts +57 -0
  503. package/src/models/model-roles.test.ts +38 -0
  504. package/src/models/model-roles.ts +180 -0
  505. package/src/{plan-pools.test.ts → models/plan-pools.test.ts} +6 -11
  506. package/src/models/plan-pools.ts +65 -0
  507. package/src/{prompt-complexity.test.ts → models/prompt-complexity.test.ts} +8 -60
  508. package/src/models/prompt-complexity.ts +215 -0
  509. package/src/{provider-specs.test.ts → models/provider-specs.test.ts} +18 -47
  510. package/src/models/provider-specs.ts +272 -0
  511. package/src/policy/approvals-execution.ts +58 -0
  512. package/src/{batch-runs.test.ts → policy/batch-runs.test.ts} +4 -20
  513. package/src/policy/batch-runs.ts +137 -0
  514. package/src/policy/capability-secrets.ts +5 -0
  515. package/src/{card-status.ts → policy/card-status.ts} +11 -26
  516. package/src/{command-classes.test.ts → policy/command-classes.test.ts} +11 -118
  517. package/src/policy/command-classes.ts +395 -0
  518. package/src/policy/command-run.ts +65 -0
  519. package/src/policy/control-scopes.ts +38 -0
  520. package/src/{credential-material.test.ts → policy/credential-material.test.ts} +4 -26
  521. package/src/policy/credential-material.ts +91 -0
  522. package/src/policy/needs-action.ts +5 -0
  523. package/src/policy/output-fields.ts +86 -0
  524. package/src/policy/overlay-lint.ts +100 -0
  525. package/src/{owner-ticket.test.ts → policy/owner-ticket.test.ts} +1 -1
  526. package/src/{owner-ticket.ts → policy/owner-ticket.ts} +9 -31
  527. package/src/policy/safety-policy.test.ts +84 -0
  528. package/src/policy/safety-policy.ts +142 -0
  529. package/src/policy/search-globs.ts +60 -0
  530. package/src/protocol/container-requirements.test.ts +72 -0
  531. package/src/protocol/container-requirements.ts +58 -0
  532. package/src/protocol/host-protocol.ts +29 -0
  533. package/src/protocol/ingress-contract.ts +103 -0
  534. package/src/{ingress-protocol.test.ts → protocol/ingress-protocol.test.ts} +25 -90
  535. package/src/protocol/ingress-protocol.ts +441 -0
  536. package/src/protocol/listener-protocol.ts +75 -0
  537. package/src/{peer-dial.test.ts → protocol/peer-dial.test.ts} +52 -1
  538. package/src/protocol/peer-dial.ts +207 -0
  539. package/src/{peer-mcp-server.ts → protocol/peer-mcp-server.ts} +16 -41
  540. package/src/protocol/request-id.ts +5 -0
  541. package/src/{routes.test.ts → protocol/routes.test.ts} +14 -22
  542. package/src/protocol/routes.ts +159 -0
  543. package/src/protocol/runner-protocol.ts +197 -0
  544. package/src/protocol/terminal-protocol.ts +13 -0
  545. package/src/protocol/webext-links.ts +50 -0
  546. package/src/protocol/webext-protocol.ts +24 -0
  547. package/src/schemas/activity.ts +22 -30
  548. package/src/schemas/agent.ts +130 -238
  549. package/src/schemas/agents.ts +165 -483
  550. package/src/schemas/approvals.ts +23 -71
  551. package/src/schemas/automations.ts +145 -249
  552. package/src/schemas/capabilities.ts +127 -414
  553. package/src/schemas/ci.ts +56 -108
  554. package/src/schemas/codebase-health.ts +7 -11
  555. package/src/schemas/devices.ts +98 -321
  556. package/src/schemas/engines.ts +16 -44
  557. package/src/schemas/environment.ts +41 -91
  558. package/src/schemas/exit.ts +24 -81
  559. package/src/schemas/extension-updates.ts +42 -87
  560. package/src/schemas/git-history.ts +30 -84
  561. package/src/schemas/git.ts +141 -256
  562. package/src/schemas/history.ts +14 -40
  563. package/src/schemas/hosts.ts +9 -15
  564. package/src/schemas/inventory.ts +8 -10
  565. package/src/schemas/issues.ts +66 -134
  566. package/src/schemas/logs.ts +15 -34
  567. package/src/schemas/loops.ts +46 -163
  568. package/src/schemas/maintenance.ts +47 -172
  569. package/src/schemas/panels.ts +20 -45
  570. package/src/schemas/personas.ts +85 -168
  571. package/src/schemas/plan-limits.ts +58 -197
  572. package/src/schemas/ports.ts +14 -32
  573. package/src/schemas/provider-oauth.ts +23 -76
  574. package/src/schemas/provider-subscriptions.ts +4 -13
  575. package/src/schemas/public.ts +4 -15
  576. package/src/schemas/push.ts +8 -36
  577. package/src/schemas/secrets.ts +20 -64
  578. package/src/schemas/settings.ts +177 -597
  579. package/src/schemas/share.ts +14 -32
  580. package/src/schemas/shared.ts +14 -13
  581. package/src/schemas/system.ts +46 -78
  582. package/src/schemas/terminal.ts +41 -120
  583. package/src/schemas/usage.ts +44 -233
  584. package/src/schemas/version-seam.test.ts +9 -26
  585. package/src/schemas/vpn.ts +27 -64
  586. package/src/schemas/webext.ts +22 -53
  587. package/src/schemas/workflows.ts +57 -183
  588. package/src/schemas/workspace-repos.ts +12 -24
  589. package/src/schemas/workspace-search.ts +17 -35
  590. package/src/schemas/workspace-setup.ts +4 -11
  591. package/src/schemas/workspace-tree.ts +32 -91
  592. package/src/state/arrival.ts +109 -0
  593. package/src/state/contract-lock.test.ts +17 -0
  594. package/src/state/contract-lock.ts +49 -0
  595. package/src/state/definition.ts +143 -0
  596. package/src/state/history-state.ts +103 -0
  597. package/src/{runtime-state.test.ts → state/runtime-state.test.ts} +3 -10
  598. package/src/state/runtime-state.ts +62 -0
  599. package/src/state/starter.ts +5 -0
  600. package/src/state/state-portability.ts +27 -0
  601. package/src/state/versions.ts +26 -0
  602. package/src/{workspace-state.test.ts → state/workspace-state.test.ts} +65 -173
  603. package/src/state/workspace-state.ts +669 -0
  604. package/src/{documents.test.ts → text/documents.test.ts} +1 -1
  605. package/src/text/documents.ts +42 -0
  606. package/src/text/embed.ts +132 -0
  607. package/src/text/mentions.ts +21 -0
  608. package/src/text/model-answer.ts +9 -0
  609. package/src/text/path-refs.ts +39 -0
  610. package/src/text/shell-regions.ts +224 -0
  611. package/src/{title.test.ts → text/title.test.ts} +13 -32
  612. package/src/text/title.ts +202 -0
  613. package/src/{transcript-fold.test.ts → text/transcript-fold.test.ts} +5 -83
  614. package/src/{transcript-fold.ts → text/transcript-fold.ts} +65 -170
  615. package/src/text/whisper.test.ts +19 -0
  616. package/src/text/whisper.ts +17 -0
  617. package/src/{workflow-faults.test.ts → text/workflow-faults.test.ts} +6 -24
  618. package/src/{workflow-faults.ts → text/workflow-faults.ts} +20 -60
  619. package/dist/agent-catalog.d.ts.map +0 -1
  620. package/dist/agent-catalog.js.map +0 -1
  621. package/dist/agent-runtimes.d.ts.map +0 -1
  622. package/dist/agent-runtimes.js.map +0 -1
  623. package/dist/approvals-execution.d.ts.map +0 -1
  624. package/dist/approvals-execution.js.map +0 -1
  625. package/dist/arrival.d.ts.map +0 -1
  626. package/dist/arrival.js.map +0 -1
  627. package/dist/batch-runs.d.ts.map +0 -1
  628. package/dist/batch-runs.js.map +0 -1
  629. package/dist/capability-env.d.ts.map +0 -1
  630. package/dist/capability-env.js.map +0 -1
  631. package/dist/capability-secrets.d.ts.map +0 -1
  632. package/dist/capability-secrets.js.map +0 -1
  633. package/dist/card-status.d.ts.map +0 -1
  634. package/dist/card-status.js.map +0 -1
  635. package/dist/command-classes.d.ts.map +0 -1
  636. package/dist/command-classes.js.map +0 -1
  637. package/dist/command-run.d.ts.map +0 -1
  638. package/dist/command-run.js.map +0 -1
  639. package/dist/contract-lock.d.ts.map +0 -1
  640. package/dist/contract-lock.js.map +0 -1
  641. package/dist/conversation-ids.d.ts +0 -4
  642. package/dist/conversation-ids.d.ts.map +0 -1
  643. package/dist/conversation-ids.js.map +0 -1
  644. package/dist/credential-material.d.ts.map +0 -1
  645. package/dist/credential-material.js.map +0 -1
  646. package/dist/definition.d.ts.map +0 -1
  647. package/dist/definition.js.map +0 -1
  648. package/dist/documents.d.ts.map +0 -1
  649. package/dist/documents.js.map +0 -1
  650. package/dist/embed.d.ts.map +0 -1
  651. package/dist/embed.js.map +0 -1
  652. package/dist/events.d.ts +0 -4336
  653. package/dist/events.d.ts.map +0 -1
  654. package/dist/events.js +0 -725
  655. package/dist/events.js.map +0 -1
  656. package/dist/fast-tier.d.ts.map +0 -1
  657. package/dist/fast-tier.js.map +0 -1
  658. package/dist/history-state.d.ts.map +0 -1
  659. package/dist/history-state.js.map +0 -1
  660. package/dist/host-protocol.d.ts.map +0 -1
  661. package/dist/host-protocol.js.map +0 -1
  662. package/dist/hostnames.d.ts.map +0 -1
  663. package/dist/hostnames.js.map +0 -1
  664. package/dist/ingress-contract.d.ts.map +0 -1
  665. package/dist/ingress-contract.js.map +0 -1
  666. package/dist/ingress-protocol.d.ts.map +0 -1
  667. package/dist/ingress-protocol.js.map +0 -1
  668. package/dist/listener-protocol.d.ts.map +0 -1
  669. package/dist/listener-protocol.js.map +0 -1
  670. package/dist/mentions.d.ts.map +0 -1
  671. package/dist/mentions.js.map +0 -1
  672. package/dist/model-order.d.ts.map +0 -1
  673. package/dist/model-order.js.map +0 -1
  674. package/dist/model-pins.d.ts.map +0 -1
  675. package/dist/model-pins.js +0 -45
  676. package/dist/model-pins.js.map +0 -1
  677. package/dist/model-roles.d.ts.map +0 -1
  678. package/dist/model-roles.js.map +0 -1
  679. package/dist/needs-action.d.ts.map +0 -1
  680. package/dist/needs-action.js.map +0 -1
  681. package/dist/output-fields.d.ts.map +0 -1
  682. package/dist/output-fields.js.map +0 -1
  683. package/dist/overlay-lint.d.ts.map +0 -1
  684. package/dist/overlay-lint.js.map +0 -1
  685. package/dist/owner-ticket.d.ts.map +0 -1
  686. package/dist/owner-ticket.js.map +0 -1
  687. package/dist/path-refs.d.ts.map +0 -1
  688. package/dist/path-refs.js.map +0 -1
  689. package/dist/peer-dial.d.ts.map +0 -1
  690. package/dist/peer-dial.js.map +0 -1
  691. package/dist/peer-mcp-server.d.ts.map +0 -1
  692. package/dist/peer-mcp-server.js.map +0 -1
  693. package/dist/plan-pools.d.ts.map +0 -1
  694. package/dist/plan-pools.js.map +0 -1
  695. package/dist/prompt-complexity.d.ts.map +0 -1
  696. package/dist/prompt-complexity.js.map +0 -1
  697. package/dist/provider-specs.d.ts.map +0 -1
  698. package/dist/provider-specs.js.map +0 -1
  699. package/dist/request-id.d.ts.map +0 -1
  700. package/dist/request-id.js.map +0 -1
  701. package/dist/routes.d.ts.map +0 -1
  702. package/dist/routes.js.map +0 -1
  703. package/dist/runner-protocol.d.ts.map +0 -1
  704. package/dist/runner-protocol.js.map +0 -1
  705. package/dist/runtime-state.d.ts.map +0 -1
  706. package/dist/runtime-state.js.map +0 -1
  707. package/dist/safety-policy.d.ts.map +0 -1
  708. package/dist/safety-policy.js.map +0 -1
  709. package/dist/schemas/context.d.ts +0 -30
  710. package/dist/schemas/context.d.ts.map +0 -1
  711. package/dist/schemas/context.js +0 -34
  712. package/dist/schemas/context.js.map +0 -1
  713. package/dist/search-globs.d.ts.map +0 -1
  714. package/dist/search-globs.js.map +0 -1
  715. package/dist/session-names.d.ts.map +0 -1
  716. package/dist/session-names.js.map +0 -1
  717. package/dist/share-paths.d.ts.map +0 -1
  718. package/dist/share-paths.js.map +0 -1
  719. package/dist/shell-regions.d.ts.map +0 -1
  720. package/dist/shell-regions.js.map +0 -1
  721. package/dist/sse.d.ts.map +0 -1
  722. package/dist/sse.js.map +0 -1
  723. package/dist/starter.d.ts.map +0 -1
  724. package/dist/starter.js.map +0 -1
  725. package/dist/state-portability.d.ts.map +0 -1
  726. package/dist/state-portability.js.map +0 -1
  727. package/dist/terminal-protocol.d.ts.map +0 -1
  728. package/dist/terminal-protocol.js.map +0 -1
  729. package/dist/title.d.ts.map +0 -1
  730. package/dist/title.js.map +0 -1
  731. package/dist/transcript-fold.d.ts.map +0 -1
  732. package/dist/transcript-fold.js.map +0 -1
  733. package/dist/tunnel-ids.d.ts.map +0 -1
  734. package/dist/tunnel-ids.js.map +0 -1
  735. package/dist/versions.d.ts.map +0 -1
  736. package/dist/versions.js.map +0 -1
  737. package/dist/webext-links.d.ts.map +0 -1
  738. package/dist/webext-links.js.map +0 -1
  739. package/dist/webext-protocol.d.ts.map +0 -1
  740. package/dist/webext-protocol.js.map +0 -1
  741. package/dist/workflow-faults.d.ts.map +0 -1
  742. package/dist/workflow-faults.js.map +0 -1
  743. package/dist/workspace-state.d.ts.map +0 -1
  744. package/dist/workspace-state.js.map +0 -1
  745. package/src/agent-catalog.ts +0 -316
  746. package/src/agent-runtimes.ts +0 -419
  747. package/src/approvals-execution.ts +0 -96
  748. package/src/arrival.ts +0 -160
  749. package/src/batch-runs.ts +0 -188
  750. package/src/capability-ledger.test.ts +0 -140
  751. package/src/capability-secrets.ts +0 -20
  752. package/src/command-classes.ts +0 -617
  753. package/src/command-run.ts +0 -78
  754. package/src/contract-lock.test.ts +0 -23
  755. package/src/contract-lock.ts +0 -66
  756. package/src/conversation-ids.ts +0 -207
  757. package/src/credential-material.ts +0 -181
  758. package/src/definition.ts +0 -207
  759. package/src/documents.ts +0 -67
  760. package/src/embed.ts +0 -164
  761. package/src/events.ts +0 -1870
  762. package/src/fast-tier.ts +0 -72
  763. package/src/history-state.ts +0 -174
  764. package/src/host-protocol.ts +0 -36
  765. package/src/hostnames.ts +0 -180
  766. package/src/ingress-contract.ts +0 -157
  767. package/src/ingress-protocol.ts +0 -625
  768. package/src/listener-protocol.ts +0 -96
  769. package/src/mentions.ts +0 -25
  770. package/src/model-order.ts +0 -262
  771. package/src/model-pins.test.ts +0 -202
  772. package/src/model-pins.ts +0 -183
  773. package/src/model-roles.ts +0 -224
  774. package/src/needs-action.ts +0 -14
  775. package/src/output-fields.ts +0 -111
  776. package/src/overlay-lint.ts +0 -116
  777. package/src/path-refs.ts +0 -59
  778. package/src/peer-dial.ts +0 -163
  779. package/src/plan-pools.ts +0 -92
  780. package/src/prompt-complexity.ts +0 -334
  781. package/src/provider-specs.ts +0 -432
  782. package/src/request-id.ts +0 -41
  783. package/src/routes.ts +0 -219
  784. package/src/runner-protocol.ts +0 -239
  785. package/src/runtime-state.ts +0 -140
  786. package/src/safety-policy.test.ts +0 -88
  787. package/src/safety-policy.ts +0 -258
  788. package/src/schemas/context.ts +0 -87
  789. package/src/search-globs.ts +0 -76
  790. package/src/session-names.ts +0 -44
  791. package/src/share-paths.ts +0 -68
  792. package/src/shell-regions.ts +0 -289
  793. package/src/starter.ts +0 -13
  794. package/src/state-portability.ts +0 -56
  795. package/src/terminal-protocol.ts +0 -16
  796. package/src/title.ts +0 -267
  797. package/src/tunnel-ids.ts +0 -57
  798. package/src/versions.ts +0 -48
  799. package/src/webext-links.ts +0 -90
  800. package/src/webext-protocol.ts +0 -27
  801. package/src/workspace-state.ts +0 -1096
  802. /package/dist/{hostnames.d.ts → ids/hostnames.d.ts} +0 -0
  803. /package/dist/{hostnames.js → ids/hostnames.js} +0 -0
  804. /package/dist/{session-names.d.ts → ids/session-names.d.ts} +0 -0
  805. /package/dist/{session-names.js → ids/session-names.js} +0 -0
  806. /package/dist/{share-paths.d.ts → ids/share-paths.d.ts} +0 -0
  807. /package/dist/{share-paths.js → ids/share-paths.js} +0 -0
  808. /package/dist/{agent-catalog.js → models/agent-catalog.js} +0 -0
  809. /package/dist/{agent-runtimes.d.ts → models/agent-runtimes.d.ts} +0 -0
  810. /package/dist/{agent-runtimes.js → models/agent-runtimes.js} +0 -0
  811. /package/dist/{fast-tier.js → models/fast-tier.js} +0 -0
  812. /package/dist/{model-order.d.ts → models/model-order.d.ts} +0 -0
  813. /package/dist/{model-order.js → models/model-order.js} +0 -0
  814. /package/dist/{plan-pools.js → models/plan-pools.js} +0 -0
  815. /package/dist/{prompt-complexity.d.ts → models/prompt-complexity.d.ts} +0 -0
  816. /package/dist/{prompt-complexity.js → models/prompt-complexity.js} +0 -0
  817. /package/dist/{provider-specs.d.ts → models/provider-specs.d.ts} +0 -0
  818. /package/dist/{provider-specs.js → models/provider-specs.js} +0 -0
  819. /package/dist/{approvals-execution.d.ts → policy/approvals-execution.d.ts} +0 -0
  820. /package/dist/{approvals-execution.js → policy/approvals-execution.js} +0 -0
  821. /package/dist/{capability-env.d.ts → policy/capability-env.d.ts} +0 -0
  822. /package/dist/{capability-env.js → policy/capability-env.js} +0 -0
  823. /package/dist/{capability-secrets.d.ts → policy/capability-secrets.d.ts} +0 -0
  824. /package/dist/{capability-secrets.js → policy/capability-secrets.js} +0 -0
  825. /package/dist/{command-run.js → policy/command-run.js} +0 -0
  826. /package/dist/{credential-material.d.ts → policy/credential-material.d.ts} +0 -0
  827. /package/dist/{credential-material.js → policy/credential-material.js} +0 -0
  828. /package/dist/{needs-action.d.ts → policy/needs-action.d.ts} +0 -0
  829. /package/dist/{needs-action.js → policy/needs-action.js} +0 -0
  830. /package/dist/{output-fields.d.ts → policy/output-fields.d.ts} +0 -0
  831. /package/dist/{output-fields.js → policy/output-fields.js} +0 -0
  832. /package/dist/{overlay-lint.d.ts → policy/overlay-lint.d.ts} +0 -0
  833. /package/dist/{overlay-lint.js → policy/overlay-lint.js} +0 -0
  834. /package/dist/{owner-ticket.d.ts → policy/owner-ticket.d.ts} +0 -0
  835. /package/dist/{search-globs.d.ts → policy/search-globs.d.ts} +0 -0
  836. /package/dist/{search-globs.js → policy/search-globs.js} +0 -0
  837. /package/dist/{ingress-contract.d.ts → protocol/ingress-contract.d.ts} +0 -0
  838. /package/dist/{ingress-protocol.d.ts → protocol/ingress-protocol.d.ts} +0 -0
  839. /package/dist/{ingress-protocol.js → protocol/ingress-protocol.js} +0 -0
  840. /package/dist/{listener-protocol.d.ts → protocol/listener-protocol.d.ts} +0 -0
  841. /package/dist/{peer-mcp-server.d.ts → protocol/peer-mcp-server.d.ts} +0 -0
  842. /package/dist/{peer-mcp-server.js → protocol/peer-mcp-server.js} +0 -0
  843. /package/dist/{request-id.d.ts → protocol/request-id.d.ts} +0 -0
  844. /package/dist/{request-id.js → protocol/request-id.js} +0 -0
  845. /package/dist/{routes.d.ts → protocol/routes.d.ts} +0 -0
  846. /package/dist/{routes.js → protocol/routes.js} +0 -0
  847. /package/dist/{sse.d.ts → protocol/sse.d.ts} +0 -0
  848. /package/dist/{sse.js → protocol/sse.js} +0 -0
  849. /package/dist/{terminal-protocol.js → protocol/terminal-protocol.js} +0 -0
  850. /package/dist/{webext-links.d.ts → protocol/webext-links.d.ts} +0 -0
  851. /package/dist/{webext-links.js → protocol/webext-links.js} +0 -0
  852. /package/dist/{arrival.d.ts → state/arrival.d.ts} +0 -0
  853. /package/dist/{contract-lock.d.ts → state/contract-lock.d.ts} +0 -0
  854. /package/dist/{history-state.d.ts → state/history-state.d.ts} +0 -0
  855. /package/dist/{runtime-state.d.ts → state/runtime-state.d.ts} +0 -0
  856. /package/dist/{runtime-state.js → state/runtime-state.js} +0 -0
  857. /package/dist/{starter.d.ts → state/starter.d.ts} +0 -0
  858. /package/dist/{starter.js → state/starter.js} +0 -0
  859. /package/dist/{state-portability.d.ts → state/state-portability.d.ts} +0 -0
  860. /package/dist/{state-portability.js → state/state-portability.js} +0 -0
  861. /package/dist/{versions.d.ts → state/versions.d.ts} +0 -0
  862. /package/dist/{versions.js → state/versions.js} +0 -0
  863. /package/dist/{embed.d.ts → text/embed.d.ts} +0 -0
  864. /package/dist/{embed.js → text/embed.js} +0 -0
  865. /package/dist/{mentions.d.ts → text/mentions.d.ts} +0 -0
  866. /package/dist/{mentions.js → text/mentions.js} +0 -0
  867. /package/dist/{path-refs.d.ts → text/path-refs.d.ts} +0 -0
  868. /package/dist/{path-refs.js → text/path-refs.js} +0 -0
  869. /package/dist/{shell-regions.js → text/shell-regions.js} +0 -0
  870. /package/dist/{title.d.ts → text/title.d.ts} +0 -0
  871. /package/dist/{title.js → text/title.js} +0 -0
  872. /package/src/{hostnames.test.ts → ids/hostnames.test.ts} +0 -0
  873. /package/src/{share-paths.test.ts → ids/share-paths.test.ts} +0 -0
  874. /package/src/{capability-env.ts → policy/capability-env.ts} +0 -0
  875. /package/src/{overlay-lint.test.ts → policy/overlay-lint.test.ts} +0 -0
  876. /package/src/{search-globs.test.ts → policy/search-globs.test.ts} +0 -0
  877. /package/src/{ingress-contract.test.ts → protocol/ingress-contract.test.ts} +0 -0
  878. /package/src/{peer-mcp-server.test.ts → protocol/peer-mcp-server.test.ts} +0 -0
  879. /package/src/{sse.ts → protocol/sse.ts} +0 -0
  880. /package/src/{versions.test.ts → state/versions.test.ts} +0 -0
  881. /package/src/{embed.test.ts → text/embed.test.ts} +0 -0
  882. /package/src/{mentions.test.ts → text/mentions.test.ts} +0 -0
  883. /package/src/{path-refs.test.ts → text/path-refs.test.ts} +0 -0
@@ -4,43 +4,14 @@ import { CHORE_INVARIANTS, composeAsk, REPORT_INVARIANTS, TRIAGE_NOTE } from "./
4
4
  import { componentStem, frameworksOf, idiomRule, normalizePath, UI_FRAMEWORKS, usesTailwind } from "./stack.js";
5
5
  import { WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG } from "./workspace-scope.js";
6
6
 
7
- /* THE CHORE BOOK, what routine maintenance a repository is owed, and what has to be TRUE before we say so.
8
- *
9
- * Everything in here is a standing offer: work that is worth doing eventually, that nobody will ever put on a
10
- * sprint board, and that a person cannot notice is overdue by looking at their editor. The engineering problem is
11
- * not finding such work, any linter will hand you a thousand findings, it is deciding which of them is worth
12
- * interrupting somebody about, on a surface they will still be reading in six months.
13
- *
14
- * Three rules, and every entry below obeys all three:
15
- *
16
- * 1. DELTAS, NOT ABSOLUTES. "38 packages are undocumented" is a statistic; it will be true every day for a year,
17
- * and a tile lit every day teaches the eye to stop seeing the rail. "A package appeared that nothing explains"
18
- * is an event. So a chore's `digest` is built from the IDENTITIES of what it found, which packages, which
19
- * advisories, which files, and the rail speaks when that set changes, not while it is merely non-empty. The
20
- * standing count still shows inside the panel, next to the thing it describes, which is where a statistic
21
- * belongs.
22
- *
23
- * 2. LEADER-RELATIVE, NOT TUNED. Nowhere in here is there a threshold that would need a different value for a
24
- * Rust repo, a fresh scaffold, or a ten-year monolith, with one deliberate exception (duplication's 5%, which
25
- * is a percentage of the tree and therefore already scale-free). "Three times the median of its own ranking"
26
- * needs no calibration and cannot rot.
27
- *
28
- * 3. THE EVIDENCE IS THE TRUTH; THE LEDGER ONLY DEBOUNCES. Nothing here can be ticked off. A chore goes quiet
29
- * because the measurement moved, which means someone fixing it by hand, or an unrelated change fixing it by
30
- * accident, is registered exactly like a chore turn doing it. The ledger's only power is to stop the rail
31
- * repeating itself about evidence a turn has already been spent on (verdict.ts).
32
- *
33
- * What is NOT here is as deliberate. There is no composite score, no letter grade, no "health: 78%". Those are
34
- * not comparable across projects, cannot be checked by the reader, and turn a set of specific, arguable findings
35
- * into one number nobody can act on. And no chore is ever created enabled-and-hidden: a chore that runs is a
36
- * turn that spends money and writes to the workspace, so it is either something the owner started or an
37
- * automation they can see in a list. */
7
+ // Routine maintenance a repo is owed, surfaced only as events: a chore's `digest` is built from the identities of what
8
+ // changed, not a count, so ordinary drift never rebadges. Thresholds are leader-relative, not a per-repo tuned number.
9
+ // A chore goes quiet only because the measurement itself moved; nothing here is manually ticked off.
38
10
 
39
11
  export type ChoreStance = "act" | "report";
40
12
 
41
- /* WHAT KIND OF CLAIM A CHORE MAKES ON SOMEONE'S ATTENTION. Four of them, ordered from "this is a risk you are
42
- * carrying right now" to "this is worth thinking about this quarter", see CHORE_KINDS at the foot of this file,
43
- * which carries the argument and the words the panel groups under. */
13
+ // What kind of claim a chore makes on someone's attention, from an active risk to a periodic review; see CHORE_KINDS
14
+ // for the order and the words the panel groups under.
44
15
  export type ChoreKind = "carrying" | "accruing" | "drifting" | "surveying";
45
16
 
46
17
  export interface ChoreContext {
@@ -53,104 +24,57 @@ export interface ChoreContext {
53
24
  readonly nowMs: number;
54
25
  }
55
26
 
56
- // What a chore found, when it found anything. `undefined` from `assess` is the healthy case and the common one.
27
+ // What a chore found, when it found anything; `undefined` from `assess` is the healthy, common case.
57
28
  export interface ChoreFinding {
58
- // One line, in numbers, for the row. The reader decides from this whether to open anything.
29
+ // One line, in numbers; the reader decides from this alone whether to open anything.
59
30
  readonly headline: string;
60
- // The evidence itself, one claim per line, what the panel lists under the row, and what makes the headline
61
- // checkable rather than something to be believed.
31
+ // The evidence, one claim per line; what makes the headline checkable, not just believed.
62
32
  readonly detail: readonly string[];
63
- // The identity of THIS evidence. See digest.ts: it is what the rail's transitions are measured against.
33
+ // The identity of this evidence; see digest.ts, it is what the rail's transitions are measured against.
64
34
  readonly digest: string;
65
- // `warning` is for a risk the owner is carrying right now, a live advisory, a runtime past its EOL. Everything
66
- // else is `info`, including large and ugly numbers, because "there is a lot of it" is not an emergency.
35
+ // `warning` is for a risk carried right now (a live advisory, an EOL runtime); everything else is `info`.
67
36
  readonly severity: "info" | "warning";
68
- // The numbers again, in the agent's terms, for the prompt's "Why:" line. Exact, the agent may recount them.
37
+ // The numbers again, in the agent's terms, for the prompt's "Why:" line; exact, the agent may recount them.
69
38
  readonly why: string;
70
39
  }
71
40
 
72
41
  export interface Chore {
73
42
  readonly id: string;
74
43
  readonly title: string;
75
- // An app icon name. Left as a plain string for the same reason the extension API leaves Activation.icon open:
76
- // this library must not depend on the UI kit to name a glyph.
44
+ // An app icon name, left as a plain string so this library doesn't depend on the UI kit to name a glyph.
77
45
  readonly icon: string;
78
46
  // The one-line standing description, shown whether or not the chore is currently due.
79
47
  readonly description: string;
80
- /* WHICH OF THE FOUR KINDS OF CLAIM THIS IS (CHORE_KINDS, at the foot of this file). It decides the book's
81
- * order and the panel's grouping, and it is a FIELD rather than a comment above the array for exactly that
82
- * reason: the reading order is the one editorial claim this surface makes, and a claim spelled as a comment
83
- * beside a hand-maintained list is one nobody can check and the compiler cannot keep. */
48
+ // A field, not a comment, so the book's reading order is compiler-checked, not hand-maintained.
84
49
  readonly kind: ChoreKind;
85
- /* THE RULE, in words, what has to be true for this chore to be due, stated so a reader can check it against
86
- * the evidence below it and disagree.
87
- *
88
- * This is not decoration. A row that says "4 majors waiting" and nothing else is asking to be taken on
89
- * trust; the same row saying "shown because: a dependency is a major version behind" is a claim someone can
90
- * argue with, and arguing with it is how the book gets better. It rides into the prompt too, so the agent is
91
- * told the rule it was woken by rather than left to infer it from the numbers.
92
- *
93
- * Kept as prose next to the code that implements it, which means it can drift from it, the tests below
94
- * cannot check English. The rule for writing one: say the THRESHOLD, not the subject. "Duplication is high"
95
- * is a topic; "more than 5% of the tree is duplicated" is a criterion. */
50
+ // The threshold this chore is due by, stated as a criterion a reader can check and disagree with, not a topic.
96
51
  readonly criterion: string;
97
- /* WHETHER THIS IS A QUESTION WORTH ASKING OF THIS REPOSITORY AT ALL, returns undefined when it is, and what
98
- * is MISSING when it is not.
99
- *
100
- * Distinct from `assess`, and the distinction is the whole point: `assess` asks whether the answer is yes,
101
- * this asks whether the question makes sense. "Re-read the documentation against the code" in a repository
102
- * with no documentation is not a chore that is currently clear, it is one that will never apply here, and
103
- * showing it as clear says we checked something we cannot check. A chore that does not apply is dropped from
104
- * the panel entirely; a line in the scope strip records that it was considered.
105
- *
106
- * A BARE CAUSE, "no Dockerfile", never "this repository ships no Dockerfile, so there is no image to slim".
107
- * Same spelling as `ProbeSpec.unavailable`, and for the same reason both surfaces need: one absent
108
- * package.json rules out five chores, and five sentences saying so at length is the wall of text this phrasing
109
- * exists to prevent. The panel groups by this string, so the CONSEQUENCE, which chores it costs, is the list
110
- * beside it rather than a clause repeated inside every entry. Identical causes must be spelled identically or
111
- * they group apart.
112
- *
113
- * Reads `signals` rather than probes on purpose: applicability is about what the repository IS, which is a
114
- * fact the daemon holds without measuring anything. If a gate needed a probe it would be describing the
115
- * answer rather than the question. */
52
+ // Whether the question makes sense here, distinct from `assess`; undefined means yes, else a bare cause spelled
53
+ // identically to group by.
116
54
  readonly applies?: (signals: ChoreSignals) => string | undefined;
117
- // Whether the turn is allowed to CHANGE anything. Not a hint, it selects the invariants block, and a
118
- // report-stance chore is told in words that editing would be a surprise.
55
+ // Whether the turn may change anything; not a hint, it selects the invariants block and is stated to the agent.
119
56
  readonly stance: ChoreStance;
120
- // Probes that must have run and succeeded before this chore can be assessed at all. Missing ⇒ `unavailable`:
121
- // rendered greyed, never badged, and never mistaken for a clean result.
57
+ // Probes that must have run and succeeded first; missing means unavailable, shown greyed, never mistaken for clean.
122
58
  readonly needs: readonly ProbeId[];
123
- /* How long until this is worth doing again REGARDLESS of what changed. For a measured chore this is a backstop
124
- * (evidence normally decides); for a survey chore it is the whole trigger, because "read this code with fresh
125
- * eyes" has no measurement and its value is entirely in being done periodically. */
59
+ // How long until this is worth doing again regardless of what changed: a backstop for a measured chore, the whole
60
+ // trigger for a survey.
126
61
  readonly cadenceMs: number;
127
- // A survey has no measurement: it is due on its cadence and clear otherwise. Named rather than inferred from
128
- // an empty `needs`, because the two are different claims and the panel says which one a row is.
62
+ // Named rather than inferred from an empty `needs`: a survey has no measurement, and the panel says which kind of
63
+ // row this is.
129
64
  readonly survey?: true;
130
- /* THE SCHEDULED FORM, for the chores worth running unattended, what the Automations page offers as a
131
- * one-click "code chore", and the second way this book is consumed.
132
- *
133
- * The two modes are genuinely different and both are wanted. The Maintenance panel is EVIDENCE-driven: it
134
- * reads what the daemon already measured and offers a turn against a specific finding you can read first. An
135
- * automation is SCHEDULE-driven: it wakes on a clock, at 3am, with nobody watching. So an automation cannot
136
- * carry a finding, there is no verdict at fire time, and instead it carries a GUARD: a shell one-liner that
137
- * runs for free on the sandbox's own clock and exits non-zero to skip, so the half that costs a turn only
138
- * starts when there is something to start it for.
139
- *
140
- * `report` is where the guard leaves its findings. A guard's stdout is discarded on success (only a FAILING
141
- * guard's output survives, as the skip reason), so a file is how the free deterministic half hands what it
142
- * found to the expensive half. */
65
+ // Wakes on a clock, unattended, so it carries a guard (a shell one-liner, exits non-zero to skip) instead of a
66
+ // finding.
143
67
  readonly automation?: {
144
68
  readonly cron: string;
145
69
  readonly guard: string;
146
70
  readonly note: string;
147
71
  readonly report: string;
148
- // How the woken turn is told what it is looking at, the "Why:" line, in place of a finding.
72
+ // How the woken turn is told what it is looking at, in place of a finding.
149
73
  readonly woke: string;
150
74
  };
151
75
  readonly assess: (context: ChoreContext) => ChoreFinding | undefined;
152
- // The prompt's three variable parts (prompt.ts owns the shape). `diagnosis` says what the numbers MEAN, `goal`
153
- // says what shape to move towards, never a design, and `done` is falsifiable by the agent itself.
76
+ // The prompt's three parts: `diagnosis` explains the numbers, `goal` is the shape to move toward (never a design),
77
+ // `done` is agent-falsifiable.
154
78
  readonly diagnosis: string;
155
79
  readonly goal: string;
156
80
  readonly done: string;
@@ -158,32 +82,28 @@ export interface Chore {
158
82
 
159
83
  const DAY_MS = 86_400_000;
160
84
 
161
- /* Where a scheduled chore's guard leaves its report for the woken turn to read. Under /tmp because they are
162
- * inputs to a turn that starts moments later, never something to keep, and deliberately the SAME paths the
163
- * probe runner uses, so a workspace that runs both does not keep two copies of the same measurement. */
85
+ // Where a scheduled chore's guard leaves its report; under /tmp since these feed a turn moments later, not kept.
164
86
  const AUDIT_REPORT = `/tmp/intentic-chore-audit.json`;
165
87
  const KNIP_REPORT = `/tmp/intentic-chore-knip.json`;
166
88
  const JSCPD_DIR = `/tmp/intentic-chore-jscpd`;
167
89
  const JSCPD_REPORT = `${JSCPD_DIR}/jscpd-report.json`;
168
90
 
169
- // How a repo is named to a person and to an agent. "root" is the wire id the daemon's git and health routes
170
- // already use for the workspace's own repository, and it is a word an agent would otherwise read as a directory
171
- // called "root", so it is spelled out here, once, rather than at every call site that builds a prompt.
91
+ // How a repo is named to a person or an agent; "root" (the wire id for the workspace's own repo) reads as a real
92
+ // directory name to an agent, so it is spelled out here once rather than at every call site.
172
93
  export const repoLabel = (repo: string): string => (repo === `root` || repo === `` ? `the workspace root repository` : repo);
173
94
 
174
- // The same repository, named for a surface that has a 16rem column or a chip to say it in. `repoLabel` is prose
175
- // and reads as prose inside a sentence ("update dependencies in the workspace root repository"); a rail row wants
176
- // the name on its own, and "the workspace root repository" truncates to "the workspace root reposi…" there.
95
+ // The same repository, named for a narrow column or chip; `repoLabel`'s prose truncates badly there ("the
96
+ // workspace root reposi…").
177
97
  export const repoName = (repo: string): string => (repo === `root` || repo === `` ? `workspace root` : repo);
178
98
 
179
99
  const plural = (count: number, one: string, many = `${one}s`): string => `${count} ${count === 1 ? one : many}`;
180
100
 
181
- // One outdated dependency, as the panel lists it. The semver step leads, because it is what decides whether the
182
- // row is a morning's work or a project.
101
+ // One outdated dependency, as the panel lists it; the semver step leads, since it decides whether the row is a
102
+ // morning's work or a project.
183
103
  const outdatedLine = (entry: OutdatedPackage): string => `${entry.kind} · ${entry.name} ${entry.current} → ${entry.latest}`;
184
104
 
185
- // The `facts` of a probe that actually ran. Anything else, never run, unavailable, failed, reads as absent, so
186
- // no assess() can accidentally treat an unmeasured repo as a measured clean one.
105
+ // The facts of a probe that actually ran; anything else (never run, unavailable, failed) reads as absent, so
106
+ // assess() can't mistake an unmeasured repo for a clean one.
187
107
  const factsOf = <T extends ProbeId>(context: ChoreContext, id: T): Extract<NonNullable<ProbeResult["facts"]>, { id: T }> | undefined => {
188
108
  const probe = context.probes.get(id);
189
109
  if (probe?.state !== `ok` || probe.facts === undefined || probe.facts.id !== id) {
@@ -196,11 +116,9 @@ const factsOf = <T extends ProbeId>(context: ChoreContext, id: T): Extract<NonNu
196
116
 
197
117
  const BLOCKING = new Set<Advisory["severity"]>([`critical`, `high`]);
198
118
 
199
- /* SECURITY. The only chore with no cadence at all: an advisory is not something that becomes worth looking at
200
- * after thirty days, and there is nothing periodic about it. It is also the only one that reaches `warning`
201
- * routinely, which is exactly why the bar is critical-or-high and production-or-dev is carried through to the
202
- * prompt rather than flattened, a moderate advisory in a build-time-only tool badging red is how `warning` stops
203
- * meaning anything within a week. */
119
+ // Security is the only chore with no cadence: an advisory isn't something that becomes worth reading after 30
120
+ // days. Also the only one that reaches `warning` routinely, so the bar is critical-or-high with production/dev carried
121
+ // to the prompt.
204
122
  const security: Chore = {
205
123
  id: `security-advisories`,
206
124
  title: `Patch security advisories`,
@@ -240,13 +158,12 @@ const security: Chore = {
240
158
  (advisory) =>
241
159
  `${advisory.severity} · ${advisory.name}, ${advisory.title}${advisory.patched === undefined ? ` (no patch yet)` : ``}`,
242
160
  ),
243
- // Identities, not counts: every advisory that appears or is fixed is genuinely news, and there is no
244
- // ordinary drift here to absorb.
161
+ // Identities, not counts: every advisory that appears or is fixed is genuinely news, with no ordinary drift
162
+ // to absorb.
245
163
  digest: digestOf(...blocking.map((advisory) => `${advisory.name}@${advisory.severity}`).toSorted()),
246
164
  severity: production.length > 0 ? `warning` : `info`,
247
- // Named, not counted. "1 high advisory" tells an agent nothing it can act on, and the first thing it
248
- // would have to do is re-derive the list we already have, badly, because pnpm audit is slow and it
249
- // would be reading a different tree by then.
165
+ // Named, not counted; re-deriving the list itself would be slow, and pnpm audit would read a different tree
166
+ // by then.
250
167
  why:
251
168
  `pnpm audit reports ${plural(blocking.length, `high or critical advisory`, `high or critical advisories`)} against ` +
252
169
  `${repoLabel(context.repo)}, ${production.length} reaching a production dependency path, ${patchable.length} with a published patched range: ` +
@@ -262,10 +179,8 @@ const security: Chore = {
262
179
  done: `Done when \`pnpm audit\` reports fewer high/critical advisories than it did, and the repository's type-check and tests pass.`,
263
180
  };
264
181
 
265
- /* DEPENDENCIES. Majors are the finding; the total is context. A repo that is forty patch releases behind is a
266
- * morning's work and does not need a rail tile, while one major on a framework is a project, so the digest is
267
- * built from WHICH packages have a major waiting, and a new one appearing is the event. The total count rides
268
- * along bucketed (digest.ts) so that ordinary drift, which is constant, does not read as news. */
182
+ // Majors are the finding, the total is context: the digest is keyed to which packages have a major waiting, with
183
+ // the count riding along bucketed so ordinary drift doesn't read as news.
269
184
  const OUTDATED_NOISE_FLOOR = 20;
270
185
 
271
186
  const dependencies: Chore = {
@@ -285,8 +200,8 @@ const dependencies: Chore = {
285
200
  return undefined;
286
201
  }
287
202
  const majors = facts.packages.filter((entry) => entry.kind === `major`);
288
- // Nothing major and a short tail is a healthy repository, not a chore. The floor is on the TOTAL rather
289
- // than on any one package because minors and patches are only worth a turn in bulk.
203
+ // A healthy repo, not a chore: the floor is on the total, since minors and patches are only worth a turn in
204
+ // bulk.
290
205
  if (majors.length === 0 && facts.packages.length < OUTDATED_NOISE_FLOOR) {
291
206
  return undefined;
292
207
  }
@@ -298,8 +213,8 @@ const dependencies: Chore = {
298
213
  detail: majors.toSorted((left, right) => left.name.localeCompare(right.name)).map(outdatedLine),
299
214
  digest: digestOf(...majors.map((entry) => `${entry.name}@${entry.latest}`).toSorted(), `total:${bucketOf(facts.packages.length)}`),
300
215
  severity: `info`,
301
- // The majors are named because they are what the turn is actually about, the minors and patches are a
302
- // bulk operation the agent will enumerate itself, and listing four hundred of them here would bury it.
216
+ // Majors are named since they are what the turn is about; minors and patches are a bulk operation the agent
217
+ // enumerates itself.
303
218
  why:
304
219
  `pnpm outdated reports ${plural(facts.packages.length, `dependency`, `dependencies`)} behind the registry in ` +
305
220
  `${repoLabel(context.repo)}, ${majors.length} of them by a major version` +
@@ -315,9 +230,8 @@ const dependencies: Chore = {
315
230
  done: `Done when the repository's type-check and tests pass, and your summary names every major you took and every one you left, with the reason.`,
316
231
  };
317
232
 
318
- /* DEAD CODE. knip's counts, folded into one chore rather than split by kind: unused files, unused exports and
319
- * unused dependencies are the same finding wearing three hats, they are fixed in one pass, and three rows that
320
- * light together are three chances to teach someone to ignore the rail. */
233
+ // knip's counts folded into one chore rather than split by kind: unused files, exports and dependencies are the
234
+ // same finding, fixed in one pass.
321
235
  const deadCode: Chore = {
322
236
  id: `dead-code`,
323
237
  title: `Clear out dead code`,
@@ -331,9 +245,8 @@ const deadCode: Chore = {
331
245
  cadenceMs: 14 * DAY_MS,
332
246
  automation: {
333
247
  cron: `0 3 * * *`,
334
- // Two gates, so the two ways to not run are distinguishable in the run history: knip absent (a repo that
335
- // never adopted it) reads differently from knip clean. `pnpm exec` resolves the repo's own devDependency
336
- // rather than downloading a floating version that would disagree with its knip.json.
248
+ // Two gates so a repo that never adopted knip reads differently from one that's clean; `pnpm exec` resolves the
249
+ // repo's own devDependency.
337
250
  guard:
338
251
  `pnpm exec knip --version >/dev/null 2>&1 || { echo "knip is not a devDependency of this repo"; exit 1; }; ` +
339
252
  `pnpm exec knip --reporter json > ${KNIP_REPORT} && { echo "no dead code"; exit 1; }`,
@@ -354,12 +267,12 @@ const deadCode: Chore = {
354
267
  return {
355
268
  headline: `${plural(files, `unreferenced file`)}, ${plural(exports + types, `unused export`)}, ${plural(unusedDeps + devDependencies, `unused dependency`, `unused dependencies`)}`,
356
269
  detail: sample.map((path) => `unreferenced · ${path}`),
357
- // The file identities carry the news (a newly-dead file is an event); the export and dependency counts
358
- // ride along bucketed, since they drift by one constantly as code is written.
270
+ // File identities carry the news (a newly-dead file is an event); export/dependency counts ride along
271
+ // bucketed, since they drift constantly.
359
272
  digest: digestOf(...sample.toSorted(), `exports:${bucketOf(exports + types)}`, `deps:${bucketOf(unusedDeps + devDependencies)}`),
360
273
  severity: `info`,
361
- // The sample rather than the full list, and the goal tells the agent to re-run knip for the rest: this
362
- // measurement is hours old, and sending a turn at a file that has already been deleted wastes it.
274
+ // The sample, not the full list: this measurement is hours old, and the goal tells the agent to re-run knip
275
+ // for the rest.
363
276
  why:
364
277
  `knip reports ${plural(files, `unreferenced file`)}, ${exports + types} unused exports and ` +
365
278
  `${unusedDeps + devDependencies} unused dependencies in ${repoLabel(context.repo)}` +
@@ -376,11 +289,9 @@ const deadCode: Chore = {
376
289
  done: `Done when knip reports fewer findings, the repository's type-check and tests pass, and nothing you deleted is reachable from another package.`,
377
290
  };
378
291
 
379
- /* DUPLICATION. Report-stance, and it is the clearest case for why that stance exists at all. Most duplication
380
- * should not be removed: generated files, tests that repeat on purpose, and two things that merely look alike
381
- * today but answer to different owners tomorrow. Deciding which copies genuinely have to change together is a
382
- * design judgement, and an agent that "collapses duplication" unattended produces exactly the abstraction that
383
- * gets deleted a year later. */
292
+ // Report-stance: most duplication shouldn't be removed (generated files, deliberate test repetition, lookalikes
293
+ // with different owners); deciding which copies must change together is a design judgement no unattended agent should
294
+ // make.
384
295
  const DUPLICATION_FLOOR = 5;
385
296
 
386
297
  const duplication: Chore = {
@@ -395,8 +306,7 @@ const duplication: Chore = {
395
306
  cadenceMs: 30 * DAY_MS,
396
307
  automation: {
397
308
  cron: `0 3 * * 1`,
398
- // Gated on the percentage rather than "any clone at all", which every real repository has: below this the
399
- // report is noise that would wake an agent every week to say nothing actionable.
309
+ // Gated on the percentage, not "any clone at all" (which every repo has); below this the report is noise.
400
310
  guard:
401
311
  `pnpm dlx jscpd ${WORKSPACE_ROOT_JSCPD_EXCLUDE_ARG} --reporters json --output ${JSCPD_DIR} --min-lines 12 --threshold 100 . >/dev/null 2>&1; ` +
402
312
  `[ "$(jq '.statistics.total.percentage // 0 | floor' ${JSCPD_REPORT} 2>/dev/null || echo 0)" -ge ${DUPLICATION_FLOOR} ]`,
@@ -413,8 +323,8 @@ const duplication: Chore = {
413
323
  return {
414
324
  headline: `${percentage.toFixed(1)}% of the tree is duplicated, across ${plural(clones, `clone`)}`,
415
325
  detail: top.map((clone) => `${clone.lines} lines · ${clone.first} ↔ ${clone.second}`),
416
- // A whole percentage point is the smallest move worth calling news; the biggest clones' identities
417
- // carry the rest, so a new large clone appearing is an event even at a flat percentage.
326
+ // A whole percentage point is the smallest move worth calling news; the biggest clones' identities carry
327
+ // the rest.
418
328
  digest: digestOf(`pct:${Math.round(percentage)}`, ...top.map((clone) => `${clone.first}|${clone.second}`).toSorted()),
419
329
  severity: `info`,
420
330
  why:
@@ -431,24 +341,9 @@ const duplication: Chore = {
431
341
  done: `Done when every clone in the report has either a named extraction or a one-line reason it should stay.`,
432
342
  };
433
343
 
434
- /* TEST STRENGTH. The one chore whose evidence is about the tests rather than the code, and it exists because
435
- * nothing else in this workspace can produce it.
436
- *
437
- * A green suite is not evidence that the code is checked. Coverage says a line RAN; it cannot say an assertion
438
- * depended on what the line produced. The gap between those two is where a model's tests live: they execute
439
- * everything and assert almost nothing, and every gate here says yes to them — they type-check, they lint, they
440
- * pass.
441
- *
442
- * MEASURED IN THIS REPOSITORY, on sandbox-contract's own chore module: 109 hand-written tests, and 16 of 58
443
- * injected faults survived. The one worth reading is in `bucketOf`, whose comment in digest.ts argues at length
444
- * that the zero boundary is load-bearing. Move that boundary and the suite stays green, because the test holding
445
- * it is written relationally — `expect(bucketOf(0)).not.toBe(bucketOf(1))` — and with the boundary moved the two
446
- * values are still different. The careful, un-brittle assertion is precisely the one that cannot see the change.
447
- *
448
- * THE FLOOR IS LOW ON PURPOSE. 60% is where Stryker's own default report turns red, and it is far under what a
449
- * well-tested module scores, because this chore is looking for suites that are decorative rather than suites that
450
- * are imperfect. A threshold near the good number would badge every honest package in the repo, which is how a
451
- * maintenance surface teaches people to ignore it. */
344
+ // The only chore whose evidence is about the tests, not the code: a green suite proves a line ran, not that
345
+ // anything depended on what it produced. The floor is set low on purpose, to catch decorative suites, not to grade good
346
+ // ones.
452
347
  const MUTATION_FLOOR = 60;
453
348
 
454
349
  const testStrength: Chore = {
@@ -460,11 +355,8 @@ const testStrength: Chore = {
460
355
  criterion: `Stryker's mutation score for the repo is under ${MUTATION_FLOOR}%.`,
461
356
  stance: `act`,
462
357
  needs: [`mutation`],
463
- /* Weekly. This was quarterly on the reasoning that a mutation score moves when tests are rewritten and that
464
- * is not a weekly event; on 2026-08-31 agents rewrote about 180 test files in an afternoon, and the score is
465
- * exactly the number that should have said so. The probe is still the most expensive one here, and
466
- * `--incremental` is what makes a weekly cadence affordable: the first run costs a full run, every one after it
467
- * costs the mutants whose code or tests changed. */
358
+ // Weekly: `--incremental` makes this affordable, the first run costs a full run, every one after costs only what
359
+ // changed.
468
360
  cadenceMs: 7 * DAY_MS,
469
361
  assess: (context) => {
470
362
  const facts = factsOf(context, `mutation`);
@@ -474,13 +366,11 @@ const testStrength: Chore = {
474
366
  const { score, killed, survived, survivors } = facts.mutation;
475
367
  return {
476
368
  headline: `${survived} injected faults went unnoticed, ${score}% of them caught`,
477
- // The survivors themselves, not the score. A percentage is a mood; a named line with the change that
478
- // nothing objected to is a morning's work with the answer already in it.
369
+ // The survivors themselves, not the score; a named line with the change nothing objected to is a morning's
370
+ // work already.
479
371
  detail: survivors.map((one) => `${one.file}:${one.line} · ${one.mutator} → ${one.replacement} · survived`),
480
- /* Bucketed, via the same helper the other counting chores use, so ordinary drift does not read as
481
- * news: a score moving 54 → 55 is not a thing to interrupt anyone about. The survivors' IDENTITIES
482
- * ride along, so a NEW weak spot appearing speaks even while the number holds steady — which is the
483
- * case that matters, because that is a test somebody just wrote. */
372
+ // Bucketed so ordinary score drift isn't news; survivors' identities ride along, so a new weak spot speaks
373
+ // even at a steady score.
484
374
  digest: digestOf(`bucket:${bucketOf(100 - score)}`, ...survivors.map((one) => `${one.file}:${one.line}`).toSorted()),
485
375
  severity: `info`,
486
376
  why:
@@ -498,12 +388,8 @@ const testStrength: Chore = {
498
388
  done: `Done when every named survivor has either a new assertion that fails without the change, or a one-line note saying why it cannot be observed.`,
499
389
  };
500
390
 
501
- /* DOCUMENTATION. The evidence is a package with no README, which IS its architecture document in this
502
- * workspace, so this is a stat on the package directory rather than a lookup in a parallel tree. It sounds like
503
- * a coverage statistic
504
- * and would be one if the rail read it directly. It does not: the digest is the SET of undocumented package
505
- * directories, so a long-standing backlog goes quiet after it is seen once, and a package appearing that nothing
506
- * explains is an event that speaks. That is the whole difference between this being useful and being a nag. */
391
+ // Evidence is a package with no README, which is its architecture document here. The digest is the set of
392
+ // undocumented directories, so a long-standing backlog goes quiet after being seen once.
507
393
  const documentation: Chore = {
508
394
  id: `documentation-refresh`,
509
395
  title: `Document what nothing explains`,
@@ -539,16 +425,9 @@ const documentation: Chore = {
539
425
  done: `Done when every package you named has a document that a newcomer could use to find the file they need, and no other file changed.`,
540
426
  };
541
427
 
542
- /* COMPLEXITY. The one chore whose evidence comes from the resident index rather than a subprocess, and the one
543
- * most at risk of being a ranking laundered into a to-do list, there is ALWAYS a top of a hotspot ranking, and
544
- * "your worst file" is not a finding. So it does not report the ranking. It reports the two shapes within it that
545
- * are genuinely arguable:
546
- *
547
- * volatile AND depended-on a hotspot that is also a key module: every edit ripples outward.
548
- * out of proportion branching three times the median of its own ranking: tangled, not merely busy.
549
- *
550
- * Both are relative to the same list the user is reading, so nothing here needs tuning per repository or per
551
- * language, and a healthy repo produces an empty set rather than a top five. */
428
+ // Reports only the two shapes worth arguing about in a hotspot ranking:
429
+ // - volatile and depended-on: a hotspot that is also a key module, every edit ripples outward.
430
+ // - out of proportion: branching three times the median of its own ranking.
552
431
  const COMPLEXITY_MULTIPLE = 3;
553
432
 
554
433
  const median = (values: readonly number[]): number => {
@@ -571,8 +450,8 @@ const complexity: Chore = {
571
450
  needs: [],
572
451
  cadenceMs: 30 * DAY_MS,
573
452
  assess: (context) => {
574
- // A half-built index ranks whatever it has finished reading, which is not the repository. Better to say
575
- // nothing than to send a turn at the wrong file.
453
+ // A half-built index ranks whatever it has finished reading, not the repository; better to say nothing than
454
+ // target the wrong file.
576
455
  if (!context.signals.indexed || context.signals.hotspots.length === 0) {
577
456
  return undefined;
578
457
  }
@@ -605,11 +484,7 @@ const complexity: Chore = {
605
484
  done: `Done when \`iq hotspots\` reports materially fewer branch points for that file, the repository's checks pass, and no importer changed meaning.`,
606
485
  };
607
486
 
608
- /* RUNTIME. A static table, and it is honest about being one: there is no network call here, so the dates below
609
- * are a fact about the day this file was last edited rather than a live feed. That is the right trade for a
610
- * signal that moves twice a year and must work on a box with no outbound access, but it does mean this table is
611
- * maintenance in its own right, and a major missing from it reads as "not end-of-life", which is the safe way to
612
- * be wrong. Source: nodejs/Release. */
487
+ // A static table, current only as of this file's last edit; no network call. Source: nodejs/Release.
613
488
  const NODE_EOL: Readonly<Record<number, string>> = {
614
489
  16: `2023-09-11`,
615
490
  18: `2025-04-30`,
@@ -617,8 +492,7 @@ const NODE_EOL: Readonly<Record<number, string>> = {
617
492
  22: `2027-04-30`,
618
493
  24: `2028-04-30`,
619
494
  };
620
- // How far ahead of an end-of-life date the chore starts speaking. A quarter, because moving a runtime is planned
621
- // work, telling someone the day security patches stop is telling them too late to do anything but scramble.
495
+ // How far ahead of end-of-life the chore starts speaking; a quarter, since moving a runtime is planned work.
622
496
  const EOL_HORIZON_MS = 90 * DAY_MS;
623
497
 
624
498
  const runtime: Chore = {
@@ -644,7 +518,7 @@ const runtime: Chore = {
644
518
  }
645
519
  const past = context.nowMs >= eolMs;
646
520
  const days = Math.round(Math.abs(eolMs - context.nowMs) / DAY_MS);
647
- // Which packages would have to be argued with, so the finding names the work rather than only the fact.
521
+ // Which packages would have to be argued with, so the finding names the work, not just the fact.
648
522
  const pinned = context.signals.packages.filter((entry) => entry.engines?.[`node`] !== undefined);
649
523
  return {
650
524
  headline: past
@@ -655,7 +529,7 @@ const runtime: Chore = {
655
529
  `end of life · ${eol}`,
656
530
  ...pinned.map((entry) => `pinned · ${entry.name} requires node ${entry.engines?.[`node`] ?? ``}`),
657
531
  ],
658
- // The state, not the date: a countdown would mint a new digest every single day and badge forever.
532
+ // The state, not the date: a countdown would mint a new digest, and badge, every single day.
659
533
  digest: digestOf(`node:${major}`, past ? `eol` : `approaching`),
660
534
  severity: past ? `warning` : `info`,
661
535
  why:
@@ -671,11 +545,8 @@ const runtime: Chore = {
671
545
  done: `Done when the pins name a supported release, the repository's type-check and tests pass on it, and anything needing a rebuild is named as such.`,
672
546
  };
673
547
 
674
- /* LIBRARIES. The one chore here with evidence for a question that usually gets asked as a vibe ("should we be
675
- * using a library for this?"). Two libraries that solve the same problem in one tree is a fact, not an opinion:
676
- * somebody added the second one without removing the first, both are now in the bundle, and new code picks
677
- * whichever the neighbouring file used. The table below is deliberately short and only names categories where
678
- * having two is genuinely a mistake, not, say, two test runners, which is an ordinary migration. */
548
+ // Evidence for a question usually asked as a vibe: two libraries solving the same problem is a fact, not an
549
+ // opinion. The table is short, naming only categories where having two is a genuine mistake, not an ordinary migration.
679
550
  const CATEGORIES: readonly { readonly category: string; readonly members: readonly string[] }[] = [
680
551
  { category: `date handling`, members: [`moment`, `dayjs`, `date-fns`, `luxon`, `js-joda`] },
681
552
  { category: `HTTP clients`, members: [`axios`, `got`, `node-fetch`, `superagent`, `undici`, `request`] },
@@ -724,61 +595,31 @@ const libraries: Chore = {
724
595
  done: `Done when every overlapping pair has a recommendation with a call-site count behind it, or a reason the overlap is fine.`,
725
596
  };
726
597
 
727
- /* ---- THE FRONT-END CHORES -------------------------------------------------------------------------------------
728
- *
729
- * Four chores that only exist where a UI framework does, kept together because they share one gate and one
730
- * probe, and split across the reading order in CHORES, since where a row belongs is decided by what KIND of
731
- * finding it is, not by which file paragraph it was written in.
732
- *
733
- * They gate on `shape.deps` rather than on `signals.packages`, and that is not interchangeable. `packages` is
734
- * populated from pnpm-workspace.yaml, so it is EMPTY for a repository that is not a monorepo, which is what a
735
- * Vite app, a Next app and an Angular CLI project all are. A framework gate reading it would be permanently dark
736
- * in the overwhelming majority of the repositories these four were written for, and dark silently: the chores
737
- * would not appear, the footer would say the repository has no packages, and nothing would look broken.
738
- *
739
- * All four also say something the rest of the book does not have to. A component, a class name and a bundle chunk
740
- * are things nobody sees the whole of, you read one component at a time, and the tenth copy of a button looks
741
- * exactly like the first nine did. That is the same argument the whole surface rests on, just further from the
742
- * places a compiler will ever help. */
598
+ // Four chores that only exist where a UI framework does; gated on `shape.deps`, not `signals.packages` (empty
599
+ // for a non-monorepo app, which would leave the gate permanently and silently dark). All four catch things nobody sees
600
+ // the whole of at once: a component, a class name, a bundle chunk.
743
601
 
744
- // How many rows of evidence a UI finding lists before it is a wall rather than a list. The standing count still
745
- // leads the headline; this only bounds what is enumerated underneath it.
602
+ // How many evidence rows a UI finding lists before it is a wall, not a list; the standing count still leads the
603
+ // headline.
746
604
  const DETAIL_LIMIT = 8;
747
605
 
748
606
  const FRAMEWORK_LABELS = UI_FRAMEWORKS.map((framework) => framework.label).join(`, `);
749
607
 
750
- // One gate, one cause, four chores. Built from the table so that a framework added to stack.ts cannot leave a
751
- // stale list of names behind in a reason nobody re-reads.
608
+ // One gate, one cause, four chores; built from the framework table so a framework added to stack.ts can't leave
609
+ // a stale name behind in the reason.
752
610
  const needsFramework = (signals: ChoreSignals): string | undefined =>
753
611
  frameworksOf(signals.shape.deps).length > 0 ? undefined : `no ${FRAMEWORK_LABELS}`;
754
612
 
755
613
  const bytesLabel = (bytes: number): string => (bytes >= 1024 * 1024 ? `${(bytes / (1024 * 1024)).toFixed(1)} MB` : `${Math.round(bytes / 1024)} kB`);
756
614
 
757
- /* BUNDLE. What a browser downloads before anything appears, which is the fact about a front-end that is furthest
758
- * from anything visible in an editor: every dependency looks the same size in an import statement.
759
- *
760
- * The criterion is a SHARE, and that is deliberate, it is the second exception to the book's leader-relative
761
- * rule, and it earns the same defence duplication's 5% does. A byte threshold would need a different value for a
762
- * marketing page and an IDE, would be argued about forever, and would be wrong the moment either one grew. "One
763
- * chunk is more than half of everything you ship" needs no calibration: it says the build is not split, which is
764
- * true or false at any size. A well-split app has its largest chunk well under this whatever it weighs, and a
765
- * small app that genuinely is one chunk trips it and is right to, that IS its entire download.
766
- *
767
- * Report-stance. Where the split boundaries go is a routing and product decision, and an agent that lazily
768
- * imported things unattended at three in the morning would be making it. */
615
+ // The criterion is a share of total size, not a byte threshold, since a byte value would need a different number
616
+ // per app. Report-stance: where to split is a product decision no unattended agent should make.
769
617
  const BUNDLE_SHARE_FLOOR = 50;
770
- // Below this there is no ranking to be an outlier in, two files cannot tell you anything about how a build is
771
- // divided, and the largest of them is over half by arithmetic rather than by fault.
618
+ // Below this there is no ranking to be an outlier in; the largest asset is over half by arithmetic, not by fault.
772
619
  const BUNDLE_MIN_ASSETS = 3;
773
620
 
774
- /* An asset's name with its content hash taken out, `assets/vendor-DlAUqK2U.js` becomes `assets/vendor.js`.
775
- *
776
- * Without this the digest changes on every single build, because a content hash changing is the entire point of a
777
- * content hash. The chore would badge after every `pnpm build` while reporting nothing new, which is precisely
778
- * the lit-every-day failure the digest exists to prevent.
779
- *
780
- * Eight or more characters containing a digit, immediately before the final extension: long enough to leave
781
- * `vendor-react.js` and `.min.js` alone, specific enough to catch Vite's `-DlAUqK2U` and webpack's `.9f2a1b0c`. */
621
+ // Strips a build asset's content hash (`vendor-DlAUqK2U.js` → `vendor.js`) so the digest doesn't change on every
622
+ // build; long and specific enough to leave `vendor-react.js` alone but catch Vite's and webpack's hash formats.
782
623
  const stableAsset = (path: string): string => path.replace(/[.-](?=[A-Za-z0-9_-]*[0-9])[A-Za-z0-9_-]{8,}(\.[a-z0-9]+)$/, `$1`);
783
624
 
784
625
  const bundleWeight: Chore = {
@@ -801,8 +642,8 @@ const bundleWeight: Chore = {
801
642
  if (assets.length < BUNDLE_MIN_ASSETS || totalGzip === 0) {
802
643
  return undefined;
803
644
  }
804
- // By GZIP, not by raw bytes. What is on disk is not what crosses the wire, and a large but highly
805
- // compressible asset, a source map comment, a big JSON blob, is not the download this is about.
645
+ // By gzip, not raw bytes: what's on disk isn't what crosses the wire, and a compressible asset isn't the
646
+ // download this is about.
806
647
  const ranked = assets.toSorted((left, right) => right.gzip - left.gzip);
807
648
  const largest = ranked[0];
808
649
  if (largest === undefined) {
@@ -817,8 +658,8 @@ const bundleWeight: Chore = {
817
658
  detail: ranked
818
659
  .slice(0, DETAIL_LIMIT)
819
660
  .map((asset) => `${bytesLabel(asset.gzip)} gzipped · ${asset.path} (${bytesLabel(asset.bytes)} on disk)`),
820
- // The bucketed total and the hash-stripped identities of the biggest chunks. A rebuild of the same
821
- // code is silent; a new heavy chunk appearing, or the whole thing doubling, is not.
661
+ // The bucketed total and hash-stripped identities of the biggest chunks; a rebuild of the same code stays
662
+ // silent, a new heavy chunk doesn't.
822
663
  digest: digestOf(
823
664
  `total:${bucketOf(totalGzip)}`,
824
665
  ...ranked
@@ -826,7 +667,7 @@ const bundleWeight: Chore = {
826
667
  .map((asset) => stableAsset(asset.path))
827
668
  .toSorted(),
828
669
  ),
829
- // Not a risk being carried, however large. `warning` is reserved for something with a clock on it.
670
+ // Not a risk being carried, however large; `warning` is reserved for something with a clock on it.
830
671
  severity: `info`,
831
672
  why:
832
673
  `The build output in ${dir}/ of ${repoLabel(context.repo)} is ${bytesLabel(totalGzip)} gzipped across ` +
@@ -847,14 +688,8 @@ const bundleWeight: Chore = {
847
688
  done: `Done when every recommendation names a specific import boundary and the bytes it would move out of the first download.`,
848
689
  };
849
690
 
850
- /* FRAMEWORK IDIOMS. A migration nobody finished, which is the most ordinary state for a front-end of any age: the
851
- * new way arrived, the new files use it, and the old files keep working, so nothing ever forces the rest.
852
- *
853
- * The digest is the one place this chore differs in shape from its neighbours, and it has to. Digesting the file
854
- * identities, the way the documentation chore does, would re-badge every time anyone touched any of two hundred
855
- * files, because a migration in progress is a set that changes constantly. So it digests the BUCKETED COUNT per
856
- * idiom instead: a kind of legacy code appearing where there was none speaks, real progress through a bucket
857
- * speaks, and one more file drifting in or out of a set of two hundred does not. */
691
+ // Digests the bucketed count per idiom, not file identities: a migration in progress is a set that changes
692
+ // constantly, so a new kind of legacy code appearing, or real progress through a bucket, is what speaks.
858
693
  const frameworkIdiom: Chore = {
859
694
  id: `framework-idiom`,
860
695
  title: `Finish the framework migrations`,
@@ -871,18 +706,9 @@ const frameworkIdiom: Chore = {
871
706
  if (facts === undefined) {
872
707
  return undefined;
873
708
  }
874
- /* Two rules are dropped rather than shown, and the second is the one that would have made this chore
875
- * embarrassing.
876
- *
877
- * AN IDIOM THIS BUILD HAS NEVER HEARD OF. The daemon composes the sweep from its own copy of the table, so
878
- * a sandbox image ahead of the browser can report a rule that has no label or replacement here, and a row
879
- * saying "42 files use react-foo" with no idea what to do about them is worse than no row.
880
- *
881
- * AN IDIOM BELONGING TO A FRAMEWORK THIS REPOSITORY DOES NOT USE. A probe's command is a fixed string, so
882
- * every rule in the table is swept in every repository, and an Angular pattern gets its chance in a Vue
883
- * codebase: `RouterModule.forRoot` inside a comment, a `*ngIf` in an example string, and, the case that
884
- * caught this, the book's own rule table quoting its own patterns back at it. What the repository
885
- * DECLARES is the arbiter, the same `deps` the gate above reads. */
709
+ // Drops rules for two cases: an idiom this build's daemon doesn't know about (a sandbox ahead of the browser),
710
+ // and an idiom belonging to a framework this repository doesn't declare using (a probe scans every rule
711
+ // everywhere).
886
712
  const frameworks = new Set(frameworksOf(context.signals.shape.deps).map((framework) => framework.id));
887
713
  const found = facts.scan.idioms.flatMap(({ id, files }) => {
888
714
  const rule = idiomRule(id);
@@ -917,21 +743,9 @@ const frameworkIdiom: Chore = {
917
743
  done: `Done when a re-scan reports fewer files on that idiom, the repository's type-check and tests pass, and every file you skipped has a one-line reason.`,
918
744
  };
919
745
 
920
- /* COMPONENTS. Two components that are the same component, which is the `library-overlap` finding turned inward:
921
- * somebody needed a button, did not find the one that existed, and wrote a second one. It is the most ordinary
922
- * kind of duplication in a front-end and the one no tool complains about, because both files are perfectly good
923
- * code and neither knows the other exists.
924
- *
925
- * TWO KINDS OF EVIDENCE, and they catch opposite failures. A NAME FAMILY catches components that were written
926
- * separately and never shared a line, `BaseButton.vue` and `ButtonV2.tsx` reduce to the same stem, and no clone
927
- * detector will ever connect them. A CLONE PAIR catches the reverse: two components with unrelated names doing
928
- * the same work, which is what jscpd is actually good at, filtered to the pairs where both sides are components
929
- * so it is a finding about the UI rather than a slice of the repo-wide duplication chore.
930
- *
931
- * It needs jscpd rather than reading it if present. Half a measurement would let the row claim it had looked for
932
- * shared logic in a repository where that sweep has never run, the exact "measured and found nothing" lie the
933
- * `unavailable` state exists to make impossible. jscpd is already running weekly for the duplication chore in any
934
- * Node repository, so the honest choice is also the free one. */
746
+ // Two kinds of evidence: a name family catches components written separately that never shared a line; a clone
747
+ // pair catches unrelated names doing the same work. Needs jscpd rather than reading it if present, so it never claims
748
+ // to have looked when it hasn't.
935
749
  const componentOverlap: Chore = {
936
750
  id: `component-overlap`,
937
751
  title: `Settle on one component per job`,
@@ -960,9 +774,8 @@ const componentOverlap: Chore = {
960
774
  .filter(([, paths]) => paths.length > 1)
961
775
  .map(([stem, paths]) => ({ stem, paths: paths.toSorted() }))
962
776
  .toSorted((left, right) => right.paths.length - left.paths.length);
963
- // Only the clones with a component on BOTH sides. A component that shares a block with a utility module
964
- // is the duplication chore's finding, not this one, and reporting it here would be two rows lighting for
965
- // one fact.
777
+ // Only clones with a component on both sides; one shared with a utility module is the duplication chore's
778
+ // finding, not this one.
966
779
  const inventory = new Set(ui.scan.components.map(normalizePath));
967
780
  const pairs = jscpd.duplication.top.filter(
968
781
  (clone) => inventory.has(normalizePath(clone.first)) && inventory.has(normalizePath(clone.second)),
@@ -980,8 +793,8 @@ const componentOverlap: Chore = {
980
793
  ...families.slice(0, DETAIL_LIMIT).map((family) => `${family.stem} · ${family.paths.join(`, `)}`),
981
794
  ...pairs.map((clone) => `${clone.lines} shared lines · ${normalizePath(clone.first)} ↔ ${normalizePath(clone.second)}`),
982
795
  ],
983
- // Identities on both halves: every component that joins or leaves a family, and every clone pair that
984
- // appears, is genuinely a new fact rather than drift in a number.
796
+ // Identities on both halves: every component joining or leaving a family, and every clone pair, is a new
797
+ // fact, not drift.
985
798
  digest: digestOf(
986
799
  ...families.map((family) => `${family.stem}:${family.paths.join(`+`)}`).toSorted(),
987
800
  ...pairs.map((clone) => `${normalizePath(clone.first)}|${normalizePath(clone.second)}`).toSorted(),
@@ -1011,15 +824,8 @@ const componentOverlap: Chore = {
1011
824
  done: `Done when every group has either a component to keep with a call-site count, a shared unit to extract with a home, or a reason it is fine.`,
1012
825
  };
1013
826
 
1014
- /* TAILWIND. A design system exists to make a decision once; an arbitrary value is that decision being made again,
1015
- * inline, by whoever was in the file. What makes this measurable rather than a matter of taste is that Tailwind
1016
- * spells the bypass out loud, `bg-[#3b82f6]` is the palette being stepped around, in the markup, in a form no
1017
- * reviewer can miss and no linter mentions.
1018
- *
1019
- * Deliberately NOT every arbitrary value. `grid-cols-[1fr_auto]` is the feature working as intended and there is
1020
- * no token it should have been; matching those would make this an objection to Tailwind rather than a finding
1021
- * about this repository. Only colours and pixel sizes, which are the two things the theme definitely already has
1022
- * an answer for. */
827
+ // Only colours and pixel sizes, not every arbitrary value (`grid-cols-[1fr_auto]` is the feature working as
828
+ // intended); those are the two things the theme already has an answer for.
1023
829
  const tailwindBypass: Chore = {
1024
830
  id: `tailwind-arbitrary-values`,
1025
831
  title: `Put hard-coded styles back on the scale`,
@@ -1045,9 +851,8 @@ const tailwindBypass: Chore = {
1045
851
  return {
1046
852
  headline: `${plural(total, `hard-coded value`)} across ${plural(bypasses.length, `file`)}`,
1047
853
  detail: worst.map((entry) => `${entry.path} · ${plural(entry.count, `value`)}`),
1048
- // The worst files by identity, a new file arriving at the top of this list is the event, with the
1049
- // spread and the total riding along bucketed, because both drift by one every time anyone writes
1050
- // markup and neither is worth interrupting somebody about.
854
+ // Worst files by identity lead; the spread and total ride along bucketed, since both drift by one with
855
+ // every markup edit.
1051
856
  digest: digestOf(...worst.map((entry) => entry.path).toSorted(), `files:${bucketOf(bypasses.length)}`, `total:${bucketOf(total)}`),
1052
857
  severity: `info`,
1053
858
  why:
@@ -1069,23 +874,9 @@ const tailwindBypass: Chore = {
1069
874
  done: `Done when a re-scan reports fewer hard-coded values, nothing renders differently, and every value you left has a one-line reason.`,
1070
875
  };
1071
876
 
1072
- /* THE SURVEYS. Chores with no measurement at all, and they are here because the absence of a measurement is not
1073
- * the absence of value, these are the reviews a codebase silently rots without, and none of them can be detected
1074
- * by a tool. Their trigger is the calendar, and the ledger is what makes that trigger honest: a survey is due
1075
- * because it has not been done in a quarter, which is a claim the panel can show and the reader can check.
1076
- *
1077
- * All of them are report-stance. A survey that starts editing is the most surprising thing this surface could do,
1078
- * and none of them has a specific enough finding to justify a diff.
1079
- *
1080
- * A SURVEY NEEDS ITS `applies` GATE MORE THAN A MEASURED CHORE DOES, not less, and this is the trap the shape of
1081
- * the thing sets. A measured chore is gated by its own evidence for free: no undocumented packages, no finding,
1082
- * no row. A survey has no evidence to be absent, "90 days have passed" is true of every repository in the
1083
- * world, so without a gate it fires everywhere, forever, including in the repositories where its subject does
1084
- * not exist. "Re-read the documentation against the code" in a repository with no documentation is the exact
1085
- * failure, and it is not a hypothetical: it is what this helper did before the gate existed.
1086
- *
1087
- * An options object rather than the eight positional arguments this grew into: `id, title, icon, description,
1088
- * diagnosis, goal, done, 90` reads as nothing at all at the call site, and the gate would have made it nine. */
877
+ // Chores with no measurement at all, triggered by the calendar; the ledger is what makes that trigger honest.
878
+ // All are report-stance. `applies` matters more here than for a measured chore: a survey has no evidence to be absent,
879
+ // so an ungated one fires everywhere, forever.
1089
880
  interface SurveySpec {
1090
881
  readonly id: string;
1091
882
  readonly title: string;
@@ -1095,9 +886,8 @@ interface SurveySpec {
1095
886
  readonly goal: string;
1096
887
  readonly done: string;
1097
888
  readonly cadenceDays: number;
1098
- // What must exist in the repository for this review to have a subject. Required, not optional, precisely
1099
- // because forgetting it is the failure mode above, a survey that genuinely applies everywhere still has to
1100
- // say so out loud, with `() => undefined`.
889
+ // What must exist for this review to have a subject; required, not optional, since a survey that applies everywhere
890
+ // must say so explicitly.
1101
891
  readonly applies: (signals: ChoreSignals) => string | undefined;
1102
892
  }
1103
893
 
@@ -1106,9 +896,8 @@ const survey = ({ id, title, icon, description, diagnosis, goal, done, cadenceDa
1106
896
  title,
1107
897
  icon,
1108
898
  description,
1109
- // Not a parameter of SurveySpec, and it never will be: a survey has no measurement, so "due because it has
1110
- // been that long" IS the surveying kind. The two are the same claim spelled twice, and the test below holds
1111
- // them to it in both directions.
899
+ // Not a SurveySpec parameter: a survey has no measurement, so "due because it has been that long" is the surveying
900
+ // kind.
1112
901
  kind: `surveying`,
1113
902
  criterion: `${cadenceDays} days have passed since this review was last run.`,
1114
903
  applies,
@@ -1116,8 +905,7 @@ const survey = ({ id, title, icon, description, diagnosis, goal, done, cadenceDa
1116
905
  needs: [],
1117
906
  cadenceMs: cadenceDays * DAY_MS,
1118
907
  survey: true,
1119
- // A survey's evidence is that time has passed, so the digest is the PERIOD it is due for: one badge per
1120
- // quarter, and a run inside that quarter settles it until the next one begins.
908
+ // A survey's evidence is that time passed, so the digest is the period it is due for: one badge per cadence window.
1121
909
  assess: (context) => ({
1122
910
  headline: `Not surveyed in ${cadenceDays} days`,
1123
911
  detail: [`Cadence · every ${cadenceDays} days`],
@@ -1130,9 +918,8 @@ const survey = ({ id, title, icon, description, diagnosis, goal, done, cadenceDa
1130
918
  done,
1131
919
  });
1132
920
 
1133
- // Below this a repository is too small for cross-cutting patterns to have diverged from each other: there is one
1134
- // way things are done because there is barely more than one place doing them. Counted in INDEXED files, so a
1135
- // scaffold that is mostly config and lockfiles does not pass it by accident.
921
+ // Below this a repo is too small for cross-cutting patterns to have diverged; counted in indexed files so a config-only
922
+ // scaffold doesn't pass by accident.
1136
923
  const PATTERNS_FLOOR = 25;
1137
924
 
1138
925
  const patterns = survey({
@@ -1148,8 +935,8 @@ const patterns = survey({
1148
935
  `estimate the size of the conversion. Do not convert anything.`,
1149
936
  done: `Done when each concern has a named convention, a reference file, and a count of the sites that diverge from it.`,
1150
937
  cadenceDays: 90,
1151
- // The one cause that is a measurement rather than an absence, and it still groups: every chore gated on size
1152
- // is gated on the SAME size, so the string is the same string.
938
+ // The one cause that is a measurement, not an absence; every size-gated chore uses this same string so they group
939
+ // together.
1153
940
  applies: (signals) => (signals.totals.files >= PATTERNS_FLOOR ? undefined : `only ${signals.totals.files} indexed files`),
1154
941
  });
1155
942
 
@@ -1169,15 +956,8 @@ const deprecated = survey({
1169
956
  applies: (signals) => (signals.shape.packageManifest ? undefined : `no package.json`),
1170
957
  });
1171
958
 
1172
- /* THE CHORE THAT NAMED THE PROBLEM. Gated on documents actually EXISTING, which is the whole reason `applies`
1173
- * exists: without it this survey fires on its cadence in every repository, including the ones with nothing to
1174
- * re-read, and the first thing an owner of a fresh workspace sees is an offer to re-read documentation they have
1175
- * never written. That is not a chore being wrong about a threshold, it is the surface admitting it never looked.
1176
- *
1177
- * Note which fact it gates on: the MAP, not the directory. An empty `docs/architecture/` is a directory somebody
1178
- * made and never filled, and a gate on the directory would put the chore back exactly where it started. The
1179
- * survey then reads the package READMEs too, they are the package pages, but a repo with no map has not been
1180
- * documented at all, and that is the case worth staying quiet for. */
959
+ // Gated on the docs map existing, not the directory: an empty docs/architecture/ is undocumented too. Also
960
+ // reads the package READMEs, but a repo with no map hasn't been documented at all.
1181
961
  const documentationDrift = survey({
1182
962
  id: `documentation-drift`,
1183
963
  title: `Re-read the documentation against the code`,
@@ -1193,12 +973,8 @@ const documentationDrift = survey({
1193
973
  applies: (signals) => (signals.shape.docs.length > 0 ? undefined : `no architecture documents`),
1194
974
  });
1195
975
 
1196
- /* THE TWO CHORES THAT ONLY EXIST WHERE THEIR SUBJECT DOES. Both are surveys, nothing here can measure whether a
1197
- * pipeline caches well or an image is bigger than it needs to be without running them, and running someone's CI
1198
- * to find out would be a strange thing for a maintenance panel to do, so both are gated on the artefact itself.
1199
- * Together they are the argument for `applies` being first-class rather than folded into `assess`: neither has
1200
- * any evidence to be absent, and in a repository with no pipeline and no image both would otherwise sit in the
1201
- * list forever, permanently due, describing work that cannot be done. */
976
+ // Both surveys, since nothing here can measure pipeline caching or image bloat without running them; gated on
977
+ // the artefact itself so a repo with neither doesn't sit permanently due.
1202
978
  const pipelines = survey({
1203
979
  id: `ci-hygiene`,
1204
980
  title: `Tighten the CI pipeline`,
@@ -1231,25 +1007,9 @@ const images = survey({
1231
1007
  applies: (signals) => (signals.shape.dockerfiles.length > 0 ? undefined : `no Dockerfile`),
1232
1008
  });
1233
1009
 
1234
- /* THE BOOK'S ORDER, which is the panel's reading order and therefore a product decision rather than whatever
1235
- * order these were written in. It narrows from "this is a risk you are carrying right now" to "this is worth
1236
- * thinking about this quarter".
1237
- *
1238
- * This used to be a comment above a hand-sorted array, the four kinds named in prose, the order maintained by
1239
- * whoever added the last chore, and nothing anywhere that could check the two agreed. It was also thrown away at
1240
- * render: the panel listed every chore in one flat column, so the single editorial claim this surface makes
1241
- * ("a live advisory and a quarterly re-read are not the same kind of thing") was invisible and therefore
1242
- * unarguable, on a page whose whole design is that every claim shows its working.
1243
- *
1244
- * So the kinds are data. They order the book here, they group the rows in the panel, and `caption` is the
1245
- * sentence the panel puts beside each group so the grouping argues for itself.
1246
- *
1247
- * Ordering is by KIND, not by whether a given repository will see them: a chore that does not apply is dropped
1248
- * from that repository's list entirely (verdict.ts), so the reading order never has holes in it. It is also why
1249
- * a block of chores written together does not READ together: the front-end four are one paragraph in this file
1250
- * because they share a gate and a probe, and `kind` is what puts a Vue repository's bundle row next to its
1251
- * dependency row rather than in a "front-end" section at the bottom. Where a chore is written and where it is
1252
- * ranked are two separate facts, and only one of them is a product decision. */
1010
+ // The panel's reading order, as data rather than a hand-sorted array: `kind` orders the book and groups the
1011
+ // panel's rows, `caption` argues for the grouping. Ordered by kind, not by which repository will see them; a
1012
+ // non-applicable chore is dropped entirely, so the order never has holes.
1253
1013
  export interface ChoreKindSpec {
1254
1014
  readonly kind: ChoreKind;
1255
1015
  // Title case, because the panel renders it as a group heading rather than as a sentence.
@@ -1265,8 +1025,8 @@ export const CHORE_KINDS: readonly ChoreKindSpec[] = [
1265
1025
  { kind: `surveying`, label: `Surveying`, caption: `periodic reads with nothing measuring them, due because it has been that long` },
1266
1026
  ];
1267
1027
 
1268
- // Declaration order, which decides nothing but the order WITHIN a kind, the sort below is stable, so the two
1269
- // facts stay separable: this list is where a chore is written down, CHORE_KINDS is where it is ranked.
1028
+ // Declaration order decides nothing but order within a kind (the sort below is stable); this is where a chore
1029
+ // is written, CHORE_KINDS is where it is ranked.
1270
1030
  const BOOK: readonly Chore[] = [
1271
1031
  security,
1272
1032
  runtime,
@@ -1290,20 +1050,17 @@ const BOOK: readonly Chore[] = [
1290
1050
 
1291
1051
  const KIND_ORDER: readonly ChoreKind[] = CHORE_KINDS.map(({ kind }) => kind);
1292
1052
 
1293
- // Sorted rather than filtered into groups, so no chore can ever be dropped out of the book by a kind the list
1294
- // above forgot, a missing kind sorts to the front, where it is visible, instead of vanishing.
1053
+ // Sorted, not filtered into groups, so a kind missing from the list above sorts to the front, visible, instead of
1054
+ // vanishing.
1295
1055
  export const CHORES: readonly Chore[] = BOOK.toSorted((left, right) => KIND_ORDER.indexOf(left.kind) - KIND_ORDER.indexOf(right.kind));
1296
1056
 
1297
1057
  export const choreById = (id: string): Chore | undefined => CHORES.find((chore) => chore.id === id);
1298
1058
 
1299
- // The prompt for one chore against one finding. Built here rather than in the view because the panel, the badge's
1300
- // tooltip and the automation that runs unattended must all be describing the same turn.
1301
- /* THE SCHEDULED TURN, for a chore woken by its automation rather than started from the panel. Same four parts and
1302
- * the same invariants, a chore asks for the same work whoever started it, with the guard's own report standing
1303
- * in for the finding, because at 3am there is no verdict to quote and no reader to have checked it first.
1304
- *
1305
- * Workspace-wide rather than per repository: an automation's guard runs at the workspace root on the sandbox's
1306
- * clock, and it has no repo argument to be scoped by. */
1059
+ // The prompt for one chore, built here rather than in the view, so the panel, the badge's tooltip and an
1060
+ // unattended automation all describe the same turn.
1061
+ // Same four parts as a finding-driven turn, with the guard's own report standing in for the finding, since at
1062
+ // 3am there is no verdict to quote. Workspace-wide: an automation's guard runs at the root with no repo argument to
1063
+ // scope it.
1307
1064
  export const choreAutomationPrompt = (chore: Chore): string | undefined =>
1308
1065
  chore.automation === undefined
1309
1066
  ? undefined
@@ -1319,9 +1076,8 @@ export const choreAutomationPrompt = (chore: Chore): string | undefined =>
1319
1076
  export const chorePrompt = (chore: Chore, finding: ChoreFinding, repo: string): string =>
1320
1077
  composeAsk({
1321
1078
  subject: `${chore.title} in ${repoLabel(repo)}.`,
1322
- // The RULE before the numbers. An agent told only "4 majors waiting" has to infer why anyone cares; told
1323
- // the criterion it was woken by, it can also tell us the criterion was wrong, which is the single most
1324
- // useful thing a chore turn can report back, and the only way the book gets better.
1079
+ // The rule before the numbers: an agent told the criterion, not just the count, can report that the criterion
1080
+ // itself was wrong.
1325
1081
  why: `${finding.why} You were woken because: ${chore.criterion} ${TRIAGE_NOTE}`,
1326
1082
  diagnosis: chore.diagnosis,
1327
1083
  goal: chore.goal,