scream-code 0.12.5 → 0.12.6

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-BQeV1dTM.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-BI6Q02oM.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";
@@ -54,7 +54,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
54
54
  import { Command, Option } from "commander";
55
55
  import { createInterface } from "node:readline/promises";
56
56
  import chalk, { chalkStderr } from "chalk";
57
- import { CombinedAutocompleteProvider, Container, Editor, FlexSpacer, Image, Input, Key, Markdown, ProcessTerminal, Spacer, TUI, Text, decodeKittyPrintable, deleteAllKittyImages, fuzzyFilter, fuzzyMatch, getCapabilities, getImageDimensions, isKeyRelease, matchesKey, setTightMode, sliceByColumn, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@liutod-scream/pi-tui";
57
+ import { CombinedAutocompleteProvider, Container, Editor, HStack, Image, Input, Key, Markdown, ProcessTerminal, ScrollView, Spacer, Text, TuiAltScreen, VStack, decodeKittyPrintable, deleteAllKittyImages, fuzzyFilter, fuzzyMatch, getCapabilities, getImageDimensions, isKeyRelease, matchesKey, sliceByColumn, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@liutod-scream/pi-tui";
58
58
  import { highlight, supportsLanguage } from "cli-highlight";
59
59
  import { diffWords } from "diff";
60
60
  import { gt, valid } from "semver";
@@ -121634,7 +121634,7 @@ function optionalBuildString(value) {
121634
121634
  return typeof value === "string" && value.length > 0 ? value : void 0;
121635
121635
  }
121636
121636
  const SCREAM_BUILD_INFO = {
121637
- version: optionalBuildString("0.12.5"),
121637
+ version: optionalBuildString("0.12.6"),
121638
121638
  channel: optionalBuildString(""),
121639
121639
  commit: optionalBuildString(""),
121640
121640
  buildTarget: optionalBuildString("darwin-arm64")
@@ -123993,7 +123993,7 @@ async function handleConnectCommand(host, args) {
123993
123993
  ok: false,
123994
123994
  label: "Failed to load catalog."
123995
123995
  });
123996
- host.showError(`Failed to fetch catalog: ${formatErrorMessage(error)}`);
123996
+ host.showError(t("auth.catalog_fetch_failed", { error: formatErrorMessage(error) }));
123997
123997
  }
123998
123998
  }
123999
123999
  }
@@ -127448,7 +127448,7 @@ async function guidedGoalSetup(host) {
127448
127448
  host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
127449
127449
  return;
127450
127450
  }
127451
- const { TextInputDialogComponent } = await import("./text-input-dialog-CEUCIznb.mjs");
127451
+ const { TextInputDialogComponent } = await import("./text-input-dialog-BViNsv5f.mjs");
127452
127452
  const initialDesc = await promptText(host, TextInputDialogComponent, {
127453
127453
  title: t("goal.setup_title_initial"),
127454
127454
  subtitle: t("goal.setup_desc_hint"),
@@ -127469,7 +127469,7 @@ async function guidedGoalSetup(host) {
127469
127469
  await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
127470
127470
  }
127471
127471
  async function showGoalConfigWizard(host, session, objective, replace) {
127472
- const { TextInputDialogComponent } = await import("./text-input-dialog-CEUCIznb.mjs");
127472
+ const { TextInputDialogComponent } = await import("./text-input-dialog-BViNsv5f.mjs");
127473
127473
  const turnInput = await promptNumber(host, TextInputDialogComponent, {
127474
127474
  title: t("goal.wizard_title", { objective }),
127475
127475
  subtitle: t("goal.budget_turns_hint"),
@@ -128281,7 +128281,7 @@ var AssistantMessageComponent = class {
128281
128281
  const age = Date.now() - (this.fadeStartMs ?? 0);
128282
128282
  this.cachedWidth = void 0;
128283
128283
  this.cachedLines = void 0;
128284
- this.ui?.requestComponentRender(this);
128284
+ this.ui?.requestRender();
128285
128285
  if (age >= 1200) this.stopFade();
128286
128286
  }, FADE_TICK_MS);
128287
128287
  this.ui.requestRender();
@@ -128775,7 +128775,7 @@ var ThinkingComponent = class {
128775
128775
  if (this.ui === void 0 || this.spinnerInterval !== void 0) return;
128776
128776
  this.spinnerInterval = setInterval(() => {
128777
128777
  this.spinnerFrame = (this.spinnerFrame + 1) % BRAILLE_SPINNER_FRAMES.length;
128778
- this.ui?.requestComponentRender(this);
128778
+ this.ui?.requestRender();
128779
128779
  }, 80);
128780
128780
  }
128781
128781
  stopSpinner() {
@@ -133217,7 +133217,7 @@ var MoonLoader = class extends Text {
133217
133217
  const frame = BRAILLE_SPINNER_FRAMES[this.currentFrame];
133218
133218
  const coloredFrame = this.colorFn ? this.colorFn(frame) : frame;
133219
133219
  this.setText(this.label ? `${coloredFrame} ${this.label}` : coloredFrame);
133220
- this.ui.requestComponentRender(this);
133220
+ this.ui.requestRender();
133221
133221
  }
133222
133222
  };
133223
133223
  //#endregion
@@ -133353,9 +133353,6 @@ function getFallbackSkillMarketplace() {
133353
133353
  }
133354
133354
  //#endregion
133355
133355
  //#region src/tui/utils/component-capabilities.ts
133356
- function isExpandable(obj) {
133357
- return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
133358
- }
133359
133356
  function isPlanExpandable(obj) {
133360
133357
  return typeof obj === "object" && obj !== null && "setPlanExpanded" in obj && typeof obj.setPlanExpanded === "function";
133361
133358
  }
@@ -136235,6 +136232,17 @@ var AuthFlowController = class {
136235
136232
  availableModels: config.models ?? {},
136236
136233
  availableProviders: config.providers ?? {}
136237
136234
  });
136235
+ this.prefetchCatalogCache();
136236
+ }
136237
+ /**
136238
+ * Best-effort background catalog refresh. Fetches the remote catalog and,
136239
+ * on success, updates the on-disk cache. On failure it stays silent: the
136240
+ * existing cache (or built-in) keeps working. Never throws.
136241
+ */
136242
+ async prefetchCatalogCache() {
136243
+ try {
136244
+ saveCatalogCache(await fetchCatalog(DEFAULT_CATALOG_URL), resolveScreamHome());
136245
+ } catch {}
136238
136246
  }
136239
136247
  async activateModelAfterLogin(model, thinkingLevel) {
136240
136248
  const { host } = this;
@@ -140590,9 +140598,8 @@ var TasksBrowserController = class {
140590
140598
  colors: state.theme.colors,
140591
140599
  ...this.buildCallbacks()
140592
140600
  }, state.terminal);
140593
- const savedChildren = [...state.ui.children];
140594
- state.ui.clear();
140595
- state.ui.addChild(component);
140601
+ const savedLayoutRoot = state.layoutRoot;
140602
+ state.ui.setLayoutRoot(component);
140596
140603
  state.ui.setFocus(component);
140597
140604
  state.ui.requestRender(true);
140598
140605
  const pollTimer = setInterval(() => {
@@ -140600,7 +140607,7 @@ var TasksBrowserController = class {
140600
140607
  }, 1e3);
140601
140608
  this.host.setTasksBrowser({
140602
140609
  component,
140603
- savedChildren,
140610
+ savedLayoutRoot,
140604
140611
  filter,
140605
140612
  selectedTaskId,
140606
140613
  tailOutput: void 0,
@@ -140620,8 +140627,7 @@ var TasksBrowserController = class {
140620
140627
  if (browser.viewer !== void 0) this.closeOutputViewer();
140621
140628
  if (browser.pollTimer !== void 0) clearInterval(browser.pollTimer);
140622
140629
  if (browser.flashTimer !== void 0) clearTimeout(browser.flashTimer);
140623
- state.ui.clear();
140624
- for (const child of browser.savedChildren) state.ui.addChild(child);
140630
+ state.ui.setLayoutRoot(browser.savedLayoutRoot);
140625
140631
  this.host.setTasksBrowser(void 0);
140626
140632
  state.ui.setFocus(state.editor);
140627
140633
  state.ui.requestRender(true);
@@ -140791,9 +140797,8 @@ var TasksBrowserController = class {
140791
140797
  this.closeOutputViewer();
140792
140798
  }
140793
140799
  }, state.terminal);
140794
- const savedBrowserChildren = [...state.ui.children];
140795
- state.ui.clear();
140796
- state.ui.addChild(viewer);
140800
+ const savedBrowserLayout = state.layoutRoot;
140801
+ state.ui.setLayoutRoot(viewer);
140797
140802
  state.ui.setFocus(viewer);
140798
140803
  state.ui.requestRender(true);
140799
140804
  const pollTimer = setInterval(() => {
@@ -140801,7 +140806,7 @@ var TasksBrowserController = class {
140801
140806
  }, 1e3);
140802
140807
  browser.viewer = {
140803
140808
  component: viewer,
140804
- savedChildren: savedBrowserChildren,
140809
+ savedLayoutRoot: savedBrowserLayout,
140805
140810
  taskId,
140806
140811
  output,
140807
140812
  refreshId: 0,
@@ -140857,8 +140862,7 @@ var TasksBrowserController = class {
140857
140862
  const viewer = browser.viewer;
140858
140863
  clearInterval(viewer.pollTimer);
140859
140864
  browser.viewer = void 0;
140860
- this.host.state.ui.clear();
140861
- for (const child of viewer.savedChildren) this.host.state.ui.addChild(child);
140865
+ this.host.state.ui.setLayoutRoot(viewer.savedLayoutRoot);
140862
140866
  this.host.state.ui.setFocus(browser.component);
140863
140867
  this.host.state.ui.requestRender(true);
140864
140868
  }
@@ -141294,13 +141298,6 @@ var TranscriptController = class TranscriptController {
141294
141298
  toggleToolOutputExpansion() {
141295
141299
  const { state } = this.host;
141296
141300
  state.toolOutputExpanded = !state.toolOutputExpanded;
141297
- const walk = (children) => {
141298
- for (const child of children) {
141299
- if (isExpandable(child)) child.setExpanded(state.toolOutputExpanded);
141300
- if ("children" in child && Array.isArray(child.children)) walk(child.children);
141301
- }
141302
- };
141303
- walk(state.transcriptContainer.children);
141304
141301
  state.ui.requestRender();
141305
141302
  }
141306
141303
  togglePlanExpansion() {
@@ -141349,6 +141346,44 @@ var GutterContainer = class extends Container {
141349
141346
  }
141350
141347
  };
141351
141348
  //#endregion
141349
+ //#region src/tui/components/panes/status-bar-pane.ts
141350
+ /**
141351
+ * A fixed one-line status bar shown directly above the input editor: it
141352
+ * displays the current work phase (idle / waiting / thinking / composing /
141353
+ * tool) with its spinner, pinned to the bottom of the terminal via the dock
141354
+ * VStack. Designed to hold more status widgets later — add children to the
141355
+ * container when needed.
141356
+ */
141357
+ var StatusBarPaneComponent = class extends Container {
141358
+ constructor(options) {
141359
+ super();
141360
+ this.update(options);
141361
+ }
141362
+ /** Re-renders the bar for a new mode/label. The spinner/pulse are the
141363
+ * caller's shared instances (kept alive across mode changes), so this only
141364
+ * swaps which children are visible. */
141365
+ update(options) {
141366
+ this.clear();
141367
+ if (options.mode === "idle") return;
141368
+ if (options.mode === "waiting" || options.mode === "tool" || options.mode === "composing" || options.mode === "thinking") {
141369
+ if (options.pulseWave !== void 0) {
141370
+ if (options.label.length > 0) {
141371
+ const row = new HStack();
141372
+ row.addChild(options.pulseWave);
141373
+ row.addChild(new Text(` ${options.label}`, 1, 0));
141374
+ this.addChild(row);
141375
+ } else this.addChild(options.pulseWave);
141376
+ return;
141377
+ }
141378
+ if (options.spinner !== void 0) {
141379
+ this.addChild(options.spinner);
141380
+ return;
141381
+ }
141382
+ if (options.label.length > 0) this.addChild(new Text(options.label, 1, 0));
141383
+ }
141384
+ }
141385
+ };
141386
+ //#endregion
141352
141387
  //#region src/tui/theme/bundle.ts
141353
141388
  function createScreamTUIThemeBundle(theme, resolvedTheme) {
141354
141389
  const actualTheme = resolvedTheme ?? resolveThemeSync(theme);
@@ -141640,36 +141675,11 @@ var PulseWaveLoader = class extends Text {
141640
141675
  }
141641
141676
  };
141642
141677
  //#endregion
141643
- //#region src/tui/components/panes/activity-pane.ts
141644
- var ActivityPaneComponent = class extends Container {
141645
- constructor(options) {
141646
- super();
141647
- if (options.mode === "waiting" || options.mode === "tool") {
141648
- if (options.spinner !== void 0) {
141649
- this.addChild(new Spacer(1));
141650
- this.addChild(options.spinner);
141651
- }
141652
- if (options.pulseWave !== void 0) {
141653
- this.addChild(new Spacer(1));
141654
- this.addChild(options.pulseWave);
141655
- }
141656
- return;
141657
- }
141658
- if (options.mode === "composing" && options.spinner !== void 0) {
141659
- this.addChild(new Spacer(1));
141660
- this.addChild(options.spinner);
141661
- if (options.pulseWave !== void 0) {
141662
- this.addChild(new Spacer(1));
141663
- this.addChild(options.pulseWave);
141664
- }
141665
- }
141666
- }
141667
- };
141668
- //#endregion
141669
141678
  //#region src/tui/controllers/lifecycle-controller.ts
141670
141679
  var LifecycleController = class LifecycleController {
141671
141680
  host;
141672
141681
  signalCleanupHandlers = [];
141682
+ footerWrap;
141673
141683
  ccConnectPollTimer;
141674
141684
  memoryIdleTimer;
141675
141685
  memoryCountdownTimer;
@@ -141677,6 +141687,9 @@ var LifecycleController = class LifecycleController {
141677
141687
  terminalFocusTrackingDispose;
141678
141688
  terminalThemeTrackingDispose;
141679
141689
  lastActivityMode;
141690
+ /** The active status-bar loader (PulseWaveLoader or MoonLoader). Owned by
141691
+ * this controller; stopped before replacement to avoid leaking timers. */
141692
+ statusBarLoader;
141680
141693
  static MEMORY_IDLE_MS = 900 * 1e3;
141681
141694
  static MEMORY_COUNTDOWN_MS = 15 * 1e3;
141682
141695
  static MEMORY_EXTRACT_COOLDOWN_MS = 600 * 1e3;
@@ -141816,19 +141829,72 @@ var LifecycleController = class LifecycleController {
141816
141829
  buildLayout() {
141817
141830
  const { ui } = this.host.state;
141818
141831
  ui.clear();
141819
- ui.addChild(this.host.state.transcriptContainer);
141820
- ui.addChild(this.host.state.activityContainer);
141821
- ui.addChild(this.host.state.todoPanelContainer);
141822
- ui.addChild(this.host.state.queueContainer);
141823
- ui.addChild(this.host.state.errorBannerContainer);
141824
- ui.addChild(this.host.state.planModeBannerContainer);
141825
- ui.addChild(new FlexSpacer());
141826
- ui.addChild(this.host.state.editorContainer);
141832
+ const scrollContent = new Container();
141833
+ scrollContent.addChild(this.host.state.transcriptContainer);
141834
+ scrollContent.addChild(this.host.state.activityContainer);
141835
+ scrollContent.addChild(this.host.state.queueContainer);
141836
+ const transcriptScrollView = new ScrollView(scrollContent, {
141837
+ follow: "end",
141838
+ primary: true,
141839
+ scrollbar: "auto"
141840
+ });
141841
+ const dock = new VStack([
141842
+ {
141843
+ component: this.host.state.todoPanelContainer,
141844
+ shrink: 1,
141845
+ minSize: 0,
141846
+ visible: (viewport) => viewport.width >= 90
141847
+ },
141848
+ {
141849
+ component: this.host.state.errorBannerContainer,
141850
+ shrink: 1,
141851
+ minSize: 0
141852
+ },
141853
+ {
141854
+ component: this.host.state.planModeBannerContainer,
141855
+ shrink: 1,
141856
+ minSize: 0
141857
+ },
141858
+ {
141859
+ component: this.host.state.statusBarContainer,
141860
+ shrink: 1,
141861
+ minSize: 1,
141862
+ visible: (viewport) => viewport.width >= 60
141863
+ },
141864
+ {
141865
+ component: this.host.state.editorContainer,
141866
+ shrink: 1,
141867
+ minSize: 3
141868
+ },
141869
+ {
141870
+ component: this.ensureFooterWrap(),
141871
+ shrink: 1,
141872
+ minSize: 1
141873
+ }
141874
+ ]);
141875
+ const layoutRoot = new VStack([{
141876
+ component: transcriptScrollView,
141877
+ basis: 0,
141878
+ grow: 1,
141879
+ shrink: 1,
141880
+ minSize: 1
141881
+ }, {
141882
+ component: dock,
141883
+ basis: "auto",
141884
+ grow: 0,
141885
+ shrink: 1,
141886
+ minSize: 1
141887
+ }]);
141888
+ ui.setLayoutRoot(layoutRoot);
141889
+ this.host.state.layoutRoot = layoutRoot;
141827
141890
  }
141828
141891
  mountFooter() {
141829
- const footerWrap = new GutterContainer(1, 1);
141830
- footerWrap.addChild(this.host.state.footer);
141831
- this.host.state.ui.addChild(footerWrap);
141892
+ this.ensureFooterWrap();
141893
+ this.footerWrap.addChild(this.host.state.footer);
141894
+ }
141895
+ ensureFooterWrap() {
141896
+ if (this.footerWrap === void 0) this.footerWrap = new GutterContainer(1, 1);
141897
+ return this.footerWrap;
141832
141898
  }
141833
141899
  refreshTerminalThemeTracking() {
141834
141900
  this.stopTerminalThemeTracking();
@@ -141863,48 +141929,57 @@ var LifecycleController = class LifecycleController {
141863
141929
  this.syncTerminalProgress(this.shouldShowTerminalProgress(effectiveMode));
141864
141930
  if (effectiveMode === this.lastActivityMode) return;
141865
141931
  this.lastActivityMode = effectiveMode;
141932
+ this.updateStatusBar(effectiveMode);
141866
141933
  const { state } = this.host;
141867
141934
  state.activityContainer.clear();
141868
141935
  switch (effectiveMode) {
141869
141936
  case "hidden":
141937
+ case "idle":
141870
141938
  this.stopActivitySpinner();
141871
141939
  this.stopPulseWave();
141872
- state.ui.requestRender();
141873
- return;
141874
- case "waiting": {
141875
- this.stopActivitySpinner();
141876
- const pulseWave = this.ensurePulseWave();
141877
- state.activityContainer.addChild(new ActivityPaneComponent({
141878
- mode: "waiting",
141879
- pulseWave
141880
- }));
141881
141940
  break;
141882
- }
141941
+ case "waiting":
141883
141942
  case "thinking":
141943
+ case "composing":
141944
+ case "tool":
141884
141945
  this.stopActivitySpinner();
141885
141946
  this.stopPulseWave();
141886
141947
  break;
141887
- case "composing": {
141888
- const spinner = this.ensureActivitySpinner("working...", (s) => chalk.hex(state.theme.colors.primary)(s));
141889
- state.activityContainer.addChild(new ActivityPaneComponent({
141890
- mode: "composing",
141891
- spinner
141892
- }));
141893
- break;
141894
- }
141895
- case "tool": {
141896
- this.stopActivitySpinner();
141897
- const pulseWave = this.ensurePulseWave();
141898
- state.activityContainer.addChild(new ActivityPaneComponent({
141899
- mode: "tool",
141900
- pulseWave
141901
- }));
141948
+ }
141949
+ state.ui.requestRender();
141950
+ }
141951
+ /**
141952
+ * Updates the fixed status bar above the editor to reflect the current
141953
+ * work phase. Called only when the phase actually changes. Uses its OWN
141954
+ * spinner/pulse instances (a component can only have one parent, so the
141955
+ * activity pane's instances must not be shared). Recreating a loader on
141956
+ * every call would leak setInterval timers (each PulseWaveLoader.start()
141957
+ * registers one and the old instance is never stopped), so the previous
141958
+ * instance is explicitly stopped before a new one is mounted. Idle leaves
141959
+ * the bar empty.
141960
+ */
141961
+ updateStatusBar(mode) {
141962
+ const { state } = this.host;
141963
+ state.statusBarContainer.clear();
141964
+ this.statusBarLoader?.stop();
141965
+ this.statusBarLoader = void 0;
141966
+ switch (mode) {
141967
+ case "waiting":
141968
+ case "composing":
141969
+ case "tool":
141970
+ {
141971
+ const loader = new PulseWaveLoader(state.ui, state.theme.colors.primary);
141972
+ this.statusBarLoader = loader;
141973
+ state.statusBarContainer.addChild(new StatusBarPaneComponent({
141974
+ mode,
141975
+ label: "",
141976
+ pulseWave: loader
141977
+ }));
141978
+ }
141902
141979
  break;
141903
- }
141980
+ case "thinking": break;
141904
141981
  case "idle":
141905
- this.stopActivitySpinner();
141906
- this.stopPulseWave();
141907
- break;
141982
+ case "hidden": break;
141908
141983
  }
141909
141984
  state.ui.requestRender();
141910
141985
  }
@@ -141927,28 +142002,12 @@ var LifecycleController = class LifecycleController {
141927
142002
  this.host.state.terminal.setProgress(active);
141928
142003
  this.host.state.terminalState.progressActive = active;
141929
142004
  }
141930
- ensureActivitySpinner(label = "", colorFn) {
141931
- if (this.host.state.activitySpinner === null) {
141932
- const instance = new MoonLoader(this.host.state.ui, colorFn, label);
141933
- this.host.state.activitySpinner = { instance };
141934
- return instance;
141935
- }
141936
- this.host.state.activitySpinner.instance.setLabel(label);
141937
- if (colorFn !== void 0) this.host.state.activitySpinner.instance.setColorFn(colorFn);
141938
- return this.host.state.activitySpinner.instance;
141939
- }
141940
142005
  stopActivitySpinner() {
141941
142006
  if (this.host.state.activitySpinner !== null) {
141942
142007
  this.host.state.activitySpinner.instance.stop();
141943
142008
  this.host.state.activitySpinner = null;
141944
142009
  }
141945
142010
  }
141946
- ensurePulseWave() {
141947
- if (this.host.state.pulseWave !== null) return this.host.state.pulseWave;
141948
- const instance = new PulseWaveLoader(this.host.state.ui, this.host.state.theme.colors.primary);
141949
- this.host.state.pulseWave = instance;
141950
- return instance;
141951
- }
141952
142011
  stopPulseWave() {
141953
142012
  if (this.host.state.pulseWave !== null) {
141954
142013
  this.host.state.pulseWave.stop();
@@ -142375,18 +142434,10 @@ var InputController = class InputController {
142375
142434
  this.host = host;
142376
142435
  }
142377
142436
  setupAutocomplete() {
142378
- const visible = this.host.getSlashCommands().filter((cmd) => !(cmd.name.startsWith("skill:") && cmd.source === "builtin"));
142379
- const slashCommands = visible.map((cmd) => cmd);
142437
+ const slashCommands = this.host.getSlashCommands().filter((cmd) => !(cmd.name.startsWith("skill:") && cmd.source === "builtin")).map((cmd) => cmd);
142380
142438
  const { state } = this.host;
142381
142439
  const provider = new FileMentionProvider(slashCommands, state.appState.workDir, state.fdPath, state.gitLsFilesCache);
142382
142440
  state.editor.setAutocompleteProvider(provider);
142383
- const argumentHints = /* @__PURE__ */ new Map();
142384
- for (const cmd of visible) {
142385
- if (cmd.argumentHint === void 0) continue;
142386
- argumentHints.set(cmd.name, cmd.argumentHint);
142387
- for (const alias of cmd.aliases) argumentHints.set(alias, cmd.argumentHint);
142388
- }
142389
- state.editor.setArgumentHints(argumentHints);
142390
142441
  state.editor.onFirstInput = () => {
142391
142442
  this.host.stopWelcomeBreathing();
142392
142443
  this.#permanentlyStopBreathing();
@@ -143681,8 +143732,7 @@ function createTUIState(options) {
143681
143732
  const initialAppState = options.initialAppState;
143682
143733
  const theme = createScreamTUIThemeBundle(initialAppState.theme, options.resolvedTheme);
143683
143734
  const terminal = new ProcessTerminal();
143684
- const ui = new TUI(terminal);
143685
- ui.setClearOnShrink(true);
143735
+ const ui = new TuiAltScreen(terminal);
143686
143736
  const uiAny = ui;
143687
143737
  const originalDoRender = uiAny["doRender"].bind(ui);
143688
143738
  let recovering = false;
@@ -143708,6 +143758,7 @@ function createTUIState(options) {
143708
143758
  };
143709
143759
  const transcriptContainer = new GutterContainer(1, 1);
143710
143760
  const activityContainer = new GutterContainer(1, 1);
143761
+ const statusBarContainer = new GutterContainer(1, 1);
143711
143762
  const todoPanelContainer = new GutterContainer(1, 1);
143712
143763
  const todoPanel = new TodoPanelComponent(theme.colors);
143713
143764
  const queueContainer = new GutterContainer(1, 1);
@@ -143725,8 +143776,10 @@ function createTUIState(options) {
143725
143776
  return {
143726
143777
  ui,
143727
143778
  terminal,
143779
+ layoutRoot: void 0,
143728
143780
  transcriptContainer,
143729
143781
  activityContainer,
143782
+ statusBarContainer,
143730
143783
  todoPanelContainer,
143731
143784
  todoPanel,
143732
143785
  queueContainer,
@@ -144634,7 +144687,7 @@ var ApprovalPanelComponent = class extends Container {
144634
144687
  };
144635
144688
  if (this.ui !== void 0) this.intervalId = setInterval(() => {
144636
144689
  this.animFrame = (this.animFrame + 1) % PIXEL_PULSE_FRAMES.length;
144637
- this.ui?.requestComponentRender(this);
144690
+ this.ui?.requestRender();
144638
144691
  }, 100);
144639
144692
  }
144640
144693
  /** Stop the selection pulse. Idempotent; called on submit and on hide. */
@@ -145863,7 +145916,7 @@ var QuestionDialogComponent = class extends Container {
145863
145916
  this.answers = Array.from({ length: total }, () => void 0);
145864
145917
  if (this.ui !== void 0) this.intervalId = setInterval(() => {
145865
145918
  this.animFrame = (this.animFrame + 1) % PIXEL_PULSE_FRAMES.length;
145866
- this.ui?.requestComponentRender(this);
145919
+ this.ui?.requestRender();
145867
145920
  }, 100);
145868
145921
  }
145869
145922
  /** Stop the wizard pulse. Idempotent; called on respond and on hide. */
@@ -146575,7 +146628,7 @@ var DialogManager = class {
146575
146628
  }
146576
146629
  openApprovalPreview(panel, block) {
146577
146630
  if (this.approvalPreview !== void 0) return;
146578
- const savedChildren = [...this.host.state.ui.children];
146631
+ const savedLayoutRoot = this.host.state.layoutRoot;
146579
146632
  const viewer = new ApprovalPreviewViewer({
146580
146633
  block,
146581
146634
  colors: this.host.state.theme.colors,
@@ -146583,13 +146636,12 @@ var DialogManager = class {
146583
146636
  this.closeApprovalPreview();
146584
146637
  }
146585
146638
  }, this.host.state.terminal);
146586
- this.host.state.ui.clear();
146587
- this.host.state.ui.addChild(viewer);
146639
+ this.host.state.ui.setLayoutRoot(viewer);
146588
146640
  this.host.state.ui.setFocus(viewer);
146589
146641
  this.host.state.ui.requestRender(true);
146590
146642
  this.approvalPreview = {
146591
146643
  component: viewer,
146592
- savedChildren,
146644
+ savedLayoutRoot,
146593
146645
  panel
146594
146646
  };
146595
146647
  }
@@ -146597,8 +146649,7 @@ var DialogManager = class {
146597
146649
  const preview = this.approvalPreview;
146598
146650
  if (preview === void 0) return;
146599
146651
  this.approvalPreview = void 0;
146600
- this.host.state.ui.clear();
146601
- for (const child of preview.savedChildren) this.host.state.ui.addChild(child);
146652
+ this.host.state.ui.setLayoutRoot(preview.savedLayoutRoot);
146602
146653
  this.host.state.ui.setFocus(preview.panel);
146603
146654
  this.host.state.ui.requestRender(true);
146604
146655
  }
@@ -146689,7 +146740,6 @@ var ScreamTUI = class {
146689
146740
  deferUserMessages = false;
146690
146741
  aborted = false;
146691
146742
  isShuttingDown = false;
146692
- tightModeHandler = null;
146693
146743
  reverseRpcDisposers = [];
146694
146744
  startupNotice;
146695
146745
  /** Interval handle for the periodic provider-balance refresh. */
@@ -146788,11 +146838,6 @@ var ScreamTUI = class {
146788
146838
  this.inputController.setupAutocomplete();
146789
146839
  }
146790
146840
  async start() {
146791
- this.tightModeHandler = () => {
146792
- setTightMode((process.stdout.columns ?? 80) < 60);
146793
- };
146794
- this.tightModeHandler();
146795
- process.stdout.on("resize", this.tightModeHandler);
146796
146841
  this.lifecycleController.installSignalHandlers();
146797
146842
  try {
146798
146843
  const shouldReplayHistory = await this.initMainTui();
@@ -146883,11 +146928,6 @@ var ScreamTUI = class {
146883
146928
  async stop(exitCode) {
146884
146929
  if (this.isShuttingDown) return;
146885
146930
  this.isShuttingDown = true;
146886
- if (this.tightModeHandler !== null) {
146887
- process.stdout.off("resize", this.tightModeHandler);
146888
- this.tightModeHandler = null;
146889
- }
146890
- setTightMode(false);
146891
146931
  this.lifecycleController.stopCcConnectPolling();
146892
146932
  if (this.balancePollTimer !== void 0) {
146893
146933
  clearInterval(this.balancePollTimer);
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-35ccG0J0.mjs")).main();
9
+ (await import("./app-NZLMIJND.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);
@@ -410,6 +410,7 @@ const dictionaries = {
410
410
  "cc.uninstall_irreversible": "此操作不可撤销,所有 cc-connect 数据将被清除",
411
411
  "cc.confirm_uninstall_btn": "确认卸载",
412
412
  "auth.fetching_models": "正在拉取最新模型目录...",
413
+ "auth.catalog_fetch_failed": "拉取远程模型目录失败: {error}。请检查网络(目录站点在你的网络环境下可能无法访问)后重试,或使用 /config diy 自行配置服务商。",
413
414
  "auth.no_providers": "没有已配置的模型商。",
414
415
  "auth.deleted": "已删除模型商: {name}",
415
416
  "auth.input_api_url": "输入服务商 API 地址",
@@ -1472,6 +1473,7 @@ const dictionaries = {
1472
1473
  "cc.uninstall_irreversible": "This cannot be undone. All cc-connect data will be removed.",
1473
1474
  "cc.confirm_uninstall_btn": "Confirm Uninstall",
1474
1475
  "auth.fetching_models": "Fetching latest model catalog...",
1476
+ "auth.catalog_fetch_failed": "Failed to fetch the remote model catalog: {error}. Check your network (the catalog host may be unreachable in your region) and retry, or use /config diy to set up a provider manually.",
1475
1477
  "auth.no_providers": "No model providers configured.",
1476
1478
  "auth.deleted": "Deleted provider: {name}",
1477
1479
  "auth.input_api_url": "Enter provider API URL",
@@ -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-BQeV1dTM.mjs";
6
+ import { t as TextInputDialogComponent } from "./text-input-dialog-BI6Q02oM.mjs";
7
7
  export { TextInputDialogComponent };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scream-code",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "description": "A terminal-native AI agent for builders",
5
5
  "license": "MIT",
6
6
  "author": "ScreamCli",
@@ -55,7 +55,7 @@
55
55
  "smoke": "node dist/main.mjs --version"
56
56
  },
57
57
  "dependencies": {
58
- "@liutod-scream/pi-tui": "^0.80.43",
58
+ "@liutod-scream/pi-tui": "^0.84.0",
59
59
  "@mariozechner/clipboard": "^0.3.2",
60
60
  "chalk": "^5.4.1",
61
61
  "cli-highlight": "^2.1.11",