@agentuity/cli 2.0.6 → 2.0.8

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 (201) hide show
  1. package/README.md +11 -0
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +4 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  6. package/dist/cmd/build/vite/route-discovery.js +6 -0
  7. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  8. package/dist/cmd/cloud/sandbox/fs/rm.d.ts.map +1 -1
  9. package/dist/cmd/cloud/sandbox/fs/rm.js +9 -3
  10. package/dist/cmd/cloud/sandbox/fs/rm.js.map +1 -1
  11. package/dist/cmd/cloud/sandbox/fs/rmdir.d.ts.map +1 -1
  12. package/dist/cmd/cloud/sandbox/fs/rmdir.js +9 -3
  13. package/dist/cmd/cloud/sandbox/fs/rmdir.js.map +1 -1
  14. package/dist/cmd/cloud/task/close.d.ts +3 -0
  15. package/dist/cmd/cloud/task/close.d.ts.map +1 -0
  16. package/dist/cmd/cloud/task/close.js +286 -0
  17. package/dist/cmd/cloud/task/close.js.map +1 -0
  18. package/dist/cmd/cloud/task/delete.d.ts +1 -5
  19. package/dist/cmd/cloud/task/delete.d.ts.map +1 -1
  20. package/dist/cmd/cloud/task/delete.js +15 -38
  21. package/dist/cmd/cloud/task/delete.js.map +1 -1
  22. package/dist/cmd/cloud/task/index.d.ts.map +1 -1
  23. package/dist/cmd/cloud/task/index.js +10 -0
  24. package/dist/cmd/cloud/task/index.js.map +1 -1
  25. package/dist/cmd/cloud/task/list.d.ts.map +1 -1
  26. package/dist/cmd/cloud/task/list.js +97 -3
  27. package/dist/cmd/cloud/task/list.js.map +1 -1
  28. package/dist/cmd/cloud/task/util.d.ts +10 -0
  29. package/dist/cmd/cloud/task/util.d.ts.map +1 -1
  30. package/dist/cmd/cloud/task/util.js +47 -3
  31. package/dist/cmd/cloud/task/util.js.map +1 -1
  32. package/dist/cmd/coder/archive.d.ts +2 -0
  33. package/dist/cmd/coder/archive.d.ts.map +1 -0
  34. package/dist/cmd/coder/archive.js +57 -0
  35. package/dist/cmd/coder/archive.js.map +1 -0
  36. package/dist/cmd/coder/create.d.ts +2 -0
  37. package/dist/cmd/coder/create.d.ts.map +1 -0
  38. package/dist/cmd/coder/create.js +245 -0
  39. package/dist/cmd/coder/create.js.map +1 -0
  40. package/dist/cmd/coder/delete.d.ts +2 -0
  41. package/dist/cmd/coder/delete.d.ts.map +1 -0
  42. package/dist/cmd/coder/delete.js +64 -0
  43. package/dist/cmd/coder/delete.js.map +1 -0
  44. package/dist/cmd/coder/events.d.ts +2 -0
  45. package/dist/cmd/coder/events.d.ts.map +1 -0
  46. package/dist/cmd/coder/events.js +99 -0
  47. package/dist/cmd/coder/events.js.map +1 -0
  48. package/dist/cmd/coder/extension-path.d.ts +8 -0
  49. package/dist/cmd/coder/extension-path.d.ts.map +1 -0
  50. package/dist/cmd/coder/extension-path.js +59 -0
  51. package/dist/cmd/coder/extension-path.js.map +1 -0
  52. package/dist/cmd/coder/get.d.ts +2 -0
  53. package/dist/cmd/coder/get.d.ts.map +1 -0
  54. package/dist/cmd/coder/{inspect.js → get.js} +37 -33
  55. package/dist/cmd/coder/get.js.map +1 -0
  56. package/dist/cmd/coder/index.d.ts.map +1 -1
  57. package/dist/cmd/coder/index.js +54 -4
  58. package/dist/cmd/coder/index.js.map +1 -1
  59. package/dist/cmd/coder/list.d.ts.map +1 -1
  60. package/dist/cmd/coder/list.js +25 -34
  61. package/dist/cmd/coder/list.js.map +1 -1
  62. package/dist/cmd/coder/loop.d.ts +2 -0
  63. package/dist/cmd/coder/loop.d.ts.map +1 -0
  64. package/dist/cmd/coder/loop.js +78 -0
  65. package/dist/cmd/coder/loop.js.map +1 -0
  66. package/dist/cmd/coder/participants.d.ts +2 -0
  67. package/dist/cmd/coder/participants.d.ts.map +1 -0
  68. package/dist/cmd/coder/participants.js +93 -0
  69. package/dist/cmd/coder/participants.js.map +1 -0
  70. package/dist/cmd/coder/replay.d.ts +2 -0
  71. package/dist/cmd/coder/replay.d.ts.map +1 -0
  72. package/dist/cmd/coder/replay.js +53 -0
  73. package/dist/cmd/coder/replay.js.map +1 -0
  74. package/dist/cmd/coder/resolve-repo.d.ts +27 -0
  75. package/dist/cmd/coder/resolve-repo.d.ts.map +1 -0
  76. package/dist/cmd/coder/resolve-repo.js +97 -0
  77. package/dist/cmd/coder/resolve-repo.js.map +1 -0
  78. package/dist/cmd/coder/skill/buckets.d.ts +2 -0
  79. package/dist/cmd/coder/skill/buckets.d.ts.map +1 -0
  80. package/dist/cmd/coder/skill/buckets.js +174 -0
  81. package/dist/cmd/coder/skill/buckets.js.map +1 -0
  82. package/dist/cmd/coder/skill/delete.d.ts +2 -0
  83. package/dist/cmd/coder/skill/delete.d.ts.map +1 -0
  84. package/dist/cmd/coder/skill/delete.js +64 -0
  85. package/dist/cmd/coder/skill/delete.js.map +1 -0
  86. package/dist/cmd/coder/skill/index.d.ts +2 -0
  87. package/dist/cmd/coder/skill/index.d.ts.map +1 -0
  88. package/dist/cmd/coder/skill/index.js +33 -0
  89. package/dist/cmd/coder/skill/index.js.map +1 -0
  90. package/dist/cmd/coder/skill/list.d.ts +2 -0
  91. package/dist/cmd/coder/skill/list.d.ts.map +1 -0
  92. package/dist/cmd/coder/skill/list.js +93 -0
  93. package/dist/cmd/coder/skill/list.js.map +1 -0
  94. package/dist/cmd/coder/skill/save.d.ts +2 -0
  95. package/dist/cmd/coder/skill/save.d.ts.map +1 -0
  96. package/dist/cmd/coder/skill/save.js +77 -0
  97. package/dist/cmd/coder/skill/save.js.map +1 -0
  98. package/dist/cmd/coder/start.d.ts.map +1 -1
  99. package/dist/cmd/coder/start.js +88 -117
  100. package/dist/cmd/coder/start.js.map +1 -1
  101. package/dist/cmd/coder/tui-init.d.ts +4 -1
  102. package/dist/cmd/coder/tui-init.d.ts.map +1 -1
  103. package/dist/cmd/coder/tui-init.js +9 -3
  104. package/dist/cmd/coder/tui-init.js.map +1 -1
  105. package/dist/cmd/coder/update.d.ts +2 -0
  106. package/dist/cmd/coder/update.d.ts.map +1 -0
  107. package/dist/cmd/coder/update.js +126 -0
  108. package/dist/cmd/coder/update.js.map +1 -0
  109. package/dist/cmd/coder/users.d.ts +2 -0
  110. package/dist/cmd/coder/users.d.ts.map +1 -0
  111. package/dist/cmd/coder/users.js +97 -0
  112. package/dist/cmd/coder/users.js.map +1 -0
  113. package/dist/cmd/coder/workspace/create.d.ts +2 -0
  114. package/dist/cmd/coder/workspace/create.d.ts.map +1 -0
  115. package/dist/cmd/coder/workspace/create.js +97 -0
  116. package/dist/cmd/coder/workspace/create.js.map +1 -0
  117. package/dist/cmd/coder/workspace/delete.d.ts +2 -0
  118. package/dist/cmd/coder/workspace/delete.d.ts.map +1 -0
  119. package/dist/cmd/coder/workspace/delete.js +64 -0
  120. package/dist/cmd/coder/workspace/delete.js.map +1 -0
  121. package/dist/cmd/coder/workspace/get.d.ts +2 -0
  122. package/dist/cmd/coder/workspace/get.d.ts.map +1 -0
  123. package/dist/cmd/coder/workspace/get.js +109 -0
  124. package/dist/cmd/coder/workspace/get.js.map +1 -0
  125. package/dist/cmd/coder/workspace/index.d.ts +2 -0
  126. package/dist/cmd/coder/workspace/index.d.ts.map +1 -0
  127. package/dist/cmd/coder/workspace/index.js +38 -0
  128. package/dist/cmd/coder/workspace/index.js.map +1 -0
  129. package/dist/cmd/coder/workspace/list.d.ts +2 -0
  130. package/dist/cmd/coder/workspace/list.d.ts.map +1 -0
  131. package/dist/cmd/coder/workspace/list.js +93 -0
  132. package/dist/cmd/coder/workspace/list.js.map +1 -0
  133. package/dist/cmd/dev/sync.js +5 -5
  134. package/dist/cmd/dev/sync.js.map +1 -1
  135. package/dist/coder-hub-url.d.ts +3 -0
  136. package/dist/coder-hub-url.d.ts.map +1 -0
  137. package/dist/coder-hub-url.js +32 -0
  138. package/dist/coder-hub-url.js.map +1 -0
  139. package/dist/config.d.ts +1 -0
  140. package/dist/config.d.ts.map +1 -1
  141. package/dist/config.js +14 -3
  142. package/dist/config.js.map +1 -1
  143. package/dist/internal-logger.d.ts +4 -0
  144. package/dist/internal-logger.d.ts.map +1 -1
  145. package/dist/internal-logger.js +64 -2
  146. package/dist/internal-logger.js.map +1 -1
  147. package/dist/keychain.d.ts +3 -0
  148. package/dist/keychain.d.ts.map +1 -1
  149. package/dist/keychain.js +47 -28
  150. package/dist/keychain.js.map +1 -1
  151. package/dist/types.d.ts +1 -1
  152. package/package.json +7 -6
  153. package/src/cli.ts +4 -2
  154. package/src/cmd/ai/prompt/agent.md +6 -6
  155. package/src/cmd/build/vite/route-discovery.ts +8 -0
  156. package/src/cmd/cloud/sandbox/fs/rm.ts +8 -3
  157. package/src/cmd/cloud/sandbox/fs/rmdir.ts +8 -3
  158. package/src/cmd/cloud/task/close.ts +319 -0
  159. package/src/cmd/cloud/task/delete.ts +15 -43
  160. package/src/cmd/cloud/task/index.ts +10 -0
  161. package/src/cmd/cloud/task/list.ts +111 -4
  162. package/src/cmd/cloud/task/util.ts +59 -5
  163. package/src/cmd/coder/archive.ts +59 -0
  164. package/src/cmd/coder/create.ts +268 -0
  165. package/src/cmd/coder/delete.ts +67 -0
  166. package/src/cmd/coder/events.ts +106 -0
  167. package/src/cmd/coder/extension-path.ts +71 -0
  168. package/src/cmd/coder/{inspect.ts → get.ts} +44 -45
  169. package/src/cmd/coder/index.ts +54 -4
  170. package/src/cmd/coder/list.ts +28 -65
  171. package/src/cmd/coder/loop.ts +85 -0
  172. package/src/cmd/coder/participants.ts +100 -0
  173. package/src/cmd/coder/replay.ts +58 -0
  174. package/src/cmd/coder/resolve-repo.ts +119 -0
  175. package/src/cmd/coder/skill/buckets.ts +191 -0
  176. package/src/cmd/coder/skill/delete.ts +67 -0
  177. package/src/cmd/coder/skill/index.ts +35 -0
  178. package/src/cmd/coder/skill/list.ts +97 -0
  179. package/src/cmd/coder/skill/save.ts +84 -0
  180. package/src/cmd/coder/start.ts +104 -141
  181. package/src/cmd/coder/tui-init.ts +13 -4
  182. package/src/cmd/coder/update.ts +128 -0
  183. package/src/cmd/coder/users.ts +101 -0
  184. package/src/cmd/coder/workspace/create.ts +104 -0
  185. package/src/cmd/coder/workspace/delete.ts +70 -0
  186. package/src/cmd/coder/workspace/get.ts +112 -0
  187. package/src/cmd/coder/workspace/index.ts +38 -0
  188. package/src/cmd/coder/workspace/list.ts +101 -0
  189. package/src/cmd/dev/sync.ts +5 -5
  190. package/src/coder-hub-url.ts +32 -0
  191. package/src/config.ts +17 -3
  192. package/src/internal-logger.ts +83 -2
  193. package/src/keychain.ts +68 -39
  194. package/dist/cmd/coder/hub-url.d.ts +0 -36
  195. package/dist/cmd/coder/hub-url.d.ts.map +0 -1
  196. package/dist/cmd/coder/hub-url.js +0 -106
  197. package/dist/cmd/coder/hub-url.js.map +0 -1
  198. package/dist/cmd/coder/inspect.d.ts +0 -2
  199. package/dist/cmd/coder/inspect.d.ts.map +0 -1
  200. package/dist/cmd/coder/inspect.js.map +0 -1
  201. package/src/cmd/coder/hub-url.ts +0 -111
package/dist/keychain.js CHANGED
@@ -6,6 +6,8 @@
6
6
  */
7
7
  const SERVICE_PREFIX = 'com.agentuity.cli';
8
8
  const KEY_ACCOUNT = 'aes-encryption-key';
9
+ const AUTH_ACCOUNT = 'auth-token';
10
+ const CODER_API_KEY_ACCOUNT = 'coder-hub-api-key';
9
11
  /**
10
12
  * Check if we're running on macOS
11
13
  */
@@ -65,20 +67,10 @@ async function decrypt(combined, keyBytes) {
65
67
  const plaintext = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, ciphertext);
66
68
  return new TextDecoder().decode(plaintext);
67
69
  }
68
- /**
69
- * Store auth data in macOS Keychain
70
- */
71
- export async function saveAuthToKeychain(profileName, authData) {
72
- const service = `${SERVICE_PREFIX}.${profileName}`;
73
- const account = 'auth-token';
74
- // Get or create encryption key
70
+ async function saveEncryptedValueToKeychain(service, account, value) {
75
71
  const key = await ensureEncryptionKey(service);
76
- // Encrypt the auth data
77
- const json = JSON.stringify(authData);
78
- const encrypted = await encrypt(json, key);
72
+ const encrypted = await encrypt(value, key);
79
73
  const b64 = Buffer.from(encrypted).toString('base64');
80
- // Store encrypted auth in keychain
81
- // First try to delete if exists, then add
82
74
  const del = Bun.spawn(['security', 'delete-generic-password', '-s', service, '-a', account], {
83
75
  stderr: 'ignore',
84
76
  });
@@ -96,25 +88,39 @@ export async function saveAuthToKeychain(profileName, authData) {
96
88
  ]);
97
89
  await add.exited;
98
90
  }
91
+ async function getEncryptedValueFromKeychain(service, account) {
92
+ const find = Bun.spawn(['security', 'find-generic-password', '-s', service, '-a', account, '-w'], { stderr: 'ignore' });
93
+ const stdout = await new Response(find.stdout).text();
94
+ if (stdout.length === 0) {
95
+ return null;
96
+ }
97
+ const encrypted = Uint8Array.from(Buffer.from(stdout.trim(), 'base64'));
98
+ const key = await ensureEncryptionKey(service);
99
+ return decrypt(encrypted, key);
100
+ }
101
+ async function deleteValueFromKeychain(service, account) {
102
+ const del = Bun.spawn(['security', 'delete-generic-password', '-s', service, '-a', account], {
103
+ stderr: 'ignore',
104
+ });
105
+ await del.exited;
106
+ }
107
+ /**
108
+ * Store auth data in macOS Keychain
109
+ */
110
+ export async function saveAuthToKeychain(profileName, authData) {
111
+ const service = `${SERVICE_PREFIX}.${profileName}`;
112
+ await saveEncryptedValueToKeychain(service, AUTH_ACCOUNT, JSON.stringify(authData));
113
+ }
99
114
  /**
100
115
  * Retrieve auth data from macOS Keychain
101
116
  */
102
117
  export async function getAuthFromKeychain(profileName) {
103
118
  const service = `${SERVICE_PREFIX}.${profileName}`;
104
- const account = 'auth-token';
105
119
  try {
106
- // Get the encrypted auth data
107
- const find = Bun.spawn(['security', 'find-generic-password', '-s', service, '-a', account, '-w'], { stderr: 'ignore' });
108
- const stdout = await new Response(find.stdout).text();
109
- if (stdout.length === 0) {
120
+ const json = await getEncryptedValueFromKeychain(service, AUTH_ACCOUNT);
121
+ if (!json) {
110
122
  return null;
111
123
  }
112
- const b64 = stdout.trim();
113
- const encrypted = Uint8Array.from(Buffer.from(b64, 'base64'));
114
- // Get the encryption key
115
- const key = await ensureEncryptionKey(service);
116
- // Decrypt the auth data
117
- const json = await decrypt(encrypted, key);
118
124
  return JSON.parse(json);
119
125
  }
120
126
  catch {
@@ -126,10 +132,23 @@ export async function getAuthFromKeychain(profileName) {
126
132
  */
127
133
  export async function deleteAuthFromKeychain(profileName) {
128
134
  const service = `${SERVICE_PREFIX}.${profileName}`;
129
- const account = 'auth-token';
130
- const del = Bun.spawn(['security', 'delete-generic-password', '-s', service, '-a', account], {
131
- stderr: 'ignore',
132
- });
133
- await del.exited;
135
+ await deleteValueFromKeychain(service, AUTH_ACCOUNT);
136
+ }
137
+ export async function saveCoderApiKeyToKeychain(profileName, apiKey) {
138
+ const service = `${SERVICE_PREFIX}.${profileName}`;
139
+ await saveEncryptedValueToKeychain(service, CODER_API_KEY_ACCOUNT, apiKey);
140
+ }
141
+ export async function getCoderApiKeyFromKeychain(profileName) {
142
+ const service = `${SERVICE_PREFIX}.${profileName}`;
143
+ try {
144
+ return await getEncryptedValueFromKeychain(service, CODER_API_KEY_ACCOUNT);
145
+ }
146
+ catch {
147
+ return null;
148
+ }
149
+ }
150
+ export async function deleteCoderApiKeyFromKeychain(profileName) {
151
+ const service = `${SERVICE_PREFIX}.${profileName}`;
152
+ await deleteValueFromKeychain(service, CODER_API_KEY_ACCOUNT);
134
153
  }
135
154
  //# sourceMappingURL=keychain.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"keychain.js","sourceRoot":"","sources":["../src/keychain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keychain.js","sourceRoot":"","sources":["../src/keychain.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -716,10 +716,10 @@ export declare const BuildMetadataSchema: z.ZodObject<{
716
716
  type: z.ZodEnum<{
717
717
  email: "email";
718
718
  stream: "stream";
719
+ websocket: "websocket";
719
720
  api: "api";
720
721
  sms: "sms";
721
722
  cron: "cron";
722
- websocket: "websocket";
723
723
  sse: "sse";
724
724
  }>;
725
725
  agentIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentuity/cli",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "license": "Apache-2.0",
5
5
  "author": "Agentuity employees and contributors",
6
6
  "type": "module",
@@ -41,10 +41,11 @@
41
41
  "prepublishOnly": "bun run clean && bun run build"
42
42
  },
43
43
  "dependencies": {
44
- "@agentuity/auth": "2.0.6",
45
- "@agentuity/core": "2.0.6",
46
- "@agentuity/frontend": "2.0.6",
47
- "@agentuity/server": "2.0.6",
44
+ "@agentuity/auth": "2.0.8",
45
+ "@agentuity/coder-tui": "2.0.8",
46
+ "@agentuity/core": "2.0.8",
47
+ "@agentuity/frontend": "2.0.8",
48
+ "@agentuity/server": "2.0.8",
48
49
  "@datasert/cronjs-parser": "^1.4.0",
49
50
  "@vitejs/plugin-react": "^5.1.2",
50
51
  "acorn-loose": "^8.5.2",
@@ -63,7 +64,7 @@
63
64
  "zod": "^4.3.5"
64
65
  },
65
66
  "devDependencies": {
66
- "@agentuity/test-utils": "2.0.6",
67
+ "@agentuity/test-utils": "2.0.8",
67
68
  "@types/adm-zip": "^0.5.7",
68
69
  "@types/archiver": "^7.0.0",
69
70
  "@types/bun": "latest",
package/src/cli.ts CHANGED
@@ -1195,8 +1195,10 @@ async function registerSubcommand(
1195
1195
  // Add -y short alias for --confirm
1196
1196
  flagSpec = `-y, --${flag}`;
1197
1197
  } else if (optAliases.length > 0) {
1198
- const shortFlags = optAliases.map((a) => `-${a}`).join(', ');
1199
- flagSpec = `${shortFlags}, --${flag}`;
1198
+ const aliasFlags = optAliases
1199
+ .map((a) => (a.length === 1 ? `-${a}` : `--${a}`))
1200
+ .join(', ');
1201
+ flagSpec = `${aliasFlags}, --${flag}`;
1200
1202
  }
1201
1203
  if (opt.type === 'boolean') {
1202
1204
  if (opt.hasDefault) {
@@ -151,11 +151,11 @@ The handler receives a context object with:
151
151
 
152
152
  ```typescript
153
153
  handler: async (ctx, input) => {
154
- await ctx.kv.set('user:123', { name: 'Alice', age: 30 });
155
- const user = await ctx.kv.get('user:123');
156
- await ctx.kv.delete('user:123');
157
- const keys = await ctx.kv.list('user:*');
158
- return user;
154
+ await ctx.kv.set('users', 'user:123', { name: 'Alice', age: 30 });
155
+ const result = await ctx.kv.get('users', 'user:123');
156
+ await ctx.kv.delete('users', 'user:123');
157
+ const keys = await ctx.kv.getKeys('users');
158
+ return result.exists ? result.data : null;
159
159
  };
160
160
  ```
161
161
 
@@ -188,7 +188,7 @@ handler: async (ctx, input) => {
188
188
  handler: async (ctx, input) => {
189
189
  // Schedule background work that continues after response
190
190
  ctx.waitUntil(async () => {
191
- await ctx.kv.set('processed', Date.now());
191
+ await ctx.kv.set('state', 'processed', Date.now());
192
192
  ctx.logger.info('Background task complete');
193
193
  });
194
194
 
@@ -180,6 +180,13 @@ export async function discoverRoutes(
180
180
  version
181
181
  );
182
182
 
183
+ // Extract type-specific config from route metadata
184
+ const meta =
185
+ typeof route.handler === 'function'
186
+ ? (route.handler as any)[Symbol.for('agentuity:route-meta')]
187
+ : undefined;
188
+ const config = meta?.schedule ? { expression: meta.schedule } : undefined;
189
+
183
190
  routes.push({
184
191
  id,
185
192
  filename: toForwardSlash(relative(rootDir, mount.routerFile)),
@@ -187,6 +194,7 @@ export async function discoverRoutes(
187
194
  method,
188
195
  version,
189
196
  type: routeType,
197
+ config,
190
198
  });
191
199
  }
192
200
 
@@ -8,6 +8,7 @@ import { sandboxRmFile, sandboxResolve } from '@agentuity/server';
8
8
  const RmFileResponseSchema = z.object({
9
9
  success: z.boolean(),
10
10
  path: z.string(),
11
+ found: z.boolean(),
11
12
  });
12
13
 
13
14
  export const rmSubcommand = createCommand({
@@ -40,17 +41,21 @@ export const rmSubcommand = createCommand({
40
41
 
41
42
  const client = createSandboxClient(logger, auth, region);
42
43
 
43
- await sandboxRmFile(client, {
44
+ const result = await sandboxRmFile(client, {
44
45
  sandboxId: args.sandboxId,
45
46
  path: args.path,
46
47
  orgId,
47
48
  });
48
49
 
49
50
  if (!options.json) {
50
- tui.success(`Removed file: ${args.path}`);
51
+ if (result.found) {
52
+ tui.success(`Removed file: ${args.path}`);
53
+ } else {
54
+ tui.warning(`File not found: ${args.path} (already removed)`);
55
+ }
51
56
  }
52
57
 
53
- return { success: true, path: args.path };
58
+ return { success: true, path: args.path, found: result.found };
54
59
  },
55
60
  });
56
61
 
@@ -8,6 +8,7 @@ import { sandboxRmDir, sandboxResolve } from '@agentuity/server';
8
8
  const RmDirResponseSchema = z.object({
9
9
  success: z.boolean(),
10
10
  path: z.string(),
11
+ found: z.boolean(),
11
12
  });
12
13
 
13
14
  export const rmdirSubcommand = createCommand({
@@ -52,7 +53,7 @@ export const rmdirSubcommand = createCommand({
52
53
 
53
54
  const client = createSandboxClient(logger, auth, region);
54
55
 
55
- await sandboxRmDir(client, {
56
+ const result = await sandboxRmDir(client, {
56
57
  sandboxId: args.sandboxId,
57
58
  path: args.path,
58
59
  recursive: opts.recursive,
@@ -60,10 +61,14 @@ export const rmdirSubcommand = createCommand({
60
61
  });
61
62
 
62
63
  if (!options.json) {
63
- tui.success(`Removed directory: ${args.path}`);
64
+ if (result.found) {
65
+ tui.success(`Removed directory: ${args.path}`);
66
+ } else {
67
+ tui.warning(`Directory not found: ${args.path} (already removed)`);
68
+ }
64
69
  }
65
70
 
66
- return { success: true, path: args.path };
71
+ return { success: true, path: args.path, found: result.found };
67
72
  },
68
73
  });
69
74
 
@@ -0,0 +1,319 @@
1
+ import { z } from 'zod';
2
+ import { createCommand } from '../../../types';
3
+ import * as tui from '../../../tui';
4
+ import { createStorageAdapter, resolveMeId, parseDuration, truncate } from './util';
5
+ import { getCommand } from '../../../command-prefix';
6
+ import { isDryRunMode, outputDryRun } from '../../../explain';
7
+ import type { TaskPriority, TaskStatus, TaskType, BatchClosedTask } from '@agentuity/core';
8
+
9
+ const TaskCloseResponseSchema = z.object({
10
+ success: z.boolean().describe('Whether the operation succeeded'),
11
+ closed: z
12
+ .array(
13
+ z.object({
14
+ id: z.string().describe('Closed task ID'),
15
+ title: z.string().describe('Closed task title'),
16
+ status: z.string().describe('Task status'),
17
+ closed_date: z.string().optional().describe('ISO 8601 closed date'),
18
+ })
19
+ )
20
+ .describe('List of closed tasks'),
21
+ count: z.number().describe('Number of tasks closed'),
22
+ durationMs: z.number().describe('Operation duration in milliseconds'),
23
+ dryRun: z.boolean().optional().describe('Whether this was a dry run'),
24
+ message: z.string().optional().describe('Status message'),
25
+ });
26
+
27
+ export const closeSubcommand = createCommand({
28
+ name: 'close',
29
+ aliases: ['done', 'complete'],
30
+ description: 'Close a task by ID or batch-close tasks by filter',
31
+ tags: ['mutating', 'slow', 'requires-auth'],
32
+ requires: { auth: true },
33
+ examples: [
34
+ {
35
+ command: getCommand('cloud task close task_abc123'),
36
+ description: 'Close a single task by ID',
37
+ },
38
+ {
39
+ command: getCommand('cloud task close --status in_progress --older-than 7d'),
40
+ description: 'Close in-progress tasks older than 7 days',
41
+ },
42
+ {
43
+ command: getCommand('cloud task close --status open --limit 10 --dry-run'),
44
+ description: 'Preview which open tasks would be closed (dry run)',
45
+ },
46
+ {
47
+ command: getCommand('cloud task close --created-id me --confirm'),
48
+ description: 'Close all tasks created by me without confirmation prompt',
49
+ },
50
+ ],
51
+ schema: {
52
+ args: z.object({
53
+ id: z.string().optional().describe('Task ID to close (for single close)'),
54
+ }),
55
+ options: z.object({
56
+ status: z
57
+ .enum(['open', 'in_progress', 'started', 'done', 'completed', 'closed', 'cancelled'])
58
+ .optional()
59
+ .describe('filter batch close by status'),
60
+ type: z
61
+ .enum(['epic', 'feature', 'enhancement', 'bug', 'task'])
62
+ .optional()
63
+ .describe('filter batch close by type'),
64
+ priority: z
65
+ .enum(['high', 'medium', 'low', 'none'])
66
+ .optional()
67
+ .describe('filter batch close by priority'),
68
+ olderThan: z
69
+ .string()
70
+ .optional()
71
+ .describe('filter batch close by age (e.g. 30s, 7d, 24h, 2w)'),
72
+ parentId: z.string().optional().describe('filter batch close by parent task ID'),
73
+ createdId: z
74
+ .string()
75
+ .optional()
76
+ .describe('filter batch close by creator ID (use "me" for current user)'),
77
+ assignedId: z.string().optional().describe('filter batch close by assigned user ID'),
78
+ projectId: z.string().optional().describe('filter batch close by project ID'),
79
+ tagId: z.string().optional().describe('filter batch close by tag ID'),
80
+ idsFile: z.string().optional().describe('path to JSON file containing task IDs to close'),
81
+ orgId: z.string().optional().describe('organization ID (uses default if not specified)'),
82
+ dryRun: z
83
+ .boolean()
84
+ .optional()
85
+ .default(false)
86
+ .describe('preview changes without executing'),
87
+ limit: z.coerce
88
+ .number()
89
+ .int()
90
+ .min(1)
91
+ .max(200)
92
+ .default(50)
93
+ .describe('max tasks to close in batch mode (default: 50, max: 200)'),
94
+ confirm: z.boolean().optional().default(false).describe('skip confirmation prompt'),
95
+ }),
96
+ response: TaskCloseResponseSchema,
97
+ },
98
+
99
+ async handler(ctx) {
100
+ const { args, opts, options } = ctx;
101
+ const started = Date.now();
102
+ const storage = await createStorageAdapter(ctx);
103
+
104
+ const isSingleClose = !!args.id;
105
+ const hasFilters =
106
+ opts.status ||
107
+ opts.type ||
108
+ opts.priority ||
109
+ opts.olderThan ||
110
+ opts.parentId ||
111
+ opts.createdId ||
112
+ opts.assignedId ||
113
+ opts.projectId ||
114
+ opts.tagId ||
115
+ opts.idsFile;
116
+
117
+ if (!isSingleClose && !hasFilters) {
118
+ tui.fatal(
119
+ 'Provide a task ID for single close, or use --status, --type, --priority, --older-than, --parent-id, --created-id, --assigned-id, --project-id, --tag-id, or --ids-file for batch close.'
120
+ );
121
+ }
122
+
123
+ if (isSingleClose && hasFilters) {
124
+ tui.fatal(
125
+ 'Cannot combine task ID with filter options. Use either single close (by ID) or batch close (by filters).'
126
+ );
127
+ }
128
+
129
+ if (isSingleClose) {
130
+ if (isDryRunMode(options)) {
131
+ outputDryRun(`Would close task: ${args.id}`, options);
132
+ return {
133
+ success: true,
134
+ closed: [{ id: args.id!, title: '(dry run)', status: 'done' }],
135
+ count: 1,
136
+ durationMs: Date.now() - started,
137
+ dryRun: true,
138
+ message: 'Dry run — no tasks were closed',
139
+ };
140
+ }
141
+
142
+ if (!opts.confirm) {
143
+ const confirmed = await tui.confirm(`Close task "${args.id}"?`, false);
144
+ if (!confirmed) {
145
+ if (!options.json) tui.info('Cancelled');
146
+ return {
147
+ success: false,
148
+ closed: [],
149
+ count: 0,
150
+ durationMs: Date.now() - started,
151
+ message: 'Cancelled',
152
+ };
153
+ }
154
+ }
155
+
156
+ const task = await storage.close(args.id!);
157
+ const durationMs = Date.now() - started;
158
+
159
+ if (!options.json) {
160
+ tui.success(`Closed task ${tui.bold(task.id)} (${task.title}) in ${durationMs}ms`);
161
+ }
162
+
163
+ return {
164
+ success: true,
165
+ closed: [
166
+ {
167
+ id: task.id,
168
+ title: task.title,
169
+ status: task.status,
170
+ closed_date: task.closed_date,
171
+ },
172
+ ],
173
+ count: 1,
174
+ durationMs,
175
+ };
176
+ }
177
+
178
+ // Batch close mode
179
+ if (opts.olderThan) {
180
+ parseDuration(opts.olderThan);
181
+ }
182
+
183
+ const createdId = resolveMeId(opts.createdId, ctx);
184
+ const assignedId = resolveMeId(opts.assignedId, ctx);
185
+
186
+ // Handle IDs file
187
+ let explicitIds: string[] | undefined;
188
+ if (opts.idsFile) {
189
+ const file = Bun.file(opts.idsFile);
190
+ if (!(await file.exists())) {
191
+ tui.fatal(`IDs file not found: ${opts.idsFile}`);
192
+ }
193
+ try {
194
+ const content = await file.json();
195
+ if (Array.isArray(content)) {
196
+ explicitIds = content.map((id) => String(id));
197
+ } else if (content && Array.isArray((content as { ids?: string[] }).ids)) {
198
+ explicitIds = (content as { ids: string[] }).ids;
199
+ } else {
200
+ tui.fatal(`Invalid IDs file format. Expected array of IDs or { ids: [...] }`);
201
+ }
202
+ } catch (err) {
203
+ tui.fatal(`Failed to parse IDs file: ${err}`);
204
+ }
205
+ }
206
+
207
+ const batchParams = {
208
+ status: opts.status as TaskStatus | undefined,
209
+ type: opts.type as TaskType | undefined,
210
+ priority: opts.priority as TaskPriority | undefined,
211
+ parent_id: opts.parentId,
212
+ created_id: createdId,
213
+ assigned_id: assignedId,
214
+ project_id: opts.projectId,
215
+ tag_id: opts.tagId,
216
+ older_than: opts.olderThan,
217
+ ids: explicitIds,
218
+ limit: opts.limit,
219
+ closed_id: ctx.auth.userId,
220
+ dry_run: isDryRunMode(options),
221
+ };
222
+
223
+ // For confirmation, run a dry-run first to preview
224
+ if (!isDryRunMode(options) && !opts.confirm) {
225
+ const preview = await storage.batchClose({ ...batchParams, dry_run: true });
226
+
227
+ if (preview.count === 0) {
228
+ if (!options.json) tui.info('No tasks match the given filters');
229
+ return {
230
+ success: true,
231
+ closed: [],
232
+ count: 0,
233
+ durationMs: Date.now() - started,
234
+ message: 'No matching tasks found',
235
+ };
236
+ }
237
+
238
+ if (!options.json) {
239
+ tui.warning(
240
+ `Found ${preview.count} ${tui.plural(preview.count, 'task', 'tasks')} to close:`
241
+ );
242
+ tui.newline();
243
+
244
+ const tableData = preview.closed.map((task: BatchClosedTask) => ({
245
+ ID: tui.muted(truncate(task.id, 28)),
246
+ Title: truncate(task.title, 40),
247
+ Status: task.status,
248
+ }));
249
+
250
+ tui.table(tableData, [
251
+ { name: 'ID', alignment: 'left' },
252
+ { name: 'Title', alignment: 'left' },
253
+ { name: 'Status', alignment: 'left' },
254
+ ]);
255
+ tui.newline();
256
+ }
257
+
258
+ const confirmed = await tui.confirm(
259
+ `Close ${preview.count} ${tui.plural(preview.count, 'task', 'tasks')}?`,
260
+ false
261
+ );
262
+ if (!confirmed) {
263
+ if (!options.json) tui.info('Cancelled');
264
+ return {
265
+ success: false,
266
+ closed: [],
267
+ count: 0,
268
+ durationMs: Date.now() - started,
269
+ message: 'Cancelled',
270
+ };
271
+ }
272
+ }
273
+
274
+ // Execute batch close
275
+ const result = await storage.batchClose(batchParams);
276
+ const durationMs = Date.now() - started;
277
+
278
+ if (!options.json) {
279
+ if (result.dry_run) {
280
+ if (result.count > 0) {
281
+ tui.info(
282
+ `Dry run: would close ${result.count} ${tui.plural(result.count, 'task', 'tasks')}`
283
+ );
284
+ } else {
285
+ tui.info('No tasks match the given filters');
286
+ }
287
+ } else if (result.count > 0) {
288
+ tui.success(
289
+ `Closed ${result.count} ${tui.plural(result.count, 'task', 'tasks')} in ${durationMs}ms`
290
+ );
291
+
292
+ // Show which tasks were closed
293
+ if (result.closed.length > 0) {
294
+ tui.newline();
295
+ const closedTable = result.closed.map((task) => ({
296
+ ID: tui.muted(truncate(task.id, 28)),
297
+ Title: truncate(task.title, 40),
298
+ }));
299
+ tui.table(closedTable, [
300
+ { name: 'ID', alignment: 'left' },
301
+ { name: 'Title', alignment: 'left' },
302
+ ]);
303
+ }
304
+ } else {
305
+ tui.info('No tasks matched the given filters');
306
+ }
307
+ }
308
+
309
+ return {
310
+ success: true,
311
+ closed: result.closed,
312
+ count: result.count,
313
+ durationMs,
314
+ dryRun: result.dry_run,
315
+ };
316
+ },
317
+ });
318
+
319
+ export default closeSubcommand;