@agentuity/cli 0.1.10 → 0.1.12
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/auth.d.ts.map +1 -1
- package/dist/auth.js +6 -10
- package/dist/auth.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +89 -41
- package/dist/cli.js.map +1 -1
- package/dist/cmd/auth/login.d.ts.map +1 -1
- package/dist/cmd/auth/login.js +49 -5
- package/dist/cmd/auth/login.js.map +1 -1
- package/dist/cmd/build/patch/_util.d.ts.map +1 -1
- package/dist/cmd/build/patch/_util.js +6 -2
- package/dist/cmd/build/patch/_util.js.map +1 -1
- package/dist/cmd/cloud/agent/get.d.ts.map +1 -1
- package/dist/cmd/cloud/agent/get.js +10 -6
- package/dist/cmd/cloud/agent/get.js.map +1 -1
- package/dist/cmd/cloud/db/create.d.ts.map +1 -1
- package/dist/cmd/cloud/db/create.js +14 -3
- package/dist/cmd/cloud/db/create.js.map +1 -1
- package/dist/cmd/cloud/db/get.d.ts.map +1 -1
- package/dist/cmd/cloud/db/get.js +13 -3
- package/dist/cmd/cloud/db/get.js.map +1 -1
- package/dist/cmd/cloud/db/list.d.ts.map +1 -1
- package/dist/cmd/cloud/db/list.js +17 -25
- package/dist/cmd/cloud/db/list.js.map +1 -1
- package/dist/cmd/cloud/deployment/show.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/show.js +50 -37
- package/dist/cmd/cloud/deployment/show.js.map +1 -1
- package/dist/cmd/cloud/sandbox/create.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/create.js +19 -2
- package/dist/cmd/cloud/sandbox/create.js.map +1 -1
- package/dist/cmd/cloud/sandbox/execution/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/execution/get.js +14 -11
- package/dist/cmd/cloud/sandbox/execution/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/get.js +48 -39
- package/dist/cmd/cloud/sandbox/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/list.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/list.js +6 -1
- package/dist/cmd/cloud/sandbox/list.js.map +1 -1
- package/dist/cmd/cloud/sandbox/run.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/run.js +5 -1
- package/dist/cmd/cloud/sandbox/run.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/build.d.ts +5 -0
- package/dist/cmd/cloud/sandbox/snapshot/build.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/snapshot/build.js +590 -0
- package/dist/cmd/cloud/sandbox/snapshot/build.js.map +1 -0
- package/dist/cmd/cloud/sandbox/snapshot/generate.d.ts +3 -0
- package/dist/cmd/cloud/sandbox/snapshot/generate.d.ts.map +1 -0
- package/dist/cmd/cloud/sandbox/snapshot/generate.js +129 -0
- package/dist/cmd/cloud/sandbox/snapshot/generate.js.map +1 -0
- package/dist/cmd/cloud/sandbox/snapshot/get.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/get.js +25 -6
- package/dist/cmd/cloud/sandbox/snapshot/get.js.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/index.d.ts.map +1 -1
- package/dist/cmd/cloud/sandbox/snapshot/index.js +19 -1
- package/dist/cmd/cloud/sandbox/snapshot/index.js.map +1 -1
- package/dist/cmd/cloud/session/get.d.ts.map +1 -1
- package/dist/cmd/cloud/session/get.js +24 -23
- package/dist/cmd/cloud/session/get.js.map +1 -1
- package/dist/cmd/cloud/session/list.d.ts.map +1 -1
- package/dist/cmd/cloud/session/list.js +7 -2
- package/dist/cmd/cloud/session/list.js.map +1 -1
- package/dist/cmd/cloud/thread/get.d.ts.map +1 -1
- package/dist/cmd/cloud/thread/get.js +11 -8
- package/dist/cmd/cloud/thread/get.js.map +1 -1
- package/dist/cmd/cloud/thread/list.d.ts.map +1 -1
- package/dist/cmd/cloud/thread/list.js +6 -1
- package/dist/cmd/cloud/thread/list.js.map +1 -1
- package/dist/cmd/dev/file-watcher.d.ts.map +1 -1
- package/dist/cmd/dev/file-watcher.js +2 -0
- package/dist/cmd/dev/file-watcher.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +62 -4
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/project/auth/shared.js +1 -1
- package/dist/cmd/project/auth/shared.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +15 -1
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/cmd/setup/index.d.ts.map +1 -1
- package/dist/cmd/setup/index.js +40 -3
- package/dist/cmd/setup/index.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +10 -5
- package/dist/config.js.map +1 -1
- package/dist/steps.d.ts.map +1 -1
- package/dist/steps.js +4 -2
- package/dist/steps.js.map +1 -1
- package/dist/tui.d.ts +11 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +47 -12
- package/dist/tui.js.map +1 -1
- package/dist/utils/apt-validator.js +3 -3
- package/dist/utils/apt-validator.js.map +1 -1
- package/package.json +6 -6
- package/src/auth.ts +12 -11
- package/src/cli.ts +121 -43
- package/src/cmd/auth/login.ts +57 -5
- package/src/cmd/build/patch/_util.ts +6 -2
- package/src/cmd/cloud/agent/get.ts +14 -6
- package/src/cmd/cloud/db/create.ts +15 -3
- package/src/cmd/cloud/db/get.ts +14 -3
- package/src/cmd/cloud/db/list.ts +16 -26
- package/src/cmd/cloud/deployment/show.ts +53 -47
- package/src/cmd/cloud/sandbox/create.ts +20 -2
- package/src/cmd/cloud/sandbox/execution/get.ts +16 -13
- package/src/cmd/cloud/sandbox/get.ts +48 -38
- package/src/cmd/cloud/sandbox/list.ts +6 -1
- package/src/cmd/cloud/sandbox/run.ts +5 -1
- package/src/cmd/cloud/sandbox/snapshot/build.ts +723 -0
- package/src/cmd/cloud/sandbox/snapshot/generate.ts +136 -0
- package/src/cmd/cloud/sandbox/snapshot/get.ts +29 -6
- package/src/cmd/cloud/sandbox/snapshot/index.ts +19 -1
- package/src/cmd/cloud/session/get.ts +25 -29
- package/src/cmd/cloud/session/list.ts +7 -2
- package/src/cmd/cloud/thread/get.ts +12 -8
- package/src/cmd/cloud/thread/list.ts +6 -1
- package/src/cmd/dev/file-watcher.ts +2 -0
- package/src/cmd/dev/index.ts +76 -4
- package/src/cmd/project/auth/shared.ts +1 -1
- package/src/cmd/project/template-flow.ts +15 -1
- package/src/cmd/setup/index.ts +41 -3
- package/src/config.ts +11 -5
- package/src/steps.ts +4 -2
- package/src/tui.ts +61 -12
- package/src/utils/apt-validator.ts +3 -3
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { createCommand } from '../../../../types';
|
|
3
|
+
import { getCommand } from '../../../../command-prefix';
|
|
4
|
+
|
|
5
|
+
const TEMPLATE_YAML = `# yaml-language-server: $schema=https://agentuity.dev/schema/cli/v1/agentuity-snapshot.json
|
|
6
|
+
#
|
|
7
|
+
# Agentuity Snapshot Build File
|
|
8
|
+
# =============================
|
|
9
|
+
# This file defines a reproducible sandbox environment.
|
|
10
|
+
# Build with: agentuity cloud sandbox snapshot build <directory>
|
|
11
|
+
#
|
|
12
|
+
# For documentation, see: https://agentuity.dev/Services/Sandbox
|
|
13
|
+
|
|
14
|
+
# Required: Schema version (must be 1)
|
|
15
|
+
version: 1
|
|
16
|
+
|
|
17
|
+
# Required: Runtime environment
|
|
18
|
+
# Format: name:tag (e.g., bun:1, node:20, python:3.12)
|
|
19
|
+
# Run 'agentuity cloud sandbox runtime list' to see available runtimes
|
|
20
|
+
runtime: bun:1
|
|
21
|
+
|
|
22
|
+
# Optional: Snapshot name (alphanumeric, underscores, dashes only)
|
|
23
|
+
# If not provided, a unique name will be auto-generated
|
|
24
|
+
# name: my-snapshot
|
|
25
|
+
|
|
26
|
+
# Optional: Human-readable description
|
|
27
|
+
# Can be overridden with --description flag
|
|
28
|
+
description: My sandbox snapshot
|
|
29
|
+
|
|
30
|
+
# Optional: Apt packages to install
|
|
31
|
+
# Packages are validated against Debian stable repositories
|
|
32
|
+
# Supports version pinning: package=version or package=version* (prefix match)
|
|
33
|
+
# dependencies:
|
|
34
|
+
# - curl
|
|
35
|
+
# - ffmpeg
|
|
36
|
+
# - imagemagick=8:6.9*
|
|
37
|
+
|
|
38
|
+
# Optional: Files to include from the build context directory
|
|
39
|
+
# Supports glob patterns and negative patterns (prefix with !)
|
|
40
|
+
# Files are placed in /home/agentuity/ in the sandbox
|
|
41
|
+
# files:
|
|
42
|
+
# - "*.js" # All JS files in root
|
|
43
|
+
# - src/** # All files in src/ recursively
|
|
44
|
+
# - config/*.json # All JSON files in config/
|
|
45
|
+
# - "!**/*.test.js" # Exclude test files
|
|
46
|
+
# - "!node_modules/**" # Exclude node_modules
|
|
47
|
+
|
|
48
|
+
# Optional: Environment variables
|
|
49
|
+
# Use \${VAR} syntax for build-time substitution via --env flag
|
|
50
|
+
# env:
|
|
51
|
+
# NODE_ENV: production
|
|
52
|
+
# API_URL: https://api.example.com
|
|
53
|
+
# SECRET_KEY: \${SECRET_KEY} # Substituted from: --env SECRET_KEY=value
|
|
54
|
+
|
|
55
|
+
# Optional: Custom metadata
|
|
56
|
+
# Use \${VAR} syntax for build-time substitution via --metadata flag
|
|
57
|
+
# Stored with the snapshot for reference
|
|
58
|
+
# metadata:
|
|
59
|
+
# version: \${VERSION} # Substituted from: --metadata VERSION=1.0.0
|
|
60
|
+
# author: team-name
|
|
61
|
+
# build_date: \${BUILD_DATE}
|
|
62
|
+
`;
|
|
63
|
+
|
|
64
|
+
const TEMPLATE_JSON = {
|
|
65
|
+
$schema: 'https://agentuity.dev/schema/cli/v1/agentuity-snapshot.json',
|
|
66
|
+
version: 1,
|
|
67
|
+
runtime: 'bun:1',
|
|
68
|
+
name: 'my-snapshot',
|
|
69
|
+
description: 'My sandbox snapshot',
|
|
70
|
+
dependencies: ['curl'],
|
|
71
|
+
files: ['src/**', '*.js', '!**/*.test.js'],
|
|
72
|
+
env: {
|
|
73
|
+
NODE_ENV: 'production',
|
|
74
|
+
},
|
|
75
|
+
metadata: {
|
|
76
|
+
version: '1.0.0',
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const GenerateResponseSchema = z.object({
|
|
81
|
+
format: z.enum(['yaml', 'json']).describe('Output format'),
|
|
82
|
+
content: z.string().describe('Generated template content'),
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
export const generateSubcommand = createCommand({
|
|
86
|
+
name: 'generate',
|
|
87
|
+
aliases: ['gen', 'init'],
|
|
88
|
+
description: 'Generate a template snapshot build file',
|
|
89
|
+
tags: [],
|
|
90
|
+
requires: {},
|
|
91
|
+
skipUpgradeCheck: true,
|
|
92
|
+
skipSkill: true,
|
|
93
|
+
examples: [
|
|
94
|
+
{
|
|
95
|
+
command: getCommand('cloud sandbox snapshot generate'),
|
|
96
|
+
description: 'Generate a YAML template (default)',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
command: getCommand('cloud sandbox snapshot generate --format json'),
|
|
100
|
+
description: 'Generate a JSON template',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
command: getCommand('cloud sandbox snapshot generate > agentuity-snapshot.yaml'),
|
|
104
|
+
description: 'Save template to a file',
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
schema: {
|
|
108
|
+
options: z.object({
|
|
109
|
+
format: z.enum(['yaml', 'json']).default('yaml').describe('Output format (yaml or json)'),
|
|
110
|
+
}),
|
|
111
|
+
response: GenerateResponseSchema,
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
async handler(ctx) {
|
|
115
|
+
const { opts, options } = ctx;
|
|
116
|
+
const format = opts.format;
|
|
117
|
+
|
|
118
|
+
let content: string;
|
|
119
|
+
if (format === 'json') {
|
|
120
|
+
content = JSON.stringify(TEMPLATE_JSON, null, 2);
|
|
121
|
+
} else {
|
|
122
|
+
content = TEMPLATE_YAML;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (!options.json) {
|
|
126
|
+
console.log(content);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
format,
|
|
131
|
+
content,
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
export default generateSubcommand;
|
|
@@ -21,6 +21,7 @@ const SandboxInfoSchema = z.object({
|
|
|
21
21
|
|
|
22
22
|
const SnapshotGetResponseSchema = z.object({
|
|
23
23
|
snapshotId: z.string().describe('Snapshot ID'),
|
|
24
|
+
name: z.string().describe('Snapshot name'),
|
|
24
25
|
tag: z.string().nullable().optional().describe('Snapshot tag'),
|
|
25
26
|
sizeBytes: z.number().describe('Snapshot size in bytes'),
|
|
26
27
|
fileCount: z.number().describe('Number of files'),
|
|
@@ -28,6 +29,11 @@ const SnapshotGetResponseSchema = z.object({
|
|
|
28
29
|
createdAt: z.string().describe('Creation timestamp'),
|
|
29
30
|
downloadUrl: z.string().optional().describe('Presigned download URL'),
|
|
30
31
|
files: z.array(SnapshotFileSchema).nullable().optional().describe('Files in snapshot'),
|
|
32
|
+
userMetadata: z
|
|
33
|
+
.record(z.string(), z.string())
|
|
34
|
+
.nullable()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe('User-defined metadata'),
|
|
31
37
|
sandboxes: z
|
|
32
38
|
.array(SandboxInfoSchema)
|
|
33
39
|
.optional()
|
|
@@ -72,15 +78,32 @@ export const getSubcommand = createCommand({
|
|
|
72
78
|
);
|
|
73
79
|
|
|
74
80
|
if (!options.json) {
|
|
75
|
-
|
|
81
|
+
const tableData: Record<string, string | number> = {
|
|
82
|
+
Snapshot: tui.bold(snapshot.snapshotId),
|
|
83
|
+
Name: snapshot.name,
|
|
84
|
+
};
|
|
76
85
|
if (snapshot.tag) {
|
|
77
|
-
|
|
86
|
+
tableData['Tag'] = snapshot.tag;
|
|
78
87
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
88
|
+
tableData['Size'] = tui.formatBytes(snapshot.sizeBytes);
|
|
89
|
+
tableData['Files'] = snapshot.fileCount;
|
|
90
|
+
tableData['Created'] = snapshot.createdAt;
|
|
82
91
|
if (snapshot.parentSnapshotId) {
|
|
83
|
-
|
|
92
|
+
tableData['Parent'] = snapshot.parentSnapshotId;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
tui.table([tableData], Object.keys(tableData), { layout: 'vertical', padStart: ' ' });
|
|
96
|
+
|
|
97
|
+
if (
|
|
98
|
+
snapshot.userMetadata &&
|
|
99
|
+
typeof snapshot.userMetadata === 'object' &&
|
|
100
|
+
Object.keys(snapshot.userMetadata).length > 0
|
|
101
|
+
) {
|
|
102
|
+
console.log('');
|
|
103
|
+
tui.info('Metadata:');
|
|
104
|
+
for (const [key, value] of Object.entries(snapshot.userMetadata)) {
|
|
105
|
+
console.log(` ${tui.muted('•')} ${key}=${value}`);
|
|
106
|
+
}
|
|
84
107
|
}
|
|
85
108
|
|
|
86
109
|
if (snapshot.files && snapshot.files.length > 0) {
|
|
@@ -4,6 +4,8 @@ import { listSubcommand } from './list';
|
|
|
4
4
|
import { getSubcommand } from './get';
|
|
5
5
|
import { deleteSubcommand } from './delete';
|
|
6
6
|
import { tagSubcommand } from './tag';
|
|
7
|
+
import { buildSubcommand } from './build';
|
|
8
|
+
import { generateSubcommand } from './generate';
|
|
7
9
|
import { getCommand } from '../../../../command-prefix';
|
|
8
10
|
|
|
9
11
|
export const snapshotCommand = createCommand({
|
|
@@ -20,8 +22,24 @@ export const snapshotCommand = createCommand({
|
|
|
20
22
|
command: getCommand('cloud sandbox snapshot list'),
|
|
21
23
|
description: 'List all snapshots',
|
|
22
24
|
},
|
|
25
|
+
{
|
|
26
|
+
command: getCommand('cloud sandbox snapshot build .'),
|
|
27
|
+
description: 'Build a snapshot from a declarative file',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
command: getCommand('cloud sandbox snapshot generate > agentuity-snapshot.yaml'),
|
|
31
|
+
description: 'Generate a template build file',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
subcommands: [
|
|
35
|
+
createSubcommand,
|
|
36
|
+
listSubcommand,
|
|
37
|
+
getSubcommand,
|
|
38
|
+
deleteSubcommand,
|
|
39
|
+
tagSubcommand,
|
|
40
|
+
buildSubcommand,
|
|
41
|
+
generateSubcommand,
|
|
23
42
|
],
|
|
24
|
-
subcommands: [createSubcommand, listSubcommand, getSubcommand, deleteSubcommand, tagSubcommand],
|
|
25
43
|
requires: { auth: true, org: true },
|
|
26
44
|
});
|
|
27
45
|
|
|
@@ -67,7 +67,7 @@ const SessionGetResponseSchema = z.object({
|
|
|
67
67
|
pending: z.boolean(),
|
|
68
68
|
success: z.boolean(),
|
|
69
69
|
error: z.string().nullable(),
|
|
70
|
-
result: z.string().nullable(),
|
|
70
|
+
result: z.record(z.string(), z.unknown()).nullable(),
|
|
71
71
|
})
|
|
72
72
|
)
|
|
73
73
|
.describe('Eval runs'),
|
|
@@ -171,48 +171,44 @@ export const getSubcommand = createSubcommand({
|
|
|
171
171
|
return result;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
const tableData: Record<string, string> = {
|
|
175
|
+
ID: session.id,
|
|
176
|
+
Project: session.project_id,
|
|
177
|
+
Deployment: session.deployment_id || '-',
|
|
178
|
+
Start: new Date(session.start_time).toLocaleString(),
|
|
179
|
+
};
|
|
178
180
|
if (session.end_time) {
|
|
179
|
-
|
|
181
|
+
tableData['End'] = new Date(session.end_time).toLocaleString();
|
|
180
182
|
}
|
|
181
|
-
if (session.duration && session.end_time) {
|
|
182
|
-
|
|
183
|
-
tui.bold('Duration: ') + `${(session.duration / 1_000_000).toFixed(0)}ms`
|
|
184
|
-
);
|
|
183
|
+
if (session.duration != null && session.end_time != null) {
|
|
184
|
+
tableData['Duration'] = `${(session.duration / 1_000_000).toFixed(0)}ms`;
|
|
185
185
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
tableData['Method'] = session.method;
|
|
187
|
+
tableData['URL'] = tui.link(session.url, session.url);
|
|
188
|
+
tableData['Trigger'] = session.trigger;
|
|
189
189
|
if (session.env !== 'production') {
|
|
190
|
-
|
|
190
|
+
tableData['Environment'] = session.env;
|
|
191
191
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
(session.success ? tui.colorSuccess('✓') : tui.colorError('✗'))
|
|
196
|
-
);
|
|
197
|
-
console.log(tui.bold('Pending: ') + (session.pending ? 'Yes' : 'No'));
|
|
192
|
+
tableData['Dev Mode'] = session.devmode ? 'Yes' : 'No';
|
|
193
|
+
tableData['Success'] = session.success ? tui.colorSuccess('✓') : tui.colorError('✗');
|
|
194
|
+
tableData['Pending'] = session.pending ? 'Yes' : 'No';
|
|
198
195
|
if (session.error) {
|
|
199
|
-
|
|
196
|
+
tableData['Error'] = tui.colorError(session.error);
|
|
200
197
|
}
|
|
201
198
|
if (enriched.agents.length > 0) {
|
|
202
|
-
|
|
199
|
+
tableData['Agents'] = enriched.agents
|
|
203
200
|
.map((agent: AgentInfo) => `${agent.name} ${tui.muted(`(${agent.identifier})`)}`)
|
|
204
201
|
.join(', ');
|
|
205
|
-
console.log(tui.bold('Agents: ') + agentDisplay);
|
|
206
202
|
}
|
|
207
203
|
if (enriched.route) {
|
|
208
|
-
|
|
209
|
-
tui.
|
|
210
|
-
`${enriched.route.method.toUpperCase()} ${enriched.route.path} ${tui.muted(`(${enriched.route.id})`)}`
|
|
211
|
-
);
|
|
204
|
+
tableData['Route'] =
|
|
205
|
+
`${enriched.route.method.toUpperCase()} ${enriched.route.path} ${tui.muted(`(${enriched.route.id})`)}`;
|
|
212
206
|
} else {
|
|
213
|
-
|
|
207
|
+
tableData['Route ID'] = session.route_id;
|
|
214
208
|
}
|
|
215
|
-
|
|
209
|
+
tableData['Thread ID'] = session.thread_id;
|
|
210
|
+
|
|
211
|
+
tui.table([tableData], Object.keys(tableData), { layout: 'vertical', padStart: ' ' });
|
|
216
212
|
|
|
217
213
|
if (enriched.evalRuns.length > 0) {
|
|
218
214
|
console.log('');
|
|
@@ -53,6 +53,10 @@ export const listSubcommand = createSubcommand({
|
|
|
53
53
|
command: getCommand('cloud session list --env=production'),
|
|
54
54
|
description: 'Only production environment',
|
|
55
55
|
},
|
|
56
|
+
{
|
|
57
|
+
command: getCommand('cloud session list --all'),
|
|
58
|
+
description: 'List all sessions regardless of project context',
|
|
59
|
+
},
|
|
56
60
|
],
|
|
57
61
|
aliases: ['ls'],
|
|
58
62
|
requires: { auth: true },
|
|
@@ -76,6 +80,7 @@ export const listSubcommand = createSubcommand({
|
|
|
76
80
|
.default(10)
|
|
77
81
|
.describe('Number of sessions to list (1–100)'),
|
|
78
82
|
projectId: z.string().optional().describe('Filter by project ID'),
|
|
83
|
+
all: z.boolean().optional().describe('List all sessions regardless of project context'),
|
|
79
84
|
deploymentId: z.string().optional().describe('Filter by deployment ID'),
|
|
80
85
|
trigger: z.string().optional().describe('Filter by trigger type (api, cron, webhook)'),
|
|
81
86
|
env: z.string().optional().describe('Filter by environment'),
|
|
@@ -89,14 +94,14 @@ export const listSubcommand = createSubcommand({
|
|
|
89
94
|
response: SessionListResponseSchema,
|
|
90
95
|
},
|
|
91
96
|
webUrl: (ctx) => {
|
|
92
|
-
const projectId = ctx.opts?.projectId || ctx.project?.projectId;
|
|
97
|
+
const projectId = ctx.opts?.all ? undefined : ctx.opts?.projectId || ctx.project?.projectId;
|
|
93
98
|
return projectId ? `/projects/${encodeURIComponent(projectId)}/sessions` : undefined;
|
|
94
99
|
},
|
|
95
100
|
async handler(ctx) {
|
|
96
101
|
const { logger, auth, project, opts, options, config } = ctx;
|
|
97
102
|
const catalystClient = await getGlobalCatalystAPIClient(logger, auth, config?.name);
|
|
98
103
|
|
|
99
|
-
const projectId = opts.projectId || project?.projectId;
|
|
104
|
+
const projectId = opts.all ? undefined : opts.projectId || project?.projectId;
|
|
100
105
|
|
|
101
106
|
try {
|
|
102
107
|
const sessions = await sessionList(catalystClient, {
|
|
@@ -59,21 +59,25 @@ export const getSubcommand = createSubcommand({
|
|
|
59
59
|
return result;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
62
|
+
const tableData: Record<string, string> = {
|
|
63
|
+
ID: thread.id,
|
|
64
|
+
Project: thread.project_id,
|
|
65
|
+
Created: new Date(thread.created_at).toLocaleString(),
|
|
66
|
+
Updated: new Date(thread.updated_at).toLocaleString(),
|
|
67
|
+
Deleted: thread.deleted ? 'Yes' : 'No',
|
|
68
|
+
};
|
|
67
69
|
if (thread.deleted_at) {
|
|
68
|
-
|
|
70
|
+
tableData['Deleted At'] = new Date(thread.deleted_at).toLocaleString();
|
|
69
71
|
}
|
|
70
72
|
if (thread.deleted_by) {
|
|
71
|
-
|
|
73
|
+
tableData['Deleted By'] = thread.deleted_by;
|
|
72
74
|
}
|
|
73
75
|
if (thread.user_data) {
|
|
74
|
-
|
|
76
|
+
tableData['User Data'] = thread.user_data;
|
|
75
77
|
}
|
|
76
78
|
|
|
79
|
+
tui.table([tableData], Object.keys(tableData), { layout: 'vertical', padStart: ' ' });
|
|
80
|
+
|
|
77
81
|
return result;
|
|
78
82
|
} catch (ex) {
|
|
79
83
|
if (ex instanceof APIError && ex.status === 404) {
|
|
@@ -34,6 +34,10 @@ export const listSubcommand = createSubcommand({
|
|
|
34
34
|
command: getCommand('cloud thread list --org-id=org_*'),
|
|
35
35
|
description: 'Filter by organization',
|
|
36
36
|
},
|
|
37
|
+
{
|
|
38
|
+
command: getCommand('cloud thread list --all'),
|
|
39
|
+
description: 'List all threads regardless of project context',
|
|
40
|
+
},
|
|
37
41
|
],
|
|
38
42
|
aliases: ['ls'],
|
|
39
43
|
requires: { auth: true },
|
|
@@ -58,6 +62,7 @@ export const listSubcommand = createSubcommand({
|
|
|
58
62
|
.describe('Number of threads to list (1–100)'),
|
|
59
63
|
orgId: z.string().optional().describe('Filter by organization ID'),
|
|
60
64
|
projectId: z.string().optional().describe('Filter by project ID'),
|
|
65
|
+
all: z.boolean().optional().describe('List all threads regardless of project context'),
|
|
61
66
|
}),
|
|
62
67
|
response: ThreadListResponseSchema,
|
|
63
68
|
},
|
|
@@ -65,7 +70,7 @@ export const listSubcommand = createSubcommand({
|
|
|
65
70
|
const { logger, auth, project, opts, options, config } = ctx;
|
|
66
71
|
const catalystClient = await getGlobalCatalystAPIClient(logger, auth, config?.name);
|
|
67
72
|
|
|
68
|
-
const projectId = opts.projectId || project?.projectId;
|
|
73
|
+
const projectId = opts.all ? undefined : opts.projectId || project?.projectId;
|
|
69
74
|
const orgId = opts.orgId;
|
|
70
75
|
|
|
71
76
|
try {
|
|
@@ -55,6 +55,7 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
|
|
|
55
55
|
'.idea',
|
|
56
56
|
'.DS_Store',
|
|
57
57
|
'.playwright',
|
|
58
|
+
'.bun',
|
|
58
59
|
'src/generated',
|
|
59
60
|
]);
|
|
60
61
|
|
|
@@ -76,6 +77,7 @@ export function createFileWatcher(options: FileWatcherOptions): FileWatcherManag
|
|
|
76
77
|
'.dist',
|
|
77
78
|
'.vscode',
|
|
78
79
|
'.idea',
|
|
80
|
+
'.bun',
|
|
79
81
|
'.DS_Store',
|
|
80
82
|
'.playwright',
|
|
81
83
|
'src/web', // Vite handles frontend with HMR - no backend restart needed
|
package/src/cmd/dev/index.ts
CHANGED
|
@@ -12,9 +12,10 @@ import { APIClient, getAPIBaseURL, getAppBaseURL, getGravityDevModeURL } from '.
|
|
|
12
12
|
import { download } from './download';
|
|
13
13
|
import { createDevmodeSyncService } from './sync';
|
|
14
14
|
import { getDevmodeDeploymentId } from '../build/ast';
|
|
15
|
-
import { getDefaultConfigDir, saveConfig, loadProjectSDKKey } from '../../config';
|
|
15
|
+
import { getDefaultConfigDir, saveConfig, loadProjectSDKKey, getAuth } from '../../config';
|
|
16
16
|
import type { Config } from '../../types';
|
|
17
17
|
import { typecheck } from '../build/typecheck';
|
|
18
|
+
import { isTTY, hasLoggedInBefore } from '../../auth';
|
|
18
19
|
import { createFileWatcher } from './file-watcher';
|
|
19
20
|
import { regenerateSkillsAsync } from './skills';
|
|
20
21
|
import { prepareDevLock, releaseLockSync } from './dev-lock';
|
|
@@ -171,12 +172,15 @@ export const command = createCommand({
|
|
|
171
172
|
.describe('The TCP port to start the dev server (also reads from PORT env)'),
|
|
172
173
|
}),
|
|
173
174
|
},
|
|
174
|
-
optional: {
|
|
175
|
+
optional: { project: true },
|
|
175
176
|
|
|
176
177
|
async handler(ctx) {
|
|
177
|
-
const { opts, logger, project, projectDir
|
|
178
|
+
const { opts, logger, project, projectDir } = ctx;
|
|
178
179
|
let { config } = ctx;
|
|
179
180
|
|
|
181
|
+
// Get auth state - we handle auth ourselves based on project state
|
|
182
|
+
let auth = await getAuth();
|
|
183
|
+
|
|
180
184
|
const rootDir = resolve(projectDir);
|
|
181
185
|
const appTs = join(rootDir, 'app.ts');
|
|
182
186
|
const srcDir = join(rootDir, 'src');
|
|
@@ -208,6 +212,71 @@ export const command = createCommand({
|
|
|
208
212
|
originalExit(1);
|
|
209
213
|
}
|
|
210
214
|
|
|
215
|
+
// Handle authentication state based on project registration
|
|
216
|
+
if (project) {
|
|
217
|
+
// Registered project (has agentuity.json) - check if user needs to login
|
|
218
|
+
const isValidAuth = auth && auth.expires > new Date();
|
|
219
|
+
if (!isValidAuth) {
|
|
220
|
+
if (isTTY()) {
|
|
221
|
+
const hasProfile = await hasLoggedInBefore();
|
|
222
|
+
const message = hasProfile
|
|
223
|
+
? 'Your session has expired or you are not logged in.'
|
|
224
|
+
: 'This project is registered with Agentuity Cloud but you are not logged in.';
|
|
225
|
+
|
|
226
|
+
tui.warning(message);
|
|
227
|
+
tui.newline();
|
|
228
|
+
|
|
229
|
+
const shouldLogin = await tui.confirm(
|
|
230
|
+
hasProfile ? 'Would you like to login now?' : 'Would you like to login or create an account?',
|
|
231
|
+
true
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
if (shouldLogin) {
|
|
235
|
+
tui.newline();
|
|
236
|
+
|
|
237
|
+
// Run login flow inline
|
|
238
|
+
const { loginCommand } = await import('../auth/login');
|
|
239
|
+
|
|
240
|
+
// Ensure apiClient is available for login handler
|
|
241
|
+
const loginCtx = ctx as unknown as Record<string, unknown>;
|
|
242
|
+
if (!loginCtx.apiClient) {
|
|
243
|
+
loginCtx.apiClient = new APIClient(getAPIBaseURL(config), logger, config);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (loginCommand.handler) {
|
|
247
|
+
await loginCommand.handler(
|
|
248
|
+
loginCtx as Parameters<NonNullable<typeof loginCommand.handler>>[0]
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Refresh auth state after login
|
|
253
|
+
const freshAuth = await getAuth();
|
|
254
|
+
if (!freshAuth || freshAuth.expires <= new Date()) {
|
|
255
|
+
tui.fatal('Login was not completed successfully.', ErrorCode.AUTH_FAILED);
|
|
256
|
+
}
|
|
257
|
+
auth = freshAuth;
|
|
258
|
+
tui.newline();
|
|
259
|
+
tui.success('Login successful! Continuing with dev server...');
|
|
260
|
+
tui.newline();
|
|
261
|
+
} else {
|
|
262
|
+
// User chose not to login - show warning about disabled features
|
|
263
|
+
tui.newline();
|
|
264
|
+
tui.showLoggedOutMessage(getAppBaseURL(config), hasProfile);
|
|
265
|
+
}
|
|
266
|
+
} else {
|
|
267
|
+
// Non-TTY: fatal error with instruction
|
|
268
|
+
logger.fatal(
|
|
269
|
+
`Authentication required for this project.\n` +
|
|
270
|
+
`Run "${getCommand('auth login')}" to login to Agentuity`,
|
|
271
|
+
ErrorCode.AUTH_REQUIRED
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
} else {
|
|
276
|
+
// No agentuity.json - local-only mode, ignore auth state
|
|
277
|
+
tui.showLocalOnlyWarning();
|
|
278
|
+
}
|
|
279
|
+
|
|
211
280
|
// Prepare dev lock: cleans up stale processes from previous sessions
|
|
212
281
|
// and creates a new lockfile for this session
|
|
213
282
|
const devLock = await prepareDevLock(rootDir, opts.port, logger);
|
|
@@ -229,7 +298,10 @@ export const command = createCommand({
|
|
|
229
298
|
try {
|
|
230
299
|
// Setup devmode and gravity (if using public URL)
|
|
231
300
|
const useMockService = process.env.DEVMODE_SYNC_SERVICE_MOCK === 'true';
|
|
232
|
-
|
|
301
|
+
// Create apiClient with fresh auth API key (important after inline login)
|
|
302
|
+
const apiClient = auth
|
|
303
|
+
? new APIClient(getAPIBaseURL(config), logger, auth.apiKey, config)
|
|
304
|
+
: null;
|
|
233
305
|
const syncService = apiClient
|
|
234
306
|
? createDevmodeSyncService({
|
|
235
307
|
logger,
|
|
@@ -262,7 +262,7 @@ export async function detectOrmSetup(projectDir: string): Promise<OrmSetup> {
|
|
|
262
262
|
* @returns SQL DDL statements for auth tables
|
|
263
263
|
*/
|
|
264
264
|
export async function generateAuthSchemaSql(logger: Logger, projectDir: string): Promise<string> {
|
|
265
|
-
const schemaPath = path.join(projectDir, 'node_modules/@agentuity/auth/
|
|
265
|
+
const schemaPath = path.join(projectDir, 'node_modules/@agentuity/auth/dist/schema.js');
|
|
266
266
|
|
|
267
267
|
if (!(await Bun.file(schemaPath).exists())) {
|
|
268
268
|
throw new Error(
|
|
@@ -342,11 +342,25 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<void> {
|
|
|
342
342
|
}
|
|
343
343
|
switch (choices.db_action) {
|
|
344
344
|
case 'Create New': {
|
|
345
|
+
const dbName = await prompt.text({
|
|
346
|
+
message: 'Database name',
|
|
347
|
+
hint: 'Optional - press Enter to auto-generate',
|
|
348
|
+
});
|
|
349
|
+
const dbDescription = await prompt.text({
|
|
350
|
+
message: 'Database description',
|
|
351
|
+
hint: 'Optional - press Enter to skip',
|
|
352
|
+
});
|
|
345
353
|
const created = await tui.spinner({
|
|
346
354
|
message: 'Provisioning New SQL Database',
|
|
347
355
|
clearOnSuccess: true,
|
|
348
356
|
callback: async () => {
|
|
349
|
-
return createResources(catalystClient, orgId, region!, [
|
|
357
|
+
return createResources(catalystClient, orgId, region!, [
|
|
358
|
+
{
|
|
359
|
+
type: 'db',
|
|
360
|
+
name: dbName || undefined,
|
|
361
|
+
description: dbDescription || undefined,
|
|
362
|
+
},
|
|
363
|
+
]);
|
|
350
364
|
},
|
|
351
365
|
});
|
|
352
366
|
// Collect env vars from newly created resource
|
package/src/cmd/setup/index.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createCommand } from '../../types';
|
|
3
|
+
import { hasLoggedInBefore } from '../../auth';
|
|
3
4
|
import { showBanner } from '../../banner';
|
|
4
5
|
import * as tui from '../../tui';
|
|
5
6
|
import { getCommand } from '../../command-prefix';
|
|
6
7
|
|
|
8
|
+
const validateToken = /[\d]{7,}\.[\w-_.]{22}/;
|
|
9
|
+
|
|
7
10
|
export const command = createCommand({
|
|
8
11
|
name: 'setup',
|
|
9
12
|
description: 'Display first-run setup information (internal use)',
|
|
@@ -11,22 +14,57 @@ export const command = createCommand({
|
|
|
11
14
|
skipUpgradeCheck: true,
|
|
12
15
|
skipSkill: true,
|
|
13
16
|
tags: ['read-only', 'fast'],
|
|
14
|
-
optional: { auth: true },
|
|
15
17
|
schema: {
|
|
16
18
|
options: z.object({
|
|
17
19
|
nonInteractive: z.boolean().optional().describe('Run in non-interactive mode'),
|
|
20
|
+
setupToken: z.string().optional().describe('Use a one-time use setup token'),
|
|
18
21
|
}),
|
|
19
22
|
},
|
|
20
23
|
|
|
21
24
|
async handler(ctx) {
|
|
22
|
-
const { opts
|
|
25
|
+
const { opts } = ctx;
|
|
23
26
|
const _nonInteractive = opts.nonInteractive ?? false;
|
|
24
27
|
|
|
28
|
+
// validate the one time setup token if provided
|
|
29
|
+
if (opts?.setupToken && opts.setupToken !== '-' && validateToken.test(opts.setupToken)) {
|
|
30
|
+
const [hours] = opts.setupToken.split('.');
|
|
31
|
+
const tokenInterval = Number(hours);
|
|
32
|
+
if (!Number.isNaN(tokenInterval)) {
|
|
33
|
+
const now = Math.round(Date.now() / (60_000 * 5));
|
|
34
|
+
if (tokenInterval === now || tokenInterval === now - 1) {
|
|
35
|
+
const ok = await tui.spinner({
|
|
36
|
+
message: 'Validating your identity',
|
|
37
|
+
clearOnSuccess: true,
|
|
38
|
+
callback: async () => {
|
|
39
|
+
const newargs = process.argv.map((x) => (x === 'setup' ? 'login' : x));
|
|
40
|
+
const r = Bun.spawn({
|
|
41
|
+
cmd: newargs.concat('--json'),
|
|
42
|
+
stdout: 'pipe',
|
|
43
|
+
stderr: 'inherit',
|
|
44
|
+
});
|
|
45
|
+
await r.exited;
|
|
46
|
+
try {
|
|
47
|
+
const res = JSON.parse(await r.stdout.text()) as { success: boolean };
|
|
48
|
+
return res.success;
|
|
49
|
+
} catch {
|
|
50
|
+
/* fall through */
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
if (ok) {
|
|
56
|
+
/* TODO */
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
25
63
|
tui.newline();
|
|
26
64
|
showBanner();
|
|
27
65
|
tui.newline();
|
|
28
66
|
|
|
29
|
-
if (!
|
|
67
|
+
if (!(await hasLoggedInBefore())) {
|
|
30
68
|
tui.output(`${tui.muted('To get started, run:')}`);
|
|
31
69
|
tui.newline();
|
|
32
70
|
tui.output(
|