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,290 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports._testing = void 0;
37
+ exports.isTelemetryEnabled = isTelemetryEnabled;
38
+ exports.getTelemetryStatus = getTelemetryStatus;
39
+ exports.setTelemetryEnabled = setTelemetryEnabled;
40
+ exports.getOrCreateInstallId = getOrCreateInstallId;
41
+ exports.countChatsLast24h = countChatsLast24h;
42
+ exports.buildPayload = buildPayload;
43
+ exports.sendHeartbeat = sendHeartbeat;
44
+ exports.startTelemetryHeartbeat = startTelemetryHeartbeat;
45
+ /**
46
+ * Opt-out telemetry heartbeat (round-2-deferred §4).
47
+ *
48
+ * Daemon-side ping to chorus.codes once per boot + once per 24h. The
49
+ * payload is a fixed, audited shape — version, OS, arch, node major,
50
+ * daemon uptime, count of chats in the last 24h. No chat content, no
51
+ * file paths, no hostnames, no API keys.
52
+ *
53
+ * Three opt-out paths, any one disables:
54
+ * 1. CHORUS_TELEMETRY=0 environment variable
55
+ * 2. ~/.chorus/no-telemetry touch-file (matches cargo / brew convention)
56
+ * 3. settings key `telemetry.enabled` set to false
57
+ *
58
+ * The endpoint may not exist yet — sends are fire-and-forget with a 5s
59
+ * timeout; failure logs at debug level only and never blocks the daemon
60
+ * or surfaces to the user. Schema-versioned (`schema: 1`) so future
61
+ * payload changes are additive and old daemons keep working.
62
+ */
63
+ const fs = __importStar(require("fs"));
64
+ const os = __importStar(require("os"));
65
+ const path = __importStar(require("path"));
66
+ const crypto_1 = require("crypto");
67
+ const index_js_1 = require("./db/index.js");
68
+ const ENDPOINT = 'https://chorus.codes/api/telemetry';
69
+ const SETTINGS_KEY = 'telemetry.enabled';
70
+ const HEARTBEAT_INTERVAL_MS = 24 * 60 * 60 * 1000;
71
+ const SEND_TIMEOUT_MS = 5_000;
72
+ function chorusDir() {
73
+ return path.join(os.homedir(), '.chorus');
74
+ }
75
+ function installIdPath() {
76
+ return path.join(chorusDir(), 'install-id');
77
+ }
78
+ function noTelemetryPath() {
79
+ return path.join(chorusDir(), 'no-telemetry');
80
+ }
81
+ /** Common falsy strings users naturally type to mean "off". */
82
+ const ENV_DISABLE_VALUES = new Set(['0', 'false', 'no', 'off']);
83
+ /**
84
+ * Check all three opt-out paths. Returns false if any one disables.
85
+ * Settings DB is consulted last so env / touch-file work even when the
86
+ * DB hasn't been opened yet (e.g. first-boot probe).
87
+ *
88
+ * `CHORUS_TELEMETRY` accepts any of `0`/`false`/`no`/`off` (case
89
+ * insensitive); anything else leaves telemetry enabled. The variable
90
+ * is a soft kill switch, not a strict on/off enum.
91
+ */
92
+ async function isTelemetryEnabled() {
93
+ const env = process.env.CHORUS_TELEMETRY;
94
+ if (env !== undefined && ENV_DISABLE_VALUES.has(env.toLowerCase()))
95
+ return false;
96
+ if (fs.existsSync(noTelemetryPath()))
97
+ return false;
98
+ try {
99
+ const raw = await index_js_1.settings.get(SETTINGS_KEY);
100
+ if (raw === false)
101
+ return false;
102
+ }
103
+ catch {
104
+ // DB not ready — assume enabled at the per-call level. The boot
105
+ // wiring won't hit this path because it runs after seedSettings().
106
+ }
107
+ return true;
108
+ }
109
+ /**
110
+ * Detailed status used by the cockpit UI: same effective answer as
111
+ * `isTelemetryEnabled` plus a breakdown of which path is winning, so the
112
+ * settings page can explain "disabled by env var" rather than show a toggle
113
+ * that secretly does nothing.
114
+ */
115
+ async function getTelemetryStatus() {
116
+ const env = process.env.CHORUS_TELEMETRY;
117
+ const envOverride = env !== undefined && ENV_DISABLE_VALUES.has(env.toLowerCase());
118
+ const fileOverride = fs.existsSync(noTelemetryPath());
119
+ let settingValue;
120
+ try {
121
+ const raw = await index_js_1.settings.get(SETTINGS_KEY);
122
+ if (raw === true || raw === false)
123
+ settingValue = raw;
124
+ }
125
+ catch {
126
+ /* DB not ready — leave undefined */
127
+ }
128
+ const enabled = !envOverride && !fileOverride && settingValue !== false;
129
+ return { enabled, envOverride, fileOverride, settingValue, endpoint: ENDPOINT };
130
+ }
131
+ /** Set the persisted opt-in flag. Env / file overrides still trump it. */
132
+ async function setTelemetryEnabled(value) {
133
+ await index_js_1.settings.set(SETTINGS_KEY, value);
134
+ return getTelemetryStatus();
135
+ }
136
+ /**
137
+ * Read or mint an anonymous install ID. Lives in `~/.chorus/install-id`
138
+ * as a single line; user can `rm` it to reset (a new UUID is minted on
139
+ * the next call). Not derived from anything machine-specific.
140
+ */
141
+ function getOrCreateInstallId() {
142
+ const dir = chorusDir();
143
+ if (!fs.existsSync(dir))
144
+ fs.mkdirSync(dir, { recursive: true });
145
+ const file = installIdPath();
146
+ if (fs.existsSync(file)) {
147
+ const existing = fs.readFileSync(file, 'utf-8').trim();
148
+ // Tolerate manual edits / partial writes — only accept UUID-shaped
149
+ // strings (any version); anything else gets replaced with a fresh ID
150
+ // rather than failing the heartbeat. randomUUID() emits v4, but the
151
+ // shape check is intentionally version-agnostic so a hand-edited v7
152
+ // installId from a downstream tool keeps working.
153
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(existing)) {
154
+ return existing;
155
+ }
156
+ }
157
+ const fresh = (0, crypto_1.randomUUID)();
158
+ // 0o600 — readable + writable only by the daemon's user. Belt-and-
159
+ // braces against ID correlation across users on a shared host.
160
+ fs.writeFileSync(file, fresh + '\n', { mode: 0o600 });
161
+ return fresh;
162
+ }
163
+ /**
164
+ * Count chats created in the last 24 hours. Pure DB read; no chat
165
+ * content, just a count of rows.
166
+ */
167
+ async function countChatsLast24h(now = Date.now()) {
168
+ const cutoff = now - HEARTBEAT_INTERVAL_MS;
169
+ const db = await (0, index_js_1.getDb)();
170
+ const result = await db.execute({
171
+ sql: 'SELECT COUNT(*) AS n FROM chats WHERE created_at >= ?',
172
+ args: [cutoff],
173
+ });
174
+ const row = result.rows[0];
175
+ if (!row)
176
+ return 0;
177
+ // libsql returns column values via row.n (object access) when columns
178
+ // are aliased — index access is also valid. Be defensive across both.
179
+ const raw = row.n ?? row[0];
180
+ const n = typeof raw === 'bigint' ? Number(raw) : Number(raw ?? 0);
181
+ return Number.isFinite(n) && n >= 0 ? Math.floor(n) : 0;
182
+ }
183
+ /**
184
+ * Assemble the payload. Pure shape — easy to test against the spec.
185
+ * `version` is read from package.json so a stale literal can't drift;
186
+ * caller supplies it (the daemon already imports its own version).
187
+ */
188
+ async function buildPayload(args) {
189
+ const now = args.now ?? Date.now();
190
+ // Node 'major' only — minor/patch leak less-useful detail and bloat
191
+ // the analytics cardinality.
192
+ const nodeMajor = process.versions.node.split('.')[0];
193
+ return {
194
+ schema: 1,
195
+ installId: getOrCreateInstallId(),
196
+ version: args.version,
197
+ os: process.platform,
198
+ arch: process.arch,
199
+ node: nodeMajor,
200
+ daemonUptimeSeconds: Math.max(0, Math.floor((now - args.daemonStartedAt) / 1000)),
201
+ chatsLast24h: await countChatsLast24h(now),
202
+ };
203
+ }
204
+ /**
205
+ * Fire-and-forget POST. Honours all three opt-out paths. Never throws —
206
+ * a dead endpoint, DB error during `buildPayload`, fs error during
207
+ * `getOrCreateInstallId`, or any other failure resolves to `null`
208
+ * rather than rejecting. Returns the sent payload on success so tests
209
+ * can assert exact bytes without scraping log lines.
210
+ *
211
+ * Round-1 dogfood (PR #6) caught a bug here: `buildPayload` ran
212
+ * outside the try/catch, so a transient libsql disconnect during
213
+ * shutdown rejected the promise the daemon discarded with `void`,
214
+ * producing an unhandled rejection. The whole body is now wrapped.
215
+ */
216
+ async function sendHeartbeat(args) {
217
+ const log = args.log ?? ((m) => console.log(`[telemetry] ${m}`));
218
+ try {
219
+ if (!(await isTelemetryEnabled()))
220
+ return null;
221
+ const payload = await buildPayload({
222
+ version: args.version,
223
+ daemonStartedAt: args.daemonStartedAt,
224
+ });
225
+ const fetchFn = args.fetchImpl ?? fetch;
226
+ const controller = new AbortController();
227
+ const timeout = setTimeout(() => controller.abort(), SEND_TIMEOUT_MS);
228
+ try {
229
+ await fetchFn(ENDPOINT, {
230
+ method: 'POST',
231
+ headers: { 'Content-Type': 'application/json' },
232
+ body: JSON.stringify(payload),
233
+ signal: controller.signal,
234
+ });
235
+ return payload;
236
+ }
237
+ finally {
238
+ clearTimeout(timeout);
239
+ }
240
+ }
241
+ catch (err) {
242
+ log(`heartbeat failed: ${err instanceof Error ? err.message : String(err)}`);
243
+ return null;
244
+ }
245
+ }
246
+ /**
247
+ * Boot wiring — fires once now (after a small delay so the daemon is
248
+ * definitely listening) and then every 24h. Returns the interval handle
249
+ * so the daemon can clear it on shutdown.
250
+ */
251
+ function startTelemetryHeartbeat(args) {
252
+ const setIntervalFn = args.setIntervalImpl ?? setInterval;
253
+ const setTimeoutFn = args.setTimeoutImpl ?? setTimeout;
254
+ // Small delay on first send so the daemon is definitely up + the DB is
255
+ // open. 5s is enough; the heartbeat itself has a 5s timeout.
256
+ const bootHandle = setTimeoutFn(() => {
257
+ void sendHeartbeat({ version: args.version, daemonStartedAt: args.daemonStartedAt });
258
+ }, 5_000);
259
+ const intervalHandle = setIntervalFn(() => {
260
+ void sendHeartbeat({ version: args.version, daemonStartedAt: args.daemonStartedAt });
261
+ }, HEARTBEAT_INTERVAL_MS);
262
+ // Don't pin the event loop. If the daemon ever wants natural exit
263
+ // (e.g. SIGTERM → fastify.close → drain pendings), telemetry timers
264
+ // shouldn't keep it alive. The daemon also calls .stop() on signal,
265
+ // so this is belt-and-braces.
266
+ if (typeof bootHandle.unref === 'function') {
267
+ bootHandle.unref();
268
+ }
269
+ if (typeof intervalHandle.unref === 'function') {
270
+ intervalHandle.unref();
271
+ }
272
+ return {
273
+ stop: () => {
274
+ clearTimeout(bootHandle);
275
+ clearInterval(intervalHandle);
276
+ },
277
+ };
278
+ }
279
+ // Test-only seams. These are exported under a stable namespace so the
280
+ // test file can mutate paths without touching `~/.chorus` on the host.
281
+ exports._testing = {
282
+ installIdPath,
283
+ noTelemetryPath,
284
+ chorusDir,
285
+ ENDPOINT,
286
+ SETTINGS_KEY,
287
+ HEARTBEAT_INTERVAL_MS,
288
+ SEND_TIMEOUT_MS,
289
+ };
290
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/lib/telemetry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,319 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TemplateSchema = exports.PhaseSchema = exports.DEFAULT_TMUX_PHASE_TIMEOUT_MS = exports.DEFAULT_PHASE_TIMEOUT_MS = void 0;
4
+ exports.isReviewOnlyPhase = isReviewOnlyPhase;
5
+ exports.templateRequiresArtifact = templateRequiresArtifact;
6
+ const zod_1 = require("zod");
7
+ /**
8
+ * Single phase within a template.
9
+ *
10
+ * Two phase shapes share the schema:
11
+ *
12
+ * - Standard phases (kind: plan | spec | tests | implement | review |
13
+ * verify | divergence): doer required, optional reviewer, iterate
14
+ * loop with rounds. The runner spawns the doer, then any reviewers,
15
+ * then loops on disagreement up to maxRounds.
16
+ *
17
+ * - Review-only phase (kind: review_only): NO doer block. The artifact
18
+ * is supplied at chat-create time and written into the doer answer
19
+ * slot synthetically. iterate is ignored — review-only is always one
20
+ * pass. ship is also auto-skipped (no doer diff to commit).
21
+ *
22
+ * The two are unified into one PhaseSchema via a discriminated union on
23
+ * `kind`. Templates pick exactly one shape per phase and the runner
24
+ * branches on the discriminator.
25
+ */
26
+ /**
27
+ * Default per-phase wait budget for the headless transport, used when a
28
+ * template doesn't override `timeoutMs`. Headless wraps a streaming
29
+ * subprocess; 10 min is the spawn-level wall.
30
+ */
31
+ exports.DEFAULT_PHASE_TIMEOUT_MS = 10 * 60 * 1000;
32
+ /**
33
+ * Default per-phase wait budget for the tmux file-watch path. Tighter
34
+ * than headless because the tmux flow polls a file the CLI is writing
35
+ * via a TUI — if 5 min pass with no answer.md content the CLI is almost
36
+ * certainly stuck on a prompt or has crashed silently. A template's
37
+ * `phase.timeoutMs` override beats this default on either transport.
38
+ */
39
+ exports.DEFAULT_TMUX_PHASE_TIMEOUT_MS = 5 * 60 * 1000;
40
+ /**
41
+ * Bounds on the optional per-phase timeout override.
42
+ * 30s floor catches typos; 1h ceiling catches misconfigs that would let a
43
+ * runaway CLI sit forever. A template that legitimately needs longer can
44
+ * be raised here, but anything beyond an hour is almost certainly a bug.
45
+ */
46
+ const PHASE_TIMEOUT_MIN_MS = 30_000;
47
+ const PHASE_TIMEOUT_MAX_MS = 60 * 60 * 1000;
48
+ const PhaseTimeoutSchema = zod_1.z
49
+ .number()
50
+ .int()
51
+ .min(PHASE_TIMEOUT_MIN_MS)
52
+ .max(PHASE_TIMEOUT_MAX_MS)
53
+ .optional();
54
+ const lineageEnum = zod_1.z.enum(['anthropic', 'openai', 'google', 'opencode', 'moonshot', 'openrouter', 'any']);
55
+ const reviewerLineageEnum = zod_1.z.enum(['anthropic', 'openai', 'google', 'opencode', 'moonshot', 'openrouter']);
56
+ const ReviewerSchema = zod_1.z.object({
57
+ require: zod_1.z.number().int().min(0).default(1),
58
+ crossLineage: zod_1.z.boolean().default(true),
59
+ candidates: zod_1.z.array(zod_1.z.object({
60
+ lineage: reviewerLineageEnum,
61
+ models: zod_1.z.array(zod_1.z.string()).optional(),
62
+ /**
63
+ * Optional persona id. When set, the runner prepends the persona's
64
+ * `system_prompt` (looked up from the personas table at runtime) to
65
+ * the reviewer's ask.md so this slot reviews from a specific
66
+ * worldview — e.g. `sentinel` (security), `cartographer`
67
+ * (cross-platform), `translator` (UX).
68
+ *
69
+ * Lookup is lazy: an unknown id parses fine here but the runner
70
+ * silently falls back to the no-persona prompt rather than failing
71
+ * the run. Validation that a personaId resolves is the cockpit's
72
+ * job (the picker only offers ids that exist).
73
+ */
74
+ persona: zod_1.z.string().optional(),
75
+ })),
76
+ });
77
+ const InputsSchema = zod_1.z.object({
78
+ include: zod_1.z.array(zod_1.z.string()).default([]),
79
+ exclude: zod_1.z.array(zod_1.z.string()).default([]),
80
+ }).default({ include: [], exclude: [] });
81
+ const IterateSchema = zod_1.z.object({
82
+ maxRounds: zod_1.z.number().int().min(1).default(2),
83
+ onDisagreement: zod_1.z.enum(['continue', 'escalate', 'accept-doer']).default('continue'),
84
+ // Reuse the same tmux session across rounds 1..N of THIS phase.
85
+ // Default true = save tokens (LLM keeps context in its session).
86
+ // Set false when a fresh perspective per round matters more than cost.
87
+ shareSessionAcrossRounds: zod_1.z.boolean().default(true),
88
+ // Reuse this phase's tmux session for the NEXT phase too.
89
+ // Default false = fresh session per phase boundary (different artifacts).
90
+ // Rare to enable; only when phases are tightly coupled and context-sharing helps.
91
+ shareSessionAcrossPhases: zod_1.z.boolean().default(false),
92
+ }).default({
93
+ maxRounds: 2,
94
+ onDisagreement: 'continue',
95
+ shareSessionAcrossRounds: true,
96
+ shareSessionAcrossPhases: false,
97
+ });
98
+ /**
99
+ * Standard phase: doer + optional reviewers + iterate loop.
100
+ */
101
+ const StandardPhaseSchema = zod_1.z.object({
102
+ id: zod_1.z.string().min(1),
103
+ kind: zod_1.z.enum(['plan', 'spec', 'tests', 'implement', 'review', 'verify', 'divergence']),
104
+ title: zod_1.z.string().min(1),
105
+ description: zod_1.z.string().optional(),
106
+ doer: zod_1.z.object({
107
+ lineage: lineageEnum,
108
+ models: zod_1.z.array(zod_1.z.string()).optional(),
109
+ /**
110
+ * Optional persona id. Same semantics as on reviewer candidates —
111
+ * persona.system_prompt prepends the doer's ask. Lets a template
112
+ * say "build this with a security-first worldview" instead of
113
+ * leaving worldview implicit in the doer model.
114
+ */
115
+ persona: zod_1.z.string().optional(),
116
+ }),
117
+ reviewer: ReviewerSchema.optional(),
118
+ inputs: InputsSchema,
119
+ iterate: IterateSchema,
120
+ /**
121
+ * Optional hard wait budget for both the doer subprocess and each
122
+ * reviewer subprocess in this phase. When unset, the runner falls back
123
+ * to DEFAULT_PHASE_TIMEOUT_MS. Bounds: 30s ≤ timeoutMs ≤ 1h.
124
+ */
125
+ timeoutMs: PhaseTimeoutSchema,
126
+ });
127
+ /**
128
+ * Review-only phase: artifact supplied at runtime, no doer, single pass.
129
+ *
130
+ * The `artifact` block carries cockpit hints (label, hint placeholder) and
131
+ * a hard size cap that the chat-create endpoint enforces. iterate is
132
+ * deliberately omitted — review-only is always one round, and surfacing
133
+ * iterate would imply the runner could loop, which it can't.
134
+ */
135
+ const ReviewOnlyPhaseSchema = zod_1.z.object({
136
+ id: zod_1.z.string().min(1),
137
+ kind: zod_1.z.literal('review_only'),
138
+ title: zod_1.z.string().min(1),
139
+ description: zod_1.z.string().optional(),
140
+ reviewer: ReviewerSchema,
141
+ artifact: zod_1.z.object({
142
+ label: zod_1.z.string().min(1).default('Artifact to review'),
143
+ hint: zod_1.z.string().default('Paste a unified diff, a markdown draft, code, or any text blob.'),
144
+ // 1 MiB default cap. Anything larger is rejected at chat-create time.
145
+ maxBytes: zod_1.z.number().int().min(1).default(1024 * 1024),
146
+ }).default({
147
+ label: 'Artifact to review',
148
+ hint: 'Paste a unified diff, a markdown draft, code, or any text blob.',
149
+ maxBytes: 1024 * 1024,
150
+ }),
151
+ inputs: InputsSchema,
152
+ /** Same per-phase override as standard phases; applies to all reviewers. */
153
+ timeoutMs: PhaseTimeoutSchema,
154
+ });
155
+ exports.PhaseSchema = zod_1.z.discriminatedUnion('kind', [
156
+ StandardPhaseSchema.extend({ kind: zod_1.z.literal('plan') }),
157
+ StandardPhaseSchema.extend({ kind: zod_1.z.literal('spec') }),
158
+ StandardPhaseSchema.extend({ kind: zod_1.z.literal('tests') }),
159
+ StandardPhaseSchema.extend({ kind: zod_1.z.literal('implement') }),
160
+ StandardPhaseSchema.extend({ kind: zod_1.z.literal('review') }),
161
+ StandardPhaseSchema.extend({ kind: zod_1.z.literal('verify') }),
162
+ StandardPhaseSchema.extend({ kind: zod_1.z.literal('divergence') }),
163
+ ReviewOnlyPhaseSchema,
164
+ ]);
165
+ /**
166
+ * Type guard: is this phase a review-only phase?
167
+ *
168
+ * Centralised so callers don't repeat the literal check. Also gives the
169
+ * compiler a narrowing hook so `phase.artifact` is type-safe inside the
170
+ * branch (and `phase.doer` is type-safe outside it).
171
+ */
172
+ function isReviewOnlyPhase(phase) {
173
+ return phase.kind === 'review_only';
174
+ }
175
+ /**
176
+ * A built-in or user-authored template.
177
+ * Defines the workflow: phases, agreement threshold, and escalation policy.
178
+ */
179
+ exports.TemplateSchema = zod_1.z.object({
180
+ id: zod_1.z.string().min(1),
181
+ name: zod_1.z.string().min(1),
182
+ description: zod_1.z.string().min(1),
183
+ author: zod_1.z.string().default('chorus'),
184
+ // Agreement policy
185
+ agreementThreshold: zod_1.z.number().min(0).max(1).default(0.66),
186
+ onThresholdMet: zod_1.z.enum(['merge', 'ask', 'review']).default('ask'),
187
+ maxRounds: zod_1.z.number().int().min(1).default(3),
188
+ // Runtime defaults
189
+ yoloDefault: zod_1.z.boolean().default(false),
190
+ /**
191
+ * Per-template approximation of the input-token boilerplate that goes
192
+ * into ONE reviewer's first round. Includes system prompt, persona
193
+ * block, and ask scaffolding that the daemon prepends before the
194
+ * user's artifact/work text. Used by the cockpit's pre-submit cost
195
+ * estimate; a heuristic, not a contract — actual usage depends on the
196
+ * shim's prompt-builder output.
197
+ *
198
+ * Defaults to 800 in the cockpit when a template doesn't declare a
199
+ * value (matches the previous hardcoded baseline). Templates with
200
+ * heavier scaffolding (multi-phase, dense persona text) should set
201
+ * this higher; lighter templates (review-only) lower.
202
+ */
203
+ estimatedBaselineTokens: zod_1.z.number().int().min(0).optional(),
204
+ // The workflow phases.
205
+ //
206
+ // Hybrid templates (review_only mixed with standard phases) are explicitly
207
+ // out of scope for v0.5 — the chat-create endpoint only checks phases[0]
208
+ // when deciding whether `artifact` is required, so a non-first review_only
209
+ // phase would silently run with an empty artifact. Reject the shape at
210
+ // parse time instead of accepting it and producing garbage reviews.
211
+ phases: zod_1.z
212
+ .array(exports.PhaseSchema)
213
+ .min(1)
214
+ .refine((phases) => {
215
+ const reviewOnlyCount = phases.filter((p) => p.kind === 'review_only').length;
216
+ // Either all standard, or exactly one review_only that occupies the
217
+ // entire phase list. (No partial mix; no two review_only phases —
218
+ // multi-pass review-only is also out of scope.)
219
+ return reviewOnlyCount === 0 || (reviewOnlyCount === 1 && phases.length === 1);
220
+ }, {
221
+ message: 'review_only phases cannot be mixed with other phase kinds and only one is allowed (hybrid templates are out of scope)',
222
+ })
223
+ .refine((phases) => {
224
+ // Phase IDs are referenced from the runner (phase_events.phase_id,
225
+ // chat dir layout, gate keys). Duplicates would clobber each other.
226
+ const ids = phases.map((p) => p.id);
227
+ return new Set(ids).size === ids.length;
228
+ }, {
229
+ message: 'phase ids must be unique',
230
+ }),
231
+ /**
232
+ * Optional Ship phase — runs after all phases pass + reviewers agree.
233
+ *
234
+ * When `enabled: true` AND the chat was created with `repoPath`:
235
+ * 1. Verify git context (gh CLI installed/authed, repoPath is a repo
236
+ * with a remote, base branch resolvable)
237
+ * 2. Stage + commit doer's diff with a message from the chat
238
+ * 3. Push the chorus branch
239
+ * 4. `gh pr create` against baseBranch
240
+ * 5. Stop. No auto-merge in v0.5 — human clicks Merge in GitHub UI.
241
+ *
242
+ * When `enabled: false` OR chat has no repoPath: phase is skipped,
243
+ * chat ends with status=approved as before. No noise.
244
+ *
245
+ * On any failure (gh missing, push reject, dirty working tree, etc.):
246
+ * chat ends with status=blocked and the failure mode in the meta.
247
+ *
248
+ * Note: a template whose first phase is `review_only` cannot ship — the
249
+ * runner skips ship for those regardless of this flag (no doer diff
250
+ * exists). The flag is allowed in the YAML so a template author can
251
+ * write the field without the validator rejecting it; the runner is
252
+ * the enforcement point.
253
+ */
254
+ ship: zod_1.z
255
+ .object({
256
+ enabled: zod_1.z.boolean().default(false),
257
+ /** Base branch to PR against. If unset, ship.ts detects default branch. */
258
+ baseBranch: zod_1.z.string().optional(),
259
+ /** Branch name pattern. {chatId} is substituted. */
260
+ branchPattern: zod_1.z.string().default('chorus/{chatId}'),
261
+ /** PR title template. {template} {chatId} substituted. */
262
+ titleTemplate: zod_1.z.string().default('chorus: {template} via #{chatId}'),
263
+ })
264
+ .optional(),
265
+ /**
266
+ * Template-level fallback voices. Tried in order whenever a slot
267
+ * exhausts its own per-slot model chain (`candidate.models[]`) without
268
+ * producing an answer.
269
+ *
270
+ * Split by role so authors can tune doer-failure recovery independently
271
+ * from reviewer-failure recovery — typical case: a Sonnet/Haiku ladder
272
+ * for doer (cheap, fast) but a different lineage entirely for reviewer
273
+ * fallback (diversity preservation).
274
+ *
275
+ * Dedupe rule (strict, by lineage+model, scoped per-phase per-role):
276
+ * - Skip if the candidate matches the failed slot itself (would just
277
+ * fail again).
278
+ * - Skip if the candidate matches any OTHER active slot of the same
279
+ * role in the same phase (e.g. reviewers=[kimi, deepseek] with
280
+ * fallback.reviewer=[kimi] → don't raise a second kimi reviewer).
281
+ *
282
+ * Each entry is a single voice. Authors who want a multi-model fallback
283
+ * chain put them as separate rows in priority order. Same-lineage only
284
+ * for v0.7 (cross-lineage swap is a bigger feature; out of scope).
285
+ */
286
+ fallback: zod_1.z
287
+ .object({
288
+ doer: zod_1.z
289
+ .array(zod_1.z.object({
290
+ lineage: lineageEnum,
291
+ models: zod_1.z.array(zod_1.z.string()).min(1),
292
+ persona: zod_1.z.string().optional(),
293
+ }))
294
+ .optional(),
295
+ reviewer: zod_1.z
296
+ .array(zod_1.z.object({
297
+ lineage: reviewerLineageEnum,
298
+ models: zod_1.z.array(zod_1.z.string()).min(1),
299
+ persona: zod_1.z.string().optional(),
300
+ }))
301
+ .optional(),
302
+ })
303
+ .optional(),
304
+ });
305
+ /**
306
+ * Convenience: does the template's first phase require a runtime artifact?
307
+ *
308
+ * Used by the chat-create endpoint to gate the `artifact` body field and by
309
+ * cockpit/CLI surfaces to swap UI between "task" and "artifact" affordances.
310
+ *
311
+ * NOTE: only the first phase is consulted. Hybrid templates (some phases
312
+ * review_only, some not) are out of scope for v0.5 and would need a richer
313
+ * answer.
314
+ */
315
+ function templateRequiresArtifact(template) {
316
+ const first = template.phases[0];
317
+ return first ? isReviewOnlyPhase(first) : false;
318
+ }
319
+ //# sourceMappingURL=template-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-schema.js","sourceRoot":"","sources":["../../src/lib/template-schema.ts"],"names":[],"mappings":"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"}