@earendil-works/pi-coding-agent 0.81.1 → 0.82.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/README.md +13 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session.d.ts +11 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +7 -8
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +11 -3
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +4 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +7 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-config.d.ts +30 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +6 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -2
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +1 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +20 -3
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/model-runtime.d.ts +0 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +3 -5
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/remote-catalog-provider.d.ts +1 -1
- package/dist/core/remote-catalog-provider.d.ts.map +1 -1
- package/dist/core/remote-catalog-provider.js +24 -11
- package/dist/core/remote-catalog-provider.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +3 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +34 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js +3 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +7 -2
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +3 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +10 -2
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/extension-editor.d.ts +1 -2
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +16 -46
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +22 -13
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/external-editor.d.ts +12 -0
- package/dist/modes/interactive/external-editor.d.ts.map +1 -0
- package/dist/modes/interactive/external-editor.js +37 -0
- package/dist/modes/interactive/external-editor.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +52 -58
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +19 -8
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +3 -1
- package/dist/utils/version-check.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +5 -2
- package/docs/environment-variables.md +88 -0
- package/docs/extensions.md +13 -5
- package/docs/index.md +1 -0
- package/docs/models.md +6 -2
- package/docs/providers.md +8 -1
- package/docs/rpc.md +23 -6
- package/docs/settings.md +1 -1
- package/docs/usage.md +0 -13
- package/examples/extensions/custom-compaction.ts +3 -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/handoff.ts +9 -1
- package/examples/extensions/message-renderer.ts +2 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +3 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +16 -15
- package/package.json +5 -4
|
@@ -17,7 +17,7 @@ import { FooterDataProvider } from "../../core/footer-data-provider.js";
|
|
|
17
17
|
import { configureHttpDispatcher, formatHttpIdleTimeoutMs } from "../../core/http-dispatcher.js";
|
|
18
18
|
import { KeybindingsManager } from "../../core/keybindings.js";
|
|
19
19
|
import { createCompactionSummaryMessage } from "../../core/messages.js";
|
|
20
|
-
import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope } from "../../core/model-resolver.js";
|
|
20
|
+
import { defaultModelPerProvider, findExactModelReferenceMatch, resolveModelScope, resolveModelScopeWithDiagnostics, } from "../../core/model-resolver.js";
|
|
21
21
|
import { DefaultPackageManager } from "../../core/package-manager.js";
|
|
22
22
|
import { formatMissingSessionCwdPrompt, MissingSessionCwdError } from "../../core/session-cwd.js";
|
|
23
23
|
import { SessionManager, sessionEntryToContextMessages } from "../../core/session-manager.js";
|
|
@@ -64,6 +64,7 @@ import { TreeSelectorComponent } from "./components/tree-selector.js";
|
|
|
64
64
|
import { TrustSelectorComponent } from "./components/trust-selector.js";
|
|
65
65
|
import { UserMessageComponent } from "./components/user-message.js";
|
|
66
66
|
import { UserMessageSelectorComponent } from "./components/user-message-selector.js";
|
|
67
|
+
import { editInExternalEditor } from "./external-editor.js";
|
|
67
68
|
import { getModelSearchText } from "./model-search.js";
|
|
68
69
|
import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMarkdownTheme, getThemeByName, onThemeChange, setRegisteredThemes, stopThemeWatcher, Theme, theme, } from "./theme/theme.js";
|
|
69
70
|
import { InteractiveThemeController } from "./theme/theme-controller.js";
|
|
@@ -272,7 +273,7 @@ export class InteractiveMode {
|
|
|
272
273
|
await this.rebindCurrentSession({ renderBeforeBind: true });
|
|
273
274
|
});
|
|
274
275
|
this.version = VERSION;
|
|
275
|
-
this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor());
|
|
276
|
+
this.ui = new TUI(new ProcessTerminal(), this.settingsManager.getShowHardwareCursor(), getAgentDir());
|
|
276
277
|
this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
|
|
277
278
|
this.headerContainer = new Container();
|
|
278
279
|
this.loadedResourcesContainer = new Container();
|
|
@@ -797,8 +798,15 @@ export class InteractiveMode {
|
|
|
797
798
|
* Get a short path relative to the package root for display.
|
|
798
799
|
*/
|
|
799
800
|
getShortPath(fullPath, sourceInfo) {
|
|
801
|
+
const normalizedFullPath = fullPath.replace(/\\/g, "/");
|
|
800
802
|
const baseDir = sourceInfo?.baseDir;
|
|
801
803
|
if (baseDir && this.isPackageSource(sourceInfo)) {
|
|
804
|
+
const normalizedBaseDir = baseDir.replace(/\\/g, "/");
|
|
805
|
+
const npmRootMatch = normalizedBaseDir.match(/^(.*\/node_modules)\/(@?[^/]+(?:\/[^/]+)?)$/);
|
|
806
|
+
// If fullPath is under the same node_modules root as baseDir, preserve that relative topology.
|
|
807
|
+
if (npmRootMatch?.[1] && normalizedFullPath.startsWith(`${npmRootMatch[1]}/`)) {
|
|
808
|
+
return path.posix.relative(normalizedBaseDir, normalizedFullPath);
|
|
809
|
+
}
|
|
802
810
|
const relativePath = path.relative(path.resolve(baseDir), path.resolve(fullPath));
|
|
803
811
|
if (relativePath &&
|
|
804
812
|
relativePath !== "." &&
|
|
@@ -809,11 +817,11 @@ export class InteractiveMode {
|
|
|
809
817
|
}
|
|
810
818
|
}
|
|
811
819
|
const source = sourceInfo?.source ?? "";
|
|
812
|
-
const npmMatch =
|
|
820
|
+
const npmMatch = normalizedFullPath.match(/node_modules\/(@?[^/]+(?:\/[^/]+)?)\/(.*)/);
|
|
813
821
|
if (npmMatch && source.startsWith("npm:")) {
|
|
814
822
|
return npmMatch[2];
|
|
815
823
|
}
|
|
816
|
-
const gitMatch =
|
|
824
|
+
const gitMatch = normalizedFullPath.match(/git\/[^/]+\/[^/]+\/(.*)/);
|
|
817
825
|
if (gitMatch && source.startsWith("git:")) {
|
|
818
826
|
return gitMatch[1];
|
|
819
827
|
}
|
|
@@ -1353,6 +1361,7 @@ export class InteractiveMode {
|
|
|
1353
1361
|
sessionManager: this.sessionManager,
|
|
1354
1362
|
modelRegistry: extensionRunner.getModelRegistry(),
|
|
1355
1363
|
model: this.session.model,
|
|
1364
|
+
thinkingLevel: this.session.thinkingLevel,
|
|
1356
1365
|
isIdle: () => this.session.isIdle,
|
|
1357
1366
|
isProjectTrusted: () => this.settingsManager.isProjectTrusted(),
|
|
1358
1367
|
signal: this.session.agent.signal,
|
|
@@ -2038,7 +2047,7 @@ export class InteractiveMode {
|
|
|
2038
2047
|
this.defaultEditor.onAction("app.model.select", () => this.showModelSelector());
|
|
2039
2048
|
this.defaultEditor.onAction("app.tools.expand", () => this.toggleToolOutputExpansion());
|
|
2040
2049
|
this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
|
|
2041
|
-
this.defaultEditor.onAction("app.editor.external", () => this.
|
|
2050
|
+
this.defaultEditor.onAction("app.editor.external", () => void this.handleOpenExternalEditor());
|
|
2042
2051
|
this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand());
|
|
2043
2052
|
this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
|
|
2044
2053
|
this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
|
|
@@ -2400,6 +2409,9 @@ export class InteractiveMode {
|
|
|
2400
2409
|
}
|
|
2401
2410
|
this.ui.requestRender();
|
|
2402
2411
|
break;
|
|
2412
|
+
case "bash_execution_update":
|
|
2413
|
+
// The bash execution callback handles TUI output rendering.
|
|
2414
|
+
break;
|
|
2403
2415
|
case "tool_execution_start": {
|
|
2404
2416
|
let component = this.pendingTools.get(event.toolCallId);
|
|
2405
2417
|
if (!component) {
|
|
@@ -2610,7 +2622,7 @@ export class InteractiveMode {
|
|
|
2610
2622
|
case "custom": {
|
|
2611
2623
|
if (message.display) {
|
|
2612
2624
|
const renderer = this.session.extensionRunner.getMessageRenderer(message.customType);
|
|
2613
|
-
const component = new CustomMessageComponent(message, renderer, this.getMarkdownThemeWithSettings());
|
|
2625
|
+
const component = new CustomMessageComponent(message, renderer, this.getMarkdownThemeWithSettings(), this.outputPad);
|
|
2614
2626
|
component.setExpanded(this.toolOutputExpanded);
|
|
2615
2627
|
this.chatContainer.addChild(component);
|
|
2616
2628
|
}
|
|
@@ -3122,51 +3134,21 @@ export class InteractiveMode {
|
|
|
3122
3134
|
}
|
|
3123
3135
|
this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
|
|
3124
3136
|
}
|
|
3125
|
-
async
|
|
3137
|
+
async handleOpenExternalEditor() {
|
|
3126
3138
|
const editorCmd = this.settingsManager.getExternalEditorCommand();
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
return;
|
|
3130
|
-
}
|
|
3131
|
-
const currentText = this.editor.getExpandedText?.() ?? this.editor.getText();
|
|
3132
|
-
const tmpFile = path.join(os.tmpdir(), `pi-editor-${Date.now()}.pi.md`);
|
|
3139
|
+
const content = this.editor.getExpandedText?.() ?? this.editor.getText();
|
|
3140
|
+
this.ui.stop();
|
|
3133
3141
|
try {
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
this.ui.stop();
|
|
3138
|
-
// Split by space to support editor arguments (e.g., "code --wait")
|
|
3139
|
-
const [editor, ...editorArgs] = editorCmd.split(" ");
|
|
3140
|
-
process.stdout.write(`Launching external editor: ${editorCmd}\nPi will resume when the editor exits.\n`);
|
|
3141
|
-
// Do not use spawnSync here. On Windows, synchronous child_process calls can keep
|
|
3142
|
-
// Node/libuv's console input read active after ui.stop() pauses stdin, racing
|
|
3143
|
-
// vim/nvim for the console input buffer until Ctrl+C cancels the pending read.
|
|
3144
|
-
const status = await new Promise((resolve) => {
|
|
3145
|
-
const child = spawn(editor, [...editorArgs, tmpFile], {
|
|
3146
|
-
stdio: "inherit",
|
|
3147
|
-
shell: process.platform === "win32",
|
|
3148
|
-
});
|
|
3149
|
-
child.on("error", () => resolve(null));
|
|
3150
|
-
child.on("close", (code) => resolve(code));
|
|
3142
|
+
const result = await editInExternalEditor({
|
|
3143
|
+
command: editorCmd,
|
|
3144
|
+
content,
|
|
3151
3145
|
});
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
const newContent = fs.readFileSync(tmpFile, "utf-8").replace(/\n$/, "");
|
|
3155
|
-
this.editor.setText(newContent);
|
|
3146
|
+
if (result.status === "complete") {
|
|
3147
|
+
this.editor.setText(result.content);
|
|
3156
3148
|
}
|
|
3157
|
-
// On non-zero exit, keep original text (no action needed)
|
|
3158
3149
|
}
|
|
3159
3150
|
finally {
|
|
3160
|
-
// Clean up temp file
|
|
3161
|
-
try {
|
|
3162
|
-
fs.unlinkSync(tmpFile);
|
|
3163
|
-
}
|
|
3164
|
-
catch {
|
|
3165
|
-
// Ignore cleanup errors
|
|
3166
|
-
}
|
|
3167
|
-
// Restart TUI
|
|
3168
3151
|
this.ui.start();
|
|
3169
|
-
// Force full re-render since external editor uses alternate screen
|
|
3170
3152
|
this.ui.requestRender(true);
|
|
3171
3153
|
}
|
|
3172
3154
|
}
|
|
@@ -3543,7 +3525,9 @@ export class InteractiveMode {
|
|
|
3543
3525
|
this.outputPad = padding;
|
|
3544
3526
|
if (this.streamingComponent || this.session.isStreaming) {
|
|
3545
3527
|
for (const child of this.chatContainer.children) {
|
|
3546
|
-
if (child instanceof AssistantMessageComponent ||
|
|
3528
|
+
if (child instanceof AssistantMessageComponent ||
|
|
3529
|
+
child instanceof CustomMessageComponent ||
|
|
3530
|
+
child instanceof UserMessageComponent) {
|
|
3547
3531
|
child.setOutputPad(padding);
|
|
3548
3532
|
}
|
|
3549
3533
|
}
|
|
@@ -3728,12 +3712,17 @@ export class InteractiveMode {
|
|
|
3728
3712
|
// Get all available models
|
|
3729
3713
|
await this.session.modelRuntime.refresh();
|
|
3730
3714
|
const allModels = [...(await this.session.modelRuntime.getAvailable())];
|
|
3731
|
-
|
|
3715
|
+
const allModelIds = new Set(allModels.map((model) => `${model.provider}/${model.id}`));
|
|
3716
|
+
const configuredPatterns = this.settingsManager.getEnabledModels();
|
|
3717
|
+
const sessionScopedModels = this.session.scopedModels;
|
|
3718
|
+
if (allModels.length === 0 && !configuredPatterns?.length && sessionScopedModels.length === 0) {
|
|
3732
3719
|
this.showStatus("No models available");
|
|
3733
3720
|
return;
|
|
3734
3721
|
}
|
|
3722
|
+
const configuredScope = configuredPatterns?.length
|
|
3723
|
+
? await resolveModelScopeWithDiagnostics(configuredPatterns, this.session.modelRuntime)
|
|
3724
|
+
: undefined;
|
|
3735
3725
|
// Check if session has scoped models (from previous session-only changes or CLI --models)
|
|
3736
|
-
const sessionScopedModels = this.session.scopedModels;
|
|
3737
3726
|
const hasSessionScope = sessionScopedModels.length > 0;
|
|
3738
3727
|
// Build enabled model IDs from session state or settings
|
|
3739
3728
|
let currentEnabledIds = null;
|
|
@@ -3741,18 +3730,22 @@ export class InteractiveMode {
|
|
|
3741
3730
|
// Use current session's scoped models
|
|
3742
3731
|
currentEnabledIds = sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
|
|
3743
3732
|
}
|
|
3744
|
-
else {
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3733
|
+
else if (configuredScope) {
|
|
3734
|
+
currentEnabledIds = configuredScope.scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
|
|
3735
|
+
}
|
|
3736
|
+
for (const diagnostic of configuredScope?.diagnostics ?? []) {
|
|
3737
|
+
if (diagnostic.code !== "no-match")
|
|
3738
|
+
continue;
|
|
3739
|
+
currentEnabledIds ??= [];
|
|
3740
|
+
if (!currentEnabledIds.includes(diagnostic.pattern))
|
|
3741
|
+
currentEnabledIds.push(diagnostic.pattern);
|
|
3751
3742
|
}
|
|
3752
3743
|
// Helper to update session's scoped models (session-only, no persist)
|
|
3753
3744
|
const updateSessionModels = async (enabledIds) => {
|
|
3754
3745
|
currentEnabledIds = enabledIds === null ? null : [...enabledIds];
|
|
3755
|
-
|
|
3746
|
+
const hasEnabledAvailableModel = enabledIds?.some((id) => allModelIds.has(id)) ?? false;
|
|
3747
|
+
const allAvailableModelsEnabled = enabledIds !== null && [...allModelIds].every((id) => enabledIds.includes(id));
|
|
3748
|
+
if (enabledIds && hasEnabledAvailableModel && !allAvailableModelsEnabled) {
|
|
3756
3749
|
const newScopedModels = await resolveModelScope(enabledIds, this.session.modelRuntime);
|
|
3757
3750
|
this.session.setScopedModels(newScopedModels.map((sm) => ({
|
|
3758
3751
|
model: sm.model,
|
|
@@ -3776,9 +3769,10 @@ export class InteractiveMode {
|
|
|
3776
3769
|
},
|
|
3777
3770
|
onPersist: (enabledIds) => {
|
|
3778
3771
|
// Persist to settings
|
|
3779
|
-
const
|
|
3780
|
-
|
|
3781
|
-
|
|
3772
|
+
const allEnabled = enabledIds !== null &&
|
|
3773
|
+
enabledIds.length === allModels.length &&
|
|
3774
|
+
enabledIds.every((id) => allModelIds.has(id));
|
|
3775
|
+
const newPatterns = enabledIds === null || allEnabled ? undefined : enabledIds;
|
|
3782
3776
|
this.settingsManager.setEnabledModels(newPatterns ? [...newPatterns] : undefined);
|
|
3783
3777
|
this.showStatus("Model selection saved to settings");
|
|
3784
3778
|
},
|