scream-code 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.mjs +222 -153
  2. package/package.json +2 -2
package/dist/main.mjs CHANGED
@@ -85268,6 +85268,11 @@ async function runToolCallBatch(step, response) {
85268
85268
  try {
85269
85269
  for (let index = 0; index < calls.length; index += 1) {
85270
85270
  const call = calls[index];
85271
+ if (step.signal.aborted) {
85272
+ await dispatchToolCall(step, call, call.args);
85273
+ pendingResults.push(Promise.resolve(makeErrorToolResult(call, call.args, abortedToolOutput(call.toolName, step.signal))));
85274
+ continue;
85275
+ }
85271
85276
  const prepared = await prepareToolCall(step, call);
85272
85277
  pendingResults.push(scheduler.add(prepared.task));
85273
85278
  if (prepared.stopBatchAfterThis === true) {
@@ -113594,10 +113599,27 @@ async function locateWindowsGitBash(deps) {
113594
113599
  checked.push(inferred);
113595
113600
  if (await deps.isFile(inferred)) return inferred;
113596
113601
  }
113602
+ const fellback = inferBashByWalkingUp(gitExe);
113603
+ if (fellback !== void 0) {
113604
+ checked.push(fellback);
113605
+ if (await deps.isFile(fellback)) return fellback;
113606
+ }
113597
113607
  }
113598
- const candidates = ["C:\\Program Files\\Git\\bin\\bash.exe", "C:\\Program Files (x86)\\Git\\bin\\bash.exe"];
113608
+ const bashExe = await deps.findExecutable("bash.exe");
113609
+ if (bashExe !== void 0) {
113610
+ checked.push(bashExe);
113611
+ return bashExe;
113612
+ }
113613
+ const candidates = [
113614
+ "C:\\Program Files\\Git\\bin\\bash.exe",
113615
+ "C:\\Program Files (x86)\\Git\\bin\\bash.exe",
113616
+ "C:\\msys64\\usr\\bin\\bash.exe",
113617
+ "C:\\cygwin64\\bin\\bash.exe"
113618
+ ];
113599
113619
  const localAppData = deps.env["LOCALAPPDATA"]?.trim();
113600
113620
  if (localAppData !== void 0 && localAppData.length > 0) candidates.push(`${localAppData}\\Programs\\Git\\bin\\bash.exe`);
113621
+ const userProfile = deps.env["USERPROFILE"]?.trim();
113622
+ if (userProfile !== void 0 && userProfile.length > 0) candidates.push(`${userProfile}\\scoop\\apps\\git\\current\\bin\\bash.exe`);
113601
113623
  for (const candidate of candidates) {
113602
113624
  checked.push(candidate);
113603
113625
  if (await deps.isFile(candidate)) return candidate;
@@ -113615,6 +113637,16 @@ function inferGitBashFromGitExe(gitExe) {
113615
113637
  }
113616
113638
  }
113617
113639
  }
113640
+ function inferBashByWalkingUp(gitExe) {
113641
+ const sep = gitExe.includes("\\") ? "\\" : "/";
113642
+ const parts = gitExe.split(sep);
113643
+ for (let i = parts.length - 1; i >= 1 && parts.length - i <= 6; i -= 1) {
113644
+ const root = parts.slice(0, i).join(sep) || sep;
113645
+ const candidate = `${root}${sep}bin${sep}bash.exe`;
113646
+ const gitDir = parts.slice(0, -1).join(sep);
113647
+ if (`${root}${sep}bin` !== gitDir) return candidate;
113648
+ }
113649
+ }
113618
113650
  /**
113619
113651
  * Production convenience — derive the deps bag from Node's ambient surface.
113620
113652
  *
@@ -114245,6 +114277,10 @@ var ScreamCore = class {
114245
114277
  });
114246
114278
  this.sdk = rpcClient(this);
114247
114279
  }
114280
+ /** Resolve the shell environment so missing Git Bash is surfaced early. */
114281
+ async preflight() {
114282
+ await this.jian;
114283
+ }
114248
114284
  async createSession(input) {
114249
114285
  const options = input;
114250
114286
  const workDir = requiredWorkDir("createSession", options.workDir);
@@ -114949,6 +114985,9 @@ var SDKRpcClient = class {
114949
114985
  get configPath() {
114950
114986
  return this.core.configPath;
114951
114987
  }
114988
+ async preflight() {
114989
+ await this.core.preflight();
114990
+ }
114952
114991
  async createSession(input) {
114953
114992
  const rpc = await this.getRpc();
114954
114993
  const { planMode, ...coreInput } = input;
@@ -115887,6 +115926,10 @@ var ScreamHarness = class {
115887
115926
  async getExperimentalFlags() {
115888
115927
  return this.rpc.getExperimentalFlags();
115889
115928
  }
115929
+ /** Validate host environment before starting the UI. */
115930
+ async preflight() {
115931
+ await this.rpc.preflight();
115932
+ }
115890
115933
  async ensureConfigFile() {
115891
115934
  await ensureConfigFile(this.configPath);
115892
115935
  }
@@ -131527,6 +131570,15 @@ function createTUIState(options) {
131527
131570
  const theme = createScreamTUIThemeBundle(initialAppState.theme, options.resolvedTheme);
131528
131571
  const terminal = new ProcessTerminal();
131529
131572
  const ui = new TUI(terminal);
131573
+ const uiAny = ui;
131574
+ const originalDoRender = uiAny["doRender"].bind(ui);
131575
+ uiAny["doRender"] = () => {
131576
+ try {
131577
+ originalDoRender();
131578
+ } catch (error) {
131579
+ console.error("[scream-code] render error:", error);
131580
+ }
131581
+ };
131530
131582
  const transcriptContainer = new GutterContainer(1, 1);
131531
131583
  const activityContainer = new GutterContainer(1, 1);
131532
131584
  const todoPanelContainer = new GutterContainer(1, 1);
@@ -135376,112 +135428,114 @@ var ScreamTUI = class {
135376
135428
  };
135377
135429
  //#endregion
135378
135430
  //#region src/tui/components/chrome/loading.ts
135379
- const { stdout } = process$1;
135380
- const BRIGHT = "\x1B[38;2;255;255;255m";
135381
- const RESET = "\x1B[0m";
135382
- const THEME_GREEN = {
135383
- dark: "\x1B[38;2;78;200;126m",
135384
- light: "\x1B[38;2;14;122;56m"
135431
+ const { stdout, stdin } = process$1;
135432
+ const LOGO = [
135433
+ "███████╗ ██████╗██████╗ ███████╗ █████╗ ███╗ ███╗ ██████╗ ██████╗ ██████╗ ███████╗",
135434
+ "██╔════╝██╔════╝██╔══██╗██╔════╝██╔══██╗████╗ ████║ ██╔════╝██╔═══██╗██╔══██╗██╔════╝",
135435
+ "███████╗██║ ██████╔╝█████╗ ███████║██╔████╔██║ ██║ ██║ ██║██║ ██║█████╗ ",
135436
+ "╚════██║██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║ ██║ ██║ ██║██║ ██║██╔══╝ ",
135437
+ "███████║╚██████╗██║ ██║███████╗██║ ██║██║ ╚═╝ ██║ ╚██████╗╚██████╔╝██████╔╝███████╗",
135438
+ "╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝"
135439
+ ];
135440
+ const SHADOW_CHARS = new Set([
135441
+ "╚",
135442
+ "═",
135443
+ "╝",
135444
+ "║",
135445
+ "╔",
135446
+ "╗",
135447
+ "╠",
135448
+ "╣",
135449
+ "╦",
135450
+ "╩",
135451
+ "╬"
135452
+ ]);
135453
+ const SHEEN_STEP = 2;
135454
+ const SHEEN_INTERVAL_MS = 150;
135455
+ const THEME_ACCENT = {
135456
+ dark: [
135457
+ 78,
135458
+ 200,
135459
+ 126
135460
+ ],
135461
+ light: [
135462
+ 14,
135463
+ 122,
135464
+ 56
135465
+ ]
135385
135466
  };
135386
- const FRAMES = [
135387
- {
135388
- duration: 80,
135389
- content: [
135390
- "┌┐",
135391
- "││",
135392
- "││",
135393
- "└┘"
135394
- ]
135395
- },
135396
- {
135397
- duration: 80,
135398
- content: [
135399
- "┌──────┐",
135400
- "│ │",
135401
- "│ │",
135402
- "└──────┘"
135403
- ]
135404
- },
135405
- {
135406
- duration: 80,
135407
- content: [
135408
- "┌──────────────────┐",
135409
- "│ │",
135410
- "│ │",
135411
- "└──────────────────┘"
135412
- ]
135413
- },
135414
- {
135415
- duration: 80,
135416
- content: [
135417
- "┌──────────────────────────────┐",
135418
- "│ │",
135419
- "│ welcome to scream code │",
135420
- "│ │",
135421
- "└──────────────────────────────┘"
135422
- ]
135423
- },
135424
- {
135425
- duration: 100,
135426
- content: [
135427
- "┌─────────────────────────────────────────────────────────────────┐",
135428
- "│ │",
135429
- "│ welcome to scream code │",
135430
- "│ │",
135431
- "│ ███████╗ ██████╗██████╗ ███████╗ █████╗ ███╗ ███╗ │",
135432
- "│ ██╔════╝ ██╔════╝██╔══██╗██╔════╝██╔══██╗████╗ ████║ │",
135433
- "│ ███████╗ ██║ ██████╔╝█████╗ ███████║██╔████╔██║ │",
135434
- "│ ╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║ │",
135435
- "│ ███████║ ╚██████╗██║ ██║███████╗██║ ██║██║ ╚═╝ ██║ │",
135436
- "│ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ │",
135437
- "│ │",
135438
- "└─────────────────────────────────────────────────────────────────┘"
135439
- ]
135440
- },
135441
- {
135442
- duration: 120,
135443
- content: [
135444
- "┌─────────────────────────────────────────────────────────────────┐",
135445
- "│ │",
135446
- "│ welcome to scream code │",
135447
- "│ │",
135448
- "│ ███████╗ ██████╗██████╗ ███████╗ █████╗ ███╗ ███╗ │",
135449
- "│ ██╔════╝ ██╔════╝██╔══██╗██╔════╝██╔══██╗████╗ ████║ │",
135450
- "│ ███████╗ ██║ ██████╔╝█████╗ ███████║██╔████╔██║ │",
135451
- "│ ╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║ │",
135452
- "│ ███████║ ╚██████╗██║ ██║███████╗██║ ██║██║ ╚═╝ ██║ │",
135453
- "│ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ │",
135454
- "│ │",
135455
- "│ 你的中文智能Ai助手 │",
135456
- "└─────────────────────────────────────────────────────────────────┘"
135457
- ]
135458
- },
135459
- {
135460
- duration: 9999,
135461
- content: [
135462
- "┌─────────────────────────────────────────────────────────────────┐",
135463
- "│ │",
135464
- "│ welcome to scream code │",
135465
- "│ │",
135466
- "│ ███████╗ ██████╗██████╗ ███████╗ █████╗ ███╗ ███╗ │",
135467
- "│ ██╔════╝ ██╔════╝██╔══██╗██╔════╝██╔══██╗████╗ ████║ │",
135468
- "│ ███████╗ ██║ ██████╔╝█████╗ ███████║██╔████╔██║ │",
135469
- "│ ╚════██║ ██║ ██╔══██╗██╔══╝ ██╔══██║██║╚██╔╝██║ │",
135470
- "│ ███████║ ╚██████╗██║ ██║███████╗██║ ██║██║ ╚═╝ ██║ │",
135471
- "│ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ │",
135472
- "│ │",
135473
- "│ 你的中文智能Ai助手 │",
135474
- "└─────────────────────────────────────────────────────────────────┘"
135475
- ]
135476
- }
135467
+ const BLOCK_RGB = [
135468
+ 255,
135469
+ 255,
135470
+ 255
135471
+ ];
135472
+ const LOGO_RGB = [
135473
+ 136,
135474
+ 136,
135475
+ 136
135477
135476
  ];
135478
- function color(line, green) {
135479
- const s = line.replace(/[│ ]/g, "");
135480
- const tb = (line.startsWith("┌") || line.startsWith("└")) && (line.endsWith("┐") || line.endsWith("┘")) && s.replace(/[─┌┐└┘]/g, "") === "";
135481
- const es = line.startsWith("│") && line.endsWith("│") && s === "";
135482
- if (tb || es) return green;
135483
- if (line.includes("welcome") || line.includes("scream") || line.includes("你的中文")) return green;
135484
- return BRIGHT;
135477
+ const DIM_RGB = [
135478
+ 85,
135479
+ 85,
135480
+ 85
135481
+ ];
135482
+ function fg(r, g, b) {
135483
+ return `\x1b[38;2;${r};${g};${b}m`;
135484
+ }
135485
+ const RESET = "\x1B[0m";
135486
+ const BOLD = "\x1B[1m";
135487
+ const DIM = "\x1B[2m";
135488
+ function renderSheen(char, charIndex, sheenPos, isReversing, accent) {
135489
+ if (char === " ") return " ";
135490
+ if (char === "█") return `${fg(...BLOCK_RGB)}█${RESET}`;
135491
+ if (!SHADOW_CHARS.has(char)) return `${fg(...LOGO_RGB)}${char}${RESET}`;
135492
+ let color;
135493
+ if (isReversing) color = charIndex <= sheenPos ? LOGO_RGB : accent;
135494
+ else color = charIndex <= sheenPos ? accent : LOGO_RGB;
135495
+ return `${fg(...color)}${char}${RESET}`;
135496
+ }
135497
+ const LOADING_TEXT = "Ai正在加载中...";
135498
+ function buildShimmerPalette(n, accent) {
135499
+ const size = Math.max(8, Math.min(20, Math.ceil(n * 1.5)));
135500
+ const palette = [];
135501
+ for (let i = 0; i < size; i++) {
135502
+ const t = i / (size - 1);
135503
+ palette.push([
135504
+ Math.round(accent[0] - t * accent[0] * .35),
135505
+ Math.round(accent[1] - t * accent[1] * .6),
135506
+ Math.round(accent[2] - t * accent[2] * .33)
135507
+ ]);
135508
+ }
135509
+ return palette;
135510
+ }
135511
+ function renderShimmer(pulse, accent) {
135512
+ const chars = LOADING_TEXT.split("");
135513
+ const n = chars.length;
135514
+ const palette = buildShimmerPalette(n, accent);
135515
+ let out = "";
135516
+ for (let i = 0; i < n; i++) {
135517
+ const phase = (pulse - i + n) % n;
135518
+ const color = palette[phase];
135519
+ const ratio = n <= 1 ? 0 : phase / (n - 1);
135520
+ out += `${ratio < .23 ? BOLD : ratio < .69 ? "" : DIM}${fg(...color)}${chars[i]}${RESET}`;
135521
+ }
135522
+ return out;
135523
+ }
135524
+ function getTerminalSize() {
135525
+ return {
135526
+ cols: stdout.columns || 80,
135527
+ rows: stdout.rows || 24
135528
+ };
135529
+ }
135530
+ function visualWidth(s) {
135531
+ let w = 0;
135532
+ for (const ch of s.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "")) w += /[一-鿿 -〿＀-￯]/.test(ch) ? 2 : 1;
135533
+ return w;
135534
+ }
135535
+ function centerPad(text, width) {
135536
+ const plainW = visualWidth(text);
135537
+ const pad = Math.max(0, Math.floor((width - plainW) / 2));
135538
+ return " ".repeat(pad) + text;
135485
135539
  }
135486
135540
  let ansiSupported = null;
135487
135541
  function supportsAnsi() {
@@ -135523,63 +135577,77 @@ function supportsAnsi() {
135523
135577
  ansiSupported = false;
135524
135578
  return false;
135525
135579
  }
135526
- function plainFrame(frameIndex, green) {
135527
- const f = FRAMES[Math.min(frameIndex, FRAMES.length - 1)];
135528
- let out = "";
135529
- for (const l of f.content) out += color(l, green) + (l || " ") + "\x1B[0m\n";
135530
- return out;
135531
- }
135532
- const LOADING_STAGES = [
135533
- "正在整理记忆区域....",
135534
- "正在加载用户喜好....",
135535
- "正在确认模型配置....",
135536
- "正在加载scream code...."
135537
- ];
135538
- const STAGE_DELAYS_MS = [
135539
- 450,
135540
- 350,
135541
- 650,
135542
- 350
135543
- ];
135544
135580
  function runLoadingAnimation(theme = "dark") {
135545
- const green = THEME_GREEN[theme];
135546
135581
  if (!supportsAnsi()) {
135547
- stdout.write(plainFrame(FRAMES.length - 1, green));
135548
- for (const stage of LOADING_STAGES) stdout.write(green + stage + "\x1B[0m\n");
135582
+ for (const line of LOGO) stdout.write(`${fg(...LOGO_RGB)}${line}${RESET}\n`);
135549
135583
  return Promise.resolve();
135550
135584
  }
135551
135585
  return new Promise((resolve) => {
135552
- const last = FRAMES.length - 1;
135553
- let frame = 0;
135554
- function draw(i) {
135555
- stdout.write("\x1B[H" + plainFrame(i, green));
135556
- }
135557
- function showStages(stages, index) {
135558
- if (index >= stages.length) {
135559
- setTimeout(() => {
135560
- stdout.write("\x1B[2J\x1B[H\x1B[?25h");
135561
- resolve();
135562
- }, 400);
135563
- return;
135564
- }
135565
- stdout.write("\n" + green + stages[index] + RESET);
135566
- const delay = STAGE_DELAYS_MS[index] ?? 350;
135567
- setTimeout(() => showStages(stages, index + 1), delay);
135586
+ stdout.write("\x1B[?1049h");
135587
+ stdout.write("\x1B[2J");
135588
+ stdout.write("\x1B[?25l");
135589
+ const accent = THEME_ACCENT[theme];
135590
+ let sheenPos = 0;
135591
+ let isReversing = false;
135592
+ let shimmerPulse = 0;
135593
+ let phase = "loading";
135594
+ function render() {
135595
+ const { cols, rows } = getTerminalSize();
135596
+ const lines = [];
135597
+ const contentHeight = LOGO.length + 4;
135598
+ const topPad = Math.max(0, Math.floor((rows - contentHeight) / 2));
135599
+ for (let i = 0; i < topPad; i++) lines.push("");
135600
+ for (const line of LOGO) {
135601
+ let colored = "";
135602
+ for (let ci = 0; ci < line.length; ci++) colored += renderSheen(line[ci], ci, sheenPos, isReversing, accent);
135603
+ lines.push(centerPad(colored, cols));
135604
+ }
135605
+ if (phase === "loading") lines.push(centerPad(renderShimmer(shimmerPulse, accent), cols));
135606
+ else lines.push(centerPad(`${BOLD}${fg(...accent)}点击按下 ENTER 唤醒核心${RESET}`, cols));
135607
+ lines.push("");
135608
+ lines.push("");
135609
+ lines.push(centerPad(`${fg(...DIM_RGB)}按住 Ctrl+C 即可退出 Scream Code${RESET}`, cols));
135610
+ while (lines.length < rows) lines.push("");
135611
+ stdout.write("\x1B[H");
135612
+ stdout.write(lines.join("\n"));
135568
135613
  }
135569
135614
  function tick() {
135570
- if (frame >= last) {
135571
- setTimeout(() => {
135572
- showStages(LOADING_STAGES, 0);
135573
- }, 600);
135574
- return;
135615
+ sheenPos += SHEEN_STEP;
135616
+ if (sheenPos >= 90) {
135617
+ isReversing = !isReversing;
135618
+ sheenPos = 0;
135575
135619
  }
135576
- draw(frame);
135577
- frame++;
135578
- setTimeout(tick, FRAMES[frame - 1].duration);
135620
+ shimmerPulse = (shimmerPulse + 1) % 10;
135621
+ render();
135579
135622
  }
135580
- stdout.write("\x1B[?25l\x1B[2J\x1B[H");
135581
- draw(0);
135582
- setTimeout(tick, FRAMES[0].duration);
135623
+ function cleanup() {
135624
+ clearInterval(timer);
135625
+ stdin.removeAllListeners("data");
135626
+ stdin.setRawMode(false);
135627
+ stdout.write("\x1B[?25h");
135628
+ stdout.write("\x1B[?1049l");
135629
+ }
135630
+ function interrupt() {
135631
+ cleanup();
135632
+ process$1.exit(0);
135633
+ }
135634
+ process$1.on("SIGINT", interrupt);
135635
+ process$1.on("SIGTERM", interrupt);
135636
+ stdin.setRawMode(true);
135637
+ stdin.on("data", (data) => {
135638
+ const key = data.toString();
135639
+ if (key === "") interrupt();
135640
+ if ((key === "\r" || key === "\n") && phase === "ready") {
135641
+ cleanup();
135642
+ resolve();
135643
+ }
135644
+ });
135645
+ render();
135646
+ const timer = setInterval(tick, SHEEN_INTERVAL_MS);
135647
+ setTimeout(() => {
135648
+ phase = "ready";
135649
+ render();
135650
+ }, 400);
135583
135651
  });
135584
135652
  }
135585
135653
  //#endregion
@@ -135619,6 +135687,7 @@ async function runShell(opts, version) {
135619
135687
  await harness.ensureConfigFile();
135620
135688
  const config = await harness.getConfig();
135621
135689
  const configMs = Date.now() - configStartedAt;
135690
+ await harness.preflight();
135622
135691
  await runLoadingAnimation(resolvedTheme);
135623
135692
  const tui = new ScreamTUI(harness, {
135624
135693
  cliOptions: opts,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scream-code",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "The Starting Point for Next-Gen Agents",
5
5
  "license": "MIT",
6
6
  "author": "ScreamCli",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "publishConfig": {
42
42
  "access": "public",
43
- "provenance": true
43
+ "provenance": false
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsdown",