scream-code 0.11.6 → 0.11.8
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.
|
@@ -7,7 +7,7 @@ import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } fr
|
|
|
7
7
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
8
8
|
import { C as join$1, D as resolve$1, E as relative$1, S as isAbsolute$1, T as parse$7, a as isSupportedFile, b as basename$1, i as ingestFile, r as ingestDirectory, t as multiSearch, w as normalize, x as dirname$2, y as KnowledgeStore } from "./src-BH9W5k24.mjs";
|
|
9
9
|
import { t as require_base64_js } from "./base64-js-DzVmk6Nb.mjs";
|
|
10
|
-
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
10
|
+
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-DYHGTG6m.mjs";
|
|
11
11
|
import { createRequire } from "node:module";
|
|
12
12
|
import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
13
13
|
import * as fs$1 from "node:fs/promises";
|
|
@@ -74934,7 +74934,7 @@ var BashTool = class {
|
|
|
74934
74934
|
},
|
|
74935
74935
|
approvalRule: literalRulePattern(this.name, args.command),
|
|
74936
74936
|
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.command),
|
|
74937
|
-
execute: (
|
|
74937
|
+
execute: (ctx) => this.execution(args, ctx)
|
|
74938
74938
|
};
|
|
74939
74939
|
}
|
|
74940
74940
|
spawn(effectiveCwd, command) {
|
|
@@ -74954,7 +74954,8 @@ var BashTool = class {
|
|
|
74954
74954
|
};
|
|
74955
74955
|
return this.jian.execWithEnv(shellArgs, mergedEnv);
|
|
74956
74956
|
}
|
|
74957
|
-
async execution(args,
|
|
74957
|
+
async execution(args, ctx) {
|
|
74958
|
+
const { signal, onUpdate } = ctx;
|
|
74958
74959
|
const completedBg = drainCompletedBackgroundTasks();
|
|
74959
74960
|
const bgPrefix = completedBg.length > 0 ? completedBg.map((t) => `[Background task ${t.id} completed] Command: ${t.command}\nExit code: ${String(t.exitCode)} (${(t.elapsedMs / 1e3).toFixed(1)}s)\nOutput:\n${t.output}\n---\n`).join("") : "";
|
|
74960
74961
|
if (signal.aborted) return {
|
|
@@ -74993,6 +74994,14 @@ var BashTool = class {
|
|
|
74993
74994
|
} catch {}
|
|
74994
74995
|
let aborted = false;
|
|
74995
74996
|
let killed = false;
|
|
74997
|
+
let streaming = true;
|
|
74998
|
+
const forwardChunk = (kind, text) => {
|
|
74999
|
+
if (!streaming || signal.aborted || onUpdate === void 0) return;
|
|
75000
|
+
onUpdate({
|
|
75001
|
+
kind,
|
|
75002
|
+
text
|
|
75003
|
+
});
|
|
75004
|
+
};
|
|
74996
75005
|
const killProc = async () => {
|
|
74997
75006
|
if (killed) return;
|
|
74998
75007
|
killed = true;
|
|
@@ -75030,17 +75039,39 @@ var BashTool = class {
|
|
|
75030
75039
|
return artifactPath;
|
|
75031
75040
|
} });
|
|
75032
75041
|
if (bgPrefix.length > 0) builder.write(bgPrefix);
|
|
75033
|
-
const completionPromise = Promise.all([Promise.all([readStreamIntoBuilder(proc.stdout, builder), readStreamIntoBuilder(proc.stderr, builder)]), proc.wait()]).then(([, exitCode]) => ({
|
|
75042
|
+
const completionPromise = Promise.all([Promise.all([readStreamIntoBuilder(proc.stdout, builder, (text) => forwardChunk("stdout", text)), readStreamIntoBuilder(proc.stderr, builder, (text) => forwardChunk("stderr", text))]), proc.wait()]).then(([, exitCode]) => ({
|
|
75034
75043
|
timedOut: false,
|
|
75035
75044
|
exitCode
|
|
75036
75045
|
}));
|
|
75037
75046
|
const raceResult = timeoutMs !== void 0 ? await Promise.race([completionPromise, timeoutPromise]) : await completionPromise;
|
|
75038
75047
|
if (raceResult.timedOut) {
|
|
75048
|
+
streaming = false;
|
|
75039
75049
|
const timeoutLabel = timeoutMs % 1e3 === 0 ? `${String(timeoutMs / 1e3)}s` : `${String(timeoutMs)}ms`;
|
|
75040
75050
|
const taskId = createBackgroundTask(command, completionPromise.then(({ exitCode }) => ({
|
|
75041
75051
|
exitCode,
|
|
75042
75052
|
output: builder.toString()
|
|
75043
75053
|
})));
|
|
75054
|
+
if (onUpdate !== void 0) completionPromise.then(({ exitCode }) => {
|
|
75055
|
+
onUpdate({
|
|
75056
|
+
kind: "custom",
|
|
75057
|
+
customKind: "background.task.terminated",
|
|
75058
|
+
customData: {
|
|
75059
|
+
id: taskId,
|
|
75060
|
+
command,
|
|
75061
|
+
exitCode
|
|
75062
|
+
}
|
|
75063
|
+
});
|
|
75064
|
+
}, () => {
|
|
75065
|
+
onUpdate({
|
|
75066
|
+
kind: "custom",
|
|
75067
|
+
customKind: "background.task.terminated",
|
|
75068
|
+
customData: {
|
|
75069
|
+
id: taskId,
|
|
75070
|
+
command,
|
|
75071
|
+
exitCode: -1
|
|
75072
|
+
}
|
|
75073
|
+
});
|
|
75074
|
+
});
|
|
75044
75075
|
const outputSoFar = builder.toString();
|
|
75045
75076
|
return {
|
|
75046
75077
|
output: `Command timed out after ${timeoutLabel} but is still running in the background (task: ${taskId}).\nOutput so far (${String(builder.nChars)} chars):\n${outputSoFar}\n---\nThe command will complete in the background. The result will be included in your next Bash call.`,
|
|
@@ -75138,13 +75169,33 @@ human_shell_hint: Tell the human to run /tasks to open the interactive backgroun
|
|
|
75138
75169
|
return builder.ok("Background task started", { brief: `Started ${taskId}` });
|
|
75139
75170
|
}
|
|
75140
75171
|
};
|
|
75141
|
-
|
|
75172
|
+
const LIVE_OUTPUT_FLUSH_MS = 100;
|
|
75173
|
+
async function readStreamIntoBuilder(stream, builder, onChunk) {
|
|
75142
75174
|
const decoder = new StringDecoder("utf8");
|
|
75175
|
+
let pending = "";
|
|
75176
|
+
let lastFlush = 0;
|
|
75177
|
+
const flush = (force) => {
|
|
75178
|
+
if (pending.length === 0) return;
|
|
75179
|
+
if (!force && Date.now() - lastFlush < LIVE_OUTPUT_FLUSH_MS) return;
|
|
75180
|
+
onChunk?.(pending);
|
|
75181
|
+
pending = "";
|
|
75182
|
+
lastFlush = Date.now();
|
|
75183
|
+
};
|
|
75143
75184
|
for await (const chunk of stream) {
|
|
75144
75185
|
const buf = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
75145
|
-
|
|
75186
|
+
const text = decoder.write(buf);
|
|
75187
|
+
builder.write(text);
|
|
75188
|
+
if (onChunk !== void 0) {
|
|
75189
|
+
pending += text;
|
|
75190
|
+
flush(false);
|
|
75191
|
+
}
|
|
75192
|
+
}
|
|
75193
|
+
const tail = decoder.end();
|
|
75194
|
+
builder.write(tail);
|
|
75195
|
+
if (onChunk !== void 0) {
|
|
75196
|
+
pending += tail;
|
|
75197
|
+
flush(true);
|
|
75146
75198
|
}
|
|
75147
|
-
builder.write(decoder.end());
|
|
75148
75199
|
}
|
|
75149
75200
|
function shellQuote$1(s) {
|
|
75150
75201
|
return `'${s.replaceAll("'", "'\\''")}'`;
|
|
@@ -119182,6 +119233,77 @@ function parsePositiveInt(value) {
|
|
|
119182
119233
|
return n;
|
|
119183
119234
|
}
|
|
119184
119235
|
//#endregion
|
|
119236
|
+
//#region ../../packages/agent-core/src/session/provider-balance.ts
|
|
119237
|
+
const fetchers = [{
|
|
119238
|
+
matches: (baseUrl) => {
|
|
119239
|
+
try {
|
|
119240
|
+
return new URL(baseUrl).hostname === "api.deepseek.com";
|
|
119241
|
+
} catch {
|
|
119242
|
+
return false;
|
|
119243
|
+
}
|
|
119244
|
+
},
|
|
119245
|
+
fetch: async (baseUrl, apiKey) => {
|
|
119246
|
+
try {
|
|
119247
|
+
const root = new URL(baseUrl).origin;
|
|
119248
|
+
const res = await fetch(`${root}/user/balance`, {
|
|
119249
|
+
headers: {
|
|
119250
|
+
Accept: "application/json",
|
|
119251
|
+
Authorization: `Bearer ${apiKey}`
|
|
119252
|
+
},
|
|
119253
|
+
signal: AbortSignal.timeout(5e3)
|
|
119254
|
+
});
|
|
119255
|
+
if (!res.ok) return null;
|
|
119256
|
+
const info = (await res.json()).balance_infos?.[0];
|
|
119257
|
+
if (info?.total_balance === void 0) return null;
|
|
119258
|
+
return {
|
|
119259
|
+
currency: info.currency ?? "",
|
|
119260
|
+
totalBalance: info.total_balance
|
|
119261
|
+
};
|
|
119262
|
+
} catch {
|
|
119263
|
+
return null;
|
|
119264
|
+
}
|
|
119265
|
+
}
|
|
119266
|
+
}, {
|
|
119267
|
+
matches: (baseUrl) => {
|
|
119268
|
+
try {
|
|
119269
|
+
return new URL(baseUrl).hostname === "api.moonshot.cn";
|
|
119270
|
+
} catch {
|
|
119271
|
+
return false;
|
|
119272
|
+
}
|
|
119273
|
+
},
|
|
119274
|
+
fetch: async (baseUrl, apiKey) => {
|
|
119275
|
+
try {
|
|
119276
|
+
const root = new URL(baseUrl).origin;
|
|
119277
|
+
const res = await fetch(`${root}/v1/users/me/balance`, {
|
|
119278
|
+
headers: {
|
|
119279
|
+
Accept: "application/json",
|
|
119280
|
+
Authorization: `Bearer ${apiKey}`
|
|
119281
|
+
},
|
|
119282
|
+
signal: AbortSignal.timeout(5e3)
|
|
119283
|
+
});
|
|
119284
|
+
if (!res.ok) return null;
|
|
119285
|
+
const data = await res.json();
|
|
119286
|
+
if (typeof data.data?.available_balance !== "number") return null;
|
|
119287
|
+
return {
|
|
119288
|
+
currency: "CNY",
|
|
119289
|
+
totalBalance: data.data.available_balance.toFixed(2)
|
|
119290
|
+
};
|
|
119291
|
+
} catch {
|
|
119292
|
+
return null;
|
|
119293
|
+
}
|
|
119294
|
+
}
|
|
119295
|
+
}];
|
|
119296
|
+
/**
|
|
119297
|
+
* Look up the balance for the given provider endpoint.
|
|
119298
|
+
* Returns null when the endpoint is not a recognized official vendor or
|
|
119299
|
+
* when the lookup fails — callers render nothing in that case.
|
|
119300
|
+
*/
|
|
119301
|
+
async function fetchProviderBalance(baseUrl, apiKey) {
|
|
119302
|
+
const fetcher = fetchers.find((f) => f.matches(baseUrl));
|
|
119303
|
+
if (!fetcher) return null;
|
|
119304
|
+
return fetcher.fetch(baseUrl, apiKey);
|
|
119305
|
+
}
|
|
119306
|
+
//#endregion
|
|
119185
119307
|
//#region ../../packages/node-sdk/src/auth.ts
|
|
119186
119308
|
var ScreamAuthFacade = class {
|
|
119187
119309
|
options;
|
|
@@ -120602,7 +120724,7 @@ function optionalBuildString(value) {
|
|
|
120602
120724
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
120603
120725
|
}
|
|
120604
120726
|
const SCREAM_BUILD_INFO = {
|
|
120605
|
-
version: optionalBuildString("0.11.
|
|
120727
|
+
version: optionalBuildString("0.11.8"),
|
|
120606
120728
|
channel: optionalBuildString(""),
|
|
120607
120729
|
commit: optionalBuildString(""),
|
|
120608
120730
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -120867,11 +120989,15 @@ const NotificationsConfigSchema = z.object({
|
|
|
120867
120989
|
const TuiLikePreferencesSchema = z.object({
|
|
120868
120990
|
nickname: z.string().optional(),
|
|
120869
120991
|
tone: z.string().optional(),
|
|
120870
|
-
other: z.string().optional()
|
|
120992
|
+
other: z.string().optional(),
|
|
120993
|
+
/** Explicit prohibitions: things the user does NOT want done. */
|
|
120994
|
+
doNot: z.string().optional()
|
|
120871
120995
|
});
|
|
120872
120996
|
const TuiConfigFileSchema = z.object({
|
|
120873
120997
|
theme: TuiThemeSchema.optional(),
|
|
120874
120998
|
language: z.enum(["zh", "en"]).optional(),
|
|
120999
|
+
/** Auto-enter the welcome page after the loading splash finishes. */
|
|
121000
|
+
autoStart: z.boolean().optional(),
|
|
120875
121001
|
editor: z.object({ command: z.string().optional() }).optional(),
|
|
120876
121002
|
notifications: z.object({
|
|
120877
121003
|
enabled: z.boolean().optional(),
|
|
@@ -120887,6 +121013,7 @@ const TuiConfigFileSchema = z.object({
|
|
|
120887
121013
|
const TuiConfigSchema = z.object({
|
|
120888
121014
|
theme: TuiThemeSchema,
|
|
120889
121015
|
language: z.enum(["zh", "en"]),
|
|
121016
|
+
autoStart: z.boolean(),
|
|
120890
121017
|
editorCommand: z.string().nullable(),
|
|
120891
121018
|
notifications: NotificationsConfigSchema,
|
|
120892
121019
|
like: TuiLikePreferencesSchema,
|
|
@@ -120903,6 +121030,7 @@ const DEFAULT_NOTIFICATIONS_CONFIG = {
|
|
|
120903
121030
|
const DEFAULT_TUI_CONFIG = TuiConfigSchema.parse({
|
|
120904
121031
|
theme: "auto",
|
|
120905
121032
|
language: getLocale(),
|
|
121033
|
+
autoStart: false,
|
|
120906
121034
|
editorCommand: null,
|
|
120907
121035
|
notifications: DEFAULT_NOTIFICATIONS_CONFIG,
|
|
120908
121036
|
like: {},
|
|
@@ -120955,6 +121083,7 @@ function normalizeTuiConfig(config) {
|
|
|
120955
121083
|
return TuiConfigSchema.parse({
|
|
120956
121084
|
theme: config.theme ?? DEFAULT_TUI_CONFIG.theme,
|
|
120957
121085
|
language: config.language ?? DEFAULT_TUI_CONFIG.language,
|
|
121086
|
+
autoStart: config.autoStart ?? DEFAULT_TUI_CONFIG.autoStart,
|
|
120958
121087
|
editorCommand: command === void 0 || command.length === 0 ? null : command,
|
|
120959
121088
|
notifications: {
|
|
120960
121089
|
enabled: config.notifications?.enabled ?? DEFAULT_NOTIFICATIONS_CONFIG.enabled,
|
|
@@ -120998,6 +121127,7 @@ function renderTuiConfig(config) {
|
|
|
120998
121127
|
|
|
120999
121128
|
theme = "${config.theme}" # "auto" | "dark" | "light"
|
|
121000
121129
|
language = "${config.language}" # "zh" | "en"
|
|
121130
|
+
autoStart = ${String(config.autoStart)} # true = auto-enter welcome after loading
|
|
121001
121131
|
|
|
121002
121132
|
[editor]
|
|
121003
121133
|
command = "${escapeTomlBasicString(config.editorCommand ?? "")}" # Empty uses $VISUAL / $EDITOR
|
|
@@ -123250,7 +123380,7 @@ function mountProfileList(host) {
|
|
|
123250
123380
|
const { subagentModels: bindings, availableModels } = host.state.appState;
|
|
123251
123381
|
const options = getSubagentProfiles().map((profile) => {
|
|
123252
123382
|
const alias = bindings[profile.name];
|
|
123253
|
-
const bindingLabel = alias === void 0 ? t("subagent.follow_main") : modelDisplayName$1(alias, availableModels[alias]);
|
|
123383
|
+
const bindingLabel = alias === void 0 ? t("subagent.follow_main") : availableModels[alias] !== void 0 ? modelDisplayName$1(alias, availableModels[alias]) : t("subagent.stale_binding", { alias });
|
|
123254
123384
|
return {
|
|
123255
123385
|
value: profile.name,
|
|
123256
123386
|
label: `${profile.name} → ${bindingLabel}`,
|
|
@@ -123304,6 +123434,10 @@ async function applyBinding(host, profileName, value) {
|
|
|
123304
123434
|
const configPath = getTuiConfigPath();
|
|
123305
123435
|
try {
|
|
123306
123436
|
const current = await loadTuiConfig(configPath);
|
|
123437
|
+
if (value !== FOLLOW_MAIN && host.state.appState.availableModels[value] === void 0) {
|
|
123438
|
+
host.showError(t("subagent.invalid_alias", { alias: value }));
|
|
123439
|
+
return;
|
|
123440
|
+
}
|
|
123307
123441
|
const updated = { ...current.subagentModels };
|
|
123308
123442
|
if (value === FOLLOW_MAIN) delete updated[profileName];
|
|
123309
123443
|
else updated[profileName] = value;
|
|
@@ -123813,14 +123947,33 @@ function formatTokenCount(n) {
|
|
|
123813
123947
|
function safeUsage(usage) {
|
|
123814
123948
|
return safeUsageRatio(usage);
|
|
123815
123949
|
}
|
|
123950
|
+
const CONTEXT_BAR_WIDTH = 10;
|
|
123951
|
+
const CONTEXT_BAR_FILLED = "▰";
|
|
123952
|
+
const CONTEXT_BAR_EMPTY = "▱";
|
|
123953
|
+
function currencySymbol(currency) {
|
|
123954
|
+
if (currency === "CNY") return "¥";
|
|
123955
|
+
if (currency === "USD") return "$";
|
|
123956
|
+
return `${currency} `;
|
|
123957
|
+
}
|
|
123958
|
+
/**
|
|
123959
|
+
* Half-block progress bar for context usage: `▰▰▰▱▱▱▱▱▱▱` (10 cells).
|
|
123960
|
+
* Filled cells are rounded from the clamped ratio, so 0% is all-empty and
|
|
123961
|
+
* >=100% is all-filled; NaN/undefined coerce through safeUsageRatio first.
|
|
123962
|
+
*/
|
|
123963
|
+
function formatContextBar(usage, width = CONTEXT_BAR_WIDTH) {
|
|
123964
|
+
const clamped = Math.min(1, Math.max(0, safeUsageRatio(usage)));
|
|
123965
|
+
const filled = Math.round(clamped * width);
|
|
123966
|
+
return CONTEXT_BAR_FILLED.repeat(filled) + CONTEXT_BAR_EMPTY.repeat(width - filled);
|
|
123967
|
+
}
|
|
123816
123968
|
function formatContextStatus(usage, tokens, maxTokens) {
|
|
123817
123969
|
const pct = `${(safeUsage(usage) * 100).toFixed(1)}%`;
|
|
123970
|
+
const barAndPct = `${formatContextBar(usage)} ${pct}`;
|
|
123818
123971
|
if (maxTokens && maxTokens > 0 && tokens !== void 0) return t("footer.context", {
|
|
123819
|
-
pct,
|
|
123972
|
+
pct: barAndPct,
|
|
123820
123973
|
tokens: formatTokenCount(tokens),
|
|
123821
123974
|
maxTokens: formatTokenCount(maxTokens)
|
|
123822
123975
|
});
|
|
123823
|
-
return t("footer.context_short", { pct });
|
|
123976
|
+
return t("footer.context_short", { pct: barAndPct });
|
|
123824
123977
|
}
|
|
123825
123978
|
/** Format goal wall-clock duration compactly: `3m`, `1m30s`, `45s`. */
|
|
123826
123979
|
function formatGoalDuration(ms) {
|
|
@@ -124023,8 +124176,12 @@ var FooterComponent = class {
|
|
|
124023
124176
|
left.push(chalk.hex(colors.primary).bold(goalLabel));
|
|
124024
124177
|
}
|
|
124025
124178
|
const model = shortenModel(modelDisplayName(state));
|
|
124026
|
-
if (model)
|
|
124027
|
-
|
|
124179
|
+
if (model) {
|
|
124180
|
+
if (state.streamingPhase === "thinking") left.push(shimmerText(model, colors));
|
|
124181
|
+
else left.push(chalk.hex(colors.textDim)(model));
|
|
124182
|
+
const balance = state.providerBalance;
|
|
124183
|
+
if (balance !== null && balance !== void 0) left.push(chalk.hex(colors.textDim)(`${currencySymbol(balance.currency)}${balance.totalBalance}`));
|
|
124184
|
+
}
|
|
124028
124185
|
if (this.backgroundBashTaskCount > 0) left.push(chalk.hex(colors.primary)(`[${t("footer.tasks_running", { count: String(this.backgroundBashTaskCount) })}]`));
|
|
124029
124186
|
if (this.backgroundAgentCount > 0) left.push(chalk.hex(colors.primary)(`[${t("footer.agents_running", { count: String(this.backgroundAgentCount) })}]`));
|
|
124030
124187
|
const git = this.gitCache.getStatus();
|
|
@@ -124093,6 +124250,7 @@ async function applyLanguageChoice(host, locale) {
|
|
|
124093
124250
|
setLocale(locale);
|
|
124094
124251
|
host.state.appState.language = locale;
|
|
124095
124252
|
await saveTuiConfig({
|
|
124253
|
+
...await loadTuiConfig(),
|
|
124096
124254
|
theme: host.state.appState.theme,
|
|
124097
124255
|
language: locale,
|
|
124098
124256
|
editorCommand: host.state.appState.editorCommand,
|
|
@@ -124470,6 +124628,7 @@ function createMarkdownTheme(colors) {
|
|
|
124470
124628
|
quote: (text) => chalk.hex(colors.mdQuote)(text),
|
|
124471
124629
|
quoteBorder: (text) => chalk.hex(colors.mdQuote)(text),
|
|
124472
124630
|
hr: (text) => border(text),
|
|
124631
|
+
tableHeader: (text) => chalk.bold.hex(colors.accent)(text),
|
|
124473
124632
|
listBullet: (text) => chalk.hex(colors.roleAssistant)(text.replace(/^-/, "•")),
|
|
124474
124633
|
bold: (text) => chalk.bold(text),
|
|
124475
124634
|
italic: (text) => chalk.italic(text),
|
|
@@ -124861,6 +125020,84 @@ async function loadManagedUsageReport(host) {
|
|
|
124861
125020
|
} };
|
|
124862
125021
|
}
|
|
124863
125022
|
//#endregion
|
|
125023
|
+
//#region src/tui/api-balance.ts
|
|
125024
|
+
/**
|
|
125025
|
+
* TUI-side provider balance lookup.
|
|
125026
|
+
*
|
|
125027
|
+
* Reads the runtime config.toml (same file the engine consumes), resolves
|
|
125028
|
+
* the plaintext API key (direct value or the provider's ENV_VAR env
|
|
125029
|
+
* reference), and delegates the actual query to the engine's
|
|
125030
|
+
* fetchProviderBalance. Results are cached briefly so footer renders do
|
|
125031
|
+
* not hammer the vendor endpoint.
|
|
125032
|
+
*/
|
|
125033
|
+
const BALANCE_CACHE_MS = 6e4;
|
|
125034
|
+
const cache = /* @__PURE__ */ new Map();
|
|
125035
|
+
/** Monotonic id so an out-of-order lookup can never overwrite a newer one. */
|
|
125036
|
+
let latestRequestId = 0;
|
|
125037
|
+
function resolveApiKey(providerName) {
|
|
125038
|
+
const provider = readConfigFile(join(getDataDir(), "config.toml")).providers?.[providerName];
|
|
125039
|
+
if (!provider) return void 0;
|
|
125040
|
+
const direct = provider.apiKey?.trim();
|
|
125041
|
+
if (direct !== void 0 && direct.length > 0) return direct;
|
|
125042
|
+
const envKey = envKeyForProviderType(provider.type);
|
|
125043
|
+
const stored = envKey !== void 0 ? provider.env?.[envKey]?.trim() : void 0;
|
|
125044
|
+
return stored !== void 0 && stored.length > 0 ? stored : void 0;
|
|
125045
|
+
}
|
|
125046
|
+
function envKeyForProviderType(type) {
|
|
125047
|
+
switch (type) {
|
|
125048
|
+
case "anthropic": return "ANTHROPIC_API_KEY";
|
|
125049
|
+
case "openai":
|
|
125050
|
+
case "openai_responses": return "OPENAI_API_KEY";
|
|
125051
|
+
case "scream": return "SCREAM_API_KEY";
|
|
125052
|
+
case "google-genai": return "GOOGLE_API_KEY";
|
|
125053
|
+
case "vertexai": return "VERTEXAI_API_KEY";
|
|
125054
|
+
default: return;
|
|
125055
|
+
}
|
|
125056
|
+
}
|
|
125057
|
+
async function loadBalance(providerName) {
|
|
125058
|
+
try {
|
|
125059
|
+
const provider = readConfigFile(join(getDataDir(), "config.toml")).providers?.[providerName];
|
|
125060
|
+
if (!provider?.baseUrl) return null;
|
|
125061
|
+
const apiKey = resolveApiKey(providerName);
|
|
125062
|
+
if (apiKey === void 0) return null;
|
|
125063
|
+
return await fetchProviderBalance(provider.baseUrl, apiKey);
|
|
125064
|
+
} catch {
|
|
125065
|
+
return null;
|
|
125066
|
+
}
|
|
125067
|
+
}
|
|
125068
|
+
/**
|
|
125069
|
+
* Look up the balance for the provider that serves the given model
|
|
125070
|
+
* (model names follow the "provider/model" convention). Returns null when
|
|
125071
|
+
* the provider is unknown, unofficial, or the lookup failed — callers
|
|
125072
|
+
* render nothing in that case. Cached for BALANCE_CACHE_MS per provider.
|
|
125073
|
+
*/
|
|
125074
|
+
async function getProviderBalanceForModel(model) {
|
|
125075
|
+
const providerName = model.split("/")[0] ?? "";
|
|
125076
|
+
if (providerName.length === 0) return null;
|
|
125077
|
+
const cached = cache.get(providerName);
|
|
125078
|
+
if (cached !== void 0 && Date.now() - cached.at < BALANCE_CACHE_MS) return cached.balance;
|
|
125079
|
+
const balance = await loadBalance(providerName);
|
|
125080
|
+
cache.set(providerName, {
|
|
125081
|
+
balance,
|
|
125082
|
+
at: Date.now()
|
|
125083
|
+
});
|
|
125084
|
+
return balance;
|
|
125085
|
+
}
|
|
125086
|
+
/**
|
|
125087
|
+
* Fetch the balance for a model and push it into app state. Fire-and-forget:
|
|
125088
|
+
* failures resolve to null inside getProviderBalanceForModel, so callers
|
|
125089
|
+
* (startup sync and model switches) never await it. A request id guards
|
|
125090
|
+
* against out-of-order resolutions: when the user switches models quickly,
|
|
125091
|
+
* only the latest lookup's result is committed.
|
|
125092
|
+
*/
|
|
125093
|
+
function refreshProviderBalance(model, setAppState) {
|
|
125094
|
+
const requestId = ++latestRequestId;
|
|
125095
|
+
getProviderBalanceForModel(model).then((balance) => {
|
|
125096
|
+
if (requestId !== latestRequestId) return;
|
|
125097
|
+
setAppState({ providerBalance: balance });
|
|
125098
|
+
});
|
|
125099
|
+
}
|
|
125100
|
+
//#endregion
|
|
124864
125101
|
//#region src/tui/commands/config.ts
|
|
124865
125102
|
/**
|
|
124866
125103
|
* Storm Breaker guard for model switches. Returns the (currentTokens,
|
|
@@ -125159,6 +125396,7 @@ async function applyEditorChoice(host, value) {
|
|
|
125159
125396
|
const editorCommand = value.length > 0 ? value : null;
|
|
125160
125397
|
try {
|
|
125161
125398
|
await saveTuiConfig({
|
|
125399
|
+
...await loadTuiConfig(),
|
|
125162
125400
|
theme: host.state.appState.theme,
|
|
125163
125401
|
language: host.state.appState.language,
|
|
125164
125402
|
editorCommand,
|
|
@@ -125286,8 +125524,10 @@ async function performModelSwitch(host, alias, thinkingLevel) {
|
|
|
125286
125524
|
}
|
|
125287
125525
|
host.setAppState({
|
|
125288
125526
|
model: effectiveAlias,
|
|
125289
|
-
thinkingLevel: effectiveThinking
|
|
125527
|
+
thinkingLevel: effectiveThinking,
|
|
125528
|
+
providerBalance: null
|
|
125290
125529
|
});
|
|
125530
|
+
refreshProviderBalance(effectiveAlias, (patch) => host.setAppState(patch));
|
|
125291
125531
|
let persisted = false;
|
|
125292
125532
|
try {
|
|
125293
125533
|
persisted = await persistModelSelection(host, alias, thinkingLevel);
|
|
@@ -125344,6 +125584,7 @@ async function applyThemeChoice(host, theme) {
|
|
|
125344
125584
|
}
|
|
125345
125585
|
try {
|
|
125346
125586
|
await saveTuiConfig({
|
|
125587
|
+
...await loadTuiConfig(),
|
|
125347
125588
|
theme,
|
|
125348
125589
|
language: host.state.appState.language,
|
|
125349
125590
|
editorCommand: host.state.appState.editorCommand,
|
|
@@ -126121,7 +126362,7 @@ async function guidedGoalSetup(host) {
|
|
|
126121
126362
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
126122
126363
|
return;
|
|
126123
126364
|
}
|
|
126124
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
126365
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DX3hKoBF.mjs");
|
|
126125
126366
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
126126
126367
|
title: t("goal.setup_title_initial"),
|
|
126127
126368
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -126142,7 +126383,7 @@ async function guidedGoalSetup(host) {
|
|
|
126142
126383
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
126143
126384
|
}
|
|
126144
126385
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
126145
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
126386
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DX3hKoBF.mjs");
|
|
126146
126387
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
126147
126388
|
title: t("goal.wizard_title", { objective }),
|
|
126148
126389
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -128529,7 +128770,7 @@ const globGlance = (_toolCall, result, colors) => {
|
|
|
128529
128770
|
const more = names.length - GLANCE_SAMPLES;
|
|
128530
128771
|
return `${head}${shown}${more > 0 ? dim(` (+${String(more)})`) : ""}`;
|
|
128531
128772
|
}).join(dim(" "));
|
|
128532
|
-
const extLine = [...countExtensions(lines).entries()].
|
|
128773
|
+
const extLine = [...countExtensions(lines).entries()].toSorted((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).slice(0, MAX_EXTENSION_COUNTS).map(([ext, count]) => `${dim(ext)}:${dim(` ${String(count)}`)}`).join(dim(", "));
|
|
128533
128774
|
if (extLine.length === 0) return dirLine;
|
|
128534
128775
|
return `${dirLine}${dim(" ")}${extLine}`;
|
|
128535
128776
|
};
|
|
@@ -128559,8 +128800,56 @@ const readGlance = (toolCall, result, colors) => {
|
|
|
128559
128800
|
if (parts.length === 0) return "";
|
|
128560
128801
|
return parts.join(dim(" · "));
|
|
128561
128802
|
};
|
|
128803
|
+
/**
|
|
128804
|
+
* Parse the fixed WebSearch output protocol emitted by
|
|
128805
|
+
* `web-search.ts` (`Title: …` / `Date: …` / `URL: …` / `Snippet: …`,
|
|
128806
|
+
* entries separated by `---`) into structured entries so the collapsed
|
|
128807
|
+
* card can show a title/URL glance instead of a bare "N results" chip.
|
|
128808
|
+
*/
|
|
128809
|
+
function parseWebSearchOutput(output) {
|
|
128810
|
+
const entries = [];
|
|
128811
|
+
let title;
|
|
128812
|
+
let url;
|
|
128813
|
+
let inSnippet = false;
|
|
128814
|
+
for (const line of output.split("\n")) {
|
|
128815
|
+
if (line.startsWith("---")) {
|
|
128816
|
+
if (title !== void 0 || url !== void 0) entries.push({
|
|
128817
|
+
title: title ?? "",
|
|
128818
|
+
url: url ?? ""
|
|
128819
|
+
});
|
|
128820
|
+
title = void 0;
|
|
128821
|
+
url = void 0;
|
|
128822
|
+
inSnippet = false;
|
|
128823
|
+
continue;
|
|
128824
|
+
}
|
|
128825
|
+
if (inSnippet) continue;
|
|
128826
|
+
if (line.startsWith("Snippet: ")) inSnippet = true;
|
|
128827
|
+
else if (line.startsWith("Title: ")) title = line.slice(7);
|
|
128828
|
+
else if (line.startsWith("URL: ")) url = line.slice(5);
|
|
128829
|
+
}
|
|
128830
|
+
if (title !== void 0 || url !== void 0) entries.push({
|
|
128831
|
+
title: title ?? "",
|
|
128832
|
+
url: url ?? ""
|
|
128833
|
+
});
|
|
128834
|
+
return entries;
|
|
128835
|
+
}
|
|
128836
|
+
function truncateText(text, max = 60) {
|
|
128837
|
+
return text.length <= max ? text : `${text.slice(0, max - 1)}…`;
|
|
128838
|
+
}
|
|
128839
|
+
const webSearchGlance = (_toolCall, result, colors) => {
|
|
128840
|
+
const entries = parseWebSearchOutput(result.output);
|
|
128841
|
+
if (entries.length === 0) return "";
|
|
128842
|
+
const titleColor = chalk.hex(colors.roleTool);
|
|
128843
|
+
const dim = chalk.dim;
|
|
128844
|
+
const lines = entries.slice(0, GLANCE_SAMPLES).map((e) => {
|
|
128845
|
+
return [e.title.length > 0 ? titleColor(truncateText(e.title)) : "", e.url.length > 0 ? dim(truncateText(e.url)) : ""].filter((s) => s.length > 0).join(dim(" — "));
|
|
128846
|
+
});
|
|
128847
|
+
const remaining = entries.length - GLANCE_SAMPLES;
|
|
128848
|
+
if (remaining > 0) lines.push(dim(`+${String(remaining)} more`));
|
|
128849
|
+
return lines.join("\n");
|
|
128850
|
+
};
|
|
128562
128851
|
const fetchSummary = withGlance(null);
|
|
128563
|
-
const webSearchSummary = withGlance(
|
|
128852
|
+
const webSearchSummary = withGlance(webSearchGlance);
|
|
128564
128853
|
const thinkSummary = withGlance(null);
|
|
128565
128854
|
const editSummary = withGlance(null);
|
|
128566
128855
|
const writeSummary = withGlance(null);
|
|
@@ -128608,6 +128897,7 @@ const STREAMING_PROGRESS_INTERVAL_MS = 1e3;
|
|
|
128608
128897
|
const SUBAGENT_ELAPSED_INTERVAL_MS = 1e3;
|
|
128609
128898
|
const PROGRESS_URL_RE = /https?:\/\/\S+/g;
|
|
128610
128899
|
const MAX_PROGRESS_LINE_CHARS = 1e4;
|
|
128900
|
+
const MAX_LIVE_OUTPUT_CHARS = 5e4;
|
|
128611
128901
|
function backgroundFailureMessage(status) {
|
|
128612
128902
|
switch (status) {
|
|
128613
128903
|
case "lost": return t("toolcall.bg_agent_lost");
|
|
@@ -128926,6 +129216,10 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
128926
129216
|
subagentEndedAtMs;
|
|
128927
129217
|
progressLines = [];
|
|
128928
129218
|
static MAX_PROGRESS_LINES = 24;
|
|
129219
|
+
/** Live stdout/stderr accumulated via appendLiveOutput while the tool runs. */
|
|
129220
|
+
liveOutput = "";
|
|
129221
|
+
/** Session permission mode at card creation; drives ExitPlanMode chip wording. */
|
|
129222
|
+
permissionMode;
|
|
128929
129223
|
writeStreamContentStart = -1;
|
|
128930
129224
|
writeStreamNlScanOffset = 0;
|
|
128931
129225
|
writeStreamNlCount = 0;
|
|
@@ -128988,6 +129282,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
128988
129282
|
setResult(result) {
|
|
128989
129283
|
this.result = result;
|
|
128990
129284
|
this.progressLines = [];
|
|
129285
|
+
this.liveOutput = "";
|
|
128991
129286
|
this.finalizeSubagentElapsedIfNeeded();
|
|
128992
129287
|
this.syncStreamingProgressTimer();
|
|
128993
129288
|
this.syncSubagentElapsedTimer();
|
|
@@ -129018,6 +129313,31 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129018
129313
|
this.notifySnapshotChange();
|
|
129019
129314
|
this.ui?.requestRender();
|
|
129020
129315
|
}
|
|
129316
|
+
/**
|
|
129317
|
+
* Append live stdout/stderr from a running tool (Bash). Kept separate
|
|
129318
|
+
* from appendProgress so streaming command output renders with the same
|
|
129319
|
+
* tail-preview styling as the final result. The buffer is capped and
|
|
129320
|
+
* tail-preserving so a runaway command cannot grow the box unboundedly;
|
|
129321
|
+
* the block is dropped entirely once the real result lands.
|
|
129322
|
+
*/
|
|
129323
|
+
appendLiveOutput(text) {
|
|
129324
|
+
if (this.result !== void 0 || text.length === 0) return;
|
|
129325
|
+
this.liveOutput += text;
|
|
129326
|
+
if (this.liveOutput.length > MAX_LIVE_OUTPUT_CHARS) this.liveOutput = `[...truncated]\n${this.liveOutput.slice(this.liveOutput.length - MAX_LIVE_OUTPUT_CHARS)}`;
|
|
129327
|
+
this.rebuildContent();
|
|
129328
|
+
this.notifySnapshotChange();
|
|
129329
|
+
this.ui?.requestRender();
|
|
129330
|
+
}
|
|
129331
|
+
/**
|
|
129332
|
+
* Records the session permission mode so ExitPlanMode can render an
|
|
129333
|
+
* honest "auto-approved" chip when the plan passed without user review.
|
|
129334
|
+
*/
|
|
129335
|
+
setPermissionMode(mode) {
|
|
129336
|
+
if (this.permissionMode === mode) return;
|
|
129337
|
+
this.permissionMode = mode;
|
|
129338
|
+
this.headerText.setText(this.buildHeader());
|
|
129339
|
+
this.ui?.requestRender();
|
|
129340
|
+
}
|
|
129021
129341
|
dispose() {
|
|
129022
129342
|
if (this.disposed) return;
|
|
129023
129343
|
this.disposed = true;
|
|
@@ -129433,6 +129753,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129433
129753
|
if (!isFinished || result === void 0 || result.is_error === true) return label;
|
|
129434
129754
|
const outcome = interpretExitPlanModeOutcome(result.output);
|
|
129435
129755
|
if (outcome.kind === "approved") {
|
|
129756
|
+
if (this.permissionMode === "auto" && outcome.chosen === void 0) return `${label}${chalk.hex(colors.warning)(` · ${t("toolcall.auto_approved")}`)}`;
|
|
129436
129757
|
const chipText = outcome.chosen !== void 0 && outcome.chosen.length > 0 ? t("toolcall.approved", { chosen: outcome.chosen }) : t("toolcall.approved_label");
|
|
129437
129758
|
return `${label}${chalk.hex(colors.success)(` · ${chipText}`)}`;
|
|
129438
129759
|
}
|
|
@@ -129465,6 +129786,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129465
129786
|
this.markDirty();
|
|
129466
129787
|
while (this.children.length > this.callPreviewEndIndex) this.children.pop();
|
|
129467
129788
|
this.buildProgressBlock();
|
|
129789
|
+
this.buildLiveOutputBlock();
|
|
129468
129790
|
this.buildContent();
|
|
129469
129791
|
this.buildSubagentBlock();
|
|
129470
129792
|
}
|
|
@@ -129474,6 +129796,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129474
129796
|
this.buildCallPreview();
|
|
129475
129797
|
this.callPreviewEndIndex = this.children.length;
|
|
129476
129798
|
this.buildProgressBlock();
|
|
129799
|
+
this.buildLiveOutputBlock();
|
|
129477
129800
|
this.buildContent();
|
|
129478
129801
|
this.buildSubagentBlock();
|
|
129479
129802
|
}
|
|
@@ -129503,6 +129826,25 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129503
129826
|
this.addChild(new Text(styled, 2, 0));
|
|
129504
129827
|
}
|
|
129505
129828
|
}
|
|
129829
|
+
/**
|
|
129830
|
+
* Render live stdout/stderr while the tool is still running. Reuses the
|
|
129831
|
+
* shell result renderer so the streaming tail matches the final output's
|
|
129832
|
+
* preview styling (including ctrl+o expansion); the block is skipped once
|
|
129833
|
+
* the real result has landed.
|
|
129834
|
+
*/
|
|
129835
|
+
buildLiveOutputBlock() {
|
|
129836
|
+
if (this.result !== void 0) return;
|
|
129837
|
+
if (this.liveOutput.length === 0) return;
|
|
129838
|
+
const components = shellExecutionResultRenderer(this.toolCall, {
|
|
129839
|
+
tool_call_id: this.toolCall.id,
|
|
129840
|
+
output: this.liveOutput,
|
|
129841
|
+
is_error: false
|
|
129842
|
+
}, {
|
|
129843
|
+
expanded: this.expanded,
|
|
129844
|
+
colors: this.colors
|
|
129845
|
+
});
|
|
129846
|
+
for (const component of components) this.addChild(component);
|
|
129847
|
+
}
|
|
129506
129848
|
buildSubagentBlock() {
|
|
129507
129849
|
if (this.subagentAgentId === void 0 && this.ongoingSubCalls.size === 0 && this.finishedSubCalls.length === 0 && this.subagentText.length === 0 && this.subagentPhase === void 0 && this.backgroundTaskTerminalPhase === void 0) return;
|
|
129508
129850
|
if (this.isSingleSubagentView()) {
|
|
@@ -132442,8 +132784,11 @@ function buildRoleAdditionalText(prefs) {
|
|
|
132442
132784
|
if (prefs.nickname !== void 0 && prefs.nickname.trim().length > 0) items.push(`- Nickname: address the user as "${prefs.nickname.trim()}".`);
|
|
132443
132785
|
if (prefs.tone !== void 0 && prefs.tone.trim().length > 0) items.push(`- Tone: respond in ${prefs.tone.trim()} tone.`);
|
|
132444
132786
|
if (prefs.other !== void 0 && prefs.other.trim().length > 0) items.push(`- Other: ${prefs.other.trim()}`);
|
|
132445
|
-
|
|
132446
|
-
|
|
132787
|
+
const doNot = prefs.doNot?.trim();
|
|
132788
|
+
if (items.length === 0 && (doNot === void 0 || doNot.length === 0)) return "";
|
|
132789
|
+
lines.push("", ...items);
|
|
132790
|
+
if (doNot !== void 0 && doNot.length > 0) lines.push("", "## Do NOT (explicit prohibitions — NEVER do these)", doNot);
|
|
132791
|
+
lines.push("", t("like.priority"));
|
|
132447
132792
|
return lines.join("\n");
|
|
132448
132793
|
}
|
|
132449
132794
|
async function getUserPrefsPath() {
|
|
@@ -132451,12 +132796,23 @@ async function getUserPrefsPath() {
|
|
|
132451
132796
|
}
|
|
132452
132797
|
async function persistLikePreferences(host, prefs) {
|
|
132453
132798
|
const configPath = getTuiConfigPath();
|
|
132454
|
-
await
|
|
132455
|
-
|
|
132799
|
+
const current = await loadTuiConfig(configPath);
|
|
132800
|
+
const updated = {
|
|
132801
|
+
...current,
|
|
132456
132802
|
like: prefs
|
|
132457
|
-
}
|
|
132458
|
-
|
|
132459
|
-
|
|
132803
|
+
};
|
|
132804
|
+
try {
|
|
132805
|
+
await saveTuiConfig(updated, configPath);
|
|
132806
|
+
await writeFile(await getUserPrefsPath(), buildRoleAdditionalText(prefs), "utf-8");
|
|
132807
|
+
} catch (error) {
|
|
132808
|
+
try {
|
|
132809
|
+
await saveTuiConfig(current, configPath);
|
|
132810
|
+
} catch {}
|
|
132811
|
+
try {
|
|
132812
|
+
await writeFile(await getUserPrefsPath(), buildRoleAdditionalText(current.like ?? {}), "utf-8");
|
|
132813
|
+
} catch {}
|
|
132814
|
+
throw error;
|
|
132815
|
+
}
|
|
132460
132816
|
host.setAppState({ like: prefs });
|
|
132461
132817
|
}
|
|
132462
132818
|
async function handleLikeCommand(host) {
|
|
@@ -132491,10 +132847,21 @@ async function handleLikeCommand(host) {
|
|
|
132491
132847
|
host.showStatus(t("like.cancelled"), host.state.theme.colors.textDim);
|
|
132492
132848
|
return;
|
|
132493
132849
|
}
|
|
132850
|
+
const doNot = await promptTextInput$1(host, t("like.do_not"), {
|
|
132851
|
+
subtitle: t("like.do_not_hint"),
|
|
132852
|
+
placeholder: t("like.do_not_example"),
|
|
132853
|
+
initialValue: current.doNot,
|
|
132854
|
+
allowEmpty: true
|
|
132855
|
+
});
|
|
132856
|
+
if (doNot === void 0) {
|
|
132857
|
+
host.showStatus(t("like.cancelled"), host.state.theme.colors.textDim);
|
|
132858
|
+
return;
|
|
132859
|
+
}
|
|
132494
132860
|
await persistLikePreferences(host, {
|
|
132495
132861
|
nickname: nickname.trim().length > 0 ? nickname.trim() : void 0,
|
|
132496
132862
|
tone: tone.trim().length > 0 ? tone.trim() : void 0,
|
|
132497
|
-
other: other.trim().length > 0 ? other.trim() : void 0
|
|
132863
|
+
other: other.trim().length > 0 ? other.trim() : void 0,
|
|
132864
|
+
doNot: doNot.trim().length > 0 ? doNot.trim() : void 0
|
|
132498
132865
|
});
|
|
132499
132866
|
host.showStatus(t("like.saved"), host.state.theme.colors.success);
|
|
132500
132867
|
}
|
|
@@ -136525,12 +136892,32 @@ var SessionEventHandler = class {
|
|
|
136525
136892
|
streamingUI.scheduleFlush();
|
|
136526
136893
|
}
|
|
136527
136894
|
handleToolProgress(event) {
|
|
136528
|
-
if (event.update.kind
|
|
136895
|
+
if (event.update.kind === "custom" && event.update.customKind === "background.task.terminated") {
|
|
136896
|
+
const data = event.update.customData;
|
|
136897
|
+
const id = typeof data?.id === "string" ? data.id : "";
|
|
136898
|
+
const command = typeof data?.command === "string" ? data.command : "";
|
|
136899
|
+
const exitCode = typeof data?.exitCode === "number" ? data.exitCode : -1;
|
|
136900
|
+
const preview = command.length > 60 ? `${command.slice(0, 59)}…` : command;
|
|
136901
|
+
if (exitCode === 0) this.host.showNotice(t("bash.background_completed", {
|
|
136902
|
+
id,
|
|
136903
|
+
command: preview
|
|
136904
|
+
}));
|
|
136905
|
+
else this.host.showNotice(t("bash.background_failed", {
|
|
136906
|
+
id,
|
|
136907
|
+
command: preview,
|
|
136908
|
+
exitCode: String(exitCode)
|
|
136909
|
+
}));
|
|
136910
|
+
return;
|
|
136911
|
+
}
|
|
136529
136912
|
const text = event.update.text;
|
|
136530
136913
|
if (text === void 0 || text.length === 0) return;
|
|
136531
136914
|
const tc = this.host.streamingUI.getToolComponent(event.toolCallId);
|
|
136532
136915
|
if (tc === void 0) return;
|
|
136533
|
-
|
|
136916
|
+
if (event.update.kind === "status") {
|
|
136917
|
+
tc.appendProgress(text);
|
|
136918
|
+
return;
|
|
136919
|
+
}
|
|
136920
|
+
if (event.update.kind === "stdout" || event.update.kind === "stderr") tc.appendLiveOutput(text);
|
|
136534
136921
|
}
|
|
136535
136922
|
handleToolResult(event) {
|
|
136536
136923
|
const { streamingUI } = this.host;
|
|
@@ -138146,6 +138533,7 @@ var StreamingUIController = class {
|
|
|
138146
138533
|
}
|
|
138147
138534
|
const { state } = this.host;
|
|
138148
138535
|
const tc = new ToolCallComponent(toolCall, void 0, state.theme.colors, state.ui, state.theme.markdownTheme, state.appState.workDir);
|
|
138536
|
+
tc.setPermissionMode(state.appState.permissionMode);
|
|
138149
138537
|
const entry = {
|
|
138150
138538
|
id: nextTranscriptId(),
|
|
138151
138539
|
kind: "tool_call",
|
|
@@ -138231,6 +138619,7 @@ var StreamingUIController = class {
|
|
|
138231
138619
|
}
|
|
138232
138620
|
if (matchedCall?.name === "AskUserQuestion") {
|
|
138233
138621
|
const completed = new ToolCallComponent(matchedCall, result, state.theme.colors, state.ui, state.theme.markdownTheme, state.appState.workDir);
|
|
138622
|
+
completed.setPermissionMode(state.appState.permissionMode);
|
|
138234
138623
|
if (state.toolOutputExpanded) completed.setExpanded(true);
|
|
138235
138624
|
if (state.planExpanded) completed.setPlanExpanded(true);
|
|
138236
138625
|
const entry = {
|
|
@@ -142770,8 +143159,10 @@ var SessionManager$1 = class {
|
|
|
142770
143159
|
wallClockBaseAt: Date.now()
|
|
142771
143160
|
} : null,
|
|
142772
143161
|
goalActive: goal?.status === "active",
|
|
142773
|
-
goalContinuationCount: 0
|
|
143162
|
+
goalContinuationCount: 0,
|
|
143163
|
+
providerBalance: null
|
|
142774
143164
|
});
|
|
143165
|
+
refreshProviderBalance(status.model ?? "", (patch) => this.host.setAppState(patch));
|
|
142775
143166
|
}
|
|
142776
143167
|
async activateRuntime() {
|
|
142777
143168
|
const session = this.requireSession();
|
|
@@ -143618,6 +144009,8 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143618
144009
|
searchQuery = "";
|
|
143619
144010
|
isSearching = false;
|
|
143620
144011
|
searchInput = "";
|
|
144012
|
+
/** Memo ids ticked for batch delete (space toggles, a selects all). */
|
|
144013
|
+
selectedIds = /* @__PURE__ */ new Set();
|
|
143621
144014
|
memos;
|
|
143622
144015
|
total;
|
|
143623
144016
|
loading;
|
|
@@ -143646,6 +144039,7 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143646
144039
|
this.memos = result.memos;
|
|
143647
144040
|
this.total = result.total;
|
|
143648
144041
|
this.selectedIndex = 0;
|
|
144042
|
+
this.selectedIds.clear();
|
|
143649
144043
|
} catch {
|
|
143650
144044
|
this.memos = [];
|
|
143651
144045
|
this.total = 0;
|
|
@@ -143677,8 +144071,11 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143677
144071
|
}
|
|
143678
144072
|
if (this.mode === "confirmDelete") {
|
|
143679
144073
|
if (matchesKey(data, Key.enter)) {
|
|
143680
|
-
|
|
143681
|
-
|
|
144074
|
+
if (this.selectedIds.size > 0) this.deleteSelectedAndReload();
|
|
144075
|
+
else {
|
|
144076
|
+
const memo = this.memos[this.selectedIndex];
|
|
144077
|
+
if (memo) this.deleteAndReload(memo.id);
|
|
144078
|
+
}
|
|
143682
144079
|
return;
|
|
143683
144080
|
}
|
|
143684
144081
|
if (matchesKey(data, Key.escape)) {
|
|
@@ -143725,7 +144122,23 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143725
144122
|
return;
|
|
143726
144123
|
}
|
|
143727
144124
|
if (ch === "d" || ch === "D") {
|
|
143728
|
-
if (this.memos.length > 0) this.mode = "confirmDelete";
|
|
144125
|
+
if (this.selectedIds.size > 0 || this.memos.length > 0) this.mode = "confirmDelete";
|
|
144126
|
+
return;
|
|
144127
|
+
}
|
|
144128
|
+
if (ch === " ") {
|
|
144129
|
+
const memo = this.memos[this.selectedIndex];
|
|
144130
|
+
if (memo) {
|
|
144131
|
+
if (this.selectedIds.has(memo.id)) this.selectedIds.delete(memo.id);
|
|
144132
|
+
else this.selectedIds.add(memo.id);
|
|
144133
|
+
this.ui?.requestRender();
|
|
144134
|
+
}
|
|
144135
|
+
return;
|
|
144136
|
+
}
|
|
144137
|
+
if (ch === "a" || ch === "A") {
|
|
144138
|
+
if (this.memos.length === 0) return;
|
|
144139
|
+
if (this.memos.every((memo) => this.selectedIds.has(memo.id))) this.selectedIds.clear();
|
|
144140
|
+
else for (const memo of this.memos) this.selectedIds.add(memo.id);
|
|
144141
|
+
this.ui?.requestRender();
|
|
143729
144142
|
return;
|
|
143730
144143
|
}
|
|
143731
144144
|
if (ch === "/") {
|
|
@@ -143754,6 +144167,15 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143754
144167
|
if (this.selectedIndex >= this.memos.length) this.selectedIndex = Math.max(0, this.memos.length - 1);
|
|
143755
144168
|
this.ui?.requestRender();
|
|
143756
144169
|
}
|
|
144170
|
+
async deleteSelectedAndReload() {
|
|
144171
|
+
const ids = [...this.selectedIds];
|
|
144172
|
+
for (const id of ids) try {
|
|
144173
|
+
await this.store.delete(id);
|
|
144174
|
+
} catch {}
|
|
144175
|
+
await this.loadMemos();
|
|
144176
|
+
this.mode = "list";
|
|
144177
|
+
this.ui?.requestRender();
|
|
144178
|
+
}
|
|
143757
144179
|
render(width) {
|
|
143758
144180
|
const c = this.colors;
|
|
143759
144181
|
const lines = [];
|
|
@@ -143766,7 +144188,7 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143766
144188
|
return lines;
|
|
143767
144189
|
}
|
|
143768
144190
|
const headerLabel = t("memory.notebook_title");
|
|
143769
|
-
const headerHint = this.searchQuery.length > 0 ? t("memory.esc_clear_search") : t("memory.nav_hint");
|
|
144191
|
+
const headerHint = this.searchQuery.length > 0 ? t("memory.esc_clear_search") : this.selectedIds.size > 0 ? t("memory.batch_hint", { count: String(this.selectedIds.size) }) : t("memory.nav_hint");
|
|
143770
144192
|
const labelWidth = visibleWidth(headerLabel);
|
|
143771
144193
|
const shownHint = truncateToWidth(headerHint, Math.max(0, width - labelWidth), ELLIPSIS$1);
|
|
143772
144194
|
lines.push(chalk.hex(c.primary).bold(headerLabel) + chalk.hex(c.textMuted)(shownHint));
|
|
@@ -143787,10 +144209,15 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143787
144209
|
}
|
|
143788
144210
|
if (this.mode === "detail" && this.detailMemo) return this.renderDetail(lines, width, c);
|
|
143789
144211
|
if (this.mode === "confirmDelete") {
|
|
143790
|
-
|
|
143791
|
-
|
|
143792
|
-
lines.push(
|
|
143793
|
-
|
|
144212
|
+
if (this.selectedIds.size > 0) {
|
|
144213
|
+
lines.push(truncateToWidth(chalk.hex(c.warning).bold(t("memory.batch_delete_confirm", { count: String(this.selectedIds.size) })), width, ELLIPSIS$1));
|
|
144214
|
+
lines.push(chalk.hex(c.warning)(t("memory.batch_delete_hint")));
|
|
144215
|
+
} else {
|
|
144216
|
+
const memo = this.memos[this.selectedIndex];
|
|
144217
|
+
if (memo) {
|
|
144218
|
+
lines.push(truncateToWidth(chalk.hex(c.warning).bold(` ${t("memory.deleting")}${memo.userNeed}`), width, ELLIPSIS$1));
|
|
144219
|
+
lines.push(chalk.hex(c.warning)(t("memory.delete_confirm_hint")));
|
|
144220
|
+
}
|
|
143794
144221
|
}
|
|
143795
144222
|
lines.push(chalk.hex(c.primary)("─".repeat(width)));
|
|
143796
144223
|
return lines;
|
|
@@ -143818,6 +144245,7 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143818
144245
|
renderMemoCard(width, memo, isSelected) {
|
|
143819
144246
|
const c = this.colors;
|
|
143820
144247
|
const pointer = isSelected ? "❯" : " ";
|
|
144248
|
+
const check = this.selectedIds.has(memo.id) ? "☑" : "□";
|
|
143821
144249
|
const indent = " ";
|
|
143822
144250
|
const indentWidth = visibleWidth(indent);
|
|
143823
144251
|
const titleColor = isSelected ? c.primary : c.text;
|
|
@@ -143825,10 +144253,12 @@ var MemoryPickerComponent = class extends Container {
|
|
|
143825
144253
|
const trailingParts = [formatRelativeTime$1(memo.recordedAt), sourceLabel(memo.extractionSource)].filter((p) => p.length > 0);
|
|
143826
144254
|
const trailingText = trailingParts.length > 0 ? " " + trailingParts.join(" ") : "";
|
|
143827
144255
|
const trailingWidth = visibleWidth(trailingText);
|
|
143828
|
-
const headerPrefixWidth = visibleWidth(pointer) + 1;
|
|
144256
|
+
const headerPrefixWidth = visibleWidth(pointer) + 1 + visibleWidth(check) + 1;
|
|
143829
144257
|
const titleBudget = Math.max(8, width - headerPrefixWidth - trailingWidth);
|
|
143830
144258
|
const shownTitle = truncateToWidth(singleLine$1(memo.userNeed), titleBudget, ELLIPSIS$1);
|
|
144259
|
+
const checkColor = this.selectedIds.has(memo.id) ? c.primary : c.textDim;
|
|
143831
144260
|
let header = chalk.hex(isSelected ? c.primary : c.textDim)(pointer + " ");
|
|
144261
|
+
header += chalk.hex(checkColor)(check + " ");
|
|
143832
144262
|
header += titleStyle(shownTitle);
|
|
143833
144263
|
if (trailingText.length > 0) header += chalk.hex(c.textDim)(trailingText);
|
|
143834
144264
|
const card = [truncateToWidth(header, width, ELLIPSIS$1)];
|
|
@@ -143965,12 +144395,15 @@ var SessionPickerComponent = class extends Container {
|
|
|
143965
144395
|
onSelect;
|
|
143966
144396
|
onCancel;
|
|
143967
144397
|
onDelete;
|
|
144398
|
+
onDeleteMany;
|
|
143968
144399
|
onStatus;
|
|
143969
144400
|
maxVisibleSessions;
|
|
143970
144401
|
loading;
|
|
143971
144402
|
focused = false;
|
|
143972
144403
|
selectedIndex = 0;
|
|
143973
144404
|
confirmingDelete = false;
|
|
144405
|
+
/** Session ids ticked for batch delete (space toggles, a selects all). */
|
|
144406
|
+
selectedIds = /* @__PURE__ */ new Set();
|
|
143974
144407
|
constructor(opts) {
|
|
143975
144408
|
super();
|
|
143976
144409
|
this.sessions = opts.sessions;
|
|
@@ -143980,6 +144413,7 @@ var SessionPickerComponent = class extends Container {
|
|
|
143980
144413
|
this.onSelect = opts.onSelect;
|
|
143981
144414
|
this.onCancel = opts.onCancel;
|
|
143982
144415
|
this.onDelete = opts.onDelete;
|
|
144416
|
+
this.onDeleteMany = opts.onDeleteMany;
|
|
143983
144417
|
this.onStatus = opts.onStatus;
|
|
143984
144418
|
this.maxVisibleSessions = opts.maxVisibleSessions ?? 4;
|
|
143985
144419
|
}
|
|
@@ -143997,6 +144431,15 @@ var SessionPickerComponent = class extends Container {
|
|
|
143997
144431
|
if (!session) return;
|
|
143998
144432
|
if (this.confirmingDelete) {
|
|
143999
144433
|
this.confirmingDelete = false;
|
|
144434
|
+
if (this.selectedIds.size > 0) {
|
|
144435
|
+
if (this.onDeleteMany === void 0) {
|
|
144436
|
+
this.confirmingDelete = true;
|
|
144437
|
+
this.onStatus(t("session_picker.batch_delete_unavailable"));
|
|
144438
|
+
return;
|
|
144439
|
+
}
|
|
144440
|
+
this.onDeleteMany?.([...this.selectedIds]);
|
|
144441
|
+
return;
|
|
144442
|
+
}
|
|
144000
144443
|
if (session.metadata?.["source"] === "cc-connect") {
|
|
144001
144444
|
this.onStatus(t("session_picker.cc_restricted"));
|
|
144002
144445
|
return;
|
|
@@ -144012,11 +144455,13 @@ var SessionPickerComponent = class extends Container {
|
|
|
144012
144455
|
return;
|
|
144013
144456
|
}
|
|
144014
144457
|
if (matchesKey(data, Key.up)) {
|
|
144458
|
+
if (this.confirmingDelete) return;
|
|
144015
144459
|
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
|
144016
144460
|
this.confirmingDelete = false;
|
|
144017
144461
|
return;
|
|
144018
144462
|
}
|
|
144019
144463
|
if (matchesKey(data, Key.down)) {
|
|
144464
|
+
if (this.confirmingDelete) return;
|
|
144020
144465
|
this.selectedIndex = Math.min(this.sessions.length - 1, this.selectedIndex + 1);
|
|
144021
144466
|
this.confirmingDelete = false;
|
|
144022
144467
|
return;
|
|
@@ -144031,6 +144476,26 @@ var SessionPickerComponent = class extends Container {
|
|
|
144031
144476
|
}
|
|
144032
144477
|
if (session.id !== this.currentSessionId) this.confirmingDelete = true;
|
|
144033
144478
|
}
|
|
144479
|
+
if (k === " " && !this.confirmingDelete) {
|
|
144480
|
+
const session = this.sessions[this.selectedIndex];
|
|
144481
|
+
if (!session || session.id === this.currentSessionId) return;
|
|
144482
|
+
if (session.metadata?.["source"] === "cc-connect") {
|
|
144483
|
+
this.onStatus(t("session_picker.cc_restricted"));
|
|
144484
|
+
return;
|
|
144485
|
+
}
|
|
144486
|
+
if (this.selectedIds.has(session.id)) this.selectedIds.delete(session.id);
|
|
144487
|
+
else this.selectedIds.add(session.id);
|
|
144488
|
+
return;
|
|
144489
|
+
}
|
|
144490
|
+
if (k === "a" || k === "A") {
|
|
144491
|
+
if (this.confirmingDelete) return;
|
|
144492
|
+
if (this.sessions.length === 0) return;
|
|
144493
|
+
const selectable = this.sessions.filter((s) => s.id !== this.currentSessionId && s.metadata?.["source"] !== "cc-connect");
|
|
144494
|
+
if (selectable.length === 0) return;
|
|
144495
|
+
if (selectable.every((s) => this.selectedIds.has(s.id))) this.selectedIds.clear();
|
|
144496
|
+
else for (const s of selectable) this.selectedIds.add(s.id);
|
|
144497
|
+
return;
|
|
144498
|
+
}
|
|
144034
144499
|
}
|
|
144035
144500
|
render(width) {
|
|
144036
144501
|
const colors = this.colors;
|
|
@@ -144048,7 +144513,7 @@ var SessionPickerComponent = class extends Container {
|
|
|
144048
144513
|
return lines;
|
|
144049
144514
|
}
|
|
144050
144515
|
const headerLabel = t("session.picker_title");
|
|
144051
|
-
const headerHint = this.confirmingDelete ? t("session.delete_confirm") : t("session.picker_hint");
|
|
144516
|
+
const headerHint = this.confirmingDelete ? this.selectedIds.size > 0 ? t("session_picker.batch_delete_confirm", { count: String(this.selectedIds.size) }) : t("session.delete_confirm") : this.selectedIds.size > 0 ? t("session_picker.batch_hint", { count: String(this.selectedIds.size) }) : t("session.picker_hint");
|
|
144052
144517
|
const labelWidth = visibleWidth(headerLabel);
|
|
144053
144518
|
const shownHint = truncateToWidth(headerHint, Math.max(0, width - labelWidth), ELLIPSIS);
|
|
144054
144519
|
const hintColor = this.confirmingDelete ? colors.warning : colors.textMuted;
|
|
@@ -144074,6 +144539,7 @@ var SessionPickerComponent = class extends Container {
|
|
|
144074
144539
|
renderSessionCard(width, session, isSelected, isCurrent) {
|
|
144075
144540
|
const colors = this.colors;
|
|
144076
144541
|
const pointer = isSelected ? "❯" : " ";
|
|
144542
|
+
const check = this.selectedIds.has(session.id) ? "☑" : "□";
|
|
144077
144543
|
const indent = " ";
|
|
144078
144544
|
const indentWidth = visibleWidth(indent);
|
|
144079
144545
|
const titleColor = isSelected ? colors.primary : colors.text;
|
|
@@ -144087,14 +144553,16 @@ var SessionPickerComponent = class extends Container {
|
|
|
144087
144553
|
});
|
|
144088
144554
|
const trailingParts = [time, badge].filter((p) => p.length > 0);
|
|
144089
144555
|
const trailingWidth = visibleWidth(trailingParts.length > 0 ? " " + trailingParts.join(" ") : "");
|
|
144090
|
-
const headerPrefixWidth = visibleWidth(pointer) + 1;
|
|
144556
|
+
const headerPrefixWidth = visibleWidth(pointer) + 1 + visibleWidth(check) + 1;
|
|
144091
144557
|
const titleBudget = Math.max(8, width - headerPrefixWidth - trailingWidth);
|
|
144092
144558
|
const shownTitle = truncateToWidth(singleLine(titleSource), titleBudget, ELLIPSIS);
|
|
144559
|
+
const checkColor = this.selectedIds.has(session.id) ? colors.primary : colors.textDim;
|
|
144093
144560
|
let header = chalk.hex(isSelected ? colors.primary : colors.textDim)(pointer + " ");
|
|
144561
|
+
header += chalk.hex(checkColor)(check + " ");
|
|
144094
144562
|
header += titleStyle(shownTitle);
|
|
144095
144563
|
if (time.length > 0) header += " " + chalk.hex(colors.textDim)(time);
|
|
144096
144564
|
if (badge.length > 0) header += " " + chalk.hex(colors.success)(badge);
|
|
144097
|
-
const card = [header];
|
|
144565
|
+
const card = [truncateToWidth(header, width)];
|
|
144098
144566
|
const fullId = session.id;
|
|
144099
144567
|
const idWidth = visibleWidth(fullId);
|
|
144100
144568
|
const metaGap = " ";
|
|
@@ -144839,6 +145307,27 @@ var DialogManager = class {
|
|
|
144839
145307
|
}).catch((error) => {
|
|
144840
145308
|
this.host.showError(error instanceof Error ? error.message : String(error));
|
|
144841
145309
|
});
|
|
145310
|
+
},
|
|
145311
|
+
onDeleteMany: (sessionIds) => {
|
|
145312
|
+
const ccIds = new Set(this.host.getSessions().filter((s) => s.metadata?.["source"] === "cc-connect").map((s) => s.id));
|
|
145313
|
+
const deletable = sessionIds.filter((id) => !ccIds.has(id));
|
|
145314
|
+
if (deletable.length === 0) {
|
|
145315
|
+
this.host.showStatus(t("dialog.cc_managed"));
|
|
145316
|
+
return;
|
|
145317
|
+
}
|
|
145318
|
+
(async () => {
|
|
145319
|
+
for (const id of deletable) try {
|
|
145320
|
+
await this.host.deleteSession(id);
|
|
145321
|
+
} catch (error) {
|
|
145322
|
+
this.host.showError(error instanceof Error ? error.message : String(error));
|
|
145323
|
+
break;
|
|
145324
|
+
}
|
|
145325
|
+
await this.host.fetchSessions();
|
|
145326
|
+
if (this.host.getSessions().length === 0) this.hideSessionPicker();
|
|
145327
|
+
else if (this.host.state.activeDialog === "session-picker") this.mountSessionPicker(onCancel);
|
|
145328
|
+
})().catch((error) => {
|
|
145329
|
+
this.host.showError(error instanceof Error ? error.message : String(error));
|
|
145330
|
+
});
|
|
144842
145331
|
}
|
|
144843
145332
|
}));
|
|
144844
145333
|
}
|
|
@@ -144973,6 +145462,7 @@ function createInitialAppState(input) {
|
|
|
144973
145462
|
contextUsage: 0,
|
|
144974
145463
|
contextTokens: 0,
|
|
144975
145464
|
maxContextTokens: 0,
|
|
145465
|
+
providerBalance: null,
|
|
144976
145466
|
isCompacting: false,
|
|
144977
145467
|
lastCompactionFinishedAt: void 0,
|
|
144978
145468
|
autoCompactionCount: 0,
|
|
@@ -145768,14 +146258,20 @@ function supportsAnsi() {
|
|
|
145768
146258
|
ansiSupported = false;
|
|
145769
146259
|
return false;
|
|
145770
146260
|
}
|
|
145771
|
-
function runLoadingAnimation(theme = "dark") {
|
|
146261
|
+
async function runLoadingAnimation(theme = "dark") {
|
|
145772
146262
|
if (!supportsAnsi()) {
|
|
145773
146263
|
const { cols } = getTerminalSize();
|
|
145774
146264
|
if (cols >= FULL_LOGO_MIN_COLS) for (const line of LOGO) stdout.write(`${fg(...LOGO_RGB)}${line}${RESET}\n`);
|
|
145775
146265
|
else for (const line of COMPACT_LOGO) stdout.write(`${fg(...BLOCK_RGB)}${line}${RESET}\n`);
|
|
145776
146266
|
stdout.write(`${BOLD}${fg(...THEME_PRIMARY[theme])}${t("loading.waking")}${RESET}\n`);
|
|
145777
|
-
return
|
|
146267
|
+
return;
|
|
145778
146268
|
}
|
|
146269
|
+
let autoStart = false;
|
|
146270
|
+
try {
|
|
146271
|
+
autoStart = (await loadTuiConfig()).autoStart;
|
|
146272
|
+
} catch {}
|
|
146273
|
+
const autoStartAtBoot = autoStart;
|
|
146274
|
+
let toggled = false;
|
|
145779
146275
|
return new Promise((resolve) => {
|
|
145780
146276
|
if (process$1.platform !== "win32") stdout.write("\x1B[?1049h");
|
|
145781
146277
|
stdout.write("\x1B[2J");
|
|
@@ -145809,7 +146305,9 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
145809
146305
|
else lines.push(centerPad(`${BOLD}${fg(...breatheColor)}${t("loading.press_enter")}${RESET}`, cols));
|
|
145810
146306
|
lines.push("");
|
|
145811
146307
|
lines.push("");
|
|
145812
|
-
|
|
146308
|
+
const rightText = toggled ? autoStart ? t("loading.auto_start_on") : t("loading.auto_start_off") : t("loading.auto_start_hint");
|
|
146309
|
+
const hint = `${t("loading.quit_hint")} ${rightText}`;
|
|
146310
|
+
lines.push(centerPad(`${fg(...DIM_RGB)}${hint}${RESET}`, cols));
|
|
145813
146311
|
while (lines.length < rows) lines.push("");
|
|
145814
146312
|
stdout.write("\x1B[H");
|
|
145815
146313
|
stdout.write(lines.join("\n"));
|
|
@@ -145830,6 +146328,20 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
145830
146328
|
interrupt();
|
|
145831
146329
|
return;
|
|
145832
146330
|
}
|
|
146331
|
+
if (key === "") {
|
|
146332
|
+
toggled = true;
|
|
146333
|
+
autoStart = !autoStart;
|
|
146334
|
+
(async () => {
|
|
146335
|
+
try {
|
|
146336
|
+
await saveTuiConfig({
|
|
146337
|
+
...await loadTuiConfig(),
|
|
146338
|
+
autoStart
|
|
146339
|
+
});
|
|
146340
|
+
} catch {}
|
|
146341
|
+
})();
|
|
146342
|
+
render();
|
|
146343
|
+
return;
|
|
146344
|
+
}
|
|
145833
146345
|
if ((key === "\r" || key === "\n") && phase === "ready") {
|
|
145834
146346
|
cleanup();
|
|
145835
146347
|
resolve();
|
|
@@ -145875,6 +146387,10 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
145875
146387
|
}).then(() => {
|
|
145876
146388
|
phase = "ready";
|
|
145877
146389
|
render();
|
|
146390
|
+
if (autoStartAtBoot) setTimeout(() => {
|
|
146391
|
+
cleanup();
|
|
146392
|
+
resolve();
|
|
146393
|
+
}, 350);
|
|
145878
146394
|
});
|
|
145879
146395
|
});
|
|
145880
146396
|
}
|
package/dist/main.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
//#region src/main.ts
|
|
8
8
|
try {
|
|
9
|
-
(await import("./app-
|
|
9
|
+
(await import("./app-zSNn5qdo.mjs")).main();
|
|
10
10
|
} catch (error) {
|
|
11
11
|
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
12
12
|
process.exit(1);
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { t as TextInputDialogComponent } from "./text-input-dialog-
|
|
6
|
+
import { t as TextInputDialogComponent } from "./text-input-dialog-DYHGTG6m.mjs";
|
|
7
7
|
export { TextInputDialogComponent };
|
|
@@ -221,6 +221,9 @@ const dictionaries = {
|
|
|
221
221
|
"loading.waking": "正在唤醒核心...",
|
|
222
222
|
"loading.press_enter": "按下 ENTER 唤醒核心",
|
|
223
223
|
"loading.quit_hint": "按住 Ctrl+C 即可退出 Scream Code",
|
|
224
|
+
"loading.auto_start_hint": "Ctrl+E 即可切换一键启动",
|
|
225
|
+
"loading.auto_start_on": "Ctrl+E 即可切换一键启动(默认启动开)",
|
|
226
|
+
"loading.auto_start_off": "Ctrl+E 即可切换一键启动(默认启动关)",
|
|
224
227
|
"language.picker_title": "语言 / Language",
|
|
225
228
|
"language.picker_hint": "↑↓ 选择 · Enter 确认 · Esc 取消",
|
|
226
229
|
"language.unchanged": "语言未更改:\"{locale}\"。",
|
|
@@ -428,6 +431,9 @@ const dictionaries = {
|
|
|
428
431
|
"like.other": "其他偏好",
|
|
429
432
|
"like.other_hint": "例如:多说例子、先给结论再展开、避免术语等(留空表示不设置)",
|
|
430
433
|
"like.other_example": "例如:请用中文回答,避免缩写",
|
|
434
|
+
"like.do_not": "用户禁止",
|
|
435
|
+
"like.do_not_hint": "用户明确不让做的事。Agent 绝不能做这些。",
|
|
436
|
+
"like.do_not_example": "例如:未经询问绝不修改用户的配置文件",
|
|
431
437
|
"like.cancelled": "已取消 /like 设置",
|
|
432
438
|
"like.saved": "偏好已保存(下次新会话生效)",
|
|
433
439
|
"revoke.streaming": "无法在 streaming 中撤回 — 请先按 Esc 或 Ctrl-C 取消。",
|
|
@@ -467,9 +473,12 @@ const dictionaries = {
|
|
|
467
473
|
"session.loading": "正在加载会话...",
|
|
468
474
|
"session_picker.empty": "未找到会话。按 Escape 关闭。",
|
|
469
475
|
"session_picker.cc_restricted": "CC专属会话不支持切换或删除,请点击或复制下方文件路径进入手动管理",
|
|
476
|
+
"session_picker.batch_delete_confirm": "删除选中的 {count} 个会话?",
|
|
477
|
+
"session_picker.batch_delete_unavailable": "此处不支持批量删除。",
|
|
478
|
+
"session_picker.batch_hint": "[空格] 选择 · [a] 全选 · [d] 删除选中({count})",
|
|
470
479
|
"session.picker_title": "会话 ",
|
|
471
480
|
"session.delete_confirm": "⚠️ 按 Enter 确认删除,Esc 取消",
|
|
472
|
-
"session.picker_hint": "(↑↓ 导航,Enter
|
|
481
|
+
"session.picker_hint": "(↑↓ 导航,Enter 打开,空格 标记,a 全选,d 删除,Esc 取消)",
|
|
473
482
|
"model.nav_model": "↑↓ 模型",
|
|
474
483
|
"model.nav_thinking": "←→ 思考等级",
|
|
475
484
|
"model.nav_page": "PgUp/PgDn 翻页",
|
|
@@ -532,13 +541,16 @@ const dictionaries = {
|
|
|
532
541
|
"memory.search_label": "搜索: ",
|
|
533
542
|
"memory.notebook_title": "记忆备忘录 ",
|
|
534
543
|
"memory.esc_clear_search": "(Esc 清除搜索)",
|
|
535
|
-
"memory.nav_hint": "(↑↓ 导航,Enter
|
|
544
|
+
"memory.nav_hint": "(↑↓ 导航,Enter 查看,空格 标记,a 全选,i 注入,d 删除,/ 搜索,Esc 关闭)",
|
|
536
545
|
"memory.loading": "正在加载...",
|
|
537
546
|
"memory.no_match": "未找到匹配 \"{query}\" 的记忆。",
|
|
538
547
|
"memory.empty": "暂无记忆备忘录。",
|
|
539
548
|
"memory.auto_extract_hint": " 压缩对话或退出会话时,系统会自动提取并保存。",
|
|
540
549
|
"memory.deleting": "删除: ",
|
|
541
550
|
"memory.delete_confirm_hint": " 按 Enter 确认删除,Esc 取消",
|
|
551
|
+
"memory.batch_delete_confirm": "删除选中的 {count} 条记忆?",
|
|
552
|
+
"memory.batch_delete_hint": " 按 Enter 确认批量删除,Esc 取消",
|
|
553
|
+
"memory.batch_hint": "已选 {count} 条 · [空格] 选择 · [a] 全选 · [d] 删除选中",
|
|
542
554
|
"memory.showing_range": "{start}-{end} / {total} 条",
|
|
543
555
|
"memory.id_label": "ID: ",
|
|
544
556
|
"memory.source_label": "来源: ",
|
|
@@ -593,6 +605,7 @@ const dictionaries = {
|
|
|
593
605
|
"toolcall.current_plan": "当前计划",
|
|
594
606
|
"toolcall.approved": "已批准:{chosen}",
|
|
595
607
|
"toolcall.approved_label": "已批准",
|
|
608
|
+
"toolcall.auto_approved": "自动批准",
|
|
596
609
|
"toolcall.input_unavailable": "无法收集你的输入",
|
|
597
610
|
"toolcall.input_collected": "已收集你的答案",
|
|
598
611
|
"toolcall.waiting_input": "等待你的输入",
|
|
@@ -720,6 +733,8 @@ const dictionaries = {
|
|
|
720
733
|
"subagent.bind_title": "绑定 {profile}",
|
|
721
734
|
"subagent.model_hint": "↑↓ 选择模型 · Enter 确认 · Esc 返回",
|
|
722
735
|
"subagent.save_failed": "保存失败:{msg}",
|
|
736
|
+
"subagent.stale_binding": "{alias}(已失效)",
|
|
737
|
+
"subagent.invalid_alias": "模型别名 {alias} 不存在",
|
|
723
738
|
"kdoctree.no_title": "(无标题)",
|
|
724
739
|
"kdoctree.empty": "(空)",
|
|
725
740
|
"kdoctree.move": "移动",
|
|
@@ -803,6 +818,8 @@ const dictionaries = {
|
|
|
803
818
|
"export.session_title": "# Scream 会话导出",
|
|
804
819
|
"bgtask.agent_task": "代理任务",
|
|
805
820
|
"bgtask.bash_task": "bash 任务",
|
|
821
|
+
"bash.background_completed": "后台任务 {id} 已完成:{command}",
|
|
822
|
+
"bash.background_failed": "后台任务 {id} 执行失败(退出码 {exitCode}):{command}",
|
|
806
823
|
"bgtask.started_bg": "{subject} 已在后台启动",
|
|
807
824
|
"bgtask.awaiting_approval": "{subject} 等待审批",
|
|
808
825
|
"bgtask.completed_bg": "{subject} 已在后台完成",
|
|
@@ -1252,6 +1269,9 @@ const dictionaries = {
|
|
|
1252
1269
|
"loading.waking": "Waking core...",
|
|
1253
1270
|
"loading.press_enter": "Press ENTER to wake core",
|
|
1254
1271
|
"loading.quit_hint": "Hold Ctrl+C to quit Scream Code",
|
|
1272
|
+
"loading.auto_start_hint": "Ctrl+E to toggle auto-start",
|
|
1273
|
+
"loading.auto_start_on": "Ctrl+E to toggle auto-start (ON)",
|
|
1274
|
+
"loading.auto_start_off": "Ctrl+E to toggle auto-start (OFF)",
|
|
1255
1275
|
"language.picker_title": "Language / 语言",
|
|
1256
1276
|
"language.picker_hint": "↑↓ Select · Enter confirm · Esc cancel",
|
|
1257
1277
|
"language.unchanged": "Language unchanged: \"{locale}\".",
|
|
@@ -1459,6 +1479,9 @@ const dictionaries = {
|
|
|
1459
1479
|
"like.other": "Other preferences",
|
|
1460
1480
|
"like.other_hint": "e.g. more examples, conclusion first, avoid jargon (leave empty to skip)",
|
|
1461
1481
|
"like.other_example": "e.g. Answer in English, avoid abbreviations",
|
|
1482
|
+
"like.do_not": "User Prohibitions",
|
|
1483
|
+
"like.do_not_hint": "Things the user explicitly does NOT want done. The agent must NEVER do these.",
|
|
1484
|
+
"like.do_not_example": "e.g. Never modify user config files without asking",
|
|
1462
1485
|
"like.cancelled": "/like setup cancelled",
|
|
1463
1486
|
"like.saved": "Preferences saved (takes effect in next session)",
|
|
1464
1487
|
"revoke.streaming": "Cannot revoke during streaming — press Esc or Ctrl-C to cancel first.",
|
|
@@ -1498,9 +1521,12 @@ const dictionaries = {
|
|
|
1498
1521
|
"session.loading": "Loading sessions...",
|
|
1499
1522
|
"session_picker.empty": "No sessions found. Press Escape to close.",
|
|
1500
1523
|
"session_picker.cc_restricted": "CC sessions cannot be switched or deleted. Use the file path below to manage manually",
|
|
1524
|
+
"session_picker.batch_delete_confirm": "Delete {count} selected sessions?",
|
|
1525
|
+
"session_picker.batch_delete_unavailable": "Batch delete is not available here.",
|
|
1526
|
+
"session_picker.batch_hint": "[space] select · [a] all · [d] delete selected ({count})",
|
|
1501
1527
|
"session.picker_title": "Sessions ",
|
|
1502
1528
|
"session.delete_confirm": "⚠️ Press Enter to confirm delete, Esc to cancel",
|
|
1503
|
-
"session.picker_hint": "(↑↓ Navigate, Enter
|
|
1529
|
+
"session.picker_hint": "(↑↓ Navigate, Enter Open, Space Mark, a All, d Delete, Esc Cancel)",
|
|
1504
1530
|
"model.nav_model": "↑↓ Model",
|
|
1505
1531
|
"model.nav_thinking": "←→ Thinking",
|
|
1506
1532
|
"model.nav_page": "PgUp/PgDn Page",
|
|
@@ -1563,13 +1589,16 @@ const dictionaries = {
|
|
|
1563
1589
|
"memory.search_label": "Search: ",
|
|
1564
1590
|
"memory.notebook_title": "Memory Notebook ",
|
|
1565
1591
|
"memory.esc_clear_search": "(Esc clear search)",
|
|
1566
|
-
"memory.nav_hint": "(↑↓ Navigate, Enter View, i Inject, d Delete, / Search, Esc Close)",
|
|
1592
|
+
"memory.nav_hint": "(↑↓ Navigate, Enter View, Space Mark, a All, i Inject, d Delete, / Search, Esc Close)",
|
|
1567
1593
|
"memory.loading": "Loading...",
|
|
1568
1594
|
"memory.no_match": "No memories matching \"{query}\".",
|
|
1569
1595
|
"memory.empty": "No memories yet.",
|
|
1570
1596
|
"memory.auto_extract_hint": " Memories are extracted automatically when compacting or exiting a session.",
|
|
1571
1597
|
"memory.deleting": "Delete: ",
|
|
1572
1598
|
"memory.delete_confirm_hint": " Press Enter to confirm delete, Esc to cancel",
|
|
1599
|
+
"memory.batch_delete_confirm": "Delete {count} selected memos?",
|
|
1600
|
+
"memory.batch_delete_hint": " Press Enter to confirm batch delete, Esc to cancel",
|
|
1601
|
+
"memory.batch_hint": "{count} selected · [space] select · [a] all · [d] delete selected",
|
|
1573
1602
|
"memory.showing_range": "{start}-{end} / {total} items",
|
|
1574
1603
|
"memory.id_label": "ID: ",
|
|
1575
1604
|
"memory.source_label": "Source: ",
|
|
@@ -1624,6 +1653,7 @@ const dictionaries = {
|
|
|
1624
1653
|
"toolcall.current_plan": "Current Plan",
|
|
1625
1654
|
"toolcall.approved": "Approved: {chosen}",
|
|
1626
1655
|
"toolcall.approved_label": "Approved",
|
|
1656
|
+
"toolcall.auto_approved": "Auto-approved",
|
|
1627
1657
|
"toolcall.input_unavailable": "Could not collect your input",
|
|
1628
1658
|
"toolcall.input_collected": "Collected your answer",
|
|
1629
1659
|
"toolcall.waiting_input": "Waiting for your input",
|
|
@@ -1751,6 +1781,8 @@ const dictionaries = {
|
|
|
1751
1781
|
"subagent.bind_title": "Bind {profile}",
|
|
1752
1782
|
"subagent.model_hint": "↑↓ Select model · Enter confirm · Esc back",
|
|
1753
1783
|
"subagent.save_failed": "Save failed: {msg}",
|
|
1784
|
+
"subagent.stale_binding": "{alias} (stale)",
|
|
1785
|
+
"subagent.invalid_alias": "Model alias {alias} does not exist",
|
|
1754
1786
|
"kdoctree.no_title": "(untitled)",
|
|
1755
1787
|
"kdoctree.empty": "(empty)",
|
|
1756
1788
|
"kdoctree.move": "Move",
|
|
@@ -1834,6 +1866,8 @@ const dictionaries = {
|
|
|
1834
1866
|
"export.session_title": "# Scream Session Export",
|
|
1835
1867
|
"bgtask.agent_task": "Agent task",
|
|
1836
1868
|
"bgtask.bash_task": "Bash task",
|
|
1869
|
+
"bash.background_completed": "Background task {id} completed: {command}",
|
|
1870
|
+
"bash.background_failed": "Background task {id} failed (exit {exitCode}): {command}",
|
|
1837
1871
|
"bgtask.started_bg": "{subject} started in background",
|
|
1838
1872
|
"bgtask.awaiting_approval": "{subject} awaiting approval",
|
|
1839
1873
|
"bgtask.completed_bg": "{subject} completed in background",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scream-code",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.8",
|
|
4
4
|
"description": "A terminal-native AI agent for builders",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ScreamCli",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"smoke": "node dist/main.mjs --version"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@liutod-scream/pi-tui": "^0.80.
|
|
62
|
+
"@liutod-scream/pi-tui": "^0.80.32",
|
|
63
63
|
"@mariozechner/clipboard": "^0.3.2",
|
|
64
64
|
"chalk": "^5.4.1",
|
|
65
65
|
"cli-highlight": "^2.1.11",
|