@agentuity/cli 0.0.53 → 0.0.54
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 +66 -8
- package/dist/cli.js.map +1 -1
- package/dist/cmd/auth/ssh/add.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/add.js +28 -13
- package/dist/cmd/auth/ssh/add.js.map +1 -1
- package/dist/cmd/auth/ssh/delete.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/delete.js +28 -18
- package/dist/cmd/auth/ssh/delete.js.map +1 -1
- package/dist/cmd/auth/ssh/list.d.ts.map +1 -1
- package/dist/cmd/auth/ssh/list.js +5 -6
- package/dist/cmd/auth/ssh/list.js.map +1 -1
- package/dist/cmd/build/ast.d.ts +34 -0
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +159 -0
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/bundler.d.ts +2 -1
- package/dist/cmd/build/bundler.d.ts.map +1 -1
- package/dist/cmd/build/bundler.js +77 -16
- package/dist/cmd/build/bundler.js.map +1 -1
- package/dist/cmd/build/plugin.d.ts.map +1 -1
- package/dist/cmd/build/plugin.js +74 -4
- package/dist/cmd/build/plugin.js.map +1 -1
- package/dist/cmd/cloud/deployment/list.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/list.js +28 -23
- package/dist/cmd/cloud/deployment/list.js.map +1 -1
- package/dist/cmd/cloud/deployment/show.d.ts.map +1 -1
- package/dist/cmd/cloud/deployment/show.js +50 -47
- package/dist/cmd/cloud/deployment/show.js.map +1 -1
- package/dist/cmd/cloud/env/get.d.ts.map +1 -1
- package/dist/cmd/cloud/env/get.js +16 -14
- package/dist/cmd/cloud/env/get.js.map +1 -1
- package/dist/cmd/cloud/env/list.d.ts.map +1 -1
- package/dist/cmd/cloud/env/list.js +24 -20
- package/dist/cmd/cloud/env/list.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/get.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/get.js +18 -16
- package/dist/cmd/cloud/keyvalue/get.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/keys.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/keys.js +11 -11
- package/dist/cmd/cloud/keyvalue/keys.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/list-namespaces.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/list-namespaces.js +11 -7
- package/dist/cmd/cloud/keyvalue/list-namespaces.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/search.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/search.js +16 -17
- package/dist/cmd/cloud/keyvalue/search.js.map +1 -1
- package/dist/cmd/cloud/keyvalue/stats.d.ts.map +1 -1
- package/dist/cmd/cloud/keyvalue/stats.js +38 -23
- package/dist/cmd/cloud/keyvalue/stats.js.map +1 -1
- package/dist/cmd/cloud/objectstore/get.d.ts.map +1 -1
- package/dist/cmd/cloud/objectstore/get.js +17 -15
- package/dist/cmd/cloud/objectstore/get.js.map +1 -1
- package/dist/cmd/cloud/objectstore/list-buckets.d.ts.map +1 -1
- package/dist/cmd/cloud/objectstore/list-buckets.js +12 -8
- package/dist/cmd/cloud/objectstore/list-buckets.js.map +1 -1
- package/dist/cmd/cloud/objectstore/list-keys.d.ts.map +1 -1
- package/dist/cmd/cloud/objectstore/list-keys.js +13 -10
- package/dist/cmd/cloud/objectstore/list-keys.js.map +1 -1
- package/dist/cmd/cloud/resource/list.d.ts.map +1 -1
- package/dist/cmd/cloud/resource/list.js +38 -27
- package/dist/cmd/cloud/resource/list.js.map +1 -1
- package/dist/cmd/cloud/secret/get.d.ts.map +1 -1
- package/dist/cmd/cloud/secret/get.js +17 -15
- package/dist/cmd/cloud/secret/get.js.map +1 -1
- package/dist/cmd/cloud/secret/list.d.ts.map +1 -1
- package/dist/cmd/cloud/secret/list.js +24 -20
- package/dist/cmd/cloud/secret/list.js.map +1 -1
- package/dist/cmd/cloud/session/logs.d.ts.map +1 -1
- package/dist/cmd/cloud/session/logs.js +18 -15
- package/dist/cmd/cloud/session/logs.js.map +1 -1
- package/dist/cmd/dev/agents.d.ts.map +1 -1
- package/dist/cmd/dev/agents.js +55 -41
- package/dist/cmd/dev/agents.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +2 -0
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/profile/create.js +1 -1
- package/dist/cmd/profile/create.js.map +1 -1
- package/dist/cmd/profile/delete.d.ts.map +1 -1
- package/dist/cmd/profile/delete.js +1 -1
- package/dist/cmd/profile/delete.js.map +1 -1
- package/dist/cmd/profile/list.d.ts.map +1 -1
- package/dist/cmd/profile/list.js +29 -11
- package/dist/cmd/profile/list.js.map +1 -1
- package/dist/cmd/profile/show.d.ts.map +1 -1
- package/dist/cmd/profile/show.js +7 -10
- package/dist/cmd/profile/show.js.map +1 -1
- package/dist/cmd/project/delete.js +1 -1
- package/dist/cmd/project/delete.js.map +1 -1
- package/dist/cmd/version/index.d.ts.map +1 -1
- package/dist/cmd/version/index.js +1 -1
- package/dist/cmd/version/index.js.map +1 -1
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +3 -1
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +32 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +3 -3
- package/src/cli.ts +109 -8
- package/src/cmd/auth/ssh/add.ts +37 -17
- package/src/cmd/auth/ssh/delete.ts +36 -23
- package/src/cmd/auth/ssh/list.ts +8 -6
- package/src/cmd/build/ast.ts +203 -0
- package/src/cmd/build/bundler.ts +81 -15
- package/src/cmd/build/plugin.ts +92 -4
- package/src/cmd/cloud/deployment/list.ts +30 -26
- package/src/cmd/cloud/deployment/show.ts +47 -42
- package/src/cmd/cloud/env/get.ts +14 -12
- package/src/cmd/cloud/env/list.ts +24 -22
- package/src/cmd/cloud/keyvalue/get.ts +19 -14
- package/src/cmd/cloud/keyvalue/keys.ts +10 -12
- package/src/cmd/cloud/keyvalue/list-namespaces.ts +10 -8
- package/src/cmd/cloud/keyvalue/search.ts +14 -17
- package/src/cmd/cloud/keyvalue/stats.ts +52 -28
- package/src/cmd/cloud/objectstore/get.ts +18 -13
- package/src/cmd/cloud/objectstore/list-buckets.ts +11 -9
- package/src/cmd/cloud/objectstore/list-keys.ts +12 -11
- package/src/cmd/cloud/resource/list.ts +33 -23
- package/src/cmd/cloud/secret/get.ts +15 -13
- package/src/cmd/cloud/secret/list.ts +24 -22
- package/src/cmd/cloud/session/logs.ts +18 -17
- package/src/cmd/dev/agents.ts +70 -50
- package/src/cmd/dev/index.ts +2 -0
- package/src/cmd/profile/create.ts +3 -3
- package/src/cmd/profile/delete.ts +5 -2
- package/src/cmd/profile/list.ts +31 -11
- package/src/cmd/profile/show.ts +15 -12
- package/src/cmd/project/delete.ts +1 -1
- package/src/cmd/version/index.ts +5 -1
- package/src/tui.ts +3 -1
- package/src/types.ts +32 -10
package/src/cmd/build/bundler.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { $ } from 'bun';
|
|
2
2
|
import { join, relative, resolve, dirname } from 'node:path';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
3
4
|
import { cpSync, existsSync, mkdirSync, rmSync } from 'node:fs';
|
|
4
5
|
import gitParseUrl from 'git-url-parse';
|
|
5
6
|
import AgentuityBundler, { getBuildMetadata } from './plugin';
|
|
@@ -7,6 +8,8 @@ import { getFilesRecursively } from './file';
|
|
|
7
8
|
import { getVersion } from '../../version';
|
|
8
9
|
import type { Project } from '../../types';
|
|
9
10
|
import { fixDuplicateExportsInDirectory } from './fix-duplicate-exports';
|
|
11
|
+
import { createLogger } from '@agentuity/server';
|
|
12
|
+
import type { LogLevel } from '../../types';
|
|
10
13
|
|
|
11
14
|
export interface BundleOptions {
|
|
12
15
|
rootDir: string;
|
|
@@ -16,6 +19,7 @@ export interface BundleOptions {
|
|
|
16
19
|
projectId?: string;
|
|
17
20
|
deploymentId?: string;
|
|
18
21
|
project?: Project;
|
|
22
|
+
port?: number;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
export async function bundle({
|
|
@@ -25,6 +29,7 @@ export async function bundle({
|
|
|
25
29
|
dev = false,
|
|
26
30
|
rootDir,
|
|
27
31
|
project,
|
|
32
|
+
port,
|
|
28
33
|
}: BundleOptions) {
|
|
29
34
|
const appFile = join(rootDir, 'app.ts');
|
|
30
35
|
if (!existsSync(appFile)) {
|
|
@@ -246,26 +251,87 @@ export async function bundle({
|
|
|
246
251
|
}
|
|
247
252
|
}
|
|
248
253
|
})();
|
|
254
|
+
}
|
|
249
255
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
256
|
+
// Bundle workbench app if detected via setupWorkbench
|
|
257
|
+
const { analyzeWorkbench } = await import('./ast');
|
|
258
|
+
if (existsSync(appFile)) {
|
|
259
|
+
const appContent = await Bun.file(appFile).text();
|
|
260
|
+
const analysis = await analyzeWorkbench(appContent);
|
|
261
|
+
|
|
262
|
+
if (analysis.hasWorkbench) {
|
|
263
|
+
// Encode workbench config for environment variable
|
|
264
|
+
const { encodeWorkbenchConfig } = await import('@agentuity/core');
|
|
265
|
+
const config = analysis.config || { route: '/workbench', headers: {} };
|
|
266
|
+
// Add port to config (defaults to 3500 if not provided)
|
|
267
|
+
const configWithPort = { ...config, port: port || 3500 };
|
|
268
|
+
const encodedConfig = encodeWorkbenchConfig(configWithPort);
|
|
269
|
+
const workbenchDefine = {
|
|
270
|
+
...define,
|
|
271
|
+
AGENTUITY_WORKBENCH_CONFIG_INLINE: JSON.stringify(encodedConfig),
|
|
272
|
+
};
|
|
273
|
+
const logger = createLogger((process.env.AGENTUITY_LOG_LEVEL as LogLevel) || 'info');
|
|
274
|
+
try {
|
|
275
|
+
const projectRequire = createRequire(resolve(rootDir, 'package.json'));
|
|
276
|
+
const workbenchPkgPath = projectRequire.resolve('@agentuity/workbench/package.json');
|
|
277
|
+
const workbenchAppDir = join(dirname(workbenchPkgPath), 'src', 'app');
|
|
278
|
+
|
|
279
|
+
if (existsSync(workbenchAppDir)) {
|
|
280
|
+
const workbenchIndexFile = join(workbenchAppDir, 'index.html');
|
|
281
|
+
if (existsSync(workbenchIndexFile)) {
|
|
282
|
+
// Bundle workbench using same config as main web app
|
|
283
|
+
const workbenchBuildConfig: Bun.BuildConfig = {
|
|
284
|
+
entrypoints: [workbenchIndexFile],
|
|
285
|
+
root: workbenchAppDir,
|
|
286
|
+
outdir: join(outDir, 'workbench'),
|
|
287
|
+
define: workbenchDefine,
|
|
288
|
+
sourcemap: dev ? 'inline' : 'linked',
|
|
289
|
+
plugins: [AgentuityBundler],
|
|
290
|
+
target: 'browser',
|
|
291
|
+
format: 'esm',
|
|
292
|
+
banner: `// Generated file. DO NOT EDIT`,
|
|
293
|
+
minify: true,
|
|
294
|
+
splitting: true,
|
|
295
|
+
packages: 'bundle',
|
|
296
|
+
naming: {
|
|
297
|
+
entry: '[dir]/[name].[ext]',
|
|
298
|
+
chunk: 'workbench/chunk/[name]-[hash].[ext]',
|
|
299
|
+
asset: 'workbench/asset/[name]-[hash].[ext]',
|
|
300
|
+
},
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
const workbenchResult = await Bun.build(workbenchBuildConfig);
|
|
304
|
+
if (workbenchResult.success) {
|
|
305
|
+
logger.debug('Workbench bundled successfully');
|
|
306
|
+
} else {
|
|
307
|
+
logger.error('Workbench bundling failed:', workbenchResult.logs.join('\n'));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
} catch (error) {
|
|
312
|
+
logger.error('Failed to bundle workbench:', error);
|
|
265
313
|
}
|
|
266
314
|
}
|
|
267
315
|
}
|
|
268
316
|
|
|
317
|
+
if (!dev && buildmetadata) {
|
|
318
|
+
const webPublicDir = join(webDir, 'public');
|
|
319
|
+
if (existsSync(webPublicDir)) {
|
|
320
|
+
const assets = buildmetadata.assets;
|
|
321
|
+
const webOutPublicDir = join(outDir, 'web', 'public');
|
|
322
|
+
cpSync(webPublicDir, webOutPublicDir, { recursive: true });
|
|
323
|
+
[...new Bun.Glob('**.*').scanSync(webOutPublicDir)].forEach((f) => {
|
|
324
|
+
const bf = Bun.file(join(webOutPublicDir, f));
|
|
325
|
+
assets.push({
|
|
326
|
+
filename: join('public', f),
|
|
327
|
+
kind: 'static',
|
|
328
|
+
contentType: bf.type,
|
|
329
|
+
size: bf.size,
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
269
335
|
if (!dev && Bun.which('git') && buildmetadata?.deployment) {
|
|
270
336
|
buildmetadata.deployment.git = {
|
|
271
337
|
commit: process.env.GIT_SHA || process.env.GITHUB_SHA,
|
package/src/cmd/build/plugin.ts
CHANGED
|
@@ -2,7 +2,14 @@ import type { BunPlugin } from 'bun';
|
|
|
2
2
|
import { dirname, basename, join, resolve } from 'node:path';
|
|
3
3
|
import { existsSync, writeFileSync, mkdirSync, unlinkSync } from 'node:fs';
|
|
4
4
|
import type { BuildMetadata } from '@agentuity/server';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
parseAgentMetadata,
|
|
7
|
+
parseRoute,
|
|
8
|
+
parseEvalMetadata,
|
|
9
|
+
analyzeWorkbench,
|
|
10
|
+
checkRouteConflicts,
|
|
11
|
+
type WorkbenchConfig,
|
|
12
|
+
} from './ast';
|
|
6
13
|
import { applyPatch, generatePatches } from './patch';
|
|
7
14
|
import { detectSubagent } from '../../utils/detectSubagent';
|
|
8
15
|
import { createLogger } from '@agentuity/server';
|
|
@@ -19,6 +26,50 @@ function toPascalCase(str: string): string {
|
|
|
19
26
|
return camel.charAt(0).toUpperCase() + camel.slice(1);
|
|
20
27
|
}
|
|
21
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Setup workbench configuration by analyzing app.ts file
|
|
31
|
+
*/
|
|
32
|
+
async function setupWorkbench(srcDir: string): Promise<WorkbenchConfig | null> {
|
|
33
|
+
// Look for app.ts in both root and src directories
|
|
34
|
+
const rootAppFile = join(dirname(srcDir), 'app.ts');
|
|
35
|
+
const srcAppFile = join(srcDir, 'app.ts');
|
|
36
|
+
|
|
37
|
+
let appFile = '';
|
|
38
|
+
if (existsSync(rootAppFile)) {
|
|
39
|
+
appFile = rootAppFile;
|
|
40
|
+
} else if (existsSync(srcAppFile)) {
|
|
41
|
+
appFile = srcAppFile;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!appFile || !existsSync(appFile)) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const appContent = await Bun.file(appFile).text();
|
|
49
|
+
const analysis = await analyzeWorkbench(appContent);
|
|
50
|
+
|
|
51
|
+
if (!analysis.hasWorkbench) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const workbenchConfig = analysis.config;
|
|
56
|
+
|
|
57
|
+
// Check for route conflicts if workbench is being used
|
|
58
|
+
if (workbenchConfig?.route) {
|
|
59
|
+
const hasConflict = await checkRouteConflicts(appContent, workbenchConfig.route);
|
|
60
|
+
if (hasConflict) {
|
|
61
|
+
const logger = createLogger((process.env.AGENTUITY_LOG_LEVEL as LogLevel) || 'info');
|
|
62
|
+
logger.error(`🚨 Route conflict detected!\n`);
|
|
63
|
+
logger.error(
|
|
64
|
+
` Workbench route '${workbenchConfig.route}' conflicts with existing application route`
|
|
65
|
+
);
|
|
66
|
+
logger.error(` Please use a different route or remove the conflicting route.\n`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return workbenchConfig;
|
|
71
|
+
}
|
|
72
|
+
|
|
22
73
|
function generateAgentRegistry(srcDir: string, agentInfo: Array<Record<string, string>>) {
|
|
23
74
|
// Separate parent agents and subagents
|
|
24
75
|
const parentAgents = agentInfo.filter((a) => !a.parent);
|
|
@@ -226,7 +277,6 @@ ${typeExports}
|
|
|
226
277
|
// Augment @agentuity/runtime types with strongly-typed agents from this project
|
|
227
278
|
declare module "@agentuity/runtime" {
|
|
228
279
|
// Augment the AgentRegistry interface with project-specific strongly-typed agents
|
|
229
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
230
280
|
export interface AgentRegistry {
|
|
231
281
|
${runtimeAgentTypes}
|
|
232
282
|
}
|
|
@@ -291,6 +341,10 @@ const AgentuityBundler: BunPlugin = {
|
|
|
291
341
|
const deploymentId = build.config.define?.['process.env.AGENTUITY_CLOUD_DEPLOYMENT_ID']
|
|
292
342
|
? JSON.parse(build.config.define['process.env.AGENTUITY_CLOUD_DEPLOYMENT_ID'])
|
|
293
343
|
: '';
|
|
344
|
+
const isDevMode =
|
|
345
|
+
(build.config.define?.['process.env.NODE_ENV']
|
|
346
|
+
? JSON.parse(build.config.define['process.env.NODE_ENV'])
|
|
347
|
+
: 'production') === 'development';
|
|
294
348
|
const routes: Set<string> = new Set();
|
|
295
349
|
const agentInfo: Array<Record<string, string>> = [];
|
|
296
350
|
const agentMetadata: Map<string, Map<string, string>> = new Map<
|
|
@@ -493,11 +547,45 @@ const AgentuityBundler: BunPlugin = {
|
|
|
493
547
|
const indexFile = join(srcDir, 'web', 'index.html');
|
|
494
548
|
|
|
495
549
|
if (existsSync(indexFile)) {
|
|
550
|
+
// Setup workbench configuration - evaluate fresh each time during builds
|
|
551
|
+
const workbenchConfig = await setupWorkbench(srcDir);
|
|
552
|
+
|
|
496
553
|
inserts.unshift(`await (async () => {
|
|
497
554
|
const { serveStatic } = require('hono/bun');
|
|
498
|
-
const { getRouter } = await import('@agentuity/runtime');
|
|
555
|
+
const { getRouter, registerDevModeRoutes } = await import('@agentuity/runtime');
|
|
499
556
|
const router = getRouter()!;
|
|
500
|
-
|
|
557
|
+
|
|
558
|
+
// Setup workbench routes if workbench was bundled
|
|
559
|
+
const workbenchIndexPath = import.meta.dir + '/workbench/index.html';
|
|
560
|
+
if (await Bun.file(workbenchIndexPath).exists()) {
|
|
561
|
+
let workbenchIndex = await Bun.file(workbenchIndexPath).text();
|
|
562
|
+
|
|
563
|
+
// Always serve assets at /workbench/* regardless of HTML route
|
|
564
|
+
const workbenchStatic = serveStatic({ root: import.meta.dir + '/workbench' });
|
|
565
|
+
router.get('/workbench/*', workbenchStatic);
|
|
566
|
+
|
|
567
|
+
// Use the workbench config determined at build time
|
|
568
|
+
const route = ${JSON.stringify(workbenchConfig?.route || '/workbench')};
|
|
569
|
+
|
|
570
|
+
// If using custom route, update HTML to point to absolute /workbench/ paths
|
|
571
|
+
if (route !== '/workbench') {
|
|
572
|
+
workbenchIndex = workbenchIndex.replace(new RegExp('src="\\\\.\\\\/workbench\\\\/', 'g'), 'src="/workbench/');
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Serve HTML at the configured route
|
|
576
|
+
router.get(route, (c) => c.html(workbenchIndex));
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
let index = await Bun.file(import.meta.dir + '/web/index.html').text();
|
|
580
|
+
if (${isDevMode}) {
|
|
581
|
+
const end = index.lastIndexOf('</html>');
|
|
582
|
+
const html = registerDevModeRoutes(router);
|
|
583
|
+
if (end > 0) {
|
|
584
|
+
index = index.substring(0,end) + html + index.substring(end);
|
|
585
|
+
} else {
|
|
586
|
+
index += html;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
501
589
|
const webstatic = serveStatic({ root: import.meta.dir + '/web' });
|
|
502
590
|
router.get('/', (c) => c.html(index));
|
|
503
591
|
router.get('/web/chunk/*', webstatic);
|
|
@@ -53,42 +53,46 @@ export const listSubcommand = createSubcommand({
|
|
|
53
53
|
},
|
|
54
54
|
async handler(ctx) {
|
|
55
55
|
const projectId = resolveProjectId(ctx, { projectId: ctx.opts['project-id'] });
|
|
56
|
-
const { apiClient, opts } = ctx;
|
|
56
|
+
const { apiClient, opts, options } = ctx;
|
|
57
57
|
|
|
58
58
|
try {
|
|
59
59
|
const deployments = await projectDeploymentList(apiClient, projectId, opts.count);
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
tui.info('No deployments found.');
|
|
63
|
-
return [];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const tableData = deployments.map((d) => ({
|
|
67
|
-
ID: d.id,
|
|
68
|
-
State: d.state || 'unknown',
|
|
69
|
-
Active: d.active ? 'Yes' : '',
|
|
70
|
-
Created: new Date(d.createdAt).toLocaleString(),
|
|
71
|
-
Message: d.message || '',
|
|
72
|
-
Tags: d.tags.join(', '),
|
|
73
|
-
}));
|
|
74
|
-
|
|
75
|
-
tui.table(tableData, [
|
|
76
|
-
{ name: 'ID', alignment: 'left' },
|
|
77
|
-
{ name: 'State', alignment: 'left' },
|
|
78
|
-
{ name: 'Active', alignment: 'center' },
|
|
79
|
-
{ name: 'Created', alignment: 'left' },
|
|
80
|
-
{ name: 'Message', alignment: 'left' },
|
|
81
|
-
{ name: 'Tags', alignment: 'left' },
|
|
82
|
-
]);
|
|
83
|
-
|
|
84
|
-
return deployments.map((d) => ({
|
|
61
|
+
const result = deployments.map((d) => ({
|
|
85
62
|
id: d.id,
|
|
86
63
|
state: d.state,
|
|
87
64
|
active: d.active,
|
|
88
65
|
createdAt: d.createdAt,
|
|
89
|
-
message: d.message,
|
|
66
|
+
message: d.message ?? undefined,
|
|
90
67
|
tags: d.tags,
|
|
91
68
|
}));
|
|
69
|
+
|
|
70
|
+
// Skip TUI output in JSON mode
|
|
71
|
+
if (!options.json) {
|
|
72
|
+
if (deployments.length === 0) {
|
|
73
|
+
tui.info('No deployments found.');
|
|
74
|
+
} else {
|
|
75
|
+
const tableData = deployments.map((d) => ({
|
|
76
|
+
ID: d.id,
|
|
77
|
+
State: d.state || 'unknown',
|
|
78
|
+
Active: d.active ? 'Yes' : '',
|
|
79
|
+
Created: new Date(d.createdAt).toLocaleString(),
|
|
80
|
+
Message: d.message || '',
|
|
81
|
+
Tags: d.tags.join(', '),
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
tui.table(tableData, [
|
|
85
|
+
{ name: 'ID', alignment: 'left' },
|
|
86
|
+
{ name: 'State', alignment: 'left' },
|
|
87
|
+
{ name: 'Active', alignment: 'center' },
|
|
88
|
+
{ name: 'Created', alignment: 'left' },
|
|
89
|
+
{ name: 'Message', alignment: 'left' },
|
|
90
|
+
{ name: 'Tags', alignment: 'left' },
|
|
91
|
+
]);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return result;
|
|
92
96
|
} catch (ex) {
|
|
93
97
|
tui.fatal(
|
|
94
98
|
`Failed to list deployments: ${ex instanceof Error ? ex.message : String(ex)}`,
|
|
@@ -42,63 +42,68 @@ export const showSubcommand = createSubcommand({
|
|
|
42
42
|
idempotent: true,
|
|
43
43
|
async handler(ctx) {
|
|
44
44
|
const projectId = resolveProjectId(ctx, { projectId: ctx.opts['project-id'] });
|
|
45
|
-
const { apiClient, args } = ctx;
|
|
45
|
+
const { apiClient, args, options } = ctx;
|
|
46
46
|
|
|
47
47
|
try {
|
|
48
48
|
const deployment = await projectDeploymentGet(apiClient, projectId, args.deployment_id);
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
// Skip TUI output in JSON mode
|
|
51
|
+
if (!options.json) {
|
|
52
|
+
tui.banner(`Deployment ${deployment.id}`, `State: ${deployment.state || 'unknown'}`);
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
54
|
+
console.log(tui.bold('ID: ') + deployment.id);
|
|
55
|
+
console.log(tui.bold('Project: ') + projectId);
|
|
56
|
+
console.log(tui.bold('State: ') + (deployment.state || 'unknown'));
|
|
57
|
+
console.log(tui.bold('Active: ') + (deployment.active ? 'Yes' : 'No'));
|
|
58
|
+
console.log(tui.bold('Created: ') + new Date(deployment.createdAt).toLocaleString());
|
|
59
|
+
if (deployment.updatedAt) {
|
|
60
|
+
console.log(
|
|
61
|
+
tui.bold('Updated: ') + new Date(deployment.updatedAt).toLocaleString()
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
if (deployment.message) {
|
|
65
|
+
console.log(tui.bold('Message: ') + deployment.message);
|
|
66
|
+
}
|
|
67
|
+
if (deployment.tags.length > 0) {
|
|
68
|
+
console.log(tui.bold('Tags: ') + deployment.tags.join(', '));
|
|
69
|
+
}
|
|
70
|
+
if (deployment.customDomains && deployment.customDomains.length > 0) {
|
|
71
|
+
console.log(tui.bold('Domains: ') + deployment.customDomains.join(', '));
|
|
72
|
+
}
|
|
73
|
+
if (deployment.cloudRegion) {
|
|
74
|
+
console.log(tui.bold('Region: ') + deployment.cloudRegion);
|
|
75
|
+
}
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
// Metadata
|
|
78
|
+
const origin = deployment.metadata?.origin;
|
|
79
|
+
if (origin?.commit) {
|
|
80
|
+
tui.newline();
|
|
81
|
+
tui.info('Origin Information');
|
|
82
|
+
if (origin.trigger) console.log(` Trigger: ${origin.trigger}`);
|
|
83
|
+
if (origin.provider) console.log(` Provider: ${origin.provider}`);
|
|
84
|
+
if (origin.event) console.log(` Event: ${origin.event}`);
|
|
85
|
+
if (origin.branch) console.log(` Branch: ${origin.branch}`);
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
if (origin.commit) {
|
|
88
|
+
console.log(` Commit: ${origin.commit.hash}`);
|
|
89
|
+
if (origin.commit.message) console.log(` Message: ${origin.commit.message}`);
|
|
90
|
+
if (origin.commit.author?.name)
|
|
91
|
+
console.log(` Author: ${origin.commit.author.name}`);
|
|
92
|
+
}
|
|
88
93
|
}
|
|
89
94
|
}
|
|
90
95
|
|
|
91
96
|
return {
|
|
92
97
|
id: deployment.id,
|
|
93
|
-
state: deployment.state,
|
|
98
|
+
state: deployment.state ?? undefined,
|
|
94
99
|
active: deployment.active,
|
|
95
100
|
createdAt: deployment.createdAt,
|
|
96
|
-
updatedAt: deployment.updatedAt,
|
|
97
|
-
message: deployment.message,
|
|
101
|
+
updatedAt: deployment.updatedAt ?? undefined,
|
|
102
|
+
message: deployment.message ?? undefined,
|
|
98
103
|
tags: deployment.tags,
|
|
99
|
-
customDomains: deployment.customDomains,
|
|
100
|
-
cloudRegion: deployment.cloudRegion,
|
|
101
|
-
metadata: deployment.metadata,
|
|
104
|
+
customDomains: deployment.customDomains ?? undefined,
|
|
105
|
+
cloudRegion: deployment.cloudRegion ?? undefined,
|
|
106
|
+
metadata: deployment.metadata ?? undefined,
|
|
102
107
|
};
|
|
103
108
|
} catch (ex) {
|
|
104
109
|
tui.fatal(`Failed to show deployment: ${ex instanceof Error ? ex.message : String(ex)}`);
|
package/src/cmd/cloud/env/get.ts
CHANGED
|
@@ -32,7 +32,7 @@ export const getSubcommand = createSubcommand({
|
|
|
32
32
|
idempotent: true,
|
|
33
33
|
|
|
34
34
|
async handler(ctx) {
|
|
35
|
-
const { args, opts, apiClient, project } = ctx;
|
|
35
|
+
const { args, opts, apiClient, project, options } = ctx;
|
|
36
36
|
|
|
37
37
|
// Fetch project with unmasked secrets
|
|
38
38
|
const projectData = await tui.spinner('Fetching environment variables', () => {
|
|
@@ -46,18 +46,20 @@ export const getSubcommand = createSubcommand({
|
|
|
46
46
|
tui.fatal(`Environment variable '${args.key}' not found`, ErrorCode.RESOURCE_NOT_FOUND);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (
|
|
52
|
-
|
|
49
|
+
if (!options.json) {
|
|
50
|
+
// Display the value, masked if requested
|
|
51
|
+
if (process.stdout.isTTY) {
|
|
52
|
+
if (opts?.mask) {
|
|
53
|
+
tui.success(`${args.key}=${maskSecret(value)}`);
|
|
54
|
+
} else {
|
|
55
|
+
tui.success(`${args.key}=${value}`);
|
|
56
|
+
}
|
|
53
57
|
} else {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
} else {
|
|
60
|
-
console.log(`${args.key}=${value}`);
|
|
58
|
+
if (opts?.mask) {
|
|
59
|
+
console.log(`${args.key}=${maskSecret(value)}`);
|
|
60
|
+
} else {
|
|
61
|
+
console.log(`${args.key}=${value}`);
|
|
62
|
+
}
|
|
61
63
|
}
|
|
62
64
|
}
|
|
63
65
|
|
|
@@ -29,7 +29,7 @@ export const listSubcommand = createSubcommand({
|
|
|
29
29
|
},
|
|
30
30
|
|
|
31
31
|
async handler(ctx) {
|
|
32
|
-
const { opts, apiClient, project } = ctx;
|
|
32
|
+
const { opts, apiClient, project, options } = ctx;
|
|
33
33
|
|
|
34
34
|
// Fetch project with unmasked secrets
|
|
35
35
|
const projectData = await tui.spinner('Fetching environment variables', () => {
|
|
@@ -38,28 +38,30 @@ export const listSubcommand = createSubcommand({
|
|
|
38
38
|
|
|
39
39
|
const env = projectData.env || {};
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// Display the variables
|
|
47
|
-
if (process.stdout.isTTY) {
|
|
48
|
-
tui.newline();
|
|
49
|
-
tui.info(`Environment Variables (${Object.keys(env).length}):`);
|
|
50
|
-
tui.newline();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const sortedKeys = Object.keys(env).sort();
|
|
54
|
-
// For env vars, masking should be explicitly opted-in (default false)
|
|
55
|
-
const shouldMask = opts?.mask === true;
|
|
56
|
-
for (const key of sortedKeys) {
|
|
57
|
-
const value = env[key];
|
|
58
|
-
const displayValue = shouldMask ? maskSecret(value) : value;
|
|
59
|
-
if (process.stdout.isTTY) {
|
|
60
|
-
console.log(`${tui.bold(key)}=${displayValue}`);
|
|
41
|
+
// Skip TUI output in JSON mode
|
|
42
|
+
if (!options.json) {
|
|
43
|
+
if (Object.keys(env).length === 0) {
|
|
44
|
+
tui.info('No environment variables found');
|
|
61
45
|
} else {
|
|
62
|
-
|
|
46
|
+
// Display the variables
|
|
47
|
+
if (process.stdout.isTTY) {
|
|
48
|
+
tui.newline();
|
|
49
|
+
tui.info(`Environment Variables (${Object.keys(env).length}):`);
|
|
50
|
+
tui.newline();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const sortedKeys = Object.keys(env).sort();
|
|
54
|
+
// For env vars, masking should be explicitly opted-in (default false)
|
|
55
|
+
const shouldMask = opts?.mask === true;
|
|
56
|
+
for (const key of sortedKeys) {
|
|
57
|
+
const value = env[key];
|
|
58
|
+
const displayValue = shouldMask ? maskSecret(value) : value;
|
|
59
|
+
if (process.stdout.isTTY) {
|
|
60
|
+
console.log(`${tui.bold(key)}=${displayValue}`);
|
|
61
|
+
} else {
|
|
62
|
+
console.log(`${key}=${displayValue}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
|
|
@@ -31,27 +31,32 @@ export const getSubcommand = createCommand({
|
|
|
31
31
|
idempotent: true,
|
|
32
32
|
|
|
33
33
|
async handler(ctx) {
|
|
34
|
-
const { args } = ctx;
|
|
34
|
+
const { args, options } = ctx;
|
|
35
35
|
const storage = await createStorageAdapter(ctx);
|
|
36
36
|
const started = Date.now();
|
|
37
37
|
const res = await storage.get(args.namespace, args.key);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
|
|
39
|
+
if (!options.json) {
|
|
40
|
+
if (res.exists) {
|
|
41
|
+
if (res.data) {
|
|
42
|
+
if (res.contentType?.includes('json')) {
|
|
43
|
+
const val = tryParseJSON(res.data as unknown as string);
|
|
44
|
+
tui.json(val);
|
|
45
|
+
} else if (res.contentType?.includes('text')) {
|
|
46
|
+
console.log(String(res.data));
|
|
47
|
+
} else {
|
|
48
|
+
const b = res.data as ArrayBuffer;
|
|
49
|
+
tui.info(`Read ${b.byteLength} bytes (${res.contentType})`);
|
|
50
|
+
}
|
|
51
|
+
tui.success(
|
|
52
|
+
`retrieved in ${(Date.now() - started).toFixed(1)}ms (${res.contentType})`
|
|
53
|
+
);
|
|
45
54
|
} else {
|
|
46
|
-
|
|
47
|
-
tui.info(`Read ${b.byteLength} bytes (${res.contentType})`);
|
|
55
|
+
tui.warning(`${args.key} returned empty data for ${args.namespace}`);
|
|
48
56
|
}
|
|
49
|
-
tui.success(`retrieved in ${(Date.now() - started).toFixed(1)}ms (${res.contentType})`);
|
|
50
57
|
} else {
|
|
51
|
-
tui.warning(`${args.key}
|
|
58
|
+
tui.warning(`${args.key} does not exist in ${args.namespace}`);
|
|
52
59
|
}
|
|
53
|
-
} else {
|
|
54
|
-
tui.warning(`${args.key} does not exist in ${args.namespace}`);
|
|
55
60
|
}
|
|
56
61
|
|
|
57
62
|
return {
|
|
@@ -29,22 +29,20 @@ export const keysSubcommand = createCommand({
|
|
|
29
29
|
},
|
|
30
30
|
|
|
31
31
|
async handler(ctx) {
|
|
32
|
-
const { args } = ctx;
|
|
32
|
+
const { args, options } = ctx;
|
|
33
33
|
const kv = await createStorageAdapter(ctx);
|
|
34
34
|
|
|
35
35
|
const keys = await kv.getKeys(args.name);
|
|
36
36
|
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
keys
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
for (const key of keys) {
|
|
47
|
-
tui.info(` ${key}`);
|
|
37
|
+
if (!options.json) {
|
|
38
|
+
if (keys.length === 0) {
|
|
39
|
+
tui.info(`No keys found in namespace ${tui.bold(args.name)}`);
|
|
40
|
+
} else {
|
|
41
|
+
tui.info(`Found ${keys.length} key(s) in ${tui.bold(args.name)}:`);
|
|
42
|
+
for (const key of keys) {
|
|
43
|
+
tui.info(` ${key}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
48
46
|
}
|
|
49
47
|
|
|
50
48
|
return {
|
|
@@ -23,17 +23,19 @@ export const listNamespacesSubcommand = createCommand({
|
|
|
23
23
|
idempotent: true,
|
|
24
24
|
|
|
25
25
|
async handler(ctx) {
|
|
26
|
+
const { options } = ctx;
|
|
26
27
|
const storage = await createStorageAdapter(ctx);
|
|
27
28
|
const namespaces = await storage.getNamespaces();
|
|
28
29
|
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
if (!options.json) {
|
|
31
|
+
if (namespaces.length === 0) {
|
|
32
|
+
tui.info('No namespaces found');
|
|
33
|
+
} else {
|
|
34
|
+
tui.info(`Found ${namespaces.length} namespace(s):`);
|
|
35
|
+
for (const name of namespaces) {
|
|
36
|
+
tui.arrow(name);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
return namespaces;
|