chorus-codes 0.7.0 → 0.7.2

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 (293) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/cache/.previewinfo +1 -1
  4. package/.next/cache/.rscinfo +1 -1
  5. package/.next/cache/.tsbuildinfo +1 -1
  6. package/.next/fallback-build-manifest.json +3 -3
  7. package/.next/prerender-manifest.json +3 -3
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  15. package/.next/server/app/_not-found.html +1 -1
  16. package/.next/server/app/_not-found.rsc +1 -1
  17. package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  18. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  19. package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  20. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  21. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  22. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  23. package/.next/server/app/new.html +1 -1
  24. package/.next/server/app/new.rsc +1 -1
  25. package/.next/server/app/new.segments/_full.segment.rsc +1 -1
  26. package/.next/server/app/new.segments/_head.segment.rsc +1 -1
  27. package/.next/server/app/new.segments/_index.segment.rsc +1 -1
  28. package/.next/server/app/new.segments/_tree.segment.rsc +1 -1
  29. package/.next/server/app/new.segments/new/__PAGE__.segment.rsc +1 -1
  30. package/.next/server/app/new.segments/new.segment.rsc +1 -1
  31. package/.next/server/app/onboarding.html +1 -1
  32. package/.next/server/app/onboarding.rsc +1 -1
  33. package/.next/server/app/onboarding.segments/_full.segment.rsc +1 -1
  34. package/.next/server/app/onboarding.segments/_head.segment.rsc +1 -1
  35. package/.next/server/app/onboarding.segments/_index.segment.rsc +1 -1
  36. package/.next/server/app/onboarding.segments/_tree.segment.rsc +1 -1
  37. package/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +1 -1
  38. package/.next/server/app/onboarding.segments/onboarding.segment.rsc +1 -1
  39. package/.next/server/app/personas.html +1 -1
  40. package/.next/server/app/personas.rsc +1 -1
  41. package/.next/server/app/personas.segments/_full.segment.rsc +1 -1
  42. package/.next/server/app/personas.segments/_head.segment.rsc +1 -1
  43. package/.next/server/app/personas.segments/_index.segment.rsc +1 -1
  44. package/.next/server/app/personas.segments/_tree.segment.rsc +1 -1
  45. package/.next/server/app/personas.segments/personas/__PAGE__.segment.rsc +1 -1
  46. package/.next/server/app/personas.segments/personas.segment.rsc +1 -1
  47. package/.next/server/app/settings.html +1 -1
  48. package/.next/server/app/settings.rsc +1 -1
  49. package/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  50. package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  51. package/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  52. package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  53. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
  54. package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  55. package/.next/server/app/templates.html +1 -1
  56. package/.next/server/app/templates.rsc +1 -1
  57. package/.next/server/app/templates.segments/_full.segment.rsc +1 -1
  58. package/.next/server/app/templates.segments/_head.segment.rsc +1 -1
  59. package/.next/server/app/templates.segments/_index.segment.rsc +1 -1
  60. package/.next/server/app/templates.segments/_tree.segment.rsc +1 -1
  61. package/.next/server/app/templates.segments/templates/__PAGE__.segment.rsc +1 -1
  62. package/.next/server/app/templates.segments/templates.segment.rsc +1 -1
  63. package/.next/server/middleware-build-manifest.js +3 -3
  64. package/.next/server/pages/404.html +1 -1
  65. package/.next/server/pages/500.html +1 -1
  66. package/.next/server/server-reference-manifest.js +1 -1
  67. package/.next/server/server-reference-manifest.json +1 -1
  68. package/.next/trace +1 -1
  69. package/.next/trace-build +1 -1
  70. package/README.md +38 -15
  71. package/dist/cli/commands/doctor.js +116 -0
  72. package/dist/cli/commands/doctor.js.map +1 -0
  73. package/dist/cli/commands/init.js +211 -0
  74. package/dist/cli/commands/init.js.map +1 -0
  75. package/dist/cli/commands/start.js +298 -0
  76. package/dist/cli/commands/start.js.map +1 -0
  77. package/dist/cli/commands/status.js +54 -0
  78. package/dist/cli/commands/status.js.map +1 -0
  79. package/dist/cli/commands/stop.js +97 -0
  80. package/dist/cli/commands/stop.js.map +1 -0
  81. package/dist/cli/connect.js +108 -0
  82. package/dist/cli/connect.js.map +1 -0
  83. package/dist/cli/index.js +99 -0
  84. package/dist/cli/index.js.map +1 -0
  85. package/dist/cli/port-utils.js +260 -0
  86. package/dist/cli/port-utils.js.map +1 -0
  87. package/dist/cli/runtime-env.js +60 -0
  88. package/dist/cli/runtime-env.js.map +1 -0
  89. package/dist/cli/shared.js +54 -0
  90. package/dist/cli/shared.js.map +1 -0
  91. package/dist/cli/ui.js +60 -0
  92. package/dist/cli/ui.js.map +1 -0
  93. package/dist/daemon/agents/claude.js +98 -0
  94. package/dist/daemon/agents/claude.js.map +1 -0
  95. package/dist/daemon/agents/codex.js +160 -0
  96. package/dist/daemon/agents/codex.js.map +1 -0
  97. package/dist/daemon/agents/gemini.js +111 -0
  98. package/dist/daemon/agents/gemini.js.map +1 -0
  99. package/dist/daemon/agents/index.js +59 -0
  100. package/dist/daemon/agents/index.js.map +1 -0
  101. package/dist/daemon/agents/kimi.js +206 -0
  102. package/dist/daemon/agents/kimi.js.map +1 -0
  103. package/dist/daemon/agents/opencode.js +228 -0
  104. package/dist/daemon/agents/opencode.js.map +1 -0
  105. package/dist/daemon/agents/openrouter.js +274 -0
  106. package/dist/daemon/agents/openrouter.js.map +1 -0
  107. package/dist/daemon/agents/parsers/claude.js +63 -0
  108. package/dist/daemon/agents/parsers/claude.js.map +1 -0
  109. package/dist/daemon/agents/parsers/codex.js +51 -0
  110. package/dist/daemon/agents/parsers/codex.js.map +1 -0
  111. package/dist/daemon/agents/parsers/gemini.js +144 -0
  112. package/dist/daemon/agents/parsers/gemini.js.map +1 -0
  113. package/dist/daemon/agents/parsers/index.js +31 -0
  114. package/dist/daemon/agents/parsers/index.js.map +1 -0
  115. package/dist/daemon/agents/parsers/kimi.js +8 -0
  116. package/dist/daemon/agents/parsers/kimi.js.map +1 -0
  117. package/dist/daemon/agents/parsers/opencode.js +105 -0
  118. package/dist/daemon/agents/parsers/opencode.js.map +1 -0
  119. package/dist/daemon/agents/parsers/openrouter.js +69 -0
  120. package/dist/daemon/agents/parsers/openrouter.js.map +1 -0
  121. package/dist/daemon/agents/parsers/shared.js +17 -0
  122. package/dist/daemon/agents/parsers/shared.js.map +1 -0
  123. package/dist/daemon/agents/preflight.js +83 -0
  124. package/dist/daemon/agents/preflight.js.map +1 -0
  125. package/dist/daemon/agents/quote.js +45 -0
  126. package/dist/daemon/agents/quote.js.map +1 -0
  127. package/dist/daemon/agents/sandbox-guard.js +69 -0
  128. package/dist/daemon/agents/sandbox-guard.js.map +1 -0
  129. package/dist/daemon/agents/types.js +6 -0
  130. package/dist/daemon/agents/types.js.map +1 -0
  131. package/dist/daemon/api-response.js +65 -0
  132. package/dist/daemon/api-response.js.map +1 -0
  133. package/dist/daemon/error-detector.js +329 -0
  134. package/dist/daemon/error-detector.js.map +1 -0
  135. package/dist/daemon/headless.js +533 -0
  136. package/dist/daemon/headless.js.map +1 -0
  137. package/dist/daemon/index.js +333 -0
  138. package/dist/daemon/index.js.map +1 -0
  139. package/dist/daemon/openrouter.js +192 -0
  140. package/dist/daemon/openrouter.js.map +1 -0
  141. package/dist/daemon/orchestrators/claude.js +163 -0
  142. package/dist/daemon/orchestrators/claude.js.map +1 -0
  143. package/dist/daemon/orchestrators/codex.js +101 -0
  144. package/dist/daemon/orchestrators/codex.js.map +1 -0
  145. package/dist/daemon/orchestrators/cursor-windsurf.js +118 -0
  146. package/dist/daemon/orchestrators/cursor-windsurf.js.map +1 -0
  147. package/dist/daemon/orchestrators/gemini.js +108 -0
  148. package/dist/daemon/orchestrators/gemini.js.map +1 -0
  149. package/dist/daemon/orchestrators/index.js +90 -0
  150. package/dist/daemon/orchestrators/index.js.map +1 -0
  151. package/dist/daemon/orchestrators/kimi.js +108 -0
  152. package/dist/daemon/orchestrators/kimi.js.map +1 -0
  153. package/dist/daemon/orchestrators/opencode.js +152 -0
  154. package/dist/daemon/orchestrators/opencode.js.map +1 -0
  155. package/dist/daemon/orchestrators/shared.js +60 -0
  156. package/dist/daemon/orchestrators/shared.js.map +1 -0
  157. package/dist/daemon/output-watcher.js +131 -0
  158. package/dist/daemon/output-watcher.js.map +1 -0
  159. package/dist/daemon/participant-aborts.js +123 -0
  160. package/dist/daemon/participant-aborts.js.map +1 -0
  161. package/dist/daemon/reaper.js +46 -0
  162. package/dist/daemon/reaper.js.map +1 -0
  163. package/dist/daemon/routes/chats-events.js +62 -0
  164. package/dist/daemon/routes/chats-events.js.map +1 -0
  165. package/dist/daemon/routes/chats-stream.js +241 -0
  166. package/dist/daemon/routes/chats-stream.js.map +1 -0
  167. package/dist/daemon/routes/chats-validation.js +13 -0
  168. package/dist/daemon/routes/chats-validation.js.map +1 -0
  169. package/dist/daemon/routes/chats.js +545 -0
  170. package/dist/daemon/routes/chats.js.map +1 -0
  171. package/dist/daemon/routes/openrouter.js +103 -0
  172. package/dist/daemon/routes/openrouter.js.map +1 -0
  173. package/dist/daemon/routes/settings.js +199 -0
  174. package/dist/daemon/routes/settings.js.map +1 -0
  175. package/dist/daemon/routes/stats.js +155 -0
  176. package/dist/daemon/routes/stats.js.map +1 -0
  177. package/dist/daemon/routes/system.js +208 -0
  178. package/dist/daemon/routes/system.js.map +1 -0
  179. package/dist/daemon/routes/templates-personas.js +254 -0
  180. package/dist/daemon/routes/templates-personas.js.map +1 -0
  181. package/dist/daemon/routes/voices.js +139 -0
  182. package/dist/daemon/routes/voices.js.map +1 -0
  183. package/dist/daemon/runner/doer-driver.js +346 -0
  184. package/dist/daemon/runner/doer-driver.js.map +1 -0
  185. package/dist/daemon/runner/doer.js +336 -0
  186. package/dist/daemon/runner/doer.js.map +1 -0
  187. package/dist/daemon/runner/prior-round.js +140 -0
  188. package/dist/daemon/runner/prior-round.js.map +1 -0
  189. package/dist/daemon/runner/prompt-builder.js +292 -0
  190. package/dist/daemon/runner/prompt-builder.js.map +1 -0
  191. package/dist/daemon/runner/review-only-phase.js +103 -0
  192. package/dist/daemon/runner/review-only-phase.js.map +1 -0
  193. package/dist/daemon/runner/reviewer-driver.js +410 -0
  194. package/dist/daemon/runner/reviewer-driver.js.map +1 -0
  195. package/dist/daemon/runner/reviewer.js +384 -0
  196. package/dist/daemon/runner/reviewer.js.map +1 -0
  197. package/dist/daemon/runner/run-with-fallback.js +56 -0
  198. package/dist/daemon/runner/run-with-fallback.js.map +1 -0
  199. package/dist/daemon/runner/sanitize-name.js +8 -0
  200. package/dist/daemon/runner/sanitize-name.js.map +1 -0
  201. package/dist/daemon/runner/stream-file-writer.js +116 -0
  202. package/dist/daemon/runner/stream-file-writer.js.map +1 -0
  203. package/dist/daemon/runner/swap-sidecar.js +102 -0
  204. package/dist/daemon/runner/swap-sidecar.js.map +1 -0
  205. package/dist/daemon/runner/template-fallback.js +119 -0
  206. package/dist/daemon/runner/template-fallback.js.map +1 -0
  207. package/dist/daemon/runner/types.js +3 -0
  208. package/dist/daemon/runner/types.js.map +1 -0
  209. package/dist/daemon/runner/verdict.js +51 -0
  210. package/dist/daemon/runner/verdict.js.map +1 -0
  211. package/dist/daemon/runner-multiplex.js +364 -0
  212. package/dist/daemon/runner-multiplex.js.map +1 -0
  213. package/dist/daemon/runner.js +427 -0
  214. package/dist/daemon/runner.js.map +1 -0
  215. package/dist/daemon/ship.js +340 -0
  216. package/dist/daemon/ship.js.map +1 -0
  217. package/dist/daemon/template-cache.js +37 -0
  218. package/dist/daemon/template-cache.js.map +1 -0
  219. package/dist/daemon/tmux-types.js +9 -0
  220. package/dist/daemon/tmux-types.js.map +1 -0
  221. package/dist/daemon/tmux.js +341 -0
  222. package/dist/daemon/tmux.js.map +1 -0
  223. package/dist/lib/atomic-write.js +55 -0
  224. package/dist/lib/atomic-write.js.map +1 -0
  225. package/dist/lib/chat-events-bus.js +27 -0
  226. package/dist/lib/chat-events-bus.js.map +1 -0
  227. package/dist/lib/chat-slug.js +105 -0
  228. package/dist/lib/chat-slug.js.map +1 -0
  229. package/dist/lib/cli-detect.js +388 -0
  230. package/dist/lib/cli-detect.js.map +1 -0
  231. package/dist/lib/cli-health.js +156 -0
  232. package/dist/lib/cli-health.js.map +1 -0
  233. package/dist/lib/cli-paths.js +113 -0
  234. package/dist/lib/cli-paths.js.map +1 -0
  235. package/dist/lib/cli-precheck.js +141 -0
  236. package/dist/lib/cli-precheck.js.map +1 -0
  237. package/dist/lib/db/chats.js +244 -0
  238. package/dist/lib/db/chats.js.map +1 -0
  239. package/dist/lib/db/connection.js +254 -0
  240. package/dist/lib/db/connection.js.map +1 -0
  241. package/dist/lib/db/index.js +34 -0
  242. package/dist/lib/db/index.js.map +1 -0
  243. package/dist/lib/db/personas.js +65 -0
  244. package/dist/lib/db/personas.js.map +1 -0
  245. package/dist/lib/db/phase-events.js +172 -0
  246. package/dist/lib/db/phase-events.js.map +1 -0
  247. package/dist/lib/db/secrets.js +53 -0
  248. package/dist/lib/db/secrets.js.map +1 -0
  249. package/dist/lib/db/settings.js +47 -0
  250. package/dist/lib/db/settings.js.map +1 -0
  251. package/dist/lib/db/templates.js +75 -0
  252. package/dist/lib/db/templates.js.map +1 -0
  253. package/dist/lib/db/voices.js +184 -0
  254. package/dist/lib/db/voices.js.map +1 -0
  255. package/dist/lib/lineage-maps.js +200 -0
  256. package/dist/lib/lineage-maps.js.map +1 -0
  257. package/dist/lib/logger.js +186 -0
  258. package/dist/lib/logger.js.map +1 -0
  259. package/dist/lib/personas.js +117 -0
  260. package/dist/lib/personas.js.map +1 -0
  261. package/dist/lib/runtime-path.js +222 -0
  262. package/dist/lib/runtime-path.js.map +1 -0
  263. package/dist/lib/settings/billing.js +58 -0
  264. package/dist/lib/settings/billing.js.map +1 -0
  265. package/dist/lib/settings/permissions.js +81 -0
  266. package/dist/lib/settings/permissions.js.map +1 -0
  267. package/dist/lib/settings/transport.js +113 -0
  268. package/dist/lib/settings/transport.js.map +1 -0
  269. package/dist/lib/telemetry.js +290 -0
  270. package/dist/lib/telemetry.js.map +1 -0
  271. package/dist/lib/template-schema.js +319 -0
  272. package/dist/lib/template-schema.js.map +1 -0
  273. package/dist/lib/template-validation.js +82 -0
  274. package/dist/lib/template-validation.js.map +1 -0
  275. package/dist/lib/voices.js +533 -0
  276. package/dist/lib/voices.js.map +1 -0
  277. package/dist/mcp/client.js +138 -0
  278. package/dist/mcp/client.js.map +1 -0
  279. package/dist/mcp/index.js +178 -0
  280. package/dist/mcp/index.js.map +1 -0
  281. package/dist/mcp/tools.js +355 -0
  282. package/dist/mcp/tools.js.map +1 -0
  283. package/package.json +2 -1
  284. package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0beh7rg._.js +0 -6077
  285. package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0beh7rg._.js.map +0 -69
  286. package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0pjsj.j._.js +0 -6318
  287. package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0pjsj.j._.js.map +0 -71
  288. package/.next/dev/types/cache-life.d.ts +0 -145
  289. package/.next/dev/types/routes.d.ts +0 -84
  290. package/.next/dev/types/validator.ts +0 -178
  291. /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 9cD3yIOGe_Aqr17uJHTQS}/_buildManifest.js +0 -0
  292. /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 9cD3yIOGe_Aqr17uJHTQS}/_clientMiddlewareManifest.js +0 -0
  293. /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 9cD3yIOGe_Aqr17uJHTQS}/_ssgManifest.js +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/lib/db/settings.ts"],"names":[],"mappings":";;;AAAA,mDAAwC;AAO3B,QAAA,QAAQ,GAAG;IACtB,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,EAAE,GAAG,MAAM,IAAA,qBAAK,GAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC;YAC9B,GAAG,EAAE,0CAA0C;YAC/C,IAAI,EAAE,CAAC,GAAG,CAAC;SACZ,CAAC,CAAC;QACH,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAe,CAAC;QAC7C,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAc;QACnC,MAAM,EAAE,GAAG,MAAM,IAAA,qBAAK,GAAE,CAAC;QACzB,MAAM,WAAW,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9E,MAAM,EAAE,CAAC,OAAO,CAAC;YACf,GAAG,EAAE,4DAA4D;YACjE,IAAI,EAAE,CAAC,GAAG,EAAE,WAAW,CAAC;SACzB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM;QACV,MAAM,EAAE,GAAG,MAAM,IAAA,qBAAK,GAAE,CAAC;QACzB,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC;QACnE,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,GAAG,CAAC,GAAa,CAAC;YAC5B,MAAM,CAAC,GAAG,GAAG,CAAC,KAAe,CAAC;YAC9B,IAAI,CAAC;gBACH,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACzB,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACb,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF,CAAC"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.templates = void 0;
4
+ const zod_1 = require("zod");
5
+ const connection_js_1 = require("./connection.js");
6
+ const TemplateSchema = zod_1.z.object({
7
+ id: zod_1.z.string(),
8
+ source: zod_1.z.enum(['builtin', 'user']),
9
+ yaml: zod_1.z.string(),
10
+ created_at: zod_1.z.number().int(),
11
+ updated_at: zod_1.z.number().int(),
12
+ });
13
+ /**
14
+ * SQLite stores text columns as TEXT, but `INSERT ... readfile(...)` and
15
+ * some admin tools write BLOBs. Transport-specific note (verified during
16
+ * plan review):
17
+ * - better-sqlite3 surfaces BLOBs as Node Buffer (extends Uint8Array).
18
+ * - @libsql/client surfaces BLOBs as ArrayBuffer (NOT instanceof Uint8Array).
19
+ * Check ArrayBuffer first; fall through to Uint8Array as a defensive
20
+ * belt in case a Buffer-typed value sneaks in via direct stmt.run paths
21
+ * or future migrations.
22
+ */
23
+ function coerceTemplateYaml(row) {
24
+ if (!row || typeof row !== 'object')
25
+ return row;
26
+ const r = row;
27
+ if (r.yaml instanceof ArrayBuffer) {
28
+ return { ...r, yaml: new TextDecoder().decode(new Uint8Array(r.yaml)) };
29
+ }
30
+ if (r.yaml instanceof Uint8Array) {
31
+ return { ...r, yaml: new TextDecoder().decode(r.yaml) };
32
+ }
33
+ return r;
34
+ }
35
+ exports.templates = {
36
+ async create(id, yaml, source = 'user') {
37
+ const db = await (0, connection_js_1.getDb)();
38
+ const now = Date.now();
39
+ await db.execute({
40
+ sql: `
41
+ INSERT OR REPLACE INTO templates (id, source, yaml, created_at, updated_at)
42
+ VALUES (?, ?, ?, ?, ?)
43
+ `,
44
+ args: [id, source, yaml, now, now],
45
+ });
46
+ const row = await exports.templates.getById(id);
47
+ if (!row)
48
+ throw new Error(`templates.create: row vanished: ${id}`);
49
+ return row;
50
+ },
51
+ async list() {
52
+ const db = await (0, connection_js_1.getDb)();
53
+ const result = await db.execute('SELECT * FROM templates ORDER BY created_at DESC');
54
+ return result.rows.map((row) => TemplateSchema.parse(coerceTemplateYaml(row)));
55
+ },
56
+ async getById(id) {
57
+ const db = await (0, connection_js_1.getDb)();
58
+ const result = await db.execute({
59
+ sql: 'SELECT * FROM templates WHERE id = ?',
60
+ args: [id],
61
+ });
62
+ if (result.rows.length === 0)
63
+ return null;
64
+ return TemplateSchema.parse(coerceTemplateYaml(result.rows[0]));
65
+ },
66
+ /** Hard-delete by id. Caller is responsible for refusing built-in rows
67
+ * before reaching here — the boot seed in src/daemon/index.ts re-creates
68
+ * built-in templates from `templates/*.yaml`, so a built-in delete would
69
+ * come back on next start. */
70
+ async delete(id) {
71
+ const db = await (0, connection_js_1.getDb)();
72
+ await db.execute({ sql: 'DELETE FROM templates WHERE id = ?', args: [id] });
73
+ },
74
+ };
75
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../../src/lib/db/templates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.voices = void 0;
4
+ const zod_1 = require("zod");
5
+ const connection_js_1 = require("./connection.js");
6
+ const VoiceRowSchema = zod_1.z.object({
7
+ id: zod_1.z.string(),
8
+ label: zod_1.z.string(),
9
+ source: zod_1.z.enum(['cli', 'api']),
10
+ provider: zod_1.z.string(),
11
+ model_id: zod_1.z.string(),
12
+ lineage: zod_1.z.enum(['anthropic', 'openai', 'google', 'opencode', 'moonshot']),
13
+ vendor_family: zod_1.z.string().nullable(),
14
+ input_cost_per_mtok: zod_1.z.number().nullable(),
15
+ output_cost_per_mtok: zod_1.z.number().nullable(),
16
+ enabled: zod_1.z.coerce.boolean(),
17
+ disabled_reason: zod_1.z.enum(['user', 'auto_missing']).nullable().optional().default(null),
18
+ created_at: zod_1.z.number().int(),
19
+ updated_at: zod_1.z.number().int(),
20
+ });
21
+ exports.voices = {
22
+ /**
23
+ * Upsert a voice row. Updates label/model_id/cost/vendor_family on
24
+ * existing rows. `enabled` and `disabled_reason` follow this precedence:
25
+ *
26
+ * 1. Caller passes the field explicitly → use it (caller intent wins).
27
+ * For disabled_reason, an explicit `null` means "clear".
28
+ * 2. Caller omits the field on an existing row → preserve current value.
29
+ * 3. Caller omits on a fresh row → default (`enabled=true`,
30
+ * `disabled_reason=null`).
31
+ *
32
+ * The previous "existing always wins on enabled" behaviour silently
33
+ * dropped seed overrides — meaning auto_missing rows could never be
34
+ * re-enabled when the CLI returned, and migration-data overrides were
35
+ * dead code on existing installs.
36
+ */
37
+ async upsert(input) {
38
+ const db = await (0, connection_js_1.getDb)();
39
+ const now = Date.now();
40
+ const existing = await exports.voices.getById(input.id);
41
+ const enabledExplicit = input.enabled !== undefined;
42
+ const reasonExplicit = 'disabled_reason' in input;
43
+ let enabledValue;
44
+ if (enabledExplicit)
45
+ enabledValue = input.enabled ? 1 : 0;
46
+ else if (existing)
47
+ enabledValue = existing.enabled ? 1 : 0;
48
+ else
49
+ enabledValue = 1;
50
+ let reasonValue;
51
+ if (reasonExplicit)
52
+ reasonValue = input.disabled_reason ?? null;
53
+ else if (existing)
54
+ reasonValue = existing.disabled_reason ?? null;
55
+ else
56
+ reasonValue = null;
57
+ await db.execute({
58
+ sql: `
59
+ INSERT OR REPLACE INTO voices
60
+ (id, label, source, provider, model_id, lineage, vendor_family,
61
+ input_cost_per_mtok, output_cost_per_mtok, enabled,
62
+ disabled_reason, created_at, updated_at)
63
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
64
+ `,
65
+ args: [
66
+ input.id,
67
+ input.label,
68
+ input.source,
69
+ input.provider,
70
+ input.model_id,
71
+ input.lineage,
72
+ input.vendor_family ?? null,
73
+ input.input_cost_per_mtok ?? null,
74
+ input.output_cost_per_mtok ?? null,
75
+ enabledValue,
76
+ reasonValue,
77
+ existing?.created_at ?? now,
78
+ now,
79
+ ],
80
+ });
81
+ const row = await exports.voices.getById(input.id);
82
+ if (!row)
83
+ throw new Error(`voices.upsert: row vanished: ${input.id}`);
84
+ return row;
85
+ },
86
+ async list(filter) {
87
+ const db = await (0, connection_js_1.getDb)();
88
+ const where = [];
89
+ const args = [];
90
+ if (filter?.lineage) {
91
+ where.push('lineage = ?');
92
+ args.push(filter.lineage);
93
+ }
94
+ if (filter?.source) {
95
+ where.push('source = ?');
96
+ args.push(filter.source);
97
+ }
98
+ if (filter?.provider) {
99
+ where.push('provider = ?');
100
+ args.push(filter.provider);
101
+ }
102
+ if (filter?.enabled !== undefined) {
103
+ where.push('enabled = ?');
104
+ args.push(filter.enabled ? 1 : 0);
105
+ }
106
+ const sql = 'SELECT * FROM voices' +
107
+ (where.length > 0 ? ' WHERE ' + where.join(' AND ') : '') +
108
+ ' ORDER BY provider ASC, label ASC';
109
+ const result = await db.execute({ sql, args: args });
110
+ return result.rows.map((row) => VoiceRowSchema.parse(row));
111
+ },
112
+ async getById(id) {
113
+ const db = await (0, connection_js_1.getDb)();
114
+ const result = await db.execute({
115
+ sql: 'SELECT * FROM voices WHERE id = ?',
116
+ args: [id],
117
+ });
118
+ if (result.rows.length === 0)
119
+ return null;
120
+ return VoiceRowSchema.parse(result.rows[0]);
121
+ },
122
+ async update(id, partial) {
123
+ const db = await (0, connection_js_1.getDb)();
124
+ const existing = await exports.voices.getById(id);
125
+ if (!existing)
126
+ throw new Error(`Voice ${id} not found`);
127
+ const enabledChanged = partial.enabled !== undefined && partial.enabled !== existing.enabled;
128
+ const reasonExplicit = 'disabled_reason' in partial;
129
+ // Default reason policy: when the caller flips enabled without
130
+ // touching disabled_reason, we record intent automatically.
131
+ // - enabled true→false → 'user' (cockpit/API toggle counts as user
132
+ // intent unless caller says otherwise)
133
+ // - enabled false→true → null (re-enabling clears any stale auto/user)
134
+ let nextReason;
135
+ if (reasonExplicit) {
136
+ nextReason = partial.disabled_reason ?? null;
137
+ }
138
+ else if (enabledChanged) {
139
+ nextReason = partial.enabled ? null : 'user';
140
+ }
141
+ else {
142
+ nextReason = existing.disabled_reason ?? null;
143
+ }
144
+ const next = {
145
+ label: partial.label ?? existing.label,
146
+ enabled: partial.enabled ?? existing.enabled,
147
+ input_cost_per_mtok: partial.input_cost_per_mtok !== undefined
148
+ ? partial.input_cost_per_mtok
149
+ : existing.input_cost_per_mtok,
150
+ output_cost_per_mtok: partial.output_cost_per_mtok !== undefined
151
+ ? partial.output_cost_per_mtok
152
+ : existing.output_cost_per_mtok,
153
+ model_id: partial.model_id ?? existing.model_id,
154
+ disabled_reason: nextReason,
155
+ };
156
+ await db.execute({
157
+ sql: `
158
+ UPDATE voices
159
+ SET label = ?, enabled = ?, input_cost_per_mtok = ?, output_cost_per_mtok = ?, model_id = ?,
160
+ disabled_reason = ?, updated_at = ?
161
+ WHERE id = ?
162
+ `,
163
+ args: [
164
+ next.label,
165
+ next.enabled ? 1 : 0,
166
+ next.input_cost_per_mtok,
167
+ next.output_cost_per_mtok,
168
+ next.model_id,
169
+ next.disabled_reason,
170
+ Date.now(),
171
+ id,
172
+ ],
173
+ });
174
+ const row = await exports.voices.getById(id);
175
+ if (!row)
176
+ throw new Error(`voices.update: row vanished: ${id}`);
177
+ return row;
178
+ },
179
+ async delete(id) {
180
+ const db = await (0, connection_js_1.getDb)();
181
+ await db.execute({ sql: 'DELETE FROM voices WHERE id = ?', args: [id] });
182
+ },
183
+ };
184
+ //# sourceMappingURL=voices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voices.js","sourceRoot":"","sources":["../../../src/lib/db/voices.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ /**
3
+ * Single source of truth for lineage display labels and colour swatches.
4
+ *
5
+ * Two parallel maps because the data flows from two directions:
6
+ * - Templates use the daemon-side YAML schema lineage names ("anthropic",
7
+ * "openai", "google", "opencode", "moonshot"). UI helpers translate
8
+ * these to the cockpit-side ReviewerLineage names ("claude", "codex",
9
+ * "gemini", "opencode", "kimi") via UI_LINEAGE_MAP / mapLineage.
10
+ * - Personas use the daemon-side names directly via recommended_lineage.
11
+ *
12
+ * Keep both maps keyed by the daemon-side names; let callers translate
13
+ * inputs once at the boundary and look up via the canonical key.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.UI_LINEAGE_BRAND = exports.UI_LINEAGE_AVAILABLE_MODELS = exports.UI_LINEAGE_DEFAULT_MODEL = exports.UI_LINEAGE_LABEL = exports.LINEAGE_LABEL = void 0;
17
+ exports.lineageLabel = lineageLabel;
18
+ exports.lineageDot = lineageDot;
19
+ exports.uiLineageLabel = uiLineageLabel;
20
+ exports.uiLineageDot = uiLineageDot;
21
+ exports.uiLineageDefaultModel = uiLineageDefaultModel;
22
+ exports.LINEAGE_LABEL = {
23
+ anthropic: "Claude",
24
+ openai: "Codex",
25
+ google: "Gemini",
26
+ opencode: "OpenCode",
27
+ moonshot: "Kimi",
28
+ };
29
+ /** Tailwind background colour class for the small lineage dot indicator. */
30
+ const LINEAGE_DOT = {
31
+ anthropic: "bg-violet-400",
32
+ openai: "bg-orange-400",
33
+ google: "bg-blue-400",
34
+ opencode: "bg-emerald-400",
35
+ moonshot: "bg-pink-400",
36
+ };
37
+ /** Returns the human label for a lineage, falling back to the raw key. */
38
+ function lineageLabel(lineage) {
39
+ if (!lineage)
40
+ return "";
41
+ return exports.LINEAGE_LABEL[lineage] ?? lineage;
42
+ }
43
+ /** Returns the dot colour class, falling back to a neutral muted dot. */
44
+ function lineageDot(lineage) {
45
+ if (!lineage)
46
+ return "bg-muted";
47
+ return LINEAGE_DOT[lineage] ?? "bg-muted";
48
+ }
49
+ exports.UI_LINEAGE_LABEL = {
50
+ claude: "Claude",
51
+ codex: "Codex",
52
+ gemini: "Gemini",
53
+ opencode: "OpenCode",
54
+ kimi: "Kimi",
55
+ // Meta-lineage for HTTP-dispatched voices. The real underlying lineage
56
+ // (anthropic/openai/google/etc.) is preserved on the voices table for
57
+ // diversity scoring; this label is what the cockpit cards show because
58
+ // the runner creates `reviewer-openrouter-N` dirs regardless of the
59
+ // underlying model.
60
+ openrouter: "OpenRouter",
61
+ };
62
+ const UI_LINEAGE_DOT = {
63
+ claude: "bg-violet-400",
64
+ codex: "bg-orange-400",
65
+ gemini: "bg-blue-400",
66
+ opencode: "bg-emerald-400",
67
+ kimi: "bg-pink-400",
68
+ // Cyan picked over amber — amber reads as "warning/in-progress" in UI
69
+ // convention, which clashed with lineage-as-brand semantics. Cyan is
70
+ // brand-distinct without state ambiguity.
71
+ openrouter: "bg-cyan-400",
72
+ };
73
+ function uiLineageLabel(lineage) {
74
+ if (!lineage)
75
+ return "";
76
+ return exports.UI_LINEAGE_LABEL[lineage] ?? lineage;
77
+ }
78
+ function uiLineageDot(lineage) {
79
+ if (!lineage)
80
+ return "bg-muted";
81
+ return UI_LINEAGE_DOT[lineage] ?? "bg-muted";
82
+ }
83
+ /**
84
+ * Default model per UI lineage when a template's `models: []` is empty.
85
+ * Mirrors the per-lineage defaults used by phase-editor and new-template-dialog;
86
+ * lifted here so the run page can show the actual model on cards even when
87
+ * the YAML omits it.
88
+ */
89
+ exports.UI_LINEAGE_DEFAULT_MODEL = {
90
+ claude: "claude-opus-4-7",
91
+ codex: "gpt-5.5",
92
+ gemini: "gemini-3.1-pro-preview",
93
+ opencode: "kimi-k2.6",
94
+ kimi: "kimi-k2.6",
95
+ // No sensible default for openrouter — user explicitly selects a model.
96
+ // Empty string lets `models?.[0] ?? defaultModel` resolve to "" which
97
+ // the run page treats as "no model" (skips the · model · separator).
98
+ openrouter: "",
99
+ };
100
+ /**
101
+ * Curated model lists per CLI. Used as a fallback when the CLI doesn't
102
+ * expose a live model-listing command (claude / gemini / kimi today). For
103
+ * codex we run `codex debug models` at seed time and prefer the live
104
+ * catalog; the list below is the safety net if that probe fails.
105
+ *
106
+ * Cross-checked against `opencode models` (which aggregates upstream
107
+ * provider names) and `codex debug models` so entries here are real
108
+ * model ids the corresponding CLI accepts. Don't list speculative names —
109
+ * a wrong entry here is what makes the home page look unprofessional.
110
+ *
111
+ * Order = recommended first; the first entry is the canonical default
112
+ * and matches UI_LINEAGE_DEFAULT_MODEL.
113
+ *
114
+ * OpenCode is omitted because it's always discovered live via
115
+ * `opencode models` (gateway-aware). Cursor/Windsurf are IDE
116
+ * orchestrators with no model selection of their own.
117
+ */
118
+ exports.UI_LINEAGE_AVAILABLE_MODELS = {
119
+ claude: [
120
+ "claude-opus-4-7",
121
+ "claude-sonnet-4-6",
122
+ "claude-sonnet-4-5",
123
+ "claude-haiku-4-5",
124
+ "claude-opus-4-5",
125
+ ],
126
+ codex: [
127
+ "gpt-5.5",
128
+ "gpt-5.4",
129
+ "gpt-5.4-mini",
130
+ "gpt-5.3-codex",
131
+ "gpt-5.2",
132
+ ],
133
+ // Gemini list verified 2026-05-04 by `gemini -p "ok" --model <X>`.
134
+ // gemini-3-flash returned ModelNotFoundError; only the names below
135
+ // are accepted by the current Gemini CLI version.
136
+ gemini: [
137
+ "gemini-3.1-pro-preview",
138
+ "gemini-2.5-pro",
139
+ "gemini-2.5-flash",
140
+ ],
141
+ // Kimi list cross-checked against the official kimi-cli docs +
142
+ // source (2026-05-04):
143
+ // - CHANGELOG.md: kimi-k2.6, kimi-k2-thinking
144
+ // - klips/klip-6: kimi-k2-thinking-turbo (recommended turbo flagship)
145
+ // - sdks/kimi-sdk/README.md, klips/klip-7: kimi-k2-turbo-preview
146
+ // - Welcome screen dropped hardcoded kimi-k2.5, but it still works
147
+ // Not end-to-end probed because the dedicated kimi CLI needs a
148
+ // separate Moonshot account login; cross-referenced from official docs
149
+ // is the next-best signal.
150
+ // Index 0 must match UI_LINEAGE_DEFAULT_MODEL.kimi to keep the seed's
151
+ // immutable provider row pointed at the same default. kimi-k2.6 has
152
+ // been the chorus default since v0.7; not auto-rotating to the
153
+ // turbo-thinking variant here so existing installs don't silently
154
+ // change behavior. Users can still toggle the turbo entries on.
155
+ kimi: [
156
+ "kimi-k2.6",
157
+ "kimi-k2-thinking-turbo",
158
+ "kimi-k2-turbo-preview",
159
+ "kimi-k2-thinking",
160
+ "kimi-k2.5",
161
+ ],
162
+ };
163
+ function uiLineageDefaultModel(lineage) {
164
+ if (!lineage)
165
+ return undefined;
166
+ return exports.UI_LINEAGE_DEFAULT_MODEL[lineage];
167
+ }
168
+ exports.UI_LINEAGE_BRAND = {
169
+ claude: {
170
+ dot: "bg-violet-400",
171
+ ring: "ring-violet-400/40",
172
+ gradient: "bg-gradient-to-b from-violet-500/15 to-card",
173
+ },
174
+ codex: {
175
+ dot: "bg-orange-400",
176
+ ring: "ring-orange-400/40",
177
+ gradient: "bg-gradient-to-b from-orange-500/15 to-card",
178
+ },
179
+ gemini: {
180
+ dot: "bg-blue-400",
181
+ ring: "ring-blue-400/40",
182
+ gradient: "bg-gradient-to-b from-blue-500/15 to-card",
183
+ },
184
+ opencode: {
185
+ dot: "bg-emerald-400",
186
+ ring: "ring-emerald-400/40",
187
+ gradient: "bg-gradient-to-b from-emerald-500/15 to-card",
188
+ },
189
+ kimi: {
190
+ dot: "bg-pink-400",
191
+ ring: "ring-pink-400/40",
192
+ gradient: "bg-gradient-to-b from-pink-500/15 to-card",
193
+ },
194
+ openrouter: {
195
+ dot: "bg-cyan-400",
196
+ ring: "ring-cyan-400/40",
197
+ gradient: "bg-gradient-to-b from-cyan-500/15 to-card",
198
+ },
199
+ };
200
+ //# sourceMappingURL=lineage-maps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lineage-maps.js","sourceRoot":"","sources":["../../src/lib/lineage-maps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ /**
3
+ * Structured logging substrate (round-2-deferred §3).
4
+ *
5
+ * Every log line is one JSON object on stdout. The wire shape mirrors
6
+ * pino's defaults so a future swap to pino is transparent for any
7
+ * downstream consumer (`chorus logs --chat <id>`, log aggregators, etc):
8
+ *
9
+ * {"level":30,"time":1714654200000,"pid":1234,"hostname":"box","chatId":"abc","msg":"phase done"}
10
+ *
11
+ * - `level` is the numeric pino value (debug=20, info=30, warn=40, error=50)
12
+ * - `time` is ms since epoch (not `ts`)
13
+ * - `pid` + `hostname` are emitted once per line, captured at logger-init
14
+ *
15
+ * Child loggers carry their context fields — call sites in the runner do
16
+ * `const log = chatLogger(chatId, { phase: 'review', role: 'reviewer' })`
17
+ * log.info({lineage:'openai'}, 'reviewer started')
18
+ * and the chatId / phase / role get baked into every line that logger
19
+ * emits without each call site repeating them.
20
+ *
21
+ * No runtime dependency. The default is `console.log(JSON.stringify(...))` —
22
+ * if a future load profile justifies it, swap to pino without changing
23
+ * call sites OR the wire shape.
24
+ *
25
+ * `CHORUS_LOG_LEVEL` env var gates the floor (debug | info | warn | error).
26
+ * Default is info. Setting it to debug surfaces verbose internals; setting
27
+ * it to error silences phase-progress noise during dogfood streaming.
28
+ *
29
+ * Round-1 dogfood (PR #7) caught:
30
+ * - ts/level were clobberable by user fields → core fields now win
31
+ * - JSON.stringify could throw on circular refs / BigInt → safe wrapper
32
+ * emits a degraded fallback line instead of crashing the daemon
33
+ * - Error objects serialized to `{}` → expanded to {message,name,stack}
34
+ *
35
+ * Test seam: pass `_writer` when constructing — tests inject a function
36
+ * that pushes lines into an array and assert exact JSON shape. Production
37
+ * call sites use the default `console.log` chain.
38
+ */
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.logger = void 0;
41
+ exports.createLogger = createLogger;
42
+ exports.chatLogger = chatLogger;
43
+ const os_1 = require("os");
44
+ /** Pino-compatible numeric levels. Wire shape matches pino's default. */
45
+ const LEVEL_RANK = {
46
+ debug: 20,
47
+ info: 30,
48
+ warn: 40,
49
+ error: 50,
50
+ };
51
+ const defaultWriter = (line) => {
52
+ // process.stdout.write is sync + line-buffered when stdout is a pipe (the
53
+ // typical daemon shape). console.log adds a trailing newline that we
54
+ // want; it's also what existing chorus call sites use, so output ordering
55
+ // stays the same when sites migrate.
56
+ console.log(line);
57
+ };
58
+ /** Captured once at module load. Daemon doesn't move between machines. */
59
+ const HOST = (() => {
60
+ try {
61
+ return (0, os_1.hostname)();
62
+ }
63
+ catch {
64
+ return 'unknown';
65
+ }
66
+ })();
67
+ const PID = process.pid;
68
+ /**
69
+ * Replacer for JSON.stringify that:
70
+ * - Expands `Error` instances to {message, name, stack, cause?}
71
+ * - Defangs BigInt to its string form (JSON.stringify throws on raw BigInt)
72
+ * - Detects circular references and returns the literal string
73
+ * '[Circular]' rather than throwing.
74
+ *
75
+ * Falls through to the default stringify behaviour for everything else.
76
+ */
77
+ function buildSafeReplacer() {
78
+ const seen = new WeakSet();
79
+ return function safe(_key, value) {
80
+ if (typeof value === 'bigint')
81
+ return value.toString();
82
+ if (value instanceof Error) {
83
+ const out = {
84
+ message: value.message,
85
+ name: value.name,
86
+ stack: value.stack,
87
+ };
88
+ const cause = value.cause;
89
+ if (cause !== undefined)
90
+ out.cause = cause;
91
+ return out;
92
+ }
93
+ if (value !== null && typeof value === 'object') {
94
+ if (seen.has(value))
95
+ return '[Circular]';
96
+ seen.add(value);
97
+ }
98
+ return value;
99
+ };
100
+ }
101
+ /**
102
+ * Stringify a log line without ever throwing. The replacer handles
103
+ * Error / BigInt / circular refs; if it still fails (toJSON that
104
+ * throws, exotic proxies, etc.) we emit a degraded fallback line
105
+ * referencing the failure rather than crashing the daemon's logger.
106
+ */
107
+ function safeStringify(line) {
108
+ try {
109
+ return JSON.stringify(line, buildSafeReplacer());
110
+ }
111
+ catch (err) {
112
+ return JSON.stringify({
113
+ level: line.level,
114
+ time: line.time,
115
+ pid: line.pid,
116
+ hostname: line.hostname,
117
+ msg: 'log_serialize_failed',
118
+ err: err instanceof Error ? err.message : String(err),
119
+ });
120
+ }
121
+ }
122
+ class LoggerImpl {
123
+ bound;
124
+ threshold;
125
+ writer;
126
+ constructor(bound, threshold, writer) {
127
+ this.bound = bound;
128
+ this.threshold = threshold;
129
+ this.writer = writer;
130
+ }
131
+ emit(level, fieldsOrMsg, msg) {
132
+ if (LEVEL_RANK[level] < this.threshold)
133
+ return;
134
+ const isFields = typeof fieldsOrMsg === 'object' && fieldsOrMsg !== null;
135
+ const fields = isFields ? fieldsOrMsg : {};
136
+ const message = isFields ? msg : fieldsOrMsg;
137
+ // Spread order: user-provided spreads FIRST, then core wire fields
138
+ // (level, time, pid, hostname). User fields cannot clobber the core
139
+ // shape — round-1 dogfood caught a `log.info({level:'fake'})` foot-gun.
140
+ const line = {
141
+ ...this.bound,
142
+ ...fields,
143
+ ...(message !== undefined ? { msg: message } : {}),
144
+ level: LEVEL_RANK[level],
145
+ time: Date.now(),
146
+ pid: PID,
147
+ hostname: HOST,
148
+ };
149
+ this.writer(safeStringify(line));
150
+ }
151
+ debug(fields, msg) { this.emit('debug', fields, msg); }
152
+ info(fields, msg) { this.emit('info', fields, msg); }
153
+ warn(fields, msg) { this.emit('warn', fields, msg); }
154
+ error(fields, msg) { this.emit('error', fields, msg); }
155
+ child(bound) {
156
+ return new LoggerImpl({ ...this.bound, ...bound }, this.threshold, this.writer);
157
+ }
158
+ }
159
+ function resolveThreshold() {
160
+ const raw = (process.env.CHORUS_LOG_LEVEL ?? '').toLowerCase();
161
+ if (raw === 'debug' || raw === 'info' || raw === 'warn' || raw === 'error') {
162
+ return LEVEL_RANK[raw];
163
+ }
164
+ return LEVEL_RANK.info;
165
+ }
166
+ /**
167
+ * Build the root logger. The daemon constructs ONE root and passes child
168
+ * loggers down to call sites. Tests construct their own with an in-memory
169
+ * writer.
170
+ */
171
+ function createLogger(opts) {
172
+ const writer = opts?._writer ?? defaultWriter;
173
+ const threshold = opts?._level ? LEVEL_RANK[opts._level] : resolveThreshold();
174
+ return new LoggerImpl({}, threshold, writer);
175
+ }
176
+ /**
177
+ * Module-singleton root logger for general-purpose call sites that don't
178
+ * have a chat / request context. Prefer `chatLogger(chatId)` when the
179
+ * chat correlation key is known.
180
+ */
181
+ exports.logger = createLogger();
182
+ /** Convenience: child logger pre-bound to a chat correlation key. */
183
+ function chatLogger(chatId, extra) {
184
+ return exports.logger.child({ chatId, ...extra });
185
+ }
186
+ //# sourceMappingURL=logger.js.map