@elyracode/coding-agent 0.7.5 → 0.7.7
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.
- package/CHANGELOG.md +15 -0
- package/dist/core/agent-session.d.ts +34 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +149 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/types.d.ts +5 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/git-checkpoint.d.ts +70 -0
- package/dist/core/git-checkpoint.d.ts.map +1 -0
- package/dist/core/git-checkpoint.js +140 -0
- package/dist/core/git-checkpoint.js.map +1 -0
- package/dist/core/keybindings.d.ts +5 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +1 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/sdk.js +4 -4
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/rewind-selector.d.ts +38 -0
- package/dist/modes/interactive/components/rewind-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/rewind-selector.js +119 -0
- package/dist/modes/interactive/components/rewind-selector.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +63 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +4 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +4 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/docs/extensions.md +19 -0
- package/docs/keybindings.md +1 -0
- package/docs/packages.md +20 -0
- package/docs/sessions.md +30 -8
- package/docs/usage.md +2 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type Component, Container } from "@elyracode/tui";
|
|
2
|
+
/** A rewind point shown in the selector. */
|
|
3
|
+
export interface RewindPoint {
|
|
4
|
+
/** Session entry ID for this rewind point. */
|
|
5
|
+
entryId: string;
|
|
6
|
+
/** Human-readable description of the state at this point. */
|
|
7
|
+
text: string;
|
|
8
|
+
/** ISO timestamp. */
|
|
9
|
+
timestamp: string;
|
|
10
|
+
/** Number of files that will change if rewinding to this point. */
|
|
11
|
+
filesChanged: number;
|
|
12
|
+
/** Whether this is the current position in the session. */
|
|
13
|
+
isCurrent: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* List component for navigating rewind points.
|
|
17
|
+
*/
|
|
18
|
+
declare class RewindList implements Component {
|
|
19
|
+
private items;
|
|
20
|
+
private selectedIndex;
|
|
21
|
+
private maxVisible;
|
|
22
|
+
onSelect?: (entryId: string) => void;
|
|
23
|
+
onCancel?: () => void;
|
|
24
|
+
constructor(items: RewindPoint[], initialSelectedIndex?: number);
|
|
25
|
+
invalidate(): void;
|
|
26
|
+
render(width: number): string[];
|
|
27
|
+
handleInput(keyData: string): void;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Container component for the rewind selector UI.
|
|
31
|
+
*/
|
|
32
|
+
export declare class RewindSelectorComponent extends Container {
|
|
33
|
+
private rewindList;
|
|
34
|
+
constructor(items: RewindPoint[], onSelect: (entryId: string) => void, onCancel: () => void, initialSelectedIndex?: number);
|
|
35
|
+
getList(): RewindList;
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=rewind-selector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewind-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/rewind-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,SAAS,EAAiD,MAAM,gBAAgB,CAAC;AAI1G,4CAA4C;AAC5C,MAAM,WAAW,WAAW;IAC3B,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,YAAY,EAAE,MAAM,CAAC;IACrB,2DAA2D;IAC3D,SAAS,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,cAAM,UAAW,YAAW,SAAS;IACpC,OAAO,CAAC,KAAK,CAAqB;IAClC,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,UAAU,CAAM;IAEjB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAE7B,YAAY,KAAK,EAAE,WAAW,EAAE,EAAE,oBAAoB,CAAC,EAAE,MAAM,EAG9D;IAED,UAAU,IAAI,IAAI,CAEjB;IAED,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAkD9B;IAED,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAcjC;CACD;AAED;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,SAAS;IACrD,OAAO,CAAC,UAAU,CAAa;IAE/B,YACC,KAAK,EAAE,WAAW,EAAE,EACpB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACnC,QAAQ,EAAE,MAAM,IAAI,EACpB,oBAAoB,CAAC,EAAE,MAAM,EAwB7B;IAED,OAAO,IAAI,UAAU,CAEpB;CACD"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { Container, getKeybindings, Spacer, Text, truncateToWidth } from "@elyracode/tui";
|
|
2
|
+
import { theme } from "../theme/theme.js";
|
|
3
|
+
import { DynamicBorder } from "./dynamic-border.js";
|
|
4
|
+
/**
|
|
5
|
+
* List component for navigating rewind points.
|
|
6
|
+
*/
|
|
7
|
+
class RewindList {
|
|
8
|
+
constructor(items, initialSelectedIndex) {
|
|
9
|
+
this.items = [];
|
|
10
|
+
this.selectedIndex = 0;
|
|
11
|
+
this.maxVisible = 10;
|
|
12
|
+
this.items = items;
|
|
13
|
+
this.selectedIndex = initialSelectedIndex ?? Math.max(0, items.length - 1);
|
|
14
|
+
}
|
|
15
|
+
invalidate() {
|
|
16
|
+
// No cached state
|
|
17
|
+
}
|
|
18
|
+
render(width) {
|
|
19
|
+
const lines = [];
|
|
20
|
+
if (this.items.length === 0) {
|
|
21
|
+
lines.push(theme.fg("muted", " No rewind points available"));
|
|
22
|
+
return lines;
|
|
23
|
+
}
|
|
24
|
+
// Calculate visible range with scrolling
|
|
25
|
+
const startIndex = Math.max(0, Math.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.items.length - this.maxVisible));
|
|
26
|
+
const endIndex = Math.min(startIndex + this.maxVisible, this.items.length);
|
|
27
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
28
|
+
const item = this.items[i];
|
|
29
|
+
const isSelected = i === this.selectedIndex;
|
|
30
|
+
// First line: cursor + description
|
|
31
|
+
const cursor = isSelected ? theme.fg("accent", "› ") : " ";
|
|
32
|
+
const normalizedText = item.text.replace(/\n/g, " ").trim();
|
|
33
|
+
const maxWidth = width - 2;
|
|
34
|
+
const truncatedText = truncateToWidth(normalizedText, maxWidth);
|
|
35
|
+
const styledText = item.isCurrent
|
|
36
|
+
? theme.fg("muted", `${truncatedText} (current)`)
|
|
37
|
+
: isSelected
|
|
38
|
+
? theme.bold(truncatedText)
|
|
39
|
+
: truncatedText;
|
|
40
|
+
lines.push(cursor + styledText);
|
|
41
|
+
// Second line: metadata
|
|
42
|
+
const time = formatTimestamp(item.timestamp);
|
|
43
|
+
const fileInfo = item.isCurrent
|
|
44
|
+
? ""
|
|
45
|
+
: item.filesChanged === 1
|
|
46
|
+
? " · 1 file will change"
|
|
47
|
+
: item.filesChanged > 1
|
|
48
|
+
? ` · ${item.filesChanged} files will change`
|
|
49
|
+
: "";
|
|
50
|
+
lines.push(theme.fg("muted", ` ${time}${fileInfo}`));
|
|
51
|
+
lines.push(""); // spacer
|
|
52
|
+
}
|
|
53
|
+
// Scroll indicator
|
|
54
|
+
if (startIndex > 0 || endIndex < this.items.length) {
|
|
55
|
+
lines.push(theme.fg("muted", ` (${this.selectedIndex + 1}/${this.items.length})`));
|
|
56
|
+
}
|
|
57
|
+
return lines;
|
|
58
|
+
}
|
|
59
|
+
handleInput(keyData) {
|
|
60
|
+
const kb = getKeybindings();
|
|
61
|
+
if (kb.matches(keyData, "tui.select.up")) {
|
|
62
|
+
this.selectedIndex = this.selectedIndex === 0 ? this.items.length - 1 : this.selectedIndex - 1;
|
|
63
|
+
}
|
|
64
|
+
else if (kb.matches(keyData, "tui.select.down")) {
|
|
65
|
+
this.selectedIndex = this.selectedIndex === this.items.length - 1 ? 0 : this.selectedIndex + 1;
|
|
66
|
+
}
|
|
67
|
+
else if (kb.matches(keyData, "tui.select.confirm")) {
|
|
68
|
+
const selected = this.items[this.selectedIndex];
|
|
69
|
+
if (selected && !selected.isCurrent && this.onSelect) {
|
|
70
|
+
this.onSelect(selected.entryId);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if (kb.matches(keyData, "tui.select.cancel")) {
|
|
74
|
+
this.onCancel?.();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Container component for the rewind selector UI.
|
|
80
|
+
*/
|
|
81
|
+
export class RewindSelectorComponent extends Container {
|
|
82
|
+
constructor(items, onSelect, onCancel, initialSelectedIndex) {
|
|
83
|
+
super();
|
|
84
|
+
this.addChild(new Spacer(1));
|
|
85
|
+
this.addChild(new Text(theme.bold("Rewind Session"), 1, 0));
|
|
86
|
+
this.addChild(new Text(theme.fg("muted", "Select a point to rewind to — restores both conversation and file state"), 1, 0));
|
|
87
|
+
this.addChild(new Spacer(1));
|
|
88
|
+
this.addChild(new DynamicBorder());
|
|
89
|
+
this.addChild(new Spacer(1));
|
|
90
|
+
this.rewindList = new RewindList(items, initialSelectedIndex);
|
|
91
|
+
this.rewindList.onSelect = onSelect;
|
|
92
|
+
this.rewindList.onCancel = onCancel;
|
|
93
|
+
this.addChild(this.rewindList);
|
|
94
|
+
this.addChild(new Spacer(1));
|
|
95
|
+
this.addChild(new DynamicBorder());
|
|
96
|
+
if (items.length === 0) {
|
|
97
|
+
setTimeout(() => onCancel(), 100);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
getList() {
|
|
101
|
+
return this.rewindList;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** Format an ISO timestamp to a human-readable relative or short form. */
|
|
105
|
+
function formatTimestamp(iso) {
|
|
106
|
+
const date = new Date(iso);
|
|
107
|
+
const now = Date.now();
|
|
108
|
+
const diffMs = now - date.getTime();
|
|
109
|
+
const diffMin = Math.floor(diffMs / 60_000);
|
|
110
|
+
if (diffMin < 1)
|
|
111
|
+
return "just now";
|
|
112
|
+
if (diffMin < 60)
|
|
113
|
+
return `${diffMin}m ago`;
|
|
114
|
+
const diffHours = Math.floor(diffMin / 60);
|
|
115
|
+
if (diffHours < 24)
|
|
116
|
+
return `${diffHours}h ago`;
|
|
117
|
+
return date.toLocaleDateString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" });
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=rewind-selector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rewind-selector.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/rewind-selector.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Component, Container, getKeybindings, Spacer, Text, truncateToWidth } from \"@elyracode/tui\";\nimport { theme } from \"../theme/theme.js\";\nimport { DynamicBorder } from \"./dynamic-border.js\";\n\n/** A rewind point shown in the selector. */\nexport interface RewindPoint {\n\t/** Session entry ID for this rewind point. */\n\tentryId: string;\n\t/** Human-readable description of the state at this point. */\n\ttext: string;\n\t/** ISO timestamp. */\n\ttimestamp: string;\n\t/** Number of files that will change if rewinding to this point. */\n\tfilesChanged: number;\n\t/** Whether this is the current position in the session. */\n\tisCurrent: boolean;\n}\n\n/**\n * List component for navigating rewind points.\n */\nclass RewindList implements Component {\n\tprivate items: RewindPoint[] = [];\n\tprivate selectedIndex = 0;\n\tprivate maxVisible = 10;\n\n\tpublic onSelect?: (entryId: string) => void;\n\tpublic onCancel?: () => void;\n\n\tconstructor(items: RewindPoint[], initialSelectedIndex?: number) {\n\t\tthis.items = items;\n\t\tthis.selectedIndex = initialSelectedIndex ?? Math.max(0, items.length - 1);\n\t}\n\n\tinvalidate(): void {\n\t\t// No cached state\n\t}\n\n\trender(width: number): string[] {\n\t\tconst lines: string[] = [];\n\n\t\tif (this.items.length === 0) {\n\t\t\tlines.push(theme.fg(\"muted\", \" No rewind points available\"));\n\t\t\treturn lines;\n\t\t}\n\n\t\t// Calculate visible range with scrolling\n\t\tconst startIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.selectedIndex - Math.floor(this.maxVisible / 2), this.items.length - this.maxVisible),\n\t\t);\n\t\tconst endIndex = Math.min(startIndex + this.maxVisible, this.items.length);\n\n\t\tfor (let i = startIndex; i < endIndex; i++) {\n\t\t\tconst item = this.items[i];\n\t\t\tconst isSelected = i === this.selectedIndex;\n\n\t\t\t// First line: cursor + description\n\t\t\tconst cursor = isSelected ? theme.fg(\"accent\", \"› \") : \" \";\n\t\t\tconst normalizedText = item.text.replace(/\\n/g, \" \").trim();\n\t\t\tconst maxWidth = width - 2;\n\t\t\tconst truncatedText = truncateToWidth(normalizedText, maxWidth);\n\t\t\tconst styledText = item.isCurrent\n\t\t\t\t? theme.fg(\"muted\", `${truncatedText} (current)`)\n\t\t\t\t: isSelected\n\t\t\t\t\t? theme.bold(truncatedText)\n\t\t\t\t\t: truncatedText;\n\t\t\tlines.push(cursor + styledText);\n\n\t\t\t// Second line: metadata\n\t\t\tconst time = formatTimestamp(item.timestamp);\n\t\t\tconst fileInfo = item.isCurrent\n\t\t\t\t? \"\"\n\t\t\t\t: item.filesChanged === 1\n\t\t\t\t\t? \" · 1 file will change\"\n\t\t\t\t\t: item.filesChanged > 1\n\t\t\t\t\t\t? ` · ${item.filesChanged} files will change`\n\t\t\t\t\t\t: \"\";\n\t\t\tlines.push(theme.fg(\"muted\", ` ${time}${fileInfo}`));\n\t\t\tlines.push(\"\"); // spacer\n\t\t}\n\n\t\t// Scroll indicator\n\t\tif (startIndex > 0 || endIndex < this.items.length) {\n\t\t\tlines.push(theme.fg(\"muted\", ` (${this.selectedIndex + 1}/${this.items.length})`));\n\t\t}\n\n\t\treturn lines;\n\t}\n\n\thandleInput(keyData: string): void {\n\t\tconst kb = getKeybindings();\n\t\tif (kb.matches(keyData, \"tui.select.up\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === 0 ? this.items.length - 1 : this.selectedIndex - 1;\n\t\t} else if (kb.matches(keyData, \"tui.select.down\")) {\n\t\t\tthis.selectedIndex = this.selectedIndex === this.items.length - 1 ? 0 : this.selectedIndex + 1;\n\t\t} else if (kb.matches(keyData, \"tui.select.confirm\")) {\n\t\t\tconst selected = this.items[this.selectedIndex];\n\t\t\tif (selected && !selected.isCurrent && this.onSelect) {\n\t\t\t\tthis.onSelect(selected.entryId);\n\t\t\t}\n\t\t} else if (kb.matches(keyData, \"tui.select.cancel\")) {\n\t\t\tthis.onCancel?.();\n\t\t}\n\t}\n}\n\n/**\n * Container component for the rewind selector UI.\n */\nexport class RewindSelectorComponent extends Container {\n\tprivate rewindList: RewindList;\n\n\tconstructor(\n\t\titems: RewindPoint[],\n\t\tonSelect: (entryId: string) => void,\n\t\tonCancel: () => void,\n\t\tinitialSelectedIndex?: number,\n\t) {\n\t\tsuper();\n\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new Text(theme.bold(\"Rewind Session\"), 1, 0));\n\t\tthis.addChild(\n\t\t\tnew Text(theme.fg(\"muted\", \"Select a point to rewind to — restores both conversation and file state\"), 1, 0),\n\t\t);\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\t\tthis.addChild(new Spacer(1));\n\n\t\tthis.rewindList = new RewindList(items, initialSelectedIndex);\n\t\tthis.rewindList.onSelect = onSelect;\n\t\tthis.rewindList.onCancel = onCancel;\n\t\tthis.addChild(this.rewindList);\n\n\t\tthis.addChild(new Spacer(1));\n\t\tthis.addChild(new DynamicBorder());\n\n\t\tif (items.length === 0) {\n\t\t\tsetTimeout(() => onCancel(), 100);\n\t\t}\n\t}\n\n\tgetList(): RewindList {\n\t\treturn this.rewindList;\n\t}\n}\n\n/** Format an ISO timestamp to a human-readable relative or short form. */\nfunction formatTimestamp(iso: string): string {\n\tconst date = new Date(iso);\n\tconst now = Date.now();\n\tconst diffMs = now - date.getTime();\n\tconst diffMin = Math.floor(diffMs / 60_000);\n\n\tif (diffMin < 1) return \"just now\";\n\tif (diffMin < 60) return `${diffMin}m ago`;\n\tconst diffHours = Math.floor(diffMin / 60);\n\tif (diffHours < 24) return `${diffHours}h ago`;\n\treturn date.toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", hour: \"2-digit\", minute: \"2-digit\" });\n}\n"]}
|
|
@@ -340,6 +340,7 @@ export declare class InteractiveMode {
|
|
|
340
340
|
private showUserMessageSelector;
|
|
341
341
|
private handleCloneCommand;
|
|
342
342
|
private showTreeSelector;
|
|
343
|
+
private showRewindSelector;
|
|
343
344
|
private showSessionSelector;
|
|
344
345
|
private handleResumeSession;
|
|
345
346
|
private getLoginProviderOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interactive-mode.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-mode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAGN,KAAK,YAAY,EAKjB,MAAM,eAAe,CAAC;AA6CvB,OAAO,EAAE,KAAK,mBAAmB,EAAkC,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"interactive-mode.d.ts","sourceRoot":"","sources":["../../../src/modes/interactive/interactive-mode.ts"],"names":[],"mappings":"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"}
|
|
@@ -50,6 +50,7 @@ import { formatKeyText, keyDisplayText, keyHint, keyText, rawKeyHint } from "./c
|
|
|
50
50
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
51
51
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
52
52
|
import { OAuthSelectorComponent } from "./components/oauth-selector.js";
|
|
53
|
+
import { RewindSelectorComponent } from "./components/rewind-selector.js";
|
|
53
54
|
import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
|
|
54
55
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
55
56
|
import { SettingsSelectorComponent } from "./components/settings-selector.js";
|
|
@@ -1178,6 +1179,19 @@ export class InteractiveMode {
|
|
|
1178
1179
|
void this.flushCompactionQueue({ willRetry: false });
|
|
1179
1180
|
return { cancelled: false };
|
|
1180
1181
|
},
|
|
1182
|
+
rewind: async (entryId) => {
|
|
1183
|
+
const result = await this.session.rewind(entryId);
|
|
1184
|
+
if (!result.cancelled && !result.error) {
|
|
1185
|
+
this.chatContainer.clear();
|
|
1186
|
+
this.renderInitialMessages();
|
|
1187
|
+
if (result.editorText && !this.editor.getText().trim()) {
|
|
1188
|
+
this.editor.setText(result.editorText);
|
|
1189
|
+
}
|
|
1190
|
+
this.showStatus("Rewound to selected point");
|
|
1191
|
+
void this.flushCompactionQueue({ willRetry: false });
|
|
1192
|
+
}
|
|
1193
|
+
return { cancelled: result.cancelled, filesRestored: result.filesRestored, error: result.error };
|
|
1194
|
+
},
|
|
1181
1195
|
switchSession: async (sessionPath, options) => {
|
|
1182
1196
|
return this.handleResumeSession(sessionPath, options);
|
|
1183
1197
|
},
|
|
@@ -1939,6 +1953,7 @@ export class InteractiveMode {
|
|
|
1939
1953
|
this.defaultEditor.onAction("app.session.tree", () => this.showTreeSelector());
|
|
1940
1954
|
this.defaultEditor.onAction("app.session.fork", () => this.showUserMessageSelector());
|
|
1941
1955
|
this.defaultEditor.onAction("app.session.resume", () => this.showSessionSelector());
|
|
1956
|
+
this.defaultEditor.onAction("app.session.rewind", () => this.showRewindSelector());
|
|
1942
1957
|
this.defaultEditor.onChange = (text) => {
|
|
1943
1958
|
const wasBashMode = this.isBashMode;
|
|
1944
1959
|
this.isBashMode = text.trimStart().startsWith("!");
|
|
@@ -2122,6 +2137,11 @@ export class InteractiveMode {
|
|
|
2122
2137
|
this.editor.setText("");
|
|
2123
2138
|
return;
|
|
2124
2139
|
}
|
|
2140
|
+
if (text === "/rewind") {
|
|
2141
|
+
this.showRewindSelector();
|
|
2142
|
+
this.editor.setText("");
|
|
2143
|
+
return;
|
|
2144
|
+
}
|
|
2125
2145
|
if (text === "/login") {
|
|
2126
2146
|
this.showOAuthSelector("login");
|
|
2127
2147
|
this.editor.setText("");
|
|
@@ -4234,6 +4254,49 @@ export class InteractiveMode {
|
|
|
4234
4254
|
return { component: selector, focus: selector };
|
|
4235
4255
|
});
|
|
4236
4256
|
}
|
|
4257
|
+
showRewindSelector() {
|
|
4258
|
+
const points = this.session.getRewindPoints();
|
|
4259
|
+
if (points.length === 0) {
|
|
4260
|
+
this.showStatus("No rewind points available — checkpoints are created when the agent runs");
|
|
4261
|
+
return;
|
|
4262
|
+
}
|
|
4263
|
+
// Pre-select the second-to-last point (last non-current point)
|
|
4264
|
+
const initialIndex = Math.max(0, points.length - 2);
|
|
4265
|
+
this.showSelector((done) => {
|
|
4266
|
+
const selector = new RewindSelectorComponent(points, async (entryId) => {
|
|
4267
|
+
done();
|
|
4268
|
+
try {
|
|
4269
|
+
const result = await this.session.rewind(entryId);
|
|
4270
|
+
if (result.cancelled) {
|
|
4271
|
+
this.ui.requestRender();
|
|
4272
|
+
return;
|
|
4273
|
+
}
|
|
4274
|
+
if (result.error) {
|
|
4275
|
+
this.showError(`Rewind error: ${result.error}`);
|
|
4276
|
+
return;
|
|
4277
|
+
}
|
|
4278
|
+
// Rebuild the chat UI
|
|
4279
|
+
this.chatContainer.clear();
|
|
4280
|
+
this.renderInitialMessages();
|
|
4281
|
+
if (result.editorText && !this.editor.getText().trim()) {
|
|
4282
|
+
this.editor.setText(result.editorText);
|
|
4283
|
+
}
|
|
4284
|
+
const fileMsg = result.filesRestored > 0
|
|
4285
|
+
? ` (${result.filesRestored} file${result.filesRestored === 1 ? "" : "s"} restored)`
|
|
4286
|
+
: "";
|
|
4287
|
+
this.showStatus(`Rewound to selected point${fileMsg}`);
|
|
4288
|
+
void this.flushCompactionQueue({ willRetry: false });
|
|
4289
|
+
}
|
|
4290
|
+
catch (error) {
|
|
4291
|
+
this.showError(error instanceof Error ? error.message : String(error));
|
|
4292
|
+
}
|
|
4293
|
+
}, () => {
|
|
4294
|
+
done();
|
|
4295
|
+
this.ui.requestRender();
|
|
4296
|
+
}, initialIndex);
|
|
4297
|
+
return { component: selector, focus: selector.getList() };
|
|
4298
|
+
});
|
|
4299
|
+
}
|
|
4237
4300
|
showSessionSelector() {
|
|
4238
4301
|
this.showSelector((done) => {
|
|
4239
4302
|
const selector = new SessionSelectorComponent((onProgress) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress), SessionManager.listAll, async (sessionPath) => {
|