@agentuity/cli 2.0.7 → 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 (176) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +4 -2
  3. package/dist/cli.js.map +1 -1
  4. package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
  5. package/dist/cmd/build/vite/route-discovery.js +6 -0
  6. package/dist/cmd/build/vite/route-discovery.js.map +1 -1
  7. package/dist/cmd/cloud/sandbox/fs/rm.d.ts.map +1 -1
  8. package/dist/cmd/cloud/sandbox/fs/rm.js +9 -3
  9. package/dist/cmd/cloud/sandbox/fs/rm.js.map +1 -1
  10. package/dist/cmd/cloud/sandbox/fs/rmdir.d.ts.map +1 -1
  11. package/dist/cmd/cloud/sandbox/fs/rmdir.js +9 -3
  12. package/dist/cmd/cloud/sandbox/fs/rmdir.js.map +1 -1
  13. package/dist/cmd/coder/archive.d.ts +2 -0
  14. package/dist/cmd/coder/archive.d.ts.map +1 -0
  15. package/dist/cmd/coder/archive.js +57 -0
  16. package/dist/cmd/coder/archive.js.map +1 -0
  17. package/dist/cmd/coder/create.d.ts +2 -0
  18. package/dist/cmd/coder/create.d.ts.map +1 -0
  19. package/dist/cmd/coder/create.js +245 -0
  20. package/dist/cmd/coder/create.js.map +1 -0
  21. package/dist/cmd/coder/delete.d.ts +2 -0
  22. package/dist/cmd/coder/delete.d.ts.map +1 -0
  23. package/dist/cmd/coder/delete.js +64 -0
  24. package/dist/cmd/coder/delete.js.map +1 -0
  25. package/dist/cmd/coder/events.d.ts +2 -0
  26. package/dist/cmd/coder/events.d.ts.map +1 -0
  27. package/dist/cmd/coder/events.js +99 -0
  28. package/dist/cmd/coder/events.js.map +1 -0
  29. package/dist/cmd/coder/extension-path.d.ts +8 -0
  30. package/dist/cmd/coder/extension-path.d.ts.map +1 -0
  31. package/dist/cmd/coder/extension-path.js +59 -0
  32. package/dist/cmd/coder/extension-path.js.map +1 -0
  33. package/dist/cmd/coder/get.d.ts +2 -0
  34. package/dist/cmd/coder/get.d.ts.map +1 -0
  35. package/dist/cmd/coder/{inspect.js → get.js} +38 -42
  36. package/dist/cmd/coder/get.js.map +1 -0
  37. package/dist/cmd/coder/index.d.ts.map +1 -1
  38. package/dist/cmd/coder/index.js +52 -7
  39. package/dist/cmd/coder/index.js.map +1 -1
  40. package/dist/cmd/coder/list.d.ts.map +1 -1
  41. package/dist/cmd/coder/list.js +26 -42
  42. package/dist/cmd/coder/list.js.map +1 -1
  43. package/dist/cmd/coder/loop.d.ts +2 -0
  44. package/dist/cmd/coder/loop.d.ts.map +1 -0
  45. package/dist/cmd/coder/loop.js +78 -0
  46. package/dist/cmd/coder/loop.js.map +1 -0
  47. package/dist/cmd/coder/participants.d.ts +2 -0
  48. package/dist/cmd/coder/participants.d.ts.map +1 -0
  49. package/dist/cmd/coder/participants.js +93 -0
  50. package/dist/cmd/coder/participants.js.map +1 -0
  51. package/dist/cmd/coder/replay.d.ts +2 -0
  52. package/dist/cmd/coder/replay.d.ts.map +1 -0
  53. package/dist/cmd/coder/replay.js +53 -0
  54. package/dist/cmd/coder/replay.js.map +1 -0
  55. package/dist/cmd/coder/resolve-repo.d.ts +27 -0
  56. package/dist/cmd/coder/resolve-repo.d.ts.map +1 -0
  57. package/dist/cmd/coder/resolve-repo.js +97 -0
  58. package/dist/cmd/coder/resolve-repo.js.map +1 -0
  59. package/dist/cmd/coder/skill/buckets.d.ts +2 -0
  60. package/dist/cmd/coder/skill/buckets.d.ts.map +1 -0
  61. package/dist/cmd/coder/skill/buckets.js +174 -0
  62. package/dist/cmd/coder/skill/buckets.js.map +1 -0
  63. package/dist/cmd/coder/skill/delete.d.ts +2 -0
  64. package/dist/cmd/coder/skill/delete.d.ts.map +1 -0
  65. package/dist/cmd/coder/skill/delete.js +64 -0
  66. package/dist/cmd/coder/skill/delete.js.map +1 -0
  67. package/dist/cmd/coder/skill/index.d.ts +2 -0
  68. package/dist/cmd/coder/skill/index.d.ts.map +1 -0
  69. package/dist/cmd/coder/skill/index.js +33 -0
  70. package/dist/cmd/coder/skill/index.js.map +1 -0
  71. package/dist/cmd/coder/skill/list.d.ts +2 -0
  72. package/dist/cmd/coder/skill/list.d.ts.map +1 -0
  73. package/dist/cmd/coder/skill/list.js +93 -0
  74. package/dist/cmd/coder/skill/list.js.map +1 -0
  75. package/dist/cmd/coder/skill/save.d.ts +2 -0
  76. package/dist/cmd/coder/skill/save.d.ts.map +1 -0
  77. package/dist/cmd/coder/skill/save.js +77 -0
  78. package/dist/cmd/coder/skill/save.js.map +1 -0
  79. package/dist/cmd/coder/start.d.ts.map +1 -1
  80. package/dist/cmd/coder/start.js +87 -131
  81. package/dist/cmd/coder/start.js.map +1 -1
  82. package/dist/cmd/coder/tui-init.d.ts.map +1 -1
  83. package/dist/cmd/coder/tui-init.js +7 -2
  84. package/dist/cmd/coder/tui-init.js.map +1 -1
  85. package/dist/cmd/coder/update.d.ts +2 -0
  86. package/dist/cmd/coder/update.d.ts.map +1 -0
  87. package/dist/cmd/coder/update.js +126 -0
  88. package/dist/cmd/coder/update.js.map +1 -0
  89. package/dist/cmd/coder/users.d.ts +2 -0
  90. package/dist/cmd/coder/users.d.ts.map +1 -0
  91. package/dist/cmd/coder/users.js +97 -0
  92. package/dist/cmd/coder/users.js.map +1 -0
  93. package/dist/cmd/coder/workspace/create.d.ts +2 -0
  94. package/dist/cmd/coder/workspace/create.d.ts.map +1 -0
  95. package/dist/cmd/coder/workspace/create.js +97 -0
  96. package/dist/cmd/coder/workspace/create.js.map +1 -0
  97. package/dist/cmd/coder/workspace/delete.d.ts +2 -0
  98. package/dist/cmd/coder/workspace/delete.d.ts.map +1 -0
  99. package/dist/cmd/coder/workspace/delete.js +64 -0
  100. package/dist/cmd/coder/workspace/delete.js.map +1 -0
  101. package/dist/cmd/coder/workspace/get.d.ts +2 -0
  102. package/dist/cmd/coder/workspace/get.d.ts.map +1 -0
  103. package/dist/cmd/coder/workspace/get.js +109 -0
  104. package/dist/cmd/coder/workspace/get.js.map +1 -0
  105. package/dist/cmd/coder/workspace/index.d.ts +2 -0
  106. package/dist/cmd/coder/workspace/index.d.ts.map +1 -0
  107. package/dist/cmd/coder/workspace/index.js +38 -0
  108. package/dist/cmd/coder/workspace/index.js.map +1 -0
  109. package/dist/cmd/coder/workspace/list.d.ts +2 -0
  110. package/dist/cmd/coder/workspace/list.d.ts.map +1 -0
  111. package/dist/cmd/coder/workspace/list.js +93 -0
  112. package/dist/cmd/coder/workspace/list.js.map +1 -0
  113. package/dist/config.d.ts.map +1 -1
  114. package/dist/config.js +3 -3
  115. package/dist/config.js.map +1 -1
  116. package/dist/types.d.ts +1 -5
  117. package/dist/types.d.ts.map +1 -1
  118. package/dist/types.js +0 -10
  119. package/dist/types.js.map +1 -1
  120. package/package.json +7 -6
  121. package/src/cli.ts +4 -2
  122. package/src/cmd/ai/prompt/agent.md +6 -6
  123. package/src/cmd/build/vite/route-discovery.ts +8 -0
  124. package/src/cmd/cloud/sandbox/fs/rm.ts +8 -3
  125. package/src/cmd/cloud/sandbox/fs/rmdir.ts +8 -3
  126. package/src/cmd/coder/archive.ts +59 -0
  127. package/src/cmd/coder/create.ts +268 -0
  128. package/src/cmd/coder/delete.ts +67 -0
  129. package/src/cmd/coder/events.ts +106 -0
  130. package/src/cmd/coder/extension-path.ts +71 -0
  131. package/src/cmd/coder/{inspect.ts → get.ts} +45 -69
  132. package/src/cmd/coder/index.ts +52 -7
  133. package/src/cmd/coder/list.ts +29 -89
  134. package/src/cmd/coder/loop.ts +85 -0
  135. package/src/cmd/coder/participants.ts +100 -0
  136. package/src/cmd/coder/replay.ts +58 -0
  137. package/src/cmd/coder/resolve-repo.ts +119 -0
  138. package/src/cmd/coder/skill/buckets.ts +191 -0
  139. package/src/cmd/coder/skill/delete.ts +67 -0
  140. package/src/cmd/coder/skill/index.ts +35 -0
  141. package/src/cmd/coder/skill/list.ts +97 -0
  142. package/src/cmd/coder/skill/save.ts +84 -0
  143. package/src/cmd/coder/start.ts +101 -174
  144. package/src/cmd/coder/tui-init.ts +7 -3
  145. package/src/cmd/coder/update.ts +128 -0
  146. package/src/cmd/coder/users.ts +101 -0
  147. package/src/cmd/coder/workspace/create.ts +104 -0
  148. package/src/cmd/coder/workspace/delete.ts +70 -0
  149. package/src/cmd/coder/workspace/get.ts +112 -0
  150. package/src/cmd/coder/workspace/index.ts +38 -0
  151. package/src/cmd/coder/workspace/list.ts +101 -0
  152. package/src/config.ts +4 -3
  153. package/src/types.ts +0 -10
  154. package/dist/cmd/coder/config/index.d.ts +0 -2
  155. package/dist/cmd/coder/config/index.d.ts.map +0 -1
  156. package/dist/cmd/coder/config/index.js +0 -20
  157. package/dist/cmd/coder/config/index.js.map +0 -1
  158. package/dist/cmd/coder/config/set.d.ts +0 -2
  159. package/dist/cmd/coder/config/set.d.ts.map +0 -1
  160. package/dist/cmd/coder/config/set.js +0 -100
  161. package/dist/cmd/coder/config/set.js.map +0 -1
  162. package/dist/cmd/coder/hub-url.d.ts +0 -47
  163. package/dist/cmd/coder/hub-url.d.ts.map +0 -1
  164. package/dist/cmd/coder/hub-url.js +0 -148
  165. package/dist/cmd/coder/hub-url.js.map +0 -1
  166. package/dist/cmd/coder/inspect.d.ts +0 -2
  167. package/dist/cmd/coder/inspect.d.ts.map +0 -1
  168. package/dist/cmd/coder/inspect.js.map +0 -1
  169. package/dist/coder-config.d.ts +0 -14
  170. package/dist/coder-config.d.ts.map +0 -1
  171. package/dist/coder-config.js +0 -119
  172. package/dist/coder-config.js.map +0 -1
  173. package/src/cmd/coder/config/index.ts +0 -20
  174. package/src/cmd/coder/config/set.ts +0 -112
  175. package/src/cmd/coder/hub-url.ts +0 -205
  176. package/src/coder-config.ts +0 -141
@@ -0,0 +1,59 @@
1
+ import { z } from 'zod';
2
+ import { CoderClient } from '@agentuity/core/coder';
3
+ import { ValidationOutputError } from '@agentuity/core';
4
+ import { createSubcommand } from '../../types';
5
+ import * as tui from '../../tui';
6
+ import { getCommand } from '../../command-prefix';
7
+ import { ErrorCode } from '../../errors';
8
+
9
+ export const archiveSubcommand = createSubcommand({
10
+ name: 'archive',
11
+ description: 'Archive a Coder Hub session',
12
+ tags: ['mutating', 'requires-auth'],
13
+ requires: { auth: true, org: true },
14
+ examples: [
15
+ {
16
+ command: getCommand('coder archive codesess_abc123'),
17
+ description: 'Archive a session',
18
+ },
19
+ {
20
+ command: getCommand('coder archive codesess_abc123 --json'),
21
+ description: 'Archive a session and return JSON output',
22
+ },
23
+ ],
24
+ schema: {
25
+ args: z.object({
26
+ sessionId: z.string().describe('Session ID to archive'),
27
+ }),
28
+ options: z.object({
29
+ url: z.string().optional().describe('Coder API URL override'),
30
+ }),
31
+ },
32
+ async handler(ctx) {
33
+ const { args, opts, options } = ctx;
34
+ const client = new CoderClient({
35
+ apiKey: ctx.auth.apiKey,
36
+ url: opts?.url,
37
+ orgId: ctx.orgId,
38
+ });
39
+
40
+ try {
41
+ const session = await client.archiveSession(args.sessionId);
42
+ const result = session ?? { archived: true, sessionId: args.sessionId };
43
+
44
+ if (options.json) {
45
+ return result;
46
+ }
47
+
48
+ tui.success(`Session ${args.sessionId} archived.`);
49
+ return result;
50
+ } catch (err) {
51
+ if (err instanceof ValidationOutputError) {
52
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
53
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
54
+ }
55
+ const msg = err instanceof Error ? err.message : String(err);
56
+ tui.fatal(`Failed to archive session ${args.sessionId}: ${msg}`, ErrorCode.NETWORK_ERROR);
57
+ }
58
+ },
59
+ });
@@ -0,0 +1,268 @@
1
+ import { z } from 'zod';
2
+ import {
3
+ CoderClient,
4
+ type CoderCreateSessionRequest,
5
+ normalizeVisibility,
6
+ } from '@agentuity/core/coder';
7
+ import { ValidationOutputError } from '@agentuity/core';
8
+ import { toCoderHubWsUrl } from '../../coder-hub-url';
9
+ import { createSubcommand } from '../../types';
10
+ import * as tui from '../../tui';
11
+ import { getCommand } from '../../command-prefix';
12
+ import { ErrorCode } from '../../errors';
13
+ import { resolveExtensionPath, resolveExtensionRuntimeModulePath } from './extension-path';
14
+ import { resolveGitHubRepo } from './resolve-repo';
15
+
16
+ export const createCoderSubcommand = createSubcommand({
17
+ name: 'create',
18
+ aliases: ['new'],
19
+ description: 'Create a new Coder session',
20
+ tags: ['mutating', 'requires-auth'],
21
+ requires: { auth: true, org: true },
22
+ examples: [
23
+ {
24
+ command: getCommand('coder create "Build a REST API"'),
25
+ description: 'Create a simple session',
26
+ },
27
+ {
28
+ command: getCommand('coder create "Fix the login bug" --repo https://github.com/org/repo'),
29
+ description: 'Create with a repo',
30
+ },
31
+ {
32
+ command: getCommand('coder create "Refactor auth" --connect'),
33
+ description: 'Create and attach TUI',
34
+ },
35
+ {
36
+ command: getCommand(
37
+ 'coder create "Build feature" --workflow-mode loop --loop-goal "Complete implementation" --loop-max-iterations 20'
38
+ ),
39
+ description: 'Create a loop session',
40
+ },
41
+ {
42
+ command: getCommand(
43
+ 'coder create "Quick task" --label "My Task" --tags frontend,urgent --json'
44
+ ),
45
+ description: 'Create with label and tags, return JSON',
46
+ },
47
+ ],
48
+ schema: {
49
+ args: z.object({
50
+ task: z.string().describe('Task prompt for the session'),
51
+ }),
52
+ options: z.object({
53
+ // Connection
54
+ url: z.string().optional().describe('Coder API URL override'),
55
+ connect: z.boolean().optional().describe('Connect to the session after creation'),
56
+ extension: z
57
+ .string()
58
+ .optional()
59
+ .describe('Coder extension path override (used with --connect)'),
60
+
61
+ // Session config
62
+ label: z.string().optional().describe('Human-readable session label'),
63
+ agent: z.string().optional().describe('Default agent role (e.g. lead, scout)'),
64
+ visibility: z
65
+ .string()
66
+ .optional()
67
+ .describe('Session visibility: private, org, or collaborate'),
68
+
69
+ // Workflow
70
+ workflowMode: z.string().optional().describe('Workflow mode: standard or loop'),
71
+ loopGoal: z.string().optional().describe('Goal for loop mode execution'),
72
+ loopMaxIterations: z.number().optional().describe('Maximum loop iterations'),
73
+ loopAutoContinue: z
74
+ .boolean()
75
+ .optional()
76
+ .describe('Auto-continue loop without manual approval'),
77
+ loopAllowDetached: z
78
+ .boolean()
79
+ .optional()
80
+ .describe('Allow loop to continue when no client attached'),
81
+
82
+ // Repository
83
+ repo: z.string().optional().describe('Git repository URL to clone'),
84
+ repoBranch: z.string().optional().describe('Branch to checkout for the repository'),
85
+
86
+ // Resources
87
+ workspaceId: z.string().optional().describe('Workspace ID to use'),
88
+ tags: z.string().optional().describe('Comma-separated tags'),
89
+ env: z
90
+ .string()
91
+ .optional()
92
+ .describe('Environment variables as KEY=VALUE pairs, comma-separated'),
93
+
94
+ // Skills (by ID for now)
95
+ savedSkillIds: z.string().optional().describe('Comma-separated saved skill IDs'),
96
+ skillBucketIds: z.string().optional().describe('Comma-separated skill bucket IDs'),
97
+ }),
98
+ },
99
+ async handler(ctx) {
100
+ const { args, opts, options } = ctx;
101
+ const client = new CoderClient({
102
+ apiKey: ctx.auth.apiKey,
103
+ url: opts?.url,
104
+ orgId: ctx.orgId,
105
+ });
106
+
107
+ // Build the create session request body from flags
108
+ const body: CoderCreateSessionRequest = {
109
+ task: args.task,
110
+ ...(opts?.label && { label: opts.label }),
111
+ ...(opts?.agent && { agent: opts.agent }),
112
+ ...(opts?.visibility && { visibility: normalizeVisibility(opts.visibility) }),
113
+ ...(opts?.workflowMode && { workflowMode: opts.workflowMode as 'standard' | 'loop' }),
114
+ };
115
+
116
+ // Build loop config if any loop option is set
117
+ if (
118
+ opts?.loopGoal ||
119
+ opts?.loopMaxIterations ||
120
+ opts?.loopAutoContinue !== undefined ||
121
+ opts?.loopAllowDetached !== undefined
122
+ ) {
123
+ body.loop = {};
124
+ if (opts?.loopGoal) body.loop.goal = opts.loopGoal;
125
+ if (opts?.loopMaxIterations) body.loop.maxIterations = opts.loopMaxIterations;
126
+ if (opts?.loopAutoContinue !== undefined) body.loop.autoContinue = opts.loopAutoContinue;
127
+ if (opts?.loopAllowDetached !== undefined)
128
+ body.loop.allowDetached = opts.loopAllowDetached;
129
+ // Auto-set workflowMode to loop if loop options provided
130
+ if (!body.workflowMode) body.workflowMode = 'loop';
131
+ }
132
+
133
+ // Parse repo
134
+ if (opts?.repo) {
135
+ if (!options.json) tui.output('Resolving repository...');
136
+ try {
137
+ const resolved = await resolveGitHubRepo(client, opts.repo, opts?.repoBranch);
138
+ body.repo = resolved;
139
+ } catch (err) {
140
+ const msg = err instanceof Error ? err.message : String(err);
141
+ tui.fatal(`Failed to resolve repository: ${msg}`, ErrorCode.VALIDATION_FAILED);
142
+ return;
143
+ }
144
+ }
145
+
146
+ // Parse comma-separated values
147
+ if (opts?.tags)
148
+ body.tags = opts.tags
149
+ .split(',')
150
+ .map((t) => t.trim())
151
+ .filter(Boolean);
152
+ if (opts?.savedSkillIds)
153
+ body.savedSkillIds = opts.savedSkillIds
154
+ .split(',')
155
+ .map((s) => s.trim())
156
+ .filter(Boolean);
157
+ if (opts?.skillBucketIds)
158
+ body.skillBucketIds = opts.skillBucketIds
159
+ .split(',')
160
+ .map((s) => s.trim())
161
+ .filter(Boolean);
162
+
163
+ // Parse env vars: KEY=VALUE,KEY2=VALUE2
164
+ if (opts?.env) {
165
+ body.env = {};
166
+ for (const pair of opts.env.split(',')) {
167
+ const eq = pair.indexOf('=');
168
+ if (eq > 0) {
169
+ body.env[pair.slice(0, eq).trim()] = pair.slice(eq + 1).trim();
170
+ }
171
+ }
172
+ }
173
+
174
+ if (opts?.workspaceId) body.workspaceId = opts.workspaceId;
175
+
176
+ // Create the session
177
+ try {
178
+ const created = await client.createSession(body);
179
+
180
+ // JSON mode: return result and stop
181
+ if (options.json) {
182
+ return created;
183
+ }
184
+
185
+ tui.success(`Session ${created.sessionId} created (status: ${created.status})`);
186
+
187
+ // If --connect, wait for provisioning then attach TUI
188
+ if (opts?.connect) {
189
+ tui.output('Waiting for session to provision...');
190
+
191
+ // Poll until session is active
192
+ let status = created.status;
193
+ const startTime = Date.now();
194
+ const POLL_TIMEOUT = 120_000;
195
+ const POLL_INTERVAL = 3_000;
196
+
197
+ while (Date.now() - startTime < POLL_TIMEOUT) {
198
+ if (status !== 'creating' && status !== 'provisioning') break;
199
+ await new Promise((r) => setTimeout(r, POLL_INTERVAL));
200
+ try {
201
+ const detail = await client.getSession(created.sessionId);
202
+ status = detail.status;
203
+ } catch {
204
+ // Network blip — keep polling
205
+ }
206
+ }
207
+
208
+ if (status !== 'active') {
209
+ tui.fatal(
210
+ `Session did not become active (status: ${status})`,
211
+ ErrorCode.NETWORK_ERROR
212
+ );
213
+ return;
214
+ }
215
+
216
+ // Resolve extension and WS URL, then launch TUI
217
+ const hubHttpUrl = await client.getUrl();
218
+ const hubWsUrl = toCoderHubWsUrl(hubHttpUrl);
219
+
220
+ const extensionPath = await resolveExtensionPath(opts?.extension);
221
+ if (!extensionPath) {
222
+ tui.fatal(
223
+ 'Could not find the Agentuity Coder extension.\n\nTry:\n - Reinstall or update @agentuity/cli\n - Install it locally: npm install @agentuity/coder-tui\n - Set AGENTUITY_CODER_EXTENSION environment variable\n - Pass --extension flag',
224
+ ErrorCode.CONFIG_INVALID
225
+ );
226
+ return;
227
+ }
228
+
229
+ const remoteTuiPath = await resolveExtensionRuntimeModulePath(extensionPath);
230
+ if (!remoteTuiPath) {
231
+ tui.fatal(
232
+ `Coder extension at ${extensionPath} is missing the remote TUI entrypoint`,
233
+ ErrorCode.CONFIG_INVALID
234
+ );
235
+ return;
236
+ }
237
+
238
+ if (!options.json) {
239
+ tui.newline();
240
+ tui.output(` Hub: ${tui.bold(hubWsUrl)}`);
241
+ tui.output(` Extension: ${tui.bold(extensionPath)}`);
242
+ tui.output(` Session: ${tui.bold(created.sessionId)}`);
243
+ tui.newline();
244
+ }
245
+
246
+ try {
247
+ const { runRemoteTui } = await import(remoteTuiPath);
248
+ await runRemoteTui({
249
+ hubWsUrl,
250
+ sessionId: created.sessionId,
251
+ apiKey: ctx.auth.apiKey,
252
+ orgId: ctx.orgId,
253
+ });
254
+ } catch (err) {
255
+ const msg = err instanceof Error ? err.message : String(err);
256
+ tui.fatal(`Remote TUI failed: ${msg}`, ErrorCode.NETWORK_ERROR);
257
+ }
258
+ }
259
+ } catch (err) {
260
+ if (err instanceof ValidationOutputError) {
261
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
262
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
263
+ }
264
+ const msg = err instanceof Error ? err.message : String(err);
265
+ tui.fatal(`Failed to create Coder session: ${msg}`, ErrorCode.NETWORK_ERROR);
266
+ }
267
+ },
268
+ });
@@ -0,0 +1,67 @@
1
+ import { z } from 'zod';
2
+ import { CoderClient } from '@agentuity/core/coder';
3
+ import { ValidationOutputError } from '@agentuity/core';
4
+ import { createSubcommand } from '../../types';
5
+ import * as tui from '../../tui';
6
+ import { getCommand } from '../../command-prefix';
7
+ import { ErrorCode } from '../../errors';
8
+
9
+ export const deleteSubcommand = createSubcommand({
10
+ name: 'delete',
11
+ aliases: ['rm', 'del', 'remove'],
12
+ description: 'Delete a Coder Hub session',
13
+ tags: ['destructive', 'deletes-resource', 'requires-auth'],
14
+ requires: { auth: true, org: true },
15
+ examples: [
16
+ {
17
+ command: getCommand('coder delete codesess_abc123'),
18
+ description: 'Delete a session',
19
+ },
20
+ {
21
+ command: getCommand('coder delete codesess_abc123 --json'),
22
+ description: 'Delete a session and return JSON output',
23
+ },
24
+ ],
25
+ schema: {
26
+ args: z.object({
27
+ sessionId: z.string().describe('Session ID to delete'),
28
+ }),
29
+ options: z.object({
30
+ url: z.string().optional().describe('Coder API URL override'),
31
+ }),
32
+ },
33
+ async handler(ctx) {
34
+ const { args, opts, options } = ctx;
35
+ const client = new CoderClient({
36
+ apiKey: ctx.auth.apiKey,
37
+ url: opts?.url,
38
+ orgId: ctx.orgId,
39
+ });
40
+
41
+ if (!options.json) {
42
+ const confirmed = await tui.confirm(`Delete session ${args.sessionId}?`, false);
43
+ if (!confirmed) {
44
+ tui.info('Cancelled.');
45
+ return { deleted: false, sessionId: args.sessionId };
46
+ }
47
+ }
48
+
49
+ try {
50
+ await client.deleteSession(args.sessionId);
51
+ } catch (err) {
52
+ if (err instanceof ValidationOutputError) {
53
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
54
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
55
+ }
56
+ const msg = err instanceof Error ? err.message : String(err);
57
+ tui.fatal(`Failed to delete session ${args.sessionId}: ${msg}`, ErrorCode.NETWORK_ERROR);
58
+ }
59
+
60
+ if (options.json) {
61
+ return { deleted: true, sessionId: args.sessionId };
62
+ }
63
+
64
+ tui.success(`Session ${args.sessionId} deleted.`);
65
+ return { deleted: true, sessionId: args.sessionId };
66
+ },
67
+ });
@@ -0,0 +1,106 @@
1
+ import { z } from 'zod';
2
+ import { CoderClient } from '@agentuity/core/coder';
3
+ import { ValidationOutputError } from '@agentuity/core';
4
+ import { createSubcommand } from '../../types';
5
+ import * as tui from '../../tui';
6
+ import { getCommand } from '../../command-prefix';
7
+ import { ErrorCode } from '../../errors';
8
+
9
+ function formatRelativeTime(isoDate: string): string {
10
+ const parsed = new Date(isoDate).getTime();
11
+ if (Number.isNaN(parsed)) return 'unknown';
12
+ const diffMs = Math.max(0, Date.now() - parsed);
13
+ const seconds = Math.floor(diffMs / 1000);
14
+ if (seconds < 60) return `${seconds}s ago`;
15
+ const minutes = Math.floor(seconds / 60);
16
+ if (minutes < 60) return `${minutes}m ago`;
17
+ const hours = Math.floor(minutes / 60);
18
+ if (hours < 24) return `${hours}h ago`;
19
+ const days = Math.floor(hours / 24);
20
+ return `${days}d ago`;
21
+ }
22
+
23
+ export const eventsSubcommand = createSubcommand({
24
+ name: 'events',
25
+ aliases: ['event', 'ev'],
26
+ description: 'List event history for a Coder Hub session',
27
+ tags: ['read-only', 'requires-auth'],
28
+ idempotent: true,
29
+ requires: { auth: true, org: true },
30
+ examples: [
31
+ {
32
+ command: getCommand('coder events codesess_abc123'),
33
+ description: 'List recent session events',
34
+ },
35
+ {
36
+ command: getCommand('coder events codesess_abc123 --limit 100 --json'),
37
+ description: 'Get session event history as JSON',
38
+ },
39
+ ],
40
+ schema: {
41
+ args: z.object({
42
+ sessionId: z.string().describe('Session ID to list events for'),
43
+ }),
44
+ options: z.object({
45
+ limit: z
46
+ .number()
47
+ .int()
48
+ .positive()
49
+ .optional()
50
+ .describe('Maximum number of events to return'),
51
+ url: z.string().optional().describe('Coder API URL override'),
52
+ }),
53
+ },
54
+ async handler(ctx) {
55
+ const { args, opts, options } = ctx;
56
+ const client = new CoderClient({
57
+ apiKey: ctx.auth.apiKey,
58
+ url: opts?.url,
59
+ orgId: ctx.orgId,
60
+ });
61
+
62
+ try {
63
+ const data = await client.listEventHistory(args.sessionId, {
64
+ limit: opts?.limit ?? 50,
65
+ });
66
+
67
+ if (options.json) {
68
+ return data;
69
+ }
70
+
71
+ if (data.events.length === 0) {
72
+ tui.info(`No events found for session ${args.sessionId}.`);
73
+ return data;
74
+ }
75
+
76
+ tui.table(
77
+ data.events.map((e) => ({
78
+ Event: e.event,
79
+ Category: e.category ?? '-',
80
+ Agent: e.agent ?? '-',
81
+ 'Task ID': e.taskId ?? '-',
82
+ Occurred: e.occurredAt ? formatRelativeTime(e.occurredAt) : '-',
83
+ })),
84
+ [
85
+ { name: 'Event', alignment: 'left' },
86
+ { name: 'Category', alignment: 'left' },
87
+ { name: 'Agent', alignment: 'left' },
88
+ { name: 'Task ID', alignment: 'left' },
89
+ { name: 'Occurred', alignment: 'right' },
90
+ ]
91
+ );
92
+
93
+ return data;
94
+ } catch (err) {
95
+ if (err instanceof ValidationOutputError) {
96
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
97
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
98
+ }
99
+ const msg = err instanceof Error ? err.message : String(err);
100
+ tui.fatal(
101
+ `Failed to list event history for session ${args.sessionId}: ${msg}`,
102
+ ErrorCode.NETWORK_ERROR
103
+ );
104
+ }
105
+ },
106
+ });
@@ -0,0 +1,71 @@
1
+ import { dirname, resolve } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ export type ExtensionPathResolverOptions = {
5
+ cwd?: string;
6
+ env?: NodeJS.ProcessEnv;
7
+ moduleUrl?: string;
8
+ };
9
+
10
+ export async function resolveExtensionPath(
11
+ flagPath?: string,
12
+ options: ExtensionPathResolverOptions = {}
13
+ ): Promise<string | null> {
14
+ const cwd = options.cwd ?? process.cwd();
15
+ const env = options.env ?? process.env;
16
+ const moduleUrl = options.moduleUrl ?? import.meta.url;
17
+
18
+ // 1. Explicit flag
19
+ if (flagPath) {
20
+ return resolve(cwd, flagPath);
21
+ }
22
+
23
+ // 2. Env var
24
+ const envPath = env.AGENTUITY_CODER_EXTENSION;
25
+ if (envPath) {
26
+ return resolve(cwd, envPath);
27
+ }
28
+
29
+ // 3. Bundled with CLI package (require.resolve)
30
+ try {
31
+ const cliDir = fileURLToPath(new URL('.', moduleUrl));
32
+ const entryPath = require.resolve('@agentuity/coder-tui', { paths: [cliDir] });
33
+ let dir = dirname(entryPath);
34
+ while (dir !== dirname(dir)) {
35
+ if (await Bun.file(resolve(dir, 'package.json')).exists()) return dir;
36
+ dir = dirname(dir);
37
+ }
38
+ } catch {
39
+ // require.resolve may fail in workspace/worktree setups — fall through to direct lookup
40
+ }
41
+
42
+ // 4. Direct node_modules lookup (workspace symlink fallback)
43
+ try {
44
+ const cliDir = fileURLToPath(new URL('.', moduleUrl));
45
+ // Walk up from this file to the CLI package root, then check node_modules
46
+ let dir = cliDir;
47
+ for (let i = 0; i < 10; i++) {
48
+ const candidate = resolve(dir, 'node_modules', '@agentuity', 'coder-tui');
49
+ if (await Bun.file(resolve(candidate, 'package.json')).exists()) return candidate;
50
+ const parent = dirname(dir);
51
+ if (parent === dir) break;
52
+ dir = parent;
53
+ }
54
+ } catch {
55
+ // ignore
56
+ }
57
+
58
+ return null;
59
+ }
60
+
61
+ export async function resolveExtensionRuntimeModulePath(
62
+ extensionPath: string
63
+ ): Promise<string | null> {
64
+ const sourceModulePath = resolve(extensionPath, 'src', 'remote-tui.ts');
65
+ if (await Bun.file(sourceModulePath).exists()) return sourceModulePath;
66
+
67
+ const distModulePath = resolve(extensionPath, 'dist', 'remote-tui.js');
68
+ if (await Bun.file(distModulePath).exists()) return distModulePath;
69
+
70
+ return null;
71
+ }