@aexol/spectral 0.7.1 → 0.7.5

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 (219) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/agent/agents.js +1 -1
  3. package/dist/agent/index.js +199 -184
  4. package/dist/commands/serve.js +0 -3
  5. package/dist/designer/data/systems/renault/DESIGN.md +1 -1
  6. package/dist/designer/philosophies.js +668 -0
  7. package/dist/mcp/sampling-handler.js +1 -1
  8. package/dist/memory/commands/status.js +1 -1
  9. package/dist/memory/compaction.js +2 -2
  10. package/dist/memory/config.js +1 -1
  11. package/dist/memory/debug-log.js +1 -1
  12. package/dist/memory/hooks/compaction-hook.js +29 -0
  13. package/dist/memory/index.js +2 -0
  14. package/dist/memory/observer.js +2 -2
  15. package/dist/memory/project-observations-store.js +14 -0
  16. package/dist/memory/tokens.js +1 -1
  17. package/dist/memory/tools/read-project-observations.js +82 -0
  18. package/dist/memory/tools/recall-observation.js +2 -2
  19. package/dist/pi/agent-core/agent-loop.js +501 -0
  20. package/dist/pi/agent-core/agent.js +401 -0
  21. package/dist/pi/agent-core/harness/agent-harness.js +899 -0
  22. package/dist/pi/agent-core/harness/compaction/branch-summarization.js +173 -0
  23. package/dist/pi/agent-core/harness/compaction/compaction.js +532 -0
  24. package/dist/pi/agent-core/harness/compaction/utils.js +130 -0
  25. package/dist/pi/agent-core/harness/env/nodejs.js +485 -0
  26. package/dist/pi/agent-core/harness/messages.js +101 -0
  27. package/dist/pi/agent-core/harness/prompt-templates.js +229 -0
  28. package/dist/pi/agent-core/harness/session/jsonl-repo.js +100 -0
  29. package/dist/pi/agent-core/harness/session/jsonl-storage.js +230 -0
  30. package/dist/pi/agent-core/harness/session/memory-repo.js +41 -0
  31. package/dist/pi/agent-core/harness/session/memory-storage.js +113 -0
  32. package/dist/pi/agent-core/harness/session/repo-utils.js +38 -0
  33. package/dist/pi/agent-core/harness/session/session.js +196 -0
  34. package/dist/pi/agent-core/harness/session/uuid.js +49 -0
  35. package/dist/pi/agent-core/harness/skills.js +310 -0
  36. package/dist/pi/agent-core/harness/system-prompt.js +29 -0
  37. package/dist/pi/agent-core/harness/types.js +93 -0
  38. package/dist/pi/agent-core/harness/utils/shell-output.js +125 -0
  39. package/dist/pi/agent-core/harness/utils/truncate.js +289 -0
  40. package/dist/pi/agent-core/index.js +24 -0
  41. package/dist/pi/agent-core/node.js +2 -0
  42. package/dist/pi/agent-core/proxy.js +277 -0
  43. package/dist/pi/agent-core/types.js +1 -0
  44. package/dist/pi/ai/api-registry.js +43 -0
  45. package/dist/pi/ai/cli.js +120 -0
  46. package/dist/pi/ai/env-api-keys.js +169 -0
  47. package/dist/pi/ai/image-models.generated.js +441 -0
  48. package/dist/pi/ai/image-models.js +22 -0
  49. package/dist/pi/ai/images-api-registry.js +21 -0
  50. package/dist/pi/ai/images.js +13 -0
  51. package/dist/pi/ai/index.js +18 -0
  52. package/dist/pi/ai/models.generated.js +16220 -0
  53. package/dist/pi/ai/models.js +70 -0
  54. package/dist/pi/ai/oauth.js +1 -0
  55. package/dist/pi/ai/providers/anthropic.js +945 -0
  56. package/dist/pi/ai/providers/faux.js +367 -0
  57. package/dist/pi/ai/providers/github-copilot-headers.js +28 -0
  58. package/dist/pi/ai/providers/openai-completions.js +945 -0
  59. package/dist/pi/ai/providers/openai-prompt-cache.js +9 -0
  60. package/dist/pi/ai/providers/register-builtins.js +97 -0
  61. package/dist/pi/ai/providers/simple-options.js +40 -0
  62. package/dist/pi/ai/providers/transform-messages.js +183 -0
  63. package/dist/pi/ai/session-resources.js +21 -0
  64. package/dist/pi/ai/stream.js +26 -0
  65. package/dist/pi/ai/types.js +1 -0
  66. package/dist/pi/ai/utils/diagnostics.js +24 -0
  67. package/dist/pi/ai/utils/event-stream.js +80 -0
  68. package/dist/pi/ai/utils/hash.js +13 -0
  69. package/dist/pi/ai/utils/headers.js +7 -0
  70. package/dist/pi/ai/utils/json-parse.js +112 -0
  71. package/dist/pi/ai/utils/node-http-proxy.js +96 -0
  72. package/dist/pi/ai/utils/oauth/anthropic.js +334 -0
  73. package/dist/pi/ai/utils/oauth/device-code.js +54 -0
  74. package/dist/pi/ai/utils/oauth/github-copilot.js +270 -0
  75. package/dist/pi/ai/utils/oauth/index.js +121 -0
  76. package/dist/pi/ai/utils/oauth/oauth-page.js +104 -0
  77. package/dist/pi/ai/utils/oauth/openai-codex.js +384 -0
  78. package/dist/pi/ai/utils/oauth/pkce.js +30 -0
  79. package/dist/pi/ai/utils/oauth/types.js +1 -0
  80. package/dist/pi/ai/utils/overflow.js +150 -0
  81. package/dist/pi/ai/utils/sanitize-unicode.js +25 -0
  82. package/dist/pi/ai/utils/typebox-helpers.js +20 -0
  83. package/dist/pi/ai/utils/validation.js +280 -0
  84. package/dist/pi/coding-agent/bun/cli.js +7 -0
  85. package/dist/pi/coding-agent/bun/restore-sandbox-env.js +31 -0
  86. package/dist/pi/coding-agent/cli/args.js +340 -0
  87. package/dist/pi/coding-agent/cli/file-processor.js +82 -0
  88. package/dist/pi/coding-agent/cli/initial-message.js +21 -0
  89. package/dist/pi/coding-agent/cli.js +17 -0
  90. package/dist/pi/coding-agent/config.js +414 -0
  91. package/dist/pi/coding-agent/core/agent-session-runtime.js +299 -0
  92. package/dist/pi/coding-agent/core/agent-session-services.js +117 -0
  93. package/dist/pi/coding-agent/core/agent-session.js +2498 -0
  94. package/dist/pi/coding-agent/core/auth-guidance.js +20 -0
  95. package/dist/pi/coding-agent/core/auth-storage.js +441 -0
  96. package/dist/pi/coding-agent/core/bash-executor.js +110 -0
  97. package/dist/pi/coding-agent/core/compaction/branch-summarization.js +242 -0
  98. package/dist/pi/coding-agent/core/compaction/compaction.js +624 -0
  99. package/dist/pi/coding-agent/core/compaction/index.js +6 -0
  100. package/dist/pi/coding-agent/core/compaction/utils.js +152 -0
  101. package/dist/pi/coding-agent/core/defaults.js +1 -0
  102. package/dist/pi/coding-agent/core/diagnostics.js +1 -0
  103. package/dist/pi/coding-agent/core/event-bus.js +24 -0
  104. package/dist/pi/coding-agent/core/exec.js +74 -0
  105. package/dist/pi/coding-agent/core/export-html/ansi-to-html.js +248 -0
  106. package/dist/pi/coding-agent/core/export-html/index.js +225 -0
  107. package/dist/pi/coding-agent/core/export-html/tool-renderer.js +107 -0
  108. package/dist/pi/coding-agent/core/extensions/index.js +8 -0
  109. package/dist/pi/coding-agent/core/extensions/loader.js +485 -0
  110. package/dist/pi/coding-agent/core/extensions/runner.js +824 -0
  111. package/dist/pi/coding-agent/core/extensions/types.js +44 -0
  112. package/dist/pi/coding-agent/core/extensions/wrapper.js +21 -0
  113. package/dist/pi/coding-agent/core/footer-data-provider.js +309 -0
  114. package/dist/pi/coding-agent/core/http-dispatcher.js +47 -0
  115. package/dist/pi/coding-agent/core/index.js +11 -0
  116. package/dist/pi/coding-agent/core/keybindings.js +294 -0
  117. package/dist/pi/coding-agent/core/messages.js +122 -0
  118. package/dist/pi/coding-agent/core/model-registry.js +728 -0
  119. package/dist/pi/coding-agent/core/model-resolver.js +494 -0
  120. package/dist/pi/coding-agent/core/output-guard.js +58 -0
  121. package/dist/pi/coding-agent/core/package-manager.js +2020 -0
  122. package/dist/pi/coding-agent/core/prompt-templates.js +237 -0
  123. package/dist/pi/coding-agent/core/provider-display-names.js +32 -0
  124. package/dist/pi/coding-agent/core/resolve-config-value.js +125 -0
  125. package/dist/pi/coding-agent/core/resource-loader.js +733 -0
  126. package/dist/pi/coding-agent/core/sdk.js +282 -0
  127. package/dist/pi/coding-agent/core/session-cwd.js +37 -0
  128. package/dist/pi/coding-agent/core/session-manager.js +1146 -0
  129. package/dist/pi/coding-agent/core/settings-manager.js +794 -0
  130. package/dist/pi/coding-agent/core/skills.js +386 -0
  131. package/dist/pi/coding-agent/core/slash-commands.js +24 -0
  132. package/dist/pi/coding-agent/core/source-info.js +18 -0
  133. package/dist/pi/coding-agent/core/system-prompt.js +122 -0
  134. package/dist/pi/coding-agent/core/telemetry.js +8 -0
  135. package/dist/pi/coding-agent/core/timings.js +30 -0
  136. package/dist/pi/coding-agent/core/tools/bash.js +341 -0
  137. package/dist/pi/coding-agent/core/tools/edit-diff.js +344 -0
  138. package/dist/pi/coding-agent/core/tools/edit.js +324 -0
  139. package/dist/pi/coding-agent/core/tools/file-mutation-queue.js +36 -0
  140. package/dist/pi/coding-agent/core/tools/find.js +297 -0
  141. package/dist/pi/coding-agent/core/tools/grep.js +303 -0
  142. package/dist/pi/coding-agent/core/tools/index.js +111 -0
  143. package/dist/pi/coding-agent/core/tools/ls.js +168 -0
  144. package/dist/pi/coding-agent/core/tools/output-accumulator.js +183 -0
  145. package/dist/pi/coding-agent/core/tools/path-utils.js +61 -0
  146. package/dist/pi/coding-agent/core/tools/read.js +288 -0
  147. package/dist/pi/coding-agent/core/tools/render-utils.js +48 -0
  148. package/dist/pi/coding-agent/core/tools/tool-definition-wrapper.js +33 -0
  149. package/dist/pi/coding-agent/core/tools/truncate.js +214 -0
  150. package/dist/pi/coding-agent/core/tools/write.js +212 -0
  151. package/dist/pi/coding-agent/index.js +41 -0
  152. package/dist/pi/coding-agent/main.js +5 -0
  153. package/dist/pi/coding-agent/migrations.js +280 -0
  154. package/dist/pi/coding-agent/modes/index.js +7 -0
  155. package/dist/pi/coding-agent/modes/interactive/components/diff.js +132 -0
  156. package/dist/pi/coding-agent/modes/interactive/components/keybinding-hints.js +35 -0
  157. package/dist/pi/coding-agent/modes/interactive/components/visual-truncate.js +32 -0
  158. package/dist/pi/coding-agent/modes/interactive/interactive-mode.js +3 -0
  159. package/dist/pi/coding-agent/modes/interactive/theme/theme.js +1023 -0
  160. package/dist/pi/coding-agent/modes/print-mode.js +130 -0
  161. package/dist/pi/coding-agent/modes/rpc/jsonl.js +48 -0
  162. package/dist/pi/coding-agent/modes/rpc/rpc-client.js +409 -0
  163. package/dist/pi/coding-agent/modes/rpc/rpc-mode.js +600 -0
  164. package/dist/pi/coding-agent/modes/rpc/rpc-types.js +7 -0
  165. package/dist/pi/coding-agent/utils/ansi.js +51 -0
  166. package/dist/pi/coding-agent/utils/changelog.js +86 -0
  167. package/dist/pi/coding-agent/utils/child-process.js +87 -0
  168. package/dist/pi/coding-agent/utils/clipboard-image.js +244 -0
  169. package/dist/pi/coding-agent/utils/clipboard-native.js +13 -0
  170. package/dist/pi/coding-agent/utils/clipboard.js +116 -0
  171. package/dist/pi/coding-agent/utils/exif-orientation.js +157 -0
  172. package/dist/pi/coding-agent/utils/frontmatter.js +25 -0
  173. package/dist/pi/coding-agent/utils/fs-watch.js +24 -0
  174. package/dist/pi/coding-agent/utils/git.js +162 -0
  175. package/dist/pi/coding-agent/utils/html.js +39 -0
  176. package/dist/pi/coding-agent/utils/image-convert.js +38 -0
  177. package/dist/pi/coding-agent/utils/image-resize.js +136 -0
  178. package/dist/pi/coding-agent/utils/mime.js +68 -0
  179. package/dist/pi/coding-agent/utils/paths.js +91 -0
  180. package/dist/pi/coding-agent/utils/photon.js +120 -0
  181. package/dist/pi/coding-agent/utils/pi-user-agent.js +4 -0
  182. package/dist/pi/coding-agent/utils/shell.js +194 -0
  183. package/dist/pi/coding-agent/utils/sleep.js +16 -0
  184. package/dist/pi/coding-agent/utils/syntax-highlight.js +117 -0
  185. package/dist/pi/coding-agent/utils/tools-manager.js +327 -0
  186. package/dist/pi/coding-agent/utils/version-check.js +81 -0
  187. package/dist/pi/coding-agent/utils/windows-self-update.js +76 -0
  188. package/dist/pi/tui/autocomplete.js +631 -0
  189. package/dist/pi/tui/components/box.js +103 -0
  190. package/dist/pi/tui/components/cancellable-loader.js +34 -0
  191. package/dist/pi/tui/components/editor.js +1915 -0
  192. package/dist/pi/tui/components/image.js +88 -0
  193. package/dist/pi/tui/components/input.js +425 -0
  194. package/dist/pi/tui/components/loader.js +68 -0
  195. package/dist/pi/tui/components/markdown.js +633 -0
  196. package/dist/pi/tui/components/select-list.js +158 -0
  197. package/dist/pi/tui/components/settings-list.js +184 -0
  198. package/dist/pi/tui/components/spacer.js +22 -0
  199. package/dist/pi/tui/components/text.js +88 -0
  200. package/dist/pi/tui/components/truncated-text.js +50 -0
  201. package/dist/pi/tui/editor-component.js +1 -0
  202. package/dist/pi/tui/fuzzy.js +109 -0
  203. package/dist/pi/tui/index.js +31 -0
  204. package/dist/pi/tui/keybindings.js +173 -0
  205. package/dist/pi/tui/keys.js +1172 -0
  206. package/dist/pi/tui/kill-ring.js +43 -0
  207. package/dist/pi/tui/stdin-buffer.js +360 -0
  208. package/dist/pi/tui/terminal-image.js +335 -0
  209. package/dist/pi/tui/terminal.js +324 -0
  210. package/dist/pi/tui/tui.js +1076 -0
  211. package/dist/pi/tui/undo-stack.js +24 -0
  212. package/dist/pi/tui/utils.js +1016 -0
  213. package/dist/relay/dispatcher.js +30 -0
  214. package/dist/server/handlers/queue.js +52 -0
  215. package/dist/server/pi-bridge.js +9 -1
  216. package/dist/server/session-stream.js +76 -111
  217. package/dist/server/storage.js +154 -2
  218. package/dist/server/title-generator.js +14 -153
  219. package/package.json +24 -6
@@ -0,0 +1,113 @@
1
+ import { SessionError, } from "../types.js";
2
+ import { uuidv7 } from "./uuid.js";
3
+ function updateLabelCache(labelsById, entry) {
4
+ if (entry.type !== "label")
5
+ return;
6
+ const label = entry.label?.trim();
7
+ if (label) {
8
+ labelsById.set(entry.targetId, label);
9
+ }
10
+ else {
11
+ labelsById.delete(entry.targetId);
12
+ }
13
+ }
14
+ function buildLabelsById(entries) {
15
+ const labelsById = new Map();
16
+ for (const entry of entries) {
17
+ updateLabelCache(labelsById, entry);
18
+ }
19
+ return labelsById;
20
+ }
21
+ function generateEntryId(byId) {
22
+ for (let i = 0; i < 100; i++) {
23
+ const id = uuidv7().slice(0, 8);
24
+ if (!byId.has(id))
25
+ return id;
26
+ }
27
+ return uuidv7();
28
+ }
29
+ function leafIdAfterEntry(entry) {
30
+ return entry.type === "leaf" ? entry.targetId : entry.id;
31
+ }
32
+ export class InMemorySessionStorage {
33
+ metadata;
34
+ entries;
35
+ byId;
36
+ labelsById;
37
+ leafId;
38
+ constructor(options) {
39
+ this.entries = options?.entries ? [...options.entries] : [];
40
+ this.byId = new Map(this.entries.map((entry) => [entry.id, entry]));
41
+ this.labelsById = buildLabelsById(this.entries);
42
+ this.leafId = null;
43
+ for (const entry of this.entries)
44
+ this.leafId = leafIdAfterEntry(entry);
45
+ if (this.leafId !== null && !this.byId.has(this.leafId)) {
46
+ throw new SessionError("invalid_session", `Entry ${this.leafId} not found`);
47
+ }
48
+ this.metadata = options?.metadata ?? { id: uuidv7(), createdAt: new Date().toISOString() };
49
+ }
50
+ async getMetadata() {
51
+ return this.metadata;
52
+ }
53
+ async getLeafId() {
54
+ if (this.leafId !== null && !this.byId.has(this.leafId)) {
55
+ throw new SessionError("invalid_session", `Entry ${this.leafId} not found`);
56
+ }
57
+ return this.leafId;
58
+ }
59
+ async setLeafId(leafId) {
60
+ if (leafId !== null && !this.byId.has(leafId)) {
61
+ throw new SessionError("not_found", `Entry ${leafId} not found`);
62
+ }
63
+ const entry = {
64
+ type: "leaf",
65
+ id: generateEntryId(this.byId),
66
+ parentId: this.leafId,
67
+ timestamp: new Date().toISOString(),
68
+ targetId: leafId,
69
+ };
70
+ this.entries.push(entry);
71
+ this.byId.set(entry.id, entry);
72
+ this.leafId = leafId;
73
+ }
74
+ async createEntryId() {
75
+ return generateEntryId(this.byId);
76
+ }
77
+ async appendEntry(entry) {
78
+ this.entries.push(entry);
79
+ this.byId.set(entry.id, entry);
80
+ updateLabelCache(this.labelsById, entry);
81
+ this.leafId = leafIdAfterEntry(entry);
82
+ }
83
+ async getEntry(id) {
84
+ return this.byId.get(id);
85
+ }
86
+ async findEntries(type) {
87
+ return this.entries.filter((entry) => entry.type === type);
88
+ }
89
+ async getLabel(id) {
90
+ return this.labelsById.get(id);
91
+ }
92
+ async getPathToRoot(leafId) {
93
+ if (leafId === null)
94
+ return [];
95
+ const path = [];
96
+ let current = this.byId.get(leafId);
97
+ if (!current)
98
+ throw new SessionError("not_found", `Entry ${leafId} not found`);
99
+ while (current) {
100
+ path.unshift(current);
101
+ if (!current.parentId)
102
+ break;
103
+ const parent = this.byId.get(current.parentId);
104
+ if (!parent)
105
+ throw new SessionError("invalid_session", `Entry ${current.parentId} not found`);
106
+ current = parent;
107
+ }
108
+ return path;
109
+ }
110
+ async getEntries() {
111
+ return [...this.entries];
112
+ }
113
+ }
@@ -0,0 +1,38 @@
1
+ import { SessionError, } from "../types.js";
2
+ import { Session } from "./session.js";
3
+ import { uuidv7 } from "./uuid.js";
4
+ export function createSessionId() {
5
+ return uuidv7();
6
+ }
7
+ export function createTimestamp() {
8
+ return new Date().toISOString();
9
+ }
10
+ export function toSession(storage) {
11
+ return new Session(storage);
12
+ }
13
+ export function getFileSystemResultOrThrow(result, message) {
14
+ if (!result.ok) {
15
+ const code = result.error.code === "not_found" ? "not_found" : "storage";
16
+ throw new SessionError(code, `${message}: ${result.error.message}`, result.error);
17
+ }
18
+ return result.value;
19
+ }
20
+ export async function getEntriesToFork(storage, options) {
21
+ if (!options.entryId)
22
+ return storage.getEntries();
23
+ const target = await storage.getEntry(options.entryId);
24
+ if (!target) {
25
+ throw new SessionError("invalid_fork_target", `Entry ${options.entryId} not found`);
26
+ }
27
+ let effectiveLeafId;
28
+ if ((options.position ?? "before") === "at") {
29
+ effectiveLeafId = target.id;
30
+ }
31
+ else {
32
+ if (target.type !== "message" || target.message.role !== "user") {
33
+ throw new SessionError("invalid_fork_target", `Entry ${options.entryId} is not a user message`);
34
+ }
35
+ effectiveLeafId = target.parentId;
36
+ }
37
+ return storage.getPathToRoot(effectiveLeafId);
38
+ }
@@ -0,0 +1,196 @@
1
+ import { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage } from "../messages.js";
2
+ import { SessionError } from "../types.js";
3
+ export function buildSessionContext(pathEntries) {
4
+ let thinkingLevel = "off";
5
+ let model = null;
6
+ let compaction = null;
7
+ for (const entry of pathEntries) {
8
+ if (entry.type === "thinking_level_change") {
9
+ thinkingLevel = entry.thinkingLevel;
10
+ }
11
+ else if (entry.type === "model_change") {
12
+ model = { provider: entry.provider, modelId: entry.modelId };
13
+ }
14
+ else if (entry.type === "message" && entry.message.role === "assistant") {
15
+ model = { provider: entry.message.provider, modelId: entry.message.model };
16
+ }
17
+ else if (entry.type === "compaction") {
18
+ compaction = entry;
19
+ }
20
+ }
21
+ const messages = [];
22
+ const appendMessage = (entry) => {
23
+ if (entry.type === "message") {
24
+ messages.push(entry.message);
25
+ }
26
+ else if (entry.type === "custom_message") {
27
+ messages.push(createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp));
28
+ }
29
+ else if (entry.type === "branch_summary" && entry.summary) {
30
+ messages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));
31
+ }
32
+ };
33
+ if (compaction) {
34
+ messages.push(createCompactionSummaryMessage(compaction.summary, compaction.tokensBefore, compaction.timestamp));
35
+ const compactionIdx = pathEntries.findIndex((e) => e.type === "compaction" && e.id === compaction.id);
36
+ let foundFirstKept = false;
37
+ for (let i = 0; i < compactionIdx; i++) {
38
+ const entry = pathEntries[i];
39
+ if (entry.id === compaction.firstKeptEntryId)
40
+ foundFirstKept = true;
41
+ if (foundFirstKept)
42
+ appendMessage(entry);
43
+ }
44
+ for (let i = compactionIdx + 1; i < pathEntries.length; i++) {
45
+ appendMessage(pathEntries[i]);
46
+ }
47
+ }
48
+ else {
49
+ for (const entry of pathEntries) {
50
+ appendMessage(entry);
51
+ }
52
+ }
53
+ return { messages, thinkingLevel, model };
54
+ }
55
+ export class Session {
56
+ storage;
57
+ constructor(storage) {
58
+ this.storage = storage;
59
+ }
60
+ getMetadata() {
61
+ return this.storage.getMetadata();
62
+ }
63
+ getStorage() {
64
+ return this.storage;
65
+ }
66
+ getLeafId() {
67
+ return this.storage.getLeafId();
68
+ }
69
+ getEntry(id) {
70
+ return this.storage.getEntry(id);
71
+ }
72
+ getEntries() {
73
+ return this.storage.getEntries();
74
+ }
75
+ async getBranch(fromId) {
76
+ const leafId = fromId ?? (await this.storage.getLeafId());
77
+ return this.storage.getPathToRoot(leafId);
78
+ }
79
+ async buildContext() {
80
+ return buildSessionContext(await this.getBranch());
81
+ }
82
+ getLabel(id) {
83
+ return this.storage.getLabel(id);
84
+ }
85
+ async getSessionName() {
86
+ const entries = await this.storage.findEntries("session_info");
87
+ return entries[entries.length - 1]?.name?.trim() || undefined;
88
+ }
89
+ async appendTypedEntry(entry) {
90
+ await this.storage.appendEntry(entry);
91
+ return entry.id;
92
+ }
93
+ async appendMessage(message) {
94
+ return this.appendTypedEntry({
95
+ type: "message",
96
+ id: await this.storage.createEntryId(),
97
+ parentId: await this.storage.getLeafId(),
98
+ timestamp: new Date().toISOString(),
99
+ message,
100
+ });
101
+ }
102
+ async appendThinkingLevelChange(thinkingLevel) {
103
+ return this.appendTypedEntry({
104
+ type: "thinking_level_change",
105
+ id: await this.storage.createEntryId(),
106
+ parentId: await this.storage.getLeafId(),
107
+ timestamp: new Date().toISOString(),
108
+ thinkingLevel,
109
+ });
110
+ }
111
+ async appendModelChange(provider, modelId) {
112
+ return this.appendTypedEntry({
113
+ type: "model_change",
114
+ id: await this.storage.createEntryId(),
115
+ parentId: await this.storage.getLeafId(),
116
+ timestamp: new Date().toISOString(),
117
+ provider,
118
+ modelId,
119
+ });
120
+ }
121
+ async appendCompaction(summary, firstKeptEntryId, tokensBefore, details, fromHook) {
122
+ return this.appendTypedEntry({
123
+ type: "compaction",
124
+ id: await this.storage.createEntryId(),
125
+ parentId: await this.storage.getLeafId(),
126
+ timestamp: new Date().toISOString(),
127
+ summary,
128
+ firstKeptEntryId,
129
+ tokensBefore,
130
+ details,
131
+ fromHook,
132
+ });
133
+ }
134
+ async appendCustomEntry(customType, data) {
135
+ return this.appendTypedEntry({
136
+ type: "custom",
137
+ id: await this.storage.createEntryId(),
138
+ parentId: await this.storage.getLeafId(),
139
+ timestamp: new Date().toISOString(),
140
+ customType,
141
+ data,
142
+ });
143
+ }
144
+ async appendCustomMessageEntry(customType, content, display, details) {
145
+ return this.appendTypedEntry({
146
+ type: "custom_message",
147
+ id: await this.storage.createEntryId(),
148
+ parentId: await this.storage.getLeafId(),
149
+ timestamp: new Date().toISOString(),
150
+ customType,
151
+ content,
152
+ display,
153
+ details,
154
+ });
155
+ }
156
+ async appendLabel(targetId, label) {
157
+ if (!(await this.storage.getEntry(targetId))) {
158
+ throw new SessionError("not_found", `Entry ${targetId} not found`);
159
+ }
160
+ return this.appendTypedEntry({
161
+ type: "label",
162
+ id: await this.storage.createEntryId(),
163
+ parentId: await this.storage.getLeafId(),
164
+ timestamp: new Date().toISOString(),
165
+ targetId,
166
+ label,
167
+ });
168
+ }
169
+ async appendSessionName(name) {
170
+ return this.appendTypedEntry({
171
+ type: "session_info",
172
+ id: await this.storage.createEntryId(),
173
+ parentId: await this.storage.getLeafId(),
174
+ timestamp: new Date().toISOString(),
175
+ name: name.trim(),
176
+ });
177
+ }
178
+ async moveTo(entryId, summary) {
179
+ if (entryId !== null && !(await this.storage.getEntry(entryId))) {
180
+ throw new SessionError("not_found", `Entry ${entryId} not found`);
181
+ }
182
+ await this.storage.setLeafId(entryId);
183
+ if (!summary)
184
+ return undefined;
185
+ return this.appendTypedEntry({
186
+ type: "branch_summary",
187
+ id: await this.storage.createEntryId(),
188
+ parentId: entryId,
189
+ timestamp: new Date().toISOString(),
190
+ fromId: entryId ?? "root",
191
+ summary: summary.summary,
192
+ details: summary.details,
193
+ fromHook: summary.fromHook,
194
+ });
195
+ }
196
+ }
@@ -0,0 +1,49 @@
1
+ let lastTimestamp = -Infinity;
2
+ let sequence = 0;
3
+ function fillRandomBytes(bytes) {
4
+ const crypto = globalThis.crypto;
5
+ if (crypto?.getRandomValues) {
6
+ crypto.getRandomValues(bytes);
7
+ return;
8
+ }
9
+ for (let i = 0; i < bytes.length; i++) {
10
+ bytes[i] = Math.floor(Math.random() * 256);
11
+ }
12
+ }
13
+ export function uuidv7() {
14
+ const random = new Uint8Array(16);
15
+ fillRandomBytes(random);
16
+ const timestamp = Date.now();
17
+ if (timestamp > lastTimestamp) {
18
+ sequence = random[6] * 0x1000000 + random[7] * 0x10000 + random[8] * 0x100 + random[9];
19
+ lastTimestamp = timestamp;
20
+ }
21
+ else {
22
+ sequence = (sequence + 1) >>> 0;
23
+ if (sequence === 0) {
24
+ lastTimestamp++;
25
+ }
26
+ }
27
+ const bytes = new Uint8Array(16);
28
+ bytes[0] = (lastTimestamp / 0x10000000000) & 0xff;
29
+ bytes[1] = (lastTimestamp / 0x100000000) & 0xff;
30
+ bytes[2] = (lastTimestamp / 0x1000000) & 0xff;
31
+ bytes[3] = (lastTimestamp / 0x10000) & 0xff;
32
+ bytes[4] = (lastTimestamp / 0x100) & 0xff;
33
+ bytes[5] = lastTimestamp & 0xff;
34
+ bytes[6] = 0x70 | ((sequence >>> 28) & 0x0f);
35
+ bytes[7] = (sequence >>> 20) & 0xff;
36
+ bytes[8] = 0x80 | ((sequence >>> 14) & 0x3f);
37
+ bytes[9] = (sequence >>> 6) & 0xff;
38
+ bytes[10] = ((sequence & 0x3f) << 2) | (random[10] & 0x03);
39
+ bytes[11] = random[11];
40
+ bytes[12] = random[12];
41
+ bytes[13] = random[13];
42
+ bytes[14] = random[14];
43
+ bytes[15] = random[15];
44
+ return formatUuid(bytes);
45
+ }
46
+ function formatUuid(bytes) {
47
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
48
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10, 16).join("")}`;
49
+ }