@psnext/slingcli 2.5.20260725-1 → 2.5.20260727-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/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
- package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +8 -3
- package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.js +37 -35
- package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +11 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +8 -3
- package/node_modules/@earendil-works/pi-ai/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +13 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/remote-catalog-provider.js +19 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +3 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +4 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/provider.js +6 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/custom-message.js +10 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +22 -13
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +38 -27
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +12 -12
- package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -5
- package/node_modules/@earendil-works/pi-server/package.json +2 -2
- package/node_modules/@earendil-works/pi-tui/dist/tui.js +1 -1
- package/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/package.json +7 -7
- package/slingshot/index.js +164 -164
|
@@ -55,22 +55,39 @@ export function withRemoteCatalog(provider, catalogBaseUrl = DEFAULT_CATALOG_BAS
|
|
|
55
55
|
Date.now() - stored.checkedAt < REMOTE_CATALOG_REFRESH_INTERVAL_MS) {
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
|
+
// Only revalidate when a cached body backs the validator, so a 304 can never
|
|
59
|
+
// leave the overlay empty.
|
|
60
|
+
const validator = stored?.models.length ? stored.etag : undefined;
|
|
58
61
|
const url = new URL(`/api/models/providers/${encodeURIComponent(provider.id)}`, catalogBaseUrl);
|
|
59
62
|
const response = await fetch(url, {
|
|
60
63
|
headers: {
|
|
61
64
|
accept: "application/json",
|
|
62
65
|
"User-Agent": getPiUserAgent(VERSION),
|
|
66
|
+
...(validator ? { "if-none-match": validator } : {}),
|
|
63
67
|
},
|
|
64
68
|
signal: context.signal,
|
|
65
69
|
});
|
|
66
70
|
if (context.signal?.aborted)
|
|
67
71
|
return;
|
|
68
72
|
const checkedAt = Date.now();
|
|
73
|
+
// Unchanged: dynamicModels already holds the stored overlay, so only the
|
|
74
|
+
// freshness window moves.
|
|
75
|
+
if (response.status === 304 && stored) {
|
|
76
|
+
await context.store.write({ ...stored, checkedAt });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
69
79
|
if (response.status === 404 || response.status === 501) {
|
|
70
|
-
await context.store.write({
|
|
80
|
+
await context.store.write({
|
|
81
|
+
...(stored ?? { models: [] }),
|
|
82
|
+
checkedAt,
|
|
83
|
+
lastModified: 0,
|
|
84
|
+
etag: undefined,
|
|
85
|
+
});
|
|
71
86
|
return;
|
|
72
87
|
}
|
|
73
88
|
if (!response.ok) {
|
|
89
|
+
// Transient failure: the cached body and its validator stay valid, so keep the
|
|
90
|
+
// etag and let the next refresh revalidate instead of downloading the catalog.
|
|
74
91
|
await context.store.write({ ...(stored ?? { models: [] }), checkedAt });
|
|
75
92
|
throw new Error(`Model catalog request failed for ${provider.id}: ${response.status}`);
|
|
76
93
|
}
|
|
@@ -82,6 +99,7 @@ export function withRemoteCatalog(provider, catalogBaseUrl = DEFAULT_CATALOG_BAS
|
|
|
82
99
|
models: refreshed,
|
|
83
100
|
checkedAt,
|
|
84
101
|
lastModified: Number.isNaN(lastModified) ? 0 : lastModified,
|
|
102
|
+
etag: response.headers.get("etag") ?? undefined,
|
|
85
103
|
};
|
|
86
104
|
dynamicModels = remoteModels(entry, localGeneratedAt);
|
|
87
105
|
await context.store.write(entry);
|
|
@@ -84,10 +84,10 @@ Sling documentation (read only when the user asks about sling itself, its SDK, e
|
|
|
84
84
|
- Main documentation: ${readmePath}
|
|
85
85
|
- Additional docs: ${docsPath}
|
|
86
86
|
- Examples: ${examplesPath} (extensions, custom tools, SDK)
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
- When reading sling docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory
|
|
88
|
+
- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), sling packages (docs/packages.md), environment variables (docs/environment-variables.md)
|
|
89
|
+
- When working on sling topics, read the docs and examples, and follow .md cross-references before implementing
|
|
90
|
+
- Always read sling .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;
|
|
91
91
|
if (appendSection) {
|
|
92
92
|
prompt += appendSection;
|
|
93
93
|
}
|
|
@@ -85,6 +85,10 @@ export function createLlamaProvider() {
|
|
|
85
85
|
},
|
|
86
86
|
getModels: () => models,
|
|
87
87
|
refreshModels: async (context) => {
|
|
88
|
+
const stored = await context.store.read();
|
|
89
|
+
if (stored) {
|
|
90
|
+
models = stored.models.filter((model) => model.provider === LLAMA_PROVIDER_ID && model.api === "openai-completions");
|
|
91
|
+
}
|
|
88
92
|
if (!context.allowNetwork || context.signal?.aborted || context.credential?.type !== "api_key")
|
|
89
93
|
return;
|
|
90
94
|
const serverUrl = credentialServerUrl(context.credential);
|
|
@@ -92,6 +96,8 @@ export function createLlamaProvider() {
|
|
|
92
96
|
return;
|
|
93
97
|
const catalog = await new LlamaClient(serverUrl, context.credential.key).list({ signal: context.signal });
|
|
94
98
|
setCatalog(catalog, serverUrl);
|
|
99
|
+
if (!context.signal?.aborted)
|
|
100
|
+
await context.store.write({ models, checkedAt: Date.now() });
|
|
95
101
|
},
|
|
96
102
|
stream: (model, context, options) => stream(model, context, options),
|
|
97
103
|
streamSimple: (model, context, options) => streamSimple(model, context, options),
|
|
@@ -11,11 +11,13 @@ export class CustomMessageComponent extends Container {
|
|
|
11
11
|
customComponent;
|
|
12
12
|
markdownTheme;
|
|
13
13
|
_expanded = false;
|
|
14
|
-
|
|
14
|
+
outputPad;
|
|
15
|
+
constructor(message, customRenderer, markdownTheme = getMarkdownTheme(), outputPad = 1) {
|
|
15
16
|
super();
|
|
16
17
|
this.message = message;
|
|
17
18
|
this.customRenderer = customRenderer;
|
|
18
19
|
this.markdownTheme = markdownTheme;
|
|
20
|
+
this.outputPad = outputPad;
|
|
19
21
|
this.addChild(new Spacer(1));
|
|
20
22
|
// Create box with purple background (used for default rendering)
|
|
21
23
|
this.box = new Box(1, 1, (t) => theme.bg("customMessageBg", t));
|
|
@@ -27,6 +29,12 @@ export class CustomMessageComponent extends Container {
|
|
|
27
29
|
this.rebuild();
|
|
28
30
|
}
|
|
29
31
|
}
|
|
32
|
+
setOutputPad(outputPad) {
|
|
33
|
+
if (this.outputPad !== outputPad) {
|
|
34
|
+
this.outputPad = outputPad;
|
|
35
|
+
this.rebuild();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
30
38
|
invalidate() {
|
|
31
39
|
super.invalidate();
|
|
32
40
|
this.rebuild();
|
|
@@ -41,7 +49,7 @@ export class CustomMessageComponent extends Container {
|
|
|
41
49
|
// Try custom renderer first - it handles its own styling
|
|
42
50
|
if (this.customRenderer) {
|
|
43
51
|
try {
|
|
44
|
-
const component = this.customRenderer(this.message, { expanded: this._expanded }, theme);
|
|
52
|
+
const component = this.customRenderer(this.message, { expanded: this._expanded, outputPad: this.outputPad }, theme);
|
|
45
53
|
if (component) {
|
|
46
54
|
// Custom renderer provides its own styled component
|
|
47
55
|
this.customComponent = component;
|
|
@@ -23,7 +23,7 @@ function enableAll(enabledIds, allIds, targetIds) {
|
|
|
23
23
|
if (!result.includes(id))
|
|
24
24
|
result.push(id);
|
|
25
25
|
}
|
|
26
|
-
return result.length === allIds.length ? null : result;
|
|
26
|
+
return result.length === allIds.length && result.every((id) => allIds.includes(id)) ? null : result;
|
|
27
27
|
}
|
|
28
28
|
function clearAll(enabledIds, allIds, targetIds) {
|
|
29
29
|
if (enabledIds === null) {
|
|
@@ -108,19 +108,19 @@ export class ScopedModelsSelectorComponent extends Container {
|
|
|
108
108
|
this.updateList();
|
|
109
109
|
}
|
|
110
110
|
buildItems() {
|
|
111
|
-
|
|
112
|
-
return getSortedIds(this.enabledIds, this.allIds)
|
|
113
|
-
.filter((id) => this.modelsById.has(id))
|
|
114
|
-
.map((id) => ({
|
|
111
|
+
return getSortedIds(this.enabledIds, this.allIds).map((id) => ({
|
|
115
112
|
fullId: id,
|
|
116
113
|
model: this.modelsById.get(id),
|
|
117
114
|
enabled: isEnabled(this.enabledIds, id),
|
|
118
115
|
}));
|
|
119
116
|
}
|
|
120
117
|
getFooterText() {
|
|
121
|
-
const enabledCount = this.enabledIds?.length ?? this.allIds.length;
|
|
118
|
+
const enabledCount = this.enabledIds?.filter((id) => this.modelsById.has(id)).length ?? this.allIds.length;
|
|
119
|
+
const unavailableCount = this.enabledIds?.filter((id) => !this.modelsById.has(id)).length ?? 0;
|
|
122
120
|
const allEnabled = this.enabledIds === null;
|
|
123
|
-
const countText = allEnabled
|
|
121
|
+
const countText = allEnabled
|
|
122
|
+
? "all enabled"
|
|
123
|
+
: `${enabledCount}/${this.allIds.length} enabled${unavailableCount ? ` · ${unavailableCount} unavailable` : ""}`;
|
|
124
124
|
const parts = [
|
|
125
125
|
`${keyText("tui.select.confirm")} toggle`,
|
|
126
126
|
`${keyText("app.models.enableAll")} all`,
|
|
@@ -138,7 +138,9 @@ export class ScopedModelsSelectorComponent extends Container {
|
|
|
138
138
|
const query = this.searchInput.getValue();
|
|
139
139
|
const items = this.buildItems();
|
|
140
140
|
this.filteredItems = query
|
|
141
|
-
? fuzzyFilter(items, query, (
|
|
141
|
+
? fuzzyFilter(items, query, (item) => item.model
|
|
142
|
+
? getModelSearchText({ id: item.model.id, provider: item.model.provider, name: item.model.name })
|
|
143
|
+
: item.fullId)
|
|
142
144
|
: items;
|
|
143
145
|
this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredItems.length - 1));
|
|
144
146
|
this.updateList();
|
|
@@ -160,9 +162,16 @@ export class ScopedModelsSelectorComponent extends Container {
|
|
|
160
162
|
const item = this.filteredItems[i];
|
|
161
163
|
const isSelected = i === this.selectedIndex;
|
|
162
164
|
const prefix = isSelected ? theme.fg("accent", "→ ") : " ";
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
const
|
|
165
|
+
const id = item.model?.id ?? item.fullId;
|
|
166
|
+
const modelText = isSelected ? theme.fg("accent", id) : id;
|
|
167
|
+
const providerBadge = theme.fg("muted", item.model ? ` [${item.model.provider}]` : " [unavailable]");
|
|
168
|
+
const status = item.model
|
|
169
|
+
? allEnabled
|
|
170
|
+
? ""
|
|
171
|
+
: item.enabled
|
|
172
|
+
? theme.fg("success", " ✓")
|
|
173
|
+
: theme.fg("dim", " ✗")
|
|
174
|
+
: theme.fg("dim", " ✗");
|
|
166
175
|
this.listContainer.addChild(new Text(`${prefix}${modelText}${providerBadge}${status}`, 0, 0));
|
|
167
176
|
}
|
|
168
177
|
// Add scroll indicator if needed
|
|
@@ -172,7 +181,7 @@ export class ScopedModelsSelectorComponent extends Container {
|
|
|
172
181
|
if (this.filteredItems.length > 0) {
|
|
173
182
|
const selected = this.filteredItems[this.selectedIndex];
|
|
174
183
|
this.listContainer.addChild(new Spacer(1));
|
|
175
|
-
this.listContainer.addChild(new Text(theme.fg("muted", ` Model Name: ${selected.model.name}`), 0, 0));
|
|
184
|
+
this.listContainer.addChild(new Text(theme.fg("muted", ` ${selected.model ? `Model Name: ${selected.model.name}` : "Model unavailable"}`), 0, 0));
|
|
176
185
|
}
|
|
177
186
|
}
|
|
178
187
|
handleInput(data) {
|
|
@@ -246,7 +255,7 @@ export class ScopedModelsSelectorComponent extends Container {
|
|
|
246
255
|
// Toggle provider of current item
|
|
247
256
|
if (kb.matches(data, "app.models.toggleProvider")) {
|
|
248
257
|
const item = this.filteredItems[this.selectedIndex];
|
|
249
|
-
if (item) {
|
|
258
|
+
if (item?.model) {
|
|
250
259
|
const provider = item.model.provider;
|
|
251
260
|
const providerIds = this.allIds.filter((id) => this.modelsById.get(id).provider === provider);
|
|
252
261
|
const allEnabled = providerIds.every((id) => isEnabled(this.enabledIds, id));
|
package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js
CHANGED
|
@@ -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";
|
|
@@ -30,7 +30,6 @@ import { copyToClipboard, readClipboardText } from "../../utils/clipboard.js";
|
|
|
30
30
|
import { extensionForImageMimeType, readClipboardImage } from "../../utils/clipboard-image.js";
|
|
31
31
|
import { parseGitUrl } from "../../utils/git.js";
|
|
32
32
|
import { getCwdRelativePath } from "../../utils/paths.js";
|
|
33
|
-
import { getPiUserAgent } from "../../utils/pi-user-agent.js";
|
|
34
33
|
import { killTrackedDetachedChildren } from "../../utils/shell.js";
|
|
35
34
|
import { ensureTool } from "../../utils/tools-manager.js";
|
|
36
35
|
import { checkForNewPiVersion } from "../../utils/version-check.js";
|
|
@@ -461,7 +460,7 @@ export class InteractiveMode {
|
|
|
461
460
|
return;
|
|
462
461
|
this.registerSignalHandlers();
|
|
463
462
|
// Load changelog (only show new entries, skip for resumed sessions)
|
|
464
|
-
//
|
|
463
|
+
//this.changelogMarkdown = this.getChangelogForDisplay();
|
|
465
464
|
// Ensure fd and rg are available (downloads if missing, adds to PATH via getBinDir)
|
|
466
465
|
// Both are needed: fd for autocomplete, rg for grep tool and bash commands
|
|
467
466
|
const [fdPath] = await Promise.all([ensureTool("fd"), ensureTool("rg")]);
|
|
@@ -591,7 +590,7 @@ export class InteractiveMode {
|
|
|
591
590
|
// Start version check asynchronously
|
|
592
591
|
checkForNewPiVersion(this.version).then((newRelease) => {
|
|
593
592
|
if (newRelease) {
|
|
594
|
-
this.showNewVersionNotification(newRelease);
|
|
593
|
+
//this.showNewVersionNotification(newRelease);
|
|
595
594
|
}
|
|
596
595
|
});
|
|
597
596
|
// Start package update check asynchronously
|
|
@@ -751,14 +750,14 @@ export class InteractiveMode {
|
|
|
751
750
|
if (!isInstallTelemetryEnabled(this.settingsManager)) {
|
|
752
751
|
return;
|
|
753
752
|
}
|
|
754
|
-
void fetch(`https://pi.dev/api/report-install?version=${encodeURIComponent(version)}`, {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
})
|
|
760
|
-
|
|
761
|
-
|
|
753
|
+
// void fetch(`https://pi.dev/api/report-install?version=${encodeURIComponent(version)}`, {
|
|
754
|
+
// headers: {
|
|
755
|
+
// "User-Agent": getPiUserAgent(version),
|
|
756
|
+
// },
|
|
757
|
+
// signal: AbortSignal.timeout(5000),
|
|
758
|
+
// })
|
|
759
|
+
// .then(() => undefined)
|
|
760
|
+
// .catch(() => undefined);
|
|
762
761
|
}
|
|
763
762
|
getMarkdownThemeWithSettings() {
|
|
764
763
|
return {
|
|
@@ -2623,7 +2622,7 @@ export class InteractiveMode {
|
|
|
2623
2622
|
case "custom": {
|
|
2624
2623
|
if (message.display) {
|
|
2625
2624
|
const renderer = this.session.extensionRunner.getMessageRenderer(message.customType);
|
|
2626
|
-
const component = new CustomMessageComponent(message, renderer, this.getMarkdownThemeWithSettings());
|
|
2625
|
+
const component = new CustomMessageComponent(message, renderer, this.getMarkdownThemeWithSettings(), this.outputPad);
|
|
2627
2626
|
component.setExpanded(this.toolOutputExpanded);
|
|
2628
2627
|
this.chatContainer.addChild(component);
|
|
2629
2628
|
}
|
|
@@ -3526,7 +3525,9 @@ export class InteractiveMode {
|
|
|
3526
3525
|
this.outputPad = padding;
|
|
3527
3526
|
if (this.streamingComponent || this.session.isStreaming) {
|
|
3528
3527
|
for (const child of this.chatContainer.children) {
|
|
3529
|
-
if (child instanceof AssistantMessageComponent ||
|
|
3528
|
+
if (child instanceof AssistantMessageComponent ||
|
|
3529
|
+
child instanceof CustomMessageComponent ||
|
|
3530
|
+
child instanceof UserMessageComponent) {
|
|
3530
3531
|
child.setOutputPad(padding);
|
|
3531
3532
|
}
|
|
3532
3533
|
}
|
|
@@ -3711,12 +3712,17 @@ export class InteractiveMode {
|
|
|
3711
3712
|
// Get all available models
|
|
3712
3713
|
await this.session.modelRuntime.refresh();
|
|
3713
3714
|
const allModels = [...(await this.session.modelRuntime.getAvailable())];
|
|
3714
|
-
|
|
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) {
|
|
3715
3719
|
this.showStatus("No models available");
|
|
3716
3720
|
return;
|
|
3717
3721
|
}
|
|
3722
|
+
const configuredScope = configuredPatterns?.length
|
|
3723
|
+
? await resolveModelScopeWithDiagnostics(configuredPatterns, this.session.modelRuntime)
|
|
3724
|
+
: undefined;
|
|
3718
3725
|
// Check if session has scoped models (from previous session-only changes or CLI --models)
|
|
3719
|
-
const sessionScopedModels = this.session.scopedModels;
|
|
3720
3726
|
const hasSessionScope = sessionScopedModels.length > 0;
|
|
3721
3727
|
// Build enabled model IDs from session state or settings
|
|
3722
3728
|
let currentEnabledIds = null;
|
|
@@ -3724,18 +3730,22 @@ export class InteractiveMode {
|
|
|
3724
3730
|
// Use current session's scoped models
|
|
3725
3731
|
currentEnabledIds = sessionScopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
|
|
3726
3732
|
}
|
|
3727
|
-
else {
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
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);
|
|
3734
3742
|
}
|
|
3735
3743
|
// Helper to update session's scoped models (session-only, no persist)
|
|
3736
3744
|
const updateSessionModels = async (enabledIds) => {
|
|
3737
3745
|
currentEnabledIds = enabledIds === null ? null : [...enabledIds];
|
|
3738
|
-
|
|
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) {
|
|
3739
3749
|
const newScopedModels = await resolveModelScope(enabledIds, this.session.modelRuntime);
|
|
3740
3750
|
this.session.setScopedModels(newScopedModels.map((sm) => ({
|
|
3741
3751
|
model: sm.model,
|
|
@@ -3759,9 +3769,10 @@ export class InteractiveMode {
|
|
|
3759
3769
|
},
|
|
3760
3770
|
onPersist: (enabledIds) => {
|
|
3761
3771
|
// Persist to settings
|
|
3762
|
-
const
|
|
3763
|
-
|
|
3764
|
-
|
|
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;
|
|
3765
3776
|
this.settingsManager.setEnabledModels(newPatterns ? [...newPatterns] : undefined);
|
|
3766
3777
|
this.showStatus("Model selection saved to settings");
|
|
3767
3778
|
},
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-coding-agent",
|
|
3
|
-
"version": "0.82.
|
|
3
|
+
"version": "0.82.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@earendil-works/pi-coding-agent",
|
|
9
|
-
"version": "0.82.
|
|
9
|
+
"version": "0.82.1",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@earendil-works/pi-agent-core": "^0.82.
|
|
13
|
-
"@earendil-works/pi-ai": "^0.82.
|
|
14
|
-
"@earendil-works/pi-tui": "^0.82.
|
|
12
|
+
"@earendil-works/pi-agent-core": "^0.82.1",
|
|
13
|
+
"@earendil-works/pi-ai": "^0.82.1",
|
|
14
|
+
"@earendil-works/pi-tui": "^0.82.1",
|
|
15
15
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
16
16
|
"chalk": "5.6.2",
|
|
17
17
|
"cross-spawn": "7.0.6",
|
|
@@ -474,11 +474,11 @@
|
|
|
474
474
|
}
|
|
475
475
|
},
|
|
476
476
|
"node_modules/@earendil-works/pi-agent-core": {
|
|
477
|
-
"version": "0.82.
|
|
478
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.82.
|
|
477
|
+
"version": "0.82.1",
|
|
478
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.82.1.tgz",
|
|
479
479
|
"license": "MIT",
|
|
480
480
|
"dependencies": {
|
|
481
|
-
"@earendil-works/pi-ai": "^0.82.
|
|
481
|
+
"@earendil-works/pi-ai": "^0.82.1",
|
|
482
482
|
"diff": "8.0.4",
|
|
483
483
|
"ignore": "7.0.5",
|
|
484
484
|
"typebox": "1.1.38",
|
|
@@ -489,8 +489,8 @@
|
|
|
489
489
|
}
|
|
490
490
|
},
|
|
491
491
|
"node_modules/@earendil-works/pi-ai": {
|
|
492
|
-
"version": "0.82.
|
|
493
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.82.
|
|
492
|
+
"version": "0.82.1",
|
|
493
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.82.1.tgz",
|
|
494
494
|
"license": "MIT",
|
|
495
495
|
"dependencies": {
|
|
496
496
|
"@anthropic-ai/sdk": "0.91.1",
|
|
@@ -513,8 +513,8 @@
|
|
|
513
513
|
}
|
|
514
514
|
},
|
|
515
515
|
"node_modules/@earendil-works/pi-tui": {
|
|
516
|
-
"version": "0.82.
|
|
517
|
-
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.82.
|
|
516
|
+
"version": "0.82.1",
|
|
517
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.82.1.tgz",
|
|
518
518
|
"license": "MIT",
|
|
519
519
|
"dependencies": {
|
|
520
520
|
"get-east-asian-width": "1.6.0",
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-coding-agent",
|
|
3
|
-
"version": "0.82.
|
|
3
|
+
"version": "0.82.1",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
7
|
-
"configDir": ".
|
|
7
|
+
"configDir": ".sling",
|
|
8
|
+
"name": "sling"
|
|
8
9
|
},
|
|
9
10
|
"bin": {
|
|
10
11
|
"pi": "dist/cli.js"
|
|
@@ -39,9 +40,9 @@
|
|
|
39
40
|
"prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap"
|
|
40
41
|
},
|
|
41
42
|
"dependencies": {
|
|
42
|
-
"@earendil-works/pi-agent-core": "^0.82.
|
|
43
|
-
"@earendil-works/pi-ai": "^0.82.
|
|
44
|
-
"@earendil-works/pi-tui": "^0.82.
|
|
43
|
+
"@earendil-works/pi-agent-core": "^0.82.1",
|
|
44
|
+
"@earendil-works/pi-ai": "^0.82.1",
|
|
45
|
+
"@earendil-works/pi-tui": "^0.82.1",
|
|
45
46
|
"@silvia-odwyer/photon-node": "0.3.4",
|
|
46
47
|
"chalk": "5.6.2",
|
|
47
48
|
"cross-spawn": "7.0.6",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@earendil-works/pi-server",
|
|
3
|
-
"version": "0.82.
|
|
3
|
+
"version": "0.82.1",
|
|
4
4
|
"description": "experimental server package for pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"node": ">=22.19.0"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@earendil-works/pi-coding-agent": "^0.82.
|
|
43
|
+
"@earendil-works/pi-coding-agent": "^0.82.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"shx": "0.4.0"
|
|
@@ -141,7 +141,7 @@ export class TUI extends Container {
|
|
|
141
141
|
constructor(terminal, showHardwareCursor, logDirectory) {
|
|
142
142
|
super();
|
|
143
143
|
this.terminal = terminal;
|
|
144
|
-
this.logDirectory = logDirectory ?? process.env.PI_CODING_AGENT_DIR ?? path.join(os.homedir(), ".
|
|
144
|
+
this.logDirectory = logDirectory ?? process.env.PI_CODING_AGENT_DIR ?? path.join(os.homedir(), ".pi", "agent");
|
|
145
145
|
if (showHardwareCursor !== undefined) {
|
|
146
146
|
this.showHardwareCursor = showHardwareCursor;
|
|
147
147
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@psnext/slingcli",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.20260727-1",
|
|
4
4
|
"description": "Connects Sling CLI to Publicis Sapient Slingshot enterprise LLM gateway. Bundles the pi coding-agent runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
"type": "git",
|
|
30
30
|
"url": "git+https://pscode.lioncloud.net/psaiproducts/slingcli.git"
|
|
31
31
|
},
|
|
32
|
-
"slingVersion": "2.5.
|
|
32
|
+
"slingVersion": "2.5.20260727-1",
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@earendil-works/pi-tui": "file:../.sling-pack/earendil-works-pi-tui-0.82.
|
|
35
|
-
"@earendil-works/pi-ai": "file:../.sling-pack/earendil-works-pi-ai-0.82.
|
|
36
|
-
"@earendil-works/pi-agent-core": "file:../.sling-pack/earendil-works-pi-agent-core-0.82.
|
|
37
|
-
"@earendil-works/pi-coding-agent": "file:../.sling-pack/earendil-works-pi-coding-agent-0.82.
|
|
38
|
-
"@earendil-works/pi-server": "file:../.sling-pack/earendil-works-pi-server-0.82.
|
|
34
|
+
"@earendil-works/pi-tui": "file:../.sling-pack/earendil-works-pi-tui-0.82.1.tgz",
|
|
35
|
+
"@earendil-works/pi-ai": "file:../.sling-pack/earendil-works-pi-ai-0.82.1.tgz",
|
|
36
|
+
"@earendil-works/pi-agent-core": "file:../.sling-pack/earendil-works-pi-agent-core-0.82.1.tgz",
|
|
37
|
+
"@earendil-works/pi-coding-agent": "file:../.sling-pack/earendil-works-pi-coding-agent-0.82.1.tgz",
|
|
38
|
+
"@earendil-works/pi-server": "file:../.sling-pack/earendil-works-pi-server-0.82.1.tgz",
|
|
39
39
|
"undici": "^7.19.1",
|
|
40
40
|
"semver": "^7.6.0"
|
|
41
41
|
},
|