@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,565 @@
1
+ import {
2
+ assertSafeId
3
+ } from "./chunk-5N2FG33Q.js";
4
+ import {
5
+ fsyncDirectory,
6
+ safeResourceWrite
7
+ } from "./chunk-VPAWTYLY.js";
8
+ import {
9
+ clioStateDir,
10
+ stateRootRemoved
11
+ } from "./chunk-X3NE4WVW.js";
12
+ import {
13
+ readClioVersion,
14
+ readPiMonoVersion
15
+ } from "./chunk-DXQNI4PC.js";
16
+
17
+ // src/engine/session.ts
18
+ import { createHash, randomBytes } from "node:crypto";
19
+ import {
20
+ closeSync,
21
+ existsSync,
22
+ constants as fsConstants,
23
+ fstatSync,
24
+ fsyncSync,
25
+ mkdirSync,
26
+ openSync,
27
+ readdirSync,
28
+ readFileSync,
29
+ readSync,
30
+ renameSync,
31
+ statSync,
32
+ writeSync
33
+ } from "node:fs";
34
+ import { dirname, join, resolve } from "node:path";
35
+ import { StringDecoder } from "node:string_decoder";
36
+ var CURRENT_SESSION_FORMAT_VERSION = 3;
37
+ function cwdHash(cwd) {
38
+ const normalized = resolve(cwd);
39
+ return createHash("sha256").update(normalized).digest("hex").slice(0, 16);
40
+ }
41
+ function sessionPaths(meta) {
42
+ const dir = join(clioStateDir(), "sessions", meta.cwdHash, meta.id);
43
+ mkdirSync(dir, { recursive: true });
44
+ return {
45
+ current: join(dir, "current.jsonl"),
46
+ tree: join(dir, "tree.json"),
47
+ meta: join(dir, "meta.json")
48
+ };
49
+ }
50
+ function atomicWrite(targetPath, contents) {
51
+ safeResourceWrite(targetPath, contents);
52
+ }
53
+ var reportedSessionJsonlWarnings = /* @__PURE__ */ new Set();
54
+ var REPORTED_SESSION_JSONL_WARNING_LIMIT = 1e3;
55
+ function defaultSessionJsonlWarning(warning) {
56
+ const key = `${warning.path}:${warning.line}:${warning.message}`;
57
+ if (reportedSessionJsonlWarnings.has(key)) return;
58
+ if (reportedSessionJsonlWarnings.size >= REPORTED_SESSION_JSONL_WARNING_LIMIT) reportedSessionJsonlWarnings.clear();
59
+ reportedSessionJsonlWarnings.add(key);
60
+ process.stderr.write(`[clio:session] ${warning.path}:${warning.line}: ${warning.message}
61
+ `);
62
+ }
63
+ function serializeJsonl(entries) {
64
+ if (entries.length === 0) return "";
65
+ const lines = entries.map((entry, index) => {
66
+ const serialized = JSON.stringify(entry);
67
+ if (serialized === void 0) {
68
+ throw new Error(`session JSONL entry ${index + 1} is not serializable`);
69
+ }
70
+ return serialized;
71
+ });
72
+ return `${lines.join("\n")}
73
+ `;
74
+ }
75
+ function writeJsonlFileAtomic(targetPath, entries, options = {}) {
76
+ const dir = dirname(targetPath);
77
+ mkdirSync(dir, { recursive: true });
78
+ const body = serializeJsonl(entries);
79
+ const tmp = `${targetPath}.tmp`;
80
+ const fd = openSync(tmp, "w");
81
+ try {
82
+ writeSync(fd, body);
83
+ fsyncSync(fd);
84
+ } finally {
85
+ closeSync(fd);
86
+ }
87
+ options.beforeRename?.(tmp, targetPath);
88
+ renameSync(tmp, targetPath);
89
+ fsyncDirectory(dir);
90
+ }
91
+ function recoverJsonlTargetIfMissing(targetPath) {
92
+ if (existsSync(targetPath)) return targetPath;
93
+ const tmp = `${targetPath}.tmp`;
94
+ try {
95
+ if (!statSync(tmp).isFile()) return null;
96
+ renameSync(tmp, targetPath);
97
+ fsyncDirectory(dirname(targetPath));
98
+ return targetPath;
99
+ } catch {
100
+ return existsSync(targetPath) ? targetPath : existsSync(tmp) ? tmp : null;
101
+ }
102
+ }
103
+ var SESSION_JSONL_READ_CHUNK_BYTES = 64 * 1024;
104
+ function parseSessionJsonlLine(line, lineNumber, readPath, entries, warn) {
105
+ if (line.trim().length === 0) return;
106
+ try {
107
+ entries.push(JSON.parse(line));
108
+ } catch (error) {
109
+ const message = error instanceof Error ? error.message : String(error);
110
+ warn({ path: readPath, line: lineNumber, message: `invalid JSON skipped: ${message}` });
111
+ }
112
+ }
113
+ function readSessionFileEntries(path, options = {}) {
114
+ const readPath = recoverJsonlTargetIfMissing(path);
115
+ if (readPath === null) return [];
116
+ const entries = [];
117
+ const warn = options.onWarning ?? defaultSessionJsonlWarning;
118
+ const fd = openSync(readPath, "r");
119
+ const buffer = Buffer.allocUnsafe(SESSION_JSONL_READ_CHUNK_BYTES);
120
+ const decoder = new StringDecoder("utf8");
121
+ let pending = "";
122
+ let lineNumber = 0;
123
+ try {
124
+ for (; ; ) {
125
+ const bytesRead = readSync(fd, buffer, 0, buffer.length, null);
126
+ if (bytesRead === 0) break;
127
+ pending += decoder.write(buffer.subarray(0, bytesRead));
128
+ for (; ; ) {
129
+ const newlineIndex = pending.indexOf("\n");
130
+ if (newlineIndex < 0) break;
131
+ const line = pending.slice(0, newlineIndex);
132
+ pending = pending.slice(newlineIndex + 1);
133
+ lineNumber += 1;
134
+ parseSessionJsonlLine(line, lineNumber, readPath, entries, warn);
135
+ }
136
+ }
137
+ pending += decoder.end();
138
+ if (pending.length > 0) {
139
+ lineNumber += 1;
140
+ parseSessionJsonlLine(pending, lineNumber, readPath, entries, warn);
141
+ }
142
+ } finally {
143
+ closeSync(fd);
144
+ }
145
+ return entries;
146
+ }
147
+ function readExactAt(fd, buffer, position, length) {
148
+ let read = 0;
149
+ while (read < length) {
150
+ const got = readSync(fd, buffer, read, length - read, position + read);
151
+ if (got === 0) break;
152
+ read += got;
153
+ }
154
+ }
155
+ function readSessionFileTailEntries(path, maxEntries, options = {}) {
156
+ const readPath = recoverJsonlTargetIfMissing(path);
157
+ if (readPath === null) return { entries: [], linesParsed: 0, reachedStart: true };
158
+ const warn = options.onWarning ?? defaultSessionJsonlWarning;
159
+ const bound = Number.isFinite(maxEntries) && maxEntries > 0 ? Math.floor(maxEntries) : 1;
160
+ const chunkBytes = options.chunkBytes !== void 0 && options.chunkBytes > 0 ? Math.floor(options.chunkBytes) : SESSION_JSONL_READ_CHUNK_BYTES;
161
+ const fd = openSync(readPath, "r");
162
+ try {
163
+ const size = fstatSync(fd).size;
164
+ if (size === 0) return { entries: [], linesParsed: 0, reachedStart: true };
165
+ let windowBytes = Math.min(size, chunkBytes);
166
+ for (; ; ) {
167
+ const offset = Math.max(0, size - windowBytes);
168
+ const length = size - offset;
169
+ const buffer = Buffer.allocUnsafe(length);
170
+ readExactAt(fd, buffer, offset, length);
171
+ const decoder = new StringDecoder("utf8");
172
+ const text = decoder.write(buffer) + decoder.end();
173
+ const reachedStart = offset === 0;
174
+ const lines = text.split("\n");
175
+ const candidate = reachedStart ? lines : lines.slice(1);
176
+ const nonEmpty = candidate.filter((line) => line.trim().length > 0);
177
+ if (nonEmpty.length >= bound || reachedStart) {
178
+ const tail = nonEmpty.slice(Math.max(0, nonEmpty.length - bound));
179
+ const entries = [];
180
+ let lineNumber = 0;
181
+ for (const line of tail) {
182
+ lineNumber += 1;
183
+ parseSessionJsonlLine(line, lineNumber, readPath, entries, warn);
184
+ }
185
+ return { entries, linesParsed: tail.length, reachedStart };
186
+ }
187
+ if (windowBytes >= size) return { entries: [], linesParsed: 0, reachedStart: true };
188
+ windowBytes = Math.min(size, windowBytes * 2);
189
+ }
190
+ } finally {
191
+ closeSync(fd);
192
+ }
193
+ }
194
+ function readSessionTailTurns(id, maxTurns) {
195
+ const currentPath = sessionCurrentPath(id);
196
+ const result = readSessionFileTailEntries(currentPath, maxTurns + 1);
197
+ const turns = result.entries.filter((entry) => !isSessionJsonlHeader(entry));
198
+ return {
199
+ entries: turns.slice(Math.max(0, turns.length - maxTurns)),
200
+ linesParsed: result.linesParsed,
201
+ reachedStart: result.reachedStart
202
+ };
203
+ }
204
+ function isPositiveInteger(value) {
205
+ return typeof value === "number" && Number.isInteger(value) && value > 0;
206
+ }
207
+ function isOptionalString(value) {
208
+ return value === void 0 || typeof value === "string";
209
+ }
210
+ function isSessionJsonlHeader(value) {
211
+ if (!value || typeof value !== "object") return false;
212
+ const v = value;
213
+ return v.type === "session" && isPositiveInteger(v.version) && typeof v.id === "string" && typeof v.timestamp === "string" && typeof v.cwd === "string" && isOptionalString(v.parentSession) && isOptionalString(v.parentTurnId);
214
+ }
215
+ function sessionHeaderFromMeta(meta, options = {}) {
216
+ const header = {
217
+ type: "session",
218
+ version: CURRENT_SESSION_FORMAT_VERSION,
219
+ id: meta.id,
220
+ timestamp: meta.createdAt,
221
+ cwd: meta.cwd
222
+ };
223
+ if (options.parentSession !== void 0) header.parentSession = options.parentSession;
224
+ if (options.parentTurnId !== void 0) header.parentTurnId = options.parentTurnId;
225
+ return header;
226
+ }
227
+ function ensureSessionHeader(meta, entries, options = {}) {
228
+ const first = entries[0];
229
+ if (isSessionJsonlHeader(first)) return [...entries];
230
+ return [sessionHeaderFromMeta(meta, options), ...entries];
231
+ }
232
+ function recordFromTurn(turn) {
233
+ const entry = {
234
+ kind: "message",
235
+ turnId: turn.id,
236
+ parentTurnId: turn.parentId,
237
+ timestamp: turn.at,
238
+ role: turn.kind,
239
+ payload: turn.payload
240
+ };
241
+ return entry;
242
+ }
243
+ function newTurnId() {
244
+ const n = BigInt(`0x${randomBytes(8).toString("hex")}`);
245
+ const raw = n.toString(36);
246
+ if (raw.length >= 12) return raw.slice(0, 12);
247
+ return raw.padStart(12, "0");
248
+ }
249
+ function buildMeta(input) {
250
+ const resolvedCwd = resolve(input.cwd);
251
+ return {
252
+ id: newTurnId(),
253
+ cwd: resolvedCwd,
254
+ cwdHash: cwdHash(resolvedCwd),
255
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
256
+ endedAt: null,
257
+ model: input.model ?? null,
258
+ target: input.target ?? null,
259
+ clioVersion: readClioVersion(),
260
+ piMonoVersion: readPiMonoVersion(),
261
+ platform: process.platform,
262
+ nodeVersion: process.version,
263
+ sessionFormatVersion: CURRENT_SESSION_FORMAT_VERSION
264
+ };
265
+ }
266
+ function readMetaFile(path) {
267
+ const raw = readFileSync(path, "utf8");
268
+ return JSON.parse(raw);
269
+ }
270
+ var TURN_KINDS = [
271
+ "user",
272
+ "assistant",
273
+ "tool_call",
274
+ "tool_result",
275
+ "system",
276
+ "checkpoint"
277
+ ];
278
+ function isTurnKind(value) {
279
+ return typeof value === "string" && TURN_KINDS.includes(value);
280
+ }
281
+ function nullableString(value) {
282
+ return value === null || typeof value === "string";
283
+ }
284
+ function isSessionTreeNode(value) {
285
+ if (!value || typeof value !== "object") return false;
286
+ const node = value;
287
+ return typeof node.id === "string" && nullableString(node.parentId) && typeof node.at === "string" && isTurnKind(node.kind);
288
+ }
289
+ function readTreeFile(path) {
290
+ if (!existsSync(path)) return [];
291
+ try {
292
+ const raw = readFileSync(path, "utf8");
293
+ if (raw.trim().length === 0) return [];
294
+ const parsed = JSON.parse(raw);
295
+ if (!Array.isArray(parsed)) return [];
296
+ return parsed.filter(isSessionTreeNode);
297
+ } catch {
298
+ return [];
299
+ }
300
+ }
301
+ function treeNodeFromFileEntry(entry) {
302
+ if (!entry || typeof entry !== "object" || isSessionJsonlHeader(entry)) return null;
303
+ const value = entry;
304
+ if (value.kind === "message" && typeof value.turnId === "string" && nullableString(value.parentTurnId) && typeof value.timestamp === "string" && isTurnKind(value.role) && Object.hasOwn(value, "payload")) {
305
+ return { id: value.turnId, parentId: value.parentTurnId, at: value.timestamp, kind: value.role };
306
+ }
307
+ return null;
308
+ }
309
+ function treeFromFileEntries(fileEntries) {
310
+ const nodes = [];
311
+ for (const entry of fileEntries) {
312
+ const node = treeNodeFromFileEntry(entry);
313
+ if (node) nodes.push(node);
314
+ }
315
+ return nodes;
316
+ }
317
+ function sameTreeNode(a, b) {
318
+ return !!a && a.id === b.id && a.parentId === b.parentId && a.at === b.at && a.kind === b.kind;
319
+ }
320
+ function sameTree(a, b) {
321
+ if (a.length !== b.length) return false;
322
+ for (let i = 0; i < a.length; i += 1) {
323
+ const left = a[i];
324
+ const right = b[i];
325
+ if (!left || !right || !sameTreeNode(left, right)) return false;
326
+ }
327
+ return true;
328
+ }
329
+ function recoverTreeFromJsonl(diskTree, fileEntries) {
330
+ const recovered = treeFromFileEntries(fileEntries);
331
+ if (recovered.length === 0) return diskTree;
332
+ return sameTree(diskTree, recovered) ? diskTree : recovered;
333
+ }
334
+ function sessionCurrentPath(id) {
335
+ return join(findSessionDir(id), "current.jsonl");
336
+ }
337
+ function findSessionDir(id) {
338
+ assertSafeId(id, "session");
339
+ const sessionsRoot = join(clioStateDir(), "sessions");
340
+ if (!existsSync(sessionsRoot)) {
341
+ throw new Error(`session not found: ${id}`);
342
+ }
343
+ for (const entry of readdirSync(sessionsRoot, { withFileTypes: true })) {
344
+ if (!entry.isDirectory()) continue;
345
+ const candidate = join(sessionsRoot, entry.name, id);
346
+ if (existsSync(candidate) && statSync(candidate).isDirectory()) {
347
+ return candidate;
348
+ }
349
+ }
350
+ throw new Error(`session not found: ${id}`);
351
+ }
352
+ function readSessionMeta(id) {
353
+ return readMetaFile(join(findSessionDir(id), "meta.json"));
354
+ }
355
+ var APPEND_FSYNC_DEBOUNCE_MS = 500;
356
+ function endsWithNewline(path) {
357
+ let size;
358
+ try {
359
+ size = statSync(path).size;
360
+ } catch {
361
+ return true;
362
+ }
363
+ if (size === 0) return true;
364
+ const fd = openSync(path, "r");
365
+ try {
366
+ const buf = Buffer.alloc(1);
367
+ readSync(fd, buf, 0, 1, size - 1);
368
+ return buf[0] === 10;
369
+ } finally {
370
+ closeSync(fd);
371
+ }
372
+ }
373
+ function appendSessionFileEntry(targetPath, entry) {
374
+ const appendPath = recoverJsonlTargetIfMissing(targetPath);
375
+ if (appendPath === null) throw new Error(`session JSONL file not found: ${targetPath}`);
376
+ const serialized = JSON.stringify(entry);
377
+ if (serialized === void 0) throw new Error("session JSONL entry is not serializable");
378
+ const line = Buffer.from(`${endsWithNewline(appendPath) ? "" : "\n"}${serialized}
379
+ `, "utf8");
380
+ const fd = openSync(appendPath, fsConstants.O_WRONLY | fsConstants.O_APPEND);
381
+ try {
382
+ const written = writeSync(fd, line);
383
+ if (written !== line.length) {
384
+ throw new Error(`short session JSONL append: wrote ${written} of ${line.length} bytes`);
385
+ }
386
+ fsyncSync(fd);
387
+ } finally {
388
+ closeSync(fd);
389
+ }
390
+ }
391
+ function createWriter(meta, initialTree, initialFileEntries, headerOptions = {}) {
392
+ const paths = sessionPaths(meta);
393
+ const tree = [...initialTree];
394
+ const fileEntries = ensureSessionHeader(meta, initialFileEntries, headerOptions);
395
+ let closed = false;
396
+ let appendFd = null;
397
+ let fsyncTimer = null;
398
+ if (!isSessionJsonlHeader(initialFileEntries[0])) {
399
+ writeJsonlFileAtomic(paths.current, fileEntries);
400
+ }
401
+ function openAppendFd() {
402
+ if (appendFd !== null) return appendFd;
403
+ const tornTail = !endsWithNewline(paths.current);
404
+ appendFd = openSync(paths.current, "a");
405
+ if (tornTail) writeSync(appendFd, "\n");
406
+ return appendFd;
407
+ }
408
+ function scheduleFsync() {
409
+ if (fsyncTimer !== null) return;
410
+ fsyncTimer = setTimeout(() => {
411
+ fsyncTimer = null;
412
+ if (appendFd === null) return;
413
+ try {
414
+ fsyncSync(appendFd);
415
+ } catch {
416
+ }
417
+ }, APPEND_FSYNC_DEBOUNCE_MS);
418
+ fsyncTimer.unref?.();
419
+ }
420
+ function closeAppendFd(opts) {
421
+ if (fsyncTimer !== null) {
422
+ clearTimeout(fsyncTimer);
423
+ fsyncTimer = null;
424
+ }
425
+ if (appendFd === null) return;
426
+ try {
427
+ if (opts.flush) fsyncSync(appendFd);
428
+ } finally {
429
+ closeSync(appendFd);
430
+ appendFd = null;
431
+ }
432
+ }
433
+ function appendLine(entry) {
434
+ const serialized = JSON.stringify(entry);
435
+ if (serialized === void 0) {
436
+ throw new Error("session JSONL entry is not serializable");
437
+ }
438
+ writeSync(openAppendFd(), `${serialized}
439
+ `);
440
+ scheduleFsync();
441
+ }
442
+ return {
443
+ append(turn) {
444
+ if (closed) throw new Error("session writer closed");
445
+ const record = recordFromTurn(turn);
446
+ appendLine(record);
447
+ fileEntries.push(record);
448
+ tree.push({
449
+ id: turn.id,
450
+ parentId: turn.parentId,
451
+ at: turn.at,
452
+ kind: turn.kind
453
+ });
454
+ },
455
+ appendEntry(entry, opts) {
456
+ if (closed) throw new Error("session writer closed");
457
+ appendLine(entry);
458
+ fileEntries.push(entry);
459
+ if (opts?.treeNode) tree.push(opts.treeNode);
460
+ },
461
+ replaceEntries(entries) {
462
+ if (closed) throw new Error("session writer closed");
463
+ closeAppendFd({ flush: false });
464
+ const existingHeader = fileEntries.find(isSessionJsonlHeader);
465
+ const body = entries.filter((entry) => !isSessionJsonlHeader(entry));
466
+ const nextEntries = existingHeader ? [existingHeader, ...body] : ensureSessionHeader(meta, body, headerOptions);
467
+ writeJsonlFileAtomic(paths.current, nextEntries);
468
+ fileEntries.length = 0;
469
+ fileEntries.push(...nextEntries);
470
+ const recoveredTree = treeFromFileEntries(nextEntries);
471
+ if (recoveredTree.length > 0) {
472
+ tree.length = 0;
473
+ tree.push(...recoveredTree);
474
+ }
475
+ },
476
+ async persistTree() {
477
+ if (appendFd !== null) fsyncSync(appendFd);
478
+ if (stateRootRemoved()) return;
479
+ atomicWrite(paths.tree, JSON.stringify(tree, null, 2));
480
+ },
481
+ flushAppends() {
482
+ if (appendFd !== null) fsyncSync(appendFd);
483
+ },
484
+ async close() {
485
+ if (closed) return;
486
+ closeAppendFd({ flush: true });
487
+ closed = true;
488
+ if (stateRootRemoved()) return;
489
+ atomicWrite(paths.tree, JSON.stringify(tree, null, 2));
490
+ const ended = { ...meta, endedAt: (/* @__PURE__ */ new Date()).toISOString() };
491
+ atomicWrite(paths.meta, JSON.stringify(ended, null, 2));
492
+ meta.endedAt = ended.endedAt;
493
+ }
494
+ };
495
+ }
496
+ function createSession(input) {
497
+ const meta = buildMeta(input);
498
+ const paths = sessionPaths(meta);
499
+ atomicWrite(paths.meta, JSON.stringify(meta, null, 2));
500
+ const headerOptions = {};
501
+ if (input.parentSession !== void 0) headerOptions.parentSession = input.parentSession;
502
+ if (input.parentTurnId !== void 0) headerOptions.parentTurnId = input.parentTurnId;
503
+ const initialEntries = ensureSessionHeader(meta, input.initialEntries ?? [], headerOptions);
504
+ const initialTree = [...input.initialTree ?? []];
505
+ writeJsonlFileAtomic(paths.current, initialEntries);
506
+ atomicWrite(paths.tree, JSON.stringify(initialTree, null, 2));
507
+ const writer = createWriter(meta, initialTree, initialEntries, headerOptions);
508
+ return { meta, writer };
509
+ }
510
+ function openSession(id) {
511
+ const dir = findSessionDir(id);
512
+ const metaPath = join(dir, "meta.json");
513
+ const meta = readMetaFile(metaPath);
514
+ const currentPath = join(dir, "current.jsonl");
515
+ const fileEntries = readSessionFileEntries(currentPath);
516
+ const turns = fileEntries.filter((entry) => !isSessionJsonlHeader(entry));
517
+ const header = fileEntries.find(isSessionJsonlHeader) ?? null;
518
+ const tree = recoverTreeFromJsonl(readTreeFile(join(dir, "tree.json")), fileEntries);
519
+ return {
520
+ meta() {
521
+ return meta;
522
+ },
523
+ turns() {
524
+ return turns;
525
+ },
526
+ fileEntries() {
527
+ return fileEntries;
528
+ },
529
+ header() {
530
+ return header;
531
+ },
532
+ tree() {
533
+ return tree;
534
+ }
535
+ };
536
+ }
537
+ function resumeSession(id) {
538
+ const dir = findSessionDir(id);
539
+ const metaPath = join(dir, "meta.json");
540
+ const meta = readMetaFile(metaPath);
541
+ if (meta.endedAt !== null) {
542
+ meta.endedAt = null;
543
+ atomicWrite(metaPath, JSON.stringify(meta, null, 2));
544
+ }
545
+ const existingFileEntries = readSessionFileEntries(join(dir, "current.jsonl"));
546
+ const existingTree = recoverTreeFromJsonl(readTreeFile(join(dir, "tree.json")), existingFileEntries);
547
+ const writer = createWriter(meta, existingTree, existingFileEntries);
548
+ return { meta, writer, tree: existingTree };
549
+ }
550
+
551
+ export {
552
+ CURRENT_SESSION_FORMAT_VERSION,
553
+ cwdHash,
554
+ sessionPaths,
555
+ atomicWrite,
556
+ readSessionFileEntries,
557
+ readSessionTailTurns,
558
+ sessionCurrentPath,
559
+ readSessionMeta,
560
+ appendSessionFileEntry,
561
+ createSession,
562
+ openSession,
563
+ resumeSession
564
+ };
565
+ //# sourceMappingURL=chunk-UGYAX5YI.js.map