opensquid 0.5.441 → 0.5.449

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 (391) hide show
  1. package/README.md +1 -0
  2. package/dist/functions/arm_scope.d.ts +27 -0
  3. package/dist/functions/arm_scope.d.ts.map +1 -0
  4. package/dist/functions/arm_scope.js +52 -0
  5. package/dist/functions/arm_scope.js.map +1 -0
  6. package/dist/functions/index.d.ts +1 -0
  7. package/dist/functions/index.d.ts.map +1 -1
  8. package/dist/functions/index.js +1 -0
  9. package/dist/functions/index.js.map +1 -1
  10. package/dist/functions/recall_pre_inject.d.ts.map +1 -1
  11. package/dist/functions/recall_pre_inject.js +12 -0
  12. package/dist/functions/recall_pre_inject.js.map +1 -1
  13. package/dist/rag/store_git.d.ts +23 -0
  14. package/dist/rag/store_git.d.ts.map +1 -0
  15. package/dist/rag/store_git.js +57 -0
  16. package/dist/rag/store_git.js.map +1 -0
  17. package/dist/runtime/bootstrap.d.ts.map +1 -1
  18. package/dist/runtime/bootstrap.js +2 -0
  19. package/dist/runtime/bootstrap.js.map +1 -1
  20. package/dist/runtime/handoff/render.d.ts +5 -4
  21. package/dist/runtime/handoff/render.d.ts.map +1 -1
  22. package/dist/runtime/handoff/render.js +7 -7
  23. package/dist/runtime/handoff/render.js.map +1 -1
  24. package/dist/runtime/hooks/active_task_mirror.js +0 -0
  25. package/dist/runtime/hooks/apply_patch.js +0 -0
  26. package/dist/runtime/hooks/dispatch.js +0 -0
  27. package/dist/runtime/hooks/hook_output.js +0 -0
  28. package/dist/runtime/hooks/memory_reconcile.js +0 -0
  29. package/dist/runtime/hooks/new_project_detect.js +0 -0
  30. package/dist/runtime/hooks/profession_resolver.js +0 -0
  31. package/dist/runtime/hooks/scope_intent.js +0 -0
  32. package/dist/runtime/hooks/session-end.js +11 -0
  33. package/dist/runtime/hooks/session-end.js.map +1 -1
  34. package/dist/runtime/hooks/session_id.js +0 -0
  35. package/dist/runtime/hooks/session_liveness.js +0 -0
  36. package/dist/runtime/hooks/stop_drive.js +0 -0
  37. package/dist/runtime/hooks/stop_stream.js +0 -0
  38. package/dist/runtime/hooks/subagent_guard.js +0 -0
  39. package/dist/runtime/hooks/transcript.js +0 -0
  40. package/dist/runtime/hooks/transcript_tasks.js +0 -0
  41. package/dist/runtime/ralph/orchestrator.d.ts.map +1 -1
  42. package/dist/runtime/ralph/orchestrator.js +2 -1
  43. package/dist/runtime/ralph/orchestrator.js.map +1 -1
  44. package/dist/setup/cli/limits_state.d.ts.map +1 -1
  45. package/dist/setup/cli/limits_state.js +6 -40
  46. package/dist/setup/cli/limits_state.js.map +1 -1
  47. package/dist/setup/cli/pack_walk.d.ts +32 -0
  48. package/dist/setup/cli/pack_walk.d.ts.map +1 -0
  49. package/dist/setup/cli/pack_walk.js +76 -0
  50. package/dist/setup/cli/pack_walk.js.map +1 -0
  51. package/dist/setup/cli/permissions_state.d.ts.map +1 -1
  52. package/dist/setup/cli/permissions_state.js +6 -37
  53. package/dist/setup/cli/permissions_state.js.map +1 -1
  54. package/dist/setup/cli/triggers_state.d.ts.map +1 -1
  55. package/dist/setup/cli/triggers_state.js +3 -29
  56. package/dist/setup/cli/triggers_state.js.map +1 -1
  57. package/dist/workgraph/events.d.ts.map +1 -1
  58. package/dist/workgraph/events.js +10 -0
  59. package/dist/workgraph/events.js.map +1 -1
  60. package/dist/workgraph/store.d.ts.map +1 -1
  61. package/dist/workgraph/store.js +5 -0
  62. package/dist/workgraph/store.js.map +1 -1
  63. package/dist/workgraph/types.d.ts +2 -1
  64. package/dist/workgraph/types.d.ts.map +1 -1
  65. package/docs/ARCHITECTURE.md +268 -0
  66. package/docs/pack-runtime.md +15 -12
  67. package/docs/skill-grammar-guide.md +4 -4
  68. package/package.json +5 -3
  69. package/packs/builtin/coding-flow/skills/entry-and-handoffs/skill.yaml +13 -17
  70. package/dist/anti-drift/evaluator.d.ts +0 -88
  71. package/dist/anti-drift/evaluator.d.ts.map +0 -1
  72. package/dist/anti-drift/evaluator.js +0 -417
  73. package/dist/anti-drift/evaluator.js.map +0 -1
  74. package/dist/anti-drift/evaluator.test.js +0 -78
  75. package/dist/anti-drift/rules.d.ts +0 -80
  76. package/dist/anti-drift/rules.d.ts.map +0 -1
  77. package/dist/anti-drift/rules.js +0 -368
  78. package/dist/anti-drift/rules.js.map +0 -1
  79. package/dist/anti-drift/rules.test.js +0 -213
  80. package/dist/anti-drift/state.d.ts +0 -107
  81. package/dist/anti-drift/state.d.ts.map +0 -1
  82. package/dist/anti-drift/state.js +0 -177
  83. package/dist/anti-drift/state.js.map +0 -1
  84. package/dist/anti-drift/state.test.js +0 -120
  85. package/dist/chat/adapters/discord.d.ts +0 -41
  86. package/dist/chat/adapters/discord.d.ts.map +0 -1
  87. package/dist/chat/adapters/discord.js +0 -176
  88. package/dist/chat/adapters/discord.js.map +0 -1
  89. package/dist/chat/adapters/discord.test.js +0 -25
  90. package/dist/chat/adapters/slack.d.ts +0 -43
  91. package/dist/chat/adapters/slack.d.ts.map +0 -1
  92. package/dist/chat/adapters/slack.js +0 -172
  93. package/dist/chat/adapters/slack.js.map +0 -1
  94. package/dist/chat/adapters/slack.test.js +0 -30
  95. package/dist/chat/adapters/telegram.d.ts +0 -148
  96. package/dist/chat/adapters/telegram.d.ts.map +0 -1
  97. package/dist/chat/adapters/telegram.js +0 -498
  98. package/dist/chat/adapters/telegram.js.map +0 -1
  99. package/dist/chat/adapters/telegram.test.js +0 -94
  100. package/dist/chat/config.d.ts +0 -98
  101. package/dist/chat/config.d.ts.map +0 -1
  102. package/dist/chat/config.js +0 -185
  103. package/dist/chat/config.js.map +0 -1
  104. package/dist/chat/daemon/active-project.d.ts +0 -17
  105. package/dist/chat/daemon/active-project.d.ts.map +0 -1
  106. package/dist/chat/daemon/active-project.js +0 -23
  107. package/dist/chat/daemon/active-project.js.map +0 -1
  108. package/dist/chat/daemon/autospawn.d.ts +0 -40
  109. package/dist/chat/daemon/autospawn.d.ts.map +0 -1
  110. package/dist/chat/daemon/autospawn.js +0 -129
  111. package/dist/chat/daemon/autospawn.js.map +0 -1
  112. package/dist/chat/daemon/autospawn.test.js +0 -112
  113. package/dist/chat/daemon/cli.d.ts +0 -18
  114. package/dist/chat/daemon/cli.d.ts.map +0 -1
  115. package/dist/chat/daemon/cli.js +0 -71
  116. package/dist/chat/daemon/cli.js.map +0 -1
  117. package/dist/chat/daemon/collisions.js +0 -384
  118. package/dist/chat/daemon/health-check.d.ts +0 -69
  119. package/dist/chat/daemon/health-check.d.ts.map +0 -1
  120. package/dist/chat/daemon/health-check.js +0 -112
  121. package/dist/chat/daemon/health-check.js.map +0 -1
  122. package/dist/chat/daemon/inbox-read.d.ts +0 -35
  123. package/dist/chat/daemon/inbox-read.d.ts.map +0 -1
  124. package/dist/chat/daemon/inbox-read.js +0 -75
  125. package/dist/chat/daemon/inbox-read.js.map +0 -1
  126. package/dist/chat/daemon/inbox-read.test.js +0 -97
  127. package/dist/chat/daemon/inbox.d.ts +0 -63
  128. package/dist/chat/daemon/inbox.d.ts.map +0 -1
  129. package/dist/chat/daemon/inbox.js +0 -56
  130. package/dist/chat/daemon/inbox.js.map +0 -1
  131. package/dist/chat/daemon/inbox.test.js +0 -110
  132. package/dist/chat/daemon/lifecycle.d.ts +0 -71
  133. package/dist/chat/daemon/lifecycle.d.ts.map +0 -1
  134. package/dist/chat/daemon/lifecycle.js +0 -221
  135. package/dist/chat/daemon/lifecycle.js.map +0 -1
  136. package/dist/chat/daemon/lifecycle.test.js +0 -163
  137. package/dist/chat/daemon/protocol.d.ts +0 -107
  138. package/dist/chat/daemon/protocol.d.ts.map +0 -1
  139. package/dist/chat/daemon/protocol.js +0 -54
  140. package/dist/chat/daemon/protocol.js.map +0 -1
  141. package/dist/chat/daemon/routing.d.ts +0 -140
  142. package/dist/chat/daemon/routing.d.ts.map +0 -1
  143. package/dist/chat/daemon/routing.js +0 -198
  144. package/dist/chat/daemon/routing.js.map +0 -1
  145. package/dist/chat/daemon/routing.test.js +0 -259
  146. package/dist/chat/daemon/rpc-client.d.ts +0 -45
  147. package/dist/chat/daemon/rpc-client.d.ts.map +0 -1
  148. package/dist/chat/daemon/rpc-client.js +0 -133
  149. package/dist/chat/daemon/rpc-client.js.map +0 -1
  150. package/dist/chat/daemon/rpc-server.d.ts +0 -39
  151. package/dist/chat/daemon/rpc-server.d.ts.map +0 -1
  152. package/dist/chat/daemon/rpc-server.js +0 -385
  153. package/dist/chat/daemon/rpc-server.js.map +0 -1
  154. package/dist/chat/daemon/rpc.test.js +0 -177
  155. package/dist/chat/daemon/subscribers.js +0 -257
  156. package/dist/chat/daemon/worker.d.ts +0 -27
  157. package/dist/chat/daemon/worker.d.ts.map +0 -1
  158. package/dist/chat/daemon/worker.js +0 -313
  159. package/dist/chat/daemon/worker.js.map +0 -1
  160. package/dist/chat/daemon/workspace-topic.js +0 -324
  161. package/dist/chat/env-token.d.ts +0 -60
  162. package/dist/chat/env-token.d.ts.map +0 -1
  163. package/dist/chat/env-token.js +0 -137
  164. package/dist/chat/env-token.js.map +0 -1
  165. package/dist/chat/env-token.test.js +0 -160
  166. package/dist/chat/factory.d.ts +0 -30
  167. package/dist/chat/factory.d.ts.map +0 -1
  168. package/dist/chat/factory.js +0 -50
  169. package/dist/chat/factory.js.map +0 -1
  170. package/dist/chat/factory.test.js +0 -55
  171. package/dist/chat/gateway.d.ts +0 -176
  172. package/dist/chat/gateway.d.ts.map +0 -1
  173. package/dist/chat/gateway.js +0 -146
  174. package/dist/chat/gateway.js.map +0 -1
  175. package/dist/chat/gateway.test.js +0 -192
  176. package/dist/claude-md.d.ts +0 -39
  177. package/dist/claude-md.d.ts.map +0 -1
  178. package/dist/claude-md.js +0 -113
  179. package/dist/claude-md.js.map +0 -1
  180. package/dist/claude-md.test.js +0 -91
  181. package/dist/codex/activate.d.ts +0 -66
  182. package/dist/codex/activate.d.ts.map +0 -1
  183. package/dist/codex/activate.js +0 -329
  184. package/dist/codex/activate.js.map +0 -1
  185. package/dist/codex/activate.test.js +0 -229
  186. package/dist/codex/bundled-default/bundled-default.test.js +0 -161
  187. package/dist/codex/cli-publish.test.js +0 -133
  188. package/dist/codex/cli.d.ts +0 -35
  189. package/dist/codex/cli.d.ts.map +0 -1
  190. package/dist/codex/cli.js +0 -554
  191. package/dist/codex/cli.js.map +0 -1
  192. package/dist/codex/cli.test.js +0 -277
  193. package/dist/codex/import-skill-md.d.ts +0 -53
  194. package/dist/codex/import-skill-md.d.ts.map +0 -1
  195. package/dist/codex/import-skill-md.js +0 -236
  196. package/dist/codex/import-skill-md.js.map +0 -1
  197. package/dist/codex/import-skill-md.test.js +0 -225
  198. package/dist/codex/loader.d.ts +0 -27
  199. package/dist/codex/loader.d.ts.map +0 -1
  200. package/dist/codex/loader.js +0 -86
  201. package/dist/codex/loader.js.map +0 -1
  202. package/dist/codex/loader.test.js +0 -75
  203. package/dist/codex/parse.d.ts +0 -28
  204. package/dist/codex/parse.d.ts.map +0 -1
  205. package/dist/codex/parse.js +0 -309
  206. package/dist/codex/parse.js.map +0 -1
  207. package/dist/codex/parse.test.js +0 -241
  208. package/dist/codex/store.d.ts +0 -87
  209. package/dist/codex/store.d.ts.map +0 -1
  210. package/dist/codex/store.js +0 -205
  211. package/dist/codex/store.js.map +0 -1
  212. package/dist/codex/store.test.js +0 -242
  213. package/dist/codex/types.d.ts +0 -398
  214. package/dist/codex/types.d.ts.map +0 -1
  215. package/dist/codex/types.js +0 -21
  216. package/dist/codex/types.js.map +0 -1
  217. package/dist/config.d.ts +0 -53
  218. package/dist/config.d.ts.map +0 -1
  219. package/dist/config.js +0 -202
  220. package/dist/config.js.map +0 -1
  221. package/dist/config.test.js +0 -117
  222. package/dist/engine/cli.d.ts +0 -14
  223. package/dist/engine/cli.d.ts.map +0 -1
  224. package/dist/engine/cli.js +0 -171
  225. package/dist/engine/cli.js.map +0 -1
  226. package/dist/engine/client.d.ts +0 -219
  227. package/dist/engine/client.d.ts.map +0 -1
  228. package/dist/engine/client.js +0 -312
  229. package/dist/engine/client.js.map +0 -1
  230. package/dist/engine/config.d.ts +0 -62
  231. package/dist/engine/config.d.ts.map +0 -1
  232. package/dist/engine/config.js +0 -223
  233. package/dist/engine/config.js.map +0 -1
  234. package/dist/engine/index.d.ts +0 -17
  235. package/dist/engine/index.d.ts.map +0 -1
  236. package/dist/engine/index.js +0 -16
  237. package/dist/engine/index.js.map +0 -1
  238. package/dist/engine/resolver.d.ts +0 -62
  239. package/dist/engine/resolver.d.ts.map +0 -1
  240. package/dist/engine/resolver.js +0 -103
  241. package/dist/engine/resolver.js.map +0 -1
  242. package/dist/engine/singleton.d.ts +0 -95
  243. package/dist/engine/singleton.d.ts.map +0 -1
  244. package/dist/engine/singleton.js +0 -325
  245. package/dist/engine/singleton.js.map +0 -1
  246. package/dist/engine/types.d.ts +0 -402
  247. package/dist/engine/types.d.ts.map +0 -1
  248. package/dist/engine/types.js +0 -22
  249. package/dist/engine/types.js.map +0 -1
  250. package/dist/engine-binary-resolver.js +0 -110
  251. package/dist/engine-binary-resolver.test.js +0 -61
  252. package/dist/engine-cli.js +0 -60
  253. package/dist/engine-client.js +0 -301
  254. package/dist/engine-client.test.js +0 -118
  255. package/dist/functions/chain_state.d.ts +0 -51
  256. package/dist/functions/chain_state.d.ts.map +0 -1
  257. package/dist/functions/chain_state.js +0 -59
  258. package/dist/functions/chain_state.js.map +0 -1
  259. package/dist/hooks/drift-catalog.d.ts +0 -68
  260. package/dist/hooks/drift-catalog.d.ts.map +0 -1
  261. package/dist/hooks/drift-catalog.js +0 -184
  262. package/dist/hooks/drift-catalog.js.map +0 -1
  263. package/dist/hooks/drift-catalog.test.js +0 -154
  264. package/dist/hooks/drift-patterns.d.ts +0 -110
  265. package/dist/hooks/drift-patterns.d.ts.map +0 -1
  266. package/dist/hooks/drift-patterns.js +0 -289
  267. package/dist/hooks/drift-patterns.js.map +0 -1
  268. package/dist/hooks/drift-patterns.test.js +0 -325
  269. package/dist/hooks/engine-vocab-gate.d.ts +0 -108
  270. package/dist/hooks/engine-vocab-gate.d.ts.map +0 -1
  271. package/dist/hooks/engine-vocab-gate.js +0 -225
  272. package/dist/hooks/engine-vocab-gate.js.map +0 -1
  273. package/dist/hooks/engine-vocab-gate.test.js +0 -170
  274. package/dist/hooks/heartbeat.d.ts +0 -107
  275. package/dist/hooks/heartbeat.d.ts.map +0 -1
  276. package/dist/hooks/heartbeat.js +0 -316
  277. package/dist/hooks/heartbeat.js.map +0 -1
  278. package/dist/hooks/heartbeat.test.js +0 -393
  279. package/dist/hooks/honesty-ledger-session-scope.test.js +0 -100
  280. package/dist/hooks/honesty-ledger.d.ts +0 -123
  281. package/dist/hooks/honesty-ledger.d.ts.map +0 -1
  282. package/dist/hooks/honesty-ledger.js +0 -226
  283. package/dist/hooks/honesty-ledger.js.map +0 -1
  284. package/dist/hooks/honesty-ledger.test.js +0 -466
  285. package/dist/hooks/inline-report-check.d.ts +0 -63
  286. package/dist/hooks/inline-report-check.d.ts.map +0 -1
  287. package/dist/hooks/inline-report-check.js +0 -88
  288. package/dist/hooks/inline-report-check.js.map +0 -1
  289. package/dist/hooks/inline-report-check.test.js +0 -96
  290. package/dist/hooks/pre-tool-use.d.ts +0 -62
  291. package/dist/hooks/pre-tool-use.d.ts.map +0 -1
  292. package/dist/hooks/pre-tool-use.js +0 -342
  293. package/dist/hooks/pre-tool-use.js.map +0 -1
  294. package/dist/hooks/pre-tool-use.test.js +0 -134
  295. package/dist/hooks/session-end.d.ts +0 -15
  296. package/dist/hooks/session-end.d.ts.map +0 -1
  297. package/dist/hooks/session-end.js +0 -60
  298. package/dist/hooks/session-end.js.map +0 -1
  299. package/dist/hooks/session-end.test.js +0 -52
  300. package/dist/hooks/stop.d.ts +0 -35
  301. package/dist/hooks/stop.d.ts.map +0 -1
  302. package/dist/hooks/stop.js +0 -136
  303. package/dist/hooks/stop.js.map +0 -1
  304. package/dist/hooks/transcript-active-task.test.js +0 -342
  305. package/dist/hooks/transcript.d.ts +0 -26
  306. package/dist/hooks/transcript.d.ts.map +0 -1
  307. package/dist/hooks/transcript.js +0 -266
  308. package/dist/hooks/transcript.js.map +0 -1
  309. package/dist/hooks/transcript.test.js +0 -103
  310. package/dist/hooks/user-prompt-submit.d.ts +0 -74
  311. package/dist/hooks/user-prompt-submit.d.ts.map +0 -1
  312. package/dist/hooks/user-prompt-submit.js +0 -256
  313. package/dist/hooks/user-prompt-submit.js.map +0 -1
  314. package/dist/hooks/user-prompt-submit.test.js +0 -118
  315. package/dist/hooks/versioning-gate.d.ts +0 -101
  316. package/dist/hooks/versioning-gate.d.ts.map +0 -1
  317. package/dist/hooks/versioning-gate.js +0 -245
  318. package/dist/hooks/versioning-gate.js.map +0 -1
  319. package/dist/hooks/versioning-gate.test.js +0 -368
  320. package/dist/hooks/workflow-gate.d.ts +0 -64
  321. package/dist/hooks/workflow-gate.d.ts.map +0 -1
  322. package/dist/hooks/workflow-gate.js +0 -152
  323. package/dist/hooks/workflow-gate.js.map +0 -1
  324. package/dist/hooks/workflow-gate.test.js +0 -197
  325. package/dist/hooks-cli.d.ts +0 -25
  326. package/dist/hooks-cli.d.ts.map +0 -1
  327. package/dist/hooks-cli.js +0 -286
  328. package/dist/hooks-cli.js.map +0 -1
  329. package/dist/hooks-cli.test.js +0 -148
  330. package/dist/origin.d.ts +0 -16
  331. package/dist/origin.d.ts.map +0 -1
  332. package/dist/origin.js +0 -92
  333. package/dist/origin.js.map +0 -1
  334. package/dist/packs/seed_lessons_ingest.d.ts +0 -30
  335. package/dist/packs/seed_lessons_ingest.d.ts.map +0 -1
  336. package/dist/packs/seed_lessons_ingest.js +0 -107
  337. package/dist/packs/seed_lessons_ingest.js.map +0 -1
  338. package/dist/project-cli.d.ts +0 -7
  339. package/dist/project-cli.d.ts.map +0 -1
  340. package/dist/project-cli.js +0 -145
  341. package/dist/project-cli.js.map +0 -1
  342. package/dist/project.d.ts +0 -127
  343. package/dist/project.d.ts.map +0 -1
  344. package/dist/project.js +0 -281
  345. package/dist/project.js.map +0 -1
  346. package/dist/project.test.js +0 -287
  347. package/dist/rag/backends/loop_engine.d.ts +0 -61
  348. package/dist/rag/backends/loop_engine.d.ts.map +0 -1
  349. package/dist/rag/backends/loop_engine.js +0 -160
  350. package/dist/rag/backends/loop_engine.js.map +0 -1
  351. package/dist/recall.d.ts +0 -82
  352. package/dist/recall.d.ts.map +0 -1
  353. package/dist/recall.js +0 -81
  354. package/dist/recall.js.map +0 -1
  355. package/dist/runtime/agent_bridge/autospawn.d.ts +0 -131
  356. package/dist/runtime/agent_bridge/autospawn.d.ts.map +0 -1
  357. package/dist/runtime/agent_bridge/autospawn.js +0 -251
  358. package/dist/runtime/agent_bridge/autospawn.js.map +0 -1
  359. package/dist/runtime/chain_state.d.ts +0 -124
  360. package/dist/runtime/chain_state.d.ts.map +0 -1
  361. package/dist/runtime/chain_state.js +0 -189
  362. package/dist/runtime/chain_state.js.map +0 -1
  363. package/dist/runtime/hooks/permission_decision.d.ts +0 -34
  364. package/dist/runtime/hooks/permission_decision.d.ts.map +0 -1
  365. package/dist/runtime/hooks/permission_decision.js +0 -39
  366. package/dist/runtime/hooks/permission_decision.js.map +0 -1
  367. package/dist/runtime/workflow_fsm.d.ts +0 -21
  368. package/dist/runtime/workflow_fsm.d.ts.map +0 -1
  369. package/dist/runtime/workflow_fsm.js +0 -25
  370. package/dist/runtime/workflow_fsm.js.map +0 -1
  371. package/dist/runtime/workflow_map.d.ts +0 -26
  372. package/dist/runtime/workflow_map.d.ts.map +0 -1
  373. package/dist/runtime/workflow_map.js +0 -38
  374. package/dist/runtime/workflow_map.js.map +0 -1
  375. package/dist/scope.d.ts +0 -48
  376. package/dist/scope.d.ts.map +0 -1
  377. package/dist/scope.js +0 -111
  378. package/dist/scope.js.map +0 -1
  379. package/dist/setup/cli/topic_create_step.d.ts +0 -84
  380. package/dist/setup/cli/topic_create_step.d.ts.map +0 -1
  381. package/dist/setup/cli/topic_create_step.js +0 -213
  382. package/dist/setup/cli/topic_create_step.js.map +0 -1
  383. package/dist/system-export.d.ts +0 -65
  384. package/dist/system-export.d.ts.map +0 -1
  385. package/dist/system-export.js +0 -194
  386. package/dist/system-export.js.map +0 -1
  387. package/dist/utterance/classifier.d.ts +0 -53
  388. package/dist/utterance/classifier.d.ts.map +0 -1
  389. package/dist/utterance/classifier.js +0 -184
  390. package/dist/utterance/classifier.js.map +0 -1
  391. package/dist/utterance/classifier.test.js +0 -147
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-end.d.ts","sourceRoot":"","sources":["../../src.legacy/hooks/session-end.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAaH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CA+CvD"}
@@ -1,60 +0,0 @@
1
- /**
2
- * `opensquid hook session-end` — Claude Code SessionEnd hook handler.
3
- *
4
- * Fires when a Claude Code session terminates. Wipes the session's
5
- * honesty-ledger state (turn-ledger.jsonl + broken-promises.jsonl) so
6
- * the ledger doesn't grow unbounded across all-time sessions.
7
- *
8
- * Without this hook, every Claude Code session creates a
9
- * <data-root>/sessions/<id>/ directory with two JSONL files that
10
- * never get cleaned up. Disk usage grows linearly with session count.
11
- *
12
- * Exit 0 always — SessionEnd is cleanup, not blocking.
13
- */
14
- import { runDriftCatalogScan } from "./drift-catalog.js";
15
- import { clearSession } from "./honesty-ledger.js";
16
- export async function runSessionEndHook() {
17
- let raw = "";
18
- for await (const chunk of process.stdin) {
19
- raw += chunk;
20
- }
21
- if (!raw.trim())
22
- process.exit(0);
23
- let payload;
24
- try {
25
- payload = JSON.parse(raw);
26
- }
27
- catch {
28
- process.exit(0);
29
- }
30
- const sessionId = payload.session_id;
31
- if (!sessionId)
32
- process.exit(0);
33
- // 0.7.22 / D10 — automated drift catalog. Scan the transcript for
34
- // drift markers (user corrections, locked-rule citations, agent
35
- // mea-culpas) and append to the project's drift-catalog.jsonl. Runs
36
- // BEFORE clearSession so any session-scoped state used for context
37
- // is still available.
38
- try {
39
- const count = await runDriftCatalogScan({
40
- sessionId,
41
- transcriptPath: payload.transcript_path,
42
- cwd: payload.cwd,
43
- });
44
- if (count > 0) {
45
- process.stderr.write(`🦑 [opensquid drift-catalog] recorded ${count} drift marker(s)\n`);
46
- }
47
- }
48
- catch (err) {
49
- process.stderr.write(`[opensquid hook session-end] drift-catalog scan failed (non-fatal): ${err instanceof Error ? err.message : err}\n`);
50
- }
51
- try {
52
- await clearSession(sessionId);
53
- }
54
- catch (err) {
55
- // Cleanup failure is non-fatal — disk-space leak, not a correctness bug.
56
- process.stderr.write(`[opensquid hook session-end] clearSession failed: ${err instanceof Error ? err.message : err}\n`);
57
- }
58
- process.exit(0);
59
- }
60
- //# sourceMappingURL=session-end.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-end.js","sourceRoot":"","sources":["../../src.legacy/hooks/session-end.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAUnD,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,GAAG,IAAI,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEjC,IAAI,OAAwB,CAAC;IAC7B,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;IACrC,IAAI,CAAC,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEhC,kEAAkE;IAClE,gEAAgE;IAChE,oEAAoE;IACpE,mEAAmE;IACnE,sBAAsB;IACtB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC;YACtC,SAAS;YACT,cAAc,EAAE,OAAO,CAAC,eAAe;YACvC,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;QACH,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,yCAAyC,KAAK,oBAAoB,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,uEAAuE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CACpH,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,yEAAyE;QACzE,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qDAAqD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAClG,CAAC;IACJ,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
@@ -1,52 +0,0 @@
1
- import * as crypto from "node:crypto";
2
- import { promises as fs } from "node:fs";
3
- import * as os from "node:os";
4
- import * as path from "node:path";
5
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
- import { clearSession, readBrokenPromises, readTurnLedger, recordBrokenPromise, recordToolCall, } from "./honesty-ledger.js";
7
- let tmpRoot;
8
- const SESSION = "session-end-test";
9
- beforeEach(async () => {
10
- tmpRoot = path.join(os.tmpdir(), `oscli-session-end-${crypto.randomUUID()}`);
11
- await fs.mkdir(tmpRoot, { recursive: true });
12
- });
13
- afterEach(async () => {
14
- await fs.rm(tmpRoot, { recursive: true, force: true });
15
- });
16
- describe("SessionEnd cleanup (clearSession via the hook)", () => {
17
- it("wipes both ledger and broken-promises after population", async () => {
18
- await recordToolCall(SESSION, "Bash", "npm test", { dataRoot: tmpRoot });
19
- await recordToolCall(SESSION, "Bash", "git commit -m foo", { dataRoot: tmpRoot });
20
- await recordBrokenPromise(SESSION, {
21
- ts: "2026-05-15T00:00:00Z",
22
- claim_id: "fake",
23
- claim_label: "x",
24
- matched_text: "y",
25
- reason: "z",
26
- }, { dataRoot: tmpRoot });
27
- // Sanity-check the precondition.
28
- expect((await readTurnLedger(SESSION, { dataRoot: tmpRoot })).length).toBe(2);
29
- expect((await readBrokenPromises(SESSION, { dataRoot: tmpRoot })).length).toBe(1);
30
- // SessionEnd action.
31
- await clearSession(SESSION, { dataRoot: tmpRoot });
32
- expect(await readTurnLedger(SESSION, { dataRoot: tmpRoot })).toEqual([]);
33
- expect(await readBrokenPromises(SESSION, { dataRoot: tmpRoot })).toEqual([]);
34
- });
35
- it("session directory remains, just empty of ledger files", async () => {
36
- await recordToolCall(SESSION, "Bash", "ls", { dataRoot: tmpRoot });
37
- await clearSession(SESSION, { dataRoot: tmpRoot });
38
- // The sessions/<id>/ directory itself is preserved (cheap),
39
- // only the JSONL files inside are removed.
40
- const dir = path.join(tmpRoot, "sessions", SESSION);
41
- await expect(fs.access(dir)).resolves.toBeUndefined();
42
- const entries = await fs.readdir(dir);
43
- expect(entries).toEqual([]);
44
- });
45
- it("does NOT touch other sessions' ledgers", async () => {
46
- await recordToolCall(SESSION, "Bash", "ls", { dataRoot: tmpRoot });
47
- await recordToolCall("other-session", "Bash", "ls", { dataRoot: tmpRoot });
48
- await clearSession(SESSION, { dataRoot: tmpRoot });
49
- expect((await readTurnLedger(SESSION, { dataRoot: tmpRoot })).length).toBe(0);
50
- expect((await readTurnLedger("other-session", { dataRoot: tmpRoot })).length).toBe(1);
51
- });
52
- });
@@ -1,35 +0,0 @@
1
- /**
2
- * `opensquid hook stop` — Claude Code Stop hook handler.
3
- *
4
- * Fires at the end of every assistant turn. Two responsibilities:
5
- *
6
- * 1. Honesty ledger reconciliation: cross-reference the assistant's
7
- * final message against the session's accumulated tool-call ledger.
8
- * Any unfulfilled claim is recorded as a broken promise that the
9
- * next turn's UserPromptSubmit hook surfaces back to the agent.
10
- *
11
- * 2. Token-threshold heartbeat: estimate transcript token count, and
12
- * if the conversation has grown past the configured threshold
13
- * since the last checkpoint, arm a pending heartbeat marker so
14
- * the next UserPromptSubmit hook injects a re-anchor nudge into
15
- * the agent's context. The agent (already authenticated and in
16
- * the loop) does the actual recall + classify work inline.
17
- *
18
- * Exit 0 always — Stop hook is observational, not blocking.
19
- *
20
- * Wired in ~/.claude/settings.json:
21
- *
22
- * "Stop": [
23
- * { "hooks": [{
24
- * "type": "command",
25
- * "command": "node /path/to/opensquid/dist/index.js hook stop"
26
- * }] }
27
- * ]
28
- *
29
- * Pre-#124: this hook also spawned a detached LLM-classifier subprocess.
30
- * Removed in favor of the heartbeat path — opensquid stays in-MCP-ecosystem
31
- * (no external LLM dependency, no subprocess), and the agent does the
32
- * classification work inline per CLAUDE.md classify-and-act rules.
33
- */
34
- export declare function runStopHook(): Promise<void>;
35
- //# sourceMappingURL=stop.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stop.d.ts","sourceRoot":"","sources":["../../src.legacy/hooks/stop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAmBH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CA4GjD"}
@@ -1,136 +0,0 @@
1
- /**
2
- * `opensquid hook stop` — Claude Code Stop hook handler.
3
- *
4
- * Fires at the end of every assistant turn. Two responsibilities:
5
- *
6
- * 1. Honesty ledger reconciliation: cross-reference the assistant's
7
- * final message against the session's accumulated tool-call ledger.
8
- * Any unfulfilled claim is recorded as a broken promise that the
9
- * next turn's UserPromptSubmit hook surfaces back to the agent.
10
- *
11
- * 2. Token-threshold heartbeat: estimate transcript token count, and
12
- * if the conversation has grown past the configured threshold
13
- * since the last checkpoint, arm a pending heartbeat marker so
14
- * the next UserPromptSubmit hook injects a re-anchor nudge into
15
- * the agent's context. The agent (already authenticated and in
16
- * the loop) does the actual recall + classify work inline.
17
- *
18
- * Exit 0 always — Stop hook is observational, not blocking.
19
- *
20
- * Wired in ~/.claude/settings.json:
21
- *
22
- * "Stop": [
23
- * { "hooks": [{
24
- * "type": "command",
25
- * "command": "node /path/to/opensquid/dist/index.js hook stop"
26
- * }] }
27
- * ]
28
- *
29
- * Pre-#124: this hook also spawned a detached LLM-classifier subprocess.
30
- * Removed in favor of the heartbeat path — opensquid stays in-MCP-ecosystem
31
- * (no external LLM dependency, no subprocess), and the agent does the
32
- * classification work inline per CLAUDE.md classify-and-act rules.
33
- */
34
- import { clearTurnLedger, reconcile, readBrokenPromises, readTurnLedger, recordBrokenPromise, } from "./honesty-ledger.js";
35
- import { checkAndMaybeArm } from "./heartbeat.js";
36
- import { checkInlineReportFormat } from "./inline-report-check.js";
37
- import { readLastAssistantText } from "./transcript.js";
38
- export async function runStopHook() {
39
- let raw = "";
40
- for await (const chunk of process.stdin) {
41
- raw += chunk;
42
- }
43
- if (!raw.trim()) {
44
- process.exit(0);
45
- }
46
- let payload;
47
- try {
48
- payload = JSON.parse(raw);
49
- }
50
- catch {
51
- process.stderr.write("[opensquid hook stop] malformed input — proceeding\n");
52
- process.exit(0);
53
- }
54
- const sessionId = payload.session_id;
55
- if (!sessionId)
56
- process.exit(0);
57
- // -- (1) Honesty-ledger reconcile ----------------------------------
58
- const assistantText = payload.transcript_path
59
- ? await readLastAssistantText(payload.transcript_path)
60
- : "";
61
- const ledger = await readTurnLedger(sessionId);
62
- const broken = reconcile(assistantText, ledger);
63
- const existing = await readBrokenPromises(sessionId);
64
- const existingKeys = new Set(existing.map((p) => `${p.claim_id}|${p.matched_text}`));
65
- const fresh = [];
66
- for (const promise of broken) {
67
- const key = `${promise.claim_id}|${promise.matched_text}`;
68
- if (existingKeys.has(key))
69
- continue;
70
- fresh.push(promise);
71
- try {
72
- await recordBrokenPromise(sessionId, promise);
73
- }
74
- catch (err) {
75
- process.stderr.write(`[opensquid hook stop] failed to record promise: ${err instanceof Error ? err.message : err}\n`);
76
- }
77
- }
78
- if (fresh.length > 0) {
79
- for (const p of fresh) {
80
- process.stderr.write(`🦑 [opensquid honesty] ${p.claim_id}: ${p.reason}\n`);
81
- }
82
- }
83
- // 0.7.30 / D3 follow-up — when the agent writes a completion-report-
84
- // shaped status update inline (vs. via mcp__opensquid__chat_send),
85
- // D3's chat_send check doesn't fire. Catch the inline case here at
86
- // Stop time and surface as a broken-promise next turn.
87
- if (assistantText) {
88
- const inlineViolation = checkInlineReportFormat(assistantText);
89
- if (inlineViolation) {
90
- const broken = {
91
- ts: new Date().toISOString(),
92
- claim_id: "inline-report-missing-phases",
93
- claim_label: "PHASES block per [[feedback_telegram_reports]]",
94
- matched_text: inlineViolation.matched_text,
95
- reason: `inline message shape suggests a completion report ` +
96
- `(version_refs=${inlineViolation.signals.version_refs}, ` +
97
- `commit_hashes=${inlineViolation.signals.hash_refs}) but the ` +
98
- `PHASES heading is missing. Catches D3 inline variant.`,
99
- };
100
- try {
101
- await recordBrokenPromise(sessionId, broken);
102
- process.stderr.write(`🦑 [opensquid honesty] ${broken.claim_id}: ${broken.reason}\n`);
103
- }
104
- catch (err) {
105
- process.stderr.write(`[opensquid hook stop] inline-report check write failed: ${err instanceof Error ? err.message : err}\n`);
106
- }
107
- }
108
- }
109
- // 0.7.8 (#162): clear the turn-ledger AFTER reconciliation so the
110
- // next turn's claims reconcile against ONLY that turn's tool calls.
111
- // Previously the ledger only cleared at SessionEnd, which meant
112
- // yesterday's git push satisfied today's "I'll push" claim on long
113
- // resumed sessions — the load-bearing #160 finding for ledger drift.
114
- try {
115
- await clearTurnLedger(sessionId);
116
- }
117
- catch (err) {
118
- process.stderr.write(`[opensquid hook stop] turn-ledger clear failed (non-fatal): ${err instanceof Error ? err.message : err}\n`);
119
- }
120
- // -- (2) Token-threshold heartbeat ---------------------------------
121
- if (payload.transcript_path) {
122
- try {
123
- const armed = await checkAndMaybeArm(sessionId, payload.transcript_path);
124
- if (armed) {
125
- // Surface to stderr too so the user sees that opensquid noticed
126
- // drift (in addition to the agent seeing it next turn via UPS).
127
- process.stderr.write(`🦑 [opensquid heartbeat-armed] ${armed}\n`);
128
- }
129
- }
130
- catch (err) {
131
- process.stderr.write(`[opensquid hook stop] heartbeat check failed (non-fatal): ${err instanceof Error ? err.message : err}\n`);
132
- }
133
- }
134
- process.exit(0);
135
- }
136
- //# sourceMappingURL=stop.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"stop.js","sourceRoot":"","sources":["../../src.legacy/hooks/stop.ts"],"names":[],"mappings":"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"}
@@ -1,342 +0,0 @@
1
- /**
2
- * Tests for `readActiveTaskId` — the transcript-walking helper that
3
- * finds the most-recent TodoWrite in_progress task id. Used by the
4
- * workflow gate to figure out which task's phase ledger to query.
5
- */
6
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
7
- import * as crypto from "node:crypto";
8
- import { promises as fs } from "node:fs";
9
- import * as os from "node:os";
10
- import * as path from "node:path";
11
- import { fileURLToPath } from "node:url";
12
- import { readActiveTaskId } from "./transcript.js";
13
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
- let tmpDir;
15
- let transcriptPath;
16
- beforeEach(async () => {
17
- tmpDir = path.join(os.tmpdir(), `opensquid-tx-${crypto.randomUUID()}`);
18
- await fs.mkdir(tmpDir, { recursive: true });
19
- transcriptPath = path.join(tmpDir, "transcript.jsonl");
20
- });
21
- afterEach(async () => {
22
- await fs.rm(tmpDir, { recursive: true, force: true });
23
- });
24
- async function writeEvents(events) {
25
- const lines = events.map((e) => JSON.stringify(e)).join("\n") + "\n";
26
- await fs.writeFile(transcriptPath, lines, "utf8");
27
- }
28
- function todoWriteEvent(todos) {
29
- return {
30
- type: "assistant",
31
- message: {
32
- role: "assistant",
33
- content: [
34
- {
35
- type: "tool_use",
36
- name: "TodoWrite",
37
- input: { todos },
38
- },
39
- ],
40
- },
41
- };
42
- }
43
- describe("readActiveTaskId", () => {
44
- it("returns null when transcript doesn't exist", async () => {
45
- expect(await readActiveTaskId(path.join(tmpDir, "missing.jsonl"))).toBeNull();
46
- });
47
- it("returns null when transcript is empty", async () => {
48
- await fs.writeFile(transcriptPath, "", "utf8");
49
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
50
- });
51
- it("returns null when no TodoWrite block exists", async () => {
52
- await writeEvents([
53
- { type: "user", message: { role: "user", content: "hi" } },
54
- { type: "assistant", message: { role: "assistant", content: "hello" } },
55
- ]);
56
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
57
- });
58
- it("returns null when TodoWrite has no in_progress items", async () => {
59
- await writeEvents([
60
- todoWriteEvent([
61
- { id: "1", status: "completed" },
62
- { id: "2", status: "pending" },
63
- ]),
64
- ]);
65
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
66
- });
67
- it("returns the in_progress task id from a single TodoWrite", async () => {
68
- await writeEvents([
69
- todoWriteEvent([
70
- { id: "1", status: "completed" },
71
- { id: "2", status: "in_progress" },
72
- { id: "3", status: "pending" },
73
- ]),
74
- ]);
75
- expect(await readActiveTaskId(transcriptPath)).toBe("2");
76
- });
77
- it("prefers the MOST RECENT TodoWrite when multiple exist", async () => {
78
- await writeEvents([
79
- todoWriteEvent([{ id: "old-task", status: "in_progress" }]),
80
- todoWriteEvent([{ id: "newer-task", status: "in_progress" }]),
81
- ]);
82
- expect(await readActiveTaskId(transcriptPath)).toBe("newer-task");
83
- });
84
- it("stops at the most-recent TodoWrite even if its in_progress is null", async () => {
85
- // The MOST RECENT TodoWrite has no in_progress (all completed).
86
- // We must NOT fall back to an OLDER TodoWrite's in_progress that
87
- // may have been overwritten. Returns null.
88
- await writeEvents([
89
- todoWriteEvent([{ id: "stale-task", status: "in_progress" }]),
90
- todoWriteEvent([
91
- { id: "stale-task", status: "completed" },
92
- { id: "all-done", status: "completed" },
93
- ]),
94
- ]);
95
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
96
- });
97
- it("ignores non-assistant events between TodoWrites", async () => {
98
- await writeEvents([
99
- { type: "user", message: { role: "user", content: "do thing" } },
100
- todoWriteEvent([{ id: "active", status: "in_progress" }]),
101
- { type: "user", message: { role: "user", content: "now go" } },
102
- ]);
103
- expect(await readActiveTaskId(transcriptPath)).toBe("active");
104
- });
105
- it("ignores assistant text events without tool_use blocks", async () => {
106
- await writeEvents([
107
- todoWriteEvent([{ id: "real-active", status: "in_progress" }]),
108
- {
109
- type: "assistant",
110
- message: {
111
- role: "assistant",
112
- content: [{ type: "text", text: "thinking..." }],
113
- },
114
- },
115
- ]);
116
- expect(await readActiveTaskId(transcriptPath)).toBe("real-active");
117
- });
118
- it("ignores other tool_use events (Bash, Edit, etc.)", async () => {
119
- await writeEvents([
120
- todoWriteEvent([{ id: "active", status: "in_progress" }]),
121
- {
122
- type: "assistant",
123
- message: {
124
- role: "assistant",
125
- content: [{ type: "tool_use", name: "Bash", input: { command: "ls" } }],
126
- },
127
- },
128
- ]);
129
- expect(await readActiveTaskId(transcriptPath)).toBe("active");
130
- });
131
- it("coerces numeric ids to strings", async () => {
132
- await writeEvents([
133
- todoWriteEvent([
134
- // Some serializations encode id as number.
135
- { id: 127, status: "in_progress" },
136
- ]),
137
- ]);
138
- expect(await readActiveTaskId(transcriptPath)).toBe("127");
139
- });
140
- it("handles malformed JSON lines gracefully", async () => {
141
- await fs.writeFile(transcriptPath, [
142
- "{ malformed",
143
- JSON.stringify(todoWriteEvent([{ id: "active", status: "in_progress" }])),
144
- "still bad json",
145
- ].join("\n"), "utf8");
146
- expect(await readActiveTaskId(transcriptPath)).toBe("active");
147
- });
148
- });
149
- // =====================================================================
150
- // v0.6.2 — TaskCreate + TaskUpdate recognition (the real-world Claude
151
- // Code shape; TodoWrite was the v0.6.1 shape). My own dogfood session
152
- // today used TaskCreate/TaskUpdate exclusively → workflow gate silent-
153
- // allowed every commit because readActiveTaskId only recognized
154
- // TodoWrite. This block is the regression coverage for the fix.
155
- // =====================================================================
156
- function assistantToolUse(name, blockId, input) {
157
- return {
158
- type: "assistant",
159
- message: {
160
- role: "assistant",
161
- content: [
162
- {
163
- type: "tool_use",
164
- id: blockId,
165
- name,
166
- input,
167
- caller: { type: "direct" },
168
- },
169
- ],
170
- },
171
- };
172
- }
173
- function toolResult(toolUseId, content) {
174
- return {
175
- type: "user",
176
- message: {
177
- role: "user",
178
- content: [
179
- {
180
- type: "tool_result",
181
- tool_use_id: toolUseId,
182
- content,
183
- },
184
- ],
185
- },
186
- };
187
- }
188
- describe("readActiveTaskId — TaskUpdate (v0.6.2 fix)", () => {
189
- it("returns the taskId from TaskUpdate(status=in_progress)", async () => {
190
- await writeEvents([
191
- assistantToolUse("TaskUpdate", "tu-1", { taskId: "131", status: "in_progress" }),
192
- ]);
193
- expect(await readActiveTaskId(transcriptPath)).toBe("131");
194
- });
195
- it("does not return tasks marked completed by a later TaskUpdate", async () => {
196
- await writeEvents([
197
- assistantToolUse("TaskUpdate", "tu-1", { taskId: "131", status: "in_progress" }),
198
- assistantToolUse("TaskUpdate", "tu-2", { taskId: "131", status: "completed" }),
199
- ]);
200
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
201
- });
202
- it("picks the most-recently-touched in_progress task when multiple are active", async () => {
203
- await writeEvents([
204
- assistantToolUse("TaskUpdate", "tu-1", { taskId: "100", status: "in_progress" }),
205
- assistantToolUse("TaskUpdate", "tu-2", { taskId: "200", status: "in_progress" }),
206
- assistantToolUse("TaskUpdate", "tu-3", { taskId: "300", status: "in_progress" }),
207
- ]);
208
- expect(await readActiveTaskId(transcriptPath)).toBe("300");
209
- });
210
- it("coerces numeric taskId to string", async () => {
211
- await writeEvents([
212
- assistantToolUse("TaskUpdate", "tu-1", { taskId: 131, status: "in_progress" }),
213
- ]);
214
- expect(await readActiveTaskId(transcriptPath)).toBe("131");
215
- });
216
- it("ignores TaskUpdate with deleted status", async () => {
217
- await writeEvents([
218
- assistantToolUse("TaskUpdate", "tu-1", { taskId: "131", status: "in_progress" }),
219
- assistantToolUse("TaskUpdate", "tu-2", { taskId: "131", status: "deleted" }),
220
- ]);
221
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
222
- });
223
- });
224
- describe("readActiveTaskId — TaskCreate (v0.6.2 fix)", () => {
225
- it("does NOT return TaskCreate'd tasks (default status = pending, not in_progress)", async () => {
226
- // TaskCreate alone leaves the task as pending. Active-task detection
227
- // requires an explicit TaskUpdate(in_progress) — otherwise no gate
228
- // for tasks that were created but never started.
229
- await writeEvents([
230
- assistantToolUse("TaskCreate", "tc-1", {
231
- subject: "Some task",
232
- description: "...",
233
- }),
234
- toolResult("tc-1", "Task #131 created successfully: Some task"),
235
- ]);
236
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
237
- });
238
- it("returns the assigned id when TaskCreate is followed by TaskUpdate(in_progress)", async () => {
239
- await writeEvents([
240
- assistantToolUse("TaskCreate", "tc-1", { subject: "X", description: "..." }),
241
- toolResult("tc-1", "Task #131 created successfully: X"),
242
- assistantToolUse("TaskUpdate", "tu-1", { taskId: "131", status: "in_progress" }),
243
- ]);
244
- expect(await readActiveTaskId(transcriptPath)).toBe("131");
245
- });
246
- it("handles TaskCreate without a matching tool_result (truncated transcript)", async () => {
247
- await writeEvents([
248
- assistantToolUse("TaskCreate", "tc-1", { subject: "X", description: "..." }),
249
- // No tool_result follows
250
- ]);
251
- // No id assigned, no in_progress → null.
252
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
253
- });
254
- });
255
- // =====================================================================
256
- // Real-world fixture — captured from an actual Claude Code session.
257
- // The fixture lives at __fixtures__/real-task-shape.jsonl. If Claude
258
- // Code ever changes the wire format for TaskCreate / TaskUpdate, this
259
- // test fails BEFORE the workflow gate silently regresses in
260
- // production. Earlier audit recommendation (v0.6.2 audit MED): synthesized
261
- // tests passed in v0.6.1 but real-world shape didn't match — the same
262
- // failure mode would have been caught here.
263
- // =====================================================================
264
- describe("readActiveTaskId — real Claude Code transcript fixture", () => {
265
- it("recognizes TaskCreate + tool_result + TaskUpdate captured from a real session", async () => {
266
- const fixturePath = path.resolve(__dirname, "__fixtures__", "real-task-shape.jsonl");
267
- // The fixture is 3 events: TaskCreate "X" → tool_result "Task #1 created" →
268
- // TaskUpdate(taskId=1, status=in_progress). Expected active task: "1".
269
- const active = await readActiveTaskId(fixturePath);
270
- expect(active).toBe("1");
271
- });
272
- });
273
- // =====================================================================
274
- // 0.7.9 (#163) — stale in_progress demotion
275
- // =====================================================================
276
- function assistantToolUseAt(name, blockId, input, timestamp) {
277
- return {
278
- type: "assistant",
279
- timestamp,
280
- message: {
281
- role: "assistant",
282
- content: [{ type: "tool_use", id: blockId, name, input, caller: { type: "direct" } }],
283
- },
284
- };
285
- }
286
- function userEventAt(timestamp, text = "hello") {
287
- return { type: "user", timestamp, message: { role: "user", content: text } };
288
- }
289
- describe("readActiveTaskId — stale-task demotion (#163)", () => {
290
- const oldDay = "2026-05-16T08:00:00Z"; // ~24h before latest
291
- const today = "2026-05-17T08:00:00Z"; // latest activity
292
- it("returns null when the only in_progress task is >1hr stale relative to latest activity", async () => {
293
- await writeEvents([
294
- assistantToolUseAt("TaskUpdate", "tu-1", { taskId: "999", status: "in_progress" }, oldDay),
295
- // Many later events with newer timestamps — none touch task 999.
296
- userEventAt(today, "new conversation today"),
297
- ]);
298
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
299
- });
300
- it("keeps the in_progress task when it was recently touched", async () => {
301
- const recent = "2026-05-17T07:30:00Z"; // 30 min before latest
302
- await writeEvents([
303
- assistantToolUseAt("TaskUpdate", "tu-1", { taskId: "42", status: "in_progress" }, recent),
304
- userEventAt(today),
305
- ]);
306
- expect(await readActiveTaskId(transcriptPath)).toBe("42");
307
- });
308
- it("picks the more-recent in_progress when two exist (one stale, one fresh)", async () => {
309
- const recent = "2026-05-17T07:45:00Z";
310
- await writeEvents([
311
- assistantToolUseAt("TaskUpdate", "tu-1", { taskId: "X", status: "in_progress" }, oldDay),
312
- assistantToolUseAt("TaskUpdate", "tu-2", { taskId: "Y", status: "in_progress" }, recent),
313
- userEventAt(today),
314
- ]);
315
- expect(await readActiveTaskId(transcriptPath)).toBe("Y");
316
- });
317
- it("falls back to line-idx pick (no demotion) when events have no timestamps", async () => {
318
- // Pre-existing behavior preserved when timestamps aren't available.
319
- await writeEvents([
320
- assistantToolUse("TaskUpdate", "tu-1", { taskId: "no-ts", status: "in_progress" }),
321
- ]);
322
- expect(await readActiveTaskId(transcriptPath)).toBe("no-ts");
323
- });
324
- });
325
- describe("readActiveTaskId — mixed TodoWrite + TaskUpdate", () => {
326
- it("latest write wins per id, regardless of which tool", async () => {
327
- // TodoWrite snapshot says id=5 is in_progress; later TaskUpdate
328
- // marks id=5 completed. TaskUpdate is later → wins.
329
- await writeEvents([
330
- todoWriteEvent([{ id: "5", status: "in_progress" }]),
331
- assistantToolUse("TaskUpdate", "tu-1", { taskId: "5", status: "completed" }),
332
- ]);
333
- expect(await readActiveTaskId(transcriptPath)).toBeNull();
334
- });
335
- it("TodoWrite snapshot can revive an id that TaskUpdate marked completed if it comes later", async () => {
336
- await writeEvents([
337
- assistantToolUse("TaskUpdate", "tu-1", { taskId: "5", status: "completed" }),
338
- todoWriteEvent([{ id: "5", status: "in_progress" }]),
339
- ]);
340
- expect(await readActiveTaskId(transcriptPath)).toBe("5");
341
- });
342
- });