@ashx-j/lunr 0.1.7 → 0.2.0
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/dist/builtin-extensions/lunr-todos.d.ts +7 -6
- package/dist/builtin-extensions/lunr-todos.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-todos.js +24 -11
- package/dist/builtin-extensions/lunr-todos.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js +9 -5
- package/dist/builtin-extensions/narumiruna-pi-goal/src/commands.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js +31 -3
- package/dist/builtin-extensions/narumiruna-pi-goal/src/goal.js.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.d.ts +1 -0
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.d.ts.map +1 -1
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js +14 -4
- package/dist/builtin-extensions/narumiruna-pi-goal/src/runtime.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js +4 -3
- package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js +12 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +3 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +8 -0
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +22 -2
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/index.js +38 -230
- package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/render-search-chrome.d.ts +35 -0
- package/dist/builtin-extensions/pi-web-access/render-search-chrome.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-web-access/render-search-chrome.js +93 -0
- package/dist/builtin-extensions/pi-web-access/render-search-chrome.js.map +1 -0
- package/dist/catalog/models.json +1 -1
- package/dist/catalog/providers/cloudflare-workers-ai.json +1 -1
- package/dist/catalog/providers/huggingface.json +1 -1
- package/dist/catalog/providers/opencode-go.json +1 -1
- package/dist/catalog/providers/openrouter.json +1 -1
- package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
- package/dist/catalog/publication.json +3 -3
- package/dist/core/context-breakdown.d.ts +21 -1
- package/dist/core/context-breakdown.d.ts.map +1 -1
- package/dist/core/context-breakdown.js +58 -2
- package/dist/core/context-breakdown.js.map +1 -1
- package/dist/core/permission-mode-control.d.ts +27 -0
- package/dist/core/permission-mode-control.d.ts.map +1 -0
- package/dist/core/permission-mode-control.js +39 -0
- package/dist/core/permission-mode-control.js.map +1 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +0 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +14 -20
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +2 -0
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +10 -0
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +1 -0
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/context-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/context-view.js +3 -1
- package/dist/modes/interactive/components/context-view.js.map +1 -1
- package/dist/modes/interactive/components/plan-message.d.ts +17 -0
- package/dist/modes/interactive/components/plan-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/plan-message.js +43 -0
- package/dist/modes/interactive/components/plan-message.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +3 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/usage-view.d.ts +4 -25
- package/dist/modes/interactive/components/usage-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/usage-view.js +17 -69
- package/dist/modes/interactive/components/usage-view.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts +1 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +1 -0
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +17 -6
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +196 -114
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/smooth-streaming.d.ts +39 -6
- package/dist/modes/interactive/smooth-streaming.d.ts.map +1 -1
- package/dist/modes/interactive/smooth-streaming.js +160 -73
- package/dist/modes/interactive/smooth-streaming.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +7 -3
- package/dist/utils/clipboard-image.js.map +1 -1
- package/docs/terminal-setup.md +13 -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/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/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
|
@@ -27,6 +27,7 @@ import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScop
|
|
|
27
27
|
import { refreshModelCandidatesForInit } from "../../core/model-runtime.js";
|
|
28
28
|
import { getModelTiersBridge } from "../../core/model-tiers.js";
|
|
29
29
|
import { registerPermissionModeBridge } from "../../core/permission-mode.js";
|
|
30
|
+
import { nextModeForGoal, registerPermissionModeControlBridge } from "../../core/permission-mode-control.js";
|
|
30
31
|
import { AUTO_MODE_ADDENDUM, getPermissionMode, nextPermissionMode, registerApprovalHandler, resetPermissions, restorePermissionModeAfterPlan, setPermissionMode, } from "../../core/permissions.js";
|
|
31
32
|
import { PLAN_MODE_ADDENDUM } from "../../core/plan-mode.js";
|
|
32
33
|
import * as processRegistry from "../../core/process-registry.js";
|
|
@@ -37,9 +38,8 @@ import { SessionManager, sessionEntryToContextMessages } from "../../core/sessio
|
|
|
37
38
|
import { BUILTIN_SLASH_COMMANDS } from "../../core/slash-commands.js";
|
|
38
39
|
// lunr: moved to core/swarm.ts so the gateway can reuse it.
|
|
39
40
|
import { buildSwarmPrompt } from "../../core/swarm.js";
|
|
40
|
-
import { hasTrustRequiringProjectResources, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
41
|
-
import { collectUsageHistory } from "../../core/usage-history.js";
|
|
42
41
|
import { time } from "../../core/timings.js";
|
|
42
|
+
import { hasTrustRequiringProjectResources, ProjectTrustStore } from "../../core/trust-manager.js";
|
|
43
43
|
import { getPlanUsageResult } from "../../core/usage-service.js";
|
|
44
44
|
import { modelToUserEntry } from "../../core/user-models.js";
|
|
45
45
|
import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
|
|
@@ -71,6 +71,7 @@ import { formatKeyText, keyDisplayText, keyText } from "./components/keybinding-
|
|
|
71
71
|
import { LoginDialogComponent } from "./components/login-dialog.js";
|
|
72
72
|
import { ModelSelectorComponent } from "./components/model-selector.js";
|
|
73
73
|
import { formatAuthSelectorProviderType, OAuthSelectorComponent, } from "./components/oauth-selector.js";
|
|
74
|
+
import { PlanMessageComponent } from "./components/plan-message.js";
|
|
74
75
|
import { ProcessesSelectorComponent } from "./components/processes-selector.js";
|
|
75
76
|
import { ScopedModelsSelectorComponent } from "./components/scoped-models-selector.js";
|
|
76
77
|
import { SessionSelectorComponent } from "./components/session-selector.js";
|
|
@@ -81,11 +82,11 @@ import { updateThinkingRunTimings } from "./components/thinking-summary.js";
|
|
|
81
82
|
import { ToolExecutionComponent } from "./components/tool-execution.js";
|
|
82
83
|
import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
83
84
|
import { TrustSelectorComponent } from "./components/trust-selector.js";
|
|
84
|
-
import {
|
|
85
|
+
import { renderUsageBox } from "./components/usage-view.js";
|
|
85
86
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
86
87
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
87
88
|
import { getModelSearchText } from "./model-search.js";
|
|
88
|
-
import { countMessageGraphemes, sliceMessageContent } from "./smooth-streaming.js";
|
|
89
|
+
import { computeSmoothRevealStep, countGraphemesBeforeToolCall, countMessageGraphemes, sliceMessageContent, } from "./smooth-streaming.js";
|
|
89
90
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, getThemeName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
90
91
|
import { InteractiveThemeController } from "./theme/theme-controller.js";
|
|
91
92
|
function isExpandable(obj) {
|
|
@@ -253,7 +254,6 @@ export class InteractiveMode {
|
|
|
253
254
|
// flashing whole chunks.
|
|
254
255
|
streamingTargetMessage = undefined;
|
|
255
256
|
streamingDisplayedLength = 0;
|
|
256
|
-
lastSmoothRenderAt = 0;
|
|
257
257
|
smoothStreamingTimer = undefined;
|
|
258
258
|
// Tool execution tracking: toolCallId -> component
|
|
259
259
|
pendingTools = new Map();
|
|
@@ -282,6 +282,9 @@ export class InteractiveMode {
|
|
|
282
282
|
// lunr: mode in effect before the current plan stretch. Used by approve / `/plan off`
|
|
283
283
|
// / `/plan <text>` to leave plan. Shift+Tab and `/mode` pick the destination themselves.
|
|
284
284
|
previousPermissionMode;
|
|
285
|
+
// lunr: mode in effect before `/goal` forced session auto. Dedicated so it cannot
|
|
286
|
+
// collide with plan restore.
|
|
287
|
+
preGoalPermissionMode;
|
|
285
288
|
// lunr: in-memory redo stack for /undo and /redo (leaf entry ids; cleared on any
|
|
286
289
|
// new user message, never persisted — undone turns reappear after restart)
|
|
287
290
|
redoStack = [];
|
|
@@ -343,6 +346,7 @@ export class InteractiveMode {
|
|
|
343
346
|
this.resetExtensionUI();
|
|
344
347
|
// lunr: reset permission mode to configured default + clear session approvals
|
|
345
348
|
this.previousPermissionMode = undefined;
|
|
349
|
+
this.preGoalPermissionMode = undefined;
|
|
346
350
|
resetPermissions(this.settingsManager.getDefaultPermissionMode());
|
|
347
351
|
// lunr: clear process registry and rollback state
|
|
348
352
|
processRegistry.clearRegistry();
|
|
@@ -362,8 +366,17 @@ export class InteractiveMode {
|
|
|
362
366
|
this.version = VERSION;
|
|
363
367
|
this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
|
|
364
368
|
this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
|
|
369
|
+
this.ui.onTextSelected = (text) => {
|
|
370
|
+
void copyToClipboard(text)
|
|
371
|
+
.then(() => this.showStatus("Copied."))
|
|
372
|
+
.catch((error) => this.showError(error instanceof Error ? error.message : String(error)));
|
|
373
|
+
};
|
|
365
374
|
// lunr: register the permission-mode footer bridge (provider-side: InteractiveMode owns the state).
|
|
366
375
|
registerPermissionModeBridge(() => getPermissionMode());
|
|
376
|
+
registerPermissionModeControlBridge({
|
|
377
|
+
enterGoalAuto: () => this.enterGoalAuto(),
|
|
378
|
+
leaveGoalAuto: () => this.leaveGoalAuto(),
|
|
379
|
+
});
|
|
367
380
|
// lunr: reset permission mode to configured default on startup.
|
|
368
381
|
resetPermissions(this.settingsManager.getDefaultPermissionMode());
|
|
369
382
|
this.headerContainer = new Container();
|
|
@@ -2252,11 +2265,6 @@ export class InteractiveMode {
|
|
|
2252
2265
|
await this.handleUsageCommand();
|
|
2253
2266
|
return;
|
|
2254
2267
|
}
|
|
2255
|
-
if (text === "/token-usage") {
|
|
2256
|
-
this.editor.setText("");
|
|
2257
|
-
this.handleTokenUsageCommand();
|
|
2258
|
-
return;
|
|
2259
|
-
}
|
|
2260
2268
|
if (text === "/context") {
|
|
2261
2269
|
this.editor.setText("");
|
|
2262
2270
|
this.handleContextCommand();
|
|
@@ -2440,9 +2448,17 @@ export class InteractiveMode {
|
|
|
2440
2448
|
this.editor.addToHistory?.(text);
|
|
2441
2449
|
};
|
|
2442
2450
|
}
|
|
2443
|
-
/** Smooth streaming tick rate (
|
|
2444
|
-
static SMOOTH_STREAMING_TICK_MS =
|
|
2445
|
-
|
|
2451
|
+
/** Smooth streaming tick rate (~30 FPS). TUI already caps paints at 16ms. */
|
|
2452
|
+
static SMOOTH_STREAMING_TICK_MS = 33;
|
|
2453
|
+
getSmoothStreamingOptions() {
|
|
2454
|
+
return { hideThinking: this.hideThinkingBlock };
|
|
2455
|
+
}
|
|
2456
|
+
clearSmoothStreamingTimer() {
|
|
2457
|
+
if (this.smoothStreamingTimer) {
|
|
2458
|
+
clearInterval(this.smoothStreamingTimer);
|
|
2459
|
+
this.smoothStreamingTimer = undefined;
|
|
2460
|
+
}
|
|
2461
|
+
}
|
|
2446
2462
|
startSmoothStreaming() {
|
|
2447
2463
|
if (this.smoothStreamingTimer)
|
|
2448
2464
|
return;
|
|
@@ -2452,38 +2468,96 @@ export class InteractiveMode {
|
|
|
2452
2468
|
// Never keep the process alive just to finish a reveal animation.
|
|
2453
2469
|
this.smoothStreamingTimer.unref?.();
|
|
2454
2470
|
}
|
|
2471
|
+
/** Apply the current reveal slice and sync tool cards that have crossed the frontier. */
|
|
2472
|
+
paintSmoothStreamingFrame() {
|
|
2473
|
+
const target = this.streamingTargetMessage;
|
|
2474
|
+
if (!this.streamingComponent || !target)
|
|
2475
|
+
return;
|
|
2476
|
+
const opts = this.getSmoothStreamingOptions();
|
|
2477
|
+
const revealed = sliceMessageContent(target, this.streamingDisplayedLength, opts);
|
|
2478
|
+
this.streamingComponent.updateContent(revealed);
|
|
2479
|
+
this.syncRevealedStreamingTools(revealed, target);
|
|
2480
|
+
this.ui.requestRender();
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Create/update tool cards only once smooth streaming has revealed past their
|
|
2484
|
+
* leading text. Args always come from the full target so later arg deltas apply.
|
|
2485
|
+
*/
|
|
2486
|
+
syncRevealedStreamingTools(revealed, target) {
|
|
2487
|
+
const revealedIds = new Set();
|
|
2488
|
+
for (const block of revealed.content) {
|
|
2489
|
+
if (block.type === "toolCall")
|
|
2490
|
+
revealedIds.add(block.id);
|
|
2491
|
+
}
|
|
2492
|
+
for (const content of target.content) {
|
|
2493
|
+
if (content.type !== "toolCall" || !revealedIds.has(content.id))
|
|
2494
|
+
continue;
|
|
2495
|
+
if (!this.pendingTools.has(content.id)) {
|
|
2496
|
+
const component = new ToolExecutionComponent(content.name, content.id, content.arguments, {
|
|
2497
|
+
showImages: this.settingsManager.getShowImages(),
|
|
2498
|
+
imageWidthCells: this.settingsManager.getImageWidthCells(),
|
|
2499
|
+
}, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
|
|
2500
|
+
component.setExpanded(this.toolOutputExpanded);
|
|
2501
|
+
this.addToolComponentToChat(component);
|
|
2502
|
+
this.pendingTools.set(content.id, component);
|
|
2503
|
+
}
|
|
2504
|
+
else {
|
|
2505
|
+
const component = this.pendingTools.get(content.id);
|
|
2506
|
+
if (component) {
|
|
2507
|
+
component.updateArgs(content.arguments);
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2455
2512
|
advanceSmoothStreaming() {
|
|
2456
2513
|
const target = this.streamingTargetMessage;
|
|
2457
2514
|
if (!this.streamingComponent || !target) {
|
|
2458
2515
|
this.stopSmoothStreaming();
|
|
2459
2516
|
return;
|
|
2460
2517
|
}
|
|
2461
|
-
const
|
|
2462
|
-
|
|
2518
|
+
const opts = this.getSmoothStreamingOptions();
|
|
2519
|
+
const total = countMessageGraphemes(target, opts);
|
|
2520
|
+
if (this.streamingDisplayedLength >= total) {
|
|
2521
|
+
// Caught up: stop the interval until new backlog arrives.
|
|
2522
|
+
this.clearSmoothStreamingTimer();
|
|
2463
2523
|
return;
|
|
2464
|
-
|
|
2465
|
-
// the more graphemes each tick reveals.
|
|
2524
|
+
}
|
|
2466
2525
|
const backlog = total - this.streamingDisplayedLength;
|
|
2467
|
-
this.streamingDisplayedLength +=
|
|
2526
|
+
this.streamingDisplayedLength += computeSmoothRevealStep(backlog);
|
|
2468
2527
|
if (this.streamingDisplayedLength > total) {
|
|
2469
2528
|
this.streamingDisplayedLength = total;
|
|
2470
2529
|
}
|
|
2471
|
-
this.
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
if (now - this.lastSmoothRenderAt >= 33) {
|
|
2475
|
-
this.lastSmoothRenderAt = now;
|
|
2476
|
-
this.ui.requestRender();
|
|
2530
|
+
this.paintSmoothStreamingFrame();
|
|
2531
|
+
if (this.streamingDisplayedLength >= total) {
|
|
2532
|
+
this.clearSmoothStreamingTimer();
|
|
2477
2533
|
}
|
|
2478
2534
|
}
|
|
2479
2535
|
stopSmoothStreaming() {
|
|
2480
|
-
|
|
2481
|
-
clearInterval(this.smoothStreamingTimer);
|
|
2482
|
-
this.smoothStreamingTimer = undefined;
|
|
2483
|
-
}
|
|
2536
|
+
this.clearSmoothStreamingTimer();
|
|
2484
2537
|
this.streamingTargetMessage = undefined;
|
|
2485
2538
|
this.streamingDisplayedLength = 0;
|
|
2486
|
-
|
|
2539
|
+
}
|
|
2540
|
+
/** Apply a mid-stream smoothStreaming setting change without rewinding. */
|
|
2541
|
+
applySmoothStreamingSettingChange(enabled) {
|
|
2542
|
+
this.settingsManager.setSmoothStreaming(enabled);
|
|
2543
|
+
if (!this.streamingComponent || !this.streamingMessage)
|
|
2544
|
+
return;
|
|
2545
|
+
if (enabled) {
|
|
2546
|
+
// Already showing the full live message; start the reveal cursor at the
|
|
2547
|
+
// current visible length so the next deltas only animate new text.
|
|
2548
|
+
this.streamingTargetMessage = this.streamingMessage;
|
|
2549
|
+
const opts = this.getSmoothStreamingOptions();
|
|
2550
|
+
this.streamingDisplayedLength = countMessageGraphemes(this.streamingMessage, opts);
|
|
2551
|
+
this.paintSmoothStreamingFrame();
|
|
2552
|
+
this.startSmoothStreaming();
|
|
2553
|
+
return;
|
|
2554
|
+
}
|
|
2555
|
+
// Off: stop the timer and snap to the full target immediately.
|
|
2556
|
+
this.clearSmoothStreamingTimer();
|
|
2557
|
+
this.streamingTargetMessage = this.streamingMessage;
|
|
2558
|
+
this.streamingComponent.updateContent(this.streamingMessage);
|
|
2559
|
+
this.syncRevealedStreamingTools(this.streamingMessage, this.streamingMessage);
|
|
2560
|
+
this.ui.requestRender();
|
|
2487
2561
|
}
|
|
2488
2562
|
subscribeToAgent() {
|
|
2489
2563
|
this.unsubscribe = this.session.subscribe(async (event) => {
|
|
@@ -2561,7 +2635,7 @@ export class InteractiveMode {
|
|
|
2561
2635
|
this.streamingDisplayedLength = 0;
|
|
2562
2636
|
this.chatContainer.addChild(this.streamingComponent);
|
|
2563
2637
|
if (this.settingsManager.getSmoothStreaming()) {
|
|
2564
|
-
this.streamingComponent.updateContent(sliceMessageContent(this.streamingMessage, 0));
|
|
2638
|
+
this.streamingComponent.updateContent(sliceMessageContent(this.streamingMessage, 0, this.getSmoothStreamingOptions()));
|
|
2565
2639
|
}
|
|
2566
2640
|
else {
|
|
2567
2641
|
this.streamingComponent.updateContent(this.streamingMessage);
|
|
@@ -2577,40 +2651,32 @@ export class InteractiveMode {
|
|
|
2577
2651
|
// so smooth-streaming reveal lag doesn't inflate durations.
|
|
2578
2652
|
updateThinkingRunTimings(this.thinkingRunTimings, this.streamingMessage.content, Date.now(), false);
|
|
2579
2653
|
if (this.settingsManager.getSmoothStreaming()) {
|
|
2580
|
-
// Smooth streaming:
|
|
2581
|
-
//
|
|
2582
|
-
this.
|
|
2654
|
+
// Smooth streaming: timer reveals graphemes. Tool cards sync from
|
|
2655
|
+
// the reveal frontier so they don't jump ahead of leading text.
|
|
2656
|
+
const opts = this.getSmoothStreamingOptions();
|
|
2657
|
+
const total = countMessageGraphemes(this.streamingMessage, opts);
|
|
2658
|
+
if (this.streamingDisplayedLength >= total) {
|
|
2659
|
+
// Already caught up (or tool-only): paint so new tool cards appear.
|
|
2660
|
+
this.paintSmoothStreamingFrame();
|
|
2661
|
+
this.clearSmoothStreamingTimer();
|
|
2662
|
+
}
|
|
2663
|
+
else {
|
|
2664
|
+
this.startSmoothStreaming();
|
|
2665
|
+
}
|
|
2583
2666
|
}
|
|
2584
2667
|
else {
|
|
2585
2668
|
this.streamingComponent.updateContent(this.streamingMessage);
|
|
2669
|
+
this.syncRevealedStreamingTools(this.streamingMessage, this.streamingMessage);
|
|
2670
|
+
this.ui.requestRender();
|
|
2586
2671
|
}
|
|
2587
|
-
for (const content of this.streamingMessage.content) {
|
|
2588
|
-
if (content.type === "toolCall") {
|
|
2589
|
-
if (!this.pendingTools.has(content.id)) {
|
|
2590
|
-
const component = new ToolExecutionComponent(content.name, content.id, content.arguments, {
|
|
2591
|
-
showImages: this.settingsManager.getShowImages(),
|
|
2592
|
-
imageWidthCells: this.settingsManager.getImageWidthCells(),
|
|
2593
|
-
}, this.getRegisteredToolDefinition(content.name), this.ui, this.sessionManager.getCwd());
|
|
2594
|
-
component.setExpanded(this.toolOutputExpanded);
|
|
2595
|
-
this.addToolComponentToChat(component);
|
|
2596
|
-
this.pendingTools.set(content.id, component);
|
|
2597
|
-
}
|
|
2598
|
-
else {
|
|
2599
|
-
const component = this.pendingTools.get(content.id);
|
|
2600
|
-
if (component) {
|
|
2601
|
-
component.updateArgs(content.arguments);
|
|
2602
|
-
}
|
|
2603
|
-
}
|
|
2604
|
-
}
|
|
2605
|
-
}
|
|
2606
|
-
this.ui.requestRender();
|
|
2607
2672
|
}
|
|
2608
2673
|
break;
|
|
2609
2674
|
case "message_end":
|
|
2610
2675
|
if (event.message.role === "user")
|
|
2611
2676
|
break;
|
|
2612
2677
|
if (this.streamingComponent && event.message.role === "assistant") {
|
|
2613
|
-
//
|
|
2678
|
+
// Snap remaining graphemes on end (abort/error and normal stop).
|
|
2679
|
+
// Avoids multi-second leftover animation; paint always follows below.
|
|
2614
2680
|
this.stopSmoothStreaming();
|
|
2615
2681
|
this.streamingMessage = event.message;
|
|
2616
2682
|
let errorMessage;
|
|
@@ -2653,6 +2719,18 @@ export class InteractiveMode {
|
|
|
2653
2719
|
this.ui.requestRender();
|
|
2654
2720
|
break;
|
|
2655
2721
|
case "tool_execution_start": {
|
|
2722
|
+
// If smooth streaming still has leading text unrevealed, flush through
|
|
2723
|
+
// this tool so the running card is not hidden behind the typewriter.
|
|
2724
|
+
if (this.settingsManager.getSmoothStreaming() &&
|
|
2725
|
+
this.streamingTargetMessage &&
|
|
2726
|
+
this.streamingComponent) {
|
|
2727
|
+
const opts = this.getSmoothStreamingOptions();
|
|
2728
|
+
const needed = countGraphemesBeforeToolCall(this.streamingTargetMessage, event.toolCallId, opts);
|
|
2729
|
+
if (this.streamingDisplayedLength < needed) {
|
|
2730
|
+
this.streamingDisplayedLength = needed;
|
|
2731
|
+
}
|
|
2732
|
+
this.paintSmoothStreamingFrame();
|
|
2733
|
+
}
|
|
2656
2734
|
let component = this.pendingTools.get(event.toolCallId);
|
|
2657
2735
|
if (!component) {
|
|
2658
2736
|
component = new ToolExecutionComponent(event.toolName, event.toolCallId, event.args, {
|
|
@@ -3117,7 +3195,7 @@ export class InteractiveMode {
|
|
|
3117
3195
|
if (this.isShuttingDown)
|
|
3118
3196
|
return;
|
|
3119
3197
|
this.isShuttingDown = true;
|
|
3120
|
-
this.stopSmoothStreaming
|
|
3198
|
+
this.stopSmoothStreaming();
|
|
3121
3199
|
// Keep signal handlers registered until terminal cleanup has completed.
|
|
3122
3200
|
// `signal-exit` checks the listener list during the same SIGTERM/SIGHUP
|
|
3123
3201
|
// dispatch and re-sends the signal if only its own listeners remain.
|
|
@@ -3418,10 +3496,25 @@ export class InteractiveMode {
|
|
|
3418
3496
|
// Rebuild chat from session messages
|
|
3419
3497
|
this.chatContainer.clear();
|
|
3420
3498
|
this.rebuildChatFromMessages();
|
|
3421
|
-
// If streaming, re-add the streaming component with updated visibility and re-render
|
|
3499
|
+
// If streaming, re-add the streaming component with updated visibility and re-render.
|
|
3500
|
+
// Re-slice to the current revealed length so hide-thinking does not dump the tail.
|
|
3422
3501
|
if (this.streamingComponent && this.streamingMessage) {
|
|
3423
3502
|
this.streamingComponent.setHideThinkingBlock(this.hideThinkingBlock);
|
|
3424
|
-
this.
|
|
3503
|
+
if (this.settingsManager.getSmoothStreaming() && this.streamingTargetMessage) {
|
|
3504
|
+
const opts = this.getSmoothStreamingOptions();
|
|
3505
|
+
const total = countMessageGraphemes(this.streamingTargetMessage, opts);
|
|
3506
|
+
if (this.streamingDisplayedLength > total) {
|
|
3507
|
+
this.streamingDisplayedLength = total;
|
|
3508
|
+
}
|
|
3509
|
+
this.paintSmoothStreamingFrame();
|
|
3510
|
+
// Restart the timer if new (or still-pending) backlog exists.
|
|
3511
|
+
if (this.streamingDisplayedLength < total) {
|
|
3512
|
+
this.startSmoothStreaming();
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
else {
|
|
3516
|
+
this.streamingComponent.updateContent(this.streamingMessage);
|
|
3517
|
+
}
|
|
3425
3518
|
this.chatContainer.addChild(this.streamingComponent);
|
|
3426
3519
|
}
|
|
3427
3520
|
this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
|
|
@@ -3818,7 +3911,7 @@ export class InteractiveMode {
|
|
|
3818
3911
|
this.settingsManager.setQuietStartup(enabled);
|
|
3819
3912
|
},
|
|
3820
3913
|
onSmoothStreamingChange: (enabled) => {
|
|
3821
|
-
this.
|
|
3914
|
+
this.applySmoothStreamingSettingChange(enabled);
|
|
3822
3915
|
},
|
|
3823
3916
|
onSessionRetentionDaysChange: (days) => {
|
|
3824
3917
|
this.settingsManager.setSessionRetentionDays(days);
|
|
@@ -5904,41 +5997,24 @@ export class InteractiveMode {
|
|
|
5904
5997
|
this.chatContainer.addChild(new Text(info, 1, 0));
|
|
5905
5998
|
this.ui.requestRender();
|
|
5906
5999
|
}
|
|
5907
|
-
|
|
5908
|
-
|
|
5909
|
-
const
|
|
5910
|
-
|
|
5911
|
-
if (entry.type !== "message" || entry.message.role !== "assistant")
|
|
5912
|
-
continue;
|
|
5913
|
-
const message = entry.message;
|
|
5914
|
-
const usage = message.usage;
|
|
5915
|
-
const key = `${message.provider}/${message.responseModel ?? message.model}`;
|
|
5916
|
-
let row = perModelMap.get(key);
|
|
5917
|
-
if (!row) {
|
|
5918
|
-
row = { model: key, input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 };
|
|
5919
|
-
perModelMap.set(key, row);
|
|
5920
|
-
}
|
|
5921
|
-
row.input += usage.input;
|
|
5922
|
-
row.output += usage.output;
|
|
5923
|
-
row.cacheRead += usage.cacheRead;
|
|
5924
|
-
row.cacheWrite += usage.cacheWrite;
|
|
5925
|
-
row.total += usage.input + usage.output + usage.cacheRead + usage.cacheWrite;
|
|
5926
|
-
}
|
|
5927
|
-
return Array.from(perModelMap.values()).sort((a, b) => b.total - a.total);
|
|
5928
|
-
}
|
|
5929
|
-
// lunr: 30-day history from session files on disk; best-effort — on any
|
|
5930
|
-
// error the section is simply omitted.
|
|
5931
|
-
collectUsageHistorySafe() {
|
|
5932
|
-
try {
|
|
5933
|
-
return collectUsageHistory({ sinceMs: Date.now() - 30 * 24 * 60 * 60 * 1000 });
|
|
5934
|
-
}
|
|
5935
|
-
catch {
|
|
6000
|
+
collectUsageBreakdown() {
|
|
6001
|
+
const model = this.session.model;
|
|
6002
|
+
const contextWindow = model?.contextWindow ?? 0;
|
|
6003
|
+
if (!model || contextWindow <= 0)
|
|
5936
6004
|
return undefined;
|
|
5937
|
-
|
|
6005
|
+
const tools = this.session
|
|
6006
|
+
.getActiveToolNames()
|
|
6007
|
+
.map((name) => this.session.getToolDefinition(name))
|
|
6008
|
+
.filter((definition) => definition !== undefined);
|
|
6009
|
+
return computeContextBreakdown({
|
|
6010
|
+
systemPrompt: this.session.systemPrompt,
|
|
6011
|
+
tools,
|
|
6012
|
+
messages: this.session.messages,
|
|
6013
|
+
contextWindow,
|
|
6014
|
+
});
|
|
5938
6015
|
}
|
|
5939
|
-
// lunr: /usage —
|
|
5940
|
-
// bar, and subscription plan usage
|
|
5941
|
-
// adapter). Per-model rows live in /token-usage.
|
|
6016
|
+
// lunr: /usage — current session only: token totals, live context split,
|
|
6017
|
+
// context-window bar, and subscription plan usage.
|
|
5942
6018
|
async handleUsageCommand() {
|
|
5943
6019
|
const stats = this.session.getSessionStats();
|
|
5944
6020
|
const sessionTotals = stats.tokens.total > 0
|
|
@@ -5953,24 +6029,14 @@ export class InteractiveMode {
|
|
|
5953
6029
|
const context = this.session.getContextUsage();
|
|
5954
6030
|
const provider = this.session.model?.provider;
|
|
5955
6031
|
const planResult = provider ? await getPlanUsageResult(provider, this.session.modelRuntime) : {};
|
|
5956
|
-
const
|
|
5957
|
-
const lines = renderUsageBox({ sessionTotals, context, plan: planResult.usage,
|
|
6032
|
+
const breakdown = this.collectUsageBreakdown();
|
|
6033
|
+
const lines = renderUsageBox({ sessionTotals, context, plan: planResult.usage, breakdown }, this.ui.terminal.columns);
|
|
5958
6034
|
this.chatContainer.addChild(new Spacer(1));
|
|
5959
6035
|
this.chatContainer.addChild(new Text(lines.join("\n"), 1, 0));
|
|
5960
6036
|
if (planResult.error)
|
|
5961
6037
|
this.showStatus(planResult.error);
|
|
5962
6038
|
this.ui.requestRender();
|
|
5963
6039
|
}
|
|
5964
|
-
// lunr: /token-usage — per-model token breakdown for the current session and
|
|
5965
|
-
// the last 30 days (from session files on disk).
|
|
5966
|
-
handleTokenUsageCommand() {
|
|
5967
|
-
const sessionRows = this.collectSessionModelRows();
|
|
5968
|
-
const history = this.collectUsageHistorySafe();
|
|
5969
|
-
const lines = renderTokenUsageBox({ sessionRows, history }, this.ui.terminal.columns);
|
|
5970
|
-
this.chatContainer.addChild(new Spacer(1));
|
|
5971
|
-
this.chatContainer.addChild(new Text(lines.join("\n"), 1, 0));
|
|
5972
|
-
this.ui.requestRender();
|
|
5973
|
-
}
|
|
5974
6040
|
// lunr: /context — estimated breakdown of what consumes the context window
|
|
5975
6041
|
// (system prompt incl. project context files, tool definitions, and the live
|
|
5976
6042
|
// session messages). Uses session.messages, so post-compaction renders match
|
|
@@ -5982,16 +6048,11 @@ export class InteractiveMode {
|
|
|
5982
6048
|
this.showStatus("No model selected or context window unknown.");
|
|
5983
6049
|
return;
|
|
5984
6050
|
}
|
|
5985
|
-
const
|
|
5986
|
-
|
|
5987
|
-
.
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
systemPrompt: this.session.systemPrompt,
|
|
5991
|
-
tools,
|
|
5992
|
-
messages: this.session.messages,
|
|
5993
|
-
contextWindow,
|
|
5994
|
-
});
|
|
6051
|
+
const breakdown = this.collectUsageBreakdown();
|
|
6052
|
+
if (!breakdown) {
|
|
6053
|
+
this.showStatus("No model selected or context window unknown.");
|
|
6054
|
+
return;
|
|
6055
|
+
}
|
|
5995
6056
|
const lines = renderContextBox({ breakdown, model: `${model.provider}/${model.id}` }, this.ui.terminal.columns);
|
|
5996
6057
|
this.chatContainer.addChild(new Spacer(1));
|
|
5997
6058
|
this.chatContainer.addChild(new Text(lines.join("\n"), 1, 0));
|
|
@@ -6083,6 +6144,21 @@ export class InteractiveMode {
|
|
|
6083
6144
|
this.session.setSystemPromptAppend(undefined);
|
|
6084
6145
|
}
|
|
6085
6146
|
}
|
|
6147
|
+
// lunr: `/goal` forces session auto without writing settings.
|
|
6148
|
+
enterGoalAuto() {
|
|
6149
|
+
const next = nextModeForGoal(getPermissionMode(), "enter", this.preGoalPermissionMode);
|
|
6150
|
+
this.preGoalPermissionMode = next.saved;
|
|
6151
|
+
if (next.mode !== getPermissionMode()) {
|
|
6152
|
+
this.applyPermissionMode(next.mode, { silent: true });
|
|
6153
|
+
}
|
|
6154
|
+
}
|
|
6155
|
+
leaveGoalAuto() {
|
|
6156
|
+
const next = nextModeForGoal(getPermissionMode(), "leave", this.preGoalPermissionMode);
|
|
6157
|
+
this.preGoalPermissionMode = next.saved;
|
|
6158
|
+
if (next.mode !== getPermissionMode()) {
|
|
6159
|
+
this.applyPermissionMode(next.mode, { silent: true });
|
|
6160
|
+
}
|
|
6161
|
+
}
|
|
6086
6162
|
applyPermissionMode(mode, opts) {
|
|
6087
6163
|
const prev = getPermissionMode();
|
|
6088
6164
|
if (mode === "plan" && prev !== "plan") {
|
|
@@ -6178,7 +6254,13 @@ export class InteractiveMode {
|
|
|
6178
6254
|
// lunr: approval dialog for present_plan (plan mode). The "with feedback"
|
|
6179
6255
|
// options collect a one-line note via showExtensionInput that becomes part of
|
|
6180
6256
|
// the result text the model sees. Esc/close counts as Decline.
|
|
6257
|
+
showPlanInChat(summary) {
|
|
6258
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
6259
|
+
this.chatContainer.addChild(new PlanMessageComponent(summary, this.getMarkdownThemeWithSettings(), this.outputPad, this.settingsManager.getGutterRail()));
|
|
6260
|
+
this.ui.requestRender();
|
|
6261
|
+
}
|
|
6181
6262
|
async showPlanApprovalDialog(summary) {
|
|
6263
|
+
this.showPlanInChat(summary);
|
|
6182
6264
|
return new Promise((resolve) => {
|
|
6183
6265
|
this.showSelector((done) => {
|
|
6184
6266
|
const selector = new ExtensionSelectorComponent("▶ Approve plan?", ["Approve", "Approve with feedback", "Decline", "Decline with feedback"], (option) => {
|
|
@@ -6202,7 +6284,7 @@ export class InteractiveMode {
|
|
|
6202
6284
|
}, () => {
|
|
6203
6285
|
done();
|
|
6204
6286
|
resolve("reject");
|
|
6205
|
-
}
|
|
6287
|
+
});
|
|
6206
6288
|
return { component: selector, focus: selector };
|
|
6207
6289
|
});
|
|
6208
6290
|
});
|