@code-yeongyu/senpi-agent-core 2026.8.12 → 2026.8.13

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 (153) hide show
  1. package/README.md +13 -7
  2. package/dist/agent-loop.js +5 -1
  3. package/dist/agent-loop.js.map +1 -1
  4. package/dist/agent.d.ts +3 -1
  5. package/dist/agent.d.ts.map +1 -1
  6. package/dist/agent.js +8 -0
  7. package/dist/agent.js.map +1 -1
  8. package/dist/harness/agent-harness.d.ts +452 -96
  9. package/dist/harness/agent-harness.d.ts.map +1 -1
  10. package/dist/harness/agent-harness.js +162 -1005
  11. package/dist/harness/agent-harness.js.map +1 -1
  12. package/dist/harness/compaction/branch-summarization.d.ts +13 -6
  13. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  14. package/dist/harness/compaction/branch-summarization.js +10 -14
  15. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  16. package/dist/harness/compaction/compaction.d.ts +14 -17
  17. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  18. package/dist/harness/compaction/compaction.js +23 -36
  19. package/dist/harness/compaction/compaction.js.map +1 -1
  20. package/dist/harness/env/nodejs.d.ts +1 -0
  21. package/dist/harness/env/nodejs.d.ts.map +1 -1
  22. package/dist/harness/env/nodejs.js +23 -7
  23. package/dist/harness/env/nodejs.js.map +1 -1
  24. package/dist/harness/messages.d.ts +3 -3
  25. package/dist/harness/messages.d.ts.map +1 -1
  26. package/dist/harness/messages.js +3 -3
  27. package/dist/harness/messages.js.map +1 -1
  28. package/dist/harness/prompt-templates.d.ts.map +1 -1
  29. package/dist/harness/prompt-templates.js +4 -9
  30. package/dist/harness/prompt-templates.js.map +1 -1
  31. package/dist/harness/reducer.d.ts +100 -0
  32. package/dist/harness/reducer.d.ts.map +1 -0
  33. package/dist/harness/reducer.js +414 -0
  34. package/dist/harness/reducer.js.map +1 -0
  35. package/dist/harness/result.d.ts +40 -0
  36. package/dist/harness/result.d.ts.map +1 -0
  37. package/dist/harness/result.js +41 -0
  38. package/dist/harness/result.js.map +1 -0
  39. package/dist/harness/session/context.d.ts +22 -0
  40. package/dist/harness/session/context.d.ts.map +1 -0
  41. package/dist/harness/session/context.js +67 -0
  42. package/dist/harness/session/context.js.map +1 -0
  43. package/dist/harness/session/index.d.ts +7 -0
  44. package/dist/harness/session/index.d.ts.map +1 -0
  45. package/dist/harness/session/index.js +6 -0
  46. package/dist/harness/session/index.js.map +1 -0
  47. package/dist/harness/session/jsonl/codec.d.ts +8 -0
  48. package/dist/harness/session/jsonl/codec.d.ts.map +1 -0
  49. package/dist/harness/session/jsonl/codec.js +190 -0
  50. package/dist/harness/session/jsonl/codec.js.map +1 -0
  51. package/dist/harness/session/jsonl/errors.d.ts +5 -0
  52. package/dist/harness/session/jsonl/errors.d.ts.map +1 -0
  53. package/dist/harness/session/jsonl/errors.js +11 -0
  54. package/dist/harness/session/jsonl/errors.js.map +1 -0
  55. package/dist/harness/session/jsonl/repo.d.ts +23 -0
  56. package/dist/harness/session/jsonl/repo.d.ts.map +1 -0
  57. package/dist/harness/session/jsonl/repo.js +129 -0
  58. package/dist/harness/session/jsonl/repo.js.map +1 -0
  59. package/dist/harness/session/jsonl/storage.d.ts +43 -0
  60. package/dist/harness/session/jsonl/storage.d.ts.map +1 -0
  61. package/dist/harness/session/jsonl/storage.js +206 -0
  62. package/dist/harness/session/jsonl/storage.js.map +1 -0
  63. package/dist/harness/session/jsonl/types.d.ts +38 -0
  64. package/dist/harness/session/jsonl/types.d.ts.map +1 -0
  65. package/dist/harness/session/jsonl/types.js +2 -0
  66. package/dist/harness/session/jsonl/types.js.map +1 -0
  67. package/dist/harness/session/jsonl.d.ts +3 -0
  68. package/dist/harness/session/jsonl.d.ts.map +1 -0
  69. package/dist/harness/session/jsonl.js +2 -0
  70. package/dist/harness/session/jsonl.js.map +1 -0
  71. package/dist/harness/session/memory.d.ts +44 -0
  72. package/dist/harness/session/memory.d.ts.map +1 -0
  73. package/dist/harness/session/memory.js +142 -0
  74. package/dist/harness/session/memory.js.map +1 -0
  75. package/dist/harness/session/search.d.ts +19 -0
  76. package/dist/harness/session/search.d.ts.map +1 -0
  77. package/dist/harness/session/search.js +41 -0
  78. package/dist/harness/session/search.js.map +1 -0
  79. package/dist/harness/session/session.d.ts +43 -38
  80. package/dist/harness/session/session.d.ts.map +1 -1
  81. package/dist/harness/session/session.js +186 -304
  82. package/dist/harness/session/session.js.map +1 -1
  83. package/dist/harness/session/state.d.ts +65 -0
  84. package/dist/harness/session/state.d.ts.map +1 -0
  85. package/dist/harness/session/state.js +320 -0
  86. package/dist/harness/session/state.js.map +1 -0
  87. package/dist/harness/session/testing/conformance.d.ts +4 -0
  88. package/dist/harness/session/testing/conformance.d.ts.map +1 -0
  89. package/dist/harness/session/testing/conformance.js +743 -0
  90. package/dist/harness/session/testing/conformance.js.map +1 -0
  91. package/dist/harness/session/testing/index.d.ts +3 -0
  92. package/dist/harness/session/testing/index.d.ts.map +1 -0
  93. package/dist/harness/session/testing/index.js +2 -0
  94. package/dist/harness/session/testing/index.js.map +1 -0
  95. package/dist/harness/session/testing/types.d.ts +14 -0
  96. package/dist/harness/session/testing/types.d.ts.map +1 -0
  97. package/dist/harness/session/testing/types.js +2 -0
  98. package/dist/harness/session/testing/types.js.map +1 -0
  99. package/dist/harness/session/types.d.ts +333 -0
  100. package/dist/harness/session/types.d.ts.map +1 -0
  101. package/dist/harness/session/types.js +9 -0
  102. package/dist/harness/session/types.js.map +1 -0
  103. package/dist/harness/skills.js +21 -19
  104. package/dist/harness/skills.js.map +1 -1
  105. package/dist/harness/telemetry.d.ts +1221 -0
  106. package/dist/harness/telemetry.d.ts.map +1 -0
  107. package/dist/harness/telemetry.js +508 -0
  108. package/dist/harness/telemetry.js.map +1 -0
  109. package/dist/harness/types.d.ts +8 -485
  110. package/dist/harness/types.d.ts.map +1 -1
  111. package/dist/harness/types.js +4 -16
  112. package/dist/harness/types.js.map +1 -1
  113. package/dist/harness/utils/truncate.js.map +1 -1
  114. package/dist/index.d.ts +10 -9
  115. package/dist/index.d.ts.map +1 -1
  116. package/dist/index.js +7 -8
  117. package/dist/index.js.map +1 -1
  118. package/dist/proxy.d.ts +1 -1
  119. package/dist/proxy.d.ts.map +1 -1
  120. package/dist/proxy.js +1 -0
  121. package/dist/proxy.js.map +1 -1
  122. package/dist/types.d.ts +6 -0
  123. package/dist/types.d.ts.map +1 -1
  124. package/dist/types.js.map +1 -1
  125. package/package.json +9 -2
  126. package/dist/harness/session/array-session-reader.d.ts +0 -3
  127. package/dist/harness/session/array-session-reader.d.ts.map +0 -1
  128. package/dist/harness/session/array-session-reader.js +0 -70
  129. package/dist/harness/session/array-session-reader.js.map +0 -1
  130. package/dist/harness/session/fork.d.ts +0 -4
  131. package/dist/harness/session/fork.d.ts.map +0 -1
  132. package/dist/harness/session/fork.js +0 -22
  133. package/dist/harness/session/fork.js.map +0 -1
  134. package/dist/harness/session/jsonl-store.d.ts +0 -13
  135. package/dist/harness/session/jsonl-store.d.ts.map +0 -1
  136. package/dist/harness/session/jsonl-store.js +0 -304
  137. package/dist/harness/session/jsonl-store.js.map +0 -1
  138. package/dist/harness/session/keyed-operation-queue.d.ts +0 -17
  139. package/dist/harness/session/keyed-operation-queue.d.ts.map +0 -1
  140. package/dist/harness/session/keyed-operation-queue.js +0 -60
  141. package/dist/harness/session/keyed-operation-queue.js.map +0 -1
  142. package/dist/harness/session/memory-store.d.ts +0 -6
  143. package/dist/harness/session/memory-store.d.ts.map +0 -1
  144. package/dist/harness/session/memory-store.js +0 -107
  145. package/dist/harness/session/memory-store.js.map +0 -1
  146. package/dist/harness/session/repository.d.ts +0 -28
  147. package/dist/harness/session/repository.d.ts.map +0 -1
  148. package/dist/harness/session/repository.js +0 -61
  149. package/dist/harness/session/repository.js.map +0 -1
  150. package/dist/harness/session/search-backend.d.ts +0 -8
  151. package/dist/harness/session/search-backend.d.ts.map +0 -1
  152. package/dist/harness/session/search-backend.js +0 -22
  153. package/dist/harness/session/search-backend.js.map +0 -1
@@ -0,0 +1,67 @@
1
+ import { createBranchSummaryMessage, createCompactionSummaryMessage } from "../messages.js";
2
+ function deriveSessionContextState(pathEntries) {
3
+ let thinkingLevel = "off";
4
+ let model = null;
5
+ let activeToolNames = null;
6
+ for (const entry of pathEntries) {
7
+ if (entry.type === "thinking_level_change") {
8
+ thinkingLevel = entry.thinkingLevel;
9
+ }
10
+ else if (entry.type === "model_change") {
11
+ model = { provider: entry.provider, modelId: entry.modelId };
12
+ }
13
+ else if (entry.type === "message" && entry.message.role === "assistant") {
14
+ model = { provider: entry.message.provider, modelId: entry.message.model };
15
+ }
16
+ else if (entry.type === "active_tools_change") {
17
+ activeToolNames = [...entry.activeToolNames];
18
+ }
19
+ }
20
+ return { thinkingLevel, model, activeToolNames };
21
+ }
22
+ export function defaultContextEntryTransform(pathEntries) {
23
+ let compaction;
24
+ let compactionIndex = -1;
25
+ for (let index = pathEntries.length - 1; index >= 0; index--) {
26
+ const entry = pathEntries[index];
27
+ if (entry.type === "compaction") {
28
+ compaction = entry;
29
+ compactionIndex = index;
30
+ break;
31
+ }
32
+ }
33
+ return compaction === undefined ? [...pathEntries] : [compaction, ...pathEntries.slice(compactionIndex + 1)];
34
+ }
35
+ export function buildContextEntries(pathEntries, options = {}) {
36
+ let entries = defaultContextEntryTransform(pathEntries);
37
+ for (const transform of options.entryTransforms ?? [])
38
+ entries = [...transform(entries)];
39
+ return entries;
40
+ }
41
+ export function sessionEntryToContextMessages(entry, index, entries, options = {}) {
42
+ if (entry.type === "message") {
43
+ if (entry.message.role === "assistant" && entry.message.stopReason === "deferred")
44
+ return [];
45
+ return [entry.message];
46
+ }
47
+ if (entry.type === "compaction") {
48
+ return [
49
+ createCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp),
50
+ ...entry.retainedTail,
51
+ ];
52
+ }
53
+ if (entry.type === "branch_summary" && entry.summary) {
54
+ return [createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp)];
55
+ }
56
+ if (entry.type === "custom") {
57
+ return [...(options.entryProjectors?.[entry.customType]?.(entry, index, entries) ?? [])];
58
+ }
59
+ return [];
60
+ }
61
+ export function buildSessionContext(pathEntries, options = {}) {
62
+ const state = deriveSessionContextState(pathEntries);
63
+ const contextEntries = buildContextEntries(pathEntries, options);
64
+ const messages = contextEntries.flatMap((entry, index) => sessionEntryToContextMessages(entry, index, contextEntries, options));
65
+ return { ...state, messages };
66
+ }
67
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/harness/session/context.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"../../types.ts\";\nimport { createBranchSummaryMessage, createCompactionSummaryMessage } from \"../messages.ts\";\nimport type { CompactionEntry, CustomEntry, Entry } from \"./types.ts\";\n\nexport interface SessionContext {\n\tmessages: AgentMessage[];\n\tthinkingLevel: string;\n\tmodel: { provider: string; modelId: string } | null;\n\tactiveToolNames: string[] | null;\n}\n\nexport type ContextEntryTransform = (entries: readonly Entry[]) => readonly Entry[];\n\nexport type CustomEntryContextMessageProjector = (\n\tentry: CustomEntry,\n\tindex: number,\n\tentries: readonly Entry[],\n) => readonly AgentMessage[] | undefined;\n\nexport interface SessionContextBuildOptions {\n\tentryTransforms?: readonly ContextEntryTransform[];\n\tentryProjectors?: Readonly<Record<string, CustomEntryContextMessageProjector>>;\n}\n\nfunction deriveSessionContextState(pathEntries: readonly Entry[]): Omit<SessionContext, \"messages\"> {\n\tlet thinkingLevel = \"off\";\n\tlet model: { provider: string; modelId: string } | null = null;\n\tlet activeToolNames: string[] | null = null;\n\n\tfor (const entry of pathEntries) {\n\t\tif (entry.type === \"thinking_level_change\") {\n\t\t\tthinkingLevel = entry.thinkingLevel;\n\t\t} else if (entry.type === \"model_change\") {\n\t\t\tmodel = { provider: entry.provider, modelId: entry.modelId };\n\t\t} else if (entry.type === \"message\" && entry.message.role === \"assistant\") {\n\t\t\tmodel = { provider: entry.message.provider, modelId: entry.message.model };\n\t\t} else if (entry.type === \"active_tools_change\") {\n\t\t\tactiveToolNames = [...entry.activeToolNames];\n\t\t}\n\t}\n\n\treturn { thinkingLevel, model, activeToolNames };\n}\n\nexport function defaultContextEntryTransform(pathEntries: readonly Entry[]): Entry[] {\n\tlet compaction: CompactionEntry | undefined;\n\tlet compactionIndex = -1;\n\tfor (let index = pathEntries.length - 1; index >= 0; index--) {\n\t\tconst entry = pathEntries[index]!;\n\t\tif (entry.type === \"compaction\") {\n\t\t\tcompaction = entry;\n\t\t\tcompactionIndex = index;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn compaction === undefined ? [...pathEntries] : [compaction, ...pathEntries.slice(compactionIndex + 1)];\n}\n\nexport function buildContextEntries(pathEntries: readonly Entry[], options: SessionContextBuildOptions = {}): Entry[] {\n\tlet entries = defaultContextEntryTransform(pathEntries);\n\tfor (const transform of options.entryTransforms ?? []) entries = [...transform(entries)];\n\treturn entries;\n}\n\nexport function sessionEntryToContextMessages(\n\tentry: Entry,\n\tindex: number,\n\tentries: readonly Entry[],\n\toptions: SessionContextBuildOptions = {},\n): AgentMessage[] {\n\tif (entry.type === \"message\") {\n\t\tif (entry.message.role === \"assistant\" && entry.message.stopReason === \"deferred\") return [];\n\t\treturn [entry.message];\n\t}\n\tif (entry.type === \"compaction\") {\n\t\treturn [\n\t\t\tcreateCompactionSummaryMessage(entry.summary, entry.tokensBefore, entry.timestamp),\n\t\t\t...entry.retainedTail,\n\t\t];\n\t}\n\tif (entry.type === \"branch_summary\" && entry.summary) {\n\t\treturn [createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp)];\n\t}\n\tif (entry.type === \"custom\") {\n\t\treturn [...(options.entryProjectors?.[entry.customType]?.(entry, index, entries) ?? [])];\n\t}\n\treturn [];\n}\n\nexport function buildSessionContext(\n\tpathEntries: readonly Entry[],\n\toptions: SessionContextBuildOptions = {},\n): SessionContext {\n\tconst state = deriveSessionContextState(pathEntries);\n\tconst contextEntries = buildContextEntries(pathEntries, options);\n\tconst messages = contextEntries.flatMap((entry, index) =>\n\t\tsessionEntryToContextMessages(entry, index, contextEntries, options),\n\t);\n\treturn { ...state, messages };\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export * from "./context.ts";
2
+ export type { JsonlSessionCreateOptions, JsonlSessionListOptions, JsonlSessionMetadata, JsonlSessionRepoFileSystem, JsonlSessionRepoOptions, JsonlV4Header, } from "./jsonl.ts";
3
+ export { JsonlSessionRepo } from "./jsonl.ts";
4
+ export * from "./memory.ts";
5
+ export * from "./session.ts";
6
+ export * from "./types.ts";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/harness/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,YAAY,EACX,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,uBAAuB,EACvB,aAAa,GACb,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from "./context.js";
2
+ export { JsonlSessionRepo } from "./jsonl.js";
3
+ export * from "./memory.js";
4
+ export * from "./session.js";
5
+ export * from "./types.js";
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/harness/session/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAS7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./context.ts\";\nexport type {\n\tJsonlSessionCreateOptions,\n\tJsonlSessionListOptions,\n\tJsonlSessionMetadata,\n\tJsonlSessionRepoFileSystem,\n\tJsonlSessionRepoOptions,\n\tJsonlV4Header,\n} from \"./jsonl.ts\";\nexport { JsonlSessionRepo } from \"./jsonl.ts\";\nexport * from \"./memory.ts\";\nexport * from \"./session.ts\";\nexport * from \"./types.ts\";\n"]}
@@ -0,0 +1,8 @@
1
+ import type { SessionMutation } from "../state.ts";
2
+ import type { JsonlSessionMetadata, JsonlV4Header } from "./types.ts";
3
+ export declare function parseHeader(line: string, path: string): JsonlV4Header;
4
+ export declare function encodeHeader(header: JsonlV4Header): string;
5
+ export declare function metadataFromHeader(header: JsonlV4Header, path: string, modifiedAt: number): JsonlSessionMetadata;
6
+ export declare function parseMutation(line: string, path: string, lineNumber: number): SessionMutation;
7
+ export declare function encodeMutation(mutation: SessionMutation): string;
8
+ //# sourceMappingURL=codec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/codec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGnD,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA6DtE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CA4BrE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAE1D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,oBAAoB,CAchH;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,eAAe,CAiE7F;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,eAAe,GAAG,MAAM,CAWhE"}
@@ -0,0 +1,190 @@
1
+ import { invalidFile } from "./errors.js";
2
+ const ENTRY_TYPES = new Set([
3
+ "message",
4
+ "model_change",
5
+ "thinking_level_change",
6
+ "active_tools_change",
7
+ "compaction",
8
+ "branch_summary",
9
+ "custom",
10
+ ]);
11
+ const RECORD_TYPES = new Set([
12
+ "operation_started",
13
+ "abort_requested",
14
+ "operation_finished",
15
+ "step_attempt",
16
+ "tool_started",
17
+ "queue_enqueued",
18
+ "queue_cancelled",
19
+ "write_deferred",
20
+ "usage",
21
+ ]);
22
+ const OPERATION_KINDS = new Set(["run", "compaction", "navigation"]);
23
+ function isObject(value) {
24
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25
+ }
26
+ function parseObject(line, path, lineNumber) {
27
+ let value;
28
+ try {
29
+ value = JSON.parse(line);
30
+ }
31
+ catch (error) {
32
+ throw invalidFile(path, lineNumber, "is not valid JSON", error instanceof Error ? error : undefined);
33
+ }
34
+ if (!isObject(value))
35
+ throw invalidFile(path, lineNumber, "is not a JSON object");
36
+ return value;
37
+ }
38
+ function requireString(value, path, line, field) {
39
+ if (typeof value !== "string")
40
+ throw invalidFile(path, line, `has invalid ${field}`);
41
+ return value;
42
+ }
43
+ function requireSequence(value, path, line) {
44
+ if (!Number.isSafeInteger(value) || value <= 0)
45
+ throw invalidFile(path, line, "has invalid seq");
46
+ return value;
47
+ }
48
+ function requireTimestamp(value, path, line) {
49
+ if (!Number.isSafeInteger(value) || value < 0)
50
+ throw invalidFile(path, line, "has invalid timestamp");
51
+ return value;
52
+ }
53
+ function requireNullableId(value, path, line, field) {
54
+ if (value !== null && typeof value !== "string") {
55
+ throw invalidFile(path, line, `has invalid ${field}`);
56
+ }
57
+ return value;
58
+ }
59
+ export function parseHeader(line, path) {
60
+ const value = parseObject(line, path, 1);
61
+ if (value.kind !== "header")
62
+ throw invalidFile(path, 1, "is not a header");
63
+ if (value.version !== 4)
64
+ throw invalidFile(path, 1, "has unsupported session version");
65
+ const parentSessionId = value.parentSessionId;
66
+ if (parentSessionId !== undefined && typeof parentSessionId !== "string") {
67
+ throw invalidFile(path, 1, "has invalid parentSessionId");
68
+ }
69
+ const legacyParentSessionPath = value.legacyParentSessionPath;
70
+ if (legacyParentSessionPath !== undefined && typeof legacyParentSessionPath !== "string") {
71
+ throw invalidFile(path, 1, "has invalid legacyParentSessionPath");
72
+ }
73
+ if (parentSessionId !== undefined && legacyParentSessionPath !== undefined) {
74
+ throw invalidFile(path, 1, "has both parentSessionId and legacyParentSessionPath");
75
+ }
76
+ const metadataValue = value.metadata;
77
+ if (metadataValue !== undefined && !isObject(metadataValue))
78
+ throw invalidFile(path, 1, "has invalid metadata");
79
+ const metadata = metadataValue;
80
+ return {
81
+ kind: "header",
82
+ version: 4,
83
+ id: requireString(value.id, path, 1, "id"),
84
+ createdAt: requireTimestamp(value.createdAt, path, 1),
85
+ cwd: requireString(value.cwd, path, 1, "cwd"),
86
+ parentSessionId,
87
+ legacyParentSessionPath,
88
+ metadata,
89
+ };
90
+ }
91
+ export function encodeHeader(header) {
92
+ return `${JSON.stringify(header)}\n`;
93
+ }
94
+ export function metadataFromHeader(header, path, modifiedAt) {
95
+ return {
96
+ id: header.id,
97
+ createdAt: header.createdAt,
98
+ cwd: header.cwd,
99
+ path,
100
+ modifiedAt,
101
+ sourceFormat: 4,
102
+ ...(header.parentSessionId === undefined ? {} : { parentSessionId: header.parentSessionId }),
103
+ ...(header.legacyParentSessionPath === undefined
104
+ ? {}
105
+ : { legacyParentSessionPath: header.legacyParentSessionPath }),
106
+ ...(header.metadata === undefined ? {} : { metadata: header.metadata }),
107
+ };
108
+ }
109
+ export function parseMutation(line, path, lineNumber) {
110
+ const value = parseObject(line, path, lineNumber);
111
+ const seq = requireSequence(value.seq, path, lineNumber);
112
+ switch (value.kind) {
113
+ case "entry": {
114
+ const lane = value.lane === undefined ? undefined : requireString(value.lane, path, lineNumber, "lane");
115
+ const id = requireString(value.id, path, lineNumber, "id");
116
+ const type = requireString(value.type, path, lineNumber, "entry type");
117
+ if (!ENTRY_TYPES.has(type))
118
+ throw invalidFile(path, lineNumber, `has unknown entry type ${type}`);
119
+ const parentId = requireNullableId(value.parentId, path, lineNumber, "parentId");
120
+ const timestamp = requireTimestamp(value.timestamp, path, lineNumber);
121
+ if (type === "custom")
122
+ requireString(value.customType, path, lineNumber, "customType");
123
+ const { kind: _kind, lane: _lane, ...entryFields } = value;
124
+ const entry = { ...entryFields, id, type, parentId, seq, timestamp };
125
+ return lane === undefined ? { kind: "entry", entry } : { kind: "entry", lane, entry };
126
+ }
127
+ case "record": {
128
+ const id = requireString(value.id, path, lineNumber, "id");
129
+ const lane = requireString(value.lane, path, lineNumber, "lane");
130
+ const type = requireString(value.type, path, lineNumber, "record type");
131
+ if (!RECORD_TYPES.has(type))
132
+ throw invalidFile(path, lineNumber, `has unknown record type ${type}`);
133
+ const timestamp = requireTimestamp(value.timestamp, path, lineNumber);
134
+ if (type === "operation_started") {
135
+ if (!isObject(value.intent))
136
+ throw invalidFile(path, lineNumber, "has invalid intent");
137
+ const operationKind = requireString(value.intent.kind, path, lineNumber, "operation kind");
138
+ if (!OPERATION_KINDS.has(operationKind)) {
139
+ throw invalidFile(path, lineNumber, `has unknown operation kind ${operationKind}`);
140
+ }
141
+ }
142
+ if (type === "operation_finished")
143
+ requireString(value.runId, path, lineNumber, "runId");
144
+ const { kind: _kind, ...recordFields } = value;
145
+ return {
146
+ kind: "record",
147
+ record: { ...recordFields, id, lane, type, seq, timestamp },
148
+ };
149
+ }
150
+ case "lane":
151
+ return {
152
+ kind: "lane",
153
+ seq,
154
+ lane: requireString(value.lane, path, lineNumber, "lane"),
155
+ leafId: requireNullableId(value.leafId, path, lineNumber, "leafId"),
156
+ };
157
+ case "fact":
158
+ if (value.fact === "name") {
159
+ return { kind: "fact", seq, fact: "name", name: requireString(value.name, path, lineNumber, "name") };
160
+ }
161
+ if (value.fact === "label") {
162
+ if (value.label !== undefined && typeof value.label !== "string") {
163
+ throw invalidFile(path, lineNumber, "has invalid label");
164
+ }
165
+ return {
166
+ kind: "fact",
167
+ seq,
168
+ fact: "label",
169
+ targetId: requireString(value.targetId, path, lineNumber, "targetId"),
170
+ label: value.label,
171
+ };
172
+ }
173
+ throw invalidFile(path, lineNumber, "has unknown fact type");
174
+ default:
175
+ throw invalidFile(path, lineNumber, "has unknown mutation kind");
176
+ }
177
+ }
178
+ export function encodeMutation(mutation) {
179
+ switch (mutation.kind) {
180
+ case "entry":
181
+ return `${JSON.stringify({ kind: "entry", lane: mutation.lane, ...mutation.entry })}\n`;
182
+ case "record":
183
+ return `${JSON.stringify({ kind: "record", ...mutation.record })}\n`;
184
+ case "lane":
185
+ return `${JSON.stringify(mutation)}\n`;
186
+ case "fact":
187
+ return `${JSON.stringify(mutation)}\n`;
188
+ }
189
+ }
190
+ //# sourceMappingURL=codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/codec.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionMutation } from \"../state.ts\";\nimport type { Entry, LaneRecord } from \"../types.ts\";\nimport { invalidFile } from \"./errors.ts\";\nimport type { JsonlSessionMetadata, JsonlV4Header } from \"./types.ts\";\n\nconst ENTRY_TYPES = new Set<Entry[\"type\"]>([\n\t\"message\",\n\t\"model_change\",\n\t\"thinking_level_change\",\n\t\"active_tools_change\",\n\t\"compaction\",\n\t\"branch_summary\",\n\t\"custom\",\n]);\nconst RECORD_TYPES = new Set<LaneRecord[\"type\"]>([\n\t\"operation_started\",\n\t\"abort_requested\",\n\t\"operation_finished\",\n\t\"step_attempt\",\n\t\"tool_started\",\n\t\"queue_enqueued\",\n\t\"queue_cancelled\",\n\t\"write_deferred\",\n\t\"usage\",\n]);\nconst OPERATION_KINDS = new Set([\"run\", \"compaction\", \"navigation\"]);\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseObject(line: string, path: string, lineNumber: number): Record<string, unknown> {\n\tlet value: unknown;\n\ttry {\n\t\tvalue = JSON.parse(line);\n\t} catch (error) {\n\t\tthrow invalidFile(path, lineNumber, \"is not valid JSON\", error instanceof Error ? error : undefined);\n\t}\n\tif (!isObject(value)) throw invalidFile(path, lineNumber, \"is not a JSON object\");\n\treturn value;\n}\n\nfunction requireString(value: unknown, path: string, line: number, field: string): string {\n\tif (typeof value !== \"string\") throw invalidFile(path, line, `has invalid ${field}`);\n\treturn value;\n}\n\nfunction requireSequence(value: unknown, path: string, line: number): number {\n\tif (!Number.isSafeInteger(value) || (value as number) <= 0) throw invalidFile(path, line, \"has invalid seq\");\n\treturn value as number;\n}\n\nfunction requireTimestamp(value: unknown, path: string, line: number): number {\n\tif (!Number.isSafeInteger(value) || (value as number) < 0) throw invalidFile(path, line, \"has invalid timestamp\");\n\treturn value as number;\n}\n\nfunction requireNullableId(value: unknown, path: string, line: number, field: string): string | null {\n\tif (value !== null && typeof value !== \"string\") {\n\t\tthrow invalidFile(path, line, `has invalid ${field}`);\n\t}\n\treturn value as string | null;\n}\n\nexport function parseHeader(line: string, path: string): JsonlV4Header {\n\tconst value = parseObject(line, path, 1);\n\tif (value.kind !== \"header\") throw invalidFile(path, 1, \"is not a header\");\n\tif (value.version !== 4) throw invalidFile(path, 1, \"has unsupported session version\");\n\tconst parentSessionId = value.parentSessionId;\n\tif (parentSessionId !== undefined && typeof parentSessionId !== \"string\") {\n\t\tthrow invalidFile(path, 1, \"has invalid parentSessionId\");\n\t}\n\tconst legacyParentSessionPath = value.legacyParentSessionPath;\n\tif (legacyParentSessionPath !== undefined && typeof legacyParentSessionPath !== \"string\") {\n\t\tthrow invalidFile(path, 1, \"has invalid legacyParentSessionPath\");\n\t}\n\tif (parentSessionId !== undefined && legacyParentSessionPath !== undefined) {\n\t\tthrow invalidFile(path, 1, \"has both parentSessionId and legacyParentSessionPath\");\n\t}\n\tconst metadataValue = value.metadata;\n\tif (metadataValue !== undefined && !isObject(metadataValue)) throw invalidFile(path, 1, \"has invalid metadata\");\n\tconst metadata = metadataValue as JsonlV4Header[\"metadata\"];\n\treturn {\n\t\tkind: \"header\",\n\t\tversion: 4,\n\t\tid: requireString(value.id, path, 1, \"id\"),\n\t\tcreatedAt: requireTimestamp(value.createdAt, path, 1),\n\t\tcwd: requireString(value.cwd, path, 1, \"cwd\"),\n\t\tparentSessionId,\n\t\tlegacyParentSessionPath,\n\t\tmetadata,\n\t};\n}\n\nexport function encodeHeader(header: JsonlV4Header): string {\n\treturn `${JSON.stringify(header)}\\n`;\n}\n\nexport function metadataFromHeader(header: JsonlV4Header, path: string, modifiedAt: number): JsonlSessionMetadata {\n\treturn {\n\t\tid: header.id,\n\t\tcreatedAt: header.createdAt,\n\t\tcwd: header.cwd,\n\t\tpath,\n\t\tmodifiedAt,\n\t\tsourceFormat: 4,\n\t\t...(header.parentSessionId === undefined ? {} : { parentSessionId: header.parentSessionId }),\n\t\t...(header.legacyParentSessionPath === undefined\n\t\t\t? {}\n\t\t\t: { legacyParentSessionPath: header.legacyParentSessionPath }),\n\t\t...(header.metadata === undefined ? {} : { metadata: header.metadata }),\n\t};\n}\n\nexport function parseMutation(line: string, path: string, lineNumber: number): SessionMutation {\n\tconst value = parseObject(line, path, lineNumber);\n\tconst seq = requireSequence(value.seq, path, lineNumber);\n\tswitch (value.kind) {\n\t\tcase \"entry\": {\n\t\t\tconst lane = value.lane === undefined ? undefined : requireString(value.lane, path, lineNumber, \"lane\");\n\t\t\tconst id = requireString(value.id, path, lineNumber, \"id\");\n\t\t\tconst type = requireString(value.type, path, lineNumber, \"entry type\");\n\t\t\tif (!ENTRY_TYPES.has(type as Entry[\"type\"]))\n\t\t\t\tthrow invalidFile(path, lineNumber, `has unknown entry type ${type}`);\n\t\t\tconst parentId = requireNullableId(value.parentId, path, lineNumber, \"parentId\");\n\t\t\tconst timestamp = requireTimestamp(value.timestamp, path, lineNumber);\n\t\t\tif (type === \"custom\") requireString(value.customType, path, lineNumber, \"customType\");\n\t\t\tconst { kind: _kind, lane: _lane, ...entryFields } = value;\n\t\t\tconst entry = { ...entryFields, id, type, parentId, seq, timestamp } as unknown as Entry;\n\t\t\treturn lane === undefined ? { kind: \"entry\", entry } : { kind: \"entry\", lane, entry };\n\t\t}\n\t\tcase \"record\": {\n\t\t\tconst id = requireString(value.id, path, lineNumber, \"id\");\n\t\t\tconst lane = requireString(value.lane, path, lineNumber, \"lane\");\n\t\t\tconst type = requireString(value.type, path, lineNumber, \"record type\");\n\t\t\tif (!RECORD_TYPES.has(type as LaneRecord[\"type\"]))\n\t\t\t\tthrow invalidFile(path, lineNumber, `has unknown record type ${type}`);\n\t\t\tconst timestamp = requireTimestamp(value.timestamp, path, lineNumber);\n\t\t\tif (type === \"operation_started\") {\n\t\t\t\tif (!isObject(value.intent)) throw invalidFile(path, lineNumber, \"has invalid intent\");\n\t\t\t\tconst operationKind = requireString(value.intent.kind, path, lineNumber, \"operation kind\");\n\t\t\t\tif (!OPERATION_KINDS.has(operationKind)) {\n\t\t\t\t\tthrow invalidFile(path, lineNumber, `has unknown operation kind ${operationKind}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (type === \"operation_finished\") requireString(value.runId, path, lineNumber, \"runId\");\n\t\t\tconst { kind: _kind, ...recordFields } = value;\n\t\t\treturn {\n\t\t\t\tkind: \"record\",\n\t\t\t\trecord: { ...recordFields, id, lane, type, seq, timestamp } as unknown as LaneRecord,\n\t\t\t};\n\t\t}\n\t\tcase \"lane\":\n\t\t\treturn {\n\t\t\t\tkind: \"lane\",\n\t\t\t\tseq,\n\t\t\t\tlane: requireString(value.lane, path, lineNumber, \"lane\"),\n\t\t\t\tleafId: requireNullableId(value.leafId, path, lineNumber, \"leafId\"),\n\t\t\t};\n\t\tcase \"fact\":\n\t\t\tif (value.fact === \"name\") {\n\t\t\t\treturn { kind: \"fact\", seq, fact: \"name\", name: requireString(value.name, path, lineNumber, \"name\") };\n\t\t\t}\n\t\t\tif (value.fact === \"label\") {\n\t\t\t\tif (value.label !== undefined && typeof value.label !== \"string\") {\n\t\t\t\t\tthrow invalidFile(path, lineNumber, \"has invalid label\");\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tkind: \"fact\",\n\t\t\t\t\tseq,\n\t\t\t\t\tfact: \"label\",\n\t\t\t\t\ttargetId: requireString(value.targetId, path, lineNumber, \"targetId\"),\n\t\t\t\t\tlabel: value.label,\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow invalidFile(path, lineNumber, \"has unknown fact type\");\n\t\tdefault:\n\t\t\tthrow invalidFile(path, lineNumber, \"has unknown mutation kind\");\n\t}\n}\n\nexport function encodeMutation(mutation: SessionMutation): string {\n\tswitch (mutation.kind) {\n\t\tcase \"entry\":\n\t\t\treturn `${JSON.stringify({ kind: \"entry\", lane: mutation.lane, ...mutation.entry })}\\n`;\n\t\tcase \"record\":\n\t\t\treturn `${JSON.stringify({ kind: \"record\", ...mutation.record })}\\n`;\n\t\tcase \"lane\":\n\t\t\treturn `${JSON.stringify(mutation)}\\n`;\n\t\tcase \"fact\":\n\t\t\treturn `${JSON.stringify(mutation)}\\n`;\n\t}\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import type { FileError, Result } from "../../types.ts";
2
+ import { SessionError } from "../types.ts";
3
+ export declare function fileResult<T>(result: Result<T, FileError>, message: string): T;
4
+ export declare function invalidFile(path: string, line: number, message: string, cause?: Error): SessionError;
5
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAS9E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,YAAY,CAEpG"}
@@ -0,0 +1,11 @@
1
+ import { SessionError } from "../types.js";
2
+ export function fileResult(result, message) {
3
+ if (!result.ok) {
4
+ throw new SessionError(result.error.code === "not_found" ? "not_found" : "storage", `${message}: ${result.error.message}`, result.error);
5
+ }
6
+ return result.value;
7
+ }
8
+ export function invalidFile(path, line, message, cause) {
9
+ return new SessionError("invalid_entry", `Invalid JSONL v4 session ${path}: line ${line} ${message}`, cause);
10
+ }
11
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/errors.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,UAAU,UAAU,CAAI,MAA4B,EAAE,OAAe;IAC1E,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,YAAY,CACrB,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,EAC3D,GAAG,OAAO,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EACrC,MAAM,CAAC,KAAK,CACZ,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC;AACrB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,IAAY,EAAE,OAAe,EAAE,KAAa;IACrF,OAAO,IAAI,YAAY,CAAC,eAAe,EAAE,4BAA4B,IAAI,UAAU,IAAI,IAAI,OAAO,EAAE,EAAE,KAAK,CAAC,CAAC;AAC9G,CAAC","sourcesContent":["import type { FileError, Result } from \"../../types.ts\";\nimport { SessionError } from \"../types.ts\";\n\nexport function fileResult<T>(result: Result<T, FileError>, message: string): T {\n\tif (!result.ok) {\n\t\tthrow new SessionError(\n\t\t\tresult.error.code === \"not_found\" ? \"not_found\" : \"storage\",\n\t\t\t`${message}: ${result.error.message}`,\n\t\t\tresult.error,\n\t\t);\n\t}\n\treturn result.value;\n}\n\nexport function invalidFile(path: string, line: number, message: string, cause?: Error): SessionError {\n\treturn new SessionError(\"invalid_entry\", `Invalid JSONL v4 session ${path}: line ${line} ${message}`, cause);\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import { Session } from "../session.ts";
2
+ import { type ForkOptions, type SessionRepo } from "../types.ts";
3
+ import type { JsonlSessionCreateOptions, JsonlSessionListOptions, JsonlSessionMetadata, JsonlSessionRepoOptions } from "./types.ts";
4
+ export declare class JsonlSessionRepo implements SessionRepo<JsonlSessionMetadata, JsonlSessionCreateOptions, JsonlSessionListOptions> {
5
+ private readonly fs;
6
+ private readonly sessionsRootInput;
7
+ private rootPromise;
8
+ constructor(options: JsonlSessionRepoOptions);
9
+ create(options: JsonlSessionCreateOptions): Promise<Session<JsonlSessionMetadata>>;
10
+ open(metadata: JsonlSessionMetadata): Promise<Session<JsonlSessionMetadata>>;
11
+ list(): Promise<JsonlSessionMetadata[]>;
12
+ list(options: JsonlSessionListOptions): Promise<JsonlSessionMetadata[]>;
13
+ delete(metadata: JsonlSessionMetadata): Promise<void>;
14
+ fork(source: JsonlSessionMetadata, options: ForkOptions & JsonlSessionCreateOptions): Promise<Session<JsonlSessionMetadata>>;
15
+ private loadStorage;
16
+ private prepareCreate;
17
+ private listDirect;
18
+ private sessionIdExists;
19
+ private sessionDirectories;
20
+ private sessionDirectory;
21
+ private root;
22
+ }
23
+ //# sourceMappingURL=repo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/repo.ts"],"names":[],"mappings":"AACA,OAAO,EAA0B,OAAO,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,EAAE,KAAK,WAAW,EAAgB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAI/E,OAAO,KAAK,EACX,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EAEpB,uBAAuB,EAEvB,MAAM,YAAY,CAAC;AAsBpB,qBAAa,gBACZ,YAAW,WAAW,CAAC,oBAAoB,EAAE,yBAAyB,EAAE,uBAAuB,CAAC;IAEhG,OAAO,CAAC,QAAQ,CAAC,EAAE,CAA6B;IAChD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,WAAW,CAA8B;gBAErC,OAAO,EAAE,uBAAuB;IAKtC,MAAM,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAKlF,IAAI,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAIlF,IAAI,IAAI,OAAO,CAAC,oBAAoB,EAAE,CAAC;IACvC,IAAI,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAKjE,MAAM,CAAC,QAAQ,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrD,IAAI,CACT,MAAM,EAAE,oBAAoB,EAC5B,OAAO,EAAE,WAAW,GAAG,yBAAyB,GAC9C,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;YAS3B,WAAW;YAYX,aAAa;YA+Bb,UAAU;YAqBV,eAAe;YAQf,kBAAkB;YAelB,gBAAgB;IAO9B,OAAO,CAAC,IAAI;CAMZ"}
@@ -0,0 +1,129 @@
1
+ import { uuidv7 } from "@earendil-works/pi-ai";
2
+ import { assertJsonSerializable, Session } from "../session.js";
3
+ import { SessionError } from "../types.js";
4
+ import { metadataFromHeader, parseHeader } from "./codec.js";
5
+ import { fileResult, invalidFile } from "./errors.js";
6
+ import { JsonlSessionStorage } from "./storage.js";
7
+ const SESSION_ID_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;
8
+ function validateSessionId(id) {
9
+ if (!SESSION_ID_PATTERN.test(id)) {
10
+ throw new SessionError("invalid_payload", "Session id must be non-empty, contain only alphanumeric characters, '-', '_', and '.', and start and end with an alphanumeric character");
11
+ }
12
+ }
13
+ function sessionDirectoryName(cwd) {
14
+ return `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
15
+ }
16
+ function sessionFileName(createdAt, id) {
17
+ const timestamp = new Date(createdAt).toISOString().replace(/[:.]/g, "-");
18
+ return `${timestamp}_${id}.jsonl`;
19
+ }
20
+ export class JsonlSessionRepo {
21
+ constructor(options) {
22
+ this.fs = options.fs;
23
+ this.sessionsRootInput = options.sessionsRoot;
24
+ }
25
+ async create(options) {
26
+ const { header, path } = await this.prepareCreate(options);
27
+ return new Session(await JsonlSessionStorage.create(this.fs, path, header));
28
+ }
29
+ async open(metadata) {
30
+ return new Session(await this.loadStorage(metadata));
31
+ }
32
+ async list(options = {}) {
33
+ return this.listDirect(options);
34
+ }
35
+ async delete(metadata) {
36
+ fileResult(await this.fs.remove(metadata.path, { force: true }), `Failed to delete session ${metadata.path}`);
37
+ }
38
+ async fork(source, options) {
39
+ const sourceStorage = await this.loadStorage(source);
40
+ const { header, path } = await this.prepareCreate({
41
+ ...options,
42
+ parentSessionId: options.parentSessionId ?? source.id,
43
+ });
44
+ return new Session(await sourceStorage.fork(path, header, options));
45
+ }
46
+ async loadStorage(metadata) {
47
+ if (!fileResult(await this.fs.exists(metadata.path), `Failed to check session ${metadata.path}`)) {
48
+ throw new SessionError("not_found", `Session not found: ${metadata.id}`);
49
+ }
50
+ const storage = await JsonlSessionStorage.load(this.fs, metadata.path);
51
+ const loadedMetadata = await storage.getMetadata();
52
+ if (loadedMetadata.id !== metadata.id) {
53
+ throw new SessionError("invalid_entry", `Session id does not match header: ${metadata.id}`);
54
+ }
55
+ return storage;
56
+ }
57
+ async prepareCreate(options) {
58
+ const id = options.id ?? uuidv7();
59
+ validateSessionId(id);
60
+ const cwd = fileResult(await this.fs.absolutePath(options.cwd), `Failed to resolve session cwd ${options.cwd}`);
61
+ if (await this.sessionIdExists(id, cwd)) {
62
+ throw new SessionError("already_exists", `Session already exists: ${id}`);
63
+ }
64
+ const createdAt = Date.now();
65
+ const sessionDirectory = await this.sessionDirectory(cwd);
66
+ const path = fileResult(await this.fs.joinPath([sessionDirectory, sessionFileName(createdAt, id)]), `Failed to resolve path for session ${id}`);
67
+ if (options.metadata !== undefined)
68
+ assertJsonSerializable(options.metadata);
69
+ const header = {
70
+ kind: "header",
71
+ version: 4,
72
+ id,
73
+ createdAt,
74
+ cwd,
75
+ parentSessionId: options.parentSessionId,
76
+ metadata: options.metadata,
77
+ };
78
+ fileResult(await this.fs.createDir(sessionDirectory, { recursive: true }), `Failed to create sessions directory`);
79
+ return { header, path };
80
+ }
81
+ async listDirect(options) {
82
+ const directories = await this.sessionDirectories(options.cwd);
83
+ const metadata = [];
84
+ for (const directory of directories) {
85
+ const files = fileResult(await this.fs.listDir(directory), `Failed to list sessions directory ${directory}`).filter((entry) => entry.kind !== "directory" && entry.name.endsWith(".jsonl"));
86
+ for (const file of files) {
87
+ const content = fileResult(await this.fs.readTextFile(file.path), `Failed to read session header ${file.path}`);
88
+ const firstLine = content.split("\n", 1)[0];
89
+ if (!firstLine)
90
+ throw invalidFile(file.path, 1, "is missing a header");
91
+ metadata.push(metadataFromHeader(parseHeader(firstLine, file.path), file.path, file.mtimeMs));
92
+ }
93
+ }
94
+ return metadata.sort((left, right) => right.modifiedAt - left.modifiedAt);
95
+ }
96
+ async sessionIdExists(id, cwd) {
97
+ const suffix = `_${id}.jsonl`;
98
+ const directory = await this.sessionDirectory(cwd);
99
+ if (!fileResult(await this.fs.exists(directory), `Failed to check sessions directory ${directory}`))
100
+ return false;
101
+ const files = fileResult(await this.fs.listDir(directory), `Failed to list sessions directory ${directory}`);
102
+ return files.some((entry) => entry.kind !== "directory" && entry.name.endsWith(suffix));
103
+ }
104
+ async sessionDirectories(cwd) {
105
+ const root = await this.root();
106
+ if (cwd !== undefined) {
107
+ const resolvedCwd = fileResult(await this.fs.absolutePath(cwd), `Failed to resolve session cwd ${cwd}`);
108
+ const directory = await this.sessionDirectory(resolvedCwd);
109
+ return fileResult(await this.fs.exists(directory), `Failed to check sessions directory ${directory}`)
110
+ ? [directory]
111
+ : [];
112
+ }
113
+ if (!fileResult(await this.fs.exists(root), `Failed to check sessions directory ${root}`))
114
+ return [];
115
+ return fileResult(await this.fs.listDir(root), `Failed to list sessions directory ${root}`)
116
+ .filter((entry) => entry.kind === "directory" || entry.kind === "symlink")
117
+ .map((entry) => entry.path);
118
+ }
119
+ async sessionDirectory(cwd) {
120
+ return fileResult(await this.fs.joinPath([await this.root(), sessionDirectoryName(cwd)]), `Failed to resolve sessions directory for ${cwd}`);
121
+ }
122
+ root() {
123
+ this.rootPromise ??= this.fs
124
+ .absolutePath(this.sessionsRootInput)
125
+ .then((result) => fileResult(result, `Failed to resolve sessions root ${this.sessionsRootInput}`));
126
+ return this.rootPromise;
127
+ }
128
+ }
129
+ //# sourceMappingURL=repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.js","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/repo.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"@earendil-works/pi-ai\";\nimport { assertJsonSerializable, Session } from \"../session.ts\";\nimport { type ForkOptions, SessionError, type SessionRepo } from \"../types.ts\";\nimport { metadataFromHeader, parseHeader } from \"./codec.ts\";\nimport { fileResult, invalidFile } from \"./errors.ts\";\nimport { JsonlSessionStorage } from \"./storage.ts\";\nimport type {\n\tJsonlSessionCreateOptions,\n\tJsonlSessionListOptions,\n\tJsonlSessionMetadata,\n\tJsonlSessionRepoFileSystem,\n\tJsonlSessionRepoOptions,\n\tJsonlV4Header,\n} from \"./types.ts\";\n\nconst SESSION_ID_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$/;\n\nfunction validateSessionId(id: string): void {\n\tif (!SESSION_ID_PATTERN.test(id)) {\n\t\tthrow new SessionError(\n\t\t\t\"invalid_payload\",\n\t\t\t\"Session id must be non-empty, contain only alphanumeric characters, '-', '_', and '.', and start and end with an alphanumeric character\",\n\t\t);\n\t}\n}\n\nfunction sessionDirectoryName(cwd: string): string {\n\treturn `--${cwd.replace(/^[/\\\\]/, \"\").replace(/[/\\\\:]/g, \"-\")}--`;\n}\n\nfunction sessionFileName(createdAt: number, id: string): string {\n\tconst timestamp = new Date(createdAt).toISOString().replace(/[:.]/g, \"-\");\n\treturn `${timestamp}_${id}.jsonl`;\n}\n\nexport class JsonlSessionRepo\n\timplements SessionRepo<JsonlSessionMetadata, JsonlSessionCreateOptions, JsonlSessionListOptions>\n{\n\tprivate readonly fs: JsonlSessionRepoFileSystem;\n\tprivate readonly sessionsRootInput: string;\n\tprivate rootPromise: Promise<string> | undefined;\n\n\tconstructor(options: JsonlSessionRepoOptions) {\n\t\tthis.fs = options.fs;\n\t\tthis.sessionsRootInput = options.sessionsRoot;\n\t}\n\n\tasync create(options: JsonlSessionCreateOptions): Promise<Session<JsonlSessionMetadata>> {\n\t\tconst { header, path } = await this.prepareCreate(options);\n\t\treturn new Session(await JsonlSessionStorage.create(this.fs, path, header));\n\t}\n\n\tasync open(metadata: JsonlSessionMetadata): Promise<Session<JsonlSessionMetadata>> {\n\t\treturn new Session(await this.loadStorage(metadata));\n\t}\n\n\tlist(): Promise<JsonlSessionMetadata[]>;\n\tlist(options: JsonlSessionListOptions): Promise<JsonlSessionMetadata[]>;\n\tasync list(options: JsonlSessionListOptions = {}): Promise<JsonlSessionMetadata[]> {\n\t\treturn this.listDirect(options);\n\t}\n\n\tasync delete(metadata: JsonlSessionMetadata): Promise<void> {\n\t\tfileResult(await this.fs.remove(metadata.path, { force: true }), `Failed to delete session ${metadata.path}`);\n\t}\n\n\tasync fork(\n\t\tsource: JsonlSessionMetadata,\n\t\toptions: ForkOptions & JsonlSessionCreateOptions,\n\t): Promise<Session<JsonlSessionMetadata>> {\n\t\tconst sourceStorage = await this.loadStorage(source);\n\t\tconst { header, path } = await this.prepareCreate({\n\t\t\t...options,\n\t\t\tparentSessionId: options.parentSessionId ?? source.id,\n\t\t});\n\t\treturn new Session(await sourceStorage.fork(path, header, options));\n\t}\n\n\tprivate async loadStorage(metadata: JsonlSessionMetadata): Promise<JsonlSessionStorage> {\n\t\tif (!fileResult(await this.fs.exists(metadata.path), `Failed to check session ${metadata.path}`)) {\n\t\t\tthrow new SessionError(\"not_found\", `Session not found: ${metadata.id}`);\n\t\t}\n\t\tconst storage = await JsonlSessionStorage.load(this.fs, metadata.path);\n\t\tconst loadedMetadata = await storage.getMetadata();\n\t\tif (loadedMetadata.id !== metadata.id) {\n\t\t\tthrow new SessionError(\"invalid_entry\", `Session id does not match header: ${metadata.id}`);\n\t\t}\n\t\treturn storage;\n\t}\n\n\tprivate async prepareCreate(options: JsonlSessionCreateOptions): Promise<{\n\t\theader: JsonlV4Header;\n\t\tpath: string;\n\t}> {\n\t\tconst id = options.id ?? uuidv7();\n\t\tvalidateSessionId(id);\n\t\tconst cwd = fileResult(await this.fs.absolutePath(options.cwd), `Failed to resolve session cwd ${options.cwd}`);\n\t\tif (await this.sessionIdExists(id, cwd)) {\n\t\t\tthrow new SessionError(\"already_exists\", `Session already exists: ${id}`);\n\t\t}\n\n\t\tconst createdAt = Date.now();\n\t\tconst sessionDirectory = await this.sessionDirectory(cwd);\n\t\tconst path = fileResult(\n\t\t\tawait this.fs.joinPath([sessionDirectory, sessionFileName(createdAt, id)]),\n\t\t\t`Failed to resolve path for session ${id}`,\n\t\t);\n\t\tif (options.metadata !== undefined) assertJsonSerializable(options.metadata);\n\t\tconst header: JsonlV4Header = {\n\t\t\tkind: \"header\",\n\t\t\tversion: 4,\n\t\t\tid,\n\t\t\tcreatedAt,\n\t\t\tcwd,\n\t\t\tparentSessionId: options.parentSessionId,\n\t\t\tmetadata: options.metadata,\n\t\t};\n\t\tfileResult(await this.fs.createDir(sessionDirectory, { recursive: true }), `Failed to create sessions directory`);\n\t\treturn { header, path };\n\t}\n\n\tprivate async listDirect(options: JsonlSessionListOptions): Promise<JsonlSessionMetadata[]> {\n\t\tconst directories = await this.sessionDirectories(options.cwd);\n\t\tconst metadata: JsonlSessionMetadata[] = [];\n\t\tfor (const directory of directories) {\n\t\t\tconst files = fileResult(\n\t\t\t\tawait this.fs.listDir(directory),\n\t\t\t\t`Failed to list sessions directory ${directory}`,\n\t\t\t).filter((entry) => entry.kind !== \"directory\" && entry.name.endsWith(\".jsonl\"));\n\t\t\tfor (const file of files) {\n\t\t\t\tconst content = fileResult(\n\t\t\t\t\tawait this.fs.readTextFile(file.path),\n\t\t\t\t\t`Failed to read session header ${file.path}`,\n\t\t\t\t);\n\t\t\t\tconst firstLine = content.split(\"\\n\", 1)[0];\n\t\t\t\tif (!firstLine) throw invalidFile(file.path, 1, \"is missing a header\");\n\t\t\t\tmetadata.push(metadataFromHeader(parseHeader(firstLine, file.path), file.path, file.mtimeMs));\n\t\t\t}\n\t\t}\n\t\treturn metadata.sort((left, right) => right.modifiedAt - left.modifiedAt);\n\t}\n\n\tprivate async sessionIdExists(id: string, cwd: string): Promise<boolean> {\n\t\tconst suffix = `_${id}.jsonl`;\n\t\tconst directory = await this.sessionDirectory(cwd);\n\t\tif (!fileResult(await this.fs.exists(directory), `Failed to check sessions directory ${directory}`)) return false;\n\t\tconst files = fileResult(await this.fs.listDir(directory), `Failed to list sessions directory ${directory}`);\n\t\treturn files.some((entry) => entry.kind !== \"directory\" && entry.name.endsWith(suffix));\n\t}\n\n\tprivate async sessionDirectories(cwd?: string): Promise<string[]> {\n\t\tconst root = await this.root();\n\t\tif (cwd !== undefined) {\n\t\t\tconst resolvedCwd = fileResult(await this.fs.absolutePath(cwd), `Failed to resolve session cwd ${cwd}`);\n\t\t\tconst directory = await this.sessionDirectory(resolvedCwd);\n\t\t\treturn fileResult(await this.fs.exists(directory), `Failed to check sessions directory ${directory}`)\n\t\t\t\t? [directory]\n\t\t\t\t: [];\n\t\t}\n\t\tif (!fileResult(await this.fs.exists(root), `Failed to check sessions directory ${root}`)) return [];\n\t\treturn fileResult(await this.fs.listDir(root), `Failed to list sessions directory ${root}`)\n\t\t\t.filter((entry) => entry.kind === \"directory\" || entry.kind === \"symlink\")\n\t\t\t.map((entry) => entry.path);\n\t}\n\n\tprivate async sessionDirectory(cwd: string): Promise<string> {\n\t\treturn fileResult(\n\t\t\tawait this.fs.joinPath([await this.root(), sessionDirectoryName(cwd)]),\n\t\t\t`Failed to resolve sessions directory for ${cwd}`,\n\t\t);\n\t}\n\n\tprivate root(): Promise<string> {\n\t\tthis.rootPromise ??= this.fs\n\t\t\t.absolutePath(this.sessionsRootInput)\n\t\t\t.then((result) => fileResult(result, `Failed to resolve sessions root ${this.sessionsRootInput}`));\n\t\treturn this.rootPromise;\n\t}\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import { type BranchBounds, type Entry, type EntryQuery, type ForkOptions, type LanePointer, type LaneRecord, type LogItem, type LogOptions, type NewRecord, type OperationStartedRecord, type ProvisionedEntry, type RecordQuery, type SessionStats, type SessionStorage } from "../types.ts";
2
+ import type { JsonlSessionMetadata, JsonlSessionRepoFileSystem, JsonlV4Header } from "./types.ts";
3
+ export declare class JsonlSessionStorage implements SessionStorage<JsonlSessionMetadata> {
4
+ private readonly fs;
5
+ private readonly metadata;
6
+ private readonly state;
7
+ private tail;
8
+ constructor(fs: JsonlSessionRepoFileSystem, metadata: JsonlSessionMetadata);
9
+ static create(fs: JsonlSessionRepoFileSystem, path: string, header: JsonlV4Header): Promise<JsonlSessionStorage>;
10
+ static load(fs: JsonlSessionRepoFileSystem, path: string): Promise<JsonlSessionStorage>;
11
+ fork(path: string, header: JsonlV4Header, options: ForkOptions): Promise<JsonlSessionStorage>;
12
+ drain(): Promise<void>;
13
+ getMetadata(): Promise<JsonlSessionMetadata>;
14
+ getLanes(): Promise<LanePointer[]>;
15
+ createLane(lane: string, at: string | null): Promise<void>;
16
+ moveLane(lane: string, to: string | null): Promise<void>;
17
+ appendEntry<TEntry extends Entry>(newEntry: ProvisionedEntry<TEntry>, lane: string): Promise<TEntry>;
18
+ appendRecord<TRecord extends LaneRecord>(newRecord: NewRecord<TRecord>): Promise<TRecord>;
19
+ getEntry(id: string): Promise<Entry | undefined>;
20
+ findEntries(query?: EntryQuery): Promise<Entry[]>;
21
+ findEntriesOnBranch(query: EntryQuery & BranchBounds & {
22
+ start: string;
23
+ }): Promise<Entry[]>;
24
+ findRecords<K extends LaneRecord["type"]>(query: RecordQuery & {
25
+ type: K;
26
+ }): Promise<Extract<LaneRecord, {
27
+ type: K;
28
+ }>[]>;
29
+ findRecords(query?: RecordQuery): Promise<LaneRecord[]>;
30
+ findOpenOperations(lane: string, options?: {
31
+ limit?: number;
32
+ }): Promise<OperationStartedRecord[]>;
33
+ getLog(options?: LogOptions): Promise<LogItem[]>;
34
+ getName(): Promise<string | undefined>;
35
+ setName(name: string): Promise<void>;
36
+ getLabel(id: string): Promise<string | undefined>;
37
+ setLabel(id: string, label: string | undefined): Promise<void>;
38
+ getStats(): Promise<SessionStats>;
39
+ private enqueue;
40
+ private appendMutation;
41
+ private applyMutation;
42
+ }
43
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../../src/harness/session/jsonl/storage.ts"],"names":[],"mappings":"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"}