@di-code/coding-agent 0.1.7 → 0.1.9

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 (333) hide show
  1. package/README.md +54 -567
  2. package/compositions/base.yml +54 -0
  3. package/compositions/interactive.yml +14 -0
  4. package/compositions/json.yml +6 -0
  5. package/compositions/print.yml +5 -0
  6. package/compositions/rpc.yml +12 -0
  7. package/compositions/webui.yml +9 -0
  8. package/dist/cli.d.ts +22 -1
  9. package/dist/cli.d.ts.map +1 -1
  10. package/dist/cli.js +97 -3
  11. package/dist/cli.js.map +1 -1
  12. package/dist/composition-loader-entry.d.ts +11 -0
  13. package/dist/composition-loader-entry.d.ts.map +1 -0
  14. package/dist/composition-loader-entry.js +12 -0
  15. package/dist/composition-loader-entry.js.map +1 -0
  16. package/dist/compositions.d.ts +32 -0
  17. package/dist/compositions.d.ts.map +1 -0
  18. package/dist/compositions.js +173 -0
  19. package/dist/compositions.js.map +1 -0
  20. package/dist/core/session/session-manager.d.ts +9 -2
  21. package/dist/core/session/session-manager.d.ts.map +1 -1
  22. package/dist/core/session/session-manager.js +28 -0
  23. package/dist/core/session/session-manager.js.map +1 -1
  24. package/dist/core/session/session-storage.d.ts.map +1 -1
  25. package/dist/core/session/session-storage.js +20 -3
  26. package/dist/core/session/session-storage.js.map +1 -1
  27. package/dist/core/session/types.d.ts +11 -2
  28. package/dist/core/session/types.d.ts.map +1 -1
  29. package/dist/core/session/types.js.map +1 -1
  30. package/dist/core/session-tools.d.ts +5 -0
  31. package/dist/core/session-tools.d.ts.map +1 -0
  32. package/dist/core/session-tools.js +17 -0
  33. package/dist/core/session-tools.js.map +1 -0
  34. package/dist/core/session.d.ts +19 -7
  35. package/dist/core/session.d.ts.map +1 -1
  36. package/dist/core/session.js +71 -39
  37. package/dist/core/session.js.map +1 -1
  38. package/dist/core/tools/bash.d.ts +1 -38
  39. package/dist/core/tools/bash.d.ts.map +1 -1
  40. package/dist/core/tools/bash.js +1 -207
  41. package/dist/core/tools/bash.js.map +1 -1
  42. package/dist/core/tools/edit-diff.d.ts +1 -24
  43. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  44. package/dist/core/tools/edit-diff.js +1 -135
  45. package/dist/core/tools/edit-diff.js.map +1 -1
  46. package/dist/core/tools/edit.d.ts +1 -26
  47. package/dist/core/tools/edit.d.ts.map +1 -1
  48. package/dist/core/tools/edit.js +1 -140
  49. package/dist/core/tools/edit.js.map +1 -1
  50. package/dist/core/tools/file-mutation-queue.d.ts +1 -1
  51. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  52. package/dist/core/tools/file-mutation-queue.js +1 -23
  53. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  54. package/dist/core/tools/file-search.d.ts +1 -13
  55. package/dist/core/tools/file-search.d.ts.map +1 -1
  56. package/dist/core/tools/file-search.js +1 -98
  57. package/dist/core/tools/file-search.js.map +1 -1
  58. package/dist/core/tools/glob.d.ts +1 -10
  59. package/dist/core/tools/glob.d.ts.map +1 -1
  60. package/dist/core/tools/glob.js +1 -43
  61. package/dist/core/tools/glob.js.map +1 -1
  62. package/dist/core/tools/grep.d.ts +1 -12
  63. package/dist/core/tools/grep.d.ts.map +1 -1
  64. package/dist/core/tools/grep.js +1 -66
  65. package/dist/core/tools/grep.js.map +1 -1
  66. package/dist/core/tools/load-skill.d.ts +1 -9
  67. package/dist/core/tools/load-skill.d.ts.map +1 -1
  68. package/dist/core/tools/load-skill.js +1 -21
  69. package/dist/core/tools/load-skill.js.map +1 -1
  70. package/dist/core/tools/path-boundary.d.ts +1 -4
  71. package/dist/core/tools/path-boundary.d.ts.map +1 -1
  72. package/dist/core/tools/path-boundary.js +1 -65
  73. package/dist/core/tools/path-boundary.js.map +1 -1
  74. package/dist/core/tools/read.d.ts +1 -16
  75. package/dist/core/tools/read.d.ts.map +1 -1
  76. package/dist/core/tools/read.js +1 -131
  77. package/dist/core/tools/read.js.map +1 -1
  78. package/dist/core/tools/write.d.ts +1 -16
  79. package/dist/core/tools/write.d.ts.map +1 -1
  80. package/dist/core/tools/write.js +1 -44
  81. package/dist/core/tools/write.js.map +1 -1
  82. package/dist/entry.js +30 -28
  83. package/dist/entry.js.map +1 -1
  84. package/dist/index.d.ts +6 -3
  85. package/dist/index.d.ts.map +1 -1
  86. package/dist/index.js +6 -3
  87. package/dist/index.js.map +1 -1
  88. package/dist/interactive/builtin.d.ts +17 -0
  89. package/dist/interactive/builtin.d.ts.map +1 -0
  90. package/dist/interactive/builtin.js +47 -0
  91. package/dist/interactive/builtin.js.map +1 -0
  92. package/dist/interactive/controller.d.ts +85 -0
  93. package/dist/interactive/controller.d.ts.map +1 -0
  94. package/dist/interactive/controller.js +211 -0
  95. package/dist/interactive/controller.js.map +1 -0
  96. package/dist/interactive/index.d.ts +3 -0
  97. package/dist/interactive/index.d.ts.map +1 -0
  98. package/dist/interactive/index.js +3 -0
  99. package/dist/interactive/index.js.map +1 -0
  100. package/dist/interactive-host-entry.d.ts +7 -0
  101. package/dist/interactive-host-entry.d.ts.map +1 -0
  102. package/dist/interactive-host-entry.js +123 -0
  103. package/dist/interactive-host-entry.js.map +1 -0
  104. package/dist/interactive-profile.d.ts +18 -0
  105. package/dist/interactive-profile.d.ts.map +1 -0
  106. package/dist/interactive-profile.js +290 -0
  107. package/dist/interactive-profile.js.map +1 -0
  108. package/dist/interactive-resources-entry.d.ts +7 -0
  109. package/dist/interactive-resources-entry.d.ts.map +1 -0
  110. package/dist/interactive-resources-entry.js +42 -0
  111. package/dist/interactive-resources-entry.js.map +1 -0
  112. package/dist/legacy-main.d.ts +39 -0
  113. package/dist/legacy-main.d.ts.map +1 -0
  114. package/dist/legacy-main.js +611 -0
  115. package/dist/legacy-main.js.map +1 -0
  116. package/dist/main.d.ts +15 -34
  117. package/dist/main.d.ts.map +1 -1
  118. package/dist/main.js +130 -518
  119. package/dist/main.js.map +1 -1
  120. package/dist/mcp/entries.d.ts +42 -0
  121. package/dist/mcp/entries.d.ts.map +1 -0
  122. package/dist/mcp/entries.js +98 -0
  123. package/dist/mcp/entries.js.map +1 -0
  124. package/dist/mcp-client-entry.d.ts +5 -0
  125. package/dist/mcp-client-entry.d.ts.map +1 -0
  126. package/dist/mcp-client-entry.js +6 -0
  127. package/dist/mcp-client-entry.js.map +1 -0
  128. package/dist/mcp-config-entry.d.ts +5 -0
  129. package/dist/mcp-config-entry.d.ts.map +1 -0
  130. package/dist/mcp-config-entry.js +6 -0
  131. package/dist/mcp-config-entry.js.map +1 -0
  132. package/dist/mcp-tools-entry.d.ts +5 -0
  133. package/dist/mcp-tools-entry.d.ts.map +1 -0
  134. package/dist/mcp-tools-entry.js +6 -0
  135. package/dist/mcp-tools-entry.js.map +1 -0
  136. package/dist/mcp-transport-entry.d.ts +5 -0
  137. package/dist/mcp-transport-entry.d.ts.map +1 -0
  138. package/dist/mcp-transport-entry.js +6 -0
  139. package/dist/mcp-transport-entry.js.map +1 -0
  140. package/dist/modes/interactive-entry.d.ts +18 -0
  141. package/dist/modes/interactive-entry.d.ts.map +1 -0
  142. package/dist/modes/interactive-entry.js +21 -0
  143. package/dist/modes/interactive-entry.js.map +1 -0
  144. package/dist/modes/interactive.d.ts +16 -6
  145. package/dist/modes/interactive.d.ts.map +1 -1
  146. package/dist/modes/interactive.js +81 -32
  147. package/dist/modes/interactive.js.map +1 -1
  148. package/dist/modes/json-entry.d.ts +13 -0
  149. package/dist/modes/json-entry.d.ts.map +1 -0
  150. package/dist/modes/json-entry.js +14 -0
  151. package/dist/modes/json-entry.js.map +1 -0
  152. package/dist/modes/json.d.ts +4 -1
  153. package/dist/modes/json.d.ts.map +1 -1
  154. package/dist/modes/json.js +3 -3
  155. package/dist/modes/json.js.map +1 -1
  156. package/dist/modes/print-entry.d.ts +10 -0
  157. package/dist/modes/print-entry.d.ts.map +1 -0
  158. package/dist/modes/print-entry.js +11 -0
  159. package/dist/modes/print-entry.js.map +1 -0
  160. package/dist/modes/tree-selector.d.ts.map +1 -1
  161. package/dist/modes/tree-selector.js +4 -0
  162. package/dist/modes/tree-selector.js.map +1 -1
  163. package/dist/plugin-dump-composition.d.ts +6 -0
  164. package/dist/plugin-dump-composition.d.ts.map +1 -0
  165. package/dist/plugin-dump-composition.js +7 -0
  166. package/dist/plugin-dump-composition.js.map +1 -0
  167. package/dist/plugin-inventory.d.ts +7 -0
  168. package/dist/plugin-inventory.d.ts.map +1 -0
  169. package/dist/plugin-inventory.js +8 -0
  170. package/dist/plugin-inventory.js.map +1 -0
  171. package/dist/plugin-manager.d.ts +6 -0
  172. package/dist/plugin-manager.d.ts.map +1 -0
  173. package/dist/plugin-manager.js +7 -0
  174. package/dist/plugin-manager.js.map +1 -0
  175. package/dist/plugin-trace.d.ts +6 -0
  176. package/dist/plugin-trace.d.ts.map +1 -0
  177. package/dist/plugin-trace.js +7 -0
  178. package/dist/plugin-trace.js.map +1 -0
  179. package/dist/plugins/dynamic-broker.d.ts +76 -0
  180. package/dist/plugins/dynamic-broker.d.ts.map +1 -0
  181. package/dist/plugins/dynamic-broker.js +852 -0
  182. package/dist/plugins/dynamic-broker.js.map +1 -0
  183. package/dist/plugins/profile.d.ts +15 -0
  184. package/dist/plugins/profile.d.ts.map +1 -0
  185. package/dist/plugins/profile.js +34 -0
  186. package/dist/plugins/profile.js.map +1 -0
  187. package/dist/plugins/runtime-host.d.ts +37 -0
  188. package/dist/plugins/runtime-host.d.ts.map +1 -0
  189. package/dist/plugins/runtime-host.js +95 -0
  190. package/dist/plugins/runtime-host.js.map +1 -0
  191. package/dist/plugins/trust.d.ts +8 -0
  192. package/dist/plugins/trust.d.ts.map +1 -0
  193. package/dist/plugins/trust.js +59 -0
  194. package/dist/plugins/trust.js.map +1 -0
  195. package/dist/project-trust-entry.d.ts +15 -0
  196. package/dist/project-trust-entry.d.ts.map +1 -0
  197. package/dist/project-trust-entry.js +15 -0
  198. package/dist/project-trust-entry.js.map +1 -0
  199. package/dist/rpc/client.d.ts +78 -6
  200. package/dist/rpc/client.d.ts.map +1 -1
  201. package/dist/rpc/client.js +172 -4
  202. package/dist/rpc/client.js.map +1 -1
  203. package/dist/rpc/dispatcher.d.ts +121 -0
  204. package/dist/rpc/dispatcher.d.ts.map +1 -0
  205. package/dist/rpc/dispatcher.js +994 -0
  206. package/dist/rpc/dispatcher.js.map +1 -0
  207. package/dist/rpc/index.d.ts +2 -0
  208. package/dist/rpc/index.d.ts.map +1 -1
  209. package/dist/rpc/index.js +2 -0
  210. package/dist/rpc/index.js.map +1 -1
  211. package/dist/rpc/lifecycle.d.ts +6 -0
  212. package/dist/rpc/lifecycle.d.ts.map +1 -0
  213. package/dist/rpc/lifecycle.js +24 -0
  214. package/dist/rpc/lifecycle.js.map +1 -0
  215. package/dist/rpc/protocol.d.ts +112 -31
  216. package/dist/rpc/protocol.d.ts.map +1 -1
  217. package/dist/rpc/protocol.js +569 -117
  218. package/dist/rpc/protocol.js.map +1 -1
  219. package/dist/rpc/server-service.d.ts +7 -0
  220. package/dist/rpc/server-service.d.ts.map +1 -0
  221. package/dist/rpc/server-service.js +3 -0
  222. package/dist/rpc/server-service.js.map +1 -0
  223. package/dist/rpc/server.d.ts +16 -19
  224. package/dist/rpc/server.d.ts.map +1 -1
  225. package/dist/rpc/server.js +59 -115
  226. package/dist/rpc/server.js.map +1 -1
  227. package/dist/rpc-client-sdk-entry.d.ts +12 -0
  228. package/dist/rpc-client-sdk-entry.d.ts.map +1 -0
  229. package/dist/rpc-client-sdk-entry.js +11 -0
  230. package/dist/rpc-client-sdk-entry.js.map +1 -0
  231. package/dist/rpc-entry.js +50 -18
  232. package/dist/rpc-entry.js.map +1 -1
  233. package/dist/rpc-server-entry.d.ts +8 -0
  234. package/dist/rpc-server-entry.d.ts.map +1 -0
  235. package/dist/rpc-server-entry.js +67 -0
  236. package/dist/rpc-server-entry.js.map +1 -0
  237. package/dist/runtime/attachment-store.d.ts +13 -0
  238. package/dist/runtime/attachment-store.d.ts.map +1 -0
  239. package/dist/runtime/attachment-store.js +93 -0
  240. package/dist/runtime/attachment-store.js.map +1 -0
  241. package/dist/runtime/bootstrap.d.ts +14 -0
  242. package/dist/runtime/bootstrap.d.ts.map +1 -0
  243. package/dist/runtime/bootstrap.js +29 -0
  244. package/dist/runtime/bootstrap.js.map +1 -0
  245. package/dist/runtime/interactive-host-service.d.ts +22 -0
  246. package/dist/runtime/interactive-host-service.d.ts.map +1 -0
  247. package/dist/runtime/interactive-host-service.js +2 -0
  248. package/dist/runtime/interactive-host-service.js.map +1 -0
  249. package/dist/runtime/interactive-resource-service.d.ts +11 -0
  250. package/dist/runtime/interactive-resource-service.d.ts.map +1 -0
  251. package/dist/runtime/interactive-resource-service.js +3 -0
  252. package/dist/runtime/interactive-resource-service.js.map +1 -0
  253. package/dist/runtime/plugin-inventory-entry.d.ts +5 -0
  254. package/dist/runtime/plugin-inventory-entry.d.ts.map +1 -0
  255. package/dist/runtime/plugin-inventory-entry.js +18 -0
  256. package/dist/runtime/plugin-inventory-entry.js.map +1 -0
  257. package/dist/runtime/plugin-inventory-service.d.ts +8 -0
  258. package/dist/runtime/plugin-inventory-service.d.ts.map +1 -0
  259. package/dist/runtime/plugin-inventory-service.js +3 -0
  260. package/dist/runtime/plugin-inventory-service.js.map +1 -0
  261. package/dist/runtime/plugin-manager-entry.d.ts +20 -0
  262. package/dist/runtime/plugin-manager-entry.d.ts.map +1 -0
  263. package/dist/runtime/plugin-manager-entry.js +96 -0
  264. package/dist/runtime/plugin-manager-entry.js.map +1 -0
  265. package/dist/runtime/plugin-observability-entry.d.ts +12 -0
  266. package/dist/runtime/plugin-observability-entry.d.ts.map +1 -0
  267. package/dist/runtime/plugin-observability-entry.js +73 -0
  268. package/dist/runtime/plugin-observability-entry.js.map +1 -0
  269. package/dist/runtime/product-host.d.ts +91 -0
  270. package/dist/runtime/product-host.d.ts.map +1 -0
  271. package/dist/runtime/product-host.js +529 -0
  272. package/dist/runtime/product-host.js.map +1 -0
  273. package/dist/runtime/session-factory.d.ts +17 -0
  274. package/dist/runtime/session-factory.d.ts.map +1 -0
  275. package/dist/runtime/session-factory.js +75 -0
  276. package/dist/runtime/session-factory.js.map +1 -0
  277. package/dist/runtime/session-host.d.ts +152 -0
  278. package/dist/runtime/session-host.d.ts.map +1 -0
  279. package/dist/runtime/session-host.js +895 -0
  280. package/dist/runtime/session-host.js.map +1 -0
  281. package/dist/runtime-core-entry.d.ts +11 -0
  282. package/dist/runtime-core-entry.d.ts.map +1 -0
  283. package/dist/runtime-core-entry.js +9 -0
  284. package/dist/runtime-core-entry.js.map +1 -0
  285. package/dist/session-factory-entry.d.ts +7 -0
  286. package/dist/session-factory-entry.d.ts.map +1 -0
  287. package/dist/session-factory-entry.js +9 -0
  288. package/dist/session-factory-entry.js.map +1 -0
  289. package/dist/session-store-jsonl-entry.d.ts +7 -0
  290. package/dist/session-store-jsonl-entry.d.ts.map +1 -0
  291. package/dist/session-store-jsonl-entry.js +33 -0
  292. package/dist/session-store-jsonl-entry.js.map +1 -0
  293. package/dist/startup.d.ts +12 -1
  294. package/dist/startup.d.ts.map +1 -1
  295. package/dist/startup.js +106 -15
  296. package/dist/startup.js.map +1 -1
  297. package/dist/subagents/index.d.ts +2 -0
  298. package/dist/subagents/index.d.ts.map +1 -0
  299. package/dist/subagents/index.js +2 -0
  300. package/dist/subagents/index.js.map +1 -0
  301. package/dist/subagents/service.d.ts +50 -0
  302. package/dist/subagents/service.d.ts.map +1 -0
  303. package/dist/subagents/service.js +521 -0
  304. package/dist/subagents/service.js.map +1 -0
  305. package/dist/ui-host.d.ts +125 -0
  306. package/dist/ui-host.d.ts.map +1 -0
  307. package/dist/ui-host.js +275 -0
  308. package/dist/ui-host.js.map +1 -0
  309. package/dist/web/assets/index-BwfuGMvv.css +1 -0
  310. package/dist/web/assets/index-DPUaJqFJ.js +41 -0
  311. package/dist/web/assets/index-DPUaJqFJ.js.map +1 -0
  312. package/dist/web/index.html +14 -0
  313. package/dist/web-command.d.ts +11 -0
  314. package/dist/web-command.d.ts.map +1 -0
  315. package/dist/web-command.js +114 -0
  316. package/dist/web-command.js.map +1 -0
  317. package/dist/web-frontend.d.ts +73 -0
  318. package/dist/web-frontend.d.ts.map +1 -0
  319. package/dist/web-frontend.js +249 -0
  320. package/dist/web-frontend.js.map +1 -0
  321. package/dist/web.d.ts +254 -0
  322. package/dist/web.d.ts.map +1 -0
  323. package/dist/web.js +740 -0
  324. package/dist/web.js.map +1 -0
  325. package/dist/webui-entry.d.ts +3 -0
  326. package/dist/webui-entry.d.ts.map +1 -0
  327. package/dist/webui-entry.js +73 -0
  328. package/dist/webui-entry.js.map +1 -0
  329. package/dist/webui.d.ts +91 -0
  330. package/dist/webui.d.ts.map +1 -0
  331. package/dist/webui.js +882 -0
  332. package/dist/webui.js.map +1 -0
  333. package/package.json +89 -8
@@ -0,0 +1,173 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { homedir } from "node:os";
10
+ import { join, resolve } from "node:path";
11
+ import { fileURLToPath, pathToFileURL } from "node:url";
12
+ import { mergeCompositionLayers, PluginInstallManager, readCompositionFile, resolvePackagePluginExport, } from "@di-code/plugin-loader";
13
+ const observabilityEntries = [
14
+ { id: "plugin-profiler", name: "@di-code/builtins/plugin-profiler", dependsOn: ["runtime"] },
15
+ { id: "plugin-invariants", name: "@di-code/builtins/plugin-invariants", dependsOn: ["runtime"] },
16
+ { id: "plugin-test-runtime", name: "@di-code/builtins/plugin-test-runtime", dependsOn: ["runtime"] },
17
+ { id: "plugin-trace", name: "@di-code/coding-agent/plugin-trace", dependsOn: ["plugin-inventory"] },
18
+ {
19
+ id: "plugin-dump-composition",
20
+ name: "@di-code/coding-agent/plugin-dump-composition",
21
+ dependsOn: ["plugin-inventory"],
22
+ },
23
+ ];
24
+ function builtinCompositionPath(name) {
25
+ return fileURLToPath(new URL(`../compositions/${name}.yml`, import.meta.url));
26
+ }
27
+ /** Resolves the package-owned base plus exactly one mode document. */
28
+ export async function resolveDefaultComposition(name, options = {}) {
29
+ const base = await readRequiredComposition(builtinCompositionPath("base"));
30
+ const mode = name === "base" ? { entries: [] } : await readRequiredComposition(builtinCompositionPath(name));
31
+ return Object.freeze(withWorkspaceRoot(mergeCompositionLayers([
32
+ { name: "base", document: base },
33
+ {
34
+ name: "mode",
35
+ document: { entries: [...(mode.entries ?? []), ...(options.observability ? observabilityEntries : [])] },
36
+ },
37
+ ]), options.allowedRoot));
38
+ }
39
+ function isJsonObject(value) {
40
+ return typeof value === "object" && value !== null && !Array.isArray(value);
41
+ }
42
+ function withWorkspaceRoot(entries, allowedRoot) {
43
+ if (allowedRoot === undefined)
44
+ return entries;
45
+ return entries.map((entry) => entry.id === "workspace"
46
+ ? { ...entry, config: { ...(isJsonObject(entry.config) ? entry.config : {}), allowedRoot } }
47
+ : entry);
48
+ }
49
+ function markProjectEntries(document) {
50
+ const mark = (entry) => ({ ...entry, projectLocal: true });
51
+ return {
52
+ ...(document.entries ? { entries: document.entries.map(mark) } : {}),
53
+ ...(document.patches
54
+ ? {
55
+ patches: document.patches.map((patch) => "entry" in patch && patch.entry !== undefined ? { ...patch, entry: mark(patch.entry) } : patch),
56
+ }
57
+ : {}),
58
+ };
59
+ }
60
+ function isMissingFile(cause) {
61
+ return typeof cause === "object" && cause !== null && "code" in cause && cause.code === "ENOENT";
62
+ }
63
+ async function readOptionalComposition(filePath) {
64
+ try {
65
+ return await readCompositionFile(filePath);
66
+ }
67
+ catch (cause) {
68
+ if (isMissingFile(cause))
69
+ return undefined;
70
+ const message = cause instanceof Error ? cause.message : String(cause);
71
+ throw new Error(`Failed to read composition ${filePath}: ${message}`, { cause });
72
+ }
73
+ }
74
+ async function readRequiredComposition(filePath) {
75
+ try {
76
+ return await readCompositionFile(filePath);
77
+ }
78
+ catch (cause) {
79
+ const message = cause instanceof Error ? cause.message : String(cause);
80
+ throw new Error(`Failed to read composition ${filePath}: ${message}`, { cause });
81
+ }
82
+ }
83
+ /**
84
+ * Resolves built-in, user, project, and explicit composition layers in their fixed precedence order.
85
+ * Project entries are marked local so the Loader retains trust checks for entries added through project configuration.
86
+ */
87
+ export async function resolveCompositionEntries(name, options = {}) {
88
+ const cwd = resolve(options.cwd ?? process.cwd());
89
+ const agentDir = resolve(options.agentDir ?? join(homedir(), ".di-code"));
90
+ const [base, mode] = await Promise.all([
91
+ readRequiredComposition(builtinCompositionPath("base")),
92
+ readRequiredComposition(builtinCompositionPath(name)),
93
+ ]);
94
+ const layers = [
95
+ { name: "base", document: base },
96
+ {
97
+ name: "mode",
98
+ document: {
99
+ entries: [...(mode.entries ?? []), ...(options.observability ? observabilityEntries : [])],
100
+ },
101
+ },
102
+ ];
103
+ const userComposition = await readOptionalComposition(join(agentDir, "composition.yml"));
104
+ if (userComposition !== undefined)
105
+ layers.push({ name: "user", document: userComposition });
106
+ if (options.includeProjectComposition !== false) {
107
+ const projectComposition = await readOptionalComposition(join(cwd, ".di-code", "composition.yml"));
108
+ if (projectComposition !== undefined)
109
+ layers.push({ name: "project", document: markProjectEntries(projectComposition) });
110
+ }
111
+ if (options.compositionPath !== undefined) {
112
+ layers.push({ name: "explicit", document: await readRequiredComposition(resolve(cwd, options.compositionPath)) });
113
+ }
114
+ return Object.freeze(withWorkspaceRoot(mergeCompositionLayers(layers), options.allowedRoot));
115
+ }
116
+ /**
117
+ * Resolves only enabled managed plugins before the Loader receives its entry list.
118
+ * Disabled manifests are not resolved or dynamically imported.
119
+ */
120
+ export async function resolveManagedCompositionEntries(agentDir = join(homedir(), ".di-code")) {
121
+ const manager = new PluginInstallManager({ managedRoot: join(resolve(agentDir), "plugins", "installed") });
122
+ const plugins = await manager.list();
123
+ return await Promise.all(plugins
124
+ .filter((plugin) => plugin.enabled)
125
+ .map(async (plugin) => ({
126
+ id: `managed.${plugin.id}`,
127
+ name: pathToFileURL(await resolvePackagePluginExport(plugin.installedPath, plugin.manifest.entry)).href,
128
+ dependsOn: ["Bootstrap"],
129
+ required: false,
130
+ })));
131
+ }
132
+ /** Imports own composition entries from source in development; package exports handle published use. */
133
+ export function importCompositionModule(name) {
134
+ switch (name) {
135
+ case "@di-code/coding-agent/plugin-manager":
136
+ return import("./plugin-manager.js");
137
+ case "@di-code/coding-agent/plugin-inventory":
138
+ return import("./plugin-inventory.js");
139
+ case "@di-code/coding-agent/plugin-trace":
140
+ return import("./plugin-trace.js");
141
+ case "@di-code/coding-agent/plugin-dump-composition":
142
+ return import("./plugin-dump-composition.js");
143
+ case "@di-code/coding-agent/mcp-config-entry":
144
+ return import("./mcp-config-entry.js");
145
+ case "@di-code/coding-agent/mcp-client-entry":
146
+ return import("./mcp-client-entry.js");
147
+ case "@di-code/coding-agent/mcp-transport-entry":
148
+ return import("./mcp-transport-entry.js");
149
+ case "@di-code/coding-agent/mcp-tools-entry":
150
+ return import("./mcp-tools-entry.js");
151
+ case "@di-code/coding-agent/session-factory-entry":
152
+ return import("./session-factory-entry.js");
153
+ case "@di-code/coding-agent/session-store-jsonl-entry":
154
+ return import("./session-store-jsonl-entry.js");
155
+ case "@di-code/coding-agent/rpc-server-entry":
156
+ return import("./rpc-server-entry.js");
157
+ case "@di-code/coding-agent/interactive-resources-entry":
158
+ return import("./interactive-resources-entry.js");
159
+ case "@di-code/coding-agent/interactive-host-entry":
160
+ return import("./interactive-host-entry.js");
161
+ case "@di-code/coding-agent/runtime-core-entry":
162
+ return import("./runtime-core-entry.js");
163
+ case "@di-code/coding-agent/composition-loader-entry":
164
+ return import("./composition-loader-entry.js");
165
+ case "@di-code/coding-agent/project-trust-entry":
166
+ return import("./project-trust-entry.js");
167
+ case "@di-code/coding-agent/rpc-client-sdk-entry":
168
+ return import("./rpc-client-sdk-entry.js");
169
+ default:
170
+ return import(__rewriteRelativeImportExtension(name));
171
+ }
172
+ }
173
+ //# sourceMappingURL=compositions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compositions.js","sourceRoot":"","sources":["../src/compositions.ts"],"names":[],"mappings":"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","sourcesContent":["import { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport {\n\ttype CompositionDocument,\n\ttype CompositionEntry,\n\ttype CompositionLayer,\n\tmergeCompositionLayers,\n\tPluginInstallManager,\n\ttype PluginModule,\n\treadCompositionFile,\n\tresolvePackagePluginExport,\n} from \"@di-code/plugin-loader\";\n\nexport type DefaultCompositionName = \"base\" | \"interactive\" | \"print\" | \"json\" | \"rpc\" | \"webui\";\n\nexport interface CompositionResolutionOptions {\n\t/** Work root used for project composition discovery and the workspace capability. */\n\treadonly cwd?: string;\n\t/** User data root containing the optional user composition document. */\n\treadonly agentDir?: string;\n\t/** Explicit JSON or YAML composition document applied last. */\n\treadonly compositionPath?: string;\n\t/** Excludes the project composition document for this invocation. */\n\treadonly includeProjectComposition?: boolean;\n\treadonly observability?: boolean;\n\treadonly allowedRoot?: string;\n}\n\nconst observabilityEntries = [\n\t{ id: \"plugin-profiler\", name: \"@di-code/builtins/plugin-profiler\", dependsOn: [\"runtime\"] },\n\t{ id: \"plugin-invariants\", name: \"@di-code/builtins/plugin-invariants\", dependsOn: [\"runtime\"] },\n\t{ id: \"plugin-test-runtime\", name: \"@di-code/builtins/plugin-test-runtime\", dependsOn: [\"runtime\"] },\n\t{ id: \"plugin-trace\", name: \"@di-code/coding-agent/plugin-trace\", dependsOn: [\"plugin-inventory\"] },\n\t{\n\t\tid: \"plugin-dump-composition\",\n\t\tname: \"@di-code/coding-agent/plugin-dump-composition\",\n\t\tdependsOn: [\"plugin-inventory\"],\n\t},\n] as const satisfies readonly CompositionEntry[];\n\nfunction builtinCompositionPath(name: DefaultCompositionName): string {\n\treturn fileURLToPath(new URL(`../compositions/${name}.yml`, import.meta.url));\n}\n\n/** Resolves the package-owned base plus exactly one mode document. */\nexport async function resolveDefaultComposition(\n\tname: DefaultCompositionName,\n\toptions: { readonly observability?: boolean; readonly allowedRoot?: string } = {},\n): Promise<readonly CompositionEntry[]> {\n\tconst base = await readRequiredComposition(builtinCompositionPath(\"base\"));\n\tconst mode = name === \"base\" ? { entries: [] } : await readRequiredComposition(builtinCompositionPath(name));\n\treturn Object.freeze(\n\t\twithWorkspaceRoot(\n\t\t\tmergeCompositionLayers([\n\t\t\t\t{ name: \"base\", document: base },\n\t\t\t\t{\n\t\t\t\t\tname: \"mode\",\n\t\t\t\t\tdocument: { entries: [...(mode.entries ?? []), ...(options.observability ? observabilityEntries : [])] },\n\t\t\t\t},\n\t\t\t]),\n\t\t\toptions.allowedRoot,\n\t\t),\n\t);\n}\n\nfunction isJsonObject(\n\tvalue: CompositionEntry[\"config\"],\n): value is Readonly<Record<string, import(\"@di-code/plugin-loader\").JsonValue>> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction withWorkspaceRoot(\n\tentries: readonly CompositionEntry[],\n\tallowedRoot: string | undefined,\n): readonly CompositionEntry[] {\n\tif (allowedRoot === undefined) return entries;\n\treturn entries.map((entry) =>\n\t\tentry.id === \"workspace\"\n\t\t\t? { ...entry, config: { ...(isJsonObject(entry.config) ? entry.config : {}), allowedRoot } }\n\t\t\t: entry,\n\t);\n}\n\nfunction markProjectEntries(document: CompositionDocument): CompositionDocument {\n\tconst mark = (entry: CompositionEntry): CompositionEntry => ({ ...entry, projectLocal: true });\n\treturn {\n\t\t...(document.entries ? { entries: document.entries.map(mark) } : {}),\n\t\t...(document.patches\n\t\t\t? {\n\t\t\t\t\tpatches: document.patches.map((patch) =>\n\t\t\t\t\t\t\"entry\" in patch && patch.entry !== undefined ? { ...patch, entry: mark(patch.entry) } : patch,\n\t\t\t\t\t),\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\nfunction isMissingFile(cause: unknown): boolean {\n\treturn typeof cause === \"object\" && cause !== null && \"code\" in cause && cause.code === \"ENOENT\";\n}\n\nasync function readOptionalComposition(filePath: string): Promise<CompositionDocument | undefined> {\n\ttry {\n\t\treturn await readCompositionFile(filePath);\n\t} catch (cause) {\n\t\tif (isMissingFile(cause)) return undefined;\n\t\tconst message = cause instanceof Error ? cause.message : String(cause);\n\t\tthrow new Error(`Failed to read composition ${filePath}: ${message}`, { cause });\n\t}\n}\n\nasync function readRequiredComposition(filePath: string): Promise<CompositionDocument> {\n\ttry {\n\t\treturn await readCompositionFile(filePath);\n\t} catch (cause) {\n\t\tconst message = cause instanceof Error ? cause.message : String(cause);\n\t\tthrow new Error(`Failed to read composition ${filePath}: ${message}`, { cause });\n\t}\n}\n\n/**\n * Resolves built-in, user, project, and explicit composition layers in their fixed precedence order.\n * Project entries are marked local so the Loader retains trust checks for entries added through project configuration.\n */\nexport async function resolveCompositionEntries(\n\tname: DefaultCompositionName,\n\toptions: CompositionResolutionOptions = {},\n): Promise<readonly CompositionEntry[]> {\n\tconst cwd = resolve(options.cwd ?? process.cwd());\n\tconst agentDir = resolve(options.agentDir ?? join(homedir(), \".di-code\"));\n\tconst [base, mode] = await Promise.all([\n\t\treadRequiredComposition(builtinCompositionPath(\"base\")),\n\t\treadRequiredComposition(builtinCompositionPath(name)),\n\t]);\n\tconst layers: CompositionLayer[] = [\n\t\t{ name: \"base\", document: base },\n\t\t{\n\t\t\tname: \"mode\",\n\t\t\tdocument: {\n\t\t\t\tentries: [...(mode.entries ?? []), ...(options.observability ? observabilityEntries : [])],\n\t\t\t},\n\t\t},\n\t];\n\tconst userComposition = await readOptionalComposition(join(agentDir, \"composition.yml\"));\n\tif (userComposition !== undefined) layers.push({ name: \"user\", document: userComposition });\n\tif (options.includeProjectComposition !== false) {\n\t\tconst projectComposition = await readOptionalComposition(join(cwd, \".di-code\", \"composition.yml\"));\n\t\tif (projectComposition !== undefined)\n\t\t\tlayers.push({ name: \"project\", document: markProjectEntries(projectComposition) });\n\t}\n\tif (options.compositionPath !== undefined) {\n\t\tlayers.push({ name: \"explicit\", document: await readRequiredComposition(resolve(cwd, options.compositionPath)) });\n\t}\n\treturn Object.freeze(withWorkspaceRoot(mergeCompositionLayers(layers), options.allowedRoot));\n}\n\n/**\n * Resolves only enabled managed plugins before the Loader receives its entry list.\n * Disabled manifests are not resolved or dynamically imported.\n */\nexport async function resolveManagedCompositionEntries(\n\tagentDir = join(homedir(), \".di-code\"),\n): Promise<readonly CompositionEntry[]> {\n\tconst manager = new PluginInstallManager({ managedRoot: join(resolve(agentDir), \"plugins\", \"installed\") });\n\tconst plugins = await manager.list();\n\treturn await Promise.all(\n\t\tplugins\n\t\t\t.filter((plugin) => plugin.enabled)\n\t\t\t.map(async (plugin) => ({\n\t\t\t\tid: `managed.${plugin.id}`,\n\t\t\t\tname: pathToFileURL(await resolvePackagePluginExport(plugin.installedPath, plugin.manifest.entry)).href,\n\t\t\t\tdependsOn: [\"Bootstrap\"],\n\t\t\t\trequired: false,\n\t\t\t})),\n\t);\n}\n\n/** Imports own composition entries from source in development; package exports handle published use. */\nexport function importCompositionModule(name: string): Promise<PluginModule> {\n\tswitch (name) {\n\t\tcase \"@di-code/coding-agent/plugin-manager\":\n\t\t\treturn import(\"./plugin-manager.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/plugin-inventory\":\n\t\t\treturn import(\"./plugin-inventory.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/plugin-trace\":\n\t\t\treturn import(\"./plugin-trace.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/plugin-dump-composition\":\n\t\t\treturn import(\"./plugin-dump-composition.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/mcp-config-entry\":\n\t\t\treturn import(\"./mcp-config-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/mcp-client-entry\":\n\t\t\treturn import(\"./mcp-client-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/mcp-transport-entry\":\n\t\t\treturn import(\"./mcp-transport-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/mcp-tools-entry\":\n\t\t\treturn import(\"./mcp-tools-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/session-factory-entry\":\n\t\t\treturn import(\"./session-factory-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/session-store-jsonl-entry\":\n\t\t\treturn import(\"./session-store-jsonl-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/rpc-server-entry\":\n\t\t\treturn import(\"./rpc-server-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/interactive-resources-entry\":\n\t\t\treturn import(\"./interactive-resources-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/interactive-host-entry\":\n\t\t\treturn import(\"./interactive-host-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/runtime-core-entry\":\n\t\t\treturn import(\"./runtime-core-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/composition-loader-entry\":\n\t\t\treturn import(\"./composition-loader-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/project-trust-entry\":\n\t\t\treturn import(\"./project-trust-entry.ts\") as Promise<PluginModule>;\n\t\tcase \"@di-code/coding-agent/rpc-client-sdk-entry\":\n\t\t\treturn import(\"./rpc-client-sdk-entry.ts\") as Promise<PluginModule>;\n\t\tdefault:\n\t\t\treturn import(name) as Promise<PluginModule>;\n\t}\n}\n"]}
@@ -1,7 +1,7 @@
1
- import type { Message } from "@di-code/ai";
1
+ import type { JsonValue, Message } from "@di-code/ai";
2
2
  import { type BuiltSessionContext } from "../context-builder.ts";
3
3
  import { type SessionAppendOptions } from "./session-storage.ts";
4
- import { type SessionDiagnostic, type SessionEntry, type SessionHeader, type SessionMessageEntry, type SessionSummaryEntry, type SessionTreeNode } from "./types.ts";
4
+ import { type SessionDiagnostic, type SessionEntry, type SessionHeader, type SessionMessageEntry, type SessionPluginEntry, type SessionSummaryEntry, type SessionTreeNode } from "./types.ts";
5
5
  export interface SessionManagerCreateOptions {
6
6
  readonly filePath: string;
7
7
  readonly cwd: string;
@@ -50,6 +50,13 @@ export declare class SessionManager {
50
50
  readonly firstKeptEntryId: string;
51
51
  readonly tokensBefore: number;
52
52
  }): Promise<SessionSummaryEntry>;
53
+ /** Appends host-owned metadata without exposing it as a transcript message. */
54
+ appendPlugin(input: {
55
+ readonly pluginId: string;
56
+ readonly pluginVersion: string;
57
+ readonly schemaVersion: number;
58
+ readonly data: JsonValue;
59
+ }): Promise<SessionPluginEntry>;
53
60
  private addToIndexes;
54
61
  }
55
62
  //# sourceMappingURL=session-manager.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"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"}
@@ -191,6 +191,34 @@ export class SessionManager {
191
191
  this.appendQueue = operation.then(() => undefined, () => undefined);
192
192
  return operation;
193
193
  }
194
+ /** Appends host-owned metadata without exposing it as a transcript message. */
195
+ appendPlugin(input) {
196
+ const inputSnapshot = structuredClone(input);
197
+ const operation = this.appendQueue.then(async () => {
198
+ await this.ensureFileCreated();
199
+ const id = this.createId();
200
+ assertRecordId(id);
201
+ const expectedParentId = this.leafId;
202
+ const entry = {
203
+ type: "plugin",
204
+ version: SESSION_FORMAT_VERSION,
205
+ id,
206
+ parentId: expectedParentId,
207
+ timestamp: createIsoTimestamp(this.now),
208
+ pluginId: inputSnapshot.pluginId,
209
+ pluginVersion: inputSnapshot.pluginVersion,
210
+ schemaVersion: inputSnapshot.schemaVersion,
211
+ data: inputSnapshot.data,
212
+ };
213
+ await appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);
214
+ this.sessionEntries.push(structuredClone(entry));
215
+ this.addToIndexes(entry);
216
+ this.activeLeafId = entry.id;
217
+ return structuredClone(entry);
218
+ });
219
+ this.appendQueue = operation.then(() => undefined, () => undefined);
220
+ return operation;
221
+ }
194
222
  addToIndexes(entry) {
195
223
  this.entriesById.set(entry.id, structuredClone(entry));
196
224
  const children = this.childrenByParentId.get(entry.parentId) ?? [];
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { resolve } from \"node:path\";\nimport type { Message } from \"@di-code/ai\";\nimport { type BuiltSessionContext, buildSessionContext } from \"../context-builder.ts\";\nimport {\n\tappendSessionEntry,\n\tcreateSessionFile,\n\tloadSessionFile,\n\ttype SessionAppendOptions,\n} from \"./session-storage.ts\";\nimport {\n\ttype LoadedSession,\n\tSESSION_FORMAT_VERSION,\n\ttype SessionDiagnostic,\n\ttype SessionEntry,\n\ttype SessionHeader,\n\ttype SessionMessageEntry,\n\ttype SessionSummaryEntry,\n\ttype SessionTreeNode,\n} from \"./types.ts\";\n\nexport interface SessionManagerCreateOptions {\n\treadonly filePath: string;\n\treadonly cwd: string;\n\treadonly now?: () => number;\n\treadonly createId?: () => string;\n\treadonly appendOptions?: SessionAppendOptions;\n\treadonly deferCreate?: boolean;\n}\n\nexport interface SessionManagerOpenOptions {\n\treadonly now?: () => number;\n\treadonly createId?: () => string;\n\treadonly appendOptions?: SessionAppendOptions;\n}\n\nfunction assertRecordId(id: string): void {\n\tif (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(id)) {\n\t\tthrow new Error(`Generated session record id is invalid: ${JSON.stringify(id)}.`);\n\t}\n}\n\nfunction createIsoTimestamp(now: () => number): string {\n\tconst milliseconds = now();\n\tif (!Number.isFinite(milliseconds)) {\n\t\tthrow new Error(\"Session clock must return a finite Unix millisecond timestamp.\");\n\t}\n\treturn new Date(milliseconds).toISOString();\n}\n\nexport class SessionManager {\n\treadonly filePath: string;\n\tprivate readonly sessionHeader: SessionHeader;\n\tprivate readonly now: () => number;\n\tprivate readonly createId: () => string;\n\tprivate readonly appendOptions: SessionAppendOptions;\n\tprivate readonly sessionEntries: SessionEntry[];\n\tprivate readonly entriesById = new Map<string, SessionEntry>();\n\tprivate readonly childrenByParentId = new Map<string, string[]>();\n\tprivate readonly sessionDiagnostics: SessionDiagnostic[];\n\tprivate activeLeafId: string;\n\tprivate fileCreated: boolean;\n\tprivate appendQueue: Promise<void> = Promise.resolve();\n\n\tprivate constructor(filePath: string, loaded: LoadedSession, options: SessionManagerOpenOptions, fileCreated = true) {\n\t\tthis.filePath = filePath;\n\t\tthis.sessionHeader = structuredClone(loaded.header);\n\t\tthis.sessionEntries = structuredClone([...loaded.entries]);\n\t\tfor (const entry of this.sessionEntries) this.addToIndexes(entry);\n\t\tthis.activeLeafId = this.sessionEntries.at(-1)?.id ?? this.sessionHeader.id;\n\t\tthis.sessionDiagnostics = structuredClone([...loaded.diagnostics]);\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.createId = options.createId ?? randomUUID;\n\t\tthis.appendOptions = options.appendOptions ?? {};\n\t\tthis.fileCreated = fileCreated;\n\t}\n\n\tstatic async create(options: SessionManagerCreateOptions): Promise<SessionManager> {\n\t\tconst filePath = resolve(options.filePath);\n\t\tconst cwd = resolve(options.cwd);\n\t\tconst now = options.now ?? Date.now;\n\t\tconst createId = options.createId ?? randomUUID;\n\t\tconst id = createId();\n\t\tassertRecordId(id);\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\tid,\n\t\t\tparentId: null,\n\t\t\ttimestamp: createIsoTimestamp(now),\n\t\t\tcwd,\n\t\t};\n\t\tif (!options.deferCreate) await createSessionFile(filePath, header);\n\t\treturn new SessionManager(\n\t\t\tfilePath,\n\t\t\t{ header, entries: [], messages: [], diagnostics: [] },\n\t\t\t{ now, createId, appendOptions: options.appendOptions },\n\t\t\t!options.deferCreate,\n\t\t);\n\t}\n\n\tstatic async open(filePath: string, options: SessionManagerOpenOptions = {}): Promise<SessionManager> {\n\t\tconst resolvedPath = resolve(filePath);\n\t\treturn new SessionManager(resolvedPath, await loadSessionFile(resolvedPath), options);\n\t}\n\n\tget entries(): readonly SessionEntry[] {\n\t\treturn structuredClone(this.sessionEntries);\n\t}\n\n\tget header(): SessionHeader {\n\t\treturn structuredClone(this.sessionHeader);\n\t}\n\n\tget messages(): readonly Message[] {\n\t\treturn structuredClone(\n\t\t\tthis.sessionEntries\n\t\t\t\t.filter((entry): entry is SessionMessageEntry => entry.type === \"message\")\n\t\t\t\t.map((entry) => entry.message),\n\t\t);\n\t}\n\n\tgetEntry(id: string): SessionEntry | undefined {\n\t\tconst entry = this.entriesById.get(id);\n\t\treturn entry ? structuredClone(entry) : undefined;\n\t}\n\n\tgetTree(): readonly SessionTreeNode[] {\n\t\tconst nodes = new Map<string, { entry: SessionEntry; children: SessionTreeNode[] }>();\n\t\tconst roots: SessionTreeNode[] = [];\n\t\tfor (const entry of this.sessionEntries) {\n\t\t\tconst node = { entry: structuredClone(entry), children: [] as SessionTreeNode[] };\n\t\t\tnodes.set(entry.id, node);\n\t\t\tif (entry.parentId === this.sessionHeader.id) {\n\t\t\t\troots.push(node);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst parent = nodes.get(entry.parentId);\n\t\t\tif (!parent) throw new Error(`Session tree parent \"${entry.parentId}\" is missing.`);\n\t\t\tparent.children.push(node);\n\t\t}\n\t\treturn roots;\n\t}\n\n\tgetBranch(leafId = this.activeLeafId): readonly SessionEntry[] {\n\t\tconst branch: SessionEntry[] = [];\n\t\tlet currentId = leafId;\n\t\twhile (currentId !== this.sessionHeader.id) {\n\t\t\tconst entry = this.entriesById.get(currentId);\n\t\t\tif (!entry) throw new Error(`Unknown session leaf \"${currentId}\".`);\n\t\t\tbranch.push(structuredClone(entry));\n\t\t\tcurrentId = entry.parentId;\n\t\t}\n\t\tbranch.reverse();\n\t\treturn branch;\n\t}\n\n\tsetLeaf(id: string): void {\n\t\tif (id !== this.sessionHeader.id && !this.entriesById.has(id)) throw new Error(`Unknown session leaf \"${id}\".`);\n\t\tthis.activeLeafId = id;\n\t}\n\n\tresetLeaf(): void {\n\t\tthis.activeLeafId = this.sessionEntries.at(-1)?.id ?? this.sessionHeader.id;\n\t}\n\n\tbuildContext(leafId = this.activeLeafId): BuiltSessionContext {\n\t\treturn buildSessionContext(this.getBranch(leafId));\n\t}\n\n\tget latestSummary(): SessionSummaryEntry | undefined {\n\t\tconst branch = this.getBranch();\n\t\tfor (let index = branch.length - 1; index >= 0; index--) {\n\t\t\tconst entry = branch[index];\n\t\t\tif (entry?.type === \"summary\") return structuredClone(entry);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tget diagnostics(): readonly SessionDiagnostic[] {\n\t\treturn structuredClone(this.sessionDiagnostics);\n\t}\n\n\tget leafId(): string {\n\t\treturn this.activeLeafId;\n\t}\n\n\tprivate async ensureFileCreated(): Promise<void> {\n\t\tif (this.fileCreated) return;\n\t\tawait createSessionFile(this.filePath, this.sessionHeader);\n\t\tthis.fileCreated = true;\n\t}\n\n\tappendMessage(message: Message): Promise<SessionMessageEntry> {\n\t\tconst messageSnapshot = structuredClone(message);\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tawait this.ensureFileCreated();\n\t\t\tconst id = this.createId();\n\t\t\tassertRecordId(id);\n\t\t\tconst expectedParentId = this.leafId;\n\t\t\tconst entry: SessionMessageEntry = {\n\t\t\t\ttype: \"message\",\n\t\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\t\tid,\n\t\t\t\tparentId: expectedParentId,\n\t\t\t\ttimestamp: createIsoTimestamp(this.now),\n\t\t\t\tmessage: messageSnapshot,\n\t\t\t};\n\t\t\tawait appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);\n\t\t\tthis.sessionEntries.push(structuredClone(entry));\n\t\t\tthis.addToIndexes(entry);\n\t\t\tthis.activeLeafId = entry.id;\n\t\t\treturn structuredClone(entry);\n\t\t});\n\n\t\tthis.appendQueue = operation.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn operation;\n\t}\n\n\tappendSummary(input: {\n\t\treadonly summary: string;\n\t\treadonly firstKeptEntryId: string;\n\t\treadonly tokensBefore: number;\n\t}): Promise<SessionSummaryEntry> {\n\t\tconst inputSnapshot = structuredClone(input);\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tawait this.ensureFileCreated();\n\t\t\tconst id = this.createId();\n\t\t\tassertRecordId(id);\n\t\t\tconst expectedParentId = this.leafId;\n\t\t\tconst entry: SessionSummaryEntry = {\n\t\t\t\ttype: \"summary\",\n\t\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\t\tid,\n\t\t\t\tparentId: expectedParentId,\n\t\t\t\ttimestamp: createIsoTimestamp(this.now),\n\t\t\t\tsummary: inputSnapshot.summary,\n\t\t\t\tfirstKeptEntryId: inputSnapshot.firstKeptEntryId,\n\t\t\t\ttokensBefore: inputSnapshot.tokensBefore,\n\t\t\t};\n\t\t\tawait appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);\n\t\t\tthis.sessionEntries.push(structuredClone(entry));\n\t\t\tthis.addToIndexes(entry);\n\t\t\tthis.activeLeafId = entry.id;\n\t\t\treturn structuredClone(entry);\n\t\t});\n\n\t\tthis.appendQueue = operation.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn operation;\n\t}\n\n\tprivate addToIndexes(entry: SessionEntry): void {\n\t\tthis.entriesById.set(entry.id, structuredClone(entry));\n\t\tconst children = this.childrenByParentId.get(entry.parentId) ?? [];\n\t\tchildren.push(entry.id);\n\t\tthis.childrenByParentId.set(entry.parentId, children);\n\t}\n}\n"]}
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../../src/core/session/session-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { resolve } from \"node:path\";\nimport type { JsonValue, Message } from \"@di-code/ai\";\nimport { type BuiltSessionContext, buildSessionContext } from \"../context-builder.ts\";\nimport {\n\tappendSessionEntry,\n\tcreateSessionFile,\n\tloadSessionFile,\n\ttype SessionAppendOptions,\n} from \"./session-storage.ts\";\nimport {\n\ttype LoadedSession,\n\tSESSION_FORMAT_VERSION,\n\ttype SessionDiagnostic,\n\ttype SessionEntry,\n\ttype SessionHeader,\n\ttype SessionMessageEntry,\n\ttype SessionPluginEntry,\n\ttype SessionSummaryEntry,\n\ttype SessionTreeNode,\n} from \"./types.ts\";\n\nexport interface SessionManagerCreateOptions {\n\treadonly filePath: string;\n\treadonly cwd: string;\n\treadonly now?: () => number;\n\treadonly createId?: () => string;\n\treadonly appendOptions?: SessionAppendOptions;\n\treadonly deferCreate?: boolean;\n}\n\nexport interface SessionManagerOpenOptions {\n\treadonly now?: () => number;\n\treadonly createId?: () => string;\n\treadonly appendOptions?: SessionAppendOptions;\n}\n\nfunction assertRecordId(id: string): void {\n\tif (!/^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(id)) {\n\t\tthrow new Error(`Generated session record id is invalid: ${JSON.stringify(id)}.`);\n\t}\n}\n\nfunction createIsoTimestamp(now: () => number): string {\n\tconst milliseconds = now();\n\tif (!Number.isFinite(milliseconds)) {\n\t\tthrow new Error(\"Session clock must return a finite Unix millisecond timestamp.\");\n\t}\n\treturn new Date(milliseconds).toISOString();\n}\n\nexport class SessionManager {\n\treadonly filePath: string;\n\tprivate readonly sessionHeader: SessionHeader;\n\tprivate readonly now: () => number;\n\tprivate readonly createId: () => string;\n\tprivate readonly appendOptions: SessionAppendOptions;\n\tprivate readonly sessionEntries: SessionEntry[];\n\tprivate readonly entriesById = new Map<string, SessionEntry>();\n\tprivate readonly childrenByParentId = new Map<string, string[]>();\n\tprivate readonly sessionDiagnostics: SessionDiagnostic[];\n\tprivate activeLeafId: string;\n\tprivate fileCreated: boolean;\n\tprivate appendQueue: Promise<void> = Promise.resolve();\n\n\tprivate constructor(filePath: string, loaded: LoadedSession, options: SessionManagerOpenOptions, fileCreated = true) {\n\t\tthis.filePath = filePath;\n\t\tthis.sessionHeader = structuredClone(loaded.header);\n\t\tthis.sessionEntries = structuredClone([...loaded.entries]);\n\t\tfor (const entry of this.sessionEntries) this.addToIndexes(entry);\n\t\tthis.activeLeafId = this.sessionEntries.at(-1)?.id ?? this.sessionHeader.id;\n\t\tthis.sessionDiagnostics = structuredClone([...loaded.diagnostics]);\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.createId = options.createId ?? randomUUID;\n\t\tthis.appendOptions = options.appendOptions ?? {};\n\t\tthis.fileCreated = fileCreated;\n\t}\n\n\tstatic async create(options: SessionManagerCreateOptions): Promise<SessionManager> {\n\t\tconst filePath = resolve(options.filePath);\n\t\tconst cwd = resolve(options.cwd);\n\t\tconst now = options.now ?? Date.now;\n\t\tconst createId = options.createId ?? randomUUID;\n\t\tconst id = createId();\n\t\tassertRecordId(id);\n\t\tconst header: SessionHeader = {\n\t\t\ttype: \"session\",\n\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\tid,\n\t\t\tparentId: null,\n\t\t\ttimestamp: createIsoTimestamp(now),\n\t\t\tcwd,\n\t\t};\n\t\tif (!options.deferCreate) await createSessionFile(filePath, header);\n\t\treturn new SessionManager(\n\t\t\tfilePath,\n\t\t\t{ header, entries: [], messages: [], diagnostics: [] },\n\t\t\t{ now, createId, appendOptions: options.appendOptions },\n\t\t\t!options.deferCreate,\n\t\t);\n\t}\n\n\tstatic async open(filePath: string, options: SessionManagerOpenOptions = {}): Promise<SessionManager> {\n\t\tconst resolvedPath = resolve(filePath);\n\t\treturn new SessionManager(resolvedPath, await loadSessionFile(resolvedPath), options);\n\t}\n\n\tget entries(): readonly SessionEntry[] {\n\t\treturn structuredClone(this.sessionEntries);\n\t}\n\n\tget header(): SessionHeader {\n\t\treturn structuredClone(this.sessionHeader);\n\t}\n\n\tget messages(): readonly Message[] {\n\t\treturn structuredClone(\n\t\t\tthis.sessionEntries\n\t\t\t\t.filter((entry): entry is SessionMessageEntry => entry.type === \"message\")\n\t\t\t\t.map((entry) => entry.message),\n\t\t);\n\t}\n\n\tgetEntry(id: string): SessionEntry | undefined {\n\t\tconst entry = this.entriesById.get(id);\n\t\treturn entry ? structuredClone(entry) : undefined;\n\t}\n\n\tgetTree(): readonly SessionTreeNode[] {\n\t\tconst nodes = new Map<string, { entry: SessionEntry; children: SessionTreeNode[] }>();\n\t\tconst roots: SessionTreeNode[] = [];\n\t\tfor (const entry of this.sessionEntries) {\n\t\t\tconst node = { entry: structuredClone(entry), children: [] as SessionTreeNode[] };\n\t\t\tnodes.set(entry.id, node);\n\t\t\tif (entry.parentId === this.sessionHeader.id) {\n\t\t\t\troots.push(node);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst parent = nodes.get(entry.parentId);\n\t\t\tif (!parent) throw new Error(`Session tree parent \"${entry.parentId}\" is missing.`);\n\t\t\tparent.children.push(node);\n\t\t}\n\t\treturn roots;\n\t}\n\n\tgetBranch(leafId = this.activeLeafId): readonly SessionEntry[] {\n\t\tconst branch: SessionEntry[] = [];\n\t\tlet currentId = leafId;\n\t\twhile (currentId !== this.sessionHeader.id) {\n\t\t\tconst entry = this.entriesById.get(currentId);\n\t\t\tif (!entry) throw new Error(`Unknown session leaf \"${currentId}\".`);\n\t\t\tbranch.push(structuredClone(entry));\n\t\t\tcurrentId = entry.parentId;\n\t\t}\n\t\tbranch.reverse();\n\t\treturn branch;\n\t}\n\n\tsetLeaf(id: string): void {\n\t\tif (id !== this.sessionHeader.id && !this.entriesById.has(id)) throw new Error(`Unknown session leaf \"${id}\".`);\n\t\tthis.activeLeafId = id;\n\t}\n\n\tresetLeaf(): void {\n\t\tthis.activeLeafId = this.sessionEntries.at(-1)?.id ?? this.sessionHeader.id;\n\t}\n\n\tbuildContext(leafId = this.activeLeafId): BuiltSessionContext {\n\t\treturn buildSessionContext(this.getBranch(leafId));\n\t}\n\n\tget latestSummary(): SessionSummaryEntry | undefined {\n\t\tconst branch = this.getBranch();\n\t\tfor (let index = branch.length - 1; index >= 0; index--) {\n\t\t\tconst entry = branch[index];\n\t\t\tif (entry?.type === \"summary\") return structuredClone(entry);\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tget diagnostics(): readonly SessionDiagnostic[] {\n\t\treturn structuredClone(this.sessionDiagnostics);\n\t}\n\n\tget leafId(): string {\n\t\treturn this.activeLeafId;\n\t}\n\n\tprivate async ensureFileCreated(): Promise<void> {\n\t\tif (this.fileCreated) return;\n\t\tawait createSessionFile(this.filePath, this.sessionHeader);\n\t\tthis.fileCreated = true;\n\t}\n\n\tappendMessage(message: Message): Promise<SessionMessageEntry> {\n\t\tconst messageSnapshot = structuredClone(message);\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tawait this.ensureFileCreated();\n\t\t\tconst id = this.createId();\n\t\t\tassertRecordId(id);\n\t\t\tconst expectedParentId = this.leafId;\n\t\t\tconst entry: SessionMessageEntry = {\n\t\t\t\ttype: \"message\",\n\t\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\t\tid,\n\t\t\t\tparentId: expectedParentId,\n\t\t\t\ttimestamp: createIsoTimestamp(this.now),\n\t\t\t\tmessage: messageSnapshot,\n\t\t\t};\n\t\t\tawait appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);\n\t\t\tthis.sessionEntries.push(structuredClone(entry));\n\t\t\tthis.addToIndexes(entry);\n\t\t\tthis.activeLeafId = entry.id;\n\t\t\treturn structuredClone(entry);\n\t\t});\n\n\t\tthis.appendQueue = operation.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn operation;\n\t}\n\n\tappendSummary(input: {\n\t\treadonly summary: string;\n\t\treadonly firstKeptEntryId: string;\n\t\treadonly tokensBefore: number;\n\t}): Promise<SessionSummaryEntry> {\n\t\tconst inputSnapshot = structuredClone(input);\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tawait this.ensureFileCreated();\n\t\t\tconst id = this.createId();\n\t\t\tassertRecordId(id);\n\t\t\tconst expectedParentId = this.leafId;\n\t\t\tconst entry: SessionSummaryEntry = {\n\t\t\t\ttype: \"summary\",\n\t\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\t\tid,\n\t\t\t\tparentId: expectedParentId,\n\t\t\t\ttimestamp: createIsoTimestamp(this.now),\n\t\t\t\tsummary: inputSnapshot.summary,\n\t\t\t\tfirstKeptEntryId: inputSnapshot.firstKeptEntryId,\n\t\t\t\ttokensBefore: inputSnapshot.tokensBefore,\n\t\t\t};\n\t\t\tawait appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);\n\t\t\tthis.sessionEntries.push(structuredClone(entry));\n\t\t\tthis.addToIndexes(entry);\n\t\t\tthis.activeLeafId = entry.id;\n\t\t\treturn structuredClone(entry);\n\t\t});\n\n\t\tthis.appendQueue = operation.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn operation;\n\t}\n\n\t/** Appends host-owned metadata without exposing it as a transcript message. */\n\tappendPlugin(input: {\n\t\treadonly pluginId: string;\n\t\treadonly pluginVersion: string;\n\t\treadonly schemaVersion: number;\n\t\treadonly data: JsonValue;\n\t}): Promise<SessionPluginEntry> {\n\t\tconst inputSnapshot = structuredClone(input);\n\t\tconst operation = this.appendQueue.then(async () => {\n\t\t\tawait this.ensureFileCreated();\n\t\t\tconst id = this.createId();\n\t\t\tassertRecordId(id);\n\t\t\tconst expectedParentId = this.leafId;\n\t\t\tconst entry: SessionPluginEntry = {\n\t\t\t\ttype: \"plugin\",\n\t\t\t\tversion: SESSION_FORMAT_VERSION,\n\t\t\t\tid,\n\t\t\t\tparentId: expectedParentId,\n\t\t\t\ttimestamp: createIsoTimestamp(this.now),\n\t\t\t\tpluginId: inputSnapshot.pluginId,\n\t\t\t\tpluginVersion: inputSnapshot.pluginVersion,\n\t\t\t\tschemaVersion: inputSnapshot.schemaVersion,\n\t\t\t\tdata: inputSnapshot.data,\n\t\t\t};\n\t\t\tawait appendSessionEntry(this.filePath, entry, expectedParentId, this.appendOptions);\n\t\t\tthis.sessionEntries.push(structuredClone(entry));\n\t\t\tthis.addToIndexes(entry);\n\t\t\tthis.activeLeafId = entry.id;\n\t\t\treturn structuredClone(entry);\n\t\t});\n\n\t\tthis.appendQueue = operation.then(\n\t\t\t() => undefined,\n\t\t\t() => undefined,\n\t\t);\n\t\treturn operation;\n\t}\n\n\tprivate addToIndexes(entry: SessionEntry): void {\n\t\tthis.entriesById.set(entry.id, structuredClone(entry));\n\t\tconst children = this.childrenByParentId.get(entry.parentId) ?? [];\n\t\tchildren.push(entry.id);\n\t\tthis.childrenByParentId.set(entry.parentId, children);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-storage.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-storage.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,YAAY,EACjB,KAAK,aAAa,EAKlB,MAAM,YAAY,CAAC;AA6MpB,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAiF9E;AAkBD,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAaD,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9F;AA8CD,wBAAsB,kBAAkB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,YAAY,EACnB,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,oBAAyB,GAChC,OAAO,CAAC,IAAI,CAAC,CAmFf"}
1
+ {"version":3,"file":"session-storage.d.ts","sourceRoot":"","sources":["../../../src/core/session/session-storage.ts"],"names":[],"mappings":"AAGA,OAAO,EACN,KAAK,aAAa,EAElB,KAAK,YAAY,EACjB,KAAK,aAAa,EAMlB,MAAM,YAAY,CAAC;AA2NpB,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAiF9E;AAkBD,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACzD;AAaD,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB9F;AAoDD,wBAAsB,kBAAkB,CACvC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,YAAY,EACnB,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,oBAAyB,GAChC,OAAO,CAAC,IAAI,CAAC,CAmFf"}
@@ -143,8 +143,8 @@ function decodeHeader(value, filePath) {
143
143
  return value;
144
144
  }
145
145
  function decodeSessionEntry(value) {
146
- if (!isObject(value) || (value.type !== "message" && value.type !== "summary")) {
147
- return { reason: 'record type must be "message" or "summary"' };
146
+ if (!isObject(value) || (value.type !== "message" && value.type !== "summary" && value.type !== "plugin")) {
147
+ return { reason: 'record type must be "message", "summary", or "plugin"' };
148
148
  }
149
149
  if (value.version !== SESSION_FORMAT_VERSION)
150
150
  return { reason: `record version must be ${SESSION_FORMAT_VERSION}` };
@@ -159,6 +159,18 @@ function decodeSessionEntry(value) {
159
159
  return { reason: "record message does not match the Message contract" };
160
160
  return { entry: value };
161
161
  }
162
+ if (value.type === "plugin") {
163
+ if (typeof value.pluginId !== "string" ||
164
+ value.pluginId.length === 0 ||
165
+ typeof value.pluginVersion !== "string" ||
166
+ value.pluginVersion.length === 0 ||
167
+ typeof value.schemaVersion !== "number" ||
168
+ !Number.isSafeInteger(value.schemaVersion) ||
169
+ value.schemaVersion < 0 ||
170
+ !isJsonValue(value.data))
171
+ return { reason: "record plugin fields are invalid" };
172
+ return { entry: value };
173
+ }
162
174
  if (typeof value.summary !== "string" || value.summary.trim().length === 0) {
163
175
  return { reason: "record summary must be a non-empty string" };
164
176
  }
@@ -308,7 +320,12 @@ async function acquireLock(filePath, options) {
308
320
  return { handle: await open(lockPath, "wx"), lockPath };
309
321
  }
310
322
  catch (cause) {
311
- if (!isNodeError(cause) || cause.code !== "EEXIST") {
323
+ // Windows can report EPERM/EACCES while another process closes or removes the lock file.
324
+ // Treat that brief transition as contention so a writer does not fail merely because the lock vanished.
325
+ const lockBusy = isNodeError(cause) &&
326
+ (cause.code === "EEXIST" ||
327
+ (process.platform === "win32" && (cause.code === "EPERM" || cause.code === "EACCES")));
328
+ if (!lockBusy) {
312
329
  throw new SessionWriteError("APPEND_FAILED", filePath, `Failed to acquire session lock for "${filePath}".`, {
313
330
  cause,
314
331
  });
@@ -1 +1 @@
1
- {"version":3,"file":"session-storage.js","sourceRoot":"","sources":["../../../src/core/session/session-storage.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFile, mkdir, open, readFile, unlink } from \"node:fs/promises\";\nimport { dirname, posix, win32 } from \"node:path\";\nimport type { AssistantContent, AssistantMessage, Message, ToolResultContent, Usage, UserContent } from \"@di-code/ai\";\nimport {\n\ttype LoadedSession,\n\tSESSION_FORMAT_VERSION,\n\ttype SessionEntry,\n\ttype SessionHeader,\n\tSessionLoadError,\n\ttype SessionMessageEntry,\n\ttype SessionSummaryEntry,\n\tSessionWriteError,\n} from \"./types.ts\";\n\ntype JsonObject = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is JsonObject {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.length > 0;\n}\n\nfunction isNonNegativeNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\nfunction isTimestamp(value: unknown): value is number {\n\treturn Number.isSafeInteger(value) && isNonNegativeNumber(value);\n}\n\nfunction isIsoTimestamp(value: unknown): value is string {\n\tif (typeof value !== \"string\") return false;\n\tconst milliseconds = Date.parse(value);\n\treturn Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === value;\n}\n\nfunction isRecordId(value: unknown): value is string {\n\treturn typeof value === \"string\" && /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(value);\n}\n\nfunction isAbsolutePath(value: unknown): value is string {\n\treturn typeof value === \"string\" && (win32.isAbsolute(value) || posix.isAbsolute(value));\n}\n\nfunction isJsonValue(value: unknown): boolean {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return true;\n\tif (typeof value === \"number\") return Number.isFinite(value);\n\tif (Array.isArray(value)) return value.every(isJsonValue);\n\treturn isObject(value) && Object.values(value).every(isJsonValue);\n}\n\nfunction isProviderReplay(value: unknown): boolean {\n\treturn isObject(value) && isNonEmptyString(value.api) && isJsonValue(value.data);\n}\n\nfunction isImageContent(value: unknown): value is Extract<UserContent | ToolResultContent, { type: \"image\" }> {\n\treturn (\n\t\tisObject(value) && value.type === \"image\" && typeof value.data === \"string\" && isNonEmptyString(value.mimeType)\n\t);\n}\n\nfunction isTextContent(value: unknown): value is Extract<UserContent, { type: \"text\" }> {\n\treturn isObject(value) && value.type === \"text\" && typeof value.text === \"string\";\n}\n\nfunction isUserContent(value: unknown): value is UserContent {\n\treturn isTextContent(value) || isImageContent(value);\n}\n\nfunction isAssistantContent(value: unknown): value is AssistantContent {\n\tif (!isObject(value)) return false;\n\tswitch (value.type) {\n\t\tcase \"text\":\n\t\t\treturn typeof value.text === \"string\";\n\t\tcase \"thinking\":\n\t\t\treturn typeof value.thinking === \"string\";\n\t\tcase \"tool_call\":\n\t\t\treturn (\n\t\t\t\tisNonEmptyString(value.id) &&\n\t\t\t\tisNonEmptyString(value.name) &&\n\t\t\t\tisObject(value.arguments) &&\n\t\t\t\tisJsonValue(value.arguments)\n\t\t\t);\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nfunction isToolResultContent(value: unknown): value is ToolResultContent {\n\treturn isTextContent(value) || isImageContent(value);\n}\n\nfunction isUsage(value: unknown): value is Usage {\n\tif (!isObject(value) || !isObject(value.cost)) return false;\n\treturn (\n\t\tisNonNegativeNumber(value.input) &&\n\t\tisNonNegativeNumber(value.output) &&\n\t\tisNonNegativeNumber(value.cacheRead) &&\n\t\tisNonNegativeNumber(value.cacheWrite) &&\n\t\tisNonNegativeNumber(value.totalTokens) &&\n\t\tisNonNegativeNumber(value.cost.input) &&\n\t\tisNonNegativeNumber(value.cost.output) &&\n\t\tisNonNegativeNumber(value.cost.cacheRead) &&\n\t\tisNonNegativeNumber(value.cost.cacheWrite) &&\n\t\tisNonNegativeNumber(value.cost.total)\n\t);\n}\n\nfunction isAssistantMessage(value: JsonObject): value is JsonObject & AssistantMessage {\n\tif (\n\t\tvalue.role !== \"assistant\" ||\n\t\t!Array.isArray(value.content) ||\n\t\t!value.content.every(isAssistantContent) ||\n\t\t!isNonEmptyString(value.provider) ||\n\t\t!isNonEmptyString(value.model) ||\n\t\t(value.providerReplay !== undefined && !isProviderReplay(value.providerReplay)) ||\n\t\t!isUsage(value.usage) ||\n\t\t!isTimestamp(value.timestamp)\n\t) {\n\t\treturn false;\n\t}\n\n\tif (value.stopReason === \"stop\" || value.stopReason === \"length\" || value.stopReason === \"tool_use\") {\n\t\treturn value.errorMessage === undefined;\n\t}\n\tif (value.stopReason === \"error\" || value.stopReason === \"aborted\") {\n\t\treturn typeof value.errorMessage === \"string\";\n\t}\n\treturn false;\n}\n\nfunction isMessage(value: unknown): value is Message {\n\tif (!isObject(value) || !isTimestamp(value.timestamp)) return false;\n\n\tswitch (value.role) {\n\t\tcase \"user\":\n\t\t\treturn Array.isArray(value.content) && value.content.every(isUserContent);\n\t\tcase \"assistant\":\n\t\t\treturn isAssistantMessage(value);\n\t\tcase \"tool_result\":\n\t\t\treturn (\n\t\t\t\tisNonEmptyString(value.toolCallId) &&\n\t\t\t\tisNonEmptyString(value.toolName) &&\n\t\t\t\tArray.isArray(value.content) &&\n\t\t\t\tvalue.content.every(isToolResultContent) &&\n\t\t\t\t(value.details === undefined || isJsonValue(value.details)) &&\n\t\t\t\ttypeof value.isError === \"boolean\"\n\t\t\t);\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nfunction decodeHeader(value: unknown, filePath: string): SessionHeader {\n\tif (!isObject(value) || value.type !== \"session\") {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Invalid session header in \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t});\n\t}\n\tif (!(\"version\" in value)) {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Session header has no version in \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t});\n\t}\n\tif (value.version !== SESSION_FORMAT_VERSION) {\n\t\tthrow new SessionLoadError(\n\t\t\t\"UNSUPPORTED_VERSION\",\n\t\t\tfilePath,\n\t\t\t`Unsupported session version ${JSON.stringify(value.version)} in \"${filePath}\".`,\n\t\t\t{ lineNumber: 1 },\n\t\t);\n\t}\n\tif (\n\t\t!isRecordId(value.id) ||\n\t\tvalue.parentId !== null ||\n\t\t!isIsoTimestamp(value.timestamp) ||\n\t\t!isAbsolutePath(value.cwd)\n\t) {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Invalid session header fields in \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t});\n\t}\n\treturn value as unknown as SessionHeader;\n}\n\nfunction decodeSessionEntry(value: unknown): { readonly entry?: SessionEntry; readonly reason?: string } {\n\tif (!isObject(value) || (value.type !== \"message\" && value.type !== \"summary\")) {\n\t\treturn { reason: 'record type must be \"message\" or \"summary\"' };\n\t}\n\tif (value.version !== SESSION_FORMAT_VERSION) return { reason: `record version must be ${SESSION_FORMAT_VERSION}` };\n\tif (!isRecordId(value.id)) return { reason: \"record id is invalid\" };\n\tif (!isRecordId(value.parentId)) return { reason: \"record parentId is invalid\" };\n\tif (!isIsoTimestamp(value.timestamp)) return { reason: \"record timestamp is not canonical ISO 8601 UTC\" };\n\tif (value.type === \"message\") {\n\t\tif (!isMessage(value.message)) return { reason: \"record message does not match the Message contract\" };\n\t\treturn { entry: value as unknown as SessionMessageEntry };\n\t}\n\tif (typeof value.summary !== \"string\" || value.summary.trim().length === 0) {\n\t\treturn { reason: \"record summary must be a non-empty string\" };\n\t}\n\tif (!isRecordId(value.firstKeptEntryId)) return { reason: \"record firstKeptEntryId is invalid\" };\n\tif (!Number.isSafeInteger(value.tokensBefore) || !isNonNegativeNumber(value.tokensBefore)) {\n\t\treturn { reason: \"record tokensBefore must be a non-negative safe integer\" };\n\t}\n\treturn { entry: value as unknown as SessionSummaryEntry };\n}\n\nfunction withoutTrailingCarriageReturn(line: string): string {\n\treturn line.endsWith(\"\\r\") ? line.slice(0, -1) : line;\n}\n\nfunction errorText(cause: unknown): string {\n\treturn cause instanceof Error ? cause.message : String(cause);\n}\n\nexport async function loadSessionFile(filePath: string): Promise<LoadedSession> {\n\tlet content: string;\n\ttry {\n\t\tcontent = await readFile(filePath, \"utf8\");\n\t} catch (cause) {\n\t\tthrow new SessionLoadError(\"READ_FAILED\", filePath, `Failed to read session file \"${filePath}\".`, { cause });\n\t}\n\n\tconst physicalLines = content.split(\"\\n\");\n\tlet partialLineNumber: number | undefined;\n\tif (content.endsWith(\"\\n\")) {\n\t\tphysicalLines.pop();\n\t} else {\n\t\tphysicalLines.pop();\n\t\tpartialLineNumber = physicalLines.length + 1;\n\t}\n\n\tif (physicalLines.length === 0) {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Session file has no committed header: \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t});\n\t}\n\n\tlet headerValue: unknown;\n\ttry {\n\t\theaderValue = JSON.parse(withoutTrailingCarriageReturn(physicalLines[0] ?? \"\")) as unknown;\n\t} catch (cause) {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Session header is not valid JSON in \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t\tcause,\n\t\t});\n\t}\n\n\tconst header = decodeHeader(headerValue, filePath);\n\tconst entries: SessionEntry[] = [];\n\tconst diagnostics: LoadedSession[\"diagnostics\"][number][] = [];\n\tconst seenIds = new Set<string>([header.id]);\n\tconst entriesById = new Map<string, SessionEntry>();\n\n\tfor (let index = 1; index < physicalLines.length; index++) {\n\t\tconst lineNumber = index + 1;\n\t\ttry {\n\t\t\tconst value = JSON.parse(withoutTrailingCarriageReturn(physicalLines[index] ?? \"\")) as unknown;\n\t\t\tconst decoded = decodeSessionEntry(value);\n\t\t\tif (!decoded.entry) throw new Error(decoded.reason ?? \"Invalid session message record.\");\n\t\t\tif (seenIds.has(decoded.entry.id)) throw new Error(\"record id is duplicated\");\n\t\t\tif (!seenIds.has(decoded.entry.parentId)) throw new Error(\"record parentId must reference an earlier record\");\n\t\t\tif (decoded.entry.type === \"summary\") {\n\t\t\t\tconst firstKept = entriesById.get(decoded.entry.firstKeptEntryId);\n\t\t\t\tif (\n\t\t\t\t\tfirstKept?.type !== \"message\" ||\n\t\t\t\t\t!isAncestor(decoded.entry.parentId, firstKept.id, entriesById, header.id)\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(\"record firstKeptEntryId must reference an earlier message on the summary branch\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tentries.push(decoded.entry);\n\t\t\tseenIds.add(decoded.entry.id);\n\t\t\tentriesById.set(decoded.entry.id, decoded.entry);\n\t\t} catch (cause) {\n\t\t\tdiagnostics.push({ kind: \"corrupt_record\", lineNumber, reason: errorText(cause) });\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (diagnostics.length === 0 && partialLineNumber !== undefined) {\n\t\tdiagnostics.push({\n\t\t\tkind: \"trailing_partial_line\",\n\t\t\tlineNumber: partialLineNumber,\n\t\t\treason: \"final line has no newline commit marker\",\n\t\t});\n\t}\n\n\treturn {\n\t\theader,\n\t\tentries,\n\t\tmessages: entries\n\t\t\t.filter((entry): entry is SessionMessageEntry => entry.type === \"message\")\n\t\t\t.map((entry) => entry.message),\n\t\tdiagnostics,\n\t};\n}\n\nfunction isAncestor(\n\tleafId: string,\n\tancestorId: string,\n\tentriesById: ReadonlyMap<string, SessionEntry>,\n\theaderId: string,\n): boolean {\n\tlet currentId = leafId;\n\twhile (currentId !== headerId) {\n\t\tif (currentId === ancestorId) return true;\n\t\tconst current = entriesById.get(currentId);\n\t\tif (!current) return false;\n\t\tcurrentId = current.parentId;\n\t}\n\treturn false;\n}\n\nexport interface SessionAppendOptions {\n\treadonly lockTimeoutMs?: number;\n\treadonly lockRetryMs?: number;\n\treadonly now?: () => number;\n\treadonly sleep?: (milliseconds: number) => Promise<void>;\n}\n\nconst DEFAULT_LOCK_TIMEOUT_MS = 5_000;\nconst DEFAULT_LOCK_RETRY_MS = 25;\n\nfunction isNodeError(cause: unknown): cause is NodeJS.ErrnoException {\n\treturn cause instanceof Error && \"code\" in cause;\n}\n\nfunction delay(milliseconds: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\nexport async function createSessionFile(filePath: string, header: SessionHeader): Promise<void> {\n\tconst headerSnapshot = structuredClone(header);\n\ttry {\n\t\tdecodeHeader(headerSnapshot, filePath);\n\t\tawait mkdir(dirname(filePath), { recursive: true });\n\t\tconst handle = await open(filePath, \"wx\");\n\t\ttry {\n\t\t\tawait handle.writeFile(`${JSON.stringify(headerSnapshot)}\\n`, \"utf8\");\n\t\t} finally {\n\t\t\tawait handle.close();\n\t\t}\n\t} catch (cause) {\n\t\tif (cause instanceof SessionWriteError) throw cause;\n\t\tthrow new SessionWriteError(\"CREATE_FAILED\", filePath, `Failed to create session file \"${filePath}\".`, {\n\t\t\tcause,\n\t\t});\n\t}\n}\n\nasync function acquireLock(filePath: string, options: SessionAppendOptions) {\n\tconst lockPath = `${filePath}.lock`;\n\tconst timeout = options.lockTimeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS;\n\tconst retry = options.lockRetryMs ?? DEFAULT_LOCK_RETRY_MS;\n\tconst now = options.now ?? Date.now;\n\tconst sleep = options.sleep ?? delay;\n\tconst startedAt = now();\n\n\twhile (true) {\n\t\ttry {\n\t\t\treturn { handle: await open(lockPath, \"wx\"), lockPath };\n\t\t} catch (cause) {\n\t\t\tif (!isNodeError(cause) || cause.code !== \"EEXIST\") {\n\t\t\t\tthrow new SessionWriteError(\"APPEND_FAILED\", filePath, `Failed to acquire session lock for \"${filePath}\".`, {\n\t\t\t\t\tcause,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (now() - startedAt >= timeout) {\n\t\t\t\tthrow new SessionWriteError(\"LOCK_TIMEOUT\", filePath, `Timed out waiting for session lock \"${lockPath}\".`, {\n\t\t\t\t\tcause,\n\t\t\t\t});\n\t\t\t}\n\t\t\tawait sleep(retry);\n\t\t}\n\t}\n}\n\nasync function releaseLock(handle: Awaited<ReturnType<typeof open>>, lockPath: string): Promise<void> {\n\tlet closeError: unknown;\n\ttry {\n\t\tawait handle.close();\n\t} catch (cause) {\n\t\tcloseError = cause;\n\t}\n\n\ttry {\n\t\tawait unlink(lockPath);\n\t} catch (cause) {\n\t\tif (!isNodeError(cause) || cause.code !== \"ENOENT\") throw cause;\n\t}\n\n\tif (closeError !== undefined) throw closeError;\n}\n\nexport async function appendSessionEntry(\n\tfilePath: string,\n\tentry: SessionEntry,\n\texpectedParentId: string,\n\toptions: SessionAppendOptions = {},\n): Promise<void> {\n\tconst entrySnapshot = structuredClone(entry);\n\tconst decodedEntry = decodeSessionEntry(entrySnapshot);\n\tif (!decodedEntry.entry) {\n\t\tthrow new SessionWriteError(\n\t\t\t\"APPEND_FAILED\",\n\t\t\tfilePath,\n\t\t\t`Refusing to append an invalid session entry to \"${filePath}\": ${decodedEntry.reason ?? \"invalid record\"}.`,\n\t\t);\n\t}\n\tconst { handle, lockPath } = await acquireLock(filePath, options);\n\tlet operationError: unknown;\n\ttry {\n\t\tconst loaded = await loadSessionFile(filePath);\n\t\tif (loaded.diagnostics.length > 0) {\n\t\t\tthrow new SessionWriteError(\n\t\t\t\t\"CORRUPT_SESSION\",\n\t\t\t\tfilePath,\n\t\t\t\t`Refusing to append to a session with recovery diagnostics: \"${filePath}\".`,\n\t\t\t);\n\t\t}\n\n\t\tconst entriesById = new Map(loaded.entries.map((existing) => [existing.id, existing] as const));\n\t\tif (\n\t\t\tentrySnapshot.type === \"summary\" &&\n\t\t\t(entriesById.get(entrySnapshot.firstKeptEntryId)?.type !== \"message\" ||\n\t\t\t\t!isAncestor(expectedParentId, entrySnapshot.firstKeptEntryId, entriesById, loaded.header.id))\n\t\t) {\n\t\t\tthrow new SessionWriteError(\n\t\t\t\t\"APPEND_FAILED\",\n\t\t\t\tfilePath,\n\t\t\t\t`Refusing to append a summary with an invalid firstKeptEntryId to \"${filePath}\".`,\n\t\t\t);\n\t\t}\n\t\tif (loaded.header.id === entrySnapshot.id || loaded.entries.some((existing) => existing.id === entrySnapshot.id)) {\n\t\t\tthrow new SessionWriteError(\n\t\t\t\t\"APPEND_FAILED\",\n\t\t\t\tfilePath,\n\t\t\t\t`Refusing to append a duplicate session record id to \"${filePath}\".`,\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tentrySnapshot.parentId !== expectedParentId ||\n\t\t\t(expectedParentId !== loaded.header.id && !entriesById.has(expectedParentId))\n\t\t) {\n\t\t\tthrow new SessionWriteError(\n\t\t\t\t\"CONCURRENT_MODIFICATION\",\n\t\t\t\tfilePath,\n\t\t\t\t`Session parent is no longer available in \"${filePath}\".`,\n\t\t\t\t{ expectedParentId },\n\t\t\t);\n\t\t}\n\n\t\tawait appendFile(filePath, `${JSON.stringify(entrySnapshot)}\\n`, \"utf8\");\n\t} catch (cause) {\n\t\toperationError = cause;\n\t} finally {\n\t\ttry {\n\t\t\tawait releaseLock(handle, lockPath);\n\t\t} catch (cause) {\n\t\t\toperationError ??= new SessionWriteError(\n\t\t\t\t\"APPEND_FAILED\",\n\t\t\t\tfilePath,\n\t\t\t\t`Failed to release session lock for \"${filePath}\".`,\n\t\t\t\t{ cause },\n\t\t\t);\n\t\t}\n\t}\n\n\tif (operationError !== undefined) {\n\t\tif (operationError instanceof SessionWriteError) {\n\t\t\tthrow operationError;\n\t\t}\n\t\tif (operationError instanceof SessionLoadError) {\n\t\t\tconst code = operationError.code === \"READ_FAILED\" ? \"APPEND_FAILED\" : \"CORRUPT_SESSION\";\n\t\t\tthrow new SessionWriteError(code, filePath, `Unable to load session before append: \"${filePath}\".`, {\n\t\t\t\tcause: operationError,\n\t\t\t});\n\t\t}\n\t\tthrow new SessionWriteError(\"APPEND_FAILED\", filePath, `Failed to append session entry to \"${filePath}\".`, {\n\t\t\tcause: operationError,\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"session-storage.js","sourceRoot":"","sources":["../../../src/core/session/session-storage.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFile, mkdir, open, readFile, unlink } from \"node:fs/promises\";\nimport { dirname, posix, win32 } from \"node:path\";\nimport type { AssistantContent, AssistantMessage, Message, ToolResultContent, Usage, UserContent } from \"@di-code/ai\";\nimport {\n\ttype LoadedSession,\n\tSESSION_FORMAT_VERSION,\n\ttype SessionEntry,\n\ttype SessionHeader,\n\tSessionLoadError,\n\ttype SessionMessageEntry,\n\ttype SessionPluginEntry,\n\ttype SessionSummaryEntry,\n\tSessionWriteError,\n} from \"./types.ts\";\n\ntype JsonObject = Record<string, unknown>;\n\nfunction isObject(value: unknown): value is JsonObject {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.length > 0;\n}\n\nfunction isNonNegativeNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\nfunction isTimestamp(value: unknown): value is number {\n\treturn Number.isSafeInteger(value) && isNonNegativeNumber(value);\n}\n\nfunction isIsoTimestamp(value: unknown): value is string {\n\tif (typeof value !== \"string\") return false;\n\tconst milliseconds = Date.parse(value);\n\treturn Number.isFinite(milliseconds) && new Date(milliseconds).toISOString() === value;\n}\n\nfunction isRecordId(value: unknown): value is string {\n\treturn typeof value === \"string\" && /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/.test(value);\n}\n\nfunction isAbsolutePath(value: unknown): value is string {\n\treturn typeof value === \"string\" && (win32.isAbsolute(value) || posix.isAbsolute(value));\n}\n\nfunction isJsonValue(value: unknown): boolean {\n\tif (value === null || typeof value === \"string\" || typeof value === \"boolean\") return true;\n\tif (typeof value === \"number\") return Number.isFinite(value);\n\tif (Array.isArray(value)) return value.every(isJsonValue);\n\treturn isObject(value) && Object.values(value).every(isJsonValue);\n}\n\nfunction isProviderReplay(value: unknown): boolean {\n\treturn isObject(value) && isNonEmptyString(value.api) && isJsonValue(value.data);\n}\n\nfunction isImageContent(value: unknown): value is Extract<UserContent | ToolResultContent, { type: \"image\" }> {\n\treturn (\n\t\tisObject(value) && value.type === \"image\" && typeof value.data === \"string\" && isNonEmptyString(value.mimeType)\n\t);\n}\n\nfunction isTextContent(value: unknown): value is Extract<UserContent, { type: \"text\" }> {\n\treturn isObject(value) && value.type === \"text\" && typeof value.text === \"string\";\n}\n\nfunction isUserContent(value: unknown): value is UserContent {\n\treturn isTextContent(value) || isImageContent(value);\n}\n\nfunction isAssistantContent(value: unknown): value is AssistantContent {\n\tif (!isObject(value)) return false;\n\tswitch (value.type) {\n\t\tcase \"text\":\n\t\t\treturn typeof value.text === \"string\";\n\t\tcase \"thinking\":\n\t\t\treturn typeof value.thinking === \"string\";\n\t\tcase \"tool_call\":\n\t\t\treturn (\n\t\t\t\tisNonEmptyString(value.id) &&\n\t\t\t\tisNonEmptyString(value.name) &&\n\t\t\t\tisObject(value.arguments) &&\n\t\t\t\tisJsonValue(value.arguments)\n\t\t\t);\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nfunction isToolResultContent(value: unknown): value is ToolResultContent {\n\treturn isTextContent(value) || isImageContent(value);\n}\n\nfunction isUsage(value: unknown): value is Usage {\n\tif (!isObject(value) || !isObject(value.cost)) return false;\n\treturn (\n\t\tisNonNegativeNumber(value.input) &&\n\t\tisNonNegativeNumber(value.output) &&\n\t\tisNonNegativeNumber(value.cacheRead) &&\n\t\tisNonNegativeNumber(value.cacheWrite) &&\n\t\tisNonNegativeNumber(value.totalTokens) &&\n\t\tisNonNegativeNumber(value.cost.input) &&\n\t\tisNonNegativeNumber(value.cost.output) &&\n\t\tisNonNegativeNumber(value.cost.cacheRead) &&\n\t\tisNonNegativeNumber(value.cost.cacheWrite) &&\n\t\tisNonNegativeNumber(value.cost.total)\n\t);\n}\n\nfunction isAssistantMessage(value: JsonObject): value is JsonObject & AssistantMessage {\n\tif (\n\t\tvalue.role !== \"assistant\" ||\n\t\t!Array.isArray(value.content) ||\n\t\t!value.content.every(isAssistantContent) ||\n\t\t!isNonEmptyString(value.provider) ||\n\t\t!isNonEmptyString(value.model) ||\n\t\t(value.providerReplay !== undefined && !isProviderReplay(value.providerReplay)) ||\n\t\t!isUsage(value.usage) ||\n\t\t!isTimestamp(value.timestamp)\n\t) {\n\t\treturn false;\n\t}\n\n\tif (value.stopReason === \"stop\" || value.stopReason === \"length\" || value.stopReason === \"tool_use\") {\n\t\treturn value.errorMessage === undefined;\n\t}\n\tif (value.stopReason === \"error\" || value.stopReason === \"aborted\") {\n\t\treturn typeof value.errorMessage === \"string\";\n\t}\n\treturn false;\n}\n\nfunction isMessage(value: unknown): value is Message {\n\tif (!isObject(value) || !isTimestamp(value.timestamp)) return false;\n\n\tswitch (value.role) {\n\t\tcase \"user\":\n\t\t\treturn Array.isArray(value.content) && value.content.every(isUserContent);\n\t\tcase \"assistant\":\n\t\t\treturn isAssistantMessage(value);\n\t\tcase \"tool_result\":\n\t\t\treturn (\n\t\t\t\tisNonEmptyString(value.toolCallId) &&\n\t\t\t\tisNonEmptyString(value.toolName) &&\n\t\t\t\tArray.isArray(value.content) &&\n\t\t\t\tvalue.content.every(isToolResultContent) &&\n\t\t\t\t(value.details === undefined || isJsonValue(value.details)) &&\n\t\t\t\ttypeof value.isError === \"boolean\"\n\t\t\t);\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nfunction decodeHeader(value: unknown, filePath: string): SessionHeader {\n\tif (!isObject(value) || value.type !== \"session\") {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Invalid session header in \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t});\n\t}\n\tif (!(\"version\" in value)) {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Session header has no version in \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t});\n\t}\n\tif (value.version !== SESSION_FORMAT_VERSION) {\n\t\tthrow new SessionLoadError(\n\t\t\t\"UNSUPPORTED_VERSION\",\n\t\t\tfilePath,\n\t\t\t`Unsupported session version ${JSON.stringify(value.version)} in \"${filePath}\".`,\n\t\t\t{ lineNumber: 1 },\n\t\t);\n\t}\n\tif (\n\t\t!isRecordId(value.id) ||\n\t\tvalue.parentId !== null ||\n\t\t!isIsoTimestamp(value.timestamp) ||\n\t\t!isAbsolutePath(value.cwd)\n\t) {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Invalid session header fields in \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t});\n\t}\n\treturn value as unknown as SessionHeader;\n}\n\nfunction decodeSessionEntry(value: unknown): { readonly entry?: SessionEntry; readonly reason?: string } {\n\tif (!isObject(value) || (value.type !== \"message\" && value.type !== \"summary\" && value.type !== \"plugin\")) {\n\t\treturn { reason: 'record type must be \"message\", \"summary\", or \"plugin\"' };\n\t}\n\tif (value.version !== SESSION_FORMAT_VERSION) return { reason: `record version must be ${SESSION_FORMAT_VERSION}` };\n\tif (!isRecordId(value.id)) return { reason: \"record id is invalid\" };\n\tif (!isRecordId(value.parentId)) return { reason: \"record parentId is invalid\" };\n\tif (!isIsoTimestamp(value.timestamp)) return { reason: \"record timestamp is not canonical ISO 8601 UTC\" };\n\tif (value.type === \"message\") {\n\t\tif (!isMessage(value.message)) return { reason: \"record message does not match the Message contract\" };\n\t\treturn { entry: value as unknown as SessionMessageEntry };\n\t}\n\tif (value.type === \"plugin\") {\n\t\tif (\n\t\t\ttypeof value.pluginId !== \"string\" ||\n\t\t\tvalue.pluginId.length === 0 ||\n\t\t\ttypeof value.pluginVersion !== \"string\" ||\n\t\t\tvalue.pluginVersion.length === 0 ||\n\t\t\ttypeof value.schemaVersion !== \"number\" ||\n\t\t\t!Number.isSafeInteger(value.schemaVersion) ||\n\t\t\tvalue.schemaVersion < 0 ||\n\t\t\t!isJsonValue(value.data)\n\t\t)\n\t\t\treturn { reason: \"record plugin fields are invalid\" };\n\t\treturn { entry: value as unknown as SessionPluginEntry };\n\t}\n\tif (typeof value.summary !== \"string\" || value.summary.trim().length === 0) {\n\t\treturn { reason: \"record summary must be a non-empty string\" };\n\t}\n\tif (!isRecordId(value.firstKeptEntryId)) return { reason: \"record firstKeptEntryId is invalid\" };\n\tif (!Number.isSafeInteger(value.tokensBefore) || !isNonNegativeNumber(value.tokensBefore)) {\n\t\treturn { reason: \"record tokensBefore must be a non-negative safe integer\" };\n\t}\n\treturn { entry: value as unknown as SessionSummaryEntry };\n}\n\nfunction withoutTrailingCarriageReturn(line: string): string {\n\treturn line.endsWith(\"\\r\") ? line.slice(0, -1) : line;\n}\n\nfunction errorText(cause: unknown): string {\n\treturn cause instanceof Error ? cause.message : String(cause);\n}\n\nexport async function loadSessionFile(filePath: string): Promise<LoadedSession> {\n\tlet content: string;\n\ttry {\n\t\tcontent = await readFile(filePath, \"utf8\");\n\t} catch (cause) {\n\t\tthrow new SessionLoadError(\"READ_FAILED\", filePath, `Failed to read session file \"${filePath}\".`, { cause });\n\t}\n\n\tconst physicalLines = content.split(\"\\n\");\n\tlet partialLineNumber: number | undefined;\n\tif (content.endsWith(\"\\n\")) {\n\t\tphysicalLines.pop();\n\t} else {\n\t\tphysicalLines.pop();\n\t\tpartialLineNumber = physicalLines.length + 1;\n\t}\n\n\tif (physicalLines.length === 0) {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Session file has no committed header: \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t});\n\t}\n\n\tlet headerValue: unknown;\n\ttry {\n\t\theaderValue = JSON.parse(withoutTrailingCarriageReturn(physicalLines[0] ?? \"\")) as unknown;\n\t} catch (cause) {\n\t\tthrow new SessionLoadError(\"INVALID_HEADER\", filePath, `Session header is not valid JSON in \"${filePath}\".`, {\n\t\t\tlineNumber: 1,\n\t\t\tcause,\n\t\t});\n\t}\n\n\tconst header = decodeHeader(headerValue, filePath);\n\tconst entries: SessionEntry[] = [];\n\tconst diagnostics: LoadedSession[\"diagnostics\"][number][] = [];\n\tconst seenIds = new Set<string>([header.id]);\n\tconst entriesById = new Map<string, SessionEntry>();\n\n\tfor (let index = 1; index < physicalLines.length; index++) {\n\t\tconst lineNumber = index + 1;\n\t\ttry {\n\t\t\tconst value = JSON.parse(withoutTrailingCarriageReturn(physicalLines[index] ?? \"\")) as unknown;\n\t\t\tconst decoded = decodeSessionEntry(value);\n\t\t\tif (!decoded.entry) throw new Error(decoded.reason ?? \"Invalid session message record.\");\n\t\t\tif (seenIds.has(decoded.entry.id)) throw new Error(\"record id is duplicated\");\n\t\t\tif (!seenIds.has(decoded.entry.parentId)) throw new Error(\"record parentId must reference an earlier record\");\n\t\t\tif (decoded.entry.type === \"summary\") {\n\t\t\t\tconst firstKept = entriesById.get(decoded.entry.firstKeptEntryId);\n\t\t\t\tif (\n\t\t\t\t\tfirstKept?.type !== \"message\" ||\n\t\t\t\t\t!isAncestor(decoded.entry.parentId, firstKept.id, entriesById, header.id)\n\t\t\t\t) {\n\t\t\t\t\tthrow new Error(\"record firstKeptEntryId must reference an earlier message on the summary branch\");\n\t\t\t\t}\n\t\t\t}\n\t\t\tentries.push(decoded.entry);\n\t\t\tseenIds.add(decoded.entry.id);\n\t\t\tentriesById.set(decoded.entry.id, decoded.entry);\n\t\t} catch (cause) {\n\t\t\tdiagnostics.push({ kind: \"corrupt_record\", lineNumber, reason: errorText(cause) });\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (diagnostics.length === 0 && partialLineNumber !== undefined) {\n\t\tdiagnostics.push({\n\t\t\tkind: \"trailing_partial_line\",\n\t\t\tlineNumber: partialLineNumber,\n\t\t\treason: \"final line has no newline commit marker\",\n\t\t});\n\t}\n\n\treturn {\n\t\theader,\n\t\tentries,\n\t\tmessages: entries\n\t\t\t.filter((entry): entry is SessionMessageEntry => entry.type === \"message\")\n\t\t\t.map((entry) => entry.message),\n\t\tdiagnostics,\n\t};\n}\n\nfunction isAncestor(\n\tleafId: string,\n\tancestorId: string,\n\tentriesById: ReadonlyMap<string, SessionEntry>,\n\theaderId: string,\n): boolean {\n\tlet currentId = leafId;\n\twhile (currentId !== headerId) {\n\t\tif (currentId === ancestorId) return true;\n\t\tconst current = entriesById.get(currentId);\n\t\tif (!current) return false;\n\t\tcurrentId = current.parentId;\n\t}\n\treturn false;\n}\n\nexport interface SessionAppendOptions {\n\treadonly lockTimeoutMs?: number;\n\treadonly lockRetryMs?: number;\n\treadonly now?: () => number;\n\treadonly sleep?: (milliseconds: number) => Promise<void>;\n}\n\nconst DEFAULT_LOCK_TIMEOUT_MS = 5_000;\nconst DEFAULT_LOCK_RETRY_MS = 25;\n\nfunction isNodeError(cause: unknown): cause is NodeJS.ErrnoException {\n\treturn cause instanceof Error && \"code\" in cause;\n}\n\nfunction delay(milliseconds: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, milliseconds));\n}\n\nexport async function createSessionFile(filePath: string, header: SessionHeader): Promise<void> {\n\tconst headerSnapshot = structuredClone(header);\n\ttry {\n\t\tdecodeHeader(headerSnapshot, filePath);\n\t\tawait mkdir(dirname(filePath), { recursive: true });\n\t\tconst handle = await open(filePath, \"wx\");\n\t\ttry {\n\t\t\tawait handle.writeFile(`${JSON.stringify(headerSnapshot)}\\n`, \"utf8\");\n\t\t} finally {\n\t\t\tawait handle.close();\n\t\t}\n\t} catch (cause) {\n\t\tif (cause instanceof SessionWriteError) throw cause;\n\t\tthrow new SessionWriteError(\"CREATE_FAILED\", filePath, `Failed to create session file \"${filePath}\".`, {\n\t\t\tcause,\n\t\t});\n\t}\n}\n\nasync function acquireLock(filePath: string, options: SessionAppendOptions) {\n\tconst lockPath = `${filePath}.lock`;\n\tconst timeout = options.lockTimeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS;\n\tconst retry = options.lockRetryMs ?? DEFAULT_LOCK_RETRY_MS;\n\tconst now = options.now ?? Date.now;\n\tconst sleep = options.sleep ?? delay;\n\tconst startedAt = now();\n\n\twhile (true) {\n\t\ttry {\n\t\t\treturn { handle: await open(lockPath, \"wx\"), lockPath };\n\t\t} catch (cause) {\n\t\t\t// Windows can report EPERM/EACCES while another process closes or removes the lock file.\n\t\t\t// Treat that brief transition as contention so a writer does not fail merely because the lock vanished.\n\t\t\tconst lockBusy =\n\t\t\t\tisNodeError(cause) &&\n\t\t\t\t(cause.code === \"EEXIST\" ||\n\t\t\t\t\t(process.platform === \"win32\" && (cause.code === \"EPERM\" || cause.code === \"EACCES\")));\n\t\t\tif (!lockBusy) {\n\t\t\t\tthrow new SessionWriteError(\"APPEND_FAILED\", filePath, `Failed to acquire session lock for \"${filePath}\".`, {\n\t\t\t\t\tcause,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (now() - startedAt >= timeout) {\n\t\t\t\tthrow new SessionWriteError(\"LOCK_TIMEOUT\", filePath, `Timed out waiting for session lock \"${lockPath}\".`, {\n\t\t\t\t\tcause,\n\t\t\t\t});\n\t\t\t}\n\t\t\tawait sleep(retry);\n\t\t}\n\t}\n}\n\nasync function releaseLock(handle: Awaited<ReturnType<typeof open>>, lockPath: string): Promise<void> {\n\tlet closeError: unknown;\n\ttry {\n\t\tawait handle.close();\n\t} catch (cause) {\n\t\tcloseError = cause;\n\t}\n\n\ttry {\n\t\tawait unlink(lockPath);\n\t} catch (cause) {\n\t\tif (!isNodeError(cause) || cause.code !== \"ENOENT\") throw cause;\n\t}\n\n\tif (closeError !== undefined) throw closeError;\n}\n\nexport async function appendSessionEntry(\n\tfilePath: string,\n\tentry: SessionEntry,\n\texpectedParentId: string,\n\toptions: SessionAppendOptions = {},\n): Promise<void> {\n\tconst entrySnapshot = structuredClone(entry);\n\tconst decodedEntry = decodeSessionEntry(entrySnapshot);\n\tif (!decodedEntry.entry) {\n\t\tthrow new SessionWriteError(\n\t\t\t\"APPEND_FAILED\",\n\t\t\tfilePath,\n\t\t\t`Refusing to append an invalid session entry to \"${filePath}\": ${decodedEntry.reason ?? \"invalid record\"}.`,\n\t\t);\n\t}\n\tconst { handle, lockPath } = await acquireLock(filePath, options);\n\tlet operationError: unknown;\n\ttry {\n\t\tconst loaded = await loadSessionFile(filePath);\n\t\tif (loaded.diagnostics.length > 0) {\n\t\t\tthrow new SessionWriteError(\n\t\t\t\t\"CORRUPT_SESSION\",\n\t\t\t\tfilePath,\n\t\t\t\t`Refusing to append to a session with recovery diagnostics: \"${filePath}\".`,\n\t\t\t);\n\t\t}\n\n\t\tconst entriesById = new Map(loaded.entries.map((existing) => [existing.id, existing] as const));\n\t\tif (\n\t\t\tentrySnapshot.type === \"summary\" &&\n\t\t\t(entriesById.get(entrySnapshot.firstKeptEntryId)?.type !== \"message\" ||\n\t\t\t\t!isAncestor(expectedParentId, entrySnapshot.firstKeptEntryId, entriesById, loaded.header.id))\n\t\t) {\n\t\t\tthrow new SessionWriteError(\n\t\t\t\t\"APPEND_FAILED\",\n\t\t\t\tfilePath,\n\t\t\t\t`Refusing to append a summary with an invalid firstKeptEntryId to \"${filePath}\".`,\n\t\t\t);\n\t\t}\n\t\tif (loaded.header.id === entrySnapshot.id || loaded.entries.some((existing) => existing.id === entrySnapshot.id)) {\n\t\t\tthrow new SessionWriteError(\n\t\t\t\t\"APPEND_FAILED\",\n\t\t\t\tfilePath,\n\t\t\t\t`Refusing to append a duplicate session record id to \"${filePath}\".`,\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tentrySnapshot.parentId !== expectedParentId ||\n\t\t\t(expectedParentId !== loaded.header.id && !entriesById.has(expectedParentId))\n\t\t) {\n\t\t\tthrow new SessionWriteError(\n\t\t\t\t\"CONCURRENT_MODIFICATION\",\n\t\t\t\tfilePath,\n\t\t\t\t`Session parent is no longer available in \"${filePath}\".`,\n\t\t\t\t{ expectedParentId },\n\t\t\t);\n\t\t}\n\n\t\tawait appendFile(filePath, `${JSON.stringify(entrySnapshot)}\\n`, \"utf8\");\n\t} catch (cause) {\n\t\toperationError = cause;\n\t} finally {\n\t\ttry {\n\t\t\tawait releaseLock(handle, lockPath);\n\t\t} catch (cause) {\n\t\t\toperationError ??= new SessionWriteError(\n\t\t\t\t\"APPEND_FAILED\",\n\t\t\t\tfilePath,\n\t\t\t\t`Failed to release session lock for \"${filePath}\".`,\n\t\t\t\t{ cause },\n\t\t\t);\n\t\t}\n\t}\n\n\tif (operationError !== undefined) {\n\t\tif (operationError instanceof SessionWriteError) {\n\t\t\tthrow operationError;\n\t\t}\n\t\tif (operationError instanceof SessionLoadError) {\n\t\t\tconst code = operationError.code === \"READ_FAILED\" ? \"APPEND_FAILED\" : \"CORRUPT_SESSION\";\n\t\t\tthrow new SessionWriteError(code, filePath, `Unable to load session before append: \"${filePath}\".`, {\n\t\t\t\tcause: operationError,\n\t\t\t});\n\t\t}\n\t\tthrow new SessionWriteError(\"APPEND_FAILED\", filePath, `Failed to append session entry to \"${filePath}\".`, {\n\t\t\tcause: operationError,\n\t\t});\n\t}\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { Message } from "@di-code/ai";
1
+ import type { JsonValue, Message } from "@di-code/ai";
2
2
  export declare const SESSION_FORMAT_VERSION: 2;
3
3
  export interface SessionRecordBase {
4
4
  readonly version: typeof SESSION_FORMAT_VERSION;
@@ -23,7 +23,16 @@ export interface SessionSummaryEntry extends SessionRecordBase {
23
23
  readonly firstKeptEntryId: string;
24
24
  readonly tokensBefore: number;
25
25
  }
26
- export type SessionEntry = SessionMessageEntry | SessionSummaryEntry;
26
+ /** Plugin-private records are retained verbatim so newer plugins survive older readers. */
27
+ export interface SessionPluginEntry extends SessionRecordBase {
28
+ readonly type: "plugin";
29
+ readonly parentId: string;
30
+ readonly pluginId: string;
31
+ readonly pluginVersion: string;
32
+ readonly schemaVersion: number;
33
+ readonly data: JsonValue;
34
+ }
35
+ export type SessionEntry = SessionMessageEntry | SessionSummaryEntry | SessionPluginEntry;
27
36
  /** An immutable entry snapshot with its append-ordered descendants. */
28
37
  export interface SessionTreeNode {
29
38
  readonly entry: SessionEntry;