@indigoai-us/hq-cli 5.314.0 → 5.316.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 (1193) hide show
  1. package/CHANGELOG.md +4320 -1
  2. package/README.md +113 -0
  3. package/assets/bot-workers/setup/context/USER-GUIDE.md +404 -0
  4. package/assets/bot-workers/setup/context/quick-reference.md +199 -0
  5. package/assets/bot-workers/setup/skills/agents-and-team.md +167 -0
  6. package/assets/bot-workers/setup/skills/explain-hq.md +35 -0
  7. package/assets/bot-workers/setup/skills/first-company.md +74 -0
  8. package/assets/bot-workers/setup/skills/joining-a-team.md +125 -0
  9. package/assets/bot-workers/setup/skills/pricing.md +92 -0
  10. package/assets/bot-workers/setup/skills/standing-help.md +81 -0
  11. package/assets/bot-workers/setup/skills/your-business.md +281 -0
  12. package/assets/bot-workers/setup/worker.yaml +791 -0
  13. package/assets/lanes-hooks/hq-lanes-drain.json +15 -0
  14. package/assets/lanes-hooks/hq-lanes-drain.mjs +275 -0
  15. package/assets/lanes-hooks/hq-lanes-drain.sh +21 -0
  16. package/assets/lanes-reconcile/hq-lanes-reconcile.service +11 -0
  17. package/assets/lanes-reconcile/hq-lanes-reconcile.timer +12 -0
  18. package/assets/scaffold/.claude/hooks/validate-policy-frontmatter.sh +485 -0
  19. package/assets/scaffold/core/scripts/audit-log.sh +384 -0
  20. package/assets/scaffold/core/scripts/checkpoint-stop-gate.sh +281 -43
  21. package/assets/scaffold/core/scripts/clean-worktree-reconcile-handoff.sh +171 -0
  22. package/assets/scaffold/core/scripts/detect-stale-review-base.sh +199 -0
  23. package/assets/scaffold/core/scripts/eval-trigger.sh +193 -0
  24. package/assets/scaffold/core/scripts/git-pack-extension-check.sh +164 -0
  25. package/assets/scaffold/core/scripts/handoff-finalize.sh +688 -0
  26. package/assets/scaffold/core/scripts/handoff-open-steps.sh +81 -0
  27. package/assets/scaffold/core/scripts/handoff-post.sh +252 -0
  28. package/assets/scaffold/core/scripts/hook-lib.sh +345 -50
  29. package/assets/scaffold/core/scripts/hq-delegate-bundle.sh +307 -0
  30. package/assets/scaffold/core/scripts/hq-delegate-grant.sh +252 -0
  31. package/assets/scaffold/core/scripts/hq-delegate-pickup.sh +99 -0
  32. package/assets/scaffold/core/scripts/hq-delegate-publish.sh +91 -0
  33. package/assets/scaffold/core/scripts/hq-delegate-repo.sh +158 -0
  34. package/assets/scaffold/core/scripts/hq-delegate-resolve.sh +145 -0
  35. package/assets/scaffold/core/scripts/hq-delegate-secrets.sh +129 -0
  36. package/assets/scaffold/core/scripts/hq-delegate-send.sh +259 -0
  37. package/assets/scaffold/core/scripts/hq-delegate-transfer.sh +175 -0
  38. package/assets/scaffold/core/scripts/hq-delegate-verify.sh +238 -0
  39. package/assets/scaffold/core/scripts/hq-dm-bind.sh +585 -0
  40. package/assets/scaffold/core/scripts/hq-job-notify.sh +389 -0
  41. package/assets/scaffold/core/scripts/hq-job-probe.sh +835 -0
  42. package/assets/scaffold/core/scripts/hq-job-remediate.sh +359 -0
  43. package/assets/scaffold/core/scripts/hq-job-run.sh +1025 -0
  44. package/assets/scaffold/core/scripts/hq-pin.sh +118 -0
  45. package/assets/scaffold/core/scripts/hq-session.sh +184 -23
  46. package/assets/scaffold/core/scripts/jobs-schedule-parse.sh +310 -0
  47. package/assets/scaffold/core/scripts/jobs-validate.sh +451 -0
  48. package/assets/scaffold/core/scripts/knowledge-prefs.sh +55 -0
  49. package/assets/scaffold/core/scripts/lib/portable.sh +211 -0
  50. package/assets/scaffold/core/scripts/lib/secret-patterns.sh +58 -0
  51. package/assets/scaffold/core/scripts/lib/session-id.sh +3 -2
  52. package/assets/scaffold/core/scripts/lib/session-scope-capability.sh +1 -1
  53. package/assets/scaffold/core/scripts/lib/work-mesh-enqueue.sh +2 -1
  54. package/assets/scaffold/core/scripts/lib/work-mesh-live-hook.sh +378 -0
  55. package/assets/scaffold/core/scripts/lib/work-mesh-live-rebind.sh +141 -0
  56. package/assets/scaffold/core/scripts/migrate-policy-triggers.sh +378 -0
  57. package/assets/scaffold/core/scripts/ontology-audience-grant.sh +81 -0
  58. package/assets/scaffold/core/scripts/ontology-brief.mjs +93 -0
  59. package/assets/scaffold/core/scripts/ontology-candidate.sh +100 -0
  60. package/assets/scaffold/core/scripts/ontology-garden.mjs +238 -0
  61. package/assets/scaffold/core/scripts/ontology-source-worklist.sh +79 -0
  62. package/assets/scaffold/core/scripts/outpost-jobs-reconcile.sh +834 -0
  63. package/assets/scaffold/core/scripts/policy-age-report.sh +156 -0
  64. package/assets/scaffold/core/scripts/policy-retire.sh +199 -0
  65. package/assets/scaffold/core/scripts/qmd-reindex-after-sync.sh +10 -87
  66. package/assets/scaffold/core/scripts/qmd-reindex-bg.sh +40 -0
  67. package/assets/scaffold/core/scripts/read-policy-frontmatter.sh +32 -0
  68. package/assets/scaffold/core/scripts/rebuild-company-knowledge-index.sh +36 -3
  69. package/assets/scaffold/core/scripts/rebuild-projects-index.sh +99 -12
  70. package/assets/scaffold/core/scripts/refresh-vault-access.sh +188 -0
  71. package/assets/scaffold/core/scripts/register-project.sh +262 -0
  72. package/assets/scaffold/core/scripts/repo-run-registry.sh +408 -0
  73. package/assets/scaffold/core/scripts/resolve-company.sh +199 -0
  74. package/assets/scaffold/core/scripts/resume-thread-lock.sh +285 -0
  75. package/assets/scaffold/core/scripts/share-suggestion-state.sh +541 -0
  76. package/assets/scaffold/core/scripts/source-yaml-validate.sh +36 -0
  77. package/assets/scaffold/core/scripts/token-usage-report.sh +81 -20
  78. package/assets/scaffold/core/scripts/verify-story-deliverables.sh +148 -0
  79. package/assets/scaffold/core/scripts/work-mesh-live-bind-trusted.sh +152 -0
  80. package/assets/scaffold/core/scripts/work-mesh-live-rebind.sh +59 -0
  81. package/assets/scaffold/core/scripts/worktree-gc.sh +362 -0
  82. package/contracts/preflight/v1/fixtures.json +87 -0
  83. package/contracts/preflight/v1/schema.json +58 -0
  84. package/dist/bin/hq-auth-refresh.d.ts +2 -0
  85. package/dist/bin/hq-auth-refresh.js +12 -6
  86. package/dist/command-catalog.generated.d.ts +10798 -0
  87. package/dist/command-catalog.generated.js +13915 -0
  88. package/dist/command-registration-plan.d.ts +474 -0
  89. package/dist/command-registration-plan.js +136 -0
  90. package/dist/commands/__fixtures__/access-vault.d.ts +2 -0
  91. package/dist/commands/__fixtures__/access-vault.js +1 -1
  92. package/dist/commands/_patterns.d.ts +16 -0
  93. package/dist/commands/_patterns.js +20 -3
  94. package/dist/commands/access.d.ts +2 -1
  95. package/dist/commands/access.js +58 -49
  96. package/dist/commands/agent-enroll.d.ts +146 -0
  97. package/dist/commands/agent-enroll.js +401 -0
  98. package/dist/commands/agent-inbox.d.ts +9 -0
  99. package/dist/commands/agent-inbox.js +102 -0
  100. package/dist/commands/agent-kit.d.ts +87 -0
  101. package/dist/commands/agent-kit.js +480 -0
  102. package/dist/commands/agent-mcp.d.ts +24 -0
  103. package/dist/commands/agent-mcp.js +127 -0
  104. package/dist/commands/agent-probe.d.ts +77 -0
  105. package/dist/commands/agent-probe.js +335 -0
  106. package/dist/commands/agent.d.ts +13 -0
  107. package/dist/commands/agent.js +40 -0
  108. package/dist/commands/agents.d.ts +106 -4
  109. package/dist/commands/agents.js +924 -45
  110. package/dist/commands/auth.d.ts +1 -0
  111. package/dist/commands/auth.js +189 -19
  112. package/dist/commands/billing-sponsor.d.ts +83 -0
  113. package/dist/commands/billing-sponsor.js +344 -0
  114. package/dist/commands/billing.d.ts +3 -0
  115. package/dist/commands/billing.js +6 -1
  116. package/dist/commands/bot-companies.d.ts +40 -0
  117. package/dist/commands/bot-companies.js +64 -0
  118. package/dist/commands/bot-continuity.d.ts +28 -0
  119. package/dist/commands/bot-continuity.js +68 -0
  120. package/dist/commands/bot-jobs.d.ts +131 -0
  121. package/dist/commands/bot-jobs.js +474 -0
  122. package/dist/commands/bot.d.ts +278 -0
  123. package/dist/commands/bot.js +1982 -0
  124. package/dist/commands/channels.js +56 -1
  125. package/dist/commands/cloud-demote.js +3 -2
  126. package/dist/commands/cloud-provision.d.ts +14 -0
  127. package/dist/commands/cloud-provision.js +232 -58
  128. package/dist/commands/cloud-retire.d.ts +51 -0
  129. package/dist/commands/cloud-retire.js +154 -0
  130. package/dist/commands/cloud.d.ts +49 -15
  131. package/dist/commands/cloud.js +357 -122
  132. package/dist/commands/company-rename-flag.d.ts +4 -0
  133. package/dist/commands/company-rename-flag.js +7 -0
  134. package/dist/commands/company-rename.d.ts +4 -0
  135. package/dist/commands/company-rename.js +90 -0
  136. package/dist/commands/company-transfer.d.ts +4 -28
  137. package/dist/commands/company-transfer.js +5 -49
  138. package/dist/commands/company.js +68 -3
  139. package/dist/commands/core-audit-log-native.d.ts +9 -0
  140. package/dist/commands/core-audit-log-native.js +257 -0
  141. package/dist/commands/core-checkpoint-gate-setting.d.ts +59 -0
  142. package/dist/commands/core-checkpoint-gate-setting.js +163 -0
  143. package/dist/commands/core-checkpoint-stop-gate-native.d.ts +34 -0
  144. package/dist/commands/core-checkpoint-stop-gate-native.js +725 -0
  145. package/dist/commands/core-checkpoint.d.ts +19 -9
  146. package/dist/commands/core-checkpoint.js +301 -37
  147. package/dist/commands/core-command-catalog.d.ts +34 -0
  148. package/dist/commands/core-command-catalog.js +62 -0
  149. package/dist/commands/core-company-index-scope-flag.d.ts +3 -0
  150. package/dist/commands/core-company-index-scope-flag.js +6 -0
  151. package/dist/commands/core-delegate-w1b.d.ts +10 -0
  152. package/dist/commands/core-delegate-w1b.js +1219 -0
  153. package/dist/commands/core-delegate.d.ts +46 -0
  154. package/dist/commands/core-delegate.js +1040 -0
  155. package/dist/commands/core-detect-stale-review-base-native.d.ts +23 -0
  156. package/dist/commands/core-detect-stale-review-base-native.js +178 -0
  157. package/dist/commands/core-dm-bind-native.d.ts +32 -0
  158. package/dist/commands/core-dm-bind-native.js +668 -0
  159. package/dist/commands/core-eval-trigger-native.d.ts +4 -0
  160. package/dist/commands/core-eval-trigger-native.js +12 -0
  161. package/dist/commands/core-git-pack-extension-check-native.d.ts +22 -0
  162. package/dist/commands/core-git-pack-extension-check-native.js +190 -0
  163. package/dist/commands/core-handoff-fast.d.ts +18 -0
  164. package/dist/commands/core-handoff-fast.js +104 -0
  165. package/dist/commands/core-handoff-open-steps.d.ts +21 -0
  166. package/dist/commands/core-handoff-open-steps.js +264 -0
  167. package/dist/commands/core-handoff.d.ts +24 -0
  168. package/dist/commands/core-handoff.js +1144 -0
  169. package/dist/commands/core-hook-state-helpers-native.d.ts +11 -0
  170. package/dist/commands/core-hook-state-helpers-native.js +74 -0
  171. package/dist/commands/core-hq-session-native.d.ts +39 -0
  172. package/dist/commands/core-hq-session-native.js +579 -0
  173. package/dist/commands/core-job-native-utils.d.ts +6 -0
  174. package/dist/commands/core-job-native-utils.js +80 -0
  175. package/dist/commands/core-job-native.d.ts +5 -0
  176. package/dist/commands/core-job-native.js +16 -0
  177. package/dist/commands/core-job-notify-native.d.ts +36 -0
  178. package/dist/commands/core-job-notify-native.js +359 -0
  179. package/dist/commands/core-job-probe-native.d.ts +45 -0
  180. package/dist/commands/core-job-probe-native.js +564 -0
  181. package/dist/commands/core-job-remediate-native.d.ts +26 -0
  182. package/dist/commands/core-job-remediate-native.js +374 -0
  183. package/dist/commands/core-job-remote-launcher.d.ts +7 -0
  184. package/dist/commands/core-job-remote-launcher.js +51 -0
  185. package/dist/commands/core-job-run-native.d.ts +47 -0
  186. package/dist/commands/core-job-run-native.js +1215 -0
  187. package/dist/commands/core-jobs-native.d.ts +25 -0
  188. package/dist/commands/core-jobs-native.js +1339 -0
  189. package/dist/commands/core-knowledge-prefs.d.ts +11 -0
  190. package/dist/commands/core-knowledge-prefs.js +137 -0
  191. package/dist/commands/core-migrate-policy-triggers-native.d.ts +21 -0
  192. package/dist/commands/core-migrate-policy-triggers-native.js +374 -0
  193. package/dist/commands/core-native-handoff-flag.d.ts +4 -0
  194. package/dist/commands/core-native-handoff-flag.js +7 -0
  195. package/dist/commands/core-native-hook-helper-commands.d.ts +4 -0
  196. package/dist/commands/core-native-hook-helper-commands.js +56 -0
  197. package/dist/commands/core-native-hook-helpers-flag.d.ts +4 -0
  198. package/dist/commands/core-native-hook-helpers-flag.js +7 -0
  199. package/dist/commands/core-native-jobs-flag.d.ts +4 -0
  200. package/dist/commands/core-native-jobs-flag.js +7 -0
  201. package/dist/commands/core-native-policy-flag.d.ts +9 -0
  202. package/dist/commands/core-native-policy-flag.js +12 -0
  203. package/dist/commands/core-native-session-flag.d.ts +4 -0
  204. package/dist/commands/core-native-session-flag.js +7 -0
  205. package/dist/commands/core-native-utilities-flag.d.ts +4 -0
  206. package/dist/commands/core-native-utilities-flag.js +7 -0
  207. package/dist/commands/core-native-utilities.d.ts +29 -0
  208. package/dist/commands/core-native-utilities.js +54 -0
  209. package/dist/commands/core-native-worker-skills-flag.d.ts +4 -0
  210. package/dist/commands/core-native-worker-skills-flag.js +7 -0
  211. package/dist/commands/core-ontology-native.d.ts +17 -0
  212. package/dist/commands/core-ontology-native.js +916 -0
  213. package/dist/commands/core-ontology.d.ts +66 -0
  214. package/dist/commands/core-ontology.js +430 -0
  215. package/dist/commands/core-pin-native.d.ts +14 -0
  216. package/dist/commands/core-pin-native.js +236 -0
  217. package/dist/commands/core-policy-frontmatter.d.ts +8 -0
  218. package/dist/commands/core-policy-frontmatter.js +52 -0
  219. package/dist/commands/core-policy.d.ts +14 -0
  220. package/dist/commands/core-policy.js +1018 -0
  221. package/dist/commands/core-refresh-vault-access-native.d.ts +20 -0
  222. package/dist/commands/core-refresh-vault-access-native.js +229 -0
  223. package/dist/commands/core-register-project-native.d.ts +30 -0
  224. package/dist/commands/core-register-project-native.js +347 -0
  225. package/dist/commands/core-repo-run-registry-native.d.ts +19 -0
  226. package/dist/commands/core-repo-run-registry-native.js +357 -0
  227. package/dist/commands/core-resolve-company-command.d.ts +4 -0
  228. package/dist/commands/core-resolve-company-command.js +42 -0
  229. package/dist/commands/core-resolve-company-native.d.ts +28 -0
  230. package/dist/commands/core-resolve-company-native.js +408 -0
  231. package/dist/commands/core-share-suggestion-state-native.d.ts +18 -0
  232. package/dist/commands/core-share-suggestion-state-native.js +445 -0
  233. package/dist/commands/core-work-mesh-bind-trusted-native.d.ts +32 -0
  234. package/dist/commands/core-work-mesh-bind-trusted-native.js +190 -0
  235. package/dist/commands/core-work-mesh-live-rebind-native.d.ts +18 -0
  236. package/dist/commands/core-work-mesh-live-rebind-native.js +262 -0
  237. package/dist/commands/core-worker-lint-native.d.ts +4 -0
  238. package/dist/commands/core-worker-lint-native.js +160 -0
  239. package/dist/commands/core-worker-share-native.d.ts +4 -0
  240. package/dist/commands/core-worker-share-native.js +260 -0
  241. package/dist/commands/core-worker-skills-command.d.ts +8 -0
  242. package/dist/commands/core-worker-skills-command.js +33 -0
  243. package/dist/commands/core-worker-skills-runtime.d.ts +33 -0
  244. package/dist/commands/core-worker-skills-runtime.js +86 -0
  245. package/dist/commands/core.d.ts +4 -0
  246. package/dist/commands/core.js +282 -80
  247. package/dist/commands/crm.js +52 -3
  248. package/dist/commands/daemon.d.ts +63 -0
  249. package/dist/commands/daemon.js +877 -0
  250. package/dist/commands/db-provision.js +4 -4
  251. package/dist/commands/db-sql.js +7 -21
  252. package/dist/commands/deploy-comments.d.ts +3 -0
  253. package/dist/commands/deploy-comments.js +162 -0
  254. package/dist/commands/dm.d.ts +119 -12
  255. package/dist/commands/dm.js +388 -38
  256. package/dist/commands/doctor.d.ts +12 -0
  257. package/dist/commands/doctor.js +158 -12
  258. package/dist/commands/feedback.d.ts +6 -0
  259. package/dist/commands/feedback.js +86 -37
  260. package/dist/commands/files-browse.d.ts +32 -12
  261. package/dist/commands/files-browse.js +176 -60
  262. package/dist/commands/files.d.ts +17 -0
  263. package/dist/commands/files.js +300 -47
  264. package/dist/commands/group-grants.js +3 -2
  265. package/dist/commands/groups.js +6 -5
  266. package/dist/commands/index-cmd.d.ts +19 -1
  267. package/dist/commands/index-cmd.js +74 -7
  268. package/dist/commands/integrations-api.d.ts +15 -10
  269. package/dist/commands/integrations-api.js +27 -22
  270. package/dist/commands/integrations-connect.d.ts +51 -13
  271. package/dist/commands/integrations-connect.js +86 -71
  272. package/dist/commands/integrations-core.d.ts +6 -6
  273. package/dist/commands/integrations-core.js +25 -11
  274. package/dist/commands/integrations-import.d.ts +1 -1
  275. package/dist/commands/integrations-import.js +43 -24
  276. package/dist/commands/integrations-manage.js +20 -13
  277. package/dist/commands/integrations.d.ts +8 -0
  278. package/dist/commands/integrations.js +94 -7
  279. package/dist/commands/lanes-accounts.d.ts +28 -0
  280. package/dist/commands/lanes-accounts.js +595 -0
  281. package/dist/commands/lanes-autopilot.d.ts +11 -0
  282. package/dist/commands/lanes-autopilot.js +336 -0
  283. package/dist/commands/lanes-checks.d.ts +51 -0
  284. package/dist/commands/lanes-checks.js +941 -0
  285. package/dist/commands/lanes-hold.d.ts +43 -0
  286. package/dist/commands/lanes-hold.js +655 -0
  287. package/dist/commands/lanes-keep-alive-audit.d.ts +10 -0
  288. package/dist/commands/lanes-keep-alive-audit.js +19 -0
  289. package/dist/commands/lanes-kpis.d.ts +11 -0
  290. package/dist/commands/lanes-kpis.js +34 -0
  291. package/dist/commands/lanes-message.d.ts +9 -0
  292. package/dist/commands/lanes-message.js +946 -0
  293. package/dist/commands/lanes-move.d.ts +12 -0
  294. package/dist/commands/lanes-move.js +397 -0
  295. package/dist/commands/lanes-questions.d.ts +36 -0
  296. package/dist/commands/lanes-questions.js +1005 -0
  297. package/dist/commands/lanes-report.d.ts +11 -0
  298. package/dist/commands/lanes-report.js +333 -0
  299. package/dist/commands/lanes-resume.d.ts +6 -0
  300. package/dist/commands/lanes-resume.js +564 -0
  301. package/dist/commands/lanes-review.d.ts +10 -0
  302. package/dist/commands/lanes-review.js +56 -0
  303. package/dist/commands/lanes-shared.d.ts +449 -0
  304. package/dist/commands/lanes-shared.js +170 -0
  305. package/dist/commands/lanes-stories.d.ts +15 -0
  306. package/dist/commands/lanes-stories.js +347 -0
  307. package/dist/commands/lanes-watch.d.ts +7 -0
  308. package/dist/commands/lanes-watch.js +216 -0
  309. package/dist/commands/lanes.d.ts +149 -0
  310. package/dist/commands/lanes.js +9013 -0
  311. package/dist/commands/login.js +49 -6
  312. package/dist/commands/mcp-registration.d.ts +32 -25
  313. package/dist/commands/mcp-registration.js +256 -23
  314. package/dist/commands/mcp-status.js +1 -0
  315. package/dist/commands/meetings.js +55 -34
  316. package/dist/commands/members.js +5 -1
  317. package/dist/commands/mesh.d.ts +11 -0
  318. package/dist/commands/mesh.js +1086 -76
  319. package/dist/commands/monitor.d.ts +58 -0
  320. package/dist/commands/monitor.js +980 -0
  321. package/dist/commands/onboard-bot-membership.d.ts +32 -0
  322. package/dist/commands/onboard-bot-membership.js +40 -0
  323. package/dist/commands/onboard-create-identity.d.ts +26 -0
  324. package/dist/commands/onboard-create-identity.js +23 -0
  325. package/dist/commands/onboard-identity-guard.d.ts +1 -1
  326. package/dist/commands/onboard.js +24 -5
  327. package/dist/commands/outpost-pruner.d.ts +3 -0
  328. package/dist/commands/outpost-pruner.js +125 -0
  329. package/dist/commands/pack-install.js +3 -1
  330. package/dist/commands/packs.js +11 -1
  331. package/dist/commands/people.d.ts +4 -0
  332. package/dist/commands/people.js +37 -3
  333. package/dist/commands/personal-connector-settings-flag.d.ts +4 -0
  334. package/dist/commands/personal-connector-settings-flag.js +7 -0
  335. package/dist/commands/personal-targeted-push-flag.d.ts +4 -0
  336. package/dist/commands/personal-targeted-push-flag.js +7 -0
  337. package/dist/commands/personal-targeted-push-paths.d.ts +3 -0
  338. package/dist/commands/personal-targeted-push-paths.js +67 -0
  339. package/dist/commands/publish.d.ts +8 -1
  340. package/dist/commands/publish.js +17 -4
  341. package/dist/commands/reindex.js +56 -6
  342. package/dist/commands/report.d.ts +19 -0
  343. package/dist/commands/report.js +537 -0
  344. package/dist/commands/rescue.d.ts +4 -0
  345. package/dist/commands/rescue.js +27 -17
  346. package/dist/commands/run-feature-telemetry.d.ts +3 -0
  347. package/dist/commands/run-feature-telemetry.js +6 -0
  348. package/dist/commands/run.js +18 -4
  349. package/dist/commands/safe-extract.d.ts +11 -2
  350. package/dist/commands/safe-extract.js +36 -8
  351. package/dist/commands/secrets.d.ts +20 -2
  352. package/dist/commands/secrets.js +175 -71
  353. package/dist/commands/skill.d.ts +35 -4
  354. package/dist/commands/skill.js +357 -18
  355. package/dist/commands/staff/reset-test-account.d.ts +110 -0
  356. package/dist/commands/staff/reset-test-account.js +268 -0
  357. package/dist/commands/staff/test-account.d.ts +51 -0
  358. package/dist/commands/staff/test-account.js +196 -0
  359. package/dist/commands/sync-mode.d.ts +11 -0
  360. package/dist/commands/sync-mode.js +30 -0
  361. package/dist/commands/sync-narrow.js +36 -5
  362. package/dist/commands/team-sync.js +71 -10
  363. package/dist/commands/update.js +6 -0
  364. package/dist/commands/vault-retention-flag.d.ts +3 -0
  365. package/dist/commands/vault-retention-flag.js +9 -0
  366. package/dist/commands/vault-retention.d.ts +11 -0
  367. package/dist/commands/vault-retention.js +69 -0
  368. package/dist/commands/version.d.ts +10 -0
  369. package/dist/commands/version.js +11 -0
  370. package/dist/commands/whoami.d.ts +22 -0
  371. package/dist/commands/whoami.js +137 -4
  372. package/dist/commands/workers.d.ts +2 -14
  373. package/dist/commands/workers.js +7 -10
  374. package/dist/fast-core.d.ts +7 -7
  375. package/dist/fast-core.js +91 -24
  376. package/dist/fast-scaffold.d.ts +86 -0
  377. package/dist/fast-scaffold.js +381 -0
  378. package/dist/index.d.ts +3 -4
  379. package/dist/index.js +59 -9
  380. package/dist/lanes-drain-hook.d.ts +14 -0
  381. package/dist/lanes-drain-hook.js +203 -0
  382. package/dist/lazy-commands.d.ts +20 -44
  383. package/dist/lazy-commands.js +60 -58
  384. package/dist/lib/agent-kit/adopt-identity.d.ts +27 -0
  385. package/dist/lib/agent-kit/adopt-identity.js +60 -0
  386. package/dist/lib/agent-kit/attachment-download.d.ts +24 -0
  387. package/dist/lib/agent-kit/attachment-download.js +47 -0
  388. package/dist/lib/agent-kit/creds.d.ts +106 -0
  389. package/dist/lib/agent-kit/creds.js +163 -0
  390. package/dist/lib/agent-kit/fallback.d.ts +78 -0
  391. package/dist/lib/agent-kit/fallback.js +210 -0
  392. package/dist/lib/agent-kit/inbox-state.d.ts +83 -0
  393. package/dist/lib/agent-kit/inbox-state.js +159 -0
  394. package/dist/lib/agent-kit/kit-config.d.ts +56 -0
  395. package/dist/lib/agent-kit/kit-config.js +65 -0
  396. package/dist/lib/agent-kit/log.d.ts +16 -0
  397. package/dist/lib/agent-kit/log.js +46 -0
  398. package/dist/lib/agent-kit/mcp/attachments.d.ts +126 -0
  399. package/dist/lib/agent-kit/mcp/attachments.js +222 -0
  400. package/dist/lib/agent-kit/mcp/jsonrpc.d.ts +75 -0
  401. package/dist/lib/agent-kit/mcp/jsonrpc.js +164 -0
  402. package/dist/lib/agent-kit/mcp/tools.d.ts +64 -0
  403. package/dist/lib/agent-kit/mcp/tools.js +397 -0
  404. package/dist/lib/agent-kit/paths.d.ts +65 -0
  405. package/dist/lib/agent-kit/paths.js +118 -0
  406. package/dist/lib/agent-kit/private-file.d.ts +29 -0
  407. package/dist/lib/agent-kit/private-file.js +91 -0
  408. package/dist/lib/agent-kit/run/heartbeat.d.ts +72 -0
  409. package/dist/lib/agent-kit/run/heartbeat.js +128 -0
  410. package/dist/lib/agent-kit/run/inbox.d.ts +76 -0
  411. package/dist/lib/agent-kit/run/inbox.js +205 -0
  412. package/dist/lib/agent-kit/run/supervisor.d.ts +35 -0
  413. package/dist/lib/agent-kit/run/supervisor.js +85 -0
  414. package/dist/lib/agent-kit/run/sync.d.ts +33 -0
  415. package/dist/lib/agent-kit/run/sync.js +58 -0
  416. package/dist/lib/agent-kit/services.d.ts +31 -0
  417. package/dist/lib/agent-kit/services.js +55 -0
  418. package/dist/lib/agent-kit/skills.d.ts +18 -0
  419. package/dist/lib/agent-kit/skills.js +151 -0
  420. package/dist/lib/agent-kit/wake.d.ts +83 -0
  421. package/dist/lib/agent-kit/wake.js +243 -0
  422. package/dist/lib/agents/model-catalog.d.ts +62 -0
  423. package/dist/lib/agents/model-catalog.js +275 -0
  424. package/dist/lib/auth-login-provider-state.d.ts +8 -0
  425. package/dist/lib/auth-login-provider-state.js +63 -0
  426. package/dist/lib/aws-sdk-node-warning-output.d.ts +12 -0
  427. package/dist/lib/aws-sdk-node-warning-output.js +22 -0
  428. package/dist/lib/billing/free-month.d.ts +18 -0
  429. package/dist/lib/billing/free-month.js +31 -0
  430. package/dist/lib/billing/plan-limit-refusals.d.ts +69 -0
  431. package/dist/lib/billing/plan-limit-refusals.js +187 -0
  432. package/dist/lib/billing/plan-limit-upgrade-url.d.ts +11 -0
  433. package/dist/lib/billing/plan-limit-upgrade-url.js +66 -0
  434. package/dist/lib/billing/plan-lock.d.ts +143 -0
  435. package/dist/lib/billing/plan-lock.js +439 -0
  436. package/dist/lib/bot/api.d.ts +349 -0
  437. package/dist/lib/bot/api.js +316 -0
  438. package/dist/lib/bot/attachments.d.ts +45 -0
  439. package/dist/lib/bot/attachments.js +89 -0
  440. package/dist/lib/bot/cli-update.d.ts +138 -0
  441. package/dist/lib/bot/cli-update.js +278 -0
  442. package/dist/lib/bot/company-bind.d.ts +27 -0
  443. package/dist/lib/bot/company-bind.js +62 -0
  444. package/dist/lib/bot/config.d.ts +153 -0
  445. package/dist/lib/bot/config.js +233 -0
  446. package/dist/lib/bot/continuity-download.d.ts +28 -0
  447. package/dist/lib/bot/continuity-download.js +75 -0
  448. package/dist/lib/bot/continuity-install.d.ts +14 -0
  449. package/dist/lib/bot/continuity-install.js +101 -0
  450. package/dist/lib/bot/continuity.d.ts +67 -0
  451. package/dist/lib/bot/continuity.js +301 -0
  452. package/dist/lib/bot/creds.d.ts +24 -0
  453. package/dist/lib/bot/creds.js +51 -0
  454. package/dist/lib/bot/daemon.d.ts +173 -0
  455. package/dist/lib/bot/daemon.js +552 -0
  456. package/dist/lib/bot/inbox-poll-backoff-flag.d.ts +24 -0
  457. package/dist/lib/bot/inbox-poll-backoff-flag.js +135 -0
  458. package/dist/lib/bot/inbox-state.d.ts +18 -0
  459. package/dist/lib/bot/inbox-state.js +51 -0
  460. package/dist/lib/bot/index.d.ts +23 -0
  461. package/dist/lib/bot/index.js +23 -0
  462. package/dist/lib/bot/inflight.d.ts +119 -0
  463. package/dist/lib/bot/inflight.js +83 -0
  464. package/dist/lib/bot/job-completions.d.ts +89 -0
  465. package/dist/lib/bot/job-completions.js +132 -0
  466. package/dist/lib/bot/job-quiet-flag.d.ts +4 -0
  467. package/dist/lib/bot/job-quiet-flag.js +14 -0
  468. package/dist/lib/bot/job-run.d.ts +114 -0
  469. package/dist/lib/bot/job-run.js +266 -0
  470. package/dist/lib/bot/local-config.d.ts +61 -0
  471. package/dist/lib/bot/local-config.js +145 -0
  472. package/dist/lib/bot/local-jobs.d.ts +89 -0
  473. package/dist/lib/bot/local-jobs.js +459 -0
  474. package/dist/lib/bot/local-name.d.ts +54 -0
  475. package/dist/lib/bot/local-name.js +114 -0
  476. package/dist/lib/bot/log.d.ts +13 -0
  477. package/dist/lib/bot/log.js +59 -0
  478. package/dist/lib/bot/owner-context.d.ts +79 -0
  479. package/dist/lib/bot/owner-context.js +175 -0
  480. package/dist/lib/bot/paths.d.ts +76 -0
  481. package/dist/lib/bot/paths.js +131 -0
  482. package/dist/lib/bot/progress.d.ts +132 -0
  483. package/dist/lib/bot/progress.js +289 -0
  484. package/dist/lib/bot/promote.d.ts +16 -0
  485. package/dist/lib/bot/promote.js +106 -0
  486. package/dist/lib/bot/promotion-hold.d.ts +24 -0
  487. package/dist/lib/bot/promotion-hold.js +103 -0
  488. package/dist/lib/bot/promotion-receipt.d.ts +9 -0
  489. package/dist/lib/bot/promotion-receipt.js +56 -0
  490. package/dist/lib/bot/promotion-upload.d.ts +16 -0
  491. package/dist/lib/bot/promotion-upload.js +80 -0
  492. package/dist/lib/bot/prompt.d.ts +136 -0
  493. package/dist/lib/bot/prompt.js +433 -0
  494. package/dist/lib/bot/room-policy.d.ts +63 -0
  495. package/dist/lib/bot/room-policy.js +91 -0
  496. package/dist/lib/bot/run.d.ts +219 -0
  497. package/dist/lib/bot/run.js +1881 -0
  498. package/dist/lib/bot/runnable.d.ts +51 -0
  499. package/dist/lib/bot/runnable.js +65 -0
  500. package/dist/lib/bot/runtime/claude.d.ts +50 -0
  501. package/dist/lib/bot/runtime/claude.js +170 -0
  502. package/dist/lib/bot/runtime/codex.d.ts +28 -0
  503. package/dist/lib/bot/runtime/codex.js +153 -0
  504. package/dist/lib/bot/runtime/grok-acp.d.ts +40 -0
  505. package/dist/lib/bot/runtime/grok-acp.js +265 -0
  506. package/dist/lib/bot/runtime/grok.d.ts +41 -0
  507. package/dist/lib/bot/runtime/grok.js +169 -0
  508. package/dist/lib/bot/runtime/index.d.ts +36 -0
  509. package/dist/lib/bot/runtime/index.js +417 -0
  510. package/dist/lib/bot/runtime/messages-stream.d.ts +56 -0
  511. package/dist/lib/bot/runtime/messages-stream.js +194 -0
  512. package/dist/lib/bot/runtime/sanitize.d.ts +18 -0
  513. package/dist/lib/bot/runtime/sanitize.js +28 -0
  514. package/dist/lib/bot/runtime/types.d.ts +159 -0
  515. package/dist/lib/bot/runtime/types.js +51 -0
  516. package/dist/lib/bot/runtime/windows.d.ts +10 -0
  517. package/dist/lib/bot/runtime/windows.js +53 -0
  518. package/dist/lib/bot/runtime-sign-in.d.ts +24 -0
  519. package/dist/lib/bot/runtime-sign-in.js +31 -0
  520. package/dist/lib/bot/scaffold.d.ts +38 -0
  521. package/dist/lib/bot/scaffold.js +94 -0
  522. package/dist/lib/bot/self-heal.d.ts +52 -0
  523. package/dist/lib/bot/self-heal.js +79 -0
  524. package/dist/lib/bot/self-process.d.ts +19 -0
  525. package/dist/lib/bot/self-process.js +35 -0
  526. package/dist/lib/bot/session.d.ts +19 -0
  527. package/dist/lib/bot/session.js +39 -0
  528. package/dist/lib/bot/setup-explain.d.ts +64 -0
  529. package/dist/lib/bot/setup-explain.js +141 -0
  530. package/dist/lib/bot/split.d.ts +32 -0
  531. package/dist/lib/bot/split.js +241 -0
  532. package/dist/lib/bot/status.d.ts +57 -0
  533. package/dist/lib/bot/status.js +66 -0
  534. package/dist/lib/bot/worker-source.d.ts +66 -0
  535. package/dist/lib/bot/worker-source.js +283 -0
  536. package/dist/lib/checkpoint-ontology/aliases.d.ts +17 -0
  537. package/dist/lib/checkpoint-ontology/aliases.js +44 -0
  538. package/dist/lib/checkpoint-ontology/apply.d.ts +110 -0
  539. package/dist/lib/checkpoint-ontology/apply.js +777 -0
  540. package/dist/lib/checkpoint-ontology/company-brief.d.ts +18 -0
  541. package/dist/lib/checkpoint-ontology/company-brief.js +337 -0
  542. package/dist/lib/checkpoint-ontology/company.d.ts +44 -0
  543. package/dist/lib/checkpoint-ontology/company.js +118 -0
  544. package/dist/lib/checkpoint-ontology/drop-aliases.d.ts +41 -0
  545. package/dist/lib/checkpoint-ontology/drop-aliases.js +76 -0
  546. package/dist/lib/checkpoint-ontology/entity-file.d.ts +109 -0
  547. package/dist/lib/checkpoint-ontology/entity-file.js +371 -0
  548. package/dist/lib/checkpoint-ontology/identity.d.ts +38 -0
  549. package/dist/lib/checkpoint-ontology/identity.js +95 -0
  550. package/dist/lib/checkpoint-ontology/merge-copies.d.ts +199 -0
  551. package/dist/lib/checkpoint-ontology/merge-copies.js +1086 -0
  552. package/dist/lib/checkpoint-ontology/multi-writer.d.ts +101 -0
  553. package/dist/lib/checkpoint-ontology/multi-writer.js +394 -0
  554. package/dist/lib/checkpoint-ontology/plan.d.ts +193 -0
  555. package/dist/lib/checkpoint-ontology/plan.js +504 -0
  556. package/dist/lib/checkpoint-ontology/queued-touches.d.ts +29 -0
  557. package/dist/lib/checkpoint-ontology/queued-touches.js +193 -0
  558. package/dist/lib/checkpoint-ontology/sync-client.d.ts +38 -0
  559. package/dist/lib/checkpoint-ontology/sync-client.js +84 -0
  560. package/dist/lib/checkpoint-ontology/tree.d.ts +55 -0
  561. package/dist/lib/checkpoint-ontology/tree.js +198 -0
  562. package/dist/lib/company-errors-sdk-warning-flag.d.ts +5 -0
  563. package/dist/lib/company-errors-sdk-warning-flag.js +8 -0
  564. package/dist/lib/company-skill-wrapper.d.ts +1 -0
  565. package/dist/lib/company-skill-wrapper.js +121 -29
  566. package/dist/lib/core-utils/codex-skill-bridge.d.ts +2 -1
  567. package/dist/lib/core-utils/common.d.ts +0 -1
  568. package/dist/lib/core-utils/common.js +0 -9
  569. package/dist/lib/core-utils/hook-timeout-debug-context-flag.d.ts +20 -0
  570. package/dist/lib/core-utils/hook-timeout-debug-context-flag.js +81 -0
  571. package/dist/lib/core-utils/jq-json-serializer.d.ts +5 -0
  572. package/dist/lib/core-utils/jq-json-serializer.js +10 -0
  573. package/dist/lib/core-utils/qmd-reindex-after-sync.d.ts +14 -1
  574. package/dist/lib/core-utils/qmd-reindex-after-sync.js +101 -17
  575. package/dist/lib/core-utils/secret-patterns.d.ts +43 -0
  576. package/dist/lib/core-utils/secret-patterns.js +34 -0
  577. package/dist/lib/core-utils/sentry-report.d.ts +114 -0
  578. package/dist/lib/core-utils/sentry-report.js +1055 -0
  579. package/dist/lib/core-utils/soft-timeout.js +1 -1
  580. package/dist/lib/core-utils/timeout-guard-native.d.ts +7 -0
  581. package/dist/lib/core-utils/timeout-guard-native.js +40 -0
  582. package/dist/lib/core-utils/timeout-guard.d.ts +3 -3
  583. package/dist/lib/core-utils/timeout-guard.js +28 -13
  584. package/dist/lib/core-utils/token-usage-report.js +17 -3
  585. package/dist/lib/core-utils/worktree-resume.d.ts +20 -0
  586. package/dist/lib/core-utils/worktree-resume.js +1198 -0
  587. package/dist/lib/daemon/catalog.d.ts +134 -0
  588. package/dist/lib/daemon/catalog.js +358 -0
  589. package/dist/lib/daemon/config.d.ts +35 -0
  590. package/dist/lib/daemon/config.js +108 -0
  591. package/dist/lib/daemon/flag.d.ts +25 -0
  592. package/dist/lib/daemon/flag.js +59 -0
  593. package/dist/lib/daemon/handoff.d.ts +56 -0
  594. package/dist/lib/daemon/handoff.js +161 -0
  595. package/dist/lib/daemon/hq-cloud.d.ts +79 -0
  596. package/dist/lib/daemon/hq-cloud.js +183 -0
  597. package/dist/lib/daemon/install.d.ts +85 -0
  598. package/dist/lib/daemon/install.js +320 -0
  599. package/dist/lib/daemon/legacy-sync-env.d.ts +10 -0
  600. package/dist/lib/daemon/legacy-sync-env.js +58 -0
  601. package/dist/lib/daemon/legacy.d.ts +45 -0
  602. package/dist/lib/daemon/legacy.js +133 -0
  603. package/dist/lib/daemon/lock.d.ts +47 -0
  604. package/dist/lib/daemon/lock.js +138 -0
  605. package/dist/lib/daemon/machine-type.d.ts +50 -0
  606. package/dist/lib/daemon/machine-type.js +159 -0
  607. package/dist/lib/daemon/migrate.d.ts +77 -0
  608. package/dist/lib/daemon/migrate.js +265 -0
  609. package/dist/lib/daemon/paths.d.ts +24 -0
  610. package/dist/lib/daemon/paths.js +43 -0
  611. package/dist/lib/daemon/protocol-tail.d.ts +33 -0
  612. package/dist/lib/daemon/protocol-tail.js +131 -0
  613. package/dist/lib/daemon/remote-control.d.ts +74 -0
  614. package/dist/lib/daemon/remote-control.js +153 -0
  615. package/dist/lib/daemon/requests.d.ts +28 -0
  616. package/dist/lib/daemon/requests.js +65 -0
  617. package/dist/lib/daemon/run.d.ts +79 -0
  618. package/dist/lib/daemon/run.js +755 -0
  619. package/dist/lib/daemon/succession.d.ts +118 -0
  620. package/dist/lib/daemon/succession.js +263 -0
  621. package/dist/lib/daemon/supervisor.d.ts +132 -0
  622. package/dist/lib/daemon/supervisor.js +836 -0
  623. package/dist/lib/daemon/sync-runner.d.ts +58 -0
  624. package/dist/lib/daemon/sync-runner.js +277 -0
  625. package/dist/lib/daemon/tools.d.ts +52 -0
  626. package/dist/lib/daemon/tools.js +95 -0
  627. package/dist/lib/daemon/updater.d.ts +57 -0
  628. package/dist/lib/daemon/updater.js +163 -0
  629. package/dist/lib/db/control-plane.js +6 -0
  630. package/dist/lib/db/local.d.ts +0 -5
  631. package/dist/lib/db/local.js +1 -1
  632. package/dist/lib/db/migrate.d.ts +0 -12
  633. package/dist/lib/db/migrate.js +5 -5
  634. package/dist/lib/db/remote-sql.d.ts +2 -2
  635. package/dist/lib/db/remote-sql.js +3 -3
  636. package/dist/lib/db/sql.d.ts +0 -10
  637. package/dist/lib/db/sql.js +4 -8
  638. package/dist/lib/deploy-api.d.ts +5 -0
  639. package/dist/lib/deploy-api.js +21 -0
  640. package/dist/lib/deploy-apps.d.ts +13 -0
  641. package/dist/lib/deploy-apps.js +29 -0
  642. package/dist/lib/doctor/__testing__/fake-hq-tree.d.ts +1 -1
  643. package/dist/lib/doctor/__testing__/fake-hq-tree.js +1 -1
  644. package/dist/lib/doctor/__testing__/run-doctor.d.ts +8 -0
  645. package/dist/lib/doctor/__testing__/run-doctor.js +52 -0
  646. package/dist/lib/doctor/checks/bots.d.ts +13 -0
  647. package/dist/lib/doctor/checks/bots.js +189 -0
  648. package/dist/lib/doctor/checks/claude-wiring.js +70 -1
  649. package/dist/lib/doctor/checks/codex-wiring.d.ts +0 -4
  650. package/dist/lib/doctor/checks/codex-wiring.js +3 -35
  651. package/dist/lib/doctor/checks/grok-wiring.js +1 -34
  652. package/dist/lib/doctor/checks/integrations.js +11 -0
  653. package/dist/lib/doctor/checks/runtime-health.d.ts +4 -17
  654. package/dist/lib/doctor/checks/runtime-health.js +20 -7
  655. package/dist/lib/doctor/checks/scaffold-cli-floor.d.ts +6 -0
  656. package/dist/lib/doctor/checks/scaffold-cli-floor.js +73 -0
  657. package/dist/lib/doctor/checks/sync-health.d.ts +21 -0
  658. package/dist/lib/doctor/checks/sync-health.js +72 -2
  659. package/dist/lib/doctor/checks/sync-runtime.d.ts +11 -0
  660. package/dist/lib/doctor/checks/sync-runtime.js +216 -0
  661. package/dist/lib/doctor/checks/work-context.js +20 -6
  662. package/dist/lib/doctor/client-health-flag-token.d.ts +15 -0
  663. package/dist/lib/doctor/client-health-flag-token.js +66 -0
  664. package/dist/lib/doctor/client-health-reason-codes-flag.d.ts +27 -0
  665. package/dist/lib/doctor/client-health-reason-codes-flag.js +106 -0
  666. package/dist/lib/doctor/compat.d.ts +0 -16
  667. package/dist/lib/doctor/compat.js +4 -3
  668. package/dist/lib/doctor/deep/effects.js +1 -3
  669. package/dist/lib/doctor/deep/executor.d.ts +4 -10
  670. package/dist/lib/doctor/deep/executor.js +1 -1
  671. package/dist/lib/doctor/deep/parity.d.ts +2 -29
  672. package/dist/lib/doctor/deep/parity.js +7 -7
  673. package/dist/lib/doctor/deep/sandbox.d.ts +7 -25
  674. package/dist/lib/doctor/deep/sandbox.js +5 -7
  675. package/dist/lib/doctor/fix/apply.d.ts +79 -8
  676. package/dist/lib/doctor/fix/apply.js +292 -80
  677. package/dist/lib/doctor/fix/json-output.d.ts +28 -0
  678. package/dist/lib/doctor/fix/json-output.js +33 -0
  679. package/dist/lib/doctor/fix/refresh-sync-outcome.d.ts +12 -0
  680. package/dist/lib/doctor/fix/refresh-sync-outcome.js +25 -0
  681. package/dist/lib/doctor/fix/remediation.d.ts +14 -6
  682. package/dist/lib/doctor/fix/remediation.js +49 -9
  683. package/dist/lib/doctor/fixtures/schema.js +1 -3
  684. package/dist/lib/doctor/json-output.d.ts +17 -1
  685. package/dist/lib/doctor/json-output.js +7 -2
  686. package/dist/lib/doctor/platform.d.ts +0 -26
  687. package/dist/lib/doctor/platform.js +5 -5
  688. package/dist/lib/doctor/registry.d.ts +14 -0
  689. package/dist/lib/doctor/registry.js +71 -0
  690. package/dist/lib/doctor/report.js +1 -1
  691. package/dist/lib/doctor/shared.d.ts +8 -0
  692. package/dist/lib/doctor/shared.js +38 -0
  693. package/dist/lib/doctor/stray-gate-entries.d.ts +35 -0
  694. package/dist/lib/doctor/stray-gate-entries.js +83 -0
  695. package/dist/lib/doctor/types.d.ts +5 -0
  696. package/dist/lib/doctor/types.js +20 -0
  697. package/dist/lib/first-sync-next-step.d.ts +34 -0
  698. package/dist/lib/first-sync-next-step.js +179 -0
  699. package/dist/lib/flag-registry-endpoint.d.ts +5 -0
  700. package/dist/lib/flag-registry-endpoint.js +9 -0
  701. package/dist/lib/flag-registry-worker-source.generated.d.ts +2 -0
  702. package/dist/lib/flag-registry-worker-source.generated.js +3 -0
  703. package/dist/lib/flag-registry-worker.js +12 -1
  704. package/dist/lib/flag-registry.d.ts +26 -6
  705. package/dist/lib/flag-registry.js +133 -16
  706. package/dist/lib/flag-snapshot-file.d.ts +20 -0
  707. package/dist/lib/flag-snapshot-file.js +91 -0
  708. package/dist/lib/heartbeat-identity.d.ts +30 -0
  709. package/dist/lib/heartbeat-identity.js +76 -0
  710. package/dist/lib/index-render/companies.d.ts +4 -1
  711. package/dist/lib/index-render/companies.js +66 -3
  712. package/dist/lib/index-render/company-knowledge.js +80 -17
  713. package/dist/lib/index-render/index.d.ts +1 -0
  714. package/dist/lib/index-render/index.js +2 -1
  715. package/dist/lib/index-render/projects.js +82 -5
  716. package/dist/lib/index-render/shared.d.ts +13 -1
  717. package/dist/lib/index-render/shared.js +41 -2
  718. package/dist/lib/lanes/account-home.d.ts +8 -0
  719. package/dist/lib/lanes/account-home.js +10 -0
  720. package/dist/lib/lanes/accounts.d.ts +117 -0
  721. package/dist/lib/lanes/accounts.js +366 -0
  722. package/dist/lib/lanes/admission-host.d.ts +22 -0
  723. package/dist/lib/lanes/admission-host.js +37 -0
  724. package/dist/lib/lanes/admission.d.ts +26 -0
  725. package/dist/lib/lanes/admission.js +210 -0
  726. package/dist/lib/lanes/approval-gate.d.ts +8 -0
  727. package/dist/lib/lanes/approval-gate.js +90 -0
  728. package/dist/lib/lanes/autopilot-metrics.d.ts +99 -0
  729. package/dist/lib/lanes/autopilot-metrics.js +301 -0
  730. package/dist/lib/lanes/autopilot-registry.d.ts +62 -0
  731. package/dist/lib/lanes/autopilot-registry.js +192 -0
  732. package/dist/lib/lanes/autopilot.d.ts +137 -0
  733. package/dist/lib/lanes/autopilot.js +1291 -0
  734. package/dist/lib/lanes/blocker-freshness.d.ts +31 -0
  735. package/dist/lib/lanes/blocker-freshness.js +168 -0
  736. package/dist/lib/lanes/checked-company-path.d.ts +3 -0
  737. package/dist/lib/lanes/checked-company-path.js +39 -0
  738. package/dist/lib/lanes/claude-balance.d.ts +97 -0
  739. package/dist/lib/lanes/claude-balance.js +319 -0
  740. package/dist/lib/lanes/compaction.d.ts +110 -0
  741. package/dist/lib/lanes/compaction.js +293 -0
  742. package/dist/lib/lanes/config.d.ts +94 -0
  743. package/dist/lib/lanes/config.js +606 -0
  744. package/dist/lib/lanes/constants.d.ts +3 -0
  745. package/dist/lib/lanes/constants.js +3 -0
  746. package/dist/lib/lanes/delivery-core.d.ts +15 -0
  747. package/dist/lib/lanes/delivery-core.js +21 -0
  748. package/dist/lib/lanes/delivery.d.ts +180 -0
  749. package/dist/lib/lanes/delivery.js +443 -0
  750. package/dist/lib/lanes/disk-guard.d.ts +65 -0
  751. package/dist/lib/lanes/disk-guard.js +172 -0
  752. package/dist/lib/lanes/dropbox.d.ts +129 -0
  753. package/dist/lib/lanes/dropbox.js +601 -0
  754. package/dist/lib/lanes/effort.d.ts +51 -0
  755. package/dist/lib/lanes/effort.js +113 -0
  756. package/dist/lib/lanes/envelope-repair-dispatch.d.ts +26 -0
  757. package/dist/lib/lanes/envelope-repair-dispatch.js +74 -0
  758. package/dist/lib/lanes/errors.d.ts +39 -0
  759. package/dist/lib/lanes/errors.js +72 -0
  760. package/dist/lib/lanes/flag-keys.d.ts +25 -0
  761. package/dist/lib/lanes/flag-keys.js +25 -0
  762. package/dist/lib/lanes/grants.d.ts +30 -0
  763. package/dist/lib/lanes/grants.js +171 -0
  764. package/dist/lib/lanes/hire-grant-dispatch.d.ts +29 -0
  765. package/dist/lib/lanes/hire-grant-dispatch.js +315 -0
  766. package/dist/lib/lanes/hooks-install.d.ts +82 -0
  767. package/dist/lib/lanes/hooks-install.js +555 -0
  768. package/dist/lib/lanes/host-capacity.d.ts +69 -0
  769. package/dist/lib/lanes/host-capacity.js +254 -0
  770. package/dist/lib/lanes/hq-root.d.ts +19 -0
  771. package/dist/lib/lanes/hq-root.js +28 -0
  772. package/dist/lib/lanes/index.d.ts +76 -0
  773. package/dist/lib/lanes/index.js +42 -0
  774. package/dist/lib/lanes/keep-alive-audit.d.ts +47 -0
  775. package/dist/lib/lanes/keep-alive-audit.js +370 -0
  776. package/dist/lib/lanes/keep-alive.d.ts +68 -0
  777. package/dist/lib/lanes/keep-alive.js +343 -0
  778. package/dist/lib/lanes/kr-freshness.d.ts +76 -0
  779. package/dist/lib/lanes/kr-freshness.js +413 -0
  780. package/dist/lib/lanes/lane-company.d.ts +10 -0
  781. package/dist/lib/lanes/lane-company.js +41 -0
  782. package/dist/lib/lanes/liveness.d.ts +108 -0
  783. package/dist/lib/lanes/liveness.js +396 -0
  784. package/dist/lib/lanes/machine-identity.d.ts +34 -0
  785. package/dist/lib/lanes/machine-identity.js +92 -0
  786. package/dist/lib/lanes/manager-status-gate.d.ts +17 -0
  787. package/dist/lib/lanes/manager-status-gate.js +133 -0
  788. package/dist/lib/lanes/merge-command.d.ts +15 -0
  789. package/dist/lib/lanes/merge-command.js +629 -0
  790. package/dist/lib/lanes/mesh-events.d.ts +127 -0
  791. package/dist/lib/lanes/mesh-events.js +564 -0
  792. package/dist/lib/lanes/message-replay.d.ts +21 -0
  793. package/dist/lib/lanes/message-replay.js +122 -0
  794. package/dist/lib/lanes/models.d.ts +86 -0
  795. package/dist/lib/lanes/models.js +234 -0
  796. package/dist/lib/lanes/monitor.d.ts +48 -0
  797. package/dist/lib/lanes/monitor.js +428 -0
  798. package/dist/lib/lanes/move-account.d.ts +56 -0
  799. package/dist/lib/lanes/move-account.js +193 -0
  800. package/dist/lib/lanes/orphans.d.ts +25 -0
  801. package/dist/lib/lanes/orphans.js +102 -0
  802. package/dist/lib/lanes/outpost-dispatch.d.ts +156 -0
  803. package/dist/lib/lanes/outpost-dispatch.js +293 -0
  804. package/dist/lib/lanes/outpost-hire-cache.d.ts +22 -0
  805. package/dist/lib/lanes/outpost-hire-cache.js +153 -0
  806. package/dist/lib/lanes/outpost-identity.d.ts +33 -0
  807. package/dist/lib/lanes/outpost-identity.js +59 -0
  808. package/dist/lib/lanes/outpost-profile-repin.d.ts +17 -0
  809. package/dist/lib/lanes/outpost-profile-repin.js +84 -0
  810. package/dist/lib/lanes/outpost-pruner-install.d.ts +37 -0
  811. package/dist/lib/lanes/outpost-pruner-install.js +238 -0
  812. package/dist/lib/lanes/outpost-registry-worker-approval.d.ts +18 -0
  813. package/dist/lib/lanes/outpost-registry-worker-approval.js +109 -0
  814. package/dist/lib/lanes/outpost-snapshot-memo.d.ts +6 -0
  815. package/dist/lib/lanes/outpost-snapshot-memo.js +14 -0
  816. package/dist/lib/lanes/outpost-worktree-pruner-flag.d.ts +19 -0
  817. package/dist/lib/lanes/outpost-worktree-pruner-flag.js +86 -0
  818. package/dist/lib/lanes/outpost-worktree-pruner.d.ts +62 -0
  819. package/dist/lib/lanes/outpost-worktree-pruner.js +1201 -0
  820. package/dist/lib/lanes/profile.d.ts +69 -0
  821. package/dist/lib/lanes/profile.js +552 -0
  822. package/dist/lib/lanes/provider-rejection.d.ts +86 -0
  823. package/dist/lib/lanes/provider-rejection.js +286 -0
  824. package/dist/lib/lanes/questions.d.ts +90 -0
  825. package/dist/lib/lanes/questions.js +384 -0
  826. package/dist/lib/lanes/quota.d.ts +134 -0
  827. package/dist/lib/lanes/quota.js +471 -0
  828. package/dist/lib/lanes/reconcile-install.d.ts +90 -0
  829. package/dist/lib/lanes/reconcile-install.js +257 -0
  830. package/dist/lib/lanes/reconcile.d.ts +161 -0
  831. package/dist/lib/lanes/reconcile.js +3343 -0
  832. package/dist/lib/lanes/registry-flag.d.ts +35 -0
  833. package/dist/lib/lanes/registry-flag.js +164 -0
  834. package/dist/lib/lanes/registry-persona.d.ts +20 -0
  835. package/dist/lib/lanes/registry-persona.js +329 -0
  836. package/dist/lib/lanes/registry.d.ts +122 -0
  837. package/dist/lib/lanes/registry.js +570 -0
  838. package/dist/lib/lanes/reviews.d.ts +38 -0
  839. package/dist/lib/lanes/reviews.js +395 -0
  840. package/dist/lib/lanes/runaway-tool-guard.d.ts +38 -0
  841. package/dist/lib/lanes/runaway-tool-guard.js +284 -0
  842. package/dist/lib/lanes/session-relink.d.ts +25 -0
  843. package/dist/lib/lanes/session-relink.js +216 -0
  844. package/dist/lib/lanes/spawn.d.ts +355 -0
  845. package/dist/lib/lanes/spawn.js +2668 -0
  846. package/dist/lib/lanes/ssm-command-context.d.ts +12 -0
  847. package/dist/lib/lanes/ssm-command-context.js +52 -0
  848. package/dist/lib/lanes/store.d.ts +91 -0
  849. package/dist/lib/lanes/store.js +1822 -0
  850. package/dist/lib/lanes/stories.d.ts +23 -0
  851. package/dist/lib/lanes/stories.js +92 -0
  852. package/dist/lib/lanes/story-ledger.d.ts +80 -0
  853. package/dist/lib/lanes/story-ledger.js +815 -0
  854. package/dist/lib/lanes/story-switch.d.ts +21 -0
  855. package/dist/lib/lanes/story-switch.js +75 -0
  856. package/dist/lib/lanes/text-scan.d.ts +11 -0
  857. package/dist/lib/lanes/text-scan.js +103 -0
  858. package/dist/lib/lanes/throttle.d.ts +116 -0
  859. package/dist/lib/lanes/throttle.js +437 -0
  860. package/dist/lib/lanes/timestamp.d.ts +3 -0
  861. package/dist/lib/lanes/timestamp.js +26 -0
  862. package/dist/lib/lanes/tracker-checks.d.ts +77 -0
  863. package/dist/lib/lanes/tracker-checks.js +134 -0
  864. package/dist/lib/lanes/tracker-report-state.d.ts +10 -0
  865. package/dist/lib/lanes/tracker-report-state.js +124 -0
  866. package/dist/lib/lanes/tracker-report.d.ts +203 -0
  867. package/dist/lib/lanes/tracker-report.js +522 -0
  868. package/dist/lib/lanes/tracker-store.d.ts +18 -0
  869. package/dist/lib/lanes/tracker-store.js +106 -0
  870. package/dist/lib/lanes/types.d.ts +1030 -0
  871. package/dist/lib/lanes/types.js +418 -0
  872. package/dist/lib/lanes/wait.d.ts +39 -0
  873. package/dist/lib/lanes/wait.js +159 -0
  874. package/dist/lib/lanes/watch.d.ts +39 -0
  875. package/dist/lib/lanes/watch.js +249 -0
  876. package/dist/lib/lanes/watcher-main.d.ts +11 -0
  877. package/dist/lib/lanes/watcher-main.js +108 -0
  878. package/dist/lib/lanes/watcher.d.ts +287 -0
  879. package/dist/lib/lanes/watcher.js +1972 -0
  880. package/dist/lib/mesh/api.d.ts +103 -10
  881. package/dist/lib/mesh/api.js +334 -64
  882. package/dist/lib/mesh/client.d.ts +3 -2
  883. package/dist/lib/mesh/client.js +26 -7
  884. package/dist/lib/mesh/denial-codes.d.ts +5 -0
  885. package/dist/lib/mesh/denial-codes.js +14 -0
  886. package/dist/lib/mesh/live/backfill-held.d.ts +67 -16
  887. package/dist/lib/mesh/live/backfill-held.js +415 -61
  888. package/dist/lib/mesh/live/backoff.d.ts +2 -2
  889. package/dist/lib/mesh/live/backoff.js +16 -3
  890. package/dist/lib/mesh/live/daemon/board-refresh.d.ts +7 -1
  891. package/dist/lib/mesh/live/daemon/board-refresh.js +78 -30
  892. package/dist/lib/mesh/live/daemon/config.d.ts +36 -0
  893. package/dist/lib/mesh/live/daemon/config.js +120 -0
  894. package/dist/lib/mesh/live/daemon/credentials.d.ts +64 -10
  895. package/dist/lib/mesh/live/daemon/credentials.js +270 -20
  896. package/dist/lib/mesh/live/daemon/doctor.d.ts +53 -0
  897. package/dist/lib/mesh/live/daemon/doctor.js +190 -6
  898. package/dist/lib/mesh/live/daemon/index.d.ts +13 -10
  899. package/dist/lib/mesh/live/daemon/index.js +7 -6
  900. package/dist/lib/mesh/live/daemon/install.d.ts +255 -1
  901. package/dist/lib/mesh/live/daemon/install.js +811 -13
  902. package/dist/lib/mesh/live/daemon/legacy-listen.d.ts +43 -0
  903. package/dist/lib/mesh/live/daemon/legacy-listen.js +89 -0
  904. package/dist/lib/mesh/live/daemon/live-cache.d.ts +26 -0
  905. package/dist/lib/mesh/live/daemon/live-cache.js +116 -0
  906. package/dist/lib/mesh/live/daemon/mqtt-events.d.ts +7 -0
  907. package/dist/lib/mesh/live/daemon/mqtt-events.js +2 -0
  908. package/dist/lib/mesh/live/daemon/mqtt-events.test-d.d.ts +2 -0
  909. package/dist/lib/mesh/live/daemon/mqtt-events.test-d.js +10 -0
  910. package/dist/lib/mesh/live/daemon/paths.d.ts +2 -0
  911. package/dist/lib/mesh/live/daemon/paths.js +2 -0
  912. package/dist/lib/mesh/live/daemon/presence.d.ts +24 -5
  913. package/dist/lib/mesh/live/daemon/presence.js +79 -10
  914. package/dist/lib/mesh/live/daemon/run.d.ts +48 -2
  915. package/dist/lib/mesh/live/daemon/run.js +485 -33
  916. package/dist/lib/mesh/live/daemon/state.d.ts +19 -2
  917. package/dist/lib/mesh/live/daemon/state.js +34 -2
  918. package/dist/lib/mesh/live/daemon/transcript-watch.d.ts +45 -9
  919. package/dist/lib/mesh/live/daemon/transcript-watch.js +227 -31
  920. package/dist/lib/mesh/live/daemon/version-drift.d.ts +5 -0
  921. package/dist/lib/mesh/live/daemon/version-drift.js +47 -0
  922. package/dist/lib/mesh/live/daemon/work-subscribe.d.ts +32 -0
  923. package/dist/lib/mesh/live/daemon/work-subscribe.js +262 -0
  924. package/dist/lib/mesh/live/emit-client.d.ts +8 -0
  925. package/dist/lib/mesh/live/emit-client.js +23 -8
  926. package/dist/lib/mesh/live/emit-evidence.d.ts +19 -0
  927. package/dist/lib/mesh/live/emit-evidence.js +20 -2
  928. package/dist/lib/mesh/live/emit.d.ts +9 -0
  929. package/dist/lib/mesh/live/emit.js +28 -2
  930. package/dist/lib/mesh/live/enqueue.d.ts +5 -0
  931. package/dist/lib/mesh/live/enqueue.js +19 -0
  932. package/dist/lib/mesh/live/flush.d.ts +17 -5
  933. package/dist/lib/mesh/live/flush.js +391 -38
  934. package/dist/lib/mesh/live/format-spool-line.d.ts +5 -2
  935. package/dist/lib/mesh/live/format-spool-line.js +10 -0
  936. package/dist/lib/mesh/live/paths.d.ts +2 -0
  937. package/dist/lib/mesh/live/paths.js +4 -0
  938. package/dist/lib/mesh/live/report-summary.d.ts +45 -0
  939. package/dist/lib/mesh/live/report-summary.js +234 -0
  940. package/dist/lib/mesh/live/session-event.schema.json +24 -1
  941. package/dist/lib/mesh/live/session-events-client.d.ts +2 -0
  942. package/dist/lib/mesh/live/session-events-client.js +26 -0
  943. package/dist/lib/mesh/live/session-seq.d.ts +4 -0
  944. package/dist/lib/mesh/live/session-seq.js +33 -0
  945. package/dist/lib/mesh/live/spool.d.ts +19 -0
  946. package/dist/lib/mesh/live/spool.js +269 -3
  947. package/dist/lib/mesh/live/validate-session-event.d.ts +1 -1
  948. package/dist/lib/mesh/live/validate-session-event.js +1 -1
  949. package/dist/lib/mesh/project-board.d.ts +65 -0
  950. package/dist/lib/mesh/project-board.js +181 -0
  951. package/dist/lib/mesh/story-status.d.ts +22 -0
  952. package/dist/lib/mesh/story-status.js +49 -0
  953. package/dist/lib/monitor.d.ts +149 -0
  954. package/dist/lib/monitor.js +519 -0
  955. package/dist/lib/node-binary.d.ts +50 -0
  956. package/dist/lib/node-binary.js +133 -0
  957. package/dist/lib/notify-recipient.d.ts +7 -0
  958. package/dist/lib/notify-recipient.js +11 -0
  959. package/dist/lib/onboarding/checkpoint.d.ts +13 -0
  960. package/dist/lib/onboarding/checkpoint.js +44 -0
  961. package/dist/lib/onboarding/cli/onboard.d.ts +53 -0
  962. package/dist/lib/onboarding/cli/onboard.js +135 -0
  963. package/dist/lib/onboarding/cli/prompts.d.ts +28 -0
  964. package/dist/lib/onboarding/cli/prompts.js +83 -0
  965. package/dist/lib/onboarding/errors.d.ts +34 -0
  966. package/dist/lib/onboarding/errors.js +59 -0
  967. package/dist/lib/onboarding/index.d.ts +13 -0
  968. package/dist/lib/onboarding/index.js +13 -0
  969. package/dist/lib/onboarding/orchestrator.d.ts +47 -0
  970. package/dist/lib/onboarding/orchestrator.js +569 -0
  971. package/dist/lib/onboarding/types.d.ts +79 -0
  972. package/dist/lib/onboarding/types.js +8 -0
  973. package/dist/lib/plan-limit-nag.d.ts +102 -6
  974. package/dist/lib/plan-limit-nag.js +348 -43
  975. package/dist/lib/policy-validator.d.ts +7 -0
  976. package/dist/lib/policy-validator.js +187 -0
  977. package/dist/lib/process-flag-company-context.d.ts +8 -0
  978. package/dist/lib/process-flag-company-context.js +67 -0
  979. package/dist/lib/report-publish.d.ts +175 -0
  980. package/dist/lib/report-publish.js +421 -0
  981. package/dist/lib/report-run.d.ts +62 -0
  982. package/dist/lib/report-run.js +123 -0
  983. package/dist/lib/report-snapshot.d.ts +12 -0
  984. package/dist/lib/report-snapshot.js +135 -0
  985. package/dist/lib/report-templates.d.ts +9 -0
  986. package/dist/lib/report-templates.js +21 -0
  987. package/dist/lib/scaffold-cli-floor.d.ts +8 -0
  988. package/dist/lib/scaffold-cli-floor.js +50 -0
  989. package/dist/lib/scan-packages/index.d.ts +2 -0
  990. package/dist/lib/scan-packages/index.js +168 -6
  991. package/dist/lib/search-index/background.d.ts +8 -1
  992. package/dist/lib/search-index/background.js +55 -200
  993. package/dist/lib/search-index/collection-path-repair-flag.d.ts +4 -0
  994. package/dist/lib/search-index/collection-path-repair-flag.js +7 -0
  995. package/dist/lib/search-index/embed-lock.d.ts +34 -0
  996. package/dist/lib/search-index/embed-lock.js +295 -0
  997. package/dist/lib/search-index/index.d.ts +12 -0
  998. package/dist/lib/search-index/index.js +153 -7
  999. package/dist/lib/search-index/load-gate.d.ts +57 -0
  1000. package/dist/lib/search-index/load-gate.js +270 -0
  1001. package/dist/lib/search-index/max-doc-bytes.d.ts +219 -0
  1002. package/dist/lib/search-index/max-doc-bytes.js +463 -0
  1003. package/dist/lib/search-index/qmd-exit-diagnostics.d.ts +5 -0
  1004. package/dist/lib/search-index/qmd-exit-diagnostics.js +40 -0
  1005. package/dist/lib/search-index/reindex-single-flight-flag.d.ts +5 -0
  1006. package/dist/lib/search-index/reindex-single-flight-flag.js +8 -0
  1007. package/dist/lib/service-manager/index.d.ts +42 -0
  1008. package/dist/lib/service-manager/index.js +105 -0
  1009. package/dist/lib/service-manager/launchd.d.ts +81 -0
  1010. package/dist/lib/service-manager/launchd.js +212 -0
  1011. package/dist/lib/service-manager/systemd.d.ts +19 -0
  1012. package/dist/lib/service-manager/systemd.js +72 -0
  1013. package/dist/lib/service-manager/types.d.ts +34 -0
  1014. package/dist/lib/service-manager/types.js +26 -0
  1015. package/dist/lib/test-utils/isolated-flag-company-context.d.ts +3 -0
  1016. package/dist/lib/test-utils/isolated-flag-company-context.js +18 -0
  1017. package/dist/lib/work-context/bind-best.d.ts +66 -0
  1018. package/dist/lib/work-context/bind-best.js +344 -0
  1019. package/dist/lib/work-context/bind-calling-session.d.ts +26 -0
  1020. package/dist/lib/work-context/bind-calling-session.js +63 -0
  1021. package/dist/lib/work-context/company-rebind.d.ts +23 -0
  1022. package/dist/lib/work-context/company-rebind.js +59 -0
  1023. package/dist/lib/work-context/company.d.ts +22 -20
  1024. package/dist/lib/work-context/company.js +124 -40
  1025. package/dist/lib/work-context/config.d.ts +58 -11
  1026. package/dist/lib/work-context/config.js +334 -83
  1027. package/dist/lib/work-context/contract.d.ts +13 -0
  1028. package/dist/lib/work-context/contract.schema.json +3 -1
  1029. package/dist/lib/work-context/default-company.d.ts +43 -0
  1030. package/dist/lib/work-context/default-company.js +83 -0
  1031. package/dist/lib/work-context/outbox-quarantine-status-flag.d.ts +4 -0
  1032. package/dist/lib/work-context/outbox-quarantine-status-flag.js +7 -0
  1033. package/dist/lib/work-context/outbox.d.ts +27 -5
  1034. package/dist/lib/work-context/outbox.js +135 -6
  1035. package/dist/lib/work-context/prd-sync.d.ts +56 -0
  1036. package/dist/lib/work-context/prd-sync.js +197 -0
  1037. package/dist/lib/work-context/preflight-contract.d.ts +28 -0
  1038. package/dist/lib/work-context/preflight-contract.js +85 -0
  1039. package/dist/lib/work-context/prompt-rebind.d.ts +25 -0
  1040. package/dist/lib/work-context/prompt-rebind.js +85 -0
  1041. package/dist/lib/work-context/reconcile.d.ts +15 -0
  1042. package/dist/lib/work-context/reconcile.js +405 -29
  1043. package/dist/lib/work-context/state.d.ts +93 -10
  1044. package/dist/lib/work-context/state.js +342 -29
  1045. package/dist/lib/work-context/windows-acl.d.ts +123 -0
  1046. package/dist/lib/work-context/windows-acl.js +425 -0
  1047. package/dist/lib/workers-registry/index.js +62 -8
  1048. package/dist/lib/workers-registry/read.d.ts +15 -0
  1049. package/dist/lib/workers-registry/read.js +17 -0
  1050. package/dist/main.d.ts +32 -0
  1051. package/dist/main.js +273 -73
  1052. package/dist/native-fast-route.d.ts +7 -0
  1053. package/dist/native-fast-route.js +45 -0
  1054. package/dist/node-network-compat-core.d.ts +12 -0
  1055. package/dist/node-network-compat-core.js +41 -0
  1056. package/dist/node-network-compat-fast.d.ts +7 -0
  1057. package/dist/node-network-compat-fast.js +23 -0
  1058. package/dist/node-network-compat.d.ts +2 -30
  1059. package/dist/node-network-compat.js +4 -51
  1060. package/dist/node-preflight.d.ts +7 -1
  1061. package/dist/node-preflight.js +5 -5
  1062. package/dist/register-all.d.ts +4 -29
  1063. package/dist/register-all.js +4 -233
  1064. package/dist/run/discover-schemas.d.ts +2 -1
  1065. package/dist/run/env-graph-guard.d.ts +2 -2
  1066. package/dist/run/env-graph-guard.js +5 -2
  1067. package/dist/run/hq-plugin.d.ts +4 -0
  1068. package/dist/run/hq-plugin.js +36 -8
  1069. package/dist/secrets-env-fast-path.d.ts +5 -0
  1070. package/dist/secrets-env-fast-path.js +16 -0
  1071. package/dist/secrets-env-fast-route.d.ts +18 -0
  1072. package/dist/secrets-env-fast-route.js +54 -0
  1073. package/dist/sentry-before-send.js +80 -0
  1074. package/dist/sentry.d.ts +16 -4
  1075. package/dist/sentry.js +179 -18
  1076. package/dist/startup-registration.d.ts +26 -2
  1077. package/dist/startup-registration.js +116 -15
  1078. package/dist/utils/checkpoint-stamp-write-error.d.ts +28 -0
  1079. package/dist/utils/checkpoint-stamp-write-error.js +99 -0
  1080. package/dist/utils/cli-network-lifecycle.d.ts +4 -0
  1081. package/dist/utils/cli-network-lifecycle.js +11 -0
  1082. package/dist/utils/cli-telemetry.d.ts +75 -1
  1083. package/dist/utils/cli-telemetry.js +433 -7
  1084. package/dist/utils/client-health.d.ts +0 -4
  1085. package/dist/utils/client-health.js +2 -2
  1086. package/dist/utils/cognito-refresh-sentry.d.ts +3 -0
  1087. package/dist/utils/cognito-refresh-sentry.js +49 -0
  1088. package/dist/utils/cognito-session.d.ts +71 -0
  1089. package/dist/utils/cognito-session.js +481 -27
  1090. package/dist/utils/console-origin.d.ts +9 -0
  1091. package/dist/utils/console-origin.js +28 -0
  1092. package/dist/utils/contribution-table.d.ts +1 -1
  1093. package/dist/utils/core-eval-trigger.d.ts +4 -0
  1094. package/dist/utils/core-eval-trigger.js +88 -0
  1095. package/dist/utils/environmental-error.d.ts +18 -0
  1096. package/dist/utils/environmental-error.js +240 -7
  1097. package/dist/utils/exclusive-lock.d.ts +32 -0
  1098. package/dist/utils/exclusive-lock.js +75 -0
  1099. package/dist/utils/expected-cli-error.d.ts +2 -0
  1100. package/dist/utils/expected-cli-error.js +4 -0
  1101. package/dist/utils/fast-stream-errors.d.ts +12 -0
  1102. package/dist/utils/fast-stream-errors.js +18 -0
  1103. package/dist/utils/feedback-diagnostics.d.ts +2 -1
  1104. package/dist/utils/feedback-log-bundle.d.ts +51 -26
  1105. package/dist/utils/feedback-log-bundle.js +211 -31
  1106. package/dist/utils/feedback-logs.d.ts +18 -47
  1107. package/dist/utils/feedback-logs.js +50 -21
  1108. package/dist/utils/feedback-screenshots.d.ts +0 -1
  1109. package/dist/utils/feedback-screenshots.js +1 -1
  1110. package/dist/utils/files-browse-acl.d.ts +5 -0
  1111. package/dist/utils/files-browse-acl.js +11 -0
  1112. package/dist/utils/hq-core-yaml.d.ts +10 -0
  1113. package/dist/utils/hq-core-yaml.js +40 -0
  1114. package/dist/utils/hq-root-resolver.d.ts +13 -0
  1115. package/dist/utils/hq-root-resolver.js +103 -0
  1116. package/dist/utils/hq-roots.d.ts +25 -2
  1117. package/dist/utils/hq-roots.js +67 -7
  1118. package/dist/utils/incomplete-install-error.d.ts +87 -19
  1119. package/dist/utils/incomplete-install-error.js +319 -68
  1120. package/dist/utils/install-tree-torn.d.ts +260 -24
  1121. package/dist/utils/install-tree-torn.js +998 -51
  1122. package/dist/utils/large-file-guard.d.ts +0 -10
  1123. package/dist/utils/large-file-guard.js +1 -1
  1124. package/dist/utils/local-files-overview.d.ts +4 -8
  1125. package/dist/utils/local-files-overview.js +48 -7
  1126. package/dist/utils/login-provider.d.ts +7 -0
  1127. package/dist/utils/login-provider.js +34 -0
  1128. package/dist/utils/pack-contributions.d.ts +2 -14
  1129. package/dist/utils/pack-contributions.js +7 -44
  1130. package/dist/utils/package-root-diagnostics.d.ts +1 -1
  1131. package/dist/utils/people.d.ts +7 -11
  1132. package/dist/utils/people.js +5 -20
  1133. package/dist/utils/plan-gate-error.d.ts +52 -10
  1134. package/dist/utils/plan-gate-error.js +364 -41
  1135. package/dist/utils/qmd-model-download-error.d.ts +0 -8
  1136. package/dist/utils/qmd-model-download-error.js +1 -1
  1137. package/dist/utils/qmd-query-document-error.d.ts +0 -6
  1138. package/dist/utils/qmd-query-document-error.js +1 -1
  1139. package/dist/utils/redact-error-text.d.ts +0 -2
  1140. package/dist/utils/redact-error-text.js +3 -2
  1141. package/dist/utils/redact-url.d.ts +14 -0
  1142. package/dist/utils/redact-url.js +218 -0
  1143. package/dist/utils/run-bundled-script.d.ts +6 -0
  1144. package/dist/utils/run-bundled-script.js +117 -4
  1145. package/dist/utils/sandbox-runner-client.d.ts +2 -1
  1146. package/dist/utils/scaffold-fast-import-guard.d.ts +2 -0
  1147. package/dist/utils/scaffold-fast-import-guard.js +40 -0
  1148. package/dist/utils/scaffold-packlist-guard.d.ts +7 -0
  1149. package/dist/utils/scaffold-packlist-guard.js +23 -0
  1150. package/dist/utils/scaffold-sibling-references.d.ts +22 -0
  1151. package/dist/utils/scaffold-sibling-references.js +156 -0
  1152. package/dist/utils/secret-load-availability.d.ts +8 -0
  1153. package/dist/utils/secret-load-availability.js +54 -0
  1154. package/dist/utils/secrets-cache.d.ts +7 -3
  1155. package/dist/utils/secrets-cache.js +162 -14
  1156. package/dist/utils/self-update.d.ts +34 -1
  1157. package/dist/utils/self-update.js +660 -42
  1158. package/dist/utils/sentry-fingerprint.d.ts +23 -1
  1159. package/dist/utils/sentry-fingerprint.js +223 -31
  1160. package/dist/utils/staged-install.d.ts +34 -0
  1161. package/dist/utils/staged-install.js +346 -0
  1162. package/dist/utils/staged-npm-install.d.ts +16 -0
  1163. package/dist/utils/staged-npm-install.js +264 -0
  1164. package/dist/utils/sync-log-sources.d.ts +15 -0
  1165. package/dist/utils/sync-log-sources.js +36 -0
  1166. package/dist/utils/table-width.d.ts +7 -0
  1167. package/dist/utils/table-width.js +15 -0
  1168. package/dist/utils/team-upgrade.d.ts +1 -1
  1169. package/dist/utils/team-upgrade.js +4 -3
  1170. package/dist/utils/update-command-supervisor.cjs +247 -0
  1171. package/dist/utils/upload-author.d.ts +15 -0
  1172. package/dist/utils/upload-author.js +39 -0
  1173. package/dist/utils/vault-api.d.ts +21 -1
  1174. package/dist/utils/vault-api.js +251 -84
  1175. package/dist/utils/version-check.d.ts +11 -1
  1176. package/dist/utils/version-check.js +32 -3
  1177. package/dist/utils/version-gate.d.ts +101 -17
  1178. package/dist/utils/version-gate.js +645 -70
  1179. package/dist/utils/version-report.d.ts +27 -0
  1180. package/dist/utils/version-report.js +105 -0
  1181. package/dist/utils/windows-spawn.d.ts +6 -0
  1182. package/dist/utils/windows-spawn.js +37 -0
  1183. package/dist/version-request.d.ts +14 -0
  1184. package/dist/version-request.js +36 -0
  1185. package/package.json +20 -8
  1186. package/scripts/mesh-daemon-if-stale.mjs +20 -0
  1187. package/templates/reports/blank.md +3 -0
  1188. package/templates/reports/daily-digest.md +11 -0
  1189. package/templates/runbooks/update-report.md +21 -0
  1190. package/dist/commands/scaffold-fast.d.ts +0 -41
  1191. package/dist/commands/scaffold-fast.js +0 -57
  1192. package/dist/lib/work-context/index.d.ts +0 -25
  1193. package/dist/lib/work-context/index.js +0 -21
@@ -0,0 +1,1822 @@
1
+ /**
2
+ * File-backed lane / question record store (spec §10, §10.1).
3
+ *
4
+ * Root: workspace/lanes/ under the HQ root. One stable path per record;
5
+ * `status` is the pending/answered discriminator — files are never moved
6
+ * between directories. Every mutation is temp-file-plus-rename and a
7
+ * compare-and-set on `version`. Histories are capped at 50 at the append site.
8
+ */
9
+ import { randomBytes } from "node:crypto";
10
+ import * as fs from "node:fs";
11
+ import * as os from "node:os";
12
+ import * as path from "node:path";
13
+ import semver from "semver";
14
+ import { CLI_VERSION } from "../../cli-version.js";
15
+ import { generateUlid } from "../mesh/live/ulid.js";
16
+ import { resolveLanesHqRoot } from "./hq-root.js";
17
+ import { readOutpostIdentity } from "./admission-host.js";
18
+ import { LaneNotFoundError, LaneSchemaError, LaneVersionConflict, LanesError, isLaneVersionConflict, } from "./errors.js";
19
+ import { HISTORY_CAP, HOST_KINDS, LANE_STORY_STATUSES, LANE_SCHEMA_VERSION, QUESTION_SCHEMA_VERSION, SENIOR_KINDS, isHostKind, isLaneProvider, isQueuedReason, isLaneState, isQuestionStatus, isSeniorKind, isTerminalLaneState, parseMajorSchema, REQUIRED_LANE_RECORD_FIELDS, LANE_FIELD_WRITERS, LANE_WRITERS, } from "./types.js";
20
+ import { laneStories } from "./stories.js";
21
+ import { laneStoryLedgerEnabled, syncLaneToProjectStoryLedger, } from "./story-ledger.js";
22
+ export const LANES_STORE_REL = path.join("workspace", "lanes");
23
+ export const LANE_RECORDS_DIR = "lanes";
24
+ export const QUESTION_RECORDS_DIR = "questions";
25
+ export const PENDING_INDEX_DIR = path.join("questions", "index", "pending");
26
+ const LOCK_STALE_MS = 30_000;
27
+ const LOCK_RETRY_MS = 10;
28
+ const LOCK_TIMEOUT_MS = 5_000;
29
+ function defaultStoreDeps() {
30
+ return {
31
+ now: () => new Date(),
32
+ hostname: () => os.hostname(),
33
+ outpostIdentity: () => readOutpostIdentity(),
34
+ mkdirSync: fs.mkdirSync.bind(fs),
35
+ readFileSync: fs.readFileSync.bind(fs),
36
+ writeFileSync: fs.writeFileSync.bind(fs),
37
+ renameSync: fs.renameSync.bind(fs),
38
+ unlinkSync: fs.unlinkSync.bind(fs),
39
+ existsSync: fs.existsSync.bind(fs),
40
+ readdirSync: fs.readdirSync.bind(fs),
41
+ openSync: fs.openSync.bind(fs),
42
+ closeSync: fs.closeSync.bind(fs),
43
+ fsyncSync: fs.fsyncSync.bind(fs),
44
+ chmodSync: fs.chmodSync.bind(fs),
45
+ };
46
+ }
47
+ export function resolveStoreHqRoot(hqRoot, env = process.env, cwd) {
48
+ return hqRoot ?? resolveLanesHqRoot({ env, cwd });
49
+ }
50
+ export function lanesStoreRoot(hqRoot) {
51
+ return path.join(resolveStoreHqRoot(hqRoot), LANES_STORE_REL);
52
+ }
53
+ export function laneRecordPath(hqRoot, laneId) {
54
+ return path.join(lanesStoreRoot(hqRoot), LANE_RECORDS_DIR, `${laneId}.json`);
55
+ }
56
+ export function questionRecordPath(hqRoot, questionId) {
57
+ return path.join(lanesStoreRoot(hqRoot), QUESTION_RECORDS_DIR, `${questionId}.json`);
58
+ }
59
+ export function pendingMarkerPath(hqRoot, questionId) {
60
+ return path.join(lanesStoreRoot(hqRoot), PENDING_INDEX_DIR, questionId);
61
+ }
62
+ export function sanitizeHostComponent(hostname) {
63
+ const cleaned = hostname
64
+ .toLowerCase()
65
+ .replace(/[^a-z0-9]+/g, "-")
66
+ .replace(/^-+|-+$/g, "");
67
+ return (cleaned || "host").slice(0, 32);
68
+ }
69
+ /** Collision-safe across machines: ULID plus a host component. */
70
+ export function mintLaneId(deps = defaultStoreDeps()) {
71
+ const host = sanitizeHostComponent(deps.hostname());
72
+ const timestampMs = deps.now().getTime();
73
+ return `${(deps.generateLaneUlid ?? generateUlid)(timestampMs)}_${host}`;
74
+ }
75
+ export function mintQuestionId(deps = defaultStoreDeps()) {
76
+ const host = sanitizeHostComponent(deps.hostname());
77
+ const extra = randomBytes(2).toString("hex");
78
+ return `q_${generateUlid(deps.now().getTime())}_${host}_${extra}`;
79
+ }
80
+ export function appendCappedHistory(history, entry, cap = HISTORY_CAP) {
81
+ const next = [...history, entry];
82
+ if (next.length <= cap)
83
+ return next;
84
+ return next.slice(next.length - cap);
85
+ }
86
+ function ensureDir(dir, deps) {
87
+ deps.mkdirSync(dir, { recursive: true });
88
+ }
89
+ function fsyncDir(dir, deps) {
90
+ try {
91
+ const fd = deps.openSync(dir, "r");
92
+ try {
93
+ deps.fsyncSync(fd);
94
+ }
95
+ finally {
96
+ deps.closeSync(fd);
97
+ }
98
+ }
99
+ catch (err) {
100
+ const code = err.code;
101
+ if (code === "EISDIR" || code === "EINVAL" || code === "ENOTSUP")
102
+ return;
103
+ // Directory fsync is best-effort on platforms that reject it; log once.
104
+ process.stderr.write(`lanes store: directory fsync failed for ${dir}: ${err instanceof Error ? err.message : String(err)}\n`);
105
+ }
106
+ }
107
+ function atomicWriteJson(target, value, deps) {
108
+ const dir = path.dirname(target);
109
+ ensureDir(dir, deps);
110
+ const tmp = path.join(dir, `.${path.basename(target)}.tmp.${process.pid}.${Date.now()}.${randomBytes(4).toString("hex")}`);
111
+ let fd;
112
+ try {
113
+ fd = deps.openSync(tmp, "wx");
114
+ const buf = Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8");
115
+ fs.writeSync(fd, buf);
116
+ deps.fsyncSync(fd);
117
+ deps.closeSync(fd);
118
+ fd = undefined;
119
+ deps.renameSync(tmp, target);
120
+ fsyncDir(dir, deps);
121
+ try {
122
+ deps.chmodSync(target, 0o600);
123
+ }
124
+ catch (err) {
125
+ process.stderr.write(`lanes store: chmod 0600 failed for ${target}: ${err instanceof Error ? err.message : String(err)}\n`);
126
+ }
127
+ }
128
+ catch (err) {
129
+ if (fd !== undefined) {
130
+ try {
131
+ deps.closeSync(fd);
132
+ }
133
+ catch (closeErr) {
134
+ process.stderr.write(`lanes store: close failed for ${tmp}: ${closeErr instanceof Error ? closeErr.message : String(closeErr)}\n`);
135
+ }
136
+ }
137
+ try {
138
+ deps.unlinkSync(tmp);
139
+ }
140
+ catch (unlinkErr) {
141
+ const code = unlinkErr.code;
142
+ if (code !== "ENOENT") {
143
+ process.stderr.write(`lanes store: unlink tmp failed for ${tmp}: ${unlinkErr instanceof Error ? unlinkErr.message : String(unlinkErr)}\n`);
144
+ }
145
+ }
146
+ throw err;
147
+ }
148
+ }
149
+ function wait(ms) {
150
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
151
+ }
152
+ function lockPathFor(recordPath) {
153
+ return `${recordPath}.lock`;
154
+ }
155
+ function withRecordLock(recordPath, deps, fn) {
156
+ const lockPath = lockPathFor(recordPath);
157
+ ensureDir(path.dirname(recordPath), deps);
158
+ const started = Date.now();
159
+ while (true) {
160
+ let fd;
161
+ try {
162
+ fd = deps.openSync(lockPath, "wx");
163
+ try {
164
+ fs.writeSync(fd, Buffer.from(`${process.pid}\n${Date.now()}\n`, "utf8"));
165
+ }
166
+ catch (err) {
167
+ deps.closeSync(fd);
168
+ fd = undefined;
169
+ throw err;
170
+ }
171
+ try {
172
+ return fn();
173
+ }
174
+ finally {
175
+ try {
176
+ deps.closeSync(fd);
177
+ }
178
+ catch (err) {
179
+ process.stderr.write(`lanes store: lock close failed for ${lockPath}: ${err instanceof Error ? err.message : String(err)}\n`);
180
+ }
181
+ try {
182
+ deps.unlinkSync(lockPath);
183
+ }
184
+ catch (err) {
185
+ const code = err.code;
186
+ if (code !== "ENOENT") {
187
+ process.stderr.write(`lanes store: lock unlink failed for ${lockPath}: ${err instanceof Error ? err.message : String(err)}\n`);
188
+ }
189
+ }
190
+ }
191
+ }
192
+ catch (err) {
193
+ const code = err.code;
194
+ if (code !== "EEXIST")
195
+ throw err;
196
+ if (Date.now() - started > LOCK_TIMEOUT_MS) {
197
+ throw new LanesError("store_lock_timeout", `Timed out waiting for lock ${lockPath}`, { path: lockPath });
198
+ }
199
+ try {
200
+ const raw = deps.readFileSync(lockPath, "utf8");
201
+ const tsLine = raw.split("\n")[1];
202
+ const ts = tsLine ? Number(tsLine) : NaN;
203
+ if (Number.isFinite(ts) && Date.now() - ts > LOCK_STALE_MS) {
204
+ try {
205
+ deps.unlinkSync(lockPath);
206
+ }
207
+ catch (unlinkErr) {
208
+ const unlinkCode = unlinkErr.code;
209
+ if (unlinkCode !== "ENOENT")
210
+ throw unlinkErr;
211
+ }
212
+ continue;
213
+ }
214
+ }
215
+ catch (statErr) {
216
+ const statCode = statErr.code;
217
+ if (statCode !== "ENOENT") {
218
+ process.stderr.write(`lanes store: stale-lock probe failed for ${lockPath}: ${statErr instanceof Error ? statErr.message : String(statErr)}\n`);
219
+ }
220
+ }
221
+ wait(LOCK_RETRY_MS);
222
+ }
223
+ }
224
+ }
225
+ /** Run a lane-owned file read/modify/write transaction under its sidecar lock. */
226
+ export function withLaneRecordFileLock(recordPath, fn) {
227
+ return withRecordLock(recordPath, defaultStoreDeps(), fn);
228
+ }
229
+ function readJsonFile(filePath, deps) {
230
+ let text;
231
+ try {
232
+ text = deps.readFileSync(filePath, "utf8");
233
+ }
234
+ catch (err) {
235
+ const code = err.code;
236
+ if (code === "ENOENT")
237
+ return null;
238
+ throw err;
239
+ }
240
+ try {
241
+ return JSON.parse(text);
242
+ }
243
+ catch (err) {
244
+ throw new LaneSchemaError(`Invalid JSON in ${filePath}: ${err instanceof Error ? err.message : String(err)}`, { path: filePath });
245
+ }
246
+ }
247
+ function isPlainObject(value) {
248
+ return value !== null && typeof value === "object" && !Array.isArray(value);
249
+ }
250
+ function requireString(value, field) {
251
+ if (typeof value !== "string" || value.length === 0) {
252
+ throw new LaneSchemaError(`Expected non-empty string for ${field}`, {
253
+ field,
254
+ });
255
+ }
256
+ return value;
257
+ }
258
+ function requireTimestamp(value, field, filePath) {
259
+ const parsedAt = typeof value === "string" ? Date.parse(value) : NaN;
260
+ const datePart = typeof value === "string" ? value.slice(0, 10) : "";
261
+ const datePartAt = /^\d{4}-\d{2}-\d{2}$/.test(datePart)
262
+ ? Date.parse(`${datePart}T00:00:00.000Z`)
263
+ : NaN;
264
+ if (typeof value !== "string" ||
265
+ !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$/.test(value) ||
266
+ !Number.isFinite(parsedAt) ||
267
+ !Number.isFinite(datePartAt) ||
268
+ new Date(datePartAt).toISOString().slice(0, 10) !== datePart) {
269
+ throw new LaneSchemaError(`Expected ISO timestamp for ${field}`, {
270
+ path: filePath,
271
+ field,
272
+ value,
273
+ });
274
+ }
275
+ return value;
276
+ }
277
+ function requireInt(value, field) {
278
+ if (typeof value !== "number" || !Number.isInteger(value)) {
279
+ throw new LaneSchemaError(`Expected integer for ${field}`, { field });
280
+ }
281
+ return value;
282
+ }
283
+ /**
284
+ * Company on a lane/question record is either a slug+uid pair or JSON `null`.
285
+ * Absence (omitted key) is normalised to `null`. Empty strings stay a schema
286
+ * error so a no-company lane cannot be confused with a broken company object.
287
+ */
288
+ function parseOptionalCompanyField(raw, filePath) {
289
+ if (raw.company === undefined) {
290
+ raw.company = null;
291
+ return;
292
+ }
293
+ if (raw.company === null)
294
+ return;
295
+ if (!isPlainObject(raw.company)) {
296
+ throw new LaneSchemaError("company must be an object", { path: filePath });
297
+ }
298
+ requireString(raw.company.slug, "company.slug");
299
+ requireString(raw.company.uid, "company.uid");
300
+ }
301
+ function parseOptionalMeshCompanyField(raw, filePath) {
302
+ if (raw.mesh_company === undefined)
303
+ return;
304
+ if (!isPlainObject(raw.mesh_company)) {
305
+ throw new LaneSchemaError("mesh_company must be an object", { path: filePath });
306
+ }
307
+ requireString(raw.mesh_company.slug, "mesh_company.slug");
308
+ requireString(raw.mesh_company.uid, "mesh_company.uid");
309
+ }
310
+ function legacyLaneStory(raw) {
311
+ const status = raw.state === "blocked"
312
+ ? "blocked"
313
+ : raw.story_status === "review"
314
+ ? "review"
315
+ : raw.story_status === "done" || raw.story_complete === true
316
+ ? "review"
317
+ : "in_progress";
318
+ const story = {
319
+ project_id: requireString(raw.project_id, "project_id"),
320
+ story_id: requireString(raw.story_id, "story_id"),
321
+ status,
322
+ added_at: requireString(raw.created_at, "created_at"),
323
+ updated_at: requireString(raw.updated_at, "updated_at"),
324
+ };
325
+ if (typeof raw.blocked_reason === "string" && raw.blocked_reason.length > 0) {
326
+ story.blocked_reason = raw.blocked_reason;
327
+ }
328
+ return story;
329
+ }
330
+ function parseLaneStories(raw, filePath) {
331
+ if (raw.stories === undefined) {
332
+ if (raw.story_id === "" && typeof raw.no_story_reason === "string") {
333
+ raw.stories = [];
334
+ return;
335
+ }
336
+ // v1 records carried one story in the top-level fields. Keep the old
337
+ // fields authoritative for the migration and give worker-completed work
338
+ // the review state until a senior explicitly verifies it.
339
+ raw.stories = [legacyLaneStory(raw)];
340
+ return;
341
+ }
342
+ if (!Array.isArray(raw.stories) ||
343
+ (raw.stories.length === 0 && !(raw.story_id === "" && typeof raw.no_story_reason === "string"))) {
344
+ throw new LaneSchemaError("stories must be a non-empty array when present", {
345
+ path: filePath,
346
+ field: "stories",
347
+ });
348
+ }
349
+ for (const [index, value] of raw.stories.entries()) {
350
+ const field = `stories[${index}]`;
351
+ if (!isPlainObject(value)) {
352
+ throw new LaneSchemaError(`${field} must be an object`, { path: filePath, field });
353
+ }
354
+ requireString(value.project_id, `${field}.project_id`);
355
+ requireString(value.story_id, `${field}.story_id`);
356
+ requireString(value.added_at, `${field}.added_at`);
357
+ requireString(value.updated_at, `${field}.updated_at`);
358
+ if (typeof value.status !== "string" ||
359
+ !LANE_STORY_STATUSES.includes(value.status)) {
360
+ throw new LaneSchemaError(`Unknown story status ${JSON.stringify(value.status)}`, {
361
+ path: filePath,
362
+ field: `${field}.status`,
363
+ value: value.status,
364
+ accepted: [...LANE_STORY_STATUSES],
365
+ });
366
+ }
367
+ if (value.blocked_reason !== undefined) {
368
+ requireString(value.blocked_reason, `${field}.blocked_reason`);
369
+ }
370
+ if (value.verified_at !== undefined) {
371
+ requireString(value.verified_at, `${field}.verified_at`);
372
+ }
373
+ if (value.verified_by !== undefined) {
374
+ if (!isPlainObject(value.verified_by)) {
375
+ throw new LaneSchemaError(`${field}.verified_by must be an object`, {
376
+ path: filePath,
377
+ field: `${field}.verified_by`,
378
+ });
379
+ }
380
+ if (!isSeniorKind(value.verified_by.kind)) {
381
+ throw new LaneSchemaError(`Unknown senior kind ${JSON.stringify(value.verified_by.kind)}`, { path: filePath, field: `${field}.verified_by.kind` });
382
+ }
383
+ if (value.verified_by.kind !== "user") {
384
+ requireString(value.verified_by.id, `${field}.verified_by.id`);
385
+ }
386
+ }
387
+ }
388
+ }
389
+ export function parseLaneRecord(raw, filePath) {
390
+ if (!isPlainObject(raw)) {
391
+ throw new LaneSchemaError("Lane record must be a JSON object", {
392
+ path: filePath,
393
+ });
394
+ }
395
+ for (const field of REQUIRED_LANE_RECORD_FIELDS) {
396
+ if (!(field in raw)) {
397
+ throw new LaneSchemaError(`Missing required lane record field ${field}`, { path: filePath, field });
398
+ }
399
+ }
400
+ const schema_version = requireString(raw.schema_version, "schema_version");
401
+ parseMajorSchema(schema_version, "hq-lane", 1);
402
+ requireString(raw.lane_id, "lane_id");
403
+ if (raw.written_by_version !== undefined) {
404
+ const writtenByVersion = requireString(raw.written_by_version, "written_by_version");
405
+ if (!semver.valid(writtenByVersion)) {
406
+ throw new LaneSchemaError("written_by_version must be a valid semver version", {
407
+ path: filePath,
408
+ field: "written_by_version",
409
+ value: writtenByVersion,
410
+ });
411
+ }
412
+ }
413
+ if (raw.owner_written_by_version !== undefined) {
414
+ const ownerWrittenByVersion = requireString(raw.owner_written_by_version, "owner_written_by_version");
415
+ if (!semver.valid(ownerWrittenByVersion)) {
416
+ throw new LaneSchemaError("owner_written_by_version must be a valid semver version", {
417
+ path: filePath,
418
+ field: "owner_written_by_version",
419
+ value: ownerWrittenByVersion,
420
+ });
421
+ }
422
+ }
423
+ requireInt(raw.version, "version");
424
+ requireInt(raw.depth, "depth");
425
+ requireInt(raw.priority, "priority");
426
+ if (raw.ended_at !== undefined) {
427
+ requireTimestamp(raw.ended_at, "ended_at", filePath);
428
+ }
429
+ if (raw.envelope_summary !== undefined &&
430
+ (typeof raw.envelope_summary !== "string" || raw.envelope_summary.trim() === "")) {
431
+ throw new LaneSchemaError("envelope_summary must be a non-empty string when present", {
432
+ path: filePath,
433
+ field: "envelope_summary",
434
+ value: raw.envelope_summary,
435
+ });
436
+ }
437
+ if (raw.hire_grant !== undefined &&
438
+ (typeof raw.hire_grant !== "number" || !Number.isSafeInteger(raw.hire_grant) || raw.hire_grant < 0)) {
439
+ throw new LaneSchemaError("Expected non-negative safe integer for hire_grant", {
440
+ path: filePath,
441
+ field: "hire_grant",
442
+ value: raw.hire_grant,
443
+ });
444
+ }
445
+ if (raw.keep_alive !== undefined && typeof raw.keep_alive !== "boolean") {
446
+ throw new LaneSchemaError("keep_alive must be a boolean", {
447
+ path: filePath,
448
+ field: "keep_alive",
449
+ value: raw.keep_alive,
450
+ });
451
+ }
452
+ if (raw.keep_alive_standing !== undefined && typeof raw.keep_alive_standing !== "boolean") {
453
+ throw new LaneSchemaError("keep_alive_standing must be a boolean", {
454
+ path: filePath,
455
+ field: "keep_alive_standing",
456
+ value: raw.keep_alive_standing,
457
+ });
458
+ }
459
+ const keepAliveBlockedReason = raw.keep_alive_blocked_reason;
460
+ const validKeepAliveBlockedReasons = [
461
+ "not_opted_in",
462
+ "missing_opt_in_time",
463
+ "envelope_before_opt_in",
464
+ "interruption_before_opt_in",
465
+ "missing_interruption_time",
466
+ "retired",
467
+ "superseded",
468
+ "retired_list_invalid",
469
+ "terminal_state",
470
+ ];
471
+ if (keepAliveBlockedReason !== undefined &&
472
+ (typeof keepAliveBlockedReason !== "string" ||
473
+ !validKeepAliveBlockedReasons.includes(keepAliveBlockedReason))) {
474
+ throw new LaneSchemaError("keep_alive_blocked_reason is invalid", {
475
+ path: filePath,
476
+ field: "keep_alive_blocked_reason",
477
+ value: keepAliveBlockedReason,
478
+ });
479
+ }
480
+ if (raw.keep_alive_resume_count !== undefined &&
481
+ (typeof raw.keep_alive_resume_count !== "number" ||
482
+ !Number.isSafeInteger(raw.keep_alive_resume_count) ||
483
+ raw.keep_alive_resume_count < 0 || raw.keep_alive_resume_count > 24)) {
484
+ throw new LaneSchemaError("keep_alive_resume_count must be an integer from 0 through 24", {
485
+ path: filePath,
486
+ field: "keep_alive_resume_count",
487
+ value: raw.keep_alive_resume_count,
488
+ });
489
+ }
490
+ if (raw.keep_alive_blocked_resume_streak !== undefined &&
491
+ (typeof raw.keep_alive_blocked_resume_streak !== "number" ||
492
+ !Number.isSafeInteger(raw.keep_alive_blocked_resume_streak) ||
493
+ raw.keep_alive_blocked_resume_streak < 0 || raw.keep_alive_blocked_resume_streak > 2)) {
494
+ throw new LaneSchemaError("keep_alive_blocked_resume_streak must be an integer from 0 through 2", {
495
+ path: filePath,
496
+ field: "keep_alive_blocked_resume_streak",
497
+ value: raw.keep_alive_blocked_resume_streak,
498
+ });
499
+ }
500
+ for (const field of [
501
+ "keep_alive_opted_in_at",
502
+ "keep_alive_last_resume_at",
503
+ "keep_alive_next_eligible_at",
504
+ "keep_alive_exhausted_at",
505
+ "interrupted_at",
506
+ "last_run_usage_at",
507
+ ]) {
508
+ if (raw[field] !== undefined)
509
+ requireTimestamp(raw[field], field, filePath);
510
+ }
511
+ requireString(raw.project_id, "project_id");
512
+ if (typeof raw.story_id !== "string" ||
513
+ (raw.story_id.trim() === "" && raw.no_story_reason === undefined)) {
514
+ throw new LaneSchemaError("Expected non-empty string for story_id", {
515
+ path: filePath,
516
+ field: "story_id",
517
+ value: raw.story_id,
518
+ });
519
+ }
520
+ if (raw.no_story_reason !== undefined && (typeof raw.no_story_reason !== "string" || raw.no_story_reason.trim() === "")) {
521
+ throw new LaneSchemaError("no_story_reason must be a non-empty string", { path: filePath, field: "no_story_reason" });
522
+ }
523
+ if (raw.story_id.trim() !== "" && raw.no_story_reason !== undefined) {
524
+ throw new LaneSchemaError("no_story_reason requires an empty story_id", { path: filePath, field: "no_story_reason" });
525
+ }
526
+ if (raw.ledger_sync_error !== undefined && (typeof raw.ledger_sync_error !== "string" || raw.ledger_sync_error.trim() === "")) {
527
+ throw new LaneSchemaError("ledger_sync_error must be a non-empty string", { path: filePath, field: "ledger_sync_error" });
528
+ }
529
+ if (raw.pending_question_ids !== undefined && (!Array.isArray(raw.pending_question_ids) ||
530
+ raw.pending_question_ids.some((id) => typeof id !== "string" || id.trim() === "") ||
531
+ new Set(raw.pending_question_ids).size !== raw.pending_question_ids.length)) {
532
+ throw new LaneSchemaError("pending_question_ids must be an array of unique non-empty ids", { path: filePath, field: "pending_question_ids" });
533
+ }
534
+ if (raw.envelope_validation_errors !== undefined && (!Array.isArray(raw.envelope_validation_errors) ||
535
+ raw.envelope_validation_errors.length === 0 ||
536
+ raw.envelope_validation_errors.some((error) => typeof error !== "string" || error.trim() === ""))) {
537
+ throw new LaneSchemaError("envelope_validation_errors must be a non-empty array of non-empty strings", { path: filePath, field: "envelope_validation_errors" });
538
+ }
539
+ if (raw.fallback_question_cancellation_failures !== undefined) {
540
+ if (!Array.isArray(raw.fallback_question_cancellation_failures)) {
541
+ throw new LaneSchemaError("fallback_question_cancellation_failures must be an array", {
542
+ path: filePath,
543
+ field: "fallback_question_cancellation_failures",
544
+ });
545
+ }
546
+ for (const [index, entry] of raw.fallback_question_cancellation_failures.entries()) {
547
+ const field = `fallback_question_cancellation_failures[${index}]`;
548
+ if (!isPlainObject(entry) ||
549
+ Object.keys(entry).some((key) => !["at", "caller", "trigger", "question_ids", "error"].includes(key)) ||
550
+ (entry.trigger !== "message" && entry.trigger !== "resume") ||
551
+ !Array.isArray(entry.question_ids) ||
552
+ entry.question_ids.some((id) => typeof id !== "string" || id.trim() === "")) {
553
+ throw new LaneSchemaError(`${field} must be a fallback question-cancellation failure`, {
554
+ path: filePath,
555
+ field,
556
+ });
557
+ }
558
+ requireTimestamp(entry.at, `${field}.at`, filePath);
559
+ requireString(entry.caller, `${field}.caller`);
560
+ requireString(entry.error, `${field}.error`);
561
+ }
562
+ }
563
+ requireTimestamp(raw.created_at, "created_at", filePath);
564
+ requireTimestamp(raw.updated_at, "updated_at", filePath);
565
+ if (raw.queued_reason !== undefined && !isQueuedReason(raw.queued_reason)) {
566
+ throw new LaneSchemaError(`Unknown queued reason ${JSON.stringify(raw.queued_reason)}`, {
567
+ path: filePath,
568
+ field: "queued_reason",
569
+ value: raw.queued_reason,
570
+ });
571
+ }
572
+ let normalized;
573
+ if (raw.queued_details !== undefined) {
574
+ const details = raw.queued_details;
575
+ if (details === null || typeof details !== "object" || Array.isArray(details) ||
576
+ typeof details.reason !== "string") {
577
+ throw new LaneSchemaError("queued_details must describe a supported queue condition", {
578
+ path: filePath,
579
+ field: "queued_details",
580
+ });
581
+ }
582
+ const detailsRecord = details;
583
+ if (detailsRecord.reason === "worker_profile_changed") {
584
+ if ((detailsRecord.expected_hash !== null && typeof detailsRecord.expected_hash !== "string") ||
585
+ typeof detailsRecord.actual_hash !== "string" || detailsRecord.actual_hash === "" ||
586
+ typeof detailsRecord.recovery_command !== "string" || detailsRecord.recovery_command.trim() === "") {
587
+ throw new LaneSchemaError("queued_details must describe a worker_profile_changed queue reason", {
588
+ path: filePath,
589
+ field: "queued_details",
590
+ });
591
+ }
592
+ if (raw.queued_reason !== "worker_profile_changed") {
593
+ if (raw.queued_reason === undefined) {
594
+ throw new LaneSchemaError("queued_details requires queued_reason worker_profile_changed", {
595
+ path: filePath,
596
+ field: "queued_details",
597
+ queued_reason: raw.queued_reason,
598
+ });
599
+ }
600
+ normalized = { ...raw };
601
+ delete normalized.queued_details;
602
+ }
603
+ }
604
+ else if (detailsRecord.reason === "outpost_dispatch_unknown") {
605
+ if (raw.state !== "queued" ||
606
+ detailsRecord.outcome_unknown !== true ||
607
+ (detailsRecord.command_id !== null &&
608
+ (typeof detailsRecord.command_id !== "string" || detailsRecord.command_id.trim() === ""))) {
609
+ throw new LaneSchemaError("queued_details must describe an unknown Outpost dispatch on a queued lane", {
610
+ path: filePath,
611
+ field: "queued_details",
612
+ });
613
+ }
614
+ }
615
+ else if (detailsRecord.reason === "low_disk") {
616
+ if (raw.state !== "queued" || raw.queued_reason !== "low_disk" ||
617
+ !Number.isSafeInteger(detailsRecord.hq_free_bytes) || detailsRecord.hq_free_bytes < 0 ||
618
+ !Number.isSafeInteger(detailsRecord.provider_free_bytes) || detailsRecord.provider_free_bytes < 0) {
619
+ throw new LaneSchemaError("queued_details must describe measured low-disk queue state", {
620
+ path: filePath,
621
+ field: "queued_details",
622
+ });
623
+ }
624
+ requireTimestamp(detailsRecord.measured_at, "queued_details.measured_at", filePath);
625
+ }
626
+ else {
627
+ throw new LaneSchemaError("queued_details must describe a supported queue condition", {
628
+ path: filePath,
629
+ field: "queued_details",
630
+ });
631
+ }
632
+ }
633
+ if (raw.queued_at !== undefined)
634
+ requireTimestamp(raw.queued_at, "queued_at", filePath);
635
+ if (raw.admission_reserved_at !== undefined) {
636
+ requireTimestamp(raw.admission_reserved_at, "admission_reserved_at", filePath);
637
+ }
638
+ if (raw.admission_accounts !== undefined) {
639
+ if (!Array.isArray(raw.admission_accounts) ||
640
+ raw.admission_accounts.length === 0 ||
641
+ raw.admission_accounts.some((account) => typeof account !== "string" || account.trim() === "") ||
642
+ new Set(raw.admission_accounts).size !== raw.admission_accounts.length) {
643
+ throw new LaneSchemaError("admission_accounts must be a non-empty array of unique account ids", { path: filePath, field: "admission_accounts" });
644
+ }
645
+ if (typeof raw.account !== "string" || !raw.admission_accounts.includes(raw.account)) {
646
+ throw new LaneSchemaError("account must be present in admission_accounts", { path: filePath, field: "admission_accounts", account: raw.account });
647
+ }
648
+ }
649
+ if (!isLaneState(raw.state)) {
650
+ throw new LaneSchemaError(`Unknown lane state ${JSON.stringify(raw.state)}`, { path: filePath, value: raw.state });
651
+ }
652
+ if (!isLaneProvider(raw.provider)) {
653
+ throw new LaneSchemaError(`Unknown provider ${JSON.stringify(raw.provider)}`, { path: filePath, value: raw.provider });
654
+ }
655
+ if (raw.worker_policy_delivery !== undefined &&
656
+ raw.worker_policy_delivery !== "hook" &&
657
+ raw.worker_policy_delivery !== "prompt") {
658
+ throw new LaneSchemaError(`Unknown worker policy delivery mode ${JSON.stringify(raw.worker_policy_delivery)}`, { path: filePath, field: "worker_policy_delivery", value: raw.worker_policy_delivery });
659
+ }
660
+ if (raw.registry_worker !== undefined) {
661
+ const worker = raw.registry_worker;
662
+ if (!isPlainObject(worker) || Object.keys(worker).some((key) => !["id", "path", "worker_yaml_sha256", "approval_required", "human_checkpoints"].includes(key))) {
663
+ throw new LaneSchemaError("registry_worker must be a pinned registry worker record", {
664
+ path: filePath,
665
+ field: "registry_worker",
666
+ });
667
+ }
668
+ for (const key of ["id", "path"]) {
669
+ if (typeof worker[key] !== "string" || worker[key].trim().length === 0) {
670
+ throw new LaneSchemaError(`registry_worker.${key} must be a non-empty string`, {
671
+ path: filePath,
672
+ field: `registry_worker.${key}`,
673
+ });
674
+ }
675
+ }
676
+ const registryPath = worker.path.replaceAll("\\", "/");
677
+ if (path.posix.isAbsolute(registryPath) || registryPath.split("/").some((part) => part === ".." || part === ".")) {
678
+ throw new LaneSchemaError("registry_worker.path must stay within HQ_ROOT", {
679
+ path: filePath,
680
+ field: "registry_worker.path",
681
+ });
682
+ }
683
+ if (typeof worker.worker_yaml_sha256 !== "string" || !/^sha256:[a-f0-9]{64}$/.test(worker.worker_yaml_sha256)) {
684
+ throw new LaneSchemaError("registry_worker.worker_yaml_sha256 must be a SHA-256 hash", {
685
+ path: filePath,
686
+ field: "registry_worker.worker_yaml_sha256",
687
+ });
688
+ }
689
+ if (typeof worker.approval_required !== "boolean") {
690
+ throw new LaneSchemaError("registry_worker.approval_required must be a boolean", {
691
+ path: filePath,
692
+ field: "registry_worker.approval_required",
693
+ });
694
+ }
695
+ if (!Array.isArray(worker.human_checkpoints) || worker.human_checkpoints.some((checkpoint) => typeof checkpoint !== "string" || checkpoint.trim().length === 0) ||
696
+ new Set(worker.human_checkpoints).size !== worker.human_checkpoints.length) {
697
+ throw new LaneSchemaError("registry_worker.human_checkpoints must be unique non-empty strings", {
698
+ path: filePath,
699
+ field: "registry_worker.human_checkpoints",
700
+ });
701
+ }
702
+ }
703
+ if (raw.registry_worker_approval_history !== undefined) {
704
+ if (!Array.isArray(raw.registry_worker_approval_history)) {
705
+ throw new LaneSchemaError("registry_worker_approval_history must be an array when present", {
706
+ path: filePath,
707
+ field: "registry_worker_approval_history",
708
+ });
709
+ }
710
+ for (const [index, entry] of raw.registry_worker_approval_history.entries()) {
711
+ const field = `registry_worker_approval_history[${index}]`;
712
+ if (!isPlainObject(entry)) {
713
+ throw new LaneSchemaError(`${field} must be an approval audit event`, { path: filePath, field });
714
+ }
715
+ const expected = entry.event === "approved"
716
+ ? ["event", "approval_id", "checkpoint", "registry_worker_id", "worker_yaml_sha256", "reason", "actor", "at"]
717
+ : entry.event === "consumed"
718
+ ? ["event", "approval_id", "envelope_ref", "at"]
719
+ : [];
720
+ if (expected.length === 0 || Object.keys(entry).some((key) => !expected.includes(key))) {
721
+ throw new LaneSchemaError(`${field} has an unknown event or field`, { path: filePath, field });
722
+ }
723
+ for (const key of ["approval_id", ...(entry.event === "approved" ? ["checkpoint", "reason", "actor"] : ["envelope_ref"])]) {
724
+ if (typeof entry[key] !== "string" || entry[key].trim().length === 0) {
725
+ throw new LaneSchemaError(`${field}.${key} must be a non-empty string`, { path: filePath, field });
726
+ }
727
+ }
728
+ if (entry.event === "approved" && entry.worker_yaml_sha256 !== undefined &&
729
+ (typeof entry.worker_yaml_sha256 !== "string" || !/^sha256:[a-f0-9]{64}$/.test(entry.worker_yaml_sha256))) {
730
+ throw new LaneSchemaError(`${field}.worker_yaml_sha256 must be a SHA-256 hash`, {
731
+ path: filePath,
732
+ field: `${field}.worker_yaml_sha256`,
733
+ });
734
+ }
735
+ if (entry.event === "approved" && entry.registry_worker_id !== undefined &&
736
+ (typeof entry.registry_worker_id !== "string" || entry.registry_worker_id.trim().length === 0)) {
737
+ throw new LaneSchemaError(`${field}.registry_worker_id must be a non-empty string`, {
738
+ path: filePath,
739
+ field: `${field}.registry_worker_id`,
740
+ });
741
+ }
742
+ requireTimestamp(entry.at, `${field}.at`, filePath);
743
+ }
744
+ }
745
+ parseLaneStories(raw, filePath);
746
+ if (raw.last_envelope !== undefined) {
747
+ if (!isPlainObject(raw.last_envelope) || typeof raw.last_envelope.ref !== "string" ||
748
+ typeof raw.last_envelope.at !== "string" ||
749
+ !["done", "ask", "blocked"].includes(raw.last_envelope.decision) ||
750
+ (raw.last_envelope.artifacts !== undefined && !Array.isArray(raw.last_envelope.artifacts)) ||
751
+ (raw.last_envelope.blocked_reason !== undefined && typeof raw.last_envelope.blocked_reason !== "string")) {
752
+ throw new LaneSchemaError("last_envelope is malformed", { path: filePath, field: "last_envelope" });
753
+ }
754
+ }
755
+ parseOptionalCompanyField(raw, filePath);
756
+ parseOptionalMeshCompanyField(raw, filePath);
757
+ if (!isPlainObject(raw.senior)) {
758
+ throw new LaneSchemaError("senior must be an object", { path: filePath });
759
+ }
760
+ if (!isSeniorKind(raw.senior.kind)) {
761
+ throw new LaneSchemaError(`Unknown senior kind ${JSON.stringify(raw.senior.kind)}`, {
762
+ path: filePath,
763
+ field: "senior.kind",
764
+ value: raw.senior.kind,
765
+ accepted: [...SENIOR_KINDS],
766
+ });
767
+ }
768
+ if (raw.senior.kind !== "user") {
769
+ requireString(raw.senior.id, "senior.id");
770
+ }
771
+ if (!isPlainObject(raw.host)) {
772
+ throw new LaneSchemaError("host must be an object", { path: filePath });
773
+ }
774
+ if (!isHostKind(raw.host.kind)) {
775
+ throw new LaneSchemaError(`Unknown host kind ${JSON.stringify(raw.host.kind)}`, {
776
+ path: filePath,
777
+ field: "host.kind",
778
+ value: raw.host.kind,
779
+ accepted: [...HOST_KINDS],
780
+ });
781
+ }
782
+ requireString(raw.host.id, "host.id");
783
+ if (!Array.isArray(raw.senior_history)) {
784
+ throw new LaneSchemaError("senior_history must be an array", {
785
+ path: filePath,
786
+ });
787
+ }
788
+ if (raw.account_history !== undefined && !Array.isArray(raw.account_history)) {
789
+ throw new LaneSchemaError("account_history must be an array when present", {
790
+ path: filePath,
791
+ });
792
+ }
793
+ if (isPlainObject(raw.pending_resume) &&
794
+ raw.pending_resume.caller !== undefined) {
795
+ requireString(raw.pending_resume.caller, "pending_resume.caller");
796
+ }
797
+ if (raw.keep_alive_history !== undefined) {
798
+ if (!Array.isArray(raw.keep_alive_history) || raw.keep_alive_history.length > HISTORY_CAP) {
799
+ throw new LaneSchemaError(`keep_alive_history must be an array capped at ${HISTORY_CAP} entries`, {
800
+ path: filePath,
801
+ field: "keep_alive_history",
802
+ });
803
+ }
804
+ for (const [index, value] of raw.keep_alive_history.entries()) {
805
+ const field = `keep_alive_history[${index}]`;
806
+ if (!isPlainObject(value) ||
807
+ Object.keys(value).some((key) => !["at", "resumed_from", "account"].includes(key)) ||
808
+ (value.resumed_from !== "done" && value.resumed_from !== "interrupted" && value.resumed_from !== "blocked") ||
809
+ (value.account !== null && typeof value.account !== "string")) {
810
+ throw new LaneSchemaError(`${field} must be a keep-alive resume history entry`, {
811
+ path: filePath,
812
+ field,
813
+ value,
814
+ });
815
+ }
816
+ requireTimestamp(value.at, `${field}.at`, filePath);
817
+ }
818
+ }
819
+ if (raw.resume_history !== undefined) {
820
+ if (!Array.isArray(raw.resume_history) || raw.resume_history.length > HISTORY_CAP) {
821
+ throw new LaneSchemaError(`resume_history must be an array capped at ${HISTORY_CAP} entries`, {
822
+ path: filePath,
823
+ field: "resume_history",
824
+ });
825
+ }
826
+ for (const [index, value] of raw.resume_history.entries()) {
827
+ const field = `resume_history[${index}]`;
828
+ if (!isPlainObject(value) ||
829
+ Object.keys(value).some((key) => !["at", "trigger", "caller"].includes(key))) {
830
+ throw new LaneSchemaError(`${field} must be a resume history entry`, {
831
+ path: filePath,
832
+ field,
833
+ value,
834
+ });
835
+ }
836
+ requireTimestamp(value.at, `${field}.at`, filePath);
837
+ requireString(value.trigger, `${field}.trigger`);
838
+ if (value.caller !== undefined)
839
+ requireString(value.caller, `${field}.caller`);
840
+ }
841
+ }
842
+ if (raw.stop_history !== undefined) {
843
+ if (!Array.isArray(raw.stop_history)) {
844
+ throw new LaneSchemaError("stop_history must be an array when present", {
845
+ path: filePath,
846
+ field: "stop_history",
847
+ });
848
+ }
849
+ for (const [index, entry] of raw.stop_history.entries()) {
850
+ const field = `stop_history[${index}]`;
851
+ if (!isPlainObject(entry) || Object.keys(entry).some((key) => !["at", "reason"].includes(key))) {
852
+ throw new LaneSchemaError(`${field} must be a stop history entry`, { path: filePath, field });
853
+ }
854
+ if (typeof entry.reason !== "string" || entry.reason.trim() === "") {
855
+ throw new LaneSchemaError(`${field}.reason must be a non-empty string`, { path: filePath, field });
856
+ }
857
+ requireTimestamp(entry.at, `${field}.at`, filePath);
858
+ }
859
+ }
860
+ if (raw.settings_history !== undefined) {
861
+ if (!Array.isArray(raw.settings_history)) {
862
+ throw new LaneSchemaError("settings_history must be an array when present", {
863
+ path: filePath,
864
+ field: "settings_history",
865
+ });
866
+ }
867
+ for (const [index, entry] of raw.settings_history.entries()) {
868
+ const field = `settings_history[${index}]`;
869
+ if (!isPlainObject(entry) ||
870
+ Object.keys(entry).some((key) => !["at", "actor", "model", "effort", "reason"].includes(key)) ||
871
+ (entry.model === undefined && entry.effort === undefined)) {
872
+ throw new LaneSchemaError(`${field} must be a settings history entry`, { path: filePath, field });
873
+ }
874
+ requireTimestamp(entry.at, `${field}.at`, filePath);
875
+ if (typeof entry.actor !== "string" || entry.actor.trim() === "") {
876
+ throw new LaneSchemaError(`${field}.actor must be a non-empty string`, { path: filePath, field });
877
+ }
878
+ if (entry.reason !== undefined && (typeof entry.reason !== "string" || entry.reason.trim() === "")) {
879
+ throw new LaneSchemaError(`${field}.reason must be a non-empty string when present`, { path: filePath, field });
880
+ }
881
+ for (const key of ["model", "effort"]) {
882
+ const change = entry[key];
883
+ if (change === undefined)
884
+ continue;
885
+ if (!isPlainObject(change) ||
886
+ Object.keys(change).some((k) => k !== "from" && k !== "to") ||
887
+ typeof change.to !== "string" || change.to.trim() === "" ||
888
+ (change.from !== null && typeof change.from !== "string")) {
889
+ throw new LaneSchemaError(`${field}.${key} must be a {from, to} change`, { path: filePath, field });
890
+ }
891
+ }
892
+ }
893
+ }
894
+ if (raw.worker_profile_repin_history !== undefined) {
895
+ if (!Array.isArray(raw.worker_profile_repin_history)) {
896
+ throw new LaneSchemaError("worker_profile_repin_history must be an array when present", {
897
+ path: filePath,
898
+ field: "worker_profile_repin_history",
899
+ });
900
+ }
901
+ for (const [index, entry] of raw.worker_profile_repin_history.entries()) {
902
+ const field = `worker_profile_repin_history[${index}]`;
903
+ if (!isPlainObject(entry) || Object.keys(entry).some((key) => !["old_hash", "new_hash", "actor", "at", "reason"].includes(key))) {
904
+ throw new LaneSchemaError(`${field} must be an audit entry`, { path: filePath, field });
905
+ }
906
+ if (entry.old_hash !== null && (typeof entry.old_hash !== "string" || !entry.old_hash.trim())) {
907
+ throw new LaneSchemaError(`${field}.old_hash must be a non-empty string or null`, { path: filePath, field });
908
+ }
909
+ for (const key of ["new_hash", "actor", "reason"]) {
910
+ if (typeof entry[key] !== "string" || !entry[key].trim()) {
911
+ throw new LaneSchemaError(`${field}.${key} must be a non-empty string`, { path: filePath, field });
912
+ }
913
+ }
914
+ requireTimestamp(entry.at, `${field}.at`, filePath);
915
+ }
916
+ }
917
+ if (raw.account_selection !== undefined) {
918
+ parseLaneAccountSelection(raw.account_selection, filePath);
919
+ }
920
+ if (raw.placement_default !== undefined) {
921
+ const placement = raw.placement_default;
922
+ if (!isPlainObject(placement) ||
923
+ (placement.kind !== "local" && placement.kind !== "auto" && placement.kind !== "outpost") ||
924
+ (placement.kind === "outpost" && (typeof placement.id !== "string" || placement.id.trim() === "")) ||
925
+ (placement.kind !== "outpost" && "id" in placement)) {
926
+ throw new LaneSchemaError("placement_default must be local, auto, or a pinned Outpost", {
927
+ path: filePath,
928
+ field: "placement_default",
929
+ });
930
+ }
931
+ }
932
+ if (!Array.isArray(raw.attribution_history)) {
933
+ throw new LaneSchemaError("attribution_history must be an array", {
934
+ path: filePath,
935
+ });
936
+ }
937
+ // Spread-preserving: return the original object so unknown keys survive
938
+ // a parse/rewrite cycle (spec §5.1 field-preservation).
939
+ return (normalized ?? raw);
940
+ }
941
+ function parseLaneAccountSelection(value, filePath) {
942
+ const failure = (field) => new LaneSchemaError(`Invalid account_selection.${field}`, {
943
+ path: filePath,
944
+ field: `account_selection.${field}`,
945
+ });
946
+ if (!isPlainObject(value))
947
+ throw failure("must be an object");
948
+ const selection = value;
949
+ if (typeof selection.account !== "string" || selection.account.trim() === "")
950
+ throw failure("account");
951
+ if (selection.signal !== "usage" && selection.signal !== "recent_usage" && selection.signal !== "lane_count" && selection.signal !== "explicit")
952
+ throw failure("signal");
953
+ if (selection.reason !== "least_loaded" && selection.reason !== "explicit")
954
+ throw failure("reason");
955
+ if (typeof selection.selected_at !== "string" || !Number.isFinite(Date.parse(selection.selected_at)))
956
+ throw failure("selected_at");
957
+ const parseHost = (host, field) => {
958
+ if (!isPlainObject(host) || !isHostKind(host.kind) || typeof host.id !== "string" || host.id.trim() === "")
959
+ throw failure(field);
960
+ };
961
+ parseHost(selection.target_host, "target_host");
962
+ if (!Array.isArray(selection.considered) || !Array.isArray(selection.skipped_accounts) || !Array.isArray(selection.unavailable_hosts)) {
963
+ throw failure("arrays");
964
+ }
965
+ for (const [index, rowValue] of selection.considered.entries()) {
966
+ if (!isPlainObject(rowValue))
967
+ throw failure(`considered.${index}`);
968
+ const row = rowValue;
969
+ if (typeof row.account !== "string" || row.account.trim() === "" || typeof row.eligible !== "boolean" || typeof row.live_lanes !== "number" || !Number.isInteger(row.live_lanes) || row.live_lanes < 0 || typeof row.counts_complete !== "boolean" || !Array.isArray(row.hosts))
970
+ throw failure(`considered.${index}`);
971
+ if (row.ineligible_reason !== undefined && typeof row.ineligible_reason !== "string")
972
+ throw failure(`considered.${index}.ineligible_reason`);
973
+ if (row.recent_usage_at !== undefined && row.recent_usage_at !== null &&
974
+ (typeof row.recent_usage_at !== "string" || !Number.isFinite(Date.parse(row.recent_usage_at)))) {
975
+ throw failure(`considered.${index}.recent_usage_at`);
976
+ }
977
+ if (row.usage !== null) {
978
+ if (!isPlainObject(row.usage))
979
+ throw failure(`considered.${index}.usage`);
980
+ for (const key of ["five_hour_percent", "weekly_percent"]) {
981
+ const percent = row.usage[key];
982
+ if (percent !== undefined && (typeof percent !== "number" || !Number.isFinite(percent) || percent < 0 || percent > 100))
983
+ throw failure(`considered.${index}.usage.${key}`);
984
+ }
985
+ if (row.usage.sampled_at !== undefined && (typeof row.usage.sampled_at !== "string" || !Number.isFinite(Date.parse(row.usage.sampled_at))))
986
+ throw failure(`considered.${index}.usage.sampled_at`);
987
+ }
988
+ for (const [hostIndex, hostValue] of row.hosts.entries()) {
989
+ if (!isPlainObject(hostValue))
990
+ throw failure(`considered.${index}.hosts.${hostIndex}`);
991
+ const host = hostValue;
992
+ parseHost(host.host, `considered.${index}.hosts.${hostIndex}.host`);
993
+ if (typeof host.enabled !== "boolean" || !(host.logged_in === null || typeof host.logged_in === "boolean"))
994
+ throw failure(`considered.${index}.hosts.${hostIndex}.status`);
995
+ if (!(host.live_lanes === null || (typeof host.live_lanes === "number" && Number.isInteger(host.live_lanes) && host.live_lanes >= 0)))
996
+ throw failure(`considered.${index}.hosts.${hostIndex}.live_lanes`);
997
+ if (!isPlainObject(host.lane_counts))
998
+ throw failure(`considered.${index}.hosts.${hostIndex}.lane_counts`);
999
+ for (const key of ["running", "queued", "awaiting_input"]) {
1000
+ const count = host.lane_counts[key];
1001
+ if (!(count === null || (typeof count === "number" && Number.isInteger(count) && count >= 0)))
1002
+ throw failure(`considered.${index}.hosts.${hostIndex}.lane_counts.${key}`);
1003
+ }
1004
+ if (!["lane_list", "capacity", "capacity_partial", "unavailable"].includes(String(host.count_source)))
1005
+ throw failure(`considered.${index}.hosts.${hostIndex}.count_source`);
1006
+ }
1007
+ }
1008
+ for (const [index, rowValue] of selection.skipped_accounts.entries()) {
1009
+ if (!isPlainObject(rowValue))
1010
+ throw failure(`skipped_accounts.${index}`);
1011
+ const row = rowValue;
1012
+ if (typeof row.account !== "string" || row.account.trim() === "" || typeof row.reason !== "string" || row.reason.trim() === "")
1013
+ throw failure(`skipped_accounts.${index}`);
1014
+ parseHost(row.host, `skipped_accounts.${index}.host`);
1015
+ }
1016
+ for (const [index, rowValue] of selection.unavailable_hosts.entries()) {
1017
+ if (!isPlainObject(rowValue))
1018
+ throw failure(`unavailable_hosts.${index}`);
1019
+ const row = rowValue;
1020
+ if (typeof row.reason !== "string" || row.reason.trim() === "")
1021
+ throw failure(`unavailable_hosts.${index}`);
1022
+ if (isPlainObject(row.host) && row.host.kind === "unknown" && row.host.id === "unknown")
1023
+ continue;
1024
+ parseHost(row.host, `unavailable_hosts.${index}.host`);
1025
+ }
1026
+ return selection;
1027
+ }
1028
+ export function parseQuestionRecord(raw, filePath) {
1029
+ if (!isPlainObject(raw)) {
1030
+ throw new LaneSchemaError("Question record must be a JSON object", {
1031
+ path: filePath,
1032
+ });
1033
+ }
1034
+ const schema_version = requireString(raw.schema_version, "schema_version");
1035
+ parseMajorSchema(schema_version, "hq-lane-question", 1);
1036
+ if (!isQuestionStatus(raw.status)) {
1037
+ throw new LaneSchemaError(`Unknown question status ${JSON.stringify(raw.status)}`, { path: filePath, value: raw.status });
1038
+ }
1039
+ requireString(raw.question_id, "question_id");
1040
+ requireString(raw.lane_id, "lane_id");
1041
+ if (raw.priority !== undefined && raw.priority !== null && raw.priority !== "P0" && raw.priority !== "P1" && raw.priority !== "P2") {
1042
+ throw new LaneSchemaError("priority must be P0, P1, or P2 when present", {
1043
+ path: filePath,
1044
+ value: raw.priority,
1045
+ });
1046
+ }
1047
+ requireInt(raw.version, "version");
1048
+ requireInt(raw.hop, "hop");
1049
+ parseOptionalCompanyField(raw, filePath);
1050
+ if (!isPlainObject(raw.body)) {
1051
+ throw new LaneSchemaError("body must be an object", { path: filePath });
1052
+ }
1053
+ if (!Array.isArray(raw.routing_history)) {
1054
+ throw new LaneSchemaError("routing_history must be an array", {
1055
+ path: filePath,
1056
+ });
1057
+ }
1058
+ // Optional on the record, but merge-on-read spreads it; a non-array from a
1059
+ // synced sidecar must fail here, inside the per-sidecar skip, not later.
1060
+ if (raw.answer_history !== undefined && !Array.isArray(raw.answer_history)) {
1061
+ throw new LaneSchemaError("answer_history must be an array when present", {
1062
+ path: filePath,
1063
+ });
1064
+ }
1065
+ const delivered_at = raw.delivered_at === undefined ? null : raw.delivered_at;
1066
+ if (delivered_at !== null &&
1067
+ (typeof delivered_at !== "string" || !Number.isFinite(Date.parse(delivered_at)))) {
1068
+ throw new LaneSchemaError("delivered_at must be a valid timestamp or null", {
1069
+ path: filePath,
1070
+ value: delivered_at,
1071
+ });
1072
+ }
1073
+ return {
1074
+ ...raw,
1075
+ delivered_at,
1076
+ ...(raw.priority === null ? { priority: undefined } : {}),
1077
+ };
1078
+ }
1079
+ /**
1080
+ * HQ Sync sibling-twin grammar from `@indigoai-us/hq-cloud` `buildConflictPath`:
1081
+ * `<file>.json.conflict-<ISO-with-dashes>-<machine>.json`
1082
+ * (legacy twins; current engines park losers under `.hq/conflict-backups/`,
1083
+ * but merge-on-read still has to recover the ones already on disk).
1084
+ */
1085
+ export function isConflictSidecarName(recordBasename, name) {
1086
+ if (name === recordBasename || name.startsWith("."))
1087
+ return false;
1088
+ return name.startsWith(`${recordBasename}.conflict-`);
1089
+ }
1090
+ function sidecarPathsFor(recordPath, deps) {
1091
+ if (deps.conflictSidecarPathsFor) {
1092
+ return [...deps.conflictSidecarPathsFor(recordPath)];
1093
+ }
1094
+ const dir = path.dirname(recordPath);
1095
+ const base = path.basename(recordPath);
1096
+ if (!deps.existsSync(dir))
1097
+ return [];
1098
+ const names = deps.readdirSync(dir);
1099
+ const sidecars = [];
1100
+ for (const name of names) {
1101
+ if (typeof name !== "string")
1102
+ continue;
1103
+ if (!isConflictSidecarName(base, name))
1104
+ continue;
1105
+ sidecars.push(path.join(dir, name));
1106
+ }
1107
+ return sidecars;
1108
+ }
1109
+ function canonicalJson(value) {
1110
+ if (value === null || typeof value !== "object")
1111
+ return JSON.stringify(value);
1112
+ if (Array.isArray(value)) {
1113
+ return `[${value.map((item) => canonicalJson(item)).join(",")}]`;
1114
+ }
1115
+ const obj = value;
1116
+ const keys = Object.keys(obj).sort();
1117
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(obj[key])}`).join(",")}}`;
1118
+ }
1119
+ function historyTimestamp(entry) {
1120
+ if (!isPlainObject(entry))
1121
+ return "";
1122
+ if (typeof entry.at === "string")
1123
+ return entry.at;
1124
+ if (typeof entry.answered_at === "string")
1125
+ return entry.answered_at;
1126
+ return "";
1127
+ }
1128
+ /**
1129
+ * Attribution identity is the message that caused the re-point (spec §2).
1130
+ * Senior and routing entries have no named id; union is by canonical entry.
1131
+ */
1132
+ function attributionIdentity(entry) {
1133
+ if (typeof entry.message_id === "string" && entry.message_id.length > 0) {
1134
+ return `message_id:${entry.message_id}`;
1135
+ }
1136
+ return `entry:${canonicalJson(entry)}`;
1137
+ }
1138
+ function entryIdentity(entry) {
1139
+ return canonicalJson(entry);
1140
+ }
1141
+ function questionAnswerHistory(record) {
1142
+ return [
1143
+ ...(record.answer_history ?? []),
1144
+ ...(record.answer ? [record.answer] : []),
1145
+ ];
1146
+ }
1147
+ function unionHistory(lists, identity, preferred) {
1148
+ const map = new Map();
1149
+ for (const entry of preferred) {
1150
+ map.set(identity(entry), entry);
1151
+ }
1152
+ for (const list of lists) {
1153
+ for (const entry of list) {
1154
+ const id = identity(entry);
1155
+ if (!map.has(id))
1156
+ map.set(id, entry);
1157
+ }
1158
+ }
1159
+ const merged = [...map.values()].sort((a, b) => historyTimestamp(a).localeCompare(historyTimestamp(b)));
1160
+ if (merged.length <= HISTORY_CAP)
1161
+ return merged;
1162
+ return merged.slice(merged.length - HISTORY_CAP);
1163
+ }
1164
+ function higherVersionRecord(live, others) {
1165
+ let best = live;
1166
+ for (const other of others) {
1167
+ if (other.version > best.version)
1168
+ best = other;
1169
+ }
1170
+ return best;
1171
+ }
1172
+ function laneStoryIdentity(story) {
1173
+ return `${story.project_id}\u0000${story.story_id}`;
1174
+ }
1175
+ function mergeLaneStories(records, base) {
1176
+ const baseStories = laneStories(base);
1177
+ const merged = new Map();
1178
+ const baseOrder = [];
1179
+ for (const story of baseStories) {
1180
+ const key = laneStoryIdentity(story);
1181
+ if (!merged.has(key))
1182
+ baseOrder.push(key);
1183
+ merged.set(key, story);
1184
+ }
1185
+ for (const record of records) {
1186
+ if (record === base)
1187
+ continue;
1188
+ for (const story of laneStories(record)) {
1189
+ const key = laneStoryIdentity(story);
1190
+ const current = merged.get(key);
1191
+ if (!current || story.updated_at > current.updated_at) {
1192
+ merged.set(key, story);
1193
+ }
1194
+ }
1195
+ }
1196
+ const sideOnly = [...merged.keys()]
1197
+ .filter((key) => !baseOrder.includes(key))
1198
+ .sort();
1199
+ return [...baseOrder, ...sideOnly]
1200
+ .map((key) => merged.get(key))
1201
+ .filter((story) => story !== undefined);
1202
+ }
1203
+ export function mergeLaneRecords(live, sidecars) {
1204
+ if (sidecars.length === 0)
1205
+ return live;
1206
+ const all = [live, ...sidecars];
1207
+ const base = higherVersionRecord(live, sidecars);
1208
+ return {
1209
+ ...base,
1210
+ senior_history: unionHistory(all.map((record) => record.senior_history), entryIdentity, base.senior_history),
1211
+ attribution_history: unionHistory(all.map((record) => record.attribution_history), attributionIdentity, base.attribution_history),
1212
+ ...(all.some((record) => record.account_history !== undefined)
1213
+ ? {
1214
+ account_history: unionHistory(all.map((record) => record.account_history ?? []), entryIdentity, base.account_history ?? []),
1215
+ }
1216
+ : {}),
1217
+ ...(all.some((record) => record.worker_profile_repin_history !== undefined)
1218
+ ? {
1219
+ worker_profile_repin_history: unionHistory(all.map((record) => record.worker_profile_repin_history ?? []), entryIdentity, base.worker_profile_repin_history ?? []),
1220
+ }
1221
+ : {}),
1222
+ ...(all.some((record) => record.registry_worker_approval_history !== undefined)
1223
+ ? {
1224
+ registry_worker_approval_history: unionHistory(all.map((record) => record.registry_worker_approval_history ?? []), entryIdentity, base.registry_worker_approval_history ?? []),
1225
+ }
1226
+ : {}),
1227
+ ...(all.some((record) => record.failed_resume_history !== undefined)
1228
+ ? {
1229
+ failed_resume_history: unionHistory(all.map((record) => record.failed_resume_history ?? []), entryIdentity, base.failed_resume_history ?? []),
1230
+ }
1231
+ : {}),
1232
+ ...(all.some((record) => record.resume_history !== undefined)
1233
+ ? {
1234
+ resume_history: unionHistory(all.map((record) => record.resume_history ?? []), entryIdentity, base.resume_history ?? []),
1235
+ }
1236
+ : {}),
1237
+ ...(all.some((record) => record.settings_history !== undefined)
1238
+ ? {
1239
+ settings_history: unionHistory(all.map((record) => record.settings_history ?? []), entryIdentity, base.settings_history ?? []),
1240
+ }
1241
+ : {}),
1242
+ ...(all.some((record) => record.stop_history !== undefined)
1243
+ ? {
1244
+ stop_history: unionHistory(all.map((record) => record.stop_history ?? []), entryIdentity, base.stop_history ?? []),
1245
+ }
1246
+ : {}),
1247
+ stories: mergeLaneStories(all, base),
1248
+ };
1249
+ }
1250
+ export function mergeQuestionRecords(live, sidecars) {
1251
+ if (sidecars.length === 0)
1252
+ return live;
1253
+ const all = [live, ...sidecars];
1254
+ const base = higherVersionRecord(live, sidecars);
1255
+ const deliveredAt = all
1256
+ .map((record) => record.delivered_at)
1257
+ .filter((value) => typeof value === "string" && Number.isFinite(Date.parse(value)))
1258
+ .sort((a, b) => Date.parse(a) - Date.parse(b))[0] ?? null;
1259
+ return {
1260
+ ...base,
1261
+ delivered_at: deliveredAt,
1262
+ answer_history: unionHistory(all.map(questionAnswerHistory), entryIdentity, questionAnswerHistory(base)),
1263
+ routing_history: unionHistory(all.map((record) => record.routing_history), entryIdentity, base.routing_history),
1264
+ };
1265
+ }
1266
+ function loadSidecarRecords(recordPath, parse, deps) {
1267
+ const paths = sidecarPathsFor(recordPath, deps);
1268
+ const records = [];
1269
+ for (const sidecarPath of paths) {
1270
+ try {
1271
+ const raw = readJsonFile(sidecarPath, deps);
1272
+ if (raw === null)
1273
+ continue;
1274
+ records.push(parse(raw, sidecarPath));
1275
+ }
1276
+ catch (err) {
1277
+ process.stderr.write(`lanes store: skipping unreadable conflict sidecar ${sidecarPath}: ${err instanceof Error ? err.message : String(err)}\n`);
1278
+ }
1279
+ }
1280
+ return records;
1281
+ }
1282
+ function readMergedRecord(filePath, parse, merge, deps) {
1283
+ const raw = readJsonFile(filePath, deps);
1284
+ if (raw === null)
1285
+ return null;
1286
+ const live = parse(raw, filePath);
1287
+ const sidecars = loadSidecarRecords(filePath, parse, deps);
1288
+ if (sidecars.length === 0)
1289
+ return live;
1290
+ return merge(live, sidecars);
1291
+ }
1292
+ export function tryReadLane(hqRoot, laneId, deps = defaultStoreDeps()) {
1293
+ const filePath = laneRecordPath(hqRoot, laneId);
1294
+ return readMergedRecord(filePath, parseLaneRecord, mergeLaneRecords, deps);
1295
+ }
1296
+ export function readLane(hqRoot, laneId, deps = defaultStoreDeps()) {
1297
+ const record = tryReadLane(hqRoot, laneId, deps);
1298
+ if (!record)
1299
+ throw new LaneNotFoundError("lane", laneId);
1300
+ return record;
1301
+ }
1302
+ /** Reads all lanes, indexing sidecars once and sorting by creation time then id. */
1303
+ export function readAllLanes(hqRoot, deps = defaultStoreDeps()) {
1304
+ const laneIds = listLaneIds(hqRoot, deps);
1305
+ if (laneIds.length === 0)
1306
+ return [];
1307
+ const laneDir = path.join(lanesStoreRoot(hqRoot), LANE_RECORDS_DIR);
1308
+ let names;
1309
+ try {
1310
+ names = deps.readdirSync(laneDir);
1311
+ }
1312
+ catch (err) {
1313
+ if (err.code === "ENOENT")
1314
+ names = [];
1315
+ else
1316
+ throw err;
1317
+ }
1318
+ const sidecarsByRecord = new Map();
1319
+ for (const name of names) {
1320
+ if (typeof name !== "string")
1321
+ continue;
1322
+ const marker = name.indexOf(".json.conflict-");
1323
+ if (marker < 0 || name.startsWith("."))
1324
+ continue;
1325
+ const recordBasename = name.slice(0, marker + ".json".length);
1326
+ if (!isConflictSidecarName(recordBasename, name))
1327
+ continue;
1328
+ const sidecars = sidecarsByRecord.get(recordBasename) ?? [];
1329
+ sidecars.push(path.join(laneDir, name));
1330
+ sidecarsByRecord.set(recordBasename, sidecars);
1331
+ }
1332
+ const indexedDeps = {
1333
+ ...deps,
1334
+ conflictSidecarPathsFor: (recordPath) => sidecarsByRecord.get(path.basename(recordPath)) ?? [],
1335
+ };
1336
+ const records = [];
1337
+ for (const laneId of laneIds) {
1338
+ try {
1339
+ records.push(readLane(hqRoot, laneId, indexedDeps));
1340
+ }
1341
+ catch (err) {
1342
+ if (!(err instanceof LaneSchemaError))
1343
+ throw err;
1344
+ const filePath = laneRecordPath(hqRoot, laneId);
1345
+ const raw = readJsonFile(filePath, indexedDeps);
1346
+ const host = raw !== null && typeof raw === "object" && !Array.isArray(raw)
1347
+ ? raw.host
1348
+ : undefined;
1349
+ const hostRecord = host !== null && typeof host === "object" && !Array.isArray(host)
1350
+ ? host
1351
+ : undefined;
1352
+ const outpostId = hostRecord?.kind === "outpost" &&
1353
+ typeof hostRecord.id === "string" && hostRecord.id.trim() !== ""
1354
+ ? hostRecord.id
1355
+ : undefined;
1356
+ const identity = indexedDeps.outpostIdentity();
1357
+ const isRemoteMirror = outpostId !== undefined && (identity.kind === "not_outpost" ||
1358
+ (identity.kind === "id" && identity.id !== outpostId));
1359
+ if (!isRemoteMirror)
1360
+ throw err;
1361
+ const field = typeof err.details.field === "string" ? err.details.field : "unknown_field";
1362
+ process.stderr.write(`lanes store: skipping malformed mirrored lane ${laneId} field ${field}: ${err.message}\n`);
1363
+ }
1364
+ }
1365
+ return records.sort((a, b) => Date.parse(a.created_at) - Date.parse(b.created_at) ||
1366
+ a.lane_id.localeCompare(b.lane_id));
1367
+ }
1368
+ export function tryReadQuestion(hqRoot, questionId, deps = defaultStoreDeps()) {
1369
+ const filePath = questionRecordPath(hqRoot, questionId);
1370
+ return readMergedRecord(filePath, parseQuestionRecord, mergeQuestionRecords, deps);
1371
+ }
1372
+ export function readQuestion(hqRoot, questionId, deps = defaultStoreDeps()) {
1373
+ const record = tryReadQuestion(hqRoot, questionId, deps);
1374
+ if (!record)
1375
+ throw new LaneNotFoundError("question", questionId);
1376
+ return record;
1377
+ }
1378
+ /** Semver precedence includes prerelease identifiers (for example, rc.2 > rc.1). */
1379
+ export function isLaneStoreVersionNewer(storedVersion, runningVersion) {
1380
+ if (!semver.valid(storedVersion)) {
1381
+ throw new LanesError("lane_store_version_invalid", "Lane store writer version is not valid semver", {
1382
+ stored_version: storedVersion,
1383
+ });
1384
+ }
1385
+ if (!semver.valid(runningVersion)) {
1386
+ throw new LanesError("lane_store_version_invalid", "Running hq-cli version is not valid semver", {
1387
+ running_version: runningVersion,
1388
+ });
1389
+ }
1390
+ return semver.gt(storedVersion, runningVersion);
1391
+ }
1392
+ const OLDER_LANE_STORE_WRITE_OVERRIDE = "HQ_LANES_ALLOW_OLDER_WRITE";
1393
+ export const LANE_STORE_UPGRADE_COMMAND = "npm install -g @indigoai-us/hq-cli@latest";
1394
+ const warnedBackgroundWriterLaneIds = new Set();
1395
+ function assertLaneStoreWriteAllowed(lane, laneId, writer) {
1396
+ const storedVersion = lane.written_by_version;
1397
+ if (storedVersion === undefined || !isLaneStoreVersionNewer(storedVersion, CLI_VERSION))
1398
+ return;
1399
+ const warning = `Lane ${laneId} was last written by hq-cli ${storedVersion}, newer than running hq-cli ${CLI_VERSION}. Upgrade with \`${LANE_STORE_UPGRADE_COMMAND}\` before writing.`;
1400
+ if (writer === "command" || writer === "creator") {
1401
+ if (process.env[OLDER_LANE_STORE_WRITE_OVERRIDE] === "1") {
1402
+ console.warn(`${warning} Proceeding because ${OLDER_LANE_STORE_WRITE_OVERRIDE}=1 was set for this command.`);
1403
+ return;
1404
+ }
1405
+ throw new LanesError("lane_store_newer_cli", `${warning} For a one-command override, set ${OLDER_LANE_STORE_WRITE_OVERRIDE}=1.`, {
1406
+ lane_id: laneId,
1407
+ stored_version: storedVersion,
1408
+ running_version: CLI_VERSION,
1409
+ upgrade_command: LANE_STORE_UPGRADE_COMMAND,
1410
+ override: `${OLDER_LANE_STORE_WRITE_OVERRIDE}=1`,
1411
+ });
1412
+ }
1413
+ if (!warnedBackgroundWriterLaneIds.has(laneId)) {
1414
+ warnedBackgroundWriterLaneIds.add(laneId);
1415
+ console.warn(`${warning} Continuing background ${writer} writes and preserving the newer stamp.`);
1416
+ }
1417
+ }
1418
+ function newestLaneStoreVersion(storedVersion) {
1419
+ if (storedVersion !== undefined && isLaneStoreVersionNewer(storedVersion, CLI_VERSION)) {
1420
+ return storedVersion;
1421
+ }
1422
+ return CLI_VERSION;
1423
+ }
1424
+ function recordsEquivalentAsideFromClock(current, updated) {
1425
+ if (updated === current)
1426
+ return true;
1427
+ const strip = (record) => {
1428
+ const copy = { ...record };
1429
+ delete copy.version;
1430
+ delete copy.updated_at;
1431
+ return copy;
1432
+ };
1433
+ return JSON.stringify(strip(current)) === JSON.stringify(strip(updated));
1434
+ }
1435
+ function casWrite(filePath, expectedVersion, parse, merge, updater, deps, options = {}) {
1436
+ return withRecordLock(filePath, deps, () => {
1437
+ const current = readMergedRecord(filePath, parse, merge, deps);
1438
+ if (current === null) {
1439
+ throw new LaneSchemaError(`Record disappeared under lock: ${filePath}`, {
1440
+ path: filePath,
1441
+ });
1442
+ }
1443
+ if (current.version !== expectedVersion) {
1444
+ throw new LaneVersionConflict({
1445
+ path: filePath,
1446
+ expectedVersion,
1447
+ actualVersion: current.version,
1448
+ });
1449
+ }
1450
+ const updated = updater(current);
1451
+ if (recordsEquivalentAsideFromClock(current, updated)) {
1452
+ return current;
1453
+ }
1454
+ options.beforeWrite?.(current);
1455
+ const next = {
1456
+ ...current,
1457
+ ...updated,
1458
+ ...options.stamp?.(current),
1459
+ version: current.version + 1,
1460
+ updated_at: deps.now().toISOString(),
1461
+ };
1462
+ atomicWriteJson(filePath, next, deps);
1463
+ return next;
1464
+ });
1465
+ }
1466
+ export function createLane(hqRoot, init, deps = defaultStoreDeps()) {
1467
+ const now = deps.now().toISOString();
1468
+ const lane_id = init.lane_id ?? mintLaneId(deps);
1469
+ const filePath = laneRecordPath(hqRoot, lane_id);
1470
+ const record = {
1471
+ ...init,
1472
+ written_by_version: CLI_VERSION,
1473
+ hire_grant: init.hire_grant ?? 0,
1474
+ schema_version: init.schema_version ?? LANE_SCHEMA_VERSION,
1475
+ lane_id,
1476
+ version: 1,
1477
+ created_at: init.created_at ?? now,
1478
+ updated_at: init.updated_at ?? now,
1479
+ ...(init.state === "queued"
1480
+ ? { queued_at: init.queued_at ?? init.created_at ?? now }
1481
+ : {}),
1482
+ senior_history: init.senior_history ?? [],
1483
+ attribution_history: init.attribution_history ?? [],
1484
+ };
1485
+ parseLaneRecord(record, filePath);
1486
+ const created = withRecordLock(filePath, deps, () => {
1487
+ if (deps.existsSync(filePath)) {
1488
+ throw new LanesError("lane_exists", `Lane ${lane_id} already exists`, { lane_id });
1489
+ }
1490
+ atomicWriteJson(filePath, record, deps);
1491
+ return record;
1492
+ });
1493
+ return syncStoryLedgerForLane(hqRoot, created, deps);
1494
+ }
1495
+ /** Hierarchy lock: separate from record writes so callers can CAS-write while holding it. */
1496
+ export function withLaneHireLocks(hqRoot, laneIds, fn, deps = defaultStoreDeps()) {
1497
+ const uniqueIds = [...new Set(laneIds)].sort();
1498
+ const acquire = (index) => {
1499
+ const laneId = uniqueIds[index];
1500
+ if (laneId === undefined)
1501
+ return fn();
1502
+ const lockPath = path.join(lanesStoreRoot(hqRoot), "hire-locks", `${laneId}.json`);
1503
+ return withRecordLock(lockPath, deps, () => acquire(index + 1));
1504
+ };
1505
+ return acquire(0);
1506
+ }
1507
+ /** Value equality over JSON-shaped record fields; the clone breaks reference identity. */
1508
+ function fieldUnchanged(before, after) {
1509
+ if (Object.is(before, after))
1510
+ return true;
1511
+ if (before === undefined || after === undefined)
1512
+ return false;
1513
+ return JSON.stringify(before) === JSON.stringify(after);
1514
+ }
1515
+ export function updateLane(hqRoot, laneId, expectedVersion, writer, updater, deps = defaultStoreDeps()) {
1516
+ if (!LANE_WRITERS.includes(writer)) {
1517
+ throw new LanesError("lane_writer_unknown", `Unknown lane writer ${String(writer)}`, { writer });
1518
+ }
1519
+ let before;
1520
+ const updated = casWrite(laneRecordPath(hqRoot, laneId), expectedVersion, parseLaneRecord, mergeLaneRecords, (current) => {
1521
+ before = current;
1522
+ // `current` is the pre-update snapshot and stays untouched: the updater
1523
+ // receives a deep clone, so mutating its argument in place cannot reach
1524
+ // the record the ownership check compares against.
1525
+ const updated = updater(structuredClone(current));
1526
+ for (const key of Object.keys(updated)) {
1527
+ if (key === "version" || key === "updated_at" || fieldUnchanged(current[key], updated[key]))
1528
+ continue;
1529
+ const allowedWriters = LANE_FIELD_WRITERS[key];
1530
+ // Unknown forward-version fields are preserved, never assigned an
1531
+ // ownership rule by a v1 reader.
1532
+ if (allowedWriters && !allowedWriters.includes(writer)) {
1533
+ throw new LanesError("lane_writer_unauthorized", `Writer ${writer} cannot write lane field ${key}`, { writer, field: key });
1534
+ }
1535
+ }
1536
+ return updated;
1537
+ }, deps, {
1538
+ beforeWrite: (current) => assertLaneStoreWriteAllowed(current, laneId, writer),
1539
+ stamp: (current) => ({ written_by_version: newestLaneStoreVersion(current.written_by_version) }),
1540
+ });
1541
+ if (laneStoryLedgerEnabled() && before && laneLedgerRelevantChange(before, updated)) {
1542
+ return syncStoryLedgerForLane(hqRoot, updated, deps);
1543
+ }
1544
+ return updated;
1545
+ }
1546
+ function laneLedgerRelevantChange(before, after) {
1547
+ return before.state !== after.state || before.project_id !== after.project_id ||
1548
+ before.story_id !== after.story_id || before.no_story_reason !== after.no_story_reason ||
1549
+ JSON.stringify(before.pending_question_ids) !== JSON.stringify(after.pending_question_ids) ||
1550
+ JSON.stringify(before.stories) !== JSON.stringify(after.stories) ||
1551
+ JSON.stringify(before.last_envelope) !== JSON.stringify(after.last_envelope);
1552
+ }
1553
+ function syncStoryLedgerForLane(hqRoot, lane, deps) {
1554
+ if (!laneStoryLedgerEnabled())
1555
+ return lane;
1556
+ try {
1557
+ const questionRefs = [];
1558
+ for (const questionId of lane.pending_question_ids ?? []) {
1559
+ const question = readQuestion(hqRoot, questionId, deps);
1560
+ const sameCompany = question.company === null
1561
+ ? lane.company === null
1562
+ : lane.company !== null &&
1563
+ question.company.uid === lane.company.uid &&
1564
+ question.company.slug === lane.company.slug;
1565
+ if (question.lane_id !== lane.lane_id || !sameCompany) {
1566
+ throw new LanesError("story_ledger_question_mismatch", `Pending question ${questionId} does not belong to lane ${lane.lane_id}`, {
1567
+ lane_id: lane.lane_id,
1568
+ question_id: questionId,
1569
+ question_lane_id: question.lane_id,
1570
+ company: question.company?.slug ?? null,
1571
+ });
1572
+ }
1573
+ if (question.status === "pending") {
1574
+ questionRefs.push({
1575
+ question_id: question.question_id,
1576
+ project_id: question.project_id,
1577
+ story_id: question.story_id,
1578
+ });
1579
+ }
1580
+ }
1581
+ syncLaneToProjectStoryLedger(hqRoot, lane, questionRefs);
1582
+ if (lane.ledger_sync_error !== undefined) {
1583
+ retryUpdateLane(hqRoot, lane.lane_id, "story-ledger", (current) => current.ledger_sync_error === undefined
1584
+ ? current
1585
+ : { ...current, ledger_sync_error: undefined }, deps);
1586
+ }
1587
+ return readLane(hqRoot, lane.lane_id, deps);
1588
+ }
1589
+ catch (error) {
1590
+ const message = (error instanceof Error ? error.message : String(error)).slice(0, 1000) || "Story ledger synchronization failed";
1591
+ try {
1592
+ retryUpdateLane(hqRoot, lane.lane_id, "story-ledger", (current) => current.ledger_sync_error === message
1593
+ ? current
1594
+ : { ...current, ledger_sync_error: message }, deps);
1595
+ return readLane(hqRoot, lane.lane_id, deps);
1596
+ }
1597
+ catch (recordError) {
1598
+ throw new LanesError("story_ledger_sync_error_unrecorded", "Story ledger synchronization failed and the failure could not be recorded on lane " + lane.lane_id, { lane_id: lane.lane_id, cause: recordError instanceof Error ? recordError.message : String(recordError) });
1599
+ }
1600
+ }
1601
+ }
1602
+ /**
1603
+ * Replace the primary copy with a terminal snapshot returned by the Outpost
1604
+ * that owns the lane. The owner is authoritative on equal versions; a newer
1605
+ * primary version is a conflict and must not be overwritten.
1606
+ */
1607
+ export function syncLaneRecordFromOwner(hqRoot, laneId, outpostId, rawOwnerLane, deps = defaultStoreDeps(), options = {}) {
1608
+ let ownerLane;
1609
+ try {
1610
+ ownerLane = parseLaneRecord(rawOwnerLane);
1611
+ }
1612
+ catch (err) {
1613
+ throw new LanesError("outpost_lane_sync_invalid", `Outpost ${outpostId} returned an invalid lane snapshot for ${laneId}`, {
1614
+ lane_id: laneId,
1615
+ outpost_id: outpostId,
1616
+ cause: err instanceof Error ? err.message : String(err),
1617
+ });
1618
+ }
1619
+ if (ownerLane.lane_id !== laneId ||
1620
+ ownerLane.host.kind !== "outpost" ||
1621
+ ownerLane.host.id !== outpostId ||
1622
+ (!options.allowNonTerminal && !isTerminalLaneState(ownerLane.state))) {
1623
+ throw new LanesError("outpost_lane_sync_invalid", `Outpost ${outpostId} did not return an owned lane snapshot for lane ${laneId}`, {
1624
+ lane_id: laneId,
1625
+ outpost_id: outpostId,
1626
+ owner_lane_id: ownerLane.lane_id,
1627
+ owner_host: ownerLane.host,
1628
+ owner_state: ownerLane.state,
1629
+ require_terminal: !options.allowNonTerminal,
1630
+ });
1631
+ }
1632
+ const filePath = laneRecordPath(hqRoot, laneId);
1633
+ const synced = withRecordLock(filePath, deps, () => {
1634
+ const current = readMergedRecord(filePath, parseLaneRecord, mergeLaneRecords, deps);
1635
+ if (current === null) {
1636
+ throw new LaneSchemaError(`Record disappeared under lock: ${filePath}`, {
1637
+ path: filePath,
1638
+ });
1639
+ }
1640
+ if (current.lane_id !== laneId ||
1641
+ current.host.kind !== "outpost" ||
1642
+ current.host.id !== outpostId) {
1643
+ throw new LanesError("outpost_lane_sync_conflict", `Primary lane ${laneId} is no longer owned by Outpost ${outpostId}`, {
1644
+ lane_id: laneId,
1645
+ outpost_id: outpostId,
1646
+ current_lane_id: current.lane_id,
1647
+ current_host: current.host,
1648
+ });
1649
+ }
1650
+ if (ownerLane.version < current.version) {
1651
+ throw new LanesError("outpost_lane_sync_conflict", `Outpost ${outpostId} returned lane ${laneId} at version ${ownerLane.version}, behind primary version ${current.version}`, {
1652
+ lane_id: laneId,
1653
+ outpost_id: outpostId,
1654
+ owner_version: ownerLane.version,
1655
+ primary_version: current.version,
1656
+ });
1657
+ }
1658
+ const ownerSnapshot = ownerLane.outpost_command_id === undefined &&
1659
+ current.outpost_command_id !== undefined
1660
+ ? { ...ownerLane, outpost_command_id: current.outpost_command_id }
1661
+ : ownerLane;
1662
+ const merged = mergeLaneRecords(ownerSnapshot, [current]);
1663
+ const synced = {
1664
+ ...merged,
1665
+ written_by_version: newestLaneStoreVersion(current.written_by_version),
1666
+ owner_written_by_version: ownerLane.written_by_version,
1667
+ };
1668
+ parseLaneRecord(synced, filePath);
1669
+ atomicWriteJson(filePath, synced, deps);
1670
+ return synced;
1671
+ });
1672
+ return syncStoryLedgerForLane(hqRoot, synced, deps);
1673
+ }
1674
+ /** Compare-and-set with conflict retry. Callers that race a concurrent writer re-read. */
1675
+ export function retryUpdateLane(hqRoot, laneId, writer, updater, deps = defaultStoreDeps(), attempts = 5) {
1676
+ let last;
1677
+ for (let i = 0; i < attempts; i += 1) {
1678
+ try {
1679
+ const current = readLane(hqRoot, laneId, deps);
1680
+ return updateLane(hqRoot, laneId, current.version, writer, updater, deps);
1681
+ }
1682
+ catch (err) {
1683
+ last = err;
1684
+ if (!isLaneVersionConflict(err) || i === attempts - 1)
1685
+ throw err;
1686
+ }
1687
+ }
1688
+ throw last;
1689
+ }
1690
+ /** Compare-and-set with conflict retry for question records (spec §6.2). */
1691
+ export function retryUpdateQuestion(hqRoot, questionId, updater, deps = defaultStoreDeps(), attempts = 5) {
1692
+ let last;
1693
+ for (let i = 0; i < attempts; i += 1) {
1694
+ try {
1695
+ const current = readQuestion(hqRoot, questionId, deps);
1696
+ return updateQuestion(hqRoot, questionId, current.version, updater, deps);
1697
+ }
1698
+ catch (err) {
1699
+ last = err;
1700
+ if (!isLaneVersionConflict(err) || i === attempts - 1)
1701
+ throw err;
1702
+ }
1703
+ }
1704
+ throw last;
1705
+ }
1706
+ export function appendLaneSeniorHistory(hqRoot, laneId, expectedVersion, entry, deps = defaultStoreDeps()) {
1707
+ return updateLane(hqRoot, laneId, expectedVersion, "command", (current) => ({
1708
+ ...current,
1709
+ senior_history: appendCappedHistory(current.senior_history, entry),
1710
+ }), deps);
1711
+ }
1712
+ export function appendLaneAttribution(hqRoot, laneId, expectedVersion, entry, deps = defaultStoreDeps()) {
1713
+ return updateLane(hqRoot, laneId, expectedVersion, "command", (current) => ({
1714
+ ...current,
1715
+ attribution_history: appendCappedHistory(current.attribution_history, entry),
1716
+ }), deps);
1717
+ }
1718
+ function syncPendingMarker(hqRoot, question, deps) {
1719
+ const marker = pendingMarkerPath(hqRoot, question.question_id);
1720
+ if (question.status === "pending") {
1721
+ ensureDir(path.dirname(marker), deps);
1722
+ if (!deps.existsSync(marker)) {
1723
+ deps.writeFileSync(marker, "", { encoding: "utf8" });
1724
+ }
1725
+ return;
1726
+ }
1727
+ try {
1728
+ deps.unlinkSync(marker);
1729
+ }
1730
+ catch (err) {
1731
+ const code = err.code;
1732
+ if (code !== "ENOENT")
1733
+ throw err;
1734
+ }
1735
+ }
1736
+ export function createQuestion(hqRoot, init, deps = defaultStoreDeps()) {
1737
+ const question_id = init.question_id ?? mintQuestionId(deps);
1738
+ const filePath = questionRecordPath(hqRoot, question_id);
1739
+ const record = {
1740
+ ...init,
1741
+ schema_version: init.schema_version ?? QUESTION_SCHEMA_VERSION,
1742
+ question_id,
1743
+ delivered_at: init.delivered_at ?? null,
1744
+ version: 1,
1745
+ routing_history: init.routing_history ?? [],
1746
+ };
1747
+ parseQuestionRecord(record, filePath);
1748
+ const created = withRecordLock(filePath, deps, () => {
1749
+ if (deps.existsSync(filePath)) {
1750
+ throw new LanesError("question_exists", `Question ${question_id} already exists`, { question_id });
1751
+ }
1752
+ atomicWriteJson(filePath, record, deps);
1753
+ syncPendingMarker(hqRoot, record, deps);
1754
+ return record;
1755
+ });
1756
+ syncLaneQuestionReference(hqRoot, created, deps);
1757
+ return created;
1758
+ }
1759
+ export function updateQuestion(hqRoot, questionId, expectedVersion, updater, deps = defaultStoreDeps()) {
1760
+ const next = casWrite(questionRecordPath(hqRoot, questionId), expectedVersion, parseQuestionRecord, mergeQuestionRecords, updater, deps);
1761
+ syncPendingMarker(hqRoot, next, deps);
1762
+ syncLaneQuestionReference(hqRoot, next, deps);
1763
+ return next;
1764
+ }
1765
+ function syncLaneQuestionReference(hqRoot, question, deps) {
1766
+ if (!laneStoryLedgerEnabled())
1767
+ return;
1768
+ const lane = tryReadLane(hqRoot, question.lane_id, deps);
1769
+ if (!lane || question.company?.slug !== lane.company?.slug || question.company?.uid !== lane.company?.uid)
1770
+ return;
1771
+ retryUpdateLane(hqRoot, lane.lane_id, "story-ledger", (current) => {
1772
+ if (question.company?.slug !== current.company?.slug || question.company?.uid !== current.company?.uid)
1773
+ return current;
1774
+ const ids = new Set(current.pending_question_ids ?? []);
1775
+ const hadQuestion = ids.has(question.question_id);
1776
+ if (question.status === "pending")
1777
+ ids.add(question.question_id);
1778
+ else
1779
+ ids.delete(question.question_id);
1780
+ if (hadQuestion === (question.status === "pending"))
1781
+ return current;
1782
+ return { ...current, pending_question_ids: [...ids].sort() };
1783
+ }, deps);
1784
+ }
1785
+ export function appendQuestionRouting(hqRoot, questionId, expectedVersion, entry, deps = defaultStoreDeps()) {
1786
+ return updateQuestion(hqRoot, questionId, expectedVersion, (current) => ({
1787
+ ...current,
1788
+ routing_history: appendCappedHistory(current.routing_history, entry),
1789
+ }), deps);
1790
+ }
1791
+ function jsonRecordIds(names) {
1792
+ return names
1793
+ .filter((name) => typeof name === "string" &&
1794
+ name.endsWith(".json") &&
1795
+ !name.startsWith(".") &&
1796
+ !name.includes(".conflict-"))
1797
+ .map((name) => name.slice(0, -".json".length));
1798
+ }
1799
+ /**
1800
+ * Absent directory → empty list. A path that exists but cannot be listed
1801
+ * (ENOTDIR, EACCES, …) is unknown, not empty — throw `store_unreadable`.
1802
+ */
1803
+ function listRecordIds(dir, label, deps) {
1804
+ let names;
1805
+ try {
1806
+ names = deps.readdirSync(dir);
1807
+ }
1808
+ catch (err) {
1809
+ const code = err.code;
1810
+ if (code === "ENOENT")
1811
+ return [];
1812
+ throw new LanesError("store_unreadable", `Failed to read ${label} directory ${dir}: ${err instanceof Error ? err.message : String(err)}`, { path: dir });
1813
+ }
1814
+ return jsonRecordIds(names);
1815
+ }
1816
+ export function listLaneIds(hqRoot, deps = defaultStoreDeps()) {
1817
+ return listRecordIds(path.join(lanesStoreRoot(hqRoot), LANE_RECORDS_DIR), "lane", deps);
1818
+ }
1819
+ export function listQuestionIds(hqRoot, deps = defaultStoreDeps()) {
1820
+ return listRecordIds(path.join(lanesStoreRoot(hqRoot), QUESTION_RECORDS_DIR), "question", deps);
1821
+ }
1822
+ //# sourceMappingURL=store.js.map