@iowarp/clio-coder 0.3.0

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 (226) hide show
  1. package/CHANGELOG.md +407 -0
  2. package/CODE_OF_CONDUCT.md +21 -0
  3. package/CONTRIBUTING.md +224 -0
  4. package/LICENSE +202 -0
  5. package/NOTICE +9 -0
  6. package/README.md +798 -0
  7. package/SECURITY.md +72 -0
  8. package/assets/clio-coder-logo-128.webp +0 -0
  9. package/damage-control-rules.yaml +419 -0
  10. package/dist/acp-UMLFVA3F.js +92 -0
  11. package/dist/agents-Q4MYPMUW.js +91 -0
  12. package/dist/auth-O6HYIJ6J.js +521 -0
  13. package/dist/chunk-262G75JS.js +35 -0
  14. package/dist/chunk-26BZQOAD.js +1281 -0
  15. package/dist/chunk-2J63S4SF.js +508 -0
  16. package/dist/chunk-3DANZDGR.js +717 -0
  17. package/dist/chunk-4UQA7NCT.js +29 -0
  18. package/dist/chunk-527KG6XR.js +497 -0
  19. package/dist/chunk-5LDRNKX2.js +1063 -0
  20. package/dist/chunk-5N2FG33Q.js +25 -0
  21. package/dist/chunk-67MTHP2E.js +135 -0
  22. package/dist/chunk-6CWDTGUC.js +20 -0
  23. package/dist/chunk-7BHLZB3A.js +2115 -0
  24. package/dist/chunk-7RBKDI66.js +348 -0
  25. package/dist/chunk-AMFR5YA3.js +541 -0
  26. package/dist/chunk-BBUH4VAA.js +1224 -0
  27. package/dist/chunk-BYEU76JP.js +899 -0
  28. package/dist/chunk-CLJ5HLUD.js +458 -0
  29. package/dist/chunk-D5YD55AR.js +116 -0
  30. package/dist/chunk-DXQNI4PC.js +61 -0
  31. package/dist/chunk-E3NYWENM.js +1004 -0
  32. package/dist/chunk-GNGDQYDU.js +34688 -0
  33. package/dist/chunk-GOTUR54M.js +9 -0
  34. package/dist/chunk-HBU5MTAM.js +41 -0
  35. package/dist/chunk-HMYNFFY4.js +28 -0
  36. package/dist/chunk-JPOWPFCU.js +1010 -0
  37. package/dist/chunk-JWHCJDCI.js +1215 -0
  38. package/dist/chunk-KBR4MZZR.js +41 -0
  39. package/dist/chunk-KKKPTZLM.js +93 -0
  40. package/dist/chunk-ME6DNWIU.js +66 -0
  41. package/dist/chunk-NI4DEJMC.js +88 -0
  42. package/dist/chunk-O4EJEDHO.js +659 -0
  43. package/dist/chunk-PIDUD6M2.js +31 -0
  44. package/dist/chunk-PS4PFJQP.js +29459 -0
  45. package/dist/chunk-QV47YRF4.js +48 -0
  46. package/dist/chunk-RQDWMVRB.js +279 -0
  47. package/dist/chunk-TFSSEXL6.js +136 -0
  48. package/dist/chunk-TKHQ4DGZ.js +8290 -0
  49. package/dist/chunk-TPOCL34A.js +2876 -0
  50. package/dist/chunk-UGYAX5YI.js +565 -0
  51. package/dist/chunk-UHTSULZS.js +461 -0
  52. package/dist/chunk-UU3R62TT.js +128 -0
  53. package/dist/chunk-UWIJNAOB.js +3906 -0
  54. package/dist/chunk-VOO7NYPP.js +914 -0
  55. package/dist/chunk-VPAWTYLY.js +117 -0
  56. package/dist/chunk-WD6AJM35.js +1216 -0
  57. package/dist/chunk-X3BR7HWV.js +115 -0
  58. package/dist/chunk-X3NE4WVW.js +120 -0
  59. package/dist/chunk-XNISANGE.js +1395 -0
  60. package/dist/chunk-XV4ZJ6ZM.js +3177 -0
  61. package/dist/cli/index.js +236 -0
  62. package/dist/clio-KIQ5SNDS.js +53 -0
  63. package/dist/components-JVHMUBEB.js +653 -0
  64. package/dist/config-ZFCDBMDC.js +372 -0
  65. package/dist/configure-G4E3A2PG.js +27 -0
  66. package/dist/context-CDXTP2MP.js +293 -0
  67. package/dist/context-E3KIFVXI.js +185 -0
  68. package/dist/context-clear-3F4PLXOS.js +102 -0
  69. package/dist/context-index-Q7YSYTR3.js +106 -0
  70. package/dist/docs-YIETIWZI.js +280 -0
  71. package/dist/doctor-M5HJJZOL.js +61 -0
  72. package/dist/domains/agents/builtins/architect.md +33 -0
  73. package/dist/domains/agents/builtins/coder.md +31 -0
  74. package/dist/domains/agents/builtins/context-bootstrap.md +38 -0
  75. package/dist/domains/agents/builtins/debugger.md +30 -0
  76. package/dist/domains/agents/builtins/documenter.md +31 -0
  77. package/dist/domains/agents/builtins/git-master.md +30 -0
  78. package/dist/domains/agents/builtins/provenance.md +30 -0
  79. package/dist/domains/agents/builtins/researcher.md +71 -0
  80. package/dist/domains/agents/builtins/scout.md +42 -0
  81. package/dist/domains/agents/builtins/tester.md +31 -0
  82. package/dist/domains/agents/builtins/verifier.md +30 -0
  83. package/dist/domains/agents/builtins/wiki-writer.md +41 -0
  84. package/dist/eval-B3KZZESM.js +2674 -0
  85. package/dist/evidence-V67CHM35.js +233 -0
  86. package/dist/evolve-YDZSUQYA.js +518 -0
  87. package/dist/extensions-SRG7XCAH.js +207 -0
  88. package/dist/fleet-CA2CRTVG.js +760 -0
  89. package/dist/fleet-preflight-CLIAX7YR.js +21 -0
  90. package/dist/init-2OZDJE2D.js +227 -0
  91. package/dist/memory-3PIQQAKX.js +207 -0
  92. package/dist/models-DY35XI7Y.js +237 -0
  93. package/dist/paths-5OMXW7Z4.js +57 -0
  94. package/dist/preload-KZVHET2B.js +11 -0
  95. package/dist/reset-PIFYNOS3.js +216 -0
  96. package/dist/run-3VSPP24F.js +735 -0
  97. package/dist/share-D36RQCXM.js +241 -0
  98. package/dist/skills-F2MRLELY.js +445 -0
  99. package/dist/skills-eval-E2ZTW4PL.js +932 -0
  100. package/dist/targets-DZMEZAH4.js +977 -0
  101. package/dist/trace-7NYCUI2J.js +250 -0
  102. package/dist/uninstall-AD3JWHBB.js +322 -0
  103. package/dist/upgrade-WYYBKGDY.js +301 -0
  104. package/dist/usage-ULIDAGFF.js +755 -0
  105. package/dist/version-ROZ6CZKH.js +16 -0
  106. package/dist/wiki-generate-PKFIX6OB.js +377 -0
  107. package/dist/worker/entry.js +1739 -0
  108. package/docs/README.md +93 -0
  109. package/docs/acp.md +120 -0
  110. package/docs/alcf-provider.md +72 -0
  111. package/docs/architecture.md +172 -0
  112. package/docs/artifact-versions.md +54 -0
  113. package/docs/built-in-agents.md +265 -0
  114. package/docs/capacity-and-scheduling.md +97 -0
  115. package/docs/commands-and-modes.md +554 -0
  116. package/docs/config-knobs-audit.md +115 -0
  117. package/docs/configuration-and-targets.md +812 -0
  118. package/docs/context-engine.md +236 -0
  119. package/docs/dispatch-architecture-rationale.md +126 -0
  120. package/docs/documentation-coverage.md +46 -0
  121. package/docs/documentation-guide.md +166 -0
  122. package/docs/environment-variables.md +105 -0
  123. package/docs/eval-runner.md +205 -0
  124. package/docs/evals-internal.md +298 -0
  125. package/docs/evidence-and-memory.md +243 -0
  126. package/docs/evolution.md +143 -0
  127. package/docs/exit-codes-and-output.md +74 -0
  128. package/docs/extensions-and-sharing.md +306 -0
  129. package/docs/fleet-demo-runbook.md +179 -0
  130. package/docs/fleet-dispatch.md +591 -0
  131. package/docs/glossary.md +75 -0
  132. package/docs/html/agents_blueprint.html +936 -0
  133. package/docs/html/alcf_blueprint.html +324 -0
  134. package/docs/html/architecture_blueprint.html +850 -0
  135. package/docs/html/commands_blueprint.html +794 -0
  136. package/docs/html/config_knobs_audit_blueprint.html +178 -0
  137. package/docs/html/configuration_blueprint.html +1080 -0
  138. package/docs/html/context_blueprint.html +603 -0
  139. package/docs/html/documentation_blueprint.html +832 -0
  140. package/docs/html/environment_blueprint.html +404 -0
  141. package/docs/html/eval_blueprint.html +743 -0
  142. package/docs/html/evals_internal_blueprint.html +190 -0
  143. package/docs/html/evolution_blueprint.html +674 -0
  144. package/docs/html/extensions_blueprint.html +2065 -0
  145. package/docs/html/fleet_dispatch_blueprint.html +286 -0
  146. package/docs/html/index.html +919 -0
  147. package/docs/html/lifecycle_blueprint.html +723 -0
  148. package/docs/html/memory_blueprint.html +699 -0
  149. package/docs/html/middleware_blueprint.html +664 -0
  150. package/docs/html/models_blueprint.html +2366 -0
  151. package/docs/html/observability_blueprint.html +683 -0
  152. package/docs/html/provider_adapter_blueprint.html +245 -0
  153. package/docs/html/safety_blueprint.html +1386 -0
  154. package/docs/html/shared.css +571 -0
  155. package/docs/html/shared.js +143 -0
  156. package/docs/html/skills_blueprint.html +671 -0
  157. package/docs/html/soak_blueprint.html +182 -0
  158. package/docs/html/tool_usage_blueprint.html +350 -0
  159. package/docs/html/tools_blueprint.html +2249 -0
  160. package/docs/html/trace_blueprint.html +235 -0
  161. package/docs/html/tui_design_blueprint.html +314 -0
  162. package/docs/html/validation_blueprint.html +961 -0
  163. package/docs/html/worker_dispatch_blueprint.html +231 -0
  164. package/docs/installation-and-lifecycle.md +308 -0
  165. package/docs/middleware-and-components.md +148 -0
  166. package/docs/model-catalog.md +189 -0
  167. package/docs/observability.md +233 -0
  168. package/docs/proactive-memory.md +452 -0
  169. package/docs/prompt-envelope-and-tools.md +142 -0
  170. package/docs/provider-adapter-cookbook.md +148 -0
  171. package/docs/release-cut-checklist.md +138 -0
  172. package/docs/safety-model.md +357 -0
  173. package/docs/scientific-validation.md +105 -0
  174. package/docs/session-lifecycle.md +156 -0
  175. package/docs/skills-marketplace.md +46 -0
  176. package/docs/tool-usage.md +527 -0
  177. package/docs/trace-store.md +132 -0
  178. package/docs/troubleshooting.md +33 -0
  179. package/docs/tui-design.md +239 -0
  180. package/docs/worker-dispatch-mechanics.md +242 -0
  181. package/package.json +132 -0
  182. package/skills/README.md +408 -0
  183. package/skills/git/commit-crafting/SKILL.md +79 -0
  184. package/skills/git/commit-crafting/evals.md +92 -0
  185. package/skills/git/create-pr/SKILL.md +116 -0
  186. package/skills/git/create-pr/evals.md +114 -0
  187. package/skills/git/investigate-issue/SKILL.md +139 -0
  188. package/skills/git/investigate-issue/evals.md +94 -0
  189. package/skills/git/resolve-merge-conflicts/SKILL.md +96 -0
  190. package/skills/git/resolve-merge-conflicts/evals.md +58 -0
  191. package/skills/git/review-changes/SKILL.md +103 -0
  192. package/skills/git/review-changes/evals.md +85 -0
  193. package/skills/git/worktree-create/SKILL.md +92 -0
  194. package/skills/git/worktree-create/evals.md +97 -0
  195. package/skills/git/worktree-create/references/worktree-setup.md +66 -0
  196. package/skills/git/worktree-merge/SKILL.md +95 -0
  197. package/skills/git/worktree-merge/evals.md +114 -0
  198. package/skills/skill-marketplace.json +261 -0
  199. package/skills/workflow/cut-it/SKILL.md +86 -0
  200. package/skills/workflow/cut-it/evals.md +42 -0
  201. package/src/domains/agents/builtins/architect.md +33 -0
  202. package/src/domains/agents/builtins/coder.md +31 -0
  203. package/src/domains/agents/builtins/context-bootstrap.md +38 -0
  204. package/src/domains/agents/builtins/debugger.md +30 -0
  205. package/src/domains/agents/builtins/documenter.md +31 -0
  206. package/src/domains/agents/builtins/git-master.md +30 -0
  207. package/src/domains/agents/builtins/provenance.md +30 -0
  208. package/src/domains/agents/builtins/researcher.md +71 -0
  209. package/src/domains/agents/builtins/scout.md +42 -0
  210. package/src/domains/agents/builtins/tester.md +31 -0
  211. package/src/domains/agents/builtins/verifier.md +30 -0
  212. package/src/domains/agents/builtins/wiki-writer.md +41 -0
  213. package/src/domains/agents/fleets/build-review.md +34 -0
  214. package/src/domains/agents/fleets/build-test.md +35 -0
  215. package/src/domains/agents/fleets/sdlc.md +86 -0
  216. package/src/domains/prompts/fragments/identity/clio-worker.md +11 -0
  217. package/src/domains/prompts/fragments/identity/clio.md +26 -0
  218. package/src/domains/prompts/fragments/operating/contract.md +64 -0
  219. package/src/domains/prompts/fragments/safety/auto-edit.md +14 -0
  220. package/src/domains/prompts/fragments/safety/full-auto.md +14 -0
  221. package/src/domains/prompts/fragments/safety/read-only.md +13 -0
  222. package/src/domains/prompts/fragments/safety/suggest.md +13 -0
  223. package/src/domains/prompts/fragments/wiki/page.md +75 -0
  224. package/src/domains/prompts/fragments/wiki/plan.md +48 -0
  225. package/src/domains/providers/models/cloud-models/alcf.yaml +40 -0
  226. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +993 -0
@@ -0,0 +1,1004 @@
1
+ // src/domains/observability/trace-store.ts
2
+ import { createHash } from "node:crypto";
3
+ import { mkdirSync } from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import { dirname, join } from "node:path";
6
+
7
+ // src/domains/evidence/redact.ts
8
+ function createRedactionTally() {
9
+ return { count: 0 };
10
+ }
11
+ var SECRET_PATTERNS = [
12
+ {
13
+ kind: "pem",
14
+ re: /-----BEGIN [A-Z0-9 ]*(?:PRIVATE KEY|PRIVATE KEY BLOCK)-----[\s\S]*?(?:-----END [A-Z0-9 ]*(?:PRIVATE KEY|PRIVATE KEY BLOCK)-----|$)/g
15
+ },
16
+ { kind: "aws-access-key", re: /\bAKIA[0-9A-Z]{16}\b/g },
17
+ { kind: "github-token", re: /\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{20,}\b/g },
18
+ { kind: "github-token", re: /\bgithub_pat_[A-Za-z0-9_]{20,}\b/g },
19
+ { kind: "sk-key", re: /\bsk-(?:[A-Za-z0-9_-]{2,20}-)?[A-Za-z0-9_-]{16,}\b/g },
20
+ { kind: "slack-token", re: /\bxox[bpars]-[A-Za-z0-9-]{8,}\b/g },
21
+ { kind: "google-api-key", re: /\bAIza[0-9A-Za-z_-]{30,}\b/g },
22
+ { kind: "jwt", re: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}\b/g },
23
+ {
24
+ kind: "assignment",
25
+ // KEY=value / key: value / "api_key": "value" shapes where the key name
26
+ // is secret-flavored and the value is long enough to be a credential.
27
+ re: /\b((?:[A-Za-z0-9_-]*(?:api[_-]?key|apikey|secret|token|passwd|password|credential)[A-Za-z0-9_-]*)\s*["']?\s*[:=]\s*["']?)([^\s"'`;,&|<>]{8,})/gi
28
+ }
29
+ ];
30
+ function redactSecretsText(text, tally) {
31
+ let out = text;
32
+ for (const pattern of SECRET_PATTERNS) {
33
+ out = out.replace(pattern.re, (...match) => {
34
+ tally.count += 1;
35
+ if (pattern.kind === "assignment") {
36
+ return `${String(match[1])}[redacted:${pattern.kind}]`;
37
+ }
38
+ return `[redacted:${pattern.kind}]`;
39
+ });
40
+ }
41
+ return out;
42
+ }
43
+ function redactSecretsDeep(value, tally) {
44
+ if (typeof value === "string") return redactSecretsText(value, tally);
45
+ if (Array.isArray(value)) return value.map((item) => redactSecretsDeep(item, tally));
46
+ if (value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
47
+ const out = {};
48
+ for (const [key, item] of Object.entries(value)) {
49
+ out[key] = redactSecretsDeep(item, tally);
50
+ }
51
+ return out;
52
+ }
53
+ return value;
54
+ }
55
+
56
+ // src/domains/observability/trace-store.ts
57
+ var TRACE_SCHEMA_VERSION = 1;
58
+ var TRACE_DATABASE_FILE = "trace.sqlite";
59
+ var TRACE_EVENT_POLL_LIMIT = 500;
60
+ var TRACE_PAYLOAD_LIMIT_BYTES = 16 * 1024;
61
+ var TRACE_WRITE_QUEUE_LIMIT = 2048;
62
+ var sqliteConstructor = null;
63
+ function warningTracingRequested() {
64
+ const flagged = (argument) => argument === "--trace-warnings" || argument.startsWith("--trace-warnings=");
65
+ if (process.execArgv.some(flagged)) return true;
66
+ const nodeOptions = process.env.NODE_OPTIONS;
67
+ if (nodeOptions === void 0) return false;
68
+ return nodeOptions.split(/\s+/).some(flagged);
69
+ }
70
+ function isSqliteExperimentalWarning(args) {
71
+ const [warning, second] = args;
72
+ const type = typeof second === "string" ? second : typeof second === "object" && second !== null && "type" in second ? second.type : void 0;
73
+ if (type !== "ExperimentalWarning") return false;
74
+ const text = typeof warning === "string" ? warning : warning instanceof Error ? warning.message : "";
75
+ return text.includes("SQLite is an experimental feature");
76
+ }
77
+ function requireSqlite() {
78
+ return createRequire(import.meta.url)("node:sqlite").DatabaseSync;
79
+ }
80
+ function loadWithSqliteWarningSuppressed(load) {
81
+ if (warningTracingRequested()) return load();
82
+ const emitWarning = process.emitWarning;
83
+ const forward = emitWarning.bind(process);
84
+ process.emitWarning = ((...args) => {
85
+ if (isSqliteExperimentalWarning(args)) return;
86
+ forward(...args);
87
+ });
88
+ try {
89
+ return load();
90
+ } finally {
91
+ process.emitWarning = emitWarning;
92
+ }
93
+ }
94
+ function databaseSyncConstructor() {
95
+ sqliteConstructor ??= loadWithSqliteWarningSuppressed(requireSqlite);
96
+ return sqliteConstructor;
97
+ }
98
+ function traceDatabasePath(stateDir) {
99
+ return join(stateDir, TRACE_DATABASE_FILE);
100
+ }
101
+ var TraceSchemaVersionError = class extends Error {
102
+ constructor(found) {
103
+ super(
104
+ found === null ? "trace database has no schema version" : `unsupported trace schema version ${found}; this Clio supports ${TRACE_SCHEMA_VERSION}`
105
+ );
106
+ this.found = found;
107
+ this.name = "TraceSchemaVersionError";
108
+ }
109
+ found;
110
+ };
111
+ var SESSION_TRACE_ASSIGNMENT_ID = "session";
112
+ function applyConnectionPragmas(db) {
113
+ db.exec("PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL; PRAGMA busy_timeout=5000; PRAGMA foreign_keys=ON;");
114
+ }
115
+ function readVersion(db) {
116
+ const hasMeta = db.prepare("SELECT 1 AS found FROM sqlite_master WHERE type='table' AND name='meta'").get();
117
+ if (!hasMeta) return null;
118
+ const row = db.prepare("SELECT value FROM meta WHERE key='schema_version'").get();
119
+ if (!row) return null;
120
+ const parsed = Number.parseInt(row.value, 10);
121
+ return Number.isSafeInteger(parsed) ? parsed : null;
122
+ }
123
+ function assertSupportedVersion(db) {
124
+ const version = readVersion(db);
125
+ if (version !== TRACE_SCHEMA_VERSION) throw new TraceSchemaVersionError(version);
126
+ }
127
+ var SCHEMA_SQL = `
128
+ CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);
129
+ INSERT INTO meta(key, value) VALUES ('schema_version', '${TRACE_SCHEMA_VERSION}');
130
+
131
+ CREATE TABLE runs (
132
+ run_id TEXT PRIMARY KEY,
133
+ assignment_id TEXT NOT NULL,
134
+ request TEXT,
135
+ status TEXT NOT NULL CHECK(status IN ('queued','running','success','fail')),
136
+ agent TEXT NOT NULL,
137
+ target TEXT NOT NULL,
138
+ model TEXT NOT NULL,
139
+ runtime TEXT NOT NULL,
140
+ node TEXT,
141
+ started_at TEXT NOT NULL,
142
+ ended_at TEXT,
143
+ total_tokens INTEGER,
144
+ total_cost_usd REAL
145
+ );
146
+
147
+ CREATE TABLE phases (
148
+ phase_id TEXT PRIMARY KEY,
149
+ run_id TEXT NOT NULL REFERENCES runs(run_id),
150
+ seq INTEGER NOT NULL,
151
+ name TEXT NOT NULL,
152
+ kind TEXT NOT NULL,
153
+ owner TEXT NOT NULL,
154
+ description TEXT,
155
+ status TEXT NOT NULL DEFAULT 'queued' CHECK(status IN ('queued','running','success','fail')),
156
+ attempt INTEGER NOT NULL DEFAULT 0,
157
+ retries INTEGER NOT NULL DEFAULT 0,
158
+ error TEXT,
159
+ started_at TEXT,
160
+ ended_at TEXT,
161
+ input_tokens INTEGER, output_tokens INTEGER, cache_read_tokens INTEGER, cache_write_tokens INTEGER,
162
+ reasoning_tokens INTEGER, total_tokens INTEGER,
163
+ input_cost_usd REAL, output_cost_usd REAL, cache_read_cost_usd REAL, cache_write_cost_usd REAL,
164
+ total_cost_usd REAL,
165
+ context_tokens INTEGER, context_window INTEGER
166
+ );
167
+ CREATE INDEX phases_run_seq ON phases(run_id, seq);
168
+
169
+ CREATE TABLE events (
170
+ event_id TEXT PRIMARY KEY,
171
+ run_id TEXT NOT NULL REFERENCES runs(run_id),
172
+ phase_id TEXT NOT NULL REFERENCES phases(phase_id),
173
+ parent_id TEXT,
174
+ type TEXT NOT NULL,
175
+ name TEXT NOT NULL,
176
+ payload_json TEXT,
177
+ tokens INTEGER,
178
+ started_at TEXT NOT NULL,
179
+ ended_at TEXT
180
+ );
181
+ CREATE INDEX events_run_rowid ON events(run_id);
182
+ CREATE INDEX events_phase_rowid ON events(phase_id);
183
+
184
+ CREATE TABLE envelopes (
185
+ envelope_id TEXT PRIMARY KEY,
186
+ run_id TEXT NOT NULL REFERENCES runs(run_id),
187
+ phase_id TEXT NOT NULL REFERENCES phases(phase_id),
188
+ agent TEXT NOT NULL,
189
+ output_type TEXT NOT NULL,
190
+ payload_json TEXT NOT NULL,
191
+ valid INTEGER NOT NULL CHECK(valid IN (0,1)),
192
+ attempt INTEGER NOT NULL,
193
+ created_at TEXT NOT NULL
194
+ );
195
+
196
+ CREATE TABLE gate_results (
197
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
198
+ run_id TEXT NOT NULL REFERENCES runs(run_id),
199
+ phase_id TEXT NOT NULL REFERENCES phases(phase_id),
200
+ attempt INTEGER NOT NULL,
201
+ gate TEXT NOT NULL,
202
+ passed INTEGER NOT NULL CHECK(passed IN (0,1)),
203
+ violations_json TEXT NOT NULL,
204
+ checks_json TEXT,
205
+ created_at TEXT NOT NULL
206
+ );
207
+ CREATE INDEX gate_results_phase_attempt ON gate_results(phase_id, attempt);
208
+
209
+ CREATE TABLE agent_sessions (
210
+ run_id TEXT NOT NULL REFERENCES runs(run_id),
211
+ agent TEXT NOT NULL,
212
+ runtime TEXT NOT NULL,
213
+ model TEXT NOT NULL,
214
+ session_id TEXT,
215
+ context_tokens INTEGER,
216
+ context_window INTEGER,
217
+ created_at TEXT NOT NULL,
218
+ last_used_at TEXT NOT NULL,
219
+ PRIMARY KEY (run_id, agent)
220
+ );
221
+
222
+ CREATE TABLE processes (
223
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
224
+ run_id TEXT NOT NULL REFERENCES runs(run_id),
225
+ kind TEXT NOT NULL,
226
+ name TEXT NOT NULL,
227
+ pid INTEGER NOT NULL,
228
+ command TEXT NOT NULL,
229
+ command_digest TEXT NOT NULL,
230
+ started_at TEXT NOT NULL,
231
+ ended_at TEXT
232
+ );
233
+ CREATE INDEX processes_run_live ON processes(run_id, ended_at);
234
+ `;
235
+ var TraceStore = class {
236
+ constructor(path) {
237
+ this.path = path;
238
+ mkdirSync(dirname(path), { recursive: true });
239
+ this.db = new (databaseSyncConstructor())(path);
240
+ applyConnectionPragmas(this.db);
241
+ const version = readVersion(this.db);
242
+ if (version === null) this.db.exec(`BEGIN IMMEDIATE; ${SCHEMA_SQL} COMMIT;`);
243
+ else if (version !== TRACE_SCHEMA_VERSION) throw new TraceSchemaVersionError(version);
244
+ }
245
+ path;
246
+ db;
247
+ close() {
248
+ this.db.close();
249
+ }
250
+ transaction(action) {
251
+ this.db.exec("BEGIN IMMEDIATE");
252
+ try {
253
+ action();
254
+ this.db.exec("COMMIT");
255
+ } catch (error) {
256
+ this.db.exec("ROLLBACK");
257
+ throw error;
258
+ }
259
+ }
260
+ upsertRun(input, at = (/* @__PURE__ */ new Date()).toISOString()) {
261
+ this.transaction(() => {
262
+ this.db.prepare(`INSERT INTO runs
263
+ (run_id, assignment_id, request, status, agent, target, model, runtime, node, started_at)
264
+ VALUES (?, ?, ?, 'queued', ?, ?, ?, ?, ?, ?)
265
+ ON CONFLICT(run_id) DO UPDATE SET request=excluded.request, agent=excluded.agent,
266
+ target=excluded.target, model=excluded.model, runtime=excluded.runtime, node=excluded.node`).run(
267
+ input.runId,
268
+ input.runId,
269
+ input.task === void 0 ? null : traceText(input.task, 2e3),
270
+ input.agentId,
271
+ input.targetId,
272
+ input.wireModelId,
273
+ input.runtimeId,
274
+ input.node ?? null,
275
+ at
276
+ );
277
+ this.db.prepare(`INSERT INTO phases
278
+ (phase_id, run_id, seq, name, kind, owner, description, status, started_at)
279
+ VALUES (?, ?, 0, ?, 'agent', ?, ?, 'queued', NULL)
280
+ ON CONFLICT(phase_id) DO NOTHING`).run(
281
+ input.runId,
282
+ input.runId,
283
+ traceText(input.agentId, 256),
284
+ traceText(input.agentId, 256),
285
+ input.task === void 0 ? null : traceText(input.task, 2e3)
286
+ );
287
+ });
288
+ }
289
+ startRun(input, at = (/* @__PURE__ */ new Date()).toISOString()) {
290
+ this.upsertRun(input, at);
291
+ this.transaction(() => {
292
+ this.db.prepare("UPDATE runs SET status='running', started_at=? WHERE run_id=?").run(at, input.runId);
293
+ this.db.prepare("UPDATE phases SET status='running', started_at=? WHERE phase_id=?").run(at, input.runId);
294
+ this.insertEventRaw({
295
+ eventId: `${input.runId}:agent_start`,
296
+ runId: input.runId,
297
+ phaseId: input.runId,
298
+ type: "agent_start",
299
+ name: input.agentId,
300
+ payload: { target: input.targetId, model: input.wireModelId, runtime: input.runtimeId },
301
+ startedAt: at
302
+ });
303
+ if (input.pid !== null) {
304
+ this.db.prepare(`INSERT INTO processes(run_id, kind, name, pid, command, command_digest, started_at)
305
+ VALUES (?, 'worker', ?, ?, ?, ?, ?)`).run(
306
+ input.runId,
307
+ input.agentId,
308
+ input.pid,
309
+ traceText(input.processCommand ?? "[]", 2e3),
310
+ sha256(input.processCommand ?? "[]"),
311
+ at
312
+ );
313
+ }
314
+ this.db.prepare(`INSERT INTO agent_sessions
315
+ (run_id, agent, runtime, model, session_id, context_tokens, context_window, created_at, last_used_at)
316
+ VALUES (?, ?, ?, ?, NULL, NULL, ?, ?, ?)
317
+ ON CONFLICT(run_id, agent) DO UPDATE SET runtime=excluded.runtime, model=excluded.model,
318
+ context_window=excluded.context_window, last_used_at=excluded.last_used_at`).run(
319
+ input.runId,
320
+ traceText(input.agentId, 256),
321
+ traceText(input.runtimeId, 256),
322
+ traceText(input.wireModelId, 256),
323
+ input.contextWindow ?? null,
324
+ at,
325
+ at
326
+ );
327
+ });
328
+ }
329
+ insertEvent(input) {
330
+ this.transaction(() => this.insertEventRaw(input));
331
+ }
332
+ insertEventRaw(input) {
333
+ this.db.prepare(`INSERT INTO events
334
+ (event_id, run_id, phase_id, parent_id, type, name, payload_json, tokens, started_at, ended_at)
335
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
336
+ ON CONFLICT(event_id) DO UPDATE SET name=excluded.name, payload_json=excluded.payload_json,
337
+ tokens=excluded.tokens, started_at=excluded.started_at, ended_at=excluded.ended_at`).run(
338
+ input.eventId,
339
+ input.runId,
340
+ input.phaseId,
341
+ input.parentId ?? null,
342
+ input.type,
343
+ traceText(input.name, 512),
344
+ input.payload === void 0 ? null : boundedJson(input.payload),
345
+ input.tokens ?? null,
346
+ input.startedAt,
347
+ input.endedAt ?? null
348
+ );
349
+ }
350
+ recordSpend(input) {
351
+ this.transaction(() => {
352
+ this.db.prepare(`UPDATE phases SET input_tokens=?, output_tokens=?, cache_read_tokens=?, cache_write_tokens=?,
353
+ reasoning_tokens=?, total_tokens=?, input_cost_usd=?, output_cost_usd=?, cache_read_cost_usd=?,
354
+ cache_write_cost_usd=?, total_cost_usd=?, context_tokens=?, context_window=? WHERE phase_id=? AND run_id=?`).run(
355
+ input.inputTokens,
356
+ input.outputTokens,
357
+ input.cacheReadTokens,
358
+ input.cacheWriteTokens,
359
+ input.reasoningTokens,
360
+ input.totalTokens,
361
+ input.inputCostUsd ?? null,
362
+ input.outputCostUsd ?? null,
363
+ input.cacheReadCostUsd ?? null,
364
+ input.cacheWriteCostUsd ?? null,
365
+ input.totalCostUsd,
366
+ input.contextTokens ?? null,
367
+ input.contextWindow ?? null,
368
+ input.phaseId,
369
+ input.runId
370
+ );
371
+ this.db.prepare("UPDATE runs SET total_tokens=?, total_cost_usd=? WHERE run_id=?").run(input.totalTokens, input.totalCostUsd, input.runId);
372
+ });
373
+ }
374
+ recordContext(runId, contextTokens, contextWindow, at) {
375
+ this.transaction(() => {
376
+ this.db.prepare("UPDATE phases SET context_tokens=?, context_window=COALESCE(?, context_window) WHERE run_id=?").run(contextTokens, contextWindow, runId);
377
+ this.db.prepare(`UPDATE agent_sessions SET context_tokens=?, context_window=COALESCE(?, context_window),
378
+ last_used_at=? WHERE run_id=?`).run(contextTokens, contextWindow, at, runId);
379
+ });
380
+ }
381
+ recordGate(input) {
382
+ const violations = input.checks?.filter((check) => !check.ok).map((check) => `${check.item}: ${check.note}`) ?? [];
383
+ this.transaction(() => {
384
+ this.db.prepare("DELETE FROM gate_results WHERE run_id=? AND phase_id=? AND attempt=? AND gate=?").run(input.runId, input.phaseId, input.attempt, input.gate);
385
+ this.db.prepare(`INSERT INTO gate_results
386
+ (run_id, phase_id, attempt, gate, passed, violations_json, checks_json, created_at)
387
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(
388
+ input.runId,
389
+ input.phaseId,
390
+ input.attempt,
391
+ input.gate,
392
+ input.passed ? 1 : 0,
393
+ JSON.stringify(violations),
394
+ input.checks === null ? null : JSON.stringify(input.checks),
395
+ input.createdAt
396
+ );
397
+ this.insertEventRaw({
398
+ eventId: `${input.runId}:gate:${input.gate}:${input.attempt}`,
399
+ runId: input.runId,
400
+ phaseId: input.phaseId,
401
+ type: input.passed ? "gate_pass" : "gate_fail",
402
+ name: input.gate,
403
+ payload: { attempt: input.attempt, checks: input.checks, violations },
404
+ startedAt: input.createdAt
405
+ });
406
+ });
407
+ }
408
+ recordEnvelope(input) {
409
+ this.transaction(() => {
410
+ this.db.prepare(`INSERT OR REPLACE INTO envelopes
411
+ (envelope_id, run_id, phase_id, agent, output_type, payload_json, valid, attempt, created_at)
412
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(
413
+ input.envelopeId,
414
+ input.runId,
415
+ input.phaseId,
416
+ input.agent,
417
+ input.outputType,
418
+ boundedJson(input.payload),
419
+ input.valid ? 1 : 0,
420
+ input.attempt,
421
+ input.createdAt
422
+ );
423
+ });
424
+ }
425
+ startProcess(input) {
426
+ let id = 0;
427
+ this.transaction(() => {
428
+ const result = this.db.prepare(`INSERT INTO processes(run_id, kind, name, pid, command, command_digest, started_at)
429
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(
430
+ input.runId,
431
+ input.kind,
432
+ traceText(input.name, 256),
433
+ input.pid,
434
+ traceText(input.command, 2e3),
435
+ sha256(input.command),
436
+ input.startedAt
437
+ );
438
+ id = Number(result.lastInsertRowid);
439
+ });
440
+ return id;
441
+ }
442
+ endProcesses(runId, endedAt) {
443
+ this.transaction(() => {
444
+ this.db.prepare("UPDATE processes SET ended_at=? WHERE run_id=? AND ended_at IS NULL").run(endedAt, runId);
445
+ });
446
+ }
447
+ recordRetryDenied(runId, agentId, detail, at) {
448
+ this.transaction(() => {
449
+ const phase = this.db.prepare("SELECT phase_id FROM phases WHERE run_id=? ORDER BY seq LIMIT 1").get(runId);
450
+ if (!phase) return;
451
+ this.insertEventRaw({
452
+ eventId: `${runId}:retry_denied:${at}`,
453
+ runId,
454
+ phaseId: phase.phase_id,
455
+ type: "error",
456
+ name: "retry denied",
457
+ payload: { agent: agentId, detail, reason: "retry_denied" },
458
+ startedAt: at
459
+ });
460
+ });
461
+ }
462
+ finishRun(input, success, at = (/* @__PURE__ */ new Date()).toISOString()) {
463
+ this.transaction(() => {
464
+ const fallbackStartedAt = typeof input.durationMs === "number" ? new Date(Math.max(0, Date.parse(at) - input.durationMs)).toISOString() : at;
465
+ this.db.prepare(`INSERT INTO runs
466
+ (run_id, assignment_id, request, status, agent, target, model, runtime, node, started_at)
467
+ VALUES (?, ?, ?, 'running', ?, ?, ?, ?, ?, ?)
468
+ ON CONFLICT(run_id) DO NOTHING`).run(
469
+ input.runId,
470
+ input.lineage?.rootRunId ?? input.runId,
471
+ input.task === void 0 ? null : traceText(input.task, 2e3),
472
+ input.agentId,
473
+ input.targetId,
474
+ input.wireModelId,
475
+ input.runtimeId,
476
+ input.node ?? null,
477
+ fallbackStartedAt
478
+ );
479
+ this.db.prepare(`INSERT INTO phases
480
+ (phase_id, run_id, seq, name, kind, owner, description, status, started_at)
481
+ VALUES (?, ?, 0, ?, 'agent', ?, ?, 'running', ?)
482
+ ON CONFLICT(phase_id) DO NOTHING`).run(
483
+ input.runId,
484
+ input.runId,
485
+ traceText(input.agentId, 256),
486
+ traceText(input.agentId, 256),
487
+ input.task === void 0 ? null : traceText(input.task, 2e3),
488
+ fallbackStartedAt
489
+ );
490
+ this.db.prepare("UPDATE runs SET assignment_id=?, status=?, ended_at=?, total_tokens=?, total_cost_usd=? WHERE run_id=?").run(
491
+ input.lineage?.rootRunId ?? input.runId,
492
+ success ? "success" : "fail",
493
+ at,
494
+ input.tokenCount ?? null,
495
+ input.costUsd ?? null,
496
+ input.runId
497
+ );
498
+ this.db.prepare(`UPDATE phases SET status=?, attempt=?, retries=?, ended_at=?, error=?, input_tokens=?, output_tokens=?,
499
+ cache_read_tokens=?, cache_write_tokens=?, reasoning_tokens=?, total_tokens=?, total_cost_usd=?
500
+ WHERE phase_id=?`).run(
501
+ success ? "success" : "fail",
502
+ input.lineage?.attempt ?? 0,
503
+ input.lineage?.attempt ?? 0,
504
+ at,
505
+ success ? null : input.outcomeDetail,
506
+ input.inputTokenCount ?? null,
507
+ input.outputTokenCount ?? null,
508
+ input.cacheReadTokenCount ?? null,
509
+ input.cacheWriteTokenCount ?? null,
510
+ input.reasoningTokenCount ?? null,
511
+ input.tokenCount ?? null,
512
+ input.costUsd ?? null,
513
+ input.runId
514
+ );
515
+ this.db.prepare("UPDATE processes SET ended_at=? WHERE run_id=? AND ended_at IS NULL").run(at, input.runId);
516
+ this.insertEventRaw({
517
+ eventId: `${input.runId}:agent_end`,
518
+ runId: input.runId,
519
+ phaseId: input.runId,
520
+ type: "agent_end",
521
+ name: input.agentId,
522
+ payload: {
523
+ outcome: input.outcome,
524
+ outcomeDetail: input.outcomeDetail,
525
+ usage: terminalUsage(input),
526
+ cost: input.costUsd ?? null,
527
+ contextWindow: input.contextWindow ?? null
528
+ },
529
+ tokens: input.tokenCount ?? null,
530
+ startedAt: at
531
+ });
532
+ this.insertEventRaw({
533
+ eventId: `${input.runId}:phase_end`,
534
+ runId: input.runId,
535
+ phaseId: input.runId,
536
+ type: "phase_end",
537
+ name: input.agentId,
538
+ payload: { status: success ? "success" : "fail" },
539
+ startedAt: at
540
+ });
541
+ });
542
+ }
543
+ /**
544
+ * Record one fact about a turn the operator ran in the chat loop.
545
+ *
546
+ * The three shapes reuse the dispatch tables exactly: `start` opens the
547
+ * runs/phases pair, `event` appends to the same `events` table a worker's
548
+ * tool calls land in, and `finish` closes both with the turn's usage. The
549
+ * phase id is the run id, as it is for a dispatched run's single phase, so
550
+ * `clio-coder trace phases` and `clio-coder trace tail` need no session-specific path.
551
+ */
552
+ recordSessionTurn(input) {
553
+ if (input.kind === "start") {
554
+ this.startSessionTurn(input);
555
+ return;
556
+ }
557
+ if (input.kind === "event") {
558
+ this.transaction(() => {
559
+ this.insertEventRaw({
560
+ eventId: `${input.runId}:${input.eventId}`,
561
+ runId: input.runId,
562
+ phaseId: input.runId,
563
+ parentId: `${input.runId}:turn_start`,
564
+ type: input.type,
565
+ name: input.name,
566
+ ...input.payload === void 0 ? {} : { payload: input.payload },
567
+ tokens: input.tokens ?? null,
568
+ startedAt: input.startedAt,
569
+ endedAt: input.endedAt ?? null
570
+ });
571
+ });
572
+ return;
573
+ }
574
+ this.finishSessionTurn(input);
575
+ }
576
+ startSessionTurn(input) {
577
+ this.transaction(() => {
578
+ this.db.prepare(`INSERT INTO runs
579
+ (run_id, assignment_id, request, status, agent, target, model, runtime, node, started_at)
580
+ VALUES (?, ?, ?, 'running', ?, ?, ?, ?, NULL, ?)
581
+ ON CONFLICT(run_id) DO NOTHING`).run(
582
+ input.runId,
583
+ SESSION_TRACE_ASSIGNMENT_ID,
584
+ input.prompt === null ? null : traceText(input.prompt, 2e3),
585
+ traceText(input.agent, 256),
586
+ traceText(input.target, 256),
587
+ traceText(input.model, 256),
588
+ traceText(input.runtime, 256),
589
+ input.at
590
+ );
591
+ this.db.prepare(`INSERT INTO phases
592
+ (phase_id, run_id, seq, name, kind, owner, description, status, started_at)
593
+ VALUES (?, ?, 0, ?, 'session', ?, ?, 'running', ?)
594
+ ON CONFLICT(phase_id) DO NOTHING`).run(
595
+ input.runId,
596
+ input.runId,
597
+ traceText(input.agent, 256),
598
+ traceText(input.agent, 256),
599
+ input.prompt === null ? null : traceText(input.prompt, 2e3),
600
+ input.at
601
+ );
602
+ this.insertEventRaw({
603
+ eventId: `${input.runId}:turn_start`,
604
+ runId: input.runId,
605
+ phaseId: input.runId,
606
+ type: "agent_start",
607
+ name: input.agent,
608
+ payload: { target: input.target, model: input.model, runtime: input.runtime, session: true },
609
+ startedAt: input.at
610
+ });
611
+ });
612
+ }
613
+ finishSessionTurn(input) {
614
+ const usage = input.usage;
615
+ this.transaction(() => {
616
+ this.db.prepare("UPDATE runs SET status=?, ended_at=?, total_tokens=?, total_cost_usd=? WHERE run_id=?").run(input.status, input.at, usage?.totalTokens ?? null, usage?.costUsd ?? null, input.runId);
617
+ this.db.prepare(`UPDATE phases SET status=?, ended_at=?, error=?, input_tokens=?, output_tokens=?,
618
+ cache_read_tokens=?, cache_write_tokens=?, reasoning_tokens=?, total_tokens=?, total_cost_usd=?
619
+ WHERE phase_id=?`).run(
620
+ input.status,
621
+ input.at,
622
+ input.error,
623
+ usage?.inputTokens ?? null,
624
+ usage?.outputTokens ?? null,
625
+ usage?.cacheReadTokens ?? null,
626
+ usage?.cacheWriteTokens ?? null,
627
+ usage?.reasoningTokens ?? null,
628
+ usage?.totalTokens ?? null,
629
+ usage?.costUsd ?? null,
630
+ input.runId
631
+ );
632
+ this.insertEventRaw({
633
+ eventId: `${input.runId}:turn_end`,
634
+ runId: input.runId,
635
+ phaseId: input.runId,
636
+ type: "agent_end",
637
+ name: input.status,
638
+ payload: { status: input.status, error: input.error, usage },
639
+ tokens: usage?.totalTokens ?? null,
640
+ startedAt: input.at
641
+ });
642
+ });
643
+ }
644
+ };
645
+ var TraceReader = class {
646
+ constructor(path) {
647
+ this.path = path;
648
+ this.db = new (databaseSyncConstructor())(path, { readOnly: true });
649
+ this.db.exec("PRAGMA busy_timeout=5000;");
650
+ assertSupportedVersion(this.db);
651
+ const mode = this.db.prepare("PRAGMA journal_mode").get();
652
+ if (mode.journal_mode.toLowerCase() !== "wal")
653
+ throw new Error(`trace database journal mode is ${mode.journal_mode}, expected WAL`);
654
+ }
655
+ path;
656
+ db;
657
+ close() {
658
+ this.db.close();
659
+ }
660
+ runs(limit = 50) {
661
+ return this.db.prepare("SELECT * FROM runs ORDER BY started_at DESC LIMIT ?").all(clampInt(limit, 1, 500));
662
+ }
663
+ run(runId) {
664
+ return this.db.prepare("SELECT * FROM runs WHERE run_id=?").get(runId) ?? null;
665
+ }
666
+ phases(runId) {
667
+ return this.db.prepare("SELECT * FROM phases WHERE run_id=? ORDER BY seq, phase_id").all(runId);
668
+ }
669
+ events(runId, afterRowid = 0, limit = TRACE_EVENT_POLL_LIMIT) {
670
+ return this.db.prepare(`SELECT rowid, event_id, run_id, phase_id, parent_id, type, name, payload_json,
671
+ tokens, started_at, ended_at FROM events
672
+ WHERE run_id = ? AND rowid > ? ORDER BY rowid LIMIT ?`).all(
673
+ runId,
674
+ Math.max(0, Math.trunc(afterRowid)),
675
+ clampInt(limit, 1, TRACE_EVENT_POLL_LIMIT)
676
+ );
677
+ }
678
+ processes(runId) {
679
+ return this.db.prepare("SELECT * FROM processes WHERE run_id=? ORDER BY ended_at IS NOT NULL, id").all(runId);
680
+ }
681
+ gateResults(runId) {
682
+ return this.db.prepare("SELECT * FROM gate_results WHERE run_id=? ORDER BY phase_id, attempt, id").all(runId);
683
+ }
684
+ envelopes(runId) {
685
+ return this.db.prepare("SELECT * FROM envelopes WHERE run_id=? ORDER BY created_at, envelope_id").all(runId);
686
+ }
687
+ select(sql) {
688
+ assertSelectOnly(sql);
689
+ return this.db.prepare(sql).all();
690
+ }
691
+ };
692
+ function createDispatchTraceMirror(path, options = {}) {
693
+ const warn = options.warn ?? ((message) => process.stderr.write(`[clio:trace] ${message}
694
+ `));
695
+ const now = options.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
696
+ let store = null;
697
+ let chain = Promise.resolve();
698
+ let closed = false;
699
+ let degraded = false;
700
+ let pendingWrites = 0;
701
+ let droppedProgress = 0;
702
+ const starts = /* @__PURE__ */ new Map();
703
+ const seen = /* @__PURE__ */ new Map();
704
+ const contextWindows = /* @__PURE__ */ new Map();
705
+ const gateRuns = /* @__PURE__ */ new Map();
706
+ const getStore = () => {
707
+ store ??= new TraceStore(path);
708
+ return store;
709
+ };
710
+ const schedule = (work) => {
711
+ if (closed || degraded) return;
712
+ pendingWrites += 1;
713
+ chain = chain.then(
714
+ () => new Promise((resolve) => {
715
+ setImmediate(() => {
716
+ try {
717
+ if (degraded) {
718
+ pendingWrites -= 1;
719
+ return resolve();
720
+ }
721
+ work();
722
+ } catch (error) {
723
+ if (!degraded) warn(error instanceof Error ? error.message : String(error));
724
+ degraded = true;
725
+ }
726
+ pendingWrites -= 1;
727
+ resolve();
728
+ });
729
+ })
730
+ );
731
+ };
732
+ return {
733
+ enqueue(channel, raw) {
734
+ const observedAt = now();
735
+ if (pendingWrites >= TRACE_WRITE_QUEUE_LIMIT && !isCriticalTraceEvent(channel, raw)) {
736
+ droppedProgress += 1;
737
+ return;
738
+ }
739
+ schedule(() => {
740
+ if (!isRecord(raw)) return;
741
+ if (channel === "dispatch.enqueued") {
742
+ const payload = raw;
743
+ getStore().upsertRun(payload, observedAt);
744
+ if (payload.contextWindow !== void 0) contextWindows.set(payload.runId, payload.contextWindow);
745
+ if (payload.gate !== void 0) gateRuns.set(payload.runId, payload.gate);
746
+ } else if (channel === "dispatch.started")
747
+ getStore().startRun(raw, observedAt);
748
+ else if (channel === "dispatch.progress")
749
+ recordProgress(
750
+ getStore(),
751
+ raw,
752
+ starts,
753
+ seen,
754
+ contextWindows,
755
+ gateRuns,
756
+ observedAt
757
+ );
758
+ else if (channel === "dispatch.completed")
759
+ getStore().finishRun(raw, true, observedAt);
760
+ else if (channel === "dispatch.failed")
761
+ recordFailure(getStore(), raw, observedAt);
762
+ });
763
+ },
764
+ enqueueSessionTurn(trace) {
765
+ schedule(() => getStore().recordSessionTurn(trace));
766
+ },
767
+ async flush() {
768
+ await chain;
769
+ if (droppedProgress > 0) {
770
+ warn(`dropped ${droppedProgress} display-only progress events because the trace queue was full`);
771
+ droppedProgress = 0;
772
+ }
773
+ },
774
+ async close() {
775
+ closed = true;
776
+ await chain;
777
+ if (droppedProgress > 0)
778
+ warn(`dropped ${droppedProgress} display-only progress events because the trace queue was full`);
779
+ store?.close();
780
+ }
781
+ };
782
+ }
783
+ function recordProgress(store, payload, starts, seen, contextWindows, gateRuns, at) {
784
+ if (!isRecord(payload.event)) return;
785
+ const event = payload.event;
786
+ const type = typeof event.type === "string" ? event.type : "progress";
787
+ const toolCallId = stringValue(event.toolCallId) ?? stringValue(event.tool_call_id);
788
+ if (type === "message_end" && isRecord(event.message) && event.message.role === "assistant" && event.message.stopReason !== "error" && event.message.stopReason !== "aborted" && isRecord(event.message.usage)) {
789
+ const usage = event.message.usage;
790
+ const contextTokens = finiteNonNegative(usage.totalTokens) ?? finiteNonNegative(usage.total_tokens) ?? [usage.input, usage.output, usage.cacheRead, usage.cacheWrite].map((value) => finiteNonNegative(value) ?? 0).reduce((sum, value) => sum + value, 0);
791
+ store.recordContext(payload.runId, contextTokens, contextWindows.get(payload.runId) ?? null, at);
792
+ }
793
+ const gate = gateRuns.get(payload.runId);
794
+ if (type === "message_end" && gate !== void 0 && isRecord(event.message) && event.message.role === "assistant") {
795
+ const result = structuredGateResult(messageText(event.message));
796
+ if (result !== null) {
797
+ store.recordGate({
798
+ runId: payload.runId,
799
+ phaseId: payload.runId,
800
+ attempt: gate.cycle,
801
+ gate: gate.role,
802
+ passed: result.passed,
803
+ checks: result.checks,
804
+ createdAt: at
805
+ });
806
+ }
807
+ }
808
+ if ((type === "tool_execution_start" || type === "clio_tool_start") && toolCallId !== null) {
809
+ starts.set(`${payload.runId}:${toolCallId}`, {
810
+ toolCallId,
811
+ tool: stringValue(event.toolName) ?? stringValue(event.tool) ?? "tool",
812
+ args: event.args ?? null,
813
+ startedAt: at
814
+ });
815
+ return;
816
+ }
817
+ if ((type === "tool_execution_end" || type === "clio_tool_finish") && toolCallId !== null) {
818
+ const key = `${payload.runId}:${toolCallId}`;
819
+ const start = starts.get(key);
820
+ const duration = finiteNonNegative(event.durationMs);
821
+ const startedAt = start?.startedAt ?? (duration === null ? at : new Date(Date.parse(at) - duration).toISOString());
822
+ const tool = start?.tool ?? stringValue(event.toolName) ?? stringValue(event.tool) ?? "tool";
823
+ const args = start?.args ?? event.args ?? null;
824
+ const result = event.result ?? event.resultSnippet ?? null;
825
+ const ok = event.isError !== true && event.outcome !== "error" && event.outcome !== "blocked";
826
+ store.insertEvent({
827
+ eventId: `${payload.runId}:tool:${toolCallId}`,
828
+ runId: payload.runId,
829
+ phaseId: payload.runId,
830
+ parentId: `${payload.runId}:agent_start`,
831
+ type: "tool_call",
832
+ name: readableToolName(tool, args),
833
+ payload: {
834
+ tool,
835
+ tool_call_id: toolCallId,
836
+ args,
837
+ result_snippet: boundedSnippet(result),
838
+ ok,
839
+ duration_ms: duration,
840
+ agent: payload.agentId
841
+ },
842
+ startedAt,
843
+ endedAt: at
844
+ });
845
+ starts.delete(key);
846
+ return;
847
+ }
848
+ const sequence = (seen.get(payload.runId) ?? 0) + 1;
849
+ seen.set(payload.runId, sequence);
850
+ store.insertEvent({
851
+ eventId: `${payload.runId}:event:${sequence}`,
852
+ runId: payload.runId,
853
+ phaseId: payload.runId,
854
+ parentId: `${payload.runId}:agent_start`,
855
+ type: normalizeEventType(type),
856
+ name: eventName(event, type),
857
+ payload: projectProgressPayload(type, event),
858
+ tokens: eventTokens(event),
859
+ startedAt: at
860
+ });
861
+ }
862
+ function terminalUsage(input) {
863
+ if (input.tokenCount === void 0) return null;
864
+ return {
865
+ input: input.inputTokenCount ?? 0,
866
+ output: input.outputTokenCount ?? 0,
867
+ cache_read: input.cacheReadTokenCount ?? 0,
868
+ cache_write: input.cacheWriteTokenCount ?? 0,
869
+ reasoning_tokens: input.reasoningTokenCount ?? 0,
870
+ total_tokens: input.tokenCount
871
+ };
872
+ }
873
+ function recordFailure(store, input, at) {
874
+ if (input.reason === "retry_denied") {
875
+ store.recordRetryDenied(input.runId, input.agentId, input.outcomeDetail, at);
876
+ return;
877
+ }
878
+ store.finishRun(input, false, at);
879
+ }
880
+ function isCriticalTraceEvent(channel, raw) {
881
+ if (channel !== "dispatch.progress") return true;
882
+ if (!isRecord(raw) || !isRecord(raw.event)) return false;
883
+ const type = raw.event.type;
884
+ return type === "tool_execution_start" || type === "tool_execution_end" || type === "clio_tool_start" || type === "clio_tool_finish" || type === "message_end" || type === "attempt_start";
885
+ }
886
+ function projectProgressPayload(type, event) {
887
+ if (type === "message_end") {
888
+ const message = isRecord(event.message) ? event.message : {};
889
+ return {
890
+ role: message.role ?? null,
891
+ stopReason: message.stopReason ?? null,
892
+ usage: isRecord(message.usage) ? message.usage : null,
893
+ model: message.model ?? null
894
+ };
895
+ }
896
+ const projected = { sourceType: type };
897
+ for (const key of ["level", "status", "attempt", "reason", "dueAt", "previousRunId", "runId"]) {
898
+ const value = event[key];
899
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") projected[key] = value;
900
+ }
901
+ return projected;
902
+ }
903
+ function messageText(message) {
904
+ if (typeof message.content === "string") return message.content;
905
+ if (!Array.isArray(message.content)) return "";
906
+ return message.content.map((part) => isRecord(part) && part.type === "text" && typeof part.text === "string" ? part.text : "").join("");
907
+ }
908
+ function structuredGateResult(text) {
909
+ let parsed;
910
+ try {
911
+ parsed = JSON.parse(text);
912
+ } catch {
913
+ return null;
914
+ }
915
+ if (!isRecord(parsed) || !Array.isArray(parsed.checks) || parsed.checks.length === 0) return null;
916
+ const checks = [];
917
+ for (const raw of parsed.checks) {
918
+ if (!isRecord(raw) || typeof raw.name !== "string" || typeof raw.passed !== "boolean" || typeof raw.evidence !== "string") {
919
+ return null;
920
+ }
921
+ checks.push({ item: raw.name, ok: raw.passed, note: raw.evidence });
922
+ }
923
+ if (parsed.verdict !== void 0 && parsed.verdict !== "pass" && parsed.verdict !== "fail") return null;
924
+ if (parsed.winner !== void 0 && (!Number.isSafeInteger(parsed.winner) || parsed.winner < 1))
925
+ return null;
926
+ if (parsed.verdict === void 0 && parsed.winner === void 0) return null;
927
+ return { passed: parsed.verdict === "pass" || parsed.winner !== void 0, checks };
928
+ }
929
+ function normalizeEventType(type) {
930
+ if (type === "message_end") return "log";
931
+ if (type === "attempt_start") return "handoff";
932
+ return type.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64) || "progress";
933
+ }
934
+ function eventName(event, fallback) {
935
+ return stringValue(event.name) ?? stringValue(event.message) ?? fallback;
936
+ }
937
+ function eventTokens(event) {
938
+ if (!isRecord(event.message) || !isRecord(event.message.usage)) return null;
939
+ return finiteNonNegative(event.message.usage.totalTokens) ?? finiteNonNegative(event.message.usage.total_tokens);
940
+ }
941
+ function readableToolName(tool, args) {
942
+ if (isRecord(args)) {
943
+ const target = stringValue(args.command) ?? stringValue(args.path) ?? stringValue(args.file_path);
944
+ if (target !== null) return traceText(`${tool}: ${target.replace(/\s+/g, " ").trim()}`, 160);
945
+ }
946
+ return traceText(tool, 160);
947
+ }
948
+ function boundedSnippet(value) {
949
+ if (value === null || value === void 0) return null;
950
+ const encoded = typeof value === "string" ? value : JSON.stringify(value, (_key, current) => typeof current === "bigint" ? current.toString() : current);
951
+ const text = encoded ?? String(value);
952
+ return Buffer.byteLength(text) <= 4096 ? text : `${Buffer.from(text).subarray(0, 4093).toString("utf8")}\u2026`;
953
+ }
954
+ function boundedJson(value) {
955
+ const serialized = JSON.stringify(
956
+ value,
957
+ (_key, current) => typeof current === "bigint" ? current.toString() : current
958
+ );
959
+ const json = serialized === void 0 ? void 0 : redactSecretsText(serialized, createRedactionTally());
960
+ if (json === void 0) return "null";
961
+ if (Buffer.byteLength(json) <= TRACE_PAYLOAD_LIMIT_BYTES) return json;
962
+ return JSON.stringify({
963
+ truncated: true,
964
+ snippet: Buffer.from(json).subarray(0, TRACE_PAYLOAD_LIMIT_BYTES - 128).toString("utf8")
965
+ });
966
+ }
967
+ function traceText(value, maxChars) {
968
+ return redactSecretsText(value, createRedactionTally()).replace(/[\r\n\t]+/g, " ").slice(0, maxChars);
969
+ }
970
+ function sha256(value) {
971
+ return createHash("sha256").update(value, "utf8").digest("hex");
972
+ }
973
+ function assertSelectOnly(sql) {
974
+ const trimmed = sql.trim();
975
+ if (!/^(SELECT|WITH)\b/i.test(trimmed)) throw new Error("trace sql accepts SELECT or read-only WITH queries only");
976
+ if (trimmed.includes(";")) throw new Error("trace sql accepts exactly one statement");
977
+ if (/\b(INSERT|UPDATE|DELETE|REPLACE|CREATE|ALTER|DROP|ATTACH|DETACH|VACUUM|PRAGMA)\b/i.test(trimmed)) {
978
+ throw new Error("trace sql query is not read-only");
979
+ }
980
+ }
981
+ function clampInt(value, min, max) {
982
+ if (!Number.isFinite(value)) return min;
983
+ return Math.min(max, Math.max(min, Math.trunc(value)));
984
+ }
985
+ function isRecord(value) {
986
+ return typeof value === "object" && value !== null && !Array.isArray(value);
987
+ }
988
+ function stringValue(value) {
989
+ return typeof value === "string" && value.length > 0 ? value : null;
990
+ }
991
+ function finiteNonNegative(value) {
992
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
993
+ }
994
+
995
+ export {
996
+ createRedactionTally,
997
+ redactSecretsText,
998
+ redactSecretsDeep,
999
+ TRACE_EVENT_POLL_LIMIT,
1000
+ traceDatabasePath,
1001
+ TraceReader,
1002
+ createDispatchTraceMirror
1003
+ };
1004
+ //# sourceMappingURL=chunk-E3NYWENM.js.map