@quandev104/pi-style 0.2.7 → 0.2.10

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 (25) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +2 -2
  3. package/dist/extensions/pi-style.js +8900 -8464
  4. package/dist/extensions/pi-style.js.map +1 -1
  5. package/extension-src/pi-style/app/command-service.ts +2 -0
  6. package/extension-src/pi-style/domain/config-normalization.ts +3 -0
  7. package/extension-src/pi-style/domain/config-types.ts +8 -0
  8. package/extension-src/pi-style/features/messages/index.ts +451 -37
  9. package/extension-src/pi-style/features/messages/special-blocks.ts +2 -22
  10. package/extension-src/pi-style/features/startup/index.ts +24 -4
  11. package/extension-src/pi-style/features/startup/logo.ts +22 -18
  12. package/extension-src/pi-style/features/tools/bash-execution.ts +24 -8
  13. package/extension-src/pi-style/features/tools/boxed/edit.ts +25 -30
  14. package/extension-src/pi-style/features/tools/boxed/git.ts +21 -13
  15. package/extension-src/pi-style/features/tools/boxed/quick-edit.ts +35 -38
  16. package/extension-src/pi-style/features/tools/boxed/shared.ts +34 -0
  17. package/extension-src/pi-style/features/tools/boxed/turn-summary.ts +114 -38
  18. package/extension-src/pi-style/features/tools/boxed/write.ts +1 -0
  19. package/extension-src/pi-style/features/tools/index.ts +10 -6
  20. package/extension-src/pi-style/pi/compatibility-coordinator.ts +2 -0
  21. package/extension-src/pi-style/pi/compatibility-probe.ts +88 -19
  22. package/extension-src/pi-style/pi/session-coordinator.ts +20 -1
  23. package/extension-src/pi-style/shared/ansi.ts +45 -0
  24. package/extension-src/pi-style/shared/box.ts +126 -47
  25. package/package.json +10 -9
@@ -2,11 +2,13 @@
2
2
  //
3
3
  // Two deliberate design points:
4
4
  //
5
- // 1. Background painting is removed. Boxed lines are foreground-only; the
6
- // enclosing native ToolExecutionComponent container applies the semantic
7
- // status background (toolPendingBg / toolErrorBg / toolSuccessBg), and the
8
- // message-block Box applies customMessageBg. This avoids double-background
9
- // conflicts and keeps pi-style's patches renderer-scoped.
5
+ // 1. A rendered box owns its background: boxed surfaces wrap every line in
6
+ // the semantic status fill (toolPendingBg / toolErrorBg / toolSuccessBg,
7
+ // or customMessageBg for message blocks), while boxless surfaces (quiet
8
+ // tool rows/tree panels, git/gh semantic cards, turn summaries) stay
9
+ // transparent. The native container fill is always neutralized so the
10
+ // tint always comes from the component that draws the frame — one tool
11
+ // can mix both (git: boxless card + boxed diff frames).
10
12
  //
11
13
  // 2. Theme functions are accessed through a minimal structural interface
12
14
  // (BoxTheme) instead of `any`.
@@ -30,12 +32,31 @@ import { getThemeExtra } from "./theme-extras.js";
30
32
  /** Minimal structural view of Pi's Theme as used by the boxed renderers. */
31
33
  export interface BoxTheme {
32
34
  fg(color: string, text: string): string;
35
+ bg?(color: string, text: string): string;
33
36
  bold?(text: string): string;
34
37
  italic?(text: string): string;
35
38
  inverse?(text: string): string;
36
39
  getColorMode?(): string;
37
40
  }
38
41
 
42
+ /** Semantic status background name for a tool surface (mirrors Pi's native
43
+ * container fill selection). */
44
+ export function boxedToolBgName(isError?: boolean, isPartial?: boolean): string {
45
+ return isPartial ? "toolPendingBg" : isError ? "toolErrorBg" : "toolSuccessBg";
46
+ }
47
+
48
+ /** Wrap every line in the status background fill. Best-effort: themes
49
+ * without a bg() (or without the token) keep their lines untouched, and an
50
+ * empty theme color resolves to a no-op reset escape. */
51
+ export function applyBgTint(theme: BoxTheme, bgName: string, lines: string[]): string[] {
52
+ if (typeof theme.bg !== "function") return lines;
53
+ try {
54
+ return lines.map((line) => theme.bg?.(bgName, line) ?? line);
55
+ } catch {
56
+ return lines;
57
+ }
58
+ }
59
+
39
60
  const THEME_CACHE_KEYS = new WeakMap<object, number>();
40
61
  let nextThemeCacheKey = 1;
41
62
 
@@ -49,8 +70,11 @@ export function themeCacheKey(theme: object): number {
49
70
 
50
71
  export interface BoxedRenderOptions {
51
72
  widthKey?: string;
52
- /** Detail embedded in the top-border title after the tool name (e.g. the path). */
53
- headerDetail?: string;
73
+ /** Detail embedded in the top-border title after the tool name (e.g. the
74
+ * path). A function form is resolved lazily at render time so the header can
75
+ * pick up state a result renderer published in the same updateDisplay pass
76
+ * (e.g. diff stats: `path · +3 -0`). */
77
+ headerDetail?: string | (() => string);
54
78
  isError?: boolean;
55
79
  isPartial?: boolean;
56
80
  isPending?: boolean;
@@ -74,6 +98,10 @@ export interface BoxedRenderOptions {
74
98
  /** Right-side label embedded in the compact box bottom border before the
75
99
  * corner (e.g. an expand hint such as `Ctrl+O for more`). */
76
100
  bottomRightLabel?: string;
101
+ /** Tint the compact box with the semantic status background. Only framed
102
+ * compact surfaces (e.g. the write preview box) opt in — boxless compact
103
+ * surfaces (quiet-tool rows, tree panels) stay transparent. */
104
+ tint?: boolean;
77
105
  }
78
106
 
79
107
  export function isExpanded(options: { expanded?: boolean } | undefined): boolean {
@@ -461,15 +489,13 @@ export function dimLine(text: string): string {
461
489
  return `\x1b[2m${text}\x1b[22m`;
462
490
  }
463
491
 
464
- function boxText(_theme: BoxTheme, text: string): string {
465
- return dimLine(text);
492
+ /** Frame chrome (borders, side bars, dividers). Dim by default; error boxes
493
+ * pass a theme color name so the whole frame reads as failed at a glance. */
494
+ function boxText(_theme: BoxTheme, text: string, color?: string): string {
495
+ return color ? _theme.fg(color, text) : dimLine(text);
466
496
  }
467
- function boxFrameText(_theme: BoxTheme, text: string): string {
468
- return dimLine(text);
469
- }
470
-
471
- export function boxedToolBgName(isError?: boolean, isPartial?: boolean): string {
472
- return isPartial ? "toolPendingBg" : isError ? "toolErrorBg" : "toolSuccessBg";
497
+ function boxFrameText(_theme: BoxTheme, text: string, color?: string): string {
498
+ return color ? _theme.fg(color, text) : dimLine(text);
473
499
  }
474
500
 
475
501
  export function boxBorder(theme: BoxTheme, left: string, right: string, width: number): string {
@@ -493,6 +519,7 @@ export function boxLabeledBorder(
493
519
  leftLabel: string,
494
520
  rightLabel: string | undefined,
495
521
  width: number,
522
+ frameColor?: string,
496
523
  ): string {
497
524
  const renderedWidth = boxWidth(width);
498
525
  let left = leftLabel ?? "";
@@ -532,22 +559,26 @@ export function boxLabeledBorder(
532
559
  // applying the border color to the whole line in one wrap would leave every
533
560
  // dash after a label in the default color, making one border render with
534
561
  // mixed brightness.
535
- const parts: string[] = [boxFrameText(theme, `${start}${left ? "─ " : ""}`)];
562
+ const parts: string[] = [boxFrameText(theme, `${start}${left ? "─ " : ""}`, frameColor)];
536
563
  if (left) parts.push(left);
537
- parts.push(boxFrameText(theme, `${left ? " " : ""}${BOX_HORIZONTAL.repeat(Math.max(0, fill))}`));
564
+ parts.push(boxFrameText(theme, `${left ? " " : ""}${BOX_HORIZONTAL.repeat(Math.max(0, fill))}`, frameColor));
538
565
  if (right) {
539
- parts.push(boxFrameText(theme, " "), right, boxFrameText(theme, ` ${BOX_HORIZONTAL.repeat(rightFill)}`));
566
+ parts.push(
567
+ boxFrameText(theme, " ", frameColor),
568
+ right,
569
+ boxFrameText(theme, ` ${BOX_HORIZONTAL.repeat(rightFill)}`, frameColor),
570
+ );
540
571
  }
541
- parts.push(boxFrameText(theme, end));
572
+ parts.push(boxFrameText(theme, end, frameColor));
542
573
  return parts.join("");
543
574
  }
544
575
 
545
576
  /** Empty content line used for breathing room inside a box. */
546
- export function boxBlankLine(theme: BoxTheme, width: number): string {
577
+ export function boxBlankLine(theme: BoxTheme, width: number, frameColor?: string): string {
547
578
  const renderedWidth = boxWidth(width);
548
579
  const contentWidth = boxInnerWidth(renderedWidth);
549
580
  const sidePad = " ".repeat(BOX_SIDE_PADDING);
550
- return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${" ".repeat(contentWidth)}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
581
+ return `${boxFrameText(theme, BOX_VERTICAL, frameColor)}${sidePad}${" ".repeat(contentWidth)}${sidePad}${boxFrameText(theme, BOX_VERTICAL, frameColor)}`;
551
582
  }
552
583
 
553
584
  export function boxLineAligned(theme: BoxTheme, left: string, right: string, width: number): string {
@@ -584,19 +615,19 @@ export function boxLineWithRight(theme: BoxTheme, left: string, right: string, w
584
615
  return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${truncatedLeft}${gap}${divider}${right}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
585
616
  }
586
617
 
587
- export function boxLine(theme: BoxTheme, content: string, width: number): string {
618
+ export function boxLine(theme: BoxTheme, content: string, width: number, frameColor?: string): string {
588
619
  const renderedWidth = boxWidth(width);
589
620
  const contentWidth = boxInnerWidth(renderedWidth);
590
621
  const fastContent = fastBoxLineContent(content, contentWidth);
591
622
  const sidePad = " ".repeat(BOX_SIDE_PADDING);
592
623
  if (fastContent) {
593
624
  const fill = " ".repeat(Math.max(0, contentWidth - fastContent.visibleWidth));
594
- return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${fastContent.text}${fill}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
625
+ return `${boxFrameText(theme, BOX_VERTICAL, frameColor)}${sidePad}${fastContent.text}${fill}${sidePad}${boxFrameText(theme, BOX_VERTICAL, frameColor)}`;
595
626
  }
596
627
 
597
628
  const truncated = safeTruncateToWidth(content, contentWidth, "…");
598
629
  const fill = " ".repeat(Math.max(0, contentWidth - safeVisibleWidth(truncated)));
599
- return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${truncated}${fill}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
630
+ return `${boxFrameText(theme, BOX_VERTICAL, frameColor)}${sidePad}${truncated}${fill}${sidePad}${boxFrameText(theme, BOX_VERTICAL, frameColor)}`;
600
631
  }
601
632
 
602
633
  export function boxInsetDivider(theme: BoxTheme, width: number): string {
@@ -606,12 +637,12 @@ export function boxInsetDivider(theme: BoxTheme, width: number): string {
606
637
  return `${boxFrameText(theme, BOX_VERTICAL)}${sidePad}${boxText(theme, BOX_HORIZONTAL.repeat(lineWidth))}${sidePad}${boxFrameText(theme, BOX_VERTICAL)}`;
607
638
  }
608
639
 
609
- export function boxedWrappedLines(theme: BoxTheme, content: string, width: number): string[] {
610
- return safeWrapTextWithAnsi(content, boxInnerWidth(width)).map((line) => boxLine(theme, line, width));
640
+ export function boxedWrappedLines(theme: BoxTheme, content: string, width: number, frameColor?: string): string[] {
641
+ return safeWrapTextWithAnsi(content, boxInnerWidth(width)).map((line) => boxLine(theme, line, width, frameColor));
611
642
  }
612
643
 
613
- function boxedTruncatedLine(theme: BoxTheme, content: string, width: number): string {
614
- return boxLine(theme, safeTruncateToWidth(content, boxInnerWidth(width), "…"), width);
644
+ function boxedTruncatedLine(theme: BoxTheme, content: string, width: number, frameColor?: string): string {
645
+ return boxLine(theme, safeTruncateToWidth(content, boxInnerWidth(width), "…"), width, frameColor);
615
646
  }
616
647
 
617
648
  type RenderLinesCache = {
@@ -635,6 +666,7 @@ function renderBoxedOutputLines(
635
666
  outputLines: string[],
636
667
  width: number,
637
668
  rawLineBudget = DEFAULT_COLLAPSED_RENDER_LINES,
669
+ frameColor?: string,
638
670
  ): string[] {
639
671
  const budget = boxedResultRenderBudget(rawLineBudget);
640
672
  const headLimit = Math.max(0, Math.min(budget.headLines, budget.maxRenderedLines));
@@ -651,7 +683,7 @@ function renderBoxedOutputLines(
651
683
  const fragments = (outputLines[nextInputIndex] ?? "").split("\n");
652
684
  let headExceeded = false;
653
685
  for (const fragment of fragments) {
654
- const line = boxedTruncatedLine(theme, fragment, width);
686
+ const line = boxedTruncatedLine(theme, fragment, width, frameColor);
655
687
  if (!pushBoundedLines(head, [line], headLimit)) {
656
688
  headExceeded = true;
657
689
  break;
@@ -671,7 +703,7 @@ function renderBoxedOutputLines(
671
703
  for (let i = tailStart; i < outputLines.length; i++) {
672
704
  const fragments = (outputLines[i] ?? "").split("\n");
673
705
  for (const fragment of fragments) {
674
- const line = boxedTruncatedLine(theme, fragment, width);
706
+ const line = boxedTruncatedLine(theme, fragment, width, frameColor);
675
707
  tail.push(line);
676
708
  if (tail.length > tailLimit) tail.splice(0, tail.length - tailLimit);
677
709
  }
@@ -682,7 +714,7 @@ function renderBoxedOutputLines(
682
714
  skippedInputLines > 0
683
715
  ? `… rendered output truncated; ${skippedInputLines} input lines skipped before tail`
684
716
  : "… rendered output truncated";
685
- return [...head, boxLine(theme, theme.fg("muted", skippedText), width), ...tail];
717
+ return [...head, boxLine(theme, theme.fg("muted", skippedText), width, frameColor), ...tail];
686
718
  }
687
719
 
688
720
  export function renderBoxedToolCall(
@@ -704,12 +736,23 @@ export function renderBoxedToolCall(
704
736
  options.isError,
705
737
  options.isPending ? (options.running ? "running" : "pending") : undefined,
706
738
  );
707
- const headerLabel = options.headerDetail ? `${title} · ${options.headerDetail}` : title;
739
+ const headerDetail = typeof options.headerDetail === "function" ? options.headerDetail() : options.headerDetail;
740
+ const headerLabel = headerDetail ? `${title} · ${headerDetail}` : title;
708
741
  const renderedWidth = boxWidth(width);
742
+ // A failed call renders its whole frame in the error color.
743
+ const frameColor = options.isError ? "error" : undefined;
709
744
  const lines = [
710
- boxLabeledBorder(theme, BOX_ROUND_TOP_LEFT, BOX_ROUND_TOP_RIGHT, headerLabel, undefined, renderedWidth),
711
- boxBlankLine(theme, renderedWidth),
712
- ...detailLines.flatMap((line) => boxedWrappedLines(theme, line, renderedWidth)),
745
+ boxLabeledBorder(
746
+ theme,
747
+ BOX_ROUND_TOP_LEFT,
748
+ BOX_ROUND_TOP_RIGHT,
749
+ headerLabel,
750
+ undefined,
751
+ renderedWidth,
752
+ frameColor,
753
+ ),
754
+ boxBlankLine(theme, renderedWidth, frameColor),
755
+ ...detailLines.flatMap((line) => boxedWrappedLines(theme, line, renderedWidth, frameColor)),
713
756
  ];
714
757
  if (options.isPending && !options.resultSeen) {
715
758
  // Pending/running card: close the box with the status label. Once a
@@ -718,7 +761,7 @@ export function renderBoxedToolCall(
718
761
  const pendingLabel =
719
762
  options.pendingLabel ?? theme.fg("dim", `… ${options.pendingText ?? "Waiting for output…"}`);
720
763
  lines.push(
721
- boxBlankLine(theme, renderedWidth),
764
+ boxBlankLine(theme, renderedWidth, frameColor),
722
765
  boxLabeledBorder(
723
766
  theme,
724
767
  BOX_ROUND_BOTTOM_LEFT,
@@ -726,15 +769,19 @@ export function renderBoxedToolCall(
726
769
  pendingLabel,
727
770
  undefined,
728
771
  renderedWidth,
772
+ frameColor,
729
773
  ),
730
774
  );
731
775
  } else {
732
776
  // Leave the box open with trailing breathing room; the result renderer
733
777
  // continues it with the result divider.
734
- lines.push(boxBlankLine(theme, renderedWidth));
778
+ lines.push(boxBlankLine(theme, renderedWidth, frameColor));
735
779
  }
736
- cache = { width, lines };
737
- return lines;
780
+ // A rendered call box owns its status tint (the container fill is
781
+ // neutralized — see tighten/neutralize in features/tools).
782
+ const tinted = applyBgTint(theme, boxedToolBgName(options.isError, options.isPartial), lines);
783
+ cache = { width, lines: tinted };
784
+ return tinted;
738
785
  },
739
786
  };
740
787
  }
@@ -772,11 +819,20 @@ export function renderCompactBoxedToolCall(
772
819
  const _footerIsError = Boolean(options.state?.[COMPACT_FOOTER_ERROR_KEY]);
773
820
  const _footerIsPartial = Boolean(options.state?.[COMPACT_FOOTER_PARTIAL_KEY]);
774
821
  const bodyLines = options.bodyLines ? options.bodyLines(boxInnerWidth(renderedWidth)) : [];
822
+ const frameColor = options.isError ? "error" : undefined;
775
823
  const lines = [
776
- boxLabeledBorder(theme, BOX_ROUND_TOP_LEFT, BOX_ROUND_TOP_RIGHT, headerLabel, undefined, renderedWidth),
824
+ boxLabeledBorder(
825
+ theme,
826
+ BOX_ROUND_TOP_LEFT,
827
+ BOX_ROUND_TOP_RIGHT,
828
+ headerLabel,
829
+ undefined,
830
+ renderedWidth,
831
+ frameColor,
832
+ ),
777
833
  ...(bodyLines.length > 0
778
- ? bodyLines.map((line) => boxLine(theme, line, renderedWidth))
779
- : [boxBlankLine(theme, renderedWidth)]),
834
+ ? bodyLines.map((line) => boxLine(theme, line, renderedWidth, frameColor))
835
+ : [boxBlankLine(theme, renderedWidth, frameColor)]),
780
836
  ];
781
837
  if (compactFooter) {
782
838
  lines.push(
@@ -787,6 +843,7 @@ export function renderCompactBoxedToolCall(
787
843
  compactFooter,
788
844
  options.bottomRightLabel,
789
845
  renderedWidth,
846
+ frameColor,
790
847
  ),
791
848
  );
792
849
  } else if (options.isPending) {
@@ -803,13 +860,17 @@ export function renderCompactBoxedToolCall(
803
860
  pendingLabel,
804
861
  options.bottomRightLabel,
805
862
  renderedWidth,
863
+ frameColor,
806
864
  ),
807
865
  );
808
866
  } else {
809
867
  // No footer yet (transient, or the result opens the result divider):
810
868
  // leave the box open so the result renderer continues the same box.
811
869
  }
812
- return lines;
870
+ // Compact boxes tint only when the surface is a real framed box (e.g.
871
+ // the write preview) — boxless compact surfaces (quiet-tool rows,
872
+ // tree panels) stay transparent.
873
+ return options.tint ? applyBgTint(theme, boxedToolBgName(options.isError, options.isPartial), lines) : lines;
813
874
  },
814
875
  };
815
876
  }
@@ -830,6 +891,10 @@ export function renderBoxedToolResult(
830
891
  dividerLabel?: string | ((width: number) => string);
831
892
  /** Right-side label embedded in the divider between the call and the result. */
832
893
  dividerRightLabel?: string;
894
+ /** Skip the blank line between the divider (or box top) and the body — used
895
+ * when the enclosing call box already left breathing room, e.g. the
896
+ * divider-less diff results whose stats live in the box header. */
897
+ skipLeadingBlank?: boolean;
833
898
  /** Right-side label embedded in the bottom border (e.g. the expand hint). */
834
899
  expandHint?: string;
835
900
  isError?: boolean;
@@ -838,6 +903,10 @@ export function renderBoxedToolResult(
838
903
  showDivider?: boolean;
839
904
  /** Error state marker prepended to the body (default `✗ Error`). */
840
905
  errorLabel?: string;
906
+ /** Tint the result box with the semantic status background. Default on —
907
+ * every current caller draws a framed box; pass false for a boxless
908
+ * continuation. */
909
+ tint?: boolean;
841
910
  } = {},
842
911
  ): Component {
843
912
  let cache: RenderLinesCache | null = null;
@@ -861,6 +930,8 @@ export function renderBoxedToolResult(
861
930
  // rows instead of one "line" whose embedded rows break the frame.
862
931
  const outputFragments = outputLines.flatMap((line) => line.split("\n"));
863
932
  const footerText = (options.footerLines ?? []).join(" · ");
933
+ // A failed result renders its whole frame in the error color.
934
+ const frameColor = options.isError ? "error" : undefined;
864
935
  const dividerText =
865
936
  typeof options.dividerLabel === "function"
866
937
  ? options.dividerLabel(renderedWidth)
@@ -876,16 +947,18 @@ export function renderBoxedToolResult(
876
947
  theme.fg("dim", dividerText),
877
948
  options.dividerRightLabel ? theme.fg("dim", options.dividerRightLabel) : undefined,
878
949
  renderedWidth,
950
+ frameColor,
879
951
  ),
880
952
  ]),
881
- boxBlankLine(theme, renderedWidth),
953
+ ...(options.skipLeadingBlank ? [] : [boxBlankLine(theme, renderedWidth, frameColor)]),
882
954
  ...renderBoxedOutputLines(
883
955
  theme,
884
956
  outputFragments,
885
957
  renderedWidth,
886
958
  options.renderLineBudget ?? outputFragments.length,
959
+ frameColor,
887
960
  ),
888
- boxBlankLine(theme, renderedWidth),
961
+ boxBlankLine(theme, renderedWidth, frameColor),
889
962
  boxLabeledBorder(
890
963
  theme,
891
964
  BOX_ROUND_BOTTOM_LEFT,
@@ -893,10 +966,16 @@ export function renderBoxedToolResult(
893
966
  footerText,
894
967
  options.expandHint ? theme.fg("dim", options.expandHint) : undefined,
895
968
  renderedWidth,
969
+ frameColor,
896
970
  ),
897
971
  ];
898
- cache = { width, lines: rendered };
899
- return rendered;
972
+ // The result box owns its status tint (the container fill is neutralized).
973
+ const tinted =
974
+ options.tint === false
975
+ ? rendered
976
+ : applyBgTint(theme, boxedToolBgName(options.isError, options.isPartial), rendered);
977
+ cache = { width, lines: tinted };
978
+ return tinted;
900
979
  },
901
980
  };
902
981
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quandev104/pi-style",
3
- "version": "0.2.7",
3
+ "version": "0.2.10",
4
4
  "description": "A native-layout, cohesive visual style package for Pi.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -42,18 +42,19 @@
42
42
  "check": "npm run typecheck && npm run lint && npm run depcruise && npm run test && npm run build && npm run package:smoke"
43
43
  },
44
44
  "peerDependencies": {
45
- "@earendil-works/pi-agent-core": ">=0.83.0 <0.85.0",
46
- "@earendil-works/pi-ai": ">=0.83.0 <0.85.0",
47
- "@earendil-works/pi-coding-agent": ">=0.83.0 <0.85.0",
48
- "@earendil-works/pi-tui": ">=0.83.0 <0.85.0",
45
+ "@earendil-works/pi-agent-core": ">=0.83.0 <0.86.0",
46
+ "@earendil-works/pi-ai": ">=0.83.0 <0.86.0",
47
+ "@earendil-works/pi-coding-agent": ">=0.83.0 <0.86.0",
48
+ "@earendil-works/pi-tui": ">=0.83.0 <0.86.0",
49
49
  "typebox": ">=1.3.9 <2.0.0"
50
50
  },
51
51
  "devDependencies": {
52
52
  "@biomejs/biome": "^2.5.0",
53
- "@earendil-works/pi-agent-core": "^0.84.0",
54
- "@earendil-works/pi-ai": "^0.84.0",
55
- "@earendil-works/pi-coding-agent": "^0.84.0",
56
- "@earendil-works/pi-tui": "^0.84.0",
53
+ "@earendil-works/pi-agent-core": "^0.85.0",
54
+ "@earendil-works/pi-ai": "^0.85.0",
55
+ "@earendil-works/pi-coding-agent": "^0.85.0",
56
+ "@earendil-works/pi-server": "^0.85.0",
57
+ "@earendil-works/pi-tui": "^0.85.0",
57
58
  "@types/node": "^24.0.0",
58
59
  "dependency-cruiser": "^17.4.3",
59
60
  "git-cliff": "^2.13.1",