@agentuity/cli 1.0.11 → 1.0.13

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 (88) hide show
  1. package/dist/cmd/ai/opencode/dashboard.d.ts +3 -0
  2. package/dist/cmd/ai/opencode/dashboard.d.ts.map +1 -0
  3. package/dist/cmd/ai/opencode/dashboard.js +580 -0
  4. package/dist/cmd/ai/opencode/dashboard.js.map +1 -0
  5. package/dist/cmd/ai/opencode/db.d.ts +11 -0
  6. package/dist/cmd/ai/opencode/db.d.ts.map +1 -0
  7. package/dist/cmd/ai/opencode/db.js +63 -0
  8. package/dist/cmd/ai/opencode/db.js.map +1 -0
  9. package/dist/cmd/ai/opencode/index.d.ts.map +1 -1
  10. package/dist/cmd/ai/opencode/index.js +17 -1
  11. package/dist/cmd/ai/opencode/index.js.map +1 -1
  12. package/dist/cmd/ai/opencode/inspect.d.ts +3 -0
  13. package/dist/cmd/ai/opencode/inspect.d.ts.map +1 -0
  14. package/dist/cmd/ai/opencode/inspect.js +405 -0
  15. package/dist/cmd/ai/opencode/inspect.js.map +1 -0
  16. package/dist/cmd/build/ast.js +1 -1
  17. package/dist/cmd/build/ast.js.map +1 -1
  18. package/dist/cmd/cloud/db/list.d.ts.map +1 -1
  19. package/dist/cmd/cloud/db/list.js +10 -7
  20. package/dist/cmd/cloud/db/list.js.map +1 -1
  21. package/dist/cmd/cloud/keyvalue/stats.d.ts.map +1 -1
  22. package/dist/cmd/cloud/keyvalue/stats.js +78 -5
  23. package/dist/cmd/cloud/keyvalue/stats.js.map +1 -1
  24. package/dist/cmd/cloud/queue/list.d.ts.map +1 -1
  25. package/dist/cmd/cloud/queue/list.js +15 -9
  26. package/dist/cmd/cloud/queue/list.js.map +1 -1
  27. package/dist/cmd/cloud/sandbox/list.d.ts.map +1 -1
  28. package/dist/cmd/cloud/sandbox/list.js +10 -9
  29. package/dist/cmd/cloud/sandbox/list.js.map +1 -1
  30. package/dist/cmd/cloud/sandbox/runtime/list.d.ts.map +1 -1
  31. package/dist/cmd/cloud/sandbox/runtime/list.js +1 -4
  32. package/dist/cmd/cloud/sandbox/runtime/list.js.map +1 -1
  33. package/dist/cmd/cloud/sandbox/snapshot/list.d.ts.map +1 -1
  34. package/dist/cmd/cloud/sandbox/snapshot/list.js +2 -5
  35. package/dist/cmd/cloud/sandbox/snapshot/list.js.map +1 -1
  36. package/dist/cmd/cloud/session/list.d.ts.map +1 -1
  37. package/dist/cmd/cloud/session/list.js +1 -4
  38. package/dist/cmd/cloud/session/list.js.map +1 -1
  39. package/dist/cmd/cloud/storage/list.d.ts.map +1 -1
  40. package/dist/cmd/cloud/storage/list.js +16 -9
  41. package/dist/cmd/cloud/storage/list.js.map +1 -1
  42. package/dist/cmd/cloud/stream/list.d.ts.map +1 -1
  43. package/dist/cmd/cloud/stream/list.js +8 -9
  44. package/dist/cmd/cloud/stream/list.js.map +1 -1
  45. package/dist/cmd/cloud/thread/list.d.ts.map +1 -1
  46. package/dist/cmd/cloud/thread/list.js +1 -4
  47. package/dist/cmd/cloud/thread/list.js.map +1 -1
  48. package/dist/cmd/cloud/vector/stats.d.ts.map +1 -1
  49. package/dist/cmd/cloud/vector/stats.js +28 -4
  50. package/dist/cmd/cloud/vector/stats.js.map +1 -1
  51. package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
  52. package/dist/cmd/dev/file-watcher.js +42 -0
  53. package/dist/cmd/dev/file-watcher.js.map +1 -1
  54. package/dist/cmd/upgrade/index.d.ts.map +1 -1
  55. package/dist/cmd/upgrade/index.js +14 -8
  56. package/dist/cmd/upgrade/index.js.map +1 -1
  57. package/dist/cmd/upgrade/npm-availability.d.ts +12 -0
  58. package/dist/cmd/upgrade/npm-availability.d.ts.map +1 -1
  59. package/dist/cmd/upgrade/npm-availability.js +85 -6
  60. package/dist/cmd/upgrade/npm-availability.js.map +1 -1
  61. package/dist/cmd/upgrade/npm-availability.test.d.ts +2 -0
  62. package/dist/cmd/upgrade/npm-availability.test.d.ts.map +1 -0
  63. package/dist/cmd/upgrade/npm-availability.test.js +48 -0
  64. package/dist/cmd/upgrade/npm-availability.test.js.map +1 -0
  65. package/dist/version-check.js +3 -6
  66. package/dist/version-check.js.map +1 -1
  67. package/package.json +6 -6
  68. package/src/cmd/ai/opencode/dashboard.ts +772 -0
  69. package/src/cmd/ai/opencode/db.ts +66 -0
  70. package/src/cmd/ai/opencode/index.ts +17 -1
  71. package/src/cmd/ai/opencode/inspect.ts +516 -0
  72. package/src/cmd/build/ast.ts +1 -1
  73. package/src/cmd/cloud/db/list.ts +10 -7
  74. package/src/cmd/cloud/keyvalue/stats.ts +105 -11
  75. package/src/cmd/cloud/queue/list.ts +15 -9
  76. package/src/cmd/cloud/sandbox/list.ts +10 -9
  77. package/src/cmd/cloud/sandbox/runtime/list.ts +1 -4
  78. package/src/cmd/cloud/sandbox/snapshot/list.ts +2 -5
  79. package/src/cmd/cloud/session/list.ts +17 -20
  80. package/src/cmd/cloud/storage/list.ts +16 -9
  81. package/src/cmd/cloud/stream/list.ts +18 -19
  82. package/src/cmd/cloud/thread/list.ts +8 -11
  83. package/src/cmd/cloud/vector/stats.ts +39 -4
  84. package/src/cmd/dev/file-watcher.ts +44 -0
  85. package/src/cmd/upgrade/index.ts +20 -8
  86. package/src/cmd/upgrade/npm-availability.test.ts +57 -0
  87. package/src/cmd/upgrade/npm-availability.ts +101 -6
  88. package/src/version-check.ts +6 -6
@@ -3,6 +3,15 @@ import { createCommand } from '../../../types';
3
3
  import * as tui from '../../../tui';
4
4
  import { createStorageAdapter } from './util';
5
5
  import { getCommand } from '../../../command-prefix';
6
+ const KVStatsPaginatedSchema = z
7
+ .object({
8
+ total: z.number().describe('Total number of namespaces across all pages'),
9
+ limit: z.number().describe('Number of namespaces requested per page'),
10
+ offset: z.number().describe('Number of namespaces skipped'),
11
+ hasMore: z.boolean().describe('Whether there are more namespaces available'),
12
+ })
13
+ .passthrough();
14
+
6
15
  const KVStatsResponseSchema = z.union([
7
16
  z.object({
8
17
  namespace: z.string().describe('Namespace name'),
@@ -20,6 +29,7 @@ const KVStatsResponseSchema = z.union([
20
29
  lastUsedAt: z.string().optional().describe('Last used timestamp'),
21
30
  })
22
31
  ),
32
+ KVStatsPaginatedSchema,
23
33
  ]);
24
34
 
25
35
  export const statsSubcommand = createCommand({
@@ -41,13 +51,27 @@ export const statsSubcommand = createCommand({
41
51
  args: z.object({
42
52
  name: z.string().optional().describe('the keyvalue namespace'),
43
53
  }),
54
+ options: z.object({
55
+ name: z.string().optional().describe('Filter namespaces by name'),
56
+ sort: z
57
+ .enum(['name', 'size', 'records', 'created', 'lastUsed'])
58
+ .default('name')
59
+ .describe('field to sort by'),
60
+ direction: z.enum(['asc', 'desc']).default('asc').describe('sort direction'),
61
+ limit: z.coerce.number().min(0).optional().describe('Maximum number of results to return'),
62
+ offset: z.coerce.number().min(0).optional().describe('Offset for pagination'),
63
+ projectId: z.string().optional().describe('Filter by project ID'),
64
+ agentId: z.string().optional().describe('Filter by agent ID'),
65
+ projectName: z.string().optional().describe('Filter by project name'),
66
+ agentName: z.string().optional().describe('Filter by agent name'),
67
+ }),
44
68
  response: KVStatsResponseSchema,
45
69
  },
46
70
  webUrl: (ctx) =>
47
71
  ctx.args.name ? `/services/kv/${encodeURIComponent(ctx.args.name)}` : '/services/kv',
48
72
 
49
73
  async handler(ctx) {
50
- const { args, options } = ctx;
74
+ const { args, options, opts } = ctx;
51
75
  const kv = await createStorageAdapter(ctx);
52
76
 
53
77
  if (args.name) {
@@ -77,15 +101,56 @@ export const statsSubcommand = createCommand({
77
101
  lastUsedAt: stats.lastUsedAt ? String(stats.lastUsedAt) : undefined,
78
102
  };
79
103
  } else {
80
- const allStats = await kv.getAllStats();
81
- const entries = Object.entries(allStats);
104
+ const allStats = await kv.getAllStats({
105
+ ...(opts?.name && { name: opts.name }),
106
+ ...(opts?.sort && { sort: opts.sort }),
107
+ ...(opts?.direction && { direction: opts.direction }),
108
+ ...(opts?.limit !== undefined && { limit: opts.limit }),
109
+ ...(opts?.offset !== undefined && { offset: opts.offset }),
110
+ ...(opts?.projectId && { projectId: opts.projectId }),
111
+ ...(opts?.agentId && { agentId: opts.agentId }),
112
+ ...(opts?.projectName && { projectName: opts.projectName }),
113
+ ...(opts?.agentName && { agentName: opts.agentName }),
114
+ });
115
+
116
+ // Handle both paginated and flat response formats.
117
+ // Strictly validate pagination shape to avoid misclassifying a flat response
118
+ // that happens to contain a namespace literally named "namespaces".
119
+ const isPaginated =
120
+ allStats != null &&
121
+ typeof allStats === 'object' &&
122
+ 'namespaces' in allStats &&
123
+ 'total' in allStats &&
124
+ typeof (allStats as Record<string, unknown>).total === 'number' &&
125
+ typeof (allStats as Record<string, unknown>).namespaces === 'object' &&
126
+ (allStats as Record<string, unknown>).namespaces != null &&
127
+ // A paginated namespaces value is a Record of namespace entries (each with count/sum),
128
+ // not itself a single namespace entry (which would have count/sum at the top level).
129
+ !('count' in ((allStats as Record<string, unknown>).namespaces as object));
130
+ const namespaceMap = isPaginated
131
+ ? (
132
+ allStats as {
133
+ namespaces: Record<
134
+ string,
135
+ { count: number; sum: number; createdAt?: string; lastUsedAt?: string }
136
+ >;
137
+ }
138
+ ).namespaces
139
+ : (allStats as Record<
140
+ string,
141
+ { count: number; sum: number; createdAt?: string; lastUsedAt?: string }
142
+ >);
143
+ const entries = Object.entries(namespaceMap);
82
144
 
83
145
  if (!options.json) {
84
146
  if (entries.length === 0) {
85
147
  tui.info('No namespaces found');
86
148
  } else {
149
+ const totalInfo = isPaginated
150
+ ? ` (showing ${entries.length} of ${(allStats as { total: number }).total})`
151
+ : '';
87
152
  tui.info(
88
- `Found ${entries.length} ${tui.plural(entries.length, 'namespace', 'namespaces')}:`
153
+ `Found ${entries.length} ${tui.plural(entries.length, 'namespace', 'namespaces')}${totalInfo}:`
89
154
  );
90
155
  for (const [name, stats] of entries) {
91
156
  const sizeDisplay =
@@ -99,15 +164,44 @@ export const statsSubcommand = createCommand({
99
164
  }
100
165
  }
101
166
 
102
- // Convert timestamp fields to strings
167
+ // For JSON output with pagination, include metadata
168
+ if (isPaginated) {
169
+ const paginatedResult = allStats as {
170
+ namespaces: Record<
171
+ string,
172
+ { count: number; sum: number; createdAt?: string; lastUsedAt?: string }
173
+ >;
174
+ total: number;
175
+ limit: number;
176
+ offset: number;
177
+ hasMore: boolean;
178
+ };
179
+ // Convert timestamps to strings in namespaces
180
+ const namespaces: Record<
181
+ string,
182
+ { count: number; sum: number; createdAt?: string; lastUsedAt?: string }
183
+ > = {};
184
+ for (const [name, stats] of entries) {
185
+ namespaces[name] = {
186
+ count: stats.count,
187
+ sum: stats.sum,
188
+ createdAt: stats.createdAt ? String(stats.createdAt) : undefined,
189
+ lastUsedAt: stats.lastUsedAt ? String(stats.lastUsedAt) : undefined,
190
+ };
191
+ }
192
+ return {
193
+ namespaces,
194
+ total: paginatedResult.total,
195
+ limit: paginatedResult.limit,
196
+ offset: paginatedResult.offset,
197
+ hasMore: paginatedResult.hasMore,
198
+ };
199
+ }
200
+
201
+ // Non-paginated: return flat map
103
202
  const result: Record<
104
203
  string,
105
- {
106
- count: number;
107
- sum: number;
108
- createdAt?: string;
109
- lastUsedAt?: string;
110
- }
204
+ { count: number; sum: number; createdAt?: string; lastUsedAt?: string }
111
205
  > = {};
112
206
  for (const [name, stats] of entries) {
113
207
  result[name] = {
@@ -32,16 +32,19 @@ export const listSubcommand = createCommand({
32
32
  args: z.object({}),
33
33
  options: z.object({
34
34
  orgId: z.string().optional().describe('filter by organization id'),
35
- limit: z.coerce.number().optional().describe('Maximum number of queues to return'),
36
- offset: z.coerce.number().optional().describe('Offset for pagination'),
37
- sort: z
38
- .enum(['name', 'created', 'updated'])
39
- .optional()
40
- .describe('field to sort by (default: created)'),
41
- direction: z
42
- .enum(['asc', 'desc'])
35
+ limit: z.coerce.number().min(0).optional().describe('Maximum number of queues to return'),
36
+ offset: z.coerce.number().min(0).optional().describe('Offset for pagination'),
37
+ name: z.string().optional().describe('Filter by queue name'),
38
+ queueType: z.enum(['worker', 'pubsub']).optional().describe('Filter by queue type'),
39
+ status: z
40
+ .enum(['active', 'paused'])
43
41
  .optional()
44
- .describe('sort direction (default: desc)'),
42
+ .describe('Filter by queue status (active or paused)'),
43
+ sort: z
44
+ .enum(['name', 'created', 'updated', 'message_count', 'dlq_count'])
45
+ .default('created')
46
+ .describe('field to sort by'),
47
+ direction: z.enum(['asc', 'desc']).default('desc').describe('sort direction'),
45
48
  }),
46
49
  response: QueueListResponseSchema,
47
50
  },
@@ -58,6 +61,9 @@ export const listSubcommand = createCommand({
58
61
  offset: opts.offset,
59
62
  sort: opts.sort,
60
63
  direction: opts.direction,
64
+ name: opts.name,
65
+ queue_type: opts.queueType,
66
+ status: opts.status,
61
67
  },
62
68
  queueOptions
63
69
  );
@@ -66,6 +66,8 @@ export const listSubcommand = createCommand({
66
66
  ],
67
67
  schema: {
68
68
  options: z.object({
69
+ name: z.string().optional().describe('Filter by sandbox name'),
70
+ mode: z.enum(['oneshot', 'interactive']).optional().describe('Filter by sandbox mode'),
69
71
  status: z
70
72
  .enum(['creating', 'idle', 'running', 'terminated', 'failed'])
71
73
  .optional()
@@ -73,16 +75,13 @@ export const listSubcommand = createCommand({
73
75
  projectId: z.string().optional().describe('Filter by project ID'),
74
76
  orgId: z.string().optional().describe('Filter by organization ID'),
75
77
  all: z.boolean().optional().describe('List all sandboxes regardless of project context'),
76
- limit: z.number().optional().describe('Maximum number of results (default: 50, max: 100)'),
77
- offset: z.number().optional().describe('Pagination offset'),
78
+ limit: z.number().min(0).default(50).describe('Maximum number of results (max: 100)'),
79
+ offset: z.number().min(0).optional().describe('Pagination offset'),
78
80
  sort: z
79
- .enum(['name', 'created', 'updated', 'status'])
80
- .optional()
81
- .describe('field to sort by (default: created)'),
82
- direction: z
83
- .enum(['asc', 'desc'])
84
- .optional()
85
- .describe('sort direction (default: desc)'),
81
+ .enum(['name', 'created', 'updated', 'status', 'mode', 'execution_count'])
82
+ .default('created')
83
+ .describe('field to sort by'),
84
+ direction: z.enum(['asc', 'desc']).default('desc').describe('sort direction'),
86
85
  }),
87
86
  response: SandboxListResponseSchema,
88
87
  },
@@ -97,6 +96,8 @@ export const listSubcommand = createCommand({
97
96
  const projectId = opts.all || opts.orgId ? undefined : opts.projectId || project?.projectId;
98
97
 
99
98
  const result = await cliSandboxList(apiClient, {
99
+ name: opts.name,
100
+ mode: opts.mode,
100
101
  projectId,
101
102
  orgId: opts.orgId,
102
103
  status: opts.status,
@@ -38,10 +38,7 @@ export const listSubcommand = createCommand({
38
38
  .enum(['name', 'created'])
39
39
  .optional()
40
40
  .describe('field to sort by (default: created)'),
41
- direction: z
42
- .enum(['asc', 'desc'])
43
- .optional()
44
- .describe('sort direction (default: desc)'),
41
+ direction: z.enum(['asc', 'desc']).optional().describe('sort direction (default: desc)'),
45
42
  }),
46
43
  response: RuntimeListResponseSchema,
47
44
  },
@@ -48,13 +48,10 @@ export const listSubcommand = createCommand({
48
48
  offset: z.number().optional().describe('Offset for pagination'),
49
49
  orgId: z.string().optional().describe('filter by organization id'),
50
50
  sort: z
51
- .enum(['name', 'created', 'size'])
51
+ .enum(['name', 'created', 'size', 'files'])
52
52
  .optional()
53
53
  .describe('field to sort by (default: created)'),
54
- direction: z
55
- .enum(['asc', 'desc'])
56
- .optional()
57
- .describe('sort direction (default: desc)'),
54
+ direction: z.enum(['asc', 'desc']).optional().describe('sort direction (default: desc)'),
58
55
  }),
59
56
  response: SnapshotListResponseSchema,
60
57
  },
@@ -95,10 +95,7 @@ export const listSubcommand = createSubcommand({
95
95
  .enum(['created', 'updated', 'duration', 'startTime'])
96
96
  .optional()
97
97
  .describe('field to sort by (default: created)'),
98
- direction: z
99
- .enum(['asc', 'desc'])
100
- .optional()
101
- .describe('sort direction (default: desc)'),
98
+ direction: z.enum(['asc', 'desc']).optional().describe('sort direction (default: desc)'),
102
99
  }),
103
100
  response: SessionListResponseSchema,
104
101
  },
@@ -117,22 +114,22 @@ export const listSubcommand = createSubcommand({
117
114
  const projectId = opts.all || opts.orgId ? undefined : opts.projectId || project?.projectId;
118
115
 
119
116
  try {
120
- const sessions = await sessionList(catalystClient, {
121
- count: opts.count,
122
- orgId: opts?.orgId,
123
- projectId,
124
- deploymentId: opts.deploymentId,
125
- trigger: opts.trigger,
126
- env: opts.env,
127
- devmode: opts.devmode,
128
- success: opts.success,
129
- threadId: opts.threadId,
130
- agentIdentifier: opts.agentIdentifier,
131
- startAfter: opts.startAfter,
132
- startBefore: opts.startBefore,
133
- sort: opts.sort,
134
- direction: opts.direction,
135
- });
117
+ const sessions = await sessionList(catalystClient, {
118
+ count: opts.count,
119
+ orgId: opts?.orgId,
120
+ projectId,
121
+ deploymentId: opts.deploymentId,
122
+ trigger: opts.trigger,
123
+ env: opts.env,
124
+ devmode: opts.devmode,
125
+ success: opts.success,
126
+ threadId: opts.threadId,
127
+ agentIdentifier: opts.agentIdentifier,
128
+ startAfter: opts.startAfter,
129
+ startBefore: opts.startBefore,
130
+ sort: opts.sort,
131
+ direction: opts.direction,
132
+ });
136
133
 
137
134
  const result = sessions.map((s) => ({
138
135
  id: s.id,
@@ -70,6 +70,7 @@ export const listSubcommand = createSubcommand({
70
70
  }),
71
71
  options: z.object({
72
72
  orgId: z.string().optional().describe('filter by organization id'),
73
+ name: z.string().optional().describe('Filter by bucket name'),
73
74
  showCredentials: z
74
75
  .boolean()
75
76
  .optional()
@@ -78,13 +79,12 @@ export const listSubcommand = createSubcommand({
78
79
  ),
79
80
  nameOnly: z.boolean().optional().describe('Print the name only'),
80
81
  sort: z
81
- .enum(['name', 'created'])
82
- .optional()
83
- .describe('field to sort by (default: created)'),
84
- direction: z
85
- .enum(['asc', 'desc'])
86
- .optional()
87
- .describe('sort direction (default: desc)'),
82
+ .enum(['name', 'created', 'region'])
83
+ .default('created')
84
+ .describe('field to sort by'),
85
+ direction: z.enum(['asc', 'desc']).default('desc').describe('sort direction'),
86
+ limit: z.coerce.number().min(0).optional().describe('Maximum number of results to return'),
87
+ offset: z.coerce.number().min(0).optional().describe('Offset for pagination'),
88
88
  }),
89
89
  response: StorageListResponseSchema,
90
90
  },
@@ -106,8 +106,15 @@ export const listSubcommand = createSubcommand({
106
106
  return listOrgResources(catalystClient, {
107
107
  type: 's3',
108
108
  orgId: opts?.orgId,
109
- sort: opts?.sort,
110
- direction: opts?.direction,
109
+ ...(args.name
110
+ ? { name: args.name }
111
+ : {
112
+ name: opts?.name,
113
+ sort: opts?.sort,
114
+ direction: opts?.direction,
115
+ limit: opts?.limit,
116
+ offset: opts?.offset,
117
+ }),
111
118
  });
112
119
  },
113
120
  });
@@ -58,9 +58,10 @@ export const listSubcommand = createCommand({
58
58
  ],
59
59
  schema: {
60
60
  options: z.object({
61
- size: z.number().optional().describe('maximum number of streams to return (default: 100)'),
62
- offset: z.number().optional().describe('number of streams to skip for pagination'),
61
+ size: z.number().min(1).default(100).describe('maximum number of streams to return'),
62
+ offset: z.number().min(0).optional().describe('number of streams to skip for pagination'),
63
63
  namespace: z.string().optional().describe('filter by stream namespace'),
64
+ name: z.string().optional().describe('Filter by stream name'),
64
65
  metadata: z
65
66
  .string()
66
67
  .optional()
@@ -68,13 +69,10 @@ export const listSubcommand = createCommand({
68
69
  projectId: z.string().optional().describe('filter by project ID'),
69
70
  orgId: z.string().optional().describe('filter by organization ID'),
70
71
  sort: z
71
- .enum(['name', 'created', 'updated', 'size'])
72
- .optional()
73
- .describe('field to sort by (default: created)'),
74
- direction: z
75
- .enum(['asc', 'desc'])
76
- .optional()
77
- .describe('sort direction (default: desc)'),
72
+ .enum(['name', 'created', 'updated', 'size', 'count', 'lastUsed'])
73
+ .default('created')
74
+ .describe('field to sort by'),
75
+ direction: z.enum(['asc', 'desc']).default('desc').describe('sort direction'),
78
76
  }),
79
77
  response: ListStreamsResponseSchema,
80
78
  },
@@ -128,16 +126,17 @@ export const listSubcommand = createCommand({
128
126
  }
129
127
 
130
128
  try {
131
- const result = await streamList(apiClient, {
132
- limit: opts.size,
133
- offset: opts.offset,
134
- namespace: opts.namespace,
135
- metadata: metadataFilter,
136
- projectId,
137
- orgId: opts.orgId,
138
- sort: opts.sort,
139
- direction: opts.direction,
140
- });
129
+ const result = await streamList(apiClient, {
130
+ limit: opts.size,
131
+ offset: opts.offset,
132
+ namespace: opts.namespace,
133
+ name: opts.name,
134
+ metadata: metadataFilter,
135
+ projectId,
136
+ orgId: opts.orgId,
137
+ sort: opts.sort,
138
+ direction: opts.direction,
139
+ });
141
140
 
142
141
  if (options.json) {
143
142
  console.log(JSON.stringify(result, null, 2));
@@ -67,10 +67,7 @@ export const listSubcommand = createSubcommand({
67
67
  .enum(['created', 'updated'])
68
68
  .optional()
69
69
  .describe('field to sort by (default: created)'),
70
- direction: z
71
- .enum(['asc', 'desc'])
72
- .optional()
73
- .describe('sort direction (default: desc)'),
70
+ direction: z.enum(['asc', 'desc']).optional().describe('sort direction (default: desc)'),
74
71
  }),
75
72
  response: ThreadListResponseSchema,
76
73
  },
@@ -86,13 +83,13 @@ export const listSubcommand = createSubcommand({
86
83
  const orgId = opts.orgId;
87
84
 
88
85
  try {
89
- const threads = await threadList(catalystClient, {
90
- count: opts.count,
91
- orgId,
92
- projectId,
93
- sort: opts.sort,
94
- direction: opts.direction,
95
- });
86
+ const threads = await threadList(catalystClient, {
87
+ count: opts.count,
88
+ orgId,
89
+ projectId,
90
+ sort: opts.sort,
91
+ direction: opts.direction,
92
+ });
96
93
 
97
94
  const result = threads.map((t: Thread) => ({
98
95
  id: t.id,
@@ -59,13 +59,23 @@ export const statsSubcommand = createCommand({
59
59
  args: z.object({
60
60
  name: z.string().optional().describe('the vector namespace (optional)'),
61
61
  }),
62
+ options: z.object({
63
+ name: z.string().optional().describe('Filter namespaces by name'),
64
+ sort: z
65
+ .enum(['name', 'size', 'records', 'created', 'lastUsed'])
66
+ .default('name')
67
+ .describe('field to sort by'),
68
+ direction: z.enum(['asc', 'desc']).default('asc').describe('sort direction'),
69
+ limit: z.coerce.number().min(0).optional().describe('Maximum number of results to return'),
70
+ offset: z.coerce.number().min(0).optional().describe('Offset for pagination'),
71
+ }),
62
72
  response: VectorStatsResponseSchema,
63
73
  },
64
74
  webUrl: (ctx) =>
65
75
  ctx.args.name ? `/services/vector/${encodeURIComponent(ctx.args.name)}` : '/services/vector',
66
76
 
67
77
  async handler(ctx) {
68
- const { args, options } = ctx;
78
+ const { args, options, opts } = ctx;
69
79
  const storage = await createStorageAdapter(ctx);
70
80
 
71
81
  if (args.name) {
@@ -125,15 +135,40 @@ export const statsSubcommand = createCommand({
125
135
  ...stats,
126
136
  };
127
137
  } else {
128
- const allStats = await storage.getAllStats();
129
- const entries = Object.entries(allStats);
138
+ const allStats = await storage.getAllStats({
139
+ ...(opts?.name && { name: opts.name }),
140
+ ...(opts?.sort && { sort: opts.sort }),
141
+ ...(opts?.direction && { direction: opts.direction }),
142
+ ...(opts?.limit !== undefined && { limit: opts.limit }),
143
+ ...(opts?.offset !== undefined && { offset: opts.offset }),
144
+ });
145
+
146
+ // Handle both paginated and flat response formats
147
+ const isPaginated = allStats && typeof allStats === 'object' && 'namespaces' in allStats;
148
+ const namespaceMap = isPaginated
149
+ ? (
150
+ allStats as {
151
+ namespaces: Record<
152
+ string,
153
+ { sum: number; count: number; createdAt?: number; lastUsed?: number }
154
+ >;
155
+ }
156
+ ).namespaces
157
+ : (allStats as Record<
158
+ string,
159
+ { sum: number; count: number; createdAt?: number; lastUsed?: number }
160
+ >);
161
+ const entries = Object.entries(namespaceMap);
130
162
 
131
163
  if (!options.json) {
132
164
  if (entries.length === 0) {
133
165
  tui.info('No vector namespaces found');
134
166
  } else {
167
+ const totalInfo = isPaginated
168
+ ? ` (showing ${entries.length} of ${(allStats as { total: number }).total})`
169
+ : '';
135
170
  tui.info(
136
- `Found ${entries.length} ${tui.plural(entries.length, 'namespace', 'namespaces')}:`
171
+ `Found ${entries.length} ${tui.plural(entries.length, 'namespace', 'namespaces')}${totalInfo}:`
137
172
  );
138
173
 
139
174
  const tableData = entries.map(([name, stats]) => {
@@ -84,6 +84,40 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
84
84
  'src/generated', // Generated files shouldn't trigger rebuilds
85
85
  ];
86
86
 
87
+ // File extensions to ignore - non-code files that shouldn't trigger reload
88
+ const ignoreExtensions = new Set([
89
+ '.md',
90
+ '.mdx',
91
+ '.txt',
92
+ '.log',
93
+ '.lock',
94
+ '.yaml',
95
+ '.yml',
96
+ '.toml',
97
+ '.csv',
98
+ '.svg',
99
+ '.png',
100
+ '.jpg',
101
+ '.jpeg',
102
+ '.gif',
103
+ '.webp',
104
+ '.ico',
105
+ '.woff',
106
+ '.woff2',
107
+ '.ttf',
108
+ '.eot',
109
+ '.mp4',
110
+ '.mp3',
111
+ '.wav',
112
+ '.ogg',
113
+ '.webm',
114
+ '.pdf',
115
+ '.zip',
116
+ '.tar',
117
+ '.gz',
118
+ '.map',
119
+ ]);
120
+
87
121
  /**
88
122
  * Check if a path should be ignored
89
123
  */
@@ -134,6 +168,16 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
134
168
  return true;
135
169
  }
136
170
 
171
+ // Ignore files with non-code extensions
172
+ const extIndex = changedFile.lastIndexOf('.');
173
+ if (extIndex !== -1) {
174
+ const ext = changedFile.slice(extIndex).toLowerCase();
175
+ if (ignoreExtensions.has(ext)) {
176
+ logger.trace('File change ignored (%s): %s', ext, changedFile);
177
+ return true;
178
+ }
179
+ }
180
+
137
181
  // Ignore hidden files (except .env)
138
182
  if (changedFile.startsWith('.') && !changedFile.startsWith('.env')) {
139
183
  logger.trace('File change ignored (hidden file): %s', changedFile);
@@ -4,7 +4,6 @@ import { getCommand } from '../../command-prefix';
4
4
  import { z } from 'zod';
5
5
  import { ErrorCode, createError, exitWithError } from '../../errors';
6
6
  import * as tui from '../../tui';
7
- import { $ } from 'bun';
8
7
  import { tmpdir } from 'node:os';
9
8
  import { getInstallationType, type InstallationType } from '../../utils/installation-type';
10
9
 
@@ -84,14 +83,17 @@ async function performBunUpgrade(
84
83
  const { installWithRetry } = await import('./npm-availability');
85
84
 
86
85
  try {
86
+ const { spawnWithTimeout } = await import('./npm-availability');
87
+
87
88
  await installWithRetry(
88
89
  async () => {
89
90
  // Use bun to install the specific version globally
90
91
  // Run from tmpdir to avoid interference from any local package.json/node_modules
91
- const result = await $`bun add -g @agentuity/cli@${npmVersion}`
92
- .cwd(tmpdir())
93
- .quiet()
94
- .nothrow();
92
+ // spawnWithTimeout kills the process if it exceeds 30s (INSTALL_TIMEOUT_MS)
93
+ const result = await spawnWithTimeout(
94
+ ['bun', 'add', '-g', `@agentuity/cli@${npmVersion}`],
95
+ { cwd: tmpdir(), timeout: 30_000 }
96
+ );
95
97
  return { exitCode: result.exitCode, stderr: result.stderr };
96
98
  },
97
99
  { onRetry }
@@ -107,8 +109,10 @@ async function performBunUpgrade(
107
109
  * Verify the upgrade was successful by checking the installed version
108
110
  */
109
111
  async function verifyUpgrade(expectedVersion: string): Promise<void> {
110
- // Run agentuity version to check the installed version
111
- const result = await $`agentuity version`.quiet().nothrow();
112
+ const { spawnWithTimeout } = await import('./npm-availability');
113
+
114
+ // Run agentuity version to check the installed version (5s timeout — local command, sub-second normally)
115
+ const result = await spawnWithTimeout(['agentuity', 'version'], { timeout: 5_000 });
112
116
 
113
117
  if (result.exitCode !== 0) {
114
118
  throw new Error('Failed to verify upgrade - could not run agentuity version');
@@ -220,7 +224,9 @@ export const command = createCommand({
220
224
  if (!isAvailable) {
221
225
  tui.warning('The new version is not yet available on npm.');
222
226
  tui.info('This can happen right after a release. Please try again in a few minutes.');
223
- tui.info(`You can also run: ${tui.muted('bun add -g @agentuity/cli@latest')}`);
227
+ tui.newline();
228
+ tui.info('You can also upgrade manually:');
229
+ console.log(` ${tui.muted('curl -fsSL https://agentuity.sh | sh')}`);
224
230
  return {
225
231
  upgraded: false,
226
232
  from: currentVersion,
@@ -301,6 +307,12 @@ export const command = createCommand({
301
307
  installationType,
302
308
  };
303
309
 
310
+ tui.newline();
311
+ tui.info('If the upgrade continues to fail, you can reinstall manually:');
312
+ tui.newline();
313
+ console.log(` ${tui.muted('curl -fsSL https://agentuity.sh | sh')}`);
314
+ tui.newline();
315
+
304
316
  exitWithError(
305
317
  createError(ErrorCode.INTERNAL_ERROR, 'Upgrade failed', errorDetails),
306
318
  logger,