@agentuity/cli 1.0.42 → 1.0.44

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 (73) hide show
  1. package/dist/api.js +1 -1
  2. package/dist/api.js.map +1 -1
  3. package/dist/cmd/build/patch/_util.d.ts +6 -0
  4. package/dist/cmd/build/patch/_util.d.ts.map +1 -1
  5. package/dist/cmd/build/patch/_util.js +20 -1
  6. package/dist/cmd/build/patch/_util.js.map +1 -1
  7. package/dist/cmd/build/patch/index.d.ts +2 -1
  8. package/dist/cmd/build/patch/index.d.ts.map +1 -1
  9. package/dist/cmd/build/patch/index.js +2 -1
  10. package/dist/cmd/build/patch/index.js.map +1 -1
  11. package/dist/cmd/build/vite/server-bundler.d.ts.map +1 -1
  12. package/dist/cmd/build/vite/server-bundler.js +2 -6
  13. package/dist/cmd/build/vite/server-bundler.js.map +1 -1
  14. package/dist/cmd/cloud/oidc/activity.d.ts.map +1 -1
  15. package/dist/cmd/cloud/oidc/activity.js +6 -3
  16. package/dist/cmd/cloud/oidc/activity.js.map +1 -1
  17. package/dist/cmd/cloud/oidc/create.d.ts.map +1 -1
  18. package/dist/cmd/cloud/oidc/create.js +8 -5
  19. package/dist/cmd/cloud/oidc/create.js.map +1 -1
  20. package/dist/cmd/cloud/oidc/delete.d.ts.map +1 -1
  21. package/dist/cmd/cloud/oidc/delete.js +6 -3
  22. package/dist/cmd/cloud/oidc/delete.js.map +1 -1
  23. package/dist/cmd/cloud/oidc/get.d.ts.map +1 -1
  24. package/dist/cmd/cloud/oidc/get.js +6 -3
  25. package/dist/cmd/cloud/oidc/get.js.map +1 -1
  26. package/dist/cmd/cloud/oidc/list.d.ts.map +1 -1
  27. package/dist/cmd/cloud/oidc/list.js +6 -3
  28. package/dist/cmd/cloud/oidc/list.js.map +1 -1
  29. package/dist/cmd/cloud/oidc/rotate-secret.d.ts.map +1 -1
  30. package/dist/cmd/cloud/oidc/rotate-secret.js +6 -3
  31. package/dist/cmd/cloud/oidc/rotate-secret.js.map +1 -1
  32. package/dist/cmd/cloud/oidc/users.d.ts.map +1 -1
  33. package/dist/cmd/cloud/oidc/users.js +6 -3
  34. package/dist/cmd/cloud/oidc/users.js.map +1 -1
  35. package/dist/cmd/cloud/oidc/util.d.ts +10 -0
  36. package/dist/cmd/cloud/oidc/util.d.ts.map +1 -0
  37. package/dist/cmd/cloud/oidc/util.js +13 -0
  38. package/dist/cmd/cloud/oidc/util.js.map +1 -0
  39. package/dist/cmd/coder/hub-url.d.ts +1 -0
  40. package/dist/cmd/coder/hub-url.d.ts.map +1 -1
  41. package/dist/cmd/coder/hub-url.js +4 -1
  42. package/dist/cmd/coder/hub-url.js.map +1 -1
  43. package/dist/cmd/coder/start.d.ts.map +1 -1
  44. package/dist/cmd/coder/start.js +14 -8
  45. package/dist/cmd/coder/start.js.map +1 -1
  46. package/dist/cmd/coder/tui-init.d.ts +9 -0
  47. package/dist/cmd/coder/tui-init.d.ts.map +1 -0
  48. package/dist/cmd/coder/tui-init.js +56 -0
  49. package/dist/cmd/coder/tui-init.js.map +1 -0
  50. package/dist/cmd/profile/create.js +1 -1
  51. package/dist/cmd/profile/create.js.map +1 -1
  52. package/dist/utils/route-migration.d.ts +3 -3
  53. package/dist/utils/route-migration.d.ts.map +1 -1
  54. package/dist/utils/route-migration.js +8 -31
  55. package/dist/utils/route-migration.js.map +1 -1
  56. package/package.json +6 -6
  57. package/src/api.ts +1 -1
  58. package/src/cmd/build/patch/_util.ts +20 -1
  59. package/src/cmd/build/patch/index.ts +2 -1
  60. package/src/cmd/build/vite/server-bundler.ts +2 -6
  61. package/src/cmd/cloud/oidc/activity.ts +7 -4
  62. package/src/cmd/cloud/oidc/create.ts +8 -10
  63. package/src/cmd/cloud/oidc/delete.ts +7 -4
  64. package/src/cmd/cloud/oidc/get.ts +7 -4
  65. package/src/cmd/cloud/oidc/list.ts +7 -4
  66. package/src/cmd/cloud/oidc/rotate-secret.ts +7 -4
  67. package/src/cmd/cloud/oidc/users.ts +7 -4
  68. package/src/cmd/cloud/oidc/util.ts +28 -0
  69. package/src/cmd/coder/hub-url.ts +5 -1
  70. package/src/cmd/coder/start.ts +22 -8
  71. package/src/cmd/coder/tui-init.ts +75 -0
  72. package/src/cmd/profile/create.ts +1 -1
  73. package/src/utils/route-migration.ts +8 -33
@@ -7,7 +7,7 @@ import { join } from 'node:path';
7
7
  import { readdir, stat } from 'node:fs/promises';
8
8
  import type { Logger } from '../../../types';
9
9
  import type { BunPlugin, BuildOutput } from 'bun';
10
- import { generatePatches, applyPatch } from '../patch';
10
+ import { generatePatches, applyPatch, buildPatchFilter } from '../patch';
11
11
  import { getLoaderForPath, rewriteBunImports, rewritePgImports } from './db-rewrite';
12
12
 
13
13
  /**
@@ -291,13 +291,9 @@ export async function installExternalsAndBuild(options: ServerBundleOptions): Pr
291
291
  name: 'agentuity:patch',
292
292
  setup(build) {
293
293
  for (const [, patch] of patches) {
294
- let modulePath = join('node_modules', patch.module, '.*');
295
- if (patch.filename) {
296
- modulePath = join('node_modules', patch.module, patch.filename + '.*');
297
- }
298
294
  build.onLoad(
299
295
  {
300
- filter: new RegExp(modulePath),
296
+ filter: buildPatchFilter(patch.module, patch.filename),
301
297
  namespace: 'file',
302
298
  },
303
299
  async (args) => {
@@ -1,8 +1,9 @@
1
- import { oauthClientActivity, type APIClient } from '@agentuity/core';
1
+ import { oauthClientActivity } from '@agentuity/core';
2
2
  import { z } from 'zod';
3
3
  import { getCommand } from '../../../command-prefix';
4
4
  import * as tui from '../../../tui';
5
5
  import { createSubcommand } from '../../../types';
6
+ import { createOAuthClient } from './util';
6
7
 
7
8
  const OAuthClientActivityResponseSchema = z.array(
8
9
  z.object({
@@ -23,8 +24,9 @@ export const activitySubcommand = createSubcommand({
23
24
  description: 'Show OAuth activity for last 30 days',
24
25
  },
25
26
  ],
26
- requires: { auth: true, apiClient: true },
27
+ requires: { auth: true },
27
28
  idempotent: true,
29
+ webUrl: (ctx) => `/settings/oauth-apps/${encodeURIComponent(ctx.args.id)}`,
28
30
  schema: {
29
31
  args: z.object({
30
32
  id: z.string().describe('the OAuth client id'),
@@ -36,10 +38,11 @@ export const activitySubcommand = createSubcommand({
36
38
  },
37
39
 
38
40
  async handler(ctx) {
39
- const { args, opts, apiClient, options } = ctx;
41
+ const { args, opts, options } = ctx;
42
+ const catalystClient = await createOAuthClient(ctx);
40
43
 
41
44
  const activity = await tui.spinner('Fetching OAuth activity', () => {
42
- return oauthClientActivity(apiClient as APIClient, args.id, opts.days);
45
+ return oauthClientActivity(catalystClient, args.id, opts.days);
43
46
  });
44
47
 
45
48
  if (!options.json) {
@@ -1,14 +1,10 @@
1
- import {
2
- oauthClientCreate,
3
- oauthScopes,
4
- type APIClient,
5
- type OAuthClientCreateRequest,
6
- } from '@agentuity/core';
1
+ import { oauthClientCreate, oauthScopes, type OAuthClientCreateRequest } from '@agentuity/core';
7
2
  import enquirer from 'enquirer';
8
3
  import { z } from 'zod';
9
4
  import { getCommand } from '../../../command-prefix';
10
5
  import * as tui from '../../../tui';
11
6
  import { createSubcommand as createSubcommandHelper } from '../../../types';
7
+ import { createOAuthClient } from './util';
12
8
 
13
9
  const OAuthClientCreateResponseSchema = z.object({
14
10
  client: z.object({
@@ -50,8 +46,9 @@ export const createSubcommand = createSubcommandHelper({
50
46
  description: 'Create OAuth application interactively',
51
47
  },
52
48
  ],
53
- requires: { auth: true, apiClient: true },
49
+ requires: { auth: true },
54
50
  idempotent: false,
51
+ webUrl: '/settings/oauth-apps',
55
52
  schema: {
56
53
  options: z.object({
57
54
  name: z.string().optional().describe('the OAuth application name'),
@@ -74,10 +71,11 @@ export const createSubcommand = createSubcommandHelper({
74
71
  },
75
72
 
76
73
  async handler(ctx) {
77
- const { opts, apiClient, options } = ctx;
74
+ const { opts, options } = ctx;
75
+ const catalystClient = await createOAuthClient(ctx);
78
76
 
79
77
  const availableScopes = await tui.spinner('Fetching available OAuth scopes', () => {
80
- return oauthScopes(apiClient as APIClient);
78
+ return oauthScopes(catalystClient);
81
79
  });
82
80
 
83
81
  const nonInteractive = !process.stdin.isTTY || !process.stdout.isTTY;
@@ -201,7 +199,7 @@ export const createSubcommand = createSubcommandHelper({
201
199
  };
202
200
 
203
201
  const result = await tui.spinner('Creating OAuth application', () => {
204
- return oauthClientCreate(apiClient as APIClient, request);
202
+ return oauthClientCreate(catalystClient, request);
205
203
  });
206
204
 
207
205
  if (!options.json) {
@@ -1,9 +1,10 @@
1
- import { oauthClientDelete, type APIClient } from '@agentuity/core';
1
+ import { oauthClientDelete } from '@agentuity/core';
2
2
  import { z } from 'zod';
3
3
  import { getCommand } from '../../../command-prefix';
4
4
  import { ErrorCode } from '../../../errors';
5
5
  import * as tui from '../../../tui';
6
6
  import { createSubcommand } from '../../../types';
7
+ import { createOAuthClient } from './util';
7
8
 
8
9
  const OAuthClientDeleteResponseSchema = z.object({
9
10
  success: z.boolean().describe('Whether the operation succeeded'),
@@ -23,7 +24,8 @@ export const deleteSubcommand = createSubcommand({
23
24
  description: 'Delete OAuth application without confirmation',
24
25
  },
25
26
  ],
26
- requires: { auth: true, apiClient: true },
27
+ requires: { auth: true },
28
+ webUrl: '/settings/oauth-apps',
27
29
  schema: {
28
30
  args: z.object({
29
31
  id: z.string().describe('the OAuth client id to delete'),
@@ -36,7 +38,8 @@ export const deleteSubcommand = createSubcommand({
36
38
  },
37
39
 
38
40
  async handler(ctx) {
39
- const { args, opts, apiClient, options } = ctx;
41
+ const { args, opts, options } = ctx;
42
+ const catalystClient = await createOAuthClient(ctx);
40
43
 
41
44
  const skipConfirm = opts.force || opts.yes;
42
45
 
@@ -48,7 +51,7 @@ export const deleteSubcommand = createSubcommand({
48
51
  }
49
52
 
50
53
  await tui.spinner('Deleting OAuth application', () => {
51
- return oauthClientDelete(apiClient as APIClient, args.id);
54
+ return oauthClientDelete(catalystClient, args.id);
52
55
  });
53
56
 
54
57
  if (!options.json) {
@@ -1,9 +1,10 @@
1
- import { oauthClientGet, type APIClient } from '@agentuity/core';
1
+ import { oauthClientGet } from '@agentuity/core';
2
2
  import { z } from 'zod';
3
3
  import { getCommand } from '../../../command-prefix';
4
4
  import { ErrorCode } from '../../../errors';
5
5
  import * as tui from '../../../tui';
6
6
  import { createSubcommand } from '../../../types';
7
+ import { createOAuthClient } from './util';
7
8
 
8
9
  export const getSubcommand = createSubcommand({
9
10
  name: 'get',
@@ -12,8 +13,9 @@ export const getSubcommand = createSubcommand({
12
13
  examples: [
13
14
  { command: getCommand('cloud oidc get <id>'), description: 'Get OAuth application details' },
14
15
  ],
15
- requires: { auth: true, apiClient: true },
16
+ requires: { auth: true },
16
17
  idempotent: true,
18
+ webUrl: (ctx) => `/settings/oauth-apps/${encodeURIComponent(ctx.args.id)}`,
17
19
  schema: {
18
20
  args: z.object({
19
21
  id: z.string().describe('the OAuth client id'),
@@ -21,12 +23,13 @@ export const getSubcommand = createSubcommand({
21
23
  },
22
24
 
23
25
  async handler(ctx) {
24
- const { args, apiClient, options } = ctx;
26
+ const { args, options } = ctx;
27
+ const catalystClient = await createOAuthClient(ctx);
25
28
 
26
29
  let client: Awaited<ReturnType<typeof oauthClientGet>>;
27
30
  try {
28
31
  client = await tui.spinner('Fetching OAuth application', () => {
29
- return oauthClientGet(apiClient as APIClient, args.id);
32
+ return oauthClientGet(catalystClient, args.id);
30
33
  });
31
34
  } catch (error) {
32
35
  if (error instanceof Error && error.message.includes('not found')) {
@@ -1,7 +1,8 @@
1
- import { oauthClientList, type APIClient } from '@agentuity/core';
1
+ import { oauthClientList } from '@agentuity/core';
2
2
  import { getCommand } from '../../../command-prefix';
3
3
  import * as tui from '../../../tui';
4
4
  import { createSubcommand } from '../../../types';
5
+ import { createOAuthClient } from './util';
5
6
 
6
7
  export const listSubcommand = createSubcommand({
7
8
  name: 'list',
@@ -12,14 +13,16 @@ export const listSubcommand = createSubcommand({
12
13
  { command: getCommand('cloud oidc list'), description: 'List OAuth applications' },
13
14
  { command: getCommand('cloud oidc ls'), description: 'List OAuth applications' },
14
15
  ],
15
- requires: { auth: true, apiClient: true },
16
+ requires: { auth: true },
16
17
  idempotent: true,
18
+ webUrl: '/settings/oauth-apps',
17
19
 
18
20
  async handler(ctx) {
19
- const { apiClient, options } = ctx;
21
+ const { options } = ctx;
22
+ const catalystClient = await createOAuthClient(ctx);
20
23
 
21
24
  const clients = await tui.spinner('Fetching OAuth applications', () => {
22
- return oauthClientList(apiClient as APIClient);
25
+ return oauthClientList(catalystClient);
23
26
  });
24
27
 
25
28
  if (!options.json) {
@@ -1,9 +1,10 @@
1
- import { oauthClientRotateSecret, type APIClient } from '@agentuity/core';
1
+ import { oauthClientRotateSecret } from '@agentuity/core';
2
2
  import { z } from 'zod';
3
3
  import { getCommand } from '../../../command-prefix';
4
4
  import { ErrorCode } from '../../../errors';
5
5
  import * as tui from '../../../tui';
6
6
  import { createSubcommand } from '../../../types';
7
+ import { createOAuthClient } from './util';
7
8
 
8
9
  const OAuthClientRotateSecretResponseSchema = z.object({
9
10
  client_id: z.string(),
@@ -24,8 +25,9 @@ export const rotateSecretSubcommand = createSubcommand({
24
25
  description: 'Rotate OAuth client secret without confirmation',
25
26
  },
26
27
  ],
27
- requires: { auth: true, apiClient: true },
28
+ requires: { auth: true },
28
29
  idempotent: false,
30
+ webUrl: (ctx) => `/settings/oauth-apps/${encodeURIComponent(ctx.args.id)}`,
29
31
  schema: {
30
32
  args: z.object({
31
33
  id: z.string().describe('the OAuth client id'),
@@ -37,7 +39,8 @@ export const rotateSecretSubcommand = createSubcommand({
37
39
  },
38
40
 
39
41
  async handler(ctx) {
40
- const { args, opts, apiClient, options } = ctx;
42
+ const { args, opts, options } = ctx;
43
+ const catalystClient = await createOAuthClient(ctx);
41
44
 
42
45
  if (!opts.force) {
43
46
  const confirmed = await tui.confirm(
@@ -50,7 +53,7 @@ export const rotateSecretSubcommand = createSubcommand({
50
53
  }
51
54
 
52
55
  const result = await tui.spinner('Rotating OAuth client secret', () => {
53
- return oauthClientRotateSecret(apiClient as APIClient, args.id);
56
+ return oauthClientRotateSecret(catalystClient, args.id);
54
57
  });
55
58
 
56
59
  if (!options.json) {
@@ -1,8 +1,9 @@
1
- import { oauthClientUsers, type APIClient } from '@agentuity/core';
1
+ import { oauthClientUsers } from '@agentuity/core';
2
2
  import { z } from 'zod';
3
3
  import { getCommand } from '../../../command-prefix';
4
4
  import * as tui from '../../../tui';
5
5
  import { createSubcommand } from '../../../types';
6
+ import { createOAuthClient } from './util';
6
7
 
7
8
  const OAuthClientUsersResponseSchema = z.array(
8
9
  z.object({
@@ -22,8 +23,9 @@ export const usersSubcommand = createSubcommand({
22
23
  description: 'List connected users for OAuth application',
23
24
  },
24
25
  ],
25
- requires: { auth: true, apiClient: true },
26
+ requires: { auth: true },
26
27
  idempotent: true,
28
+ webUrl: (ctx) => `/settings/oauth-apps/${encodeURIComponent(ctx.args.id)}`,
27
29
  schema: {
28
30
  args: z.object({
29
31
  id: z.string().describe('the OAuth client id'),
@@ -32,10 +34,11 @@ export const usersSubcommand = createSubcommand({
32
34
  },
33
35
 
34
36
  async handler(ctx) {
35
- const { args, apiClient, options } = ctx;
37
+ const { args, options } = ctx;
38
+ const catalystClient = await createOAuthClient(ctx);
36
39
 
37
40
  const users = await tui.spinner('Fetching connected OAuth users', () => {
38
- return oauthClientUsers(apiClient as APIClient, args.id);
41
+ return oauthClientUsers(catalystClient, args.id);
39
42
  });
40
43
 
41
44
  if (!options.json) {
@@ -0,0 +1,28 @@
1
+ import type { Logger } from '@agentuity/core';
2
+ import { getGlobalCatalystAPIClient } from '../../../config';
3
+ import * as tui from '../../../tui';
4
+ import type { AuthData, Config, GlobalOptions, ProjectConfig } from '../../../types';
5
+
6
+ export async function createOAuthClient(
7
+ ctx: {
8
+ logger: Logger;
9
+ auth: AuthData;
10
+ project?: ProjectConfig;
11
+ config: Config | null;
12
+ options: GlobalOptions;
13
+ },
14
+ explicitOrgId?: string
15
+ ) {
16
+ const orgId =
17
+ explicitOrgId ??
18
+ ctx.project?.orgId ??
19
+ ctx.options.orgId ??
20
+ (process.env.AGENTUITY_CLOUD_ORG_ID || ctx.config?.preferences?.orgId);
21
+ if (!orgId) {
22
+ tui.fatal(
23
+ 'Organization ID is required. Either run from a project directory or use --org-id flag.'
24
+ );
25
+ }
26
+
27
+ return getGlobalCatalystAPIClient(ctx.logger, ctx.auth, ctx.config?.name, orgId, ctx.config);
28
+ }
@@ -41,7 +41,11 @@ export async function resolveHubUrl(flagUrl?: string): Promise<string | null> {
41
41
  export async function resolveHubWsUrl(flagUrl?: string): Promise<string | null> {
42
42
  const httpUrl = await resolveHubUrl(flagUrl);
43
43
  if (!httpUrl) return null;
44
- return normalizeToWs(httpUrl);
44
+ return toHubWsUrl(httpUrl);
45
+ }
46
+
47
+ export function toHubWsUrl(hubHttpUrl: string): string {
48
+ return normalizeToWs(hubHttpUrl);
45
49
  }
46
50
 
47
51
  /**
@@ -5,7 +5,8 @@ import { createSubcommand } from '../../types';
5
5
  import * as tui from '../../tui';
6
6
  import { getCommand } from '../../command-prefix';
7
7
  import { ErrorCode } from '../../errors';
8
- import { resolveHubWsUrl, resolveHubUrl, hubFetchHeaders } from './hub-url';
8
+ import { toHubWsUrl, resolveHubUrl, hubFetchHeaders } from './hub-url';
9
+ import { probeTuiInitAccess } from './tui-init';
9
10
 
10
11
  /**
11
12
  * Resolve the Coder extension path.
@@ -129,14 +130,32 @@ export const startSubcommand = createSubcommand({
129
130
  const { opts, options } = ctx;
130
131
 
131
132
  // Resolve Hub URL
132
- const hubWsUrl = await resolveHubWsUrl(opts?.hubUrl);
133
- if (!hubWsUrl) {
133
+ const hubHttpUrl = await resolveHubUrl(opts?.hubUrl);
134
+ if (!hubHttpUrl) {
134
135
  tui.fatal(
135
136
  'Could not find a running Coder Hub.\n\nEither:\n - Start the Hub with: bun run dev\n - Set AGENTUITY_CODER_HUB_URL environment variable\n - Pass --hub-url flag',
136
137
  ErrorCode.NETWORK_ERROR
137
138
  );
138
139
  return;
139
140
  }
141
+ const hubWsUrl = toHubWsUrl(hubHttpUrl);
142
+
143
+ const tuiInitProbe = await probeTuiInitAccess(hubHttpUrl);
144
+ if (!tuiInitProbe.ok) {
145
+ if (tuiInitProbe.code === 'unauthorized') {
146
+ tui.fatal(
147
+ `Coder Hub at ${hubHttpUrl} requires authentication.\n\nSet AGENTUITY_CODER_API_KEY in your shell and retry.\n\nServer said: ${tuiInitProbe.message}`,
148
+ ErrorCode.NETWORK_ERROR
149
+ );
150
+ return;
151
+ }
152
+
153
+ tui.fatal(
154
+ `Could not bootstrap the Coder Hub at ${hubHttpUrl}: ${tuiInitProbe.message}`,
155
+ ErrorCode.NETWORK_ERROR
156
+ );
157
+ return;
158
+ }
140
159
 
141
160
  // Resolve extension path
142
161
  const extensionPath = resolveExtensionPath(opts?.extension);
@@ -160,11 +179,6 @@ export const startSubcommand = createSubcommand({
160
179
  remoteSessionId = remoteValue;
161
180
  } else {
162
181
  // No session ID — fetch connectable sessions and show picker
163
- const hubHttpUrl = await resolveHubUrl(opts?.hubUrl);
164
- if (!hubHttpUrl) {
165
- tui.fatal('Could not find Hub URL for session picker.', ErrorCode.NETWORK_ERROR);
166
- return;
167
- }
168
182
  try {
169
183
  type SessionInfo = {
170
184
  id: string;
@@ -0,0 +1,75 @@
1
+ import { hubFetchHeaders } from './hub-url';
2
+
3
+ export type TuiInitProbeResult =
4
+ | { ok: true }
5
+ | {
6
+ ok: false;
7
+ code: 'unauthorized' | 'http_error' | 'invalid_response' | 'network_error';
8
+ message: string;
9
+ };
10
+
11
+ function normalizeErrorMessage(payload: unknown, fallback: string): string {
12
+ if (
13
+ payload &&
14
+ typeof payload === 'object' &&
15
+ typeof (payload as { error?: unknown }).error === 'string'
16
+ ) {
17
+ return (payload as { error: string }).error;
18
+ }
19
+ return fallback;
20
+ }
21
+
22
+ export async function probeTuiInitAccess(
23
+ hubHttpUrl: string,
24
+ fetchImpl: typeof fetch = fetch
25
+ ): Promise<TuiInitProbeResult> {
26
+ try {
27
+ const response = await fetchImpl(`${hubHttpUrl}/api/hub/tui/init`, {
28
+ headers: hubFetchHeaders({ accept: 'application/json' }),
29
+ signal: AbortSignal.timeout(5_000),
30
+ });
31
+
32
+ let payload: unknown;
33
+ try {
34
+ payload = await response.json();
35
+ } catch {
36
+ payload = undefined;
37
+ }
38
+
39
+ if (response.status === 401 || response.status === 403) {
40
+ return {
41
+ ok: false,
42
+ code: 'unauthorized',
43
+ message: normalizeErrorMessage(payload, `${response.status} ${response.statusText}`),
44
+ };
45
+ }
46
+
47
+ if (!response.ok) {
48
+ return {
49
+ ok: false,
50
+ code: 'http_error',
51
+ message: normalizeErrorMessage(payload, `${response.status} ${response.statusText}`),
52
+ };
53
+ }
54
+
55
+ if (
56
+ !payload ||
57
+ typeof payload !== 'object' ||
58
+ (payload as { type?: unknown }).type !== 'init'
59
+ ) {
60
+ return {
61
+ ok: false,
62
+ code: 'invalid_response',
63
+ message: 'Hub init endpoint did not return an init payload',
64
+ };
65
+ }
66
+
67
+ return { ok: true };
68
+ } catch (error) {
69
+ return {
70
+ ok: false,
71
+ code: 'network_error',
72
+ message: error instanceof Error ? error.message : String(error),
73
+ };
74
+ }
75
+ }
@@ -84,7 +84,7 @@ export const createCommand = createSubcommand({
84
84
  vector_url: 'https://catalyst.agentuity.io',
85
85
  catalyst_url: 'https://catalyst.agentuity.io',
86
86
  ion_url: 'https://ion.agentuity.io',
87
- gravity_url: 'grpc://gravity.agentuity.io:8443',
87
+ gravity_url: 'grpc://gravity.agentuity.io:443',
88
88
  };
89
89
  await saveConfig(localConfig, filename);
90
90
  }
@@ -697,19 +697,19 @@ export function performMigration(rootDir: string, routeFiles: string[]): Migrati
697
697
  * Show the migration notice and optionally perform migration.
698
698
  *
699
699
  * Called during `dev` and `build` after dependency upgrades.
700
- * Only prompts in interactive TTY sessions and only once if the user
701
- * dismisses the prompt, it won't be shown again.
700
+ * Shows an informational banner with instructionsnever blocks on
701
+ * interactive prompts (which would hang agents and CI pipelines).
702
702
  *
703
703
  * @returns true if migration was performed, false otherwise
704
704
  */
705
705
  export async function promptRouteMigration(
706
706
  rootDir: string,
707
- logger: Logger,
707
+ _logger: Logger,
708
708
  options?: { interactive?: boolean }
709
709
  ): Promise<boolean> {
710
710
  const interactive = options?.interactive ?? process.stdin.isTTY;
711
711
 
712
- // Only show the interactive migration prompt in TTY sessions
712
+ // Only show the migration notice in TTY sessions
713
713
  if (!interactive) {
714
714
  return false;
715
715
  }
@@ -722,7 +722,7 @@ export async function promptRouteMigration(
722
722
 
723
723
  const { routeFiles, alreadyNotified } = eligibility;
724
724
 
725
- // Only prompt once — if the user has already been notified or dismissed, don't ask again
725
+ // Only notify once — if the user has already been notified or dismissed, don't show again
726
726
  if (alreadyNotified) {
727
727
  return false;
728
728
  }
@@ -748,35 +748,10 @@ export async function promptRouteMigration(
748
748
  );
749
749
 
750
750
  tui.newline();
751
-
752
- const action = await tui.confirm('Would you like to migrate to explicit routing now?', false);
753
-
754
- if (!action) {
755
- writeMigrationState(rootDir, 'dismissed');
756
- tui.info(`You can migrate later by running: ${tui.muted('agentuity dev --migrate-routes')}`);
757
- tui.newline();
758
- return false;
759
- }
760
-
761
- // Perform migration
751
+ tui.info(`Migrate by running: ${tui.muted('agentuity dev --migrate-routes')}`);
762
752
  tui.newline();
763
- const result = performMigration(rootDir, routeFiles);
764
753
 
765
- if (result.success) {
766
- tui.success(result.message);
767
- if (result.filesCreated.length > 0) {
768
- tui.info(`Created: ${result.filesCreated.map((f) => tui.muted(f)).join(', ')}`);
769
- }
770
- if (result.filesModified.length > 0) {
771
- tui.info(`Modified: ${result.filesModified.map((f) => tui.muted(f)).join(', ')}`);
772
- }
773
- tui.newline();
774
- tui.info('Your existing route files were not changed — they already export routers.');
775
- tui.newline();
776
- } else {
777
- tui.warning(result.message);
778
- tui.newline();
779
- }
754
+ writeMigrationState(rootDir, 'notified');
780
755
 
781
- return result.success;
756
+ return false;
782
757
  }