@indigoai-us/hq-cli 5.313.0 → 5.314.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 (1174) hide show
  1. package/CHANGELOG.md +1 -4300
  2. package/assets/scaffold/core/scripts/checkpoint-stop-gate.sh +43 -281
  3. package/assets/scaffold/core/scripts/hook-lib.sh +50 -345
  4. package/assets/scaffold/core/scripts/hq-session.sh +23 -184
  5. package/assets/scaffold/core/scripts/lib/session-id.sh +2 -3
  6. package/assets/scaffold/core/scripts/lib/session-scope-capability.sh +1 -1
  7. package/assets/scaffold/core/scripts/lib/work-mesh-enqueue.sh +1 -2
  8. package/assets/scaffold/core/scripts/qmd-reindex-after-sync.sh +87 -10
  9. package/assets/scaffold/core/scripts/rebuild-company-knowledge-index.sh +3 -36
  10. package/assets/scaffold/core/scripts/rebuild-projects-index.sh +12 -99
  11. package/assets/scaffold/core/scripts/token-usage-report.sh +20 -81
  12. package/dist/bin/hq-auth-refresh.d.ts +0 -2
  13. package/dist/bin/hq-auth-refresh.js +6 -12
  14. package/dist/commands/__fixtures__/access-vault.d.ts +0 -2
  15. package/dist/commands/__fixtures__/access-vault.js +1 -1
  16. package/dist/commands/_patterns.d.ts +0 -16
  17. package/dist/commands/_patterns.js +3 -20
  18. package/dist/commands/access.d.ts +1 -2
  19. package/dist/commands/access.js +49 -58
  20. package/dist/commands/agents.d.ts +4 -106
  21. package/dist/commands/agents.js +45 -924
  22. package/dist/commands/auth.d.ts +0 -1
  23. package/dist/commands/auth.js +19 -189
  24. package/dist/commands/billing.d.ts +0 -3
  25. package/dist/commands/billing.js +1 -6
  26. package/dist/commands/channels.js +1 -56
  27. package/dist/commands/cloud-demote.js +2 -3
  28. package/dist/commands/cloud-provision.d.ts +0 -14
  29. package/dist/commands/cloud-provision.js +58 -232
  30. package/dist/commands/cloud.d.ts +15 -49
  31. package/dist/commands/cloud.js +122 -357
  32. package/dist/commands/company-transfer.d.ts +28 -4
  33. package/dist/commands/company-transfer.js +49 -5
  34. package/dist/commands/company.js +3 -68
  35. package/dist/commands/core-checkpoint.d.ts +9 -19
  36. package/dist/commands/core-checkpoint.js +37 -301
  37. package/dist/commands/core.d.ts +0 -4
  38. package/dist/commands/core.js +80 -277
  39. package/dist/commands/crm.js +3 -52
  40. package/dist/commands/db-provision.js +4 -4
  41. package/dist/commands/db-sql.js +21 -7
  42. package/dist/commands/dm.d.ts +12 -119
  43. package/dist/commands/dm.js +38 -388
  44. package/dist/commands/doctor.d.ts +0 -12
  45. package/dist/commands/doctor.js +12 -158
  46. package/dist/commands/feedback.d.ts +0 -6
  47. package/dist/commands/feedback.js +37 -86
  48. package/dist/commands/files-browse.d.ts +12 -32
  49. package/dist/commands/files-browse.js +60 -176
  50. package/dist/commands/files.d.ts +0 -17
  51. package/dist/commands/files.js +47 -300
  52. package/dist/commands/group-grants.js +2 -3
  53. package/dist/commands/groups.js +5 -6
  54. package/dist/commands/index-cmd.d.ts +1 -19
  55. package/dist/commands/index-cmd.js +7 -74
  56. package/dist/commands/integrations-api.d.ts +10 -15
  57. package/dist/commands/integrations-api.js +22 -27
  58. package/dist/commands/integrations-connect.d.ts +13 -51
  59. package/dist/commands/integrations-connect.js +71 -86
  60. package/dist/commands/integrations-core.d.ts +6 -6
  61. package/dist/commands/integrations-core.js +11 -25
  62. package/dist/commands/integrations-import.d.ts +1 -1
  63. package/dist/commands/integrations-import.js +24 -43
  64. package/dist/commands/integrations-manage.js +13 -20
  65. package/dist/commands/integrations.d.ts +0 -8
  66. package/dist/commands/integrations.js +7 -94
  67. package/dist/commands/login.js +6 -49
  68. package/dist/commands/mcp-registration.d.ts +25 -32
  69. package/dist/commands/mcp-registration.js +23 -256
  70. package/dist/commands/mcp-status.js +0 -1
  71. package/dist/commands/meetings.js +34 -55
  72. package/dist/commands/members.js +1 -5
  73. package/dist/commands/mesh.d.ts +0 -11
  74. package/dist/commands/mesh.js +76 -1086
  75. package/dist/commands/onboard-identity-guard.d.ts +1 -1
  76. package/dist/commands/onboard.js +5 -24
  77. package/dist/commands/pack-install.js +1 -3
  78. package/dist/commands/packs.js +1 -11
  79. package/dist/commands/people.d.ts +0 -4
  80. package/dist/commands/people.js +3 -37
  81. package/dist/commands/publish.d.ts +1 -8
  82. package/dist/commands/publish.js +4 -17
  83. package/dist/commands/reindex.js +6 -56
  84. package/dist/commands/rescue.d.ts +0 -4
  85. package/dist/commands/rescue.js +17 -27
  86. package/dist/commands/run.js +4 -18
  87. package/dist/commands/safe-extract.d.ts +2 -11
  88. package/dist/commands/safe-extract.js +8 -36
  89. package/dist/commands/scaffold-fast.d.ts +41 -0
  90. package/dist/commands/scaffold-fast.js +57 -0
  91. package/dist/commands/secrets.d.ts +2 -20
  92. package/dist/commands/secrets.js +71 -175
  93. package/dist/commands/skill.d.ts +4 -35
  94. package/dist/commands/skill.js +18 -357
  95. package/dist/commands/sync-mode.d.ts +0 -11
  96. package/dist/commands/sync-mode.js +0 -30
  97. package/dist/commands/sync-narrow.js +5 -36
  98. package/dist/commands/team-sync.js +10 -71
  99. package/dist/commands/update.js +0 -6
  100. package/dist/commands/whoami.d.ts +0 -22
  101. package/dist/commands/whoami.js +4 -137
  102. package/dist/commands/workers.d.ts +14 -2
  103. package/dist/commands/workers.js +10 -7
  104. package/dist/fast-core.d.ts +7 -6
  105. package/dist/fast-core.js +24 -87
  106. package/dist/index.d.ts +4 -3
  107. package/dist/index.js +9 -59
  108. package/dist/lazy-commands.d.ts +44 -20
  109. package/dist/lazy-commands.js +58 -60
  110. package/dist/lib/company-skill-wrapper.d.ts +0 -1
  111. package/dist/lib/company-skill-wrapper.js +29 -121
  112. package/dist/lib/core-utils/codex-skill-bridge.d.ts +1 -2
  113. package/dist/lib/core-utils/qmd-reindex-after-sync.d.ts +1 -14
  114. package/dist/lib/core-utils/qmd-reindex-after-sync.js +17 -101
  115. package/dist/lib/core-utils/soft-timeout.js +1 -1
  116. package/dist/lib/core-utils/timeout-guard.d.ts +3 -3
  117. package/dist/lib/core-utils/timeout-guard.js +13 -28
  118. package/dist/lib/core-utils/token-usage-report.js +3 -17
  119. package/dist/lib/db/control-plane.js +0 -6
  120. package/dist/lib/db/local.d.ts +5 -0
  121. package/dist/lib/db/local.js +1 -1
  122. package/dist/lib/db/migrate.d.ts +12 -0
  123. package/dist/lib/db/migrate.js +5 -5
  124. package/dist/lib/db/remote-sql.d.ts +2 -2
  125. package/dist/lib/db/remote-sql.js +3 -3
  126. package/dist/lib/db/sql.d.ts +10 -0
  127. package/dist/lib/db/sql.js +8 -4
  128. package/dist/lib/doctor/__testing__/fake-hq-tree.d.ts +1 -1
  129. package/dist/lib/doctor/__testing__/fake-hq-tree.js +1 -1
  130. package/dist/lib/doctor/checks/claude-wiring.js +1 -70
  131. package/dist/lib/doctor/checks/codex-wiring.d.ts +4 -0
  132. package/dist/lib/doctor/checks/codex-wiring.js +35 -3
  133. package/dist/lib/doctor/checks/grok-wiring.js +34 -1
  134. package/dist/lib/doctor/checks/integrations.js +0 -11
  135. package/dist/lib/doctor/checks/runtime-health.d.ts +17 -4
  136. package/dist/lib/doctor/checks/runtime-health.js +7 -20
  137. package/dist/lib/doctor/checks/sync-health.d.ts +0 -21
  138. package/dist/lib/doctor/checks/sync-health.js +2 -72
  139. package/dist/lib/doctor/checks/work-context.js +6 -20
  140. package/dist/lib/doctor/compat.d.ts +16 -0
  141. package/dist/lib/doctor/compat.js +3 -4
  142. package/dist/lib/doctor/deep/effects.js +3 -1
  143. package/dist/lib/doctor/deep/executor.d.ts +10 -4
  144. package/dist/lib/doctor/deep/executor.js +1 -1
  145. package/dist/lib/doctor/deep/parity.d.ts +29 -2
  146. package/dist/lib/doctor/deep/parity.js +7 -7
  147. package/dist/lib/doctor/deep/sandbox.d.ts +25 -7
  148. package/dist/lib/doctor/deep/sandbox.js +7 -5
  149. package/dist/lib/doctor/fix/apply.d.ts +8 -79
  150. package/dist/lib/doctor/fix/apply.js +80 -292
  151. package/dist/lib/doctor/fix/remediation.d.ts +6 -14
  152. package/dist/lib/doctor/fix/remediation.js +9 -49
  153. package/dist/lib/doctor/fixtures/schema.js +3 -1
  154. package/dist/lib/doctor/json-output.d.ts +1 -17
  155. package/dist/lib/doctor/json-output.js +2 -7
  156. package/dist/lib/doctor/platform.d.ts +26 -0
  157. package/dist/lib/doctor/platform.js +5 -5
  158. package/dist/lib/doctor/registry.d.ts +0 -14
  159. package/dist/lib/doctor/registry.js +0 -71
  160. package/dist/lib/doctor/report.js +1 -1
  161. package/dist/lib/doctor/types.d.ts +0 -5
  162. package/dist/lib/doctor/types.js +0 -20
  163. package/dist/lib/flag-registry-worker.js +1 -12
  164. package/dist/lib/flag-registry.d.ts +6 -26
  165. package/dist/lib/flag-registry.js +16 -133
  166. package/dist/lib/index-render/companies.d.ts +1 -4
  167. package/dist/lib/index-render/companies.js +3 -66
  168. package/dist/lib/index-render/company-knowledge.js +17 -80
  169. package/dist/lib/index-render/index.d.ts +0 -1
  170. package/dist/lib/index-render/index.js +1 -2
  171. package/dist/lib/index-render/projects.js +5 -82
  172. package/dist/lib/index-render/shared.d.ts +1 -13
  173. package/dist/lib/index-render/shared.js +2 -41
  174. package/dist/lib/mesh/api.d.ts +10 -103
  175. package/dist/lib/mesh/api.js +64 -334
  176. package/dist/lib/mesh/client.d.ts +2 -3
  177. package/dist/lib/mesh/client.js +7 -26
  178. package/dist/lib/mesh/live/backfill-held.d.ts +16 -67
  179. package/dist/lib/mesh/live/backfill-held.js +61 -415
  180. package/dist/lib/mesh/live/backoff.d.ts +2 -2
  181. package/dist/lib/mesh/live/backoff.js +3 -16
  182. package/dist/lib/mesh/live/daemon/board-refresh.d.ts +1 -7
  183. package/dist/lib/mesh/live/daemon/board-refresh.js +30 -78
  184. package/dist/lib/mesh/live/daemon/credentials.d.ts +10 -64
  185. package/dist/lib/mesh/live/daemon/credentials.js +20 -270
  186. package/dist/lib/mesh/live/daemon/doctor.d.ts +0 -53
  187. package/dist/lib/mesh/live/daemon/doctor.js +6 -190
  188. package/dist/lib/mesh/live/daemon/index.d.ts +10 -13
  189. package/dist/lib/mesh/live/daemon/index.js +6 -7
  190. package/dist/lib/mesh/live/daemon/install.d.ts +1 -255
  191. package/dist/lib/mesh/live/daemon/install.js +13 -811
  192. package/dist/lib/mesh/live/daemon/paths.d.ts +0 -2
  193. package/dist/lib/mesh/live/daemon/paths.js +0 -2
  194. package/dist/lib/mesh/live/daemon/presence.d.ts +5 -24
  195. package/dist/lib/mesh/live/daemon/presence.js +10 -79
  196. package/dist/lib/mesh/live/daemon/run.d.ts +2 -48
  197. package/dist/lib/mesh/live/daemon/run.js +33 -485
  198. package/dist/lib/mesh/live/daemon/state.d.ts +2 -19
  199. package/dist/lib/mesh/live/daemon/state.js +2 -34
  200. package/dist/lib/mesh/live/daemon/transcript-watch.d.ts +9 -45
  201. package/dist/lib/mesh/live/daemon/transcript-watch.js +31 -227
  202. package/dist/lib/mesh/live/emit-client.d.ts +0 -8
  203. package/dist/lib/mesh/live/emit-client.js +8 -23
  204. package/dist/lib/mesh/live/emit-evidence.d.ts +0 -19
  205. package/dist/lib/mesh/live/emit-evidence.js +2 -20
  206. package/dist/lib/mesh/live/emit.d.ts +0 -9
  207. package/dist/lib/mesh/live/emit.js +2 -28
  208. package/dist/lib/mesh/live/enqueue.d.ts +0 -5
  209. package/dist/lib/mesh/live/enqueue.js +0 -19
  210. package/dist/lib/mesh/live/flush.d.ts +5 -17
  211. package/dist/lib/mesh/live/flush.js +38 -391
  212. package/dist/lib/mesh/live/format-spool-line.d.ts +2 -5
  213. package/dist/lib/mesh/live/format-spool-line.js +0 -10
  214. package/dist/lib/mesh/live/paths.d.ts +0 -2
  215. package/dist/lib/mesh/live/paths.js +0 -4
  216. package/dist/lib/mesh/live/session-event.schema.json +1 -24
  217. package/dist/lib/mesh/live/session-events-client.d.ts +0 -2
  218. package/dist/lib/mesh/live/session-events-client.js +0 -26
  219. package/dist/lib/mesh/live/spool.d.ts +0 -19
  220. package/dist/lib/mesh/live/spool.js +3 -269
  221. package/dist/lib/mesh/live/validate-session-event.d.ts +1 -1
  222. package/dist/lib/mesh/live/validate-session-event.js +1 -1
  223. package/dist/lib/plan-limit-nag.d.ts +6 -102
  224. package/dist/lib/plan-limit-nag.js +43 -348
  225. package/dist/lib/scan-packages/index.d.ts +0 -2
  226. package/dist/lib/scan-packages/index.js +6 -168
  227. package/dist/lib/search-index/background.d.ts +1 -8
  228. package/dist/lib/search-index/background.js +200 -55
  229. package/dist/lib/search-index/index.d.ts +0 -12
  230. package/dist/lib/search-index/index.js +7 -153
  231. package/dist/lib/work-context/company.d.ts +20 -22
  232. package/dist/lib/work-context/company.js +40 -124
  233. package/dist/lib/work-context/config.d.ts +11 -58
  234. package/dist/lib/work-context/config.js +83 -334
  235. package/dist/lib/work-context/contract.d.ts +0 -13
  236. package/dist/lib/work-context/contract.schema.json +1 -3
  237. package/dist/lib/work-context/index.d.ts +25 -0
  238. package/dist/lib/work-context/index.js +21 -0
  239. package/dist/lib/work-context/outbox.d.ts +5 -27
  240. package/dist/lib/work-context/outbox.js +6 -135
  241. package/dist/lib/work-context/reconcile.d.ts +0 -15
  242. package/dist/lib/work-context/reconcile.js +29 -405
  243. package/dist/lib/work-context/state.d.ts +10 -93
  244. package/dist/lib/work-context/state.js +29 -342
  245. package/dist/lib/workers-registry/index.js +8 -62
  246. package/dist/main.d.ts +0 -32
  247. package/dist/main.js +73 -273
  248. package/dist/node-network-compat.d.ts +30 -2
  249. package/dist/node-network-compat.js +51 -4
  250. package/dist/node-preflight.d.ts +1 -7
  251. package/dist/node-preflight.js +5 -5
  252. package/dist/register-all.d.ts +29 -4
  253. package/dist/register-all.js +233 -4
  254. package/dist/run/discover-schemas.d.ts +1 -2
  255. package/dist/run/env-graph-guard.d.ts +2 -2
  256. package/dist/run/env-graph-guard.js +2 -5
  257. package/dist/run/hq-plugin.d.ts +0 -4
  258. package/dist/run/hq-plugin.js +8 -36
  259. package/dist/sentry-before-send.js +0 -80
  260. package/dist/sentry.d.ts +2 -8
  261. package/dist/sentry.js +13 -117
  262. package/dist/startup-registration.d.ts +2 -26
  263. package/dist/startup-registration.js +15 -116
  264. package/dist/utils/cli-telemetry.d.ts +1 -74
  265. package/dist/utils/cli-telemetry.js +7 -434
  266. package/dist/utils/client-health.d.ts +4 -0
  267. package/dist/utils/client-health.js +2 -2
  268. package/dist/utils/cognito-session.d.ts +0 -71
  269. package/dist/utils/cognito-session.js +27 -481
  270. package/dist/utils/contribution-table.d.ts +1 -1
  271. package/dist/utils/environmental-error.d.ts +0 -18
  272. package/dist/utils/environmental-error.js +7 -240
  273. package/dist/utils/expected-cli-error.d.ts +0 -2
  274. package/dist/utils/expected-cli-error.js +0 -4
  275. package/dist/utils/feedback-diagnostics.d.ts +1 -2
  276. package/dist/utils/feedback-log-bundle.d.ts +26 -51
  277. package/dist/utils/feedback-log-bundle.js +31 -211
  278. package/dist/utils/feedback-logs.d.ts +47 -18
  279. package/dist/utils/feedback-logs.js +21 -50
  280. package/dist/utils/feedback-screenshots.d.ts +1 -0
  281. package/dist/utils/feedback-screenshots.js +1 -1
  282. package/dist/utils/hq-roots.d.ts +2 -25
  283. package/dist/utils/hq-roots.js +7 -67
  284. package/dist/utils/incomplete-install-error.d.ts +19 -87
  285. package/dist/utils/incomplete-install-error.js +68 -319
  286. package/dist/utils/install-tree-torn.d.ts +24 -260
  287. package/dist/utils/install-tree-torn.js +51 -998
  288. package/dist/utils/large-file-guard.d.ts +10 -0
  289. package/dist/utils/large-file-guard.js +1 -1
  290. package/dist/utils/local-files-overview.d.ts +8 -4
  291. package/dist/utils/local-files-overview.js +7 -48
  292. package/dist/utils/login-provider.d.ts +0 -7
  293. package/dist/utils/login-provider.js +0 -34
  294. package/dist/utils/pack-contributions.d.ts +14 -2
  295. package/dist/utils/pack-contributions.js +44 -7
  296. package/dist/utils/package-root-diagnostics.d.ts +1 -1
  297. package/dist/utils/people.d.ts +11 -7
  298. package/dist/utils/people.js +20 -5
  299. package/dist/utils/plan-gate-error.d.ts +10 -52
  300. package/dist/utils/plan-gate-error.js +41 -364
  301. package/dist/utils/qmd-model-download-error.d.ts +8 -0
  302. package/dist/utils/qmd-model-download-error.js +1 -1
  303. package/dist/utils/qmd-query-document-error.d.ts +6 -0
  304. package/dist/utils/qmd-query-document-error.js +1 -1
  305. package/dist/utils/redact-error-text.d.ts +2 -0
  306. package/dist/utils/redact-error-text.js +2 -3
  307. package/dist/utils/run-bundled-script.d.ts +0 -6
  308. package/dist/utils/run-bundled-script.js +4 -117
  309. package/dist/utils/sandbox-runner-client.d.ts +1 -2
  310. package/dist/utils/secrets-cache.d.ts +3 -7
  311. package/dist/utils/secrets-cache.js +14 -162
  312. package/dist/utils/self-update.d.ts +1 -34
  313. package/dist/utils/self-update.js +42 -660
  314. package/dist/utils/sentry-fingerprint.d.ts +1 -23
  315. package/dist/utils/sentry-fingerprint.js +31 -223
  316. package/dist/utils/team-upgrade.d.ts +1 -1
  317. package/dist/utils/team-upgrade.js +3 -4
  318. package/dist/utils/vault-api.d.ts +1 -21
  319. package/dist/utils/vault-api.js +84 -251
  320. package/dist/utils/version-check.d.ts +1 -11
  321. package/dist/utils/version-check.js +3 -32
  322. package/dist/utils/version-gate.d.ts +17 -101
  323. package/dist/utils/version-gate.js +70 -645
  324. package/dist/utils/windows-spawn.d.ts +0 -6
  325. package/dist/utils/windows-spawn.js +0 -37
  326. package/package.json +8 -20
  327. package/README.md +0 -113
  328. package/assets/bot-workers/setup/context/USER-GUIDE.md +0 -404
  329. package/assets/bot-workers/setup/context/quick-reference.md +0 -199
  330. package/assets/bot-workers/setup/skills/agents-and-team.md +0 -167
  331. package/assets/bot-workers/setup/skills/explain-hq.md +0 -35
  332. package/assets/bot-workers/setup/skills/first-company.md +0 -74
  333. package/assets/bot-workers/setup/skills/joining-a-team.md +0 -125
  334. package/assets/bot-workers/setup/skills/pricing.md +0 -92
  335. package/assets/bot-workers/setup/skills/standing-help.md +0 -81
  336. package/assets/bot-workers/setup/skills/your-business.md +0 -281
  337. package/assets/bot-workers/setup/worker.yaml +0 -791
  338. package/assets/lanes-hooks/hq-lanes-drain.json +0 -15
  339. package/assets/lanes-hooks/hq-lanes-drain.mjs +0 -275
  340. package/assets/lanes-hooks/hq-lanes-drain.sh +0 -21
  341. package/assets/lanes-reconcile/hq-lanes-reconcile.service +0 -11
  342. package/assets/lanes-reconcile/hq-lanes-reconcile.timer +0 -12
  343. package/assets/scaffold/.claude/hooks/validate-policy-frontmatter.sh +0 -485
  344. package/assets/scaffold/core/scripts/audit-log.sh +0 -384
  345. package/assets/scaffold/core/scripts/clean-worktree-reconcile-handoff.sh +0 -171
  346. package/assets/scaffold/core/scripts/eval-trigger.sh +0 -193
  347. package/assets/scaffold/core/scripts/git-pack-extension-check.sh +0 -164
  348. package/assets/scaffold/core/scripts/handoff-finalize.sh +0 -688
  349. package/assets/scaffold/core/scripts/handoff-open-steps.sh +0 -81
  350. package/assets/scaffold/core/scripts/handoff-post.sh +0 -252
  351. package/assets/scaffold/core/scripts/hq-delegate-bundle.sh +0 -307
  352. package/assets/scaffold/core/scripts/hq-delegate-grant.sh +0 -252
  353. package/assets/scaffold/core/scripts/hq-delegate-pickup.sh +0 -99
  354. package/assets/scaffold/core/scripts/hq-delegate-publish.sh +0 -91
  355. package/assets/scaffold/core/scripts/hq-delegate-repo.sh +0 -158
  356. package/assets/scaffold/core/scripts/hq-delegate-resolve.sh +0 -145
  357. package/assets/scaffold/core/scripts/hq-delegate-secrets.sh +0 -129
  358. package/assets/scaffold/core/scripts/hq-delegate-send.sh +0 -259
  359. package/assets/scaffold/core/scripts/hq-delegate-transfer.sh +0 -175
  360. package/assets/scaffold/core/scripts/hq-delegate-verify.sh +0 -238
  361. package/assets/scaffold/core/scripts/hq-dm-bind.sh +0 -585
  362. package/assets/scaffold/core/scripts/hq-job-notify.sh +0 -389
  363. package/assets/scaffold/core/scripts/hq-job-probe.sh +0 -835
  364. package/assets/scaffold/core/scripts/hq-job-remediate.sh +0 -359
  365. package/assets/scaffold/core/scripts/hq-job-run.sh +0 -1025
  366. package/assets/scaffold/core/scripts/hq-pin.sh +0 -118
  367. package/assets/scaffold/core/scripts/jobs-schedule-parse.sh +0 -310
  368. package/assets/scaffold/core/scripts/jobs-validate.sh +0 -451
  369. package/assets/scaffold/core/scripts/knowledge-prefs.sh +0 -55
  370. package/assets/scaffold/core/scripts/lib/portable.sh +0 -211
  371. package/assets/scaffold/core/scripts/lib/secret-patterns.sh +0 -58
  372. package/assets/scaffold/core/scripts/lib/work-mesh-live-hook.sh +0 -378
  373. package/assets/scaffold/core/scripts/lib/work-mesh-live-rebind.sh +0 -141
  374. package/assets/scaffold/core/scripts/migrate-policy-triggers.sh +0 -373
  375. package/assets/scaffold/core/scripts/ontology-audience-grant.sh +0 -81
  376. package/assets/scaffold/core/scripts/ontology-brief.mjs +0 -93
  377. package/assets/scaffold/core/scripts/ontology-candidate.sh +0 -100
  378. package/assets/scaffold/core/scripts/ontology-garden.mjs +0 -238
  379. package/assets/scaffold/core/scripts/ontology-source-worklist.sh +0 -79
  380. package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +0 -834
  381. package/assets/scaffold/core/scripts/policy-age-report.sh +0 -156
  382. package/assets/scaffold/core/scripts/policy-retire.sh +0 -199
  383. package/assets/scaffold/core/scripts/qmd-reindex-bg.sh +0 -40
  384. package/assets/scaffold/core/scripts/read-policy-frontmatter.sh +0 -32
  385. package/assets/scaffold/core/scripts/refresh-vault-access.sh +0 -188
  386. package/assets/scaffold/core/scripts/register-project.sh +0 -262
  387. package/assets/scaffold/core/scripts/resolve-company.sh +0 -199
  388. package/assets/scaffold/core/scripts/resume-thread-lock.sh +0 -285
  389. package/assets/scaffold/core/scripts/source-yaml-validate.sh +0 -36
  390. package/assets/scaffold/core/scripts/verify-story-deliverables.sh +0 -148
  391. package/assets/scaffold/core/scripts/work-mesh-live-bind-trusted.sh +0 -152
  392. package/assets/scaffold/core/scripts/work-mesh-live-rebind.sh +0 -59
  393. package/assets/scaffold/core/scripts/worktree-gc.sh +0 -362
  394. package/contracts/preflight/v1/fixtures.json +0 -87
  395. package/contracts/preflight/v1/schema.json +0 -58
  396. package/dist/command-catalog.generated.d.ts +0 -10735
  397. package/dist/command-catalog.generated.js +0 -13836
  398. package/dist/command-registration-plan.d.ts +0 -474
  399. package/dist/command-registration-plan.js +0 -136
  400. package/dist/commands/agent-enroll.d.ts +0 -146
  401. package/dist/commands/agent-enroll.js +0 -401
  402. package/dist/commands/agent-inbox.d.ts +0 -9
  403. package/dist/commands/agent-inbox.js +0 -102
  404. package/dist/commands/agent-kit.d.ts +0 -87
  405. package/dist/commands/agent-kit.js +0 -480
  406. package/dist/commands/agent-mcp.d.ts +0 -24
  407. package/dist/commands/agent-mcp.js +0 -127
  408. package/dist/commands/agent-probe.d.ts +0 -77
  409. package/dist/commands/agent-probe.js +0 -335
  410. package/dist/commands/agent.d.ts +0 -13
  411. package/dist/commands/agent.js +0 -40
  412. package/dist/commands/billing-sponsor.d.ts +0 -83
  413. package/dist/commands/billing-sponsor.js +0 -344
  414. package/dist/commands/bot-companies.d.ts +0 -40
  415. package/dist/commands/bot-companies.js +0 -64
  416. package/dist/commands/bot-continuity.d.ts +0 -28
  417. package/dist/commands/bot-continuity.js +0 -68
  418. package/dist/commands/bot-jobs.d.ts +0 -127
  419. package/dist/commands/bot-jobs.js +0 -454
  420. package/dist/commands/bot.d.ts +0 -278
  421. package/dist/commands/bot.js +0 -1982
  422. package/dist/commands/cloud-retire.d.ts +0 -51
  423. package/dist/commands/cloud-retire.js +0 -154
  424. package/dist/commands/company-rename-flag.d.ts +0 -4
  425. package/dist/commands/company-rename-flag.js +0 -7
  426. package/dist/commands/company-rename.d.ts +0 -4
  427. package/dist/commands/company-rename.js +0 -90
  428. package/dist/commands/core-audit-log-native.d.ts +0 -9
  429. package/dist/commands/core-audit-log-native.js +0 -257
  430. package/dist/commands/core-checkpoint-gate-setting.d.ts +0 -59
  431. package/dist/commands/core-checkpoint-gate-setting.js +0 -163
  432. package/dist/commands/core-checkpoint-stop-gate-native.d.ts +0 -34
  433. package/dist/commands/core-checkpoint-stop-gate-native.js +0 -725
  434. package/dist/commands/core-command-catalog.d.ts +0 -34
  435. package/dist/commands/core-command-catalog.js +0 -62
  436. package/dist/commands/core-company-index-scope-flag.d.ts +0 -3
  437. package/dist/commands/core-company-index-scope-flag.js +0 -6
  438. package/dist/commands/core-delegate-w1b.d.ts +0 -10
  439. package/dist/commands/core-delegate-w1b.js +0 -1219
  440. package/dist/commands/core-delegate.d.ts +0 -46
  441. package/dist/commands/core-delegate.js +0 -1040
  442. package/dist/commands/core-dm-bind-native.d.ts +0 -32
  443. package/dist/commands/core-dm-bind-native.js +0 -668
  444. package/dist/commands/core-eval-trigger-native.d.ts +0 -4
  445. package/dist/commands/core-eval-trigger-native.js +0 -12
  446. package/dist/commands/core-git-pack-extension-check-native.d.ts +0 -22
  447. package/dist/commands/core-git-pack-extension-check-native.js +0 -190
  448. package/dist/commands/core-handoff-fast.d.ts +0 -18
  449. package/dist/commands/core-handoff-fast.js +0 -104
  450. package/dist/commands/core-handoff-open-steps.d.ts +0 -21
  451. package/dist/commands/core-handoff-open-steps.js +0 -264
  452. package/dist/commands/core-handoff.d.ts +0 -24
  453. package/dist/commands/core-handoff.js +0 -1144
  454. package/dist/commands/core-hq-session-native.d.ts +0 -39
  455. package/dist/commands/core-hq-session-native.js +0 -579
  456. package/dist/commands/core-job-native-utils.d.ts +0 -6
  457. package/dist/commands/core-job-native-utils.js +0 -80
  458. package/dist/commands/core-job-native.d.ts +0 -5
  459. package/dist/commands/core-job-native.js +0 -16
  460. package/dist/commands/core-job-notify-native.d.ts +0 -36
  461. package/dist/commands/core-job-notify-native.js +0 -359
  462. package/dist/commands/core-job-probe-native.d.ts +0 -45
  463. package/dist/commands/core-job-probe-native.js +0 -564
  464. package/dist/commands/core-job-remediate-native.d.ts +0 -26
  465. package/dist/commands/core-job-remediate-native.js +0 -374
  466. package/dist/commands/core-job-remote-launcher.d.ts +0 -7
  467. package/dist/commands/core-job-remote-launcher.js +0 -51
  468. package/dist/commands/core-job-run-native.d.ts +0 -47
  469. package/dist/commands/core-job-run-native.js +0 -1215
  470. package/dist/commands/core-jobs-native.d.ts +0 -25
  471. package/dist/commands/core-jobs-native.js +0 -1339
  472. package/dist/commands/core-knowledge-prefs.d.ts +0 -11
  473. package/dist/commands/core-knowledge-prefs.js +0 -137
  474. package/dist/commands/core-migrate-policy-triggers-native.d.ts +0 -21
  475. package/dist/commands/core-migrate-policy-triggers-native.js +0 -378
  476. package/dist/commands/core-native-handoff-flag.d.ts +0 -4
  477. package/dist/commands/core-native-handoff-flag.js +0 -7
  478. package/dist/commands/core-native-hook-helper-commands.d.ts +0 -4
  479. package/dist/commands/core-native-hook-helper-commands.js +0 -56
  480. package/dist/commands/core-native-hook-helpers-flag.d.ts +0 -4
  481. package/dist/commands/core-native-hook-helpers-flag.js +0 -7
  482. package/dist/commands/core-native-jobs-flag.d.ts +0 -4
  483. package/dist/commands/core-native-jobs-flag.js +0 -7
  484. package/dist/commands/core-native-policy-flag.d.ts +0 -9
  485. package/dist/commands/core-native-policy-flag.js +0 -12
  486. package/dist/commands/core-native-session-flag.d.ts +0 -4
  487. package/dist/commands/core-native-session-flag.js +0 -7
  488. package/dist/commands/core-native-utilities-flag.d.ts +0 -4
  489. package/dist/commands/core-native-utilities-flag.js +0 -7
  490. package/dist/commands/core-native-utilities.d.ts +0 -29
  491. package/dist/commands/core-native-utilities.js +0 -54
  492. package/dist/commands/core-native-worker-skills-flag.d.ts +0 -4
  493. package/dist/commands/core-native-worker-skills-flag.js +0 -7
  494. package/dist/commands/core-ontology-native.d.ts +0 -17
  495. package/dist/commands/core-ontology-native.js +0 -916
  496. package/dist/commands/core-ontology.d.ts +0 -66
  497. package/dist/commands/core-ontology.js +0 -430
  498. package/dist/commands/core-pin-native.d.ts +0 -14
  499. package/dist/commands/core-pin-native.js +0 -236
  500. package/dist/commands/core-policy-frontmatter.d.ts +0 -8
  501. package/dist/commands/core-policy-frontmatter.js +0 -52
  502. package/dist/commands/core-policy.d.ts +0 -14
  503. package/dist/commands/core-policy.js +0 -1018
  504. package/dist/commands/core-refresh-vault-access-native.d.ts +0 -20
  505. package/dist/commands/core-refresh-vault-access-native.js +0 -229
  506. package/dist/commands/core-register-project-native.d.ts +0 -30
  507. package/dist/commands/core-register-project-native.js +0 -347
  508. package/dist/commands/core-resolve-company-command.d.ts +0 -4
  509. package/dist/commands/core-resolve-company-command.js +0 -42
  510. package/dist/commands/core-resolve-company-native.d.ts +0 -28
  511. package/dist/commands/core-resolve-company-native.js +0 -408
  512. package/dist/commands/core-work-mesh-bind-trusted-native.d.ts +0 -32
  513. package/dist/commands/core-work-mesh-bind-trusted-native.js +0 -190
  514. package/dist/commands/core-work-mesh-live-rebind-native.d.ts +0 -18
  515. package/dist/commands/core-work-mesh-live-rebind-native.js +0 -262
  516. package/dist/commands/core-worker-lint-native.d.ts +0 -4
  517. package/dist/commands/core-worker-lint-native.js +0 -160
  518. package/dist/commands/core-worker-share-native.d.ts +0 -4
  519. package/dist/commands/core-worker-share-native.js +0 -260
  520. package/dist/commands/core-worker-skills-command.d.ts +0 -8
  521. package/dist/commands/core-worker-skills-command.js +0 -33
  522. package/dist/commands/core-worker-skills-runtime.d.ts +0 -33
  523. package/dist/commands/core-worker-skills-runtime.js +0 -86
  524. package/dist/commands/daemon.d.ts +0 -63
  525. package/dist/commands/daemon.js +0 -877
  526. package/dist/commands/deploy-comments.d.ts +0 -3
  527. package/dist/commands/deploy-comments.js +0 -162
  528. package/dist/commands/lanes-accounts.d.ts +0 -28
  529. package/dist/commands/lanes-accounts.js +0 -595
  530. package/dist/commands/lanes-autopilot.d.ts +0 -11
  531. package/dist/commands/lanes-autopilot.js +0 -336
  532. package/dist/commands/lanes-checks.d.ts +0 -51
  533. package/dist/commands/lanes-checks.js +0 -941
  534. package/dist/commands/lanes-hold.d.ts +0 -43
  535. package/dist/commands/lanes-hold.js +0 -655
  536. package/dist/commands/lanes-kpis.d.ts +0 -11
  537. package/dist/commands/lanes-kpis.js +0 -34
  538. package/dist/commands/lanes-message.d.ts +0 -9
  539. package/dist/commands/lanes-message.js +0 -937
  540. package/dist/commands/lanes-move.d.ts +0 -12
  541. package/dist/commands/lanes-move.js +0 -397
  542. package/dist/commands/lanes-questions.d.ts +0 -36
  543. package/dist/commands/lanes-questions.js +0 -1005
  544. package/dist/commands/lanes-report.d.ts +0 -11
  545. package/dist/commands/lanes-report.js +0 -333
  546. package/dist/commands/lanes-resume.d.ts +0 -6
  547. package/dist/commands/lanes-resume.js +0 -564
  548. package/dist/commands/lanes-review.d.ts +0 -10
  549. package/dist/commands/lanes-review.js +0 -56
  550. package/dist/commands/lanes-shared.d.ts +0 -448
  551. package/dist/commands/lanes-shared.js +0 -170
  552. package/dist/commands/lanes-stories.d.ts +0 -15
  553. package/dist/commands/lanes-stories.js +0 -347
  554. package/dist/commands/lanes-watch.d.ts +0 -7
  555. package/dist/commands/lanes-watch.js +0 -216
  556. package/dist/commands/lanes.d.ts +0 -149
  557. package/dist/commands/lanes.js +0 -8973
  558. package/dist/commands/monitor.d.ts +0 -58
  559. package/dist/commands/monitor.js +0 -980
  560. package/dist/commands/onboard-bot-membership.d.ts +0 -32
  561. package/dist/commands/onboard-bot-membership.js +0 -40
  562. package/dist/commands/onboard-create-identity.d.ts +0 -26
  563. package/dist/commands/onboard-create-identity.js +0 -23
  564. package/dist/commands/outpost-pruner.d.ts +0 -3
  565. package/dist/commands/outpost-pruner.js +0 -125
  566. package/dist/commands/personal-connector-settings-flag.d.ts +0 -4
  567. package/dist/commands/personal-connector-settings-flag.js +0 -7
  568. package/dist/commands/personal-targeted-push-flag.d.ts +0 -4
  569. package/dist/commands/personal-targeted-push-flag.js +0 -7
  570. package/dist/commands/personal-targeted-push-paths.d.ts +0 -3
  571. package/dist/commands/personal-targeted-push-paths.js +0 -67
  572. package/dist/commands/report.d.ts +0 -19
  573. package/dist/commands/report.js +0 -537
  574. package/dist/commands/run-feature-telemetry.d.ts +0 -3
  575. package/dist/commands/run-feature-telemetry.js +0 -6
  576. package/dist/commands/staff/reset-test-account.d.ts +0 -110
  577. package/dist/commands/staff/reset-test-account.js +0 -268
  578. package/dist/commands/staff/test-account.d.ts +0 -51
  579. package/dist/commands/staff/test-account.js +0 -196
  580. package/dist/commands/vault-retention-flag.d.ts +0 -3
  581. package/dist/commands/vault-retention-flag.js +0 -9
  582. package/dist/commands/vault-retention.d.ts +0 -11
  583. package/dist/commands/vault-retention.js +0 -69
  584. package/dist/commands/version.d.ts +0 -10
  585. package/dist/commands/version.js +0 -11
  586. package/dist/fast-scaffold.d.ts +0 -86
  587. package/dist/fast-scaffold.js +0 -364
  588. package/dist/lanes-drain-hook.d.ts +0 -14
  589. package/dist/lanes-drain-hook.js +0 -203
  590. package/dist/lib/agent-kit/adopt-identity.d.ts +0 -27
  591. package/dist/lib/agent-kit/adopt-identity.js +0 -60
  592. package/dist/lib/agent-kit/attachment-download.d.ts +0 -24
  593. package/dist/lib/agent-kit/attachment-download.js +0 -47
  594. package/dist/lib/agent-kit/creds.d.ts +0 -106
  595. package/dist/lib/agent-kit/creds.js +0 -163
  596. package/dist/lib/agent-kit/fallback.d.ts +0 -78
  597. package/dist/lib/agent-kit/fallback.js +0 -210
  598. package/dist/lib/agent-kit/inbox-state.d.ts +0 -83
  599. package/dist/lib/agent-kit/inbox-state.js +0 -159
  600. package/dist/lib/agent-kit/kit-config.d.ts +0 -56
  601. package/dist/lib/agent-kit/kit-config.js +0 -65
  602. package/dist/lib/agent-kit/log.d.ts +0 -16
  603. package/dist/lib/agent-kit/log.js +0 -46
  604. package/dist/lib/agent-kit/mcp/attachments.d.ts +0 -126
  605. package/dist/lib/agent-kit/mcp/attachments.js +0 -222
  606. package/dist/lib/agent-kit/mcp/jsonrpc.d.ts +0 -75
  607. package/dist/lib/agent-kit/mcp/jsonrpc.js +0 -164
  608. package/dist/lib/agent-kit/mcp/tools.d.ts +0 -64
  609. package/dist/lib/agent-kit/mcp/tools.js +0 -397
  610. package/dist/lib/agent-kit/paths.d.ts +0 -65
  611. package/dist/lib/agent-kit/paths.js +0 -118
  612. package/dist/lib/agent-kit/private-file.d.ts +0 -29
  613. package/dist/lib/agent-kit/private-file.js +0 -91
  614. package/dist/lib/agent-kit/run/heartbeat.d.ts +0 -72
  615. package/dist/lib/agent-kit/run/heartbeat.js +0 -128
  616. package/dist/lib/agent-kit/run/inbox.d.ts +0 -76
  617. package/dist/lib/agent-kit/run/inbox.js +0 -205
  618. package/dist/lib/agent-kit/run/supervisor.d.ts +0 -35
  619. package/dist/lib/agent-kit/run/supervisor.js +0 -85
  620. package/dist/lib/agent-kit/run/sync.d.ts +0 -33
  621. package/dist/lib/agent-kit/run/sync.js +0 -58
  622. package/dist/lib/agent-kit/services.d.ts +0 -31
  623. package/dist/lib/agent-kit/services.js +0 -55
  624. package/dist/lib/agent-kit/skills.d.ts +0 -18
  625. package/dist/lib/agent-kit/skills.js +0 -151
  626. package/dist/lib/agent-kit/wake.d.ts +0 -83
  627. package/dist/lib/agent-kit/wake.js +0 -243
  628. package/dist/lib/agents/model-catalog.d.ts +0 -62
  629. package/dist/lib/agents/model-catalog.js +0 -275
  630. package/dist/lib/auth-login-provider-state.d.ts +0 -8
  631. package/dist/lib/auth-login-provider-state.js +0 -63
  632. package/dist/lib/aws-sdk-node-warning-output.d.ts +0 -12
  633. package/dist/lib/aws-sdk-node-warning-output.js +0 -22
  634. package/dist/lib/billing/free-month.d.ts +0 -18
  635. package/dist/lib/billing/free-month.js +0 -31
  636. package/dist/lib/billing/plan-limit-refusals.d.ts +0 -69
  637. package/dist/lib/billing/plan-limit-refusals.js +0 -187
  638. package/dist/lib/billing/plan-limit-upgrade-url.d.ts +0 -11
  639. package/dist/lib/billing/plan-limit-upgrade-url.js +0 -66
  640. package/dist/lib/billing/plan-lock.d.ts +0 -143
  641. package/dist/lib/billing/plan-lock.js +0 -439
  642. package/dist/lib/bot/api.d.ts +0 -349
  643. package/dist/lib/bot/api.js +0 -316
  644. package/dist/lib/bot/attachments.d.ts +0 -45
  645. package/dist/lib/bot/attachments.js +0 -89
  646. package/dist/lib/bot/cli-update.d.ts +0 -138
  647. package/dist/lib/bot/cli-update.js +0 -278
  648. package/dist/lib/bot/company-bind.d.ts +0 -27
  649. package/dist/lib/bot/company-bind.js +0 -62
  650. package/dist/lib/bot/config.d.ts +0 -153
  651. package/dist/lib/bot/config.js +0 -233
  652. package/dist/lib/bot/continuity-download.d.ts +0 -28
  653. package/dist/lib/bot/continuity-download.js +0 -75
  654. package/dist/lib/bot/continuity-install.d.ts +0 -14
  655. package/dist/lib/bot/continuity-install.js +0 -101
  656. package/dist/lib/bot/continuity.d.ts +0 -67
  657. package/dist/lib/bot/continuity.js +0 -301
  658. package/dist/lib/bot/creds.d.ts +0 -24
  659. package/dist/lib/bot/creds.js +0 -51
  660. package/dist/lib/bot/daemon.d.ts +0 -173
  661. package/dist/lib/bot/daemon.js +0 -552
  662. package/dist/lib/bot/inbox-poll-backoff-flag.d.ts +0 -24
  663. package/dist/lib/bot/inbox-poll-backoff-flag.js +0 -135
  664. package/dist/lib/bot/inbox-state.d.ts +0 -18
  665. package/dist/lib/bot/inbox-state.js +0 -51
  666. package/dist/lib/bot/index.d.ts +0 -23
  667. package/dist/lib/bot/index.js +0 -23
  668. package/dist/lib/bot/inflight.d.ts +0 -119
  669. package/dist/lib/bot/inflight.js +0 -83
  670. package/dist/lib/bot/job-completions.d.ts +0 -89
  671. package/dist/lib/bot/job-completions.js +0 -132
  672. package/dist/lib/bot/job-run.d.ts +0 -109
  673. package/dist/lib/bot/job-run.js +0 -246
  674. package/dist/lib/bot/local-config.d.ts +0 -61
  675. package/dist/lib/bot/local-config.js +0 -145
  676. package/dist/lib/bot/local-jobs.d.ts +0 -89
  677. package/dist/lib/bot/local-jobs.js +0 -459
  678. package/dist/lib/bot/local-name.d.ts +0 -54
  679. package/dist/lib/bot/local-name.js +0 -114
  680. package/dist/lib/bot/log.d.ts +0 -13
  681. package/dist/lib/bot/log.js +0 -59
  682. package/dist/lib/bot/owner-context.d.ts +0 -79
  683. package/dist/lib/bot/owner-context.js +0 -175
  684. package/dist/lib/bot/paths.d.ts +0 -76
  685. package/dist/lib/bot/paths.js +0 -131
  686. package/dist/lib/bot/progress.d.ts +0 -132
  687. package/dist/lib/bot/progress.js +0 -289
  688. package/dist/lib/bot/promote.d.ts +0 -16
  689. package/dist/lib/bot/promote.js +0 -106
  690. package/dist/lib/bot/promotion-hold.d.ts +0 -24
  691. package/dist/lib/bot/promotion-hold.js +0 -103
  692. package/dist/lib/bot/promotion-receipt.d.ts +0 -9
  693. package/dist/lib/bot/promotion-receipt.js +0 -56
  694. package/dist/lib/bot/promotion-upload.d.ts +0 -16
  695. package/dist/lib/bot/promotion-upload.js +0 -80
  696. package/dist/lib/bot/prompt.d.ts +0 -136
  697. package/dist/lib/bot/prompt.js +0 -433
  698. package/dist/lib/bot/room-policy.d.ts +0 -63
  699. package/dist/lib/bot/room-policy.js +0 -91
  700. package/dist/lib/bot/run.d.ts +0 -217
  701. package/dist/lib/bot/run.js +0 -1869
  702. package/dist/lib/bot/runnable.d.ts +0 -51
  703. package/dist/lib/bot/runnable.js +0 -65
  704. package/dist/lib/bot/runtime/claude.d.ts +0 -50
  705. package/dist/lib/bot/runtime/claude.js +0 -170
  706. package/dist/lib/bot/runtime/codex.d.ts +0 -28
  707. package/dist/lib/bot/runtime/codex.js +0 -153
  708. package/dist/lib/bot/runtime/grok-acp.d.ts +0 -40
  709. package/dist/lib/bot/runtime/grok-acp.js +0 -265
  710. package/dist/lib/bot/runtime/grok.d.ts +0 -41
  711. package/dist/lib/bot/runtime/grok.js +0 -169
  712. package/dist/lib/bot/runtime/index.d.ts +0 -36
  713. package/dist/lib/bot/runtime/index.js +0 -417
  714. package/dist/lib/bot/runtime/messages-stream.d.ts +0 -56
  715. package/dist/lib/bot/runtime/messages-stream.js +0 -194
  716. package/dist/lib/bot/runtime/sanitize.d.ts +0 -18
  717. package/dist/lib/bot/runtime/sanitize.js +0 -28
  718. package/dist/lib/bot/runtime/types.d.ts +0 -159
  719. package/dist/lib/bot/runtime/types.js +0 -51
  720. package/dist/lib/bot/runtime/windows.d.ts +0 -10
  721. package/dist/lib/bot/runtime/windows.js +0 -53
  722. package/dist/lib/bot/runtime-sign-in.d.ts +0 -24
  723. package/dist/lib/bot/runtime-sign-in.js +0 -31
  724. package/dist/lib/bot/scaffold.d.ts +0 -38
  725. package/dist/lib/bot/scaffold.js +0 -94
  726. package/dist/lib/bot/self-heal.d.ts +0 -52
  727. package/dist/lib/bot/self-heal.js +0 -79
  728. package/dist/lib/bot/self-process.d.ts +0 -19
  729. package/dist/lib/bot/self-process.js +0 -35
  730. package/dist/lib/bot/session.d.ts +0 -19
  731. package/dist/lib/bot/session.js +0 -39
  732. package/dist/lib/bot/setup-explain.d.ts +0 -64
  733. package/dist/lib/bot/setup-explain.js +0 -141
  734. package/dist/lib/bot/split.d.ts +0 -32
  735. package/dist/lib/bot/split.js +0 -241
  736. package/dist/lib/bot/status.d.ts +0 -57
  737. package/dist/lib/bot/status.js +0 -66
  738. package/dist/lib/bot/worker-source.d.ts +0 -66
  739. package/dist/lib/bot/worker-source.js +0 -283
  740. package/dist/lib/checkpoint-ontology/aliases.d.ts +0 -17
  741. package/dist/lib/checkpoint-ontology/aliases.js +0 -44
  742. package/dist/lib/checkpoint-ontology/apply.d.ts +0 -110
  743. package/dist/lib/checkpoint-ontology/apply.js +0 -777
  744. package/dist/lib/checkpoint-ontology/company-brief.d.ts +0 -18
  745. package/dist/lib/checkpoint-ontology/company-brief.js +0 -337
  746. package/dist/lib/checkpoint-ontology/company.d.ts +0 -44
  747. package/dist/lib/checkpoint-ontology/company.js +0 -118
  748. package/dist/lib/checkpoint-ontology/drop-aliases.d.ts +0 -41
  749. package/dist/lib/checkpoint-ontology/drop-aliases.js +0 -76
  750. package/dist/lib/checkpoint-ontology/entity-file.d.ts +0 -109
  751. package/dist/lib/checkpoint-ontology/entity-file.js +0 -371
  752. package/dist/lib/checkpoint-ontology/identity.d.ts +0 -38
  753. package/dist/lib/checkpoint-ontology/identity.js +0 -95
  754. package/dist/lib/checkpoint-ontology/merge-copies.d.ts +0 -199
  755. package/dist/lib/checkpoint-ontology/merge-copies.js +0 -1086
  756. package/dist/lib/checkpoint-ontology/multi-writer.d.ts +0 -101
  757. package/dist/lib/checkpoint-ontology/multi-writer.js +0 -394
  758. package/dist/lib/checkpoint-ontology/plan.d.ts +0 -193
  759. package/dist/lib/checkpoint-ontology/plan.js +0 -504
  760. package/dist/lib/checkpoint-ontology/queued-touches.d.ts +0 -29
  761. package/dist/lib/checkpoint-ontology/queued-touches.js +0 -193
  762. package/dist/lib/checkpoint-ontology/sync-client.d.ts +0 -38
  763. package/dist/lib/checkpoint-ontology/sync-client.js +0 -84
  764. package/dist/lib/checkpoint-ontology/tree.d.ts +0 -55
  765. package/dist/lib/checkpoint-ontology/tree.js +0 -198
  766. package/dist/lib/company-errors-sdk-warning-flag.d.ts +0 -5
  767. package/dist/lib/company-errors-sdk-warning-flag.js +0 -8
  768. package/dist/lib/core-utils/hook-timeout-debug-context-flag.d.ts +0 -20
  769. package/dist/lib/core-utils/hook-timeout-debug-context-flag.js +0 -81
  770. package/dist/lib/core-utils/jq-json-serializer.d.ts +0 -5
  771. package/dist/lib/core-utils/jq-json-serializer.js +0 -10
  772. package/dist/lib/core-utils/secret-patterns.d.ts +0 -43
  773. package/dist/lib/core-utils/secret-patterns.js +0 -34
  774. package/dist/lib/core-utils/sentry-report.d.ts +0 -114
  775. package/dist/lib/core-utils/sentry-report.js +0 -1034
  776. package/dist/lib/core-utils/timeout-guard-native.d.ts +0 -7
  777. package/dist/lib/core-utils/timeout-guard-native.js +0 -40
  778. package/dist/lib/core-utils/worktree-resume.d.ts +0 -20
  779. package/dist/lib/core-utils/worktree-resume.js +0 -1198
  780. package/dist/lib/daemon/catalog.d.ts +0 -134
  781. package/dist/lib/daemon/catalog.js +0 -358
  782. package/dist/lib/daemon/config.d.ts +0 -35
  783. package/dist/lib/daemon/config.js +0 -108
  784. package/dist/lib/daemon/flag.d.ts +0 -25
  785. package/dist/lib/daemon/flag.js +0 -59
  786. package/dist/lib/daemon/handoff.d.ts +0 -56
  787. package/dist/lib/daemon/handoff.js +0 -161
  788. package/dist/lib/daemon/hq-cloud.d.ts +0 -79
  789. package/dist/lib/daemon/hq-cloud.js +0 -183
  790. package/dist/lib/daemon/install.d.ts +0 -85
  791. package/dist/lib/daemon/install.js +0 -320
  792. package/dist/lib/daemon/legacy-sync-env.d.ts +0 -10
  793. package/dist/lib/daemon/legacy-sync-env.js +0 -58
  794. package/dist/lib/daemon/legacy.d.ts +0 -45
  795. package/dist/lib/daemon/legacy.js +0 -133
  796. package/dist/lib/daemon/lock.d.ts +0 -47
  797. package/dist/lib/daemon/lock.js +0 -138
  798. package/dist/lib/daemon/machine-type.d.ts +0 -50
  799. package/dist/lib/daemon/machine-type.js +0 -159
  800. package/dist/lib/daemon/migrate.d.ts +0 -77
  801. package/dist/lib/daemon/migrate.js +0 -265
  802. package/dist/lib/daemon/paths.d.ts +0 -24
  803. package/dist/lib/daemon/paths.js +0 -43
  804. package/dist/lib/daemon/protocol-tail.d.ts +0 -33
  805. package/dist/lib/daemon/protocol-tail.js +0 -131
  806. package/dist/lib/daemon/remote-control.d.ts +0 -74
  807. package/dist/lib/daemon/remote-control.js +0 -153
  808. package/dist/lib/daemon/requests.d.ts +0 -28
  809. package/dist/lib/daemon/requests.js +0 -65
  810. package/dist/lib/daemon/run.d.ts +0 -79
  811. package/dist/lib/daemon/run.js +0 -755
  812. package/dist/lib/daemon/succession.d.ts +0 -118
  813. package/dist/lib/daemon/succession.js +0 -263
  814. package/dist/lib/daemon/supervisor.d.ts +0 -132
  815. package/dist/lib/daemon/supervisor.js +0 -836
  816. package/dist/lib/daemon/sync-runner.d.ts +0 -58
  817. package/dist/lib/daemon/sync-runner.js +0 -277
  818. package/dist/lib/daemon/tools.d.ts +0 -52
  819. package/dist/lib/daemon/tools.js +0 -95
  820. package/dist/lib/daemon/updater.d.ts +0 -57
  821. package/dist/lib/daemon/updater.js +0 -163
  822. package/dist/lib/deploy-api.d.ts +0 -5
  823. package/dist/lib/deploy-api.js +0 -21
  824. package/dist/lib/deploy-apps.d.ts +0 -13
  825. package/dist/lib/deploy-apps.js +0 -29
  826. package/dist/lib/doctor/__testing__/run-doctor.d.ts +0 -8
  827. package/dist/lib/doctor/__testing__/run-doctor.js +0 -52
  828. package/dist/lib/doctor/checks/bots.d.ts +0 -13
  829. package/dist/lib/doctor/checks/bots.js +0 -189
  830. package/dist/lib/doctor/checks/scaffold-cli-floor.d.ts +0 -6
  831. package/dist/lib/doctor/checks/scaffold-cli-floor.js +0 -73
  832. package/dist/lib/doctor/checks/sync-runtime.d.ts +0 -11
  833. package/dist/lib/doctor/checks/sync-runtime.js +0 -216
  834. package/dist/lib/doctor/client-health-flag-token.d.ts +0 -15
  835. package/dist/lib/doctor/client-health-flag-token.js +0 -66
  836. package/dist/lib/doctor/client-health-reason-codes-flag.d.ts +0 -27
  837. package/dist/lib/doctor/client-health-reason-codes-flag.js +0 -106
  838. package/dist/lib/doctor/fix/json-output.d.ts +0 -28
  839. package/dist/lib/doctor/fix/json-output.js +0 -33
  840. package/dist/lib/doctor/fix/refresh-sync-outcome.d.ts +0 -12
  841. package/dist/lib/doctor/fix/refresh-sync-outcome.js +0 -25
  842. package/dist/lib/doctor/shared.d.ts +0 -8
  843. package/dist/lib/doctor/shared.js +0 -38
  844. package/dist/lib/doctor/stray-gate-entries.d.ts +0 -35
  845. package/dist/lib/doctor/stray-gate-entries.js +0 -83
  846. package/dist/lib/first-sync-next-step.d.ts +0 -37
  847. package/dist/lib/first-sync-next-step.js +0 -189
  848. package/dist/lib/flag-registry-endpoint.d.ts +0 -5
  849. package/dist/lib/flag-registry-endpoint.js +0 -9
  850. package/dist/lib/flag-registry-worker-source.generated.d.ts +0 -2
  851. package/dist/lib/flag-registry-worker-source.generated.js +0 -3
  852. package/dist/lib/flag-snapshot-file.d.ts +0 -20
  853. package/dist/lib/flag-snapshot-file.js +0 -91
  854. package/dist/lib/heartbeat-identity.d.ts +0 -30
  855. package/dist/lib/heartbeat-identity.js +0 -76
  856. package/dist/lib/lanes/account-home.d.ts +0 -8
  857. package/dist/lib/lanes/account-home.js +0 -10
  858. package/dist/lib/lanes/accounts.d.ts +0 -117
  859. package/dist/lib/lanes/accounts.js +0 -366
  860. package/dist/lib/lanes/admission-host.d.ts +0 -22
  861. package/dist/lib/lanes/admission-host.js +0 -37
  862. package/dist/lib/lanes/admission.d.ts +0 -26
  863. package/dist/lib/lanes/admission.js +0 -210
  864. package/dist/lib/lanes/approval-gate.d.ts +0 -8
  865. package/dist/lib/lanes/approval-gate.js +0 -90
  866. package/dist/lib/lanes/autopilot-metrics.d.ts +0 -99
  867. package/dist/lib/lanes/autopilot-metrics.js +0 -301
  868. package/dist/lib/lanes/autopilot-registry.d.ts +0 -62
  869. package/dist/lib/lanes/autopilot-registry.js +0 -192
  870. package/dist/lib/lanes/autopilot.d.ts +0 -120
  871. package/dist/lib/lanes/autopilot.js +0 -1061
  872. package/dist/lib/lanes/blocker-freshness.d.ts +0 -31
  873. package/dist/lib/lanes/blocker-freshness.js +0 -168
  874. package/dist/lib/lanes/checked-company-path.d.ts +0 -3
  875. package/dist/lib/lanes/checked-company-path.js +0 -39
  876. package/dist/lib/lanes/claude-balance.d.ts +0 -97
  877. package/dist/lib/lanes/claude-balance.js +0 -319
  878. package/dist/lib/lanes/compaction.d.ts +0 -110
  879. package/dist/lib/lanes/compaction.js +0 -293
  880. package/dist/lib/lanes/config.d.ts +0 -94
  881. package/dist/lib/lanes/config.js +0 -606
  882. package/dist/lib/lanes/constants.d.ts +0 -3
  883. package/dist/lib/lanes/constants.js +0 -3
  884. package/dist/lib/lanes/delivery-core.d.ts +0 -15
  885. package/dist/lib/lanes/delivery-core.js +0 -21
  886. package/dist/lib/lanes/delivery.d.ts +0 -180
  887. package/dist/lib/lanes/delivery.js +0 -443
  888. package/dist/lib/lanes/disk-guard.d.ts +0 -66
  889. package/dist/lib/lanes/disk-guard.js +0 -172
  890. package/dist/lib/lanes/dropbox.d.ts +0 -129
  891. package/dist/lib/lanes/dropbox.js +0 -601
  892. package/dist/lib/lanes/effort.d.ts +0 -51
  893. package/dist/lib/lanes/effort.js +0 -113
  894. package/dist/lib/lanes/envelope-repair-dispatch.d.ts +0 -26
  895. package/dist/lib/lanes/envelope-repair-dispatch.js +0 -74
  896. package/dist/lib/lanes/errors.d.ts +0 -39
  897. package/dist/lib/lanes/errors.js +0 -72
  898. package/dist/lib/lanes/flag-keys.d.ts +0 -15
  899. package/dist/lib/lanes/flag-keys.js +0 -15
  900. package/dist/lib/lanes/grants.d.ts +0 -30
  901. package/dist/lib/lanes/grants.js +0 -171
  902. package/dist/lib/lanes/hire-grant-dispatch.d.ts +0 -29
  903. package/dist/lib/lanes/hire-grant-dispatch.js +0 -315
  904. package/dist/lib/lanes/hooks-install.d.ts +0 -82
  905. package/dist/lib/lanes/hooks-install.js +0 -479
  906. package/dist/lib/lanes/host-capacity.d.ts +0 -69
  907. package/dist/lib/lanes/host-capacity.js +0 -254
  908. package/dist/lib/lanes/hq-root.d.ts +0 -19
  909. package/dist/lib/lanes/hq-root.js +0 -28
  910. package/dist/lib/lanes/index.d.ts +0 -76
  911. package/dist/lib/lanes/index.js +0 -42
  912. package/dist/lib/lanes/keep-alive.d.ts +0 -68
  913. package/dist/lib/lanes/keep-alive.js +0 -343
  914. package/dist/lib/lanes/kr-freshness.d.ts +0 -76
  915. package/dist/lib/lanes/kr-freshness.js +0 -413
  916. package/dist/lib/lanes/lane-company.d.ts +0 -10
  917. package/dist/lib/lanes/lane-company.js +0 -41
  918. package/dist/lib/lanes/liveness.d.ts +0 -108
  919. package/dist/lib/lanes/liveness.js +0 -396
  920. package/dist/lib/lanes/machine-identity.d.ts +0 -34
  921. package/dist/lib/lanes/machine-identity.js +0 -92
  922. package/dist/lib/lanes/manager-status-gate.d.ts +0 -17
  923. package/dist/lib/lanes/manager-status-gate.js +0 -133
  924. package/dist/lib/lanes/merge-command.d.ts +0 -15
  925. package/dist/lib/lanes/merge-command.js +0 -629
  926. package/dist/lib/lanes/mesh-events.d.ts +0 -127
  927. package/dist/lib/lanes/mesh-events.js +0 -564
  928. package/dist/lib/lanes/message-replay.d.ts +0 -21
  929. package/dist/lib/lanes/message-replay.js +0 -122
  930. package/dist/lib/lanes/models.d.ts +0 -86
  931. package/dist/lib/lanes/models.js +0 -234
  932. package/dist/lib/lanes/monitor.d.ts +0 -48
  933. package/dist/lib/lanes/monitor.js +0 -428
  934. package/dist/lib/lanes/move-account.d.ts +0 -56
  935. package/dist/lib/lanes/move-account.js +0 -193
  936. package/dist/lib/lanes/orphans.d.ts +0 -25
  937. package/dist/lib/lanes/orphans.js +0 -102
  938. package/dist/lib/lanes/outpost-dispatch.d.ts +0 -147
  939. package/dist/lib/lanes/outpost-dispatch.js +0 -271
  940. package/dist/lib/lanes/outpost-hire-cache.d.ts +0 -22
  941. package/dist/lib/lanes/outpost-hire-cache.js +0 -153
  942. package/dist/lib/lanes/outpost-identity.d.ts +0 -33
  943. package/dist/lib/lanes/outpost-identity.js +0 -59
  944. package/dist/lib/lanes/outpost-profile-repin.d.ts +0 -17
  945. package/dist/lib/lanes/outpost-profile-repin.js +0 -84
  946. package/dist/lib/lanes/outpost-pruner-install.d.ts +0 -37
  947. package/dist/lib/lanes/outpost-pruner-install.js +0 -238
  948. package/dist/lib/lanes/outpost-registry-worker-approval.d.ts +0 -18
  949. package/dist/lib/lanes/outpost-registry-worker-approval.js +0 -109
  950. package/dist/lib/lanes/outpost-snapshot-memo.d.ts +0 -6
  951. package/dist/lib/lanes/outpost-snapshot-memo.js +0 -14
  952. package/dist/lib/lanes/outpost-worktree-pruner-flag.d.ts +0 -19
  953. package/dist/lib/lanes/outpost-worktree-pruner-flag.js +0 -86
  954. package/dist/lib/lanes/outpost-worktree-pruner.d.ts +0 -62
  955. package/dist/lib/lanes/outpost-worktree-pruner.js +0 -1201
  956. package/dist/lib/lanes/profile.d.ts +0 -69
  957. package/dist/lib/lanes/profile.js +0 -552
  958. package/dist/lib/lanes/provider-rejection.d.ts +0 -86
  959. package/dist/lib/lanes/provider-rejection.js +0 -286
  960. package/dist/lib/lanes/questions.d.ts +0 -90
  961. package/dist/lib/lanes/questions.js +0 -384
  962. package/dist/lib/lanes/quota.d.ts +0 -134
  963. package/dist/lib/lanes/quota.js +0 -471
  964. package/dist/lib/lanes/reconcile-install.d.ts +0 -90
  965. package/dist/lib/lanes/reconcile-install.js +0 -257
  966. package/dist/lib/lanes/reconcile.d.ts +0 -161
  967. package/dist/lib/lanes/reconcile.js +0 -3324
  968. package/dist/lib/lanes/registry-flag.d.ts +0 -35
  969. package/dist/lib/lanes/registry-flag.js +0 -164
  970. package/dist/lib/lanes/registry-persona.d.ts +0 -20
  971. package/dist/lib/lanes/registry-persona.js +0 -329
  972. package/dist/lib/lanes/registry.d.ts +0 -122
  973. package/dist/lib/lanes/registry.js +0 -570
  974. package/dist/lib/lanes/reviews.d.ts +0 -38
  975. package/dist/lib/lanes/reviews.js +0 -395
  976. package/dist/lib/lanes/runaway-tool-guard.d.ts +0 -38
  977. package/dist/lib/lanes/runaway-tool-guard.js +0 -284
  978. package/dist/lib/lanes/session-relink.d.ts +0 -25
  979. package/dist/lib/lanes/session-relink.js +0 -216
  980. package/dist/lib/lanes/spawn.d.ts +0 -355
  981. package/dist/lib/lanes/spawn.js +0 -2668
  982. package/dist/lib/lanes/ssm-command-context.d.ts +0 -12
  983. package/dist/lib/lanes/ssm-command-context.js +0 -52
  984. package/dist/lib/lanes/store.d.ts +0 -91
  985. package/dist/lib/lanes/store.js +0 -1822
  986. package/dist/lib/lanes/stories.d.ts +0 -23
  987. package/dist/lib/lanes/stories.js +0 -92
  988. package/dist/lib/lanes/story-ledger.d.ts +0 -80
  989. package/dist/lib/lanes/story-ledger.js +0 -815
  990. package/dist/lib/lanes/story-switch.d.ts +0 -21
  991. package/dist/lib/lanes/story-switch.js +0 -75
  992. package/dist/lib/lanes/text-scan.d.ts +0 -11
  993. package/dist/lib/lanes/text-scan.js +0 -103
  994. package/dist/lib/lanes/throttle.d.ts +0 -116
  995. package/dist/lib/lanes/throttle.js +0 -437
  996. package/dist/lib/lanes/timestamp.d.ts +0 -3
  997. package/dist/lib/lanes/timestamp.js +0 -26
  998. package/dist/lib/lanes/tracker-checks.d.ts +0 -77
  999. package/dist/lib/lanes/tracker-checks.js +0 -134
  1000. package/dist/lib/lanes/tracker-report-state.d.ts +0 -10
  1001. package/dist/lib/lanes/tracker-report-state.js +0 -124
  1002. package/dist/lib/lanes/tracker-report.d.ts +0 -203
  1003. package/dist/lib/lanes/tracker-report.js +0 -522
  1004. package/dist/lib/lanes/tracker-store.d.ts +0 -18
  1005. package/dist/lib/lanes/tracker-store.js +0 -106
  1006. package/dist/lib/lanes/types.d.ts +0 -1030
  1007. package/dist/lib/lanes/types.js +0 -418
  1008. package/dist/lib/lanes/wait.d.ts +0 -39
  1009. package/dist/lib/lanes/wait.js +0 -159
  1010. package/dist/lib/lanes/watch.d.ts +0 -39
  1011. package/dist/lib/lanes/watch.js +0 -249
  1012. package/dist/lib/lanes/watcher-main.d.ts +0 -11
  1013. package/dist/lib/lanes/watcher-main.js +0 -108
  1014. package/dist/lib/lanes/watcher.d.ts +0 -287
  1015. package/dist/lib/lanes/watcher.js +0 -1972
  1016. package/dist/lib/mesh/denial-codes.d.ts +0 -5
  1017. package/dist/lib/mesh/denial-codes.js +0 -14
  1018. package/dist/lib/mesh/live/daemon/config.d.ts +0 -36
  1019. package/dist/lib/mesh/live/daemon/config.js +0 -120
  1020. package/dist/lib/mesh/live/daemon/legacy-listen.d.ts +0 -43
  1021. package/dist/lib/mesh/live/daemon/legacy-listen.js +0 -89
  1022. package/dist/lib/mesh/live/daemon/live-cache.d.ts +0 -26
  1023. package/dist/lib/mesh/live/daemon/live-cache.js +0 -116
  1024. package/dist/lib/mesh/live/daemon/mqtt-events.d.ts +0 -7
  1025. package/dist/lib/mesh/live/daemon/mqtt-events.js +0 -2
  1026. package/dist/lib/mesh/live/daemon/mqtt-events.test-d.d.ts +0 -2
  1027. package/dist/lib/mesh/live/daemon/mqtt-events.test-d.js +0 -10
  1028. package/dist/lib/mesh/live/daemon/version-drift.d.ts +0 -5
  1029. package/dist/lib/mesh/live/daemon/version-drift.js +0 -47
  1030. package/dist/lib/mesh/live/daemon/work-subscribe.d.ts +0 -32
  1031. package/dist/lib/mesh/live/daemon/work-subscribe.js +0 -262
  1032. package/dist/lib/mesh/live/report-summary.d.ts +0 -45
  1033. package/dist/lib/mesh/live/report-summary.js +0 -234
  1034. package/dist/lib/mesh/live/session-seq.d.ts +0 -4
  1035. package/dist/lib/mesh/live/session-seq.js +0 -33
  1036. package/dist/lib/mesh/project-board.d.ts +0 -65
  1037. package/dist/lib/mesh/project-board.js +0 -181
  1038. package/dist/lib/mesh/story-status.d.ts +0 -22
  1039. package/dist/lib/mesh/story-status.js +0 -49
  1040. package/dist/lib/monitor.d.ts +0 -149
  1041. package/dist/lib/monitor.js +0 -519
  1042. package/dist/lib/node-binary.d.ts +0 -50
  1043. package/dist/lib/node-binary.js +0 -133
  1044. package/dist/lib/notify-recipient.d.ts +0 -7
  1045. package/dist/lib/notify-recipient.js +0 -11
  1046. package/dist/lib/onboarding/checkpoint.d.ts +0 -13
  1047. package/dist/lib/onboarding/checkpoint.js +0 -44
  1048. package/dist/lib/onboarding/cli/onboard.d.ts +0 -53
  1049. package/dist/lib/onboarding/cli/onboard.js +0 -135
  1050. package/dist/lib/onboarding/cli/prompts.d.ts +0 -28
  1051. package/dist/lib/onboarding/cli/prompts.js +0 -83
  1052. package/dist/lib/onboarding/errors.d.ts +0 -34
  1053. package/dist/lib/onboarding/errors.js +0 -59
  1054. package/dist/lib/onboarding/index.d.ts +0 -13
  1055. package/dist/lib/onboarding/index.js +0 -13
  1056. package/dist/lib/onboarding/orchestrator.d.ts +0 -47
  1057. package/dist/lib/onboarding/orchestrator.js +0 -569
  1058. package/dist/lib/onboarding/types.d.ts +0 -79
  1059. package/dist/lib/onboarding/types.js +0 -8
  1060. package/dist/lib/policy-validator.d.ts +0 -7
  1061. package/dist/lib/policy-validator.js +0 -187
  1062. package/dist/lib/process-flag-company-context.d.ts +0 -8
  1063. package/dist/lib/process-flag-company-context.js +0 -67
  1064. package/dist/lib/report-publish.d.ts +0 -175
  1065. package/dist/lib/report-publish.js +0 -421
  1066. package/dist/lib/report-run.d.ts +0 -62
  1067. package/dist/lib/report-run.js +0 -123
  1068. package/dist/lib/report-snapshot.d.ts +0 -12
  1069. package/dist/lib/report-snapshot.js +0 -135
  1070. package/dist/lib/report-templates.d.ts +0 -9
  1071. package/dist/lib/report-templates.js +0 -21
  1072. package/dist/lib/scaffold-cli-floor.d.ts +0 -8
  1073. package/dist/lib/scaffold-cli-floor.js +0 -50
  1074. package/dist/lib/search-index/collection-path-repair-flag.d.ts +0 -4
  1075. package/dist/lib/search-index/collection-path-repair-flag.js +0 -7
  1076. package/dist/lib/search-index/embed-lock.d.ts +0 -34
  1077. package/dist/lib/search-index/embed-lock.js +0 -295
  1078. package/dist/lib/search-index/load-gate.d.ts +0 -57
  1079. package/dist/lib/search-index/load-gate.js +0 -270
  1080. package/dist/lib/search-index/max-doc-bytes.d.ts +0 -219
  1081. package/dist/lib/search-index/max-doc-bytes.js +0 -463
  1082. package/dist/lib/search-index/qmd-exit-diagnostics.d.ts +0 -5
  1083. package/dist/lib/search-index/qmd-exit-diagnostics.js +0 -40
  1084. package/dist/lib/search-index/reindex-single-flight-flag.d.ts +0 -5
  1085. package/dist/lib/search-index/reindex-single-flight-flag.js +0 -8
  1086. package/dist/lib/service-manager/index.d.ts +0 -42
  1087. package/dist/lib/service-manager/index.js +0 -105
  1088. package/dist/lib/service-manager/launchd.d.ts +0 -81
  1089. package/dist/lib/service-manager/launchd.js +0 -212
  1090. package/dist/lib/service-manager/systemd.d.ts +0 -19
  1091. package/dist/lib/service-manager/systemd.js +0 -72
  1092. package/dist/lib/service-manager/types.d.ts +0 -34
  1093. package/dist/lib/service-manager/types.js +0 -26
  1094. package/dist/lib/test-utils/isolated-flag-company-context.d.ts +0 -3
  1095. package/dist/lib/test-utils/isolated-flag-company-context.js +0 -18
  1096. package/dist/lib/work-context/bind-best.d.ts +0 -66
  1097. package/dist/lib/work-context/bind-best.js +0 -344
  1098. package/dist/lib/work-context/bind-calling-session.d.ts +0 -26
  1099. package/dist/lib/work-context/bind-calling-session.js +0 -63
  1100. package/dist/lib/work-context/company-rebind.d.ts +0 -23
  1101. package/dist/lib/work-context/company-rebind.js +0 -59
  1102. package/dist/lib/work-context/default-company.d.ts +0 -43
  1103. package/dist/lib/work-context/default-company.js +0 -83
  1104. package/dist/lib/work-context/outbox-quarantine-status-flag.d.ts +0 -4
  1105. package/dist/lib/work-context/outbox-quarantine-status-flag.js +0 -7
  1106. package/dist/lib/work-context/prd-sync.d.ts +0 -56
  1107. package/dist/lib/work-context/prd-sync.js +0 -197
  1108. package/dist/lib/work-context/preflight-contract.d.ts +0 -28
  1109. package/dist/lib/work-context/preflight-contract.js +0 -85
  1110. package/dist/lib/work-context/prompt-rebind.d.ts +0 -25
  1111. package/dist/lib/work-context/prompt-rebind.js +0 -85
  1112. package/dist/lib/work-context/windows-acl.d.ts +0 -123
  1113. package/dist/lib/work-context/windows-acl.js +0 -425
  1114. package/dist/lib/workers-registry/read.d.ts +0 -15
  1115. package/dist/lib/workers-registry/read.js +0 -17
  1116. package/dist/native-fast-route.d.ts +0 -7
  1117. package/dist/native-fast-route.js +0 -45
  1118. package/dist/node-network-compat-core.d.ts +0 -12
  1119. package/dist/node-network-compat-core.js +0 -41
  1120. package/dist/node-network-compat-fast.d.ts +0 -7
  1121. package/dist/node-network-compat-fast.js +0 -23
  1122. package/dist/secrets-env-fast-path.d.ts +0 -5
  1123. package/dist/secrets-env-fast-path.js +0 -16
  1124. package/dist/secrets-env-fast-route.d.ts +0 -18
  1125. package/dist/secrets-env-fast-route.js +0 -54
  1126. package/dist/utils/checkpoint-stamp-write-error.d.ts +0 -28
  1127. package/dist/utils/checkpoint-stamp-write-error.js +0 -99
  1128. package/dist/utils/cli-network-lifecycle.d.ts +0 -4
  1129. package/dist/utils/cli-network-lifecycle.js +0 -11
  1130. package/dist/utils/cognito-refresh-sentry.d.ts +0 -3
  1131. package/dist/utils/cognito-refresh-sentry.js +0 -49
  1132. package/dist/utils/console-origin.d.ts +0 -9
  1133. package/dist/utils/console-origin.js +0 -28
  1134. package/dist/utils/core-eval-trigger.d.ts +0 -4
  1135. package/dist/utils/core-eval-trigger.js +0 -88
  1136. package/dist/utils/exclusive-lock.d.ts +0 -32
  1137. package/dist/utils/exclusive-lock.js +0 -75
  1138. package/dist/utils/fast-stream-errors.d.ts +0 -12
  1139. package/dist/utils/fast-stream-errors.js +0 -18
  1140. package/dist/utils/files-browse-acl.d.ts +0 -5
  1141. package/dist/utils/files-browse-acl.js +0 -11
  1142. package/dist/utils/hq-core-yaml.d.ts +0 -10
  1143. package/dist/utils/hq-core-yaml.js +0 -40
  1144. package/dist/utils/hq-root-resolver.d.ts +0 -13
  1145. package/dist/utils/hq-root-resolver.js +0 -103
  1146. package/dist/utils/redact-url.d.ts +0 -14
  1147. package/dist/utils/redact-url.js +0 -218
  1148. package/dist/utils/scaffold-fast-import-guard.d.ts +0 -2
  1149. package/dist/utils/scaffold-fast-import-guard.js +0 -40
  1150. package/dist/utils/scaffold-packlist-guard.d.ts +0 -7
  1151. package/dist/utils/scaffold-packlist-guard.js +0 -23
  1152. package/dist/utils/scaffold-sibling-references.d.ts +0 -22
  1153. package/dist/utils/scaffold-sibling-references.js +0 -156
  1154. package/dist/utils/secret-load-availability.d.ts +0 -8
  1155. package/dist/utils/secret-load-availability.js +0 -54
  1156. package/dist/utils/staged-install.d.ts +0 -34
  1157. package/dist/utils/staged-install.js +0 -346
  1158. package/dist/utils/staged-npm-install.d.ts +0 -16
  1159. package/dist/utils/staged-npm-install.js +0 -264
  1160. package/dist/utils/sync-log-sources.d.ts +0 -15
  1161. package/dist/utils/sync-log-sources.js +0 -36
  1162. package/dist/utils/table-width.d.ts +0 -7
  1163. package/dist/utils/table-width.js +0 -15
  1164. package/dist/utils/update-command-supervisor.cjs +0 -247
  1165. package/dist/utils/upload-author.d.ts +0 -15
  1166. package/dist/utils/upload-author.js +0 -39
  1167. package/dist/utils/version-report.d.ts +0 -27
  1168. package/dist/utils/version-report.js +0 -105
  1169. package/dist/version-request.d.ts +0 -14
  1170. package/dist/version-request.js +0 -36
  1171. package/scripts/mesh-daemon-if-stale.mjs +0 -20
  1172. package/templates/reports/blank.md +0 -3
  1173. package/templates/reports/daily-digest.md +0 -11
  1174. package/templates/runbooks/update-report.md +0 -21
@@ -1,1869 +0,0 @@
1
- /**
2
- * The resident bot process: `hq bot run <name>` (local-bots US-003/US-004).
3
- *
4
- * - pid lock in ~/.hq/bots/<name>/pid; status.json is the observable state
5
- * - refuses to start unless the creds file names this bot's agt_ AND the
6
- * server-side record is owned by the configured owner
7
- * - heartbeat every 30s (POST /v1/agents/{uid}/heartbeat, agent JWT)
8
- * - inbox poll every 2s: DMs go to ONE headless model turn (resumed by
9
- * session id); the reply is sent as the bot; the message is acked only after
10
- * the reply is sent; processed ids persist so a crash between reply and ack
11
- * never answers twice
12
- * - any correspondent can message the bot; each sender has a separate session
13
- * - first start only: the intro DM, then (when bot.json has `kickoff`) ONE
14
- * model turn on that prompt as if the owner sent it, answered in the DM, so
15
- * a guided bot starts working without waiting for the owner to type
16
- * - job items (channel "job"): a run the cloud fired on an EventBridge
17
- * schedule. Nothing is scheduled on this computer. The run is one model turn
18
- * in its own session (one per jobId), reported in the owner's DM with a
19
- * "scheduled job" header through the same split/recovery path as every other
20
- * reply, and reported back to the cloud EXACTLY ONCE — nothing else clears
21
- * the job's in-progress flag. A run whose staleAfter has passed still runs,
22
- * once, labelled a catch-up; older pending runs of the same job are reported
23
- * skipped-precondition instead of piling up.
24
- * - delivered room items (channels / group chats) are eligible for replies; claimed
25
- * first (first-claim-wins), one session per room, reply posted in the room
26
- * - conversations run side by side: up to MAX_PARALLEL_TURNS turns at once,
27
- * one lane per model session (one DM correspondent, or one room). Messages
28
- * in the same lane run in order, so a session is never resumed by two turns
29
- * at once and a thread's answers never arrive out of sequence.
30
- * - while a turn runs, each finished assistant message is posted as its own
31
- * message (progress.ts); turns have no time limit
32
- * - every received message gets a reply: a turn that fails after the model
33
- * started (error, crash, owner stop, restart) posts one "did not finish"
34
- * message and is NOT run again — it may already have done outward things.
35
- * inflight.json marks the turn in progress so a restart can say so.
36
- * - a turn that fails because the coding tool's sign-in no longer works
37
- * (runtime-sign-in.ts) is not a failure of the message: the bot says once
38
- * per conversation that it needs a sign-in, keeps the message un-acked,
39
- * holds new turns, and tries again every SIGN_IN_RETRY_MS (and at once
40
- * after a restart). A turn that works clears it.
41
- * - failures before the model starts (missing binary) retry with backoff;
42
- * 5 model failures in 10 minutes → state `failed` and a clean exit (launchd
43
- * does not respawn a clean exit). Owner stops never count.
44
- *
45
- * Everything with a side effect is injectable so the loop is unit-testable.
46
- */
47
- import { ownerContextBlock } from "./owner-context.js";
48
- import { randomUUID } from "node:crypto";
49
- import { hasPromotionHold } from "./promotion-hold.js";
50
- import * as fs from "node:fs";
51
- import * as path from "node:path";
52
- import { fullJitterDelayMs } from "../mesh/live/backoff.js";
53
- import { acquirePidLock, defaultPidLockDeps, releasePidLock } from "../mesh/live/daemon/pid-lock.js";
54
- import { BotApiError } from "./api.js";
55
- import { effectiveBotCompanies, effectiveBotKind, patchBotConfig, readBotConfig, resolveBotMemoryDir, SETUP_BOT_WORKER_ID } from "./config.js";
56
- import { ensureBotSessionMeta } from "./company-bind.js";
57
- import { readBotCredsIdentity } from "./creds.js";
58
- import { isProcessed, markProcessed, readInboxState } from "./inbox-state.js";
59
- import { clearInflight, patchInflight, readInflight, readInflightTurns, writeInflight } from "./inflight.js";
60
- import { containsNoReplySentinel, ProgressPoster, } from "./progress.js";
61
- import { splitBody } from "./split.js";
62
- import { createBotLogger } from "./log.js";
63
- import { buildSystemPrompt, introDmText, readPromptSources } from "./prompt.js";
64
- import { loadSetupExplainer, patchSetupIntroState, readSetupIntroState, readSetupProgressIntro, replyOffersExplain, SETUP_EXPLAINED_NOTE, setupExplainDue, } from "./setup-explain.js";
65
- import { FALLBACK_CLAUDE_PERMISSION_MODE, isClaudeBypassDisabled } from "./runtime/claude.js";
66
- import { runRuntimeTurn, RuntimeError } from "./runtime/index.js";
67
- import { botAttachmentsDir, dmSessionScope } from "./paths.js";
68
- import { attachmentTurnBlock, downloadTurnAttachments } from "./attachments.js";
69
- import { inboxEntryAttachments } from "../agent-kit/inbox-state.js";
70
- import { isAgentSender, isDmItem, isMetaNonReply, resolveReplyTarget } from "./room-policy.js";
71
- import { buildJobTurnPrompt, isCatchUpRun, isJobItem, jobReportHeader, jobRunOutput, machineTimeZone, planJobRuns, stripJobHeader, SUPERSEDED_DISPOSITION } from "./job-run.js";
72
- import { clearPendingJobCompletion, isCompletionDue, isCompletionExpired, isCompletionForOtherAgent, readPendingJobCompletions, recordPendingJobCompletion } from "./job-completions.js";
73
- import { isRuntimeSignInFailure, SIGN_IN_RETRY_MS, signInNeededText } from "./runtime-sign-in.js";
74
- import { HQ_BOT_AGENT_UID_ENV } from "../../commands/onboard-bot-membership.js";
75
- import { captureHeartbeatIdentityMismatch, identityMismatchMessage, isHeartbeatIdentityMismatch, } from "../heartbeat-identity.js";
76
- import { clearBotSession, readBotSession, writeBotSession } from "./session.js";
77
- import { defaultBotStatus, patchBotStatus, readBotStatus } from "./status.js";
78
- import { CLI_VERSION } from "../../cli-version.js";
79
- import { CLI_UPDATE_RESTART_EXIT_CODE } from "./cli-update.js";
80
- import { createInboxPollBackoffFlagReader, safeErrorClass } from "./inbox-poll-backoff-flag.js";
81
- export const INBOX_POLL_INTERVAL_MS = 2_000;
82
- export const HEARTBEAT_INTERVAL_MS = 30_000;
83
- /** First 429/5xx wait when Retry-After is absent (inbox polls at 2s). */
84
- export const API_BACKOFF_BASE_MS = 4_000;
85
- /** Ceiling for exponential poll/heartbeat backoff. */
86
- export const API_BACKOFF_CAP_MS = 5 * 60_000;
87
- /** Honor Retry-After up to this; a bogus 30-day header must not park the bot. */
88
- export const API_RETRY_AFTER_CAP_MS = 15 * 60_000;
89
- export const API_RETRY_AFTER_FLOOR_MS = 1_000;
90
- /**
91
- * How long to wait after a failed inbox poll or heartbeat.
92
- * 429/5xx (and transport errors) back off exponentially, honouring Retry-After
93
- * when present. Other 4xx keep the normal interval so a 401 is not stretched.
94
- */
95
- export function apiPollDelayMs(opts) {
96
- const intervalMs = Math.max(0, opts.intervalMs);
97
- const status = opts.err instanceof BotApiError ? opts.err.status : undefined;
98
- const retryable = status === 429 || (typeof status === "number" && status >= 500) || !(opts.err instanceof BotApiError);
99
- if (!retryable)
100
- return intervalMs;
101
- const retryAfter = opts.err instanceof BotApiError ? opts.err.retryAfterMs : undefined;
102
- const header = typeof retryAfter === "number" && Number.isFinite(retryAfter)
103
- ? Math.min(API_RETRY_AFTER_CAP_MS, Math.max(API_RETRY_AFTER_FLOOR_MS, retryAfter))
104
- : 0;
105
- const base = Math.max(intervalMs * 2, API_BACKOFF_BASE_MS);
106
- const attempt = Math.max(0, opts.attempt);
107
- const exp = Math.min(API_BACKOFF_CAP_MS, base * 2 ** attempt);
108
- const random = opts.random ?? Math.random;
109
- const jittered = Math.floor(exp * (1 + 0.2 * random()));
110
- return Math.min(API_BACKOFF_CAP_MS, Math.max(intervalMs, exp, header, jittered));
111
- }
112
- export const FAILURE_WINDOW_MS = 10 * 60 * 1000;
113
- export const FAILURE_LIMIT = 5;
114
- export const MAX_ATTEMPTS_PER_MESSAGE = 3;
115
- export const THINKING_EMOJI = "👀";
116
- export const ROOM_THINKING_STATUS = "is thinking…";
117
- export const RECENT_MESSAGES_LIMIT = 15;
118
- export const RECENT_MESSAGE_MAX_CHARS = 400;
119
- /** Model turns a bot runs at once (each on a different conversation). */
120
- export const MAX_PARALLEL_TURNS = 2;
121
- /**
122
- * Failed attempts to deliver ONE saved message before the bot stops trying.
123
- * A body the server refuses (too long, malformed) is refused identically every
124
- * time, so retrying it on every 2s poll only hammers the API and leaves the
125
- * person with no answer and no explanation.
126
- */
127
- export const RECOVERY_ATTEMPT_LIMIT = 5;
128
- /** What the person sees when a reply could not be delivered at all. */
129
- export const UNDELIVERABLE_REPLY_TEXT = "I wrote a reply but couldn't deliver it. Ask me again and I'll keep it shorter.";
130
- /**
131
- * The same, for a scheduled run. Nobody asked, so "ask me again" is wrong: the
132
- * run DID finish, and its outcome is still recorded with the job in HQ.
133
- */
134
- export const UNDELIVERABLE_JOB_REPORT_TEXT = "This scheduled run finished, but I couldn't deliver its report here. Its result is saved with the job's run history.";
135
- /**
136
- * Scheduled work must never crowd out the people the bot talks to. A job turn
137
- * can run for a long time, so at most ONE runs at a time, and a job never takes
138
- * the last free slot: a DM or a room message can always start immediately
139
- * instead of waiting, with no explanation, behind two long jobs.
140
- */
141
- export const MAX_PARALLEL_JOB_TURNS = 1;
142
- export const KICKOFF_MESSAGE_ID = "kickoff";
143
- /**
144
- * The environment a model turn's `hq` commands run in.
145
- *
146
- * The bot process carries its own machine identity in HQ_MACHINE_CREDS_FILE /
147
- * HQ_MACHINE_TOKEN_STATE_DIR so its inbox, heartbeat and posts are the bot's.
148
- * What a turn inherits depends on the bot's kind:
149
- * - A PERSONAL bot acts as its owner on every turn (DMs, the kickoff, rooms):
150
- * everything the owner asks for — a company, a bot, an invite, a share —
151
- * belongs to the owner's account, and the cloud rightly refuses a bot that
152
- * tries to own it ("No person entity found"). Stripping the marker makes
153
- * every `hq` command in the turn use the owner's sign-in, the same one the
154
- * desktop app shares, so no command needs a special case. The bot's id
155
- * (never a credential) rides along in HQ_BOT_AGENT_UID so what the owner
156
- * creates in the turn — a company — can add the bot as a member afterwards.
157
- * - A COMPANY bot acts as itself on every turn, like a cloud agent: the
158
- * machine identity stays, and the cloud evaluates it through its own
159
- * company memberships. It never acts as the owner, in DMs or in rooms.
160
- * Pure so the rule is unit-testable.
161
- */
162
- export function turnEnv(base, kind, agentUid, companySlug) {
163
- const env = { ...base };
164
- delete env[HQ_BOT_AGENT_UID_ENV];
165
- if (kind === "personal") {
166
- delete env.HQ_MACHINE_CREDS_FILE;
167
- delete env.HQ_MACHINE_TOKEN_STATE_DIR;
168
- if (agentUid)
169
- env[HQ_BOT_AGENT_UID_ENV] = agentUid;
170
- }
171
- else if (companySlug?.trim()) {
172
- env.HQ_SPAWN_COMPANY = companySlug.trim();
173
- }
174
- return env;
175
- }
176
- /** The core worker HQ's setup bot runs. */
177
- export const SETUP_WORKER_ID = SETUP_BOT_WORKER_ID;
178
- /** The one message a person gets when a turn on their message did not finish. */
179
- export function didNotFinishText(reason, progressPosted) {
180
- const r = reason.trim().replace(/[.\s]+$/, "");
181
- return `I didn't finish that — ${r}.${progressPosted ? " The messages above show how far I got." : ""}`;
182
- }
183
- export { containsNoReplySentinel };
184
- /** Grok emits is_error with this message when the model produces only reasoning tokens. */
185
- export function isReasoningOnlyError(excerpt) {
186
- return excerpt.includes("reasoning_only");
187
- }
188
- /** Owner stop, `hq bot stop` or `hq bot restart`: all arrive as the same signal. */
189
- export const STOPPED_BY_OWNER_REASON = "I was stopped before I was done";
190
- export const RESTARTED_REASON = "I was restarted while I was working on it";
191
- /**
192
- * The lane an inbox item runs in: the model session its turn resumes. Owner
193
- * DMs retain the legacy DM session; other senders and rooms each have their
194
- * own, and so does each scheduled job (two different jobs must never share a
195
- * model session, and a job must never pollute the owner's DM conversation).
196
- * An item that never reaches a model turn gets a lane of its own.
197
- */
198
- export function inboxLaneKey(item, config) {
199
- if (isDmItem(item))
200
- return dmSessionScope(item.fromPersonUid ?? "", config.ownerUid);
201
- const target = resolveReplyTarget(item, config);
202
- if (target?.kind === "room" || target?.kind === "job")
203
- return target.sessionScope;
204
- return `item:${item.messageId}`;
205
- }
206
- class FailureWindow {
207
- windowMs;
208
- limit;
209
- stamps = [];
210
- constructor(windowMs, limit) {
211
- this.windowMs = windowMs;
212
- this.limit = limit;
213
- }
214
- record(nowMs) {
215
- this.stamps.push(nowMs);
216
- while (this.stamps.length && nowMs - this.stamps[0] > this.windowMs)
217
- this.stamps.shift();
218
- return this.stamps.length;
219
- }
220
- count(nowMs) {
221
- while (this.stamps.length && nowMs - this.stamps[0] > this.windowMs)
222
- this.stamps.shift();
223
- return this.stamps.length;
224
- }
225
- exceeded(nowMs) {
226
- return this.count(nowMs) >= this.limit;
227
- }
228
- }
229
- function defaultSleep(ms, signal) {
230
- return new Promise((resolve) => {
231
- if (signal?.aborted) {
232
- resolve();
233
- return;
234
- }
235
- const timer = setTimeout(done, ms);
236
- function done() {
237
- clearTimeout(timer);
238
- signal?.removeEventListener("abort", done);
239
- resolve();
240
- }
241
- signal?.addEventListener("abort", done, { once: true });
242
- });
243
- }
244
- /**
245
- * A body posted as several parts where an early part got through and a later
246
- * one did not: `delivered` is how many parts the person has, so a retry starts
247
- * where it stopped instead of repeating what they already read.
248
- */
249
- class PartialPostError extends Error {
250
- parts;
251
- delivered;
252
- failure;
253
- constructor(parts, delivered, failure) {
254
- super(failure instanceof Error ? failure.message : String(failure));
255
- this.parts = parts;
256
- this.delivered = delivered;
257
- this.failure = failure;
258
- this.name = "PartialPostError";
259
- }
260
- }
261
- export function preflightCreds(dir, config) {
262
- const identity = readBotCredsIdentity(dir);
263
- if (!identity)
264
- return `No machine credentials for bot "${config.name}" — run: hq bot create ${config.name}`;
265
- if (identity.entityUid !== config.agentUid) {
266
- return `Credentials in ${dir} belong to ${identity.entityUid}, not this bot (${config.agentUid}); refusing to start`;
267
- }
268
- return null;
269
- }
270
- export async function runBot(deps) {
271
- const now = deps.now ?? (() => new Date());
272
- const sleep = deps.sleep ?? defaultSleep;
273
- const random = deps.random ?? Math.random;
274
- const log = deps.log ?? createBotLogger(deps.dir, now);
275
- const pid = deps.pid ?? process.pid;
276
- const { dir, config, api, runtime } = deps;
277
- const runTurn = deps.runTurn ?? ((rt, input) => runRuntimeTurn(rt, input));
278
- const inboxIntervalMs = deps.inboxIntervalMs ?? INBOX_POLL_INTERVAL_MS;
279
- const inboxPollBackoffEnabled = deps.inboxPollBackoffEnabled ?? createInboxPollBackoffFlagReader(config);
280
- const heartbeatIntervalMs = deps.heartbeatIntervalMs ?? HEARTBEAT_INTERVAL_MS;
281
- const exit = deps.exit ?? ((code) => process.exit(code));
282
- const fallback = () => defaultBotStatus(pid, config.runtime, now);
283
- const setStatus = (patch) => patchBotStatus(dir, patch, fallback, now);
284
- let state = "starting";
285
- let stopping = false;
286
- /** Aborts the model turns in progress (owner stop). */
287
- const currentTurns = new Set();
288
- const maxParallelTurns = Math.max(1, deps.maxParallelTurns ?? MAX_PARALLEL_TURNS);
289
- let resolveDone;
290
- const done = new Promise((r) => (resolveDone = r));
291
- // Only override isProcessAlive when a caller injected one: spreading an
292
- // explicit `undefined` over defaultPidLockDeps() would erase the default and
293
- // crash the daemon at startup ("deps.isProcessAlive is not a function").
294
- // Model turns run in the owner's HQ root so every skill, policy and `hq`
295
- // command resolves the way it does for the owner. (A scratch cwd was tried
296
- // on 2026-09-11 for speed; it cost the bot its skills and memory writes.)
297
- const turnCwd = config.hqRoot;
298
- // HQ's setup bot is a guided conversation: no "working on it" filler between steps.
299
- const isSetupBot = config.workerId === SETUP_WORKER_ID;
300
- /**
301
- * Setup bot, owner DM: remember whether the bot's latest reply asked the
302
- * explain-or-jump question, so a click on "Explain HQ first" can be answered
303
- * at once (setup-explain.ts). Never lets a bookkeeping error touch the turn.
304
- */
305
- const noteSetupReply = (reply) => {
306
- if (!isSetupBot)
307
- return;
308
- try {
309
- const offered = replyOffersExplain(reply);
310
- const current = readSetupIntroState(dir);
311
- if (offered && !current.offeredAt)
312
- patchSetupIntroState(dir, { offeredAt: now().toISOString() });
313
- else if (!offered && current.offeredAt)
314
- patchSetupIntroState(dir, { offeredAt: undefined });
315
- }
316
- catch (err) {
317
- log("warn", `setup intro state not updated: ${err instanceof Error ? err.message : String(err)}`);
318
- }
319
- };
320
- // Scheduled runs are reported in the owner's own zone: "every weekday at 9am"
321
- // was set up here, so "due 13:00 UTC" would read as the wrong time.
322
- const timeZone = machineTimeZone();
323
- // Personal: every turn acts as the owner. Company: every turn acts as the bot.
324
- const kind = effectiveBotKind(config);
325
- const companies = effectiveBotCompanies(config);
326
- const lockDeps = defaultPidLockDeps({
327
- pid,
328
- ...(deps.isProcessAlive ? { isProcessAlive: deps.isProcessAlive } : {}),
329
- });
330
- const finish = async (final, code, reason, beforeExit) => {
331
- if (state === "stopped" || state === "failed")
332
- return;
333
- state = final;
334
- setStatus({ state: final, ...(final === "failed" ? { lastError: reason.slice(0, 400) } : {}) });
335
- log(final === "failed" ? "error" : "info", `bot ${final}: ${reason}`);
336
- if (!deps.skipPidLock)
337
- releasePidLock(dir, lockDeps);
338
- try {
339
- beforeExit?.();
340
- }
341
- catch (err) {
342
- log("error", `before exit: ${err instanceof Error ? err.message : String(err)}`);
343
- }
344
- resolveDone(final);
345
- exit(code);
346
- };
347
- const cliVersion = deps.cliUpdate?.runningVersion ?? CLI_VERSION;
348
- /** Set once an update restart is due: no new turns, then exit for the supervisor. */
349
- let cliUpdatePending = null;
350
- const pollForCliUpdate = () => {
351
- const update = deps.cliUpdate?.poll(log) ?? null;
352
- if (!update)
353
- return false;
354
- cliUpdatePending = update;
355
- stopping = true;
356
- const busy = running.size;
357
- log("info", `hq-cli updated ${update.from} -> ${update.to}; restarting to load it${busy ? ` after ${busy} running turn${busy === 1 ? "" : "s"} finish${busy === 1 ? "es" : ""}` : ""}`);
358
- return true;
359
- };
360
- // ── Preflight: creds, pid lock, owner verification ─────────────────────────
361
- const credsProblem = preflightCreds(dir, config);
362
- if (credsProblem) {
363
- setStatus({ state: "failed", lastError: credsProblem, pid });
364
- log("error", credsProblem);
365
- resolveDone("failed");
366
- exit(0);
367
- return { stop: async () => { }, done, status: () => null, idle: () => true };
368
- }
369
- if (config.enabled === false) {
370
- setStatus({ state: "stopped", pid });
371
- log("info", "bot is disabled (hq bot start to enable)");
372
- resolveDone("stopped");
373
- exit(0);
374
- return { stop: async () => { }, done, status: () => null, idle: () => true };
375
- }
376
- if (!deps.skipPidLock) {
377
- const lock = acquirePidLock(dir, lockDeps);
378
- if (!lock.ok) {
379
- const msg = `bot "${config.name}" is already running (pid ${lock.owner.pid})`;
380
- log("warn", msg);
381
- resolveDone("stopped");
382
- exit(0);
383
- return { stop: async () => { }, done, status: () => null, idle: () => true };
384
- }
385
- }
386
- if (hasPromotionHold(dir)) {
387
- await finish("stopped", 0, "local bot held for cloud promotion");
388
- return { stop: async () => { }, done, status: () => null, idle: () => true };
389
- }
390
- // A restart is the owner's "try again" after signing in: start clean.
391
- setStatus({ ...fallback(), pid, state: "starting", canDrainForPromotion: false, runtimeSignIn: null, cliVersion });
392
- log("info", `starting ${config.name} on hq-cli ${cliVersion} (${config.runtime}, ${kind} bot${companies.length ? ` of ${companies.join(", ")}` : ""}) as ${config.agentUid} for ${config.ownerUid}`);
393
- deps.cliUpdate?.startup(log);
394
- try {
395
- const record = await api.getAgent(config.agentUid);
396
- // Promotion keeps the identity and owner. Ownership alone must not let
397
- // an old local installation start consuming the cloud bot's inbox.
398
- if (record.uid !== config.agentUid || record.computeMode !== "local" || record.botKind !== kind) {
399
- await finish("failed", 0, `identity ${config.agentUid} is not a ${kind} local bot; this installation cannot run it`);
400
- return { stop: async () => { }, done, status: () => null, idle: () => true };
401
- }
402
- const owner = record.ownerUid ?? null;
403
- if (owner !== config.ownerUid) {
404
- await finish("failed", 0, `identity ${config.agentUid} is owned by ${owner ?? "nobody"}, not ${config.ownerUid}`);
405
- return { stop: async () => { }, done, status: () => null, idle: () => true };
406
- }
407
- }
408
- catch (err) {
409
- await finish("failed", 0, `could not verify bot identity: ${err instanceof Error ? err.message : String(err)}`);
410
- return { stop: async () => { }, done, status: () => null, idle: () => true };
411
- }
412
- // ── System prompt ──────────────────────────────────────────────────────────
413
- const systemPrompt = deps.systemPromptOverride ??
414
- buildSystemPrompt({
415
- botName: config.name,
416
- ...(config.displayName ? { displayName: config.displayName } : {}),
417
- agentUid: config.agentUid,
418
- ownerUid: config.ownerUid,
419
- hqRoot: config.hqRoot,
420
- workerDir: config.workerDir,
421
- workerSource: config.workerSource,
422
- workerId: config.workerId,
423
- companySlug: config.companySlug,
424
- kind,
425
- companies,
426
- memoryDir: config.memoryDir,
427
- sources: readPromptSources(config.hqRoot, config.workerDir, undefined, {
428
- memoryDir: config.memoryDir,
429
- workerSource: config.workerSource,
430
- companySlug: config.companySlug,
431
- }),
432
- });
433
- const systemPromptFile = path.join(dir, "system-prompt.md");
434
- fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
435
- fs.writeFileSync(systemPromptFile, systemPrompt, { mode: 0o600 });
436
- if (hasPromotionHold(dir)) {
437
- await finish("stopped", 0, "local bot held for cloud promotion");
438
- return { stop: async () => { }, done, status: () => null, idle: () => true };
439
- }
440
- state = "running";
441
- setStatus({ state: "running", lastActivityAt: now().toISOString() });
442
- log("info", "running");
443
- // Read before the kickoff can write its own marker: whatever is here now was
444
- // left by a previous run that was cut off mid-turn.
445
- const leftovers = readInflightTurns(dir);
446
- // ── Intro DM (once) ────────────────────────────────────────────────────────
447
- // The kickoff turn is tied to the intro: it runs only in the start that sent
448
- // the intro, so introSentAt (persisted before the turn) guarantees it never
449
- // runs again on a restart.
450
- let kickoffAfterIntro = null;
451
- if (config.introSentAt && config.kickoffPendingSignIn && config.kickoff?.trim()) {
452
- // The kickoff was held for a sign-in on an earlier run; this start retries it.
453
- kickoffAfterIntro = {};
454
- }
455
- else if (!config.introSentAt) {
456
- try {
457
- const sent = await api.sendDm({ toPersonUid: config.ownerUid, body: introDmText(config.name, config.runtime, config.intro, { kind: effectiveBotKind(config), companies: effectiveBotCompanies(config) }) });
458
- patchBotConfig(dir, { introSentAt: now().toISOString() });
459
- log("info", "intro DM sent to owner");
460
- if (config.kickoff?.trim())
461
- kickoffAfterIntro = { ...(sent?.eventId ? { introEventId: sent.eventId } : {}) };
462
- }
463
- catch (err) {
464
- log("warn", `intro DM failed (will retry next start): ${err instanceof Error ? err.message : String(err)}`);
465
- }
466
- }
467
- // ── Heartbeat loop ─────────────────────────────────────────────────────────
468
- const failures = new FailureWindow(FAILURE_WINDOW_MS, FAILURE_LIMIT);
469
- let modelHealth = "ok";
470
- // ── Coding tool sign-in ────────────────────────────────────────────────────
471
- const signInRetryMs = Math.max(0, deps.signInRetryMs ?? SIGN_IN_RETRY_MS);
472
- let signInIssue = null;
473
- let nextSignInRetryAt = 0;
474
- /** Conversations already told this time that the bot needs a sign-in. */
475
- const toldAboutSignIn = new Set();
476
- const markSignInBroken = (excerpt) => {
477
- nextSignInRetryAt = now().getTime() + signInRetryMs;
478
- modelHealth = "degraded";
479
- if (signInIssue)
480
- return;
481
- signInIssue = { state: "expired", runtime: config.runtime, since: now().toISOString() };
482
- setStatus({ runtimeSignIn: signInIssue, lastError: excerpt.slice(0, 400) });
483
- log("warn", `${runtime.id} needs to sign in again on this computer; holding turns and retrying every ${Math.round(signInRetryMs / 1000)}s`);
484
- };
485
- const markSignInWorks = () => {
486
- if (!signInIssue)
487
- return;
488
- signInIssue = null;
489
- toldAboutSignIn.clear();
490
- setStatus({ runtimeSignIn: null });
491
- log("info", `${runtime.id} sign-in works again; resuming`);
492
- };
493
- /** Say once per conversation that the bot cannot work until its tool signs in. */
494
- const tellSignInNeeded = async (conversation, post, kickoff = false) => {
495
- if (toldAboutSignIn.has(conversation))
496
- return;
497
- try {
498
- await post(signInNeededText(config.runtime, kickoff));
499
- toldAboutSignIn.add(conversation);
500
- }
501
- catch (err) {
502
- log("warn", `could not say that ${runtime.id} needs a sign-in: ${err instanceof Error ? err.message : String(err)}`);
503
- }
504
- };
505
- const heartbeatLoop = (async () => {
506
- let heartbeatFails = 0;
507
- while (!stopping && state === "running") {
508
- try {
509
- // The server's component vocabulary is the fleet one (sync/model/task…);
510
- // runtime → model, inbox → task, sync → sync.
511
- await api.heartbeat(config.agentUid, { model: modelHealth, task: "ok", sync: "ok" });
512
- heartbeatFails = 0;
513
- setStatus({
514
- lastHeartbeatAt: now().toISOString(),
515
- lastHeartbeatOk: true,
516
- lastHeartbeatError: undefined,
517
- lastHeartbeatReason: undefined,
518
- lastHeartbeatConfiguredAgentUid: undefined,
519
- lastHeartbeatTokenAgentUid: undefined,
520
- });
521
- await sleep(heartbeatIntervalMs);
522
- }
523
- catch (err) {
524
- if (err instanceof BotApiError &&
525
- isHeartbeatIdentityMismatch({ status: err.status, code: err.code, message: err.detail })) {
526
- const tokenLabel = err.tokenAgentUid ?? "unknown";
527
- const reason = identityMismatchMessage("heartbeat", config.agentUid, tokenLabel);
528
- setStatus({
529
- lastHeartbeatOk: false,
530
- lastHeartbeatError: reason.slice(0, 400),
531
- lastHeartbeatReason: "identity_mismatch",
532
- lastHeartbeatConfiguredAgentUid: config.agentUid,
533
- ...(err.tokenAgentUid ? { lastHeartbeatTokenAgentUid: err.tokenAgentUid } : {}),
534
- });
535
- log("warn", reason);
536
- (deps.reportIdentityMismatch ?? captureHeartbeatIdentityMismatch)({
537
- runner: "bot",
538
- configuredAgentUid: config.agentUid,
539
- ...(err.tokenAgentUid ? { tokenAgentUid: err.tokenAgentUid } : {}),
540
- agentUidSource: deps.agentUidSource ?? "config_file",
541
- credsSource: deps.credsSource ?? "default",
542
- });
543
- break;
544
- }
545
- heartbeatFails += 1;
546
- const message = err instanceof Error ? err.message : String(err);
547
- setStatus({ lastHeartbeatOk: false, lastHeartbeatError: message.slice(0, 400) });
548
- log("warn", `heartbeat failed: ${message}`);
549
- await sleep(apiPollDelayMs({ err, attempt: heartbeatFails - 1, intervalMs: heartbeatIntervalMs, random }));
550
- }
551
- }
552
- })();
553
- // ── Inbox loop ─────────────────────────────────────────────────────────────
554
- const attempts = new Map();
555
- const inboxBackoffSteps = [inboxIntervalMs, 10_000, 20_000, 30_000];
556
- let inboxBackoffIndex = 0;
557
- let inboxWaitGeneration = 0;
558
- let activeInboxWait = null;
559
- const resetInboxBackoff = () => {
560
- inboxBackoffIndex = 0;
561
- inboxWaitGeneration += 1;
562
- activeInboxWait?.abort();
563
- };
564
- const waitForInbox = async (delayMs, adaptive) => {
565
- if (!adaptive) {
566
- await sleep(delayMs);
567
- return;
568
- }
569
- let remainingMs = delayMs;
570
- let observedGeneration = inboxWaitGeneration;
571
- while (remainingMs > 0 && !stopping && state === "running") {
572
- const controller = new AbortController();
573
- activeInboxWait = controller;
574
- const chunkMs = Math.min(inboxIntervalMs, remainingMs);
575
- await sleep(chunkMs, controller.signal);
576
- if (activeInboxWait === controller)
577
- activeInboxWait = null;
578
- if (stopping || state !== "running")
579
- break;
580
- if (hasPromotionHold(dir))
581
- break;
582
- if (observedGeneration !== inboxWaitGeneration || controller.signal.aborted) {
583
- observedGeneration = inboxWaitGeneration;
584
- remainingMs = inboxIntervalMs;
585
- continue;
586
- }
587
- remainingMs -= chunkMs;
588
- // Keep the install watcher at its original two-second cadence even when
589
- // the inbox itself is waiting longer between empty polls.
590
- if (remainingMs > 0 && pollForCliUpdate())
591
- break;
592
- }
593
- };
594
- /** Build the user turn for a room trigger: header + recent transcript + the message. */
595
- const buildRoomTurn = async (item, target, text) => {
596
- const name = (item.channelName ?? "").trim() || target.channelId;
597
- const members = typeof item.memberCount === "number" ? `${item.memberCount} members` : "group";
598
- const from = (item.fromDisplayName ?? "").trim() || item.fromPersonUid || "unknown";
599
- const header = `[#${name} · ${members} · from ${from}]\n[HQ sender: ${item.fromPersonUid ?? "unknown"}; owner: ${config.ownerUid}; sender is ${item.fromPersonUid === config.ownerUid ? "the owner" : "not the owner"}.]`;
600
- let recent = "";
601
- try {
602
- const rows = await api.fetchChannelMessages(target.channelId, RECENT_MESSAGES_LIMIT);
603
- const lines = rows
604
- .filter((m) => !(item.eventId && m.eventId === item.eventId))
605
- .map((m) => `- ${m.fromDisplayName ?? "someone"} (${m.fromPersonUid ?? "unknown"}): ${m.body.replace(/\s+/g, " ").slice(0, RECENT_MESSAGE_MAX_CHARS)}`);
606
- if (lines.length > 0)
607
- recent = `Recent messages:\n${lines.join("\n")}\n\n`;
608
- }
609
- catch (err) {
610
- log("warn", `recent messages for ${target.channelId} unavailable: ${err instanceof Error ? err.message : String(err)}`);
611
- }
612
- return `${header}\n${recent}${from}: ${text}`;
613
- };
614
- /**
615
- * One model turn in the given session scope: company bind, the Claude
616
- * bypass → auto fallback, and the session file update on success. Throws
617
- * the runtime error on failure (callers account for it via recordTurnFailure).
618
- */
619
- const executeTurn = async (prompt, sessionScope, tReceived, stream = {}) => {
620
- const session = readBotSession(dir, config.runtime, sessionScope);
621
- // Company bind (worker-sourced bots): HQ's company hooks key on
622
- // workspace/sessions/<sid>/meta.yaml, so the session id is fixed up front
623
- // and the meta file written before every turn (idempotent; covers session
624
- // resets). Claude gets the full hook set via its payload session id;
625
- // Codex/Grok only see HQ_SESSION_ID.
626
- const sid = session?.sessionId ?? randomUUID();
627
- const env = turnEnv(process.env, kind, config.agentUid, config.companySlug);
628
- let bind = { env };
629
- if (config.companySlug) {
630
- try {
631
- ensureBotSessionMeta(config.hqRoot, sid, config.companySlug, undefined, now);
632
- bind = { newSessionId: sid, env: { ...env, HQ_SESSION_ID: sid } };
633
- }
634
- catch (err) {
635
- log("warn", `company bind failed for ${config.companySlug}: ${err instanceof Error ? err.message : String(err)}`);
636
- }
637
- }
638
- // Only a personal bot, and only in the owner's own DM session (DMs and the
639
- // kickoff). Room prompts must keep their [#channel …] header first, and a
640
- // room turn can be triggered by other people, who must not be handed the
641
- // owner's companies. A company bot acts as itself and never gets it.
642
- // Owner context also goes on the owner's scheduled jobs: `turnEnv` strips
643
- // the machine credentials on EVERY personal-bot turn, so a job turn runs
644
- // `hq` as the owner too and needs the same block saying whose account it
645
- // is on. Rooms stay excluded (see above).
646
- const actsPurelyForOwner = sessionScope === "dm" || sessionScope.startsWith("job:");
647
- if (deps.ownerContext && actsPurelyForOwner && kind === "personal") {
648
- try {
649
- const owner = await deps.ownerContext();
650
- if (owner.status === "unavailable") {
651
- log("warn", `owner context unavailable: ${owner.reason}${owner.detail ? ` (${owner.detail})` : ""}`);
652
- }
653
- else if (owner.status === "mismatch") {
654
- log("warn", `owner context mismatch: signed in as ${owner.signedInAs}`);
655
- }
656
- prompt = `${ownerContextBlock(owner, config.agentUid)}\n\n${prompt}`;
657
- }
658
- catch (err) {
659
- log("warn", `owner context unavailable: ${err instanceof Error ? err.message : String(err)}`);
660
- }
661
- }
662
- const tTurnStart = now().getTime();
663
- // Model and thinking level are read fresh each turn, so a change from the
664
- // bot's profile (`hq bot set`) applies to the next message without a restart.
665
- const live = readBotConfig(dir) ?? config;
666
- const attemptTurn = (permissionMode) => runTurn(runtime, {
667
- prompt,
668
- systemPrompt,
669
- systemPromptFile,
670
- cwd: turnCwd,
671
- hqRoot: config.hqRoot,
672
- autoApprove: config.autoApprove !== false,
673
- ...(permissionMode ? { permissionMode } : {}),
674
- sessionId: session?.sessionId,
675
- ...(live.model ? { model: live.model } : {}),
676
- ...(live.effort ? { effort: live.effort } : {}),
677
- ...bind,
678
- ...stream,
679
- });
680
- let turn;
681
- const remembered = readStatus()?.claudePermissionMode;
682
- try {
683
- turn = await attemptTurn(remembered);
684
- }
685
- catch (err) {
686
- // Claude Code can have bypassPermissions switched off by managed
687
- // settings. Fall back to "auto" (no prompts, classifier-approved) once
688
- // and remember it, so the bot keeps working without an operator.
689
- const detail = err instanceof RuntimeError ? `${err.message}\n${err.stderrExcerpt}` : err instanceof Error ? err.message : String(err);
690
- const aborted = err instanceof RuntimeError && err.aborted;
691
- if (aborted || runtime.id !== "claude" || remembered || config.autoApprove === false || !isClaudeBypassDisabled(detail)) {
692
- throw Object.assign(err instanceof Error ? err : new Error(String(err)), { resumedSession: Boolean(session) });
693
- }
694
- log("warn", `bypassPermissions is disabled for this Claude Code; falling back to permission mode "${FALLBACK_CLAUDE_PERMISSION_MODE}"`);
695
- setStatus({ claudePermissionMode: FALLBACK_CLAUDE_PERMISSION_MODE });
696
- try {
697
- turn = await attemptTurn(FALLBACK_CLAUDE_PERMISSION_MODE);
698
- }
699
- catch (retryErr) {
700
- throw Object.assign(retryErr instanceof Error ? retryErr : new Error(String(retryErr)), { resumedSession: Boolean(session) });
701
- }
702
- }
703
- modelHealth = "ok";
704
- markSignInWorks();
705
- log("info", `model turn done in ${Math.round((now().getTime() - tTurnStart) / 1000)}s (${Math.round((tTurnStart - tReceived) / 1000)}s before it)`);
706
- if (turn.sessionId) {
707
- writeBotSession(dir, {
708
- v: 1,
709
- runtime: config.runtime,
710
- sessionId: turn.sessionId,
711
- turns: (session?.turns ?? 0) + 1,
712
- updatedAt: now().toISOString(),
713
- }, sessionScope);
714
- }
715
- return turn;
716
- };
717
- /** Failure bookkeeping shared by every model turn: window, health, status, log, stale session. */
718
- const recordTurnFailure = (err, sessionScope) => {
719
- const excerpt = err instanceof RuntimeError ? err.stderrExcerpt : err instanceof Error ? err.message : String(err);
720
- const count = failures.record(now().getTime());
721
- modelHealth = count >= FAILURE_LIMIT ? "failed" : "degraded";
722
- setStatus({ restarts: (readStatus()?.restarts ?? 0) + 1, recentFailures: count, lastError: excerpt.slice(0, 400) });
723
- log("error", `model turn failed (${count}/${FAILURE_LIMIT} in window): ${excerpt}`);
724
- // A resumed session that no longer exists must not poison every turn.
725
- const resumed = Boolean(err?.resumedSession);
726
- if (resumed && /session|resume|not found/i.test(excerpt))
727
- clearBotSession(dir, sessionScope);
728
- return { excerpt, count };
729
- };
730
- /**
731
- * One model turn that posts its in-between messages as it goes. Writes the
732
- * in-flight marker first; the caller clears it once the message is answered.
733
- */
734
- const runTurnWithProgress = async (args) => {
735
- const { messageId } = args.marker;
736
- const silenceable = args.silenceable === true;
737
- writeInflight(dir, {
738
- v: 1,
739
- ...args.marker,
740
- startedAt: now().toISOString(),
741
- ...(silenceable ? { silenceable: true } : {}),
742
- });
743
- let running = true;
744
- let posted = 0;
745
- const makeSendFn = (fn) => async (body) => {
746
- try {
747
- await fn(body);
748
- }
749
- catch (err) {
750
- log("warn", `post for ${messageId} failed: ${err instanceof Error ? err.message : String(err)}`);
751
- return false;
752
- }
753
- posted += 1;
754
- patchInflight(dir, messageId, { progressPosted: posted });
755
- if (running && args.afterProgressPost)
756
- await args.afterProgressPost().catch(() => undefined);
757
- return true;
758
- };
759
- const poster = new ProgressPoster({
760
- // The setup bot talks to someone new to HQ: its notes to itself never
761
- // reach them, and it posts no "still working" notice either — the
762
- // desktop app shows that the bot is working.
763
- ...(isSetupBot ? { dropPreToolMessages: true } : {}),
764
- ...deps.progress,
765
- ...(args.workingNotice === false || silenceable || isSetupBot ? { workingNoticeMs: 0 } : {}),
766
- ...(silenceable ? { buffer: true } : {}),
767
- send: makeSendFn(args.send),
768
- ...(args.sendFinal ? { sendFinal: makeSendFn(args.sendFinal) } : {}),
769
- });
770
- const controller = new AbortController();
771
- currentTurns.add(controller);
772
- poster.start();
773
- try {
774
- const turn = await executeTurn(args.prompt, args.sessionScope, args.tReceived, {
775
- onEvent: (event) => {
776
- if (event.kind === "message")
777
- poster.message(event.text);
778
- else if (event.kind === "tool")
779
- poster.tool();
780
- },
781
- signal: controller.signal,
782
- ...(args.readDirs?.length ? { readDirs: args.readDirs } : {}),
783
- });
784
- running = false;
785
- // Control tokens were already stripped from turn.text in runRuntimeTurn, so
786
- // a `<|eos|>`-only reply arrives here as empty. On an unmentioned room turn
787
- // a stay-quiet phrase ("No response requested." etc.) is also silence — the
788
- // meta chatter that let two bots loop on 2026-09-25.
789
- const stayQuiet = silenceable && isMetaNonReply(turn.text);
790
- const sentinelOrEmpty = containsNoReplySentinel(turn.text) || !turn.text.trim() || stayQuiet;
791
- // Unmentioned room turn: a no_reply sentinel (bare, fenced, or with
792
- // preamble), an empty/whitespace reply, or a stay-quiet phrase means stay
793
- // quiet. Abandon the poster (it posts nothing) and return a silent outcome;
794
- // the caller acks without posting anything.
795
- if (silenceable && sentinelOrEmpty) {
796
- await poster.abandon();
797
- return { outcome: { ok: true, reply: "", silent: true }, poster };
798
- }
799
- // DM or @-mentioned room: the person asked directly and must get a reply.
800
- // Strip the silence sentinel so its raw JSON never posts, then let the
801
- // poster produce its "(no reply)" fallback when there is nothing else.
802
- const finalText = sentinelOrEmpty ? "" : turn.text;
803
- await poster.finish(finalText);
804
- return { outcome: { ok: true, reply: finalText.trim() }, poster };
805
- }
806
- catch (err) {
807
- running = false;
808
- await poster.abandon();
809
- const excerpt = err instanceof RuntimeError ? err.stderrExcerpt : err instanceof Error ? err.message : String(err);
810
- const aborted = (err instanceof RuntimeError && err.aborted) || controller.signal.aborted;
811
- const started = !(err instanceof RuntimeError) || err.started;
812
- return { outcome: { ok: false, started, aborted, excerpt, error: err }, poster };
813
- }
814
- finally {
815
- currentTurns.delete(controller);
816
- }
817
- };
818
- const failureReason = (outcome) => outcome.aborted ? STOPPED_BY_OWNER_REASON : `${runtime.id} stopped with an error: ${outcome.excerpt.slice(0, 160)}`;
819
- const postOne = (target, body, rootEventId, audience) => {
820
- const root = rootEventId ? { rootEventId } : {};
821
- return target.kind === "dm"
822
- ? api.sendDm({ toPersonUid: target.peerUid, body, ...root, ...(audience ? { audience } : {}) })
823
- : api.sendChannelMessage({ channelId: target.channelId, body, ...root });
824
- };
825
- /**
826
- * Post `parts` in order, starting at `from`. A failure throws a
827
- * PartialPostError naming how many parts got through, so the caller can save
828
- * exactly the remainder.
829
- */
830
- const sendParts = async (target, parts, from, rootEventId, onDelivered, audience) => {
831
- for (let i = Math.max(0, from); i < parts.length; i += 1) {
832
- try {
833
- await postOne(target, parts[i], rootEventId, audience);
834
- }
835
- catch (err) {
836
- throw new PartialPostError(parts, i, err);
837
- }
838
- onDelivered?.(i + 1);
839
- }
840
- };
841
- /** Every outbound body goes through here, so nothing over the limit is ever posted whole. */
842
- const sendToTarget = (target, body, rootEventId, audience) => sendParts(target, splitBody(body), 0, rootEventId, undefined, audience);
843
- /**
844
- * A `send` for one conversation that remembers how much of its last failed
845
- * body got through, so the in-flight marker can record the remainder.
846
- */
847
- const trackingSend = (target, rootEventId) => {
848
- const last = { value: null };
849
- const makeSend = (audience) => async (body) => {
850
- try {
851
- await sendToTarget(target, body, rootEventId, audience);
852
- last.value = null;
853
- }
854
- catch (err) {
855
- last.value = err instanceof PartialPostError && err.delivered > 0 ? { parts: err.parts, delivered: err.delivered } : null;
856
- throw err;
857
- }
858
- };
859
- const send = makeSend(target.kind === "dm" ? "agent" : undefined);
860
- const sendFinal = makeSend(target.kind === "dm" ? "human" : undefined);
861
- const saved = (reply) => {
862
- const parts = splitBody(reply);
863
- const partial = last.value;
864
- const sameBody = partial !== null && partial.parts.length === parts.length && partial.parts.every((p, i) => p === parts[i]);
865
- return { reply, replyParts: parts, replyPartsDelivered: sameBody ? partial.delivered : 0 };
866
- };
867
- return { send, sendFinal, saved };
868
- };
869
- // ── Scheduled jobs ────────────────────────────────────────────────────────
870
- /** Newest pending run key already picked up, per jobId (one catch-up per wake). */
871
- const handledJobFires = new Map();
872
- /** Runs an older fire of a job that a newer pending run supersedes. */
873
- const supersededJobRuns = new Set();
874
- /**
875
- * Report one fired run as finished. This is the ONLY thing that clears the
876
- * job's in-progress flag in the cloud, so a failure is logged loudly and the
877
- * completion is kept for the next poll — the caller still acks, because the
878
- * work is done and must never run twice.
879
- */
880
- const completeJobRun = async (jobId, messageId, completion) => {
881
- try {
882
- await api.completeJobRun(config.agentUid, jobId, messageId, completion);
883
- clearPendingJobCompletion(dir, messageId);
884
- log("info", `reported run ${messageId} of job ${jobId} as ${completion.status}`);
885
- return true;
886
- }
887
- catch (err) {
888
- const reason = err instanceof Error ? err.message : String(err);
889
- const pending = recordPendingJobCompletion(dir, { agentUid: config.agentUid, jobId, messageId, status: completion.status, ...(completion.output !== undefined ? { output: completion.output } : {}), ...(completion.disposition !== undefined ? { disposition: completion.disposition } : {}) }, now());
890
- log("error", `COULD NOT report run ${messageId} of job ${jobId} as ${completion.status}: ${reason}. ` +
891
- `Until this is reported the cloud keeps the job marked in progress and skips its next fires. ` +
892
- `Retry ${pending.attempts} in ${Math.round((pending.nextAttemptAt - now().getTime()) / 1000)}s.`);
893
- return false;
894
- }
895
- };
896
- /**
897
- * Re-send completions the cloud has not accepted yet. Never re-runs work.
898
- * Backed off per entry and given up on by age, so a minute-long network drop
899
- * recovers instead of burning a fixed attempt budget in twenty seconds.
900
- */
901
- const retryPendingJobCompletions = async () => {
902
- const nowMs = now().getTime();
903
- for (const pending of readPendingJobCompletions(dir)) {
904
- // A folder that outlived a deleted, same-named bot: never report another
905
- // identity's run as this one's (see job-completions.ts, "After a reinstall").
906
- if (isCompletionForOtherAgent(pending, config.agentUid)) {
907
- clearPendingJobCompletion(dir, pending.messageId);
908
- log("warn", `dropped an unreported run ${pending.messageId} of job ${pending.jobId}: it belongs to ${pending.agentUid}, ` +
909
- `not this bot (${config.agentUid}) — left behind by an earlier bot with the same name`);
910
- continue;
911
- }
912
- if (isCompletionExpired(pending, nowMs)) {
913
- clearPendingJobCompletion(dir, pending.messageId);
914
- log("error", `giving up on reporting run ${pending.messageId} of job ${pending.jobId} after ${pending.attempts} attempts ` +
915
- `over an hour; the cloud has released the job's in-progress slot by itself by now`);
916
- continue;
917
- }
918
- if (!isCompletionDue(pending, nowMs))
919
- continue;
920
- await completeJobRun(pending.jobId, pending.messageId, {
921
- status: pending.status,
922
- ...(pending.output !== undefined ? { output: pending.output } : {}),
923
- ...(pending.disposition !== undefined ? { disposition: pending.disposition } : {}),
924
- });
925
- }
926
- };
927
- /**
928
- * Kick the completion retries WITHOUT blocking the poll. Awaiting them in the
929
- * inbox loop meant one hanging completion POST stalled DM delivery behind it.
930
- * One pass at a time; the tracked promise is drained on shutdown.
931
- */
932
- let completionRetryTask = Promise.resolve();
933
- let completionRetryRunning = false;
934
- const kickCompletionRetries = () => {
935
- if (completionRetryRunning)
936
- return;
937
- completionRetryRunning = true;
938
- completionRetryTask = retryPendingJobCompletions()
939
- .catch((err) => {
940
- log("warn", `retrying job completions failed: ${err instanceof Error ? err.message : String(err)}`);
941
- })
942
- .finally(() => {
943
- completionRetryRunning = false;
944
- });
945
- };
946
- /** Close a marker out: clear the thinking reaction, ack the message, forget it. */
947
- const closeMarker = async (marker, isKickoff) => {
948
- if (marker.target.kind === "dm" && marker.reactionEventId) {
949
- await api
950
- .setReaction({ peerUid: marker.target.peerUid, messageId: marker.reactionEventId, emoji: THINKING_EMOJI }, false)
951
- .catch(() => false);
952
- }
953
- if (!isKickoff) {
954
- markProcessed(dir, marker.messageId, now().toISOString());
955
- await api.ackInbox(config.agentUid, marker.messageId).catch((err) => {
956
- log("warn", `ack for recovered ${marker.messageId} failed: ${err instanceof Error ? err.message : String(err)}`);
957
- });
958
- }
959
- clearInflight(dir, marker.messageId);
960
- };
961
- /**
962
- * A scheduled run's marker is about to be closed: report its REAL outcome to
963
- * the cloud first, and record that it was reported, BEFORE the ack.
964
- *
965
- * - A saved reply means the work finished and only delivery failed: that is
966
- * `succeeded`, with the report as output — including when delivery was
967
- * given up on as impossible. The owner not getting the DM does not undo
968
- * the work, and not reporting would jam the job for an hour.
969
- * - No saved reply means the turn was cut off: `failed`.
970
- * - A marker that says it was already reported is never reported again: the
971
- * server's complete is last-write-wins, so a second report after a crash
972
- * between reporting and acking would overwrite the recorded outcome.
973
- */
974
- const reportRecoveredJobRun = async (marker) => {
975
- if (!marker.jobId || marker.jobCompleted)
976
- return;
977
- const finished = typeof marker.reply === "string";
978
- // A run that failed or was stopped carries its real reason; only a marker
979
- // with none was genuinely cut off by a restart.
980
- const failure = marker.jobFailure;
981
- const completion = finished
982
- ? { status: "succeeded", output: marker.jobOutput ?? jobRunOutput(stripJobHeader(marker.reply, marker.jobHeader)) }
983
- : failure
984
- ? {
985
- status: "failed",
986
- disposition: failure.reason.slice(0, 256),
987
- ...(failure.excerpt ? { output: jobRunOutput(failure.excerpt) } : {}),
988
- }
989
- : { status: "failed", disposition: "the run was cut off when the bot restarted" };
990
- await completeJobRun(marker.jobId, marker.messageId, completion);
991
- patchInflight(dir, marker.messageId, { jobCompleted: completion.status });
992
- };
993
- /**
994
- * The body a recovery posts. A scheduled run's FIRST message carries its
995
- * header, so a report delivered by this path still reads as a scheduled run
996
- * and not as an unsolicited DM. A body saved in parts already has the header
997
- * baked in (the job's own send put it there), so it is never added twice.
998
- */
999
- const recoveryBody = (marker) => {
1000
- // A job that failed on its own says why; "I was restarted" only when it was.
1001
- const reason = marker.jobFailure?.reason ?? RESTARTED_REASON;
1002
- const body = marker.reply ?? didNotFinishText(reason, (marker.progressPosted ?? 0) > 0);
1003
- const headerAlreadyOut = (marker.progressPosted ?? 0) > 0 || body.startsWith(marker.jobHeader ?? "\u0000");
1004
- return marker.jobHeader && !headerAlreadyOut ? `${marker.jobHeader}${body}` : body;
1005
- };
1006
- /**
1007
- * A turn that was cut off by a restart (or whose answer never got posted):
1008
- * tell the person instead of running it again. Returns false when the post
1009
- * failed, so the marker stays for the next try.
1010
- *
1011
- * The retry is bounded. Some bodies can never be delivered (the server
1012
- * refuses them however often they are sent), and re-sending one on every
1013
- * poll used to hammer the API for ever while the person saw nothing at all.
1014
- * After RECOVERY_ATTEMPT_LIMIT consecutive failures the bot posts one short
1015
- * apology it can actually deliver, closes the marker, and stops.
1016
- */
1017
- const recoverInflight = async (marker) => {
1018
- const isKickoff = marker.messageId === KICKOFF_MESSAGE_ID;
1019
- // A scheduled run left in this folder by a DIFFERENT bot (adopt into a
1020
- // folder that survived without its bot.json). Posting its report would put
1021
- // another bot's work in this bot's DM, and completing it would be a write
1022
- // under the wrong identity — the thing job-completions.ts rules out. Drop
1023
- // it: no post, no completion, no ack (the item is not in this inbox). The
1024
- // cloud releases that job's slot by itself within the hour. A marker with
1025
- // no recorded agent predates the field and is recovered as before.
1026
- if (marker.jobId && marker.agentUid && marker.agentUid !== config.agentUid) {
1027
- clearInflight(dir, marker.messageId);
1028
- log("warn", `dropped an unfinished scheduled run ${marker.messageId} of job ${marker.jobId}: it belongs to ${marker.agentUid}, ` +
1029
- `not this bot (${config.agentUid}) — left behind by an earlier bot in this folder; not posted, not reported`);
1030
- return true;
1031
- }
1032
- if (!isKickoff && isProcessed(readInboxState(dir), marker.messageId)) {
1033
- clearInflight(dir, marker.messageId);
1034
- return true;
1035
- }
1036
- // An unmentioned room turn (silenceable) that never produced a saved
1037
- // reply: the person never asked the bot to answer. Posting "I didn't
1038
- // finish that — I was restarted…" into that room is noise (2026-09-25:
1039
- // two bots posted the notice in a channel where neither was mentioned).
1040
- // Ack and clear silently; a saved `reply` still posts below because a
1041
- // real answer that only failed delivery is worth keeping.
1042
- if (!isKickoff &&
1043
- marker.silenceable === true &&
1044
- !marker.jobId &&
1045
- (marker.reply === undefined || marker.reply.trim() === "")) {
1046
- log("info", `recovered unmentioned room turn ${marker.messageId} silently (no saved reply); not posting a restart notice`);
1047
- await closeMarker(marker, isKickoff);
1048
- return true;
1049
- }
1050
- const parts = marker.replyParts ?? splitBody(recoveryBody(marker));
1051
- const from = marker.replyParts ? Math.min(Math.max(0, marker.replyPartsDelivered ?? 0), parts.length) : 0;
1052
- try {
1053
- await sendParts(marker.target, parts, from, marker.rootEventId, (count) => patchInflight(dir, marker.messageId, { replyParts: parts, replyPartsDelivered: count }));
1054
- }
1055
- catch (err) {
1056
- const reason = err instanceof Error ? err.message : String(err);
1057
- const attempt = (marker.recoveryFailures ?? 0) + 1;
1058
- if (attempt >= RECOVERY_ATTEMPT_LIMIT) {
1059
- log("warn", `gave up delivering the reply to ${marker.messageId} after ${attempt} attempts (${reason}); told the owner instead`);
1060
- if (marker.jobId) {
1061
- // Nobody asked, so "ask me again" is wrong. The header goes on only if
1062
- // no part of this run reached the chat yet.
1063
- const headerOut = (marker.progressPosted ?? 0) > 0 || (err instanceof PartialPostError ? err.delivered : from) > 0;
1064
- const text = marker.jobHeader && !headerOut ? `${marker.jobHeader}${UNDELIVERABLE_JOB_REPORT_TEXT}` : UNDELIVERABLE_JOB_REPORT_TEXT;
1065
- await postOne(marker.target, text, marker.rootEventId).catch(() => undefined);
1066
- // Giving up on DELIVERY is not giving up on the RUN: report it.
1067
- await reportRecoveredJobRun(marker);
1068
- }
1069
- else {
1070
- await postOne(marker.target, UNDELIVERABLE_REPLY_TEXT, marker.rootEventId).catch(() => undefined);
1071
- }
1072
- await closeMarker(marker, isKickoff);
1073
- return true;
1074
- }
1075
- const delivered = err instanceof PartialPostError ? err.delivered : from;
1076
- patchInflight(dir, marker.messageId, { replyParts: parts, replyPartsDelivered: delivered, recoveryFailures: attempt });
1077
- log("warn", `could not tell the owner about unfinished ${marker.messageId} (attempt ${attempt}/${RECOVERY_ATTEMPT_LIMIT}): ${reason}`);
1078
- return false;
1079
- }
1080
- await reportRecoveredJobRun(marker);
1081
- await closeMarker(marker, isKickoff);
1082
- log("info", marker.reply
1083
- ? `posted the saved reply for ${marker.messageId}`
1084
- : `told the owner ${marker.messageId} did not finish (${marker.jobFailure ? marker.jobFailure.reason : "restart"}); not re-run`);
1085
- return true;
1086
- };
1087
- /**
1088
- * First-start kickoff: ONE model turn on config.kickoff in the owner DM
1089
- * session, as if the owner had sent it, answered as a DM (with its
1090
- * in-between messages). The thinking reaction goes on the intro message
1091
- * (there is no owner message to mark). A failure never crashes the loop.
1092
- */
1093
- const runKickoff = async (introEventId) => {
1094
- const prompt = (config.kickoff ?? "").trim();
1095
- if (!prompt || stopping || state !== "running")
1096
- return;
1097
- const peerUid = config.ownerUid;
1098
- const tReceived = now().getTime();
1099
- log("info", `kickoff turn starting (${prompt.length} chars)`);
1100
- const thinking = introEventId
1101
- ? await api.setReaction({ peerUid, messageId: introEventId, emoji: THINKING_EMOJI }, true).catch(() => false)
1102
- : false;
1103
- const clearThinking = async () => {
1104
- if (thinking && introEventId) {
1105
- await api.setReaction({ peerUid, messageId: introEventId, emoji: THINKING_EMOJI }, false).catch(() => false);
1106
- }
1107
- };
1108
- const target = { kind: "dm", peerUid };
1109
- const { send, sendFinal, saved } = trackingSend(target);
1110
- const { outcome, poster } = await runTurnWithProgress({
1111
- marker: { messageId: KICKOFF_MESSAGE_ID, target, ...(thinking && introEventId ? { reactionEventId: introEventId } : {}) },
1112
- prompt,
1113
- sessionScope: "dm",
1114
- tReceived,
1115
- send,
1116
- sendFinal,
1117
- // The intro already said the bot is starting, and the app shows it thinking.
1118
- workingNotice: false,
1119
- });
1120
- await clearThinking();
1121
- if (outcome.ok) {
1122
- // The kickoff never runs silenceable, so outcome.silent is never set here.
1123
- if (poster.postedCount === 0) {
1124
- patchInflight(dir, KICKOFF_MESSAGE_ID, saved(outcome.reply));
1125
- log("warn", "kickoff reply failed to send; it is posted on the next start");
1126
- return;
1127
- }
1128
- clearInflight(dir, KICKOFF_MESSAGE_ID);
1129
- noteSetupReply(outcome.reply);
1130
- if (readBotConfig(dir)?.kickoffPendingSignIn)
1131
- patchBotConfig(dir, { kickoffPendingSignIn: false });
1132
- const st = readStatus();
1133
- setStatus({ repliesSent: (st?.repliesSent ?? 0) + 1, lastActivityAt: now().toISOString() });
1134
- log("info", `kickoff reply sent (${outcome.reply.length} chars)`);
1135
- return;
1136
- }
1137
- if (!outcome.aborted && poster.postedCount === 0 && isRuntimeSignInFailure(outcome.excerpt)) {
1138
- // Nothing ran: hold the kickoff until the tool can sign in, then run it.
1139
- clearInflight(dir, KICKOFF_MESSAGE_ID);
1140
- patchBotConfig(dir, { kickoffPendingSignIn: true });
1141
- markSignInBroken(outcome.excerpt);
1142
- await tellSignInNeeded("dm", send, true);
1143
- return;
1144
- }
1145
- if (readBotConfig(dir)?.kickoffPendingSignIn)
1146
- patchBotConfig(dir, { kickoffPendingSignIn: false });
1147
- let count = 0;
1148
- if (!outcome.aborted)
1149
- count = recordTurnFailure(outcome.error, "dm").count;
1150
- const body = outcome.started && (outcome.aborted || poster.postedCount > 0)
1151
- ? `${didNotFinishText(failureReason(outcome), poster.postedCount > 0)} Send me any message and I'll pick up from there.`
1152
- : `Sorry — I couldn't get started on my own (${runtime.id} failed: ${outcome.excerpt.slice(0, 160)}). Send me any message and I'll pick up from there, or check that ${runtime.id} is signed in on this computer.`;
1153
- try {
1154
- await send(body);
1155
- clearInflight(dir, KICKOFF_MESSAGE_ID);
1156
- }
1157
- catch {
1158
- /* the marker stays: the next start says it did not finish */
1159
- }
1160
- log("error", `kickoff turn ${outcome.aborted ? "stopped by the owner" : `failed (${count}/${FAILURE_LIMIT} in window)`}; not retried`);
1161
- if (!outcome.aborted && failures.exceeded(now().getTime())) {
1162
- await finish("failed", 0, `${FAILURE_LIMIT} model failures in 10 minutes; last: ${outcome.excerpt}`);
1163
- }
1164
- };
1165
- /**
1166
- * One fired job: a model turn on the job's own prompt, in the job's own
1167
- * session, reported in the owner's DM under a "scheduled job" header, and
1168
- * reported to the cloud exactly once.
1169
- */
1170
- const handleJobItem = async (item, target) => {
1171
- const id = item.messageId;
1172
- const { job, jobId } = target;
1173
- const peerUid = target.peerUid;
1174
- // An older pending run of this job: a newer one runs instead. Reported so
1175
- // the cloud releases the slot and the history says what happened.
1176
- if (supersededJobRuns.has(id)) {
1177
- await completeJobRun(jobId, id, { status: "skipped-precondition", disposition: SUPERSEDED_DISPOSITION });
1178
- markProcessed(dir, id, now().toISOString());
1179
- await api.ackInbox(config.agentUid, id);
1180
- supersededJobRuns.delete(id);
1181
- log("info", `skipped older run ${id} of job ${jobId}: a newer pending run of the same job runs instead`);
1182
- return;
1183
- }
1184
- const catchUp = isCatchUpRun(job, now());
1185
- const attempt = (attempts.get(id) ?? 0) + 1;
1186
- attempts.set(id, attempt);
1187
- const tReceived = now().getTime();
1188
- log("info", `received scheduled run ${id} of job ${jobId}${catchUp ? " (catch-up)" : ""}`);
1189
- // The header goes on the first message of the turn, so the owner sees at a
1190
- // glance that this is a scheduled run and not a reply to something they
1191
- // said. It rides on the marker too, so a report posted by the recovery path
1192
- // after a restart carries it as well.
1193
- //
1194
- // Every post goes through the SAME split/track path as any other reply
1195
- // (trackingSend → splitBody), so a long report is delivered in parts rather
1196
- // than refused whole. The header is only counted as delivered once a part
1197
- // actually reached the chat, and `saved` records the body EXACTLY as it was
1198
- // attempted (header included), so the parts the recovery path resends line
1199
- // up with the parts already delivered and nothing is repeated or dropped.
1200
- const header = jobReportHeader(job, catchUp, timeZone);
1201
- const markerTarget = { kind: "dm", peerUid };
1202
- const tracking = trackingSend(markerTarget);
1203
- let headerOut = false;
1204
- // What actually reached the chat, kept apart from "was anything posted".
1205
- // `poster.postedCount` counts progress posts too, so a turn that said
1206
- // "Checking the dashboards…" and then failed to post its REPORT would look
1207
- // delivered — and for a scheduled run the report is the only thing the
1208
- // owner sees; nobody will ask again.
1209
- const deliveredBodies = [];
1210
- let anySendFailed = false;
1211
- /** The body of the LAST send, when that send failed (the resume point). */
1212
- let lastFailedBody = null;
1213
- const withHeader = (body) => (headerOut ? body : `${header}${body}`);
1214
- const makeSend = (fn) => async (body) => {
1215
- const full = withHeader(body);
1216
- try {
1217
- await fn(full);
1218
- headerOut = true;
1219
- deliveredBodies.push(body);
1220
- lastFailedBody = null;
1221
- }
1222
- catch (err) {
1223
- anySendFailed = true;
1224
- lastFailedBody = full;
1225
- if (err instanceof PartialPostError && err.delivered > 0)
1226
- headerOut = true;
1227
- throw err;
1228
- }
1229
- };
1230
- const send = makeSend(tracking.send);
1231
- const sendFinal = makeSend(tracking.sendFinal);
1232
- const normalize = (text) => text.replace(/\s+/g, " ").trim();
1233
- /**
1234
- * True only when the final report itself reached the chat in full. With no
1235
- * failed post at all, the poster delivered everything it chose to (it skips
1236
- * a final that repeats a progress post, so "no failures" is the reliable
1237
- * signal). After any failure, the report must be inside a fully delivered
1238
- * post. Erring towards resending: a duplicate beats a report that vanished.
1239
- */
1240
- const reportDelivered = (reply) => poster.postedCount > 0 && (!anySendFailed || deliveredBodies.some((b) => normalize(b).includes(normalize(reply))));
1241
- /**
1242
- * The report, saved for resending. When the LAST post was the report and
1243
- * part of it already got through, resume that exact body at the parts
1244
- * delivered, so nothing is repeated. Otherwise resend the report whole,
1245
- * under its own header: the resend may come much later (after a restart)
1246
- * and must still read as a scheduled run.
1247
- */
1248
- const savedReport = (reply) => {
1249
- const jobOutput = jobRunOutput(reply);
1250
- const failed = lastFailedBody;
1251
- if (failed !== null && failed.trimEnd().endsWith(reply)) {
1252
- const resumed = tracking.saved(failed);
1253
- if ((resumed.replyPartsDelivered ?? 0) > 0)
1254
- return { ...resumed, jobOutput };
1255
- }
1256
- return { ...tracking.saved(`${header}${reply}`), jobOutput };
1257
- };
1258
- /** Remember that this run's outcome is reported, before the ack. */
1259
- const markReported = (status) => {
1260
- patchInflight(dir, id, { jobCompleted: status });
1261
- };
1262
- const { outcome, poster } = await runTurnWithProgress({
1263
- marker: { messageId: id, target: markerTarget, jobId, jobHeader: header, agentUid: config.agentUid },
1264
- prompt: buildJobTurnPrompt(job, { now: now(), timeZone }),
1265
- sessionScope: target.sessionScope,
1266
- tReceived,
1267
- send,
1268
- sendFinal,
1269
- // A scheduled run has nobody waiting in a chat: no "working on it" filler.
1270
- workingNotice: false,
1271
- });
1272
- if (outcome.ok) {
1273
- if (!reportDelivered(outcome.reply)) {
1274
- // The work finished but the REPORT did not fully reach the DM — even if
1275
- // a progress post did. Keep it (and the run un-reported and un-acked)
1276
- // so the next poll delivers it, resuming at the parts already read,
1277
- // before the run is completed. Never re-run.
1278
- patchInflight(dir, id, savedReport(outcome.reply));
1279
- log("warn", `report for run ${id} of job ${jobId} was not fully delivered; it is resent on the next poll`);
1280
- return;
1281
- }
1282
- await completeJobRun(jobId, id, { status: "succeeded", output: jobRunOutput(outcome.reply) });
1283
- markReported("succeeded");
1284
- markProcessed(dir, id, now().toISOString());
1285
- await api.ackInbox(config.agentUid, id);
1286
- clearInflight(dir, id);
1287
- attempts.delete(id);
1288
- setStatus({ repliesSent: (readStatus()?.repliesSent ?? 0) + 1, lastActivityAt: now().toISOString() });
1289
- log("info", `job ${jobId} run ${id} done (${outcome.reply.length} chars${catchUp ? ", catch-up" : ""})`);
1290
- return;
1291
- }
1292
- if (!outcome.aborted && poster.postedCount === 0 && isRuntimeSignInFailure(outcome.excerpt)) {
1293
- // Nothing ran: hold the run until the coding tool can sign in again. It
1294
- // is neither acked nor reported succeeded — the work is still owed.
1295
- clearInflight(dir, id);
1296
- attempts.delete(id);
1297
- markSignInBroken(outcome.excerpt);
1298
- await tellSignInNeeded(`job:${jobId}`, (body) => sendToTarget(markerTarget, body));
1299
- log("warn", `kept scheduled run ${id} of job ${jobId} until ${runtime.id} can sign in again`);
1300
- return; // un-acked, un-reported: run once the sign-in works
1301
- }
1302
- if (!outcome.started) {
1303
- // The model never ran, so nothing happened outside this Mac: retry.
1304
- clearInflight(dir, id);
1305
- const { excerpt } = recordTurnFailure(outcome.error, target.sessionScope);
1306
- if (failures.exceeded(now().getTime())) {
1307
- await finish("failed", 0, `${FAILURE_LIMIT} model failures in 10 minutes; last: ${excerpt}`);
1308
- return;
1309
- }
1310
- if (attempt >= MAX_ATTEMPTS_PER_MESSAGE) {
1311
- await send(`I couldn't run this one — ${runtime.id} kept failing: ${excerpt.slice(0, 160)}.`).catch(() => undefined);
1312
- await completeJobRun(jobId, id, { status: "failed", output: jobRunOutput(excerpt), disposition: `${runtime.id} could not be started` });
1313
- markReported("failed");
1314
- markProcessed(dir, id, now().toISOString());
1315
- await api.ackInbox(config.agentUid, id);
1316
- attempts.delete(id);
1317
- return;
1318
- }
1319
- await sleep(fullJitterDelayMs(failures.count(now().getTime()), { random: deps.random }));
1320
- return; // un-acked; retried on the next poll
1321
- }
1322
- // The model started: it may already have done things, so never re-run.
1323
- if (!outcome.aborted)
1324
- recordTurnFailure(outcome.error, target.sessionScope);
1325
- const reason = failureReason(outcome);
1326
- // Saved BEFORE the post: if "did not finish" cannot be posted, recovery
1327
- // reports and says this real reason, not "the bot was restarted".
1328
- patchInflight(dir, id, { jobFailure: { reason, ...(outcome.excerpt ? { excerpt: outcome.excerpt } : {}) } });
1329
- try {
1330
- await send(didNotFinishText(reason, poster.postedCount > 0));
1331
- }
1332
- catch (err) {
1333
- // Leave it un-acked with the marker: the next poll reports it.
1334
- log("warn", `could not post "did not finish" for run ${id} of job ${jobId}: ${err instanceof Error ? err.message : String(err)}`);
1335
- return;
1336
- }
1337
- await completeJobRun(jobId, id, { status: "failed", output: jobRunOutput(outcome.excerpt), disposition: reason.slice(0, 256) });
1338
- markReported("failed");
1339
- markProcessed(dir, id, now().toISOString());
1340
- await api.ackInbox(config.agentUid, id);
1341
- clearInflight(dir, id);
1342
- attempts.delete(id);
1343
- log("error", `scheduled run ${id} of job ${jobId} ${outcome.aborted ? "stopped by the owner" : "failed"} after it started; not re-run`);
1344
- if (!outcome.aborted && failures.exceeded(now().getTime())) {
1345
- await finish("failed", 0, `${FAILURE_LIMIT} model failures in 10 minutes; last: ${outcome.excerpt}`);
1346
- }
1347
- };
1348
- /**
1349
- * The instant answer to "Explain HQ first" (setup-explain.ts). Returns true
1350
- * when it answered the message (sent, marked processed, acked); false sends
1351
- * the message down the normal model path, so nothing here can leave a
1352
- * message unanswered.
1353
- */
1354
- const sendSetupExplanation = async (item, text, attachments) => {
1355
- const id = item.messageId;
1356
- let reply;
1357
- try {
1358
- const due = setupExplainDue({
1359
- text,
1360
- attachments,
1361
- state: readSetupIntroState(dir),
1362
- progress: readSetupProgressIntro(resolveBotMemoryDir(config)),
1363
- });
1364
- if (!due)
1365
- return false;
1366
- const explainer = loadSetupExplainer(config.hqRoot, config.workerDir);
1367
- if (!explainer) {
1368
- log("warn", `no usable explain-hq.md in ${config.workerDir}; answering ${id} with a model turn`);
1369
- return false;
1370
- }
1371
- reply = explainer.reply;
1372
- }
1373
- catch (err) {
1374
- log("warn", `setup explanation check failed (${err instanceof Error ? err.message : String(err)}); answering ${id} with a model turn`);
1375
- return false;
1376
- }
1377
- try {
1378
- await sendToTarget({ kind: "dm", peerUid: config.ownerUid }, reply, item.rootEventId, "human");
1379
- }
1380
- catch (err) {
1381
- log("warn", `setup explanation for ${id} could not be sent (${err instanceof Error ? err.message : String(err)}); answering with a model turn`);
1382
- return false;
1383
- }
1384
- markProcessed(dir, id, now().toISOString());
1385
- try {
1386
- patchSetupIntroState(dir, { explainedAt: now().toISOString(), notePending: true, offeredAt: undefined });
1387
- }
1388
- catch (err) {
1389
- log("warn", `setup intro state not updated: ${err instanceof Error ? err.message : String(err)}`);
1390
- }
1391
- await api.ackInbox(config.agentUid, id);
1392
- setStatus({ repliesSent: (readStatus()?.repliesSent ?? 0) + 1, lastActivityAt: now().toISOString() });
1393
- log("info", `answered ${id} with the setup explanation (no model turn)`);
1394
- return true;
1395
- };
1396
- const handleItem = async (item) => {
1397
- const id = item.messageId;
1398
- const inboxState = readInboxState(dir);
1399
- if (isProcessed(inboxState, id)) {
1400
- // Replied before a crash; only the ack was lost.
1401
- await api.ackInbox(config.agentUid, id);
1402
- clearInflight(dir, id);
1403
- log("info", `acked already-processed ${id}`);
1404
- return;
1405
- }
1406
- // A turn on this message already started once and was cut off: say so,
1407
- // never run it again.
1408
- const inflight = readInflight(dir, id);
1409
- if (inflight) {
1410
- await recoverInflight(inflight);
1411
- return;
1412
- }
1413
- const target = resolveReplyTarget(item, config);
1414
- // A bot/agent sender that did not @mention this bot must never start a model
1415
- // turn: two bots each answering the other's plain room posts loop forever
1416
- // (observed 2026-09-25). An explicit @mention still gets answered below.
1417
- if (target && target.kind === "room" && !target.mentioned && isAgentSender(item.fromPersonUid)) {
1418
- markProcessed(dir, id, now().toISOString());
1419
- await api.ackInbox(config.agentUid, id);
1420
- log("info", `ignored inbox item ${id} (room ${target.channelId}, unmentioned message from bot ${item.fromPersonUid ?? "unknown"}; not starting a turn)`);
1421
- return;
1422
- }
1423
- if (!target) {
1424
- // A job item the bot cannot run. When it names a job, the cloud is still
1425
- // holding that job's in-progress slot: acking alone would jam every later
1426
- // fire of it for an hour, and the next fire would be just as unusable —
1427
- // the same jam, forever. Report it so the slot is released.
1428
- const unusableJobId = isJobItem(item) && typeof item.jobId === "string" ? item.jobId.trim() : "";
1429
- if (unusableJobId) {
1430
- await completeJobRun(unusableJobId, id, {
1431
- status: "skipped-precondition",
1432
- disposition: "the fired run carried no prompt, so there was nothing to run",
1433
- });
1434
- }
1435
- markProcessed(dir, id, now().toISOString());
1436
- await api.ackInbox(config.agentUid, id);
1437
- log("info", isJobItem(item)
1438
- ? `ignored job item ${id}: it carries no ${unusableJobId ? "prompt" : "job id"}`
1439
- : `ignored inbox item ${id} (${item.channel || "dm"}${item.channelScope ? ` ${item.channelScope}` : ""}, not addressed to me)`);
1440
- return;
1441
- }
1442
- if (target.kind === "job") {
1443
- await handleJobItem(item, target);
1444
- return;
1445
- }
1446
- const messageText = (item.text ?? "").trim();
1447
- // A message can be only a file (no text): that is still a message to answer.
1448
- const attachmentRefs = inboxEntryAttachments(item);
1449
- if (!messageText && attachmentRefs.length === 0) {
1450
- markProcessed(dir, id, now().toISOString());
1451
- await api.ackInbox(config.agentUid, id);
1452
- return;
1453
- }
1454
- // Setup bot: "Explain HQ first" clicked while that question is pending is
1455
- // answered with the fixed explanation, with no model turn.
1456
- const ownerDm = target.kind === "dm" && target.peerUid === config.ownerUid;
1457
- if (isSetupBot && ownerDm && (await sendSetupExplanation(item, messageText, attachmentRefs.length)))
1458
- return;
1459
- const attempt = (attempts.get(id) ?? 0) + 1;
1460
- attempts.set(id, attempt);
1461
- const reactionId = item.eventId ?? id;
1462
- const tReceived = now().getTime();
1463
- const where = target.kind === "room" ? `room ${target.channelId}` : "dm";
1464
- log("info", `received ${id} (${messageText.length} chars${attachmentRefs.length ? `, ${attachmentRefs.length} attachment${attachmentRefs.length === 1 ? "" : "s"}` : ""}, ${where})`);
1465
- // Rooms: an UNMENTIONED responder (a plain room message)
1466
- // claims first so the owner's several bots produce one answer, not one
1467
- // each. A bot that was @mentioned never claims — it was asked by name and
1468
- // must answer even if a sibling bot was faster. The same claimer
1469
- // re-acquires on a retry (server lease), so the claim is safe to repeat
1470
- // when a failed turn leaves the item un-acked.
1471
- if (target.kind === "room" && !target.mentioned) {
1472
- const claimed = await api.claimChannelUnit(target.channelId, target.unitId);
1473
- if (!claimed) {
1474
- markProcessed(dir, id, now().toISOString());
1475
- await api.ackInbox(config.agentUid, id);
1476
- attempts.delete(id);
1477
- log("info", `skipped ${id}: claimed by another responder`);
1478
- return;
1479
- }
1480
- }
1481
- // Thinking indicator: DMs use a reaction; rooms use the ephemeral
1482
- // agent-status wake (cleared client-side by a post, so it is re-posted
1483
- // after each in-between message). It stays on until the turn ends.
1484
- const thinking = target.kind === "dm"
1485
- ? await api.setReaction({ peerUid: target.peerUid, messageId: reactionId, emoji: THINKING_EMOJI }, true)
1486
- : false;
1487
- if (target.kind === "room")
1488
- await api.postAgentStatus(target.channelId, ROOM_THINKING_STATUS, target.rootEventId);
1489
- const clearThinking = async () => {
1490
- if (thinking && target.kind === "dm") {
1491
- await api.setReaction({ peerUid: target.peerUid, messageId: reactionId, emoji: THINKING_EMOJI }, false);
1492
- }
1493
- };
1494
- // Attachments are fetched here, in the runner, so every runtime sees them
1495
- // the same way: the turn text names each saved file (or why it is missing).
1496
- let text = messageText;
1497
- const readDirs = [];
1498
- if (attachmentRefs.length > 0) {
1499
- const attachmentsDir = botAttachmentsDir(dir);
1500
- const files = await downloadTurnAttachments({
1501
- attachments: attachmentRefs,
1502
- botEntityUid: config.agentUid,
1503
- attachmentsDir,
1504
- resolveBotCompanyUids: async () => (await api.getAgent(config.agentUid)).companyMemberships ?? [],
1505
- ...(deps.downloadAttachment ? { download: deps.downloadAttachment } : {}),
1506
- });
1507
- for (const f of files) {
1508
- if (f.error)
1509
- log("warn", `attachment ${f.name} on ${id} not downloaded: ${f.error}`);
1510
- else
1511
- log("info", `attachment ${f.name} on ${id} saved (${f.sizeBytes ?? 0} bytes)`);
1512
- }
1513
- if (files.some((f) => f.localPath))
1514
- readDirs.push(attachmentsDir);
1515
- const block = attachmentTurnBlock(files);
1516
- text = text ? `${text}\n\n${block}` : block;
1517
- }
1518
- const sessionScope = target.kind === "room" ? target.sessionScope : dmSessionScope(target.peerUid, config.ownerUid);
1519
- // The turn after the app sent the explanation: tell the model it went out.
1520
- const setupNote = isSetupBot && ownerDm && readSetupIntroState(dir).notePending === true;
1521
- const ownerText = setupNote ? `${SETUP_EXPLAINED_NOTE}\n\n${text}` : text;
1522
- const prompt = target.kind === "room" ? await buildRoomTurn(item, target, text) : target.peerUid === config.ownerUid ? ownerText :
1523
- `[HQ DM sender: ${target.peerUid}; owner: ${config.ownerUid}; sender is not the owner.]\n\n${text}`;
1524
- const markerTarget = target.kind === "dm" ? { kind: "dm", peerUid: target.peerUid } : { kind: "room", channelId: target.channelId };
1525
- const { send, sendFinal, saved } = trackingSend(markerTarget, item.rootEventId);
1526
- const { outcome, poster } = await runTurnWithProgress({
1527
- marker: {
1528
- messageId: id,
1529
- target: markerTarget,
1530
- ...(item.rootEventId ? { rootEventId: item.rootEventId } : {}),
1531
- ...(thinking ? { reactionEventId: reactionId } : {}),
1532
- },
1533
- prompt,
1534
- sessionScope,
1535
- tReceived,
1536
- send,
1537
- sendFinal,
1538
- silenceable: target.kind === "room" && !target.mentioned,
1539
- ...(readDirs.length ? { readDirs } : {}),
1540
- ...(target.kind === "room"
1541
- ? { afterProgressPost: () => api.postAgentStatus(target.channelId, ROOM_THINKING_STATUS, target.rootEventId) }
1542
- : {}),
1543
- });
1544
- // The model saw the note once its turn ran. A turn that never started, or
1545
- // one held for a coding-tool sign-in, runs again and keeps the note for it.
1546
- if (setupNote && (outcome.ok || (outcome.started && !isRuntimeSignInFailure(outcome.excerpt)))) {
1547
- try {
1548
- patchSetupIntroState(dir, { notePending: false });
1549
- }
1550
- catch (err) {
1551
- log("warn", `setup intro state not updated: ${err instanceof Error ? err.message : String(err)}`);
1552
- }
1553
- }
1554
- if (outcome.ok && ownerDm)
1555
- noteSetupReply(outcome.reply);
1556
- if (outcome.ok) {
1557
- // A no_reply sentinel or intentionally empty reply: ack silently, post nothing.
1558
- if (outcome.silent) {
1559
- markProcessed(dir, id, now().toISOString());
1560
- await api.ackInbox(config.agentUid, id);
1561
- clearInflight(dir, id);
1562
- attempts.delete(id);
1563
- await clearThinking();
1564
- log("info", `no_reply sentinel or empty reply for ${id} (${where}); acked silently`);
1565
- return;
1566
- }
1567
- // Known gap (#614, not changed here): a progress post counts, so a final answer that fails after one is not resent.
1568
- if (poster.postedCount === 0) {
1569
- // The work finished but nothing reached the chat: keep the answer —
1570
- // in the parts it will be posted as, and how many of them already got
1571
- // through — so the next poll (or a restart) delivers the remainder
1572
- // instead of running the turn again or repeating what was read.
1573
- patchInflight(dir, id, saved(outcome.reply));
1574
- await clearThinking();
1575
- log("warn", `reply to ${id} could not be posted; it is retried on the next poll`);
1576
- return;
1577
- }
1578
- markProcessed(dir, id, now().toISOString());
1579
- await api.ackInbox(config.agentUid, id);
1580
- clearInflight(dir, id);
1581
- attempts.delete(id);
1582
- await clearThinking();
1583
- const st = readStatus();
1584
- setStatus({ repliesSent: (st?.repliesSent ?? 0) + 1, lastActivityAt: now().toISOString() });
1585
- log("info", `replied to ${id} (${outcome.reply.length} chars, ${where}, ${poster.postedCount} post${poster.postedCount === 1 ? "" : "s"})`);
1586
- return;
1587
- }
1588
- await clearThinking();
1589
- if (!outcome.aborted && poster.postedCount === 0 && isRuntimeSignInFailure(outcome.excerpt)) {
1590
- // The tool refused before doing anything: keep the message for when it
1591
- // can sign in again, and say so once in this conversation.
1592
- clearInflight(dir, id);
1593
- attempts.delete(id);
1594
- markSignInBroken(outcome.excerpt);
1595
- const conversation = markerTarget.kind === "dm" ? sessionScope : `room:${markerTarget.channelId}:${item.rootEventId ?? ""}`;
1596
- await tellSignInNeeded(conversation, send);
1597
- log("warn", `kept ${id} until ${runtime.id} can sign in again`);
1598
- return; // un-acked: answered once the sign-in works
1599
- }
1600
- if (!outcome.started) {
1601
- // The model never ran (e.g. the binary is missing): nothing happened
1602
- // outside this Mac, so retrying is safe.
1603
- clearInflight(dir, id);
1604
- const { excerpt } = recordTurnFailure(outcome.error, sessionScope);
1605
- if (failures.exceeded(now().getTime())) {
1606
- await finish("failed", 0, `${FAILURE_LIMIT} model failures in 10 minutes; last: ${excerpt}`);
1607
- return;
1608
- }
1609
- if (attempt >= MAX_ATTEMPTS_PER_MESSAGE) {
1610
- try {
1611
- await send(`Sorry — I couldn't answer that one (${runtime.id} kept failing: ${excerpt.slice(0, 160)}). Try again in a bit, or check that ${runtime.id} is signed in on this computer.`);
1612
- }
1613
- catch {
1614
- /* best-effort */
1615
- }
1616
- markProcessed(dir, id, now().toISOString());
1617
- await api.ackInbox(config.agentUid, id);
1618
- attempts.delete(id);
1619
- return;
1620
- }
1621
- await sleep(fullJitterDelayMs(failures.count(now().getTime()), { random: deps.random }));
1622
- return; // leave un-acked; retried on the next poll
1623
- }
1624
- // The model started: it may already have done things, so never re-run.
1625
- if (!outcome.aborted)
1626
- recordTurnFailure(outcome.error, sessionScope);
1627
- // reasoning_only means the model produced only reasoning tokens and no text.
1628
- const reasoningOnly = !outcome.aborted && isReasoningOnlyError(outcome.excerpt);
1629
- const silenceableTurn = target.kind === "room" && !target.mentioned;
1630
- // Unmentioned room turn that posted nothing and was not stopped by the
1631
- // owner: any model failure (reasoning_only or otherwise) is a silent
1632
- // no-reply. The failure is already recorded above via recordTurnFailure,
1633
- // so we just ack quietly and never leak the raw error into the room.
1634
- if (!outcome.aborted && poster.postedCount === 0 && silenceableTurn) {
1635
- markProcessed(dir, id, now().toISOString());
1636
- await api.ackInbox(config.agentUid, id);
1637
- clearInflight(dir, id);
1638
- attempts.delete(id);
1639
- await clearThinking();
1640
- log("info", `unmentioned room turn ${id} failed with no post (${where}); acked silently`);
1641
- if (failures.exceeded(now().getTime())) {
1642
- await finish("failed", 0, `${FAILURE_LIMIT} model failures in 10 minutes; last: ${outcome.excerpt}`);
1643
- }
1644
- return;
1645
- }
1646
- try {
1647
- // DM or @-mentioned room reasoning_only: the person asked directly, so
1648
- // still say we did not finish — but with a plain reason, never the raw
1649
- // internal error string.
1650
- const reason = reasoningOnly ? "the model returned no answer" : failureReason(outcome);
1651
- await send(didNotFinishText(reason, poster.postedCount > 0));
1652
- }
1653
- catch (err) {
1654
- // Leave it un-acked with the marker: the next poll says it did not finish.
1655
- log("warn", `could not post "did not finish" for ${id}: ${err instanceof Error ? err.message : String(err)}`);
1656
- return;
1657
- }
1658
- markProcessed(dir, id, now().toISOString());
1659
- await api.ackInbox(config.agentUid, id);
1660
- clearInflight(dir, id);
1661
- attempts.delete(id);
1662
- log("error", `turn on ${id} ${outcome.aborted ? "stopped by the owner" : "failed"} after it started; told the owner, not re-run`);
1663
- if (!outcome.aborted && failures.exceeded(now().getTime())) {
1664
- await finish("failed", 0, `${FAILURE_LIMIT} model failures in 10 minutes; last: ${outcome.excerpt}`);
1665
- }
1666
- };
1667
- // The kickoff runs alongside the heartbeat, before the first inbox poll, so
1668
- // an owner message sent meanwhile is answered after it in the same session.
1669
- const kickoff = kickoffAfterIntro
1670
- ? runKickoff(kickoffAfterIntro.introEventId).catch((err) => {
1671
- log("error", `kickoff turn crashed: ${err instanceof Error ? err.message : String(err)}`);
1672
- })
1673
- : Promise.resolve();
1674
- // ── Lanes: conversations side by side, each conversation in order ─────────
1675
- /** Messages waiting per lane, in arrival order. */
1676
- const lanes = new Map();
1677
- /** Lanes with a message being handled right now. */
1678
- const busyLanes = new Set();
1679
- /** Every message queued or being handled (the inbox re-delivers until acked). */
1680
- const pending = new Set();
1681
- const running = new Set();
1682
- const canStart = () => !stopping && state === "running" && !hasPromotionHold(dir);
1683
- /** Job turns yield to people: one at a time, and never the last free slot. */
1684
- const isJobLane = (lane) => lane.startsWith("job:");
1685
- const jobLaneBudget = Math.max(1, maxParallelTurns - 1);
1686
- const canStartJobLane = () => [...busyLanes].filter(isJobLane).length < MAX_PARALLEL_JOB_TURNS && busyLanes.size < jobLaneBudget;
1687
- const pump = () => {
1688
- for (const [lane, queue] of lanes) {
1689
- if (busyLanes.size >= maxParallelTurns || !canStart())
1690
- return;
1691
- // While the sign-in is broken, one message at a time tries it, on a timer.
1692
- if (signInIssue && (busyLanes.size > 0 || now().getTime() < nextSignInRetryAt))
1693
- return;
1694
- if (busyLanes.has(lane))
1695
- continue;
1696
- // `continue`, never `return`: a job that cannot start yet must not hold
1697
- // up the owner's DM sitting behind it in the map.
1698
- if (isJobLane(lane) && !canStartJobLane())
1699
- continue;
1700
- const item = queue.shift();
1701
- if (queue.length === 0)
1702
- lanes.delete(lane);
1703
- if (!item)
1704
- continue;
1705
- busyLanes.add(lane);
1706
- if (signInIssue)
1707
- nextSignInRetryAt = now().getTime() + signInRetryMs;
1708
- const task = handleItem(item)
1709
- .catch((err) => {
1710
- log("warn", `inbox item ${item.messageId} failed: ${err instanceof Error ? err.message : String(err)}`);
1711
- })
1712
- .finally(() => {
1713
- resetInboxBackoff();
1714
- busyLanes.delete(lane);
1715
- pending.delete(item.messageId);
1716
- running.delete(task);
1717
- pump();
1718
- });
1719
- running.add(task);
1720
- }
1721
- };
1722
- const enqueue = (item) => {
1723
- if (pending.has(item.messageId))
1724
- return;
1725
- pending.add(item.messageId);
1726
- const lane = inboxLaneKey(item, config);
1727
- const queue = lanes.get(lane);
1728
- if (queue)
1729
- queue.push(item);
1730
- else
1731
- lanes.set(lane, [item]);
1732
- };
1733
- const inboxLoop = (async () => {
1734
- // Turns cut off by the last restart are reported before anything new runs.
1735
- for (const leftover of leftovers) {
1736
- try {
1737
- await recoverInflight(leftover);
1738
- }
1739
- catch (err) {
1740
- log("warn", `recovering ${leftover.messageId} failed: ${err instanceof Error ? err.message : String(err)}`);
1741
- }
1742
- }
1743
- await kickoff;
1744
- let inboxFails = 0;
1745
- while (!stopping && state === "running") {
1746
- if (hasPromotionHold(dir))
1747
- break;
1748
- // The install under this process was updated: take nothing new, let the
1749
- // turns already running finish, then exit so the supervisor loads it.
1750
- // Queued items were never started or acked; the next process gets them.
1751
- if (pollForCliUpdate())
1752
- break;
1753
- // A kickoff held for a sign-in retries on the same timer as messages.
1754
- if (busyLanes.size === 0 &&
1755
- (!signInIssue || now().getTime() >= nextSignInRetryAt) &&
1756
- readBotConfig(dir)?.kickoffPendingSignIn) {
1757
- if (signInIssue)
1758
- nextSignInRetryAt = now().getTime() + signInRetryMs;
1759
- await runKickoff().catch((err) => {
1760
- log("error", `kickoff retry crashed: ${err instanceof Error ? err.message : String(err)}`);
1761
- });
1762
- }
1763
- // Completions the cloud has not accepted yet: re-send the report (never
1764
- // the work), alongside the poll rather than in front of it.
1765
- kickCompletionRetries();
1766
- const useInboxBackoff = await inboxPollBackoffEnabled().catch((error) => {
1767
- log("warn", `inbox poll backoff flag lookup failed (${safeErrorClass(error)}); using default-off`);
1768
- return false;
1769
- });
1770
- let items;
1771
- try {
1772
- items = await api.pullInbox(config.agentUid);
1773
- inboxFails = 0;
1774
- setStatus({ lastInboxPollAt: now().toISOString(), lastInboxPollOk: true, lastInboxError: undefined });
1775
- // One catch-up per job per wake: when several runs of the same job are
1776
- // pending, the newest runs and the older ones are reported skipped.
1777
- for (const id of planJobRuns(items, handledJobFires).superseded)
1778
- supersededJobRuns.add(id);
1779
- if (items.length > 0)
1780
- resetInboxBackoff();
1781
- for (const item of items)
1782
- enqueue(item);
1783
- pump();
1784
- if (stopping || state !== "running")
1785
- break;
1786
- }
1787
- catch (err) {
1788
- inboxFails += 1;
1789
- const message = err instanceof Error ? err.message : String(err);
1790
- setStatus({ lastInboxPollOk: false, lastInboxError: message.slice(0, 400) });
1791
- log("warn", `inbox poll failed: ${message}`);
1792
- if (stopping || state !== "running")
1793
- break;
1794
- await sleep(apiPollDelayMs({ err, attempt: inboxFails - 1, intervalMs: inboxIntervalMs, random }));
1795
- continue;
1796
- }
1797
- if (stopping || state !== "running")
1798
- break;
1799
- if (!useInboxBackoff) {
1800
- inboxBackoffIndex = 0;
1801
- await waitForInbox(inboxIntervalMs, false);
1802
- continue;
1803
- }
1804
- const delayMs = items.length > 0
1805
- ? inboxIntervalMs
1806
- : inboxBackoffSteps[Math.min(inboxBackoffIndex, inboxBackoffSteps.length - 1)];
1807
- if (items.length === 0)
1808
- inboxBackoffIndex = Math.min(inboxBackoffIndex + 1, inboxBackoffSteps.length - 1);
1809
- await waitForInbox(delayMs, true);
1810
- }
1811
- // Stop, drain and promotion wait for the turns already running. Queued
1812
- // messages were never started or acked, so the inbox delivers them again.
1813
- while (running.size > 0)
1814
- await Promise.allSettled([...running]);
1815
- await completionRetryTask;
1816
- })();
1817
- function readStatus() {
1818
- return readBotStatus(dir);
1819
- }
1820
- const stop = async (mode = "abort") => {
1821
- // An owner stop or a promotion while an update restart drains wins: the
1822
- // bot then exits 0 and stays down instead of being restarted.
1823
- cliUpdatePending = null;
1824
- if (stopping) {
1825
- if (mode === "abort")
1826
- for (const turn of currentTurns)
1827
- turn.abort();
1828
- return;
1829
- }
1830
- stopping = true;
1831
- activeInboxWait?.abort();
1832
- // End the turn in progress; its message gets "did not finish", not silence.
1833
- // Promotion instead drains that turn, including its reply and ACK, before
1834
- // the coordinator snapshots memory and starts the cloud consumer.
1835
- if (mode === "abort")
1836
- for (const turn of currentTurns)
1837
- turn.abort();
1838
- await Promise.allSettled([heartbeatLoop, inboxLoop]);
1839
- await finish("stopped", 0, mode === "drain" ? "drain completed (running turns finished)" : "stop requested");
1840
- };
1841
- const onSignal = () => {
1842
- void stop();
1843
- };
1844
- const events = deps.processEvents ?? process;
1845
- events.once("SIGTERM", onSignal);
1846
- events.once("SIGINT", onSignal);
1847
- events.once("SIGUSR2", () => { void stop("drain"); });
1848
- void inboxLoop.then(() => { if (hasPromotionHold(dir))
1849
- void stop("drain"); });
1850
- setStatus({ canDrainForPromotion: true });
1851
- void Promise.allSettled([heartbeatLoop, inboxLoop]).then(() => {
1852
- if (state !== "running")
1853
- return;
1854
- const update = cliUpdatePending;
1855
- if (!update) {
1856
- void finish("stopped", 0, "loops ended");
1857
- return;
1858
- }
1859
- try {
1860
- deps.cliUpdate?.recordRestart(update);
1861
- }
1862
- catch (err) {
1863
- log("warn", `could not record the update restart: ${err instanceof Error ? err.message : String(err)}`);
1864
- }
1865
- void finish("stopped", CLI_UPDATE_RESTART_EXIT_CODE, `hq-cli updated ${update.from} -> ${update.to}; restarting to load it`, () => deps.onCliUpdateRestart?.(update, log));
1866
- });
1867
- return { stop, done, status: readStatus, idle: () => pending.size === 0 };
1868
- }
1869
- //# sourceMappingURL=run.js.map