gentle-pi 2.5.0 → 2.6.0

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 (189) hide show
  1. package/README.md +139 -30
  2. package/assets/agents/gentle-ai-worker.md +4 -0
  3. package/assets/agents/jd-fix-agent.md +18 -0
  4. package/assets/agents/jd-judge-a.md +1 -1
  5. package/assets/agents/jd-judge-b.md +1 -1
  6. package/assets/agents/sdd-apply.md +7 -5
  7. package/assets/agents/sdd-archive.md +5 -3
  8. package/assets/agents/sdd-design.md +4 -0
  9. package/assets/agents/sdd-explore.md +4 -0
  10. package/assets/agents/sdd-init.md +4 -0
  11. package/assets/agents/sdd-onboard.md +4 -0
  12. package/assets/agents/sdd-proposal.md +4 -0
  13. package/assets/agents/sdd-remediate.md +37 -0
  14. package/assets/agents/sdd-research.md +26 -3
  15. package/assets/agents/sdd-spec.md +4 -0
  16. package/assets/agents/sdd-status.md +9 -75
  17. package/assets/agents/sdd-sync.md +4 -0
  18. package/assets/agents/sdd-tasks.md +4 -0
  19. package/assets/agents/sdd-verify.md +5 -3
  20. package/assets/chains/sdd-full.chain.md +4 -0
  21. package/assets/chains/sdd-plan.chain.md +4 -0
  22. package/assets/chains/sdd-verify.chain.md +4 -0
  23. package/assets/migrations/managed-assets-v2.5.0.json +7 -0
  24. package/assets/orchestrator-delegation.md +21 -3
  25. package/assets/sdd-orchestrator-workflow.md +54 -21
  26. package/assets/support/sdd-status-contract.md +34 -90
  27. package/contracts/telemetry/runtime-aggregate-v1.schema.json +65 -0
  28. package/docs/telemetry.md +57 -1
  29. package/docs/windows-startup-console-visibility.md +18 -0
  30. package/extensions/ask-user-choice.ts +143 -15
  31. package/extensions/codegraph-tools.ts +1 -0
  32. package/extensions/gentle-agents.ts +799 -50
  33. package/extensions/gentle-ai.ts +2033 -322
  34. package/extensions/gentle-shell.ts +145 -42
  35. package/extensions/gentle-todo.ts +47 -12
  36. package/extensions/quiet-tools.ts +1 -0
  37. package/extensions/runtime-metrics.ts +130 -0
  38. package/extensions/sdd-init.ts +2 -2
  39. package/extensions/startup-banner.ts +52 -75
  40. package/lib/agent-profiles.ts +550 -0
  41. package/lib/agents-completion-delivery.ts +72 -0
  42. package/lib/agents-config.ts +7 -10
  43. package/lib/agents-history.ts +9 -1
  44. package/lib/agents-messaging.ts +187 -0
  45. package/lib/agents-protocol.ts +77 -5
  46. package/lib/agents-runner.ts +548 -26
  47. package/lib/agents-thread-view.ts +57 -0
  48. package/lib/agents-view-layout.ts +40 -0
  49. package/lib/agents-view.ts +548 -191
  50. package/lib/agents-widget.ts +33 -14
  51. package/lib/gentle-ai-binary.ts +3 -1
  52. package/lib/gentle-ai-renderer.ts +8 -6
  53. package/lib/native-review-cli.ts +283 -1
  54. package/lib/orchestrator-presence.ts +337 -0
  55. package/lib/profiles-orchestrator.ts +203 -0
  56. package/lib/review-candidate-view-owner.ts +296 -46
  57. package/lib/review-candidate-view.ts +30 -20
  58. package/lib/review-consent-component.ts +247 -0
  59. package/lib/review-consent-ui.ts +53 -8
  60. package/lib/review-host-relay.ts +28 -0
  61. package/lib/review-integration-v2.ts +187 -5
  62. package/lib/review-last-event-controller.ts +7 -4
  63. package/lib/review-reminder-receipt.ts +74 -0
  64. package/lib/review-session-standing-permission.ts +27 -6
  65. package/lib/runtime-metrics-children.ts +199 -0
  66. package/lib/runtime-metrics-delivery.ts +68 -0
  67. package/lib/runtime-metrics-native.ts +166 -0
  68. package/lib/runtime-metrics-pi-identity.ts +113 -0
  69. package/lib/runtime-metrics-policy.ts +51 -0
  70. package/lib/runtime-metrics.ts +255 -0
  71. package/lib/sdd-preflight.ts +362 -81
  72. package/lib/sdd-research-capabilities.ts +228 -0
  73. package/lib/sdd-status.ts +29 -7
  74. package/lib/session-worktree-registry.ts +118 -0
  75. package/lib/shell-bar.ts +47 -1
  76. package/lib/shell-card.ts +1 -4
  77. package/lib/shell-changes-view.ts +362 -37
  78. package/lib/shell-changes.ts +81 -1
  79. package/lib/shell-prompt.ts +11 -15
  80. package/lib/shell-sidebar-banner.ts +11 -0
  81. package/lib/shell-sidebar-layout.ts +213 -0
  82. package/lib/shell-sidebar.ts +41 -0
  83. package/lib/shell-todo.ts +28 -11
  84. package/lib/telemetry-trigger.ts +2 -0
  85. package/package.json +6 -3
  86. package/runtime/gentle-ai-binary.mjs +3 -1
  87. package/runtime/native-review-cli.mjs +283 -1
  88. package/runtime/review-integration-v2.mjs +187 -5
  89. package/runtime/telemetry-trigger.mjs +2 -0
  90. package/scripts/build-runtime-modules.mjs +9 -1
  91. package/scripts/check-types.mjs +125 -0
  92. package/scripts/gentle-ai-installer.mjs +10 -10
  93. package/scripts/install-gentle-ai.mjs +12 -0
  94. package/scripts/install-tui-mode-setting.mjs +114 -0
  95. package/scripts/test-packed-runner.mjs +16 -2
  96. package/scripts/types-baseline.json +99 -0
  97. package/scripts/verify-package-files.mjs +4 -2
  98. package/skills/_shared/review-ledger-contract.md +17 -1
  99. package/skills/issue-creation/SKILL.md +3 -3
  100. package/skills/judgment-day/SKILL.md +17 -3
  101. package/skills/judgment-day/references/prompts-and-formats.md +14 -3
  102. package/tests/agent-profiles.test.ts +722 -0
  103. package/tests/agents-completion-delivery.test.ts +94 -0
  104. package/tests/agents-config.test.ts +62 -0
  105. package/tests/agents-fake-child.ts +15 -1
  106. package/tests/agents-grouping.test.ts +179 -0
  107. package/tests/agents-integration.test.ts +100 -0
  108. package/tests/agents-messaging.test.ts +94 -0
  109. package/tests/agents-protocol.test.ts +45 -0
  110. package/tests/agents-queries.test.ts +190 -0
  111. package/tests/agents-responsive.test.ts +43 -0
  112. package/tests/agents-runner.test.ts +571 -14
  113. package/tests/agents-thread-view.test.ts +45 -0
  114. package/tests/agents-view.test.ts +476 -65
  115. package/tests/agents-widget.test.ts +31 -1
  116. package/tests/artifact-language.test.ts +25 -2
  117. package/tests/ask-user-choice.test.ts +169 -3
  118. package/tests/asset-installation-runtime.test.ts +108 -0
  119. package/tests/autonomous-guard.test.ts +116 -1
  120. package/tests/codegraph-tools.test.ts +2 -1
  121. package/tests/delegated-key-learnings-contract.test.ts +1 -1
  122. package/tests/devbinary/native-review-parity.devtest.ts +2 -0
  123. package/tests/feature-request-form.test.ts +67 -0
  124. package/tests/fixtures/agents-messaging-child.mjs +5 -0
  125. package/tests/fixtures/runtime-metrics-native-batches.json +6 -0
  126. package/tests/gentle-agents.test.ts +1460 -33
  127. package/tests/gentle-ai-binary.test.ts +7 -2
  128. package/tests/gentle-ai-installer.test.ts +47 -47
  129. package/tests/gentle-ai-renderer.test.ts +38 -0
  130. package/tests/gentle-ai.test.ts +944 -4
  131. package/tests/gentle-shell.test.ts +303 -12
  132. package/tests/gentle-todo.test.ts +54 -10
  133. package/tests/install-tui-mode-setting.test.ts +324 -0
  134. package/tests/issue-creation-skill.test.ts +22 -0
  135. package/tests/model-routing-authority.test.ts +12 -0
  136. package/tests/native-review-capability-contract.test.ts +12 -1
  137. package/tests/native-review-cli.test.ts +277 -3
  138. package/tests/native-review-parity.test.ts +14 -7
  139. package/tests/native-sdd-attempt-authority.test.ts +7 -2
  140. package/tests/orchestrator-presence.test.ts +389 -0
  141. package/tests/package-manifest.test.ts +232 -7
  142. package/tests/profiles-orchestrator.test.ts +208 -0
  143. package/tests/quiet-tool-rendering.test.ts +1 -0
  144. package/tests/rdd-aware-verification-contract.test.ts +10 -0
  145. package/tests/review-agent-end-preflight.test.ts +332 -24
  146. package/tests/review-candidate-view.test.ts +304 -6
  147. package/tests/review-consent-ui.test.ts +352 -0
  148. package/tests/review-contract-prompt.test.ts +14 -0
  149. package/tests/review-controller-native-routing.test.ts +563 -3
  150. package/tests/review-controller.test.ts +1 -1
  151. package/tests/review-host-relay-restart-parity.test.ts +142 -1
  152. package/tests/review-host-relay-routing.test.ts +364 -4
  153. package/tests/review-host-relay.test.ts +29 -0
  154. package/tests/review-integration-v2-forward.test.ts +44 -0
  155. package/tests/review-integration-v2.test.ts +164 -0
  156. package/tests/review-last-event-closure.test.ts +105 -1
  157. package/tests/review-ledger-contract.test.ts +61 -6
  158. package/tests/review-reminder-receipt.test.ts +62 -0
  159. package/tests/review-session-standing-permission-controller.test.ts +52 -4
  160. package/tests/review-session-standing-permission.test.ts +30 -0
  161. package/tests/runtime-harness.mjs +447 -39
  162. package/tests/runtime-metrics-children.test.ts +206 -0
  163. package/tests/runtime-metrics-delivery.test.ts +85 -0
  164. package/tests/runtime-metrics-extension.test.ts +187 -0
  165. package/tests/runtime-metrics-native.test.ts +209 -0
  166. package/tests/runtime-metrics-pi-identity.test.ts +113 -0
  167. package/tests/runtime-metrics-policy.test.ts +62 -0
  168. package/tests/runtime-metrics.test.ts +184 -0
  169. package/tests/sdd-agent-tools.test.ts +10 -1
  170. package/tests/sdd-execution-routing-contract.test.ts +28 -0
  171. package/tests/sdd-managed-runtime-settlement.test.ts +331 -0
  172. package/tests/sdd-native-managed-uptake.test.ts +253 -0
  173. package/tests/sdd-planning-routing-contract.test.ts +45 -0
  174. package/tests/sdd-preflight.test.ts +252 -8
  175. package/tests/sdd-research-capabilities.test.ts +256 -0
  176. package/tests/sdd-research-live.test.ts +241 -0
  177. package/tests/sdd-selection-transport.test.ts +504 -0
  178. package/tests/sdd-status.test.ts +51 -0
  179. package/tests/session-worktree-registry.test.ts +135 -0
  180. package/tests/shell-card.test.ts +24 -3
  181. package/tests/shell-changes-view.test.ts +471 -8
  182. package/tests/shell-changes.test.ts +168 -0
  183. package/tests/shell-prompt.test.ts +28 -6
  184. package/tests/shell-sidebar-banner.test.ts +23 -0
  185. package/tests/shell-sidebar-layout.test.ts +387 -0
  186. package/tests/shell-sidebar.test.ts +50 -0
  187. package/tests/shell-todo.test.ts +100 -11
  188. package/tests/startup-banner.test.ts +126 -0
  189. package/tests/telemetry-trigger.test.ts +3 -1
@@ -2,12 +2,10 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
2
  import { VERSION } from "@earendil-works/pi-coding-agent";
3
3
  import { truncateToWidth } from "@earendil-works/pi-tui";
4
4
  import * as os from "node:os";
5
- import { exec } from "node:child_process";
6
- import { promisify } from "node:util";
5
+ import { execFile } from "node:child_process";
7
6
  import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
8
7
  import { join } from "node:path";
9
8
 
10
- const execAsync = promisify(exec);
11
9
  const PI_AGENT_DIR = join(os.homedir(), ".pi", "agent");
12
10
  const PI_NPM_DIR = join(PI_AGENT_DIR, "npm", "node_modules");
13
11
 
@@ -527,7 +525,26 @@ async function countPackageExtensions(packages: unknown[]): Promise<number> {
527
525
  return count;
528
526
  }
529
527
 
528
+ export function readGitBranch(cwd: string, run: typeof execFile = execFile): Promise<string> {
529
+ return new Promise((resolve) => {
530
+ run("git", ["-C", cwd, "branch", "--show-current"], {
531
+ encoding: "utf8",
532
+ shell: false,
533
+ windowsHide: true,
534
+ }, (error, stdout) => {
535
+ if (error) {
536
+ resolve("Not a git repo");
537
+ return;
538
+ }
539
+ const branch = String(stdout).trim();
540
+ resolve(branch ? `On branch ${branch}` : "Detached HEAD");
541
+ });
542
+ });
543
+ }
544
+
530
545
  export default function (pi: ExtensionAPI) {
546
+ let disposeHeader = () => {};
547
+ pi.on("session_shutdown", () => disposeHeader());
531
548
  const notifyBannerConfig = (ctx: any, config: BannerConfig) => {
532
549
  ctx.ui.notify(
533
550
  [
@@ -597,6 +614,7 @@ export default function (pi: ExtensionAPI) {
597
614
  registerColorCommand("gentle:banner-color");
598
615
 
599
616
  pi.on("session_start", async (_event, ctx) => {
617
+ disposeHeader();
600
618
  if (!ctx.hasUI) return;
601
619
 
602
620
  // Si se está ejecutando un comando de CLI como "pi update" o "pi install", no mostramos la intro animada.
@@ -607,16 +625,13 @@ export default function (pi: ExtensionAPI) {
607
625
 
608
626
  if (currentIntroMode() === "skip") return;
609
627
 
610
- // Fire-and-forget: el setup geométrico de cada letra corre en background
611
- // para que la animación arranque en el primer frame sin bloquear el event loop.
612
- void warmupLetterStrokes();
613
-
614
- process.stdout.write("\x1b[2J\x1b[3J\x1b[H");
615
-
628
+ // Pi has already started its renderer. Let setHeader schedule the paint;
629
+ // clearing stdout here would leave its previous-frame cache out of sync.
616
630
  const bannerConfig = await readBannerConfig();
617
631
  const palette = BANNER_PALETTES[bannerConfig.color];
618
632
  const roseBase = padLines(normalizeAscii(ROSE_LARGE_RAW));
619
633
  const logoBase = padLines(TEXT_LOGO);
634
+ void warmupLetterStrokes();
620
635
 
621
636
  let gitBranch = "Not a git repo";
622
637
  let mcpServersCount = 0;
@@ -632,12 +647,9 @@ export default function (pi: ExtensionAPI) {
632
647
  );
633
648
 
634
649
  setTimeout(() => {
635
- execAsync(`git -C "${ctx.cwd}" branch --show-current`)
636
- .then(({ stdout }) => {
637
- const b = stdout.trim();
638
- gitBranch = b ? `On branch ${b}` : "Detached HEAD";
639
- })
640
- .catch(() => {});
650
+ readGitBranch(ctx.cwd)
651
+ .then((branch) => { gitBranch = branch; })
652
+ .finally(() => refreshStats());
641
653
  }, 100);
642
654
 
643
655
  setTimeout(() => {
@@ -652,6 +664,7 @@ export default function (pi: ExtensionAPI) {
652
664
  } catch {
653
665
  mcpServersCount = 0;
654
666
  }
667
+ refreshStats();
655
668
  })();
656
669
  }, 150);
657
670
 
@@ -671,10 +684,12 @@ export default function (pi: ExtensionAPI) {
671
684
  extensionsCount = 0;
672
685
  packagesCount = 0;
673
686
  }
687
+ refreshStats();
674
688
  })();
675
689
  }, 200);
676
690
 
677
691
  let tick = 0;
692
+ let refreshStats = () => {};
678
693
  const state = {
679
694
  timer: null as NodeJS.Timeout | null,
680
695
  mode: currentIntroMode() as IntroMode,
@@ -683,6 +698,7 @@ export default function (pi: ExtensionAPI) {
683
698
  };
684
699
 
685
700
  const cleanup = () => {
701
+ refreshStats = () => {};
686
702
  if (state.timer) {
687
703
  clearInterval(state.timer);
688
704
  state.timer = null;
@@ -697,27 +713,21 @@ export default function (pi: ExtensionAPI) {
697
713
  }
698
714
  };
699
715
 
716
+ disposeHeader = cleanup;
700
717
  setTimeout(() => {
701
718
  ctx.ui.setHeader((tui, theme) => {
702
719
  if (state.timer) clearInterval(state.timer);
703
720
 
721
+ refreshStats = () => tui.requestRender();
704
722
  const animStart = Date.now();
705
- const HARD_TIMEOUT_MS = 5000;
706
-
707
723
  state.timer = setInterval(() => {
708
724
  tick++;
709
- const elapsed = Date.now() - animStart;
710
- const finishedAnimation =
711
- allStrokesReady() && tick > WRITING_END_TICK + 22;
712
- if (finishedAnimation || elapsed > HARD_TIMEOUT_MS) {
713
- cleanup();
714
- return;
715
- }
716
- try {
717
- tui.requestRender();
718
- } catch {
719
- cleanup();
725
+ const finished = allStrokesReady() && tick > WRITING_END_TICK + 22;
726
+ if (finished || Date.now() - animStart > 5000) {
727
+ clearInterval(state.timer!);
728
+ state.timer = null;
720
729
  }
730
+ try { tui.requestRender(); } catch { cleanup(); }
721
731
  }, 25);
722
732
 
723
733
  // Grace period: pi-tui emite resizes transitorios mientras compone su layout inicial.
@@ -730,11 +740,7 @@ export default function (pi: ExtensionAPI) {
730
740
  const next = currentIntroMode();
731
741
  if (next === state.mode) return;
732
742
  state.mode = next;
733
- if (next === "skip") {
734
- cleanup();
735
- process.stdout.write("\x1b[2J\x1b[3J\x1b[H");
736
- return;
737
- }
743
+ // Pi owns removal in skip mode; keep listening for later expansion.
738
744
  try {
739
745
  tui.requestRender();
740
746
  } catch {
@@ -758,9 +764,9 @@ export default function (pi: ExtensionAPI) {
758
764
  const frame = Math.floor(tick / 2);
759
765
 
760
766
  const sideBySideMinWidth = roseBase.width + 3 + logoBase.width + 4;
761
- const wideStatsMinWidth = 122;
762
767
  const horizontal =
763
768
  state.mode === "full" && bannerConfig.showRose && bannerConfig.showTextLogo && width >= sideBySideMinWidth;
769
+ const wideStatsMinWidth = 122;
764
770
  const wideStats = width >= wideStatsMinWidth;
765
771
 
766
772
  const b = new LayoutBuilder();
@@ -772,52 +778,27 @@ export default function (pi: ExtensionAPI) {
772
778
  const logoLine = logoBase.lines[logoI];
773
779
  b.addRow();
774
780
  b.lines[b.lines.length - 1].push(
775
- ...buildPenLogoLine(
776
- logoLine,
777
- logoI,
778
- logoBase.lines.length,
779
- tick,
780
- ),
781
+ ...buildPenLogoLine(logoLine, logoI, logoBase.lines.length, tick),
781
782
  );
782
783
  b.center(width);
783
784
  }
784
785
  } else if (horizontal) {
785
- const rowCount = Math.max(
786
- roseBase.lines.length,
787
- logoBase.lines.length,
788
- );
789
- const roseOffset = Math.max(
790
- 0,
791
- Math.floor((rowCount - roseBase.lines.length) / 2),
792
- );
793
- const logoOffset = Math.max(
794
- 0,
795
- Math.floor((rowCount - logoBase.lines.length) / 2),
796
- );
797
-
786
+ const rowCount = Math.max(roseBase.lines.length, logoBase.lines.length);
787
+ const roseOffset = Math.max(0, Math.floor((rowCount - roseBase.lines.length) / 2));
788
+ const logoOffset = Math.max(0, Math.floor((rowCount - logoBase.lines.length) / 2));
798
789
  for (let i = 0; i < rowCount; i++) {
799
790
  const roseI = i - roseOffset;
800
791
  const logoI = i - logoOffset;
801
- const roseLine =
802
- roseI >= 0 && roseI < roseBase.lines.length
803
- ? roseBase.lines[roseI]
804
- : " ".repeat(roseBase.width);
805
- const logoLine =
806
- logoI >= 0 && logoI < logoBase.lines.length
807
- ? logoBase.lines[logoI]
808
- : " ".repeat(logoBase.width);
809
-
792
+ const roseLine = roseI >= 0 && roseI < roseBase.lines.length
793
+ ? roseBase.lines[roseI] : " ".repeat(roseBase.width);
794
+ const logoLine = logoI >= 0 && logoI < logoBase.lines.length
795
+ ? logoBase.lines[logoI] : " ".repeat(logoBase.width);
810
796
  b.addRow();
811
797
  b.add("rose", roseLine);
812
798
  b.add("none", " ");
813
799
  if (logoI >= 0 && logoI < logoBase.lines.length) {
814
800
  b.lines[b.lines.length - 1].push(
815
- ...buildPenLogoLine(
816
- logoLine,
817
- logoI,
818
- logoBase.lines.length,
819
- tick,
820
- ),
801
+ ...buildPenLogoLine(logoLine, logoI, logoBase.lines.length, tick),
821
802
  );
822
803
  } else {
823
804
  b.add("none", " ".repeat(logoBase.width));
@@ -832,12 +813,7 @@ export default function (pi: ExtensionAPI) {
832
813
  const logoLine = logoBase.lines[logoI];
833
814
  b.addRow();
834
815
  b.lines[b.lines.length - 1].push(
835
- ...buildPenLogoLine(
836
- logoLine,
837
- logoI,
838
- logoBase.lines.length,
839
- tick,
840
- ),
816
+ ...buildPenLogoLine(logoLine, logoI, logoBase.lines.length, tick),
841
817
  );
842
818
  b.center(width);
843
819
  }
@@ -1075,7 +1051,8 @@ export default function (pi: ExtensionAPI) {
1075
1051
 
1076
1052
  return out;
1077
1053
  },
1078
- invalidate() {
1054
+ invalidate() {},
1055
+ dispose() {
1079
1056
  cleanup();
1080
1057
  },
1081
1058
  };