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,221 +0,0 @@
1
- /**
2
- * Chat-daemon lifecycle — start / stop / status (v0.7.1 Phase A).
3
- *
4
- * The daemon owns the single long-poll connection per chat platform so
5
- * multiple Claude Code projects sharing the same machine can run their
6
- * own opensquid MCP servers without colliding on the bot token (Telegram
7
- * returns 409 Conflict when two consumers long-poll the same token —
8
- * the v0.7 cause of "last-connected wins" behavior).
9
- *
10
- * Lifecycle is single-instance per machine: PID file at
11
- * ~/.opensquid/chat-daemon.pid, log at ~/.opensquid/chat-daemon.log.
12
- * A `start` call against a running daemon is a no-op (idempotent);
13
- * `stop` is also idempotent. `status` is read-only.
14
- *
15
- * Outbound RPC (Unix socket) lands in Phase B; routing config + inbox
16
- * write-out in Phase C; auto-spawn from MCP server in Phase D.
17
- */
18
- import { spawn } from "node:child_process";
19
- import { promises as fs } from "node:fs";
20
- import { existsSync } from "node:fs";
21
- import * as os from "node:os";
22
- import * as path from "node:path";
23
- import { resolveDataRoot } from "../../codex/store.js";
24
- export function daemonPaths(dataRoot) {
25
- const root = resolveDataRoot(dataRoot);
26
- return {
27
- pidFile: path.join(root, "chat-daemon.pid"),
28
- logFile: path.join(root, "chat-daemon.log"),
29
- sockFile: path.join(root, "chat-daemon.sock"),
30
- };
31
- }
32
- /**
33
- * Read the pidfile and check whether the recorded process is alive.
34
- * A pidfile that points at a dead pid is treated as not-running (the
35
- * caller should clean it up if they want; status itself is read-only).
36
- */
37
- export async function status(dataRoot) {
38
- const paths = daemonPaths(dataRoot);
39
- if (!existsSync(paths.pidFile))
40
- return { running: false };
41
- let raw;
42
- try {
43
- raw = await fs.readFile(paths.pidFile, "utf8");
44
- }
45
- catch {
46
- return { running: false };
47
- }
48
- const pid = parseInt(raw.trim(), 10);
49
- if (!Number.isFinite(pid) || pid <= 0)
50
- return { running: false };
51
- if (!isProcessAlive(pid))
52
- return { running: false, stale_pid: pid };
53
- let uptime_ms = null;
54
- try {
55
- const stat = await fs.stat(paths.pidFile);
56
- uptime_ms = Date.now() - stat.mtimeMs;
57
- }
58
- catch {
59
- /* keep null */
60
- }
61
- return { running: true, pid, uptime_ms };
62
- }
63
- /** `kill -0 <pid>` portable check — throws ESRCH if dead, EPERM if alive-but-foreign. */
64
- function isProcessAlive(pid) {
65
- try {
66
- process.kill(pid, 0);
67
- return true;
68
- }
69
- catch (err) {
70
- const code = err.code;
71
- return code === "EPERM"; // alive but owned by another user (still counts)
72
- }
73
- }
74
- /**
75
- * Start the daemon by spawning a detached child that runs
76
- * `node dist/index.js chat-daemon-worker` (the actual long-poll loop
77
- * lives in worker.ts). Returns immediately once the child has either
78
- * forked successfully or failed.
79
- *
80
- * Idempotent: a start against an already-running daemon returns
81
- * `{ already_running: true, pid }` without launching a second process.
82
- *
83
- * Stale pidfile handling: if the pidfile points at a dead pid, it's
84
- * silently removed so this call can succeed.
85
- */
86
- export async function startDaemon(options = {}) {
87
- const cur = await status(options.dataRoot);
88
- if (cur.running)
89
- return { already_running: true, pid: cur.pid };
90
- const paths = daemonPaths(options.dataRoot);
91
- if (cur.stale_pid !== undefined) {
92
- await fs.unlink(paths.pidFile).catch(() => {
93
- /* race-tolerant */
94
- });
95
- }
96
- // The log file is opened append-mode by both the parent (header
97
- // line) and the child (stdout/stderr). fs.open with 'a' is atomic
98
- // append on POSIX, which is what we want here — no race between
99
- // start runs.
100
- await fs.mkdir(path.dirname(paths.logFile), { recursive: true });
101
- const logFd = await fs.open(paths.logFile, "a");
102
- try {
103
- await logFd.write(`\n=== chat-daemon start @ ${new Date().toISOString()} ===\n` +
104
- `host=${os.hostname()} node=${process.version} platform=${process.platform}\n`);
105
- }
106
- finally {
107
- await logFd.close();
108
- }
109
- // Reopen the log file for the child's stdio. spawn() wants raw FDs,
110
- // not FileHandles, so we open via the sync API.
111
- const fsSync = await import("node:fs");
112
- const childLogFd = fsSync.openSync(paths.logFile, "a");
113
- const nodeBin = options.nodeBin ?? process.execPath;
114
- const entrypoint = options.entrypoint ?? defaultEntrypoint();
115
- // Pass dataRoot through to the worker via OPENSQUID_HOME so the
116
- // worker's resolveDataRoot() lands in the same tree the parent
117
- // selected. Tests pass a tmpdir here; production uses the default
118
- // ~/.opensquid resolution.
119
- const childEnv = {
120
- ...process.env,
121
- OPENSQUID_CHAT_DAEMON: "1",
122
- };
123
- if (options.dataRoot)
124
- childEnv.OPENSQUID_HOME = options.dataRoot;
125
- const child = spawn(nodeBin, [entrypoint, "chat-daemon-worker"], {
126
- detached: true,
127
- stdio: ["ignore", childLogFd, childLogFd],
128
- env: childEnv,
129
- });
130
- // unref so the parent (this process) can exit without waiting for the
131
- // child. The child is now an independent process group leader because
132
- // of detached:true.
133
- child.unref();
134
- fsSync.closeSync(childLogFd);
135
- if (!child.pid) {
136
- throw new Error("chat-daemon: spawn returned no pid");
137
- }
138
- // The worker writes its OWN pidfile on startup (so the recorded pid
139
- // is the worker's, not a stale spawn-only value). Wait briefly for
140
- // the pidfile to appear; if it doesn't, the worker died on startup.
141
- // The timeout is generous (8s) because a cold-start of `node
142
- // dist/index.js chat-daemon-worker` with the optional grammy /
143
- // discord.js / @slack/* SDKs in the import graph can exceed 3s on
144
- // first invocation. Subsequent starts hit OS file cache and complete
145
- // in <500ms.
146
- const workerPid = await waitForPidfile(paths.pidFile, 8000);
147
- return { already_running: false, pid: workerPid };
148
- }
149
- /**
150
- * Stop a running daemon by sending SIGTERM, then waiting briefly for
151
- * the process to exit and the pidfile to disappear. Falls back to
152
- * SIGKILL after the grace period. Idempotent — a stop against a
153
- * not-running daemon returns `{ stopped: false }` without error.
154
- */
155
- export async function stopDaemon(options = {}) {
156
- const cur = await status(options.dataRoot);
157
- if (!cur.running) {
158
- // Clean up stale pidfile if present.
159
- if (cur.stale_pid !== undefined) {
160
- await fs.unlink(daemonPaths(options.dataRoot).pidFile).catch(() => {
161
- /* race-tolerant */
162
- });
163
- }
164
- return { stopped: false };
165
- }
166
- const grace = options.graceMs ?? 3000;
167
- try {
168
- process.kill(cur.pid, "SIGTERM");
169
- }
170
- catch {
171
- /* already gone */
172
- }
173
- const deadline = Date.now() + grace;
174
- while (Date.now() < deadline) {
175
- if (!isProcessAlive(cur.pid))
176
- break;
177
- await sleep(100);
178
- }
179
- if (isProcessAlive(cur.pid)) {
180
- try {
181
- process.kill(cur.pid, "SIGKILL");
182
- }
183
- catch {
184
- /* already gone */
185
- }
186
- }
187
- // Pidfile cleanup is the worker's job on graceful shutdown — but
188
- // best-effort here for the SIGKILL path.
189
- await fs.unlink(daemonPaths(options.dataRoot).pidFile).catch(() => {
190
- /* race-tolerant */
191
- });
192
- return { stopped: true, pid: cur.pid };
193
- }
194
- function sleep(ms) {
195
- return new Promise((r) => setTimeout(r, ms));
196
- }
197
- async function waitForPidfile(pidFile, timeoutMs) {
198
- const deadline = Date.now() + timeoutMs;
199
- while (Date.now() < deadline) {
200
- try {
201
- const raw = await fs.readFile(pidFile, "utf8");
202
- const pid = parseInt(raw.trim(), 10);
203
- if (Number.isFinite(pid) && pid > 0 && isProcessAlive(pid))
204
- return pid;
205
- }
206
- catch {
207
- /* not yet written */
208
- }
209
- await sleep(50);
210
- }
211
- throw new Error(`chat-daemon: worker did not write pidfile within ${timeoutMs}ms`);
212
- }
213
- /**
214
- * Find the on-disk path of the running opensquid binary so the child
215
- * can re-invoke the same module. Defaults to argv[1] (the script Node
216
- * was invoked with) which is `dist/index.js` for normal usage.
217
- */
218
- function defaultEntrypoint() {
219
- // process.argv[1] may be a relative path when launched via npx; resolve.
220
- return path.resolve(process.argv[1] ?? "dist/index.js");
221
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/lifecycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAQvD,MAAM,UAAU,WAAW,CAAC,QAAiB;IAC3C,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO;QACL,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC;QAC3C,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,iBAAiB,CAAC;QAC3C,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,kBAAkB,CAAC;KAC9C,CAAC;AACJ,CAAC;AAMD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,QAAiB;IAC5C,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC1D,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACjE,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;IACpE,IAAI,SAAS,GAAkB,IAAI,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1C,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,eAAe;IACjB,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC;AAED,yFAAyF;AACzF,SAAS,cAAc,CAAC,GAAW;IACjC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;QACjD,OAAO,IAAI,KAAK,OAAO,CAAC,CAAC,iDAAiD;IAC5E,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,UAAwE,EAAE;IAE1E,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,GAAG,CAAC,OAAO;QAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;IAEhE,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAChC,MAAM,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YACxC,mBAAmB;QACrB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,gEAAgE;IAChE,kEAAkE;IAClE,gEAAgE;IAChE,cAAc;IACd,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,KAAK,CACf,6BAA6B,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,QAAQ;YAC3D,QAAQ,EAAE,CAAC,QAAQ,EAAE,SAAS,OAAO,CAAC,OAAO,aAAa,OAAO,CAAC,QAAQ,IAAI,CACjF,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,oEAAoE;IACpE,gDAAgD;IAChD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAEvD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;IACpD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,iBAAiB,EAAE,CAAC;IAC7D,gEAAgE;IAChE,+DAA+D;IAC/D,kEAAkE;IAClE,2BAA2B;IAC3B,MAAM,QAAQ,GAAsB;QAClC,GAAG,OAAO,CAAC,GAAG;QACd,qBAAqB,EAAE,GAAG;KAC3B,CAAC;IACF,IAAI,OAAO,CAAC,QAAQ;QAAE,QAAQ,CAAC,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC;IACjE,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,oBAAoB,CAAC,EAAE;QAC/D,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC;QACzC,GAAG,EAAE,QAAQ;KACd,CAAC,CAAC;IAEH,sEAAsE;IACtE,sEAAsE;IACtE,oBAAoB;IACpB,KAAK,CAAC,KAAK,EAAE,CAAC;IACd,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAE7B,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;IACxD,CAAC;IAED,oEAAoE;IACpE,mEAAmE;IACnE,oEAAoE;IACpE,6DAA6D;IAC7D,+DAA+D;IAC/D,kEAAkE;IAClE,qEAAqE;IACrE,aAAa;IACb,MAAM,SAAS,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5D,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,UAAmD,EAAE;IAErD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,qCAAqC;QACrC,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAChC,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;gBAChE,mBAAmB;YACrB,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC;IACtC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB;IACpB,CAAC;IACD,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IACpC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,MAAM;QACpC,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACnC,CAAC;QAAC,MAAM,CAAC;YACP,kBAAkB;QACpB,CAAC;IACH,CAAC;IACD,iEAAiE;IACjE,yCAAyC;IACzC,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QAChE,mBAAmB;IACrB,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,CAAC;AACzC,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,OAAe,EAAE,SAAiB;IAC9D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IACxC,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC/C,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACrC,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC;gBAAE,OAAO,GAAG,CAAC;QACzE,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;QACD,MAAM,KAAK,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,oDAAoD,SAAS,IAAI,CAAC,CAAC;AACrF,CAAC;AAED;;;;GAIG;AACH,SAAS,iBAAiB;IACxB,yEAAyE;IACzE,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC;AAC1D,CAAC"}
@@ -1,163 +0,0 @@
1
- /**
2
- * chat-daemon lifecycle tests (v0.7.1 Phase A).
3
- *
4
- * Exercise the start/stop/status surface against REAL detached child
5
- * processes — the lifecycle logic IS the contract (fork-detach +
6
- * pidfile + signal handling), so synthetic stubs would prove nothing.
7
- *
8
- * Each test uses a tmpdir as the data root so multiple test runs don't
9
- * collide on the shared ~/.opensquid/chat-daemon.pid path, and so a
10
- * crashed test doesn't poison a real chat-daemon install.
11
- */
12
- import { promises as fs } from "node:fs";
13
- import * as os from "node:os";
14
- import * as path from "node:path";
15
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
16
- import { daemonPaths, startDaemon, status, stopDaemon } from "./lifecycle.js";
17
- // Resolve to a real on-disk dist/index.js so the spawned worker can
18
- // actually run. Tests assume `npm run build` has been done; vitest's
19
- // suite runner triggers tsc when the build step is wired upstream.
20
- const REPO_ROOT = path.resolve(__dirname, "../../..");
21
- const ENTRYPOINT = path.join(REPO_ROOT, "dist", "index.js");
22
- let tmpDataRoot;
23
- beforeEach(async () => {
24
- tmpDataRoot = await fs.mkdtemp(path.join(os.tmpdir(), "opensquid-daemon-test-"));
25
- });
26
- afterEach(async (ctx) => {
27
- // On failure, dump the log + tmpdir contents before cleanup so we can
28
- // see what the daemon was up to. Vitest exposes the task state on ctx.
29
- if (ctx.task.result?.state === "fail") {
30
- try {
31
- const entries = await fs.readdir(tmpDataRoot);
32
- // eslint-disable-next-line no-console
33
- console.log(`[test debug] ${tmpDataRoot} entries: ${JSON.stringify(entries)}`);
34
- }
35
- catch {
36
- // eslint-disable-next-line no-console
37
- console.log(`[test debug] tmpDataRoot ${tmpDataRoot} missing`);
38
- }
39
- try {
40
- const log = await fs.readFile(path.join(tmpDataRoot, "chat-daemon.log"), "utf8");
41
- // eslint-disable-next-line no-console
42
- console.log(`[test debug] ${tmpDataRoot}/chat-daemon.log:\n${log}`);
43
- }
44
- catch {
45
- // eslint-disable-next-line no-console
46
- console.log(`[test debug] no chat-daemon.log in ${tmpDataRoot}`);
47
- }
48
- }
49
- // Best-effort: stop any daemon that's still running from a failed
50
- // test, then rm the tmp root.
51
- try {
52
- await stopDaemon({ dataRoot: tmpDataRoot });
53
- }
54
- catch {
55
- /* ignore */
56
- }
57
- await fs.rm(tmpDataRoot, { recursive: true, force: true });
58
- });
59
- function dataRootEnv() {
60
- return { dataRoot: tmpDataRoot, entrypoint: ENTRYPOINT };
61
- }
62
- describe("daemonPaths", () => {
63
- it("derives pid/log/sock paths from the data root", () => {
64
- const p = daemonPaths(tmpDataRoot);
65
- expect(p.pidFile).toBe(path.join(tmpDataRoot, "chat-daemon.pid"));
66
- expect(p.logFile).toBe(path.join(tmpDataRoot, "chat-daemon.log"));
67
- expect(p.sockFile).toBe(path.join(tmpDataRoot, "chat-daemon.sock"));
68
- });
69
- });
70
- describe("status (before any start)", () => {
71
- it("reports not-running when pidfile is absent", async () => {
72
- const s = await status(tmpDataRoot);
73
- expect(s.running).toBe(false);
74
- expect("stale_pid" in s ? s.stale_pid : undefined).toBeUndefined();
75
- });
76
- it("reports stale_pid when pidfile points at a dead pid", async () => {
77
- // pid 999999 is overwhelmingly unlikely to be a live process.
78
- const paths = daemonPaths(tmpDataRoot);
79
- await fs.mkdir(path.dirname(paths.pidFile), { recursive: true });
80
- await fs.writeFile(paths.pidFile, "999999\n");
81
- const s = await status(tmpDataRoot);
82
- expect(s.running).toBe(false);
83
- expect("stale_pid" in s ? s.stale_pid : undefined).toBe(999999);
84
- });
85
- it("reports not-running on a malformed pidfile (not a number)", async () => {
86
- const paths = daemonPaths(tmpDataRoot);
87
- await fs.mkdir(path.dirname(paths.pidFile), { recursive: true });
88
- await fs.writeFile(paths.pidFile, "garbage\n");
89
- const s = await status(tmpDataRoot);
90
- expect(s.running).toBe(false);
91
- });
92
- });
93
- describe("stopDaemon (idempotency)", () => {
94
- it("returns stopped:false when no daemon is running", async () => {
95
- const res = await stopDaemon({ dataRoot: tmpDataRoot });
96
- expect(res.stopped).toBe(false);
97
- });
98
- it("cleans up a stale pidfile during stop()", async () => {
99
- const paths = daemonPaths(tmpDataRoot);
100
- await fs.mkdir(path.dirname(paths.pidFile), { recursive: true });
101
- await fs.writeFile(paths.pidFile, "999999\n");
102
- await stopDaemon({ dataRoot: tmpDataRoot });
103
- // Pidfile should be gone.
104
- await expect(fs.access(paths.pidFile)).rejects.toThrow();
105
- });
106
- });
107
- describe("startDaemon + stopDaemon (end-to-end)", () => {
108
- it("starts, reports running, then stops cleanly", async () => {
109
- const env = dataRootEnv();
110
- const startRes = await startDaemon(env);
111
- expect(startRes.already_running).toBe(false);
112
- expect(startRes.pid).toBeGreaterThan(0);
113
- const s = await status(env.dataRoot);
114
- expect(s.running).toBe(true);
115
- if (s.running) {
116
- expect(s.pid).toBe(startRes.pid);
117
- }
118
- const stopRes = await stopDaemon({ dataRoot: env.dataRoot });
119
- expect(stopRes.stopped).toBe(true);
120
- expect(stopRes.pid).toBe(startRes.pid);
121
- // Pidfile cleaned up.
122
- const after = await status(env.dataRoot);
123
- expect(after.running).toBe(false);
124
- }, 15000);
125
- it("is idempotent: a second start() returns already_running:true with the same pid", async () => {
126
- const env = dataRootEnv();
127
- const first = await startDaemon(env);
128
- expect(first.already_running).toBe(false);
129
- const second = await startDaemon(env);
130
- expect(second.already_running).toBe(true);
131
- expect(second.pid).toBe(first.pid);
132
- await stopDaemon({ dataRoot: env.dataRoot });
133
- }, 15000);
134
- it("writes daemon boot lines to the log file", async () => {
135
- const env = dataRootEnv();
136
- await startDaemon(env);
137
- // Give the worker a beat to emit its boot lines.
138
- await new Promise((r) => setTimeout(r, 600));
139
- const log = await fs.readFile(daemonPaths(env.dataRoot).logFile, "utf8");
140
- expect(log).toContain("=== chat-daemon start @");
141
- expect(log).toContain("worker booted pid=");
142
- await stopDaemon({ dataRoot: env.dataRoot });
143
- }, 15000);
144
- it("survives a stop on a daemon spawned from a different test (stale handling)", async () => {
145
- const env = dataRootEnv();
146
- // First start, then kill the process behind status's back so the
147
- // pidfile becomes stale. Real-world: daemon crashed.
148
- const first = await startDaemon(env);
149
- try {
150
- process.kill(first.pid, "SIGKILL");
151
- }
152
- catch {
153
- /* race */
154
- }
155
- // Wait briefly for the kill to take effect.
156
- await new Promise((r) => setTimeout(r, 200));
157
- const s = await status(env.dataRoot);
158
- expect(s.running).toBe(false);
159
- // Should NOT throw and should report not-stopped (since it wasn't).
160
- const stopRes = await stopDaemon({ dataRoot: env.dataRoot });
161
- expect(stopRes.stopped).toBe(false);
162
- }, 15000);
163
- });
@@ -1,107 +0,0 @@
1
- /**
2
- * chat-daemon ↔ MCP server wire protocol (v0.7.1 Phase B).
3
- *
4
- * Shape: JSON-RPC 2.0 over newline-delimited JSON. One JSON object per
5
- * line; both directions use the same framing. Stateless — the daemon
6
- * doesn't track client connections beyond the lifetime of a single
7
- * request/response pair.
8
- *
9
- * Transport address (set by `daemonPaths().sockFile`):
10
- * - macOS/Linux: ~/.opensquid/chat-daemon.sock (AF_UNIX)
11
- * - Windows: \\.\pipe\opensquid-chat-daemon (named pipe)
12
- * Node's `net.createServer({path})` accepts both shapes transparently;
13
- * `daemonSockAddress()` below returns the right form for the host OS.
14
- *
15
- * Why not gRPC / HTTP / MCP-style stdio? gRPC drags in a 3 MB grpc-js
16
- * dependency that we already explicitly avoided in the engine's
17
- * subprocess design. HTTP needs port allocation + firewall coordination.
18
- * MCP stdio needs a parent-child relationship — but the daemon is
19
- * grandparent / orphan to the MCP servers (it outlives them). Local
20
- * socket + JSON-RPC is the smallest correct surface.
21
- */
22
- /** Send a chat message via the daemon's owned adapter. */
23
- export interface SendParams {
24
- channel: string;
25
- text: string;
26
- replyTo?: string;
27
- /** Telegram forum topic id (v0.7.2). Ignored by adapters that don't support threading. */
28
- threadId?: string;
29
- }
30
- /** v0.7.2 — Create a Telegram forum topic via the daemon's owned bot. */
31
- export interface CreateTopicParams {
32
- platform: "telegram";
33
- chat_id: string;
34
- name: string;
35
- icon_color?: number;
36
- icon_custom_emoji_id?: string;
37
- }
38
- export interface CreateTopicResult {
39
- message_thread_id: number;
40
- name: string;
41
- }
42
- export interface SendResult {
43
- ok: boolean;
44
- platform: string;
45
- message_id: string;
46
- delivered_at: string;
47
- }
48
- /** List the platforms the daemon currently has active adapters for. */
49
- export interface ListChannelsParams {
50
- }
51
- export interface ListChannelsResult {
52
- active_platforms: string[];
53
- uptime_ms: number | null;
54
- /**
55
- * 0.7.4 (#147): platforms whose long-poll lost to a 409 Conflict
56
- * and degraded to outbound-only mode. Surfaced via
57
- * `chat_daemon_status` so operators can diagnose "where did my
58
- * inbound message go?"
59
- */
60
- outbound_only_platforms?: string[];
61
- }
62
- /** Liveness probe for the auto-spawn path. */
63
- export interface PingParams {
64
- }
65
- export interface PingResult {
66
- pong: true;
67
- pid: number;
68
- version: string;
69
- }
70
- export type DaemonMethod = "send" | "list_channels" | "ping" | "create_topic";
71
- export interface JsonRpcRequest<P = unknown> {
72
- jsonrpc: "2.0";
73
- id: number | string;
74
- method: DaemonMethod;
75
- params?: P;
76
- }
77
- export interface JsonRpcSuccess<R = unknown> {
78
- jsonrpc: "2.0";
79
- id: number | string;
80
- result: R;
81
- }
82
- export interface JsonRpcFailure {
83
- jsonrpc: "2.0";
84
- id: number | string | null;
85
- error: {
86
- code: number;
87
- message: string;
88
- data?: unknown;
89
- };
90
- }
91
- export type JsonRpcResponse<R = unknown> = JsonRpcSuccess<R> | JsonRpcFailure;
92
- export declare const JSON_RPC_PARSE_ERROR = -32700;
93
- export declare const JSON_RPC_INVALID_REQUEST = -32600;
94
- export declare const JSON_RPC_METHOD_NOT_FOUND = -32601;
95
- export declare const JSON_RPC_INVALID_PARAMS = -32602;
96
- export declare const JSON_RPC_INTERNAL_ERROR = -32603;
97
- /**
98
- * Return the platform-correct socket address for `net.createServer` /
99
- * `net.connect`. On Unix this is a path on disk; on Windows this is a
100
- * named-pipe path. Node accepts both behind the same `{path}` API.
101
- *
102
- * On Windows we don't actually have a filesystem path to use, so the
103
- * pidfile name (without the .pid suffix) drives the pipe name to keep
104
- * dataRoot isolation working across multiple installs.
105
- */
106
- export declare function daemonSockAddress(dataRoot?: string): string;
107
- //# sourceMappingURL=protocol.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAWH,0DAA0D;AAC1D,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,yEAAyE;AACzE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,uEAAuE;AACvE,MAAM,WAAW,kBAAkB;CAElC;AAED,MAAM,WAAW,kBAAkB;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;CACpC;AAED,8CAA8C;AAC9C,MAAM,WAAW,UAAU;CAE1B;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,eAAe,GAAG,MAAM,GAAG,cAAc,CAAC;AAM9E,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,CAAC;CACZ;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,GAAG,OAAO;IACzC,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,MAAM,EAAE,CAAC,CAAC;CACX;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1D;AAED,MAAM,MAAM,eAAe,CAAC,CAAC,GAAG,OAAO,IAAI,cAAc,CAAC,CAAC,CAAC,GAAG,cAAc,CAAC;AAG9E,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAC3C,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAC/C,eAAO,MAAM,yBAAyB,SAAS,CAAC;AAChD,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAC9C,eAAO,MAAM,uBAAuB,SAAS,CAAC;AAM9C;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAW3D"}
@@ -1,54 +0,0 @@
1
- /**
2
- * chat-daemon ↔ MCP server wire protocol (v0.7.1 Phase B).
3
- *
4
- * Shape: JSON-RPC 2.0 over newline-delimited JSON. One JSON object per
5
- * line; both directions use the same framing. Stateless — the daemon
6
- * doesn't track client connections beyond the lifetime of a single
7
- * request/response pair.
8
- *
9
- * Transport address (set by `daemonPaths().sockFile`):
10
- * - macOS/Linux: ~/.opensquid/chat-daemon.sock (AF_UNIX)
11
- * - Windows: \\.\pipe\opensquid-chat-daemon (named pipe)
12
- * Node's `net.createServer({path})` accepts both shapes transparently;
13
- * `daemonSockAddress()` below returns the right form for the host OS.
14
- *
15
- * Why not gRPC / HTTP / MCP-style stdio? gRPC drags in a 3 MB grpc-js
16
- * dependency that we already explicitly avoided in the engine's
17
- * subprocess design. HTTP needs port allocation + firewall coordination.
18
- * MCP stdio needs a parent-child relationship — but the daemon is
19
- * grandparent / orphan to the MCP servers (it outlives them). Local
20
- * socket + JSON-RPC is the smallest correct surface.
21
- */
22
- import * as os from "node:os";
23
- import * as path from "node:path";
24
- import { daemonPaths } from "./lifecycle.js";
25
- // Standard JSON-RPC error codes (we use the public-rage subset).
26
- export const JSON_RPC_PARSE_ERROR = -32700;
27
- export const JSON_RPC_INVALID_REQUEST = -32600;
28
- export const JSON_RPC_METHOD_NOT_FOUND = -32601;
29
- export const JSON_RPC_INVALID_PARAMS = -32602;
30
- export const JSON_RPC_INTERNAL_ERROR = -32603;
31
- // ---------------------------------------------------------------------
32
- // Socket address — cross-platform
33
- // ---------------------------------------------------------------------
34
- /**
35
- * Return the platform-correct socket address for `net.createServer` /
36
- * `net.connect`. On Unix this is a path on disk; on Windows this is a
37
- * named-pipe path. Node accepts both behind the same `{path}` API.
38
- *
39
- * On Windows we don't actually have a filesystem path to use, so the
40
- * pidfile name (without the .pid suffix) drives the pipe name to keep
41
- * dataRoot isolation working across multiple installs.
42
- */
43
- export function daemonSockAddress(dataRoot) {
44
- const paths = daemonPaths(dataRoot);
45
- if (os.platform() === "win32") {
46
- // Windows named pipe — derive a stable name from the data root so
47
- // tests with tmpdirs and prod with ~/.opensquid don't collide.
48
- // Pipe names live in a flat namespace; hash the dataRoot to a
49
- // short suffix.
50
- const fingerprint = path.basename(path.dirname(paths.sockFile));
51
- return `\\\\.\\pipe\\opensquid-chat-daemon-${fingerprint}`;
52
- }
53
- return paths.sockFile;
54
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src.legacy/chat/daemon/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AA2F7C,iEAAiE;AACjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,KAAK,CAAC;AAC3C,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,KAAK,CAAC;AAC/C,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,KAAK,CAAC;AAChD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,KAAK,CAAC;AAC9C,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,KAAK,CAAC;AAE9C,wEAAwE;AACxE,kCAAkC;AAClC,wEAAwE;AAExE;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAiB;IACjD,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,EAAE,CAAC,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC9B,kEAAkE;QAClE,+DAA+D;QAC/D,8DAA8D;QAC9D,gBAAgB;QAChB,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QAChE,OAAO,sCAAsC,WAAW,EAAE,CAAC;IAC7D,CAAC;IACD,OAAO,KAAK,CAAC,QAAQ,CAAC;AACxB,CAAC"}