@astralyn/pi 0.84.1 → 0.84.3

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 (163) hide show
  1. package/CHANGELOG.md +25 -1
  2. package/dist/cli/args.js +1 -1
  3. package/dist/cli/args.js.map +1 -1
  4. package/dist/cli/config-selector.d.ts.map +1 -1
  5. package/dist/cli/config-selector.js +2 -3
  6. package/dist/cli/config-selector.js.map +1 -1
  7. package/dist/cli/startup-ui.d.ts.map +1 -1
  8. package/dist/cli/startup-ui.js +3 -5
  9. package/dist/cli/startup-ui.js.map +1 -1
  10. package/dist/config.d.ts +5 -0
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +8 -1
  13. package/dist/config.js.map +1 -1
  14. package/dist/core/agent-session.d.ts +1 -25
  15. package/dist/core/agent-session.d.ts.map +1 -1
  16. package/dist/core/agent-session.js +29 -408
  17. package/dist/core/agent-session.js.map +1 -1
  18. package/dist/core/compaction-controller.d.ts +89 -0
  19. package/dist/core/compaction-controller.d.ts.map +1 -0
  20. package/dist/core/compaction-controller.js +428 -0
  21. package/dist/core/compaction-controller.js.map +1 -0
  22. package/dist/core/extensions/index.d.ts +1 -1
  23. package/dist/core/extensions/index.d.ts.map +1 -1
  24. package/dist/core/extensions/index.js.map +1 -1
  25. package/dist/core/extensions/loader.js +3 -3
  26. package/dist/core/extensions/loader.js.map +1 -1
  27. package/dist/core/extensions/types.d.ts +1 -15
  28. package/dist/core/extensions/types.d.ts.map +1 -1
  29. package/dist/core/extensions/types.js.map +1 -1
  30. package/dist/core/provider-attribution.js +2 -2
  31. package/dist/core/provider-attribution.js.map +1 -1
  32. package/dist/core/settings-manager.js +1 -1
  33. package/dist/core/settings-manager.js.map +1 -1
  34. package/dist/core/telemetry.d.ts +1 -1
  35. package/dist/core/telemetry.d.ts.map +1 -1
  36. package/dist/core/telemetry.js +1 -1
  37. package/dist/core/telemetry.js.map +1 -1
  38. package/dist/extensions/deepwiki/index.d.ts.map +1 -1
  39. package/dist/extensions/deepwiki/index.js +23 -1
  40. package/dist/extensions/deepwiki/index.js.map +1 -1
  41. package/dist/extensions/deepwiki/render.d.ts +1 -1
  42. package/dist/extensions/deepwiki/render.d.ts.map +1 -1
  43. package/dist/extensions/deepwiki/render.js +4 -2
  44. package/dist/extensions/deepwiki/render.js.map +1 -1
  45. package/dist/extensions/index.d.ts.map +1 -1
  46. package/dist/extensions/index.js +0 -4
  47. package/dist/extensions/index.js.map +1 -1
  48. package/dist/extensions/question/index.d.ts.map +1 -1
  49. package/dist/extensions/question/index.js +0 -1
  50. package/dist/extensions/question/index.js.map +1 -1
  51. package/dist/extensions/subagent/index.d.ts.map +1 -1
  52. package/dist/extensions/subagent/index.js +20 -2
  53. package/dist/extensions/subagent/index.js.map +1 -1
  54. package/dist/extensions/todo/schema.d.ts +1 -1
  55. package/dist/extensions/todo/state.js +5 -5
  56. package/dist/extensions/todo/state.js.map +1 -1
  57. package/dist/modes/interactive/components/extension-selector.d.ts +0 -2
  58. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  59. package/dist/modes/interactive/components/extension-selector.js +1 -1
  60. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  61. package/dist/modes/interactive/components/settings-selector.js +1 -1
  62. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  63. package/dist/modes/interactive/components/tool-chrome.d.ts +28 -0
  64. package/dist/modes/interactive/components/tool-chrome.d.ts.map +1 -0
  65. package/dist/modes/interactive/components/tool-chrome.js +81 -0
  66. package/dist/modes/interactive/components/tool-chrome.js.map +1 -0
  67. package/dist/modes/interactive/components/tool-execution.d.ts +0 -3
  68. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  69. package/dist/modes/interactive/components/tool-execution.js +11 -108
  70. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  71. package/dist/modes/interactive/interactive-mode.d.ts +1 -1
  72. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  73. package/dist/modes/interactive/interactive-mode.js +35 -52
  74. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  75. package/docs/bundled/README.md +0 -2
  76. package/docs/bundled/extensions/subagent.md +1 -1
  77. package/docs/bundled/tool-presentation.md +2 -2
  78. package/docs/docs.json +0 -8
  79. package/docs/extensions.md +6 -23
  80. package/docs/settings.md +1 -1
  81. package/docs/usage.md +1 -2
  82. package/examples/extensions/README.md +2 -0
  83. package/examples/extensions/plan-mode/README.md +66 -0
  84. package/examples/extensions/plan-mode/index.ts +390 -0
  85. package/examples/extensions/plan-mode/utils.ts +168 -0
  86. package/examples/extensions/subagent/README.md +175 -0
  87. package/examples/extensions/subagent/agents/planner.md +37 -0
  88. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  89. package/examples/extensions/subagent/agents/scout.md +50 -0
  90. package/examples/extensions/subagent/agents/worker.md +24 -0
  91. package/examples/extensions/subagent/agents.ts +126 -0
  92. package/examples/extensions/subagent/index.ts +1009 -0
  93. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  94. package/examples/extensions/subagent/prompts/implement.md +10 -0
  95. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  96. package/npm-shrinkwrap.json +2 -2
  97. package/package.json +1 -1
  98. package/dist/extensions/biu/index.d.ts +0 -19
  99. package/dist/extensions/biu/index.d.ts.map +0 -1
  100. package/dist/extensions/biu/index.js +0 -350
  101. package/dist/extensions/biu/index.js.map +0 -1
  102. package/dist/extensions/biu/prompts.d.ts +0 -26
  103. package/dist/extensions/biu/prompts.d.ts.map +0 -1
  104. package/dist/extensions/biu/prompts.js +0 -260
  105. package/dist/extensions/biu/prompts.js.map +0 -1
  106. package/dist/extensions/biu/workspace.d.ts +0 -122
  107. package/dist/extensions/biu/workspace.d.ts.map +0 -1
  108. package/dist/extensions/biu/workspace.js +0 -404
  109. package/dist/extensions/biu/workspace.js.map +0 -1
  110. package/dist/extensions/rewind/anchor.d.ts +0 -29
  111. package/dist/extensions/rewind/anchor.d.ts.map +0 -1
  112. package/dist/extensions/rewind/anchor.js +0 -35
  113. package/dist/extensions/rewind/anchor.js.map +0 -1
  114. package/dist/extensions/rewind/config.d.ts +0 -16
  115. package/dist/extensions/rewind/config.d.ts.map +0 -1
  116. package/dist/extensions/rewind/config.js +0 -69
  117. package/dist/extensions/rewind/config.js.map +0 -1
  118. package/dist/extensions/rewind/engine.d.ts +0 -93
  119. package/dist/extensions/rewind/engine.d.ts.map +0 -1
  120. package/dist/extensions/rewind/engine.js +0 -778
  121. package/dist/extensions/rewind/engine.js.map +0 -1
  122. package/dist/extensions/rewind/gc.d.ts +0 -35
  123. package/dist/extensions/rewind/gc.d.ts.map +0 -1
  124. package/dist/extensions/rewind/gc.js +0 -169
  125. package/dist/extensions/rewind/gc.js.map +0 -1
  126. package/dist/extensions/rewind/index.d.ts +0 -3
  127. package/dist/extensions/rewind/index.d.ts.map +0 -1
  128. package/dist/extensions/rewind/index.js +0 -287
  129. package/dist/extensions/rewind/index.js.map +0 -1
  130. package/dist/extensions/rewind/menu.d.ts +0 -13
  131. package/dist/extensions/rewind/menu.d.ts.map +0 -1
  132. package/dist/extensions/rewind/menu.js +0 -123
  133. package/dist/extensions/rewind/menu.js.map +0 -1
  134. package/dist/extensions/rewind/paths.d.ts +0 -4
  135. package/dist/extensions/rewind/paths.d.ts.map +0 -1
  136. package/dist/extensions/rewind/paths.js +0 -15
  137. package/dist/extensions/rewind/paths.js.map +0 -1
  138. package/dist/extensions/rewind/restore.d.ts +0 -54
  139. package/dist/extensions/rewind/restore.d.ts.map +0 -1
  140. package/dist/extensions/rewind/restore.js +0 -94
  141. package/dist/extensions/rewind/restore.js.map +0 -1
  142. package/dist/extensions/rewind/snapshot.d.ts +0 -45
  143. package/dist/extensions/rewind/snapshot.d.ts.map +0 -1
  144. package/dist/extensions/rewind/snapshot.js +0 -21
  145. package/dist/extensions/rewind/snapshot.js.map +0 -1
  146. package/dist/extensions/rewind/storage.d.ts +0 -12
  147. package/dist/extensions/rewind/storage.d.ts.map +0 -1
  148. package/dist/extensions/rewind/storage.js +0 -33
  149. package/dist/extensions/rewind/storage.js.map +0 -1
  150. package/dist/extensions/rewind/text.d.ts +0 -7
  151. package/dist/extensions/rewind/text.d.ts.map +0 -1
  152. package/dist/extensions/rewind/text.js +0 -19
  153. package/dist/extensions/rewind/text.js.map +0 -1
  154. package/dist/extensions/rewind/tool-path.d.ts +0 -3
  155. package/dist/extensions/rewind/tool-path.d.ts.map +0 -1
  156. package/dist/extensions/rewind/tool-path.js +0 -9
  157. package/dist/extensions/rewind/tool-path.js.map +0 -1
  158. package/dist/utils/coalescing-terminal.d.ts +0 -132
  159. package/dist/utils/coalescing-terminal.d.ts.map +0 -1
  160. package/dist/utils/coalescing-terminal.js +0 -292
  161. package/dist/utils/coalescing-terminal.js.map +0 -1
  162. package/docs/bundled/extensions/biu.md +0 -63
  163. package/docs/bundled/extensions/rewind.md +0 -86
@@ -1,94 +0,0 @@
1
- /**
2
- * restore.ts — map a /tree navigation target to the snapshot that should be
3
- * restored and apply it via the engine.
4
- *
5
- * Snapshot semantics: a frame anchored at user entry U records the work tree
6
- * at the moment U's run STARTED (see engine.ts beginTurn). The selection here
7
- * must mirror AgentSession.navigateTree's leaf rules:
8
- *
9
- * - user / custom_message target: navigateTree removes the target's turn
10
- * from the branch (leaf = parent, text returns to the editor) → restore
11
- * to the state BEFORE that turn = the snapshot anchored at the target.
12
- * - any other target: the target's turn STAYS in the conversation
13
- * (leaf = target) → restore to the state AFTER that turn = the first
14
- * chronological snapshot anchored at a descendant turn (it recorded the
15
- * work tree when the next run began). No such snapshot → nothing was
16
- * recorded after the target, so offer no restore at all — falling back to
17
- * an ancestor frame would roll back the target turn's own edits and leave
18
- * the work tree older than the conversation.
19
- */
20
- import { applySnapshot, collectChangeDiffStats, collectChanges, } from "./engine.js";
21
- /** Cycle guard for parent-chain walks (ids are acyclic in practice). */
22
- const ANCESTOR_WALK_GUARD = 100_000;
23
- /** True when `id`'s parent chain passes through `ancestorId` (strict descent). */
24
- function isDescendantOf(view, id, ancestorId) {
25
- let cur = view.getEntry(id)?.parentId ?? null;
26
- let guard = 0;
27
- while (cur !== null && guard++ < ANCESTOR_WALK_GUARD) {
28
- if (cur === ancestorId)
29
- return true;
30
- cur = view.getEntry(cur)?.parentId ?? null;
31
- }
32
- return false;
33
- }
34
- /**
35
- * First (chronological) snapshot anchored at a strict descendant of `entryId`
36
- * — the run that started right after `entryId` existed, so its frame records
37
- * the work tree state "just after" the entry.
38
- */
39
- function snapshotAfterEntry(snapshots, view, entryId) {
40
- for (const snap of snapshots) {
41
- if (!snap.userEntryId)
42
- continue;
43
- if (isDescendantOf(view, snap.userEntryId, entryId))
44
- return snap;
45
- }
46
- return undefined;
47
- }
48
- /**
49
- * The snapshot that matches navigating to `targetId`, per the rules in the
50
- * module header. Undefined when no recorded state corresponds to the target
51
- * (then the work tree should be left alone).
52
- */
53
- export function snapshotForEntry(snapshots, view, targetId) {
54
- const target = view.getEntry(targetId);
55
- if (!target)
56
- return undefined;
57
- if (target.isTurnAnchor) {
58
- // Exact anchor match: the frame recording the state right before this
59
- // turn ran. Chronologically last wins if duplicate anchors exist.
60
- let exact;
61
- for (const snap of snapshots) {
62
- if (snap.userEntryId === targetId)
63
- exact = snap;
64
- }
65
- if (exact)
66
- return exact;
67
- // No frame for this turn (it recorded no changes): the state before it
68
- // equals the state after its parent.
69
- return target.parentId === null ? undefined : snapshotAfterEntry(snapshots, view, target.parentId);
70
- }
71
- return snapshotAfterEntry(snapshots, view, targetId);
72
- }
73
- /**
74
- * Absolute file paths restoring to this snapshot would change on disk (empty =
75
- * none). Callers use the length for the count and the paths for the preview.
76
- */
77
- export function snapshotChangedPaths(sessionId, snapshot) {
78
- return collectChanges(sessionId, snapshot);
79
- }
80
- /**
81
- * Coarse +N/−M line stats for the confirm dialog (paths must already be known
82
- * changed — typically from snapshotChangedPaths).
83
- */
84
- export function snapshotChangeDiffStats(sessionId, snapshot, changedPaths) {
85
- return collectChangeDiffStats(sessionId, snapshot, changedPaths);
86
- }
87
- /**
88
- * Restore the work tree to `snapshot` and return changed absolute paths.
89
- * Pass `onlyPaths` from a prior snapshotChangedPaths call to skip re-compare.
90
- */
91
- export async function restoreToSnapshot(sessionId, snapshot, opts) {
92
- return applySnapshot(sessionId, snapshot, opts);
93
- }
94
- //# sourceMappingURL=restore.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"restore.js","sourceRoot":"","sources":["../../../src/extensions/rewind/restore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAEN,aAAa,EAEb,sBAAsB,EACtB,cAAc,GACd,MAAM,aAAa,CAAC;AAgBrB,wEAAwE;AACxE,MAAM,mBAAmB,GAAG,OAAO,CAAC;AAEpC,kFAAkF;AAClF,SAAS,cAAc,CAAC,IAAmB,EAAE,EAAU,EAAE,UAAkB;IAC1E,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IAC9C,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,OAAO,GAAG,KAAK,IAAI,IAAI,KAAK,EAAE,GAAG,mBAAmB,EAAE,CAAC;QACtD,IAAI,GAAG,KAAK,UAAU;YAAE,OAAO,IAAI,CAAC;QACpC,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,IAAI,IAAI,CAAC;IAC5C,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,SAAS,kBAAkB,CAC1B,SAAgC,EAChC,IAAmB,EACnB,OAAe;IAEf,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC9B,IAAI,CAAC,IAAI,CAAC,WAAW;YAAE,SAAS;QAChC,IAAI,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC;YAAE,OAAO,IAAI,CAAC;IAClE,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC/B,SAAgC,EAChC,IAAmB,EACnB,QAAgB;IAEhB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAE9B,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACzB,sEAAsE;QACtE,kEAAkE;QAClE,IAAI,KAAsC,CAAC;QAC3C,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;YAC9B,IAAI,IAAI,CAAC,WAAW,KAAK,QAAQ;gBAAE,KAAK,GAAG,IAAI,CAAC;QACjD,CAAC;QACD,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,uEAAuE;QACvE,qCAAqC;QACrC,OAAO,MAAM,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpG,CAAC;IAED,OAAO,kBAAkB,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,QAA6B;IACpF,OAAO,cAAc,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CACtC,SAAiB,EACjB,QAA6B,EAC7B,YAA+B;IAE/B,OAAO,sBAAsB,CAAC,SAAS,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACtC,SAAiB,EACjB,QAA6B,EAC7B,IAA2B;IAE3B,OAAO,aAAa,CAAC,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;AACjD,CAAC","sourcesContent":["/**\n * restore.ts — map a /tree navigation target to the snapshot that should be\n * restored and apply it via the engine.\n *\n * Snapshot semantics: a frame anchored at user entry U records the work tree\n * at the moment U's run STARTED (see engine.ts beginTurn). The selection here\n * must mirror AgentSession.navigateTree's leaf rules:\n *\n * - user / custom_message target: navigateTree removes the target's turn\n * from the branch (leaf = parent, text returns to the editor) → restore\n * to the state BEFORE that turn = the snapshot anchored at the target.\n * - any other target: the target's turn STAYS in the conversation\n * (leaf = target) → restore to the state AFTER that turn = the first\n * chronological snapshot anchored at a descendant turn (it recorded the\n * work tree when the next run began). No such snapshot → nothing was\n * recorded after the target, so offer no restore at all — falling back to\n * an ancestor frame would roll back the target turn's own edits and leave\n * the work tree older than the conversation.\n */\nimport {\n\ttype ApplySnapshotOptions,\n\tapplySnapshot,\n\ttype CoarseDiffStats,\n\tcollectChangeDiffStats,\n\tcollectChanges,\n} from \"./engine.ts\";\nimport type { FileHistorySnapshot } from \"./snapshot.ts\";\n\n/** Minimal per-entry view needed to walk the tree and classify targets. */\nexport interface EntryView {\n\tid: string;\n\tparentId: string | null;\n\t/** True for entries navigateTree treats as turn starts (user / custom_message → leaf = parent). */\n\tisTurnAnchor: boolean;\n}\n\n/** Minimal session view we need to walk the entry tree. */\nexport interface EntryTreeView {\n\tgetEntry(id: string): EntryView | undefined;\n}\n\n/** Cycle guard for parent-chain walks (ids are acyclic in practice). */\nconst ANCESTOR_WALK_GUARD = 100_000;\n\n/** True when `id`'s parent chain passes through `ancestorId` (strict descent). */\nfunction isDescendantOf(view: EntryTreeView, id: string, ancestorId: string): boolean {\n\tlet cur = view.getEntry(id)?.parentId ?? null;\n\tlet guard = 0;\n\twhile (cur !== null && guard++ < ANCESTOR_WALK_GUARD) {\n\t\tif (cur === ancestorId) return true;\n\t\tcur = view.getEntry(cur)?.parentId ?? null;\n\t}\n\treturn false;\n}\n\n/**\n * First (chronological) snapshot anchored at a strict descendant of `entryId`\n * — the run that started right after `entryId` existed, so its frame records\n * the work tree state \"just after\" the entry.\n */\nfunction snapshotAfterEntry(\n\tsnapshots: FileHistorySnapshot[],\n\tview: EntryTreeView,\n\tentryId: string,\n): FileHistorySnapshot | undefined {\n\tfor (const snap of snapshots) {\n\t\tif (!snap.userEntryId) continue;\n\t\tif (isDescendantOf(view, snap.userEntryId, entryId)) return snap;\n\t}\n\treturn undefined;\n}\n\n/**\n * The snapshot that matches navigating to `targetId`, per the rules in the\n * module header. Undefined when no recorded state corresponds to the target\n * (then the work tree should be left alone).\n */\nexport function snapshotForEntry(\n\tsnapshots: FileHistorySnapshot[],\n\tview: EntryTreeView,\n\ttargetId: string,\n): FileHistorySnapshot | undefined {\n\tconst target = view.getEntry(targetId);\n\tif (!target) return undefined;\n\n\tif (target.isTurnAnchor) {\n\t\t// Exact anchor match: the frame recording the state right before this\n\t\t// turn ran. Chronologically last wins if duplicate anchors exist.\n\t\tlet exact: FileHistorySnapshot | undefined;\n\t\tfor (const snap of snapshots) {\n\t\t\tif (snap.userEntryId === targetId) exact = snap;\n\t\t}\n\t\tif (exact) return exact;\n\t\t// No frame for this turn (it recorded no changes): the state before it\n\t\t// equals the state after its parent.\n\t\treturn target.parentId === null ? undefined : snapshotAfterEntry(snapshots, view, target.parentId);\n\t}\n\n\treturn snapshotAfterEntry(snapshots, view, targetId);\n}\n\n/**\n * Absolute file paths restoring to this snapshot would change on disk (empty =\n * none). Callers use the length for the count and the paths for the preview.\n */\nexport function snapshotChangedPaths(sessionId: string, snapshot: FileHistorySnapshot): Promise<string[]> {\n\treturn collectChanges(sessionId, snapshot);\n}\n\n/**\n * Coarse +N/−M line stats for the confirm dialog (paths must already be known\n * changed — typically from snapshotChangedPaths).\n */\nexport function snapshotChangeDiffStats(\n\tsessionId: string,\n\tsnapshot: FileHistorySnapshot,\n\tchangedPaths: readonly string[],\n): Promise<CoarseDiffStats> {\n\treturn collectChangeDiffStats(sessionId, snapshot, changedPaths);\n}\n\n/**\n * Restore the work tree to `snapshot` and return changed absolute paths.\n * Pass `onlyPaths` from a prior snapshotChangedPaths call to skip re-compare.\n */\nexport async function restoreToSnapshot(\n\tsessionId: string,\n\tsnapshot: FileHistorySnapshot,\n\topts?: ApplySnapshotOptions,\n): Promise<string[]> {\n\treturn applySnapshot(sessionId, snapshot, opts);\n}\n"]}
@@ -1,45 +0,0 @@
1
- /**
2
- * snapshot.ts — persisted data shapes for the rewind extension's file-history
3
- * engine. Pure types + tiny helpers; no Pi imports, no side effects, so the
4
- * engine and its selftests can import them under plain node.
5
- *
6
- * A FileHistorySnapshot is written to the session JSONL (via the integration
7
- * layer's appendEntry, custom type "pi-rewind-snapshot"). It is never sent to
8
- * the LLM and survives reload/compaction. Each snapshot anchors to one turn and
9
- * records, for every tracked file, which backup blob holds that file's contents
10
- * as of the start of the turn.
11
- */
12
- /** Custom session-entry type used to persist snapshots to the session JSONL. */
13
- export declare const SNAPSHOT_ENTRY_TYPE = "pi-rewind-snapshot";
14
- /**
15
- * One file's backup at a specific version.
16
- * `backupName === null` means the file did not exist at this version — rewinding
17
- * to a snapshot carrying a null backup deletes the file.
18
- */
19
- export interface FileBackup {
20
- /** Backup blob filename (`<sha256(relpath)[:16]>@v<n>`), or null if the file did not exist. */
21
- backupName: string | null;
22
- /** Monotonic version for this file within the session (1-based). */
23
- version: number;
24
- }
25
- /**
26
- * One turn's snapshot. `v` lets future readers migrate old entries.
27
- * `trackedFileBackups` is keyed by the file's path *relative to cwd* when inside
28
- * cwd (else the absolute path), matching the engine's path shortening.
29
- */
30
- export interface FileHistorySnapshot {
31
- v: 1;
32
- /** Session entry id this snapshot anchors to (used to match /tree navigation). */
33
- userEntryId: string;
34
- /** Leaf/turn id when finalized (informational). */
35
- turnId: string;
36
- /** The user prompt that drove the turn (truncated; shown in the /tree sync prompt). */
37
- prompt: string;
38
- /** Map of tracking-path → the backup recorded for that file at the start of this turn. */
39
- trackedFileBackups: Record<string, FileBackup>;
40
- /** ISO timestamp the snapshot was finalized. */
41
- timestamp: string;
42
- }
43
- /** Narrow an arbitrary session-entry payload to a FileHistorySnapshot. */
44
- export declare function isSnapshot(data: unknown): data is FileHistorySnapshot;
45
- //# sourceMappingURL=snapshot.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../../src/extensions/rewind/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,gFAAgF;AAChF,eAAO,MAAM,mBAAmB,uBAAuB,CAAC;AAExD;;;;GAIG;AACH,MAAM,WAAW,UAAU;IAC1B,+FAA+F;IAC/F,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IACnC,CAAC,EAAE,CAAC,CAAC;IACL,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IACf,0FAA0F;IAC1F,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC/C,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,0EAA0E;AAC1E,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,mBAAmB,CAMrE"}
@@ -1,21 +0,0 @@
1
- /**
2
- * snapshot.ts — persisted data shapes for the rewind extension's file-history
3
- * engine. Pure types + tiny helpers; no Pi imports, no side effects, so the
4
- * engine and its selftests can import them under plain node.
5
- *
6
- * A FileHistorySnapshot is written to the session JSONL (via the integration
7
- * layer's appendEntry, custom type "pi-rewind-snapshot"). It is never sent to
8
- * the LLM and survives reload/compaction. Each snapshot anchors to one turn and
9
- * records, for every tracked file, which backup blob holds that file's contents
10
- * as of the start of the turn.
11
- */
12
- /** Custom session-entry type used to persist snapshots to the session JSONL. */
13
- export const SNAPSHOT_ENTRY_TYPE = "pi-rewind-snapshot";
14
- /** Narrow an arbitrary session-entry payload to a FileHistorySnapshot. */
15
- export function isSnapshot(data) {
16
- if (!data || typeof data !== "object")
17
- return false;
18
- const s = data;
19
- return (typeof s.userEntryId === "string" && typeof s.trackedFileBackups === "object" && s.trackedFileBackups !== null);
20
- }
21
- //# sourceMappingURL=snapshot.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../../src/extensions/rewind/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,gFAAgF;AAChF,MAAM,CAAC,MAAM,mBAAmB,GAAG,oBAAoB,CAAC;AAiCxD,0EAA0E;AAC1E,MAAM,UAAU,UAAU,CAAC,IAAa;IACvC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACpD,MAAM,CAAC,GAAG,IAAoC,CAAC;IAC/C,OAAO,CACN,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,kBAAkB,KAAK,QAAQ,IAAI,CAAC,CAAC,kBAAkB,KAAK,IAAI,CAC9G,CAAC;AACH,CAAC","sourcesContent":["/**\n * snapshot.ts — persisted data shapes for the rewind extension's file-history\n * engine. Pure types + tiny helpers; no Pi imports, no side effects, so the\n * engine and its selftests can import them under plain node.\n *\n * A FileHistorySnapshot is written to the session JSONL (via the integration\n * layer's appendEntry, custom type \"pi-rewind-snapshot\"). It is never sent to\n * the LLM and survives reload/compaction. Each snapshot anchors to one turn and\n * records, for every tracked file, which backup blob holds that file's contents\n * as of the start of the turn.\n */\n\n/** Custom session-entry type used to persist snapshots to the session JSONL. */\nexport const SNAPSHOT_ENTRY_TYPE = \"pi-rewind-snapshot\";\n\n/**\n * One file's backup at a specific version.\n * `backupName === null` means the file did not exist at this version — rewinding\n * to a snapshot carrying a null backup deletes the file.\n */\nexport interface FileBackup {\n\t/** Backup blob filename (`<sha256(relpath)[:16]>@v<n>`), or null if the file did not exist. */\n\tbackupName: string | null;\n\t/** Monotonic version for this file within the session (1-based). */\n\tversion: number;\n}\n\n/**\n * One turn's snapshot. `v` lets future readers migrate old entries.\n * `trackedFileBackups` is keyed by the file's path *relative to cwd* when inside\n * cwd (else the absolute path), matching the engine's path shortening.\n */\nexport interface FileHistorySnapshot {\n\tv: 1;\n\t/** Session entry id this snapshot anchors to (used to match /tree navigation). */\n\tuserEntryId: string;\n\t/** Leaf/turn id when finalized (informational). */\n\tturnId: string;\n\t/** The user prompt that drove the turn (truncated; shown in the /tree sync prompt). */\n\tprompt: string;\n\t/** Map of tracking-path → the backup recorded for that file at the start of this turn. */\n\ttrackedFileBackups: Record<string, FileBackup>;\n\t/** ISO timestamp the snapshot was finalized. */\n\ttimestamp: string;\n}\n\n/** Narrow an arbitrary session-entry payload to a FileHistorySnapshot. */\nexport function isSnapshot(data: unknown): data is FileHistorySnapshot {\n\tif (!data || typeof data !== \"object\") return false;\n\tconst s = data as Partial<FileHistorySnapshot>;\n\treturn (\n\t\ttypeof s.userEntryId === \"string\" && typeof s.trackedFileBackups === \"object\" && s.trackedFileBackups !== null\n\t);\n}\n"]}
@@ -1,12 +0,0 @@
1
- /** Bind the on-disk roots. Called once by index.ts (or by selftests). */
2
- export declare function configureStorage(opts: {
3
- backupsRoot: string;
4
- sessionsRoot: string;
5
- }): void;
6
- /** Root holding every session's backup directory. */
7
- export declare function backupsRootDir(): string;
8
- /** A single session's backup directory. */
9
- export declare function backupsDir(sessionId: string): string;
10
- /** Root holding Pi's session JSONL files (for orphan detection). */
11
- export declare function sessionsRootDir(): string;
12
- //# sourceMappingURL=storage.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/extensions/rewind/storage.ts"],"names":[],"mappings":"AAiBA,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAG1F;AAED,qDAAqD;AACrD,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,2CAA2C;AAC3C,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,oEAAoE;AACpE,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -1,33 +0,0 @@
1
- /**
2
- * storage.ts — injected storage roots for the rewind engine.
3
- *
4
- * engine.ts and gc.ts must stay loadable under plain node (for offline
5
- * selftests), so they cannot statically import paths.ts (which imports
6
- * getAgentDir from @astralyn/pi — unresolvable outside Pi).
7
- * Instead they read the roots from here, and the integration layer (index.ts)
8
- * calls configureStorage() with the real paths at startup. Selftests call it with
9
- * temp directories.
10
- *
11
- * No Pi imports in this module.
12
- */
13
- import { join } from "node:path";
14
- let backupsRoot = "";
15
- let sessionsRoot = "";
16
- /** Bind the on-disk roots. Called once by index.ts (or by selftests). */
17
- export function configureStorage(opts) {
18
- backupsRoot = opts.backupsRoot;
19
- sessionsRoot = opts.sessionsRoot;
20
- }
21
- /** Root holding every session's backup directory. */
22
- export function backupsRootDir() {
23
- return backupsRoot;
24
- }
25
- /** A single session's backup directory. */
26
- export function backupsDir(sessionId) {
27
- return join(backupsRoot, sessionId);
28
- }
29
- /** Root holding Pi's session JSONL files (for orphan detection). */
30
- export function sessionsRootDir() {
31
- return sessionsRoot;
32
- }
33
- //# sourceMappingURL=storage.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/extensions/rewind/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,IAAI,WAAW,GAAG,EAAE,CAAC;AACrB,IAAI,YAAY,GAAG,EAAE,CAAC;AAEtB,yEAAyE;AACzE,MAAM,UAAU,gBAAgB,CAAC,IAAmD;IACnF,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IAC/B,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;AAClC,CAAC;AAED,qDAAqD;AACrD,MAAM,UAAU,cAAc;IAC7B,OAAO,WAAW,CAAC;AACpB,CAAC;AAED,2CAA2C;AAC3C,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC3C,OAAO,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;AACrC,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,eAAe;IAC9B,OAAO,YAAY,CAAC;AACrB,CAAC","sourcesContent":["/**\n * storage.ts — injected storage roots for the rewind engine.\n *\n * engine.ts and gc.ts must stay loadable under plain node (for offline\n * selftests), so they cannot statically import paths.ts (which imports\n * getAgentDir from @astralyn/pi — unresolvable outside Pi).\n * Instead they read the roots from here, and the integration layer (index.ts)\n * calls configureStorage() with the real paths at startup. Selftests call it with\n * temp directories.\n *\n * No Pi imports in this module.\n */\nimport { join } from \"node:path\";\n\nlet backupsRoot = \"\";\nlet sessionsRoot = \"\";\n\n/** Bind the on-disk roots. Called once by index.ts (or by selftests). */\nexport function configureStorage(opts: { backupsRoot: string; sessionsRoot: string }): void {\n\tbackupsRoot = opts.backupsRoot;\n\tsessionsRoot = opts.sessionsRoot;\n}\n\n/** Root holding every session's backup directory. */\nexport function backupsRootDir(): string {\n\treturn backupsRoot;\n}\n\n/** A single session's backup directory. */\nexport function backupsDir(sessionId: string): string {\n\treturn join(backupsRoot, sessionId);\n}\n\n/** Root holding Pi's session JSONL files (for orphan detection). */\nexport function sessionsRootDir(): string {\n\treturn sessionsRoot;\n}\n"]}
@@ -1,7 +0,0 @@
1
- export interface TruncateTextOptions {
2
- ellipsis?: string;
3
- collapseWhitespace?: boolean;
4
- }
5
- export declare function truncateText(text: string, maxLength: number, options?: TruncateTextOptions): string;
6
- export declare function formatSize(bytes: number): string;
7
- //# sourceMappingURL=text.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../../src/extensions/rewind/text.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAMvG;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKhD"}
@@ -1,19 +0,0 @@
1
- export function truncateText(text, maxLength, options = {}) {
2
- const ellipsis = options.ellipsis ?? "...";
3
- const source = options.collapseWhitespace ? text.replace(/\s+/g, " ").trim() : text;
4
- if (source.length <= maxLength)
5
- return source;
6
- if (ellipsis.length >= maxLength)
7
- return ellipsis.slice(0, maxLength);
8
- return `${source.slice(0, maxLength - ellipsis.length)}${ellipsis}`;
9
- }
10
- export function formatSize(bytes) {
11
- if (bytes < 1024)
12
- return `${bytes}B`;
13
- if (bytes < 1024 * 1024)
14
- return `${(bytes / 1024).toFixed(1)}KB`;
15
- if (bytes < 1024 * 1024 * 1024)
16
- return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
17
- return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;
18
- }
19
- //# sourceMappingURL=text.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/extensions/rewind/text.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAiB,EAAE,UAA+B,EAAE;IAC9F,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC;IAC3C,MAAM,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACpF,IAAI,MAAM,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,MAAM,CAAC;IAC9C,IAAI,QAAQ,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACtE,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa;IACvC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,GAAG,CAAC;IACrC,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACjE,IAAI,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI;QAAE,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;IACjF,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACzD,CAAC","sourcesContent":["export interface TruncateTextOptions {\n\tellipsis?: string;\n\tcollapseWhitespace?: boolean;\n}\n\nexport function truncateText(text: string, maxLength: number, options: TruncateTextOptions = {}): string {\n\tconst ellipsis = options.ellipsis ?? \"...\";\n\tconst source = options.collapseWhitespace ? text.replace(/\\s+/g, \" \").trim() : text;\n\tif (source.length <= maxLength) return source;\n\tif (ellipsis.length >= maxLength) return ellipsis.slice(0, maxLength);\n\treturn `${source.slice(0, maxLength - ellipsis.length)}${ellipsis}`;\n}\n\nexport function formatSize(bytes: number): string {\n\tif (bytes < 1024) return `${bytes}B`;\n\tif (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;\n\tif (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\n\treturn `${(bytes / (1024 * 1024 * 1024)).toFixed(2)}GB`;\n}\n"]}
@@ -1,3 +0,0 @@
1
- export declare function editWriteTargetPath(input: unknown): string | undefined;
2
- export declare function resolveToolPath(rawPath: string, cwd: string): string;
3
- //# sourceMappingURL=tool-path.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-path.d.ts","sourceRoot":"","sources":["../../../src/extensions/rewind/tool-path.ts"],"names":[],"mappings":"AAEA,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAGtE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpE"}
@@ -1,9 +0,0 @@
1
- import path from "node:path";
2
- export function editWriteTargetPath(input) {
3
- const rawPath = input?.path;
4
- return typeof rawPath === "string" && rawPath.length > 0 ? rawPath : undefined;
5
- }
6
- export function resolveToolPath(rawPath, cwd) {
7
- return path.isAbsolute(rawPath) ? rawPath : path.resolve(cwd, rawPath);
8
- }
9
- //# sourceMappingURL=tool-path.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tool-path.js","sourceRoot":"","sources":["../../../src/extensions/rewind/tool-path.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,UAAU,mBAAmB,CAAC,KAAc;IACjD,MAAM,OAAO,GAAI,KAAwC,EAAE,IAAI,CAAC;IAChE,OAAO,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,GAAW;IAC3D,OAAO,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC","sourcesContent":["import path from \"node:path\";\n\nexport function editWriteTargetPath(input: unknown): string | undefined {\n\tconst rawPath = (input as { path?: unknown } | undefined)?.path;\n\treturn typeof rawPath === \"string\" && rawPath.length > 0 ? rawPath : undefined;\n}\n\nexport function resolveToolPath(rawPath: string, cwd: string): string {\n\treturn path.isAbsolute(rawPath) ? rawPath : path.resolve(cwd, rawPath);\n}\n"]}
@@ -1,132 +0,0 @@
1
- import { ProcessTerminal } from "@earendil-works/pi-tui";
2
- /**
3
- * ProcessTerminal that (1) coalesces every write issued within one synchronous
4
- * task into a single stdout write and (2) keeps content-driven full redraws
5
- * from destroying the terminal's scrollback.
6
- *
7
- * Coalescing: pi-tui emits each render pass as several separate stdout
8
- * writes: the frame wrapped in synchronized output (CSI ?2026h/l), then a
9
- * relative cursor move that parks the hardware cursor at the focused
10
- * component's caret for IME composition, then a cursor visibility toggle.
11
- * Terminals that anchor the IME candidate window to the hardware cursor
12
- * (Windows Terminal and other ConPTY hosts, WezTerm) can process the frame
13
- * write before the reposition write arrives, briefly leaving the cursor at
14
- * the end of the last repainted line. With an IME active this makes the
15
- * candidate window jump between the caret and the right edge of the input
16
- * line on every keystroke. Merging the writes makes each frame atomic, so the
17
- * only cursor position a terminal can observe is the final one.
18
- *
19
- * Scrollback preservation: pi-tui's fullRender(clear) opens with
20
- * `2J H 3J`, wiping the terminal's scrollback, and then replays the entire
21
- * transcript. During streaming, content-driven triggers (a line changing
22
- * above the viewport during markdown reflow) fire this routinely, which — in
23
- * terminals that clamp the scroll offset when scrollback vanishes, notably
24
- * Windows Terminal — yanks a scrolled-up reader to the top of the buffer on
25
- * every reflow (upstream #6502, #5576, #6050; rejected upstream fix #4204).
26
- *
27
- * Preservation is therefore windowed, not permanent: the host marks agent
28
- * runs via setAgentRunActive, which turns preservation on at run start and
29
- * keeps it on until the user's next input after the run settles, since they
30
- * may still be scrolled up reading. The input half of the window is observed
31
- * directly on this terminal's own input path, so it needs no TUI listener
32
- * and survives renderer switches (which reuse this terminal) untouched. An
33
- * idle-session full redraw — Ctrl+O toggles, mode switches — passes through
34
- * with upstream's wipe-and-replay, whose result is byte-perfect: scrollback
35
- * becomes the clean new transcript. Mid-run user toggles can arm
36
- * passNextFullRedraw for the same clean replay on their own frame.
37
- *
38
- * While preservation is active, a matching frame is rewritten to repaint
39
- * without the wipe. With setViewportTopProvider wired, the rewrite knows
40
- * which transcript line the visible screen starts at, so a frame that grew
41
- * the transcript repaints the on-screen rows with the new content at those
42
- * same positions and then scrolls the extra lines in at the bottom row.
43
- * Each bottom-row newline pushes the top row — already repainted with the
44
- * correct new content — into scrollback, exactly like ordinary streaming
45
- * output, so scrollback ends up byte-equivalent to the upstream full replay
46
- * without ever clearing it. Without the provider, or when the transcript
47
- * shrank (lines cannot be pulled back out of scrollback), the rewrite falls
48
- * back to overwriting the visible screen in place with the bottom
49
- * viewport-height rows, at the cost of a stale seam above the screen. ED 2
50
- * is avoided entirely in rewritten frames because conhost/Windows Terminal
51
- * implement it by scrolling the screen contents into scrollback rather than
52
- * erasing in place.
53
- *
54
- * Width- and height-change redraws keep the upstream wipe because re-wrapped
55
- * content genuinely invalidates old scrollback, and frames containing kitty
56
- * graphics pass through untouched. A frame that does not match the expected
57
- * shape is passed through unchanged, so if upstream reshapes its render
58
- * output the wrapper degrades back to stock behavior.
59
- */
60
- export declare class CoalescingTerminal extends ProcessTerminal {
61
- private pending;
62
- private flushQueued;
63
- private lastWriteColumns;
64
- private lastWriteRows;
65
- private viewportTopProvider;
66
- private preserve;
67
- private passArmed;
68
- private agentRunActive;
69
- private flushOnExit;
70
- /**
71
- * Enable or disable the scrollback-preserving rewrite. Preservation is
72
- * only worth its imperfections (stale renderings above the screen, seams
73
- * on shrink) while the transcript is mutating on its own and the reader
74
- * may be scrolled up — i.e. during an agent run and until the user's next
75
- * input after it settles. Outside that window every full redraw passes
76
- * through with upstream's wipe-and-replay, whose result is byte-perfect:
77
- * scrollback becomes the clean new transcript. Default: disabled.
78
- * setAgentRunActive drives this for the normal agent-run window; this
79
- * primitive remains for direct control in tests.
80
- */
81
- setScrollbackPreservation(enabled: boolean): void;
82
- /**
83
- * Open or close the agent-run half of the preservation window. Opening
84
- * (agent_start) turns preservation on. Closing (agent_settled) leaves
85
- * preservation on: trailing reflow frames may land after the run while
86
- * the reader is still scrolled up. The window then closes on the user's
87
- * next input, observed in start()'s input wrapper — once the user acts
88
- * they are back at the bottom, and upstream's clean wipe-and-replay wins
89
- * again until the next run.
90
- */
91
- setAgentRunActive(active: boolean): void;
92
- /**
93
- * Arm a one-shot exemption for an explicit user action (Ctrl+O tool
94
- * expansion, thinking visibility) so its own full redraw keeps the
95
- * upstream wipe-and-replay even while preservation is active mid-run.
96
- * The user just pressed a key, so they are interacting at the bottom;
97
- * a clean replay beats preservation's stale-seam trade-offs there. The
98
- * flag is cleared by the next write so it cannot leak onto a later
99
- * streaming redraw.
100
- */
101
- passNextFullRedraw(): void;
102
- /**
103
- * Wire the renderer's notion of which transcript line the visible screen
104
- * currently starts at (pi-tui's `previousViewportTop`). Full-redraw frames
105
- * that grew the transcript then scroll the new above-screen lines into
106
- * scrollback instead of dropping them. The provider is read while the
107
- * frame is being written, i.e. before the renderer updates its own
108
- * bookkeeping for that frame; returning undefined falls back to the
109
- * bottom-anchored in-place repaint.
110
- */
111
- setViewportTopProvider(provider: () => number | undefined): void;
112
- constructor();
113
- start(onInput: (data: string) => void, onResize: () => void): void;
114
- write(data: string): void;
115
- moveBy(lines: number): void;
116
- hideCursor(): void;
117
- showCursor(): void;
118
- clearLine(): void;
119
- clearFromCursor(): void;
120
- clearScreen(): void;
121
- stop(): void;
122
- /**
123
- * Rewrite a full-redraw frame (`?2026h 2J H 3J <lines> ?2026l`) so it
124
- * repaints the screen without wiping scrollback. Anything that does not
125
- * match this exact shape — including width-change redraws and frames
126
- * touching kitty images — passes through unchanged.
127
- */
128
- private preserveScrollback;
129
- private readViewportTop;
130
- private flush;
131
- }
132
- //# sourceMappingURL=coalescing-terminal.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"coalescing-terminal.d.ts","sourceRoot":"","sources":["../../src/utils/coalescing-terminal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AASzD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,qBAAa,kBAAmB,SAAQ,eAAe;IACtD,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,mBAAmB,CAAyC;IACpE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,WAAW,CAAsB;IAEzC;;;;;;;;;;OAUG;IACH,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIjD;;;;;;;;OAQG;IACH,iBAAiB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI;IAKxC;;;;;;;;OAQG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;;;;;;;OAQG;IACH,sBAAsB,CAAC,QAAQ,EAAE,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI;;IAWvD,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAoBlE,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAUzB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ3B,UAAU,IAAI,IAAI;IAIlB,UAAU,IAAI,IAAI;IAIlB,SAAS,IAAI,IAAI;IAIjB,eAAe,IAAI,IAAI;IAIvB,WAAW,IAAI,IAAI;IAInB,IAAI,IAAI,IAAI;IAQrB;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IA2E1B,OAAO,CAAC,eAAe;IAUvB,OAAO,CAAC,KAAK;CASb"}