@prestyj/cli 5.2.0 → 5.3.1

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 (192) hide show
  1. package/dist/app-sidecar.js +856 -91
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/core/agent-session-compaction.test.js +89 -0
  4. package/dist/core/agent-session-compaction.test.js.map +1 -1
  5. package/dist/core/agent-session-queue.test.d.ts +2 -0
  6. package/dist/core/agent-session-queue.test.d.ts.map +1 -0
  7. package/dist/core/agent-session-queue.test.js +122 -0
  8. package/dist/core/agent-session-queue.test.js.map +1 -0
  9. package/dist/core/agent-session.d.ts +79 -3
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +268 -47
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/autopilot-cycle.d.ts +119 -0
  14. package/dist/core/autopilot-cycle.d.ts.map +1 -0
  15. package/dist/core/autopilot-cycle.js +119 -0
  16. package/dist/core/autopilot-cycle.js.map +1 -0
  17. package/dist/core/autopilot-cycle.test.d.ts +2 -0
  18. package/dist/core/autopilot-cycle.test.d.ts.map +1 -0
  19. package/dist/core/autopilot-cycle.test.js +375 -0
  20. package/dist/core/autopilot-cycle.test.js.map +1 -0
  21. package/dist/core/autopilot-gate.d.ts +109 -0
  22. package/dist/core/autopilot-gate.d.ts.map +1 -0
  23. package/dist/core/autopilot-gate.js +205 -0
  24. package/dist/core/autopilot-gate.js.map +1 -0
  25. package/dist/core/autopilot-gate.test.d.ts +2 -0
  26. package/dist/core/autopilot-gate.test.d.ts.map +1 -0
  27. package/dist/core/autopilot-gate.test.js +295 -0
  28. package/dist/core/autopilot-gate.test.js.map +1 -0
  29. package/dist/core/autopilot-verdict.d.ts +20 -2
  30. package/dist/core/autopilot-verdict.d.ts.map +1 -1
  31. package/dist/core/autopilot-verdict.js +94 -3
  32. package/dist/core/autopilot-verdict.js.map +1 -1
  33. package/dist/core/autopilot-verdict.test.js +73 -0
  34. package/dist/core/autopilot-verdict.test.js.map +1 -1
  35. package/dist/core/bash-spawn-benchmark.d.ts +2 -0
  36. package/dist/core/bash-spawn-benchmark.d.ts.map +1 -0
  37. package/dist/core/bash-spawn-benchmark.js +139 -0
  38. package/dist/core/bash-spawn-benchmark.js.map +1 -0
  39. package/dist/core/hashline-edit-benchmark.d.ts +33 -1
  40. package/dist/core/hashline-edit-benchmark.d.ts.map +1 -1
  41. package/dist/core/hashline-edit-benchmark.js +193 -21
  42. package/dist/core/hashline-edit-benchmark.js.map +1 -1
  43. package/dist/core/hashline-edit-benchmark.test.js +51 -2
  44. package/dist/core/hashline-edit-benchmark.test.js.map +1 -1
  45. package/dist/core/json-mode-flag-parity.test.d.ts +2 -0
  46. package/dist/core/json-mode-flag-parity.test.d.ts.map +1 -0
  47. package/dist/core/json-mode-flag-parity.test.js +66 -0
  48. package/dist/core/json-mode-flag-parity.test.js.map +1 -0
  49. package/dist/core/mcp/deferred-catalog.d.ts +28 -0
  50. package/dist/core/mcp/deferred-catalog.d.ts.map +1 -0
  51. package/dist/core/mcp/deferred-catalog.js +72 -0
  52. package/dist/core/mcp/deferred-catalog.js.map +1 -0
  53. package/dist/core/mcp/resolve-stdio.d.ts +19 -3
  54. package/dist/core/mcp/resolve-stdio.d.ts.map +1 -1
  55. package/dist/core/mcp/resolve-stdio.js +136 -5
  56. package/dist/core/mcp/resolve-stdio.js.map +1 -1
  57. package/dist/core/mcp/resolve-stdio.test.js +82 -1
  58. package/dist/core/mcp/resolve-stdio.test.js.map +1 -1
  59. package/dist/core/nolan-context.d.ts +43 -2
  60. package/dist/core/nolan-context.d.ts.map +1 -1
  61. package/dist/core/nolan-context.js +91 -8
  62. package/dist/core/nolan-context.js.map +1 -1
  63. package/dist/core/nolan-context.test.js +167 -5
  64. package/dist/core/nolan-context.test.js.map +1 -1
  65. package/dist/core/nolan-model.d.ts +46 -0
  66. package/dist/core/nolan-model.d.ts.map +1 -0
  67. package/dist/core/nolan-model.js +30 -0
  68. package/dist/core/nolan-model.js.map +1 -0
  69. package/dist/core/nolan-model.test.d.ts +2 -0
  70. package/dist/core/nolan-model.test.d.ts.map +1 -0
  71. package/dist/core/nolan-model.test.js +51 -0
  72. package/dist/core/nolan-model.test.js.map +1 -0
  73. package/dist/core/nolan-prompt.d.ts +5 -18
  74. package/dist/core/nolan-prompt.d.ts.map +1 -1
  75. package/dist/core/nolan-prompt.js +112 -19
  76. package/dist/core/nolan-prompt.js.map +1 -1
  77. package/dist/core/nolan-prompt.test.d.ts +2 -0
  78. package/dist/core/nolan-prompt.test.d.ts.map +1 -0
  79. package/dist/core/nolan-prompt.test.js +138 -0
  80. package/dist/core/nolan-prompt.test.js.map +1 -0
  81. package/dist/core/persistent-shell.d.ts +27 -0
  82. package/dist/core/persistent-shell.d.ts.map +1 -0
  83. package/dist/core/persistent-shell.js +150 -0
  84. package/dist/core/persistent-shell.js.map +1 -0
  85. package/dist/core/persistent-shell.test.d.ts +2 -0
  86. package/dist/core/persistent-shell.test.d.ts.map +1 -0
  87. package/dist/core/persistent-shell.test.js +84 -0
  88. package/dist/core/persistent-shell.test.js.map +1 -0
  89. package/dist/core/process-manager-dev-server-repro.test.js +34 -6
  90. package/dist/core/process-manager-dev-server-repro.test.js.map +1 -1
  91. package/dist/core/progress/engine.d.ts +23 -0
  92. package/dist/core/progress/engine.d.ts.map +1 -0
  93. package/dist/core/progress/engine.js +131 -0
  94. package/dist/core/progress/engine.js.map +1 -0
  95. package/dist/core/progress/engine.test.d.ts +2 -0
  96. package/dist/core/progress/engine.test.d.ts.map +1 -0
  97. package/dist/core/progress/engine.test.js +136 -0
  98. package/dist/core/progress/engine.test.js.map +1 -0
  99. package/dist/core/progress/git-xp.d.ts +16 -0
  100. package/dist/core/progress/git-xp.d.ts.map +1 -0
  101. package/dist/core/progress/git-xp.js +106 -0
  102. package/dist/core/progress/git-xp.js.map +1 -0
  103. package/dist/core/progress/git-xp.test.d.ts +2 -0
  104. package/dist/core/progress/git-xp.test.d.ts.map +1 -0
  105. package/dist/core/progress/git-xp.test.js +88 -0
  106. package/dist/core/progress/git-xp.test.js.map +1 -0
  107. package/dist/core/progress/ranks.d.ts +21 -0
  108. package/dist/core/progress/ranks.d.ts.map +1 -0
  109. package/dist/core/progress/ranks.js +141 -0
  110. package/dist/core/progress/ranks.js.map +1 -0
  111. package/dist/core/progress/ranks.test.d.ts +2 -0
  112. package/dist/core/progress/ranks.test.d.ts.map +1 -0
  113. package/dist/core/progress/ranks.test.js +59 -0
  114. package/dist/core/progress/ranks.test.js.map +1 -0
  115. package/dist/core/progress/rebuild.d.ts +7 -0
  116. package/dist/core/progress/rebuild.d.ts.map +1 -0
  117. package/dist/core/progress/rebuild.js +106 -0
  118. package/dist/core/progress/rebuild.js.map +1 -0
  119. package/dist/core/progress/rebuild.test.d.ts +2 -0
  120. package/dist/core/progress/rebuild.test.d.ts.map +1 -0
  121. package/dist/core/progress/rebuild.test.js +72 -0
  122. package/dist/core/progress/rebuild.test.js.map +1 -0
  123. package/dist/core/progress/store.d.ts +35 -0
  124. package/dist/core/progress/store.d.ts.map +1 -0
  125. package/dist/core/progress/store.js +200 -0
  126. package/dist/core/progress/store.js.map +1 -0
  127. package/dist/core/progress/store.test.d.ts +2 -0
  128. package/dist/core/progress/store.test.d.ts.map +1 -0
  129. package/dist/core/progress/store.test.js +108 -0
  130. package/dist/core/progress/store.test.js.map +1 -0
  131. package/dist/core/progress/types.d.ts +108 -0
  132. package/dist/core/progress/types.d.ts.map +1 -0
  133. package/dist/core/progress/types.js +3 -0
  134. package/dist/core/progress/types.js.map +1 -0
  135. package/dist/core/project-discovery.d.ts.map +1 -1
  136. package/dist/core/project-discovery.js +40 -9
  137. package/dist/core/project-discovery.js.map +1 -1
  138. package/dist/core/project-discovery.test.d.ts +2 -0
  139. package/dist/core/project-discovery.test.d.ts.map +1 -0
  140. package/dist/core/project-discovery.test.js +104 -0
  141. package/dist/core/project-discovery.test.js.map +1 -0
  142. package/dist/core/session-history.d.ts +51 -0
  143. package/dist/core/session-history.d.ts.map +1 -0
  144. package/dist/core/session-history.js +156 -0
  145. package/dist/core/session-history.js.map +1 -0
  146. package/dist/core/session-history.test.d.ts +2 -0
  147. package/dist/core/session-history.test.d.ts.map +1 -0
  148. package/dist/core/session-history.test.js +101 -0
  149. package/dist/core/session-history.test.js.map +1 -0
  150. package/dist/core/session-manager.d.ts +34 -0
  151. package/dist/core/session-manager.d.ts.map +1 -1
  152. package/dist/core/session-manager.js +67 -0
  153. package/dist/core/session-manager.js.map +1 -1
  154. package/dist/core/session-manager.test.js +140 -1
  155. package/dist/core/session-manager.test.js.map +1 -1
  156. package/dist/core/settings-manager.d.ts +1 -0
  157. package/dist/core/settings-manager.d.ts.map +1 -1
  158. package/dist/core/settings-manager.js +4 -0
  159. package/dist/core/settings-manager.js.map +1 -1
  160. package/dist/core/speed-benchmark.test.js +2 -3
  161. package/dist/core/speed-benchmark.test.js.map +1 -1
  162. package/dist/system-prompt.d.ts.map +1 -1
  163. package/dist/system-prompt.js +12 -8
  164. package/dist/system-prompt.js.map +1 -1
  165. package/dist/system-prompt.test.js +15 -20
  166. package/dist/system-prompt.test.js.map +1 -1
  167. package/dist/tools/bash.d.ts +1 -0
  168. package/dist/tools/bash.d.ts.map +1 -1
  169. package/dist/tools/bash.js +27 -2
  170. package/dist/tools/bash.js.map +1 -1
  171. package/dist/tools/edit.d.ts +9 -2
  172. package/dist/tools/edit.d.ts.map +1 -1
  173. package/dist/tools/edit.js +91 -10
  174. package/dist/tools/edit.js.map +1 -1
  175. package/dist/tools/edit.test.js +97 -0
  176. package/dist/tools/edit.test.js.map +1 -1
  177. package/dist/tools/plan-mode.test.js +25 -0
  178. package/dist/tools/plan-mode.test.js.map +1 -1
  179. package/dist/tools/prompt-hints.d.ts.map +1 -1
  180. package/dist/tools/prompt-hints.js +3 -0
  181. package/dist/tools/prompt-hints.js.map +1 -1
  182. package/dist/tools/subagent.d.ts.map +1 -1
  183. package/dist/tools/subagent.js +24 -1
  184. package/dist/tools/subagent.js.map +1 -1
  185. package/dist/tools/tool-search.d.ts +15 -0
  186. package/dist/tools/tool-search.d.ts.map +1 -0
  187. package/dist/tools/tool-search.js +35 -0
  188. package/dist/tools/tool-search.js.map +1 -0
  189. package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
  190. package/dist/ui/hooks/useAgentLoop.js +22 -9
  191. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  192. package/package.json +5 -5
@@ -0,0 +1,104 @@
1
+ import fs from "node:fs/promises";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
+ import { encodeCwd } from "./encode-cwd.js";
6
+ import { discoverProjects } from "./project-discovery.js";
7
+ // Holder the hoisted mock reads at call time (vi.mock is hoisted above imports,
8
+ // so it can't close over a value assigned later without this indirection).
9
+ const state = { sessionsDir: "" };
10
+ vi.mock("../config.js", async (orig) => {
11
+ const actual = await orig();
12
+ return {
13
+ ...actual,
14
+ getAppPaths: () => ({ ...actual.getAppPaths(), sessionsDir: state.sessionsDir }),
15
+ };
16
+ });
17
+ /** Write a minimal ezcoder session file (header + one message) into `dir`. */
18
+ async function writeSession(dir, cwd) {
19
+ await fs.mkdir(dir, { recursive: true });
20
+ const header = JSON.stringify({
21
+ type: "session",
22
+ version: 2,
23
+ id: "11111111-1111-1111-1111-111111111111",
24
+ timestamp: new Date().toISOString(),
25
+ cwd,
26
+ provider: "anthropic",
27
+ model: "claude-sonnet-5",
28
+ });
29
+ const message = JSON.stringify({
30
+ type: "message",
31
+ id: "22222222-2222-2222-2222-222222222222",
32
+ timestamp: new Date().toISOString(),
33
+ message: { role: "user", content: "hi" },
34
+ });
35
+ await fs.writeFile(path.join(dir, "session.jsonl"), `${header}\n${message}\n`, "utf-8");
36
+ }
37
+ describe("discoverProjects (ezcoder store)", () => {
38
+ let tmp;
39
+ beforeEach(async () => {
40
+ tmp = await fs.mkdtemp(path.join(os.tmpdir(), "gg-discovery-"));
41
+ state.sessionsDir = path.join(tmp, ".ezcoder", "sessions");
42
+ await fs.mkdir(state.sessionsDir, { recursive: true });
43
+ // Point Claude/Codex discovery at an empty home so they contribute nothing.
44
+ vi.spyOn(os, "homedir").mockReturnValue(path.join(tmp, "home"));
45
+ });
46
+ afterEach(async () => {
47
+ vi.restoreAllMocks();
48
+ await fs.rm(tmp, { recursive: true, force: true });
49
+ });
50
+ it("lists a project whose folder name contains an underscore (regression)", async () => {
51
+ // Real project path with a literal underscore — the lossy slash→underscore
52
+ // decode would resolve this to `.../projects/my/app`, which doesn't exist,
53
+ // so the project used to silently vanish from the picker.
54
+ const projectPath = path.join(tmp, "projects", "my_app");
55
+ await fs.mkdir(projectPath, { recursive: true });
56
+ await writeSession(path.join(state.sessionsDir, encodeCwd(projectPath)), projectPath);
57
+ const projects = await discoverProjects();
58
+ const found = projects.find((p) => p.path === projectPath);
59
+ expect(found).toBeDefined();
60
+ expect(found?.name).toBe("my_app");
61
+ expect(found?.sources).toContain("ezcoder");
62
+ // The lossy decode must NOT surface as a phantom project.
63
+ expect(projects.some((p) => p.path === path.join(tmp, "projects", "my", "app"))).toBe(false);
64
+ });
65
+ it("keys the project off the header cwd, not the directory name", async () => {
66
+ // The real cwd lives in the session header; the directory name is only a
67
+ // lossy hint. Prove the header wins by giving the dir an arbitrary name
68
+ // (as happens for a copied/renamed session store) whose underscore-decode
69
+ // would resolve somewhere else entirely — the project must still resolve to
70
+ // the header's true underscore path.
71
+ const projectPath = path.join(tmp, "projects", "my_app");
72
+ await fs.mkdir(projectPath, { recursive: true });
73
+ await writeSession(path.join(state.sessionsDir, "arbitrary-store-name"), projectPath);
74
+ const projects = await discoverProjects();
75
+ const found = projects.find((p) => p.path === projectPath);
76
+ expect(found).toBeDefined();
77
+ expect(found?.name).toBe("my_app");
78
+ // The decode of "arbitrary-store-name" (an existing-looking rel path) must
79
+ // not surface as its own phantom project.
80
+ expect(projects.some((p) => p.path.endsWith("arbitrary-store-name"))).toBe(false);
81
+ });
82
+ // The best-effort decode only round-trips for underscore-free absolute paths
83
+ // (that's the whole point of the header fix). macOS's own os.tmpdir() contains
84
+ // a literal underscore, so this test roots its project under posix /tmp to get
85
+ // an underscore-free path; skip on Windows where that root doesn't exist.
86
+ it.skipIf(process.platform === "win32")("falls back to underscore decode when a session file carries no cwd header", async () => {
87
+ const root = await fs.mkdtemp("/tmp/ggfallback-");
88
+ try {
89
+ // Legacy/headerless session dir: no `type:"session"` line. The decode
90
+ // still lists it as long as the decoded path exists on disk.
91
+ const projectPath = path.join(root, "legacy");
92
+ await fs.mkdir(projectPath, { recursive: true });
93
+ const dir = path.join(state.sessionsDir, encodeCwd(projectPath));
94
+ await fs.mkdir(dir, { recursive: true });
95
+ await fs.writeFile(path.join(dir, "session.jsonl"), `${JSON.stringify({ type: "message", message: { role: "user", content: "hi" } })}\n`, "utf-8");
96
+ const projects = await discoverProjects();
97
+ expect(projects.find((p) => p.path === projectPath)).toBeDefined();
98
+ }
99
+ finally {
100
+ await fs.rm(root, { recursive: true, force: true });
101
+ }
102
+ });
103
+ });
104
+ //# sourceMappingURL=project-discovery.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-discovery.test.js","sourceRoot":"","sources":["../../src/core/project-discovery.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAGzE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,gFAAgF;AAChF,2EAA2E;AAC3E,MAAM,KAAK,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;AAElC,EAAE,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;IACrC,MAAM,MAAM,GAAG,MAAM,IAAI,EAAuB,CAAC;IACjD,OAAO;QACL,GAAG,MAAM;QACT,WAAW,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,WAAW,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;KACjF,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAC9E,KAAK,UAAU,YAAY,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC;QAC5B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,CAAC;QACV,EAAE,EAAE,sCAAsC;QAC1C,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,GAAG;QACH,QAAQ,EAAE,WAAW;QACrB,KAAK,EAAE,iBAAiB;KACzB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7B,IAAI,EAAE,SAAS;QACf,EAAE,EAAE,sCAAsC;QAC1C,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;KACzC,CAAC,CAAC;IACH,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,EAAE,GAAG,MAAM,KAAK,OAAO,IAAI,EAAE,OAAO,CAAC,CAAC;AAC1F,CAAC;AAED,QAAQ,CAAC,kCAAkC,EAAE,GAAG,EAAE;IAChD,IAAI,GAAW,CAAC;IAEhB,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;QAChE,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QAC3D,MAAM,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,4EAA4E;QAC5E,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,EAAE,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,2EAA2E;QAC3E,2EAA2E;QAC3E,0DAA0D;QAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzD,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;QAEtF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAE1C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC5C,0DAA0D;QAC1D,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC3E,yEAAyE;QACzE,wEAAwE;QACxE,0EAA0E;QAC1E,4EAA4E;QAC5E,qCAAqC;QACrC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QACzD,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACjD,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,sBAAsB,CAAC,EAAE,WAAW,CAAC,CAAC;QAEtF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,2EAA2E;QAC3E,0CAA0C;QAC1C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,6EAA6E;IAC7E,+EAA+E;IAC/E,+EAA+E;IAC/E,0EAA0E;IAC1E,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CACrC,2EAA2E,EAC3E,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAClD,IAAI,CAAC;YACH,sEAAsE;YACtE,6DAA6D;YAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YAC9C,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACjD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;YACjE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACzC,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,EAC/B,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EACpF,OAAO,CACR,CAAC;YAEF,MAAM,QAAQ,GAAG,MAAM,gBAAgB,EAAE,CAAC;YAC1C,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACrE,CAAC;gBAAS,CAAC;YACT,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -0,0 +1,51 @@
1
+ import type { Message } from "@prestyj/ai";
2
+ import type { AutopilotMarkerPayload, AppMarkerPayload, NolanTurnPayload } from "./session-manager.js";
3
+ export interface HistoryAutopilotMarker extends AutopilotMarkerPayload {
4
+ /** Stable seed derived from persisted marker data for deterministic UI copy. */
5
+ copySeed: string;
6
+ }
7
+ export declare function autopilotMarkerCopySeed(marker: AutopilotMarkerPayload): string;
8
+ /**
9
+ * Normalize persisted autopilot markers for transcript replay.
10
+ *
11
+ * Older compacted/continued sessions may carry markers whose original
12
+ * `afterMessageCount` points beyond the restored message list. Replaying those
13
+ * at EOF bunches old Nolan all-clear bubbles at the bottom, so drop them. Also
14
+ * dedupe exact marker payloads produced by old rewrite/re-persist paths.
15
+ */
16
+ export declare function normalizeAutopilotMarkersForHistory(markers: readonly AutopilotMarkerPayload[], maxAfterMessageCount: number): HistoryAutopilotMarker[];
17
+ /**
18
+ * Normalize persisted app transcript markers for replay: drop markers whose
19
+ * anchor points beyond the restored message list (stale after compaction) and
20
+ * dedupe exact payloads (old rewrite paths could re-append). Mirrors
21
+ * {@link normalizeAutopilotMarkersForHistory}.
22
+ */
23
+ export declare function normalizeAppMarkersForHistory(markers: readonly AppMarkerPayload[], maxAfterMessageCount: number): AppMarkerPayload[];
24
+ /**
25
+ * Normalize persisted Nolan turns for replay. Unlike autopilot/app markers, Nolan
26
+ * turns carry real conversation — an out-of-range anchor (stale after
27
+ * compaction) is CLAMPED to the last message instead of dropped, so the
28
+ * exchange still renders (at the end, in order) rather than vanishing. Exact
29
+ * duplicate payloads (old rewrite/re-persist paths) are deduped.
30
+ */
31
+ export declare function normalizeNolanTurnsForHistory(turns: readonly NolanTurnPayload[], maxAfterMessageCount: number): NolanTurnPayload[];
32
+ export interface RestoredUserRow {
33
+ /** The typed text as the live bubble showed it. */
34
+ text: string;
35
+ /** Attached image data URLs. */
36
+ images: string[];
37
+ /** True when the message carried a video the model could NOT watch natively
38
+ * (live showed an info row after the bubble). */
39
+ videoWarning: boolean;
40
+ }
41
+ /** Rebuild the live user bubble from a persisted user message's content. */
42
+ export declare function restoreUserRow(content: Message["content"]): RestoredUserRow;
43
+ /**
44
+ * Split a persisted assistant message into per-bubble texts. Live streaming
45
+ * ends the assistant bubble at every server_tool_call (see useAgentEvents'
46
+ * server_tool_call case), so pre- and post-tool text render as separate rows.
47
+ * Persisted content keeps that structure as separate text blocks — emit one
48
+ * text per block instead of gluing them into a single row on resume.
49
+ */
50
+ export declare function restoreAssistantTexts(content: Message["content"]): string[];
51
+ //# sourceMappingURL=session-history.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-history.d.ts","sourceRoot":"","sources":["../../src/core/session-history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAI9B,MAAM,WAAW,sBAAuB,SAAQ,sBAAsB;IACpE,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;CAClB;AAWD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAE9E;AAED;;;;;;;GAOG;AACH,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,SAAS,sBAAsB,EAAE,EAC1C,oBAAoB,EAAE,MAAM,GAC3B,sBAAsB,EAAE,CAa1B;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,SAAS,gBAAgB,EAAE,EACpC,oBAAoB,EAAE,MAAM,GAC3B,gBAAgB,EAAE,CAepB;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,SAAS,gBAAgB,EAAE,EAClC,oBAAoB,EAAE,MAAM,GAC3B,gBAAgB,EAAE,CAcpB;AAmBD,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB;sDACkD;IAClD,YAAY,EAAE,OAAO,CAAC;CACvB;AAuBD,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,eAAe,CAwB3E;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,MAAM,EAAE,CAK3E"}
@@ -0,0 +1,156 @@
1
+ import { STEERING_PREFIX } from "./steering.js";
2
+ import { AUTOPILOT_INJECTION_PREAMBLE } from "./autopilot-cycle.js";
3
+ function markerKey(marker) {
4
+ return JSON.stringify({
5
+ phase: marker.phase,
6
+ afterMessageCount: marker.afterMessageCount,
7
+ reason: marker.reason ?? null,
8
+ body: marker.body ?? null,
9
+ });
10
+ }
11
+ export function autopilotMarkerCopySeed(marker) {
12
+ return `${marker.phase}\0${marker.afterMessageCount}\0${marker.reason ?? ""}\0${marker.body ?? ""}`;
13
+ }
14
+ /**
15
+ * Normalize persisted autopilot markers for transcript replay.
16
+ *
17
+ * Older compacted/continued sessions may carry markers whose original
18
+ * `afterMessageCount` points beyond the restored message list. Replaying those
19
+ * at EOF bunches old Nolan all-clear bubbles at the bottom, so drop them. Also
20
+ * dedupe exact marker payloads produced by old rewrite/re-persist paths.
21
+ */
22
+ export function normalizeAutopilotMarkersForHistory(markers, maxAfterMessageCount) {
23
+ const seen = new Set();
24
+ const normalized = [];
25
+ for (const marker of markers) {
26
+ if (marker.afterMessageCount > maxAfterMessageCount)
27
+ continue;
28
+ const key = markerKey(marker);
29
+ if (seen.has(key))
30
+ continue;
31
+ seen.add(key);
32
+ normalized.push({ ...marker, copySeed: autopilotMarkerCopySeed(marker) });
33
+ }
34
+ return normalized;
35
+ }
36
+ /**
37
+ * Normalize persisted app transcript markers for replay: drop markers whose
38
+ * anchor points beyond the restored message list (stale after compaction) and
39
+ * dedupe exact payloads (old rewrite paths could re-append). Mirrors
40
+ * {@link normalizeAutopilotMarkersForHistory}.
41
+ */
42
+ export function normalizeAppMarkersForHistory(markers, maxAfterMessageCount) {
43
+ const seen = new Set();
44
+ const normalized = [];
45
+ for (const marker of markers) {
46
+ if (marker.afterMessageCount > maxAfterMessageCount)
47
+ continue;
48
+ const key = JSON.stringify({
49
+ kind: marker.kind,
50
+ afterMessageCount: marker.afterMessageCount,
51
+ data: marker.data,
52
+ });
53
+ if (seen.has(key))
54
+ continue;
55
+ seen.add(key);
56
+ normalized.push(marker);
57
+ }
58
+ return normalized;
59
+ }
60
+ /**
61
+ * Normalize persisted Nolan turns for replay. Unlike autopilot/app markers, Nolan
62
+ * turns carry real conversation — an out-of-range anchor (stale after
63
+ * compaction) is CLAMPED to the last message instead of dropped, so the
64
+ * exchange still renders (at the end, in order) rather than vanishing. Exact
65
+ * duplicate payloads (old rewrite/re-persist paths) are deduped.
66
+ */
67
+ export function normalizeNolanTurnsForHistory(turns, maxAfterMessageCount) {
68
+ const seen = new Set();
69
+ const normalized = [];
70
+ for (const turn of turns) {
71
+ const key = JSON.stringify({ q: turn.question, r: turn.reply, a: turn.afterMessageCount });
72
+ if (seen.has(key))
73
+ continue;
74
+ seen.add(key);
75
+ normalized.push(turn.afterMessageCount > maxAfterMessageCount
76
+ ? { ...turn, afterMessageCount: maxAfterMessageCount }
77
+ : turn);
78
+ }
79
+ return normalized;
80
+ }
81
+ // ── User-row reconstruction ────────────────────────────────────────
82
+ // The persisted user message is what the MODEL saw — steering wrapper, saved-
83
+ // path notes, attached-files block. The live bubble showed only the typed
84
+ // text, so resume must strip the machine framing back out.
85
+ /** Separator AgentSession.buildAttachmentParts uses before the file-notes
86
+ * block appended to a user message's leading text part. */
87
+ const ATTACHED_FILES_HEADER = "Attached files (inspect with your tools):";
88
+ /** Attachment-note text parts injected alongside the typed text. These never
89
+ * appeared in the live user bubble. */
90
+ const ATTACHMENT_NOTE_PATTERNS = [
91
+ /^\[Image saved at .+\]$/s,
92
+ /^The user attached a video at .+/s,
93
+ /^\[User attached a video file .+\]$/s,
94
+ ];
95
+ function stripSteering(text) {
96
+ return text.startsWith(STEERING_PREFIX) ? text.slice(STEERING_PREFIX.length) : text;
97
+ }
98
+ /** Strip the autopilot situational-awareness preamble that the sidecar prepends
99
+ * to every autopilot-injected build-session run (see frameAutopilotInjection).
100
+ * The live transcript shows the clean body via the autopilot "prompted" marker;
101
+ * on resume the raw session message must render the same clean instruction, not
102
+ * the machine-facing preamble. */
103
+ function stripAutopilotPreamble(text) {
104
+ return text.startsWith(AUTOPILOT_INJECTION_PREAMBLE)
105
+ ? text.slice(AUTOPILOT_INJECTION_PREAMBLE.length).trimStart()
106
+ : text;
107
+ }
108
+ function stripAttachedFilesBlock(text) {
109
+ if (text.startsWith(ATTACHED_FILES_HEADER))
110
+ return "";
111
+ const idx = text.indexOf(`\n\n${ATTACHED_FILES_HEADER}`);
112
+ return idx === -1 ? text : text.slice(0, idx);
113
+ }
114
+ /** Rebuild the live user bubble from a persisted user message's content. */
115
+ export function restoreUserRow(content) {
116
+ if (typeof content === "string") {
117
+ return {
118
+ text: stripAttachedFilesBlock(stripAutopilotPreamble(stripSteering(content))).trim(),
119
+ images: [],
120
+ videoWarning: false,
121
+ };
122
+ }
123
+ const images = [];
124
+ const textParts = [];
125
+ let videoWarning = false;
126
+ for (const c of content) {
127
+ if (c.type === "image") {
128
+ images.push(`data:${c.mediaType};base64,${c.data}`);
129
+ continue;
130
+ }
131
+ if (c.type !== "text" || typeof c.text !== "string")
132
+ continue;
133
+ const stripped = stripAutopilotPreamble(stripSteering(c.text));
134
+ if (stripped.startsWith("[User attached a video file"))
135
+ videoWarning = true;
136
+ if (ATTACHMENT_NOTE_PATTERNS.some((re) => re.test(stripped)))
137
+ continue;
138
+ const cleaned = stripAttachedFilesBlock(stripped);
139
+ if (cleaned.trim())
140
+ textParts.push(cleaned);
141
+ }
142
+ return { text: textParts.join("\n\n").trim(), images, videoWarning };
143
+ }
144
+ /**
145
+ * Split a persisted assistant message into per-bubble texts. Live streaming
146
+ * ends the assistant bubble at every server_tool_call (see useAgentEvents'
147
+ * server_tool_call case), so pre- and post-tool text render as separate rows.
148
+ * Persisted content keeps that structure as separate text blocks — emit one
149
+ * text per block instead of gluing them into a single row on resume.
150
+ */
151
+ export function restoreAssistantTexts(content) {
152
+ if (typeof content === "string")
153
+ return content.trim() ? [content] : [];
154
+ return content.flatMap((c) => c.type === "text" && typeof c.text === "string" && c.text.trim() ? [c.text] : []);
155
+ }
156
+ //# sourceMappingURL=session-history.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-history.js","sourceRoot":"","sources":["../../src/core/session-history.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=session-history.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-history.test.d.ts","sourceRoot":"","sources":["../../src/core/session-history.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,101 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { STEERING_PREFIX } from "./steering.js";
3
+ import { frameAutopilotInjection } from "./autopilot-cycle.js";
4
+ import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeNolanTurnsForHistory, restoreUserRow, restoreAssistantTexts, } from "./session-history.js";
5
+ describe("normalizeAutopilotMarkersForHistory", () => {
6
+ it("drops out-of-range compacted-session markers and dedupes exact all-clear rows", () => {
7
+ const markers = [
8
+ { version: 1, phase: "done", afterMessageCount: 2 },
9
+ { version: 1, phase: "done", afterMessageCount: 2 },
10
+ { version: 1, phase: "done", afterMessageCount: 9 },
11
+ { version: 1, phase: "human", afterMessageCount: 3, reason: "Needs user approval." },
12
+ { version: 1, phase: "done", afterMessageCount: 12 },
13
+ ];
14
+ const restored = normalizeAutopilotMarkersForHistory(markers, 4);
15
+ expect(restored).toEqual([
16
+ { version: 1, phase: "done", afterMessageCount: 2, copySeed: "done\u00002\u0000\u0000" },
17
+ {
18
+ version: 1,
19
+ phase: "human",
20
+ afterMessageCount: 3,
21
+ reason: "Needs user approval.",
22
+ copySeed: "human\u00003\u0000Needs user approval.\u0000",
23
+ },
24
+ ]);
25
+ expect(restored.filter((m) => m.phase === "done")).toHaveLength(1);
26
+ });
27
+ });
28
+ describe("normalizeAppMarkersForHistory", () => {
29
+ it("drops out-of-range markers and dedupes exact payloads", () => {
30
+ const markers = [
31
+ { version: 1, kind: "plan", afterMessageCount: 1, data: { reason: "complex change" } },
32
+ { version: 1, kind: "plan", afterMessageCount: 1, data: { reason: "complex change" } },
33
+ { version: 1, kind: "task", afterMessageCount: 9, data: { title: "stale task" } },
34
+ ];
35
+ expect(normalizeAppMarkersForHistory(markers, 4)).toEqual([
36
+ { version: 1, kind: "plan", afterMessageCount: 1, data: { reason: "complex change" } },
37
+ ]);
38
+ });
39
+ });
40
+ describe("normalizeNolanTurnsForHistory", () => {
41
+ it("clamps stale anchors to the last message instead of dropping, and dedupes", () => {
42
+ const turns = [
43
+ { version: 1, question: "why?", reply: "because", afterMessageCount: 2 },
44
+ { version: 1, question: "why?", reply: "because", afterMessageCount: 2 },
45
+ { version: 1, question: "later q", reply: "later a", afterMessageCount: 50 },
46
+ ];
47
+ expect(normalizeNolanTurnsForHistory(turns, 4)).toEqual([
48
+ { version: 1, question: "why?", reply: "because", afterMessageCount: 2 },
49
+ { version: 1, question: "later q", reply: "later a", afterMessageCount: 4 },
50
+ ]);
51
+ });
52
+ });
53
+ describe("restoreUserRow", () => {
54
+ it("strips the mid-run steering wrapper so queued prompts resume clean", () => {
55
+ const row = restoreUserRow(`${STEERING_PREFIX}also add dark mode`);
56
+ expect(row.text).toBe("also add dark mode");
57
+ });
58
+ it("strips the autopilot preamble so injected prompts resume as the clean body", () => {
59
+ const row = restoreUserRow(frameAutopilotInjection("Add a test for the login flow."));
60
+ expect(row.text).toBe("Add a test for the login flow.");
61
+ expect(row.text).not.toContain("[Autopilot]");
62
+ });
63
+ it("drops attachment notes and the attached-files block, keeps typed text + images", () => {
64
+ const row = restoreUserRow([
65
+ {
66
+ type: "text",
67
+ text: "what's in this screenshot?\n\nAttached files (inspect with your tools):\n- notes.txt (saved at /p/notes.txt)",
68
+ },
69
+ { type: "image", mediaType: "image/png", data: "aGk=" },
70
+ { type: "text", text: "[Image saved at /p/.gg/uploads/x.png]" },
71
+ ]);
72
+ expect(row.text).toBe("what's in this screenshot?");
73
+ expect(row.images).toEqual(["data:image/png;base64,aGk="]);
74
+ expect(row.videoWarning).toBe(false);
75
+ });
76
+ it("flags the non-native-video note so resume re-shows the live info row", () => {
77
+ const row = restoreUserRow([
78
+ { type: "text", text: "summarize this clip" },
79
+ {
80
+ type: "text",
81
+ text: "[User attached a video file at /p/clip.mp4. You cannot watch video directly; if needed, use ffmpeg to extract frames or audio.]",
82
+ },
83
+ ]);
84
+ expect(row.text).toBe("summarize this clip");
85
+ expect(row.videoWarning).toBe(true);
86
+ });
87
+ });
88
+ describe("restoreAssistantTexts", () => {
89
+ it("keeps server-tool text splits as separate bubbles", () => {
90
+ expect(restoreAssistantTexts([
91
+ { type: "text", text: "Let me search for that." },
92
+ { type: "server_tool_call", id: "st1", name: "web_search", args: {} },
93
+ { type: "text", text: "Found it — here's the answer." },
94
+ ])).toEqual(["Let me search for that.", "Found it — here's the answer."]);
95
+ });
96
+ it("passes plain string content through as one bubble", () => {
97
+ expect(restoreAssistantTexts("hello")).toEqual(["hello"]);
98
+ expect(restoreAssistantTexts(" ")).toEqual([]);
99
+ });
100
+ });
101
+ //# sourceMappingURL=session-history.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-history.test.js","sourceRoot":"","sources":["../../src/core/session-history.test.ts"],"names":[],"mappings":"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"}
@@ -49,6 +49,34 @@ export interface NolanTurnPayload {
49
49
  reply: string;
50
50
  afterMessageCount: number;
51
51
  }
52
+ /** Custom-entry kind for an autopilot verdict marker. Mirrors `nolan_turn`:
53
+ * persisted as a `custom` entry with `parentId: null` so it's never on the
54
+ * message DAG (EZ Coder never sees it) but survives resume/compaction and
55
+ * interleaves back into the transcript via `afterMessageCount`. Covers all
56
+ * four terminal/near-terminal autopilot markers so a resumed session renders
57
+ * the exact same Nolan bubble the live run showed — never the raw verdict
58
+ * keyword (e.g. `ALL_CLEAR`) the model actually replied with. */
59
+ export declare const AUTOPILOT_MARKER_CUSTOM_KIND = "autopilot_marker";
60
+ export interface AutopilotMarkerPayload {
61
+ version: 1;
62
+ phase: "prompted" | "done" | "human" | "capped" | "plan_approved";
63
+ reason?: string;
64
+ body?: string;
65
+ afterMessageCount: number;
66
+ }
67
+ /** Custom-entry kind for a generic app transcript marker (plan-mode banner,
68
+ * task header, error row, user-bubble display hint). Same not-on-the-DAG
69
+ * treatment as Nolan turns / autopilot markers: persisted with `parentId: null`
70
+ * so the LLM never sees it, anchored by `afterMessageCount` so the host can
71
+ * interleave it back into the transcript on resume. */
72
+ export declare const APP_MARKER_CUSTOM_KIND = "app_transcript_marker";
73
+ export interface AppMarkerPayload {
74
+ version: 1;
75
+ kind: "plan" | "task" | "error" | "user_hint" | "compaction";
76
+ afterMessageCount: number;
77
+ /** Kind-specific display fields (reason/title/headline/nolanSent/counts/…). */
78
+ data: Record<string, unknown>;
79
+ }
52
80
  export type SessionEntry = MessageEntry | ModelChangeEntry | ThinkingLevelChangeEntry | CompactionEntry | LabelEntry | CustomEntry;
53
81
  export interface SessionHeader {
54
82
  type: "session";
@@ -130,6 +158,12 @@ export declare class SessionManager {
130
158
  /** Read all persisted Nolan turns in file order. Returns them regardless of
131
159
  * branch (Nolan turns are not chained into the DAG), validated + normalized. */
132
160
  getNolanTurns(entries: SessionEntry[]): NolanTurnPayload[];
161
+ /** Read all persisted app transcript markers in file order, validated +
162
+ * normalized (same not-on-the-DAG treatment as Nolan turns). */
163
+ getAppMarkers(entries: SessionEntry[]): AppMarkerPayload[];
164
+ /** Read all persisted autopilot markers in file order, validated + normalized
165
+ * (same not-on-the-DAG treatment as Nolan turns). */
166
+ getAutopilotMarkers(entries: SessionEntry[]): AutopilotMarkerPayload[];
133
167
  /**
134
168
  * Ensure every assistant message with tool_use blocks is followed by a tool
135
169
  * message containing matching tool_result entries. Inserts synthetic
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAyB,SAAQ,SAAS;IACzD,IAAI,EAAE,uBAAuB,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,IAAI,EAAE,YAAY,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACf;AAED,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AAOvD;;;;;;;0EAO0E;AAC1E,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,MAAM,YAAY,GACpB,YAAY,GACZ,gBAAgB,GAChB,wBAAwB,GACxB,eAAe,GACf,UAAU,GACV,WAAW,CAAC;AAahB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,CAAC,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAiBD,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,YAAY,EAAE,MAAM,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;CACtB;AAID,MAAM,WAAW,UAAU;IACzB,qEAAqE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,qBAAa,cAAc;IACzB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,+EAA+E;IAC/E,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,cAAc,KAAK,IAAI,CAAC;gBAE5C,WAAW,EAAE,MAAM;IAI/B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAY1B,OAAO,CAAC,SAAS;IAIX,MAAM,CACV,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC;QACT,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,aAAa,CAAC;KACvB,CAAC;IAwBI,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;QACvC,MAAM,EAAE,aAAa,CAAC;QACtB,OAAO,EAAE,YAAY,EAAE,CAAC;KACzB,CAAC;IAwDI,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA+DzC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAMlD,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAKtE;;;;;;OAMG;IACG,gBAAgB,CAAC,OAAO,EAAE;QAC9B,UAAU,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;KACtB,GAAG,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAiDnD,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAQpE,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAQtD,gBAAgB;IAqC9B;;;OAGG;IACH,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,EAAE;IAYvE,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,EAAE;IASlF;qFACiF;IACjF,aAAa,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,gBAAgB,EAAE;IAkB1D;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE;IAsDtD;;;OAGG;IACH,OAAO,CAAC,UAAU;IAIlB;;;;;;;OAOG;IACH,SAAS,CACP,OAAO,EAAE,YAAY,EAAE,EACvB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,IAAI,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GAC/B,YAAY,EAAE;IAiBjB;;;OAGG;IACH,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,UAAU,EAAE;CAqCpD"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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"}
@@ -15,6 +15,20 @@ export const DISPLAY_ITEM_CUSTOM_KIND = "display_item";
15
15
  * number of non-system messages that existed when the turn was recorded, used
16
16
  * to interleave Nolan turns back into the transcript chronologically. */
17
17
  export const NOLAN_TURN_CUSTOM_KIND = "nolan_turn";
18
+ /** Custom-entry kind for an autopilot verdict marker. Mirrors `nolan_turn`:
19
+ * persisted as a `custom` entry with `parentId: null` so it's never on the
20
+ * message DAG (EZ Coder never sees it) but survives resume/compaction and
21
+ * interleaves back into the transcript via `afterMessageCount`. Covers all
22
+ * four terminal/near-terminal autopilot markers so a resumed session renders
23
+ * the exact same Nolan bubble the live run showed — never the raw verdict
24
+ * keyword (e.g. `ALL_CLEAR`) the model actually replied with. */
25
+ export const AUTOPILOT_MARKER_CUSTOM_KIND = "autopilot_marker";
26
+ /** Custom-entry kind for a generic app transcript marker (plan-mode banner,
27
+ * task header, error row, user-bubble display hint). Same not-on-the-DAG
28
+ * treatment as Nolan turns / autopilot markers: persisted with `parentId: null`
29
+ * so the LLM never sees it, anchored by `afterMessageCount` so the host can
30
+ * interleave it back into the transcript on resume. */
31
+ export const APP_MARKER_CUSTOM_KIND = "app_transcript_marker";
18
32
  function isCompletedItemLike(value) {
19
33
  return (typeof value === "object" &&
20
34
  value !== null &&
@@ -351,6 +365,59 @@ export class SessionManager {
351
365
  return [];
352
366
  });
353
367
  }
368
+ /** Read all persisted app transcript markers in file order, validated +
369
+ * normalized (same not-on-the-DAG treatment as Nolan turns). */
370
+ getAppMarkers(entries) {
371
+ return entries.flatMap((entry) => {
372
+ if (entry.type !== "custom" || entry.kind !== APP_MARKER_CUSTOM_KIND)
373
+ return [];
374
+ const p = entry.data;
375
+ const kind = p?.kind;
376
+ if (p?.version === 1 &&
377
+ (kind === "plan" ||
378
+ kind === "task" ||
379
+ kind === "error" ||
380
+ kind === "user_hint" ||
381
+ kind === "compaction")) {
382
+ return [
383
+ {
384
+ version: 1,
385
+ kind,
386
+ afterMessageCount: typeof p.afterMessageCount === "number" ? p.afterMessageCount : 0,
387
+ data: typeof p.data === "object" && p.data !== null ? p.data : {},
388
+ },
389
+ ];
390
+ }
391
+ return [];
392
+ });
393
+ }
394
+ /** Read all persisted autopilot markers in file order, validated + normalized
395
+ * (same not-on-the-DAG treatment as Nolan turns). */
396
+ getAutopilotMarkers(entries) {
397
+ return entries.flatMap((entry) => {
398
+ if (entry.type !== "custom" || entry.kind !== AUTOPILOT_MARKER_CUSTOM_KIND)
399
+ return [];
400
+ const p = entry.data;
401
+ const phase = p?.phase;
402
+ if (p?.version === 1 &&
403
+ (phase === "prompted" ||
404
+ phase === "done" ||
405
+ phase === "human" ||
406
+ phase === "capped" ||
407
+ phase === "plan_approved")) {
408
+ return [
409
+ {
410
+ version: 1,
411
+ phase,
412
+ ...(typeof p.reason === "string" ? { reason: p.reason } : {}),
413
+ ...(typeof p.body === "string" ? { body: p.body } : {}),
414
+ afterMessageCount: typeof p.afterMessageCount === "number" ? p.afterMessageCount : 0,
415
+ },
416
+ ];
417
+ }
418
+ return [];
419
+ });
420
+ }
354
421
  /**
355
422
  * Ensure every assistant message with tool_use blocks is followed by a tool
356
423
  * message containing matching tool_result entries. Inserts synthetic