@agentuity/cli 2.0.7 → 2.0.9
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.
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/cmd/build/vite/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/vite/route-discovery.js +6 -0
- package/dist/cmd/build/vite/route-discovery.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/rm.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/rm.js +9 -3
- package/dist/cmd/cloud/sandbox/fs/rm.js.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/rmdir.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/fs/rmdir.js +9 -3
- package/dist/cmd/cloud/sandbox/fs/rmdir.js.map +1 -1
- package/dist/cmd/coder/archive.d.ts +2 -0
- package/dist/cmd/coder/archive.d.ts.map +1 -0
- package/dist/cmd/coder/archive.js +57 -0
- package/dist/cmd/coder/archive.js.map +1 -0
- package/dist/cmd/coder/create.d.ts +2 -0
- package/dist/cmd/coder/create.d.ts.map +1 -0
- package/dist/cmd/coder/create.js +245 -0
- package/dist/cmd/coder/create.js.map +1 -0
- package/dist/cmd/coder/delete.d.ts +2 -0
- package/dist/cmd/coder/delete.d.ts.map +1 -0
- package/dist/cmd/coder/delete.js +64 -0
- package/dist/cmd/coder/delete.js.map +1 -0
- package/dist/cmd/coder/events.d.ts +2 -0
- package/dist/cmd/coder/events.d.ts.map +1 -0
- package/dist/cmd/coder/events.js +99 -0
- package/dist/cmd/coder/events.js.map +1 -0
- package/dist/cmd/coder/extension-path.d.ts +8 -0
- package/dist/cmd/coder/extension-path.d.ts.map +1 -0
- package/dist/cmd/coder/extension-path.js +59 -0
- package/dist/cmd/coder/extension-path.js.map +1 -0
- package/dist/cmd/coder/get.d.ts +2 -0
- package/dist/cmd/coder/get.d.ts.map +1 -0
- package/dist/cmd/coder/{inspect.js → get.js} +38 -42
- package/dist/cmd/coder/get.js.map +1 -0
- package/dist/cmd/coder/index.d.ts.map +1 -1
- package/dist/cmd/coder/index.js +52 -7
- package/dist/cmd/coder/index.js.map +1 -1
- package/dist/cmd/coder/list.d.ts.map +1 -1
- package/dist/cmd/coder/list.js +26 -42
- package/dist/cmd/coder/list.js.map +1 -1
- package/dist/cmd/coder/loop.d.ts +2 -0
- package/dist/cmd/coder/loop.d.ts.map +1 -0
- package/dist/cmd/coder/loop.js +78 -0
- package/dist/cmd/coder/loop.js.map +1 -0
- package/dist/cmd/coder/participants.d.ts +2 -0
- package/dist/cmd/coder/participants.d.ts.map +1 -0
- package/dist/cmd/coder/participants.js +93 -0
- package/dist/cmd/coder/participants.js.map +1 -0
- package/dist/cmd/coder/replay.d.ts +2 -0
- package/dist/cmd/coder/replay.d.ts.map +1 -0
- package/dist/cmd/coder/replay.js +53 -0
- package/dist/cmd/coder/replay.js.map +1 -0
- package/dist/cmd/coder/resolve-repo.d.ts +27 -0
- package/dist/cmd/coder/resolve-repo.d.ts.map +1 -0
- package/dist/cmd/coder/resolve-repo.js +97 -0
- package/dist/cmd/coder/resolve-repo.js.map +1 -0
- package/dist/cmd/coder/skill/buckets.d.ts +2 -0
- package/dist/cmd/coder/skill/buckets.d.ts.map +1 -0
- package/dist/cmd/coder/skill/buckets.js +174 -0
- package/dist/cmd/coder/skill/buckets.js.map +1 -0
- package/dist/cmd/coder/skill/delete.d.ts +2 -0
- package/dist/cmd/coder/skill/delete.d.ts.map +1 -0
- package/dist/cmd/coder/skill/delete.js +64 -0
- package/dist/cmd/coder/skill/delete.js.map +1 -0
- package/dist/cmd/coder/skill/index.d.ts +2 -0
- package/dist/cmd/coder/skill/index.d.ts.map +1 -0
- package/dist/cmd/coder/skill/index.js +33 -0
- package/dist/cmd/coder/skill/index.js.map +1 -0
- package/dist/cmd/coder/skill/list.d.ts +2 -0
- package/dist/cmd/coder/skill/list.d.ts.map +1 -0
- package/dist/cmd/coder/skill/list.js +93 -0
- package/dist/cmd/coder/skill/list.js.map +1 -0
- package/dist/cmd/coder/skill/save.d.ts +2 -0
- package/dist/cmd/coder/skill/save.d.ts.map +1 -0
- package/dist/cmd/coder/skill/save.js +77 -0
- package/dist/cmd/coder/skill/save.js.map +1 -0
- package/dist/cmd/coder/start.d.ts.map +1 -1
- package/dist/cmd/coder/start.js +87 -131
- package/dist/cmd/coder/start.js.map +1 -1
- package/dist/cmd/coder/tui-init.d.ts.map +1 -1
- package/dist/cmd/coder/tui-init.js +7 -2
- package/dist/cmd/coder/tui-init.js.map +1 -1
- package/dist/cmd/coder/update.d.ts +2 -0
- package/dist/cmd/coder/update.d.ts.map +1 -0
- package/dist/cmd/coder/update.js +126 -0
- package/dist/cmd/coder/update.js.map +1 -0
- package/dist/cmd/coder/users.d.ts +2 -0
- package/dist/cmd/coder/users.d.ts.map +1 -0
- package/dist/cmd/coder/users.js +97 -0
- package/dist/cmd/coder/users.js.map +1 -0
- package/dist/cmd/coder/workspace/create.d.ts +2 -0
- package/dist/cmd/coder/workspace/create.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/create.js +97 -0
- package/dist/cmd/coder/workspace/create.js.map +1 -0
- package/dist/cmd/coder/workspace/delete.d.ts +2 -0
- package/dist/cmd/coder/workspace/delete.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/delete.js +64 -0
- package/dist/cmd/coder/workspace/delete.js.map +1 -0
- package/dist/cmd/coder/workspace/get.d.ts +2 -0
- package/dist/cmd/coder/workspace/get.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/get.js +109 -0
- package/dist/cmd/coder/workspace/get.js.map +1 -0
- package/dist/cmd/coder/workspace/index.d.ts +2 -0
- package/dist/cmd/coder/workspace/index.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/index.js +38 -0
- package/dist/cmd/coder/workspace/index.js.map +1 -0
- package/dist/cmd/coder/workspace/list.d.ts +2 -0
- package/dist/cmd/coder/workspace/list.d.ts.map +1 -0
- package/dist/cmd/coder/workspace/list.js +93 -0
- package/dist/cmd/coder/workspace/list.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/types.d.ts +1 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +0 -10
- package/dist/types.js.map +1 -1
- package/package.json +7 -6
- package/src/cli.ts +4 -2
- package/src/cmd/ai/prompt/agent.md +6 -6
- package/src/cmd/build/vite/route-discovery.ts +8 -0
- package/src/cmd/cloud/sandbox/fs/rm.ts +8 -3
- package/src/cmd/cloud/sandbox/fs/rmdir.ts +8 -3
- package/src/cmd/coder/archive.ts +59 -0
- package/src/cmd/coder/create.ts +268 -0
- package/src/cmd/coder/delete.ts +67 -0
- package/src/cmd/coder/events.ts +106 -0
- package/src/cmd/coder/extension-path.ts +71 -0
- package/src/cmd/coder/{inspect.ts → get.ts} +45 -69
- package/src/cmd/coder/index.ts +52 -7
- package/src/cmd/coder/list.ts +29 -89
- package/src/cmd/coder/loop.ts +85 -0
- package/src/cmd/coder/participants.ts +100 -0
- package/src/cmd/coder/replay.ts +58 -0
- package/src/cmd/coder/resolve-repo.ts +119 -0
- package/src/cmd/coder/skill/buckets.ts +191 -0
- package/src/cmd/coder/skill/delete.ts +67 -0
- package/src/cmd/coder/skill/index.ts +35 -0
- package/src/cmd/coder/skill/list.ts +97 -0
- package/src/cmd/coder/skill/save.ts +84 -0
- package/src/cmd/coder/start.ts +101 -174
- package/src/cmd/coder/tui-init.ts +7 -3
- package/src/cmd/coder/update.ts +128 -0
- package/src/cmd/coder/users.ts +101 -0
- package/src/cmd/coder/workspace/create.ts +104 -0
- package/src/cmd/coder/workspace/delete.ts +70 -0
- package/src/cmd/coder/workspace/get.ts +112 -0
- package/src/cmd/coder/workspace/index.ts +38 -0
- package/src/cmd/coder/workspace/list.ts +101 -0
- package/src/config.ts +4 -3
- package/src/types.ts +0 -10
- package/dist/cmd/coder/config/index.d.ts +0 -2
- package/dist/cmd/coder/config/index.d.ts.map +0 -1
- package/dist/cmd/coder/config/index.js +0 -20
- package/dist/cmd/coder/config/index.js.map +0 -1
- package/dist/cmd/coder/config/set.d.ts +0 -2
- package/dist/cmd/coder/config/set.d.ts.map +0 -1
- package/dist/cmd/coder/config/set.js +0 -100
- package/dist/cmd/coder/config/set.js.map +0 -1
- package/dist/cmd/coder/hub-url.d.ts +0 -47
- package/dist/cmd/coder/hub-url.d.ts.map +0 -1
- package/dist/cmd/coder/hub-url.js +0 -148
- package/dist/cmd/coder/hub-url.js.map +0 -1
- package/dist/cmd/coder/inspect.d.ts +0 -2
- package/dist/cmd/coder/inspect.d.ts.map +0 -1
- package/dist/cmd/coder/inspect.js.map +0 -1
- package/dist/coder-config.d.ts +0 -14
- package/dist/coder-config.d.ts.map +0 -1
- package/dist/coder-config.js +0 -119
- package/dist/coder-config.js.map +0 -1
- package/src/cmd/coder/config/index.ts +0 -20
- package/src/cmd/coder/config/set.ts +0 -112
- package/src/cmd/coder/hub-url.ts +0 -205
- 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
|
+
}
|