pi-fabric 0.53.0 → 0.53.1

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.
@@ -686,12 +686,225 @@ var fileHighlightRange = (entry, from, to, invalidate) => {
686
686
  return out;
687
687
  };
688
688
 
689
- // src/ui/core-tool-render.ts
690
- import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
691
- import { homedir } from "node:os";
692
- import { basename as basename2, extname as extname2, isAbsolute, relative, resolve } from "node:path";
693
- import { diffLines } from "diff";
694
- import { bundledLanguages as bundledLanguages2 } from "shiki/langs";
689
+ // src/ui/structured.ts
690
+ import { stringify } from "yaml";
691
+ var normalizeJsonValue = (value) => {
692
+ try {
693
+ const serialized = JSON.stringify(value);
694
+ return serialized === void 0 ? void 0 : JSON.parse(serialized);
695
+ } catch {
696
+ return void 0;
697
+ }
698
+ };
699
+ var formatJsonAsYaml = (value) => {
700
+ const normalized = normalizeJsonValue(value);
701
+ if (normalized === void 0) return void 0;
702
+ return stringify(normalized, { indent: 2, lineWidth: 0 }).trimEnd();
703
+ };
704
+ var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
705
+ var hoistMultilineStrings = (value, path, sections, seen) => {
706
+ if (typeof value === "string") {
707
+ if (!value.includes("\n")) return value;
708
+ sections.push({ path, text: value });
709
+ return `<multi-line string, see section: ${path}>`;
710
+ }
711
+ if (Array.isArray(value)) {
712
+ if (seen.has(value)) return "[circular reference]";
713
+ seen.add(value);
714
+ const skeleton = value.map(
715
+ (item, index) => hoistMultilineStrings(item, `${path}[${index}]`, sections, seen)
716
+ );
717
+ seen.delete(value);
718
+ return skeleton;
719
+ }
720
+ if (isPlainObject(value)) {
721
+ if (seen.has(value)) return "[circular reference]";
722
+ seen.add(value);
723
+ const skeleton = {};
724
+ for (const [key, item] of Object.entries(value)) {
725
+ skeleton[key] = hoistMultilineStrings(
726
+ item,
727
+ path ? `${path}.${key}` : key,
728
+ sections,
729
+ seen
730
+ );
731
+ }
732
+ seen.delete(value);
733
+ return skeleton;
734
+ }
735
+ return value;
736
+ };
737
+ var boundedSection = (value, maxChars) => {
738
+ if (value.length <= maxChars) return value;
739
+ if (maxChars <= 0) return "";
740
+ let omitted = value.length - maxChars;
741
+ let marker = `\u2026[${omitted} chars omitted]\u2026`;
742
+ for (let pass = 0; pass < 2; pass++) {
743
+ omitted = value.length - Math.max(0, maxChars - marker.length);
744
+ marker = `\u2026[${omitted} chars omitted]\u2026`;
745
+ }
746
+ if (marker.length >= maxChars) return marker.slice(0, maxChars);
747
+ const available = maxChars - marker.length;
748
+ const head = Math.ceil(available / 2);
749
+ const tail = Math.floor(available / 2);
750
+ return `${value.slice(0, head)}${marker}${value.slice(value.length - tail)}`;
751
+ };
752
+ var fairSectionBudgets = (lengths, budget) => {
753
+ const budgets = Array.from({ length: lengths.length }, () => 0);
754
+ const pending = lengths.map((length, index) => ({ length, index })).sort((left, right) => left.length - right.length);
755
+ let remaining = Math.max(0, budget);
756
+ for (let position = 0; position < pending.length; position++) {
757
+ const item = pending[position];
758
+ const share = Math.floor(remaining / (pending.length - position));
759
+ const allocated = Math.min(item.length, share);
760
+ budgets[item.index] = allocated;
761
+ remaining -= allocated;
762
+ }
763
+ return budgets;
764
+ };
765
+ var renderHoistedSections = (yaml, sections, maxChars) => {
766
+ const headers = sections.map((section) => `--- ${section.path} (${section.text.length} chars) ---
767
+ `);
768
+ const separators = sections.length * 2;
769
+ const fixedChars = yaml.length + separators + headers.reduce((sum, header) => sum + header.length, 0);
770
+ const fullChars = fixedChars + sections.reduce((sum, section) => sum + section.text.length, 0);
771
+ const budgets = maxChars !== void 0 && fullChars > maxChars ? fairSectionBudgets(sections.map((section) => section.text.length), maxChars - fixedChars) : sections.map((section) => section.text.length);
772
+ const raw = sections.map((section, index) => `${headers[index]}${boundedSection(section.text, budgets[index])}`).join("\n\n");
773
+ return `${yaml}
774
+
775
+ ${raw}`;
776
+ };
777
+ var formatFabricValue = (value, format, maxChars) => {
778
+ if (value === void 0) return { text: "" };
779
+ if (format === "text" && typeof value === "object" && value !== null && "text" in value) {
780
+ const text = value.text;
781
+ if (typeof text === "string") return { text };
782
+ }
783
+ if (typeof value === "string") return { text: value };
784
+ if (format === "auto" || format === "yaml") {
785
+ const sections = [];
786
+ const skeleton = hoistMultilineStrings(value, "", sections, /* @__PURE__ */ new Set());
787
+ const yaml = formatJsonAsYaml(skeleton);
788
+ if (yaml !== void 0) {
789
+ if (sections.length === 0) return { text: yaml, language: "yaml" };
790
+ return {
791
+ text: renderHoistedSections(yaml, sections, maxChars),
792
+ language: "yaml",
793
+ highlightedLineCount: countNewlines(yaml) + 1
794
+ };
795
+ }
796
+ }
797
+ try {
798
+ return {
799
+ text: JSON.stringify(value, null, format === "json" ? 2 : 0),
800
+ ...format === "json" ? { language: "json" } : {}
801
+ };
802
+ } catch {
803
+ return { text: String(value) };
804
+ }
805
+ };
806
+
807
+ // src/ui/format.ts
808
+ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
809
+ var safeText = (value) => String(value ?? "").replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g, " ").replace(/[\r\n\t]+/g, " ").replace(/\s+/g, " ").trim();
810
+ var formatActorDataPreview = (data, maxChars = 200) => {
811
+ if (data === void 0) return void 0;
812
+ const clip = (value) => {
813
+ const safe = safeText(value);
814
+ return safe.length > maxChars ? `${safe.slice(0, Math.max(1, maxChars - 1))}\u2026` : safe;
815
+ };
816
+ if (typeof data === "string") return clip(data);
817
+ if (typeof data === "object" && data !== null && !Array.isArray(data) && data.fabricTruncated === true) {
818
+ const wrapper = data;
819
+ const preview = clip(String(wrapper.preview ?? ""));
820
+ const suffix = typeof wrapper.originalBytes === "number" ? `[truncated from ${wrapper.originalBytes} bytes]` : "[truncated]";
821
+ return preview ? `${preview} ${suffix}` : suffix;
822
+ }
823
+ let serialized;
824
+ try {
825
+ serialized = JSON.stringify(data) ?? String(data);
826
+ } catch {
827
+ serialized = String(data);
828
+ }
829
+ return clip(serialized);
830
+ };
831
+ var formatDuration = (milliseconds) => {
832
+ const seconds = Math.max(0, Math.floor(milliseconds / 1e3));
833
+ if (seconds < 60) return `${seconds}s`;
834
+ const minutes = Math.floor(seconds / 60);
835
+ if (minutes < 60) return `${minutes}m${String(seconds % 60).padStart(2, "0")}s`;
836
+ const hours = Math.floor(minutes / 60);
837
+ return `${hours}h${String(minutes % 60).padStart(2, "0")}m`;
838
+ };
839
+ var formatTokens = (tokens) => {
840
+ if (tokens < 1e3) return String(Math.max(0, Math.round(tokens)));
841
+ if (tokens < 1e5) return `${(tokens / 1e3).toFixed(tokens < 1e4 ? 1 : 0)}k`;
842
+ return `${(tokens / 1e3).toFixed(0)}k`;
843
+ };
844
+ var formatCost = (usd) => usd <= 0 ? "$0" : usd < 0.01 ? `$${usd.toFixed(4)}` : usd < 1 ? `$${usd.toFixed(3)}` : `$${usd.toFixed(2)}`;
845
+ var formatClock = (timestamp) => new Date(timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
846
+ var padToWidth = (value, width) => {
847
+ const clipped = truncateToWidth(value, Math.max(0, width), "");
848
+ return clipped + " ".repeat(Math.max(0, width - visibleWidth(clipped)));
849
+ };
850
+ var wrapPlainText = (value, width, maxLines = 100) => {
851
+ const safe = safeText(value);
852
+ if (!safe || width <= 0 || maxLines <= 0) return [];
853
+ const words = safe.split(" ");
854
+ const lines = [];
855
+ let current = "";
856
+ for (const word of words) {
857
+ const candidate = current ? `${current} ${word}` : word;
858
+ if (visibleWidth(candidate) <= width) {
859
+ current = candidate;
860
+ continue;
861
+ }
862
+ if (current) lines.push(truncateToWidth(current, width));
863
+ current = word;
864
+ while (visibleWidth(current) > width && lines.length < maxLines) {
865
+ let chunk = "";
866
+ let consumed = 0;
867
+ const segments = [
868
+ ...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(current)
869
+ ];
870
+ for (const { segment } of segments) {
871
+ const candidate2 = chunk + segment;
872
+ if (visibleWidth(candidate2) > width) {
873
+ if (!chunk) {
874
+ chunk = "\u2026";
875
+ consumed += segment.length;
876
+ }
877
+ break;
878
+ }
879
+ chunk = candidate2;
880
+ consumed += segment.length;
881
+ }
882
+ if (chunk) lines.push(chunk);
883
+ current = current.slice(consumed);
884
+ }
885
+ if (lines.length >= maxLines) break;
886
+ }
887
+ if (current && lines.length < maxLines) lines.push(truncateToWidth(current, width));
888
+ return lines;
889
+ };
890
+
891
+ // src/ui/types.ts
892
+ var activeStatuses = /* @__PURE__ */ new Set([
893
+ "queued",
894
+ "pending",
895
+ "ready",
896
+ "claimed",
897
+ "running",
898
+ "in_progress",
899
+ "blocked",
900
+ "loading",
901
+ "active",
902
+ "unloading"
903
+ ]);
904
+ var isActiveStatus = (status) => activeStatuses.has(status);
905
+ var orderAgentsByCreation = (agents) => agents.map((agent, index) => ({ agent, index })).sort(
906
+ (left, right) => (left.agent.startedAt ?? Number.MAX_SAFE_INTEGER) - (right.agent.startedAt ?? Number.MAX_SAFE_INTEGER) || left.index - right.index
907
+ ).map(({ agent }) => agent);
695
908
 
696
909
  // src/ui/arc-group.ts
697
910
  var ANSI_ESCAPE = /\x1b\[[0-9;]*m/g;
@@ -726,8 +939,15 @@ function pushArcItem(lines, item) {
726
939
  lines.push(item);
727
940
  }
728
941
 
942
+ // src/ui/core-tool-render.ts
943
+ import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
944
+ import { homedir } from "node:os";
945
+ import { basename as basename2, extname as extname2, isAbsolute, relative, resolve } from "node:path";
946
+ import { diffLines } from "diff";
947
+ import { bundledLanguages as bundledLanguages2 } from "shiki/langs";
948
+
729
949
  // src/ui/diff-background.ts
730
- import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
950
+ import { truncateToWidth as truncateToWidth2, visibleWidth as visibleWidth2 } from "@earendil-works/pi-tui";
731
951
  var DIFF_ADD_MARKER = "\0PI_DIFF_ADD\0";
732
952
  var DIFF_REMOVE_MARKER = "\0PI_DIFF_REMOVE\0";
733
953
  var markDiffLine = (kind, line) => (kind === "add" ? DIFF_ADD_MARKER : DIFF_REMOVE_MARKER) + line;
@@ -788,7 +1008,7 @@ var wrapDiffAnsiToWidth = (text, width, maxRows = 3, continuationPrefix = "") =>
788
1008
  let rowWidth = 0;
789
1009
  let index = 0;
790
1010
  let state = "";
791
- const continuationWidth = visibleWidth(continuationPrefix);
1011
+ const continuationWidth = visibleWidth2(continuationPrefix);
792
1012
  const pushRow = () => {
793
1013
  rows.push(truncateWrappedRow(row, rowWidth, width));
794
1014
  if (rows.length >= maxRows) {
@@ -816,17 +1036,17 @@ var wrapDiffAnsiToWidth = (text, width, maxRows = 3, continuationPrefix = "") =>
816
1036
  rowWidth += plain.length;
817
1037
  } else {
818
1038
  for (const { segment } of segmenter.segment(plain)) {
819
- const segmentWidth = visibleWidth(segment);
1039
+ const segmentWidth = visibleWidth2(segment);
820
1040
  if (rowWidth > 0 && rowWidth + segmentWidth > width && !pushRow()) return rows;
821
1041
  if (rowWidth > 0 && rowWidth + segmentWidth > width) {
822
1042
  row = state;
823
1043
  rowWidth = 0;
824
1044
  }
825
1045
  if (segmentWidth > width && rowWidth === 0) {
826
- const clipped = truncateToWidth(segment, width, "");
1046
+ const clipped = truncateToWidth2(segment, width, "");
827
1047
  if (clipped) {
828
1048
  row += clipped;
829
- rowWidth += visibleWidth(clipped);
1049
+ rowWidth += visibleWidth2(clipped);
830
1050
  }
831
1051
  if (!pushRow()) return rows;
832
1052
  continue;
@@ -843,12 +1063,12 @@ var wrapDiffAnsiToWidth = (text, width, maxRows = 3, continuationPrefix = "") =>
843
1063
  };
844
1064
  var truncateWrappedRow = (row, rowWidth, width) => {
845
1065
  if (rowWidth <= width && TRUNCATION_SAFE_RE.test(row)) return row;
846
- return truncateToWidth(row, width, "");
1066
+ return truncateToWidth2(row, width, "");
847
1067
  };
848
1068
  var truncateLastRow = (rows, width) => {
849
1069
  const last = rows.at(-1) ?? "";
850
- if (visibleWidth(last) >= width && width > 1) {
851
- rows[rows.length - 1] = truncateToWidth(last, width - 1, "") + "\u203A";
1070
+ if (visibleWidth2(last) >= width && width > 1) {
1071
+ rows[rows.length - 1] = truncateToWidth2(last, width - 1, "") + "\u203A";
852
1072
  }
853
1073
  return rows;
854
1074
  };
@@ -3706,15 +3926,6 @@ var coreToolTitle = (audit, theme, options) => {
3706
3926
  return `${title} ${renderPath(filePath, options.cwd, theme)}${metadata(theme, [timing])}`;
3707
3927
  };
3708
3928
 
3709
- // src/ui/fabric-render.ts
3710
- import { createHash } from "node:crypto";
3711
- import {
3712
- getKeybindings,
3713
- truncateToWidth as truncateToWidth2,
3714
- visibleWidth as visibleWidth2,
3715
- wrapTextWithAnsi
3716
- } from "@earendil-works/pi-tui";
3717
-
3718
3929
  // src/ui/fabric-code-parser.ts
3719
3930
  var identifierStart = (char) => /[A-Za-z_$π]/u.test(char);
3720
3931
  var identifierPart = (char) => /[A-Za-z0-9_$π]/u.test(char);
@@ -3873,6 +4084,13 @@ var fabricWriteBindings = (code) => {
3873
4084
  };
3874
4085
 
3875
4086
  // src/ui/fabric-render.ts
4087
+ import { createHash } from "node:crypto";
4088
+ import {
4089
+ getKeybindings,
4090
+ truncateToWidth as truncateToWidth3,
4091
+ visibleWidth as visibleWidth3,
4092
+ wrapTextWithAnsi
4093
+ } from "@earendil-works/pi-tui";
3876
4094
  var configuredDiffWrapRows = Number.parseInt(
3877
4095
  process.env.CODE_PREVIEW_DIFF_WRAP_ROWS ?? "",
3878
4096
  10
@@ -3930,7 +4148,7 @@ var safeTerminalText = (value) => value.replace(/[\u0000-\u0008\u000b-\u001f\u00
3930
4148
  return `\\x${code}`;
3931
4149
  });
3932
4150
  var truncateBoundedLine = (line, width) => {
3933
- const truncated = truncateToWidth2(line, width, "");
4151
+ const truncated = truncateToWidth3(line, width, "");
3934
4152
  if (!truncated.endsWith(FULL_SGR_RESET)) return truncated;
3935
4153
  return truncated.slice(0, -FULL_SGR_RESET.length) + TEXT_SGR_RESET;
3936
4154
  };
@@ -3958,7 +4176,7 @@ var BoundedLineList = class _BoundedLineList {
3958
4176
  const continuationIndent = width > 2 ? " " : "";
3959
4177
  const wrapped = wrapTextWithAnsi(
3960
4178
  line,
3961
- Math.max(1, width - visibleWidth2(continuationIndent))
4179
+ Math.max(1, width - visibleWidth3(continuationIndent))
3962
4180
  );
3963
4181
  renderedRows = wrapped.map(
3964
4182
  (row, index) => index === 0 ? row : continuationIndent + row
@@ -3968,15 +4186,15 @@ var BoundedLineList = class _BoundedLineList {
3968
4186
  continue;
3969
4187
  }
3970
4188
  const pipe = line.indexOf("\u2502 ");
3971
- const continuationPrefix = pipe < 0 ? "" : " ".repeat(visibleWidth2(line.slice(0, pipe + 2)));
4189
+ const continuationPrefix = pipe < 0 ? "" : " ".repeat(visibleWidth3(line.slice(0, pipe + 2)));
3972
4190
  const wrappedRows = wrapDiffAnsiToWidth(
3973
4191
  line,
3974
4192
  width,
3975
4193
  DIFF_WRAP_ROWS,
3976
- visibleWidth2(continuationPrefix) < width ? continuationPrefix : ""
4194
+ visibleWidth3(continuationPrefix) < width ? continuationPrefix : ""
3977
4195
  );
3978
4196
  for (const row of wrappedRows) {
3979
- const padding = " ".repeat(Math.max(0, width - visibleWidth2(row)));
4197
+ const padding = " ".repeat(Math.max(0, width - visibleWidth3(row)));
3980
4198
  rows.push(applyDiffBackground(row + padding, diffBackground(kind)));
3981
4199
  }
3982
4200
  }
@@ -4790,226 +5008,6 @@ function modelReadHint(audits, output, theme) {
4790
5008
  return theme.fg("warning", "\u2192 " + modelLines + " of " + readLines + " lines to model");
4791
5009
  }
4792
5010
 
4793
- // src/ui/structured.ts
4794
- import { stringify } from "yaml";
4795
- var normalizeJsonValue = (value) => {
4796
- try {
4797
- const serialized = JSON.stringify(value);
4798
- return serialized === void 0 ? void 0 : JSON.parse(serialized);
4799
- } catch {
4800
- return void 0;
4801
- }
4802
- };
4803
- var formatJsonAsYaml = (value) => {
4804
- const normalized = normalizeJsonValue(value);
4805
- if (normalized === void 0) return void 0;
4806
- return stringify(normalized, { indent: 2, lineWidth: 0 }).trimEnd();
4807
- };
4808
- var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
4809
- var hoistMultilineStrings = (value, path, sections, seen) => {
4810
- if (typeof value === "string") {
4811
- if (!value.includes("\n")) return value;
4812
- sections.push({ path, text: value });
4813
- return `<multi-line string, see section: ${path}>`;
4814
- }
4815
- if (Array.isArray(value)) {
4816
- if (seen.has(value)) return "[circular reference]";
4817
- seen.add(value);
4818
- const skeleton = value.map(
4819
- (item, index) => hoistMultilineStrings(item, `${path}[${index}]`, sections, seen)
4820
- );
4821
- seen.delete(value);
4822
- return skeleton;
4823
- }
4824
- if (isPlainObject(value)) {
4825
- if (seen.has(value)) return "[circular reference]";
4826
- seen.add(value);
4827
- const skeleton = {};
4828
- for (const [key, item] of Object.entries(value)) {
4829
- skeleton[key] = hoistMultilineStrings(
4830
- item,
4831
- path ? `${path}.${key}` : key,
4832
- sections,
4833
- seen
4834
- );
4835
- }
4836
- seen.delete(value);
4837
- return skeleton;
4838
- }
4839
- return value;
4840
- };
4841
- var boundedSection = (value, maxChars) => {
4842
- if (value.length <= maxChars) return value;
4843
- if (maxChars <= 0) return "";
4844
- let omitted = value.length - maxChars;
4845
- let marker = `\u2026[${omitted} chars omitted]\u2026`;
4846
- for (let pass = 0; pass < 2; pass++) {
4847
- omitted = value.length - Math.max(0, maxChars - marker.length);
4848
- marker = `\u2026[${omitted} chars omitted]\u2026`;
4849
- }
4850
- if (marker.length >= maxChars) return marker.slice(0, maxChars);
4851
- const available = maxChars - marker.length;
4852
- const head = Math.ceil(available / 2);
4853
- const tail = Math.floor(available / 2);
4854
- return `${value.slice(0, head)}${marker}${value.slice(value.length - tail)}`;
4855
- };
4856
- var fairSectionBudgets = (lengths, budget) => {
4857
- const budgets = Array.from({ length: lengths.length }, () => 0);
4858
- const pending = lengths.map((length, index) => ({ length, index })).sort((left, right) => left.length - right.length);
4859
- let remaining = Math.max(0, budget);
4860
- for (let position = 0; position < pending.length; position++) {
4861
- const item = pending[position];
4862
- const share = Math.floor(remaining / (pending.length - position));
4863
- const allocated = Math.min(item.length, share);
4864
- budgets[item.index] = allocated;
4865
- remaining -= allocated;
4866
- }
4867
- return budgets;
4868
- };
4869
- var renderHoistedSections = (yaml, sections, maxChars) => {
4870
- const headers = sections.map((section) => `--- ${section.path} (${section.text.length} chars) ---
4871
- `);
4872
- const separators = sections.length * 2;
4873
- const fixedChars = yaml.length + separators + headers.reduce((sum, header) => sum + header.length, 0);
4874
- const fullChars = fixedChars + sections.reduce((sum, section) => sum + section.text.length, 0);
4875
- const budgets = maxChars !== void 0 && fullChars > maxChars ? fairSectionBudgets(sections.map((section) => section.text.length), maxChars - fixedChars) : sections.map((section) => section.text.length);
4876
- const raw = sections.map((section, index) => `${headers[index]}${boundedSection(section.text, budgets[index])}`).join("\n\n");
4877
- return `${yaml}
4878
-
4879
- ${raw}`;
4880
- };
4881
- var formatFabricValue = (value, format, maxChars) => {
4882
- if (value === void 0) return { text: "" };
4883
- if (format === "text" && typeof value === "object" && value !== null && "text" in value) {
4884
- const text = value.text;
4885
- if (typeof text === "string") return { text };
4886
- }
4887
- if (typeof value === "string") return { text: value };
4888
- if (format === "auto" || format === "yaml") {
4889
- const sections = [];
4890
- const skeleton = hoistMultilineStrings(value, "", sections, /* @__PURE__ */ new Set());
4891
- const yaml = formatJsonAsYaml(skeleton);
4892
- if (yaml !== void 0) {
4893
- if (sections.length === 0) return { text: yaml, language: "yaml" };
4894
- return {
4895
- text: renderHoistedSections(yaml, sections, maxChars),
4896
- language: "yaml",
4897
- highlightedLineCount: countNewlines(yaml) + 1
4898
- };
4899
- }
4900
- }
4901
- try {
4902
- return {
4903
- text: JSON.stringify(value, null, format === "json" ? 2 : 0),
4904
- ...format === "json" ? { language: "json" } : {}
4905
- };
4906
- } catch {
4907
- return { text: String(value) };
4908
- }
4909
- };
4910
-
4911
- // src/ui/format.ts
4912
- import { truncateToWidth as truncateToWidth3, visibleWidth as visibleWidth3 } from "@earendil-works/pi-tui";
4913
- var safeText = (value) => String(value ?? "").replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g, " ").replace(/[\r\n\t]+/g, " ").replace(/\s+/g, " ").trim();
4914
- var formatActorDataPreview = (data, maxChars = 200) => {
4915
- if (data === void 0) return void 0;
4916
- const clip = (value) => {
4917
- const safe = safeText(value);
4918
- return safe.length > maxChars ? `${safe.slice(0, Math.max(1, maxChars - 1))}\u2026` : safe;
4919
- };
4920
- if (typeof data === "string") return clip(data);
4921
- if (typeof data === "object" && data !== null && !Array.isArray(data) && data.fabricTruncated === true) {
4922
- const wrapper = data;
4923
- const preview = clip(String(wrapper.preview ?? ""));
4924
- const suffix = typeof wrapper.originalBytes === "number" ? `[truncated from ${wrapper.originalBytes} bytes]` : "[truncated]";
4925
- return preview ? `${preview} ${suffix}` : suffix;
4926
- }
4927
- let serialized;
4928
- try {
4929
- serialized = JSON.stringify(data) ?? String(data);
4930
- } catch {
4931
- serialized = String(data);
4932
- }
4933
- return clip(serialized);
4934
- };
4935
- var formatDuration = (milliseconds) => {
4936
- const seconds = Math.max(0, Math.floor(milliseconds / 1e3));
4937
- if (seconds < 60) return `${seconds}s`;
4938
- const minutes = Math.floor(seconds / 60);
4939
- if (minutes < 60) return `${minutes}m${String(seconds % 60).padStart(2, "0")}s`;
4940
- const hours = Math.floor(minutes / 60);
4941
- return `${hours}h${String(minutes % 60).padStart(2, "0")}m`;
4942
- };
4943
- var formatTokens = (tokens) => {
4944
- if (tokens < 1e3) return String(Math.max(0, Math.round(tokens)));
4945
- if (tokens < 1e5) return `${(tokens / 1e3).toFixed(tokens < 1e4 ? 1 : 0)}k`;
4946
- return `${(tokens / 1e3).toFixed(0)}k`;
4947
- };
4948
- var formatCost = (usd) => usd <= 0 ? "$0" : usd < 0.01 ? `$${usd.toFixed(4)}` : usd < 1 ? `$${usd.toFixed(3)}` : `$${usd.toFixed(2)}`;
4949
- var formatClock = (timestamp) => new Date(timestamp).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
4950
- var padToWidth = (value, width) => {
4951
- const clipped = truncateToWidth3(value, Math.max(0, width), "");
4952
- return clipped + " ".repeat(Math.max(0, width - visibleWidth3(clipped)));
4953
- };
4954
- var wrapPlainText = (value, width, maxLines = 100) => {
4955
- const safe = safeText(value);
4956
- if (!safe || width <= 0 || maxLines <= 0) return [];
4957
- const words = safe.split(" ");
4958
- const lines = [];
4959
- let current = "";
4960
- for (const word of words) {
4961
- const candidate = current ? `${current} ${word}` : word;
4962
- if (visibleWidth3(candidate) <= width) {
4963
- current = candidate;
4964
- continue;
4965
- }
4966
- if (current) lines.push(truncateToWidth3(current, width));
4967
- current = word;
4968
- while (visibleWidth3(current) > width && lines.length < maxLines) {
4969
- let chunk = "";
4970
- let consumed = 0;
4971
- const segments = [
4972
- ...new Intl.Segmenter(void 0, { granularity: "grapheme" }).segment(current)
4973
- ];
4974
- for (const { segment } of segments) {
4975
- const candidate2 = chunk + segment;
4976
- if (visibleWidth3(candidate2) > width) {
4977
- if (!chunk) {
4978
- chunk = "\u2026";
4979
- consumed += segment.length;
4980
- }
4981
- break;
4982
- }
4983
- chunk = candidate2;
4984
- consumed += segment.length;
4985
- }
4986
- if (chunk) lines.push(chunk);
4987
- current = current.slice(consumed);
4988
- }
4989
- if (lines.length >= maxLines) break;
4990
- }
4991
- if (current && lines.length < maxLines) lines.push(truncateToWidth3(current, width));
4992
- return lines;
4993
- };
4994
-
4995
- // src/ui/types.ts
4996
- var activeStatuses = /* @__PURE__ */ new Set([
4997
- "queued",
4998
- "pending",
4999
- "ready",
5000
- "claimed",
5001
- "running",
5002
- "in_progress",
5003
- "blocked",
5004
- "loading",
5005
- "active",
5006
- "unloading"
5007
- ]);
5008
- var isActiveStatus = (status) => activeStatuses.has(status);
5009
- var orderAgentsByCreation = (agents) => agents.map((agent, index) => ({ agent, index })).sort(
5010
- (left, right) => (left.agent.startedAt ?? Number.MAX_SAFE_INTEGER) - (right.agent.startedAt ?? Number.MAX_SAFE_INTEGER) || left.index - right.index
5011
- ).map(({ agent }) => agent);
5012
-
5013
5011
  // src/ui/spinner.ts
5014
5012
  var SPINNER_INTERVAL_MS = 250;
5015
5013
  var SPINNER_FRAMES = ["\u25D0", "\u25D3", "\u25D1", "\u25D2"];
@@ -5085,4 +5083,4 @@ export {
5085
5083
  isActiveStatus,
5086
5084
  orderAgentsByCreation
5087
5085
  };
5088
- //# sourceMappingURL=chunk-CK3R6JWV.js.map
5086
+ //# sourceMappingURL=chunk-5A7D37T5.js.map