chorus-codes 0.7.0 → 0.7.1

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 (291) 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/fallback-build-manifest.json +3 -3
  6. package/.next/prerender-manifest.json +3 -3
  7. package/.next/server/app/_global-error.html +1 -1
  8. package/.next/server/app/_global-error.rsc +1 -1
  9. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/server/app/_not-found.html +1 -1
  15. package/.next/server/app/_not-found.rsc +1 -1
  16. package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  17. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  18. package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  19. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  20. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  21. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  22. package/.next/server/app/new.html +1 -1
  23. package/.next/server/app/new.rsc +1 -1
  24. package/.next/server/app/new.segments/_full.segment.rsc +1 -1
  25. package/.next/server/app/new.segments/_head.segment.rsc +1 -1
  26. package/.next/server/app/new.segments/_index.segment.rsc +1 -1
  27. package/.next/server/app/new.segments/_tree.segment.rsc +1 -1
  28. package/.next/server/app/new.segments/new/__PAGE__.segment.rsc +1 -1
  29. package/.next/server/app/new.segments/new.segment.rsc +1 -1
  30. package/.next/server/app/onboarding.html +1 -1
  31. package/.next/server/app/onboarding.rsc +1 -1
  32. package/.next/server/app/onboarding.segments/_full.segment.rsc +1 -1
  33. package/.next/server/app/onboarding.segments/_head.segment.rsc +1 -1
  34. package/.next/server/app/onboarding.segments/_index.segment.rsc +1 -1
  35. package/.next/server/app/onboarding.segments/_tree.segment.rsc +1 -1
  36. package/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +1 -1
  37. package/.next/server/app/onboarding.segments/onboarding.segment.rsc +1 -1
  38. package/.next/server/app/personas.html +1 -1
  39. package/.next/server/app/personas.rsc +1 -1
  40. package/.next/server/app/personas.segments/_full.segment.rsc +1 -1
  41. package/.next/server/app/personas.segments/_head.segment.rsc +1 -1
  42. package/.next/server/app/personas.segments/_index.segment.rsc +1 -1
  43. package/.next/server/app/personas.segments/_tree.segment.rsc +1 -1
  44. package/.next/server/app/personas.segments/personas/__PAGE__.segment.rsc +1 -1
  45. package/.next/server/app/personas.segments/personas.segment.rsc +1 -1
  46. package/.next/server/app/settings.html +1 -1
  47. package/.next/server/app/settings.rsc +1 -1
  48. package/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  49. package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  50. package/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  51. package/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  52. package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
  53. package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  54. package/.next/server/app/templates.html +1 -1
  55. package/.next/server/app/templates.rsc +1 -1
  56. package/.next/server/app/templates.segments/_full.segment.rsc +1 -1
  57. package/.next/server/app/templates.segments/_head.segment.rsc +1 -1
  58. package/.next/server/app/templates.segments/_index.segment.rsc +1 -1
  59. package/.next/server/app/templates.segments/_tree.segment.rsc +1 -1
  60. package/.next/server/app/templates.segments/templates/__PAGE__.segment.rsc +1 -1
  61. package/.next/server/app/templates.segments/templates.segment.rsc +1 -1
  62. package/.next/server/middleware-build-manifest.js +3 -3
  63. package/.next/server/pages/404.html +1 -1
  64. package/.next/server/pages/500.html +1 -1
  65. package/.next/server/server-reference-manifest.js +1 -1
  66. package/.next/server/server-reference-manifest.json +1 -1
  67. package/.next/trace +1 -1
  68. package/.next/trace-build +1 -1
  69. package/dist/cli/commands/doctor.js +116 -0
  70. package/dist/cli/commands/doctor.js.map +1 -0
  71. package/dist/cli/commands/init.js +211 -0
  72. package/dist/cli/commands/init.js.map +1 -0
  73. package/dist/cli/commands/start.js +240 -0
  74. package/dist/cli/commands/start.js.map +1 -0
  75. package/dist/cli/commands/status.js +54 -0
  76. package/dist/cli/commands/status.js.map +1 -0
  77. package/dist/cli/commands/stop.js +97 -0
  78. package/dist/cli/commands/stop.js.map +1 -0
  79. package/dist/cli/connect.js +108 -0
  80. package/dist/cli/connect.js.map +1 -0
  81. package/dist/cli/index.js +99 -0
  82. package/dist/cli/index.js.map +1 -0
  83. package/dist/cli/port-utils.js +260 -0
  84. package/dist/cli/port-utils.js.map +1 -0
  85. package/dist/cli/runtime-env.js +60 -0
  86. package/dist/cli/runtime-env.js.map +1 -0
  87. package/dist/cli/shared.js +54 -0
  88. package/dist/cli/shared.js.map +1 -0
  89. package/dist/cli/ui.js +60 -0
  90. package/dist/cli/ui.js.map +1 -0
  91. package/dist/daemon/agents/claude.js +98 -0
  92. package/dist/daemon/agents/claude.js.map +1 -0
  93. package/dist/daemon/agents/codex.js +160 -0
  94. package/dist/daemon/agents/codex.js.map +1 -0
  95. package/dist/daemon/agents/gemini.js +111 -0
  96. package/dist/daemon/agents/gemini.js.map +1 -0
  97. package/dist/daemon/agents/index.js +59 -0
  98. package/dist/daemon/agents/index.js.map +1 -0
  99. package/dist/daemon/agents/kimi.js +206 -0
  100. package/dist/daemon/agents/kimi.js.map +1 -0
  101. package/dist/daemon/agents/opencode.js +228 -0
  102. package/dist/daemon/agents/opencode.js.map +1 -0
  103. package/dist/daemon/agents/openrouter.js +274 -0
  104. package/dist/daemon/agents/openrouter.js.map +1 -0
  105. package/dist/daemon/agents/parsers/claude.js +63 -0
  106. package/dist/daemon/agents/parsers/claude.js.map +1 -0
  107. package/dist/daemon/agents/parsers/codex.js +51 -0
  108. package/dist/daemon/agents/parsers/codex.js.map +1 -0
  109. package/dist/daemon/agents/parsers/gemini.js +144 -0
  110. package/dist/daemon/agents/parsers/gemini.js.map +1 -0
  111. package/dist/daemon/agents/parsers/index.js +31 -0
  112. package/dist/daemon/agents/parsers/index.js.map +1 -0
  113. package/dist/daemon/agents/parsers/kimi.js +8 -0
  114. package/dist/daemon/agents/parsers/kimi.js.map +1 -0
  115. package/dist/daemon/agents/parsers/opencode.js +105 -0
  116. package/dist/daemon/agents/parsers/opencode.js.map +1 -0
  117. package/dist/daemon/agents/parsers/openrouter.js +69 -0
  118. package/dist/daemon/agents/parsers/openrouter.js.map +1 -0
  119. package/dist/daemon/agents/parsers/shared.js +17 -0
  120. package/dist/daemon/agents/parsers/shared.js.map +1 -0
  121. package/dist/daemon/agents/preflight.js +83 -0
  122. package/dist/daemon/agents/preflight.js.map +1 -0
  123. package/dist/daemon/agents/quote.js +45 -0
  124. package/dist/daemon/agents/quote.js.map +1 -0
  125. package/dist/daemon/agents/sandbox-guard.js +69 -0
  126. package/dist/daemon/agents/sandbox-guard.js.map +1 -0
  127. package/dist/daemon/agents/types.js +6 -0
  128. package/dist/daemon/agents/types.js.map +1 -0
  129. package/dist/daemon/api-response.js +65 -0
  130. package/dist/daemon/api-response.js.map +1 -0
  131. package/dist/daemon/error-detector.js +329 -0
  132. package/dist/daemon/error-detector.js.map +1 -0
  133. package/dist/daemon/headless.js +533 -0
  134. package/dist/daemon/headless.js.map +1 -0
  135. package/dist/daemon/index.js +333 -0
  136. package/dist/daemon/index.js.map +1 -0
  137. package/dist/daemon/openrouter.js +192 -0
  138. package/dist/daemon/openrouter.js.map +1 -0
  139. package/dist/daemon/orchestrators/claude.js +163 -0
  140. package/dist/daemon/orchestrators/claude.js.map +1 -0
  141. package/dist/daemon/orchestrators/codex.js +101 -0
  142. package/dist/daemon/orchestrators/codex.js.map +1 -0
  143. package/dist/daemon/orchestrators/cursor-windsurf.js +118 -0
  144. package/dist/daemon/orchestrators/cursor-windsurf.js.map +1 -0
  145. package/dist/daemon/orchestrators/gemini.js +108 -0
  146. package/dist/daemon/orchestrators/gemini.js.map +1 -0
  147. package/dist/daemon/orchestrators/index.js +90 -0
  148. package/dist/daemon/orchestrators/index.js.map +1 -0
  149. package/dist/daemon/orchestrators/kimi.js +108 -0
  150. package/dist/daemon/orchestrators/kimi.js.map +1 -0
  151. package/dist/daemon/orchestrators/opencode.js +152 -0
  152. package/dist/daemon/orchestrators/opencode.js.map +1 -0
  153. package/dist/daemon/orchestrators/shared.js +60 -0
  154. package/dist/daemon/orchestrators/shared.js.map +1 -0
  155. package/dist/daemon/output-watcher.js +131 -0
  156. package/dist/daemon/output-watcher.js.map +1 -0
  157. package/dist/daemon/participant-aborts.js +123 -0
  158. package/dist/daemon/participant-aborts.js.map +1 -0
  159. package/dist/daemon/reaper.js +46 -0
  160. package/dist/daemon/reaper.js.map +1 -0
  161. package/dist/daemon/routes/chats-events.js +62 -0
  162. package/dist/daemon/routes/chats-events.js.map +1 -0
  163. package/dist/daemon/routes/chats-stream.js +241 -0
  164. package/dist/daemon/routes/chats-stream.js.map +1 -0
  165. package/dist/daemon/routes/chats-validation.js +13 -0
  166. package/dist/daemon/routes/chats-validation.js.map +1 -0
  167. package/dist/daemon/routes/chats.js +545 -0
  168. package/dist/daemon/routes/chats.js.map +1 -0
  169. package/dist/daemon/routes/openrouter.js +103 -0
  170. package/dist/daemon/routes/openrouter.js.map +1 -0
  171. package/dist/daemon/routes/settings.js +199 -0
  172. package/dist/daemon/routes/settings.js.map +1 -0
  173. package/dist/daemon/routes/stats.js +155 -0
  174. package/dist/daemon/routes/stats.js.map +1 -0
  175. package/dist/daemon/routes/system.js +208 -0
  176. package/dist/daemon/routes/system.js.map +1 -0
  177. package/dist/daemon/routes/templates-personas.js +254 -0
  178. package/dist/daemon/routes/templates-personas.js.map +1 -0
  179. package/dist/daemon/routes/voices.js +139 -0
  180. package/dist/daemon/routes/voices.js.map +1 -0
  181. package/dist/daemon/runner/doer-driver.js +346 -0
  182. package/dist/daemon/runner/doer-driver.js.map +1 -0
  183. package/dist/daemon/runner/doer.js +336 -0
  184. package/dist/daemon/runner/doer.js.map +1 -0
  185. package/dist/daemon/runner/prior-round.js +140 -0
  186. package/dist/daemon/runner/prior-round.js.map +1 -0
  187. package/dist/daemon/runner/prompt-builder.js +292 -0
  188. package/dist/daemon/runner/prompt-builder.js.map +1 -0
  189. package/dist/daemon/runner/review-only-phase.js +103 -0
  190. package/dist/daemon/runner/review-only-phase.js.map +1 -0
  191. package/dist/daemon/runner/reviewer-driver.js +410 -0
  192. package/dist/daemon/runner/reviewer-driver.js.map +1 -0
  193. package/dist/daemon/runner/reviewer.js +384 -0
  194. package/dist/daemon/runner/reviewer.js.map +1 -0
  195. package/dist/daemon/runner/run-with-fallback.js +56 -0
  196. package/dist/daemon/runner/run-with-fallback.js.map +1 -0
  197. package/dist/daemon/runner/sanitize-name.js +8 -0
  198. package/dist/daemon/runner/sanitize-name.js.map +1 -0
  199. package/dist/daemon/runner/stream-file-writer.js +116 -0
  200. package/dist/daemon/runner/stream-file-writer.js.map +1 -0
  201. package/dist/daemon/runner/swap-sidecar.js +102 -0
  202. package/dist/daemon/runner/swap-sidecar.js.map +1 -0
  203. package/dist/daemon/runner/template-fallback.js +119 -0
  204. package/dist/daemon/runner/template-fallback.js.map +1 -0
  205. package/dist/daemon/runner/types.js +3 -0
  206. package/dist/daemon/runner/types.js.map +1 -0
  207. package/dist/daemon/runner/verdict.js +51 -0
  208. package/dist/daemon/runner/verdict.js.map +1 -0
  209. package/dist/daemon/runner-multiplex.js +364 -0
  210. package/dist/daemon/runner-multiplex.js.map +1 -0
  211. package/dist/daemon/runner.js +427 -0
  212. package/dist/daemon/runner.js.map +1 -0
  213. package/dist/daemon/ship.js +340 -0
  214. package/dist/daemon/ship.js.map +1 -0
  215. package/dist/daemon/template-cache.js +37 -0
  216. package/dist/daemon/template-cache.js.map +1 -0
  217. package/dist/daemon/tmux-types.js +9 -0
  218. package/dist/daemon/tmux-types.js.map +1 -0
  219. package/dist/daemon/tmux.js +341 -0
  220. package/dist/daemon/tmux.js.map +1 -0
  221. package/dist/lib/atomic-write.js +55 -0
  222. package/dist/lib/atomic-write.js.map +1 -0
  223. package/dist/lib/chat-events-bus.js +27 -0
  224. package/dist/lib/chat-events-bus.js.map +1 -0
  225. package/dist/lib/chat-slug.js +105 -0
  226. package/dist/lib/chat-slug.js.map +1 -0
  227. package/dist/lib/cli-detect.js +388 -0
  228. package/dist/lib/cli-detect.js.map +1 -0
  229. package/dist/lib/cli-health.js +156 -0
  230. package/dist/lib/cli-health.js.map +1 -0
  231. package/dist/lib/cli-paths.js +113 -0
  232. package/dist/lib/cli-paths.js.map +1 -0
  233. package/dist/lib/cli-precheck.js +141 -0
  234. package/dist/lib/cli-precheck.js.map +1 -0
  235. package/dist/lib/db/chats.js +244 -0
  236. package/dist/lib/db/chats.js.map +1 -0
  237. package/dist/lib/db/connection.js +254 -0
  238. package/dist/lib/db/connection.js.map +1 -0
  239. package/dist/lib/db/index.js +34 -0
  240. package/dist/lib/db/index.js.map +1 -0
  241. package/dist/lib/db/personas.js +65 -0
  242. package/dist/lib/db/personas.js.map +1 -0
  243. package/dist/lib/db/phase-events.js +172 -0
  244. package/dist/lib/db/phase-events.js.map +1 -0
  245. package/dist/lib/db/secrets.js +53 -0
  246. package/dist/lib/db/secrets.js.map +1 -0
  247. package/dist/lib/db/settings.js +47 -0
  248. package/dist/lib/db/settings.js.map +1 -0
  249. package/dist/lib/db/templates.js +75 -0
  250. package/dist/lib/db/templates.js.map +1 -0
  251. package/dist/lib/db/voices.js +184 -0
  252. package/dist/lib/db/voices.js.map +1 -0
  253. package/dist/lib/lineage-maps.js +200 -0
  254. package/dist/lib/lineage-maps.js.map +1 -0
  255. package/dist/lib/logger.js +186 -0
  256. package/dist/lib/logger.js.map +1 -0
  257. package/dist/lib/personas.js +117 -0
  258. package/dist/lib/personas.js.map +1 -0
  259. package/dist/lib/runtime-path.js +222 -0
  260. package/dist/lib/runtime-path.js.map +1 -0
  261. package/dist/lib/settings/billing.js +58 -0
  262. package/dist/lib/settings/billing.js.map +1 -0
  263. package/dist/lib/settings/permissions.js +81 -0
  264. package/dist/lib/settings/permissions.js.map +1 -0
  265. package/dist/lib/settings/transport.js +113 -0
  266. package/dist/lib/settings/transport.js.map +1 -0
  267. package/dist/lib/telemetry.js +290 -0
  268. package/dist/lib/telemetry.js.map +1 -0
  269. package/dist/lib/template-schema.js +319 -0
  270. package/dist/lib/template-schema.js.map +1 -0
  271. package/dist/lib/template-validation.js +82 -0
  272. package/dist/lib/template-validation.js.map +1 -0
  273. package/dist/lib/voices.js +533 -0
  274. package/dist/lib/voices.js.map +1 -0
  275. package/dist/mcp/client.js +138 -0
  276. package/dist/mcp/client.js.map +1 -0
  277. package/dist/mcp/index.js +178 -0
  278. package/dist/mcp/index.js.map +1 -0
  279. package/dist/mcp/tools.js +355 -0
  280. package/dist/mcp/tools.js.map +1 -0
  281. package/package.json +2 -1
  282. package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0beh7rg._.js +0 -6077
  283. package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0beh7rg._.js.map +0 -69
  284. package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0pjsj.j._.js +0 -6318
  285. package/.next/dev/static/chunks/05w9_next_dist_shared_lib_0pjsj.j._.js.map +0 -71
  286. package/.next/dev/types/cache-life.d.ts +0 -145
  287. package/.next/dev/types/routes.d.ts +0 -84
  288. package/.next/dev/types/validator.ts +0 -178
  289. /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 8H2I8TTPlrKuWCV-SxY5f}/_buildManifest.js +0 -0
  290. /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 8H2I8TTPlrKuWCV-SxY5f}/_clientMiddlewareManifest.js +0 -0
  291. /package/.next/static/{dJlbRLlhISA0JGtHKVqgQ → 8H2I8TTPlrKuWCV-SxY5f}/_ssgManifest.js +0 -0
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSystemRoutes = registerSystemRoutes;
4
+ const index_js_1 = require("../../lib/db/index.js");
5
+ const api_response_js_1 = require("../api-response.js");
6
+ function registerSystemRoutes(fastify, deps) {
7
+ // List blocked chats — consumed by the MCP `list_blocked` tool. There
8
+ // is no cockpit /blocked page today; older comments referenced one
9
+ // that never landed.
10
+ fastify.get('/blocked', async () => {
11
+ try {
12
+ const items = await index_js_1.chats.list({ status: 'blocked' });
13
+ return (0, api_response_js_1.successResponse)((0, api_response_js_1.listEnvelope)(items));
14
+ }
15
+ catch (error) {
16
+ const message = error instanceof Error ? error.message : 'Unknown error';
17
+ return (0, api_response_js_1.errorResponse)('db_error', message);
18
+ }
19
+ });
20
+ // ─── CLI health snapshot ──────────────────────────────────────────────
21
+ fastify.get('/cli/health', async () => {
22
+ try {
23
+ const { getAllHealth } = await import('../../lib/cli-health.js');
24
+ const items = await getAllHealth();
25
+ return (0, api_response_js_1.successResponse)((0, api_response_js_1.listEnvelope)(items));
26
+ }
27
+ catch (error) {
28
+ const message = error instanceof Error ? error.message : 'Unknown error';
29
+ return (0, api_response_js_1.errorResponse)('internal', message);
30
+ }
31
+ });
32
+ // ─── Onboarding: detect installed CLIs + validate manual paths ────────
33
+ fastify.get('/onboard/detect-clis', async () => {
34
+ try {
35
+ const { detectAllClis } = await import('../../lib/cli-detect.js');
36
+ return (0, api_response_js_1.successResponse)((0, api_response_js_1.listEnvelope)(detectAllClis()));
37
+ }
38
+ catch (error) {
39
+ const message = error instanceof Error ? error.message : 'Unknown error';
40
+ return (0, api_response_js_1.errorResponse)('internal', message);
41
+ }
42
+ });
43
+ fastify.post('/onboard/validate-cli-path', async (req) => {
44
+ try {
45
+ const { id, path: customPath } = req.body || {};
46
+ if (!id || typeof customPath !== 'string') {
47
+ return (0, api_response_js_1.errorResponse)('bad_request', 'id and path are required');
48
+ }
49
+ const { validateCliPath } = await import('../../lib/cli-detect.js');
50
+ return (0, api_response_js_1.successResponse)(validateCliPath(id, customPath));
51
+ }
52
+ catch (error) {
53
+ const message = error instanceof Error ? error.message : 'Unknown error';
54
+ return (0, api_response_js_1.errorResponse)('internal', message);
55
+ }
56
+ });
57
+ /**
58
+ * Persist a validated manual CLI path so it survives daemon restarts
59
+ * and is visible to subsequent reviewer spawns. Pre-fix the cockpit
60
+ * just kept successful validations in React state — the next boot lost
61
+ * the hint entirely (the bug the launch dogfood pass surfaced).
62
+ *
63
+ * Caller MUST validate via `/onboard/validate-cli-path` first; we
64
+ * re-validate here as a safety net so a stale React state can't store
65
+ * a path that no longer runs.
66
+ */
67
+ fastify.post('/onboard/save-cli-path', async (req) => {
68
+ try {
69
+ const { id, path: customPath } = req.body || {};
70
+ if (!id || typeof customPath !== 'string') {
71
+ return (0, api_response_js_1.errorResponse)('bad_request', 'id and path are required');
72
+ }
73
+ const { validateCliPath, clearDetectionCache } = await import('../../lib/cli-detect.js');
74
+ const validation = validateCliPath(id, customPath);
75
+ if (!validation.found) {
76
+ return (0, api_response_js_1.errorResponse)('validation', validation.reason ?? 'path failed validation');
77
+ }
78
+ const { cliPaths } = await import('../../lib/cli-paths.js');
79
+ await cliPaths.set(id, validation.path);
80
+ // Refresh sync caches so subsequent detection + spawns honour the
81
+ // new path immediately, not after the next boot.
82
+ await cliPaths.refreshCache();
83
+ clearDetectionCache();
84
+ // Also refresh the headless spawn PATH so the new dirname is
85
+ // prepended without requiring a daemon restart.
86
+ try {
87
+ const { buildRuntimePath } = await import('../../lib/runtime-path.js');
88
+ const { setSpawnPath } = await import('../headless.js');
89
+ const merged = await buildRuntimePath({
90
+ additionalDirs: cliPaths.cachedDirs(),
91
+ });
92
+ setSpawnPath(merged);
93
+ }
94
+ catch {
95
+ /* spawn-path refresh is best-effort; spawnEnv() already
96
+ prepends cli-paths cachedDirs at spawn time */
97
+ }
98
+ return (0, api_response_js_1.successResponse)({ id, path: validation.path });
99
+ }
100
+ catch (error) {
101
+ const message = error instanceof Error ? error.message : 'Unknown error';
102
+ return (0, api_response_js_1.errorResponse)('internal', message);
103
+ }
104
+ });
105
+ /** Read every saved manual CLI path. Drives the cockpit's "saved" badge
106
+ * and `chorus doctor`. Empty values are omitted. */
107
+ fastify.get('/onboard/cli-paths', async () => {
108
+ try {
109
+ const { cliPaths } = await import('../../lib/cli-paths.js');
110
+ const all = await cliPaths.listAll();
111
+ const compact = {};
112
+ for (const [id, p] of Object.entries(all)) {
113
+ if (p)
114
+ compact[id] = p;
115
+ }
116
+ return (0, api_response_js_1.successResponse)(compact);
117
+ }
118
+ catch (error) {
119
+ const message = error instanceof Error ? error.message : 'Unknown error';
120
+ return (0, api_response_js_1.errorResponse)('internal', message);
121
+ }
122
+ });
123
+ /** Forget a saved manual path. Cockpit calls this when the user
124
+ * clicks "use auto-detect instead". */
125
+ fastify.delete('/onboard/cli-paths/:id', async (req) => {
126
+ try {
127
+ const { cliPaths } = await import('../../lib/cli-paths.js');
128
+ const { clearDetectionCache } = await import('../../lib/cli-detect.js');
129
+ await cliPaths.clear(req.params.id);
130
+ clearDetectionCache();
131
+ return (0, api_response_js_1.successResponse)({ id: req.params.id, cleared: true });
132
+ }
133
+ catch (error) {
134
+ const message = error instanceof Error ? error.message : 'Unknown error';
135
+ return (0, api_response_js_1.errorResponse)('internal', message);
136
+ }
137
+ });
138
+ // ─── Orchestrators (editors that call chorus via MCP) ────────────────
139
+ fastify.get('/orchestrators', async () => {
140
+ try {
141
+ const { listOrchestrators } = await import('../orchestrators/index.js');
142
+ return (0, api_response_js_1.successResponse)((0, api_response_js_1.listEnvelope)(listOrchestrators()));
143
+ }
144
+ catch (error) {
145
+ const message = error instanceof Error ? error.message : 'Unknown error';
146
+ return (0, api_response_js_1.errorResponse)('internal', message);
147
+ }
148
+ });
149
+ fastify.post('/orchestrators/:name/connect', async (request) => {
150
+ try {
151
+ const { connectByName, listOrchestrators } = await import('../orchestrators/index.js');
152
+ const result = await connectByName(request.params.name, {
153
+ binPath: deps.chorusBinPath,
154
+ });
155
+ const status = listOrchestrators().find((o) => o.name === request.params.name);
156
+ return (0, api_response_js_1.successResponse)({ ...result, status });
157
+ }
158
+ catch (error) {
159
+ const message = error instanceof Error ? error.message : 'Unknown error';
160
+ return (0, api_response_js_1.errorResponse)('validation', message);
161
+ }
162
+ });
163
+ // ─── OpenCode model discovery ────────────────────────────────────────
164
+ // Lists models the local `opencode` CLI knows about, grouped by gateway
165
+ // prefix (`opencode/`, `opencode-go/`, `opencode-zen/`). Used by the
166
+ // onboarding flow so users can pick which subscription models they want
167
+ // chorus to expose as voices.
168
+ fastify.get('/orchestrators/opencode/models', async () => {
169
+ try {
170
+ // Resolve the actual installed path rather than spawning bare
171
+ // 'opencode' — when the daemon's $PATH doesn't include the
172
+ // installer's bin dir (common: opencode lives at
173
+ // ~/.opencode/bin, not in /usr/local/bin), bare lookup ENOENTs
174
+ // even when detection found the binary fine.
175
+ const { detectAllClis } = await import('../../lib/cli-detect.js');
176
+ const opencode = detectAllClis().find((c) => c.id === 'opencode-cli');
177
+ if (!opencode?.found || !opencode.path) {
178
+ return (0, api_response_js_1.errorResponse)('cli_failed', 'opencode CLI not found on this host. Install from https://opencode.ai or set its path manually in onboarding.');
179
+ }
180
+ const { execFile } = await import('node:child_process');
181
+ const { promisify } = await import('node:util');
182
+ const run = promisify(execFile);
183
+ const { stdout } = await run(opencode.path, ['models'], { timeout: 10_000 });
184
+ const flat = stdout
185
+ .split('\n')
186
+ .map((l) => l.trim())
187
+ .filter((l) => l.length > 0);
188
+ const gateways = {};
189
+ for (const m of flat) {
190
+ const slash = m.indexOf('/');
191
+ const gw = slash > 0 ? m.slice(0, slash) : 'other';
192
+ if (!gateways[gw])
193
+ gateways[gw] = [];
194
+ gateways[gw].push(m);
195
+ }
196
+ // Fleet defaults — kimi + deepseek via Go subscription. Only suggest
197
+ // those that actually appear in the user's `opencode models` output.
198
+ const FLEET = ['opencode-go/kimi-k2.6', 'opencode-go/deepseek-v4-pro'];
199
+ const defaultPicks = FLEET.filter((m) => flat.includes(m));
200
+ return (0, api_response_js_1.successResponse)({ gateways, flat, defaultPicks });
201
+ }
202
+ catch (error) {
203
+ const message = error instanceof Error ? error.message : 'Unknown error';
204
+ return (0, api_response_js_1.errorResponse)('cli_failed', message);
205
+ }
206
+ });
207
+ }
208
+ //# sourceMappingURL=system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.js","sourceRoot":"","sources":["../../../src/daemon/routes/system.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,254 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.registerTemplateRoutes = registerTemplateRoutes;
7
+ exports.registerPersonaRoutes = registerPersonaRoutes;
8
+ const yaml_1 = __importDefault(require("yaml"));
9
+ const index_js_1 = require("../../lib/db/index.js");
10
+ const template_validation_js_1 = require("../../lib/template-validation.js");
11
+ const api_response_js_1 = require("../api-response.js");
12
+ function registerTemplateRoutes(fastify) {
13
+ // List all templates
14
+ fastify.get('/templates', async () => {
15
+ try {
16
+ const list = await index_js_1.templates.list();
17
+ return (0, api_response_js_1.successResponse)((0, api_response_js_1.listEnvelope)(list));
18
+ }
19
+ catch (error) {
20
+ const message = error instanceof Error ? error.message : 'Unknown error';
21
+ return (0, api_response_js_1.errorResponse)('db_error', message);
22
+ }
23
+ });
24
+ // Get one template
25
+ fastify.get('/templates/:id', async (request) => {
26
+ try {
27
+ const template = await index_js_1.templates.getById(request.params.id);
28
+ if (!template) {
29
+ return (0, api_response_js_1.errorResponse)('not_found', `Template ${request.params.id} not found`);
30
+ }
31
+ const parsed = yaml_1.default.parse(template.yaml);
32
+ return (0, api_response_js_1.successResponse)({ ...template, parsed });
33
+ }
34
+ catch (error) {
35
+ const message = error instanceof Error ? error.message : 'Unknown error';
36
+ return (0, api_response_js_1.errorResponse)('db_error', message);
37
+ }
38
+ });
39
+ // Save / update template.
40
+ //
41
+ // Source promotion semantics:
42
+ // - New rows (no existing) → source='user'.
43
+ // - Edits to a builtin → source='user' AND we promote *only* if the YAML
44
+ // actually changed. Why: seedBuiltinTemplates() resyncs every builtin
45
+ // row from prompts/templates/*.yaml on each daemon boot. If we left an
46
+ // edited row marked 'builtin', the seed loop would clobber the user's
47
+ // changes on next restart. Promoting to 'user' makes the seed loop
48
+ // skip the row (it only refreshes source='builtin'), so edits persist.
49
+ // The user accepts the tradeoff: their fork no longer auto-receives
50
+ // future builtin updates from chorus upgrades. That's the *expected*
51
+ // behaviour of "I edited this, it's mine now."
52
+ // - Edits to an existing user row → stay 'user' (no-op).
53
+ // - Save with identical YAML on a builtin → stay 'builtin' (we don't
54
+ // accidentally fork from a no-op resave).
55
+ //
56
+ // Validation runs in two stages so the cockpit can surface the *right*
57
+ // error to the user:
58
+ // 1. yaml.parse — catches syntax errors (indent, missing colon, etc.).
59
+ // 2. TemplateSchema (zod) — catches structural errors (missing phases,
60
+ // unknown lineage, reviewer.require out of bounds, hybrid review_only,
61
+ // …). Without this stage a malformed-but-parseable template would
62
+ // land in the DB and crash the runner the first time it loads it
63
+ // (getParsedTemplate calls TemplateSchema.parse with no fallback).
64
+ //
65
+ // Zod errors are flattened to {path, message} pairs so the editor can
66
+ // pin each error to its field; the response shape matches the existing
67
+ // ApiResponse `{ error, details: { issues } }` envelope.
68
+ fastify.post('/templates', async (request) => {
69
+ try {
70
+ const { id, yaml: yamlContent } = request.body;
71
+ if (!id || !yamlContent) {
72
+ return (0, api_response_js_1.errorResponse)('validation', 'id and yaml are required');
73
+ }
74
+ const validation = (0, template_validation_js_1.validateTemplateYaml)(yamlContent);
75
+ if (!validation.valid) {
76
+ const summary = validation.issues
77
+ .slice(0, 3)
78
+ .map((i) => `${i.path}: ${i.message}`)
79
+ .join('; ');
80
+ return (0, api_response_js_1.errorResponse)('validation', `Template failed validation: ${summary}${validation.issues.length > 3 ? ` (+${validation.issues.length - 3} more)` : ''}`, { issues: validation.issues });
81
+ }
82
+ const existing = await index_js_1.templates.getById(id);
83
+ let source;
84
+ if (!existing) {
85
+ source = 'user';
86
+ }
87
+ else if (existing.source === 'builtin' && existing.yaml === yamlContent) {
88
+ // No-op resave on a builtin — keep it as 'builtin' so the disk
89
+ // resync still works on next boot.
90
+ source = 'builtin';
91
+ }
92
+ else {
93
+ // Real edit OR an existing user row — both end up as 'user'.
94
+ source = 'user';
95
+ }
96
+ const template = await index_js_1.templates.create(id, yamlContent, source);
97
+ return (0, api_response_js_1.successResponse)({ ...template, sourcePromoted: existing?.source === 'builtin' && source === 'user' });
98
+ }
99
+ catch (error) {
100
+ const message = error instanceof Error ? error.message : 'Unknown error';
101
+ return (0, api_response_js_1.errorResponse)('db_error', message);
102
+ }
103
+ });
104
+ // Delete a user template. Built-ins refuse because the boot seed in
105
+ // src/daemon/index.ts re-creates them from `templates/*.yaml` on next
106
+ // start — surfacing a 400 here makes the cockpit hide the delete button
107
+ // for builtins instead of silently no-op'ing. Mirrors the persona DELETE
108
+ // route shape.
109
+ fastify.delete('/templates/:id', async (request) => {
110
+ try {
111
+ const existing = await index_js_1.templates.getById(request.params.id);
112
+ if (!existing) {
113
+ return (0, api_response_js_1.errorResponse)('not_found', `Template ${request.params.id} not found`);
114
+ }
115
+ if (existing.source === 'builtin') {
116
+ return (0, api_response_js_1.errorResponse)('validation', 'Built-in templates cannot be deleted (the boot seed would recreate them). Edit instead — your changes will be preserved.');
117
+ }
118
+ await index_js_1.templates.delete(request.params.id);
119
+ return (0, api_response_js_1.successResponse)({ id: request.params.id });
120
+ }
121
+ catch (error) {
122
+ const message = error instanceof Error ? error.message : 'Unknown error';
123
+ return (0, api_response_js_1.errorResponse)('db_error', message);
124
+ }
125
+ });
126
+ }
127
+ const PERSONA_ID_RE = /^[a-z0-9][a-z0-9-]{1,63}$/;
128
+ // Ids that would collide with cockpit URL segments or sentinel persona
129
+ // values used in template prompts. Keeping this conservative — it's
130
+ // easier to lift later than to migrate user data after a clash.
131
+ const RESERVED_PERSONA_IDS = new Set([
132
+ 'new',
133
+ 'edit',
134
+ 'create',
135
+ 'delete',
136
+ 'api',
137
+ 'admin',
138
+ 'default',
139
+ 'system',
140
+ 'none',
141
+ ]);
142
+ const VALID_LINEAGES = new Set([
143
+ 'anthropic',
144
+ 'openai',
145
+ 'google',
146
+ 'opencode',
147
+ 'moonshot',
148
+ 'openrouter',
149
+ ]);
150
+ function registerPersonaRoutes(fastify) {
151
+ fastify.get('/personas', async () => {
152
+ try {
153
+ const { listPersonas } = await import('../../lib/personas.js');
154
+ const items = await listPersonas();
155
+ return (0, api_response_js_1.successResponse)((0, api_response_js_1.listEnvelope)(items));
156
+ }
157
+ catch (error) {
158
+ const message = error instanceof Error ? error.message : 'Unknown error';
159
+ return (0, api_response_js_1.errorResponse)('db_error', message);
160
+ }
161
+ });
162
+ fastify.get('/personas/:id', async (request) => {
163
+ try {
164
+ const { getPersona } = await import('../../lib/personas.js');
165
+ const row = await getPersona(request.params.id);
166
+ if (!row) {
167
+ return (0, api_response_js_1.errorResponse)('not_found', `Persona ${request.params.id} not found`);
168
+ }
169
+ return (0, api_response_js_1.successResponse)(row);
170
+ }
171
+ catch (error) {
172
+ const message = error instanceof Error ? error.message : 'Unknown error';
173
+ return (0, api_response_js_1.errorResponse)('db_error', message);
174
+ }
175
+ });
176
+ // Create or update a persona. Edits to a builtin row demote it to
177
+ // builtin=false so the boot-time seed in seedBuiltinPersonas() skips it
178
+ // and the user's edits persist across restarts (same source-promotion
179
+ // tradeoff as templates: the row no longer auto-receives upstream changes).
180
+ fastify.post('/personas', async (request) => {
181
+ try {
182
+ const { id, label, one_liner, system_prompt, recommended_lineage, forked_from } = request.body ?? {};
183
+ if (!id || !label || !one_liner || !system_prompt) {
184
+ return (0, api_response_js_1.errorResponse)('validation', 'id, label, one_liner, and system_prompt are required');
185
+ }
186
+ if (!PERSONA_ID_RE.test(id)) {
187
+ return (0, api_response_js_1.errorResponse)('validation', 'id must match /^[a-z0-9][a-z0-9-]{1,63}$/ (lowercase, dashes)');
188
+ }
189
+ if (RESERVED_PERSONA_IDS.has(id)) {
190
+ return (0, api_response_js_1.errorResponse)('validation', `id "${id}" is reserved (would collide with a UI/API route). Pick a more specific name.`);
191
+ }
192
+ if (recommended_lineage !== undefined &&
193
+ recommended_lineage !== null &&
194
+ recommended_lineage !== '' &&
195
+ !VALID_LINEAGES.has(recommended_lineage)) {
196
+ return (0, api_response_js_1.errorResponse)('validation', `recommended_lineage must be one of: ${[...VALID_LINEAGES].join(', ')}`);
197
+ }
198
+ const { personas } = await import('../../lib/db/index.js');
199
+ const existing = await personas.getById(id);
200
+ // Provenance precedence: existing row's forked_from wins (so re-saving
201
+ // a row never loses its origin), then any client-supplied forked_from
202
+ // (set by the cockpit's Duplicate handler), else null. Built-ins
203
+ // edited *in place* (id stays the same) intentionally drop forked_from
204
+ // — recording forked_from=existing.id would create a self-cycle that
205
+ // breaks any recursive lineage traversal. Sourcefulness is captured
206
+ // in the sourcePromoted flag returned to the client and the row's
207
+ // builtin=false status; we don't need a row pointing at itself.
208
+ const resolvedForkedFrom = existing
209
+ ? (existing.forked_from ?? null)
210
+ : (forked_from && forked_from !== id ? forked_from : null);
211
+ const row = await personas.upsert({
212
+ id,
213
+ label,
214
+ one_liner,
215
+ system_prompt,
216
+ recommended_lineage: recommended_lineage && recommended_lineage !== '' ? recommended_lineage : null,
217
+ // Any save through the HTTP API marks the row as user-owned so
218
+ // seedBuiltinPersonas() leaves it alone on next boot.
219
+ builtin: false,
220
+ forked_from: resolvedForkedFrom,
221
+ });
222
+ return (0, api_response_js_1.successResponse)({
223
+ ...row,
224
+ sourcePromoted: existing?.builtin === true,
225
+ });
226
+ }
227
+ catch (error) {
228
+ const message = error instanceof Error ? error.message : 'Unknown error';
229
+ return (0, api_response_js_1.errorResponse)('db_error', message);
230
+ }
231
+ });
232
+ // Delete a user persona. Builtin rows can't be deleted because the boot
233
+ // seed would just re-create them — surfacing a 400 here makes the cockpit
234
+ // hide the delete button for builtins instead of silently no-op'ing.
235
+ fastify.delete('/personas/:id', async (request) => {
236
+ try {
237
+ const { personas } = await import('../../lib/db/index.js');
238
+ const existing = await personas.getById(request.params.id);
239
+ if (!existing) {
240
+ return (0, api_response_js_1.errorResponse)('not_found', `Persona ${request.params.id} not found`);
241
+ }
242
+ if (existing.builtin) {
243
+ return (0, api_response_js_1.errorResponse)('validation', 'Built-in personas cannot be deleted (the boot seed would recreate them). Edit instead — your changes will be preserved.');
244
+ }
245
+ await personas.delete(request.params.id);
246
+ return (0, api_response_js_1.successResponse)({ id: request.params.id });
247
+ }
248
+ catch (error) {
249
+ const message = error instanceof Error ? error.message : 'Unknown error';
250
+ return (0, api_response_js_1.errorResponse)('db_error', message);
251
+ }
252
+ });
253
+ }
254
+ //# sourceMappingURL=templates-personas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates-personas.js","sourceRoot":"","sources":["../../../src/daemon/routes/templates-personas.ts"],"names":[],"mappings":";;;;;AAoBA,wDAiIC;AA0BD,sDAyIC;AA/SD,gDAAwB;AACxB,oDAAkD;AAClD,6EAAwE;AACxE,wDAM4B;AAE5B,SAAgB,sBAAsB,CAAC,OAAwB;IAC7D,qBAAqB;IACrB,OAAO,CAAC,GAAG,CAA+C,YAAY,EAAE,KAAK,IAAI,EAAE;QACjF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,oBAAS,CAAC,IAAI,EAAE,CAAC;YACpC,OAAO,IAAA,iCAAe,EAAC,IAAA,8BAAY,EAAC,IAAI,CAAC,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,IAAA,+BAAa,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,mBAAmB;IACnB,OAAO,CAAC,GAAG,CAGR,gBAAgB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,oBAAS,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC5D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,IAAA,+BAAa,EAAC,WAAW,EAAE,YAAY,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC;YAC/E,CAAC;YACD,MAAM,MAAM,GAAG,cAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACzC,OAAO,IAAA,iCAAe,EAAC,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,IAAA,+BAAa,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,0BAA0B;IAC1B,EAAE;IACF,8BAA8B;IAC9B,8CAA8C;IAC9C,2EAA2E;IAC3E,0EAA0E;IAC1E,2EAA2E;IAC3E,0EAA0E;IAC1E,uEAAuE;IACvE,2EAA2E;IAC3E,wEAAwE;IACxE,yEAAyE;IACzE,mDAAmD;IACnD,2DAA2D;IAC3D,uEAAuE;IACvE,8CAA8C;IAC9C,EAAE;IACF,uEAAuE;IACvE,qBAAqB;IACrB,yEAAyE;IACzE,yEAAyE;IACzE,4EAA4E;IAC5E,uEAAuE;IACvE,sEAAsE;IACtE,wEAAwE;IACxE,EAAE;IACF,sEAAsE;IACtE,uEAAuE;IACvE,yDAAyD;IACzD,OAAO,CAAC,IAAI,CAGT,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACjC,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAC/C,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;gBACxB,OAAO,IAAA,+BAAa,EAAC,YAAY,EAAE,0BAA0B,CAAC,CAAC;YACjE,CAAC;YAED,MAAM,UAAU,GAAG,IAAA,6CAAoB,EAAC,WAAW,CAAC,CAAC;YACrD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;gBACtB,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM;qBAC9B,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;qBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;qBACrC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO,IAAA,+BAAa,EAClB,YAAY,EACZ,+BAA+B,OAAO,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EACzH,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAC9B,CAAC;YACJ,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,oBAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC7C,IAAI,MAA0B,CAAC;YAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,GAAG,MAAM,CAAC;YAClB,CAAC;iBAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBAC1E,+DAA+D;gBAC/D,mCAAmC;gBACnC,MAAM,GAAG,SAAS,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACN,6DAA6D;gBAC7D,MAAM,GAAG,MAAM,CAAC;YAClB,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,oBAAS,CAAC,MAAM,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;YACjE,OAAO,IAAA,iCAAe,EAAC,EAAE,GAAG,QAAQ,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC,CAAC;QAC/G,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,IAAA,+BAAa,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,oEAAoE;IACpE,sEAAsE;IACtE,wEAAwE;IACxE,yEAAyE;IACzE,eAAe;IACf,OAAO,CAAC,MAAM,CAGX,gBAAgB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,oBAAS,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC5D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,IAAA,+BAAa,EAAC,WAAW,EAAE,YAAY,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC;YAC/E,CAAC;YACD,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAClC,OAAO,IAAA,+BAAa,EAClB,YAAY,EACZ,0HAA0H,CAC3H,CAAC;YACJ,CAAC;YACD,MAAM,oBAAS,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC1C,OAAO,IAAA,iCAAe,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,IAAA,+BAAa,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,aAAa,GAAG,2BAA2B,CAAC;AAClD,uEAAuE;AACvE,oEAAoE;AACpE,gEAAgE;AAChE,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,KAAK;IACL,MAAM;IACN,QAAQ;IACR,QAAQ;IACR,KAAK;IACL,OAAO;IACP,SAAS;IACT,QAAQ;IACR,MAAM;CACP,CAAC,CAAC;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;IAC7B,WAAW;IACX,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,UAAU;IACV,YAAY;CACb,CAAC,CAAC;AAEH,SAAgB,qBAAqB,CAAC,OAAwB;IAC5D,OAAO,CAAC,GAAG,CAA+C,WAAW,EAAE,KAAK,IAAI,EAAE;QAChF,IAAI,CAAC;YACH,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;YAC/D,MAAM,KAAK,GAAG,MAAM,YAAY,EAAE,CAAC;YACnC,OAAO,IAAA,iCAAe,EAAC,IAAA,8BAAY,EAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,IAAA,+BAAa,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAGR,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;YAC7D,MAAM,GAAG,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAChD,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,IAAA,+BAAa,EAAC,WAAW,EAAE,WAAW,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC;YAC9E,CAAC;YACD,OAAO,IAAA,iCAAe,EAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,IAAA,+BAAa,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,kEAAkE;IAClE,wEAAwE;IACxE,sEAAsE;IACtE,4EAA4E;IAC5E,OAAO,CAAC,IAAI,CAUT,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChC,IAAI,CAAC;YACH,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,mBAAmB,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;YACrG,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,IAAI,CAAC,aAAa,EAAE,CAAC;gBAClD,OAAO,IAAA,+BAAa,EAClB,YAAY,EACZ,sDAAsD,CACvD,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;gBAC5B,OAAO,IAAA,+BAAa,EAClB,YAAY,EACZ,+DAA+D,CAChE,CAAC;YACJ,CAAC;YACD,IAAI,oBAAoB,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;gBACjC,OAAO,IAAA,+BAAa,EAClB,YAAY,EACZ,OAAO,EAAE,+EAA+E,CACzF,CAAC;YACJ,CAAC;YACD,IACE,mBAAmB,KAAK,SAAS;gBACjC,mBAAmB,KAAK,IAAI;gBAC5B,mBAAmB,KAAK,EAAE;gBAC1B,CAAC,cAAc,CAAC,GAAG,CAAC,mBAAmB,CAAC,EACxC,CAAC;gBACD,OAAO,IAAA,+BAAa,EAClB,YAAY,EACZ,uCAAuC,CAAC,GAAG,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxE,CAAC;YACJ,CAAC;YAED,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;YAC3D,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC5C,uEAAuE;YACvE,sEAAsE;YACtE,iEAAiE;YACjE,uEAAuE;YACvE,qEAAqE;YACrE,oEAAoE;YACpE,kEAAkE;YAClE,gEAAgE;YAChE,MAAM,kBAAkB,GAAkB,QAAQ;gBAChD,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,IAAI,IAAI,CAAC;gBAChC,CAAC,CAAC,CAAC,WAAW,IAAI,WAAW,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAC7D,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;gBAChC,EAAE;gBACF,KAAK;gBACL,SAAS;gBACT,aAAa;gBACb,mBAAmB,EACjB,mBAAmB,IAAI,mBAAmB,KAAK,EAAE,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI;gBAChF,+DAA+D;gBAC/D,sDAAsD;gBACtD,OAAO,EAAE,KAAK;gBACd,WAAW,EAAE,kBAAkB;aAChC,CAAC,CAAC;YACH,OAAO,IAAA,iCAAe,EAAC;gBACrB,GAAG,GAAG;gBACN,cAAc,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI;aAC3C,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,IAAA,+BAAa,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,wEAAwE;IACxE,0EAA0E;IAC1E,qEAAqE;IACrE,OAAO,CAAC,MAAM,CAGX,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACpC,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC;YAC3D,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC3D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,IAAA,+BAAa,EAAC,WAAW,EAAE,WAAW,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,CAAC;YAC9E,CAAC;YACD,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;gBACrB,OAAO,IAAA,+BAAa,EAClB,YAAY,EACZ,yHAAyH,CAC1H,CAAC;YACJ,CAAC;YACD,MAAM,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACzC,OAAO,IAAA,iCAAe,EAAC,EAAE,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,IAAA,+BAAa,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerVoiceRoutes = registerVoiceRoutes;
4
+ const zod_1 = require("zod");
5
+ const index_js_1 = require("../../lib/db/index.js");
6
+ const api_response_js_1 = require("../api-response.js");
7
+ const Lineage = zod_1.z.enum(['anthropic', 'openai', 'google', 'opencode', 'moonshot']);
8
+ const Source = zod_1.z.enum(['cli', 'api']);
9
+ const ListQuerySchema = zod_1.z.object({
10
+ lineage: Lineage.optional(),
11
+ source: Source.optional(),
12
+ provider: zod_1.z.string().optional(),
13
+ enabled: zod_1.z
14
+ .enum(['true', 'false'])
15
+ .optional()
16
+ .transform((v) => (v === undefined ? undefined : v === 'true')),
17
+ });
18
+ // Cost fields: $/Mtok must be a finite, non-negative number. `null` is a
19
+ // distinct legitimate state ("unknown / not set"), `0` is also legitimate
20
+ // (free tier, opencode-go subscription, plan-priced reviewers). Negative
21
+ // or non-finite (NaN, Infinity) costs would corrupt downstream cost
22
+ // dashboards and the run-page chips, so we reject them at the boundary
23
+ // rather than letting bad values reach the DB.
24
+ const Cost = zod_1.z.number().finite().min(0).nullable().optional();
25
+ const PostBodySchema = zod_1.z.object({
26
+ provider: zod_1.z.string().min(1),
27
+ model_id: zod_1.z.string().min(1),
28
+ label: zod_1.z.string().min(1),
29
+ source: Source.default('api'),
30
+ lineage: Lineage,
31
+ vendor_family: zod_1.z.string().nullable().optional(),
32
+ input_cost_per_mtok: Cost,
33
+ output_cost_per_mtok: Cost,
34
+ enabled: zod_1.z.boolean().optional(),
35
+ });
36
+ const PutBodySchema = zod_1.z.object({
37
+ label: zod_1.z.string().min(1).optional(),
38
+ enabled: zod_1.z.boolean().optional(),
39
+ input_cost_per_mtok: Cost,
40
+ output_cost_per_mtok: Cost,
41
+ });
42
+ function registerVoiceRoutes(fastify) {
43
+ // List voices, optionally filtered. Default = all rows (incl. disabled).
44
+ fastify.get('/voices', async (request, reply) => {
45
+ try {
46
+ const parsed = ListQuerySchema.safeParse(request.query);
47
+ if (!parsed.success) {
48
+ return (0, api_response_js_1.sendError)(reply, 'validation', parsed.error.message);
49
+ }
50
+ const items = await index_js_1.voices.list(parsed.data);
51
+ return (0, api_response_js_1.successResponse)((0, api_response_js_1.listEnvelope)(items));
52
+ }
53
+ catch (error) {
54
+ const message = error instanceof Error ? error.message : 'Unknown error';
55
+ return (0, api_response_js_1.errorResponse)('db_error', message);
56
+ }
57
+ });
58
+ // Single-row read.
59
+ fastify.get('/voices/:id', async (request, reply) => {
60
+ try {
61
+ const v = await index_js_1.voices.getById(request.params.id);
62
+ if (!v) {
63
+ return (0, api_response_js_1.sendError)(reply, 'not_found', `Voice ${request.params.id} not found`);
64
+ }
65
+ return (0, api_response_js_1.successResponse)(v);
66
+ }
67
+ catch (error) {
68
+ const message = error instanceof Error ? error.message : 'Unknown error';
69
+ return (0, api_response_js_1.errorResponse)('db_error', message);
70
+ }
71
+ });
72
+ // Add a voice (used by OpenRouter inline + by direct API additions).
73
+ fastify.post('/voices', async (request, reply) => {
74
+ try {
75
+ const parsed = PostBodySchema.safeParse(request.body);
76
+ if (!parsed.success) {
77
+ return (0, api_response_js_1.sendError)(reply, 'validation', parsed.error.message);
78
+ }
79
+ const id = `${parsed.data.provider}:${parsed.data.model_id}`;
80
+ const existing = await index_js_1.voices.getById(id);
81
+ if (existing) {
82
+ return (0, api_response_js_1.sendError)(reply, 'conflict', `Voice ${id} already exists`);
83
+ }
84
+ const row = await index_js_1.voices.upsert({
85
+ id,
86
+ label: parsed.data.label,
87
+ source: parsed.data.source,
88
+ provider: parsed.data.provider,
89
+ model_id: parsed.data.model_id,
90
+ lineage: parsed.data.lineage,
91
+ vendor_family: parsed.data.vendor_family ?? null,
92
+ input_cost_per_mtok: parsed.data.input_cost_per_mtok ?? null,
93
+ output_cost_per_mtok: parsed.data.output_cost_per_mtok ?? null,
94
+ enabled: parsed.data.enabled,
95
+ });
96
+ return (0, api_response_js_1.successResponse)(row);
97
+ }
98
+ catch (error) {
99
+ const message = error instanceof Error ? error.message : 'Unknown error';
100
+ return (0, api_response_js_1.errorResponse)('db_error', message);
101
+ }
102
+ });
103
+ // Toggle enabled / update label / update costs.
104
+ // source/provider/lineage/vendor_family/model_id are immutable post-create.
105
+ // Note: model_id IS rewritten on cli rows during the seed loop, but only
106
+ // by the seed (via voices.upsert), not via this route.
107
+ fastify.put('/voices/:id', async (request, reply) => {
108
+ try {
109
+ const parsed = PutBodySchema.safeParse(request.body);
110
+ if (!parsed.success) {
111
+ return (0, api_response_js_1.sendError)(reply, 'validation', parsed.error.message);
112
+ }
113
+ const existing = await index_js_1.voices.getById(request.params.id);
114
+ if (!existing) {
115
+ return (0, api_response_js_1.sendError)(reply, 'not_found', `Voice ${request.params.id} not found`);
116
+ }
117
+ const row = await index_js_1.voices.update(request.params.id, parsed.data);
118
+ return (0, api_response_js_1.successResponse)(row);
119
+ }
120
+ catch (error) {
121
+ const message = error instanceof Error ? error.message : 'Unknown error';
122
+ return (0, api_response_js_1.errorResponse)('db_error', message);
123
+ }
124
+ });
125
+ // DELETE allowed for both cli + api source. cli rows auto-heal on next
126
+ // seed if the model is still detected by the gateway (per gem-2 round 1
127
+ // MED — unblocks cleanup of deprecated OpenCode models).
128
+ fastify.delete('/voices/:id', async (request) => {
129
+ try {
130
+ await index_js_1.voices.delete(request.params.id);
131
+ return (0, api_response_js_1.successResponse)({ id: request.params.id, deleted: true });
132
+ }
133
+ catch (error) {
134
+ const message = error instanceof Error ? error.message : 'Unknown error';
135
+ return (0, api_response_js_1.errorResponse)('db_error', message);
136
+ }
137
+ });
138
+ }
139
+ //# sourceMappingURL=voices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voices.js","sourceRoot":"","sources":["../../../src/daemon/routes/voices.ts"],"names":[],"mappings":"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"}