@duckmind/dm-darwin-x64 0.35.4 → 0.35.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dm +0 -0
- package/extensions/.dm-extensions.json +1 -27
- package/package.json +1 -1
- package/extensions/dm-alps/LICENSE +0 -21
- package/extensions/dm-alps/README.md +0 -22
- package/extensions/dm-alps/index.ts +0 -172
- package/extensions/dm-alps/package.json +0 -49
- package/extensions/dm-alps/src/commands.ts +0 -208
- package/extensions/dm-alps/src/features/animations/debug.ts +0 -160
- package/extensions/dm-alps/src/features/animations/index.ts +0 -33
- package/extensions/dm-alps/src/features/animations/patch.ts +0 -112
- package/extensions/dm-alps/src/features/animations/preview.ts +0 -117
- package/extensions/dm-alps/src/features/animations/registry.ts +0 -593
- package/extensions/dm-alps/src/features/animations/runtime.ts +0 -574
- package/extensions/dm-alps/src/features/animations/settings.ts +0 -69
- package/extensions/dm-alps/src/features/bottom-input/cluster.ts +0 -2
- package/extensions/dm-alps/src/features/bottom-input/compositor.ts +0 -2
- package/extensions/dm-alps/src/features/bottom-input/editor.ts +0 -148
- package/extensions/dm-alps/src/features/bottom-input/frame.ts +0 -224
- package/extensions/dm-alps/src/features/bottom-input/icons.ts +0 -36
- package/extensions/dm-alps/src/features/bottom-input/index.ts +0 -8
- package/extensions/dm-alps/src/features/bottom-input/runtime.ts +0 -1197
- package/extensions/dm-alps/src/features/bottom-input/shortcuts.ts +0 -286
- package/extensions/dm-alps/src/features/bottom-input/status.ts +0 -663
- package/extensions/dm-alps/src/features/bottom-status/index.ts +0 -2
- package/extensions/dm-alps/src/features/chrome-frame/chrome.ts +0 -222
- package/extensions/dm-alps/src/features/chrome-frame/debug.ts +0 -212
- package/extensions/dm-alps/src/features/chrome-frame/image.ts +0 -11
- package/extensions/dm-alps/src/features/chrome-frame/index.ts +0 -4
- package/extensions/dm-alps/src/features/chrome-frame/osc.ts +0 -111
- package/extensions/dm-alps/src/features/chrome-frame/patch.ts +0 -769
- package/extensions/dm-alps/src/features/chrome-frame/preview.ts +0 -67
- package/extensions/dm-alps/src/features/chrome-frame/styles.ts +0 -105
- package/extensions/dm-alps/src/features/fixed-bottom-editor/cluster.ts +0 -161
- package/extensions/dm-alps/src/features/fixed-bottom-editor/compositor.ts +0 -1149
- package/extensions/dm-alps/src/features/fixed-bottom-editor/index.ts +0 -3
- package/extensions/dm-alps/src/features/fixed-bottom-editor/runtime.ts +0 -3
- package/extensions/dm-alps/src/settings-store.ts +0 -194
- package/extensions/dm-alps/src/settings-ui.ts +0 -653
- package/extensions/dm-alps/src/settings.ts +0 -102
- package/extensions/dm-alps/src/terminal-sanitizer.ts +0 -91
- package/extensions/dm-alps/themes/LICENSE.synthwave-84 +0 -21
- package/extensions/dm-alps/themes/alps.json +0 -93
|
@@ -1,574 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import type { Component } from "@mariozechner/pi-tui";
|
|
3
|
-
import { type AnimationsSettings, cloneDefaultAnimationsSettings, normalizeAnimationsSettings } from "./settings.ts";
|
|
4
|
-
import { pickRandomAnimation, renderAnimationFrame, resolveAnimationWidth, type AnimationPhase } from "./registry.ts";
|
|
5
|
-
import { isAnimationDebugEnabled, summarizeWorkingLineWidths, writeAnimationDebugLog, type AnimationDebugEvent } from "./debug.ts";
|
|
6
|
-
|
|
7
|
-
const WORKING_WIDGET_KEY = "dm-alps-animations";
|
|
8
|
-
export const THINKING_DONE_LABEL = "Thinking complete";
|
|
9
|
-
|
|
10
|
-
export type AnimationRuntimeState = {
|
|
11
|
-
settings: AnimationsSettings;
|
|
12
|
-
frame: number;
|
|
13
|
-
timer: ReturnType<typeof setInterval> | undefined;
|
|
14
|
-
currentUiCtx: any;
|
|
15
|
-
currentEventCtx: any;
|
|
16
|
-
currentCtx: any;
|
|
17
|
-
activeComponents: Set<AnimatedThinkingComponent>;
|
|
18
|
-
randomWorking: string | undefined;
|
|
19
|
-
randomThinking: string | undefined;
|
|
20
|
-
randomTool: string | undefined;
|
|
21
|
-
previousRandomWorking: string | undefined;
|
|
22
|
-
previousRandomThinking: string | undefined;
|
|
23
|
-
previousRandomTool: string | undefined;
|
|
24
|
-
animating: boolean;
|
|
25
|
-
thinkingActive: boolean;
|
|
26
|
-
toolCallIds: Set<string>;
|
|
27
|
-
agentGeneration: number;
|
|
28
|
-
closedAgentGeneration: number;
|
|
29
|
-
toolOwners: Map<string, number>;
|
|
30
|
-
ignoredAgentContexts: WeakSet<object>;
|
|
31
|
-
hiddenLabelApplied: boolean;
|
|
32
|
-
workingMessageApplied: boolean;
|
|
33
|
-
workingWidgetApplied: boolean;
|
|
34
|
-
workingIndicatorHidden: boolean;
|
|
35
|
-
lastWorkingMessage: string | undefined;
|
|
36
|
-
lastWorkingLines: number;
|
|
37
|
-
lastWorkingLineWidths: number[];
|
|
38
|
-
currentAssistantMessage: any;
|
|
39
|
-
freezeGeneration: number;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const ANIMATIONS_STATE_KEY = Symbol.for("alps.dm.animations.runtime.v1");
|
|
43
|
-
|
|
44
|
-
export class AnimatedThinkingComponent implements Component {
|
|
45
|
-
private readonly state: AnimationRuntimeState;
|
|
46
|
-
private readonly animationName: string | undefined;
|
|
47
|
-
private readonly completionLabel: string | undefined;
|
|
48
|
-
private frozen = false;
|
|
49
|
-
|
|
50
|
-
constructor(state = getAnimationsRuntimeState(), animationName?: string, frozen = false, completionLabel?: string) {
|
|
51
|
-
this.state = state;
|
|
52
|
-
this.animationName = animationName;
|
|
53
|
-
this.completionLabel = completionLabel;
|
|
54
|
-
this.frozen = frozen;
|
|
55
|
-
if (!this.frozen) {
|
|
56
|
-
this.state.activeComponents.add(this);
|
|
57
|
-
if (shouldRunTimer(this.state)) startTimer(this.state);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
dispose(): void {
|
|
62
|
-
this.state.activeComponents.delete(this);
|
|
63
|
-
if (!shouldRunTimer(this.state)) stopTimer(this.state);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
freeze(): void {
|
|
67
|
-
if (this.frozen) return;
|
|
68
|
-
this.frozen = true;
|
|
69
|
-
this.state.activeComponents.delete(this);
|
|
70
|
-
if (!shouldRunTimer(this.state)) stopTimer(this.state);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
render(width: number): string[] {
|
|
74
|
-
if (!this.state.settings.enabled) return [" Thinking... "];
|
|
75
|
-
if (this.frozen) return [` ${this.completionLabel ?? renderThinkingCompleteLabel()} `];
|
|
76
|
-
const terminalWidth = Math.max(1, Math.floor(width));
|
|
77
|
-
const animationWidth = Math.min(resolveAnimationWidth(this.state.settings.width, terminalWidth), Math.max(1, terminalWidth - 2));
|
|
78
|
-
const name = this.animationName ?? resolveAnimationNameForPhase(this.state, "thinking");
|
|
79
|
-
return renderAnimationFrame(name, this.state.frame, animationWidth, "thinking").map((line) => ` ${line} `);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
invalidate(): void {}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function getAnimationsRuntimeState(): AnimationRuntimeState {
|
|
86
|
-
const existing = (globalThis as any)[ANIMATIONS_STATE_KEY] as Partial<AnimationRuntimeState> | undefined;
|
|
87
|
-
if (existing) return migrateAnimationsRuntimeState(existing);
|
|
88
|
-
const state = createDefaultAnimationsRuntimeState();
|
|
89
|
-
(globalThis as any)[ANIMATIONS_STATE_KEY] = state;
|
|
90
|
-
return state;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function createDefaultAnimationsRuntimeState(): AnimationRuntimeState {
|
|
94
|
-
return {
|
|
95
|
-
settings: cloneDefaultAnimationsSettings(),
|
|
96
|
-
frame: 0,
|
|
97
|
-
timer: undefined,
|
|
98
|
-
currentUiCtx: undefined,
|
|
99
|
-
currentEventCtx: undefined,
|
|
100
|
-
currentCtx: undefined,
|
|
101
|
-
activeComponents: new Set(),
|
|
102
|
-
randomWorking: undefined,
|
|
103
|
-
randomThinking: undefined,
|
|
104
|
-
randomTool: undefined,
|
|
105
|
-
previousRandomWorking: undefined,
|
|
106
|
-
previousRandomThinking: undefined,
|
|
107
|
-
previousRandomTool: undefined,
|
|
108
|
-
animating: false,
|
|
109
|
-
thinkingActive: false,
|
|
110
|
-
toolCallIds: new Set(),
|
|
111
|
-
agentGeneration: 0,
|
|
112
|
-
closedAgentGeneration: 0,
|
|
113
|
-
toolOwners: new Map(),
|
|
114
|
-
ignoredAgentContexts: new WeakSet(),
|
|
115
|
-
hiddenLabelApplied: false,
|
|
116
|
-
workingMessageApplied: false,
|
|
117
|
-
workingWidgetApplied: false,
|
|
118
|
-
workingIndicatorHidden: false,
|
|
119
|
-
lastWorkingMessage: undefined,
|
|
120
|
-
lastWorkingLines: 0,
|
|
121
|
-
lastWorkingLineWidths: [],
|
|
122
|
-
currentAssistantMessage: undefined,
|
|
123
|
-
freezeGeneration: 0,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function migrateAnimationsRuntimeState(existing: Partial<AnimationRuntimeState>): AnimationRuntimeState {
|
|
128
|
-
existing.settings = normalizeAnimationsSettings(existing.settings ?? cloneDefaultAnimationsSettings());
|
|
129
|
-
if (typeof existing.frame !== "number") existing.frame = 0;
|
|
130
|
-
if (!(existing.activeComponents instanceof Set)) existing.activeComponents = new Set();
|
|
131
|
-
if (!('currentUiCtx' in existing)) existing.currentUiCtx = canWriteWorkingAnimation(existing.currentCtx) ? existing.currentCtx : undefined;
|
|
132
|
-
if (!('currentEventCtx' in existing)) existing.currentEventCtx = undefined;
|
|
133
|
-
if (!(existing.toolCallIds instanceof Set)) existing.toolCallIds = new Set();
|
|
134
|
-
if (typeof existing.agentGeneration !== "number") existing.agentGeneration = 0;
|
|
135
|
-
if (typeof existing.closedAgentGeneration !== "number") existing.closedAgentGeneration = 0;
|
|
136
|
-
if (!(existing.toolOwners instanceof Map)) existing.toolOwners = new Map();
|
|
137
|
-
if (!(existing.ignoredAgentContexts instanceof WeakSet)) existing.ignoredAgentContexts = new WeakSet();
|
|
138
|
-
if (typeof existing.animating !== "boolean") existing.animating = false;
|
|
139
|
-
if (typeof existing.thinkingActive !== "boolean") existing.thinkingActive = false;
|
|
140
|
-
if (typeof existing.previousRandomWorking !== "string") existing.previousRandomWorking = undefined;
|
|
141
|
-
if (typeof existing.previousRandomThinking !== "string") existing.previousRandomThinking = undefined;
|
|
142
|
-
if (typeof existing.previousRandomTool !== "string") existing.previousRandomTool = undefined;
|
|
143
|
-
if (typeof existing.hiddenLabelApplied !== "boolean") existing.hiddenLabelApplied = false;
|
|
144
|
-
if (typeof existing.workingMessageApplied !== "boolean") existing.workingMessageApplied = false;
|
|
145
|
-
if (typeof existing.workingWidgetApplied !== "boolean") existing.workingWidgetApplied = false;
|
|
146
|
-
if (typeof existing.workingIndicatorHidden !== "boolean") existing.workingIndicatorHidden = false;
|
|
147
|
-
if (typeof existing.lastWorkingMessage !== "string") existing.lastWorkingMessage = undefined;
|
|
148
|
-
if (typeof existing.lastWorkingLines !== "number") existing.lastWorkingLines = 0;
|
|
149
|
-
if (!Array.isArray(existing.lastWorkingLineWidths)) existing.lastWorkingLineWidths = [];
|
|
150
|
-
if (!("currentAssistantMessage" in existing)) existing.currentAssistantMessage = undefined;
|
|
151
|
-
if (typeof existing.freezeGeneration !== "number") existing.freezeGeneration = 0;
|
|
152
|
-
return existing as AnimationRuntimeState;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function configureAnimationsRuntime(settings: AnimationsSettings): void {
|
|
156
|
-
const state = getAnimationsRuntimeState();
|
|
157
|
-
writeAnimationDebugLog({ event: "configure", state });
|
|
158
|
-
const previousFps = state.settings.fps;
|
|
159
|
-
const previousRandomMode = state.settings.randomMode;
|
|
160
|
-
state.settings = normalizeAnimationsSettings(settings);
|
|
161
|
-
if (previousRandomMode !== state.settings.randomMode) resetRandomAnimations(state);
|
|
162
|
-
if (!state.settings.enabled) {
|
|
163
|
-
stopTimer(state);
|
|
164
|
-
resetRandomAnimations(state);
|
|
165
|
-
clearWorkingAnimation(state);
|
|
166
|
-
resetHiddenThinkingLabel(state);
|
|
167
|
-
requestAnimationsRender(state);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (shouldRunTimer(state) && (!state.timer || previousFps !== state.settings.fps)) startTimer(state);
|
|
171
|
-
requestAnimationsRender(state);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export function bindAnimationsRuntimeSession(ctx: any): void {
|
|
175
|
-
const state = getAnimationsRuntimeState();
|
|
176
|
-
state.currentEventCtx = ctx;
|
|
177
|
-
if (canWriteWorkingAnimation(ctx)) {
|
|
178
|
-
state.currentUiCtx = ctx;
|
|
179
|
-
state.currentCtx = ctx;
|
|
180
|
-
writeAnimationDebugLog({ event: "bind_session", state, ctx });
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
writeAnimationDebugLog({ event: "bind_session", state, ctx, note: "ignored_no_ui_target" });
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export function handleAnimationsAgentStart(event?: any, ctx?: any): void {
|
|
187
|
-
const state = getAnimationsRuntimeState();
|
|
188
|
-
if (isStaleEventCtx(ctx)) {
|
|
189
|
-
writeAnimationDebugLog({ event: "agent_start", state, ctx, payload: event, note: "ignored_stale_ctx" });
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (isNestedAgentStart(state, ctx)) {
|
|
193
|
-
rememberIgnoredAgentContext(state, ctx);
|
|
194
|
-
writeAnimationDebugLog({ event: "agent_start", state, ctx, payload: event, note: "ignored_nested_agent" });
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
|
-
bindEventCtx(state, ctx);
|
|
198
|
-
resumeAnimationsRuntime();
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export function handleAnimationsAgentEnd(event?: any, ctx?: any): void {
|
|
202
|
-
const state = getAnimationsRuntimeState();
|
|
203
|
-
if (isIgnoredAgentContext(state, ctx) || isNestedNonWritableEvent(state, ctx)) {
|
|
204
|
-
rememberIgnoredAgentContext(state, ctx);
|
|
205
|
-
writeAnimationDebugLog({ event: "agent_end", state, ctx, payload: event, note: "ignored_nested_agent" });
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
if (isStaleEventCtx(ctx)) {
|
|
209
|
-
writeAnimationDebugLog({ event: "agent_end", state, ctx, payload: event, note: hasActiveAnimationState(state) ? "stale_ctx_cleanup_current" : "stale_ctx_no_active_runtime" });
|
|
210
|
-
if (hasActiveAnimationState(state)) pauseAnimationsRuntime();
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
bindEventCtx(state, ctx);
|
|
214
|
-
pauseAnimationsRuntime();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
export function recordAnimationsLifecycleEvent(event: AnimationDebugEvent, ctx?: any, payload?: any): void {
|
|
218
|
-
writeAnimationDebugLog({ event, state: getAnimationsRuntimeState(), ctx, payload });
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export function resumeAnimationsRuntime(): void {
|
|
222
|
-
const state = getAnimationsRuntimeState();
|
|
223
|
-
writeAnimationDebugLog({ event: "resume", state });
|
|
224
|
-
state.animating = true;
|
|
225
|
-
state.thinkingActive = false;
|
|
226
|
-
state.agentGeneration += 1;
|
|
227
|
-
state.toolCallIds.clear();
|
|
228
|
-
state.toolOwners.clear();
|
|
229
|
-
state.currentAssistantMessage = undefined;
|
|
230
|
-
state.frame = 0;
|
|
231
|
-
state.freezeGeneration += 1;
|
|
232
|
-
state.workingWidgetApplied = true;
|
|
233
|
-
resetRandomAnimations(state);
|
|
234
|
-
if (state.settings.enabled) startTimer(state);
|
|
235
|
-
requestAnimationsRender(state);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export function pauseAnimationsRuntime(): void {
|
|
239
|
-
const state = getAnimationsRuntimeState();
|
|
240
|
-
writeAnimationDebugLog({ event: "pause", state });
|
|
241
|
-
state.animating = false;
|
|
242
|
-
state.thinkingActive = false;
|
|
243
|
-
state.closedAgentGeneration = state.agentGeneration;
|
|
244
|
-
state.toolCallIds.clear();
|
|
245
|
-
state.toolOwners.clear();
|
|
246
|
-
state.currentAssistantMessage = undefined;
|
|
247
|
-
freezeAnimatedThinkingComponentsSoon(state);
|
|
248
|
-
stopTimer(state);
|
|
249
|
-
clearWorkingAnimation(state);
|
|
250
|
-
resetHiddenThinkingLabel(state);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export function handleAnimationsMessageUpdate(event: any, ctx?: any): void {
|
|
254
|
-
const state = getAnimationsRuntimeState();
|
|
255
|
-
if (shouldIgnoreScopedEvent(state, ctx)) {
|
|
256
|
-
writeAnimationDebugLog({ event: "message_update", state, ctx, payload: event, note: "ignored_scoped_event" });
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
bindEventCtx(state, ctx);
|
|
260
|
-
if (event?.message) state.currentAssistantMessage = event.message;
|
|
261
|
-
const type = event?.assistantMessageEvent?.type;
|
|
262
|
-
if (type === "thinking_start" || type === "thinking_delta") {
|
|
263
|
-
state.thinkingActive = true;
|
|
264
|
-
} else if (type === "thinking_end" || type === "text_delta") {
|
|
265
|
-
state.thinkingActive = false;
|
|
266
|
-
freezeAnimatedThinkingComponentsSoon(state);
|
|
267
|
-
}
|
|
268
|
-
if (shouldRunTimer(state) && !state.timer) startTimer(state);
|
|
269
|
-
requestAnimationsRender(state);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export function handleAnimationsMessageEnd(ctx?: any): void {
|
|
273
|
-
const state = getAnimationsRuntimeState();
|
|
274
|
-
if (shouldIgnoreScopedEvent(state, ctx)) {
|
|
275
|
-
writeAnimationDebugLog({ event: "message_end", state, ctx, note: "ignored_scoped_event" });
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
bindEventCtx(state, ctx);
|
|
279
|
-
state.thinkingActive = false;
|
|
280
|
-
state.currentAssistantMessage = undefined;
|
|
281
|
-
freezeAnimatedThinkingComponentsSoon(state);
|
|
282
|
-
requestAnimationsRender(state);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
export function handleAnimationsToolExecutionStart(event: any, ctx?: any): void {
|
|
286
|
-
const state = getAnimationsRuntimeState();
|
|
287
|
-
if (shouldIgnoreScopedEvent(state, ctx)) {
|
|
288
|
-
writeAnimationDebugLog({ event: "tool_execution_start", state, ctx, payload: event, note: "ignored_scoped_event" });
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
bindEventCtx(state, ctx);
|
|
292
|
-
const id = readToolCallId(event);
|
|
293
|
-
state.toolCallIds.add(id);
|
|
294
|
-
state.toolOwners.set(id, state.agentGeneration);
|
|
295
|
-
requestAnimationsRender(state);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
export function handleAnimationsToolExecutionEnd(event: any, ctx?: any): void {
|
|
299
|
-
const state = getAnimationsRuntimeState();
|
|
300
|
-
const stale = isStaleEventCtx(ctx) || isIgnoredAgentContext(state, ctx) || isNestedNoUiEvent(state, ctx);
|
|
301
|
-
const generation = state.agentGeneration;
|
|
302
|
-
if (event?.toolCallId === undefined) {
|
|
303
|
-
if (!stale) clearToolsForGeneration(state, generation);
|
|
304
|
-
writeAnimationDebugLog({ event: "tool_execution_end", state, ctx, payload: event, note: stale ? "ignored_stale_unknown_tool" : "cleared_current_generation_tools" });
|
|
305
|
-
if (!stale && state.animating) requestAnimationsRender(state);
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
const id = readToolCallId(event);
|
|
309
|
-
const owner = state.toolOwners.get(id);
|
|
310
|
-
if (owner !== undefined && !isIgnoredAgentContext(state, ctx) && !isNestedNoUiEvent(state, ctx)) {
|
|
311
|
-
state.toolOwners.delete(id);
|
|
312
|
-
state.toolCallIds.delete(id);
|
|
313
|
-
} else if (!stale) {
|
|
314
|
-
state.toolCallIds.delete(id);
|
|
315
|
-
}
|
|
316
|
-
writeAnimationDebugLog({ event: "tool_execution_end", state, ctx, payload: event, note: stale ? "bookkeeping_only" : undefined });
|
|
317
|
-
if (!stale && state.animating && (owner === undefined || owner === generation)) requestAnimationsRender(state);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
export function disposeAnimationsRuntime(): void {
|
|
321
|
-
const state = getAnimationsRuntimeState();
|
|
322
|
-
pauseAnimationsRuntime();
|
|
323
|
-
for (const component of state.activeComponents) component.dispose();
|
|
324
|
-
state.activeComponents.clear();
|
|
325
|
-
state.currentUiCtx = undefined;
|
|
326
|
-
state.currentEventCtx = undefined;
|
|
327
|
-
state.currentCtx = undefined;
|
|
328
|
-
resetRandomAnimations(state);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
function startTimer(state: AnimationRuntimeState): void {
|
|
332
|
-
stopTimer(state);
|
|
333
|
-
const fps = Math.max(1, state.settings.fps);
|
|
334
|
-
state.timer = setInterval(() => {
|
|
335
|
-
state.frame += 1;
|
|
336
|
-
writeAnimationDebugLog({ event: "timer_tick", state });
|
|
337
|
-
requestAnimationsRender(state);
|
|
338
|
-
}, Math.max(16, Math.round(1000 / fps)));
|
|
339
|
-
state.timer.unref?.();
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function stopTimer(state: AnimationRuntimeState): void {
|
|
343
|
-
if (!state.timer) return;
|
|
344
|
-
clearInterval(state.timer);
|
|
345
|
-
state.timer = undefined;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
function requestAnimationsRender(state: AnimationRuntimeState): void {
|
|
349
|
-
try {
|
|
350
|
-
for (const component of state.activeComponents) component.invalidate();
|
|
351
|
-
const ui = getCurrentUi(state);
|
|
352
|
-
renderWorkingAnimationFrame(state, ui);
|
|
353
|
-
if (typeof ui?.requestRender === "function") {
|
|
354
|
-
ui.requestRender();
|
|
355
|
-
}
|
|
356
|
-
} catch (error) {
|
|
357
|
-
writeAnimationDebugLog({ event: "render_fail", state, error });
|
|
358
|
-
if (!isStaleCtxError(error)) console.debug?.("[dm-alps] Animations render request failed:", error);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
function renderWorkingAnimationFrame(state: AnimationRuntimeState, ui: any): boolean {
|
|
363
|
-
if (!state.settings.enabled || !state.animating) return false;
|
|
364
|
-
if (typeof ui?.setWorkingMessage !== "function") {
|
|
365
|
-
writeAnimationDebugLog({ event: "working_render_skipped", state, note: "no_ui_target" });
|
|
366
|
-
return false;
|
|
367
|
-
}
|
|
368
|
-
const phase = resolveCurrentPhase(state);
|
|
369
|
-
const width = resolveAnimationWidth(state.settings.width, process.stdout.columns || 80);
|
|
370
|
-
const lines = renderAnimationFrame(resolveAnimationNameForPhase(state, phase), state.frame, width, phase);
|
|
371
|
-
if (isAnimationDebugEnabled()) state.lastWorkingLineWidths = summarizeWorkingLineWidths(lines);
|
|
372
|
-
restoreWorkingIndicator(state, ui);
|
|
373
|
-
const message = stableWorkingMessageForPhase(phase);
|
|
374
|
-
if (state.lastWorkingMessage !== message) {
|
|
375
|
-
ui.setWorkingMessage(message);
|
|
376
|
-
state.lastWorkingMessage = message;
|
|
377
|
-
}
|
|
378
|
-
state.workingMessageApplied = true;
|
|
379
|
-
writeAnimationDebugLog({ event: "working_render", state });
|
|
380
|
-
if (state.workingWidgetApplied && typeof ui?.setWidget === "function") {
|
|
381
|
-
ui.setWidget(WORKING_WIDGET_KEY, undefined);
|
|
382
|
-
state.workingWidgetApplied = false;
|
|
383
|
-
}
|
|
384
|
-
state.lastWorkingLines = lines.length;
|
|
385
|
-
return true;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
function syncWorkingIndicatorForLines(state: AnimationRuntimeState, ui: any, lineCount: number): void {
|
|
389
|
-
if (lineCount > 1) {
|
|
390
|
-
hideWorkingIndicator(state, ui);
|
|
391
|
-
return;
|
|
392
|
-
}
|
|
393
|
-
restoreWorkingIndicator(state, ui);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
function hideWorkingIndicator(state: AnimationRuntimeState, ui: any): void {
|
|
397
|
-
if (state.workingIndicatorHidden || typeof ui?.setWorkingIndicator !== "function") return;
|
|
398
|
-
try {
|
|
399
|
-
ui.setWorkingIndicator({ frames: [] });
|
|
400
|
-
state.workingIndicatorHidden = true;
|
|
401
|
-
} catch (error) {
|
|
402
|
-
if (!isStaleCtxError(error)) console.debug?.("[dm-alps] Animations working indicator hide failed:", error);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
function restoreWorkingIndicator(state: AnimationRuntimeState, ui: any): void {
|
|
407
|
-
if (!state.workingIndicatorHidden || typeof ui?.setWorkingIndicator !== "function") return;
|
|
408
|
-
try {
|
|
409
|
-
ui.setWorkingIndicator(undefined);
|
|
410
|
-
state.workingIndicatorHidden = false;
|
|
411
|
-
} catch (error) {
|
|
412
|
-
if (!isStaleCtxError(error)) console.debug?.("[dm-alps] Animations working indicator restore failed:", error);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
function clearWorkingAnimation(state: AnimationRuntimeState): void {
|
|
417
|
-
const shouldClearMessage = state.workingMessageApplied;
|
|
418
|
-
const shouldClearWidget = state.workingWidgetApplied;
|
|
419
|
-
const shouldRestoreIndicator = state.workingIndicatorHidden;
|
|
420
|
-
state.workingMessageApplied = false;
|
|
421
|
-
state.workingWidgetApplied = false;
|
|
422
|
-
state.workingIndicatorHidden = false;
|
|
423
|
-
state.lastWorkingMessage = undefined;
|
|
424
|
-
state.lastWorkingLines = 0;
|
|
425
|
-
state.lastWorkingLineWidths = [];
|
|
426
|
-
if (!shouldClearMessage && !shouldClearWidget && !shouldRestoreIndicator) return;
|
|
427
|
-
try {
|
|
428
|
-
const ui = getCurrentUi(state);
|
|
429
|
-
if (shouldClearWidget && typeof ui?.setWidget === "function") ui.setWidget(WORKING_WIDGET_KEY, undefined);
|
|
430
|
-
if (shouldClearMessage && typeof ui?.setWorkingMessage === "function") ui.setWorkingMessage(undefined);
|
|
431
|
-
if (shouldRestoreIndicator && typeof ui?.setWorkingIndicator === "function") ui.setWorkingIndicator(undefined);
|
|
432
|
-
} catch (error) {
|
|
433
|
-
if (!isStaleCtxError(error)) console.debug?.("[dm-alps] Animations working reset failed:", error);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
function resetHiddenThinkingLabel(state: AnimationRuntimeState): void {
|
|
438
|
-
if (!state.hiddenLabelApplied) return;
|
|
439
|
-
try {
|
|
440
|
-
getCurrentUi(state)?.setHiddenThinkingLabel?.(undefined);
|
|
441
|
-
} catch (error) {
|
|
442
|
-
if (!isStaleCtxError(error)) console.debug?.("[dm-alps] Animations hidden label reset failed:", error);
|
|
443
|
-
}
|
|
444
|
-
state.hiddenLabelApplied = false;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function getCurrentUi(state: AnimationRuntimeState): any {
|
|
448
|
-
const ctx = canWriteWorkingAnimation(state.currentUiCtx) ? state.currentUiCtx : canWriteWorkingAnimation(state.currentCtx) ? state.currentCtx : undefined;
|
|
449
|
-
return ctx?.ui;
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
function resolveCurrentPhase(state: AnimationRuntimeState): AnimationPhase {
|
|
453
|
-
if (state.thinkingActive) return "thinking";
|
|
454
|
-
if (state.toolCallIds.size > 0) return "tool";
|
|
455
|
-
return "working";
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
function stableWorkingMessageForPhase(phase: AnimationPhase): string {
|
|
459
|
-
return phase === "tool" ? "Running..." : "Working...";
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
function resolveAnimationNameForPhase(state: AnimationRuntimeState, phase: AnimationPhase): string {
|
|
463
|
-
if (!state.settings.randomMode) {
|
|
464
|
-
if (phase === "thinking") return state.settings.thinking;
|
|
465
|
-
if (phase === "tool") return state.settings.tool;
|
|
466
|
-
return state.settings.working;
|
|
467
|
-
}
|
|
468
|
-
if (phase === "thinking") {
|
|
469
|
-
if (!state.randomThinking) state.randomThinking = state.previousRandomThinking = pickRandomAnimation("thinking", state.previousRandomThinking);
|
|
470
|
-
return state.randomThinking;
|
|
471
|
-
}
|
|
472
|
-
if (phase === "tool") {
|
|
473
|
-
if (!state.randomTool) state.randomTool = state.previousRandomTool = pickRandomAnimation("working", state.previousRandomTool);
|
|
474
|
-
return state.randomTool;
|
|
475
|
-
}
|
|
476
|
-
if (!state.randomWorking) state.randomWorking = state.previousRandomWorking = pickRandomAnimation("working", state.previousRandomWorking);
|
|
477
|
-
return state.randomWorking;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
function renderThinkingCompleteLabel(): string {
|
|
481
|
-
return `\x1b[3m\x1b[38;5;141m${THINKING_DONE_LABEL}\x1b[39m\x1b[23m`;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
function freezeAnimatedThinkingComponentsSoon(state: AnimationRuntimeState): void {
|
|
485
|
-
const freezeGeneration = state.freezeGeneration;
|
|
486
|
-
const timer = setTimeout(() => {
|
|
487
|
-
if (state.freezeGeneration !== freezeGeneration) return;
|
|
488
|
-
for (const component of [...state.activeComponents]) component.freeze();
|
|
489
|
-
requestAnimationsRender(state);
|
|
490
|
-
}, 0);
|
|
491
|
-
timer.unref?.();
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
function resetRandomAnimations(state: AnimationRuntimeState): void {
|
|
495
|
-
state.randomWorking = undefined;
|
|
496
|
-
state.randomThinking = undefined;
|
|
497
|
-
state.randomTool = undefined;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
function shouldRunTimer(state: AnimationRuntimeState): boolean {
|
|
501
|
-
return state.settings.enabled && state.animating;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
function hasActiveAnimationState(state: AnimationRuntimeState): boolean {
|
|
505
|
-
return Boolean(
|
|
506
|
-
state.animating
|
|
507
|
-
|| state.timer
|
|
508
|
-
|| state.thinkingActive
|
|
509
|
-
|| state.toolCallIds.size > 0
|
|
510
|
-
|| state.workingMessageApplied
|
|
511
|
-
|| state.workingWidgetApplied
|
|
512
|
-
|| state.workingIndicatorHidden
|
|
513
|
-
|| state.activeComponents.size > 0
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
function readToolCallId(event: any): string {
|
|
518
|
-
return String(event?.toolCallId ?? "__unknown_tool__");
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
function bindEventCtx(state: AnimationRuntimeState, ctx?: any): void {
|
|
522
|
-
if (!ctx || isStaleEventCtx(ctx)) return;
|
|
523
|
-
state.currentEventCtx = ctx;
|
|
524
|
-
if (!canWriteWorkingAnimation(ctx)) return;
|
|
525
|
-
state.currentUiCtx = ctx;
|
|
526
|
-
state.currentCtx = ctx;
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
function canWriteWorkingAnimation(ctx: any): boolean {
|
|
530
|
-
return Boolean(ctx && ctx.hasUI !== false && typeof ctx.ui?.setWorkingMessage === "function");
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
function isStaleEventCtx(ctx?: any): boolean {
|
|
534
|
-
return Boolean(ctx && ctx.isCurrent === false);
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
function rememberIgnoredAgentContext(state: AnimationRuntimeState, ctx?: any): void {
|
|
538
|
-
if (ctx && (typeof ctx === "object" || typeof ctx === "function")) state.ignoredAgentContexts.add(ctx);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
function isIgnoredAgentContext(state: AnimationRuntimeState, ctx?: any): boolean {
|
|
542
|
-
return Boolean(ctx && (typeof ctx === "object" || typeof ctx === "function") && state.ignoredAgentContexts.has(ctx));
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
function isNestedAgentStart(state: AnimationRuntimeState, ctx?: any): boolean {
|
|
546
|
-
if (!state.animating || !ctx) return false;
|
|
547
|
-
if (ctx.hasUI === false && ctx !== state.currentUiCtx) return true;
|
|
548
|
-
return Boolean(state.toolCallIds.size > 0 && ctx !== state.currentCtx);
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
function shouldIgnoreScopedEvent(state: AnimationRuntimeState, ctx?: any): boolean {
|
|
552
|
-
return isStaleEventCtx(ctx) || isIgnoredAgentContext(state, ctx) || isNestedNonWritableEvent(state, ctx);
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
function isNestedNoUiEvent(state: AnimationRuntimeState, ctx?: any): boolean {
|
|
556
|
-
return isNestedNonWritableEvent(state, ctx);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
function isNestedNonWritableEvent(state: AnimationRuntimeState, ctx?: any): boolean {
|
|
560
|
-
return Boolean(state.animating && ctx && ctx !== state.currentUiCtx && !isStaleEventCtx(ctx) && !canWriteWorkingAnimation(ctx));
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
function clearToolsForGeneration(state: AnimationRuntimeState, generation: number): void {
|
|
564
|
-
for (const [id, owner] of [...state.toolOwners]) {
|
|
565
|
-
if (owner !== generation) continue;
|
|
566
|
-
state.toolOwners.delete(id);
|
|
567
|
-
state.toolCallIds.delete(id);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
function isStaleCtxError(error: unknown): boolean {
|
|
572
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
573
|
-
return message.includes("extension ctx is stale") || message.includes("stale ctx");
|
|
574
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import type { AnimationWidth } from "./registry.ts";
|
|
3
|
-
import { getAnimation } from "./registry.ts";
|
|
4
|
-
|
|
5
|
-
export type AnimationsSettings = {
|
|
6
|
-
enabled: boolean;
|
|
7
|
-
randomMode: boolean;
|
|
8
|
-
working: string;
|
|
9
|
-
thinking: string;
|
|
10
|
-
tool: string;
|
|
11
|
-
width: AnimationWidth;
|
|
12
|
-
fps: number;
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const DEFAULT_ANIMATIONS_SETTINGS: AnimationsSettings = {
|
|
16
|
-
enabled: true,
|
|
17
|
-
randomMode: false,
|
|
18
|
-
working: "typewriter",
|
|
19
|
-
thinking: "shimmer",
|
|
20
|
-
tool: "crush",
|
|
21
|
-
width: "default",
|
|
22
|
-
fps: 16,
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const ANIMATION_WIDTH_VALUES: AnimationWidth[] = ["full", "default", 20, 40, 60, 80];
|
|
26
|
-
export const ANIMATION_FPS_VALUES = [8, 12, 16, 24, 30] as const;
|
|
27
|
-
|
|
28
|
-
export function cloneDefaultAnimationsSettings(): AnimationsSettings {
|
|
29
|
-
return { ...DEFAULT_ANIMATIONS_SETTINGS };
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export function normalizeAnimationsSettings(value: unknown, defaults: AnimationsSettings = DEFAULT_ANIMATIONS_SETTINGS): AnimationsSettings {
|
|
33
|
-
const raw = isRecord(value) ? value : {};
|
|
34
|
-
return {
|
|
35
|
-
enabled: readBoolean(raw, "enabled", defaults.enabled),
|
|
36
|
-
randomMode: readBoolean(raw, "randomMode", defaults.randomMode),
|
|
37
|
-
working: readAnimationName(raw.working, defaults.working),
|
|
38
|
-
thinking: readAnimationName(raw.thinking, defaults.thinking),
|
|
39
|
-
tool: readAnimationName(raw.tool, defaults.tool),
|
|
40
|
-
width: readWidth(raw.width, defaults.width),
|
|
41
|
-
fps: readFps(raw.fps, defaults.fps),
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function readBoolean(parent: Record<string, unknown>, key: string, fallback: boolean): boolean {
|
|
46
|
-
return typeof parent[key] === "boolean" ? parent[key] : fallback;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function readAnimationName(value: unknown, fallback: string): string {
|
|
50
|
-
if (typeof value !== "string") return fallback;
|
|
51
|
-
return getAnimation(value) ? value : fallback;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function readWidth(value: unknown, fallback: AnimationWidth): AnimationWidth {
|
|
55
|
-
if (value === "full" || value === "default") return value;
|
|
56
|
-
const numeric = typeof value === "number" ? value : typeof value === "string" && /^\d+$/.test(value) ? Number(value) : NaN;
|
|
57
|
-
if (!Number.isFinite(numeric)) return fallback;
|
|
58
|
-
const matched = ANIMATION_WIDTH_VALUES.find((item) => item === numeric);
|
|
59
|
-
return matched ?? fallback;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function readFps(value: unknown, fallback: number): number {
|
|
63
|
-
const numeric = typeof value === "number" ? value : typeof value === "string" && /^\d+$/.test(value) ? Number(value) : NaN;
|
|
64
|
-
return (ANIMATION_FPS_VALUES as readonly number[]).includes(numeric) ? numeric : fallback;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
68
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
69
|
-
}
|