opensquid 0.5.441 → 0.5.447

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 (380) 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/runtime/bootstrap.d.ts.map +1 -1
  11. package/dist/runtime/bootstrap.js +2 -0
  12. package/dist/runtime/bootstrap.js.map +1 -1
  13. package/dist/runtime/handoff/render.d.ts +5 -4
  14. package/dist/runtime/handoff/render.d.ts.map +1 -1
  15. package/dist/runtime/handoff/render.js +7 -7
  16. package/dist/runtime/handoff/render.js.map +1 -1
  17. package/dist/runtime/hooks/active_task_mirror.js +0 -0
  18. package/dist/runtime/hooks/apply_patch.js +0 -0
  19. package/dist/runtime/hooks/dispatch.js +0 -0
  20. package/dist/runtime/hooks/hook_output.js +0 -0
  21. package/dist/runtime/hooks/memory_reconcile.js +0 -0
  22. package/dist/runtime/hooks/new_project_detect.js +0 -0
  23. package/dist/runtime/hooks/profession_resolver.js +0 -0
  24. package/dist/runtime/hooks/scope_intent.js +0 -0
  25. package/dist/runtime/hooks/session_id.js +0 -0
  26. package/dist/runtime/hooks/session_liveness.js +0 -0
  27. package/dist/runtime/hooks/stop_drive.js +0 -0
  28. package/dist/runtime/hooks/stop_stream.js +0 -0
  29. package/dist/runtime/hooks/subagent_guard.js +0 -0
  30. package/dist/runtime/hooks/transcript.js +0 -0
  31. package/dist/runtime/hooks/transcript_tasks.js +0 -0
  32. package/dist/runtime/ralph/orchestrator.d.ts.map +1 -1
  33. package/dist/runtime/ralph/orchestrator.js +2 -1
  34. package/dist/runtime/ralph/orchestrator.js.map +1 -1
  35. package/dist/setup/cli/limits_state.d.ts.map +1 -1
  36. package/dist/setup/cli/limits_state.js +6 -40
  37. package/dist/setup/cli/limits_state.js.map +1 -1
  38. package/dist/setup/cli/pack_walk.d.ts +32 -0
  39. package/dist/setup/cli/pack_walk.d.ts.map +1 -0
  40. package/dist/setup/cli/pack_walk.js +76 -0
  41. package/dist/setup/cli/pack_walk.js.map +1 -0
  42. package/dist/setup/cli/permissions_state.d.ts.map +1 -1
  43. package/dist/setup/cli/permissions_state.js +6 -37
  44. package/dist/setup/cli/permissions_state.js.map +1 -1
  45. package/dist/setup/cli/triggers_state.d.ts.map +1 -1
  46. package/dist/setup/cli/triggers_state.js +3 -29
  47. package/dist/setup/cli/triggers_state.js.map +1 -1
  48. package/dist/workgraph/events.d.ts.map +1 -1
  49. package/dist/workgraph/events.js +10 -0
  50. package/dist/workgraph/events.js.map +1 -1
  51. package/dist/workgraph/store.d.ts.map +1 -1
  52. package/dist/workgraph/store.js +5 -0
  53. package/dist/workgraph/store.js.map +1 -1
  54. package/dist/workgraph/types.d.ts +2 -1
  55. package/dist/workgraph/types.d.ts.map +1 -1
  56. package/docs/ARCHITECTURE.md +268 -0
  57. package/package.json +5 -3
  58. package/packs/builtin/coding-flow/skills/entry-and-handoffs/skill.yaml +13 -17
  59. package/dist/anti-drift/evaluator.d.ts +0 -88
  60. package/dist/anti-drift/evaluator.d.ts.map +0 -1
  61. package/dist/anti-drift/evaluator.js +0 -417
  62. package/dist/anti-drift/evaluator.js.map +0 -1
  63. package/dist/anti-drift/evaluator.test.js +0 -78
  64. package/dist/anti-drift/rules.d.ts +0 -80
  65. package/dist/anti-drift/rules.d.ts.map +0 -1
  66. package/dist/anti-drift/rules.js +0 -368
  67. package/dist/anti-drift/rules.js.map +0 -1
  68. package/dist/anti-drift/rules.test.js +0 -213
  69. package/dist/anti-drift/state.d.ts +0 -107
  70. package/dist/anti-drift/state.d.ts.map +0 -1
  71. package/dist/anti-drift/state.js +0 -177
  72. package/dist/anti-drift/state.js.map +0 -1
  73. package/dist/anti-drift/state.test.js +0 -120
  74. package/dist/chat/adapters/discord.d.ts +0 -41
  75. package/dist/chat/adapters/discord.d.ts.map +0 -1
  76. package/dist/chat/adapters/discord.js +0 -176
  77. package/dist/chat/adapters/discord.js.map +0 -1
  78. package/dist/chat/adapters/discord.test.js +0 -25
  79. package/dist/chat/adapters/slack.d.ts +0 -43
  80. package/dist/chat/adapters/slack.d.ts.map +0 -1
  81. package/dist/chat/adapters/slack.js +0 -172
  82. package/dist/chat/adapters/slack.js.map +0 -1
  83. package/dist/chat/adapters/slack.test.js +0 -30
  84. package/dist/chat/adapters/telegram.d.ts +0 -148
  85. package/dist/chat/adapters/telegram.d.ts.map +0 -1
  86. package/dist/chat/adapters/telegram.js +0 -498
  87. package/dist/chat/adapters/telegram.js.map +0 -1
  88. package/dist/chat/adapters/telegram.test.js +0 -94
  89. package/dist/chat/config.d.ts +0 -98
  90. package/dist/chat/config.d.ts.map +0 -1
  91. package/dist/chat/config.js +0 -185
  92. package/dist/chat/config.js.map +0 -1
  93. package/dist/chat/daemon/active-project.d.ts +0 -17
  94. package/dist/chat/daemon/active-project.d.ts.map +0 -1
  95. package/dist/chat/daemon/active-project.js +0 -23
  96. package/dist/chat/daemon/active-project.js.map +0 -1
  97. package/dist/chat/daemon/autospawn.d.ts +0 -40
  98. package/dist/chat/daemon/autospawn.d.ts.map +0 -1
  99. package/dist/chat/daemon/autospawn.js +0 -129
  100. package/dist/chat/daemon/autospawn.js.map +0 -1
  101. package/dist/chat/daemon/autospawn.test.js +0 -112
  102. package/dist/chat/daemon/cli.d.ts +0 -18
  103. package/dist/chat/daemon/cli.d.ts.map +0 -1
  104. package/dist/chat/daemon/cli.js +0 -71
  105. package/dist/chat/daemon/cli.js.map +0 -1
  106. package/dist/chat/daemon/collisions.js +0 -384
  107. package/dist/chat/daemon/health-check.d.ts +0 -69
  108. package/dist/chat/daemon/health-check.d.ts.map +0 -1
  109. package/dist/chat/daemon/health-check.js +0 -112
  110. package/dist/chat/daemon/health-check.js.map +0 -1
  111. package/dist/chat/daemon/inbox-read.d.ts +0 -35
  112. package/dist/chat/daemon/inbox-read.d.ts.map +0 -1
  113. package/dist/chat/daemon/inbox-read.js +0 -75
  114. package/dist/chat/daemon/inbox-read.js.map +0 -1
  115. package/dist/chat/daemon/inbox-read.test.js +0 -97
  116. package/dist/chat/daemon/inbox.d.ts +0 -63
  117. package/dist/chat/daemon/inbox.d.ts.map +0 -1
  118. package/dist/chat/daemon/inbox.js +0 -56
  119. package/dist/chat/daemon/inbox.js.map +0 -1
  120. package/dist/chat/daemon/inbox.test.js +0 -110
  121. package/dist/chat/daemon/lifecycle.d.ts +0 -71
  122. package/dist/chat/daemon/lifecycle.d.ts.map +0 -1
  123. package/dist/chat/daemon/lifecycle.js +0 -221
  124. package/dist/chat/daemon/lifecycle.js.map +0 -1
  125. package/dist/chat/daemon/lifecycle.test.js +0 -163
  126. package/dist/chat/daemon/protocol.d.ts +0 -107
  127. package/dist/chat/daemon/protocol.d.ts.map +0 -1
  128. package/dist/chat/daemon/protocol.js +0 -54
  129. package/dist/chat/daemon/protocol.js.map +0 -1
  130. package/dist/chat/daemon/routing.d.ts +0 -140
  131. package/dist/chat/daemon/routing.d.ts.map +0 -1
  132. package/dist/chat/daemon/routing.js +0 -198
  133. package/dist/chat/daemon/routing.js.map +0 -1
  134. package/dist/chat/daemon/routing.test.js +0 -259
  135. package/dist/chat/daemon/rpc-client.d.ts +0 -45
  136. package/dist/chat/daemon/rpc-client.d.ts.map +0 -1
  137. package/dist/chat/daemon/rpc-client.js +0 -133
  138. package/dist/chat/daemon/rpc-client.js.map +0 -1
  139. package/dist/chat/daemon/rpc-server.d.ts +0 -39
  140. package/dist/chat/daemon/rpc-server.d.ts.map +0 -1
  141. package/dist/chat/daemon/rpc-server.js +0 -385
  142. package/dist/chat/daemon/rpc-server.js.map +0 -1
  143. package/dist/chat/daemon/rpc.test.js +0 -177
  144. package/dist/chat/daemon/subscribers.js +0 -257
  145. package/dist/chat/daemon/worker.d.ts +0 -27
  146. package/dist/chat/daemon/worker.d.ts.map +0 -1
  147. package/dist/chat/daemon/worker.js +0 -313
  148. package/dist/chat/daemon/worker.js.map +0 -1
  149. package/dist/chat/daemon/workspace-topic.js +0 -324
  150. package/dist/chat/env-token.d.ts +0 -60
  151. package/dist/chat/env-token.d.ts.map +0 -1
  152. package/dist/chat/env-token.js +0 -137
  153. package/dist/chat/env-token.js.map +0 -1
  154. package/dist/chat/env-token.test.js +0 -160
  155. package/dist/chat/factory.d.ts +0 -30
  156. package/dist/chat/factory.d.ts.map +0 -1
  157. package/dist/chat/factory.js +0 -50
  158. package/dist/chat/factory.js.map +0 -1
  159. package/dist/chat/factory.test.js +0 -55
  160. package/dist/chat/gateway.d.ts +0 -176
  161. package/dist/chat/gateway.d.ts.map +0 -1
  162. package/dist/chat/gateway.js +0 -146
  163. package/dist/chat/gateway.js.map +0 -1
  164. package/dist/chat/gateway.test.js +0 -192
  165. package/dist/claude-md.d.ts +0 -39
  166. package/dist/claude-md.d.ts.map +0 -1
  167. package/dist/claude-md.js +0 -113
  168. package/dist/claude-md.js.map +0 -1
  169. package/dist/claude-md.test.js +0 -91
  170. package/dist/codex/activate.d.ts +0 -66
  171. package/dist/codex/activate.d.ts.map +0 -1
  172. package/dist/codex/activate.js +0 -329
  173. package/dist/codex/activate.js.map +0 -1
  174. package/dist/codex/activate.test.js +0 -229
  175. package/dist/codex/bundled-default/bundled-default.test.js +0 -161
  176. package/dist/codex/cli-publish.test.js +0 -133
  177. package/dist/codex/cli.d.ts +0 -35
  178. package/dist/codex/cli.d.ts.map +0 -1
  179. package/dist/codex/cli.js +0 -554
  180. package/dist/codex/cli.js.map +0 -1
  181. package/dist/codex/cli.test.js +0 -277
  182. package/dist/codex/import-skill-md.d.ts +0 -53
  183. package/dist/codex/import-skill-md.d.ts.map +0 -1
  184. package/dist/codex/import-skill-md.js +0 -236
  185. package/dist/codex/import-skill-md.js.map +0 -1
  186. package/dist/codex/import-skill-md.test.js +0 -225
  187. package/dist/codex/loader.d.ts +0 -27
  188. package/dist/codex/loader.d.ts.map +0 -1
  189. package/dist/codex/loader.js +0 -86
  190. package/dist/codex/loader.js.map +0 -1
  191. package/dist/codex/loader.test.js +0 -75
  192. package/dist/codex/parse.d.ts +0 -28
  193. package/dist/codex/parse.d.ts.map +0 -1
  194. package/dist/codex/parse.js +0 -309
  195. package/dist/codex/parse.js.map +0 -1
  196. package/dist/codex/parse.test.js +0 -241
  197. package/dist/codex/store.d.ts +0 -87
  198. package/dist/codex/store.d.ts.map +0 -1
  199. package/dist/codex/store.js +0 -205
  200. package/dist/codex/store.js.map +0 -1
  201. package/dist/codex/store.test.js +0 -242
  202. package/dist/codex/types.d.ts +0 -398
  203. package/dist/codex/types.d.ts.map +0 -1
  204. package/dist/codex/types.js +0 -21
  205. package/dist/codex/types.js.map +0 -1
  206. package/dist/config.d.ts +0 -53
  207. package/dist/config.d.ts.map +0 -1
  208. package/dist/config.js +0 -202
  209. package/dist/config.js.map +0 -1
  210. package/dist/config.test.js +0 -117
  211. package/dist/engine/cli.d.ts +0 -14
  212. package/dist/engine/cli.d.ts.map +0 -1
  213. package/dist/engine/cli.js +0 -171
  214. package/dist/engine/cli.js.map +0 -1
  215. package/dist/engine/client.d.ts +0 -219
  216. package/dist/engine/client.d.ts.map +0 -1
  217. package/dist/engine/client.js +0 -312
  218. package/dist/engine/client.js.map +0 -1
  219. package/dist/engine/config.d.ts +0 -62
  220. package/dist/engine/config.d.ts.map +0 -1
  221. package/dist/engine/config.js +0 -223
  222. package/dist/engine/config.js.map +0 -1
  223. package/dist/engine/index.d.ts +0 -17
  224. package/dist/engine/index.d.ts.map +0 -1
  225. package/dist/engine/index.js +0 -16
  226. package/dist/engine/index.js.map +0 -1
  227. package/dist/engine/resolver.d.ts +0 -62
  228. package/dist/engine/resolver.d.ts.map +0 -1
  229. package/dist/engine/resolver.js +0 -103
  230. package/dist/engine/resolver.js.map +0 -1
  231. package/dist/engine/singleton.d.ts +0 -95
  232. package/dist/engine/singleton.d.ts.map +0 -1
  233. package/dist/engine/singleton.js +0 -325
  234. package/dist/engine/singleton.js.map +0 -1
  235. package/dist/engine/types.d.ts +0 -402
  236. package/dist/engine/types.d.ts.map +0 -1
  237. package/dist/engine/types.js +0 -22
  238. package/dist/engine/types.js.map +0 -1
  239. package/dist/engine-binary-resolver.js +0 -110
  240. package/dist/engine-binary-resolver.test.js +0 -61
  241. package/dist/engine-cli.js +0 -60
  242. package/dist/engine-client.js +0 -301
  243. package/dist/engine-client.test.js +0 -118
  244. package/dist/functions/chain_state.d.ts +0 -51
  245. package/dist/functions/chain_state.d.ts.map +0 -1
  246. package/dist/functions/chain_state.js +0 -59
  247. package/dist/functions/chain_state.js.map +0 -1
  248. package/dist/hooks/drift-catalog.d.ts +0 -68
  249. package/dist/hooks/drift-catalog.d.ts.map +0 -1
  250. package/dist/hooks/drift-catalog.js +0 -184
  251. package/dist/hooks/drift-catalog.js.map +0 -1
  252. package/dist/hooks/drift-catalog.test.js +0 -154
  253. package/dist/hooks/drift-patterns.d.ts +0 -110
  254. package/dist/hooks/drift-patterns.d.ts.map +0 -1
  255. package/dist/hooks/drift-patterns.js +0 -289
  256. package/dist/hooks/drift-patterns.js.map +0 -1
  257. package/dist/hooks/drift-patterns.test.js +0 -325
  258. package/dist/hooks/engine-vocab-gate.d.ts +0 -108
  259. package/dist/hooks/engine-vocab-gate.d.ts.map +0 -1
  260. package/dist/hooks/engine-vocab-gate.js +0 -225
  261. package/dist/hooks/engine-vocab-gate.js.map +0 -1
  262. package/dist/hooks/engine-vocab-gate.test.js +0 -170
  263. package/dist/hooks/heartbeat.d.ts +0 -107
  264. package/dist/hooks/heartbeat.d.ts.map +0 -1
  265. package/dist/hooks/heartbeat.js +0 -316
  266. package/dist/hooks/heartbeat.js.map +0 -1
  267. package/dist/hooks/heartbeat.test.js +0 -393
  268. package/dist/hooks/honesty-ledger-session-scope.test.js +0 -100
  269. package/dist/hooks/honesty-ledger.d.ts +0 -123
  270. package/dist/hooks/honesty-ledger.d.ts.map +0 -1
  271. package/dist/hooks/honesty-ledger.js +0 -226
  272. package/dist/hooks/honesty-ledger.js.map +0 -1
  273. package/dist/hooks/honesty-ledger.test.js +0 -466
  274. package/dist/hooks/inline-report-check.d.ts +0 -63
  275. package/dist/hooks/inline-report-check.d.ts.map +0 -1
  276. package/dist/hooks/inline-report-check.js +0 -88
  277. package/dist/hooks/inline-report-check.js.map +0 -1
  278. package/dist/hooks/inline-report-check.test.js +0 -96
  279. package/dist/hooks/pre-tool-use.d.ts +0 -62
  280. package/dist/hooks/pre-tool-use.d.ts.map +0 -1
  281. package/dist/hooks/pre-tool-use.js +0 -342
  282. package/dist/hooks/pre-tool-use.js.map +0 -1
  283. package/dist/hooks/pre-tool-use.test.js +0 -134
  284. package/dist/hooks/session-end.d.ts +0 -15
  285. package/dist/hooks/session-end.d.ts.map +0 -1
  286. package/dist/hooks/session-end.js +0 -60
  287. package/dist/hooks/session-end.js.map +0 -1
  288. package/dist/hooks/session-end.test.js +0 -52
  289. package/dist/hooks/stop.d.ts +0 -35
  290. package/dist/hooks/stop.d.ts.map +0 -1
  291. package/dist/hooks/stop.js +0 -136
  292. package/dist/hooks/stop.js.map +0 -1
  293. package/dist/hooks/transcript-active-task.test.js +0 -342
  294. package/dist/hooks/transcript.d.ts +0 -26
  295. package/dist/hooks/transcript.d.ts.map +0 -1
  296. package/dist/hooks/transcript.js +0 -266
  297. package/dist/hooks/transcript.js.map +0 -1
  298. package/dist/hooks/transcript.test.js +0 -103
  299. package/dist/hooks/user-prompt-submit.d.ts +0 -74
  300. package/dist/hooks/user-prompt-submit.d.ts.map +0 -1
  301. package/dist/hooks/user-prompt-submit.js +0 -256
  302. package/dist/hooks/user-prompt-submit.js.map +0 -1
  303. package/dist/hooks/user-prompt-submit.test.js +0 -118
  304. package/dist/hooks/versioning-gate.d.ts +0 -101
  305. package/dist/hooks/versioning-gate.d.ts.map +0 -1
  306. package/dist/hooks/versioning-gate.js +0 -245
  307. package/dist/hooks/versioning-gate.js.map +0 -1
  308. package/dist/hooks/versioning-gate.test.js +0 -368
  309. package/dist/hooks/workflow-gate.d.ts +0 -64
  310. package/dist/hooks/workflow-gate.d.ts.map +0 -1
  311. package/dist/hooks/workflow-gate.js +0 -152
  312. package/dist/hooks/workflow-gate.js.map +0 -1
  313. package/dist/hooks/workflow-gate.test.js +0 -197
  314. package/dist/hooks-cli.d.ts +0 -25
  315. package/dist/hooks-cli.d.ts.map +0 -1
  316. package/dist/hooks-cli.js +0 -286
  317. package/dist/hooks-cli.js.map +0 -1
  318. package/dist/hooks-cli.test.js +0 -148
  319. package/dist/origin.d.ts +0 -16
  320. package/dist/origin.d.ts.map +0 -1
  321. package/dist/origin.js +0 -92
  322. package/dist/origin.js.map +0 -1
  323. package/dist/packs/seed_lessons_ingest.d.ts +0 -30
  324. package/dist/packs/seed_lessons_ingest.d.ts.map +0 -1
  325. package/dist/packs/seed_lessons_ingest.js +0 -107
  326. package/dist/packs/seed_lessons_ingest.js.map +0 -1
  327. package/dist/project-cli.d.ts +0 -7
  328. package/dist/project-cli.d.ts.map +0 -1
  329. package/dist/project-cli.js +0 -145
  330. package/dist/project-cli.js.map +0 -1
  331. package/dist/project.d.ts +0 -127
  332. package/dist/project.d.ts.map +0 -1
  333. package/dist/project.js +0 -281
  334. package/dist/project.js.map +0 -1
  335. package/dist/project.test.js +0 -287
  336. package/dist/rag/backends/loop_engine.d.ts +0 -61
  337. package/dist/rag/backends/loop_engine.d.ts.map +0 -1
  338. package/dist/rag/backends/loop_engine.js +0 -160
  339. package/dist/rag/backends/loop_engine.js.map +0 -1
  340. package/dist/recall.d.ts +0 -82
  341. package/dist/recall.d.ts.map +0 -1
  342. package/dist/recall.js +0 -81
  343. package/dist/recall.js.map +0 -1
  344. package/dist/runtime/agent_bridge/autospawn.d.ts +0 -131
  345. package/dist/runtime/agent_bridge/autospawn.d.ts.map +0 -1
  346. package/dist/runtime/agent_bridge/autospawn.js +0 -251
  347. package/dist/runtime/agent_bridge/autospawn.js.map +0 -1
  348. package/dist/runtime/chain_state.d.ts +0 -124
  349. package/dist/runtime/chain_state.d.ts.map +0 -1
  350. package/dist/runtime/chain_state.js +0 -189
  351. package/dist/runtime/chain_state.js.map +0 -1
  352. package/dist/runtime/hooks/permission_decision.d.ts +0 -34
  353. package/dist/runtime/hooks/permission_decision.d.ts.map +0 -1
  354. package/dist/runtime/hooks/permission_decision.js +0 -39
  355. package/dist/runtime/hooks/permission_decision.js.map +0 -1
  356. package/dist/runtime/workflow_fsm.d.ts +0 -21
  357. package/dist/runtime/workflow_fsm.d.ts.map +0 -1
  358. package/dist/runtime/workflow_fsm.js +0 -25
  359. package/dist/runtime/workflow_fsm.js.map +0 -1
  360. package/dist/runtime/workflow_map.d.ts +0 -26
  361. package/dist/runtime/workflow_map.d.ts.map +0 -1
  362. package/dist/runtime/workflow_map.js +0 -38
  363. package/dist/runtime/workflow_map.js.map +0 -1
  364. package/dist/scope.d.ts +0 -48
  365. package/dist/scope.d.ts.map +0 -1
  366. package/dist/scope.js +0 -111
  367. package/dist/scope.js.map +0 -1
  368. package/dist/setup/cli/topic_create_step.d.ts +0 -84
  369. package/dist/setup/cli/topic_create_step.d.ts.map +0 -1
  370. package/dist/setup/cli/topic_create_step.js +0 -213
  371. package/dist/setup/cli/topic_create_step.js.map +0 -1
  372. package/dist/system-export.d.ts +0 -65
  373. package/dist/system-export.d.ts.map +0 -1
  374. package/dist/system-export.js +0 -194
  375. package/dist/system-export.js.map +0 -1
  376. package/dist/utterance/classifier.d.ts +0 -53
  377. package/dist/utterance/classifier.d.ts.map +0 -1
  378. package/dist/utterance/classifier.js +0 -184
  379. package/dist/utterance/classifier.js.map +0 -1
  380. package/dist/utterance/classifier.test.js +0 -147
@@ -1,256 +0,0 @@
1
- /**
2
- * `opensquid hook user-prompt-submit` — Claude Code UserPromptSubmit
3
- * hook handler.
4
- *
5
- * Fires when the user submits a prompt (start of every new turn).
6
- * Surfaces TWO accumulator surfaces via stdout so the agent sees them
7
- * in its system context:
8
- *
9
- * 1. broken-promises.jsonl — claims from the prior assistant turn
10
- * that the honesty ledger flagged as unfulfilled.
11
- * 2. heartbeat-pending.txt — token-threshold re-anchor nudge written
12
- * by the Stop hook when the transcript grew past the configured
13
- * threshold (default 20K tokens, OPENSQUID_HEARTBEAT_TOKENS).
14
- *
15
- * Both surfaces are CLEARED after surfacing — one chance per item per
16
- * session, no infinite nagging.
17
- *
18
- * Exit 0 always — UserPromptSubmit is observational.
19
- *
20
- * Pre-#124: this hook also surfaced auto-classify-candidates.jsonl
21
- * written by a detached LLM subprocess. Removed alongside the auto-
22
- * classifier deletion — the agent classifies utterances inline per
23
- * CLAUDE.md, and the heartbeat reminds it to re-anchor periodically.
24
- */
25
- import * as crypto from "node:crypto";
26
- import { promises as fs } from "node:fs";
27
- import * as path from "node:path";
28
- import { resolveDataRoot } from "../codex/store.js";
29
- import { consumePendingHeartbeat, markRecallRequired } from "./heartbeat.js";
30
- /**
31
- * 0.7.10 (#164): minimum gap between consecutive UserPromptSubmit
32
- * firings before we consider the session "resumed" rather than
33
- * continuous. 5 minutes is short enough that a coffee-break doesn't
34
- * trigger, long enough that genuine process restarts always do.
35
- */
36
- const RESUME_GAP_MS = 5 * 60 * 1000;
37
- export async function runUserPromptSubmitHook() {
38
- let raw = "";
39
- for await (const chunk of process.stdin) {
40
- raw += chunk;
41
- }
42
- if (!raw.trim())
43
- process.exit(0);
44
- let payload;
45
- try {
46
- payload = JSON.parse(raw);
47
- }
48
- catch {
49
- process.exit(0);
50
- }
51
- const sessionId = payload.session_id;
52
- if (!sessionId)
53
- process.exit(0);
54
- const out = [];
55
- // 0.7.10 (#164): detect resumed sessions and inject a re-anchor
56
- // prompt. The signal is "gap since last UPS firing for this session
57
- // > RESUME_GAP_MS." First firing ever writes the marker without
58
- // injecting (the session just started; no resume happened yet).
59
- const resumeMsg = await detectResumeAndUpdateMarker(sessionId);
60
- if (resumeMsg)
61
- out.push(resumeMsg);
62
- // #112-audit finding 1: read+clear is racy if a writer appends concurrently.
63
- // Rename-then-read atomically claims the file contents — any bytes that
64
- // arrive after the rename land in a fresh file the next consumer will pick up.
65
- const broken = await consumeJsonl(path.join(resolveDataRoot(), "sessions", sessionId, "broken-promises.jsonl"));
66
- if (broken.length > 0) {
67
- out.push("🦑 [opensquid honesty-ledger] unresolved claims from the previous turn:");
68
- for (const p of broken) {
69
- out.push(` 🦑 ${p.claim_id}: "${p.matched_text}" — needed ${p.claim_label}`);
70
- }
71
- out.push("Acknowledge these in your reply: either do the missing action now, or " +
72
- "retract the claim explicitly. Don't repeat the pattern.");
73
- }
74
- // #124: heartbeat nudge surfaces here when Stop hook armed one. The agent
75
- // sees this at the top of its context for the new turn and acts on it
76
- // inline (calls recall, scans for substantive recent user turns, calls
77
- // memorize/remember/promote per CLAUDE.md classify-and-act).
78
- // 0.7.27 / D8 — surface a plan-mirror reminder when the user's
79
- // prompt contains multiple task identifiers in sequence. Catches the
80
- // "166 then 168" → agent does 166 + defers 168 misread.
81
- if (typeof payload.prompt === "string") {
82
- const mirror = detectMultiTaskDirective(payload.prompt);
83
- if (mirror) {
84
- if (out.length > 0)
85
- out.push("");
86
- out.push(mirror);
87
- }
88
- }
89
- const heartbeat = await consumePendingHeartbeat(sessionId);
90
- if (heartbeat) {
91
- if (out.length > 0)
92
- out.push("");
93
- out.push(heartbeat);
94
- // 0.7.26 / D7 — set the recall-required flag. pre-tool-use will
95
- // block any mcp__opensquid__* tool call (other than recall) until
96
- // the agent actually calls recall. Catches the "heartbeat fires,
97
- // agent acknowledges, continues without complying" drift.
98
- try {
99
- await markRecallRequired(sessionId);
100
- }
101
- catch (err) {
102
- process.stderr.write(`[opensquid hook user-prompt-submit] markRecallRequired failed (non-fatal): ${err instanceof Error ? err.message : err}\n`);
103
- }
104
- }
105
- if (out.length > 0) {
106
- process.stdout.write(out.join("\n") + "\n");
107
- }
108
- process.exit(0);
109
- }
110
- /**
111
- * 0.7.27 / D8 — detect a multi-task directive in the user's prompt
112
- * and return a "mirror back your parsed plan" reminder message.
113
- *
114
- * Trigger patterns (case-insensitive):
115
- * - "<num1> then <num2>" — bare-number sequencing (the D8 incident
116
- * shape: user said "166 then 168" — agent did 166 + deferred 168)
117
- * - "first <ref> then <ref>"
118
- * - "after <ref> do <ref>" / "after X then Y"
119
- * - Two or more `#<num>` references
120
- *
121
- * Returns the surface message when a match fires, null otherwise.
122
- * Exported for direct testing.
123
- */
124
- export function detectMultiTaskDirective(prompt) {
125
- const refs = extractTaskRefs(prompt);
126
- if (refs.length < 2)
127
- return null;
128
- return (`🦑 [opensquid] multi-task directive detected (refs: ${refs.slice(0, 5).join(", ")}). ` +
129
- `Per [[feedback_user_words_have_top_weight]] + drift D8: BEFORE executing, ` +
130
- `mirror back your parsed plan ("read as: do X, then do Y") so we catch a ` +
131
- `misread before it ships. Don't auto-defer items the user listed in parallel.`);
132
- }
133
- /**
134
- * Extract probable task references from a user prompt. Returns the
135
- * distinct references in document order, capped at 10.
136
- *
137
- * Heuristics (intentionally narrow to keep false-positives low):
138
- * - `#\d+` shapes always count
139
- * - bare 2-4-digit numbers count IF they're connected by a
140
- * sequencing word ("then" / "after" / "first" / "and then")
141
- *
142
- * Exported for testing.
143
- */
144
- export function extractTaskRefs(prompt) {
145
- const refs = [];
146
- const seen = new Set();
147
- // Pass 1: explicit #N references
148
- for (const m of prompt.matchAll(/#\d+/g)) {
149
- if (!seen.has(m[0])) {
150
- refs.push(m[0]);
151
- seen.add(m[0]);
152
- }
153
- }
154
- // Pass 2: bare-number sequences via "then" / "after" / "first ... then"
155
- // Pattern: two 2-4-digit numbers separated by "then"/"after"/"and then".
156
- for (const m of prompt.matchAll(/\b(\d{2,4})\s*(?:,\s*|\s+(?:then|after|and then|and)\s+)(\d{2,4})\b/gi)) {
157
- for (const num of [m[1], m[2]]) {
158
- const key = `#${num}`;
159
- if (!seen.has(key)) {
160
- refs.push(key);
161
- seen.add(key);
162
- }
163
- }
164
- }
165
- return refs.slice(0, 10);
166
- }
167
- /**
168
- * 0.7.10 (#164): detect resumed sessions by tracking the wall-clock
169
- * gap between consecutive UPS firings. Returns a re-anchor message
170
- * when a gap exceeds RESUME_GAP_MS, OR null when continuous /
171
- * first-ever firing.
172
- *
173
- * Marker file: ~/.opensquid/sessions/<sid>/ups-last-at.txt
174
- * Contents: ISO 8601 timestamp of the last UPS firing.
175
- *
176
- * On EVERY call: read prior timestamp → write current timestamp.
177
- * First call: marker missing → write current; return null (no resume
178
- * happened, just the session starting).
179
- * Subsequent call: gap < RESUME_GAP_MS → continuous (return null).
180
- * Subsequent call: gap >= RESUME_GAP_MS → resumed (return message).
181
- *
182
- * Exported for direct testing.
183
- */
184
- export async function detectResumeAndUpdateMarker(sessionId, options = {}) {
185
- const root = resolveDataRoot(options.dataRoot);
186
- const dir = path.join(root, "sessions", sessionId);
187
- const markerPath = path.join(dir, "ups-last-at.txt");
188
- const nowMs = options.now ?? Date.now();
189
- let prior = null;
190
- try {
191
- const raw = (await fs.readFile(markerPath, "utf8")).trim();
192
- const parsed = Date.parse(raw);
193
- if (Number.isFinite(parsed))
194
- prior = parsed;
195
- }
196
- catch {
197
- /* no marker — first firing */
198
- }
199
- await fs.mkdir(dir, { recursive: true });
200
- await fs.writeFile(markerPath, new Date(nowMs).toISOString() + "\n", "utf8");
201
- if (prior === null)
202
- return null; // first firing for this session
203
- const gapMs = nowMs - prior;
204
- if (gapMs < RESUME_GAP_MS)
205
- return null;
206
- const gapMin = Math.round(gapMs / 60000);
207
- return (`🦑 [opensquid] Session resumed (${gapMin}m since last activity). ` +
208
- `Before continuing, re-anchor: call \`recall\` for the active task, ` +
209
- `scan recent assistant turns for any unfulfilled commitments, and ` +
210
- `re-read any locked rule the next action would touch.`);
211
- }
212
- /**
213
- * Atomically claim a JSONL accumulator file: rename it to a unique
214
- * sibling, then read+parse, then delete the renamed file. Any writer
215
- * that opens the original path after the rename starts a fresh file
216
- * that the next consumer will pick up.
217
- */
218
- async function consumeJsonl(filePath) {
219
- const claimed = `${filePath}.consuming.${crypto.randomUUID()}`;
220
- try {
221
- await fs.rename(filePath, claimed);
222
- }
223
- catch {
224
- // ENOENT — nothing to consume
225
- return [];
226
- }
227
- let raw;
228
- try {
229
- raw = await fs.readFile(claimed, "utf8");
230
- }
231
- catch {
232
- raw = "";
233
- }
234
- try {
235
- await fs.rm(claimed);
236
- }
237
- catch {
238
- // already gone
239
- }
240
- if (!raw.trim())
241
- return [];
242
- const items = [];
243
- for (const line of raw.split("\n")) {
244
- const t = line.trim();
245
- if (!t)
246
- continue;
247
- try {
248
- items.push(JSON.parse(t));
249
- }
250
- catch {
251
- // skip malformed line
252
- }
253
- }
254
- return items;
255
- }
256
- //# sourceMappingURL=user-prompt-submit.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"user-prompt-submit.js","sourceRoot":"","sources":["../../src.legacy/hooks/user-prompt-submit.ts"],"names":[],"mappings":"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"}
@@ -1,118 +0,0 @@
1
- /**
2
- * Tests for UserPromptSubmit hook helpers — focused on the resume-
3
- * detection logic added in 0.7.10 (#164).
4
- */
5
- import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
- import * as crypto from "node:crypto";
7
- import { promises as fs } from "node:fs";
8
- import * as os from "node:os";
9
- import * as path from "node:path";
10
- import { detectMultiTaskDirective, detectResumeAndUpdateMarker, extractTaskRefs, } from "./user-prompt-submit.js";
11
- let tmpRoot;
12
- const SESSION = "test-session";
13
- beforeEach(async () => {
14
- tmpRoot = path.join(os.tmpdir(), `oscli-ups-${crypto.randomUUID()}`);
15
- await fs.mkdir(tmpRoot, { recursive: true });
16
- });
17
- afterEach(async () => {
18
- await fs.rm(tmpRoot, { recursive: true, force: true });
19
- });
20
- describe("detectResumeAndUpdateMarker (#164)", () => {
21
- it("returns null on first firing (no marker yet) but creates the marker", async () => {
22
- const now = Date.parse("2026-05-17T10:00:00Z");
23
- const msg = await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now });
24
- expect(msg).toBeNull();
25
- // Marker should exist with current timestamp.
26
- const written = await fs.readFile(path.join(tmpRoot, "sessions", SESSION, "ups-last-at.txt"), "utf8");
27
- expect(written.trim()).toBe(new Date(now).toISOString());
28
- });
29
- it("returns null when gap < 5 minutes (continuous session)", async () => {
30
- const first = Date.parse("2026-05-17T10:00:00Z");
31
- await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: first });
32
- const second = first + 60 * 1000; // 1 minute later
33
- const msg = await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: second });
34
- expect(msg).toBeNull();
35
- });
36
- it("returns a resume message when gap >= 5 minutes", async () => {
37
- const first = Date.parse("2026-05-17T10:00:00Z");
38
- await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: first });
39
- const second = first + 6 * 60 * 1000; // 6 minutes later
40
- const msg = await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: second });
41
- expect(msg).not.toBeNull();
42
- expect(msg).toContain("Session resumed");
43
- expect(msg).toContain("6m");
44
- expect(msg).toContain("re-anchor");
45
- expect(msg).toContain("recall");
46
- });
47
- it("returns a resume message after a long gap (hours)", async () => {
48
- const first = Date.parse("2026-05-17T00:00:00Z");
49
- await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: first });
50
- const second = first + 8 * 60 * 60 * 1000; // 8 hours later
51
- const msg = await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: second });
52
- expect(msg).not.toBeNull();
53
- expect(msg).toContain("480m"); // 8h * 60min
54
- });
55
- it("updates the marker on every firing (so next gap is measured from the most-recent)", async () => {
56
- const t0 = Date.parse("2026-05-17T10:00:00Z");
57
- await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: t0 });
58
- const t1 = t0 + 60_000;
59
- await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: t1 });
60
- const written = await fs.readFile(path.join(tmpRoot, "sessions", SESSION, "ups-last-at.txt"), "utf8");
61
- expect(written.trim()).toBe(new Date(t1).toISOString());
62
- });
63
- it("returns null at exactly the 5-minute boundary (just under)", async () => {
64
- const first = Date.parse("2026-05-17T10:00:00Z");
65
- await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: first });
66
- const second = first + 5 * 60 * 1000 - 1; // 4m59.999s
67
- const msg = await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now: second });
68
- expect(msg).toBeNull();
69
- });
70
- it("tolerates a corrupt marker file (returns null, overwrites)", async () => {
71
- const dir = path.join(tmpRoot, "sessions", SESSION);
72
- await fs.mkdir(dir, { recursive: true });
73
- await fs.writeFile(path.join(dir, "ups-last-at.txt"), "not a date", "utf8");
74
- const now = Date.parse("2026-05-17T10:00:00Z");
75
- const msg = await detectResumeAndUpdateMarker(SESSION, { dataRoot: tmpRoot, now });
76
- expect(msg).toBeNull();
77
- // Should still have written the new timestamp.
78
- const written = await fs.readFile(path.join(dir, "ups-last-at.txt"), "utf8");
79
- expect(written.trim()).toBe(new Date(now).toISOString());
80
- });
81
- it("isolates per-session (gap on session A doesn't affect session B)", async () => {
82
- const t0 = Date.parse("2026-05-17T10:00:00Z");
83
- await detectResumeAndUpdateMarker("A", { dataRoot: tmpRoot, now: t0 });
84
- // Session B's first firing 6h later — still its FIRST firing, so null.
85
- const tLater = t0 + 6 * 60 * 60 * 1000;
86
- const msgB = await detectResumeAndUpdateMarker("B", { dataRoot: tmpRoot, now: tLater });
87
- expect(msgB).toBeNull();
88
- });
89
- });
90
- describe("detectMultiTaskDirective — D8 (0.7.27)", () => {
91
- it("fires on '166 then 168' (bare-number sequencing — D8 incident shape)", () => {
92
- const m = detectMultiTaskDirective("166 then 168");
93
- expect(m).not.toBeNull();
94
- expect(m).toContain("#166");
95
- expect(m).toContain("#168");
96
- });
97
- it("fires on '#171 then #172' (explicit references)", () => {
98
- expect(detectMultiTaskDirective("#171 then #172")).not.toBeNull();
99
- });
100
- it("fires on '166, 168' comma-separated", () => {
101
- expect(detectMultiTaskDirective("166, 168")).not.toBeNull();
102
- });
103
- it("does NOT fire on a single task reference", () => {
104
- expect(detectMultiTaskDirective("work on #170")).toBeNull();
105
- expect(detectMultiTaskDirective("can you do 168")).toBeNull();
106
- });
107
- it("does NOT fire on unrelated number prose", () => {
108
- // No sequencing connector → no D8 risk.
109
- expect(detectMultiTaskDirective("we shipped 5 patches in 30 minutes")).toBeNull();
110
- });
111
- it("extractTaskRefs returns refs in document order", () => {
112
- expect(extractTaskRefs("166 then 168")).toEqual(["#166", "#168"]);
113
- expect(extractTaskRefs("#171 and #172")).toEqual(["#171", "#172"]);
114
- });
115
- it("extractTaskRefs dedupes references", () => {
116
- expect(extractTaskRefs("#170 then #170")).toEqual(["#170"]);
117
- });
118
- });
@@ -1,101 +0,0 @@
1
- /**
2
- * Versioning gate — pre-commit check enforcing per-commit patch bumps
3
- * (v0.6.3). Wired into the PreToolUse hook for `git commit` commands.
4
- *
5
- * Problem this fixes: I keep batching multiple fixes into one commit
6
- * and bumping the minor (or no bump at all) instead of one patch per
7
- * fix. The discipline rule was memorized (`mem-d2cc0e78`) but rules
8
- * I can ignore aren't structural protection. This gate makes the
9
- * discipline mechanical — if your commit touches source code AND
10
- * doesn't include a manifest version bump in the same commit, it
11
- * gets rejected before `git commit` runs.
12
- *
13
- * Detection:
14
- * 1. `git diff --cached --name-only` → list of staged files
15
- * 2. If no `src/**` files staged → allow (docs/CI/config commits
16
- * don't need version bumps)
17
- * 3. If `src/**` files staged → require a manifest (Cargo.toml or
18
- * package.json) to also be staged with a `version` line diff
19
- * 4. Otherwise → block with actionable message
20
- *
21
- * Fail-open invariant: any error running git or parsing output →
22
- * allow with a stderr warning (per the honesty-ledger + workflow-gate
23
- * precedent — never block on opensquid's own bug).
24
- *
25
- * Emergency override: `OPENSQUID_SKIP_VERSION_GATE=1` bypasses with a
26
- * loud stderr warning. For genuine emergencies (revert commits,
27
- * generated-code-only diffs, etc.) where the discipline doesn't
28
- * apply.
29
- */
30
- export interface VersioningGateInput {
31
- /** Working directory (the repo root). Defaults to process.cwd(). */
32
- cwd?: string;
33
- }
34
- export interface VersioningGateResult {
35
- /** True when the commit should be blocked. */
36
- block: boolean;
37
- /** Stderr message — always present when stderr should be written.
38
- * Non-blocking warnings also use this. */
39
- stderr: string;
40
- }
41
- export declare function evaluateVersioningGate(input?: VersioningGateInput): Promise<VersioningGateResult>;
42
- /**
43
- * Is this a source file that should trigger version-bump enforcement?
44
- * Generous definition: anything under `src/` for any language we support.
45
- */
46
- export declare function isSourceFile(p: string): boolean;
47
- /** Is this the repo's version manifest? */
48
- export declare function isManifestFile(p: string): boolean;
49
- /**
50
- * Parsed version jump from a manifest's staged diff.
51
- *
52
- * 0.7.23 / D5 — added so the gate can surface multi-patch catch-up
53
- * jumps (e.g. 0.7.10 → 0.7.14) which indicate previous src commits
54
- * shipped without bumps.
55
- */
56
- export interface VersionJump {
57
- from: string;
58
- to: string;
59
- }
60
- /**
61
- * Look at the staged diff of a manifest and return the version jump
62
- * (from → to). Returns null when the diff doesn't touch a `version`
63
- * line at all.
64
- *
65
- * Exported for direct testing.
66
- */
67
- export declare function readManifestVersionBump(cwd: string, manifestPath: string): Promise<VersionJump | null>;
68
- /**
69
- * Parse `+`/`-` lines from a manifest diff and extract the version
70
- * jump. Cargo: `version = "..."`. package.json: `"version": "..."`.
71
- *
72
- * Anchor discipline:
73
- * - Cargo (TOML, line-oriented) → anchor `^version` so we don't
74
- * match a dep with `version = "..."` in `[dependencies.foo]`.
75
- * - package.json (JSON, can be MINIFIED single-line) → do NOT
76
- * anchor; `"version"` can appear mid-line in minified JSON.
77
- *
78
- * Exported for direct testing.
79
- */
80
- export declare function parseVersionJumpFromDiff(diff: string): VersionJump | null;
81
- /**
82
- * Detect a multi-patch jump: same major.minor, but patch advances by
83
- * more than 1 (catch-up bump).
84
- *
85
- * Returns false for:
86
- * - First-time bumps (from === "")
87
- * - Same-patch (no actual jump, shouldn't happen with proper diff)
88
- * - Minor/major bumps (those are user-authorized; PATCH-ONLY rule
89
- * forbids the agent from naming them but doesn't make them "drift")
90
- * - Non-SemVer version strings (best-effort parse)
91
- *
92
- * Exported for direct testing.
93
- */
94
- export declare function isMultiPatchJump(jump: VersionJump): boolean;
95
- /**
96
- * Emergency-override env var. Loud stderr warning on bypass so it
97
- * always shows up in scrollback / CI logs. Exported for the test
98
- * suite.
99
- */
100
- export declare function checkOverrideEnv(): boolean;
101
- //# sourceMappingURL=versioning-gate.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"versioning-gate.d.ts","sourceRoot":"","sources":["../../src.legacy/hooks/versioning-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAOH,MAAM,WAAW,mBAAmB;IAClC,oEAAoE;IACpE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,8CAA8C;IAC9C,KAAK,EAAE,OAAO,CAAC;IACf;8CAC0C;IAC1C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,sBAAsB,CAC1C,KAAK,GAAE,mBAAwB,GAC9B,OAAO,CAAC,oBAAoB,CAAC,CAsF/B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAG/C;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAGjD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAY7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAuBzE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAQ3D;AAmCD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAE1C"}