scream-code 0.5.4 → 0.5.5

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 +155 -25
  2. package/package.json +1 -1
package/dist/main.mjs CHANGED
@@ -118880,6 +118880,7 @@ function escapeTomlBasicString(value) {
118880
118880
  }
118881
118881
  //#endregion
118882
118882
  //#region src/tui/constant/rendering.ts
118883
+ const MAX_SHELL_OUTPUT_BYTES = 128 * 1024;
118883
118884
  const BRAILLE_SPINNER_FRAMES = [
118884
118885
  "⠋",
118885
118886
  "⠙",
@@ -121157,13 +121158,19 @@ var UsagePanelComponent = class {
121157
121158
  lines;
121158
121159
  borderHex;
121159
121160
  title;
121161
+ cachedWidth;
121162
+ cachedLines;
121160
121163
  constructor(lines, borderHex, title = " 用量 ") {
121161
121164
  this.lines = lines;
121162
121165
  this.borderHex = borderHex;
121163
121166
  this.title = title;
121164
121167
  }
121165
- invalidate() {}
121168
+ invalidate() {
121169
+ this.cachedWidth = void 0;
121170
+ this.cachedLines = void 0;
121171
+ }
121166
121172
  render(width) {
121173
+ if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
121167
121174
  const paint = (s) => chalk.hex(this.borderHex)(s);
121168
121175
  const indent = " ".repeat(LEFT_MARGIN$1);
121169
121176
  const availableInterior = Math.max(MIN_INTERIOR_WIDTH, width - LEFT_MARGIN$1 - 2 - 2 * SIDE_PADDING$1);
@@ -121180,6 +121187,8 @@ var UsagePanelComponent = class {
121180
121187
  out.push(indent + paint("│") + " " + clipped + " ".repeat(pad) + " " + paint("│"));
121181
121188
  }
121182
121189
  out.push(bottom);
121190
+ this.cachedWidth = width;
121191
+ this.cachedLines = out;
121183
121192
  return out;
121184
121193
  }
121185
121194
  };
@@ -122161,16 +122170,29 @@ function buildEmptyGoalLines(colors) {
122161
122170
  var GoalStatusMessageComponent = class {
122162
122171
  goal;
122163
122172
  colors;
122173
+ panel;
122174
+ cachedWidth;
122175
+ cachedLines;
122164
122176
  constructor(goal, colors) {
122165
122177
  this.goal = goal;
122166
122178
  this.colors = colors;
122179
+ if (goal === null) this.panel = new UsagePanelComponent(buildEmptyGoalLines(this.colors), this.colors.success, " Scream Goal ");
122180
+ else {
122181
+ const title = ` Scream Goal · ${statusLabel(goal.status)} `;
122182
+ this.panel = new UsagePanelComponent(buildGoalReportLines(goal, this.colors), this.colors.success, title);
122183
+ }
122184
+ }
122185
+ invalidate() {
122186
+ this.cachedWidth = void 0;
122187
+ this.cachedLines = void 0;
122188
+ this.panel.invalidate();
122167
122189
  }
122168
- invalidate() {}
122169
122190
  render(width) {
122170
- const goal = this.goal;
122171
- if (goal === null) return ["", ...new UsagePanelComponent(buildEmptyGoalLines(this.colors), this.colors.success, " Scream Goal ").render(width)];
122172
- const title = ` Scream Goal · ${statusLabel(goal.status)} `;
122173
- return ["", ...new UsagePanelComponent(buildGoalReportLines(goal, this.colors), this.colors.success, title).render(width)];
122191
+ if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
122192
+ const lines = ["", ...this.panel.render(width)];
122193
+ this.cachedWidth = width;
122194
+ this.cachedLines = lines;
122195
+ return lines;
122174
122196
  }
122175
122197
  };
122176
122198
  //#endregion
@@ -122706,6 +122728,9 @@ var AssistantMessageComponent = class {
122706
122728
  bulletColor;
122707
122729
  lastText = "";
122708
122730
  showBullet;
122731
+ cachedWidth;
122732
+ cachedLines;
122733
+ markdownChild;
122709
122734
  constructor(markdownTheme, colors, showBullet = true) {
122710
122735
  this.markdownTheme = markdownTheme;
122711
122736
  this.bulletColor = colors.roleAssistant;
@@ -122713,19 +122738,40 @@ var AssistantMessageComponent = class {
122713
122738
  this.contentContainer = new Container();
122714
122739
  }
122715
122740
  setShowBullet(show) {
122741
+ if (this.showBullet === show) return;
122716
122742
  this.showBullet = show;
122743
+ this.cachedWidth = void 0;
122744
+ this.cachedLines = void 0;
122717
122745
  }
122718
122746
  updateContent(text) {
122719
- const displayText = text;
122720
- if (displayText === this.lastText) return;
122721
- this.lastText = displayText;
122747
+ const trimmedText = text.trim();
122748
+ const previousTrimmed = this.lastText.trim();
122749
+ if (trimmedText === previousTrimmed) {
122750
+ this.lastText = text;
122751
+ return;
122752
+ }
122753
+ this.lastText = text;
122754
+ this.cachedWidth = void 0;
122755
+ this.cachedLines = void 0;
122756
+ const markdownChild = this.markdownChild;
122757
+ if (markdownChild !== void 0 && trimmedText.startsWith(previousTrimmed) && trimmedText.length > previousTrimmed.length) {
122758
+ markdownChild.setText(trimmedText);
122759
+ return;
122760
+ }
122722
122761
  this.contentContainer.clear();
122723
- if (displayText.trim().length > 0) this.contentContainer.addChild(new Markdown(displayText.trim(), 0, 0, this.markdownTheme));
122762
+ this.markdownChild = void 0;
122763
+ if (trimmedText.length > 0) {
122764
+ this.markdownChild = new Markdown(trimmedText, 0, 0, this.markdownTheme);
122765
+ this.contentContainer.addChild(this.markdownChild);
122766
+ }
122724
122767
  }
122725
122768
  invalidate() {
122769
+ this.cachedWidth = void 0;
122770
+ this.cachedLines = void 0;
122726
122771
  this.contentContainer.invalidate?.();
122727
122772
  }
122728
122773
  render(width) {
122774
+ if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
122729
122775
  if (this.lastText.trim().length === 0) return [];
122730
122776
  const prefix = this.showBullet ? STATUS_BULLET : " ";
122731
122777
  const contentWidth = Math.max(1, width - visibleWidth(prefix));
@@ -122735,6 +122781,8 @@ var AssistantMessageComponent = class {
122735
122781
  const p = i === 0 && this.showBullet ? chalk.hex(this.bulletColor)(STATUS_BULLET) : " ";
122736
122782
  lines.push(p + contentLines[i]);
122737
122783
  }
122784
+ this.cachedWidth = width;
122785
+ this.cachedLines = lines;
122738
122786
  return lines;
122739
122787
  }
122740
122788
  };
@@ -122743,17 +122791,29 @@ var AssistantMessageComponent = class {
122743
122791
  var BackgroundAgentStatusComponent = class {
122744
122792
  data;
122745
122793
  colors;
122794
+ bullet;
122795
+ textComponent;
122796
+ cachedWidth;
122797
+ cachedLines;
122746
122798
  constructor(data, colors) {
122747
122799
  this.data = data;
122748
122800
  this.colors = colors;
122801
+ const tone = data.phase === "started" ? colors.primary : data.phase === "completed" ? colors.success : colors.error;
122802
+ this.bullet = data.phase === "failed" ? chalk.hex(tone)(FAILURE_MARK) : chalk.hex(tone)(STATUS_BULLET);
122803
+ const text = chalk.hex(tone)(data.headline) + (data.detail !== void 0 && data.detail.length > 0 ? chalk.hex(colors.textDim)(` (${data.detail})`) : "");
122804
+ this.textComponent = new Text(text, 0, 0);
122805
+ }
122806
+ invalidate() {
122807
+ this.cachedWidth = void 0;
122808
+ this.cachedLines = void 0;
122749
122809
  }
122750
- invalidate() {}
122751
122810
  render(width) {
122752
- const tone = this.data.phase === "started" ? this.colors.primary : this.data.phase === "completed" ? this.colors.success : this.colors.error;
122753
- const bullet = this.data.phase === "failed" ? chalk.hex(tone)(FAILURE_MARK) : chalk.hex(tone)(STATUS_BULLET);
122754
- const textComponent = new Text(chalk.hex(tone)(this.data.headline) + (this.data.detail !== void 0 && this.data.detail.length > 0 ? chalk.hex(this.colors.textDim)(` (${this.data.detail})`) : ""), 0, 0);
122811
+ if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
122755
122812
  const contentWidth = Math.max(1, width - 2);
122756
- return ["", ...textComponent.render(contentWidth).map((line, index) => (index === 0 ? bullet : " ") + line)];
122813
+ const lines = ["", ...this.textComponent.render(contentWidth).map((line, index) => (index === 0 ? this.bullet : " ") + line)];
122814
+ this.cachedWidth = width;
122815
+ this.cachedLines = lines;
122816
+ return lines;
122757
122817
  }
122758
122818
  };
122759
122819
  //#endregion
@@ -122920,6 +122980,8 @@ var ThinkingComponent = class {
122920
122980
  spinnerFrame = 0;
122921
122981
  spinnerInterval;
122922
122982
  textComponent;
122983
+ cachedWidth;
122984
+ cachedLines;
122923
122985
  constructor(text, colors, showMarker = true, mode = "finalized", ui) {
122924
122986
  this.text = text;
122925
122987
  this.color = colors.roleThinking;
@@ -122929,17 +122991,25 @@ var ThinkingComponent = class {
122929
122991
  this.textComponent = new Text(this.styled(text), 0, 0);
122930
122992
  if (mode === "live") this.startSpinner();
122931
122993
  }
122932
- invalidate() {}
122994
+ invalidate() {
122995
+ this.cachedWidth = void 0;
122996
+ this.cachedLines = void 0;
122997
+ }
122933
122998
  setText(text) {
122934
122999
  if (this.text === text) return;
122935
123000
  this.text = text;
123001
+ this.cachedWidth = void 0;
123002
+ this.cachedLines = void 0;
122936
123003
  this.textComponent.setText(this.styled(text));
122937
123004
  }
122938
123005
  styled(text) {
122939
123006
  return chalk.hex(this.color).italic(text);
122940
123007
  }
122941
123008
  finalize() {
123009
+ if (this.mode === "finalized") return;
122942
123010
  this.mode = "finalized";
123011
+ this.cachedWidth = void 0;
123012
+ this.cachedLines = void 0;
122943
123013
  this.stopSpinner();
122944
123014
  }
122945
123015
  dispose() {
@@ -122948,8 +123018,11 @@ var ThinkingComponent = class {
122948
123018
  setExpanded(expanded) {
122949
123019
  if (this.expanded === expanded) return;
122950
123020
  this.expanded = expanded;
123021
+ this.cachedWidth = void 0;
123022
+ this.cachedLines = void 0;
122951
123023
  }
122952
123024
  render(width) {
123025
+ if (this.mode === "finalized" && this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
122953
123026
  const contentWidth = Math.max(1, width - 2);
122954
123027
  const contentLines = this.text.length > 0 ? this.textComponent.render(contentWidth) : [""];
122955
123028
  if (this.mode === "live") {
@@ -122965,10 +123038,16 @@ var ThinkingComponent = class {
122965
123038
  const p = i === 0 && this.showMarker ? chalk.hex(this.color)(STATUS_BULLET) : " ";
122966
123039
  rendered.push(p + contentLines[i]);
122967
123040
  }
122968
- if (this.expanded || contentLines.length <= 2) return rendered;
123041
+ if (this.expanded || contentLines.length <= 2) {
123042
+ this.cachedWidth = width;
123043
+ this.cachedLines = rendered;
123044
+ return rendered;
123045
+ }
122969
123046
  const truncated = rendered.slice(0, 3);
122970
123047
  const remaining = contentLines.length - 2;
122971
123048
  truncated.push(" " + chalk.dim(`... (${String(remaining)} more lines, ctrl+o to expand)`));
123049
+ this.cachedWidth = width;
123050
+ this.cachedLines = truncated;
122972
123051
  return truncated;
122973
123052
  }
122974
123053
  startSpinner() {
@@ -123357,6 +123436,26 @@ function trimTrailingEmptyLines(lines) {
123357
123436
  return lines.slice(0, end);
123358
123437
  }
123359
123438
  /**
123439
+ * Returns the tail of `text` whose UTF-8 byte length is at most `maxBytes`.
123440
+ * Iterates by Unicode code points so multi-byte characters and surrogate
123441
+ * pairs are never split.
123442
+ */
123443
+ function truncateTailBytes(text, maxBytes) {
123444
+ if (Buffer.byteLength(text, "utf8") <= maxBytes) return text;
123445
+ const chars = Array.from(text);
123446
+ let start = chars.length;
123447
+ let bytes = 0;
123448
+ for (let i = chars.length - 1; i >= 0; i--) {
123449
+ const char = chars[i];
123450
+ if (char === void 0) continue;
123451
+ const charBytes = Buffer.byteLength(char, "utf8");
123452
+ if (bytes + charBytes > maxBytes) break;
123453
+ bytes += charBytes;
123454
+ start = i;
123455
+ }
123456
+ return chars.slice(start).join("");
123457
+ }
123458
+ /**
123360
123459
  * Component that renders tool output with wrap-aware line truncation.
123361
123460
  * Uses pi-tui's Text component to compute actual visual wrapped lines,
123362
123461
  * then caps at PREVIEW_LINES. This handles long single-line output (e.g.
@@ -123373,7 +123472,8 @@ var TruncatedOutputComponent = class {
123373
123472
  this.hintFormatter = options.hintFormatter;
123374
123473
  const tint = options.isError ? chalk.hex(options.colors.error) : chalk.dim;
123375
123474
  const cleaned = trimTrailingEmptyLines(output.split("\n")).join("\n");
123376
- this.textComponent = new Text(tint(cleaned), 2, 0);
123475
+ const truncated = options.maxBytes === void 0 ? cleaned : truncateTailBytes(cleaned, options.maxBytes);
123476
+ this.textComponent = new Text(tint(truncated), 2, 0);
123377
123477
  }
123378
123478
  invalidate() {
123379
123479
  this.textComponent.invalidate();
@@ -123419,6 +123519,7 @@ var ShellExecutionComponent = class extends Container {
123419
123519
  isError: result.is_error ?? false,
123420
123520
  colors,
123421
123521
  maxLines: previewLines,
123522
+ maxBytes: MAX_SHELL_OUTPUT_BYTES,
123422
123523
  hintFormatter: (remaining) => `...(还有 ${String(remaining)} 行,按 ctrl+o 展开)`
123423
123524
  }));
123424
123525
  }
@@ -124013,6 +124114,7 @@ var ToolCallComponent = class ToolCallComponent extends Container {
124013
124114
  subagentError;
124014
124115
  streamingProgressTimer;
124015
124116
  subagentElapsedTimer;
124117
+ disposed = false;
124016
124118
  subagentStartedAtMs;
124017
124119
  subagentEndedAtMs;
124018
124120
  progressLines = [];
@@ -124092,6 +124194,8 @@ var ToolCallComponent = class ToolCallComponent extends Container {
124092
124194
  this.ui?.requestRender();
124093
124195
  }
124094
124196
  dispose() {
124197
+ if (this.disposed) return;
124198
+ this.disposed = true;
124095
124199
  this.stopStreamingProgressTimer();
124096
124200
  this.stopSubagentElapsedTimer();
124097
124201
  }
@@ -124247,6 +124351,10 @@ var ToolCallComponent = class ToolCallComponent extends Container {
124247
124351
  }
124248
124352
  if (this.ui === void 0 || this.streamingProgressTimer !== void 0) return;
124249
124353
  this.streamingProgressTimer = setInterval(() => {
124354
+ if (this.disposed) {
124355
+ this.stopStreamingProgressTimer();
124356
+ return;
124357
+ }
124250
124358
  if (!this.isStreamingEditPreview()) {
124251
124359
  this.stopStreamingProgressTimer();
124252
124360
  return;
@@ -124268,6 +124376,10 @@ var ToolCallComponent = class ToolCallComponent extends Container {
124268
124376
  }
124269
124377
  if (this.ui === void 0 || this.subagentElapsedTimer !== void 0) return;
124270
124378
  this.subagentElapsedTimer = setInterval(() => {
124379
+ if (this.disposed) {
124380
+ this.stopSubagentElapsedTimer();
124381
+ return;
124382
+ }
124271
124383
  const latestPhase = this.getDerivedSubagentPhase();
124272
124384
  if (latestPhase !== "spawning" && latestPhase !== "running") {
124273
124385
  this.stopSubagentElapsedTimer();
@@ -124957,6 +125069,8 @@ var UserMessageComponent = class {
124957
125069
  textComponent;
124958
125070
  spacerComponent;
124959
125071
  imageThumbnails;
125072
+ cachedWidth;
125073
+ cachedLines;
124960
125074
  constructor(text, colors, images) {
124961
125075
  this.color = colors.roleUser;
124962
125076
  this.textComponent = new Text(chalk.hex(colors.roleUser).bold(text), 0, 0);
@@ -124964,10 +125078,13 @@ var UserMessageComponent = class {
124964
125078
  this.imageThumbnails = images?.map((img) => new ImageThumbnail(img, colors)) ?? [];
124965
125079
  }
124966
125080
  invalidate() {
125081
+ this.cachedWidth = void 0;
125082
+ this.cachedLines = void 0;
124967
125083
  this.textComponent.invalidate();
124968
125084
  for (const img of this.imageThumbnails) img.invalidate?.();
124969
125085
  }
124970
125086
  render(width) {
125087
+ if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
124971
125088
  const border = chalk.hex(this.color).bold(USER_MESSAGE_BULLET);
124972
125089
  const borderWidth = visibleWidth(border);
124973
125090
  const contentWidth = Math.max(1, width - borderWidth);
@@ -124982,6 +125099,8 @@ var UserMessageComponent = class {
124982
125099
  const imageLines = thumbnail.render(contentWidth);
124983
125100
  for (const line of imageLines) lines.push(" ".repeat(borderWidth) + line);
124984
125101
  }
125102
+ this.cachedWidth = width;
125103
+ this.cachedLines = lines;
124985
125104
  return lines;
124986
125105
  }
124987
125106
  };
@@ -130181,6 +130300,7 @@ var StreamingUIController = class {
130181
130300
  const tc = this._pendingToolComponents.get(toolCallId);
130182
130301
  if (tc) {
130183
130302
  tc.setResult(result);
130303
+ tc.dispose();
130184
130304
  this._pendingToolComponents.delete(toolCallId);
130185
130305
  state.ui.requestRender();
130186
130306
  return;
@@ -131504,6 +131624,10 @@ var CronMessageComponent = class {
131504
131624
  detail;
131505
131625
  titleColor;
131506
131626
  promptText;
131627
+ bullet;
131628
+ bulletWidth;
131629
+ cachedWidth;
131630
+ cachedLines;
131507
131631
  constructor(prompt, data, colors) {
131508
131632
  this.colors = colors;
131509
131633
  const missed = data.missedCount !== void 0;
@@ -131511,21 +131635,26 @@ var CronMessageComponent = class {
131511
131635
  this.detail = cronDetail(data);
131512
131636
  this.titleColor = data.stale === true || missed ? colors.warning : colors.accent;
131513
131637
  this.promptText = new Text(chalk.hex(colors.text)(prompt), 0, 0);
131638
+ this.bullet = chalk.hex(this.titleColor).bold(STATUS_BULLET);
131639
+ this.bulletWidth = visibleWidth(this.bullet);
131514
131640
  }
131515
131641
  invalidate() {
131642
+ this.cachedWidth = void 0;
131643
+ this.cachedLines = void 0;
131516
131644
  this.promptText.invalidate();
131517
131645
  }
131518
131646
  render(width) {
131519
- const bullet = chalk.hex(this.titleColor).bold(STATUS_BULLET);
131520
- const bulletWidth = visibleWidth(bullet);
131521
- const contentWidth = Math.max(1, width - bulletWidth);
131647
+ if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
131648
+ const contentWidth = Math.max(1, width - this.bulletWidth);
131522
131649
  const lines = [];
131523
131650
  for (const line of this.spacer.render(width)) lines.push(line);
131524
131651
  const title = chalk.hex(this.titleColor).bold(this.title);
131525
- lines.push(`${bullet}${title}`);
131526
- if (this.detail !== void 0) lines.push(`${" ".repeat(bulletWidth)}${chalk.hex(this.colors.textDim)(this.detail)}`);
131652
+ lines.push(`${this.bullet}${title}`);
131653
+ if (this.detail !== void 0) lines.push(`${" ".repeat(this.bulletWidth)}${chalk.hex(this.colors.textDim)(this.detail)}`);
131527
131654
  const promptLines = this.promptText.render(contentWidth);
131528
- for (const line of promptLines) lines.push(`${" ".repeat(bulletWidth)}${line}`);
131655
+ for (const line of promptLines) lines.push(`${" ".repeat(this.bulletWidth)}${line}`);
131656
+ this.cachedWidth = width;
131657
+ this.cachedLines = lines;
131529
131658
  return lines;
131530
131659
  }
131531
131660
  };
@@ -136549,7 +136678,7 @@ var ScreamTUI = class ScreamTUI {
136549
136678
  updateActivityPane() {
136550
136679
  const effectiveMode = this.resolveActivityPaneMode();
136551
136680
  this.syncTerminalProgress(this.shouldShowTerminalProgress(effectiveMode));
136552
- if (effectiveMode === this.lastActivityMode && (effectiveMode === "waiting" || effectiveMode === "thinking" || effectiveMode === "tool")) return;
136681
+ if (effectiveMode === this.lastActivityMode) return;
136553
136682
  this.lastActivityMode = effectiveMode;
136554
136683
  this.state.activityContainer.clear();
136555
136684
  switch (effectiveMode) {
@@ -136653,6 +136782,7 @@ var ScreamTUI = class ScreamTUI {
136653
136782
  this.state.theme.markdownTheme = nextTheme.markdownTheme;
136654
136783
  this.setAppState({ theme });
136655
136784
  this.updateEditorBorderHighlight();
136785
+ for (const child of this.state.transcriptContainer.children) child.invalidate?.();
136656
136786
  this.state.ui.requestRender(true);
136657
136787
  }
136658
136788
  refreshTerminalThemeTracking() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scream-code",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "The Starting Point for Next-Gen Agents",
5
5
  "license": "MIT",
6
6
  "author": "ScreamCli",