@jmoyers/harness 0.1.10 → 0.1.20

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 (239) hide show
  1. package/README.md +31 -35
  2. package/package.json +31 -11
  3. package/packages/harness-ai/src/anthropic-protocol.ts +68 -68
  4. package/packages/harness-ai/src/stream-text.ts +13 -91
  5. package/packages/harness-ui/src/frame-primitives.ts +158 -0
  6. package/packages/harness-ui/src/index.ts +18 -0
  7. package/packages/harness-ui/src/interaction/conversation-input-forwarder.ts +221 -0
  8. package/packages/harness-ui/src/interaction/conversation-selection-input.ts +213 -0
  9. package/packages/harness-ui/src/interaction/global-shortcut-input.ts +172 -0
  10. package/{src/ui → packages/harness-ui/src/interaction}/input-preflight.ts +10 -12
  11. package/{src/ui → packages/harness-ui/src/interaction}/input-token-router.ts +120 -69
  12. package/packages/harness-ui/src/interaction/input.ts +420 -0
  13. package/packages/harness-ui/src/interaction/left-nav-input.ts +166 -0
  14. package/{src/ui → packages/harness-ui/src/interaction}/main-pane-pointer-input.ts +91 -23
  15. package/{src/ui → packages/harness-ui/src/interaction}/pointer-routing-input.ts +112 -48
  16. package/packages/harness-ui/src/interaction/rail-pointer-input.ts +62 -0
  17. package/packages/harness-ui/src/interaction/repository-fold-input.ts +118 -0
  18. package/packages/harness-ui/src/kit.ts +476 -0
  19. package/packages/harness-ui/src/layout.ts +238 -0
  20. package/{src/ui/modals/manager.ts → packages/harness-ui/src/modal-manager.ts} +94 -64
  21. package/{src/ui → packages/harness-ui/src}/screen.ts +53 -26
  22. package/packages/harness-ui/src/surface.ts +252 -0
  23. package/packages/harness-ui/src/text-layout.ts +210 -0
  24. package/packages/nim-core/src/contracts.ts +239 -0
  25. package/packages/nim-core/src/event-store.ts +299 -0
  26. package/packages/nim-core/src/events.ts +53 -0
  27. package/packages/nim-core/src/index.ts +9 -0
  28. package/packages/nim-core/src/provider-router.ts +129 -0
  29. package/packages/nim-core/src/providers/anthropic-driver.ts +291 -0
  30. package/packages/nim-core/src/runtime-factory.ts +49 -0
  31. package/packages/nim-core/src/runtime.ts +1797 -0
  32. package/packages/nim-core/src/session-store.ts +516 -0
  33. package/packages/nim-core/src/telemetry.ts +48 -0
  34. package/packages/nim-test-tui/src/index.ts +150 -0
  35. package/packages/nim-ui-core/src/index.ts +1 -0
  36. package/packages/nim-ui-core/src/projection.ts +87 -0
  37. package/scripts/codex-live-mux-runtime.ts +2 -3721
  38. package/scripts/control-plane-daemon.ts +24 -2
  39. package/scripts/harness-bin.js +5 -0
  40. package/scripts/harness-commands.ts +300 -0
  41. package/scripts/harness-runtime.ts +82 -0
  42. package/scripts/harness.ts +33 -3007
  43. package/scripts/nim-tui-smoke.ts +748 -0
  44. package/src/cli/auth/runtime.ts +948 -0
  45. package/src/cli/default-gateway-pointer.ts +193 -0
  46. package/src/cli/gateway/runtime.ts +1872 -0
  47. package/src/cli/parsing/flags.ts +23 -0
  48. package/src/cli/parsing/session.ts +42 -0
  49. package/src/cli/runtime/context.ts +193 -0
  50. package/src/cli/runtime-app/application.ts +392 -0
  51. package/src/cli/runtime-infra/gateway-control.ts +729 -0
  52. package/{scripts/harness-inspector.ts → src/cli/workflows/inspector.ts} +14 -11
  53. package/src/cli/workflows/runtime.ts +965 -0
  54. package/src/clients/tui/left-rail-interactions.ts +519 -0
  55. package/src/clients/tui/main-pane-interactions.ts +509 -0
  56. package/src/clients/tui/modal-input-routing.ts +71 -0
  57. package/src/clients/tui/render-snapshot-adapter.ts +88 -0
  58. package/src/clients/web/synced-selectors.ts +132 -0
  59. package/src/codex/live-session.ts +82 -29
  60. package/src/config/config-core.ts +361 -10
  61. package/src/config/harness-paths.ts +4 -7
  62. package/src/config/harness-runtime-migration.ts +142 -19
  63. package/src/config/harness.config.template.jsonc +33 -0
  64. package/src/config/secrets-core.ts +92 -4
  65. package/src/control-plane/agent-realtime-api.ts +82 -427
  66. package/src/control-plane/prompt/thread-title-namer.ts +49 -23
  67. package/src/control-plane/session-summary.ts +10 -81
  68. package/src/control-plane/status/reducer-base.ts +12 -12
  69. package/src/control-plane/status/reducers/claude-status-reducer.ts +3 -3
  70. package/src/control-plane/status/reducers/codex-status-reducer.ts +4 -4
  71. package/src/control-plane/status/reducers/cursor-status-reducer.ts +3 -3
  72. package/src/control-plane/stream-client.ts +12 -2
  73. package/src/control-plane/stream-command-parser.ts +83 -143
  74. package/src/control-plane/stream-protocol.ts +53 -37
  75. package/src/control-plane/stream-server-background.ts +18 -2
  76. package/src/control-plane/stream-server-command.ts +376 -69
  77. package/src/control-plane/stream-server-session-runtime.ts +3 -2
  78. package/src/control-plane/stream-server.ts +943 -80
  79. package/src/control-plane/stream-session-runtime-types.ts +41 -0
  80. package/src/{mux/live-mux/control-plane-records.ts → core/contracts/records.ts} +24 -97
  81. package/src/core/state/observed-stream-cursor.ts +43 -0
  82. package/src/core/state/synced-observed-state.ts +273 -0
  83. package/src/core/store/harness-synced-store.ts +81 -0
  84. package/src/diff/budget.ts +136 -0
  85. package/src/diff/build.ts +289 -0
  86. package/src/diff/chunker.ts +146 -0
  87. package/src/diff/git-invoke.ts +315 -0
  88. package/src/diff/git-parse.ts +472 -0
  89. package/src/diff/hash.ts +70 -0
  90. package/src/diff/index.ts +24 -0
  91. package/src/diff/normalize.ts +134 -0
  92. package/src/diff/types.ts +178 -0
  93. package/src/diff-ui/args.ts +346 -0
  94. package/src/diff-ui/commands.ts +123 -0
  95. package/src/diff-ui/finder.ts +94 -0
  96. package/src/diff-ui/highlight.ts +127 -0
  97. package/src/diff-ui/index.ts +2 -0
  98. package/src/diff-ui/model.ts +141 -0
  99. package/src/diff-ui/pager.ts +412 -0
  100. package/src/diff-ui/render.ts +337 -0
  101. package/src/diff-ui/runtime.ts +379 -0
  102. package/src/diff-ui/state.ts +224 -0
  103. package/src/diff-ui/types.ts +236 -0
  104. package/src/domain/conversations.ts +11 -7
  105. package/src/domain/workspace.ts +76 -4
  106. package/src/mux/control-plane-op-queue.ts +93 -7
  107. package/src/mux/conversation-rail.ts +28 -71
  108. package/src/mux/dual-pane-core.ts +13 -13
  109. package/src/mux/harness-core-ui.ts +313 -42
  110. package/src/mux/input-shortcuts.ts +22 -112
  111. package/src/mux/keybinding-catalog.ts +340 -0
  112. package/src/mux/keybinding-registry.ts +103 -0
  113. package/src/mux/live-mux/command-menu-open-in.ts +280 -0
  114. package/src/mux/live-mux/command-menu.ts +167 -4
  115. package/src/mux/live-mux/conversation-state.ts +13 -0
  116. package/src/mux/live-mux/directory-resolution.ts +1 -1
  117. package/src/mux/live-mux/git-parsing.ts +16 -0
  118. package/src/mux/live-mux/git-snapshot.ts +33 -2
  119. package/src/mux/live-mux/global-shortcut-handlers.ts +6 -0
  120. package/src/mux/live-mux/home-pane-drop.ts +1 -1
  121. package/src/mux/live-mux/home-pane-pointer.ts +10 -0
  122. package/src/mux/live-mux/input-forwarding.ts +59 -2
  123. package/src/mux/live-mux/left-nav-activation.ts +124 -7
  124. package/src/mux/live-mux/left-nav.ts +35 -0
  125. package/src/mux/live-mux/link-click.ts +292 -0
  126. package/src/mux/live-mux/modal-command-menu-handler.ts +46 -9
  127. package/src/mux/live-mux/modal-conversation-handlers.ts +5 -1
  128. package/src/mux/live-mux/modal-input-reducers.ts +106 -8
  129. package/src/mux/live-mux/modal-overlays.ts +210 -31
  130. package/src/mux/live-mux/modal-pointer.ts +3 -7
  131. package/src/mux/live-mux/modal-prompt-handlers.ts +107 -1
  132. package/src/mux/live-mux/modal-release-notes-handler.ts +111 -0
  133. package/src/mux/live-mux/modal-task-editor-handler.ts +16 -11
  134. package/src/mux/live-mux/pointer-routing.ts +5 -2
  135. package/src/mux/live-mux/project-pane-pointer.ts +8 -0
  136. package/src/mux/live-mux/rail-layout.ts +33 -30
  137. package/src/mux/live-mux/release-notes.ts +383 -0
  138. package/src/mux/live-mux/render-trace-analysis.ts +52 -7
  139. package/src/mux/live-mux/repository-folding.ts +3 -0
  140. package/src/mux/live-mux/selection.ts +0 -4
  141. package/src/mux/live-mux/session-diagnostics-paths.ts +21 -0
  142. package/src/mux/project-pane-github-review.ts +271 -0
  143. package/src/mux/render-frame.ts +4 -0
  144. package/src/mux/runtime-app/codex-live-mux-runtime.ts +5191 -0
  145. package/src/mux/task-composer.ts +21 -14
  146. package/src/mux/task-focused-pane.ts +118 -117
  147. package/src/mux/task-screen-keybindings.ts +19 -82
  148. package/src/mux/workspace-rail-model.ts +270 -104
  149. package/src/mux/workspace-rail.ts +45 -22
  150. package/src/pty/session-broker.ts +1 -1
  151. package/{scripts → src/recording}/terminal-recording-gif-lib.ts +2 -2
  152. package/src/services/control-plane.ts +50 -32
  153. package/src/services/conversation-lifecycle.ts +118 -87
  154. package/src/services/conversation-startup-hydration.ts +20 -12
  155. package/src/services/directory-hydration.ts +21 -16
  156. package/src/services/event-persistence.ts +7 -0
  157. package/src/services/left-rail-pointer-handler.ts +329 -0
  158. package/src/services/mux-ui-state-persistence.ts +5 -1
  159. package/src/services/recording.ts +34 -26
  160. package/src/services/runtime-command-menu-agent-tools.ts +1 -1
  161. package/src/services/runtime-control-actions.ts +79 -61
  162. package/src/services/runtime-control-plane-ops.ts +122 -83
  163. package/src/services/runtime-conversation-actions.ts +40 -26
  164. package/src/services/runtime-conversation-activation.ts +82 -30
  165. package/src/services/runtime-conversation-starter.ts +80 -48
  166. package/src/services/runtime-conversation-title-edit.ts +91 -80
  167. package/src/services/runtime-envelope-handler.ts +107 -105
  168. package/src/services/runtime-git-state.ts +42 -29
  169. package/src/services/runtime-layout-resize.ts +3 -1
  170. package/src/services/runtime-left-rail-render.ts +99 -63
  171. package/src/services/runtime-nim-cli-session.ts +438 -0
  172. package/src/services/runtime-nim-session.ts +705 -0
  173. package/src/services/runtime-nim-tool-bridge.ts +141 -0
  174. package/src/services/runtime-observed-event-projection-pipeline.ts +45 -0
  175. package/src/services/runtime-process-wiring.ts +29 -36
  176. package/src/services/runtime-project-pane-github-review-cache.ts +164 -0
  177. package/src/services/runtime-render-flush.ts +63 -70
  178. package/src/services/runtime-render-lifecycle.ts +65 -64
  179. package/src/services/runtime-render-orchestrator.ts +55 -45
  180. package/src/services/runtime-render-pipeline.ts +106 -103
  181. package/src/services/runtime-render-state.ts +62 -49
  182. package/src/services/runtime-repository-actions.ts +97 -70
  183. package/src/services/runtime-right-pane-render.ts +80 -53
  184. package/src/services/runtime-shutdown.ts +38 -35
  185. package/src/services/runtime-stream-subscriptions.ts +35 -27
  186. package/src/services/runtime-task-composer-persistence.ts +71 -59
  187. package/src/services/runtime-task-composer-snapshot.ts +14 -0
  188. package/src/services/runtime-task-editor-actions.ts +46 -29
  189. package/src/services/runtime-task-pane-actions.ts +220 -134
  190. package/src/services/runtime-task-pane-shortcuts.ts +323 -123
  191. package/src/services/runtime-workspace-observed-effect-queue.ts +25 -0
  192. package/src/services/runtime-workspace-observed-events.ts +33 -184
  193. package/src/services/runtime-workspace-observed-transition-policy.ts +228 -0
  194. package/src/services/session-diagnostics-store.ts +217 -0
  195. package/src/services/startup-background-resume.ts +26 -21
  196. package/src/services/startup-orchestrator.ts +16 -13
  197. package/src/services/startup-paint-tracker.ts +29 -21
  198. package/src/services/startup-persisted-conversation-queue.ts +19 -13
  199. package/src/services/startup-settled-gate.ts +25 -15
  200. package/src/services/startup-shutdown.ts +18 -22
  201. package/src/services/startup-state-hydration.ts +44 -34
  202. package/src/services/startup-visibility.ts +12 -4
  203. package/src/services/task-pane-selection-actions.ts +89 -72
  204. package/src/services/task-planning-hydration.ts +24 -18
  205. package/src/services/task-planning-observed-events.ts +50 -52
  206. package/src/services/workspace-observed-events.ts +66 -63
  207. package/src/storage/storage-lifecycle-core.ts +438 -0
  208. package/src/store/control-plane-store-normalize.ts +33 -242
  209. package/src/store/control-plane-store-types.ts +1 -35
  210. package/src/store/control-plane-store.ts +396 -56
  211. package/src/store/event-store.ts +397 -3
  212. package/src/terminal/snapshot-oracle.ts +207 -94
  213. package/src/ui/mux-theme.ts +112 -8
  214. package/src/ui/panes/home-gridfire.ts +40 -31
  215. package/src/ui/panes/home.ts +10 -2
  216. package/src/ui/panes/nim.ts +315 -0
  217. package/src/mux/live-mux/actions-task.ts +0 -115
  218. package/src/mux/live-mux/left-rail-actions.ts +0 -118
  219. package/src/mux/live-mux/left-rail-conversation-click.ts +0 -82
  220. package/src/mux/live-mux/left-rail-pointer.ts +0 -74
  221. package/src/mux/live-mux/task-pane-shortcuts.ts +0 -206
  222. package/src/services/runtime-directory-actions.ts +0 -164
  223. package/src/services/runtime-input-pipeline.ts +0 -50
  224. package/src/services/runtime-input-router.ts +0 -189
  225. package/src/services/runtime-main-pane-input.ts +0 -230
  226. package/src/services/runtime-modal-input.ts +0 -119
  227. package/src/services/runtime-navigation-input.ts +0 -197
  228. package/src/services/runtime-rail-input.ts +0 -278
  229. package/src/services/runtime-task-pane.ts +0 -62
  230. package/src/services/runtime-workspace-actions.ts +0 -158
  231. package/src/ui/conversation-input-forwarder.ts +0 -114
  232. package/src/ui/conversation-selection-input.ts +0 -103
  233. package/src/ui/global-shortcut-input.ts +0 -89
  234. package/src/ui/input.ts +0 -238
  235. package/src/ui/kit.ts +0 -509
  236. package/src/ui/left-nav-input.ts +0 -80
  237. package/src/ui/left-rail-pointer-input.ts +0 -148
  238. package/src/ui/repository-fold-input.ts +0 -91
  239. package/src/ui/surface.ts +0 -224
@@ -0,0 +1,271 @@
1
+ export type ProjectPaneGitHubToggleAction = `project.github.toggle:${string}`;
2
+
3
+ type ProjectPaneGitHubPrLifecycleState = 'draft' | 'open' | 'merged' | 'closed';
4
+ type ProjectPaneGitHubCiRollup =
5
+ | 'pending'
6
+ | 'success'
7
+ | 'failure'
8
+ | 'cancelled'
9
+ | 'neutral'
10
+ | 'none';
11
+
12
+ export interface ProjectPaneGitHubReviewComment {
13
+ readonly commentId: string;
14
+ readonly authorLogin: string | null;
15
+ readonly body: string;
16
+ readonly url: string | null;
17
+ readonly createdAt: string;
18
+ readonly updatedAt: string;
19
+ }
20
+
21
+ export interface ProjectPaneGitHubReviewThread {
22
+ readonly threadId: string;
23
+ readonly isResolved: boolean;
24
+ readonly isOutdated: boolean;
25
+ readonly resolvedByLogin: string | null;
26
+ readonly comments: readonly ProjectPaneGitHubReviewComment[];
27
+ }
28
+
29
+ export interface ProjectPaneGitHubPullRequestSummary {
30
+ readonly number: number;
31
+ readonly title: string;
32
+ readonly url: string;
33
+ readonly authorLogin: string | null;
34
+ readonly headBranch: string;
35
+ readonly baseBranch: string;
36
+ readonly state: ProjectPaneGitHubPrLifecycleState;
37
+ readonly isDraft: boolean;
38
+ readonly mergedAt: string | null;
39
+ readonly closedAt: string | null;
40
+ readonly ciRollup?: ProjectPaneGitHubCiRollup | null;
41
+ readonly updatedAt: string;
42
+ readonly createdAt: string;
43
+ }
44
+
45
+ export interface ProjectPaneGitHubReviewSummary {
46
+ readonly status: 'loading' | 'ready' | 'error';
47
+ readonly branchName: string | null;
48
+ readonly branchSource: 'pinned' | 'current' | null;
49
+ readonly pr: ProjectPaneGitHubPullRequestSummary | null;
50
+ readonly openThreads: readonly ProjectPaneGitHubReviewThread[];
51
+ readonly resolvedThreads: readonly ProjectPaneGitHubReviewThread[];
52
+ readonly errorMessage: string | null;
53
+ }
54
+
55
+ interface BuildProjectPaneGitHubReviewLinesInput {
56
+ readonly review: ProjectPaneGitHubReviewSummary;
57
+ readonly expandedNodeIds: ReadonlySet<string>;
58
+ }
59
+
60
+ interface BuildProjectPaneGitHubReviewLinesResult {
61
+ readonly lines: readonly string[];
62
+ readonly actionByRelativeLineIndex: Readonly<Record<number, ProjectPaneGitHubToggleAction>>;
63
+ }
64
+
65
+ const OPEN_THREAD_GROUP_NODE_ID = 'github/open-threads';
66
+ const RESOLVED_THREAD_GROUP_NODE_ID = 'github/resolved-threads';
67
+
68
+ function sanitizeInlineText(value: string): string {
69
+ const collapsed = value.replace(/\s+/gu, ' ').trim();
70
+ return collapsed;
71
+ }
72
+
73
+ function commentPreview(body: string, maxLength = 160): string {
74
+ const normalized = sanitizeInlineText(body);
75
+ if (normalized.length <= maxLength) {
76
+ return normalized;
77
+ }
78
+ return `${normalized.slice(0, maxLength - 1)}…`;
79
+ }
80
+
81
+ function formatAuthor(login: string | null): string {
82
+ const normalized = login?.trim() ?? '';
83
+ return normalized.length > 0 ? `@${normalized}` : '@unknown';
84
+ }
85
+
86
+ function countComments(threads: readonly ProjectPaneGitHubReviewThread[]): number {
87
+ let total = 0;
88
+ for (const thread of threads) {
89
+ total += thread.comments.length;
90
+ }
91
+ return total;
92
+ }
93
+
94
+ function prStateLabel(pr: ProjectPaneGitHubPullRequestSummary): string {
95
+ if (pr.isDraft || pr.state === 'draft') {
96
+ return 'draft';
97
+ }
98
+ if (pr.state === 'merged') {
99
+ return 'merged';
100
+ }
101
+ if (pr.state === 'closed') {
102
+ return 'closed';
103
+ }
104
+ return 'open';
105
+ }
106
+
107
+ function toggleAction(nodeId: string): ProjectPaneGitHubToggleAction {
108
+ return `project.github.toggle:${nodeId}`;
109
+ }
110
+
111
+ function threadNodeId(thread: ProjectPaneGitHubReviewThread): string {
112
+ return `github/thread:${thread.threadId}`;
113
+ }
114
+
115
+ function pushLine(
116
+ lines: string[],
117
+ actionByRelativeLineIndex: Record<number, ProjectPaneGitHubToggleAction>,
118
+ line: string,
119
+ action: ProjectPaneGitHubToggleAction | null,
120
+ ): void {
121
+ const nextIndex = lines.length;
122
+ lines.push(line);
123
+ if (action !== null) {
124
+ actionByRelativeLineIndex[nextIndex] = action;
125
+ }
126
+ }
127
+
128
+ function appendThreadGroup(
129
+ lines: string[],
130
+ actionByRelativeLineIndex: Record<number, ProjectPaneGitHubToggleAction>,
131
+ input: {
132
+ readonly label: string;
133
+ readonly nodeId: string;
134
+ readonly threads: readonly ProjectPaneGitHubReviewThread[];
135
+ readonly expandedNodeIds: ReadonlySet<string>;
136
+ },
137
+ ): void {
138
+ const commentCount = countComments(input.threads);
139
+ const expanded = input.expandedNodeIds.has(input.nodeId);
140
+ const groupGlyph = expanded ? '▼' : '▶';
141
+ pushLine(
142
+ lines,
143
+ actionByRelativeLineIndex,
144
+ `${groupGlyph} ${input.label} (${String(input.threads.length)} threads, ${String(commentCount)} comments)`,
145
+ toggleAction(input.nodeId),
146
+ );
147
+ if (!expanded) {
148
+ return;
149
+ }
150
+ if (input.threads.length === 0) {
151
+ pushLine(lines, actionByRelativeLineIndex, ' (none)', null);
152
+ return;
153
+ }
154
+
155
+ for (const thread of input.threads) {
156
+ const nodeId = threadNodeId(thread);
157
+ const threadExpanded = input.expandedNodeIds.has(nodeId);
158
+ const threadGlyph = threadExpanded ? '▼' : '▶';
159
+ const firstAuthor = thread.comments[0]?.authorLogin ?? null;
160
+ const metadataParts: string[] = [];
161
+ if (thread.isOutdated) {
162
+ metadataParts.push('outdated');
163
+ }
164
+ if (thread.isResolved && thread.resolvedByLogin !== null) {
165
+ metadataParts.push(`resolved by ${formatAuthor(thread.resolvedByLogin)}`);
166
+ }
167
+ const metadataSuffix = metadataParts.length === 0 ? '' : `, ${metadataParts.join(', ')}`;
168
+ pushLine(
169
+ lines,
170
+ actionByRelativeLineIndex,
171
+ ` ${threadGlyph} ${formatAuthor(firstAuthor)} (${String(thread.comments.length)} comments${metadataSuffix})`,
172
+ toggleAction(nodeId),
173
+ );
174
+ if (!threadExpanded) {
175
+ continue;
176
+ }
177
+ if (thread.comments.length === 0) {
178
+ pushLine(lines, actionByRelativeLineIndex, ' - (no comments)', null);
179
+ continue;
180
+ }
181
+ for (const comment of thread.comments) {
182
+ const preview = commentPreview(comment.body);
183
+ pushLine(
184
+ lines,
185
+ actionByRelativeLineIndex,
186
+ ` - ${formatAuthor(comment.authorLogin)}: ${preview}`,
187
+ null,
188
+ );
189
+ }
190
+ }
191
+ }
192
+
193
+ export function buildProjectPaneGitHubReviewLines(
194
+ input: BuildProjectPaneGitHubReviewLinesInput,
195
+ ): BuildProjectPaneGitHubReviewLinesResult {
196
+ const lines: string[] = [];
197
+ const actionByRelativeLineIndex: Record<number, ProjectPaneGitHubToggleAction> = {};
198
+
199
+ pushLine(lines, actionByRelativeLineIndex, 'github review', null);
200
+
201
+ const branchName = input.review.branchName?.trim() ?? '';
202
+ const branchSource = input.review.branchSource;
203
+ const sourceLabel = branchSource === null ? '' : ` (${branchSource})`;
204
+ pushLine(
205
+ lines,
206
+ actionByRelativeLineIndex,
207
+ `branch ${branchName.length > 0 ? branchName : '(none)'}${sourceLabel}`,
208
+ null,
209
+ );
210
+
211
+ if (input.review.status === 'loading') {
212
+ pushLine(lines, actionByRelativeLineIndex, 'status loading GitHub review data…', null);
213
+ return {
214
+ lines,
215
+ actionByRelativeLineIndex,
216
+ };
217
+ }
218
+
219
+ if (input.review.status === 'error') {
220
+ const message =
221
+ input.review.errorMessage === null
222
+ ? 'unknown error'
223
+ : sanitizeInlineText(input.review.errorMessage);
224
+ pushLine(lines, actionByRelativeLineIndex, `status error ${message}`, null);
225
+ return {
226
+ lines,
227
+ actionByRelativeLineIndex,
228
+ };
229
+ }
230
+
231
+ const pr = input.review.pr;
232
+ if (pr === null) {
233
+ pushLine(lines, actionByRelativeLineIndex, 'pr none for tracked branch', null);
234
+ return {
235
+ lines,
236
+ actionByRelativeLineIndex,
237
+ };
238
+ }
239
+
240
+ const stateLabel = prStateLabel(pr);
241
+ pushLine(
242
+ lines,
243
+ actionByRelativeLineIndex,
244
+ `pr #${String(pr.number)} ${stateLabel} ${sanitizeInlineText(pr.title)}`,
245
+ null,
246
+ );
247
+ pushLine(
248
+ lines,
249
+ actionByRelativeLineIndex,
250
+ `from ${pr.headBranch} -> ${pr.baseBranch} by ${formatAuthor(pr.authorLogin)}`,
251
+ null,
252
+ );
253
+
254
+ appendThreadGroup(lines, actionByRelativeLineIndex, {
255
+ label: 'open comments',
256
+ nodeId: OPEN_THREAD_GROUP_NODE_ID,
257
+ threads: input.review.openThreads,
258
+ expandedNodeIds: input.expandedNodeIds,
259
+ });
260
+ appendThreadGroup(lines, actionByRelativeLineIndex, {
261
+ label: 'resolved comments',
262
+ nodeId: RESOLVED_THREAD_GROUP_NODE_ID,
263
+ threads: input.review.resolvedThreads,
264
+ expandedNodeIds: input.expandedNodeIds,
265
+ });
266
+
267
+ return {
268
+ lines,
269
+ actionByRelativeLineIndex,
270
+ };
271
+ }
@@ -38,6 +38,7 @@ export function buildRenderRows(
38
38
  rightRows: readonly string[],
39
39
  perf: MuxPerfStatusRow,
40
40
  statusRowDetailText?: string,
41
+ showStatusRow = true,
41
42
  ): string[] {
42
43
  const rows: string[] = [];
43
44
  const separatorAnchor = `\u001b[${String(layout.separatorCol)}G`;
@@ -47,6 +48,9 @@ export function buildRenderRows(
47
48
  const right = rightRows[row] ?? ' '.repeat(layout.rightCols);
48
49
  rows.push(`${left}\u001b[0m${separatorAnchor}${MUTED_SEPARATOR}${rightAnchor}${right}`);
49
50
  }
51
+ if (!showStatusRow) {
52
+ return rows;
53
+ }
50
54
  const defaultStatus = `[mux] fps=${perf.fps.toFixed(1)} kb/s=${perf.kbPerSecond.toFixed(1)} render=${perf.renderAvgMs.toFixed(2)}/${perf.renderMaxMs.toFixed(2)}ms output=${perf.outputHandleAvgMs.toFixed(2)}/${perf.outputHandleMaxMs.toFixed(2)}ms loop.p95=${perf.eventLoopP95Ms.toFixed(1)}ms`;
51
55
  const statusText =
52
56
  statusRowDetailText === undefined || statusRowDetailText.length === 0