@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
@@ -1,12 +1,20 @@
1
1
  import { z } from 'zod';
2
+ import {
3
+ CoderClient,
4
+ CoderSessionArchivedError,
5
+ CoderSessionNotFoundError,
6
+ } from '@agentuity/core/coder';
7
+ import { ValidationOutputError } from '@agentuity/core';
8
+
2
9
  import { createSubcommand } from '../../types';
3
10
  import * as tui from '../../tui';
4
11
  import { getCommand } from '../../command-prefix';
5
12
  import { ErrorCode } from '../../errors';
6
- import { resolveHubUrl, hubFetchHeaders } from './hub-url';
7
13
 
8
14
  function formatRelativeTime(isoDate: string): string {
9
- const diffMs = Date.now() - new Date(isoDate).getTime();
15
+ const parsed = new Date(isoDate).getTime();
16
+ if (Number.isNaN(parsed)) return 'unknown';
17
+ const diffMs = Math.max(0, Date.now() - parsed);
10
18
  const seconds = Math.floor(diffMs / 1000);
11
19
  if (seconds < 60) return `${seconds}s ago`;
12
20
  const minutes = Math.floor(seconds / 60);
@@ -28,17 +36,19 @@ function formatDuration(ms: number): string {
28
36
  return `${hours}h ${remainMin}m`;
29
37
  }
30
38
 
31
- export const inspectSubcommand = createSubcommand({
32
- name: 'inspect',
39
+ export const getSubcommand = createSubcommand({
40
+ name: 'get',
41
+ aliases: ['show', 'inspect'],
33
42
  description: 'Show detailed information about a Coder Hub session',
34
43
  tags: ['read-only', 'fast', 'requires-auth'],
44
+ requires: { auth: true, org: true },
35
45
  examples: [
36
46
  {
37
- command: getCommand('coder inspect codesess_abc123'),
38
- description: 'Inspect a session by ID',
47
+ command: getCommand('coder get codesess_abc123'),
48
+ description: 'Get a session by ID',
39
49
  },
40
50
  {
41
- command: getCommand('coder inspect codesess_abc123 --json'),
51
+ command: getCommand('coder get codesess_abc123 --json'),
42
52
  description: 'Get session details as JSON',
43
53
  },
44
54
  ],
@@ -48,21 +58,17 @@ export const inspectSubcommand = createSubcommand({
48
58
  session_id: z.string().describe('Coder session ID to inspect'),
49
59
  }),
50
60
  options: z.object({
51
- hubUrl: z.string().optional().describe('Hub URL override'),
61
+ url: z.string().optional().describe('Coder API URL override'),
52
62
  }),
53
63
  },
54
64
  async handler(ctx) {
55
65
  const { args, options, opts } = ctx;
56
66
  const sessionId = args.session_id;
57
- const hubUrl = await resolveHubUrl(opts?.hubUrl);
58
-
59
- if (!hubUrl) {
60
- tui.fatal(
61
- 'Could not find a running Coder Hub.\n\nEither:\n - Start the Hub with: bun run dev\n - Set AGENTUITY_CODER_HUB_URL environment variable\n - Pass --hub-url flag',
62
- ErrorCode.NETWORK_ERROR
63
- );
64
- return;
65
- }
67
+ const client = new CoderClient({
68
+ apiKey: ctx.auth.apiKey,
69
+ url: opts?.url,
70
+ orgId: ctx.orgId,
71
+ });
66
72
 
67
73
  let data: {
68
74
  sessionId: string;
@@ -70,18 +76,18 @@ export const inspectSubcommand = createSubcommand({
70
76
  status: string;
71
77
  createdAt: string;
72
78
  mode: string;
73
- context: {
79
+ context?: {
74
80
  branch?: string;
75
81
  workingDirectory?: string;
76
82
  };
77
- participants: Array<{
83
+ participants?: Array<{
78
84
  id: string;
79
85
  role: string;
80
86
  transport: string;
81
87
  connectedAt: string;
82
88
  idle: boolean;
83
89
  }>;
84
- tasks: Array<{
90
+ tasks?: Array<{
85
91
  taskId: string;
86
92
  agent: string;
87
93
  status: string;
@@ -90,7 +96,7 @@ export const inspectSubcommand = createSubcommand({
90
96
  startedAt: string;
91
97
  completedAt?: string;
92
98
  }>;
93
- agentActivity: Record<
99
+ agentActivity?: Record<
94
100
  string,
95
101
  {
96
102
  name: string;
@@ -103,32 +109,23 @@ export const inspectSubcommand = createSubcommand({
103
109
  };
104
110
 
105
111
  try {
106
- const resp = await fetch(`${hubUrl}/api/hub/session/${encodeURIComponent(sessionId)}`, {
107
- headers: hubFetchHeaders(),
108
- signal: AbortSignal.timeout(10_000),
109
- });
110
- if (resp.status === 404) {
112
+ data = (await client.getSession(sessionId)) as unknown as typeof data;
113
+ } catch (err) {
114
+ if (err instanceof CoderSessionNotFoundError) {
111
115
  tui.fatal(`Session not found: ${sessionId}`, ErrorCode.RESOURCE_NOT_FOUND);
112
116
  return;
113
117
  }
114
- if (resp.status === 410) {
118
+ if (err instanceof CoderSessionArchivedError) {
115
119
  tui.fatal(`Session has shut down: ${sessionId}`, ErrorCode.RESOURCE_NOT_FOUND);
116
120
  return;
117
121
  }
118
- if (!resp.ok) {
119
- tui.fatal(
120
- `Hub returned ${resp.status}: ${resp.statusText}. Is the Coder Hub running at ${hubUrl}?`,
121
- ErrorCode.API_ERROR
122
- );
123
- return;
122
+
123
+ if (err instanceof ValidationOutputError) {
124
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
125
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
124
126
  }
125
- data = (await resp.json()) as typeof data;
126
- } catch (err) {
127
127
  const msg = err instanceof Error ? err.message : String(err);
128
- tui.fatal(
129
- `Could not connect to Coder Hub at ${hubUrl}: ${msg}\n\nSet AGENTUITY_CODER_HUB_URL or start the Hub with: bun run dev`,
130
- ErrorCode.NETWORK_ERROR
131
- );
128
+ tui.fatal(`Failed to inspect Coder session ${sessionId}: ${msg}`, ErrorCode.NETWORK_ERROR);
132
129
  return;
133
130
  }
134
131
 
@@ -141,17 +138,18 @@ export const inspectSubcommand = createSubcommand({
141
138
  console.log();
142
139
  console.log(` Session: ${label} (${data.sessionId})`);
143
140
  const parts = [`Status: ${data.status}`, `Mode: ${data.mode}`];
144
- if (data.context.branch) parts.push(`Branch: ${data.context.branch}`);
141
+ if (data.context?.branch) parts.push(`Branch: ${data.context.branch}`);
145
142
  console.log(` ${parts.join(' | ')}`);
146
143
  console.log(` Created: ${data.createdAt}`);
147
144
 
148
145
  // Participants
149
146
  console.log();
150
147
  console.log(' Participants:');
151
- if (data.participants.length === 0) {
148
+ const participants = data.participants ?? [];
149
+ if (participants.length === 0) {
152
150
  console.log(' (none)');
153
151
  } else {
154
- for (const p of data.participants) {
152
+ for (const p of participants) {
155
153
  const idle = p.idle ? ' (idle)' : '';
156
154
  const connected = p.connectedAt
157
155
  ? ` connected ${formatRelativeTime(p.connectedAt)}`
@@ -163,10 +161,11 @@ export const inspectSubcommand = createSubcommand({
163
161
  }
164
162
 
165
163
  // Tasks
166
- if (data.tasks.length > 0) {
164
+ const tasks = data.tasks ?? [];
165
+ if (tasks.length > 0) {
167
166
  console.log();
168
167
  console.log(' Tasks:');
169
- for (const t of data.tasks) {
168
+ for (const t of tasks) {
170
169
  const dur = t.duration ? formatDuration(t.duration) : '-';
171
170
  const prompt = t.prompt.length > 40 ? t.prompt.slice(0, 37) + '...' : t.prompt;
172
171
  console.log(
@@ -176,7 +175,7 @@ export const inspectSubcommand = createSubcommand({
176
175
  }
177
176
 
178
177
  // Agent Activity
179
- const agents = Object.values(data.agentActivity);
178
+ const agents = Object.values(data.agentActivity ?? {});
180
179
  if (agents.length > 0) {
181
180
  console.log();
182
181
  console.log(' Agent Activity:');
@@ -1,7 +1,18 @@
1
1
  import { createCommand } from '../../types';
2
2
  import { listSubcommand } from './list';
3
- import { inspectSubcommand } from './inspect';
3
+ import { getSubcommand } from './get';
4
4
  import { startSubcommand } from './start';
5
+ import { createCoderSubcommand } from './create';
6
+ import { deleteSubcommand } from './delete';
7
+ import { archiveSubcommand } from './archive';
8
+ import { updateSubcommand } from './update';
9
+ import { usersSubcommand } from './users';
10
+ import { loopSubcommand } from './loop';
11
+ import { replaySubcommand } from './replay';
12
+ import { participantsSubcommand } from './participants';
13
+ import { eventsSubcommand } from './events';
14
+ import { workspaceCommand } from './workspace';
15
+ import { skillCommand } from './skill';
5
16
  import { getCommand } from '../../command-prefix';
6
17
 
7
18
  export const command = createCommand({
@@ -13,15 +24,54 @@ export const command = createCommand({
13
24
  command: getCommand('coder start'),
14
25
  description: 'Start a Pi session connected to the Coder Hub',
15
26
  },
27
+ {
28
+ command: getCommand('coder create "Build a REST API"'),
29
+ description: 'Create a new Coder session with a task',
30
+ },
16
31
  {
17
32
  command: getCommand('coder ls'),
18
33
  description: 'List all active Coder Hub sessions',
19
34
  },
20
35
  {
21
- command: getCommand('coder inspect <session-id>'),
36
+ command: getCommand('coder get <session-id>'),
22
37
  description: 'Show detailed session information',
23
38
  },
39
+ {
40
+ command: getCommand('coder users'),
41
+ description: 'List known Coder Hub users',
42
+ },
43
+ {
44
+ command: getCommand('coder loop <session-id>'),
45
+ description: 'Get loop state for a session',
46
+ },
47
+ {
48
+ command: getCommand('coder events <session-id> --limit 100'),
49
+ description: 'Show recent event history for a session',
50
+ },
51
+ {
52
+ command: getCommand('coder workspace list'),
53
+ description: 'List Coder workspaces',
54
+ },
55
+ {
56
+ command: getCommand('coder skill list'),
57
+ description: 'List saved skills',
58
+ },
59
+ ],
60
+ subcommands: [
61
+ startSubcommand,
62
+ createCoderSubcommand,
63
+ listSubcommand,
64
+ getSubcommand,
65
+ updateSubcommand,
66
+ deleteSubcommand,
67
+ archiveSubcommand,
68
+ usersSubcommand,
69
+ loopSubcommand,
70
+ replaySubcommand,
71
+ participantsSubcommand,
72
+ eventsSubcommand,
73
+ workspaceCommand,
74
+ skillCommand,
24
75
  ],
25
- subcommands: [startSubcommand, listSubcommand, inspectSubcommand],
26
- optional: { auth: true },
76
+ requires: { auth: true, org: true },
27
77
  });
@@ -1,12 +1,19 @@
1
1
  import { z } from 'zod';
2
+ import {
3
+ CoderClient,
4
+ type CoderSessionListItem,
5
+ CoderSessionListItemSchema,
6
+ } from '@agentuity/core/coder';
7
+ import { ValidationOutputError } from '@agentuity/core';
2
8
  import { createSubcommand } from '../../types';
3
9
  import * as tui from '../../tui';
4
10
  import { getCommand } from '../../command-prefix';
5
11
  import { ErrorCode } from '../../errors';
6
- import { resolveHubUrl, hubFetchHeaders } from './hub-url';
7
12
 
8
13
  function formatRelativeTime(isoDate: string): string {
9
- const diffMs = Date.now() - new Date(isoDate).getTime();
14
+ const parsed = new Date(isoDate).getTime();
15
+ if (Number.isNaN(parsed)) return 'unknown';
16
+ const diffMs = Math.max(0, Date.now() - parsed);
10
17
  const seconds = Math.floor(diffMs / 1000);
11
18
  if (seconds < 60) return `${seconds}s ago`;
12
19
  const minutes = Math.floor(seconds / 60);
@@ -17,20 +24,6 @@ function formatRelativeTime(isoDate: string): string {
17
24
  return `${days}d ago`;
18
25
  }
19
26
 
20
- const SessionListResponseSchema = z.array(
21
- z.object({
22
- sessionId: z.string().describe('Session ID'),
23
- label: z.string().describe('Human-readable session label'),
24
- status: z.string().describe('Session status'),
25
- mode: z.string().describe('Session mode (sandbox or tui)'),
26
- createdAt: z.string().describe('Creation timestamp'),
27
- taskCount: z.number().describe('Number of tasks'),
28
- subAgentCount: z.number().describe('Number of sub-agents'),
29
- observerCount: z.number().describe('Number of observers'),
30
- participantCount: z.number().describe('Total participant count'),
31
- })
32
- );
33
-
34
27
  export const listSubcommand = createSubcommand({
35
28
  name: 'list',
36
29
  description: 'List active Coder Hub sessions',
@@ -47,66 +40,34 @@ export const listSubcommand = createSubcommand({
47
40
  ],
48
41
  aliases: ['ls'],
49
42
  idempotent: true,
43
+ requires: { auth: true, org: true },
50
44
  schema: {
51
45
  options: z.object({
52
- hubUrl: z.string().optional().describe('Hub URL override'),
46
+ url: z.string().optional().describe('Coder API URL override'),
53
47
  }),
54
- response: SessionListResponseSchema,
48
+ response: z.array(CoderSessionListItemSchema),
55
49
  },
56
50
  async handler(ctx) {
57
51
  const { options, opts } = ctx;
58
- const hubUrl = await resolveHubUrl(opts?.hubUrl);
59
-
60
- if (!hubUrl) {
61
- tui.fatal(
62
- 'Could not find a running Coder Hub.\n\nEither:\n - Start the Hub with: bun run dev\n - Set AGENTUITY_CODER_HUB_URL environment variable\n - Pass --hub-url flag',
63
- ErrorCode.NETWORK_ERROR
64
- );
65
- return [];
66
- }
67
-
68
- let data: {
69
- sessions: {
70
- websocket: Array<{
71
- sessionId: string;
72
- label: string;
73
- status: string;
74
- mode: string;
75
- createdAt: string;
76
- taskCount: number;
77
- subAgentCount: number;
78
- observerCount: number;
79
- participantCount: number;
80
- }>;
81
- sandbox: Array<Record<string, unknown>>;
82
- };
83
- total: number;
84
- };
52
+ const client = new CoderClient({
53
+ apiKey: ctx.auth.apiKey,
54
+ url: opts?.url,
55
+ orgId: ctx.orgId,
56
+ });
85
57
 
58
+ let sessions: CoderSessionListItem[] = [];
86
59
  try {
87
- const resp = await fetch(`${hubUrl}/api/hub/sessions`, {
88
- headers: hubFetchHeaders(),
89
- signal: AbortSignal.timeout(10_000),
90
- });
91
- if (!resp.ok) {
92
- tui.fatal(
93
- `Hub returned ${resp.status}: ${resp.statusText}. Is the Coder Hub running at ${hubUrl}?`,
94
- ErrorCode.API_ERROR
95
- );
96
- return [];
97
- }
98
- data = (await resp.json()) as typeof data;
60
+ const response = await client.listSessions();
61
+ sessions = response.sessions;
99
62
  } catch (err) {
63
+ if (err instanceof ValidationOutputError) {
64
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
65
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
66
+ }
100
67
  const msg = err instanceof Error ? err.message : String(err);
101
- tui.fatal(
102
- `Could not connect to Coder Hub at ${hubUrl}: ${msg}\n\nSet AGENTUITY_CODER_HUB_URL or start the Hub with: bun run dev`,
103
- ErrorCode.NETWORK_ERROR
104
- );
105
- return [];
68
+ tui.fatal(`Failed to list Coder sessions: ${msg}`, ErrorCode.NETWORK_ERROR);
106
69
  }
107
70
 
108
- const sessions = data.sessions.websocket;
109
-
110
71
  if (options.json) {
111
72
  return sessions;
112
73
  }
@@ -117,10 +78,11 @@ export const listSubcommand = createSubcommand({
117
78
  }
118
79
 
119
80
  const tableData = sessions.map((s) => ({
120
- 'Session ID': s.sessionId.length > 20 ? s.sessionId.slice(0, 17) + '...' : s.sessionId,
81
+ 'Session ID': s.sessionId,
121
82
  Label: s.label || '-',
122
83
  Status: s.status,
123
84
  Mode: s.mode,
85
+ Owner: s.owner?.name ?? s.owner?.userId ?? '-',
124
86
  Observers: String(s.observerCount),
125
87
  Agents: String(s.subAgentCount),
126
88
  Tasks: String(s.taskCount),
@@ -132,6 +94,7 @@ export const listSubcommand = createSubcommand({
132
94
  { name: 'Label', alignment: 'left' },
133
95
  { name: 'Status', alignment: 'center' },
134
96
  { name: 'Mode', alignment: 'center' },
97
+ { name: 'Owner', alignment: 'left' },
135
98
  { name: 'Observers', alignment: 'right' },
136
99
  { name: 'Agents', alignment: 'right' },
137
100
  { name: 'Tasks', alignment: 'right' },
@@ -0,0 +1,85 @@
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 loopSubcommand = createSubcommand({
10
+ name: 'loop',
11
+ description: 'Get loop-mode state for a Coder Hub session',
12
+ tags: ['read-only', 'fast', 'requires-auth'],
13
+ idempotent: true,
14
+ requires: { auth: true, org: true },
15
+ examples: [
16
+ {
17
+ command: getCommand('coder loop codesess_abc123'),
18
+ description: 'Show loop state for a session',
19
+ },
20
+ {
21
+ command: getCommand('coder loop codesess_abc123 --json'),
22
+ description: 'Get loop state as JSON',
23
+ },
24
+ ],
25
+ schema: {
26
+ args: z.object({
27
+ sessionId: z.string().describe('Session ID to inspect loop state for'),
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
+ try {
42
+ const state = await client.getLoopState(args.sessionId);
43
+
44
+ if (options.json) {
45
+ return state;
46
+ }
47
+
48
+ const rows: Array<{ Field: string; Value: string }> = [
49
+ { Field: 'Session ID', Value: state.sessionId },
50
+ { Field: 'Workflow Mode', Value: state.workflowMode },
51
+ ];
52
+
53
+ if (!state.loop) {
54
+ rows.push({ Field: 'Loop Status', Value: 'not active' });
55
+ } else {
56
+ rows.push({ Field: 'Loop Status', Value: state.loop.status });
57
+ rows.push({ Field: 'Iteration', Value: String(state.loop.iteration) });
58
+ rows.push({
59
+ Field: 'Max Iterations',
60
+ Value: String(state.loop.maxIterations ?? '-'),
61
+ });
62
+ rows.push({ Field: 'Goal', Value: state.loop.goal ?? '-' });
63
+ rows.push({ Field: 'Summary', Value: state.loop.summary ?? '-' });
64
+ rows.push({ Field: 'Next Action', Value: state.loop.nextAction ?? '-' });
65
+ }
66
+
67
+ tui.table(rows, [
68
+ { name: 'Field', alignment: 'left' },
69
+ { name: 'Value', alignment: 'left' },
70
+ ]);
71
+
72
+ return state;
73
+ } catch (err) {
74
+ if (err instanceof ValidationOutputError) {
75
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
76
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
77
+ }
78
+ const msg = err instanceof Error ? err.message : String(err);
79
+ tui.fatal(
80
+ `Failed to get loop state for ${args.sessionId}: ${msg}`,
81
+ ErrorCode.NETWORK_ERROR
82
+ );
83
+ }
84
+ },
85
+ });
@@ -0,0 +1,100 @@
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 participantsSubcommand = createSubcommand({
24
+ name: 'participants',
25
+ aliases: ['participant', 'members'],
26
+ description: 'List participants for a Coder Hub session',
27
+ tags: ['read-only', 'fast', 'requires-auth'],
28
+ idempotent: true,
29
+ requires: { auth: true, org: true },
30
+ examples: [
31
+ {
32
+ command: getCommand('coder participants codesess_abc123'),
33
+ description: 'List session participants',
34
+ },
35
+ {
36
+ command: getCommand('coder participants codesess_abc123 --json'),
37
+ description: 'Get session participants as JSON',
38
+ },
39
+ ],
40
+ schema: {
41
+ args: z.object({
42
+ sessionId: z.string().describe('Session ID to list participants for'),
43
+ }),
44
+ options: z.object({
45
+ url: z.string().optional().describe('Coder API URL override'),
46
+ }),
47
+ },
48
+ async handler(ctx) {
49
+ const { args, opts, options } = ctx;
50
+ const client = new CoderClient({
51
+ apiKey: ctx.auth.apiKey,
52
+ url: opts?.url,
53
+ orgId: ctx.orgId,
54
+ });
55
+
56
+ try {
57
+ const data = await client.listParticipants(args.sessionId);
58
+
59
+ if (options.json) {
60
+ return data;
61
+ }
62
+
63
+ if (data.participants.length === 0) {
64
+ tui.info(`No participants found for session ${args.sessionId}.`);
65
+ return data;
66
+ }
67
+
68
+ tui.table(
69
+ data.participants.map((p) => ({
70
+ ID: p.id,
71
+ Role: p.role,
72
+ 'Agent Role': p.agentRole ?? '-',
73
+ Transport: p.transport ?? '-',
74
+ Connected: p.connectedAt ? formatRelativeTime(p.connectedAt) : '-',
75
+ 'Last Activity': p.lastActivityAt ? formatRelativeTime(p.lastActivityAt) : '-',
76
+ })),
77
+ [
78
+ { name: 'ID', alignment: 'left' },
79
+ { name: 'Role', alignment: 'left' },
80
+ { name: 'Agent Role', alignment: 'left' },
81
+ { name: 'Transport', alignment: 'center' },
82
+ { name: 'Connected', alignment: 'right' },
83
+ { name: 'Last Activity', alignment: 'right' },
84
+ ]
85
+ );
86
+
87
+ return data;
88
+ } catch (err) {
89
+ if (err instanceof ValidationOutputError) {
90
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
91
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
92
+ }
93
+ const msg = err instanceof Error ? err.message : String(err);
94
+ tui.fatal(
95
+ `Failed to list participants for session ${args.sessionId}: ${msg}`,
96
+ ErrorCode.NETWORK_ERROR
97
+ );
98
+ }
99
+ },
100
+ });
@@ -0,0 +1,58 @@
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 replaySubcommand = createSubcommand({
10
+ name: 'replay',
11
+ description: 'Get replay data for a Coder Hub session',
12
+ tags: ['read-only', 'requires-auth'],
13
+ idempotent: true,
14
+ requires: { auth: true, org: true },
15
+ examples: [
16
+ {
17
+ command: getCommand('coder replay codesess_abc123 --json'),
18
+ description: 'Get replay data as JSON',
19
+ },
20
+ ],
21
+ schema: {
22
+ args: z.object({
23
+ sessionId: z.string().describe('Session ID to get replay data for'),
24
+ }),
25
+ options: z.object({
26
+ url: z.string().optional().describe('Coder API URL override'),
27
+ }),
28
+ },
29
+ async handler(ctx) {
30
+ const { args, opts, options } = ctx;
31
+ const client = new CoderClient({
32
+ apiKey: ctx.auth.apiKey,
33
+ url: opts?.url,
34
+ orgId: ctx.orgId,
35
+ });
36
+
37
+ try {
38
+ const replay = await client.getReplay(args.sessionId);
39
+
40
+ if (!options.json) {
41
+ tui.info('Replay data is shown as JSON because it is a complex payload.');
42
+ tui.output(JSON.stringify(replay, null, 2));
43
+ }
44
+
45
+ return replay;
46
+ } catch (err) {
47
+ if (err instanceof ValidationOutputError) {
48
+ ctx.logger.trace('Validation response URL: %s', err.url ?? 'unknown');
49
+ ctx.logger.trace('Validation issues: %s', JSON.stringify(err.issues, null, 2));
50
+ }
51
+ const msg = err instanceof Error ? err.message : String(err);
52
+ tui.fatal(
53
+ `Failed to get replay for session ${args.sessionId}: ${msg}`,
54
+ ErrorCode.NETWORK_ERROR
55
+ );
56
+ }
57
+ },
58
+ });