@agentuity/cli 0.0.86 → 0.0.88
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/bin/cli.ts +7 -0
- package/dist/bun-path.d.ts.map +1 -1
- package/dist/bun-path.js +1 -3
- package/dist/bun-path.js.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/cmd/ai/index.d.ts.map +1 -1
- package/dist/cmd/ai/index.js +1 -0
- package/dist/cmd/ai/index.js.map +1 -1
- package/dist/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +5 -0
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/bundler.d.ts.map +1 -1
- package/dist/cmd/build/bundler.js +152 -7
- package/dist/cmd/build/bundler.js.map +1 -1
- package/dist/cmd/build/config-loader.d.ts +16 -0
- package/dist/cmd/build/config-loader.d.ts.map +1 -0
- package/dist/cmd/build/config-loader.js +165 -0
- package/dist/cmd/build/config-loader.js.map +1 -0
- package/dist/cmd/build/patch/_util.js +6 -6
- package/dist/cmd/build/patch/_util.js.map +1 -1
- package/dist/cmd/build/patch/llm.js +1 -1
- package/dist/cmd/build/patch/llm.js.map +1 -1
- package/dist/cmd/build/plugin.d.ts.map +1 -1
- package/dist/cmd/build/plugin.js +36 -15
- package/dist/cmd/build/plugin.js.map +1 -1
- package/dist/cmd/build/route-discovery.d.ts +8 -4
- package/dist/cmd/build/route-discovery.d.ts.map +1 -1
- package/dist/cmd/build/route-discovery.js +10 -5
- package/dist/cmd/build/route-discovery.js.map +1 -1
- package/dist/cmd/build/workbench.d.ts +1 -0
- package/dist/cmd/build/workbench.d.ts.map +1 -1
- package/dist/cmd/build/workbench.js +8 -1
- package/dist/cmd/build/workbench.js.map +1 -1
- package/dist/cmd/cloud/index.d.ts.map +1 -1
- package/dist/cmd/cloud/index.js +2 -0
- package/dist/cmd/cloud/index.js.map +1 -1
- package/dist/cmd/cloud/redis/get.d.ts +2 -0
- package/dist/cmd/cloud/redis/get.d.ts.map +1 -0
- package/dist/cmd/cloud/redis/get.js +62 -0
- package/dist/cmd/cloud/redis/get.js.map +1 -0
- package/dist/cmd/cloud/redis/index.d.ts +2 -0
- package/dist/cmd/cloud/redis/index.d.ts.map +1 -0
- package/dist/cmd/cloud/redis/index.js +13 -0
- package/dist/cmd/cloud/redis/index.js.map +1 -0
- package/dist/cmd/cloud/scp/download.js +3 -3
- package/dist/cmd/cloud/scp/download.js.map +1 -1
- package/dist/cmd/cloud/scp/upload.js +3 -3
- package/dist/cmd/cloud/scp/upload.js.map +1 -1
- package/dist/cmd/cloud/ssh.js +3 -3
- package/dist/cmd/cloud/ssh.js.map +1 -1
- package/dist/cmd/dev/index.d.ts.map +1 -1
- package/dist/cmd/dev/index.js +5 -0
- package/dist/cmd/dev/index.js.map +1 -1
- package/dist/cmd/index.d.ts.map +1 -1
- package/dist/cmd/index.js +7 -0
- package/dist/cmd/index.js.map +1 -1
- package/dist/cmd/profile/create.d.ts.map +1 -1
- package/dist/cmd/profile/create.js +1 -0
- package/dist/cmd/profile/create.js.map +1 -1
- package/dist/cmd/upgrade/index.d.ts +20 -0
- package/dist/cmd/upgrade/index.d.ts.map +1 -0
- package/dist/cmd/upgrade/index.js +307 -0
- package/dist/cmd/upgrade/index.js.map +1 -0
- package/dist/cmd/version/index.d.ts.map +1 -1
- package/dist/cmd/version/index.js +1 -0
- package/dist/cmd/version/index.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -94
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tui.d.ts +5 -0
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +23 -0
- package/dist/tui.js.map +1 -1
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/dependency-checker.d.ts +20 -0
- package/dist/utils/dependency-checker.d.ts.map +1 -0
- package/dist/utils/dependency-checker.js +161 -0
- package/dist/utils/dependency-checker.js.map +1 -0
- package/dist/version-check.d.ts +13 -0
- package/dist/version-check.d.ts.map +1 -0
- package/dist/version-check.js +177 -0
- package/dist/version-check.js.map +1 -0
- package/package.json +6 -4
- package/src/bun-path.ts +1 -3
- package/src/cli.ts +3 -3
- package/src/cmd/ai/index.ts +1 -0
- package/src/cmd/build/ast.ts +7 -0
- package/src/cmd/build/bundler.ts +181 -8
- package/src/cmd/build/config-loader.ts +200 -0
- package/src/cmd/build/patch/_util.ts +6 -6
- package/src/cmd/build/patch/llm.ts +1 -1
- package/src/cmd/build/plugin.ts +40 -17
- package/src/cmd/build/route-discovery.ts +10 -5
- package/src/cmd/build/workbench.ts +9 -1
- package/src/cmd/cloud/index.ts +2 -0
- package/src/cmd/cloud/redis/get.ts +72 -0
- package/src/cmd/cloud/redis/index.ts +13 -0
- package/src/cmd/cloud/scp/download.ts +3 -3
- package/src/cmd/cloud/scp/upload.ts +3 -3
- package/src/cmd/cloud/ssh.ts +3 -3
- package/src/cmd/dev/index.ts +11 -0
- package/src/cmd/index.ts +8 -0
- package/src/cmd/profile/create.ts +1 -0
- package/src/cmd/project/download.ts +1 -1
- package/src/cmd/upgrade/index.ts +365 -0
- package/src/cmd/version/index.ts +1 -0
- package/src/config.ts +12 -121
- package/src/git-helper.ts +4 -4
- package/src/index.ts +4 -0
- package/src/tui.ts +27 -0
- package/src/types.ts +80 -0
- package/src/utils/dependency-checker.ts +207 -0
- package/src/version-check.ts +234 -0
package/src/config.ts
CHANGED
|
@@ -407,81 +407,6 @@ function getPlaceholderValue(schema: z.ZodTypeAny): string {
|
|
|
407
407
|
}
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
-
function extractDefaultValue(schema: z.ZodTypeAny): unknown {
|
|
411
|
-
let unwrapped = schema;
|
|
412
|
-
|
|
413
|
-
// Unwrap optional layers
|
|
414
|
-
while (unwrapped instanceof z.ZodOptional) {
|
|
415
|
-
unwrapped = (unwrapped._def as unknown as { innerType: z.ZodTypeAny }).innerType;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// Check if it's a ZodDefault (has defaultValue in def or _def)
|
|
419
|
-
const checkDef = (obj: unknown): unknown => {
|
|
420
|
-
if (typeof obj !== 'object' || obj === null) return undefined;
|
|
421
|
-
const anyObj = obj as Record<string, unknown>;
|
|
422
|
-
|
|
423
|
-
// Check `def` property first (used in some Zod versions)
|
|
424
|
-
if ('def' in anyObj && typeof anyObj.def === 'object' && anyObj.def !== null) {
|
|
425
|
-
const def = anyObj.def as Record<string, unknown>;
|
|
426
|
-
if (def.type === 'default' && 'defaultValue' in def) {
|
|
427
|
-
const val = def.defaultValue;
|
|
428
|
-
return typeof val === 'function' ? (val as () => unknown)() : val;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Check `_def` property (standard Zod property)
|
|
433
|
-
if ('_def' in anyObj && typeof anyObj._def === 'object' && anyObj._def !== null) {
|
|
434
|
-
const def = anyObj._def as Record<string, unknown>;
|
|
435
|
-
if (def.type === 'default' && 'defaultValue' in def) {
|
|
436
|
-
const val = def.defaultValue;
|
|
437
|
-
return typeof val === 'function' ? (val as () => unknown)() : val;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
return undefined;
|
|
442
|
-
};
|
|
443
|
-
|
|
444
|
-
return checkDef(unwrapped);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
function getValueWithDefaults(schema: z.ZodTypeAny, providedValue: unknown): unknown {
|
|
448
|
-
// If value is explicitly provided, use it
|
|
449
|
-
if (providedValue !== undefined) {
|
|
450
|
-
return providedValue;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
// Try to extract default value
|
|
454
|
-
const defaultValue = extractDefaultValue(schema);
|
|
455
|
-
if (defaultValue !== undefined) {
|
|
456
|
-
return defaultValue;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
// For optional fields without defaults, check if it's an object
|
|
460
|
-
let unwrapped = schema;
|
|
461
|
-
if (schema instanceof z.ZodOptional) {
|
|
462
|
-
unwrapped = (schema._def as unknown as { innerType: z.ZodTypeAny }).innerType;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// If it's an object schema, recursively populate defaults
|
|
466
|
-
if (unwrapped instanceof z.ZodObject) {
|
|
467
|
-
const shape = unwrapped.shape;
|
|
468
|
-
const result: Record<string, unknown> = {};
|
|
469
|
-
let hasAnyDefaults = false;
|
|
470
|
-
|
|
471
|
-
for (const [key, fieldSchema] of Object.entries(shape)) {
|
|
472
|
-
const fieldValue = getValueWithDefaults(fieldSchema as z.ZodTypeAny, undefined);
|
|
473
|
-
if (fieldValue !== undefined) {
|
|
474
|
-
result[key] = fieldValue;
|
|
475
|
-
hasAnyDefaults = true;
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
return hasAnyDefaults ? result : undefined;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
return undefined;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
410
|
export function generateYAMLTemplate(name: string): string {
|
|
486
411
|
const lines: string[] = [];
|
|
487
412
|
|
|
@@ -552,39 +477,6 @@ class ProjectConfigNotFoundExpection extends Error {
|
|
|
552
477
|
|
|
553
478
|
type ProjectConfig = z.infer<typeof ProjectSchema>;
|
|
554
479
|
|
|
555
|
-
function generateJSON5WithComments(
|
|
556
|
-
jsonSchema: string,
|
|
557
|
-
schema: z.ZodObject<z.ZodRawShape>,
|
|
558
|
-
data: Record<string, unknown>
|
|
559
|
-
): string {
|
|
560
|
-
const lines: string[] = ['{'];
|
|
561
|
-
const shape = schema.shape;
|
|
562
|
-
const keys = Object.keys(shape);
|
|
563
|
-
|
|
564
|
-
lines.push(` "$schema": "${jsonSchema}",`);
|
|
565
|
-
|
|
566
|
-
for (let i = 0; i < keys.length; i++) {
|
|
567
|
-
const key = keys[i];
|
|
568
|
-
const fieldSchema = shape[key] as z.ZodTypeAny;
|
|
569
|
-
const description = getSchemaDescription(fieldSchema);
|
|
570
|
-
const providedValue = data[key];
|
|
571
|
-
|
|
572
|
-
if (description) {
|
|
573
|
-
lines.push(` // ${description}`);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
// Get value with defaults applied
|
|
577
|
-
const valueWithDefaults = getValueWithDefaults(fieldSchema, providedValue);
|
|
578
|
-
const safeValue = valueWithDefaults === undefined ? null : valueWithDefaults;
|
|
579
|
-
const jsonValue = JSON.stringify(safeValue, null, 2).replace(/\n/g, '\n ');
|
|
580
|
-
const comma = i < keys.length - 1 ? ',' : '';
|
|
581
|
-
lines.push(` ${JSON.stringify(key)}: ${jsonValue}${comma}`);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
lines.push('}');
|
|
585
|
-
return lines.join('\n');
|
|
586
|
-
}
|
|
587
|
-
|
|
588
480
|
export async function loadProjectConfig(
|
|
589
481
|
dir: string,
|
|
590
482
|
config?: Config | null
|
|
@@ -636,12 +528,11 @@ export async function createProjectConfig(dir: string, config: InitialProjectCon
|
|
|
636
528
|
|
|
637
529
|
// generate the project config
|
|
638
530
|
const configPath = join(dir, 'agentuity.json');
|
|
639
|
-
const
|
|
640
|
-
'https://agentuity.dev/schema/cli/v1/agentuity.json',
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
);
|
|
644
|
-
await Bun.write(configPath, json5Content + '\n');
|
|
531
|
+
const configData = {
|
|
532
|
+
$schema: 'https://agentuity.dev/schema/cli/v1/agentuity.json',
|
|
533
|
+
...sanitizedConfig,
|
|
534
|
+
};
|
|
535
|
+
await Bun.write(configPath, JSON.stringify(configData, null, 2) + '\n');
|
|
645
536
|
|
|
646
537
|
// generate the .env file with initial secret
|
|
647
538
|
const envPath = join(dir, '.env');
|
|
@@ -656,9 +547,6 @@ export async function createProjectConfig(dir: string, config: InitialProjectCon
|
|
|
656
547
|
mkdirSync(vscodeDir);
|
|
657
548
|
|
|
658
549
|
const settings = {
|
|
659
|
-
'files.associations': {
|
|
660
|
-
'agentuity.json': 'jsonc',
|
|
661
|
-
},
|
|
662
550
|
'search.exclude': {
|
|
663
551
|
'**/.git/**': true,
|
|
664
552
|
'**/node_modules/**': true,
|
|
@@ -743,12 +631,15 @@ export function getCatalystAPIClient(logger: Logger, auth: AuthData, region: str
|
|
|
743
631
|
return new ServerAPIClient(catalystUrl, logger, auth.apiKey);
|
|
744
632
|
}
|
|
745
633
|
|
|
746
|
-
export function getIONHost(config: Config | null) {
|
|
747
|
-
if (config?.
|
|
634
|
+
export function getIONHost(config: Config | null, region: string) {
|
|
635
|
+
if (config?.overrides?.ion_url) {
|
|
636
|
+
const url = new URL(config.overrides.ion_url);
|
|
637
|
+
return url.hostname;
|
|
638
|
+
}
|
|
639
|
+
if (config?.name === 'local' || region === 'local') {
|
|
748
640
|
return 'ion.agentuity.io';
|
|
749
641
|
}
|
|
750
|
-
|
|
751
|
-
return url.hostname;
|
|
642
|
+
return `ion-${region}.agentuity.cloud`;
|
|
752
643
|
}
|
|
753
644
|
|
|
754
645
|
export function getStreamURL(region: string, config: Config | null) {
|
package/src/git-helper.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Git helper utilities for detecting and using git safely.
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* On macOS, git may be a stub that triggers Xcode Command Line Tools installation popup.
|
|
5
5
|
* This helper detects the real git binary and provides safe wrappers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Check if git is available and is the real git binary (not the macOS stub).
|
|
10
|
-
*
|
|
10
|
+
*
|
|
11
11
|
* On macOS without Xcode CLT installed, /usr/bin/git exists but it's a stub that
|
|
12
12
|
* triggers a popup asking to install developer tools. We detect this by checking
|
|
13
13
|
* if Xcode Command Line Tools are installed using `xcode-select -p`.
|
|
14
|
-
*
|
|
14
|
+
*
|
|
15
15
|
* @returns true if git is available and functional, false otherwise
|
|
16
16
|
*/
|
|
17
17
|
export async function isGitAvailable(): Promise<boolean> {
|
|
@@ -28,7 +28,7 @@ export async function isGitAvailable(): Promise<boolean> {
|
|
|
28
28
|
stdout: 'pipe',
|
|
29
29
|
stderr: 'pipe',
|
|
30
30
|
});
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
// If xcode-select -p fails, CLT are not installed, git is just a stub
|
|
33
33
|
if (result.exitCode !== 0) {
|
|
34
34
|
return false;
|
package/src/index.ts
CHANGED
|
@@ -104,6 +104,10 @@ export type {
|
|
|
104
104
|
Profile,
|
|
105
105
|
AuthData,
|
|
106
106
|
CommandSchemas,
|
|
107
|
+
BuildPhase,
|
|
108
|
+
BuildContext,
|
|
109
|
+
BuildConfig,
|
|
110
|
+
BuildConfigFunction,
|
|
107
111
|
} from './types';
|
|
108
112
|
export { createSubcommand, createCommand } from './types';
|
|
109
113
|
export type { ColorScheme } from './terminal';
|
package/src/tui.ts
CHANGED
|
@@ -15,6 +15,25 @@ import { type APIClient as APIClientType } from './api';
|
|
|
15
15
|
import { getExitCode } from './errors';
|
|
16
16
|
import { maskSecret } from './env-util';
|
|
17
17
|
|
|
18
|
+
// Install global exit handler to always restore terminal cursor
|
|
19
|
+
// This ensures cursor is restored even when process.exit() is called directly
|
|
20
|
+
let exitHandlerInstalled = false;
|
|
21
|
+
function ensureCursorRestoration(): void {
|
|
22
|
+
if (exitHandlerInstalled) return;
|
|
23
|
+
exitHandlerInstalled = true;
|
|
24
|
+
|
|
25
|
+
const restoreCursor = () => {
|
|
26
|
+
// Restore cursor visibility
|
|
27
|
+
process.stderr.write('\x1B[?25h');
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Handle process exit
|
|
31
|
+
process.on('exit', restoreCursor);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Install handler immediately when module loads
|
|
35
|
+
ensureCursorRestoration();
|
|
36
|
+
|
|
18
37
|
// Re-export maskSecret for convenience
|
|
19
38
|
export { maskSecret };
|
|
20
39
|
|
|
@@ -327,6 +346,14 @@ export function newline(): void {
|
|
|
327
346
|
process.stderr.write('\n');
|
|
328
347
|
}
|
|
329
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Print plain text output without any prefix or icon
|
|
351
|
+
* Use for primary command output that shouldn't have semantic formatting
|
|
352
|
+
*/
|
|
353
|
+
export function output(message: string): void {
|
|
354
|
+
console.log(message);
|
|
355
|
+
}
|
|
356
|
+
|
|
330
357
|
/**
|
|
331
358
|
* Get the display width of a string, handling ANSI codes and OSC 8 hyperlinks
|
|
332
359
|
*
|
package/src/types.ts
CHANGED
|
@@ -63,6 +63,79 @@ export type Config = zod.infer<typeof ConfigSchema>;
|
|
|
63
63
|
|
|
64
64
|
export type LogLevel = 'debug' | 'trace' | 'info' | 'warn' | 'error';
|
|
65
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Build phases for the bundler
|
|
68
|
+
*/
|
|
69
|
+
export type BuildPhase = 'api' | 'web' | 'workbench';
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Context provided to the build config function
|
|
73
|
+
*/
|
|
74
|
+
export interface BuildContext {
|
|
75
|
+
/**
|
|
76
|
+
* The root directory of the project
|
|
77
|
+
*/
|
|
78
|
+
rootDir: string;
|
|
79
|
+
/**
|
|
80
|
+
* Whether this is a development build
|
|
81
|
+
*/
|
|
82
|
+
dev: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* The output directory for the build
|
|
85
|
+
*/
|
|
86
|
+
outDir: string;
|
|
87
|
+
/**
|
|
88
|
+
* The source directory
|
|
89
|
+
*/
|
|
90
|
+
srcDir: string;
|
|
91
|
+
/**
|
|
92
|
+
* Organization ID (if available)
|
|
93
|
+
*/
|
|
94
|
+
orgId?: string;
|
|
95
|
+
/**
|
|
96
|
+
* Project ID (if available)
|
|
97
|
+
*/
|
|
98
|
+
projectId?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Deployment region
|
|
101
|
+
*/
|
|
102
|
+
region: string;
|
|
103
|
+
/**
|
|
104
|
+
* Logger instance
|
|
105
|
+
*/
|
|
106
|
+
logger: Logger;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* User-provided build configuration for a specific phase
|
|
111
|
+
*/
|
|
112
|
+
export interface BuildConfig {
|
|
113
|
+
/**
|
|
114
|
+
* Additional Bun plugins to apply during bundling
|
|
115
|
+
* These are added AFTER the Agentuity plugin
|
|
116
|
+
*/
|
|
117
|
+
plugins?: Array<import('bun').BunPlugin>;
|
|
118
|
+
/**
|
|
119
|
+
* Additional external modules to exclude from bundling
|
|
120
|
+
* These are merged with Agentuity's default externals
|
|
121
|
+
*/
|
|
122
|
+
external?: string[];
|
|
123
|
+
/**
|
|
124
|
+
* Additional define constants for code replacement
|
|
125
|
+
* These are merged with Agentuity's default defines
|
|
126
|
+
* Note: Cannot override process.env.AGENTUITY_* or process.env.NODE_ENV
|
|
127
|
+
*/
|
|
128
|
+
define?: Record<string, string>;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Configuration function that users export from agentuity.config.ts
|
|
133
|
+
*/
|
|
134
|
+
export type BuildConfigFunction = (
|
|
135
|
+
phase: BuildPhase,
|
|
136
|
+
context: BuildContext
|
|
137
|
+
) => BuildConfig | Promise<BuildConfig>;
|
|
138
|
+
|
|
66
139
|
export interface Profile {
|
|
67
140
|
name: string;
|
|
68
141
|
filename: string;
|
|
@@ -89,6 +162,7 @@ export interface GlobalOptions {
|
|
|
89
162
|
explain?: boolean;
|
|
90
163
|
dryRun?: boolean;
|
|
91
164
|
validate?: boolean;
|
|
165
|
+
skipVersionCheck?: boolean;
|
|
92
166
|
}
|
|
93
167
|
|
|
94
168
|
export interface PaginationInfo {
|
|
@@ -282,6 +356,8 @@ export function createCommand<
|
|
|
282
356
|
banner?: true;
|
|
283
357
|
aliases?: string[];
|
|
284
358
|
hidden?: boolean;
|
|
359
|
+
executable?: boolean;
|
|
360
|
+
skipUpgradeCheck?: boolean;
|
|
285
361
|
requires?: R;
|
|
286
362
|
optional?: O;
|
|
287
363
|
examples?: CommandExample[];
|
|
@@ -318,6 +394,8 @@ type CommandDefBase =
|
|
|
318
394
|
description: string;
|
|
319
395
|
aliases?: string[];
|
|
320
396
|
banner?: boolean;
|
|
397
|
+
executable?: boolean;
|
|
398
|
+
skipUpgradeCheck?: boolean;
|
|
321
399
|
examples?: CommandExample[];
|
|
322
400
|
idempotent?: boolean;
|
|
323
401
|
prerequisites?: string[];
|
|
@@ -332,6 +410,8 @@ type CommandDefBase =
|
|
|
332
410
|
description: string;
|
|
333
411
|
aliases?: string[];
|
|
334
412
|
banner?: boolean;
|
|
413
|
+
executable?: boolean;
|
|
414
|
+
skipUpgradeCheck?: boolean;
|
|
335
415
|
examples?: CommandExample[];
|
|
336
416
|
idempotent?: boolean;
|
|
337
417
|
prerequisites?: string[];
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { $ } from 'bun';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
4
|
+
import { getVersion } from '../version';
|
|
5
|
+
import type { Logger } from '../types';
|
|
6
|
+
|
|
7
|
+
interface PackageJson {
|
|
8
|
+
dependencies?: Record<string, string>;
|
|
9
|
+
devDependencies?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface UpgradeResult {
|
|
13
|
+
upgraded: string[];
|
|
14
|
+
skipped: string[];
|
|
15
|
+
failed: string[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Checks if a version specifier should be upgraded
|
|
20
|
+
* @param specifier - The version specifier from package.json (e.g., "latest", "^1.0.0", "1.2.3")
|
|
21
|
+
* @returns true if the package should be upgraded
|
|
22
|
+
*/
|
|
23
|
+
export function shouldUpgradeVersion(specifier: string): boolean {
|
|
24
|
+
// Always upgrade "latest" and "*"
|
|
25
|
+
if (specifier === 'latest' || specifier === '*') {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Skip pinned versions (exact semver like "1.2.3")
|
|
30
|
+
if (/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/.test(specifier)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Upgrade ranges (^1.0.0, ~1.0.0, >=1.0.0, etc.)
|
|
35
|
+
// Check if the specifier is a range pattern
|
|
36
|
+
if (/^[~^>=<]/.test(specifier)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Default to not upgrading if we can't determine
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check and upgrade @agentuity/* dependencies to match CLI version
|
|
46
|
+
* @param projectDir - Root directory of the user's project
|
|
47
|
+
* @param logger - Logger instance
|
|
48
|
+
* @returns Result of the upgrade operation
|
|
49
|
+
*/
|
|
50
|
+
export async function checkAndUpgradeDependencies(
|
|
51
|
+
projectDir: string,
|
|
52
|
+
logger: Logger
|
|
53
|
+
): Promise<UpgradeResult> {
|
|
54
|
+
const result: UpgradeResult = {
|
|
55
|
+
upgraded: [],
|
|
56
|
+
skipped: [],
|
|
57
|
+
failed: [],
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Skip in CI/non-interactive environments
|
|
61
|
+
if (!process.stdin.isTTY) {
|
|
62
|
+
logger.debug('Skipping dependency check in non-interactive environment');
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const packageJsonPath = join(projectDir, 'package.json');
|
|
67
|
+
const cliVersion = getVersion();
|
|
68
|
+
|
|
69
|
+
logger.debug('CLI version: %s', cliVersion);
|
|
70
|
+
|
|
71
|
+
// Read package.json
|
|
72
|
+
let packageJson: PackageJson;
|
|
73
|
+
try {
|
|
74
|
+
packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
logger.debug('Failed to read package.json: %s', error);
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Collect all @agentuity/* packages and their original specifiers
|
|
81
|
+
const allDeps = {
|
|
82
|
+
...packageJson.dependencies,
|
|
83
|
+
...packageJson.devDependencies,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const agentuitPackages = Object.entries(allDeps)
|
|
87
|
+
.filter(([name]) => name.startsWith('@agentuity/'))
|
|
88
|
+
.map(([name, specifier]) => ({ name, specifier }));
|
|
89
|
+
|
|
90
|
+
if (agentuitPackages.length === 0) {
|
|
91
|
+
logger.debug('No @agentuity/* packages found in package.json');
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Check which packages need upgrading
|
|
96
|
+
const packagesToUpgrade = agentuitPackages.filter(({ specifier }) =>
|
|
97
|
+
shouldUpgradeVersion(specifier)
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (packagesToUpgrade.length === 0) {
|
|
101
|
+
logger.debug('All @agentuity/* packages are pinned, skipping upgrade');
|
|
102
|
+
for (const pkg of agentuitPackages) {
|
|
103
|
+
result.skipped.push(pkg.name);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check if CLI version is different from installed packages
|
|
109
|
+
let needsUpgrade = false;
|
|
110
|
+
for (const { name } of packagesToUpgrade) {
|
|
111
|
+
try {
|
|
112
|
+
const installedPackageJson = JSON.parse(
|
|
113
|
+
readFileSync(join(projectDir, 'node_modules', name, 'package.json'), 'utf-8')
|
|
114
|
+
);
|
|
115
|
+
const installedVersion: string = installedPackageJson.version;
|
|
116
|
+
if (installedVersion !== cliVersion) {
|
|
117
|
+
logger.debug(
|
|
118
|
+
'%s: installed=%s, cli=%s (needs upgrade)',
|
|
119
|
+
name,
|
|
120
|
+
installedVersion,
|
|
121
|
+
cliVersion
|
|
122
|
+
);
|
|
123
|
+
needsUpgrade = true;
|
|
124
|
+
} else {
|
|
125
|
+
logger.debug('%s: already at correct version %s', name, installedVersion);
|
|
126
|
+
}
|
|
127
|
+
} catch {
|
|
128
|
+
// Package not installed or can't read version - needs upgrade
|
|
129
|
+
logger.debug('%s: not installed or unreadable, needs upgrade', name);
|
|
130
|
+
needsUpgrade = true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!needsUpgrade) {
|
|
135
|
+
logger.debug('All @agentuity/* packages are already at CLI version');
|
|
136
|
+
for (const pkg of packagesToUpgrade) {
|
|
137
|
+
result.skipped.push(pkg.name);
|
|
138
|
+
}
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Upgrade packages
|
|
143
|
+
logger.debug('Upgrading %d @agentuity/* package(s) to %s', packagesToUpgrade.length, cliVersion);
|
|
144
|
+
|
|
145
|
+
for (const { name } of packagesToUpgrade) {
|
|
146
|
+
try {
|
|
147
|
+
logger.debug('Installing %s@%s', name, cliVersion);
|
|
148
|
+
const installResult = await $`bun add ${name}@${cliVersion}`
|
|
149
|
+
.cwd(projectDir)
|
|
150
|
+
.quiet()
|
|
151
|
+
.nothrow();
|
|
152
|
+
|
|
153
|
+
if (installResult.exitCode !== 0) {
|
|
154
|
+
logger.error(
|
|
155
|
+
'Failed to install %s@%s: %s',
|
|
156
|
+
name,
|
|
157
|
+
cliVersion,
|
|
158
|
+
installResult.stderr.toString()
|
|
159
|
+
);
|
|
160
|
+
result.failed.push(name);
|
|
161
|
+
} else {
|
|
162
|
+
logger.debug('Successfully installed %s@%s', name, cliVersion);
|
|
163
|
+
result.upgraded.push(name);
|
|
164
|
+
}
|
|
165
|
+
} catch (_error) {
|
|
166
|
+
logger.error('Error installing %s: %s', name, _error);
|
|
167
|
+
result.failed.push(name);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Restore original version specifiers in package.json
|
|
172
|
+
// (bun add replaces them with specific versions)
|
|
173
|
+
if (result.upgraded.length > 0) {
|
|
174
|
+
try {
|
|
175
|
+
const updatedPackageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
176
|
+
let modified = false;
|
|
177
|
+
|
|
178
|
+
for (const { name, specifier } of packagesToUpgrade) {
|
|
179
|
+
// Only restore if we successfully upgraded
|
|
180
|
+
if (!result.upgraded.includes(name)) {
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Check both dependencies and devDependencies
|
|
185
|
+
if (updatedPackageJson.dependencies?.[name]) {
|
|
186
|
+
updatedPackageJson.dependencies[name] = specifier;
|
|
187
|
+
modified = true;
|
|
188
|
+
logger.debug('Restored %s to "%s" in dependencies', name, specifier);
|
|
189
|
+
}
|
|
190
|
+
if (updatedPackageJson.devDependencies?.[name]) {
|
|
191
|
+
updatedPackageJson.devDependencies[name] = specifier;
|
|
192
|
+
modified = true;
|
|
193
|
+
logger.debug('Restored %s to "%s" in devDependencies', name, specifier);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (modified) {
|
|
198
|
+
writeFileSync(packageJsonPath, JSON.stringify(updatedPackageJson, null, 2) + '\n');
|
|
199
|
+
logger.debug('Restored original version specifiers in package.json');
|
|
200
|
+
}
|
|
201
|
+
} catch (_error) {
|
|
202
|
+
logger.warn('Failed to restore version specifiers in package.json: %s', _error);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return result;
|
|
207
|
+
}
|