atom-lite 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +25 -14
- package/dist/agent/loop.d.ts +10 -0
- package/dist/agent/loop.js +114 -1
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/turn-recorder.d.ts +4 -0
- package/dist/agent/turn-recorder.js +1 -0
- package/dist/agent/turn-recorder.js.map +1 -1
- package/dist/agent/types.d.ts +22 -0
- package/dist/cli/app.js +160 -40
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/commands.js +180 -0
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/main.js +2 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/tool-box.js +3 -2
- package/dist/cli/tool-box.js.map +1 -1
- package/dist/config/defaults.js +1 -1
- package/dist/config/load.js +2 -2
- package/dist/config/load.js.map +1 -1
- package/dist/config/schema.d.ts +4 -0
- package/dist/config/schema.js +5 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/context/budget.js +19 -1
- package/dist/context/budget.js.map +1 -1
- package/dist/eval/runner.d.ts +51 -0
- package/dist/eval/runner.js +230 -0
- package/dist/eval/runner.js.map +1 -0
- package/dist/mcp/client.js +2 -1
- package/dist/mcp/client.js.map +1 -1
- package/dist/providers/context-window.d.ts +4 -0
- package/dist/providers/context-window.js +54 -0
- package/dist/providers/context-window.js.map +1 -1
- package/dist/providers/factory.js +3 -0
- package/dist/providers/factory.js.map +1 -1
- package/dist/providers/gemini.d.ts +2 -0
- package/dist/providers/gemini.js +18 -11
- package/dist/providers/gemini.js.map +1 -1
- package/dist/providers/ollama.d.ts +3 -0
- package/dist/providers/ollama.js +9 -0
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai-compatible.d.ts +2 -0
- package/dist/providers/openai-compatible.js +24 -3
- package/dist/providers/openai-compatible.js.map +1 -1
- package/dist/runtime/background-tasks.d.ts +23 -0
- package/dist/runtime/background-tasks.js +141 -0
- package/dist/runtime/background-tasks.js.map +1 -0
- package/dist/runtime/checkpoint-store.d.ts +64 -0
- package/dist/runtime/checkpoint-store.js +419 -0
- package/dist/runtime/checkpoint-store.js.map +1 -0
- package/dist/tools/bash.js +45 -9
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.js +28 -8
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read.js +70 -9
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/task.d.ts +2 -0
- package/dist/tools/task.js +55 -0
- package/dist/tools/task.js.map +1 -0
- package/dist/tools/types.d.ts +8 -1
- package/dist/tools/write.js +29 -8
- package/dist/tools/write.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -0
- package/dist/version.js +14 -0
- package/dist/version.js.map +1 -0
- package/package.json +3 -2
package/dist/cli/app.js
CHANGED
|
@@ -9,14 +9,15 @@ import { execSync, spawn } from "node:child_process";
|
|
|
9
9
|
import { defaultShell, terminateProcessTree } from "../security/process.js";
|
|
10
10
|
import { openSearchablePicker } from "./picker.js";
|
|
11
11
|
import { openCommandPalette } from "./palette.js";
|
|
12
|
-
import { bareCommandName, createCommandRegistry } from "./commands.js";
|
|
12
|
+
import { bareCommandName, createCommandRegistry, } from "./commands.js";
|
|
13
13
|
import { resolveTheme, themeLabel, themeNames, markdownThemeFor, } from "./theme.js";
|
|
14
14
|
import { SecretInput } from "./secret-input.js";
|
|
15
15
|
import { StatusLine } from "./status-line.js";
|
|
16
16
|
import { Activity } from "./activity.js";
|
|
17
17
|
import { ToolBox } from "./tool-box.js";
|
|
18
|
+
import { ApprovalPrompt } from "./approval-prompt.js";
|
|
18
19
|
import { Banner } from "./banner.js";
|
|
19
|
-
import { formatContextUsage, knownContextWindow, } from "../providers/context-window.js";
|
|
20
|
+
import { formatContextUsage, knownContextWindow, knownVisionModel, } from "../providers/context-window.js";
|
|
20
21
|
import { StreamText } from "./stream-text.js";
|
|
21
22
|
import { Transcript } from "./transcript.js";
|
|
22
23
|
import { AgentRuntime } from "../agent/loop.js";
|
|
@@ -28,8 +29,8 @@ import { ProjectTrustPrompt } from "./trust-prompt.js";
|
|
|
28
29
|
import { formatSessionList, formatSessionSearch, searchSessions, sessionTitleFromEvents, } from "../sessions/search.js";
|
|
29
30
|
import { providerSwitchNotice, sessionHistoryLines, sessionSelectionFromEvents, } from "../sessions/history.js";
|
|
30
31
|
import { blockAtLine, createMouseCapture, handleMouseEvent, parseSgrMouse, shouldEnableMouse, } from "./mouse.js";
|
|
31
|
-
import { readTool, writeTool, editTool, bashTool, webfetchTool, websearchTool, grepTool, globTool } from "../tools/index.js";
|
|
32
|
-
import { McpManager, formatMcpStatus, formatMcpDoctor, createMcpTools } from "../mcp/index.js";
|
|
32
|
+
import { readTool, writeTool, editTool, bashTool, webfetchTool, websearchTool, grepTool, globTool, taskTool, } from "../tools/index.js";
|
|
33
|
+
import { McpManager, formatMcpStatus, formatMcpDoctor, createMcpTools, } from "../mcp/index.js";
|
|
33
34
|
import { createProvider } from "../providers/factory.js";
|
|
34
35
|
import { availableProviderNames, getPreset, listModelsForProvider, materializeProviderConfig, probeApiKey, providerLabel, PROVIDER_PRESETS, } from "../providers/catalog.js";
|
|
35
36
|
import { ContextManager } from "../context/manager.js";
|
|
@@ -90,7 +91,8 @@ export async function run(args) {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
if (showVersion) {
|
|
93
|
-
|
|
94
|
+
const { VERSION } = await import("../version.js");
|
|
95
|
+
process.stdout.write(VERSION + "\n");
|
|
94
96
|
return;
|
|
95
97
|
}
|
|
96
98
|
if (listSessions || searchSessionsQuery !== undefined) {
|
|
@@ -125,12 +127,23 @@ export async function run(args) {
|
|
|
125
127
|
modelByProvider.set(provider.id, modelOverride);
|
|
126
128
|
const useTools = !positional.includes("__notools__");
|
|
127
129
|
const builtInTools = useTools
|
|
128
|
-
? [
|
|
130
|
+
? [
|
|
131
|
+
readTool,
|
|
132
|
+
writeTool,
|
|
133
|
+
editTool,
|
|
134
|
+
bashTool,
|
|
135
|
+
webfetchTool,
|
|
136
|
+
websearchTool,
|
|
137
|
+
grepTool,
|
|
138
|
+
globTool,
|
|
139
|
+
taskTool,
|
|
140
|
+
]
|
|
129
141
|
: [];
|
|
130
142
|
const interactive = process.stdin.isTTY === true && !jsonMode;
|
|
131
143
|
// one-shot task from positional or stdin
|
|
132
144
|
let stdinTask = "";
|
|
133
|
-
if (!process.stdin.isTTY &&
|
|
145
|
+
if (!process.stdin.isTTY &&
|
|
146
|
+
positional.filter((p) => !p.startsWith("__")).length === 0) {
|
|
134
147
|
const chunks = [];
|
|
135
148
|
for await (const chunk of process.stdin)
|
|
136
149
|
chunks.push(chunk);
|
|
@@ -140,9 +153,11 @@ export async function run(args) {
|
|
|
140
153
|
const oneShot = (taskArgs.join(" ").trim() || stdinTask).trim();
|
|
141
154
|
const store = new JsonlSessionStore();
|
|
142
155
|
let session = sessionOverride
|
|
143
|
-
? store.resume(sessionOverride) ??
|
|
156
|
+
? (store.resume(sessionOverride) ??
|
|
157
|
+
store.create(process.cwd(), provider.id))
|
|
144
158
|
: positional.includes("__continue__")
|
|
145
|
-
? store.resumeLatest(process.cwd()) ??
|
|
159
|
+
? (store.resumeLatest(process.cwd()) ??
|
|
160
|
+
store.create(process.cwd(), provider.id))
|
|
146
161
|
: store.create(process.cwd(), provider.id);
|
|
147
162
|
const mcpServers = (config.mcpServers ?? {});
|
|
148
163
|
const mcpManager = new McpManager({
|
|
@@ -165,7 +180,9 @@ export async function run(args) {
|
|
|
165
180
|
try {
|
|
166
181
|
const { execFileSync } = require("node:child_process");
|
|
167
182
|
const parts = value.slice(1).trim().split(/\s+/);
|
|
168
|
-
return execFileSync(parts[0], parts.slice(1), {
|
|
183
|
+
return execFileSync(parts[0], parts.slice(1), {
|
|
184
|
+
encoding: "utf8",
|
|
185
|
+
}).trim();
|
|
169
186
|
}
|
|
170
187
|
catch {
|
|
171
188
|
return undefined;
|
|
@@ -203,7 +220,7 @@ export async function run(args) {
|
|
|
203
220
|
// Bridge Pi-style extension providers into Atom-lite's config so they
|
|
204
221
|
// appear in /provider, /model, and the command palette.
|
|
205
222
|
for (const loaded of extensionLoader.list()) {
|
|
206
|
-
for (const [name, provider] of
|
|
223
|
+
for (const [name, provider] of loaded.registries?.providers ?? new Map()) {
|
|
207
224
|
const cfg = provider?.config ?? {};
|
|
208
225
|
const firstModel = Array.isArray(cfg.models) && cfg.models.length > 0
|
|
209
226
|
? (cfg.models[0].id ?? cfg.models[0].name ?? "default")
|
|
@@ -278,9 +295,14 @@ export async function run(args) {
|
|
|
278
295
|
contextManager,
|
|
279
296
|
extensionDispatch,
|
|
280
297
|
bashConcurrency: config.runtime.bashConcurrency,
|
|
298
|
+
checkpointingEnabled: interactive || Boolean(config.runtime.checkpointing),
|
|
281
299
|
});
|
|
282
300
|
mcpManager.onToolsChanged = () => {
|
|
283
|
-
runtime.setTools([
|
|
301
|
+
runtime.setTools([
|
|
302
|
+
...builtInTools,
|
|
303
|
+
...extensionTools,
|
|
304
|
+
...createMcpTools(mcpManager),
|
|
305
|
+
]);
|
|
284
306
|
};
|
|
285
307
|
if (oneShot || !interactive) {
|
|
286
308
|
// non-interactive / one-shot path
|
|
@@ -290,7 +312,11 @@ export async function run(args) {
|
|
|
290
312
|
try {
|
|
291
313
|
if (useTools) {
|
|
292
314
|
await mcpManager.syncTools();
|
|
293
|
-
runtime.setTools([
|
|
315
|
+
runtime.setTools([
|
|
316
|
+
...builtInTools,
|
|
317
|
+
...extensionTools,
|
|
318
|
+
...createMcpTools(mcpManager),
|
|
319
|
+
]);
|
|
294
320
|
}
|
|
295
321
|
const result = await runtime.runAgentTurn(oneShot || " ", session, controller.signal);
|
|
296
322
|
if (jsonMode) {
|
|
@@ -302,7 +328,9 @@ export async function run(args) {
|
|
|
302
328
|
}
|
|
303
329
|
catch (err) {
|
|
304
330
|
if (jsonMode)
|
|
305
|
-
process.stderr.write(JSON.stringify({
|
|
331
|
+
process.stderr.write(JSON.stringify({
|
|
332
|
+
error: err instanceof Error ? err.message : String(err),
|
|
333
|
+
}) + "\n");
|
|
306
334
|
else
|
|
307
335
|
process.stderr.write(`atom-lite: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
308
336
|
process.exit(1);
|
|
@@ -314,14 +342,16 @@ export async function run(args) {
|
|
|
314
342
|
return;
|
|
315
343
|
}
|
|
316
344
|
// ---- Interactive TUI (first-class) ----
|
|
317
|
-
const { TuiAltScreen, Text, Input, Editor, Container, Spacer, ScrollView, VStack, Loader, Markdown, Box } = await import("@earendil-works/pi-tui");
|
|
345
|
+
const { TuiAltScreen, Text, Input, Editor, Container, Spacer, ScrollView, VStack, Loader, Markdown, Box, } = await import("@earendil-works/pi-tui");
|
|
318
346
|
const mouseEnabled = shouldEnableMouse({
|
|
319
347
|
interactive,
|
|
320
348
|
configured: config.ui.mouse,
|
|
321
349
|
stdoutIsTTY: process.stdout.isTTY === true,
|
|
322
350
|
});
|
|
323
351
|
const terminal = new ProcessTerminal();
|
|
324
|
-
const tui = new TuiAltScreen(terminal, false, undefined, {
|
|
352
|
+
const tui = new TuiAltScreen(terminal, false, undefined, {
|
|
353
|
+
mouse: mouseEnabled,
|
|
354
|
+
});
|
|
325
355
|
const mouseCapture = createMouseCapture((data) => terminal.write(data));
|
|
326
356
|
let effortLevel = "medium";
|
|
327
357
|
runtime.setEffort(effortLevel);
|
|
@@ -349,9 +379,17 @@ export async function run(args) {
|
|
|
349
379
|
displayPath = "~" + cwd.slice(home.length);
|
|
350
380
|
let branch = "";
|
|
351
381
|
try {
|
|
352
|
-
branch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
382
|
+
branch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
383
|
+
cwd,
|
|
384
|
+
encoding: "utf8",
|
|
385
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
386
|
+
}).trim();
|
|
353
387
|
if (branch === "HEAD") {
|
|
354
|
-
branch = execSync("git rev-parse --short HEAD", {
|
|
388
|
+
branch = execSync("git rev-parse --short HEAD", {
|
|
389
|
+
cwd,
|
|
390
|
+
encoding: "utf8",
|
|
391
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
392
|
+
}).trim();
|
|
355
393
|
}
|
|
356
394
|
}
|
|
357
395
|
catch {
|
|
@@ -401,7 +439,9 @@ export async function run(args) {
|
|
|
401
439
|
const sig = skillCacheSignature(process.cwd());
|
|
402
440
|
if (sig === registrySkillSignature)
|
|
403
441
|
return;
|
|
404
|
-
commandRegistry = createCommandRegistry({
|
|
442
|
+
commandRegistry = createCommandRegistry({
|
|
443
|
+
skills: cachedSkillRegistry().list(),
|
|
444
|
+
});
|
|
405
445
|
registrySkillSignature = sig;
|
|
406
446
|
input.setAutocompleteProvider(new CombinedAutocompleteProvider(commandRegistry.autocomplete(), process.cwd(), fdPath));
|
|
407
447
|
}
|
|
@@ -433,7 +473,9 @@ export async function run(args) {
|
|
|
433
473
|
input.autocompleteList) {
|
|
434
474
|
const selected = input.autocompleteList.getSelectedItem?.();
|
|
435
475
|
const name = selected?.value ?? selected?.name ?? selected?.label;
|
|
436
|
-
const cmd = name
|
|
476
|
+
const cmd = name
|
|
477
|
+
? commandRegistry.get(String(name).replace(/^\//, ""))
|
|
478
|
+
: undefined;
|
|
437
479
|
if (cmd?.bareInvokable) {
|
|
438
480
|
originalHandleInput("\t");
|
|
439
481
|
return;
|
|
@@ -595,7 +637,11 @@ export async function run(args) {
|
|
|
595
637
|
try {
|
|
596
638
|
if (useTools) {
|
|
597
639
|
await mcpManager.syncTools();
|
|
598
|
-
runtime.setTools([
|
|
640
|
+
runtime.setTools([
|
|
641
|
+
...builtInTools,
|
|
642
|
+
...extensionTools,
|
|
643
|
+
...createMcpTools(mcpManager),
|
|
644
|
+
]);
|
|
599
645
|
}
|
|
600
646
|
const turnResult = await runtime.runAgentTurn(prompt, session, controller.signal);
|
|
601
647
|
if (turnResult === "TOKEN_BUDGET_REACHED") {
|
|
@@ -746,11 +792,21 @@ export async function run(args) {
|
|
|
746
792
|
function refreshContextWindow() {
|
|
747
793
|
const profile = provider.id;
|
|
748
794
|
const model = currentModelLabel();
|
|
749
|
-
const
|
|
750
|
-
const
|
|
751
|
-
|
|
795
|
+
const pcfg = profileConfig(profile);
|
|
796
|
+
const configuredWindow = pcfg?.contextWindow;
|
|
797
|
+
const window = typeof configuredWindow === "number" && configuredWindow > 0
|
|
798
|
+
? configuredWindow
|
|
752
799
|
: knownContextWindow(model);
|
|
753
800
|
runtime.setContextWindow(window);
|
|
801
|
+
// Config override for vision takes precedence over provider metadata.
|
|
802
|
+
if (typeof pcfg?.supportsVision === "boolean") {
|
|
803
|
+
runtime.setSupportsVision(pcfg.supportsVision);
|
|
804
|
+
}
|
|
805
|
+
else {
|
|
806
|
+
const guessed = knownVisionModel(model);
|
|
807
|
+
if (typeof guessed === "boolean")
|
|
808
|
+
runtime.setSupportsVision(guessed);
|
|
809
|
+
}
|
|
754
810
|
updateStatus();
|
|
755
811
|
const getModelInfo = provider.getModelInfo;
|
|
756
812
|
if (typeof getModelInfo !== "function")
|
|
@@ -761,10 +817,16 @@ export async function run(args) {
|
|
|
761
817
|
if (provider.id !== profile || currentModelLabel() !== model)
|
|
762
818
|
return;
|
|
763
819
|
const resolved = info?.contextWindow;
|
|
764
|
-
if (typeof resolved === "number" &&
|
|
820
|
+
if (typeof resolved === "number" &&
|
|
821
|
+
resolved > 0 &&
|
|
822
|
+
typeof configuredWindow !== "number") {
|
|
765
823
|
runtime.setContextWindow(resolved);
|
|
766
824
|
updateStatus();
|
|
767
825
|
}
|
|
826
|
+
if (typeof pcfg?.supportsVision !== "boolean" &&
|
|
827
|
+
typeof info?.supportsVision === "boolean") {
|
|
828
|
+
runtime.setSupportsVision(info.supportsVision);
|
|
829
|
+
}
|
|
768
830
|
})
|
|
769
831
|
.catch(() => {
|
|
770
832
|
// Keep the static/config fallback.
|
|
@@ -775,7 +837,7 @@ export async function run(args) {
|
|
|
775
837
|
const MODEL_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
776
838
|
const modelCache = new Map();
|
|
777
839
|
for (const loaded of extensionLoader.list()) {
|
|
778
|
-
for (const [name, provider] of
|
|
840
|
+
for (const [name, provider] of loaded.registries?.providers ?? new Map()) {
|
|
779
841
|
const cfg = provider?.config ?? {};
|
|
780
842
|
const models = Array.isArray(cfg.models)
|
|
781
843
|
? cfg.models.map((m) => m.id ?? m.name).filter(Boolean)
|
|
@@ -1011,7 +1073,11 @@ export async function run(args) {
|
|
|
1011
1073
|
provider = createProvider(config, preset.id, chosen);
|
|
1012
1074
|
runtime.switchModel(provider, chosen);
|
|
1013
1075
|
if (typeof session.appendEvent === "function") {
|
|
1014
|
-
session.appendEvent({
|
|
1076
|
+
session.appendEvent({
|
|
1077
|
+
type: "provider_selected",
|
|
1078
|
+
provider: preset.id,
|
|
1079
|
+
model: chosen,
|
|
1080
|
+
});
|
|
1015
1081
|
}
|
|
1016
1082
|
refreshContextWindow();
|
|
1017
1083
|
appendLine(`provider: ${preset.label} (${preset.id}) · model: ${chosen}`);
|
|
@@ -1262,7 +1328,9 @@ export async function run(args) {
|
|
|
1262
1328
|
return "No extensions discovered.";
|
|
1263
1329
|
return report
|
|
1264
1330
|
.map((ext) => {
|
|
1265
|
-
const origin = ext.origin
|
|
1331
|
+
const origin = ext.origin
|
|
1332
|
+
? `${ext.source}:${ext.origin}`
|
|
1333
|
+
: ext.source;
|
|
1266
1334
|
const version = ext.version ? `v${ext.version}` : "-";
|
|
1267
1335
|
const counts = `${ext.toolCount} tools / ${ext.commandCount} commands`;
|
|
1268
1336
|
const error = ext.error ? `\t${ext.error}` : "";
|
|
@@ -1280,7 +1348,9 @@ export async function run(args) {
|
|
|
1280
1348
|
return showThinking;
|
|
1281
1349
|
},
|
|
1282
1350
|
setTheme: setThemeTarget,
|
|
1283
|
-
listSkills: () => cachedSkillRegistry()
|
|
1351
|
+
listSkills: () => cachedSkillRegistry()
|
|
1352
|
+
.list()
|
|
1353
|
+
.map((skill) => ({
|
|
1284
1354
|
name: skill.name,
|
|
1285
1355
|
description: skill.description,
|
|
1286
1356
|
})),
|
|
@@ -1347,9 +1417,7 @@ export async function run(args) {
|
|
|
1347
1417
|
const summaries = scope === "all" ? store.list() : store.list(process.cwd());
|
|
1348
1418
|
const toggle = {
|
|
1349
1419
|
value: "__scope__",
|
|
1350
|
-
label: scope === "all"
|
|
1351
|
-
? "Show this workspace only"
|
|
1352
|
-
: "Show all workspaces",
|
|
1420
|
+
label: scope === "all" ? "Show this workspace only" : "Show all workspaces",
|
|
1353
1421
|
description: `scope: ${scope === "all" ? "all workspaces" : process.cwd()}`,
|
|
1354
1422
|
};
|
|
1355
1423
|
return [
|
|
@@ -1373,7 +1441,9 @@ export async function run(args) {
|
|
|
1373
1441
|
if (item.value === "__scope__") {
|
|
1374
1442
|
scope = scope === "all" ? "workspace" : "all";
|
|
1375
1443
|
picker.updateItems(buildItems());
|
|
1376
|
-
picker.setStatus(scope === "all"
|
|
1444
|
+
picker.setStatus(scope === "all"
|
|
1445
|
+
? "showing all workspaces"
|
|
1446
|
+
: "showing this workspace");
|
|
1377
1447
|
return;
|
|
1378
1448
|
}
|
|
1379
1449
|
picker.close();
|
|
@@ -1530,7 +1600,8 @@ export async function run(args) {
|
|
|
1530
1600
|
}
|
|
1531
1601
|
extensionProviderNames.clear();
|
|
1532
1602
|
for (const loaded of extensionLoader.list()) {
|
|
1533
|
-
for (const [name, provider] of
|
|
1603
|
+
for (const [name, provider] of loaded.registries?.providers ??
|
|
1604
|
+
new Map()) {
|
|
1534
1605
|
const cfg = provider?.config ?? {};
|
|
1535
1606
|
const firstModel = Array.isArray(cfg.models) && cfg.models.length > 0
|
|
1536
1607
|
? (cfg.models[0].id ?? cfg.models[0].name ?? "default")
|
|
@@ -1715,6 +1786,22 @@ export async function run(args) {
|
|
|
1715
1786
|
else if (e.type === "context_usage") {
|
|
1716
1787
|
updateStatus();
|
|
1717
1788
|
}
|
|
1789
|
+
else if (e.type === "background_task_complete") {
|
|
1790
|
+
appendLine(`background task ${e.id}: ${e.status} (exit ${e.exitCode ?? "null"})`, theme.tokens.dim);
|
|
1791
|
+
tui.requestRender();
|
|
1792
|
+
}
|
|
1793
|
+
else if (e.type === "checkpoint_created") {
|
|
1794
|
+
appendLine(`checkpoint ${e.id} created`, theme.tokens.dim);
|
|
1795
|
+
tui.requestRender();
|
|
1796
|
+
}
|
|
1797
|
+
else if (e.type === "checkpoint_failed") {
|
|
1798
|
+
appendLine(`checkpoint failed: ${e.reason}`, theme.tokens.warning);
|
|
1799
|
+
tui.requestRender();
|
|
1800
|
+
}
|
|
1801
|
+
else if (e.type === "checkpoint_unavailable") {
|
|
1802
|
+
appendLine(`checkpoint unavailable: ${e.reason ?? "not a git repository"}`, theme.tokens.warning);
|
|
1803
|
+
tui.requestRender();
|
|
1804
|
+
}
|
|
1718
1805
|
else if (e.type === "budget_warning") {
|
|
1719
1806
|
appendLine(`budget warning (${e.scope}): ${e.used}/${e.limit} tokens`, theme.tokens.warning);
|
|
1720
1807
|
tui.requestRender();
|
|
@@ -1722,7 +1809,11 @@ export async function run(args) {
|
|
|
1722
1809
|
else if (e.type === "model_switched") {
|
|
1723
1810
|
appendLine(`switched model to ${e.provider}/${e.model}`);
|
|
1724
1811
|
if (typeof session.appendEvent === "function") {
|
|
1725
|
-
session.appendEvent({
|
|
1812
|
+
session.appendEvent({
|
|
1813
|
+
type: "model_switched",
|
|
1814
|
+
provider: e.provider,
|
|
1815
|
+
model: e.model,
|
|
1816
|
+
});
|
|
1726
1817
|
}
|
|
1727
1818
|
updateStatus();
|
|
1728
1819
|
}
|
|
@@ -1768,7 +1859,11 @@ export async function run(args) {
|
|
|
1768
1859
|
lines.push(` config: FAIL ${e instanceof Error ? e.message : String(e)}`);
|
|
1769
1860
|
}
|
|
1770
1861
|
try {
|
|
1771
|
-
const r = await provider.generate({
|
|
1862
|
+
const r = await provider.generate({
|
|
1863
|
+
model: modelOverride ?? "default",
|
|
1864
|
+
messages: [{ role: "user", content: [{ type: "text", text: "ping" }] }],
|
|
1865
|
+
tools: [],
|
|
1866
|
+
});
|
|
1772
1867
|
lines.push(` provider generate: ok (${r.finishReason})`);
|
|
1773
1868
|
}
|
|
1774
1869
|
catch (e) {
|
|
@@ -1793,7 +1888,11 @@ export async function run(args) {
|
|
|
1793
1888
|
}
|
|
1794
1889
|
if (useTools) {
|
|
1795
1890
|
await mcpManager.syncTools();
|
|
1796
|
-
runtime.setTools([
|
|
1891
|
+
runtime.setTools([
|
|
1892
|
+
...builtInTools,
|
|
1893
|
+
...extensionTools,
|
|
1894
|
+
...createMcpTools(mcpManager),
|
|
1895
|
+
]);
|
|
1797
1896
|
}
|
|
1798
1897
|
appendLine(formatMcpStatus(mcpManager.status()));
|
|
1799
1898
|
return;
|
|
@@ -1901,7 +2000,9 @@ export async function run(args) {
|
|
|
1901
2000
|
for (const message of session.messages) {
|
|
1902
2001
|
if (message.role === "user") {
|
|
1903
2002
|
turn++;
|
|
1904
|
-
const snippet = redactText(messageText(message))
|
|
2003
|
+
const snippet = redactText(messageText(message))
|
|
2004
|
+
.split("\\n")[0]
|
|
2005
|
+
.slice(0, 80);
|
|
1905
2006
|
lines.push(`${turn}. ${snippet || "(empty)"}`);
|
|
1906
2007
|
}
|
|
1907
2008
|
}
|
|
@@ -2030,8 +2131,27 @@ export async function run(args) {
|
|
|
2030
2131
|
appendLine(`> ${trimmed}`, theme.tokens.user);
|
|
2031
2132
|
await runTurn(trimmed);
|
|
2032
2133
|
};
|
|
2033
|
-
|
|
2034
|
-
|
|
2134
|
+
approvals.handler = interactive
|
|
2135
|
+
? (req) => new Promise((resolve) => {
|
|
2136
|
+
uiModalOpen = true;
|
|
2137
|
+
closeOverlay();
|
|
2138
|
+
dropdownContainer.clear();
|
|
2139
|
+
activity.setPhase("waiting");
|
|
2140
|
+
const prompt = new ApprovalPrompt(req, (decision) => {
|
|
2141
|
+
uiModalOpen = false;
|
|
2142
|
+
dropdownContainer.clear();
|
|
2143
|
+
tui.setFocus(input);
|
|
2144
|
+
activity.setPhase("working");
|
|
2145
|
+
if (decision === "trust-session") {
|
|
2146
|
+
appendLine("trusted this session: outside-workspace operations will run without approval", theme.tokens.dim);
|
|
2147
|
+
}
|
|
2148
|
+
resolve(decision);
|
|
2149
|
+
});
|
|
2150
|
+
dropdownContainer.addChild(prompt);
|
|
2151
|
+
tui.setFocus(prompt);
|
|
2152
|
+
tui.requestRender();
|
|
2153
|
+
})
|
|
2154
|
+
: undefined;
|
|
2035
2155
|
process.on("SIGTERM", () => {
|
|
2036
2156
|
void mcpManager.close().finally(() => {
|
|
2037
2157
|
tui.stop();
|