scream-code 0.11.5 → 0.11.7
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-BdUmo73M.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";
|
|
@@ -74692,6 +74692,62 @@ function truncateUtf8$1(input, maxBytes) {
|
|
|
74692
74692
|
//#region ../../packages/agent-core/src/tools/builtin/shell/bash.md
|
|
74693
74693
|
var bash_default = "Execute a `{{ SHELL_NAME }}` command. Use this for shell semantics — pipes, env, processes, git, package managers, build/test runners, anything genuinely interactive or multi-step.\n\n**Translate these to a dedicated tool instead:**\n- `cat` / `head` / `tail` (known path) → `Read`\n- `sed` / `awk` (in-place edit) → `Edit`\n- `echo > file` / `cat <<EOF` → `Write`\n- `find` / recursive `ls` to locate files by name pattern → `Glob` (plain `ls <known-directory>` is fine for listing a directory)\n- `grep` / `rg` (search file contents) → `Grep`\n- `echo` / `printf` (talk to the user) → just output text directly\n\nThe dedicated tools render in the per-tool permission UI and keep raw stdout out of the conversation; that is why they are worth reaching for whenever one fits.\n\n**Output:**\nThe stdout and stderr will be combined and returned as a string. The output may be truncated if it is too long. If the command failed, the output will end with a `Command failed with exit code: N` line stating the non-zero exit code.\n\nIf `run_in_background=true`, the command will be started as a background task and this tool will return a task ID instead of waiting for command completion. When doing that, you must provide a short `description`. Background commands default to a {{ DEFAULT_BACKGROUND_TIMEOUT_S }}s timeout and `timeout` is capped at {{ MAX_BACKGROUND_TIMEOUT_S }}s; set `disable_timeout=true` only when the task should run without a timeout. You will be automatically notified when the task completes. Use `TaskOutput` for a non-blocking status/output snapshot, and only set `block=true` when you explicitly want to wait for completion. Use `TaskStop` only if the task must be cancelled. If a human user wants to inspect background tasks themselves, point them to the `/tasks` command, which opens an interactive panel; it has no subcommands.\n\n**Guidelines for safety and security:**\n- Each shell tool call will be executed in a fresh shell environment. The shell variables, current working directory changes, and the shell history is not preserved between calls.\n- The tool call will return after the command is finished. You shall not use this tool to execute an interactive command or a command that may run forever. For possibly long-running foreground commands, set the `timeout` argument in seconds. Foreground commands default to {{ DEFAULT_TIMEOUT_S }}s and allow up to {{ MAX_TIMEOUT_S }}s.\n- Avoid using `..` to access files or directories outside of the working directory.\n- Avoid modifying files outside of the working directory unless explicitly instructed to do so.\n- Never run commands that require superuser privileges unless explicitly instructed to do so.\n\n**Guidelines for efficiency:**\n- For multiple related commands, use `&&` to chain them in a single call, e.g. `cd /path && ls -la`\n- Use `;` to run commands sequentially regardless of success/failure\n- Use `||` for conditional execution (run second command only if first fails)\n- Use pipe operations (`|`) and redirections (`>`, `>>`) to chain input and output between commands\n- Always quote file paths containing spaces with double quotes (e.g., cd \"/path with spaces/\")\n- Compose multi-step logic in a single call with `if` / `case` / `for` / `while` control flows.\n- Prefer `run_in_background=true` for long-running builds, tests, watchers, or servers when you need the conversation to continue before the command finishes.\n\n**Commands available:**\nThe following common command categories are usually available. Availability still depends on the host, so when in doubt run `which <command>` first to confirm a command exists before relying on it.\n- Navigation and inspection: `ls`, `pwd`, `cd`, `stat`, `file`, `du`, `df`, `tree`\n- File and directory management: `cp`, `mv`, `rm`, `mkdir`, `touch`, `ln`, `chmod`, `chown`\n- Text and data processing: `wc`, `sort`, `uniq`, `cut`, `tr`, `diff`, `xargs`\n- Archives and compression: `tar`, `gzip`, `gunzip`, `zip`, `unzip`\n- Networking and transfer: `curl`, `wget`, `ping`, `ssh`, `scp`\n- Version control: `git`\n- Process and system: `ps`, `kill`, `top`, `env`, `date`, `uname`, `whoami`\n- Language and package toolchains: `node`, `npm`, `pnpm`, `yarn`, `python`, `pip` (use whichever the project actually relies on)\n";
|
|
74694
74694
|
//#endregion
|
|
74695
|
+
//#region ../../packages/agent-core/src/tools/builtin/shell/background-tasks.ts
|
|
74696
|
+
/**
|
|
74697
|
+
* Lightweight store for foreground Bash commands that were moved to
|
|
74698
|
+
* background on timeout. The process continues running; when it exits
|
|
74699
|
+
* the result is stored here and surfaced to the model on the next Bash
|
|
74700
|
+
* call.
|
|
74701
|
+
*
|
|
74702
|
+
* This is intentionally simple - it does NOT use the full
|
|
74703
|
+
* BackgroundProcessManager (which assumes it owns the process streams
|
|
74704
|
+
* from spawn). Here the streams are already being read by the
|
|
74705
|
+
* foreground ToolResultBuilder, so we just wrap the pending
|
|
74706
|
+
* completion promise.
|
|
74707
|
+
*/
|
|
74708
|
+
const pendingTasks = /* @__PURE__ */ new Map();
|
|
74709
|
+
const MAX_PENDING = 10;
|
|
74710
|
+
function createBackgroundTask(command, completion) {
|
|
74711
|
+
const id = randomUUID().slice(0, 8);
|
|
74712
|
+
const task = {
|
|
74713
|
+
command,
|
|
74714
|
+
startedAt: Date.now(),
|
|
74715
|
+
completion
|
|
74716
|
+
};
|
|
74717
|
+
if (pendingTasks.size >= MAX_PENDING) {
|
|
74718
|
+
const oldest = pendingTasks.keys().next().value;
|
|
74719
|
+
if (oldest !== void 0) pendingTasks.delete(oldest);
|
|
74720
|
+
}
|
|
74721
|
+
pendingTasks.set(id, task);
|
|
74722
|
+
task.completion.then((result) => {
|
|
74723
|
+
task.result = result;
|
|
74724
|
+
}, () => {
|
|
74725
|
+
task.result = {
|
|
74726
|
+
exitCode: -1,
|
|
74727
|
+
output: "Background process failed."
|
|
74728
|
+
};
|
|
74729
|
+
});
|
|
74730
|
+
return id;
|
|
74731
|
+
}
|
|
74732
|
+
/**
|
|
74733
|
+
* Collect results from background tasks that have completed since the
|
|
74734
|
+
* last check. Each completed task is returned once and then removed.
|
|
74735
|
+
*/
|
|
74736
|
+
function drainCompletedBackgroundTasks() {
|
|
74737
|
+
const completed = [];
|
|
74738
|
+
for (const [id, task] of pendingTasks) if (task.result !== void 0) {
|
|
74739
|
+
completed.push({
|
|
74740
|
+
id,
|
|
74741
|
+
command: task.command,
|
|
74742
|
+
exitCode: task.result.exitCode,
|
|
74743
|
+
output: task.result.output,
|
|
74744
|
+
elapsedMs: Date.now() - task.startedAt
|
|
74745
|
+
});
|
|
74746
|
+
pendingTasks.delete(id);
|
|
74747
|
+
}
|
|
74748
|
+
return completed;
|
|
74749
|
+
}
|
|
74750
|
+
//#endregion
|
|
74695
74751
|
//#region ../../packages/agent-core/src/tools/builtin/shell/bash.ts
|
|
74696
74752
|
/**
|
|
74697
74753
|
* BashTool — execute shell commands.
|
|
@@ -74878,7 +74934,7 @@ var BashTool = class {
|
|
|
74878
74934
|
},
|
|
74879
74935
|
approvalRule: literalRulePattern(this.name, args.command),
|
|
74880
74936
|
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.command),
|
|
74881
|
-
execute: (
|
|
74937
|
+
execute: (ctx) => this.execution(args, ctx)
|
|
74882
74938
|
};
|
|
74883
74939
|
}
|
|
74884
74940
|
spawn(effectiveCwd, command) {
|
|
@@ -74898,14 +74954,17 @@ var BashTool = class {
|
|
|
74898
74954
|
};
|
|
74899
74955
|
return this.jian.execWithEnv(shellArgs, mergedEnv);
|
|
74900
74956
|
}
|
|
74901
|
-
async execution(args,
|
|
74957
|
+
async execution(args, ctx) {
|
|
74958
|
+
const { signal, onUpdate } = ctx;
|
|
74959
|
+
const completedBg = drainCompletedBackgroundTasks();
|
|
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("") : "";
|
|
74902
74961
|
if (signal.aborted) return {
|
|
74903
74962
|
isError: true,
|
|
74904
|
-
output: "Aborted before command started"
|
|
74963
|
+
output: bgPrefix + "Aborted before command started"
|
|
74905
74964
|
};
|
|
74906
74965
|
if (args.command.length === 0) return {
|
|
74907
74966
|
isError: true,
|
|
74908
|
-
output: "Command cannot be empty."
|
|
74967
|
+
output: bgPrefix + "Command cannot be empty."
|
|
74909
74968
|
};
|
|
74910
74969
|
const validationError = validateCommand(args.command, this.isWindowsBash);
|
|
74911
74970
|
if (validationError !== null) return validationError;
|
|
@@ -74933,9 +74992,16 @@ var BashTool = class {
|
|
|
74933
74992
|
try {
|
|
74934
74993
|
proc.stdin.end();
|
|
74935
74994
|
} catch {}
|
|
74936
|
-
let timedOut = false;
|
|
74937
74995
|
let aborted = false;
|
|
74938
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
|
+
};
|
|
74939
75005
|
const killProc = async () => {
|
|
74940
75006
|
if (killed) return;
|
|
74941
75007
|
killed = true;
|
|
@@ -74962,21 +75028,57 @@ var BashTool = class {
|
|
|
74962
75028
|
killProc();
|
|
74963
75029
|
};
|
|
74964
75030
|
signal.addEventListener("abort", onAbort);
|
|
74965
|
-
|
|
74966
|
-
|
|
74967
|
-
|
|
74968
|
-
}
|
|
75031
|
+
let timeoutHandle;
|
|
75032
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
75033
|
+
if (timeoutMs !== void 0) timeoutHandle = setTimeout(() => resolve({ timedOut: true }), timeoutMs);
|
|
75034
|
+
});
|
|
74969
75035
|
try {
|
|
74970
75036
|
const builder = new ToolResultBuilder({ artifactSink: async (fullOutput) => {
|
|
74971
75037
|
const artifactPath = join(tmpdir(), `scream-bash-output-${randomUUID()}.log`);
|
|
74972
75038
|
await writeFile(artifactPath, fullOutput, "utf8");
|
|
74973
75039
|
return artifactPath;
|
|
74974
75040
|
} });
|
|
74975
|
-
|
|
74976
|
-
|
|
75041
|
+
if (bgPrefix.length > 0) builder.write(bgPrefix);
|
|
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]) => ({
|
|
75043
|
+
timedOut: false,
|
|
75044
|
+
exitCode
|
|
75045
|
+
}));
|
|
75046
|
+
const raceResult = timeoutMs !== void 0 ? await Promise.race([completionPromise, timeoutPromise]) : await completionPromise;
|
|
75047
|
+
if (raceResult.timedOut) {
|
|
75048
|
+
streaming = false;
|
|
74977
75049
|
const timeoutLabel = timeoutMs % 1e3 === 0 ? `${String(timeoutMs / 1e3)}s` : `${String(timeoutMs)}ms`;
|
|
74978
|
-
|
|
75050
|
+
const taskId = createBackgroundTask(command, completionPromise.then(({ exitCode }) => ({
|
|
75051
|
+
exitCode,
|
|
75052
|
+
output: builder.toString()
|
|
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
|
+
});
|
|
75075
|
+
const outputSoFar = builder.toString();
|
|
75076
|
+
return {
|
|
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.`,
|
|
75078
|
+
isError: false
|
|
75079
|
+
};
|
|
74979
75080
|
}
|
|
75081
|
+
const { exitCode } = raceResult;
|
|
74980
75082
|
if (aborted) return builder.error("Interrupted by user", { brief: "Interrupted by user" });
|
|
74981
75083
|
const isError = exitCode !== 0;
|
|
74982
75084
|
if (isError && builder.nChars === 0) builder.write(`Process exited with code ${String(exitCode)}`);
|
|
@@ -74989,7 +75091,7 @@ var BashTool = class {
|
|
|
74989
75091
|
output: error instanceof Error ? error.message : String(error)
|
|
74990
75092
|
};
|
|
74991
75093
|
} finally {
|
|
74992
|
-
clearTimeout(timeoutHandle);
|
|
75094
|
+
if (timeoutHandle !== void 0) clearTimeout(timeoutHandle);
|
|
74993
75095
|
signal.removeEventListener("abort", onAbort);
|
|
74994
75096
|
}
|
|
74995
75097
|
}
|
|
@@ -75067,13 +75169,33 @@ human_shell_hint: Tell the human to run /tasks to open the interactive backgroun
|
|
|
75067
75169
|
return builder.ok("Background task started", { brief: `Started ${taskId}` });
|
|
75068
75170
|
}
|
|
75069
75171
|
};
|
|
75070
|
-
|
|
75172
|
+
const LIVE_OUTPUT_FLUSH_MS = 100;
|
|
75173
|
+
async function readStreamIntoBuilder(stream, builder, onChunk) {
|
|
75071
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
|
+
};
|
|
75072
75184
|
for await (const chunk of stream) {
|
|
75073
75185
|
const buf = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
75074
|
-
|
|
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);
|
|
75075
75198
|
}
|
|
75076
|
-
builder.write(decoder.end());
|
|
75077
75199
|
}
|
|
75078
75200
|
function shellQuote$1(s) {
|
|
75079
75201
|
return `'${s.replaceAll("'", "'\\''")}'`;
|
|
@@ -120531,7 +120653,7 @@ function optionalBuildString(value) {
|
|
|
120531
120653
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
120532
120654
|
}
|
|
120533
120655
|
const SCREAM_BUILD_INFO = {
|
|
120534
|
-
version: optionalBuildString("0.11.
|
|
120656
|
+
version: optionalBuildString("0.11.7"),
|
|
120535
120657
|
channel: optionalBuildString(""),
|
|
120536
120658
|
commit: optionalBuildString(""),
|
|
120537
120659
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -120801,6 +120923,8 @@ const TuiLikePreferencesSchema = z.object({
|
|
|
120801
120923
|
const TuiConfigFileSchema = z.object({
|
|
120802
120924
|
theme: TuiThemeSchema.optional(),
|
|
120803
120925
|
language: z.enum(["zh", "en"]).optional(),
|
|
120926
|
+
/** Auto-enter the welcome page after the loading splash finishes. */
|
|
120927
|
+
autoStart: z.boolean().optional(),
|
|
120804
120928
|
editor: z.object({ command: z.string().optional() }).optional(),
|
|
120805
120929
|
notifications: z.object({
|
|
120806
120930
|
enabled: z.boolean().optional(),
|
|
@@ -120816,6 +120940,7 @@ const TuiConfigFileSchema = z.object({
|
|
|
120816
120940
|
const TuiConfigSchema = z.object({
|
|
120817
120941
|
theme: TuiThemeSchema,
|
|
120818
120942
|
language: z.enum(["zh", "en"]),
|
|
120943
|
+
autoStart: z.boolean(),
|
|
120819
120944
|
editorCommand: z.string().nullable(),
|
|
120820
120945
|
notifications: NotificationsConfigSchema,
|
|
120821
120946
|
like: TuiLikePreferencesSchema,
|
|
@@ -120832,6 +120957,7 @@ const DEFAULT_NOTIFICATIONS_CONFIG = {
|
|
|
120832
120957
|
const DEFAULT_TUI_CONFIG = TuiConfigSchema.parse({
|
|
120833
120958
|
theme: "auto",
|
|
120834
120959
|
language: getLocale(),
|
|
120960
|
+
autoStart: false,
|
|
120835
120961
|
editorCommand: null,
|
|
120836
120962
|
notifications: DEFAULT_NOTIFICATIONS_CONFIG,
|
|
120837
120963
|
like: {},
|
|
@@ -120884,6 +121010,7 @@ function normalizeTuiConfig(config) {
|
|
|
120884
121010
|
return TuiConfigSchema.parse({
|
|
120885
121011
|
theme: config.theme ?? DEFAULT_TUI_CONFIG.theme,
|
|
120886
121012
|
language: config.language ?? DEFAULT_TUI_CONFIG.language,
|
|
121013
|
+
autoStart: config.autoStart ?? DEFAULT_TUI_CONFIG.autoStart,
|
|
120887
121014
|
editorCommand: command === void 0 || command.length === 0 ? null : command,
|
|
120888
121015
|
notifications: {
|
|
120889
121016
|
enabled: config.notifications?.enabled ?? DEFAULT_NOTIFICATIONS_CONFIG.enabled,
|
|
@@ -120927,6 +121054,7 @@ function renderTuiConfig(config) {
|
|
|
120927
121054
|
|
|
120928
121055
|
theme = "${config.theme}" # "auto" | "dark" | "light"
|
|
120929
121056
|
language = "${config.language}" # "zh" | "en"
|
|
121057
|
+
autoStart = ${String(config.autoStart)} # true = auto-enter welcome after loading
|
|
120930
121058
|
|
|
120931
121059
|
[editor]
|
|
120932
121060
|
command = "${escapeTomlBasicString(config.editorCommand ?? "")}" # Empty uses $VISUAL / $EDITOR
|
|
@@ -123742,14 +123870,28 @@ function formatTokenCount(n) {
|
|
|
123742
123870
|
function safeUsage(usage) {
|
|
123743
123871
|
return safeUsageRatio(usage);
|
|
123744
123872
|
}
|
|
123873
|
+
const CONTEXT_BAR_WIDTH = 10;
|
|
123874
|
+
const CONTEXT_BAR_FILLED = "▰";
|
|
123875
|
+
const CONTEXT_BAR_EMPTY = "▱";
|
|
123876
|
+
/**
|
|
123877
|
+
* Half-block progress bar for context usage: `▰▰▰▱▱▱▱▱▱▱` (10 cells).
|
|
123878
|
+
* Filled cells are rounded from the clamped ratio, so 0% is all-empty and
|
|
123879
|
+
* >=100% is all-filled; NaN/undefined coerce through safeUsageRatio first.
|
|
123880
|
+
*/
|
|
123881
|
+
function formatContextBar(usage, width = CONTEXT_BAR_WIDTH) {
|
|
123882
|
+
const clamped = Math.min(1, Math.max(0, safeUsageRatio(usage)));
|
|
123883
|
+
const filled = Math.round(clamped * width);
|
|
123884
|
+
return CONTEXT_BAR_FILLED.repeat(filled) + CONTEXT_BAR_EMPTY.repeat(width - filled);
|
|
123885
|
+
}
|
|
123745
123886
|
function formatContextStatus(usage, tokens, maxTokens) {
|
|
123746
123887
|
const pct = `${(safeUsage(usage) * 100).toFixed(1)}%`;
|
|
123888
|
+
const barAndPct = `${formatContextBar(usage)} ${pct}`;
|
|
123747
123889
|
if (maxTokens && maxTokens > 0 && tokens !== void 0) return t("footer.context", {
|
|
123748
|
-
pct,
|
|
123890
|
+
pct: barAndPct,
|
|
123749
123891
|
tokens: formatTokenCount(tokens),
|
|
123750
123892
|
maxTokens: formatTokenCount(maxTokens)
|
|
123751
123893
|
});
|
|
123752
|
-
return t("footer.context_short", { pct });
|
|
123894
|
+
return t("footer.context_short", { pct: barAndPct });
|
|
123753
123895
|
}
|
|
123754
123896
|
/** Format goal wall-clock duration compactly: `3m`, `1m30s`, `45s`. */
|
|
123755
123897
|
function formatGoalDuration(ms) {
|
|
@@ -124022,6 +124164,7 @@ async function applyLanguageChoice(host, locale) {
|
|
|
124022
124164
|
setLocale(locale);
|
|
124023
124165
|
host.state.appState.language = locale;
|
|
124024
124166
|
await saveTuiConfig({
|
|
124167
|
+
...await loadTuiConfig(),
|
|
124025
124168
|
theme: host.state.appState.theme,
|
|
124026
124169
|
language: locale,
|
|
124027
124170
|
editorCommand: host.state.appState.editorCommand,
|
|
@@ -125088,6 +125231,7 @@ async function applyEditorChoice(host, value) {
|
|
|
125088
125231
|
const editorCommand = value.length > 0 ? value : null;
|
|
125089
125232
|
try {
|
|
125090
125233
|
await saveTuiConfig({
|
|
125234
|
+
...await loadTuiConfig(),
|
|
125091
125235
|
theme: host.state.appState.theme,
|
|
125092
125236
|
language: host.state.appState.language,
|
|
125093
125237
|
editorCommand,
|
|
@@ -125273,6 +125417,7 @@ async function applyThemeChoice(host, theme) {
|
|
|
125273
125417
|
}
|
|
125274
125418
|
try {
|
|
125275
125419
|
await saveTuiConfig({
|
|
125420
|
+
...await loadTuiConfig(),
|
|
125276
125421
|
theme,
|
|
125277
125422
|
language: host.state.appState.language,
|
|
125278
125423
|
editorCommand: host.state.appState.editorCommand,
|
|
@@ -126050,7 +126195,7 @@ async function guidedGoalSetup(host) {
|
|
|
126050
126195
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
126051
126196
|
return;
|
|
126052
126197
|
}
|
|
126053
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
126198
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-Ct-Yn67a.mjs");
|
|
126054
126199
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
126055
126200
|
title: t("goal.setup_title_initial"),
|
|
126056
126201
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -126071,7 +126216,7 @@ async function guidedGoalSetup(host) {
|
|
|
126071
126216
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
126072
126217
|
}
|
|
126073
126218
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
126074
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
126219
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-Ct-Yn67a.mjs");
|
|
126075
126220
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
126076
126221
|
title: t("goal.wizard_title", { objective }),
|
|
126077
126222
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -128458,7 +128603,7 @@ const globGlance = (_toolCall, result, colors) => {
|
|
|
128458
128603
|
const more = names.length - GLANCE_SAMPLES;
|
|
128459
128604
|
return `${head}${shown}${more > 0 ? dim(` (+${String(more)})`) : ""}`;
|
|
128460
128605
|
}).join(dim(" "));
|
|
128461
|
-
const extLine = [...countExtensions(lines).entries()].
|
|
128606
|
+
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(", "));
|
|
128462
128607
|
if (extLine.length === 0) return dirLine;
|
|
128463
128608
|
return `${dirLine}${dim(" ")}${extLine}`;
|
|
128464
128609
|
};
|
|
@@ -128488,8 +128633,56 @@ const readGlance = (toolCall, result, colors) => {
|
|
|
128488
128633
|
if (parts.length === 0) return "";
|
|
128489
128634
|
return parts.join(dim(" · "));
|
|
128490
128635
|
};
|
|
128636
|
+
/**
|
|
128637
|
+
* Parse the fixed WebSearch output protocol emitted by
|
|
128638
|
+
* `web-search.ts` (`Title: …` / `Date: …` / `URL: …` / `Snippet: …`,
|
|
128639
|
+
* entries separated by `---`) into structured entries so the collapsed
|
|
128640
|
+
* card can show a title/URL glance instead of a bare "N results" chip.
|
|
128641
|
+
*/
|
|
128642
|
+
function parseWebSearchOutput(output) {
|
|
128643
|
+
const entries = [];
|
|
128644
|
+
let title;
|
|
128645
|
+
let url;
|
|
128646
|
+
let inSnippet = false;
|
|
128647
|
+
for (const line of output.split("\n")) {
|
|
128648
|
+
if (line.startsWith("---")) {
|
|
128649
|
+
if (title !== void 0 || url !== void 0) entries.push({
|
|
128650
|
+
title: title ?? "",
|
|
128651
|
+
url: url ?? ""
|
|
128652
|
+
});
|
|
128653
|
+
title = void 0;
|
|
128654
|
+
url = void 0;
|
|
128655
|
+
inSnippet = false;
|
|
128656
|
+
continue;
|
|
128657
|
+
}
|
|
128658
|
+
if (inSnippet) continue;
|
|
128659
|
+
if (line.startsWith("Snippet: ")) inSnippet = true;
|
|
128660
|
+
else if (line.startsWith("Title: ")) title = line.slice(7);
|
|
128661
|
+
else if (line.startsWith("URL: ")) url = line.slice(5);
|
|
128662
|
+
}
|
|
128663
|
+
if (title !== void 0 || url !== void 0) entries.push({
|
|
128664
|
+
title: title ?? "",
|
|
128665
|
+
url: url ?? ""
|
|
128666
|
+
});
|
|
128667
|
+
return entries;
|
|
128668
|
+
}
|
|
128669
|
+
function truncateText(text, max = 60) {
|
|
128670
|
+
return text.length <= max ? text : `${text.slice(0, max - 1)}…`;
|
|
128671
|
+
}
|
|
128672
|
+
const webSearchGlance = (_toolCall, result, colors) => {
|
|
128673
|
+
const entries = parseWebSearchOutput(result.output);
|
|
128674
|
+
if (entries.length === 0) return "";
|
|
128675
|
+
const titleColor = chalk.hex(colors.roleTool);
|
|
128676
|
+
const dim = chalk.dim;
|
|
128677
|
+
const lines = entries.slice(0, GLANCE_SAMPLES).map((e) => {
|
|
128678
|
+
return [e.title.length > 0 ? titleColor(truncateText(e.title)) : "", e.url.length > 0 ? dim(truncateText(e.url)) : ""].filter((s) => s.length > 0).join(dim(" — "));
|
|
128679
|
+
});
|
|
128680
|
+
const remaining = entries.length - GLANCE_SAMPLES;
|
|
128681
|
+
if (remaining > 0) lines.push(dim(`+${String(remaining)} more`));
|
|
128682
|
+
return lines.join("\n");
|
|
128683
|
+
};
|
|
128491
128684
|
const fetchSummary = withGlance(null);
|
|
128492
|
-
const webSearchSummary = withGlance(
|
|
128685
|
+
const webSearchSummary = withGlance(webSearchGlance);
|
|
128493
128686
|
const thinkSummary = withGlance(null);
|
|
128494
128687
|
const editSummary = withGlance(null);
|
|
128495
128688
|
const writeSummary = withGlance(null);
|
|
@@ -128537,6 +128730,7 @@ const STREAMING_PROGRESS_INTERVAL_MS = 1e3;
|
|
|
128537
128730
|
const SUBAGENT_ELAPSED_INTERVAL_MS = 1e3;
|
|
128538
128731
|
const PROGRESS_URL_RE = /https?:\/\/\S+/g;
|
|
128539
128732
|
const MAX_PROGRESS_LINE_CHARS = 1e4;
|
|
128733
|
+
const MAX_LIVE_OUTPUT_CHARS = 5e4;
|
|
128540
128734
|
function backgroundFailureMessage(status) {
|
|
128541
128735
|
switch (status) {
|
|
128542
128736
|
case "lost": return t("toolcall.bg_agent_lost");
|
|
@@ -128855,6 +129049,10 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
128855
129049
|
subagentEndedAtMs;
|
|
128856
129050
|
progressLines = [];
|
|
128857
129051
|
static MAX_PROGRESS_LINES = 24;
|
|
129052
|
+
/** Live stdout/stderr accumulated via appendLiveOutput while the tool runs. */
|
|
129053
|
+
liveOutput = "";
|
|
129054
|
+
/** Session permission mode at card creation; drives ExitPlanMode chip wording. */
|
|
129055
|
+
permissionMode;
|
|
128858
129056
|
writeStreamContentStart = -1;
|
|
128859
129057
|
writeStreamNlScanOffset = 0;
|
|
128860
129058
|
writeStreamNlCount = 0;
|
|
@@ -128917,6 +129115,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
128917
129115
|
setResult(result) {
|
|
128918
129116
|
this.result = result;
|
|
128919
129117
|
this.progressLines = [];
|
|
129118
|
+
this.liveOutput = "";
|
|
128920
129119
|
this.finalizeSubagentElapsedIfNeeded();
|
|
128921
129120
|
this.syncStreamingProgressTimer();
|
|
128922
129121
|
this.syncSubagentElapsedTimer();
|
|
@@ -128947,6 +129146,31 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
128947
129146
|
this.notifySnapshotChange();
|
|
128948
129147
|
this.ui?.requestRender();
|
|
128949
129148
|
}
|
|
129149
|
+
/**
|
|
129150
|
+
* Append live stdout/stderr from a running tool (Bash). Kept separate
|
|
129151
|
+
* from appendProgress so streaming command output renders with the same
|
|
129152
|
+
* tail-preview styling as the final result. The buffer is capped and
|
|
129153
|
+
* tail-preserving so a runaway command cannot grow the box unboundedly;
|
|
129154
|
+
* the block is dropped entirely once the real result lands.
|
|
129155
|
+
*/
|
|
129156
|
+
appendLiveOutput(text) {
|
|
129157
|
+
if (this.result !== void 0 || text.length === 0) return;
|
|
129158
|
+
this.liveOutput += text;
|
|
129159
|
+
if (this.liveOutput.length > MAX_LIVE_OUTPUT_CHARS) this.liveOutput = `[...truncated]\n${this.liveOutput.slice(this.liveOutput.length - MAX_LIVE_OUTPUT_CHARS)}`;
|
|
129160
|
+
this.rebuildContent();
|
|
129161
|
+
this.notifySnapshotChange();
|
|
129162
|
+
this.ui?.requestRender();
|
|
129163
|
+
}
|
|
129164
|
+
/**
|
|
129165
|
+
* Records the session permission mode so ExitPlanMode can render an
|
|
129166
|
+
* honest "auto-approved" chip when the plan passed without user review.
|
|
129167
|
+
*/
|
|
129168
|
+
setPermissionMode(mode) {
|
|
129169
|
+
if (this.permissionMode === mode) return;
|
|
129170
|
+
this.permissionMode = mode;
|
|
129171
|
+
this.headerText.setText(this.buildHeader());
|
|
129172
|
+
this.ui?.requestRender();
|
|
129173
|
+
}
|
|
128950
129174
|
dispose() {
|
|
128951
129175
|
if (this.disposed) return;
|
|
128952
129176
|
this.disposed = true;
|
|
@@ -129351,7 +129575,10 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129351
129575
|
const isError = result?.is_error ?? false;
|
|
129352
129576
|
const isTruncated = toolCall.truncated === true && !isFinished;
|
|
129353
129577
|
let bullet;
|
|
129354
|
-
if (isFinished)
|
|
129578
|
+
if (isFinished) if (isError) {
|
|
129579
|
+
const output = typeof result?.output === "string" ? result.output : "";
|
|
129580
|
+
bullet = /\b(?:aborted|cancelled|canceled)\b/i.test(output) ? chalk.hex(colors.warning)("⊙ ") : chalk.hex(colors.error)("✗ ");
|
|
129581
|
+
} else bullet = chalk.hex(colors.success)(STATUS_BULLET);
|
|
129355
129582
|
else if (isTruncated) bullet = chalk.hex(colors.error)("✗ ");
|
|
129356
129583
|
else bullet = chalk.hex(colors.roleAssistant)(STATUS_BULLET);
|
|
129357
129584
|
if (toolCall.name === "ExitPlanMode") {
|
|
@@ -129359,6 +129586,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129359
129586
|
if (!isFinished || result === void 0 || result.is_error === true) return label;
|
|
129360
129587
|
const outcome = interpretExitPlanModeOutcome(result.output);
|
|
129361
129588
|
if (outcome.kind === "approved") {
|
|
129589
|
+
if (this.permissionMode === "auto" && outcome.chosen === void 0) return `${label}${chalk.hex(colors.warning)(` · ${t("toolcall.auto_approved")}`)}`;
|
|
129362
129590
|
const chipText = outcome.chosen !== void 0 && outcome.chosen.length > 0 ? t("toolcall.approved", { chosen: outcome.chosen }) : t("toolcall.approved_label");
|
|
129363
129591
|
return `${label}${chalk.hex(colors.success)(` · ${chipText}`)}`;
|
|
129364
129592
|
}
|
|
@@ -129391,6 +129619,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129391
129619
|
this.markDirty();
|
|
129392
129620
|
while (this.children.length > this.callPreviewEndIndex) this.children.pop();
|
|
129393
129621
|
this.buildProgressBlock();
|
|
129622
|
+
this.buildLiveOutputBlock();
|
|
129394
129623
|
this.buildContent();
|
|
129395
129624
|
this.buildSubagentBlock();
|
|
129396
129625
|
}
|
|
@@ -129400,6 +129629,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129400
129629
|
this.buildCallPreview();
|
|
129401
129630
|
this.callPreviewEndIndex = this.children.length;
|
|
129402
129631
|
this.buildProgressBlock();
|
|
129632
|
+
this.buildLiveOutputBlock();
|
|
129403
129633
|
this.buildContent();
|
|
129404
129634
|
this.buildSubagentBlock();
|
|
129405
129635
|
}
|
|
@@ -129429,6 +129659,25 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
129429
129659
|
this.addChild(new Text(styled, 2, 0));
|
|
129430
129660
|
}
|
|
129431
129661
|
}
|
|
129662
|
+
/**
|
|
129663
|
+
* Render live stdout/stderr while the tool is still running. Reuses the
|
|
129664
|
+
* shell result renderer so the streaming tail matches the final output's
|
|
129665
|
+
* preview styling (including ctrl+o expansion); the block is skipped once
|
|
129666
|
+
* the real result has landed.
|
|
129667
|
+
*/
|
|
129668
|
+
buildLiveOutputBlock() {
|
|
129669
|
+
if (this.result !== void 0) return;
|
|
129670
|
+
if (this.liveOutput.length === 0) return;
|
|
129671
|
+
const components = shellExecutionResultRenderer(this.toolCall, {
|
|
129672
|
+
tool_call_id: this.toolCall.id,
|
|
129673
|
+
output: this.liveOutput,
|
|
129674
|
+
is_error: false
|
|
129675
|
+
}, {
|
|
129676
|
+
expanded: this.expanded,
|
|
129677
|
+
colors: this.colors
|
|
129678
|
+
});
|
|
129679
|
+
for (const component of components) this.addChild(component);
|
|
129680
|
+
}
|
|
129432
129681
|
buildSubagentBlock() {
|
|
129433
129682
|
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;
|
|
129434
129683
|
if (this.isSingleSubagentView()) {
|
|
@@ -130845,17 +131094,6 @@ async function handleUpdateCommand(host) {
|
|
|
130845
131094
|
* 查看已安装的 MCP 服务器状态,一键安装推荐服务器。 */
|
|
130846
131095
|
function getRecommended() {
|
|
130847
131096
|
return [{
|
|
130848
|
-
name: "peekaboo",
|
|
130849
|
-
displayName: "Peekaboo",
|
|
130850
|
-
description: t("mcp.desktop_desc"),
|
|
130851
|
-
command: "npx",
|
|
130852
|
-
args: [
|
|
130853
|
-
"-y",
|
|
130854
|
-
"@steipete/peekaboo",
|
|
130855
|
-
"mcp"
|
|
130856
|
-
],
|
|
130857
|
-
macOnly: true
|
|
130858
|
-
}, {
|
|
130859
131097
|
name: "chrome-devtools",
|
|
130860
131098
|
displayName: "Chrome DevTools",
|
|
130861
131099
|
description: t("mcp.browser_desc"),
|
|
@@ -130865,6 +131103,14 @@ function getRecommended() {
|
|
|
130865
131103
|
"chrome-devtools-mcp@latest",
|
|
130866
131104
|
"--no-usage-statistics"
|
|
130867
131105
|
]
|
|
131106
|
+
}, {
|
|
131107
|
+
name: "scream-life",
|
|
131108
|
+
displayName: "ScreamLife",
|
|
131109
|
+
description: "Decision memory system - captures and analyzes your decisions during conversations",
|
|
131110
|
+
command: "bun",
|
|
131111
|
+
args: ["{INSTALL_DIR}/Core/mcp-server.ts"],
|
|
131112
|
+
env: { SCREAM_LIFE_DB_PATH: "{INSTALL_DIR}/Data/scream-life.db" },
|
|
131113
|
+
gitUrl: "https://github.com/LIUTod/scream-life.git"
|
|
130868
131114
|
}];
|
|
130869
131115
|
}
|
|
130870
131116
|
function getStatusLabels() {
|
|
@@ -131039,12 +131285,37 @@ async function installMcp(host, rec) {
|
|
|
131039
131285
|
const spinner = host.showProgressSpinner(`${t("mcp.installing")} ${rec.displayName}...`);
|
|
131040
131286
|
spinner.setLabel(`${t("mcp.configuring")} ${rec.displayName}...`);
|
|
131041
131287
|
try {
|
|
131042
|
-
|
|
131043
|
-
|
|
131288
|
+
let resolvedArgs = rec.args;
|
|
131289
|
+
let resolvedEnv = rec.env;
|
|
131290
|
+
if (rec.gitUrl !== void 0) {
|
|
131291
|
+
const installDir = join(getDataDir(), "mcp", rec.name);
|
|
131292
|
+
if (existsSync(join(installDir, ".git"))) {
|
|
131293
|
+
spinner.setLabel(`Updating ${rec.displayName}...`);
|
|
131294
|
+
execSync(`git pull --ff-only`, {
|
|
131295
|
+
cwd: installDir,
|
|
131296
|
+
stdio: "pipe",
|
|
131297
|
+
timeout: 3e4
|
|
131298
|
+
});
|
|
131299
|
+
} else {
|
|
131300
|
+
spinner.setLabel(`Cloning ${rec.displayName}...`);
|
|
131301
|
+
await mkdir(installDir, { recursive: true });
|
|
131302
|
+
execSync(`git clone --depth 1 ${rec.gitUrl} "${installDir}"`, {
|
|
131303
|
+
stdio: "pipe",
|
|
131304
|
+
timeout: 6e4
|
|
131305
|
+
});
|
|
131306
|
+
}
|
|
131307
|
+
await mkdir(join(installDir, "Data"), { recursive: true });
|
|
131308
|
+
resolvedArgs = rec.args.map((a) => a.replaceAll("{INSTALL_DIR}", installDir));
|
|
131309
|
+
if (resolvedEnv !== void 0) resolvedEnv = Object.fromEntries(Object.entries(resolvedEnv).map(([k, v]) => [k, v.replaceAll("{INSTALL_DIR}", installDir)]));
|
|
131310
|
+
}
|
|
131311
|
+
await writeMcpConfig(host, rec.name, rec.command, resolvedArgs, resolvedEnv);
|
|
131312
|
+
const serverConfig = {
|
|
131044
131313
|
transport: "stdio",
|
|
131045
131314
|
command: rec.command,
|
|
131046
|
-
args:
|
|
131047
|
-
}
|
|
131315
|
+
args: resolvedArgs
|
|
131316
|
+
};
|
|
131317
|
+
if (resolvedEnv !== void 0 && Object.keys(resolvedEnv).length > 0) serverConfig.env = resolvedEnv;
|
|
131318
|
+
await session.addMcpServer(rec.name, serverConfig);
|
|
131048
131319
|
spinner.stop({
|
|
131049
131320
|
ok: true,
|
|
131050
131321
|
label: t("mcp.install_success", { name: rec.displayName })
|
|
@@ -131090,7 +131361,7 @@ async function uninstallMcp(host, name) {
|
|
|
131090
131361
|
host.showError(t("mcp.uninstall_failed", { msg: error instanceof Error ? error.message : String(error) }));
|
|
131091
131362
|
}
|
|
131092
131363
|
}
|
|
131093
|
-
async function writeMcpConfig(host, name, command, args) {
|
|
131364
|
+
async function writeMcpConfig(host, name, command, args, env) {
|
|
131094
131365
|
const configPath = join(getDataDir(), "mcp.json");
|
|
131095
131366
|
let data = {};
|
|
131096
131367
|
try {
|
|
@@ -131098,12 +131369,14 @@ async function writeMcpConfig(host, name, command, args) {
|
|
|
131098
131369
|
data = JSON.parse(text);
|
|
131099
131370
|
} catch {}
|
|
131100
131371
|
const servers = data["mcpServers"] ?? {};
|
|
131101
|
-
|
|
131372
|
+
const config = {
|
|
131102
131373
|
transport: "stdio",
|
|
131103
131374
|
command,
|
|
131104
131375
|
args,
|
|
131105
131376
|
startupTimeoutMs: 3e5
|
|
131106
131377
|
};
|
|
131378
|
+
if (env !== void 0 && Object.keys(env).length > 0) config["env"] = env;
|
|
131379
|
+
servers[name] = config;
|
|
131107
131380
|
data["mcpServers"] = servers;
|
|
131108
131381
|
await mkdir(dirname$1(configPath), { recursive: true });
|
|
131109
131382
|
await writeFile(configPath, JSON.stringify(data, null, 2), "utf-8");
|
|
@@ -136427,12 +136700,32 @@ var SessionEventHandler = class {
|
|
|
136427
136700
|
streamingUI.scheduleFlush();
|
|
136428
136701
|
}
|
|
136429
136702
|
handleToolProgress(event) {
|
|
136430
|
-
if (event.update.kind
|
|
136703
|
+
if (event.update.kind === "custom" && event.update.customKind === "background.task.terminated") {
|
|
136704
|
+
const data = event.update.customData;
|
|
136705
|
+
const id = typeof data?.id === "string" ? data.id : "";
|
|
136706
|
+
const command = typeof data?.command === "string" ? data.command : "";
|
|
136707
|
+
const exitCode = typeof data?.exitCode === "number" ? data.exitCode : -1;
|
|
136708
|
+
const preview = command.length > 60 ? `${command.slice(0, 59)}…` : command;
|
|
136709
|
+
if (exitCode === 0) this.host.showNotice(t("bash.background_completed", {
|
|
136710
|
+
id,
|
|
136711
|
+
command: preview
|
|
136712
|
+
}));
|
|
136713
|
+
else this.host.showNotice(t("bash.background_failed", {
|
|
136714
|
+
id,
|
|
136715
|
+
command: preview,
|
|
136716
|
+
exitCode: String(exitCode)
|
|
136717
|
+
}));
|
|
136718
|
+
return;
|
|
136719
|
+
}
|
|
136431
136720
|
const text = event.update.text;
|
|
136432
136721
|
if (text === void 0 || text.length === 0) return;
|
|
136433
136722
|
const tc = this.host.streamingUI.getToolComponent(event.toolCallId);
|
|
136434
136723
|
if (tc === void 0) return;
|
|
136435
|
-
|
|
136724
|
+
if (event.update.kind === "status") {
|
|
136725
|
+
tc.appendProgress(text);
|
|
136726
|
+
return;
|
|
136727
|
+
}
|
|
136728
|
+
if (event.update.kind === "stdout" || event.update.kind === "stderr") tc.appendLiveOutput(text);
|
|
136436
136729
|
}
|
|
136437
136730
|
handleToolResult(event) {
|
|
136438
136731
|
const { streamingUI } = this.host;
|
|
@@ -138048,6 +138341,7 @@ var StreamingUIController = class {
|
|
|
138048
138341
|
}
|
|
138049
138342
|
const { state } = this.host;
|
|
138050
138343
|
const tc = new ToolCallComponent(toolCall, void 0, state.theme.colors, state.ui, state.theme.markdownTheme, state.appState.workDir);
|
|
138344
|
+
tc.setPermissionMode(state.appState.permissionMode);
|
|
138051
138345
|
const entry = {
|
|
138052
138346
|
id: nextTranscriptId(),
|
|
138053
138347
|
kind: "tool_call",
|
|
@@ -138133,6 +138427,7 @@ var StreamingUIController = class {
|
|
|
138133
138427
|
}
|
|
138134
138428
|
if (matchedCall?.name === "AskUserQuestion") {
|
|
138135
138429
|
const completed = new ToolCallComponent(matchedCall, result, state.theme.colors, state.ui, state.theme.markdownTheme, state.appState.workDir);
|
|
138430
|
+
completed.setPermissionMode(state.appState.permissionMode);
|
|
138136
138431
|
if (state.toolOutputExpanded) completed.setExpanded(true);
|
|
138137
138432
|
if (state.planExpanded) completed.setPlanExpanded(true);
|
|
138138
138433
|
const entry = {
|
|
@@ -143318,6 +143613,10 @@ const DEFAULT_KEYBOARD_SHORTCUTS = [
|
|
|
143318
143613
|
keys: "Shift-Tab",
|
|
143319
143614
|
description: t("help.toggle_plan")
|
|
143320
143615
|
},
|
|
143616
|
+
{
|
|
143617
|
+
keys: "Ctrl-G",
|
|
143618
|
+
description: t("help.external_editor")
|
|
143619
|
+
},
|
|
143321
143620
|
{
|
|
143322
143621
|
keys: "Ctrl-O",
|
|
143323
143622
|
description: t("help.toggle_output")
|
|
@@ -145666,14 +145965,20 @@ function supportsAnsi() {
|
|
|
145666
145965
|
ansiSupported = false;
|
|
145667
145966
|
return false;
|
|
145668
145967
|
}
|
|
145669
|
-
function runLoadingAnimation(theme = "dark") {
|
|
145968
|
+
async function runLoadingAnimation(theme = "dark") {
|
|
145670
145969
|
if (!supportsAnsi()) {
|
|
145671
145970
|
const { cols } = getTerminalSize();
|
|
145672
145971
|
if (cols >= FULL_LOGO_MIN_COLS) for (const line of LOGO) stdout.write(`${fg(...LOGO_RGB)}${line}${RESET}\n`);
|
|
145673
145972
|
else for (const line of COMPACT_LOGO) stdout.write(`${fg(...BLOCK_RGB)}${line}${RESET}\n`);
|
|
145674
145973
|
stdout.write(`${BOLD}${fg(...THEME_PRIMARY[theme])}${t("loading.waking")}${RESET}\n`);
|
|
145675
|
-
return
|
|
145974
|
+
return;
|
|
145676
145975
|
}
|
|
145976
|
+
let autoStart = false;
|
|
145977
|
+
try {
|
|
145978
|
+
autoStart = (await loadTuiConfig()).autoStart;
|
|
145979
|
+
} catch {}
|
|
145980
|
+
const autoStartAtBoot = autoStart;
|
|
145981
|
+
let toggled = false;
|
|
145677
145982
|
return new Promise((resolve) => {
|
|
145678
145983
|
if (process$1.platform !== "win32") stdout.write("\x1B[?1049h");
|
|
145679
145984
|
stdout.write("\x1B[2J");
|
|
@@ -145707,7 +146012,9 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
145707
146012
|
else lines.push(centerPad(`${BOLD}${fg(...breatheColor)}${t("loading.press_enter")}${RESET}`, cols));
|
|
145708
146013
|
lines.push("");
|
|
145709
146014
|
lines.push("");
|
|
145710
|
-
|
|
146015
|
+
const rightText = toggled ? autoStart ? t("loading.auto_start_on") : t("loading.auto_start_off") : t("loading.auto_start_hint");
|
|
146016
|
+
const hint = `${t("loading.quit_hint")} ${rightText}`;
|
|
146017
|
+
lines.push(centerPad(`${fg(...DIM_RGB)}${hint}${RESET}`, cols));
|
|
145711
146018
|
while (lines.length < rows) lines.push("");
|
|
145712
146019
|
stdout.write("\x1B[H");
|
|
145713
146020
|
stdout.write(lines.join("\n"));
|
|
@@ -145728,6 +146035,20 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
145728
146035
|
interrupt();
|
|
145729
146036
|
return;
|
|
145730
146037
|
}
|
|
146038
|
+
if (key === "") {
|
|
146039
|
+
toggled = true;
|
|
146040
|
+
autoStart = !autoStart;
|
|
146041
|
+
(async () => {
|
|
146042
|
+
try {
|
|
146043
|
+
await saveTuiConfig({
|
|
146044
|
+
...await loadTuiConfig(),
|
|
146045
|
+
autoStart
|
|
146046
|
+
});
|
|
146047
|
+
} catch {}
|
|
146048
|
+
})();
|
|
146049
|
+
render();
|
|
146050
|
+
return;
|
|
146051
|
+
}
|
|
145731
146052
|
if ((key === "\r" || key === "\n") && phase === "ready") {
|
|
145732
146053
|
cleanup();
|
|
145733
146054
|
resolve();
|
|
@@ -145773,6 +146094,10 @@ function runLoadingAnimation(theme = "dark") {
|
|
|
145773
146094
|
}).then(() => {
|
|
145774
146095
|
phase = "ready";
|
|
145775
146096
|
render();
|
|
146097
|
+
if (autoStartAtBoot) setTimeout(() => {
|
|
146098
|
+
cleanup();
|
|
146099
|
+
resolve();
|
|
146100
|
+
}, 350);
|
|
145776
146101
|
});
|
|
145777
146102
|
});
|
|
145778
146103
|
}
|
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-D95_TREY.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);
|
|
@@ -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}\"。",
|
|
@@ -489,6 +492,7 @@ const dictionaries = {
|
|
|
489
492
|
"help.toggle_output": "切换工具输出展开",
|
|
490
493
|
"help.interrupt": "中途干预 — 在流式传输中插入后续提示",
|
|
491
494
|
"help.newline": "插入换行",
|
|
495
|
+
"help.external_editor": "在外部编辑器中编辑 ($VISUAL / $EDITOR)",
|
|
492
496
|
"help.cancel_stream": "中断流 / 清空输入",
|
|
493
497
|
"help.exit": "退出(空输入时)",
|
|
494
498
|
"help.close_dialog": "关闭对话框 / 中断流",
|
|
@@ -592,6 +596,7 @@ const dictionaries = {
|
|
|
592
596
|
"toolcall.current_plan": "当前计划",
|
|
593
597
|
"toolcall.approved": "已批准:{chosen}",
|
|
594
598
|
"toolcall.approved_label": "已批准",
|
|
599
|
+
"toolcall.auto_approved": "自动批准",
|
|
595
600
|
"toolcall.input_unavailable": "无法收集你的输入",
|
|
596
601
|
"toolcall.input_collected": "已收集你的答案",
|
|
597
602
|
"toolcall.waiting_input": "等待你的输入",
|
|
@@ -802,6 +807,8 @@ const dictionaries = {
|
|
|
802
807
|
"export.session_title": "# Scream 会话导出",
|
|
803
808
|
"bgtask.agent_task": "代理任务",
|
|
804
809
|
"bgtask.bash_task": "bash 任务",
|
|
810
|
+
"bash.background_completed": "后台任务 {id} 已完成:{command}",
|
|
811
|
+
"bash.background_failed": "后台任务 {id} 执行失败(退出码 {exitCode}):{command}",
|
|
805
812
|
"bgtask.started_bg": "{subject} 已在后台启动",
|
|
806
813
|
"bgtask.awaiting_approval": "{subject} 等待审批",
|
|
807
814
|
"bgtask.completed_bg": "{subject} 已在后台完成",
|
|
@@ -1251,6 +1258,9 @@ const dictionaries = {
|
|
|
1251
1258
|
"loading.waking": "Waking core...",
|
|
1252
1259
|
"loading.press_enter": "Press ENTER to wake core",
|
|
1253
1260
|
"loading.quit_hint": "Hold Ctrl+C to quit Scream Code",
|
|
1261
|
+
"loading.auto_start_hint": "Ctrl+E to toggle auto-start",
|
|
1262
|
+
"loading.auto_start_on": "Ctrl+E to toggle auto-start (ON)",
|
|
1263
|
+
"loading.auto_start_off": "Ctrl+E to toggle auto-start (OFF)",
|
|
1254
1264
|
"language.picker_title": "Language / 语言",
|
|
1255
1265
|
"language.picker_hint": "↑↓ Select · Enter confirm · Esc cancel",
|
|
1256
1266
|
"language.unchanged": "Language unchanged: \"{locale}\".",
|
|
@@ -1519,6 +1529,7 @@ const dictionaries = {
|
|
|
1519
1529
|
"help.toggle_output": "Toggle tool output expansion",
|
|
1520
1530
|
"help.interrupt": "Interrupt — insert follow-up prompt during streaming",
|
|
1521
1531
|
"help.newline": "Insert newline",
|
|
1532
|
+
"help.external_editor": "Edit in external editor ($VISUAL / $EDITOR)",
|
|
1522
1533
|
"help.cancel_stream": "Cancel stream / Clear input",
|
|
1523
1534
|
"help.exit": "Exit (when input is empty)",
|
|
1524
1535
|
"help.close_dialog": "Close dialog / Cancel stream",
|
|
@@ -1622,6 +1633,7 @@ const dictionaries = {
|
|
|
1622
1633
|
"toolcall.current_plan": "Current Plan",
|
|
1623
1634
|
"toolcall.approved": "Approved: {chosen}",
|
|
1624
1635
|
"toolcall.approved_label": "Approved",
|
|
1636
|
+
"toolcall.auto_approved": "Auto-approved",
|
|
1625
1637
|
"toolcall.input_unavailable": "Could not collect your input",
|
|
1626
1638
|
"toolcall.input_collected": "Collected your answer",
|
|
1627
1639
|
"toolcall.waiting_input": "Waiting for your input",
|
|
@@ -1832,6 +1844,8 @@ const dictionaries = {
|
|
|
1832
1844
|
"export.session_title": "# Scream Session Export",
|
|
1833
1845
|
"bgtask.agent_task": "Agent task",
|
|
1834
1846
|
"bgtask.bash_task": "Bash task",
|
|
1847
|
+
"bash.background_completed": "Background task {id} completed: {command}",
|
|
1848
|
+
"bash.background_failed": "Background task {id} failed (exit {exitCode}): {command}",
|
|
1835
1849
|
"bgtask.started_bg": "{subject} started in background",
|
|
1836
1850
|
"bgtask.awaiting_approval": "{subject} awaiting approval",
|
|
1837
1851
|
"bgtask.completed_bg": "{subject} completed in background",
|
|
@@ -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-BdUmo73M.mjs";
|
|
7
7
|
export { TextInputDialogComponent };
|