@psnext/slingcli 2.4.20260601-1 → 2.5.20260602-2
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/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler/package.json +4 -4
- package/node_modules/@aws-sdk/credential-provider-node/dist-cjs/index.js +12 -1
- package/node_modules/@aws-sdk/credential-provider-node/dist-es/runtime/memoize-chain.js +12 -1
- package/node_modules/@aws-sdk/credential-provider-node/package.json +1 -1
- package/node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler/package.json +4 -4
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +81 -18
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +1 -0
- package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +14 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +197 -190
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +84 -21
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +24 -14
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +5 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/google-vertex.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/google.js +5 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/mistral.js +2 -3
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +130 -62
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +18 -12
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses-shared.js +4 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +5 -9
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/stream.js +14 -2
- package/node_modules/@earendil-works/pi-ai/dist/utils/abort-signals.js +34 -0
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +8 -7
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/openai-codex.js +179 -79
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/args.js +27 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +9 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +29 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +21 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/footer-data-provider.js +29 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +65 -13
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-resolver.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/resolve-config-value.js +134 -11
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +12 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +167 -96
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +14 -9
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +0 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +7 -10
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +6 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/render-utils.js +17 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +5 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/index.js +2 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +69 -16
- package/node_modules/@earendil-works/pi-coding-agent/dist/migrations.js +118 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +2 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +61 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +10 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/print-mode.js +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +4 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/deprecation.js +13 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/json.js +7 -0
- package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +71 -56
- package/node_modules/@earendil-works/pi-coding-agent/package.json +7 -7
- package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +9 -53
- package/node_modules/@earendil-works/pi-tui/dist/components/input.js +6 -54
- package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +34 -7
- package/node_modules/@earendil-works/pi-tui/dist/terminal.js +172 -37
- package/node_modules/@earendil-works/pi-tui/dist/tui.js +166 -22
- package/node_modules/@earendil-works/pi-tui/dist/utils.js +8 -3
- package/node_modules/@earendil-works/pi-tui/dist/word-navigation.js +96 -0
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/node_modules/@mariozechner/clipboard/Cargo.toml +3 -3
- package/node_modules/@mariozechner/clipboard/index.d.ts +34 -20
- package/node_modules/@mariozechner/clipboard/index.js +546 -257
- package/node_modules/@mariozechner/clipboard/package.json +14 -14
- package/node_modules/@mariozechner/clipboard/src/lib.rs +4 -9
- package/node_modules/@mariozechner/clipboard-linux-x64-gnu/clipboard.linux-x64-gnu.node +0 -0
- package/node_modules/@mariozechner/clipboard-linux-x64-gnu/package.json +2 -2
- package/node_modules/@smithy/core/dist-cjs/submodules/retry/index.browser.js +39 -22
- package/node_modules/@smithy/core/dist-cjs/submodules/retry/index.js +39 -22
- package/node_modules/@smithy/core/dist-es/submodules/retry/middleware-retry/configurations.js +19 -6
- package/node_modules/@smithy/core/dist-es/submodules/retry/middleware-retry/retryMiddleware.js +4 -5
- package/node_modules/@smithy/core/dist-es/submodules/retry/service-error-classification/constants.js +1 -1
- package/node_modules/@smithy/core/dist-es/submodules/retry/util-retry/ConfiguredRetryStrategy.js +4 -5
- package/node_modules/@smithy/core/dist-es/submodules/retry/util-retry/DefaultRetryToken.js +3 -0
- package/node_modules/@smithy/core/dist-es/submodules/retry/util-retry/StandardRetryStrategy.js +9 -5
- package/node_modules/@smithy/core/dist-types/submodules/retry/middleware-retry/configurations.d.ts +4 -1
- package/node_modules/@smithy/core/dist-types/submodules/retry/util-retry/ConfiguredRetryStrategy.d.ts +1 -2
- package/node_modules/@smithy/core/dist-types/submodules/retry/util-retry/DefaultRetryToken.d.ts +3 -0
- package/node_modules/@smithy/core/dist-types/submodules/retry/util-retry/StandardRetryStrategy.d.ts +1 -1
- package/node_modules/@smithy/core/package.json +2 -2
- package/node_modules/@smithy/credential-provider-imds/package.json +3 -3
- package/node_modules/@smithy/fetch-http-handler/package.json +4 -4
- package/node_modules/@smithy/signature-v4/package.json +3 -3
- package/node_modules/@smithy/types/dist-types/retry.d.ts +25 -0
- package/node_modules/@smithy/types/package.json +1 -1
- package/package.json +6 -6
- package/slingshot/index.js +231 -230
|
@@ -6,7 +6,7 @@ import { keyHint } from "../../modes/interactive/components/keybinding-hints.js"
|
|
|
6
6
|
import { getLanguageFromPath, highlightCode } from "../../modes/interactive/theme/theme.js";
|
|
7
7
|
import { withFileMutationQueue } from "./file-mutation-queue.js";
|
|
8
8
|
import { resolveToCwd } from "./path-utils.js";
|
|
9
|
-
import {
|
|
9
|
+
import { normalizeDisplayText, renderToolPath, replaceTabs, str } from "./render-utils.js";
|
|
10
10
|
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
11
11
|
const writeSchema = Type.Object({
|
|
12
12
|
path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
|
|
@@ -90,12 +90,11 @@ function trimTrailingEmptyLines(lines) {
|
|
|
90
90
|
}
|
|
91
91
|
return lines.slice(0, end);
|
|
92
92
|
}
|
|
93
|
-
function formatWriteCall(args, options, theme, cache) {
|
|
93
|
+
function formatWriteCall(args, options, theme, cache, cwd) {
|
|
94
94
|
const rawPath = str(args?.file_path ?? args?.path);
|
|
95
95
|
const fileContent = str(args?.content);
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
let text = `${theme.fg("toolTitle", theme.bold("write"))} ${path === null ? invalidArg : path ? theme.fg("accent", path) : theme.fg("toolOutput", "...")}`;
|
|
96
|
+
const pathDisplay = renderToolPath(rawPath, theme, cwd);
|
|
97
|
+
let text = `${theme.fg("toolTitle", theme.bold("write"))} ${pathDisplay}`;
|
|
99
98
|
if (fileContent === null) {
|
|
100
99
|
text += `\n\n${theme.fg("error", "[invalid content arg - expected string]")}`;
|
|
101
100
|
}
|
|
@@ -176,7 +175,7 @@ export function createWriteToolDefinition(cwd, options) {
|
|
|
176
175
|
else {
|
|
177
176
|
component.cache = undefined;
|
|
178
177
|
}
|
|
179
|
-
component.setText(formatWriteCall(renderArgs, { expanded: context.expanded, isPartial: context.isPartial }, theme, component.cache));
|
|
178
|
+
component.setText(formatWriteCall(renderArgs, { expanded: context.expanded, isPartial: context.isPartial }, theme, component.cache, context.cwd));
|
|
180
179
|
return component;
|
|
181
180
|
},
|
|
182
181
|
renderResult(result, _options, theme, context) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// Core session management
|
|
2
|
+
export { parseArgs } from "./cli/args.js";
|
|
2
3
|
// Config paths
|
|
3
4
|
export { getAgentDir, VERSION } from "./config.js";
|
|
4
5
|
export { AgentSession, parseSkillBlock, } from "./core/agent-session.js";
|
|
@@ -36,6 +37,7 @@ export { getLanguageFromPath, getMarkdownTheme, getSelectListTheme, getSettingsL
|
|
|
36
37
|
// Clipboard utilities
|
|
37
38
|
export { copyToClipboard } from "./utils/clipboard.js";
|
|
38
39
|
export { parseFrontmatter, stripFrontmatter } from "./utils/frontmatter.js";
|
|
40
|
+
export { convertToPng } from "./utils/image-convert.js";
|
|
39
41
|
export { formatDimensionNote, resizeImage } from "./utils/image-resize.js";
|
|
40
42
|
// Shell utilities
|
|
41
43
|
export { getShellConfig } from "./utils/shell.js";
|
|
@@ -24,7 +24,7 @@ import { KeybindingsManager } from "./core/keybindings.js";
|
|
|
24
24
|
import { resolveCliModel, resolveModelScope } from "./core/model-resolver.js";
|
|
25
25
|
import { restoreStdout, takeOverStdout } from "./core/output-guard.js";
|
|
26
26
|
import { formatMissingSessionCwdPrompt, getMissingSessionCwdIssue, MissingSessionCwdError, } from "./core/session-cwd.js";
|
|
27
|
-
import { SessionManager } from "./core/session-manager.js";
|
|
27
|
+
import { assertValidSessionId, SessionManager } from "./core/session-manager.js";
|
|
28
28
|
import { SettingsManager } from "./core/settings-manager.js";
|
|
29
29
|
import { printTimings, resetTimings, time } from "./core/timings.js";
|
|
30
30
|
import { runMigrations, showDeprecationWarnings } from "./migrations.js";
|
|
@@ -104,6 +104,11 @@ async function prepareInitialMessage(parsed, autoResizeImages, stdinContent) {
|
|
|
104
104
|
* Resolve a session argument to a file path.
|
|
105
105
|
* If it looks like a path, use as-is. Otherwise try to match as session ID prefix.
|
|
106
106
|
*/
|
|
107
|
+
async function findLocalSessionByExactId(sessionId, cwd, sessionDir) {
|
|
108
|
+
const localSessions = await SessionManager.list(cwd, sessionDir);
|
|
109
|
+
const localMatch = localSessions.find((s) => s.id === sessionId);
|
|
110
|
+
return localMatch ? { type: "local", path: localMatch.path } : undefined;
|
|
111
|
+
}
|
|
107
112
|
async function resolveSessionPath(sessionArg, cwd, sessionDir) {
|
|
108
113
|
// If it looks like a file path, resolve it before handing it to the session manager.
|
|
109
114
|
if (sessionArg.includes("/") || sessionArg.includes("\\") || sessionArg.endsWith(".jsonl")) {
|
|
@@ -111,16 +116,15 @@ async function resolveSessionPath(sessionArg, cwd, sessionDir) {
|
|
|
111
116
|
}
|
|
112
117
|
// Try to match as session ID in current project first
|
|
113
118
|
const localSessions = await SessionManager.list(cwd, sessionDir);
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
116
|
-
return { type: "local", path:
|
|
119
|
+
const localMatch = localSessions.find((s) => s.id === sessionArg) ?? localSessions.find((s) => s.id.startsWith(sessionArg));
|
|
120
|
+
if (localMatch) {
|
|
121
|
+
return { type: "local", path: localMatch.path };
|
|
117
122
|
}
|
|
118
123
|
// Try global search across all projects
|
|
119
|
-
const allSessions = await SessionManager.listAll();
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
122
|
-
|
|
123
|
-
return { type: "global", path: match.path, cwd: match.cwd };
|
|
124
|
+
const allSessions = await SessionManager.listAll(sessionDir);
|
|
125
|
+
const globalMatch = allSessions.find((s) => s.id === sessionArg) ?? allSessions.find((s) => s.id.startsWith(sessionArg));
|
|
126
|
+
if (globalMatch) {
|
|
127
|
+
return { type: "global", path: globalMatch.path, cwd: globalMatch.cwd };
|
|
124
128
|
}
|
|
125
129
|
// Not found anywhere
|
|
126
130
|
return { type: "not_found", arg: sessionArg };
|
|
@@ -152,9 +156,31 @@ function validateForkFlags(parsed) {
|
|
|
152
156
|
process.exit(1);
|
|
153
157
|
}
|
|
154
158
|
}
|
|
155
|
-
function
|
|
159
|
+
function validateSessionIdFlags(parsed) {
|
|
160
|
+
if (parsed.sessionId === undefined)
|
|
161
|
+
return;
|
|
162
|
+
const conflictingFlags = [
|
|
163
|
+
parsed.session ? "--session" : undefined,
|
|
164
|
+
parsed.continue ? "--continue" : undefined,
|
|
165
|
+
parsed.resume ? "--resume" : undefined,
|
|
166
|
+
parsed.noSession ? "--no-session" : undefined,
|
|
167
|
+
].filter((flag) => flag !== undefined);
|
|
168
|
+
if (conflictingFlags.length > 0) {
|
|
169
|
+
console.error(chalk.red(`Error: --session-id cannot be combined with ${conflictingFlags.join(", ")}`));
|
|
170
|
+
process.exit(1);
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
assertValidSessionId(parsed.sessionId);
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
177
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function forkSessionOrExit(sourcePath, cwd, sessionDir, sessionId) {
|
|
156
182
|
try {
|
|
157
|
-
return SessionManager.forkFrom(sourcePath, cwd, sessionDir);
|
|
183
|
+
return SessionManager.forkFrom(sourcePath, cwd, sessionDir, { id: sessionId });
|
|
158
184
|
}
|
|
159
185
|
catch (error) {
|
|
160
186
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -163,16 +189,23 @@ function forkSessionOrExit(sourcePath, cwd, sessionDir) {
|
|
|
163
189
|
}
|
|
164
190
|
}
|
|
165
191
|
async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
|
|
166
|
-
if (parsed.noSession) {
|
|
167
|
-
return SessionManager.inMemory();
|
|
192
|
+
if (parsed.noSession || parsed.help || parsed.listModels !== undefined) {
|
|
193
|
+
return SessionManager.inMemory(cwd);
|
|
168
194
|
}
|
|
169
195
|
if (parsed.fork) {
|
|
196
|
+
if (parsed.sessionId) {
|
|
197
|
+
const existingTarget = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
|
|
198
|
+
if (existingTarget) {
|
|
199
|
+
console.error(chalk.red(`Session already exists with id '${parsed.sessionId}'`));
|
|
200
|
+
process.exit(1);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
170
203
|
const resolved = await resolveSessionPath(parsed.fork, cwd, sessionDir);
|
|
171
204
|
switch (resolved.type) {
|
|
172
205
|
case "path":
|
|
173
206
|
case "local":
|
|
174
207
|
case "global":
|
|
175
|
-
return forkSessionOrExit(resolved.path, cwd, sessionDir);
|
|
208
|
+
return forkSessionOrExit(resolved.path, cwd, sessionDir, parsed.sessionId);
|
|
176
209
|
case "not_found":
|
|
177
210
|
console.error(chalk.red(`No session found matching '${resolved.arg}'`));
|
|
178
211
|
process.exit(1);
|
|
@@ -201,7 +234,7 @@ async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
|
|
|
201
234
|
if (parsed.resume) {
|
|
202
235
|
initTheme(settingsManager.getTheme(), true);
|
|
203
236
|
try {
|
|
204
|
-
const selectedPath = await selectSession((onProgress) => SessionManager.list(cwd, sessionDir, onProgress), SessionManager.listAll);
|
|
237
|
+
const selectedPath = await selectSession((onProgress) => SessionManager.list(cwd, sessionDir, onProgress), (onProgress) => SessionManager.listAll(sessionDir, onProgress));
|
|
205
238
|
if (!selectedPath) {
|
|
206
239
|
console.log(chalk.dim("No session selected"));
|
|
207
240
|
process.exit(0);
|
|
@@ -215,7 +248,13 @@ async function createSessionManager(parsed, cwd, sessionDir, settingsManager) {
|
|
|
215
248
|
if (parsed.continue) {
|
|
216
249
|
return SessionManager.continueRecent(cwd, sessionDir);
|
|
217
250
|
}
|
|
218
|
-
|
|
251
|
+
if (parsed.sessionId) {
|
|
252
|
+
const existingSession = await findLocalSessionByExactId(parsed.sessionId, cwd, sessionDir);
|
|
253
|
+
if (existingSession) {
|
|
254
|
+
return SessionManager.open(existingSession.path, sessionDir);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return SessionManager.create(cwd, sessionDir, { id: parsed.sessionId });
|
|
219
258
|
}
|
|
220
259
|
function buildSessionOptions(parsed, scopedModels, hasExistingSession, modelRegistry, settingsManager) {
|
|
221
260
|
const options = {};
|
|
@@ -292,6 +331,9 @@ function buildSessionOptions(parsed, scopedModels, hasExistingSession, modelRegi
|
|
|
292
331
|
if (parsed.tools) {
|
|
293
332
|
options.tools = [...parsed.tools];
|
|
294
333
|
}
|
|
334
|
+
if (parsed.excludeTools) {
|
|
335
|
+
options.excludeTools = [...parsed.excludeTools];
|
|
336
|
+
}
|
|
295
337
|
return { options, cliThinkingFromModel, diagnostics };
|
|
296
338
|
}
|
|
297
339
|
function resolveCliPaths(cwd, paths) {
|
|
@@ -373,6 +415,7 @@ export async function main(args, options) {
|
|
|
373
415
|
process.exit(1);
|
|
374
416
|
}
|
|
375
417
|
validateForkFlags(parsed);
|
|
418
|
+
validateSessionIdFlags(parsed);
|
|
376
419
|
// Run migrations (pass cwd for project-local migrations)
|
|
377
420
|
const { migratedAuthProviders: migratedProviders, deprecationWarnings } = runMigrations(process.cwd());
|
|
378
421
|
time("runMigrations");
|
|
@@ -404,6 +447,14 @@ export async function main(args, options) {
|
|
|
404
447
|
process.exit(1);
|
|
405
448
|
}
|
|
406
449
|
}
|
|
450
|
+
if (parsed.name !== undefined) {
|
|
451
|
+
const name = parsed.name.trim();
|
|
452
|
+
if (!name) {
|
|
453
|
+
console.error(chalk.red("Error: --name requires a non-empty value"));
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
456
|
+
sessionManager.appendSessionInfo(name);
|
|
457
|
+
}
|
|
407
458
|
time("createSessionManager");
|
|
408
459
|
const resolvedExtensionPaths = resolveCliPaths(cwd, parsed.extensions);
|
|
409
460
|
const resolvedSkillPaths = resolveCliPaths(cwd, parsed.skills);
|
|
@@ -463,6 +514,7 @@ export async function main(args, options) {
|
|
|
463
514
|
thinkingLevel: sessionOptions.thinkingLevel,
|
|
464
515
|
scopedModels: sessionOptions.scopedModels,
|
|
465
516
|
tools: sessionOptions.tools,
|
|
517
|
+
excludeTools: sessionOptions.excludeTools,
|
|
466
518
|
noTools: sessionOptions.noTools,
|
|
467
519
|
customTools: sessionOptions.customTools,
|
|
468
520
|
});
|
|
@@ -482,6 +534,7 @@ export async function main(args, options) {
|
|
|
482
534
|
agentDir,
|
|
483
535
|
sessionManager,
|
|
484
536
|
});
|
|
537
|
+
time("createAgentSessionRuntime");
|
|
485
538
|
const { services, session, modelFallbackMessage } = runtime;
|
|
486
539
|
const { settingsManager, modelRegistry, resourceLoader } = services;
|
|
487
540
|
configureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());
|
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
* One-time migrations that run on startup.
|
|
3
3
|
*/
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
5
|
+
import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "fs";
|
|
6
6
|
import { dirname, join } from "path";
|
|
7
7
|
import { CONFIG_DIR_NAME, getAgentDir, getBinDir } from "./config.js";
|
|
8
8
|
import { migrateKeybindingsConfig } from "./core/keybindings.js";
|
|
9
|
+
import { isLegacyEnvVarNameConfigValue } from "./core/resolve-config-value.js";
|
|
10
|
+
import { stripJsonComments } from "./utils/json.js";
|
|
9
11
|
const MIGRATION_GUIDE_URL = "https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration";
|
|
10
12
|
const EXTENSIONS_DOC_URL = "https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/docs/extensions.md";
|
|
11
13
|
/**
|
|
@@ -63,6 +65,120 @@ export function migrateAuthToAuthJson() {
|
|
|
63
65
|
}
|
|
64
66
|
return providers;
|
|
65
67
|
}
|
|
68
|
+
function migrateLegacyEnvVarString(value) {
|
|
69
|
+
return isLegacyEnvVarNameConfigValue(value) ? `$${value}` : undefined;
|
|
70
|
+
}
|
|
71
|
+
function migrateStringProperty(record, key, location, migrations) {
|
|
72
|
+
const value = record[key];
|
|
73
|
+
if (typeof value !== "string")
|
|
74
|
+
return false;
|
|
75
|
+
const migrated = migrateLegacyEnvVarString(value);
|
|
76
|
+
if (migrated === undefined)
|
|
77
|
+
return false;
|
|
78
|
+
record[key] = migrated;
|
|
79
|
+
migrations.push({ location, from: value, to: migrated });
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
function migrateHeadersConfig(headers, location, migrations) {
|
|
83
|
+
if (typeof headers !== "object" || headers === null || Array.isArray(headers))
|
|
84
|
+
return false;
|
|
85
|
+
const headerRecord = headers;
|
|
86
|
+
let migrated = false;
|
|
87
|
+
for (const [key, value] of Object.entries(headerRecord)) {
|
|
88
|
+
if (typeof value !== "string")
|
|
89
|
+
continue;
|
|
90
|
+
const migratedValue = migrateLegacyEnvVarString(value);
|
|
91
|
+
if (migratedValue === undefined)
|
|
92
|
+
continue;
|
|
93
|
+
headerRecord[key] = migratedValue;
|
|
94
|
+
migrations.push({ location: `${location}[${JSON.stringify(key)}]`, from: value, to: migratedValue });
|
|
95
|
+
migrated = true;
|
|
96
|
+
}
|
|
97
|
+
return migrated;
|
|
98
|
+
}
|
|
99
|
+
function migrateAuthJsonConfigValues(agentDir) {
|
|
100
|
+
const authPath = join(agentDir, "auth.json");
|
|
101
|
+
if (!existsSync(authPath))
|
|
102
|
+
return [];
|
|
103
|
+
try {
|
|
104
|
+
const parsed = JSON.parse(readFileSync(authPath, "utf-8"));
|
|
105
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
106
|
+
return [];
|
|
107
|
+
const authData = parsed;
|
|
108
|
+
const migrations = [];
|
|
109
|
+
for (const [provider, credential] of Object.entries(authData)) {
|
|
110
|
+
if (typeof credential !== "object" || credential === null || Array.isArray(credential))
|
|
111
|
+
continue;
|
|
112
|
+
const credentialRecord = credential;
|
|
113
|
+
if (credentialRecord.type !== "api_key")
|
|
114
|
+
continue;
|
|
115
|
+
migrateStringProperty(credentialRecord, "key", `auth.json[${JSON.stringify(provider)}].key`, migrations);
|
|
116
|
+
}
|
|
117
|
+
if (migrations.length === 0)
|
|
118
|
+
return [];
|
|
119
|
+
writeFileSync(authPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf-8");
|
|
120
|
+
chmodSync(authPath, 0o600);
|
|
121
|
+
return migrations;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function migrateModelsJsonConfigValues(agentDir) {
|
|
128
|
+
const modelsPath = join(agentDir, "models.json");
|
|
129
|
+
if (!existsSync(modelsPath))
|
|
130
|
+
return [];
|
|
131
|
+
const parsed = JSON.parse(stripJsonComments(readFileSync(modelsPath, "utf-8")));
|
|
132
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
133
|
+
return [];
|
|
134
|
+
const modelsData = parsed;
|
|
135
|
+
const providers = modelsData.providers;
|
|
136
|
+
if (typeof providers !== "object" || providers === null || Array.isArray(providers))
|
|
137
|
+
return [];
|
|
138
|
+
const migrations = [];
|
|
139
|
+
for (const [provider, providerConfig] of Object.entries(providers)) {
|
|
140
|
+
if (typeof providerConfig !== "object" || providerConfig === null || Array.isArray(providerConfig))
|
|
141
|
+
continue;
|
|
142
|
+
const providerRecord = providerConfig;
|
|
143
|
+
const providerLocation = `models.json.providers[${JSON.stringify(provider)}]`;
|
|
144
|
+
migrateStringProperty(providerRecord, "apiKey", `${providerLocation}.apiKey`, migrations);
|
|
145
|
+
migrateHeadersConfig(providerRecord.headers, `${providerLocation}.headers`, migrations);
|
|
146
|
+
if (Array.isArray(providerRecord.models)) {
|
|
147
|
+
for (let index = 0; index < providerRecord.models.length; index++) {
|
|
148
|
+
const modelConfig = providerRecord.models[index];
|
|
149
|
+
if (typeof modelConfig !== "object" || modelConfig === null || Array.isArray(modelConfig))
|
|
150
|
+
continue;
|
|
151
|
+
const modelRecord = modelConfig;
|
|
152
|
+
const modelKey = typeof modelRecord.id === "string" ? JSON.stringify(modelRecord.id) : String(index);
|
|
153
|
+
migrateHeadersConfig(modelRecord.headers, `${providerLocation}.models[${modelKey}].headers`, migrations);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const modelOverrides = providerRecord.modelOverrides;
|
|
157
|
+
if (typeof modelOverrides === "object" && modelOverrides !== null && !Array.isArray(modelOverrides)) {
|
|
158
|
+
for (const [modelId, modelOverride] of Object.entries(modelOverrides)) {
|
|
159
|
+
if (typeof modelOverride !== "object" || modelOverride === null || Array.isArray(modelOverride))
|
|
160
|
+
continue;
|
|
161
|
+
const modelOverrideRecord = modelOverride;
|
|
162
|
+
migrateHeadersConfig(modelOverrideRecord.headers, `${providerLocation}.modelOverrides[${JSON.stringify(modelId)}].headers`, migrations);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (migrations.length === 0)
|
|
167
|
+
return [];
|
|
168
|
+
writeFileSync(modelsPath, `${JSON.stringify(parsed, null, 2)}\n`, "utf-8");
|
|
169
|
+
return migrations;
|
|
170
|
+
}
|
|
171
|
+
function migrateExplicitEnvVarConfigValues() {
|
|
172
|
+
const agentDir = getAgentDir();
|
|
173
|
+
const migrations = [...migrateAuthJsonConfigValues(agentDir), ...migrateModelsJsonConfigValues(agentDir)];
|
|
174
|
+
if (migrations.length === 0)
|
|
175
|
+
return;
|
|
176
|
+
const details = migrations.map((migration) => ` - ${migration.location}: ${migration.from} -> ${migration.to}`);
|
|
177
|
+
console.log(chalk.yellow([
|
|
178
|
+
"Warning: Migrated API key/header environment references to explicit $ENV_VAR syntax. Plain strings will be treated as literals.",
|
|
179
|
+
...details,
|
|
180
|
+
].join("\n")));
|
|
181
|
+
}
|
|
66
182
|
/**
|
|
67
183
|
* Migrate sessions from ~/.pi/agent/*.jsonl to proper session directories.
|
|
68
184
|
*
|
|
@@ -272,6 +388,7 @@ export async function showDeprecationWarnings(warnings) {
|
|
|
272
388
|
*/
|
|
273
389
|
export function runMigrations(cwd) {
|
|
274
390
|
const migratedAuthProviders = migrateAuthToAuthJson();
|
|
391
|
+
migrateExplicitEnvVarConfigValues();
|
|
275
392
|
migrateSessionsFromAgentRoot();
|
|
276
393
|
migrateToolsToBin();
|
|
277
394
|
migrateKeybindingsConfigFile();
|
|
@@ -41,7 +41,7 @@ function getGroupLabel(metadata) {
|
|
|
41
41
|
? `User (${formatBaseDir(metadata.baseDir)})`
|
|
42
42
|
: `Project (${formatBaseDir(metadata.baseDir)})`;
|
|
43
43
|
}
|
|
44
|
-
return metadata.scope === "user" ? "User (~/.
|
|
44
|
+
return metadata.scope === "user" ? "User (~/.sling/agent/)" : "Project (.sling/)";
|
|
45
45
|
}
|
|
46
46
|
return metadata.scope === "user" ? "User settings" : "Project settings";
|
|
47
47
|
}
|
|
@@ -68,7 +68,7 @@ export class LoginDialogComponent extends Container {
|
|
|
68
68
|
/**
|
|
69
69
|
* Called by onAuth callback - show URL and optional instructions
|
|
70
70
|
*/
|
|
71
|
-
showAuth(url, instructions
|
|
71
|
+
showAuth(url, instructions) {
|
|
72
72
|
this.contentContainer.clear();
|
|
73
73
|
this.contentContainer.addChild(new Spacer(1));
|
|
74
74
|
const linkedUrl = `\x1b]8;;${url}\x07${url}\x1b]8;;\x07`;
|
|
@@ -80,9 +80,7 @@ export class LoginDialogComponent extends Container {
|
|
|
80
80
|
this.contentContainer.addChild(new Spacer(1));
|
|
81
81
|
this.contentContainer.addChild(new Text(theme.fg("warning", instructions), 1, 0));
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
this.openUrl(url);
|
|
85
|
-
}
|
|
83
|
+
this.openUrl(url);
|
|
86
84
|
this.tui.requestRender();
|
|
87
85
|
}
|
|
88
86
|
/**
|
package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js
CHANGED
|
@@ -8,6 +8,7 @@ import * as os from "node:os";
|
|
|
8
8
|
import * as path from "node:path";
|
|
9
9
|
import { getProviders, } from "@earendil-works/pi-ai";
|
|
10
10
|
import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@earendil-works/pi-tui";
|
|
11
|
+
import chalk from "chalk";
|
|
11
12
|
import { spawn, spawnSync } from "child_process";
|
|
12
13
|
import { APP_NAME, APP_TITLE, getAgentDir, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
|
|
13
14
|
import { parseSkillBlock } from "../../core/agent-session.js";
|
|
@@ -91,6 +92,27 @@ function isAnthropicSubscriptionAuthKey(apiKey) {
|
|
|
91
92
|
function isUnknownModel(model) {
|
|
92
93
|
return !!model && model.provider === "unknown" && model.id === "unknown" && model.api === "unknown";
|
|
93
94
|
}
|
|
95
|
+
function quoteIfNeeded(value) {
|
|
96
|
+
if (value.length > 0 && !/[^a-zA-Z0-9_\-./~:@]/.test(value)) {
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
100
|
+
}
|
|
101
|
+
export function formatResumeCommand(sessionManager) {
|
|
102
|
+
if (!process.stdout.isTTY)
|
|
103
|
+
return undefined;
|
|
104
|
+
if (!sessionManager.isPersisted())
|
|
105
|
+
return undefined;
|
|
106
|
+
const sessionFile = sessionManager.getSessionFile();
|
|
107
|
+
if (!sessionFile || !fs.existsSync(sessionFile))
|
|
108
|
+
return undefined;
|
|
109
|
+
const args = [APP_NAME];
|
|
110
|
+
if (!sessionManager.usesDefaultSessionDir()) {
|
|
111
|
+
args.push("--session-dir", quoteIfNeeded(sessionManager.getSessionDir()));
|
|
112
|
+
}
|
|
113
|
+
args.push("--session", sessionManager.getSessionId());
|
|
114
|
+
return args.join(" ");
|
|
115
|
+
}
|
|
94
116
|
function hasDefaultModelProvider(providerId) {
|
|
95
117
|
return providerId in defaultModelPerProvider;
|
|
96
118
|
}
|
|
@@ -125,6 +147,7 @@ export class InteractiveMode {
|
|
|
125
147
|
version;
|
|
126
148
|
isInitialized = false;
|
|
127
149
|
onInputCallback;
|
|
150
|
+
pendingUserInputs = [];
|
|
128
151
|
loadingAnimation = undefined;
|
|
129
152
|
workingMessage = undefined;
|
|
130
153
|
workingVisible = true;
|
|
@@ -1106,6 +1129,7 @@ export class InteractiveMode {
|
|
|
1106
1129
|
const uiContext = this.createExtensionUIContext();
|
|
1107
1130
|
await this.session.bindExtensions({
|
|
1108
1131
|
uiContext,
|
|
1132
|
+
mode: "tui",
|
|
1109
1133
|
abortHandler: () => {
|
|
1110
1134
|
this.restoreQueuedMessagesToEditor({ abort: true });
|
|
1111
1135
|
},
|
|
@@ -1245,6 +1269,7 @@ export class InteractiveMode {
|
|
|
1245
1269
|
// Create a context for shortcut handlers
|
|
1246
1270
|
const createContext = () => ({
|
|
1247
1271
|
ui: this.createExtensionUIContext(),
|
|
1272
|
+
mode: "tui",
|
|
1248
1273
|
hasUI: true,
|
|
1249
1274
|
cwd: this.sessionManager.getCwd(),
|
|
1250
1275
|
sessionManager: this.sessionManager,
|
|
@@ -2130,6 +2155,9 @@ export class InteractiveMode {
|
|
|
2130
2155
|
if (this.onInputCallback) {
|
|
2131
2156
|
this.onInputCallback(text);
|
|
2132
2157
|
}
|
|
2158
|
+
else {
|
|
2159
|
+
this.pendingUserInputs.push(text);
|
|
2160
|
+
}
|
|
2133
2161
|
this.editor.addToHistory?.(text);
|
|
2134
2162
|
};
|
|
2135
2163
|
}
|
|
@@ -2608,6 +2636,10 @@ export class InteractiveMode {
|
|
|
2608
2636
|
}
|
|
2609
2637
|
}
|
|
2610
2638
|
async getUserInput() {
|
|
2639
|
+
const queuedInput = this.pendingUserInputs.shift();
|
|
2640
|
+
if (queuedInput !== undefined) {
|
|
2641
|
+
return queuedInput;
|
|
2642
|
+
}
|
|
2611
2643
|
return new Promise((resolve) => {
|
|
2612
2644
|
this.onInputCallback = (text) => {
|
|
2613
2645
|
this.onInputCallback = undefined;
|
|
@@ -2643,16 +2675,36 @@ export class InteractiveMode {
|
|
|
2643
2675
|
* repaint the final frame while the process is exiting.
|
|
2644
2676
|
*/
|
|
2645
2677
|
isShuttingDown = false;
|
|
2646
|
-
async shutdown() {
|
|
2678
|
+
async shutdown(options) {
|
|
2647
2679
|
if (this.isShuttingDown)
|
|
2648
2680
|
return;
|
|
2649
2681
|
this.isShuttingDown = true;
|
|
2650
2682
|
this.unregisterSignalHandlers();
|
|
2683
|
+
if (options?.fromSignal) {
|
|
2684
|
+
// Signal-triggered shutdown (SIGTERM/SIGHUP). Emit extension cleanup
|
|
2685
|
+
// (session_shutdown) BEFORE touching the terminal. Extension teardown
|
|
2686
|
+
// such as removing sockets does not write to the tty, so it must not be
|
|
2687
|
+
// skipped if a later terminal-restore write fails on a dead or stalled
|
|
2688
|
+
// terminal. If the terminal is gone, the restore writes below emit EIO,
|
|
2689
|
+
// which the stdout/stderr error handler turns into emergencyTerminalExit;
|
|
2690
|
+
// the render loop is already idle, so this cannot hot-spin (see #4144).
|
|
2691
|
+
await this.runtimeHost.dispose();
|
|
2692
|
+
await this.ui.terminal.drainInput(1000);
|
|
2693
|
+
this.stop();
|
|
2694
|
+
process.exit(0);
|
|
2695
|
+
}
|
|
2696
|
+
// Interactive quit (Ctrl+D, Ctrl+C, /quit, extension shutdown()). Stop the
|
|
2697
|
+
// TUI before emitting shutdown events so extension UI cleanup cannot repaint
|
|
2698
|
+
// the final frame while the process is exiting.
|
|
2651
2699
|
// Drain any in-flight Kitty key release events before stopping.
|
|
2652
2700
|
// This prevents escape sequences from leaking to the parent shell over slow SSH.
|
|
2653
2701
|
await this.ui.terminal.drainInput(1000);
|
|
2654
2702
|
this.stop();
|
|
2655
2703
|
await this.runtimeHost.dispose();
|
|
2704
|
+
const resumeCommand = formatResumeCommand(this.sessionManager);
|
|
2705
|
+
if (resumeCommand) {
|
|
2706
|
+
process.stdout.write(`${chalk.dim("To resume this session:")} ${resumeCommand}\n`);
|
|
2707
|
+
}
|
|
2656
2708
|
process.exit(0);
|
|
2657
2709
|
}
|
|
2658
2710
|
emergencyTerminalExit() {
|
|
@@ -2711,11 +2763,12 @@ export class InteractiveMode {
|
|
|
2711
2763
|
}
|
|
2712
2764
|
for (const signal of signals) {
|
|
2713
2765
|
const handler = () => {
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2766
|
+
// SIGHUP no longer hard-exits: graceful shutdown emits session_shutdown
|
|
2767
|
+
// first, then attempts terminal restore. A genuinely dead terminal
|
|
2768
|
+
// surfaces as an EIO on the restore writes, which the stdout/stderr
|
|
2769
|
+
// error handler converts into emergencyTerminalExit (see #4144, #5080).
|
|
2717
2770
|
killTrackedDetachedChildren();
|
|
2718
|
-
void this.shutdown();
|
|
2771
|
+
void this.shutdown({ fromSignal: true });
|
|
2719
2772
|
};
|
|
2720
2773
|
process.prependListener(signal, handler);
|
|
2721
2774
|
this.signalCleanupHandlers.push(() => process.off(signal, handler));
|
|
@@ -3642,7 +3695,9 @@ export class InteractiveMode {
|
|
|
3642
3695
|
}
|
|
3643
3696
|
showSessionSelector() {
|
|
3644
3697
|
this.showSelector((done) => {
|
|
3645
|
-
const selector = new SessionSelectorComponent((onProgress) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress),
|
|
3698
|
+
const selector = new SessionSelectorComponent((onProgress) => SessionManager.list(this.sessionManager.getCwd(), this.sessionManager.getSessionDir(), onProgress), (onProgress) => this.sessionManager.usesDefaultSessionDir()
|
|
3699
|
+
? SessionManager.listAll(onProgress)
|
|
3700
|
+
: SessionManager.listAll(this.sessionManager.getSessionDir(), onProgress), async (sessionPath) => {
|
|
3646
3701
|
done();
|
|
3647
3702
|
await this.handleResumeSession(sessionPath);
|
|
3648
3703
|
}, () => {
|
|
@@ -844,17 +844,27 @@ function buildCliHighlightTheme(t) {
|
|
|
844
844
|
built_in: (s) => t.fg("syntaxType", s),
|
|
845
845
|
literal: (s) => t.fg("syntaxNumber", s),
|
|
846
846
|
number: (s) => t.fg("syntaxNumber", s),
|
|
847
|
+
regexp: (s) => t.fg("syntaxString", s),
|
|
847
848
|
string: (s) => t.fg("syntaxString", s),
|
|
848
849
|
comment: (s) => t.fg("syntaxComment", s),
|
|
850
|
+
doctag: (s) => t.fg("syntaxComment", s),
|
|
851
|
+
meta: (s) => t.fg("muted", s),
|
|
849
852
|
function: (s) => t.fg("syntaxFunction", s),
|
|
850
853
|
title: (s) => t.fg("syntaxFunction", s),
|
|
851
854
|
class: (s) => t.fg("syntaxType", s),
|
|
852
855
|
type: (s) => t.fg("syntaxType", s),
|
|
856
|
+
tag: (s) => t.fg("syntaxPunctuation", s),
|
|
857
|
+
name: (s) => t.fg("syntaxKeyword", s),
|
|
853
858
|
attr: (s) => t.fg("syntaxVariable", s),
|
|
854
859
|
variable: (s) => t.fg("syntaxVariable", s),
|
|
855
860
|
params: (s) => t.fg("syntaxVariable", s),
|
|
856
861
|
operator: (s) => t.fg("syntaxOperator", s),
|
|
857
862
|
punctuation: (s) => t.fg("syntaxPunctuation", s),
|
|
863
|
+
emphasis: (s) => t.italic(s),
|
|
864
|
+
strong: (s) => t.bold(s),
|
|
865
|
+
link: (s) => t.underline(s),
|
|
866
|
+
addition: (s) => t.fg("toolDiffAdded", s),
|
|
867
|
+
deletion: (s) => t.fg("toolDiffRemoved", s),
|
|
858
868
|
};
|
|
859
869
|
}
|
|
860
870
|
function getCliHighlightTheme(t) {
|
|
@@ -48,6 +48,7 @@ export async function runPrintMode(runtimeHost, options) {
|
|
|
48
48
|
const rebindSession = async () => {
|
|
49
49
|
session = runtimeHost.session;
|
|
50
50
|
await session.bindExtensions({
|
|
51
|
+
mode: mode === "json" ? "json" : "print",
|
|
51
52
|
commandContextActions: {
|
|
52
53
|
waitForIdle: () => session.agent.waitForIdle(),
|
|
53
54
|
newSession: async (newSessionOptions) => runtimeHost.newSession(newSessionOptions),
|
|
@@ -228,6 +228,7 @@ export async function runRpcMode(runtimeHost) {
|
|
|
228
228
|
session = runtimeHost.session;
|
|
229
229
|
await session.bindExtensions({
|
|
230
230
|
uiContext: createExtensionUIContext(),
|
|
231
|
+
mode: "rpc",
|
|
231
232
|
commandContextActions: {
|
|
232
233
|
waitForIdle: () => session.agent.waitForIdle(),
|
|
233
234
|
newSession: async (options) => runtimeHost.newSession(options),
|
|
@@ -427,7 +428,9 @@ export async function runRpcMode(runtimeHost) {
|
|
|
427
428
|
// Bash
|
|
428
429
|
// =================================================================
|
|
429
430
|
case "bash": {
|
|
430
|
-
const result = await session.executeBash(command.command
|
|
431
|
+
const result = await session.executeBash(command.command, undefined, {
|
|
432
|
+
excludeFromContext: command.excludeFromContext,
|
|
433
|
+
});
|
|
431
434
|
return success(id, "bash", result);
|
|
432
435
|
}
|
|
433
436
|
case "abort_bash": {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
const emittedDeprecationWarnings = new Set();
|
|
3
|
+
export function warnDeprecation(message) {
|
|
4
|
+
if (emittedDeprecationWarnings.has(message))
|
|
5
|
+
return;
|
|
6
|
+
emittedDeprecationWarnings.add(message);
|
|
7
|
+
console.warn(chalk.yellow(`Deprecation warning: ${message}`));
|
|
8
|
+
}
|
|
9
|
+
/** Clear deprecation warning state. Exported for tests. */
|
|
10
|
+
export function clearDeprecationWarningsForTests() {
|
|
11
|
+
emittedDeprecationWarnings.clear();
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=deprecation.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Strip `//` line comments and trailing commas from JSON, leaving string literals untouched. */
|
|
2
|
+
export function stripJsonComments(input) {
|
|
3
|
+
return input
|
|
4
|
+
.replace(/"(?:\\.|[^"\\])*"|\/\/[^\n]*/g, (m) => (m[0] === '"' ? m : ""))
|
|
5
|
+
.replace(/"(?:\\.|[^"\\])*"|,(\s*[}\]])/g, (m, tail) => tail ?? (m[0] === '"' ? m : ""));
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=json.js.map
|