@jmoyers/harness 0.1.11 → 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 (232) hide show
  1. package/README.md +31 -39
  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/packages/harness-ui/src/modal-manager.ts +222 -0
  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 -3872
  38. package/scripts/control-plane-daemon.ts +11 -0
  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 -3019
  43. package/scripts/nim-tui-smoke.ts +748 -0
  44. package/src/cli/auth/runtime.ts +948 -0
  45. package/src/cli/gateway/runtime.ts +1872 -0
  46. package/src/cli/parsing/flags.ts +23 -0
  47. package/src/cli/parsing/session.ts +42 -0
  48. package/src/cli/runtime/context.ts +193 -0
  49. package/src/cli/runtime-app/application.ts +392 -0
  50. package/src/cli/runtime-infra/gateway-control.ts +729 -0
  51. package/{scripts/harness-inspector.ts → src/cli/workflows/inspector.ts} +14 -11
  52. package/src/cli/workflows/runtime.ts +965 -0
  53. package/src/clients/tui/left-rail-interactions.ts +519 -0
  54. package/src/clients/tui/main-pane-interactions.ts +509 -0
  55. package/src/clients/tui/modal-input-routing.ts +71 -0
  56. package/src/clients/tui/render-snapshot-adapter.ts +88 -0
  57. package/src/clients/web/synced-selectors.ts +132 -0
  58. package/src/codex/live-session.ts +82 -29
  59. package/src/config/config-core.ts +348 -8
  60. package/src/config/harness.config.template.jsonc +33 -0
  61. package/src/control-plane/agent-realtime-api.ts +82 -427
  62. package/src/control-plane/session-summary.ts +10 -81
  63. package/src/control-plane/status/reducer-base.ts +12 -12
  64. package/src/control-plane/status/reducers/claude-status-reducer.ts +3 -3
  65. package/src/control-plane/status/reducers/codex-status-reducer.ts +4 -4
  66. package/src/control-plane/status/reducers/cursor-status-reducer.ts +3 -3
  67. package/src/control-plane/stream-client.ts +12 -2
  68. package/src/control-plane/stream-command-parser.ts +83 -143
  69. package/src/control-plane/stream-protocol.ts +53 -37
  70. package/src/control-plane/stream-server-command.ts +376 -69
  71. package/src/control-plane/stream-server-session-runtime.ts +3 -2
  72. package/src/control-plane/stream-server.ts +864 -70
  73. package/src/control-plane/stream-session-runtime-types.ts +41 -0
  74. package/src/{mux/live-mux/control-plane-records.ts → core/contracts/records.ts} +24 -97
  75. package/src/core/state/observed-stream-cursor.ts +43 -0
  76. package/src/core/state/synced-observed-state.ts +273 -0
  77. package/src/core/store/harness-synced-store.ts +81 -0
  78. package/src/diff/budget.ts +136 -0
  79. package/src/diff/build.ts +289 -0
  80. package/src/diff/chunker.ts +146 -0
  81. package/src/diff/git-invoke.ts +315 -0
  82. package/src/diff/git-parse.ts +472 -0
  83. package/src/diff/hash.ts +70 -0
  84. package/src/diff/index.ts +24 -0
  85. package/src/diff/normalize.ts +134 -0
  86. package/src/diff/types.ts +178 -0
  87. package/src/diff-ui/args.ts +346 -0
  88. package/src/diff-ui/commands.ts +123 -0
  89. package/src/diff-ui/finder.ts +94 -0
  90. package/src/diff-ui/highlight.ts +127 -0
  91. package/src/diff-ui/index.ts +2 -0
  92. package/src/diff-ui/model.ts +141 -0
  93. package/src/diff-ui/pager.ts +412 -0
  94. package/src/diff-ui/render.ts +337 -0
  95. package/src/diff-ui/runtime.ts +379 -0
  96. package/src/diff-ui/state.ts +224 -0
  97. package/src/diff-ui/types.ts +236 -0
  98. package/src/domain/workspace.ts +68 -5
  99. package/src/mux/control-plane-op-queue.ts +93 -7
  100. package/src/mux/conversation-rail.ts +28 -71
  101. package/src/mux/dual-pane-core.ts +13 -13
  102. package/src/mux/harness-core-ui.ts +313 -42
  103. package/src/mux/input-shortcuts.ts +13 -131
  104. package/src/mux/keybinding-catalog.ts +340 -0
  105. package/src/mux/keybinding-registry.ts +103 -0
  106. package/src/mux/live-mux/command-menu-open-in.ts +280 -0
  107. package/src/mux/live-mux/command-menu.ts +167 -4
  108. package/src/mux/live-mux/conversation-state.ts +13 -0
  109. package/src/mux/live-mux/directory-resolution.ts +1 -1
  110. package/src/mux/live-mux/git-snapshot.ts +33 -2
  111. package/src/mux/live-mux/global-shortcut-handlers.ts +6 -0
  112. package/src/mux/live-mux/home-pane-drop.ts +1 -1
  113. package/src/mux/live-mux/home-pane-pointer.ts +10 -0
  114. package/src/mux/live-mux/input-forwarding.ts +59 -2
  115. package/src/mux/live-mux/left-nav-activation.ts +124 -7
  116. package/src/mux/live-mux/left-nav.ts +35 -0
  117. package/src/mux/live-mux/link-click.ts +292 -0
  118. package/src/mux/live-mux/modal-command-menu-handler.ts +46 -9
  119. package/src/mux/live-mux/modal-conversation-handlers.ts +5 -1
  120. package/src/mux/live-mux/modal-input-reducers.ts +77 -12
  121. package/src/mux/live-mux/modal-overlays.ts +168 -34
  122. package/src/mux/live-mux/modal-pointer.ts +3 -7
  123. package/src/mux/live-mux/modal-prompt-handlers.ts +23 -2
  124. package/src/mux/live-mux/modal-release-notes-handler.ts +111 -0
  125. package/src/mux/live-mux/modal-task-editor-handler.ts +16 -11
  126. package/src/mux/live-mux/pointer-routing.ts +5 -2
  127. package/src/mux/live-mux/project-pane-pointer.ts +8 -0
  128. package/src/mux/live-mux/rail-layout.ts +33 -30
  129. package/src/mux/live-mux/release-notes.ts +383 -0
  130. package/src/mux/live-mux/render-trace-analysis.ts +52 -7
  131. package/src/mux/live-mux/repository-folding.ts +3 -0
  132. package/src/mux/live-mux/selection.ts +0 -4
  133. package/src/mux/live-mux/session-diagnostics-paths.ts +21 -0
  134. package/src/mux/project-pane-github-review.ts +271 -0
  135. package/src/mux/render-frame.ts +4 -0
  136. package/src/mux/runtime-app/codex-live-mux-runtime.ts +5191 -0
  137. package/src/mux/task-composer.ts +21 -14
  138. package/src/mux/task-focused-pane.ts +118 -117
  139. package/src/mux/task-screen-keybindings.ts +10 -101
  140. package/src/mux/workspace-rail-model.ts +270 -104
  141. package/src/mux/workspace-rail.ts +45 -22
  142. package/src/pty/session-broker.ts +1 -1
  143. package/{scripts → src/recording}/terminal-recording-gif-lib.ts +2 -2
  144. package/src/services/control-plane.ts +50 -32
  145. package/src/services/conversation-lifecycle.ts +118 -87
  146. package/src/services/conversation-startup-hydration.ts +20 -12
  147. package/src/services/directory-hydration.ts +21 -16
  148. package/src/services/event-persistence.ts +7 -0
  149. package/src/services/left-rail-pointer-handler.ts +329 -0
  150. package/src/services/mux-ui-state-persistence.ts +5 -1
  151. package/src/services/recording.ts +34 -26
  152. package/src/services/runtime-command-menu-agent-tools.ts +1 -1
  153. package/src/services/runtime-control-actions.ts +79 -61
  154. package/src/services/runtime-control-plane-ops.ts +122 -83
  155. package/src/services/runtime-conversation-actions.ts +40 -26
  156. package/src/services/runtime-conversation-activation.ts +73 -46
  157. package/src/services/runtime-conversation-starter.ts +53 -45
  158. package/src/services/runtime-conversation-title-edit.ts +91 -80
  159. package/src/services/runtime-envelope-handler.ts +107 -105
  160. package/src/services/runtime-git-state.ts +42 -29
  161. package/src/services/runtime-layout-resize.ts +3 -1
  162. package/src/services/runtime-left-rail-render.ts +99 -63
  163. package/src/services/runtime-nim-cli-session.ts +438 -0
  164. package/src/services/runtime-nim-session.ts +705 -0
  165. package/src/services/runtime-nim-tool-bridge.ts +141 -0
  166. package/src/services/runtime-observed-event-projection-pipeline.ts +45 -0
  167. package/src/services/runtime-process-wiring.ts +29 -36
  168. package/src/services/runtime-project-pane-github-review-cache.ts +164 -0
  169. package/src/services/runtime-render-flush.ts +63 -70
  170. package/src/services/runtime-render-lifecycle.ts +65 -64
  171. package/src/services/runtime-render-orchestrator.ts +55 -45
  172. package/src/services/runtime-render-pipeline.ts +106 -103
  173. package/src/services/runtime-render-state.ts +62 -49
  174. package/src/services/runtime-repository-actions.ts +97 -72
  175. package/src/services/runtime-right-pane-render.ts +80 -53
  176. package/src/services/runtime-shutdown.ts +38 -35
  177. package/src/services/runtime-stream-subscriptions.ts +35 -27
  178. package/src/services/runtime-task-composer-persistence.ts +71 -59
  179. package/src/services/runtime-task-composer-snapshot.ts +14 -0
  180. package/src/services/runtime-task-editor-actions.ts +46 -29
  181. package/src/services/runtime-task-pane-actions.ts +220 -134
  182. package/src/services/runtime-task-pane-shortcuts.ts +323 -123
  183. package/src/services/runtime-workspace-observed-effect-queue.ts +25 -0
  184. package/src/services/runtime-workspace-observed-events.ts +33 -184
  185. package/src/services/runtime-workspace-observed-transition-policy.ts +228 -0
  186. package/src/services/session-diagnostics-store.ts +217 -0
  187. package/src/services/startup-background-resume.ts +26 -21
  188. package/src/services/startup-orchestrator.ts +16 -13
  189. package/src/services/startup-paint-tracker.ts +29 -21
  190. package/src/services/startup-persisted-conversation-queue.ts +19 -13
  191. package/src/services/startup-settled-gate.ts +25 -15
  192. package/src/services/startup-shutdown.ts +18 -22
  193. package/src/services/startup-state-hydration.ts +44 -34
  194. package/src/services/startup-visibility.ts +12 -4
  195. package/src/services/task-pane-selection-actions.ts +89 -72
  196. package/src/services/task-planning-hydration.ts +24 -18
  197. package/src/services/task-planning-observed-events.ts +50 -52
  198. package/src/services/workspace-observed-events.ts +66 -63
  199. package/src/storage/storage-lifecycle-core.ts +438 -0
  200. package/src/store/control-plane-store-normalize.ts +33 -242
  201. package/src/store/control-plane-store-types.ts +1 -35
  202. package/src/store/control-plane-store.ts +360 -56
  203. package/src/store/event-store.ts +366 -8
  204. package/src/terminal/snapshot-oracle.ts +207 -94
  205. package/src/ui/mux-theme.ts +112 -8
  206. package/src/ui/panes/home-gridfire.ts +40 -31
  207. package/src/ui/panes/home.ts +10 -2
  208. package/src/ui/panes/nim.ts +315 -0
  209. package/src/mux/live-mux/actions-task.ts +0 -115
  210. package/src/mux/live-mux/left-rail-actions.ts +0 -118
  211. package/src/mux/live-mux/left-rail-conversation-click.ts +0 -85
  212. package/src/mux/live-mux/left-rail-pointer.ts +0 -74
  213. package/src/mux/live-mux/task-pane-shortcuts.ts +0 -206
  214. package/src/services/runtime-directory-actions.ts +0 -164
  215. package/src/services/runtime-input-pipeline.ts +0 -50
  216. package/src/services/runtime-input-router.ts +0 -195
  217. package/src/services/runtime-main-pane-input.ts +0 -230
  218. package/src/services/runtime-modal-input.ts +0 -137
  219. package/src/services/runtime-navigation-input.ts +0 -197
  220. package/src/services/runtime-rail-input.ts +0 -279
  221. package/src/services/runtime-task-pane.ts +0 -62
  222. package/src/services/runtime-workspace-actions.ts +0 -158
  223. package/src/ui/conversation-input-forwarder.ts +0 -114
  224. package/src/ui/conversation-selection-input.ts +0 -103
  225. package/src/ui/global-shortcut-input.ts +0 -89
  226. package/src/ui/input.ts +0 -269
  227. package/src/ui/kit.ts +0 -509
  228. package/src/ui/left-nav-input.ts +0 -80
  229. package/src/ui/left-rail-pointer-input.ts +0 -148
  230. package/src/ui/modals/manager.ts +0 -218
  231. package/src/ui/repository-fold-input.ts +0 -91
  232. package/src/ui/surface.ts +0 -224
@@ -231,7 +231,18 @@ async function main(): Promise<number> {
231
231
  branchStrategy: loadedConfig.config.github.branchStrategy,
232
232
  viewerLogin: loadedConfig.config.github.viewerLogin,
233
233
  },
234
+ linear: {
235
+ enabled: loadedConfig.config.linear.enabled,
236
+ apiBaseUrl: loadedConfig.config.linear.apiBaseUrl,
237
+ tokenEnvVar: loadedConfig.config.linear.tokenEnvVar,
238
+ },
234
239
  lifecycleHooks: loadedConfig.config.hooks.lifecycle,
240
+ storageLifecyclePolicy: loadedConfig.config.storage.lifecycle,
241
+ storageLifecyclePolicyReload: {
242
+ cwd: invocationDirectory,
243
+ filePath: configPath,
244
+ env: process.env,
245
+ },
235
246
  startSession: (input) => {
236
247
  const sessionOptions: Parameters<typeof startCodexLiveSession>[0] = {
237
248
  args: input.args,
@@ -67,8 +67,13 @@ if (!ensureBunAvailable({ command: bunCommand })) {
67
67
  const here = dirname(fileURLToPath(import.meta.url));
68
68
  const scriptPath = resolve(here, './harness.ts');
69
69
  const runtimeArgs = [scriptPath, ...process.argv.slice(2)];
70
+ const runtimeEnv = {
71
+ ...process.env,
72
+ HARNESS_INVOKE_CWD: process.cwd(),
73
+ };
70
74
  const child = spawn(bunCommand, runtimeArgs, {
71
75
  stdio: 'inherit',
76
+ env: runtimeEnv,
72
77
  });
73
78
 
74
79
  child.once('exit', (code, signal) => {
@@ -0,0 +1,300 @@
1
+ import { Command, Flags } from '@oclif/core';
2
+ import {
3
+ parseSessionName,
4
+ runAnimateCli,
5
+ runAuthCli,
6
+ runClientCli,
7
+ runCursorHooksCli,
8
+ runDiffCli,
9
+ runGatewayCli,
10
+ runNimCli,
11
+ runProfileCli,
12
+ runRenderTraceCli,
13
+ runStatusTimelineCli,
14
+ runUpdateCli,
15
+ } from './harness-runtime.ts';
16
+
17
+ const sessionFlag = Flags.string({
18
+ description:
19
+ 'Session namespace used to isolate gateway record/log/db/profile/status-trace artifacts.',
20
+ });
21
+
22
+ interface SessionParseResult {
23
+ sessionName: string | null;
24
+ argv: readonly string[];
25
+ }
26
+
27
+ abstract class HarnessCommandBase extends Command {
28
+ static override strict = false;
29
+
30
+ protected extractSessionArg(argv: readonly string[]): SessionParseResult {
31
+ const passthrough: string[] = [];
32
+ let sessionName: string | null = null;
33
+
34
+ for (let index = 0; index < argv.length; index += 1) {
35
+ const arg = argv[index]!;
36
+ if (arg === '--session') {
37
+ const value = argv[index + 1];
38
+ if (value === undefined) {
39
+ throw new Error('missing value for --session');
40
+ }
41
+ sessionName = parseSessionName(value);
42
+ index += 1;
43
+ continue;
44
+ }
45
+ passthrough.push(arg);
46
+ }
47
+
48
+ return {
49
+ sessionName,
50
+ argv: passthrough,
51
+ };
52
+ }
53
+
54
+ protected exitIfNeeded(code: number): void {
55
+ if (code !== 0) {
56
+ this.exit(code);
57
+ }
58
+ }
59
+ }
60
+
61
+ class ClientCommand extends HarnessCommandBase {
62
+ static override summary = 'Launch the mux client (default when no explicit command is provided).';
63
+
64
+ static override usage = [
65
+ '[--session <name>] [mux-args...]',
66
+ 'client [--session <name>] [mux-args...]',
67
+ ];
68
+
69
+ static override flags = {
70
+ help: Flags.help({ char: 'h' }),
71
+ session: sessionFlag,
72
+ };
73
+
74
+ override async run(): Promise<void> {
75
+ const parsed = this.extractSessionArg(this.argv);
76
+ const code = await runClientCli(parsed.argv, parsed.sessionName);
77
+ this.exitIfNeeded(code);
78
+ }
79
+ }
80
+
81
+ class GatewayCommand extends HarnessCommandBase {
82
+ static override summary = 'Manage the control-plane gateway lifecycle and direct command calls.';
83
+
84
+ static override usage = [
85
+ 'gateway [--session <name>] start [--host <host>] [--port <port>] [--auth-token <token>] [--state-db-path <path>]',
86
+ 'gateway [--session <name>] run [--host <host>] [--port <port>] [--auth-token <token>] [--state-db-path <path>]',
87
+ 'gateway [--session <name>] stop [--force] [--timeout-ms <ms>] [--cleanup-orphans|--no-cleanup-orphans]',
88
+ 'gateway [--session <name>] status',
89
+ 'gateway [--session <name>] restart [--host <host>] [--port <port>] [--auth-token <token>] [--state-db-path <path>]',
90
+ 'gateway [--session <name>] call --json \'{"type":"session.list"}\'',
91
+ 'gateway [--session <name>] gc [--older-than-days <days>]',
92
+ ];
93
+
94
+ static override flags = {
95
+ help: Flags.help({ char: 'h' }),
96
+ session: sessionFlag,
97
+ };
98
+
99
+ override async run(): Promise<void> {
100
+ const parsed = this.extractSessionArg(this.argv);
101
+ if (parsed.argv.length === 0) {
102
+ this.error('missing gateway subcommand', { exit: 2 });
103
+ }
104
+ const code = await runGatewayCli(parsed.argv, parsed.sessionName);
105
+ this.exitIfNeeded(code);
106
+ }
107
+ }
108
+
109
+ class ProfileCommand extends HarnessCommandBase {
110
+ static override summary =
111
+ 'Manage gateway/client CPU profiling and live inspector profiling sessions.';
112
+
113
+ static override usage = [
114
+ 'profile [--session <name>] start [--profile-dir <path>]',
115
+ 'profile [--session <name>] stop [--timeout-ms <ms>]',
116
+ 'profile [--session <name>] run [--profile-dir <path>] [mux-args...]',
117
+ 'profile [--session <name>] [--profile-dir <path>] [mux-args...]',
118
+ ];
119
+
120
+ static override flags = {
121
+ help: Flags.help({ char: 'h' }),
122
+ session: sessionFlag,
123
+ };
124
+
125
+ override async run(): Promise<void> {
126
+ const parsed = this.extractSessionArg(this.argv);
127
+ const code = await runProfileCli(parsed.argv, parsed.sessionName);
128
+ this.exitIfNeeded(code);
129
+ }
130
+ }
131
+
132
+ class StatusTimelineCommand extends HarnessCommandBase {
133
+ static override summary = 'Start or stop writing status timeline artifacts for a session.';
134
+
135
+ static override usage = [
136
+ 'status-timeline [--session <name>] start [--output-path <path>]',
137
+ 'status-timeline [--session <name>] stop',
138
+ 'status-timeline [--session <name>] [--output-path <path>]',
139
+ ];
140
+
141
+ static override flags = {
142
+ help: Flags.help({ char: 'h' }),
143
+ session: sessionFlag,
144
+ };
145
+
146
+ override async run(): Promise<void> {
147
+ const parsed = this.extractSessionArg(this.argv);
148
+ const code = await runStatusTimelineCli(parsed.argv, parsed.sessionName);
149
+ this.exitIfNeeded(code);
150
+ }
151
+ }
152
+
153
+ class RenderTraceCommand extends HarnessCommandBase {
154
+ static override summary = 'Start or stop render trace recording for a session.';
155
+
156
+ static override usage = [
157
+ 'render-trace [--session <name>] start [--output-path <path>] [--conversation-id <id>]',
158
+ 'render-trace [--session <name>] stop',
159
+ 'render-trace [--session <name>] [--output-path <path>] [--conversation-id <id>]',
160
+ ];
161
+
162
+ static override flags = {
163
+ help: Flags.help({ char: 'h' }),
164
+ session: sessionFlag,
165
+ };
166
+
167
+ override async run(): Promise<void> {
168
+ const parsed = this.extractSessionArg(this.argv);
169
+ const code = await runRenderTraceCli(parsed.argv, parsed.sessionName);
170
+ this.exitIfNeeded(code);
171
+ }
172
+ }
173
+
174
+ class AuthCommand extends HarnessCommandBase {
175
+ static override summary = 'Authenticate providers and manage saved credential state.';
176
+
177
+ static override usage = [
178
+ 'auth login <github|linear> [--no-browser] [--timeout-ms <ms>] [--scopes <list>] [--callback-port <port>]',
179
+ 'auth logout <github|linear|all>',
180
+ 'auth status [--json]',
181
+ ];
182
+
183
+ static override flags = {
184
+ help: Flags.help({ char: 'h' }),
185
+ session: sessionFlag,
186
+ };
187
+
188
+ override async run(): Promise<void> {
189
+ const parsed = this.extractSessionArg(this.argv);
190
+ const code = await runAuthCli(parsed.argv, parsed.sessionName);
191
+ this.exitIfNeeded(code);
192
+ }
193
+ }
194
+
195
+ class UpdateCommand extends HarnessCommandBase {
196
+ static override summary = 'Install the latest Harness package globally using Bun.';
197
+
198
+ static override aliases = ['upgrade'];
199
+
200
+ static override usage = ['update', 'upgrade'];
201
+
202
+ static override flags = {
203
+ help: Flags.help({ char: 'h' }),
204
+ session: sessionFlag,
205
+ };
206
+
207
+ override async run(): Promise<void> {
208
+ const parsed = this.extractSessionArg(this.argv);
209
+ const code = runUpdateCli(parsed.argv, parsed.sessionName);
210
+ this.exitIfNeeded(code);
211
+ }
212
+ }
213
+
214
+ class CursorHooksCommand extends HarnessCommandBase {
215
+ static override summary = 'Install or uninstall managed Cursor hooks.';
216
+
217
+ static override usage = [
218
+ 'cursor-hooks [--session <name>] install [--hooks-file <path>]',
219
+ 'cursor-hooks [--session <name>] uninstall [--hooks-file <path>]',
220
+ ];
221
+
222
+ static override flags = {
223
+ help: Flags.help({ char: 'h' }),
224
+ session: sessionFlag,
225
+ };
226
+
227
+ override async run(): Promise<void> {
228
+ const parsed = this.extractSessionArg(this.argv);
229
+ const code = await runCursorHooksCli(parsed.argv, parsed.sessionName);
230
+ this.exitIfNeeded(code);
231
+ }
232
+ }
233
+
234
+ class AnimateCommand extends HarnessCommandBase {
235
+ static override summary = 'Render the terminal animation benchmark scene.';
236
+
237
+ static override usage = [
238
+ 'animate [--fps <fps>] [--frames <count>] [--duration-ms <ms>] [--seed <seed>] [--no-color]',
239
+ ];
240
+
241
+ static override flags = {
242
+ help: Flags.help({ char: 'h' }),
243
+ session: sessionFlag,
244
+ };
245
+
246
+ override async run(): Promise<void> {
247
+ const parsed = this.extractSessionArg(this.argv);
248
+ const code = await runAnimateCli(parsed.argv);
249
+ this.exitIfNeeded(code);
250
+ }
251
+ }
252
+
253
+ class NimCommand extends HarnessCommandBase {
254
+ static override summary = 'Run Nim interactive TUI smoke/debug client.';
255
+
256
+ static override usage = ['nim [options]'];
257
+
258
+ static override flags = {
259
+ help: Flags.help({ char: 'h' }),
260
+ session: sessionFlag,
261
+ };
262
+
263
+ override async run(): Promise<void> {
264
+ const parsed = this.extractSessionArg(this.argv);
265
+ const code = await runNimCli(parsed.argv, parsed.sessionName);
266
+ this.exitIfNeeded(code);
267
+ }
268
+ }
269
+
270
+ class DiffCommand extends HarnessCommandBase {
271
+ static override summary = 'Render git diffs in the diff TUI/CLI view.';
272
+
273
+ static override usage = ['diff [--session <name>] [diff-options...]'];
274
+
275
+ static override flags = {
276
+ session: sessionFlag,
277
+ };
278
+
279
+ override async run(): Promise<void> {
280
+ const parsed = this.extractSessionArg(this.argv);
281
+ const code = await runDiffCli(parsed.argv, parsed.sessionName);
282
+ this.exitIfNeeded(code);
283
+ }
284
+ }
285
+
286
+ const commands = {
287
+ client: ClientCommand,
288
+ gateway: GatewayCommand,
289
+ profile: ProfileCommand,
290
+ 'status-timeline': StatusTimelineCommand,
291
+ 'render-trace': RenderTraceCommand,
292
+ auth: AuthCommand,
293
+ update: UpdateCommand,
294
+ 'cursor-hooks': CursorHooksCommand,
295
+ nim: NimCommand,
296
+ animate: AnimateCommand,
297
+ diff: DiffCommand,
298
+ } satisfies Record<string, Command.Class>;
299
+
300
+ export default commands;
@@ -0,0 +1,82 @@
1
+ import { runHarnessAnimate } from './harness-animate.ts';
2
+ import { runNimTuiSmoke } from './nim-tui-smoke.ts';
3
+ import {
4
+ createDefaultHarnessRuntimeApplication,
5
+ type HarnessRuntimeApplication,
6
+ } from '../src/cli/runtime-app/application.ts';
7
+ import { parseGlobalCliOptions, parseSessionName } from '../src/cli/parsing/session.ts';
8
+
9
+ const app: HarnessRuntimeApplication = createDefaultHarnessRuntimeApplication();
10
+
11
+ export { parseGlobalCliOptions, parseSessionName };
12
+
13
+ export async function runGatewayCli(
14
+ args: readonly string[],
15
+ sessionName: string | null,
16
+ ): Promise<number> {
17
+ return await app.runGatewayCli(args, sessionName);
18
+ }
19
+
20
+ export async function runProfileCli(
21
+ args: readonly string[],
22
+ sessionName: string | null,
23
+ ): Promise<number> {
24
+ return await app.runProfileCli(args, sessionName);
25
+ }
26
+
27
+ export async function runStatusTimelineCli(
28
+ args: readonly string[],
29
+ sessionName: string | null,
30
+ ): Promise<number> {
31
+ return await app.runStatusTimelineCli(args, sessionName);
32
+ }
33
+
34
+ export async function runRenderTraceCli(
35
+ args: readonly string[],
36
+ sessionName: string | null,
37
+ ): Promise<number> {
38
+ return await app.runRenderTraceCli(args, sessionName);
39
+ }
40
+
41
+ export async function runAuthCli(
42
+ args: readonly string[],
43
+ sessionName: string | null,
44
+ ): Promise<number> {
45
+ return await app.runAuthCli(args, sessionName);
46
+ }
47
+
48
+ export function runUpdateCli(args: readonly string[], sessionName: string | null): number {
49
+ return app.runUpdateCli(args, sessionName);
50
+ }
51
+
52
+ export async function runCursorHooksCli(
53
+ args: readonly string[],
54
+ sessionName: string | null,
55
+ ): Promise<number> {
56
+ return await app.runCursorHooksCli(args, sessionName);
57
+ }
58
+
59
+ export async function runDiffCli(
60
+ args: readonly string[],
61
+ sessionName: string | null,
62
+ ): Promise<number> {
63
+ return await app.runDiffCli(args, sessionName);
64
+ }
65
+
66
+ export async function runClientCli(
67
+ args: readonly string[],
68
+ sessionName: string | null,
69
+ ): Promise<number> {
70
+ return await app.runClientCli(args, sessionName);
71
+ }
72
+
73
+ export async function runAnimateCli(args: readonly string[]): Promise<number> {
74
+ return await runHarnessAnimate(args);
75
+ }
76
+
77
+ export async function runNimCli(
78
+ args: readonly string[],
79
+ sessionName: string | null,
80
+ ): Promise<number> {
81
+ return await runNimTuiSmoke(args, { sessionName });
82
+ }