@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.
Files changed (30) hide show
  1. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  2. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +8 -3
  3. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/radius.js +37 -35
  4. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +11 -1
  5. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  6. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  7. package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -1
  8. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cloudflare-ai-gateway.json +1 -1
  9. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  10. package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
  11. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  12. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  13. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  14. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +8 -3
  15. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  16. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +13 -3
  17. package/node_modules/@earendil-works/pi-coding-agent/dist/core/remote-catalog-provider.js +19 -1
  18. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +3 -0
  19. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +4 -4
  20. package/node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/provider.js +6 -0
  21. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/custom-message.js +10 -2
  22. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/scoped-models-selector.js +22 -13
  23. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +38 -27
  24. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +12 -12
  25. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -5
  26. package/node_modules/@earendil-works/pi-server/package.json +2 -2
  27. package/node_modules/@earendil-works/pi-tui/dist/tui.js +1 -1
  28. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  29. package/package.json +7 -7
  30. 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({ ...(stored ?? { models: [] }), checkedAt, lastModified: 0 });
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);
@@ -33,6 +33,9 @@ function loadContextFileFromDir(dir) {
33
33
  const filePath = join(dir, filename);
34
34
  if (existsSync(filePath)) {
35
35
  try {
36
+ if (!statSync(filePath).isFile()) {
37
+ continue;
38
+ }
36
39
  return {
37
40
  path: filePath,
38
41
  content: readFileSync(filePath, "utf-8"),
@@ -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
- -- 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)`;
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
- constructor(message, customRenderer, markdownTheme = getMarkdownTheme()) {
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
- // Filter out IDs that no longer have a corresponding model (e.g., after logout)
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 ? "all enabled" : `${enabledCount}/${this.allIds.length} enabled`;
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, (i) => getModelSearchText({ id: i.model.id, provider: i.model.provider, name: i.model.name }))
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 modelText = isSelected ? theme.fg("accent", item.model.id) : item.model.id;
164
- const providerBadge = theme.fg("muted", ` [${item.model.provider}]`);
165
- const status = allEnabled ? "" : item.enabled ? theme.fg("success", " ✓") : theme.fg("dim", " ");
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));
@@ -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
- // this.changelogMarkdown = this.getChangelogForDisplay();
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
- headers: {
756
- "User-Agent": getPiUserAgent(version),
757
- },
758
- signal: AbortSignal.timeout(5000),
759
- })
760
- .then(() => undefined)
761
- .catch(() => undefined);
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 || child instanceof UserMessageComponent) {
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
- if (allModels.length === 0) {
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
- // Fall back to settings
3729
- const patterns = this.settingsManager.getEnabledModels();
3730
- if (patterns !== undefined && patterns.length > 0) {
3731
- const scopedModels = await resolveModelScope(patterns, this.session.modelRuntime);
3732
- currentEnabledIds = scopedModels.map((scoped) => `${scoped.model.provider}/${scoped.model.id}`);
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
- if (enabledIds && enabledIds.length > 0 && enabledIds.length < allModels.length) {
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 newPatterns = enabledIds === null || enabledIds.length === allModels.length
3763
- ? undefined // All enabled = clear filter
3764
- : enabledIds;
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.0",
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.0",
9
+ "version": "0.82.1",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@earendil-works/pi-agent-core": "^0.82.0",
13
- "@earendil-works/pi-ai": "^0.82.0",
14
- "@earendil-works/pi-tui": "^0.82.0",
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.0",
478
- "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.82.0.tgz",
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.0",
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.0",
493
- "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.82.0.tgz",
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.0",
517
- "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.82.0.tgz",
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.0",
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": ".pi"
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.0",
43
- "@earendil-works/pi-ai": "^0.82.0",
44
- "@earendil-works/pi-tui": "^0.82.0",
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.0",
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.0"
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(), ".sling", "agent");
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
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-tui",
3
- "version": "0.82.0",
3
+ "version": "0.82.1",
4
4
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@psnext/slingcli",
3
- "version": "2.5.20260725-1",
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.20260725-1",
32
+ "slingVersion": "2.5.20260727-1",
33
33
  "dependencies": {
34
- "@earendil-works/pi-tui": "file:../.sling-pack/earendil-works-pi-tui-0.82.0.tgz",
35
- "@earendil-works/pi-ai": "file:../.sling-pack/earendil-works-pi-ai-0.82.0.tgz",
36
- "@earendil-works/pi-agent-core": "file:../.sling-pack/earendil-works-pi-agent-core-0.82.0.tgz",
37
- "@earendil-works/pi-coding-agent": "file:../.sling-pack/earendil-works-pi-coding-agent-0.82.0.tgz",
38
- "@earendil-works/pi-server": "file:../.sling-pack/earendil-works-pi-server-0.82.0.tgz",
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
  },