@ashx-j/lunr 0.2.8 → 0.2.10
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/ashxj-spinners.d.ts +4 -0
- package/dist/builtin-extensions/ashxj-spinners.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-spinners.js +14 -3
- package/dist/builtin-extensions/ashxj-spinners.js.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.d.ts +4 -0
- package/dist/builtin-extensions/ashxj-tui.d.ts.map +1 -1
- package/dist/builtin-extensions/ashxj-tui.js +49 -4
- package/dist/builtin-extensions/ashxj-tui.js.map +1 -1
- package/dist/builtin-extensions/lunr-behavior.d.ts +2 -1
- package/dist/builtin-extensions/lunr-behavior.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-behavior.js +26 -14
- package/dist/builtin-extensions/lunr-behavior.js.map +1 -1
- package/dist/builtin-extensions/lunr-todos.d.ts +4 -7
- package/dist/builtin-extensions/lunr-todos.d.ts.map +1 -1
- package/dist/builtin-extensions/lunr-todos.js +18 -10
- package/dist/builtin-extensions/lunr-todos.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js +3 -3
- package/dist/builtin-extensions/pi-subagents/src/agents/agent-management.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js +4 -4
- package/dist/builtin-extensions/pi-subagents/src/extension/schemas.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.js +4 -5
- package/dist/builtin-extensions/pi-subagents/src/extension/tool-description.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 +5 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/execution.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +6 -18
- package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js +13 -5
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/model-fallback.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/runs/shared/parallel-utils.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/lunr-child-context.d.ts +21 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/lunr-child-context.d.ts.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/lunr-child-context.js +22 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/lunr-child-context.js.map +1 -0
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts +2 -2
- package/dist/builtin-extensions/pi-subagents/src/shared/types.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js +2 -2
- package/dist/builtin-extensions/pi-subagents/src/shared/types.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js +2 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/prompt-workflows.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js +10 -18
- package/dist/builtin-extensions/pi-subagents/src/slash/slash-commands.js.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts +4 -6
- package/dist/builtin-extensions/pi-subagents/src/tui/render.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-subagents/src/tui/render.js +26 -18
- 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 +3 -1
- package/dist/builtin-extensions/pi-web-access/index.js.map +1 -1
- package/dist/builtin-extensions/pi-web-access/render-search-error.d.ts.map +1 -1
- package/dist/builtin-extensions/pi-web-access/render-search-error.js +1 -1
- package/dist/builtin-extensions/pi-web-access/render-search-error.js.map +1 -1
- package/dist/catalog/models.json +1 -1
- package/dist/catalog/providers/nvidia.json +1 -1
- package/dist/catalog/providers/opencode-go.json +1 -1
- package/dist/catalog/providers/opencode.json +1 -1
- package/dist/catalog/providers/openrouter.json +1 -1
- package/dist/catalog/providers/qwen-cloud-cn.json +1 -1
- package/dist/catalog/providers/vercel-ai-gateway.json +1 -1
- package/dist/catalog/providers/xai.json +1 -1
- package/dist/catalog/publication.json +2 -2
- package/dist/cli/update-cli.d.ts +16 -0
- package/dist/cli/update-cli.d.ts.map +1 -0
- package/dist/cli/update-cli.js +83 -0
- package/dist/cli/update-cli.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -0
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +9 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/behavior-preset.d.ts +60 -0
- package/dist/core/behavior-preset.d.ts.map +1 -0
- package/dist/core/behavior-preset.js +257 -0
- package/dist/core/behavior-preset.js.map +1 -0
- package/dist/core/customize.d.ts +4 -0
- package/dist/core/customize.d.ts.map +1 -1
- package/dist/core/customize.js +12 -0
- package/dist/core/customize.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +12 -1
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +70 -5
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/keybindings.d.ts +2 -2
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +1 -1
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-tiers.d.ts +9 -0
- package/dist/core/model-tiers.d.ts.map +1 -1
- package/dist/core/model-tiers.js +16 -0
- package/dist/core/model-tiers.js.map +1 -1
- package/dist/core/settings-manager.d.ts +26 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +74 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +3 -4
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +9 -6
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +2 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +2 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +2 -1
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +2 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +13 -3
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +10 -2
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +5 -3
- package/dist/core/tools/write.js.map +1 -1
- package/dist/core/update-check.d.ts +32 -0
- package/dist/core/update-check.d.ts.map +1 -0
- package/dist/core/update-check.js +112 -0
- package/dist/core/update-check.js.map +1 -0
- package/dist/core/usage-service.d.ts +24 -1
- package/dist/core/usage-service.d.ts.map +1 -1
- package/dist/core/usage-service.js +91 -14
- package/dist/core/usage-service.js.map +1 -1
- package/dist/gateway/agent-bridge.d.ts +1 -0
- package/dist/gateway/agent-bridge.d.ts.map +1 -1
- package/dist/gateway/agent-bridge.js +5 -1
- package/dist/gateway/agent-bridge.js.map +1 -1
- package/dist/gateway/cron.d.ts.map +1 -1
- package/dist/gateway/cron.js +5 -1
- package/dist/gateway/cron.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +13 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +4 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +68 -10
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +15 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +168 -11
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-tail.d.ts +1 -0
- package/dist/modes/interactive/components/thinking-tail.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-tail.js +2 -6
- package/dist/modes/interactive/components/thinking-tail.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +7 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +84 -16
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +19 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +221 -37
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/keybindings.md +1 -1
- package/docs/terminal-setup.md +2 -2
- 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
|
@@ -6,12 +6,14 @@ import * as crypto from "node:crypto";
|
|
|
6
6
|
import * as fs from "node:fs";
|
|
7
7
|
import * as os from "node:os";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import {
|
|
9
|
+
import { getSupportedThinkingLevels, } from "@ashx-j/lunr-ai/compat";
|
|
10
|
+
import { collectImageMarkerIds, CombinedAutocompleteProvider, Container, formatImageMarker, fuzzyFilter, isFocusable, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@ashx-j/lunr-tui";
|
|
10
11
|
import chalk from "chalk";
|
|
11
12
|
import { spawn, spawnSync } from "child_process";
|
|
12
13
|
import { APP_NAME, APP_TITLE, appendDebugLog, CONFIG_DIR_NAME, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
|
|
13
14
|
import { parseSkillBlock } from "../../core/agent-session.js";
|
|
14
15
|
import { SessionImportFileNotFoundError } from "../../core/agent-session-runtime.js";
|
|
16
|
+
import { applyBehaviorPreset, reconcileBehaviorPreset } from "../../core/behavior-preset.js";
|
|
15
17
|
import { CACHE_TTL_MS, collectCacheMisses, computeCacheWaste, detectCacheMiss, } from "../../core/cache-stats.js";
|
|
16
18
|
import { formatCatalogRefreshSummary } from "../../core/catalog-merge.js";
|
|
17
19
|
import { computeContextBreakdown } from "../../core/context-breakdown.js";
|
|
@@ -26,6 +28,8 @@ import { isValidProviderBaseUrl, parseModelIds, slugifyProviderId, upsertCustomP
|
|
|
26
28
|
import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope } from "../../core/model-resolver.js";
|
|
27
29
|
import { refreshModelCandidatesForInit } from "../../core/model-runtime.js";
|
|
28
30
|
import { getModelTiersBridge } from "../../core/model-tiers.js";
|
|
31
|
+
import { checkForUpdate, markUpdateNotified } from "../../core/update-check.js";
|
|
32
|
+
import { getUsageServiceBridge } from "../../core/usage-service.js";
|
|
29
33
|
import { registerPermissionModeBridge } from "../../core/permission-mode.js";
|
|
30
34
|
import { nextModeForGoal, registerPermissionModeControlBridge } from "../../core/permission-mode-control.js";
|
|
31
35
|
import { AUTO_MODE_ADDENDUM, getPermissionMode, nextPermissionMode, registerApprovalHandler, resetPermissions, restorePermissionModeAfterPlan, setPermissionMode, } from "../../core/permissions.js";
|
|
@@ -45,6 +49,7 @@ import { modelToUserEntry } from "../../core/user-models.js";
|
|
|
45
49
|
import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
|
|
46
50
|
import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
|
|
47
51
|
import { parseGitUrl } from "../../utils/git.js";
|
|
52
|
+
import { processImage } from "../../utils/image-process.js";
|
|
48
53
|
import { getCwdRelativePath } from "../../utils/paths.js";
|
|
49
54
|
import { killTrackedDetachedChildren } from "../../utils/shell.js";
|
|
50
55
|
import { ensureTool, getToolPath } from "../../utils/tools-manager.js";
|
|
@@ -232,6 +237,8 @@ export class InteractiveMode {
|
|
|
232
237
|
isInitialized = false;
|
|
233
238
|
onInputCallback;
|
|
234
239
|
pendingUserInputs = [];
|
|
240
|
+
stagedSubmitImages;
|
|
241
|
+
fallbackImageAttachments = new Map();
|
|
235
242
|
activeStatusIndicator = undefined;
|
|
236
243
|
idleStatus = new IdleStatus();
|
|
237
244
|
workingMessage = undefined;
|
|
@@ -589,6 +596,8 @@ export class InteractiveMode {
|
|
|
589
596
|
this.ui.start();
|
|
590
597
|
this.isInitialized = true;
|
|
591
598
|
time("ui.start");
|
|
599
|
+
void this.maybeNotifyCliUpdate();
|
|
600
|
+
this.startPlanUsagePolling();
|
|
592
601
|
// lunr: register the permission approval dialog handler so manual mode can prompt.
|
|
593
602
|
registerApprovalHandler(async (req) => {
|
|
594
603
|
// lunr: auto-activated agent swarms get their own dialog; on approval the
|
|
@@ -599,7 +608,7 @@ export class InteractiveMode {
|
|
|
599
608
|
const decision = typeof resp === "string" ? resp : resp.decision;
|
|
600
609
|
if (decision !== "reject") {
|
|
601
610
|
this.swarmMode = true;
|
|
602
|
-
this.setExtensionStatus("swarm", "swarm
|
|
611
|
+
this.setExtensionStatus("swarm", "swarm");
|
|
603
612
|
}
|
|
604
613
|
return resp;
|
|
605
614
|
}
|
|
@@ -665,6 +674,38 @@ export class InteractiveMode {
|
|
|
665
674
|
await this.deferredBuiltinAttachPromise;
|
|
666
675
|
}
|
|
667
676
|
}
|
|
677
|
+
planUsageTimer;
|
|
678
|
+
startPlanUsagePolling() {
|
|
679
|
+
const bridge = getUsageServiceBridge();
|
|
680
|
+
if (!bridge)
|
|
681
|
+
return;
|
|
682
|
+
bridge.setOnUpdate(() => this.ui.requestRender());
|
|
683
|
+
const tick = () => {
|
|
684
|
+
const provider = this.session.model?.provider;
|
|
685
|
+
if (provider)
|
|
686
|
+
bridge.prefetch(provider);
|
|
687
|
+
};
|
|
688
|
+
tick();
|
|
689
|
+
this.planUsageTimer = setInterval(tick, 60_000);
|
|
690
|
+
this.planUsageTimer.unref?.();
|
|
691
|
+
}
|
|
692
|
+
/** Background npm version check. Never blocks first paint. Workspace installs skip. */
|
|
693
|
+
async maybeNotifyCliUpdate() {
|
|
694
|
+
try {
|
|
695
|
+
const result = await checkForUpdate({
|
|
696
|
+
currentVersion: VERSION,
|
|
697
|
+
agentDir: getAgentDir(),
|
|
698
|
+
offline: process.env.PI_OFFLINE === "1",
|
|
699
|
+
});
|
|
700
|
+
if (!result?.notice)
|
|
701
|
+
return;
|
|
702
|
+
this.showStatus(result.notice);
|
|
703
|
+
markUpdateNotified(getAgentDir(), result.latest);
|
|
704
|
+
}
|
|
705
|
+
catch {
|
|
706
|
+
// Version check is best-effort.
|
|
707
|
+
}
|
|
708
|
+
}
|
|
668
709
|
/**
|
|
669
710
|
* Update terminal title with session name and cwd.
|
|
670
711
|
*/
|
|
@@ -730,7 +771,7 @@ export class InteractiveMode {
|
|
|
730
771
|
while (true) {
|
|
731
772
|
const userInput = await this.getUserInput();
|
|
732
773
|
try {
|
|
733
|
-
await this.promptAfterDeferredBuiltins(userInput);
|
|
774
|
+
await this.promptAfterDeferredBuiltins(userInput.text, { images: userInput.images });
|
|
734
775
|
}
|
|
735
776
|
catch (error) {
|
|
736
777
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
@@ -1304,7 +1345,7 @@ export class InteractiveMode {
|
|
|
1304
1345
|
this.chatContainer.clear();
|
|
1305
1346
|
this.renderInitialMessages();
|
|
1306
1347
|
if (result.editorText && !this.editor.getText().trim()) {
|
|
1307
|
-
this.
|
|
1348
|
+
this.restoreEditorFromTreeResult(result);
|
|
1308
1349
|
}
|
|
1309
1350
|
this.showStatus("Navigated to selected point");
|
|
1310
1351
|
void this.flushCompactionQueue({ willRetry: false });
|
|
@@ -2117,7 +2158,7 @@ export class InteractiveMode {
|
|
|
2117
2158
|
// Global debug handler on TUI (works regardless of focus)
|
|
2118
2159
|
this.ui.onDebug = () => this.handleDebugCommand();
|
|
2119
2160
|
this.defaultEditor.onAction("app.model.select", () => void this.showModelSelector());
|
|
2120
|
-
|
|
2161
|
+
// lunr: tool/thinking expand is per-item click; ctrl+o is not bound (tree filter still uses ctrl+o).
|
|
2121
2162
|
this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
|
|
2122
2163
|
this.defaultEditor.onAction("app.editor.external", () => this.openExternalEditor());
|
|
2123
2164
|
this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand());
|
|
@@ -2135,8 +2176,8 @@ export class InteractiveMode {
|
|
|
2135
2176
|
}
|
|
2136
2177
|
};
|
|
2137
2178
|
// Handle clipboard paste (keybinding: app.clipboard.pasteImage, Alt+V on Windows —
|
|
2138
|
-
// Ctrl+V is owned by the terminal and never reaches us). Images
|
|
2139
|
-
// otherwise, paste plain text from the system clipboard.
|
|
2179
|
+
// Ctrl+V is owned by the terminal and never reaches us). Images become `[image_n]`
|
|
2180
|
+
// chips; otherwise, paste plain text from the system clipboard.
|
|
2140
2181
|
this.defaultEditor.onPasteImage = () => {
|
|
2141
2182
|
void this.handleClipboardPaste();
|
|
2142
2183
|
};
|
|
@@ -2171,18 +2212,104 @@ export class InteractiveMode {
|
|
|
2171
2212
|
}
|
|
2172
2213
|
});
|
|
2173
2214
|
}
|
|
2215
|
+
writeClipboardImageFile(image) {
|
|
2216
|
+
const ext = extensionForImageMimeType(image.mimeType) ?? "png";
|
|
2217
|
+
const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;
|
|
2218
|
+
const filePath = path.join(os.tmpdir(), fileName);
|
|
2219
|
+
fs.writeFileSync(filePath, Buffer.from(image.bytes));
|
|
2220
|
+
return { path: filePath, mimeType: image.mimeType };
|
|
2221
|
+
}
|
|
2222
|
+
insertImageChip(attachment) {
|
|
2223
|
+
if (this.editor.insertImageMarker) {
|
|
2224
|
+
return this.editor.insertImageMarker(attachment);
|
|
2225
|
+
}
|
|
2226
|
+
const existing = collectImageMarkerIds(this.editor.getText());
|
|
2227
|
+
const used = new Set([...existing, ...this.fallbackImageAttachments.keys()]);
|
|
2228
|
+
let id = 1;
|
|
2229
|
+
while (used.has(id))
|
|
2230
|
+
id++;
|
|
2231
|
+
this.fallbackImageAttachments.set(id, { id, path: attachment.path, mimeType: attachment.mimeType });
|
|
2232
|
+
this.editor.insertTextAtCursor?.(formatImageMarker(id));
|
|
2233
|
+
return id;
|
|
2234
|
+
}
|
|
2235
|
+
takeSubmittedImages(submittedText) {
|
|
2236
|
+
if (this.editor.takePendingImages) {
|
|
2237
|
+
this.fallbackImageAttachments.clear();
|
|
2238
|
+
return this.editor.takePendingImages();
|
|
2239
|
+
}
|
|
2240
|
+
if (this.editor.getPendingImages) {
|
|
2241
|
+
this.fallbackImageAttachments.clear();
|
|
2242
|
+
return this.editor.getPendingImages();
|
|
2243
|
+
}
|
|
2244
|
+
const pending = [];
|
|
2245
|
+
for (const id of collectImageMarkerIds(submittedText ?? this.editor.getText())) {
|
|
2246
|
+
const attachment = this.fallbackImageAttachments.get(id);
|
|
2247
|
+
if (attachment)
|
|
2248
|
+
pending.push(attachment);
|
|
2249
|
+
}
|
|
2250
|
+
this.fallbackImageAttachments.clear();
|
|
2251
|
+
return pending;
|
|
2252
|
+
}
|
|
2253
|
+
consumeStagedSubmitImages() {
|
|
2254
|
+
const staged = this.stagedSubmitImages;
|
|
2255
|
+
this.stagedSubmitImages = undefined;
|
|
2256
|
+
return staged;
|
|
2257
|
+
}
|
|
2258
|
+
async loadImageAttachments(attachments) {
|
|
2259
|
+
if (attachments.length === 0)
|
|
2260
|
+
return undefined;
|
|
2261
|
+
const images = [];
|
|
2262
|
+
const autoResizeImages = this.settingsManager.getImageAutoResize();
|
|
2263
|
+
for (const attachment of attachments) {
|
|
2264
|
+
try {
|
|
2265
|
+
const bytes = fs.readFileSync(attachment.path);
|
|
2266
|
+
const processed = await processImage(bytes, attachment.mimeType, { autoResizeImages });
|
|
2267
|
+
if (!processed.ok) {
|
|
2268
|
+
this.showStatus(processed.message);
|
|
2269
|
+
continue;
|
|
2270
|
+
}
|
|
2271
|
+
images.push({
|
|
2272
|
+
type: "image",
|
|
2273
|
+
mimeType: processed.mimeType,
|
|
2274
|
+
data: processed.data,
|
|
2275
|
+
});
|
|
2276
|
+
}
|
|
2277
|
+
catch (err) {
|
|
2278
|
+
this.showStatus(`Could not attach ${formatImageMarker(attachment.id)}: ${err instanceof Error ? err.message : String(err)}`);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
return images.length > 0 ? images : undefined;
|
|
2282
|
+
}
|
|
2283
|
+
restoreEditorDraft(text, images) {
|
|
2284
|
+
this.editor.setText(text);
|
|
2285
|
+
if (!images || images.length === 0)
|
|
2286
|
+
return;
|
|
2287
|
+
const ids = collectImageMarkerIds(text);
|
|
2288
|
+
if (ids.length === 0 || !this.editor.restoreImageMarkers)
|
|
2289
|
+
return;
|
|
2290
|
+
const attachments = [];
|
|
2291
|
+
for (let i = 0; i < Math.min(ids.length, images.length); i++) {
|
|
2292
|
+
const id = ids[i];
|
|
2293
|
+
const image = images[i];
|
|
2294
|
+
const saved = this.writeClipboardImageFile({
|
|
2295
|
+
bytes: Buffer.from(image.data, "base64"),
|
|
2296
|
+
mimeType: image.mimeType,
|
|
2297
|
+
});
|
|
2298
|
+
attachments.push({ id, path: saved.path, mimeType: saved.mimeType });
|
|
2299
|
+
}
|
|
2300
|
+
this.editor.restoreImageMarkers(attachments);
|
|
2301
|
+
}
|
|
2302
|
+
restoreEditorFromTreeResult(result) {
|
|
2303
|
+
this.restoreEditorDraft(result.editorText ?? "", result.editorImages);
|
|
2304
|
+
}
|
|
2174
2305
|
async handleClipboardPaste() {
|
|
2175
2306
|
try {
|
|
2176
2307
|
const image = await readClipboardImage();
|
|
2177
2308
|
if (image) {
|
|
2178
|
-
const
|
|
2179
|
-
const
|
|
2180
|
-
const fileName = `pi-clipboard-${crypto.randomUUID()}.${ext}`;
|
|
2181
|
-
const filePath = path.join(tmpDir, fileName);
|
|
2182
|
-
fs.writeFileSync(filePath, Buffer.from(image.bytes));
|
|
2183
|
-
this.editor.insertTextAtCursor?.(filePath);
|
|
2309
|
+
const saved = this.writeClipboardImageFile(image);
|
|
2310
|
+
const id = this.insertImageChip(saved);
|
|
2184
2311
|
this.ui.requestRender();
|
|
2185
|
-
this.showStatus(`Pasted
|
|
2312
|
+
this.showStatus(`Pasted ${formatImageMarker(id)}`);
|
|
2186
2313
|
return;
|
|
2187
2314
|
}
|
|
2188
2315
|
const text = await readClipboardText();
|
|
@@ -2200,8 +2327,11 @@ export class InteractiveMode {
|
|
|
2200
2327
|
setupEditorSubmitHandler() {
|
|
2201
2328
|
this.defaultEditor.onSubmit = async (text) => {
|
|
2202
2329
|
text = text.trim();
|
|
2203
|
-
if (!text)
|
|
2330
|
+
if (!text) {
|
|
2331
|
+
this.takeSubmittedImages(text);
|
|
2204
2332
|
return;
|
|
2333
|
+
}
|
|
2334
|
+
const images = this.consumeStagedSubmitImages() ?? (await this.loadImageAttachments(this.takeSubmittedImages(text)));
|
|
2205
2335
|
this.ui.setChatScroll(0);
|
|
2206
2336
|
// Handle commands
|
|
2207
2337
|
if (text === "/settings") {
|
|
@@ -2422,7 +2552,7 @@ export class InteractiveMode {
|
|
|
2422
2552
|
await this.promptAfterDeferredBuiltins(text);
|
|
2423
2553
|
}
|
|
2424
2554
|
else {
|
|
2425
|
-
this.queueCompactionMessage(text, "steer");
|
|
2555
|
+
this.queueCompactionMessage(text, "steer", images);
|
|
2426
2556
|
}
|
|
2427
2557
|
return;
|
|
2428
2558
|
}
|
|
@@ -2431,7 +2561,7 @@ export class InteractiveMode {
|
|
|
2431
2561
|
if (this.session.isStreaming) {
|
|
2432
2562
|
this.editor.addToHistory?.(text);
|
|
2433
2563
|
this.editor.setText("");
|
|
2434
|
-
await this.promptAfterDeferredBuiltins(text, { streamingBehavior: "steer" });
|
|
2564
|
+
await this.promptAfterDeferredBuiltins(text, { streamingBehavior: "steer", images });
|
|
2435
2565
|
this.updatePendingMessagesDisplay();
|
|
2436
2566
|
this.ui.requestRender();
|
|
2437
2567
|
return;
|
|
@@ -2440,10 +2570,10 @@ export class InteractiveMode {
|
|
|
2440
2570
|
// First, move any pending bash components to chat
|
|
2441
2571
|
this.flushPendingBashComponents();
|
|
2442
2572
|
if (this.onInputCallback) {
|
|
2443
|
-
this.onInputCallback(text);
|
|
2573
|
+
this.onInputCallback({ text, images });
|
|
2444
2574
|
}
|
|
2445
2575
|
else {
|
|
2446
|
-
this.pendingUserInputs.push(text);
|
|
2576
|
+
this.pendingUserInputs.push({ text, images });
|
|
2447
2577
|
}
|
|
2448
2578
|
this.editor.addToHistory?.(text);
|
|
2449
2579
|
};
|
|
@@ -3156,9 +3286,9 @@ export class InteractiveMode {
|
|
|
3156
3286
|
return queuedInput;
|
|
3157
3287
|
}
|
|
3158
3288
|
return new Promise((resolve) => {
|
|
3159
|
-
this.onInputCallback = (
|
|
3289
|
+
this.onInputCallback = (input) => {
|
|
3160
3290
|
this.onInputCallback = undefined;
|
|
3161
|
-
resolve(
|
|
3291
|
+
resolve(input);
|
|
3162
3292
|
};
|
|
3163
3293
|
});
|
|
3164
3294
|
}
|
|
@@ -3194,6 +3324,11 @@ export class InteractiveMode {
|
|
|
3194
3324
|
return;
|
|
3195
3325
|
this.isShuttingDown = true;
|
|
3196
3326
|
this.stopSmoothStreaming();
|
|
3327
|
+
if (this.planUsageTimer) {
|
|
3328
|
+
clearInterval(this.planUsageTimer);
|
|
3329
|
+
this.planUsageTimer = undefined;
|
|
3330
|
+
}
|
|
3331
|
+
getUsageServiceBridge()?.setOnUpdate(undefined);
|
|
3197
3332
|
// Keep signal handlers registered until terminal cleanup has completed.
|
|
3198
3333
|
// `signal-exit` checks the listener list during the same SIGTERM/SIGHUP
|
|
3199
3334
|
// dispatch and re-sends the signal if only its own listeners remain.
|
|
@@ -3386,21 +3521,25 @@ export class InteractiveMode {
|
|
|
3386
3521
|
await this.promptAfterDeferredBuiltins(text);
|
|
3387
3522
|
}
|
|
3388
3523
|
else {
|
|
3389
|
-
this.
|
|
3524
|
+
const images = await this.loadImageAttachments(this.takeSubmittedImages(text));
|
|
3525
|
+
this.queueCompactionMessage(text, "followUp", images);
|
|
3390
3526
|
}
|
|
3391
3527
|
return;
|
|
3392
3528
|
}
|
|
3393
3529
|
// Alt+Enter queues a follow-up message (waits until agent finishes)
|
|
3394
3530
|
// This handles extension commands (execute immediately), prompt template expansion, and queueing
|
|
3395
3531
|
if (this.session.isStreaming) {
|
|
3532
|
+
const images = await this.loadImageAttachments(this.takeSubmittedImages(text));
|
|
3396
3533
|
this.editor.addToHistory?.(text);
|
|
3397
3534
|
this.editor.setText("");
|
|
3398
|
-
await this.promptAfterDeferredBuiltins(text, { streamingBehavior: "followUp" });
|
|
3535
|
+
await this.promptAfterDeferredBuiltins(text, { streamingBehavior: "followUp", images });
|
|
3399
3536
|
this.updatePendingMessagesDisplay();
|
|
3400
3537
|
this.ui.requestRender();
|
|
3401
3538
|
}
|
|
3402
3539
|
// If not streaming, Alt+Enter acts like regular Enter (trigger onSubmit)
|
|
3403
3540
|
else if (this.editor.onSubmit) {
|
|
3541
|
+
const images = await this.loadImageAttachments(this.takeSubmittedImages(text));
|
|
3542
|
+
this.stagedSubmitImages = images;
|
|
3404
3543
|
this.editor.setText("");
|
|
3405
3544
|
this.editor.onSubmit(text);
|
|
3406
3545
|
}
|
|
@@ -3652,8 +3791,8 @@ export class InteractiveMode {
|
|
|
3652
3791
|
}
|
|
3653
3792
|
return allQueued.length;
|
|
3654
3793
|
}
|
|
3655
|
-
queueCompactionMessage(text, mode) {
|
|
3656
|
-
this.compactionQueuedMessages.push({ text, mode });
|
|
3794
|
+
queueCompactionMessage(text, mode, images) {
|
|
3795
|
+
this.compactionQueuedMessages.push({ text, mode, images });
|
|
3657
3796
|
this.editor.addToHistory?.(text);
|
|
3658
3797
|
this.editor.setText("");
|
|
3659
3798
|
this.updatePendingMessagesDisplay();
|
|
@@ -3688,10 +3827,10 @@ export class InteractiveMode {
|
|
|
3688
3827
|
await this.promptAfterDeferredBuiltins(message.text);
|
|
3689
3828
|
}
|
|
3690
3829
|
else if (message.mode === "followUp") {
|
|
3691
|
-
await this.session.followUp(message.text);
|
|
3830
|
+
await this.session.followUp(message.text, message.images);
|
|
3692
3831
|
}
|
|
3693
3832
|
else {
|
|
3694
|
-
await this.session.steer(message.text);
|
|
3833
|
+
await this.session.steer(message.text, message.images);
|
|
3695
3834
|
}
|
|
3696
3835
|
}
|
|
3697
3836
|
this.updatePendingMessagesDisplay();
|
|
@@ -3714,7 +3853,9 @@ export class InteractiveMode {
|
|
|
3714
3853
|
await this.promptAfterDeferredBuiltins(message.text);
|
|
3715
3854
|
}
|
|
3716
3855
|
// Send first prompt (starts streaming)
|
|
3717
|
-
const promptPromise = this.promptAfterDeferredBuiltins(firstPrompt.text
|
|
3856
|
+
const promptPromise = this.promptAfterDeferredBuiltins(firstPrompt.text, {
|
|
3857
|
+
images: firstPrompt.images,
|
|
3858
|
+
}).catch((error) => {
|
|
3718
3859
|
restoreQueue(error);
|
|
3719
3860
|
});
|
|
3720
3861
|
// Queue remaining messages
|
|
@@ -3723,10 +3864,10 @@ export class InteractiveMode {
|
|
|
3723
3864
|
await this.promptAfterDeferredBuiltins(message.text);
|
|
3724
3865
|
}
|
|
3725
3866
|
else if (message.mode === "followUp") {
|
|
3726
|
-
await this.session.followUp(message.text);
|
|
3867
|
+
await this.session.followUp(message.text, message.images);
|
|
3727
3868
|
}
|
|
3728
3869
|
else {
|
|
3729
|
-
await this.session.steer(message.text);
|
|
3870
|
+
await this.session.steer(message.text, message.images);
|
|
3730
3871
|
}
|
|
3731
3872
|
}
|
|
3732
3873
|
this.updatePendingMessagesDisplay();
|
|
@@ -3801,6 +3942,7 @@ export class InteractiveMode {
|
|
|
3801
3942
|
showTerminalProgress: this.settingsManager.getShowTerminalProgress(),
|
|
3802
3943
|
modelTiers: this.settingsManager.getModelTiers(),
|
|
3803
3944
|
memoryCharCap: this.settingsManager.getMemoryCharCap(),
|
|
3945
|
+
behaviorPreset: reconcileBehaviorPreset(this.settingsManager),
|
|
3804
3946
|
searchCurator: getSearchCuratorSetting(),
|
|
3805
3947
|
// lunr: TUI customize settings
|
|
3806
3948
|
gutterRail: this.settingsManager.getGutterRail(),
|
|
@@ -3809,7 +3951,12 @@ export class InteractiveMode {
|
|
|
3809
3951
|
footerLsp: this.settingsManager.getFooterLsp(),
|
|
3810
3952
|
footerContext: this.settingsManager.getFooterContext(),
|
|
3811
3953
|
footerTokens: this.settingsManager.getFooterTokens(),
|
|
3954
|
+
footerTps: this.settingsManager.getFooterTps(),
|
|
3812
3955
|
footerStatuses: this.settingsManager.getFooterStatuses(),
|
|
3956
|
+
footerGit: this.settingsManager.getFooterGit(),
|
|
3957
|
+
footerPlan: this.settingsManager.getFooterPlan(),
|
|
3958
|
+
footerPlanBar: this.settingsManager.getFooterPlanBar(),
|
|
3959
|
+
planUsageWindow: this.settingsManager.getPlanUsageWindow(),
|
|
3813
3960
|
defaultPermissionMode: this.settingsManager.getDefaultPermissionMode(),
|
|
3814
3961
|
rollbackEnabled: this.settingsManager.getRollbackEnabled(),
|
|
3815
3962
|
rollbackTurns: this.settingsManager.getRollbackTurns(),
|
|
@@ -3973,9 +4120,28 @@ export class InteractiveMode {
|
|
|
3973
4120
|
onModelTierModelChange: (tier, model) => {
|
|
3974
4121
|
this.settingsManager.setTierModel(tier, model);
|
|
3975
4122
|
},
|
|
4123
|
+
onModelTierThinkingChange: (tier, level) => {
|
|
4124
|
+
this.settingsManager.setTierThinking(tier, level);
|
|
4125
|
+
},
|
|
4126
|
+
getTierThinkingLevels: (tier) => {
|
|
4127
|
+
const model = this.resolveModelReference(this.settingsManager.getTierModel(tier));
|
|
4128
|
+
if (model)
|
|
4129
|
+
return getSupportedThinkingLevels(model);
|
|
4130
|
+
return this.session.getAvailableThinkingLevels();
|
|
4131
|
+
},
|
|
3976
4132
|
onMemoryCharCapChange: (cap) => {
|
|
3977
4133
|
this.settingsManager.setMemoryCharCap(cap);
|
|
3978
4134
|
},
|
|
4135
|
+
onBehaviorPresetChange: (preset) => {
|
|
4136
|
+
const result = applyBehaviorPreset(this.settingsManager, preset, getAgentDir(), {
|
|
4137
|
+
overwrite: true,
|
|
4138
|
+
});
|
|
4139
|
+
if (result.ok) {
|
|
4140
|
+
this.showStatus(preset === "custom"
|
|
4141
|
+
? "Behavior preset: custom (file is source of truth)"
|
|
4142
|
+
: `Behavior preset: ${preset}`);
|
|
4143
|
+
}
|
|
4144
|
+
},
|
|
3979
4145
|
onSearchCuratorChange: (setting) => {
|
|
3980
4146
|
if (!setSearchCuratorSetting(setting)) {
|
|
3981
4147
|
this.showError("pi-web-access is not loaded; curator setting unavailable.");
|
|
@@ -4000,9 +4166,24 @@ export class InteractiveMode {
|
|
|
4000
4166
|
onFooterTokensChange: (enabled) => {
|
|
4001
4167
|
this.settingsManager.setFooterTokens(enabled);
|
|
4002
4168
|
},
|
|
4169
|
+
onFooterTpsChange: (enabled) => {
|
|
4170
|
+
this.settingsManager.setFooterTps(enabled);
|
|
4171
|
+
},
|
|
4003
4172
|
onFooterStatusesChange: (enabled) => {
|
|
4004
4173
|
this.settingsManager.setFooterStatuses(enabled);
|
|
4005
4174
|
},
|
|
4175
|
+
onFooterGitChange: (enabled) => {
|
|
4176
|
+
this.settingsManager.setFooterGit(enabled);
|
|
4177
|
+
},
|
|
4178
|
+
onFooterPlanChange: (enabled) => {
|
|
4179
|
+
this.settingsManager.setFooterPlan(enabled);
|
|
4180
|
+
},
|
|
4181
|
+
onFooterPlanBarChange: (enabled) => {
|
|
4182
|
+
this.settingsManager.setFooterPlanBar(enabled);
|
|
4183
|
+
},
|
|
4184
|
+
onPlanUsageWindowChange: (window) => {
|
|
4185
|
+
this.settingsManager.setPlanUsageWindow(window);
|
|
4186
|
+
},
|
|
4006
4187
|
onDefaultPermissionModeChange: (mode) => {
|
|
4007
4188
|
this.settingsManager.setDefaultPermissionMode(mode);
|
|
4008
4189
|
},
|
|
@@ -4606,7 +4787,7 @@ export class InteractiveMode {
|
|
|
4606
4787
|
this.chatContainer.clear();
|
|
4607
4788
|
this.renderInitialMessages();
|
|
4608
4789
|
if (result.editorText && !this.editor.getText().trim()) {
|
|
4609
|
-
this.
|
|
4790
|
+
this.restoreEditorFromTreeResult(result);
|
|
4610
4791
|
}
|
|
4611
4792
|
this.showStatus("Navigated to selected point");
|
|
4612
4793
|
void this.flushCompactionQueue({ willRetry: false });
|
|
@@ -5425,7 +5606,7 @@ export class InteractiveMode {
|
|
|
5425
5606
|
return;
|
|
5426
5607
|
}
|
|
5427
5608
|
this.swarmMode = true;
|
|
5428
|
-
this.setExtensionStatus("swarm", "swarm
|
|
5609
|
+
this.setExtensionStatus("swarm", "swarm");
|
|
5429
5610
|
await this.sendUserMessageAfterDeferredBuiltins(buildSwarmPrompt(task));
|
|
5430
5611
|
}
|
|
5431
5612
|
async handleResearchCommand(args) {
|
|
@@ -5523,7 +5704,7 @@ export class InteractiveMode {
|
|
|
5523
5704
|
this.chatContainer.clear();
|
|
5524
5705
|
this.renderInitialMessages();
|
|
5525
5706
|
void this.flushCompactionQueue({ willRetry: false });
|
|
5526
|
-
return { editorText: result.editorText };
|
|
5707
|
+
return { editorText: result.editorText, editorImages: result.editorImages };
|
|
5527
5708
|
}
|
|
5528
5709
|
catch (error) {
|
|
5529
5710
|
this.showError(error instanceof Error ? error.message : String(error));
|
|
@@ -5540,7 +5721,10 @@ export class InteractiveMode {
|
|
|
5540
5721
|
const result = await this.rewindLastTurn("edit");
|
|
5541
5722
|
if (!result)
|
|
5542
5723
|
return;
|
|
5543
|
-
this.
|
|
5724
|
+
this.restoreEditorFromTreeResult({
|
|
5725
|
+
editorText: result.editorText ?? "",
|
|
5726
|
+
editorImages: result.editorImages,
|
|
5727
|
+
});
|
|
5544
5728
|
this.showStatus("Editing last message. /redo to restore.");
|
|
5545
5729
|
}
|
|
5546
5730
|
async handleRedoCommand() {
|
|
@@ -5563,7 +5747,7 @@ export class InteractiveMode {
|
|
|
5563
5747
|
this.chatContainer.clear();
|
|
5564
5748
|
this.renderInitialMessages();
|
|
5565
5749
|
if (result.editorText && !this.editor.getText().trim()) {
|
|
5566
|
-
this.
|
|
5750
|
+
this.restoreEditorFromTreeResult(result);
|
|
5567
5751
|
}
|
|
5568
5752
|
this.showStatus("Redone");
|
|
5569
5753
|
void this.flushCompactionQueue({ willRetry: false });
|
|
@@ -6419,7 +6603,7 @@ export class InteractiveMode {
|
|
|
6419
6603
|
const cyclePermissionMode = this.getAppKeyDisplay("app.mode.cycle");
|
|
6420
6604
|
const cycleModelForward = this.getAppKeyDisplay("app.model.cycleForward");
|
|
6421
6605
|
const selectModel = this.getAppKeyDisplay("app.model.select");
|
|
6422
|
-
const expandTools =
|
|
6606
|
+
const expandTools = "click";
|
|
6423
6607
|
const toggleThinking = this.getAppKeyDisplay("app.thinking.toggle");
|
|
6424
6608
|
const externalEditor = this.getAppKeyDisplay("app.editor.external");
|
|
6425
6609
|
const cycleModelBackward = this.getAppKeyDisplay("app.model.cycleBackward");
|
|
@@ -6464,7 +6648,7 @@ export class InteractiveMode {
|
|
|
6464
6648
|
| \`${cyclePermissionMode}\` | Cycle permission mode |
|
|
6465
6649
|
${cycleThinkingLevel ? `| \`${cycleThinkingLevel}\` | Cycle thinking level |\n` : ""}| \`${cycleModelForward}\` / \`${cycleModelBackward}\` | Cycle models |
|
|
6466
6650
|
| \`${selectModel}\` | Open model selector |
|
|
6467
|
-
| \`${expandTools}\` |
|
|
6651
|
+
| \`${expandTools}\` | Expand or collapse a thinking/tool card |
|
|
6468
6652
|
| \`${toggleThinking}\` | Toggle thinking block visibility |
|
|
6469
6653
|
| \`${externalEditor}\` | Edit message in external editor |
|
|
6470
6654
|
| \`${copyMessage}\` | Copy last assistant message |
|