@agentuity/cli 1.0.59 → 2.0.0-beta.1

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/bin/cli.ts +2 -3
  2. package/dist/cmd/build/app-config-extractor.d.ts +27 -0
  3. package/dist/cmd/build/app-config-extractor.d.ts.map +1 -0
  4. package/dist/cmd/build/app-config-extractor.js +152 -0
  5. package/dist/cmd/build/app-config-extractor.js.map +1 -0
  6. package/dist/cmd/build/app-router-detector.d.ts +2 -5
  7. package/dist/cmd/build/app-router-detector.d.ts.map +1 -1
  8. package/dist/cmd/build/app-router-detector.js +130 -154
  9. package/dist/cmd/build/app-router-detector.js.map +1 -1
  10. package/dist/cmd/build/ci.d.ts.map +1 -1
  11. package/dist/cmd/build/ci.js +5 -21
  12. package/dist/cmd/build/ci.js.map +1 -1
  13. package/dist/cmd/build/ids.d.ts +11 -0
  14. package/dist/cmd/build/ids.d.ts.map +1 -0
  15. package/dist/cmd/build/ids.js +18 -0
  16. package/dist/cmd/build/ids.js.map +1 -0
  17. package/dist/cmd/build/index.d.ts.map +1 -1
  18. package/dist/cmd/build/index.js +8 -0
  19. package/dist/cmd/build/index.js.map +1 -1
  20. package/dist/cmd/build/vite/agent-discovery.d.ts +8 -4
  21. package/dist/cmd/build/vite/agent-discovery.d.ts.map +1 -1
  22. package/dist/cmd/build/vite/agent-discovery.js +166 -487
  23. package/dist/cmd/build/vite/agent-discovery.js.map +1 -1
  24. package/dist/cmd/build/vite/bun-dev-server.d.ts +43 -14
  25. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  26. package/dist/cmd/build/vite/bun-dev-server.js +290 -129
  27. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  28. package/dist/cmd/build/vite/config-loader.d.ts +15 -20
  29. package/dist/cmd/build/vite/config-loader.d.ts.map +1 -1
  30. package/dist/cmd/build/vite/config-loader.js +41 -74
  31. package/dist/cmd/build/vite/config-loader.js.map +1 -1
  32. package/dist/cmd/build/vite/docs-generator.d.ts.map +1 -1
  33. package/dist/cmd/build/vite/docs-generator.js +0 -2
  34. package/dist/cmd/build/vite/docs-generator.js.map +1 -1
  35. package/dist/cmd/build/vite/index.d.ts.map +1 -1
  36. package/dist/cmd/build/vite/index.js +0 -36
  37. package/dist/cmd/build/vite/index.js.map +1 -1
  38. package/dist/cmd/build/vite/lifecycle-generator.d.ts +10 -2
  39. package/dist/cmd/build/vite/lifecycle-generator.d.ts.map +1 -1
  40. package/dist/cmd/build/vite/lifecycle-generator.js +302 -23
  41. package/dist/cmd/build/vite/lifecycle-generator.js.map +1 -1
  42. package/dist/cmd/build/vite/route-discovery.d.ts +11 -38
  43. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  44. package/dist/cmd/build/vite/route-discovery.js +97 -177
  45. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  46. package/dist/cmd/build/vite/server-bundler.js +1 -1
  47. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  48. package/dist/cmd/build/vite/static-renderer.d.ts +0 -2
  49. package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
  50. package/dist/cmd/build/vite/static-renderer.js +19 -13
  51. package/dist/cmd/build/vite/static-renderer.js.map +1 -1
  52. package/dist/cmd/build/vite/vite-asset-server-config.d.ts +6 -3
  53. package/dist/cmd/build/vite/vite-asset-server-config.d.ts.map +1 -1
  54. package/dist/cmd/build/vite/vite-asset-server-config.js +175 -69
  55. package/dist/cmd/build/vite/vite-asset-server-config.js.map +1 -1
  56. package/dist/cmd/build/vite/vite-asset-server.d.ts +8 -3
  57. package/dist/cmd/build/vite/vite-asset-server.d.ts.map +1 -1
  58. package/dist/cmd/build/vite/vite-asset-server.js +14 -13
  59. package/dist/cmd/build/vite/vite-asset-server.js.map +1 -1
  60. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  61. package/dist/cmd/build/vite/vite-builder.js +42 -190
  62. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  63. package/dist/cmd/build/vite/ws-proxy.d.ts +53 -0
  64. package/dist/cmd/build/vite/ws-proxy.d.ts.map +1 -0
  65. package/dist/cmd/build/vite/ws-proxy.js +95 -0
  66. package/dist/cmd/build/vite/ws-proxy.js.map +1 -0
  67. package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
  68. package/dist/cmd/build/vite-bundler.js +0 -3
  69. package/dist/cmd/build/vite-bundler.js.map +1 -1
  70. package/dist/cmd/cloud/deploy-fork.d.ts.map +1 -1
  71. package/dist/cmd/cloud/deploy-fork.js +15 -36
  72. package/dist/cmd/cloud/deploy-fork.js.map +1 -1
  73. package/dist/cmd/cloud/sandbox/exec.d.ts.map +1 -1
  74. package/dist/cmd/cloud/sandbox/exec.js +28 -86
  75. package/dist/cmd/cloud/sandbox/exec.js.map +1 -1
  76. package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
  77. package/dist/cmd/cloud/sandbox/run.js +2 -9
  78. package/dist/cmd/cloud/sandbox/run.js.map +1 -1
  79. package/dist/cmd/cloud/sandbox/snapshot/build.js +2 -2
  80. package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
  81. package/dist/cmd/coder/hub-url.d.ts.map +1 -1
  82. package/dist/cmd/coder/hub-url.js +1 -3
  83. package/dist/cmd/coder/hub-url.js.map +1 -1
  84. package/dist/cmd/coder/start.js +6 -6
  85. package/dist/cmd/coder/start.js.map +1 -1
  86. package/dist/cmd/coder/tui-init.d.ts +2 -2
  87. package/dist/cmd/coder/tui-init.js +2 -2
  88. package/dist/cmd/coder/tui-init.js.map +1 -1
  89. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  90. package/dist/cmd/dev/file-watcher.js +2 -8
  91. package/dist/cmd/dev/file-watcher.js.map +1 -1
  92. package/dist/cmd/dev/index.d.ts.map +1 -1
  93. package/dist/cmd/dev/index.js +432 -752
  94. package/dist/cmd/dev/index.js.map +1 -1
  95. package/dist/cmd/dev/process-manager.d.ts +104 -0
  96. package/dist/cmd/dev/process-manager.d.ts.map +1 -0
  97. package/dist/cmd/dev/process-manager.js +204 -0
  98. package/dist/cmd/dev/process-manager.js.map +1 -0
  99. package/dist/errors.d.ts +10 -24
  100. package/dist/errors.d.ts.map +1 -1
  101. package/dist/errors.js +12 -42
  102. package/dist/errors.js.map +1 -1
  103. package/dist/schema-generator.d.ts.map +1 -1
  104. package/dist/schema-generator.js +12 -2
  105. package/dist/schema-generator.js.map +1 -1
  106. package/dist/tui.d.ts.map +1 -1
  107. package/dist/tui.js +5 -19
  108. package/dist/tui.js.map +1 -1
  109. package/dist/utils/version-mismatch.d.ts +39 -0
  110. package/dist/utils/version-mismatch.d.ts.map +1 -0
  111. package/dist/utils/version-mismatch.js +161 -0
  112. package/dist/utils/version-mismatch.js.map +1 -0
  113. package/package.json +6 -6
  114. package/src/cmd/ai/prompt/agent.md +0 -1
  115. package/src/cmd/ai/prompt/api.md +0 -7
  116. package/src/cmd/ai/prompt/web.md +51 -213
  117. package/src/cmd/build/app-config-extractor.ts +186 -0
  118. package/src/cmd/build/app-router-detector.ts +152 -182
  119. package/src/cmd/build/ci.ts +5 -21
  120. package/src/cmd/build/ids.ts +19 -0
  121. package/src/cmd/build/index.ts +10 -0
  122. package/src/cmd/build/vite/agent-discovery.ts +208 -679
  123. package/src/cmd/build/vite/bun-dev-server.ts +383 -146
  124. package/src/cmd/build/vite/config-loader.ts +45 -77
  125. package/src/cmd/build/vite/docs-generator.ts +0 -2
  126. package/src/cmd/build/vite/index.ts +1 -42
  127. package/src/cmd/build/vite/lifecycle-generator.ts +345 -21
  128. package/src/cmd/build/vite/route-discovery.ts +116 -274
  129. package/src/cmd/build/vite/server-bundler.ts +1 -1
  130. package/src/cmd/build/vite/static-renderer.ts +23 -15
  131. package/src/cmd/build/vite/vite-asset-server-config.ts +200 -70
  132. package/src/cmd/build/vite/vite-asset-server.ts +25 -15
  133. package/src/cmd/build/vite/vite-builder.ts +49 -220
  134. package/src/cmd/build/vite/ws-proxy.ts +126 -0
  135. package/src/cmd/build/vite-bundler.ts +0 -4
  136. package/src/cmd/cloud/deploy-fork.ts +16 -39
  137. package/src/cmd/cloud/sandbox/exec.ts +23 -130
  138. package/src/cmd/cloud/sandbox/run.ts +2 -9
  139. package/src/cmd/cloud/sandbox/snapshot/build.ts +2 -2
  140. package/src/cmd/coder/hub-url.ts +1 -3
  141. package/src/cmd/coder/start.ts +6 -6
  142. package/src/cmd/coder/tui-init.ts +4 -4
  143. package/src/cmd/dev/file-watcher.ts +2 -9
  144. package/src/cmd/dev/index.ts +476 -859
  145. package/src/cmd/dev/process-manager.ts +261 -0
  146. package/src/errors.ts +12 -44
  147. package/src/schema-generator.ts +12 -2
  148. package/src/tui.ts +5 -18
  149. package/src/utils/version-mismatch.ts +204 -0
  150. package/dist/cmd/build/ast.d.ts +0 -78
  151. package/dist/cmd/build/ast.d.ts.map +0 -1
  152. package/dist/cmd/build/ast.js +0 -2703
  153. package/dist/cmd/build/ast.js.map +0 -1
  154. package/dist/cmd/build/entry-generator.d.ts +0 -25
  155. package/dist/cmd/build/entry-generator.d.ts.map +0 -1
  156. package/dist/cmd/build/entry-generator.js +0 -695
  157. package/dist/cmd/build/entry-generator.js.map +0 -1
  158. package/dist/cmd/build/vite/api-mount-path.d.ts +0 -61
  159. package/dist/cmd/build/vite/api-mount-path.d.ts.map +0 -1
  160. package/dist/cmd/build/vite/api-mount-path.js +0 -83
  161. package/dist/cmd/build/vite/api-mount-path.js.map +0 -1
  162. package/dist/cmd/build/vite/registry-generator.d.ts +0 -19
  163. package/dist/cmd/build/vite/registry-generator.d.ts.map +0 -1
  164. package/dist/cmd/build/vite/registry-generator.js +0 -1108
  165. package/dist/cmd/build/vite/registry-generator.js.map +0 -1
  166. package/dist/cmd/build/webanalytics-generator.d.ts +0 -16
  167. package/dist/cmd/build/webanalytics-generator.d.ts.map +0 -1
  168. package/dist/cmd/build/webanalytics-generator.js +0 -178
  169. package/dist/cmd/build/webanalytics-generator.js.map +0 -1
  170. package/dist/cmd/build/workbench.d.ts +0 -7
  171. package/dist/cmd/build/workbench.d.ts.map +0 -1
  172. package/dist/cmd/build/workbench.js +0 -55
  173. package/dist/cmd/build/workbench.js.map +0 -1
  174. package/dist/utils/route-migration.d.ts +0 -62
  175. package/dist/utils/route-migration.d.ts.map +0 -1
  176. package/dist/utils/route-migration.js +0 -630
  177. package/dist/utils/route-migration.js.map +0 -1
  178. package/dist/utils/stream-capture.d.ts +0 -9
  179. package/dist/utils/stream-capture.d.ts.map +0 -1
  180. package/dist/utils/stream-capture.js +0 -34
  181. package/dist/utils/stream-capture.js.map +0 -1
  182. package/src/cmd/build/ast.ts +0 -3529
  183. package/src/cmd/build/entry-generator.ts +0 -760
  184. package/src/cmd/build/vite/api-mount-path.ts +0 -87
  185. package/src/cmd/build/vite/registry-generator.ts +0 -1267
  186. package/src/cmd/build/webanalytics-generator.ts +0 -197
  187. package/src/cmd/build/workbench.ts +0 -58
  188. package/src/utils/route-migration.ts +0 -757
  189. package/src/utils/stream-capture.ts +0 -39
@@ -98,8 +98,6 @@ export const execSubcommand = createCommand({
98
98
  process.on('SIGTERM', handleSignal);
99
99
 
100
100
  try {
101
- logger.debug('[exec] calling sandboxExecute for %s', args.sandboxId);
102
- const executeStart = Date.now();
103
101
  const execution = await sandboxExecute(client, {
104
102
  sandboxId: args.sandboxId,
105
103
  options: {
@@ -109,13 +107,6 @@ export const execSubcommand = createCommand({
109
107
  },
110
108
  orgId,
111
109
  });
112
- logger.debug(
113
- '[exec] sandboxExecute returned in %dms: executionId=%s, stdoutUrl=%s, stderrUrl=%s',
114
- Date.now() - executeStart,
115
- execution.executionId,
116
- execution.stdoutStreamUrl ?? 'none',
117
- execution.stderrStreamUrl ?? 'none'
118
- );
119
110
 
120
111
  if (execution.autoResumed && !options.json) {
121
112
  tui.warning('Sandbox was automatically resumed from suspended state');
@@ -125,17 +116,10 @@ export const execSubcommand = createCommand({
125
116
  const stderrStreamUrl = execution.stderrStreamUrl;
126
117
  const streamAbortController = new AbortController();
127
118
  const streamPromises: Promise<void>[] = [];
128
- const streamLabels: string[] = [];
129
119
 
130
120
  // Check if stdout and stderr are the same stream (combined output)
131
121
  const isCombinedOutput =
132
122
  stdoutStreamUrl && stderrStreamUrl && stdoutStreamUrl === stderrStreamUrl;
133
- logger.debug(
134
- '[exec] stream mode: combined=%s, stdoutUrl=%s, stderrUrl=%s',
135
- isCombinedOutput,
136
- stdoutStreamUrl ?? 'none',
137
- stderrStreamUrl ?? 'none'
138
- );
139
123
 
140
124
  // Set up stream capture — in JSON mode, capture to buffers;
141
125
  // when streams are separate, capture stdout/stderr independently
@@ -169,11 +153,9 @@ export const execSubcommand = createCommand({
169
153
 
170
154
  if (isCombinedOutput) {
171
155
  // Stream combined output to stdout only to avoid duplicates
172
- logger.debug('[exec] starting combined stream: %s', stdoutStreamUrl);
173
- streamLabels.push('combined');
156
+ logger.debug('using combined output stream (stdout === stderr): %s', stdoutStreamUrl);
174
157
  streamPromises.push(
175
158
  streamUrlToWritable(
176
- 'combined',
177
159
  stdoutStreamUrl,
178
160
  stdoutWritable,
179
161
  streamAbortController.signal,
@@ -182,11 +164,9 @@ export const execSubcommand = createCommand({
182
164
  );
183
165
  } else {
184
166
  if (stdoutStreamUrl) {
185
- logger.debug('[exec] starting stdout stream: %s', stdoutStreamUrl);
186
- streamLabels.push('stdout');
167
+ logger.debug('starting stdout stream from: %s', stdoutStreamUrl);
187
168
  streamPromises.push(
188
169
  streamUrlToWritable(
189
- 'stdout',
190
170
  stdoutStreamUrl,
191
171
  stdoutWritable,
192
172
  streamAbortController.signal,
@@ -196,11 +176,9 @@ export const execSubcommand = createCommand({
196
176
  }
197
177
 
198
178
  if (stderrStreamUrl) {
199
- logger.debug('[exec] starting stderr stream: %s', stderrStreamUrl);
200
- streamLabels.push('stderr');
179
+ logger.debug('starting stderr stream from: %s', stderrStreamUrl);
201
180
  streamPromises.push(
202
181
  streamUrlToWritable(
203
- 'stderr',
204
182
  stderrStreamUrl,
205
183
  stderrWritable,
206
184
  streamAbortController.signal,
@@ -210,63 +188,17 @@ export const execSubcommand = createCommand({
210
188
  }
211
189
  }
212
190
 
213
- logger.debug(
214
- '[exec] %d stream(s) started [%s], now long-polling executionGet',
215
- streamPromises.length,
216
- streamLabels.join(', ')
217
- );
218
-
219
191
  // Use server-side long-polling to wait for execution completion
220
192
  // This is more efficient than client-side polling and provides immediate
221
193
  // error detection if the sandbox is terminated
222
- let finalExecution: Awaited<ReturnType<typeof executionGet>>;
223
- const pollStart = Date.now();
224
- try {
225
- finalExecution = await executionGet(client, {
226
- executionId: execution.executionId,
227
- orgId,
228
- wait: EXECUTION_WAIT_DURATION,
229
- });
230
- } catch (err) {
231
- // Abort any active stream readers before rethrowing so they
232
- // don't keep running after the execution poll has failed.
233
- streamAbortController.abort();
234
- throw err;
235
- }
236
- logger.debug(
237
- '[exec] executionGet returned in %dms: status=%s, exitCode=%s',
238
- Date.now() - pollStart,
239
- finalExecution.status,
240
- finalExecution.exitCode ?? 'undefined'
241
- );
194
+ const finalExecution = await executionGet(client, {
195
+ executionId: execution.executionId,
196
+ orgId,
197
+ wait: EXECUTION_WAIT_DURATION,
198
+ });
242
199
 
243
- // Wait for all streams to reach EOF (Pulse blocks until true EOF).
244
- // Safety: execution is confirmed complete so all data has been written
245
- // and complete/v2 sent. If Pulse doesn't close the response within
246
- // a grace period (e.g. cross-server routing delay, stale metadata
247
- // cache), abort the streams to prevent an indefinite hang.
248
- if (streamPromises.length > 0) {
249
- logger.debug('[exec] waiting for %d stream(s) to EOF', streamPromises.length);
250
- const streamWaitStart = Date.now();
251
- let graceTriggered = false;
252
- const streamGrace = setTimeout(() => {
253
- graceTriggered = true;
254
- logger.debug(
255
- '[exec] stream grace period (5s) expired after execution complete — aborting streams'
256
- );
257
- streamAbortController.abort();
258
- }, 5_000);
259
- try {
260
- await Promise.all(streamPromises);
261
- } finally {
262
- clearTimeout(streamGrace);
263
- }
264
- logger.debug(
265
- '[exec] all streams done in %dms (graceTriggered=%s)',
266
- Date.now() - streamWaitStart,
267
- graceTriggered
268
- );
269
- }
200
+ // Wait for all streams to reach EOF (Pulse blocks until true EOF)
201
+ await Promise.all(streamPromises);
270
202
 
271
203
  // Ensure stdout is fully flushed before continuing
272
204
  if (!options.json && process.stdout.writable) {
@@ -286,21 +218,12 @@ export const execSubcommand = createCommand({
286
218
  const stderrOutput =
287
219
  !isCombinedOutput && stderrStreamUrl ? stderrChunks.join('') : undefined;
288
220
 
289
- if (finalExecution.exitCode !== undefined && finalExecution.exitCode !== 0) {
290
- if (!options.json) {
221
+ if (!options.json) {
222
+ if (finalExecution.exitCode === 0) {
223
+ // no op
224
+ } else if (finalExecution.exitCode !== undefined) {
291
225
  tui.error(`failed with exit code ${finalExecution.exitCode} in ${duration}ms`);
292
- }
293
- process.exitCode = finalExecution.exitCode;
294
- } else if (finalExecution.exitCode === undefined) {
295
- const failStatuses = ['failed', 'error', 'timeout', 'killed'];
296
- if (failStatuses.includes(finalExecution.status)) {
297
- if (!options.json) {
298
- tui.error(
299
- `Execution ${tui.bold(finalExecution.executionId)} ${finalExecution.status} in ${duration}ms`
300
- );
301
- }
302
- process.exitCode = 1;
303
- } else if (!options.json) {
226
+ } else {
304
227
  tui.info(
305
228
  `Execution ${tui.bold(finalExecution.executionId)} - Status: ${finalExecution.status}`
306
229
  );
@@ -326,72 +249,42 @@ export const execSubcommand = createCommand({
326
249
  });
327
250
 
328
251
  async function streamUrlToWritable(
329
- label: string,
330
252
  url: string,
331
253
  writable: NodeJS.WritableStream,
332
254
  signal: AbortSignal,
333
255
  logger: Logger
334
256
  ): Promise<void> {
335
- const streamStart = Date.now();
336
257
  try {
337
- // Signal to Pulse that this is a v2 stream so it waits for v2 metadata
338
- // instead of falling back to the legacy download path on a short timeout.
339
- const v2Url = new URL(url);
340
- v2Url.searchParams.set('v', '2');
341
- logger.debug('[stream:%s] fetching: %s', label, v2Url.href);
342
- const response = await fetch(v2Url.href, { signal });
343
- logger.debug(
344
- '[stream:%s] response status=%d in %dms',
345
- label,
346
- response.status,
347
- Date.now() - streamStart
348
- );
258
+ logger.debug('fetching stream: %s', url);
259
+ const response = await fetch(url, { signal });
260
+ logger.debug('stream response status: %d', response.status);
349
261
 
350
262
  if (!response.ok || !response.body) {
351
- logger.debug('[stream:%s] not ok or no body — returning', label);
263
+ logger.debug('stream response not ok or no body');
352
264
  return;
353
265
  }
354
266
 
355
267
  const reader = response.body.getReader();
356
- let chunks = 0;
357
- let totalBytes = 0;
358
268
 
359
269
  // Read until EOF - Pulse will block until data is available
360
270
  while (true) {
361
271
  const { done, value } = await reader.read();
362
272
  if (done) {
363
- logger.debug(
364
- '[stream:%s] EOF after %dms (%d chunks, %d bytes)',
365
- label,
366
- Date.now() - streamStart,
367
- chunks,
368
- totalBytes
369
- );
273
+ logger.debug('stream EOF');
370
274
  break;
371
275
  }
372
276
 
373
277
  if (value) {
374
- chunks++;
375
- totalBytes += value.length;
376
- if (chunks <= 3 || chunks % 100 === 0) {
377
- logger.debug(
378
- '[stream:%s] chunk #%d: %d bytes (total: %d bytes, +%dms)',
379
- label,
380
- chunks,
381
- value.length,
382
- totalBytes,
383
- Date.now() - streamStart
384
- );
385
- }
278
+ logger.debug('stream chunk: %d bytes', value.length);
386
279
  await writeAndDrain(writable, value);
387
280
  }
388
281
  }
389
282
  } catch (err) {
390
283
  if (err instanceof Error && err.name === 'AbortError') {
391
- logger.debug('[stream:%s] aborted after %dms', label, Date.now() - streamStart);
284
+ logger.debug('stream aborted');
392
285
  return;
393
286
  }
394
- logger.debug('[stream:%s] error after %dms: %s', label, Date.now() - streamStart, err);
287
+ logger.debug('stream error: %s', err);
395
288
  }
396
289
  }
397
290
 
@@ -194,17 +194,10 @@ export const runSubcommand = createCommand({
194
194
  const duration = Date.now() - started;
195
195
  const output = outputChunks.join('');
196
196
 
197
- if (result.exitCode !== 0) {
198
- if (!options.json) {
197
+ if (!options.json) {
198
+ if (result.exitCode !== 0) {
199
199
  tui.error(`failed with exit code ${result.exitCode} in ${duration}ms`);
200
200
  }
201
- // Use process.exit() directly rather than process.exitCode to ensure
202
- // the exit code propagates reliably across all runtimes (Bun/Node).
203
- // process.exitCode can be overwritten by later async cleanup.
204
- if (!options.json) {
205
- process.exit(result.exitCode);
206
- }
207
- process.exitCode = result.exitCode;
208
201
  }
209
202
 
210
203
  return {
@@ -17,7 +17,7 @@ import { z } from 'zod';
17
17
  import { getCommand } from '../../../../command-prefix';
18
18
  import { getCatalystAPIClient } from '../../../../config';
19
19
  import { encryptFIPSKEMDEMStream } from '../../../../crypto/box';
20
- import { ErrorCode, getExitCode } from '../../../../errors';
20
+ import { ErrorCode } from '../../../../errors';
21
21
  import * as tui from '../../../../tui';
22
22
  import { createCommand } from '../../../../types';
23
23
  import { validateAptDependencies } from '../../../../utils/apt-validator';
@@ -941,7 +941,7 @@ export const buildSubcommand = createCommand({
941
941
  2
942
942
  )
943
943
  );
944
- process.exit(getExitCode(ErrorCode.MALWARE_DETECTED));
944
+ process.exit(ErrorCode.MALWARE_DETECTED);
945
945
  }
946
946
 
947
947
  console.log('');
@@ -58,10 +58,8 @@ function normalizeToHttp(url: string): string {
58
58
  if (normalized.startsWith('ws://')) normalized = 'http://' + normalized.slice(5);
59
59
  else if (normalized.startsWith('wss://')) normalized = 'https://' + normalized.slice(6);
60
60
 
61
- // Strip known Hub transport/helper paths to get the HTTP base URL.
62
- // Accept `/ws` as a convenience alias because users often copy the raw route name.
61
+ // Strip /api/ws or /api/hub/* paths to get base URL
63
62
  normalized = normalized.replace(/\/api\/ws\b.*$/, '');
64
- normalized = normalized.replace(/\/ws\b.*$/, '');
65
63
  normalized = normalized.replace(/\/api\/hub\b.*$/, '');
66
64
 
67
65
  return normalized.replace(/\/+$/, '');
@@ -6,7 +6,7 @@ import * as tui from '../../tui';
6
6
  import { getCommand } from '../../command-prefix';
7
7
  import { ErrorCode } from '../../errors';
8
8
  import { toHubWsUrl, resolveHubUrl, hubFetchHeaders } from './hub-url';
9
- import { probeHubInitAccess } from './tui-init';
9
+ import { probeTuiInitAccess } from './tui-init';
10
10
 
11
11
  /**
12
12
  * Resolve the Coder extension path.
@@ -140,18 +140,18 @@ export const startSubcommand = createSubcommand({
140
140
  }
141
141
  const hubWsUrl = toHubWsUrl(hubHttpUrl);
142
142
 
143
- const initProbe = await probeHubInitAccess(hubHttpUrl);
144
- if (!initProbe.ok) {
145
- if (initProbe.code === 'unauthorized') {
143
+ const tuiInitProbe = await probeTuiInitAccess(hubHttpUrl);
144
+ if (!tuiInitProbe.ok) {
145
+ if (tuiInitProbe.code === 'unauthorized') {
146
146
  tui.fatal(
147
- `Coder Hub at ${hubHttpUrl} requires authentication.\n\nSet AGENTUITY_CODER_API_KEY in your shell and retry.\n\nServer said: ${initProbe.message}`,
147
+ `Coder Hub at ${hubHttpUrl} requires authentication.\n\nSet AGENTUITY_CODER_API_KEY in your shell and retry.\n\nServer said: ${tuiInitProbe.message}`,
148
148
  ErrorCode.NETWORK_ERROR
149
149
  );
150
150
  return;
151
151
  }
152
152
 
153
153
  tui.fatal(
154
- `Could not bootstrap the Coder Hub at ${hubHttpUrl}: ${initProbe.message}`,
154
+ `Could not bootstrap the Coder Hub at ${hubHttpUrl}: ${tuiInitProbe.message}`,
155
155
  ErrorCode.NETWORK_ERROR
156
156
  );
157
157
  return;
@@ -1,6 +1,6 @@
1
1
  import { hubFetchHeaders } from './hub-url';
2
2
 
3
- export type HubInitProbeResult =
3
+ export type TuiInitProbeResult =
4
4
  | { ok: true }
5
5
  | {
6
6
  ok: false;
@@ -19,12 +19,12 @@ function normalizeErrorMessage(payload: unknown, fallback: string): string {
19
19
  return fallback;
20
20
  }
21
21
 
22
- export async function probeHubInitAccess(
22
+ export async function probeTuiInitAccess(
23
23
  hubHttpUrl: string,
24
24
  fetchImpl: typeof fetch = fetch
25
- ): Promise<HubInitProbeResult> {
25
+ ): Promise<TuiInitProbeResult> {
26
26
  try {
27
- const response = await fetchImpl(`${hubHttpUrl}/api/hub/init`, {
27
+ const response = await fetchImpl(`${hubHttpUrl}/api/hub/tui/init`, {
28
28
  headers: hubFetchHeaders({ accept: 'application/json' }),
29
29
  signal: AbortSignal.timeout(5_000),
30
30
  });
@@ -8,7 +8,7 @@
8
8
  import { watch, type FSWatcher, statSync, readdirSync, lstatSync } from 'node:fs';
9
9
  import { resolve, relative } from 'node:path';
10
10
  import type { Logger } from '../../types';
11
- import { createAgentTemplates, createAPITemplates } from './templates';
11
+ import { createAgentTemplates } from './templates';
12
12
 
13
13
  export interface FileWatcherOptions {
14
14
  rootDir: string;
@@ -219,7 +219,7 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
219
219
  isDirectory = false;
220
220
  }
221
221
 
222
- // Check if an empty directory was created in src/agent/ or src/api/
222
+ // Check if an empty directory was created in src/agent/
223
223
  // This helps with developer experience by auto-scaffolding template files
224
224
  if (changedFile && eventType === 'rename' && isDirectory) {
225
225
  try {
@@ -229,19 +229,12 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
229
229
  // Check if it's empty
230
230
  const contents = readdirSync(absPath);
231
231
  if (contents.length === 0) {
232
- // Check if this is an agent or API directory
233
232
  if (
234
233
  normalizedPath.startsWith('src/agent/') ||
235
234
  normalizedPath.includes('/src/agent/')
236
235
  ) {
237
236
  logger.debug('Agent directory created: %s', changedFile);
238
237
  createAgentTemplates(absPath);
239
- } else if (
240
- normalizedPath.startsWith('src/api/') ||
241
- normalizedPath.includes('/src/api/')
242
- ) {
243
- logger.debug('API directory created: %s', changedFile);
244
- createAPITemplates(absPath);
245
238
  }
246
239
  }
247
240
  } catch (error) {