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-DRUaPOEQ.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-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: ({ signal }) => this.execution(args, signal)
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, signal) {
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
- const timeoutHandle = setTimeout(() => {
74966
- timedOut = true;
74967
- killProc();
74968
- }, timeoutMs);
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
- const [, exitCode] = await Promise.all([Promise.all([readStreamIntoBuilder(proc.stdout, builder), readStreamIntoBuilder(proc.stderr, builder)]), proc.wait()]);
74976
- if (timedOut) {
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
- return builder.error(`Command killed by timeout (${timeoutLabel})`, { brief: `Killed by timeout (${timeoutLabel})` });
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
- async function readStreamIntoBuilder(stream, builder) {
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
- builder.write(decoder.write(buf));
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.5"),
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-B1ak519Y.mjs");
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-B1ak519Y.mjs");
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()].sort((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(", "));
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(null);
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) bullet = isError ? chalk.hex(colors.error)("✗ ") : chalk.hex(colors.success)(STATUS_BULLET);
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
- await writeMcpConfig(host, rec.name, rec.command, rec.args);
131043
- await session.addMcpServer(rec.name, {
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: rec.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
- servers[name] = {
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 !== "status") return;
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
- tc.appendProgress(text);
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 Promise.resolve();
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
- lines.push(centerPad(`${fg(...DIM_RGB)}${t("loading.quit_hint")}${RESET}`, cols));
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-GFawIzQ9.mjs")).main();
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-DRUaPOEQ.mjs";
6
+ import { t as TextInputDialogComponent } from "./text-input-dialog-BdUmo73M.mjs";
7
7
  export { TextInputDialogComponent };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scream-code",
3
- "version": "0.11.5",
3
+ "version": "0.11.7",
4
4
  "description": "A terminal-native AI agent for builders",
5
5
  "license": "MIT",
6
6
  "author": "ScreamCli",