@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
@@ -0,0 +1,57 @@
1
+ import { test, expect, beforeAll, afterAll } from 'bun:test';
2
+ import { spawnWithTimeout } from './npm-availability';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+
6
+ // bun info requires a package.json in its cwd, and isVersionAvailableOnNpm
7
+ // uses tmpdir() as cwd. Ensure a minimal package.json exists there for tests.
8
+ const tmpPackageJson = join(tmpdir(), 'package.json');
9
+ let createdPackageJson = false;
10
+
11
+ beforeAll(async () => {
12
+ const file = Bun.file(tmpPackageJson);
13
+ if (!(await file.exists())) {
14
+ await Bun.write(file, '{}');
15
+ createdPackageJson = true;
16
+ }
17
+ });
18
+
19
+ afterAll(async () => {
20
+ if (createdPackageJson) {
21
+ const { unlink } = await import('node:fs/promises');
22
+ await unlink(tmpPackageJson).catch(() => {});
23
+ }
24
+ });
25
+
26
+ test('spawnWithTimeout kills process on timeout', async () => {
27
+ // spawn a command that hangs with a short timeout (500ms)
28
+ await expect(
29
+ spawnWithTimeout(['bun', '-e', 'setTimeout(()=>{},60000)'], { timeout: 500 })
30
+ ).rejects.toThrow(/timed out/);
31
+ });
32
+
33
+ test('spawnWithTimeout returns result when command completes in time', async () => {
34
+ const result = await spawnWithTimeout(['bun', '-e', "console.log('hello')"], {
35
+ timeout: 5_000,
36
+ });
37
+ expect(result.exitCode).toBe(0);
38
+ expect(result.stdout.toString().trim()).toBe('hello');
39
+ });
40
+
41
+ test('spawnWithTimeout returns non-zero exit code without throwing', async () => {
42
+ const result = await spawnWithTimeout(['bun', '-e', 'process.exit(1)'], { timeout: 5_000 });
43
+ expect(result.exitCode).not.toBe(0);
44
+ });
45
+
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);
@@ -3,11 +3,91 @@
3
3
  * Used to verify a version is available via bun's resolver before attempting upgrade.
4
4
  */
5
5
 
6
- import { $ } from 'bun';
7
6
  import { tmpdir } from 'node:os';
8
7
 
9
8
  const PACKAGE_SPEC = '@agentuity/cli';
10
9
 
10
+ /** Default timeout for `bun info` subprocess calls (10 seconds) */
11
+ const BUN_INFO_TIMEOUT_MS = 10_000;
12
+
13
+ /** Default timeout for install (`bun add -g`) subprocess calls (30 seconds) */
14
+ const INSTALL_TIMEOUT_MS = 30_000;
15
+
16
+ /**
17
+ * Run a command via Bun.spawn with a timeout that kills the process.
18
+ * Returns { exitCode, stdout, stderr } similar to Bun's $ shell result.
19
+ */
20
+ export async function spawnWithTimeout(
21
+ cmd: string[],
22
+ options: { cwd?: string; timeout: number }
23
+ ): Promise<{ exitCode: number; stdout: Buffer; stderr: Buffer }> {
24
+ const proc = Bun.spawn(cmd, {
25
+ cwd: options.cwd,
26
+ stdout: 'pipe',
27
+ stderr: 'pipe',
28
+ });
29
+
30
+ let timedOut = false;
31
+ const timer = setTimeout(() => {
32
+ timedOut = true;
33
+ proc.kill();
34
+ }, options.timeout);
35
+
36
+ try {
37
+ const [exitCode, stdoutBytes, stderrBytes] = await Promise.all([
38
+ proc.exited,
39
+ new Response(proc.stdout).arrayBuffer(),
40
+ new Response(proc.stderr).arrayBuffer(),
41
+ ]);
42
+
43
+ if (timedOut) {
44
+ throw new Error(`Command timed out after ${options.timeout}ms: ${cmd.join(' ')}`);
45
+ }
46
+
47
+ return {
48
+ exitCode,
49
+ stdout: Buffer.from(stdoutBytes),
50
+ stderr: Buffer.from(stderrBytes),
51
+ };
52
+ } finally {
53
+ clearTimeout(timer);
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Sentinel error thrown exclusively by withTimeout so the retry loop can
59
+ * distinguish a genuine timeout from other failures (e.g. permission errors).
60
+ */
61
+ class TimeoutError extends Error {
62
+ constructor(description: string, timeoutMs: number) {
63
+ super(`${description} timed out after ${timeoutMs}ms`);
64
+ this.name = 'TimeoutError';
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Race a promise against a timeout. Unlike spawnWithTimeout (which kills a process),
70
+ * this is a generic wrapper for any async operation (e.g. the installFn callback).
71
+ *
72
+ * Throws a {@link TimeoutError} (not a plain Error) so callers can tell
73
+ * timeouts apart from other exceptions.
74
+ */
75
+ async function withTimeout<T>(
76
+ promise: Promise<T>,
77
+ timeoutMs: number,
78
+ description: string
79
+ ): Promise<T> {
80
+ let timer: ReturnType<typeof setTimeout>;
81
+ const timeoutPromise = new Promise<never>((_, reject) => {
82
+ timer = setTimeout(() => reject(new TimeoutError(description, timeoutMs)), timeoutMs);
83
+ });
84
+ try {
85
+ return await Promise.race([promise, timeoutPromise]);
86
+ } finally {
87
+ clearTimeout(timer!);
88
+ }
89
+ }
90
+
11
91
  /**
12
92
  * Check if a specific version of @agentuity/cli is resolvable by bun.
13
93
  * Uses `bun info` to verify bun's own resolver/CDN can see the version,
@@ -20,10 +100,10 @@ const PACKAGE_SPEC = '@agentuity/cli';
20
100
  export async function isVersionAvailableOnNpm(version: string): Promise<boolean> {
21
101
  const normalizedVersion = version.replace(/^v/, '');
22
102
  try {
23
- const result = await $`bun info ${PACKAGE_SPEC}@${normalizedVersion} --json`
24
- .cwd(tmpdir())
25
- .quiet()
26
- .nothrow();
103
+ const result = await spawnWithTimeout(
104
+ ['bun', 'info', `${PACKAGE_SPEC}@${normalizedVersion}`, '--json'],
105
+ { cwd: tmpdir(), timeout: BUN_INFO_TIMEOUT_MS }
106
+ );
27
107
  if (result.exitCode !== 0) {
28
108
  return false;
29
109
  }
@@ -147,7 +227,22 @@ export async function installWithRetry(
147
227
  let delay = initialDelayMs;
148
228
 
149
229
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
150
- const result = await installFn();
230
+ let result: { exitCode: number; stderr: Buffer };
231
+ try {
232
+ result = await withTimeout(installFn(), INSTALL_TIMEOUT_MS, 'Install command');
233
+ } catch (error) {
234
+ // Only retry on timeouts — non-timeout errors (permissions, disk, etc.) are fatal
235
+ if (!(error instanceof TimeoutError)) {
236
+ throw error;
237
+ }
238
+ if (attempt === maxAttempts) {
239
+ throw error;
240
+ }
241
+ onRetry?.(attempt, delay);
242
+ await new Promise((resolve) => setTimeout(resolve, delay));
243
+ delay = Math.min(Math.round(delay * multiplier), maxDelayMs);
244
+ continue;
245
+ }
151
246
 
152
247
  if (result.exitCode === 0) {
153
248
  return result;
@@ -4,7 +4,6 @@ import { fetchLatestVersion } from './cmd/upgrade';
4
4
  import { getVersion, getCompareUrl, getReleaseUrl, toTag } from './version';
5
5
  import * as tui from './tui';
6
6
  import { saveConfig } from './config';
7
- import { $ } from 'bun';
8
7
  import { tmpdir } from 'node:os';
9
8
  import { getExecutingAgent } from './agent-detection';
10
9
 
@@ -174,13 +173,14 @@ async function performUpgrade(logger: Logger, targetVersion: string): Promise<vo
174
173
 
175
174
  // Use bun to install the specific version globally with retry for CDN propagation delays
176
175
  // Run from tmpdir to avoid interference from any local package.json/node_modules
177
- const { installWithRetry } = await import('./cmd/upgrade/npm-availability');
176
+ const { installWithRetry, spawnWithTimeout } = await import('./cmd/upgrade/npm-availability');
178
177
  await installWithRetry(
179
178
  async () => {
180
- const result = await $`bun add -g @agentuity/cli@${npmVersion}`
181
- .cwd(tmpdir())
182
- .quiet()
183
- .nothrow();
179
+ // spawnWithTimeout kills the process if it exceeds 30s
180
+ const result = await spawnWithTimeout(
181
+ ['bun', 'add', '-g', `@agentuity/cli@${npmVersion}`],
182
+ { cwd: tmpdir(), timeout: 30_000 }
183
+ );
184
184
  return { exitCode: result.exitCode, stderr: result.stderr };
185
185
  },
186
186
  {