pi-harness-runtime 1.1.134 → 1.1.136

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 (106) hide show
  1. package/index.ts +100 -47
  2. package/package.json +1 -1
  3. package/packages/a2a-adapter/package.json +1 -1
  4. package/packages/architecture-generator/package.json +1 -1
  5. package/packages/auth/package.json +1 -1
  6. package/packages/autonomous-refactor/package.json +1 -1
  7. package/packages/autonomous-runtime/package.json +1 -1
  8. package/packages/cache-strategy/package.json +1 -1
  9. package/packages/capability-registry/package.json +1 -1
  10. package/packages/checkpoint/package.json +1 -1
  11. package/packages/cli-plugin-sdk/package.json +1 -1
  12. package/packages/clipboard/package.json +1 -1
  13. package/packages/clipboard-plugin/package.json +1 -1
  14. package/packages/code-generation/package.json +1 -1
  15. package/packages/code-review/package.json +1 -1
  16. package/packages/codex-adapter/package.json +1 -1
  17. package/packages/config-capture/package.json +1 -1
  18. package/packages/context-compiler/package.json +1 -1
  19. package/packages/context-discovery/package.json +1 -1
  20. package/packages/context-manager/package.json +1 -1
  21. package/packages/cookie-sanitizer/package.json +1 -1
  22. package/packages/cost-optimizer/package.json +1 -1
  23. package/packages/dependency-analyzer/package.json +1 -1
  24. package/packages/django-plugin/package.json +1 -1
  25. package/packages/doc-generator/package.json +1 -1
  26. package/packages/evaluation-engine/package.json +1 -1
  27. package/packages/evaluation-runner/package.json +1 -1
  28. package/packages/event-bus/package.json +1 -1
  29. package/packages/event-store/package.json +1 -1
  30. package/packages/experience-replay/package.json +1 -1
  31. package/packages/feedback-collector/package.json +1 -1
  32. package/packages/file-copy-helper/package.json +1 -1
  33. package/packages/framework-detector/package.json +1 -1
  34. package/packages/framework-plugin-sdk/package.json +1 -1
  35. package/packages/frappe-plugin/package.json +1 -1
  36. package/packages/generic-web-plugin/package.json +1 -1
  37. package/packages/health-monitor/package.json +1 -1
  38. package/packages/intent-analyzer/package.json +1 -1
  39. package/packages/jev-judge/package.json +1 -1
  40. package/packages/knowledge-graph/package.json +1 -1
  41. package/packages/knowledge-retrieval/package.json +1 -1
  42. package/packages/laravel-plugin/package.json +1 -1
  43. package/packages/learning-engine/package.json +1 -1
  44. package/packages/mcp-adapter/package.json +1 -1
  45. package/packages/memory-engine/package.json +1 -1
  46. package/packages/milestone-manager/package.json +1 -1
  47. package/packages/model-registry/package.json +1 -1
  48. package/packages/nextjs-plugin/package.json +1 -1
  49. package/packages/notification/package.json +1 -1
  50. package/packages/observability/package.json +1 -1
  51. package/packages/okf-indexer/package.json +1 -1
  52. package/packages/performance-optimizer/package.json +1 -1
  53. package/packages/privilege-broker/package.json +1 -1
  54. package/packages/project-analyzer/package.json +1 -1
  55. package/packages/project-bootstrap/package.json +1 -1
  56. package/packages/projection-engine/package.json +1 -1
  57. package/packages/prompt-compiler/package.json +1 -1
  58. package/packages/prompt-versioning/package.json +1 -1
  59. package/packages/provider-adapter-sdk/package.json +1 -1
  60. package/packages/provider-router/package.json +1 -1
  61. package/packages/provider-selector/package.json +1 -1
  62. package/packages/providers/package.json +1 -1
  63. package/packages/qdrant-skills/package.json +1 -1
  64. package/packages/quota-manager/package.json +1 -1
  65. package/packages/rate-limiter/package.json +1 -1
  66. package/packages/react-vite-plugin/package.json +1 -1
  67. package/packages/release-manager/package.json +1 -1
  68. package/packages/requirement-compiler/package.json +1 -1
  69. package/packages/runtime/package.json +1 -1
  70. package/packages/scheduler/package.json +1 -1
  71. package/packages/scheduler-adapter/package.json +1 -1
  72. package/packages/session/package.json +1 -1
  73. package/packages/session-api/package.json +1 -1
  74. package/packages/session-export/package.json +1 -1
  75. package/packages/shared-context/package.json +1 -1
  76. package/packages/skill-mcp-client/package.json +1 -1
  77. package/packages/skill-registry/package.json +1 -1
  78. package/packages/skills/package.json +1 -1
  79. package/packages/sprint-planner/package.json +1 -1
  80. package/packages/subscription-engine/package.json +1 -1
  81. package/packages/task-compiler/package.json +1 -1
  82. package/packages/tencentdb-memory/package.json +1 -1
  83. package/packages/tencentdb-sync/package.json +1 -1
  84. package/packages/test-data-generator/package.json +1 -1
  85. package/packages/test-generator/package.json +1 -1
  86. package/packages/todo-bd-sync/package.json +1 -1
  87. package/packages/token-estimation/package.json +1 -1
  88. package/packages/token-optimizer/package.json +1 -1
  89. package/packages/trajectory/package.json +1 -1
  90. package/packages/tui/dist/harness-header.d.ts +41 -0
  91. package/packages/tui/dist/harness-header.d.ts.map +1 -0
  92. package/packages/tui/dist/harness-header.js +184 -0
  93. package/packages/tui/dist/harness-header.js.map +1 -0
  94. package/packages/tui/dist/index.d.ts +9 -0
  95. package/packages/tui/dist/index.d.ts.map +1 -0
  96. package/packages/tui/dist/index.js +9 -0
  97. package/packages/tui/dist/index.js.map +1 -0
  98. package/packages/tui/package.json +1 -1
  99. package/packages/tui/src/harness-header.ts +255 -0
  100. package/packages/tui/src/index.ts +9 -0
  101. package/packages/tui/test/harness-header.test.ts +310 -0
  102. package/packages/types/package.json +1 -1
  103. package/packages/workflow-events/package.json +1 -1
  104. package/packages/workspace-scanner/package.json +1 -1
  105. package/packages/worktree/package.json +1 -1
  106. package/packages/write-review/package.json +1 -1
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Harness ASCII Banner — a Pi-compatible custom header using Unicode half-block art.
3
+ *
4
+ * Uses the same half-block rendering technique as Pi's built-in header:
5
+ * - `▀` (U+2580) fills the upper half of a terminal cell
6
+ * - `▄` (U+2584) fills the lower half of a terminal cell
7
+ * - Foreground + background color creates two "pixels" per cell
8
+ *
9
+ * Logo: 4 cells wide × 2 rows. Pattern is Harness-branded (accent + success colors).
10
+ * Compact/expanded states respond to Ctrl+O via Pi's global setExpanded() mechanism.
11
+ *
12
+ * MIT — derived from general technique documented in upstream pi-coding-agent.
13
+ * Harness branding is original work of the harness project.
14
+ */
15
+ import { keyText, keyHint, rawKeyHint } from "@earendil-works/pi-coding-agent";
16
+ // ---------------------------------------------------------------------------
17
+ // Logo design
18
+ // ---------------------------------------------------------------------------
19
+ //
20
+ // Logical 4×4 pixel grid (each cell = foreground+background color pair):
21
+ //
22
+ // Row 0: ░ ░ ▓ ▒ (top half-blocks: accent, accent, dim, dim)
23
+ // Row 1: ▓ ░ ░ ▒ (bottom half-blocks: dim, success, success, dim)
24
+ //
25
+ // Rendered as 2 text rows with 4 terminal cells per row:
26
+ // Line 0: ▀▀█▄ (▀ = upper-half, █ = full-block, ▄ = lower-half)
27
+ // Line 1: █▀▀▄ (same characters, different color pairing)
28
+ //
29
+ // Colors:
30
+ // - accent = harness primary (teal in harness theme, adapts to user's theme)
31
+ // - success = harness secondary (green in harness theme)
32
+ // - muted = dim teal (for visual depth)
33
+ // - dim = dim blue (for visual depth)
34
+ //
35
+ // The logo is NOT Pi's logo — it uses the same rendering technique only.
36
+ // Logo glyphs documented in logoLines() for reference.
37
+ /** Harness primary color — uses theme "accent" (teal in harness theme) */
38
+ function logoAccent(text, theme) {
39
+ return theme.fg("accent", text);
40
+ }
41
+ /** Harness secondary color — uses theme "success" (green in harness theme) */
42
+ function logoSecondary(text, theme) {
43
+ return theme.fg("success", text);
44
+ }
45
+ /** Dim foreground — uses theme "muted" for depth */
46
+ function logoDim(text, theme) {
47
+ return theme.fg("muted", text);
48
+ }
49
+ /**
50
+ * Build the two colored logo lines for the Harness mark.
51
+ *
52
+ * Color segment per cell (each char = one terminal cell):
53
+ * Line 0: ▀▀█▄ → ▀(accent) ▀(accent) █(muted) ▄(muted)
54
+ * Line 1: █▀▀▄ → █(muted) ▀(success) ▀(success) ▄(muted)
55
+ */
56
+ function logoLines(theme) {
57
+ return [
58
+ logoAccent("▀", theme) +
59
+ logoAccent("▀", theme) +
60
+ logoDim("█", theme) +
61
+ logoDim("▄", theme),
62
+ logoDim("█", theme) +
63
+ logoSecondary("▀", theme) +
64
+ logoSecondary("▀", theme) +
65
+ logoDim("▄", theme),
66
+ ];
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Fallback (Apple Terminal, no half-block support, or print/RPC modes)
70
+ // ---------------------------------------------------------------------------
71
+ const FALLBACK_LOGO_LINE0 = "Harness";
72
+ const FALLBACK_LOGO_LINE1 = "";
73
+ export function createHarnessHeader(_tui, _theme, options) {
74
+ return new HarnessHeaderComponent(_theme, options);
75
+ }
76
+ class HarnessHeaderComponent {
77
+ theme;
78
+ options;
79
+ expanded = false;
80
+ supportsHalfBlocks = true;
81
+ constructor(theme, options) {
82
+ this.theme = theme;
83
+ this.options = {
84
+ productName: "Harness",
85
+ onboardingText: "Harness extends Pi with quota management, automation, memory, and multi-agent workflows.",
86
+ ...options,
87
+ };
88
+ }
89
+ // --- Component interface ---
90
+ render(_width) {
91
+ const { version, onboardingText } = this.options;
92
+ // Logo: half-block art or plain fallback
93
+ const [logoLine0, logoLine1] = this.supportsHalfBlocks
94
+ ? logoLines(this.theme)
95
+ : [FALLBACK_LOGO_LINE0, FALLBACK_LOGO_LINE1];
96
+ const versionStr = this.theme.fg("dim", `v${version}`);
97
+ const expandKey = keyText("app.tools.expand");
98
+ const onboarding = this.theme.fg("dim", onboardingText);
99
+ if (this.expanded) {
100
+ return this.renderExpanded(logoLine0, versionStr, expandKey, onboarding);
101
+ }
102
+ return this.renderCompact(logoLine0, logoLine1, versionStr, expandKey, onboarding);
103
+ }
104
+ renderCompact(logoLine0, logoLine1, versionStr, expandKey, onboarding) {
105
+ const { productName } = this.options;
106
+ // Build compact one-line shortcuts
107
+ const hints = [
108
+ keyHint("app.interrupt", "interrupt"),
109
+ rawKeyHint(`${keyText("app.clear")}/${keyText("app.exit")}`, "clear/exit"),
110
+ rawKeyHint("/", "commands"),
111
+ rawKeyHint("!", "bash"),
112
+ keyHint("app.tools.expand", "more"),
113
+ ].join(this.theme.fg("muted", " · "));
114
+ // Line 0: logo + product name + version
115
+ const line0 = `${logoLine0} ${this.theme.fg("text", productName)} ${versionStr}`;
116
+ // Line 1: bottom logo row + compact hints
117
+ const line1 = `${logoLine1} ${hints}`;
118
+ // Line 2: expand prompt
119
+ const line2 = this.theme.fg("dim", `Press ${expandKey} to show full startup help and loaded resources.`);
120
+ // Line 4 (blank line 3): onboarding
121
+ const line4 = onboarding;
122
+ return ["", line0, line1, line2, "", line4, ""];
123
+ }
124
+ renderExpanded(logoLine0, versionStr, expandKey, onboarding) {
125
+ const { productName } = this.options;
126
+ // Line 0: logo + product name + version
127
+ const line0 = `${logoLine0} ${this.theme.fg("text", productName)} ${versionStr}`;
128
+ // Expanded: one shortcut per line
129
+ const expandedLines = [
130
+ keyHint("app.interrupt", "abort the current agent turn"),
131
+ keyHint("app.clear", "clear the current session"),
132
+ keyHint("app.exit", "exit Pi"),
133
+ rawKeyHint("/", "show available slash commands"),
134
+ rawKeyHint("!", "open a bash shell"),
135
+ keyHint("app.tools.expand", "expand/collapse tool output and this header"),
136
+ this.theme.fg("muted", `${expandKey} to collapse`),
137
+ ];
138
+ // Line 2: expand prompt
139
+ const line2 = this.theme.fg("dim", `Press ${expandKey} to show compact header.`);
140
+ // Line 4: onboarding
141
+ const line4 = onboarding;
142
+ // Compose: blank, logo, blank, expanded hints (indented), blank, expand prompt, blank, onboarding, blank
143
+ const result = [""];
144
+ result.push(line0);
145
+ result.push(""); // blank after logo
146
+ for (const hint of expandedLines) {
147
+ result.push(` ${hint}`);
148
+ }
149
+ result.push("");
150
+ result.push(line2);
151
+ result.push("");
152
+ result.push(line4);
153
+ result.push("");
154
+ return result;
155
+ }
156
+ invalidate() {
157
+ // Theme changes or expansion state changes call this to request re-render.
158
+ // The TUI calls render() again automatically.
159
+ }
160
+ // --- Expandable interface (called by Pi when Ctrl+O toggles) ---
161
+ setExpanded(expanded) {
162
+ if (this.expanded === expanded)
163
+ return;
164
+ this.expanded = expanded;
165
+ this.invalidate();
166
+ }
167
+ // --- Cleanup ---
168
+ dispose() {
169
+ // No persistent resources to clean up.
170
+ }
171
+ }
172
+ // ---------------------------------------------------------------------------
173
+ // Visible width helper (ANSI-aware)
174
+ // ---------------------------------------------------------------------------
175
+ /** Strip ANSI escape sequences to get visible character count. */
176
+ export function visibleWidth(str) {
177
+ // Remove all ANSI CSI sequences: \x1b[...X
178
+ return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").length;
179
+ }
180
+ /** Strip ANSI to get plain text for width/equality checks. */
181
+ export function stripAnsi(str) {
182
+ return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "");
183
+ }
184
+ //# sourceMappingURL=harness-header.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"harness-header.js","sourceRoot":"","sources":["../src/harness-header.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @pi-harness/tui — TUI integration utilities for pi-harness-runtime.
3
+ *
4
+ * Exports the Harness custom header component that replaces Pi's built-in
5
+ * startup banner with a harness-branded version using Unicode half-block art.
6
+ */
7
+ export { createHarnessHeader, type HarnessHeaderOptions } from "./harness-header.js";
8
+ export { visibleWidth, stripAnsi } from "./harness-header.js";
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @pi-harness/tui — TUI integration utilities for pi-harness-runtime.
3
+ *
4
+ * Exports the Harness custom header component that replaces Pi's built-in
5
+ * startup banner with a harness-branded version using Unicode half-block art.
6
+ */
7
+ export { createHarnessHeader } from "./harness-header.js";
8
+ export { visibleWidth, stripAnsi } from "./harness-header.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,mBAAmB,EAA6B,MAAM,qBAAqB,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-harness/tui",
3
- "version": "1.1.134",
3
+ "version": "1.1.136",
4
4
  "description": "pi-harness-runtime — tui",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Harness ASCII Banner — a Pi-compatible custom header using Unicode half-block art.
3
+ *
4
+ * Uses the same half-block rendering technique as Pi's built-in header:
5
+ * - `▀` (U+2580) fills the upper half of a terminal cell
6
+ * - `▄` (U+2584) fills the lower half of a terminal cell
7
+ * - Foreground + background color creates two "pixels" per cell
8
+ *
9
+ * Logo: 4 cells wide × 2 rows. Pattern is Harness-branded (accent + success colors).
10
+ * Compact/expanded states respond to Ctrl+O via Pi's global setExpanded() mechanism.
11
+ *
12
+ * MIT — derived from general technique documented in upstream pi-coding-agent.
13
+ * Harness branding is original work of the harness project.
14
+ */
15
+
16
+ import type { Component, TUI } from "@earendil-works/pi-tui";
17
+
18
+ // Re-export Theme from pi-coding-agent since @pi-harness/tui has no theme dependency.
19
+ // Extensions already depend on @earendil-works/pi-coding-agent.
20
+ import type { Theme } from "@earendil-works/pi-coding-agent";
21
+ import { keyText, keyHint, rawKeyHint } from "@earendil-works/pi-coding-agent";
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Logo design
25
+ // ---------------------------------------------------------------------------
26
+ //
27
+ // Logical 4×4 pixel grid (each cell = foreground+background color pair):
28
+ //
29
+ // Row 0: ░ ░ ▓ ▒ (top half-blocks: accent, accent, dim, dim)
30
+ // Row 1: ▓ ░ ░ ▒ (bottom half-blocks: dim, success, success, dim)
31
+ //
32
+ // Rendered as 2 text rows with 4 terminal cells per row:
33
+ // Line 0: ▀▀█▄ (▀ = upper-half, █ = full-block, ▄ = lower-half)
34
+ // Line 1: █▀▀▄ (same characters, different color pairing)
35
+ //
36
+ // Colors:
37
+ // - accent = harness primary (teal in harness theme, adapts to user's theme)
38
+ // - success = harness secondary (green in harness theme)
39
+ // - muted = dim teal (for visual depth)
40
+ // - dim = dim blue (for visual depth)
41
+ //
42
+ // The logo is NOT Pi's logo — it uses the same rendering technique only.
43
+
44
+ // Logo glyphs documented in logoLines() for reference.
45
+
46
+ /** Harness primary color — uses theme "accent" (teal in harness theme) */
47
+ function logoAccent(text: string, theme: Theme): string {
48
+ return theme.fg("accent", text);
49
+ }
50
+
51
+ /** Harness secondary color — uses theme "success" (green in harness theme) */
52
+ function logoSecondary(text: string, theme: Theme): string {
53
+ return theme.fg("success", text);
54
+ }
55
+
56
+ /** Dim foreground — uses theme "muted" for depth */
57
+ function logoDim(text: string, theme: Theme): string {
58
+ return theme.fg("muted", text);
59
+ }
60
+
61
+ /**
62
+ * Build the two colored logo lines for the Harness mark.
63
+ *
64
+ * Color segment per cell (each char = one terminal cell):
65
+ * Line 0: ▀▀█▄ → ▀(accent) ▀(accent) █(muted) ▄(muted)
66
+ * Line 1: █▀▀▄ → █(muted) ▀(success) ▀(success) ▄(muted)
67
+ */
68
+ function logoLines(theme: Theme): [string, string] {
69
+ return [
70
+ logoAccent("▀", theme) +
71
+ logoAccent("▀", theme) +
72
+ logoDim("█", theme) +
73
+ logoDim("▄", theme),
74
+ logoDim("█", theme) +
75
+ logoSecondary("▀", theme) +
76
+ logoSecondary("▀", theme) +
77
+ logoDim("▄", theme),
78
+ ];
79
+ }
80
+
81
+ // ---------------------------------------------------------------------------
82
+ // Fallback (Apple Terminal, no half-block support, or print/RPC modes)
83
+ // ---------------------------------------------------------------------------
84
+
85
+ const FALLBACK_LOGO_LINE0 = "Harness";
86
+ const FALLBACK_LOGO_LINE1 = "";
87
+
88
+ // ---------------------------------------------------------------------------
89
+ // HarnessHeader component
90
+ // ---------------------------------------------------------------------------
91
+
92
+ export interface HarnessHeaderOptions {
93
+ version: string;
94
+ productName?: string;
95
+ onboardingText?: string;
96
+ }
97
+
98
+ export function createHarnessHeader(
99
+ _tui: TUI,
100
+ _theme: Theme,
101
+ options: HarnessHeaderOptions,
102
+ ): HarnessHeaderComponent {
103
+ return new HarnessHeaderComponent(_theme, options);
104
+ }
105
+
106
+ class HarnessHeaderComponent implements Component {
107
+ private readonly theme: Theme;
108
+ private readonly options: Required<HarnessHeaderOptions>;
109
+ private expanded = false;
110
+ private supportsHalfBlocks = true;
111
+
112
+ constructor(theme: Theme, options: HarnessHeaderOptions) {
113
+ this.theme = theme;
114
+ this.options = {
115
+ productName: "Harness",
116
+ onboardingText:
117
+ "Harness extends Pi with quota management, automation, memory, and multi-agent workflows.",
118
+ ...options,
119
+ };
120
+ }
121
+
122
+ // --- Component interface ---
123
+
124
+ render(_width: number): string[] {
125
+ const { version, onboardingText } = this.options;
126
+
127
+ // Logo: half-block art or plain fallback
128
+ const [logoLine0, logoLine1] = this.supportsHalfBlocks
129
+ ? logoLines(this.theme)
130
+ : [FALLBACK_LOGO_LINE0, FALLBACK_LOGO_LINE1];
131
+
132
+ const versionStr = this.theme.fg("dim", `v${version}`);
133
+ const expandKey = keyText("app.tools.expand");
134
+ const onboarding = this.theme.fg("dim", onboardingText);
135
+
136
+ if (this.expanded) {
137
+ return this.renderExpanded(logoLine0, versionStr, expandKey, onboarding);
138
+ }
139
+ return this.renderCompact(logoLine0, logoLine1, versionStr, expandKey, onboarding);
140
+ }
141
+
142
+ private renderCompact(
143
+ logoLine0: string,
144
+ logoLine1: string,
145
+ versionStr: string,
146
+ expandKey: string,
147
+ onboarding: string,
148
+ ): string[] {
149
+ const { productName } = this.options;
150
+
151
+ // Build compact one-line shortcuts
152
+ const hints = [
153
+ keyHint("app.interrupt", "interrupt"),
154
+ rawKeyHint(`${keyText("app.clear")}/${keyText("app.exit")}`, "clear/exit"),
155
+ rawKeyHint("/", "commands"),
156
+ rawKeyHint("!", "bash"),
157
+ keyHint("app.tools.expand", "more"),
158
+ ].join(this.theme.fg("muted", " · "));
159
+
160
+ // Line 0: logo + product name + version
161
+ const line0 = `${logoLine0} ${this.theme.fg("text", productName)} ${versionStr}`;
162
+
163
+ // Line 1: bottom logo row + compact hints
164
+ const line1 = `${logoLine1} ${hints}`;
165
+
166
+ // Line 2: expand prompt
167
+ const line2 = this.theme.fg(
168
+ "dim",
169
+ `Press ${expandKey} to show full startup help and loaded resources.`,
170
+ );
171
+
172
+ // Line 4 (blank line 3): onboarding
173
+ const line4 = onboarding;
174
+
175
+ return ["", line0, line1, line2, "", line4, ""];
176
+ }
177
+
178
+ private renderExpanded(
179
+ logoLine0: string,
180
+ versionStr: string,
181
+ expandKey: string,
182
+ onboarding: string,
183
+ ): string[] {
184
+ const { productName } = this.options;
185
+
186
+ // Line 0: logo + product name + version
187
+ const line0 = `${logoLine0} ${this.theme.fg("text", productName)} ${versionStr}`;
188
+
189
+ // Expanded: one shortcut per line
190
+ const expandedLines = [
191
+ keyHint("app.interrupt", "abort the current agent turn"),
192
+ keyHint("app.clear", "clear the current session"),
193
+ keyHint("app.exit", "exit Pi"),
194
+ rawKeyHint("/", "show available slash commands"),
195
+ rawKeyHint("!", "open a bash shell"),
196
+ keyHint("app.tools.expand", "expand/collapse tool output and this header"),
197
+ this.theme.fg("muted", `${expandKey} to collapse`),
198
+ ];
199
+
200
+ // Line 2: expand prompt
201
+ const line2 = this.theme.fg("dim", `Press ${expandKey} to show compact header.`);
202
+
203
+ // Line 4: onboarding
204
+ const line4 = onboarding;
205
+
206
+ // Compose: blank, logo, blank, expanded hints (indented), blank, expand prompt, blank, onboarding, blank
207
+ const result: string[] = [""];
208
+ result.push(line0);
209
+ result.push(""); // blank after logo
210
+ for (const hint of expandedLines) {
211
+ result.push(` ${hint}`);
212
+ }
213
+ result.push("");
214
+ result.push(line2);
215
+ result.push("");
216
+ result.push(line4);
217
+ result.push("");
218
+
219
+ return result;
220
+ }
221
+
222
+ invalidate(): void {
223
+ // Theme changes or expansion state changes call this to request re-render.
224
+ // The TUI calls render() again automatically.
225
+ }
226
+
227
+ // --- Expandable interface (called by Pi when Ctrl+O toggles) ---
228
+
229
+ setExpanded(expanded: boolean): void {
230
+ if (this.expanded === expanded) return;
231
+ this.expanded = expanded;
232
+ this.invalidate();
233
+ }
234
+
235
+ // --- Cleanup ---
236
+
237
+ dispose(): void {
238
+ // No persistent resources to clean up.
239
+ }
240
+ }
241
+
242
+ // ---------------------------------------------------------------------------
243
+ // Visible width helper (ANSI-aware)
244
+ // ---------------------------------------------------------------------------
245
+
246
+ /** Strip ANSI escape sequences to get visible character count. */
247
+ export function visibleWidth(str: string): number {
248
+ // Remove all ANSI CSI sequences: \x1b[...X
249
+ return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").length;
250
+ }
251
+
252
+ /** Strip ANSI to get plain text for width/equality checks. */
253
+ export function stripAnsi(str: string): string {
254
+ return str.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "");
255
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @pi-harness/tui — TUI integration utilities for pi-harness-runtime.
3
+ *
4
+ * Exports the Harness custom header component that replaces Pi's built-in
5
+ * startup banner with a harness-branded version using Unicode half-block art.
6
+ */
7
+
8
+ export { createHarnessHeader, type HarnessHeaderOptions } from "./harness-header.js";
9
+ export { visibleWidth, stripAnsi } from "./harness-header.js";