lsd-pi 1.1.4 → 1.1.6
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/README.md +2 -1
- package/dist/headless-ui.js +2 -0
- package/dist/onboarding.js +11 -8
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +14 -0
- package/dist/resources/extensions/async-jobs/await-tool.js +14 -0
- package/dist/resources/extensions/async-jobs/cancel-job-tool.js +7 -0
- package/dist/resources/extensions/cache-timer/index.js +5 -0
- package/dist/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
- package/dist/resources/extensions/codex-rotate/README.md +9 -3
- package/dist/resources/extensions/codex-rotate/commands.js +15 -8
- package/dist/resources/extensions/codex-rotate/index.js +17 -8
- package/dist/resources/extensions/memory/auto-extract.js +196 -80
- package/dist/resources/extensions/memory/dream.js +86 -19
- package/dist/resources/extensions/shared/rtk.js +89 -87
- package/dist/resources/extensions/subagent/index.js +33 -7
- package/dist/startup-model-validation.js +12 -2
- package/dist/update-check.js +2 -2
- package/dist/update-cmd.js +3 -3
- package/dist/welcome-screen.js +43 -14
- package/package.json +3 -2
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js +46 -0
- package/packages/pi-coding-agent/dist/core/agent-session.clear-queue.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts +8 -0
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +43 -4
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/keybindings.js +2 -0
- package/packages/pi-coding-agent/dist/core/keybindings.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/pty-executor.d.ts +48 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.js +173 -0
- package/packages/pi-coding-agent/dist/core/pty-executor.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +16 -3
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +18 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tool-approval.js +2 -2
- package/packages/pi-coding-agent/dist/core/tool-approval.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts +7 -0
- package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/index.js +23 -2
- package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts +50 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.js +289 -0
- package/packages/pi-coding-agent/dist/core/tools/pty.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +36 -22
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +3 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +23 -62
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js +1 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts +39 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js +182 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/embedded-terminal.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +6 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +36 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js +2 -4
- package/packages/pi-coding-agent/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +106 -77
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +4 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts +11 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +49 -13
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +3 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +27 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +251 -39
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts +10 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.js +67 -0
- package/packages/pi-coding-agent/dist/utils/terminal-screen.js.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts +7 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.js +67 -0
- package/packages/pi-coding-agent/dist/utils/terminal-serializer.js.map +1 -0
- package/packages/pi-coding-agent/package.json +9 -4
- package/packages/pi-coding-agent/src/core/agent-session.clear-queue.test.ts +50 -0
- package/packages/pi-coding-agent/src/core/agent-session.ts +50 -4
- package/packages/pi-coding-agent/src/core/extensions/types.ts +1 -1
- package/packages/pi-coding-agent/src/core/keybindings.ts +4 -1
- package/packages/pi-coding-agent/src/core/pty-executor.ts +229 -0
- package/packages/pi-coding-agent/src/core/sdk.ts +16 -3
- package/packages/pi-coding-agent/src/core/settings-manager.ts +27 -0
- package/packages/pi-coding-agent/src/core/tool-approval.ts +2 -2
- package/packages/pi-coding-agent/src/core/tools/index.ts +35 -2
- package/packages/pi-coding-agent/src/core/tools/pty.ts +354 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +37 -24
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +22 -70
- package/packages/pi-coding-agent/src/modes/interactive/components/branch-summary-message.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/compaction-summary-message.ts +1 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/embedded-terminal.ts +224 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +45 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/skill-invocation-message.ts +2 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +104 -81
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +5 -19
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +55 -13
- package/packages/pi-coding-agent/src/modes/interactive/controllers/extension-ui-controller.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +3 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +296 -48
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +2 -2
- package/packages/pi-coding-agent/src/utils/terminal-screen.ts +77 -0
- package/packages/pi-coding-agent/src/utils/terminal-serializer.ts +72 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts +2 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js +105 -0
- package/packages/pi-tui/dist/components/__tests__/editor-dropped-image.test.js.map +1 -0
- package/packages/pi-tui/dist/components/editor.d.ts +4 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +57 -3
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/loader.d.ts +26 -6
- package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/loader.js +178 -18
- package/packages/pi-tui/dist/components/loader.js.map +1 -1
- package/packages/pi-tui/src/components/editor.ts +65 -3
- package/packages/pi-tui/src/components/loader.ts +196 -19
- package/pkg/dist/modes/interactive/theme/themes.js +2 -2
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +13 -0
- package/src/resources/extensions/async-jobs/await-tool.ts +13 -0
- package/src/resources/extensions/async-jobs/cancel-job-tool.ts +8 -0
- package/src/resources/extensions/cache-timer/index.ts +102 -96
- package/src/resources/extensions/codex-rotate/IMPLEMENTATION.md +18 -13
- package/src/resources/extensions/codex-rotate/README.md +9 -3
- package/src/resources/extensions/codex-rotate/commands.ts +335 -329
- package/src/resources/extensions/codex-rotate/index.ts +85 -75
- package/src/resources/extensions/memory/auto-extract.ts +330 -204
- package/src/resources/extensions/memory/dream.ts +88 -21
- package/src/resources/extensions/memory/tests/auto-extract.test.ts +200 -144
- package/src/resources/extensions/shared/rtk.js +112 -0
- package/src/resources/extensions/subagent/index.ts +35 -6
|
@@ -1,23 +1,81 @@
|
|
|
1
1
|
import type { TUI } from "../tui.js";
|
|
2
2
|
import { Text } from "./text.js";
|
|
3
3
|
|
|
4
|
+
// ─── ANSI helpers ─────────────────────────────────────────────────────────────
|
|
5
|
+
|
|
6
|
+
const ESC = "\x1b[";
|
|
7
|
+
const RESET = "\x1b[0m";
|
|
8
|
+
const DIM = "\x1b[2m";
|
|
9
|
+
const BOLD = "\x1b[1m";
|
|
10
|
+
|
|
11
|
+
/** 24-bit foreground color */
|
|
12
|
+
function rgb(r: number, g: number, b: number, s: string): string {
|
|
13
|
+
return `${ESC}38;2;${r};${g};${b}m${s}${RESET}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Interpolate between two RGB colors at position t ∈ [0,1] */
|
|
17
|
+
function lerpColor(
|
|
18
|
+
r1: number, g1: number, b1: number,
|
|
19
|
+
r2: number, g2: number, b2: number,
|
|
20
|
+
t: number,
|
|
21
|
+
): [number, number, number] {
|
|
22
|
+
return [
|
|
23
|
+
Math.round(r1 + (r2 - r1) * t),
|
|
24
|
+
Math.round(g1 + (g2 - g1) * t),
|
|
25
|
+
Math.round(b1 + (b2 - b1) * t),
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ─── Timing constants ─────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
const TYPING_SPEED = 55; // ms per character typed
|
|
32
|
+
const HOLD_TIME = 5000; // ms to hold the full word
|
|
33
|
+
const ERASE_SPEED = 35; // ms per character erased
|
|
34
|
+
|
|
35
|
+
// ─── Phase type ───────────────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
type Phase = "typing" | "hold" | "erase";
|
|
38
|
+
|
|
4
39
|
/**
|
|
5
|
-
* Loader component
|
|
40
|
+
* Loader component — braille spinner + animated word cycling.
|
|
41
|
+
*
|
|
42
|
+
* Each word types in character by character (typewriter), holds with a moving
|
|
43
|
+
* blue→cyan shimmer gradient, then erases right-to-left before the next word.
|
|
6
44
|
*/
|
|
7
45
|
export class Loader extends Text {
|
|
46
|
+
// ── spinner ───────────────────────────────────────────────────────────────
|
|
8
47
|
private frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
9
48
|
private currentFrame = 0;
|
|
10
|
-
private
|
|
49
|
+
private spinnerIntervalId: NodeJS.Timeout | null = null;
|
|
11
50
|
private ui: TUI | null = null;
|
|
12
51
|
|
|
52
|
+
// ── message state ─────────────────────────────────────────────────────────
|
|
53
|
+
private message: string = "";
|
|
54
|
+
|
|
55
|
+
// ── word animation ────────────────────────────────────────────────────────
|
|
56
|
+
private cycleMessages: string[] | null = null;
|
|
57
|
+
private cycleIndex = 0;
|
|
58
|
+
private phase: Phase = "typing";
|
|
59
|
+
private visibleChars = 0;
|
|
60
|
+
private wordAnimId: NodeJS.Timeout | null = null;
|
|
61
|
+
|
|
62
|
+
// ── shimmer gradient: theme blueHigh → blueXhigh ─────────────────────────
|
|
63
|
+
private readonly gradStart: [number, number, number] = [147, 197, 253]; // #93c5fd (blue-300)
|
|
64
|
+
private readonly gradEnd: [number, number, number] = [191, 219, 254]; // #bfdbfe (blue-200)
|
|
65
|
+
|
|
66
|
+
// Shimmer ticks independently at ~40ms for smooth gradient movement
|
|
67
|
+
private shimmerTick = 0;
|
|
68
|
+
private shimmerIntervalId: NodeJS.Timeout | null = null;
|
|
69
|
+
|
|
13
70
|
constructor(
|
|
14
71
|
ui: TUI,
|
|
15
72
|
private spinnerColorFn: (str: string) => string,
|
|
16
|
-
private
|
|
17
|
-
|
|
73
|
+
private _messageColorFn: (str: string) => string,
|
|
74
|
+
message: string = "Loading…",
|
|
18
75
|
) {
|
|
19
76
|
super("", 1, 0);
|
|
20
77
|
this.ui = ui;
|
|
78
|
+
this.message = message;
|
|
21
79
|
this.start();
|
|
22
80
|
}
|
|
23
81
|
|
|
@@ -25,22 +83,63 @@ export class Loader extends Text {
|
|
|
25
83
|
return ["", ...super.render(width)];
|
|
26
84
|
}
|
|
27
85
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
86
|
+
// ── public API ────────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
setCycleMessages(messages: string[], _intervalMs = 3000) {
|
|
89
|
+
this.cycleMessages = [...messages];
|
|
90
|
+
this.cycleIndex = 0;
|
|
91
|
+
this.message = this.cycleMessages[0];
|
|
92
|
+
if (this.spinnerIntervalId) {
|
|
93
|
+
this.startWordAnimation();
|
|
31
94
|
}
|
|
32
95
|
this.updateDisplay();
|
|
33
|
-
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
clearCycleMessages() {
|
|
99
|
+
this.stopWordAnimation();
|
|
100
|
+
this.cycleMessages = null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
setMessage(message: string) {
|
|
104
|
+
// When an explicit message is set externally (e.g. "Waiting for approval…"),
|
|
105
|
+
// pause the cycle so it doesn't immediately overwrite the override.
|
|
106
|
+
this.stopWordAnimation();
|
|
107
|
+
this.cycleMessages = null;
|
|
108
|
+
this.message = message;
|
|
109
|
+
this.updateDisplay();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
resumeCycle() {
|
|
113
|
+
if (this.cycleMessages && !this.wordAnimId) {
|
|
114
|
+
this.startWordAnimation();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
start() {
|
|
119
|
+
if (this.spinnerIntervalId) clearInterval(this.spinnerIntervalId);
|
|
120
|
+
this.spinnerIntervalId = setInterval(() => {
|
|
34
121
|
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
35
122
|
this.updateDisplay();
|
|
36
123
|
}, 80);
|
|
124
|
+
|
|
125
|
+
// Shimmer ticks independently at ~40ms for smooth gradient movement
|
|
126
|
+
if (this.shimmerIntervalId) clearInterval(this.shimmerIntervalId);
|
|
127
|
+
this.shimmerIntervalId = setInterval(() => {
|
|
128
|
+
this.shimmerTick++;
|
|
129
|
+
if (this.cycleMessages) this.updateDisplay();
|
|
130
|
+
}, 40);
|
|
131
|
+
|
|
132
|
+
if (this.cycleMessages) {
|
|
133
|
+
this.startWordAnimation();
|
|
134
|
+
} else {
|
|
135
|
+
this.updateDisplay();
|
|
136
|
+
}
|
|
37
137
|
}
|
|
38
138
|
|
|
39
139
|
stop() {
|
|
40
|
-
if (this.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
140
|
+
if (this.spinnerIntervalId) { clearInterval(this.spinnerIntervalId); this.spinnerIntervalId = null; }
|
|
141
|
+
if (this.shimmerIntervalId) { clearInterval(this.shimmerIntervalId); this.shimmerIntervalId = null; }
|
|
142
|
+
this.stopWordAnimation();
|
|
44
143
|
}
|
|
45
144
|
|
|
46
145
|
dispose() {
|
|
@@ -48,16 +147,94 @@ export class Loader extends Text {
|
|
|
48
147
|
this.ui = null;
|
|
49
148
|
}
|
|
50
149
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
150
|
+
// ── word animation internals ──────────────────────────────────────────────
|
|
151
|
+
|
|
152
|
+
private startWordAnimation() {
|
|
153
|
+
this.stopWordAnimation();
|
|
154
|
+
this.phase = "typing";
|
|
155
|
+
this.visibleChars = 0;
|
|
156
|
+
this.scheduleWordTick();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private stopWordAnimation() {
|
|
160
|
+
if (this.wordAnimId) { clearTimeout(this.wordAnimId); this.wordAnimId = null; }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private scheduleWordTick() {
|
|
164
|
+
const word = this.currentWord();
|
|
165
|
+
|
|
166
|
+
if (this.phase === "typing") {
|
|
167
|
+
if (this.visibleChars < word.length) {
|
|
168
|
+
this.wordAnimId = setTimeout(() => {
|
|
169
|
+
this.visibleChars++;
|
|
170
|
+
this.updateDisplay();
|
|
171
|
+
this.scheduleWordTick();
|
|
172
|
+
}, TYPING_SPEED);
|
|
173
|
+
} else {
|
|
174
|
+
// Full word shown → hold
|
|
175
|
+
this.phase = "hold";
|
|
176
|
+
this.wordAnimId = setTimeout(() => {
|
|
177
|
+
this.phase = "erase";
|
|
178
|
+
this.scheduleWordTick();
|
|
179
|
+
}, HOLD_TIME);
|
|
180
|
+
}
|
|
181
|
+
} else if (this.phase === "erase") {
|
|
182
|
+
if (this.visibleChars > 0) {
|
|
183
|
+
this.wordAnimId = setTimeout(() => {
|
|
184
|
+
this.visibleChars--;
|
|
185
|
+
this.updateDisplay();
|
|
186
|
+
this.scheduleWordTick();
|
|
187
|
+
}, ERASE_SPEED);
|
|
188
|
+
} else {
|
|
189
|
+
// Advance to next word
|
|
190
|
+
if (this.cycleMessages) {
|
|
191
|
+
this.cycleIndex = (this.cycleIndex + 1) % this.cycleMessages.length;
|
|
192
|
+
this.message = this.cycleMessages[this.cycleIndex];
|
|
193
|
+
}
|
|
194
|
+
this.phase = "typing";
|
|
195
|
+
this.scheduleWordTick();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private currentWord(): string {
|
|
201
|
+
return this.message;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ── rendering ─────────────────────────────────────────────────────────────
|
|
205
|
+
|
|
206
|
+
private renderAnimatedWord(): string {
|
|
207
|
+
const word = this.currentWord();
|
|
208
|
+
const visible = word.slice(0, this.visibleChars);
|
|
209
|
+
if (!visible) return DIM + " " + RESET;
|
|
210
|
+
|
|
211
|
+
// Each char gets a colour position that travels through the gradient.
|
|
212
|
+
// The "wave" offset shifts every shimmerTick for a moving shimmer.
|
|
213
|
+
let out = "";
|
|
214
|
+
for (let i = 0; i < visible.length; i++) {
|
|
215
|
+
const wave = (i / Math.max(word.length - 1, 1));
|
|
216
|
+
// Slow rightward drift
|
|
217
|
+
const drift = (this.shimmerTick * 0.025) % 1;
|
|
218
|
+
const t = ((wave + drift) % 1);
|
|
219
|
+
const [r, g, b] = lerpColor(...this.gradStart, ...this.gradEnd, t);
|
|
220
|
+
|
|
221
|
+
// Last char being typed gets a bright flash
|
|
222
|
+
const isEdge = (this.phase === "typing" && i === visible.length - 1);
|
|
223
|
+
const char = isEdge
|
|
224
|
+
? `${BOLD}${rgb(255, 255, 255, visible[i])}`
|
|
225
|
+
: rgb(r, g, b, visible[i]);
|
|
226
|
+
out += char;
|
|
227
|
+
}
|
|
228
|
+
return out;
|
|
54
229
|
}
|
|
55
230
|
|
|
56
231
|
private updateDisplay() {
|
|
57
232
|
const frame = this.frames[this.currentFrame];
|
|
58
|
-
this.
|
|
59
|
-
|
|
60
|
-
this.
|
|
61
|
-
|
|
233
|
+
const spinner = this.spinnerColorFn(frame);
|
|
234
|
+
const text = this.cycleMessages
|
|
235
|
+
? this.renderAnimatedWord()
|
|
236
|
+
: this._messageColorFn(this.message);
|
|
237
|
+
this.setText(`${spinner} ${text}`);
|
|
238
|
+
if (this.ui) this.ui.requestRender();
|
|
62
239
|
}
|
|
63
240
|
}
|
|
@@ -87,7 +87,7 @@ const dark = {
|
|
|
87
87
|
thinkingMedium: "blueHigh",
|
|
88
88
|
thinkingHigh: "blueXhigh",
|
|
89
89
|
thinkingXhigh: "cyan",
|
|
90
|
-
bashMode: "
|
|
90
|
+
bashMode: "accent",
|
|
91
91
|
},
|
|
92
92
|
export: {
|
|
93
93
|
pageBg: "#18181e",
|
|
@@ -175,7 +175,7 @@ const light = {
|
|
|
175
175
|
thinkingMedium: "teal",
|
|
176
176
|
thinkingHigh: "blueHigh",
|
|
177
177
|
thinkingXhigh: "blueXhigh",
|
|
178
|
-
bashMode: "
|
|
178
|
+
bashMode: "accent",
|
|
179
179
|
},
|
|
180
180
|
export: {
|
|
181
181
|
pageBg: "#f8f8f8",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themes.js","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/themes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E,MAAM,IAAI,GAAc;IACvB,IAAI,EAAE,MAAM;IACZ,IAAI,EAAE;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,SAAS;QAClB,QAAQ,EAAE,SAAS;QACnB,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,SAAS;QACpB,OAAO,EAAE,SAAS;QAClB,UAAU,EAAE,SAAS;QACrB,QAAQ,EAAE,SAAS;QACnB,SAAS,EAAE,SAAS;QACpB,UAAU,EAAE,SAAS;QACrB,SAAS,EAAE,SAAS;QACpB,aAAa,EAAE,SAAS;QACxB,aAAa,EAAE,SAAS;QACxB,WAAW,EAAE,SAAS;QACtB,WAAW,EAAE,SAAS;KACtB;IACD,MAAM,EAAE;QACP,MAAM,EAAE,QAAQ;QAChB,MAAM,EAAE,MAAM;QACd,YAAY,EAAE,MAAM;QACpB,WAAW,EAAE,MAAM;QACnB,OAAO,EAAE,OAAO;QAChB,KAAK,EAAE,KAAK;QACZ,OAAO,EAAE,QAAQ;QACjB,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,EAAE;QACR,YAAY,EAAE,MAAM;QAEpB,UAAU,EAAE,YAAY;QACxB,aAAa,EAAE,WAAW;QAC1B,eAAe,EAAE,EAAE;QACnB,eAAe,EAAE,aAAa;QAC9B,iBAAiB,EAAE,EAAE;QACrB,kBAAkB,EAAE,SAAS;QAC7B,aAAa,EAAE,eAAe;QAC9B,aAAa,EAAE,eAAe;QAC9B,WAAW,EAAE,aAAa;QAC1B,SAAS,EAAE,EAAE;QACb,UAAU,EAAE,MAAM;QAElB,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,SAAS;QACjB,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,QAAQ;QAChB,WAAW,EAAE,OAAO;QACpB,iBAAiB,EAAE,MAAM;QACzB,OAAO,EAAE,MAAM;QACf,aAAa,EAAE,MAAM;QACrB,IAAI,EAAE,MAAM;QACZ,YAAY,EAAE,QAAQ;QAEtB,aAAa,EAAE,OAAO;QACtB,eAAe,EAAE,KAAK;QACtB,eAAe,EAAE,MAAM;QAEvB,aAAa,EAAE,SAAS;QACxB,aAAa,EAAE,SAAS;QACxB,cAAc,EAAE,SAAS;QACzB,cAAc,EAAE,SAAS;QACzB,YAAY,EAAE,SAAS;QACvB,YAAY,EAAE,SAAS;QACvB,UAAU,EAAE,SAAS;QACrB,cAAc,EAAE,SAAS;QACzB,iBAAiB,EAAE,SAAS;QAE5B,WAAW,EAAE,WAAW;QACxB,eAAe,EAAE,SAAS;QAC1B,WAAW,EAAE,YAAY;QACzB,cAAc,EAAE,UAAU;QAC1B,YAAY,EAAE,WAAW;QACzB,aAAa,EAAE,MAAM;QAErB,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"themes.js","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/themes.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Built-in theme definitions.\n *\n * Each theme is a self-contained record of color values. Variable references\n * (e.g. \"accent\") are resolved against the `vars` map at load time by the\n * theme engine in theme.ts.\n *\n * To add a new built-in theme, add an entry to `builtinThemes` below.\n */\n\n// Re-use the ThemeJson type from the schema defined in theme.ts.\n// We import only the type to avoid circular runtime dependencies.\nimport type { ThemeJson } from \"./theme.js\";\n\n// ---------------------------------------------------------------------------\n// Dark theme\n// ---------------------------------------------------------------------------\n\nconst dark: ThemeJson = {\n\tname: \"dark\",\n\tvars: {\n\t\tcyan: \"#4a8cf7\",\n\t\tblue: \"#4a8cf7\",\n\t\tgreen: \"#b5bd68\",\n\t\tred: \"#cc6666\",\n\t\tyellow: \"#facc15\",\n\t\tviolet: \"#a78bfa\",\n\t\tgray: \"#bec8d6\",\n\t\tdimGray: \"#8793a3\",\n\t\tdarkGray: \"#505050\",\n\t\taccent: \"#60a5fa\",\n\t\tblueMuted: \"#1e3a8a\",\n\t\tblueLow: \"#2563eb\",\n\t\tblueMedium: \"#4a8cf7\",\n\t\tblueHigh: \"#60a5fa\",\n\t\tblueXhigh: \"#93c5fd\",\n\t\tselectedBg: \"#323640\",\n\t\tuserMsgBg: \"#252930\",\n\t\ttoolPendingBg: \"#1e2230\",\n\t\ttoolSuccessBg: \"#1a2330\",\n\t\ttoolErrorBg: \"#2a1e30\",\n\t\tcustomMsgBg: \"#2d2838\",\n\t},\n\tcolors: {\n\t\taccent: \"accent\",\n\t\tborder: \"blue\",\n\t\tborderAccent: \"cyan\",\n\t\tborderMuted: \"blue\",\n\t\tsuccess: \"green\",\n\t\terror: \"red\",\n\t\twarning: \"yellow\",\n\t\tviolet: \"violet\",\n\t\tmuted: \"gray\",\n\t\tdim: \"dimGray\",\n\t\ttext: \"\",\n\t\tthinkingText: \"gray\",\n\n\t\tselectedBg: \"selectedBg\",\n\t\tuserMessageBg: \"userMsgBg\",\n\t\tuserMessageText: \"\",\n\t\tcustomMessageBg: \"customMsgBg\",\n\t\tcustomMessageText: \"\",\n\t\tcustomMessageLabel: \"#9575cd\",\n\t\ttoolPendingBg: \"toolPendingBg\",\n\t\ttoolSuccessBg: \"toolSuccessBg\",\n\t\ttoolErrorBg: \"toolErrorBg\",\n\t\ttoolTitle: \"\",\n\t\ttoolOutput: \"gray\",\n\n\t\tmdHeading: \"#f0c674\",\n\t\tmdLink: \"#5a8aaa\",\n\t\tmdLinkUrl: \"dimGray\",\n\t\tmdCode: \"accent\",\n\t\tmdCodeBlock: \"green\",\n\t\tmdCodeBlockBorder: \"gray\",\n\t\tmdQuote: \"gray\",\n\t\tmdQuoteBorder: \"gray\",\n\t\tmdHr: \"gray\",\n\t\tmdListBullet: \"accent\",\n\n\t\ttoolDiffAdded: \"green\",\n\t\ttoolDiffRemoved: \"red\",\n\t\ttoolDiffContext: \"gray\",\n\n\t\tsyntaxComment: \"#6A9955\",\n\t\tsyntaxKeyword: \"#569CD6\",\n\t\tsyntaxFunction: \"#DCDCAA\",\n\t\tsyntaxVariable: \"#9CDCFE\",\n\t\tsyntaxString: \"#CE9178\",\n\t\tsyntaxNumber: \"#B5CEA8\",\n\t\tsyntaxType: \"#4EC9B0\",\n\t\tsyntaxOperator: \"#D4D4D4\",\n\t\tsyntaxPunctuation: \"#D4D4D4\",\n\n\t\tthinkingOff: \"blueMuted\",\n\t\tthinkingMinimal: \"blueLow\",\n\t\tthinkingLow: \"blueMedium\",\n\t\tthinkingMedium: \"blueHigh\",\n\t\tthinkingHigh: \"blueXhigh\",\n\t\tthinkingXhigh: \"cyan\",\n\n\t\tbashMode: \"accent\",\n\t},\n\texport: {\n\t\tpageBg: \"#18181e\",\n\t\tcardBg: \"#1e1e24\",\n\t\tinfoBg: \"#3c3728\",\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// Light theme\n// ---------------------------------------------------------------------------\n\nconst light: ThemeJson = {\n\tname: \"light\",\n\tvars: {\n\t\tteal: \"#3b82f6\",\n\t\tblue: \"#547da7\",\n\t\tgreen: \"#588458\",\n\t\tred: \"#aa5555\",\n\t\tyellow: \"#eab308\",\n\t\twarning: \"#7a5a00\",\n\t\tviolet: \"#8b5cf6\",\n\t\tmediumGray: \"#6c6c6c\",\n\t\tdimGray: \"#767676\",\n\t\tlightGray: \"#b0b0b0\",\n\t\tblueMuted: \"#6b8fb8\",\n\t\tblueLow: \"#547da7\",\n\t\tblueMedium: \"#3b82f6\",\n\t\tblueHigh: \"#2563eb\",\n\t\tblueXhigh: \"#1d4ed8\",\n\t\tselectedBg: \"#d0d0e0\",\n\t\tuserMsgBg: \"#e8e8e8\",\n\t\ttoolPendingBg: \"#e8eaf0\",\n\t\ttoolSuccessBg: \"#e8f0f0\",\n\t\ttoolErrorBg: \"#f0e8ee\",\n\t\tcustomMsgBg: \"#ede7f6\",\n\t},\n\tcolors: {\n\t\taccent: \"teal\",\n\t\tborder: \"blue\",\n\t\tborderAccent: \"teal\",\n\t\tborderMuted: \"lightGray\",\n\t\tsuccess: \"green\",\n\t\terror: \"red\",\n\t\twarning: \"warning\",\n\t\tviolet: \"violet\",\n\t\tmuted: \"mediumGray\",\n\t\tdim: \"dimGray\",\n\t\ttext: \"\",\n\t\tthinkingText: \"mediumGray\",\n\n\t\tselectedBg: \"selectedBg\",\n\t\tuserMessageBg: \"userMsgBg\",\n\t\tuserMessageText: \"\",\n\t\tcustomMessageBg: \"customMsgBg\",\n\t\tcustomMessageText: \"\",\n\t\tcustomMessageLabel: \"#7e57c2\",\n\t\ttoolPendingBg: \"toolPendingBg\",\n\t\ttoolSuccessBg: \"toolSuccessBg\",\n\t\ttoolErrorBg: \"toolErrorBg\",\n\t\ttoolTitle: \"\",\n\t\ttoolOutput: \"mediumGray\",\n\n\t\tmdHeading: \"yellow\",\n\t\tmdLink: \"blue\",\n\t\tmdLinkUrl: \"dimGray\",\n\t\tmdCode: \"teal\",\n\t\tmdCodeBlock: \"green\",\n\t\tmdCodeBlockBorder: \"mediumGray\",\n\t\tmdQuote: \"mediumGray\",\n\t\tmdQuoteBorder: \"mediumGray\",\n\t\tmdHr: \"mediumGray\",\n\t\tmdListBullet: \"green\",\n\n\t\ttoolDiffAdded: \"green\",\n\t\ttoolDiffRemoved: \"red\",\n\t\ttoolDiffContext: \"mediumGray\",\n\n\t\tsyntaxComment: \"#008000\",\n\t\tsyntaxKeyword: \"#0000FF\",\n\t\tsyntaxFunction: \"#795E26\",\n\t\tsyntaxVariable: \"#001080\",\n\t\tsyntaxString: \"#A31515\",\n\t\tsyntaxNumber: \"#098658\",\n\t\tsyntaxType: \"#267F99\",\n\t\tsyntaxOperator: \"#000000\",\n\t\tsyntaxPunctuation: \"#000000\",\n\n\t\tthinkingOff: \"blueMuted\",\n\t\tthinkingMinimal: \"blueLow\",\n\t\tthinkingLow: \"blueMedium\",\n\t\tthinkingMedium: \"teal\",\n\t\tthinkingHigh: \"blueHigh\",\n\t\tthinkingXhigh: \"blueXhigh\",\n\n\t\tbashMode: \"accent\",\n\t},\n\texport: {\n\t\tpageBg: \"#f8f8f8\",\n\t\tcardBg: \"#ffffff\",\n\t\tinfoBg: \"#fffae6\",\n\t},\n};\n\n// ---------------------------------------------------------------------------\n// Export\n// ---------------------------------------------------------------------------\n\nexport const builtinThemes: Record<string, ThemeJson> = { dark, light };\n"]}
|
package/pkg/package.json
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
DEFAULT_MAX_BYTES,
|
|
14
14
|
DEFAULT_MAX_LINES,
|
|
15
15
|
} from "@gsd/pi-coding-agent";
|
|
16
|
+
import { Text } from "@gsd/pi-tui";
|
|
16
17
|
import { Type } from "@sinclair/typebox";
|
|
17
18
|
import { spawn, spawnSync } from "node:child_process";
|
|
18
19
|
import { createWriteStream } from "node:fs";
|
|
@@ -81,6 +82,18 @@ export function createAsyncBashTool(
|
|
|
81
82
|
"Check /jobs to see all running and recent background jobs.",
|
|
82
83
|
],
|
|
83
84
|
parameters: schema,
|
|
85
|
+
renderCall(args, theme, options) {
|
|
86
|
+
const cmd = args.command ?? "";
|
|
87
|
+
const display = cmd.length > 80 ? cmd.slice(0, 77) + "..." : cmd;
|
|
88
|
+
const indicator = options?.statusIndicator ? `${options.statusIndicator} ` : "";
|
|
89
|
+
let text = indicator + theme.fg("toolTitle", theme.bold("async_bash "));
|
|
90
|
+
text += theme.fg("bashMode", "$ ");
|
|
91
|
+
text += theme.fg("accent", display || theme.fg("muted", "..."));
|
|
92
|
+
if (args.label) text += theme.fg("muted", ` (${args.label})`);
|
|
93
|
+
if (args.timeout) text += theme.fg("dim", ` timeout:${args.timeout}s`);
|
|
94
|
+
return new Text(text, 0, 0);
|
|
95
|
+
},
|
|
96
|
+
|
|
84
97
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
85
98
|
const manager = getManager();
|
|
86
99
|
const cwd = getCwd();
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ToolDefinition } from "@gsd/pi-coding-agent";
|
|
9
|
+
import { Text } from "@gsd/pi-tui";
|
|
9
10
|
import { Type } from "@sinclair/typebox";
|
|
10
11
|
import type { AsyncJobManager, Job } from "./job-manager.js";
|
|
11
12
|
|
|
@@ -33,6 +34,18 @@ export function createAwaitTool(getManager: () => AsyncJobManager): ToolDefiniti
|
|
|
33
34
|
description:
|
|
34
35
|
"Wait for background jobs to complete. Provide specific job IDs or omit to wait for the next job that finishes. Returns results of completed jobs.",
|
|
35
36
|
parameters: schema,
|
|
37
|
+
renderCall(args, theme, options) {
|
|
38
|
+
const indicator = options?.statusIndicator ? `${options.statusIndicator} ` : "";
|
|
39
|
+
let text = indicator + theme.fg("toolTitle", theme.bold("await_job"));
|
|
40
|
+
if (args.jobs && args.jobs.length > 0) {
|
|
41
|
+
text += " " + theme.fg("accent", args.jobs.join(", "));
|
|
42
|
+
} else {
|
|
43
|
+
text += theme.fg("muted", " (any)");
|
|
44
|
+
}
|
|
45
|
+
if (args.timeout) text += theme.fg("dim", ` timeout:${args.timeout}s`);
|
|
46
|
+
return new Text(text, 0, 0);
|
|
47
|
+
},
|
|
48
|
+
|
|
36
49
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
37
50
|
const manager = getManager();
|
|
38
51
|
const { jobs: jobIds, timeout } = params;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { ToolDefinition } from "@gsd/pi-coding-agent";
|
|
6
|
+
import { Text } from "@gsd/pi-tui";
|
|
6
7
|
import { Type } from "@sinclair/typebox";
|
|
7
8
|
import type { AsyncJobManager } from "./job-manager.js";
|
|
8
9
|
|
|
@@ -16,6 +17,13 @@ export function createCancelJobTool(getManager: () => AsyncJobManager): ToolDefi
|
|
|
16
17
|
label: "Cancel Background Job",
|
|
17
18
|
description: "Cancel a running background job by its ID.",
|
|
18
19
|
parameters: schema,
|
|
20
|
+
renderCall(args, theme, options) {
|
|
21
|
+
const indicator = options?.statusIndicator ? `${options.statusIndicator} ` : "";
|
|
22
|
+
let text = indicator + theme.fg("toolTitle", theme.bold("cancel_job "));
|
|
23
|
+
text += theme.fg("accent", args.job_id);
|
|
24
|
+
return new Text(text, 0, 0);
|
|
25
|
+
},
|
|
26
|
+
|
|
19
27
|
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
20
28
|
const manager = getManager();
|
|
21
29
|
const result = manager.cancel(params.job_id);
|
|
@@ -17,6 +17,8 @@ import type { ExtensionAPI, ExtensionUIContext } from "@gsd/pi-coding-agent";
|
|
|
17
17
|
import { getAgentDir } from "@gsd/pi-coding-agent";
|
|
18
18
|
|
|
19
19
|
const STATUS_KEY = "cache-timer";
|
|
20
|
+
const IS_MEMORY_MAINTENANCE_WORKER = process.env.LSD_MEMORY_EXTRACT === "1" || process.env.LSD_MEMORY_DREAM === "1";
|
|
21
|
+
const IS_CACHE_TIMER_FORCED_OFF = process.env.LSD_DISABLE_CACHE_TIMER === "1" || process.env.GSD_DISABLE_CACHE_TIMER === "1";
|
|
20
22
|
|
|
21
23
|
// ANSI color codes for timer display
|
|
22
24
|
const ANSI_RESET = "\x1b[0m";
|
|
@@ -24,112 +26,116 @@ const ANSI_YELLOW = "\x1b[33m";
|
|
|
24
26
|
const ANSI_RED = "\x1b[31m";
|
|
25
27
|
|
|
26
28
|
function getSettingsPath(): string {
|
|
27
|
-
|
|
29
|
+
return join(getAgentDir(), "settings.json");
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
function readEnabled(): boolean {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
try {
|
|
34
|
+
const path = getSettingsPath();
|
|
35
|
+
if (!existsSync(path)) return true;
|
|
36
|
+
const settings = JSON.parse(readFileSync(path, "utf-8"));
|
|
37
|
+
// SettingsManager stores `cacheTimer` as a top-level boolean (default true)
|
|
38
|
+
return settings?.cacheTimer !== false;
|
|
39
|
+
} catch {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
function writeEnabled(enabled: boolean): void {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
const path = getSettingsPath();
|
|
46
|
+
let settings: Record<string, unknown> = {};
|
|
47
|
+
try {
|
|
48
|
+
if (existsSync(path)) {
|
|
49
|
+
settings = JSON.parse(readFileSync(path, "utf-8"));
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
// ignore parse errors, start fresh
|
|
53
|
+
}
|
|
54
|
+
settings.cacheTimer = enabled;
|
|
55
|
+
writeFileSync(path, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
function formatElapsed(ms: number): string {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
59
|
+
const totalSeconds = Math.floor(ms / 1000);
|
|
60
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
61
|
+
const seconds = totalSeconds % 60;
|
|
62
|
+
const time = `${minutes}:${seconds.toString().padStart(2, "0")}`;
|
|
63
|
+
|
|
64
|
+
if (ms >= 10 * 60 * 1000) {
|
|
65
|
+
// 10+ minutes: red
|
|
66
|
+
return `${ANSI_RED}⏱ ${time}${ANSI_RESET}`;
|
|
67
|
+
} else if (ms >= 5 * 60 * 1000) {
|
|
68
|
+
// 5–10 minutes: yellow
|
|
69
|
+
return `${ANSI_YELLOW}⏱ ${time}${ANSI_RESET}`;
|
|
70
|
+
}
|
|
71
|
+
// Under 5 minutes: plain (inherits footer dim styling)
|
|
72
|
+
return `⏱ ${time}`;
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
export default function cacheTimerExtension(pi: ExtensionAPI) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
76
|
+
if (IS_MEMORY_MAINTENANCE_WORKER || IS_CACHE_TIMER_FORCED_OFF) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let timer: ReturnType<typeof setInterval> | null = null;
|
|
81
|
+
let startTime: number | null = null;
|
|
82
|
+
let enabled = readEnabled();
|
|
83
|
+
|
|
84
|
+
// We capture the ui reference on first use — it stays valid for the session lifetime
|
|
85
|
+
let ui: ExtensionUIContext | null = null;
|
|
86
|
+
|
|
87
|
+
function startTimer(uiCtx: ExtensionUIContext): void {
|
|
88
|
+
stopTimer();
|
|
89
|
+
if (!enabled) return;
|
|
90
|
+
ui = uiCtx;
|
|
91
|
+
startTime = Date.now();
|
|
92
|
+
uiCtx.setStatus(STATUS_KEY, formatElapsed(0));
|
|
93
|
+
timer = setInterval(() => {
|
|
94
|
+
if (startTime !== null && ui !== null) {
|
|
95
|
+
ui.setStatus(STATUS_KEY, formatElapsed(Date.now() - startTime));
|
|
96
|
+
}
|
|
97
|
+
}, 1000);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function stopTimer(): void {
|
|
101
|
+
if (timer !== null) {
|
|
102
|
+
clearInterval(timer);
|
|
103
|
+
timer = null;
|
|
104
|
+
}
|
|
105
|
+
startTime = null;
|
|
106
|
+
if (ui !== null) {
|
|
107
|
+
ui.setStatus(STATUS_KEY, undefined);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// When the agent finishes a response, start counting up
|
|
112
|
+
pi.on("agent_end", async (_event, ctx) => {
|
|
113
|
+
startTimer(ctx.ui);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// When the user submits a new request, clear the timer
|
|
117
|
+
pi.on("agent_start", async (_event, ctx) => {
|
|
118
|
+
ui = ctx.ui;
|
|
119
|
+
stopTimer();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Clean up on session shutdown
|
|
123
|
+
pi.on("session_shutdown", () => {
|
|
124
|
+
stopTimer();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// /cache-timer — toggle on/off
|
|
128
|
+
pi.registerCommand("cache-timer", {
|
|
129
|
+
description: "Toggle the cache elapsed-time timer in the footer",
|
|
130
|
+
async handler(_args, ctx) {
|
|
131
|
+
enabled = !enabled;
|
|
132
|
+
writeEnabled(enabled);
|
|
133
|
+
if (enabled) {
|
|
134
|
+
ctx.ui.notify("Cache timer enabled", "info");
|
|
135
|
+
} else {
|
|
136
|
+
stopTimer();
|
|
137
|
+
ctx.ui.notify("Cache timer disabled", "info");
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
});
|
|
135
141
|
}
|