@agentuity/cli 1.0.12 → 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 (79) 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.map +1 -1
  56. package/dist/cmd/upgrade/npm-availability.d.ts.map +1 -1
  57. package/dist/cmd/upgrade/npm-availability.js.map +1 -1
  58. package/dist/cmd/upgrade/npm-availability.test.js.map +1 -1
  59. package/package.json +6 -6
  60. package/src/cmd/ai/opencode/dashboard.ts +772 -0
  61. package/src/cmd/ai/opencode/db.ts +66 -0
  62. package/src/cmd/ai/opencode/index.ts +17 -1
  63. package/src/cmd/ai/opencode/inspect.ts +516 -0
  64. package/src/cmd/build/ast.ts +1 -1
  65. package/src/cmd/cloud/db/list.ts +10 -7
  66. package/src/cmd/cloud/keyvalue/stats.ts +105 -11
  67. package/src/cmd/cloud/queue/list.ts +15 -9
  68. package/src/cmd/cloud/sandbox/list.ts +10 -9
  69. package/src/cmd/cloud/sandbox/runtime/list.ts +1 -4
  70. package/src/cmd/cloud/sandbox/snapshot/list.ts +2 -5
  71. package/src/cmd/cloud/session/list.ts +17 -20
  72. package/src/cmd/cloud/storage/list.ts +16 -9
  73. package/src/cmd/cloud/stream/list.ts +18 -19
  74. package/src/cmd/cloud/thread/list.ts +8 -11
  75. package/src/cmd/cloud/vector/stats.ts +39 -4
  76. package/src/cmd/dev/file-watcher.ts +44 -0
  77. package/src/cmd/upgrade/index.ts +1 -3
  78. package/src/cmd/upgrade/npm-availability.test.ts +12 -20
  79. package/src/cmd/upgrade/npm-availability.ts +1 -3
@@ -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);
@@ -223,9 +223,7 @@ export const command = createCommand({
223
223
 
224
224
  if (!isAvailable) {
225
225
  tui.warning('The new version is not yet available on npm.');
226
- tui.info(
227
- 'This can happen right after a release. Please try again in a few minutes.'
228
- );
226
+ tui.info('This can happen right after a release. Please try again in a few minutes.');
229
227
  tui.newline();
230
228
  tui.info('You can also upgrade manually:');
231
229
  console.log(` ${tui.muted('curl -fsSL https://agentuity.sh | sh')}`);
@@ -43,23 +43,15 @@ test('spawnWithTimeout returns non-zero exit code without throwing', async () =>
43
43
  expect(result.exitCode).not.toBe(0);
44
44
  });
45
45
 
46
- test(
47
- 'isVersionAvailableOnNpm returns true for a known version',
48
- async () => {
49
- const { isVersionAvailableOnNpm } = await import('./npm-availability');
50
- // Use a known-good old version that definitely exists
51
- const result = await isVersionAvailableOnNpm('1.0.10');
52
- expect(result).toBe(true);
53
- },
54
- 15_000
55
- ); // generous test timeout but the function itself has 10s subprocess timeout
56
-
57
- test(
58
- 'isVersionAvailableOnNpm returns false for non-existent version',
59
- async () => {
60
- const { isVersionAvailableOnNpm } = await import('./npm-availability');
61
- const result = await isVersionAvailableOnNpm('999.999.999');
62
- expect(result).toBe(false);
63
- },
64
- 15_000
65
- );
46
+ test('isVersionAvailableOnNpm returns true for a known version', async () => {
47
+ const { isVersionAvailableOnNpm } = await import('./npm-availability');
48
+ // Use a known-good old version that definitely exists
49
+ const result = await isVersionAvailableOnNpm('1.0.10');
50
+ expect(result).toBe(true);
51
+ }, 15_000); // generous test timeout but the function itself has 10s subprocess timeout
52
+
53
+ test('isVersionAvailableOnNpm returns false for non-existent version', async () => {
54
+ const { isVersionAvailableOnNpm } = await import('./npm-availability');
55
+ const result = await isVersionAvailableOnNpm('999.999.999');
56
+ expect(result).toBe(false);
57
+ }, 15_000);
@@ -41,9 +41,7 @@ export async function spawnWithTimeout(
41
41
  ]);
42
42
 
43
43
  if (timedOut) {
44
- throw new Error(
45
- `Command timed out after ${options.timeout}ms: ${cmd.join(' ')}`
46
- );
44
+ throw new Error(`Command timed out after ${options.timeout}ms: ${cmd.join(' ')}`);
47
45
  }
48
46
 
49
47
  return {