@agentuity/cli 1.0.24 → 1.0.25

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 (147) hide show
  1. package/dist/cache/index.d.ts +1 -0
  2. package/dist/cache/index.d.ts.map +1 -1
  3. package/dist/cache/index.js +1 -0
  4. package/dist/cache/index.js.map +1 -1
  5. package/dist/cache/user-cache.d.ts +20 -0
  6. package/dist/cache/user-cache.d.ts.map +1 -0
  7. package/dist/cache/user-cache.js +79 -0
  8. package/dist/cache/user-cache.js.map +1 -0
  9. package/dist/cmd/auth/logout.d.ts.map +1 -1
  10. package/dist/cmd/auth/logout.js +3 -1
  11. package/dist/cmd/auth/logout.js.map +1 -1
  12. package/dist/cmd/build/entry-generator.d.ts +4 -0
  13. package/dist/cmd/build/entry-generator.d.ts.map +1 -1
  14. package/dist/cmd/build/entry-generator.js +18 -3
  15. package/dist/cmd/build/entry-generator.js.map +1 -1
  16. package/dist/cmd/build/vite/bun-dev-server.d.ts +1 -0
  17. package/dist/cmd/build/vite/bun-dev-server.d.ts.map +1 -1
  18. package/dist/cmd/build/vite/bun-dev-server.js +11 -9
  19. package/dist/cmd/build/vite/bun-dev-server.js.map +1 -1
  20. package/dist/cmd/cloud/db/stats.d.ts.map +1 -1
  21. package/dist/cmd/cloud/db/stats.js.map +1 -1
  22. package/dist/cmd/cloud/email/create.d.ts.map +1 -1
  23. package/dist/cmd/cloud/email/create.js +1 -4
  24. package/dist/cmd/cloud/email/create.js.map +1 -1
  25. package/dist/cmd/cloud/email/destination/delete.d.ts.map +1 -1
  26. package/dist/cmd/cloud/email/destination/delete.js +5 -1
  27. package/dist/cmd/cloud/email/destination/delete.js.map +1 -1
  28. package/dist/cmd/cloud/email/get.d.ts.map +1 -1
  29. package/dist/cmd/cloud/email/get.js +1 -3
  30. package/dist/cmd/cloud/email/get.js.map +1 -1
  31. package/dist/cmd/cloud/email/send.d.ts.map +1 -1
  32. package/dist/cmd/cloud/email/send.js +1 -5
  33. package/dist/cmd/cloud/email/send.js.map +1 -1
  34. package/dist/cmd/cloud/email/stats.d.ts.map +1 -1
  35. package/dist/cmd/cloud/email/stats.js.map +1 -1
  36. package/dist/cmd/cloud/email/util.d.ts.map +1 -1
  37. package/dist/cmd/cloud/email/util.js +1 -2
  38. package/dist/cmd/cloud/email/util.js.map +1 -1
  39. package/dist/cmd/cloud/sandbox/snapshot/build.d.ts.map +1 -1
  40. package/dist/cmd/cloud/sandbox/snapshot/build.js +4 -1
  41. package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -1
  42. package/dist/cmd/cloud/sandbox/stats.d.ts.map +1 -1
  43. package/dist/cmd/cloud/sandbox/stats.js.map +1 -1
  44. package/dist/cmd/cloud/schedule/delete.d.ts.map +1 -1
  45. package/dist/cmd/cloud/schedule/delete.js +4 -1
  46. package/dist/cmd/cloud/schedule/delete.js.map +1 -1
  47. package/dist/cmd/cloud/schedule/delivery/list.d.ts.map +1 -1
  48. package/dist/cmd/cloud/schedule/delivery/list.js.map +1 -1
  49. package/dist/cmd/cloud/schedule/destination/create.d.ts.map +1 -1
  50. package/dist/cmd/cloud/schedule/destination/create.js +3 -1
  51. package/dist/cmd/cloud/schedule/destination/create.js.map +1 -1
  52. package/dist/cmd/cloud/schedule/destination/index.d.ts.map +1 -1
  53. package/dist/cmd/cloud/schedule/destination/index.js.map +1 -1
  54. package/dist/cmd/cloud/schedule/destination/list.d.ts.map +1 -1
  55. package/dist/cmd/cloud/schedule/destination/list.js.map +1 -1
  56. package/dist/cmd/cloud/schedule/get.d.ts.map +1 -1
  57. package/dist/cmd/cloud/schedule/get.js +4 -1
  58. package/dist/cmd/cloud/schedule/get.js.map +1 -1
  59. package/dist/cmd/cloud/schedule/index.d.ts.map +1 -1
  60. package/dist/cmd/cloud/schedule/index.js +4 -1
  61. package/dist/cmd/cloud/schedule/index.js.map +1 -1
  62. package/dist/cmd/cloud/schedule/list.d.ts.map +1 -1
  63. package/dist/cmd/cloud/schedule/list.js.map +1 -1
  64. package/dist/cmd/cloud/schedule/stats.d.ts.map +1 -1
  65. package/dist/cmd/cloud/schedule/stats.js.map +1 -1
  66. package/dist/cmd/cloud/schedule/util.d.ts.map +1 -1
  67. package/dist/cmd/cloud/schedule/util.js +1 -2
  68. package/dist/cmd/cloud/schedule/util.js.map +1 -1
  69. package/dist/cmd/cloud/services/stats.d.ts.map +1 -1
  70. package/dist/cmd/cloud/services/stats.js.map +1 -1
  71. package/dist/cmd/cloud/stream/index.d.ts.map +1 -1
  72. package/dist/cmd/cloud/stream/index.js +7 -1
  73. package/dist/cmd/cloud/stream/index.js.map +1 -1
  74. package/dist/cmd/cloud/stream/stats.d.ts.map +1 -1
  75. package/dist/cmd/cloud/stream/stats.js.map +1 -1
  76. package/dist/cmd/cloud/task/attachment.d.ts +2 -0
  77. package/dist/cmd/cloud/task/attachment.d.ts.map +1 -0
  78. package/dist/cmd/cloud/task/attachment.js +393 -0
  79. package/dist/cmd/cloud/task/attachment.js.map +1 -0
  80. package/dist/cmd/cloud/task/create.d.ts.map +1 -1
  81. package/dist/cmd/cloud/task/create.js +126 -5
  82. package/dist/cmd/cloud/task/create.js.map +1 -1
  83. package/dist/cmd/cloud/task/get.d.ts.map +1 -1
  84. package/dist/cmd/cloud/task/get.js +29 -11
  85. package/dist/cmd/cloud/task/get.js.map +1 -1
  86. package/dist/cmd/cloud/task/index.d.ts.map +1 -1
  87. package/dist/cmd/cloud/task/index.js +13 -1
  88. package/dist/cmd/cloud/task/index.js.map +1 -1
  89. package/dist/cmd/cloud/task/list.d.ts.map +1 -1
  90. package/dist/cmd/cloud/task/list.js +31 -15
  91. package/dist/cmd/cloud/task/list.js.map +1 -1
  92. package/dist/cmd/cloud/task/stats.js +2 -0
  93. package/dist/cmd/cloud/task/stats.js.map +1 -1
  94. package/dist/cmd/cloud/task/util.d.ts.map +1 -1
  95. package/dist/cmd/cloud/task/util.js +2 -4
  96. package/dist/cmd/cloud/task/util.js.map +1 -1
  97. package/dist/cmd/cloud/webhook/create.d.ts.map +1 -1
  98. package/dist/cmd/cloud/webhook/create.js +6 -1
  99. package/dist/cmd/cloud/webhook/create.js.map +1 -1
  100. package/dist/cmd/cloud/webhook/deliveries.d.ts.map +1 -1
  101. package/dist/cmd/cloud/webhook/deliveries.js +4 -1
  102. package/dist/cmd/cloud/webhook/deliveries.js.map +1 -1
  103. package/dist/cmd/cloud/webhook/destinations.d.ts.map +1 -1
  104. package/dist/cmd/cloud/webhook/destinations.js +4 -5
  105. package/dist/cmd/cloud/webhook/destinations.js.map +1 -1
  106. package/dist/cmd/dev/index.d.ts.map +1 -1
  107. package/dist/cmd/dev/index.js +80 -34
  108. package/dist/cmd/dev/index.js.map +1 -1
  109. package/package.json +6 -6
  110. package/src/cache/index.ts +2 -0
  111. package/src/cache/user-cache.ts +93 -0
  112. package/src/cmd/auth/logout.ts +3 -1
  113. package/src/cmd/build/entry-generator.ts +34 -4
  114. package/src/cmd/build/vite/bun-dev-server.ts +21 -9
  115. package/src/cmd/cloud/db/stats.ts +4 -12
  116. package/src/cmd/cloud/email/create.ts +1 -4
  117. package/src/cmd/cloud/email/destination/delete.ts +5 -1
  118. package/src/cmd/cloud/email/get.ts +1 -3
  119. package/src/cmd/cloud/email/send.ts +1 -5
  120. package/src/cmd/cloud/email/stats.ts +2 -6
  121. package/src/cmd/cloud/email/util.ts +1 -2
  122. package/src/cmd/cloud/sandbox/snapshot/build.ts +25 -6
  123. package/src/cmd/cloud/sandbox/stats.ts +2 -6
  124. package/src/cmd/cloud/schedule/delete.ts +4 -1
  125. package/src/cmd/cloud/schedule/delivery/list.ts +15 -13
  126. package/src/cmd/cloud/schedule/destination/create.ts +11 -3
  127. package/src/cmd/cloud/schedule/destination/index.ts +3 -1
  128. package/src/cmd/cloud/schedule/destination/list.ts +19 -17
  129. package/src/cmd/cloud/schedule/get.ts +25 -20
  130. package/src/cmd/cloud/schedule/index.ts +4 -1
  131. package/src/cmd/cloud/schedule/list.ts +18 -16
  132. package/src/cmd/cloud/schedule/stats.ts +1 -3
  133. package/src/cmd/cloud/schedule/util.ts +1 -2
  134. package/src/cmd/cloud/services/stats.ts +13 -39
  135. package/src/cmd/cloud/stream/index.ts +7 -1
  136. package/src/cmd/cloud/stream/stats.ts +2 -6
  137. package/src/cmd/cloud/task/attachment.ts +432 -0
  138. package/src/cmd/cloud/task/create.ts +131 -5
  139. package/src/cmd/cloud/task/get.ts +30 -12
  140. package/src/cmd/cloud/task/index.ts +13 -1
  141. package/src/cmd/cloud/task/list.ts +31 -15
  142. package/src/cmd/cloud/task/stats.ts +3 -3
  143. package/src/cmd/cloud/task/util.ts +2 -4
  144. package/src/cmd/cloud/webhook/create.ts +6 -1
  145. package/src/cmd/cloud/webhook/deliveries.ts +4 -5
  146. package/src/cmd/cloud/webhook/destinations.ts +4 -5
  147. package/src/cmd/dev/index.ts +91 -48
@@ -4,6 +4,13 @@ import * as tui from '../../../tui';
4
4
  import { createStorageAdapter, cacheTaskId } from './util';
5
5
  import { getCommand } from '../../../command-prefix';
6
6
 
7
+ const EntityRefSchema = z
8
+ .object({
9
+ id: z.string(),
10
+ name: z.string(),
11
+ })
12
+ .optional();
13
+
7
14
  const TaskGetResponseSchema = z.object({
8
15
  success: z.boolean().describe('Whether the operation succeeded'),
9
16
  task: z.object({
@@ -14,15 +21,17 @@ const TaskGetResponseSchema = z.object({
14
21
  status: z.string().describe('Task status'),
15
22
  priority: z.string().describe('Task priority'),
16
23
  parent_id: z.string().optional().describe('Parent task ID'),
17
- assigned_id: z.string().optional().describe('Assigned agent or user ID'),
18
- created_id: z.string().describe('Creator ID'),
19
- closed_id: z.string().optional().describe('Closer ID'),
24
+ creator: EntityRefSchema.describe('Creator'),
25
+ assignee: EntityRefSchema.describe('Assignee'),
26
+ closer: EntityRefSchema.describe('Closer'),
27
+ project: EntityRefSchema.describe('Project'),
20
28
  metadata: z.record(z.string(), z.unknown()).optional().describe('Task metadata'),
21
29
  created_at: z.string().describe('Creation timestamp'),
22
30
  updated_at: z.string().describe('Last update timestamp'),
23
31
  open_date: z.string().optional().describe('Date task was opened'),
24
32
  in_progress_date: z.string().optional().describe('Date task moved to in-progress'),
25
33
  closed_date: z.string().optional().describe('Date task was closed'),
34
+ cancelled_date: z.string().optional().describe('Date task was cancelled'),
26
35
  }),
27
36
  durationMs: z.number().describe('Operation duration in milliseconds'),
28
37
  });
@@ -78,16 +87,20 @@ export const getSubcommand = createCommand({
78
87
  tableData['Description'] = task.description;
79
88
  }
80
89
 
81
- tableData['Creator'] = task.created_id;
82
-
83
- if (task.assigned_id) {
84
- tableData['Assigned'] = task.assigned_id;
90
+ if (task.creator) {
91
+ tableData['Creator'] = `${task.creator.name} (${task.creator.id})`;
92
+ }
93
+ if (task.assignee) {
94
+ tableData['Assigned'] = `${task.assignee.name} (${task.assignee.id})`;
95
+ }
96
+ if (task.project) {
97
+ tableData['Project'] = `${task.project.name} (${task.project.id})`;
85
98
  }
86
99
  if (task.parent_id) {
87
100
  tableData['Parent'] = task.parent_id;
88
101
  }
89
- if (task.closed_id) {
90
- tableData['Closed By'] = task.closed_id;
102
+ if (task.closer) {
103
+ tableData['Closed By'] = `${task.closer.name} (${task.closer.id})`;
91
104
  }
92
105
 
93
106
  tableData['Created'] = new Date(task.created_at).toLocaleString();
@@ -102,6 +115,9 @@ export const getSubcommand = createCommand({
102
115
  if (task.closed_date) {
103
116
  tableData['Closed'] = new Date(task.closed_date).toLocaleString();
104
117
  }
118
+ if (task.cancelled_date) {
119
+ tableData['Cancelled'] = new Date(task.cancelled_date).toLocaleString();
120
+ }
105
121
  tui.table([tableData], Object.keys(tableData), { layout: 'vertical', padStart: ' ' });
106
122
 
107
123
  if (task.metadata && Object.keys(task.metadata).length > 0) {
@@ -121,15 +137,17 @@ export const getSubcommand = createCommand({
121
137
  status: task.status,
122
138
  priority: task.priority,
123
139
  parent_id: task.parent_id,
124
- assigned_id: task.assigned_id,
125
- created_id: task.created_id,
126
- closed_id: task.closed_id,
140
+ creator: task.creator,
141
+ assignee: task.assignee,
142
+ closer: task.closer,
143
+ project: task.project,
127
144
  metadata: task.metadata,
128
145
  created_at: task.created_at,
129
146
  updated_at: task.updated_at,
130
147
  open_date: task.open_date,
131
148
  in_progress_date: task.in_progress_date,
132
149
  closed_date: task.closed_date,
150
+ cancelled_date: task.cancelled_date,
133
151
  },
134
152
  durationMs,
135
153
  };
@@ -4,6 +4,7 @@ import { createSubcommand } from './create';
4
4
  import { updateSubcommand } from './update';
5
5
  import { listSubcommand } from './list';
6
6
  import { statsSubcommand } from './stats';
7
+ import { attachmentSubcommand } from './attachment';
7
8
  import { getCommand } from '../../../command-prefix';
8
9
 
9
10
  export const taskCommand = createCommand({
@@ -27,8 +28,19 @@ export const taskCommand = createCommand({
27
28
  command: getCommand('cloud task update task_abc123 --status in_progress'),
28
29
  description: 'Update task status',
29
30
  },
31
+ {
32
+ command: getCommand('cloud task attachment upload task_abc123 ./report.pdf'),
33
+ description: 'Upload a file attachment to a task',
34
+ },
35
+ ],
36
+ subcommands: [
37
+ getSubcommand,
38
+ createSubcommand,
39
+ updateSubcommand,
40
+ listSubcommand,
41
+ statsSubcommand,
42
+ attachmentSubcommand,
30
43
  ],
31
- subcommands: [getSubcommand, createSubcommand, updateSubcommand, listSubcommand, statsSubcommand],
32
44
  requires: { auth: true },
33
45
  });
34
46
 
@@ -14,7 +14,24 @@ const TaskListResponseSchema = z.object({
14
14
  type: z.string(),
15
15
  status: z.string(),
16
16
  priority: z.string(),
17
- assigned_id: z.string().optional(),
17
+ creator: z
18
+ .object({
19
+ id: z.string(),
20
+ name: z.string(),
21
+ })
22
+ .optional(),
23
+ assignee: z
24
+ .object({
25
+ id: z.string(),
26
+ name: z.string(),
27
+ })
28
+ .optional(),
29
+ project: z
30
+ .object({
31
+ id: z.string(),
32
+ name: z.string(),
33
+ })
34
+ .optional(),
18
35
  created_at: z.string(),
19
36
  updated_at: z.string(),
20
37
  })
@@ -35,7 +52,9 @@ const PRIORITY_COLORS: Record<string, (s: string) => string> = {
35
52
  const STATUS_COLORS: Record<string, (s: string) => string> = {
36
53
  open: tui.colorSuccess,
37
54
  in_progress: tui.colorWarning,
55
+ done: tui.colorInfo,
38
56
  closed: tui.muted,
57
+ cancelled: tui.muted,
39
58
  };
40
59
 
41
60
  function formatPriority(p: string): string {
@@ -86,7 +105,10 @@ export const listSubcommand = createCommand({
86
105
  ],
87
106
  schema: {
88
107
  options: z.object({
89
- status: z.enum(['open', 'in_progress', 'closed']).optional().describe('filter by status'),
108
+ status: z
109
+ .enum(['open', 'in_progress', 'done', 'closed', 'cancelled'])
110
+ .optional()
111
+ .describe('filter by status'),
90
112
  type: z
91
113
  .enum(['epic', 'feature', 'enhancement', 'bug', 'task'])
92
114
  .optional()
@@ -98,17 +120,7 @@ export const listSubcommand = createCommand({
98
120
  assignedId: z.string().optional().describe('filter by assigned agent or user ID'),
99
121
  parentId: z.string().optional().describe('filter by parent task ID'),
100
122
  sort: z
101
- .enum([
102
- 'created_at',
103
- 'updated_at',
104
- 'priority',
105
- 'status',
106
- 'title',
107
- 'type',
108
- 'open_date',
109
- 'in_progress_date',
110
- 'closed_date',
111
- ])
123
+ .enum(['created_at', 'updated_at', 'priority'])
112
124
  .optional()
113
125
  .describe('field to sort by (default: created_at)'),
114
126
  order: z.enum(['asc', 'desc']).optional().describe('sort order (default: desc)'),
@@ -147,7 +159,8 @@ export const listSubcommand = createCommand({
147
159
  Type: task.type,
148
160
  Status: formatStatus(task.status),
149
161
  Priority: formatPriority(task.priority),
150
- Assigned: task.assigned_id ?? tui.muted('—'),
162
+ Creator: task.creator?.name ? truncate(task.creator.name, 20) : tui.muted('—'),
163
+ Assigned: task.assignee?.name ? truncate(task.assignee.name, 20) : tui.muted('—'),
151
164
  Updated: new Date(task.updated_at).toLocaleDateString(),
152
165
  }));
153
166
 
@@ -157,6 +170,7 @@ export const listSubcommand = createCommand({
157
170
  { name: 'Type', alignment: 'left' },
158
171
  { name: 'Status', alignment: 'left' },
159
172
  { name: 'Priority', alignment: 'left' },
173
+ { name: 'Creator', alignment: 'left' },
160
174
  { name: 'Assigned', alignment: 'left' },
161
175
  { name: 'Updated', alignment: 'left' },
162
176
  ]);
@@ -175,7 +189,9 @@ export const listSubcommand = createCommand({
175
189
  type: task.type,
176
190
  status: task.status,
177
191
  priority: task.priority,
178
- assigned_id: task.assigned_id,
192
+ creator: task.creator,
193
+ assignee: task.assignee,
194
+ project: task.project,
179
195
  created_at: task.created_at,
180
196
  updated_at: task.updated_at,
181
197
  })),
@@ -21,10 +21,10 @@ function displayStats(data: ServiceStatsData): void {
21
21
  tui.newline();
22
22
  console.log(` ${tui.muted('Total:')} ${formatNumber(svc.total)}`);
23
23
  console.log(` ${tui.muted('Open:')} ${formatNumber(svc.open)}`);
24
- console.log(
25
- ` ${tui.muted('In Progress:')} ${formatNumber(svc.inProgress)}`
26
- );
24
+ console.log(` ${tui.muted('In Progress:')} ${formatNumber(svc.inProgress)}`);
25
+ console.log(` ${tui.muted('Done:')} ${formatNumber(svc.done)}`);
27
26
  console.log(` ${tui.muted('Closed:')} ${formatNumber(svc.closed)}`);
27
+ console.log(` ${tui.muted('Cancelled:')} ${formatNumber(svc.cancelled)}`);
28
28
  }
29
29
 
30
30
  export const statsSubcommand = createCommand({
@@ -15,8 +15,7 @@ export interface TaskContext {
15
15
 
16
16
  export async function createStorageAdapter(ctx: TaskContext) {
17
17
  const orgId =
18
- ctx.options.orgId ??
19
- (process.env.AGENTUITY_CLOUD_ORG_ID || ctx.config?.preferences?.orgId);
18
+ ctx.options.orgId ?? (process.env.AGENTUITY_CLOUD_ORG_ID || ctx.config?.preferences?.orgId);
20
19
  if (!orgId) {
21
20
  tui.fatal('Organization ID is required. Use --org-id flag or set AGENTUITY_CLOUD_ORG_ID.');
22
21
  }
@@ -47,8 +46,7 @@ export async function cacheTaskId(
47
46
  const profileName = ctx.config?.name ?? defaultProfileName;
48
47
  const region = await getDefaultRegion(profileName, ctx.config);
49
48
  const orgId =
50
- ctx.options.orgId ??
51
- (process.env.AGENTUITY_CLOUD_ORG_ID || ctx.config?.preferences?.orgId);
49
+ ctx.options.orgId ?? (process.env.AGENTUITY_CLOUD_ORG_ID || ctx.config?.preferences?.orgId);
52
50
  await setResourceInfo('task', profileName, taskId, region, orgId);
53
51
  }
54
52
 
@@ -5,7 +5,12 @@ import { createWebhookAPIClient, getWebhookApiOptions } from './util';
5
5
  import { getCommand } from '../../../command-prefix';
6
6
  import { createWebhook, WebhookSchema } from '@agentuity/server';
7
7
 
8
- const WebhookCreateResponseSchema = WebhookSchema.pick({ id: true, name: true, url: true, created_at: true });
8
+ const WebhookCreateResponseSchema = WebhookSchema.pick({
9
+ id: true,
10
+ name: true,
11
+ url: true,
12
+ created_at: true,
13
+ });
9
14
 
10
15
  export const createSubcommand = createCommand({
11
16
  name: 'create',
@@ -130,11 +130,10 @@ const retryDeliverySubcommand = createSubcommand({
130
130
 
131
131
  if (!options.json) {
132
132
  tui.success(`Retried delivery: ${tui.bold(delivery.id)}`);
133
- tui.table(
134
- [{ ID: delivery.id, Status: delivery.status }],
135
- ['ID', 'Status'],
136
- { layout: 'vertical', padStart: ' ' }
137
- );
133
+ tui.table([{ ID: delivery.id, Status: delivery.status }], ['ID', 'Status'], {
134
+ layout: 'vertical',
135
+ padStart: ' ',
136
+ });
138
137
  }
139
138
 
140
139
  return delivery;
@@ -59,10 +59,7 @@ const listDestinationsSubcommand = createSubcommand({
59
59
  } else {
60
60
  const tableData = destinations.map((d: WebhookDestination) => {
61
61
  const config =
62
- d.type === 'url' &&
63
- d.config &&
64
- typeof d.config === 'object' &&
65
- 'url' in d.config
62
+ d.type === 'url' && d.config && typeof d.config === 'object' && 'url' in d.config
66
63
  ? String((d.config as Record<string, unknown>).url)
67
64
  : JSON.stringify(d.config);
68
65
  return {
@@ -192,7 +189,9 @@ const updateDestinationSubcommand = createSubcommand({
192
189
  if (!options.json) {
193
190
  tui.success(`Updated destination: ${destination.id}`);
194
191
  const url =
195
- destination.config && typeof destination.config === 'object' && 'url' in destination.config
192
+ destination.config &&
193
+ typeof destination.config === 'object' &&
194
+ 'url' in destination.config
196
195
  ? (destination.config as Record<string, unknown>).url
197
196
  : JSON.stringify(destination.config);
198
197
  console.log(` URL: ${url}`);
@@ -222,6 +222,16 @@ export const command = createCommand({
222
222
  .boolean()
223
223
  .optional()
224
224
  .describe('Enable bun debugger with breakpoint at first line'),
225
+ experimentalNoBundle: z
226
+ .boolean()
227
+ .optional()
228
+ .describe(
229
+ '[Experimental] Skip Bun.build in dev mode — run generated entry file directly'
230
+ ),
231
+ noTypecheck: z
232
+ .boolean()
233
+ .optional()
234
+ .describe('Skip TypeScript type checking on startup and restarts'),
225
235
  }),
226
236
  },
227
237
  optional: { project: true },
@@ -856,15 +866,19 @@ export const command = createCommand({
856
866
 
857
867
  // Generate entry file and bundle for dev server (with LLM patches)
858
868
  await tui.spinner({
859
- message: 'Building dev bundle',
869
+ message: opts.experimentalNoBundle
870
+ ? 'Preparing dev server'
871
+ : 'Building dev bundle',
860
872
  callback: async () => {
861
- // Step 0: typecheck
873
+ // Step 0: typecheck (skip with --no-typecheck)
862
874
  typeCheckErrors = undefined;
863
875
 
864
- const typeResult = await typecheck(rootDir);
865
- if (!typeResult.success) {
866
- typeCheckErrors = typeResult.output;
867
- return;
876
+ if (!opts.noTypecheck) {
877
+ const typeResult = await typecheck(rootDir);
878
+ if (!typeResult.success) {
879
+ typeCheckErrors = typeResult.output;
880
+ return;
881
+ }
868
882
  }
869
883
 
870
884
  // Step 1: Generate workbench files if enabled (must be done before entry generation)
@@ -881,7 +895,7 @@ export const command = createCommand({
881
895
  );
882
896
  }
883
897
 
884
- // Step 2: Discover agents and routes for registry generation
898
+ // Step 2: Discover agents and routes in parallel
885
899
  const srcDir = join(rootDir, 'src');
886
900
  const { discoverAgents } = await import('../build/vite/agent-discovery');
887
901
  const { discoverRoutes } = await import('../build/vite/route-discovery');
@@ -889,48 +903,70 @@ export const command = createCommand({
889
903
  '../build/vite/registry-generator'
890
904
  );
891
905
 
892
- const agentMetadata = await discoverAgents(
893
- srcDir,
894
- project?.projectId ?? '',
895
- deploymentId,
896
- logger
897
- );
898
- const { routes, routeInfoList } = await discoverRoutes(
899
- srcDir,
900
- project?.projectId ?? '',
901
- deploymentId,
902
- logger
903
- );
904
-
905
- // Generate agent and route registries for type augmentation
906
- // (TypeScript needs these files to exist for proper type inference)
907
- generateAgentRegistry(srcDir, agentMetadata);
908
- generateRouteRegistry(srcDir, routeInfoList);
909
- logger.debug('Agent and route registries generated for dev mode');
910
-
911
- // Step 3: Generate entry file with workbench and analytics config
912
- // Note: vitePort is NOT passed here - the app reads process.env.VITE_PORT at runtime
913
- const { generateEntryFile } = await import('../build/entry-generator');
914
- await generateEntryFile({
915
- rootDir,
916
- projectId: project?.projectId ?? '',
917
- deploymentId,
918
- logger,
919
- mode: 'dev',
920
- workbench: workbenchConfigData.enabled ? workbenchConfigData : undefined,
921
- analytics: agentuityConfig?.analytics,
922
- });
906
+ const [agentMetadata, { routes, routeInfoList }] = await Promise.all([
907
+ discoverAgents(srcDir, project?.projectId ?? '', deploymentId, logger),
908
+ discoverRoutes(srcDir, project?.projectId ?? '', deploymentId, logger),
909
+ ]);
910
+
911
+ // Step 2.5: Compute a hash of discovery results to skip codegen when unchanged
912
+ // This avoids rewriting identical files on every restart
913
+ const discoveryFingerprint = Bun.hash(
914
+ JSON.stringify({
915
+ agents: agentMetadata.map((a) => a.id + a.filename),
916
+ routes: routeInfoList.map((r) => r.method + r.path + r.filename),
917
+ })
918
+ ).toString(36);
919
+
920
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
921
+ const prevFingerprint = (globalThis as any)
922
+ .__AGENTUITY_DISCOVERY_FINGERPRINT__ as string | undefined;
923
+ const discoveryChanged = discoveryFingerprint !== prevFingerprint;
924
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
925
+ (globalThis as any).__AGENTUITY_DISCOVERY_FINGERPRINT__ = discoveryFingerprint;
926
+
927
+ if (discoveryChanged) {
928
+ // Generate agent and route registries for type augmentation
929
+ // (TypeScript needs these files to exist for proper type inference)
930
+ generateAgentRegistry(srcDir, agentMetadata);
931
+ generateRouteRegistry(srcDir, routeInfoList);
932
+ logger.debug('Agent and route registries generated for dev mode');
933
+
934
+ // Step 3: Generate entry file with workbench and analytics config
935
+ // Pass pre-discovered routes to avoid redundant route discovery
936
+ const { generateEntryFile } = await import('../build/entry-generator');
937
+ await generateEntryFile({
938
+ rootDir,
939
+ projectId: project?.projectId ?? '',
940
+ deploymentId,
941
+ logger,
942
+ mode: 'dev',
943
+ workbench: workbenchConfigData.enabled ? workbenchConfigData : undefined,
944
+ analytics: agentuityConfig?.analytics,
945
+ noBundle: opts.experimentalNoBundle,
946
+ preDiscoveredRoutes: routeInfoList,
947
+ });
948
+ } else {
949
+ logger.debug(
950
+ 'Discovery unchanged (fingerprint: %s), skipping codegen',
951
+ discoveryFingerprint
952
+ );
953
+ }
923
954
 
924
- // Step 4: Bundle the app with LLM patches (dev mode = no minification)
925
- // This produces .agentuity/app.js with AI Gateway routing patches applied
926
- const { installExternalsAndBuild } = await import(
927
- '../build/vite/server-bundler'
928
- );
929
- await installExternalsAndBuild({
930
- rootDir,
931
- dev: true, // DevMode: no minification, inline sourcemaps
932
- logger,
933
- });
955
+ // Step 4: Bundle the app with LLM patches (skip in --experimental-no-bundle mode)
956
+ if (!opts.experimentalNoBundle) {
957
+ // This produces .agentuity/app.js with AI Gateway routing patches applied
958
+ // Must re-bundle even if discovery unchanged (user code may have changed)
959
+ const { installExternalsAndBuild } = await import(
960
+ '../build/vite/server-bundler'
961
+ );
962
+ await installExternalsAndBuild({
963
+ rootDir,
964
+ dev: true,
965
+ logger,
966
+ });
967
+ } else {
968
+ logger.debug('Skipping Bun.build (--experimental-no-bundle mode)');
969
+ }
934
970
 
935
971
  // Generate metadata file (needed for eval ID lookup at runtime)
936
972
  // Reuse agentMetadata and routes from Step 2
@@ -1068,6 +1104,12 @@ export const command = createCommand({
1068
1104
  process.env.AGENTUITY_CLOUD_DEPLOYMENT_ID = deploymentId;
1069
1105
  }
1070
1106
 
1107
+ if (devmode?.hostname) {
1108
+ process.env.AGENTUITY_DEVMODE_URL = `https://${devmode.hostname}`;
1109
+ } else {
1110
+ process.env.AGENTUITY_DEVMODE_URL = `http://localhost:${opts.port}`;
1111
+ }
1112
+
1071
1113
  // Set Vite port for asset proxying in bundled app
1072
1114
  process.env.VITE_PORT = String(vitePort);
1073
1115
 
@@ -1085,6 +1127,7 @@ export const command = createCommand({
1085
1127
  inspect: opts.inspect,
1086
1128
  inspectWait: opts.inspectWait,
1087
1129
  inspectBrk: opts.inspectBrk,
1130
+ noBundle: opts.experimentalNoBundle,
1088
1131
  });
1089
1132
 
1090
1133
  // Wait for app.ts to finish loading (Vite is ready but app may still be initializing)