@agentuity/cli 1.0.41 → 1.0.43
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/cmd/build/ast.d.ts.map +1 -1
- package/dist/cmd/build/ast.js +3 -3
- package/dist/cmd/build/ast.js.map +1 -1
- package/dist/cmd/build/typecheck.d.ts.map +1 -1
- package/dist/cmd/build/typecheck.js +52 -1
- package/dist/cmd/build/typecheck.js.map +1 -1
- package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -1
- package/dist/cmd/build/vite/static-renderer.js +22 -8
- package/dist/cmd/build/vite/static-renderer.js.map +1 -1
- package/dist/cmd/cloud/index.d.ts.map +1 -1
- package/dist/cmd/cloud/index.js +4 -0
- package/dist/cmd/cloud/index.js.map +1 -1
- package/dist/cmd/cloud/monitor.d.ts +3 -0
- package/dist/cmd/cloud/monitor.d.ts.map +1 -0
- package/dist/cmd/cloud/monitor.js +300 -0
- package/dist/cmd/cloud/monitor.js.map +1 -0
- package/dist/cmd/cloud/oidc/activity.d.ts +2 -0
- package/dist/cmd/cloud/oidc/activity.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/activity.js +57 -0
- package/dist/cmd/cloud/oidc/activity.js.map +1 -0
- package/dist/cmd/cloud/oidc/create.d.ts +2 -0
- package/dist/cmd/cloud/oidc/create.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/create.js +204 -0
- package/dist/cmd/cloud/oidc/create.js.map +1 -0
- package/dist/cmd/cloud/oidc/delete.d.ts +2 -0
- package/dist/cmd/cloud/oidc/delete.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/delete.js +59 -0
- package/dist/cmd/cloud/oidc/delete.js.map +1 -0
- package/dist/cmd/cloud/oidc/get.d.ts +2 -0
- package/dist/cmd/cloud/oidc/get.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/get.js +62 -0
- package/dist/cmd/cloud/oidc/get.js.map +1 -0
- package/dist/cmd/cloud/oidc/index.d.ts +3 -0
- package/dist/cmd/cloud/oidc/index.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/index.js +32 -0
- package/dist/cmd/cloud/oidc/index.js.map +1 -0
- package/dist/cmd/cloud/oidc/list.d.ts +2 -0
- package/dist/cmd/cloud/oidc/list.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/list.js +48 -0
- package/dist/cmd/cloud/oidc/list.js.map +1 -0
- package/dist/cmd/cloud/oidc/rotate-secret.d.ts +2 -0
- package/dist/cmd/cloud/oidc/rotate-secret.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/rotate-secret.js +66 -0
- package/dist/cmd/cloud/oidc/rotate-secret.js.map +1 -0
- package/dist/cmd/cloud/oidc/users.d.ts +2 -0
- package/dist/cmd/cloud/oidc/users.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/users.js +53 -0
- package/dist/cmd/cloud/oidc/users.js.map +1 -0
- package/dist/cmd/cloud/oidc/util.d.ts +10 -0
- package/dist/cmd/cloud/oidc/util.d.ts.map +1 -0
- package/dist/cmd/cloud/oidc/util.js +13 -0
- package/dist/cmd/cloud/oidc/util.js.map +1 -0
- package/dist/cmd/coder/hub-url.d.ts +1 -0
- package/dist/cmd/coder/hub-url.d.ts.map +1 -1
- package/dist/cmd/coder/hub-url.js +4 -1
- package/dist/cmd/coder/hub-url.js.map +1 -1
- package/dist/cmd/coder/start.d.ts.map +1 -1
- package/dist/cmd/coder/start.js +14 -8
- package/dist/cmd/coder/start.js.map +1 -1
- package/dist/cmd/coder/tui-init.d.ts +9 -0
- package/dist/cmd/coder/tui-init.d.ts.map +1 -0
- package/dist/cmd/coder/tui-init.js +56 -0
- package/dist/cmd/coder/tui-init.js.map +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +14 -5
- package/dist/config.js.map +1 -1
- package/dist/utils/jsonc.d.ts +13 -0
- package/dist/utils/jsonc.d.ts.map +1 -0
- package/dist/utils/jsonc.js +63 -0
- package/dist/utils/jsonc.js.map +1 -0
- package/dist/utils/route-migration.d.ts +2 -1
- package/dist/utils/route-migration.d.ts.map +1 -1
- package/dist/utils/route-migration.js +23 -32
- package/dist/utils/route-migration.js.map +1 -1
- package/dist/utils/zip.d.ts.map +1 -1
- package/dist/utils/zip.js +18 -2
- package/dist/utils/zip.js.map +1 -1
- package/package.json +6 -7
- package/src/cmd/build/ast.ts +6 -3
- package/src/cmd/build/typecheck.ts +60 -1
- package/src/cmd/build/vite/static-renderer.ts +24 -8
- package/src/cmd/cloud/index.ts +4 -0
- package/src/cmd/cloud/monitor.ts +375 -0
- package/src/cmd/cloud/oidc/activity.ts +64 -0
- package/src/cmd/cloud/oidc/create.ts +230 -0
- package/src/cmd/cloud/oidc/delete.ts +66 -0
- package/src/cmd/cloud/oidc/get.ts +68 -0
- package/src/cmd/cloud/oidc/index.ts +35 -0
- package/src/cmd/cloud/oidc/list.ts +53 -0
- package/src/cmd/cloud/oidc/rotate-secret.ts +80 -0
- package/src/cmd/cloud/oidc/users.ts +60 -0
- package/src/cmd/cloud/oidc/util.ts +28 -0
- package/src/cmd/coder/hub-url.ts +5 -1
- package/src/cmd/coder/start.ts +22 -8
- package/src/cmd/coder/tui-init.ts +75 -0
- package/src/config.ts +16 -5
- package/src/utils/jsonc.ts +67 -0
- package/src/utils/route-migration.ts +29 -40
- package/src/utils/zip.ts +17 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { hubFetchHeaders } from './hub-url';
|
|
2
|
+
|
|
3
|
+
export type TuiInitProbeResult =
|
|
4
|
+
| { ok: true }
|
|
5
|
+
| {
|
|
6
|
+
ok: false;
|
|
7
|
+
code: 'unauthorized' | 'http_error' | 'invalid_response' | 'network_error';
|
|
8
|
+
message: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function normalizeErrorMessage(payload: unknown, fallback: string): string {
|
|
12
|
+
if (
|
|
13
|
+
payload &&
|
|
14
|
+
typeof payload === 'object' &&
|
|
15
|
+
typeof (payload as { error?: unknown }).error === 'string'
|
|
16
|
+
) {
|
|
17
|
+
return (payload as { error: string }).error;
|
|
18
|
+
}
|
|
19
|
+
return fallback;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function probeTuiInitAccess(
|
|
23
|
+
hubHttpUrl: string,
|
|
24
|
+
fetchImpl: typeof fetch = fetch
|
|
25
|
+
): Promise<TuiInitProbeResult> {
|
|
26
|
+
try {
|
|
27
|
+
const response = await fetchImpl(`${hubHttpUrl}/api/hub/tui/init`, {
|
|
28
|
+
headers: hubFetchHeaders({ accept: 'application/json' }),
|
|
29
|
+
signal: AbortSignal.timeout(5_000),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
let payload: unknown;
|
|
33
|
+
try {
|
|
34
|
+
payload = await response.json();
|
|
35
|
+
} catch {
|
|
36
|
+
payload = undefined;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (response.status === 401 || response.status === 403) {
|
|
40
|
+
return {
|
|
41
|
+
ok: false,
|
|
42
|
+
code: 'unauthorized',
|
|
43
|
+
message: normalizeErrorMessage(payload, `${response.status} ${response.statusText}`),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
return {
|
|
49
|
+
ok: false,
|
|
50
|
+
code: 'http_error',
|
|
51
|
+
message: normalizeErrorMessage(payload, `${response.status} ${response.statusText}`),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (
|
|
56
|
+
!payload ||
|
|
57
|
+
typeof payload !== 'object' ||
|
|
58
|
+
(payload as { type?: unknown }).type !== 'init'
|
|
59
|
+
) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
code: 'invalid_response',
|
|
63
|
+
message: 'Hub init endpoint did not return an init payload',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return { ok: true };
|
|
68
|
+
} catch (error) {
|
|
69
|
+
return {
|
|
70
|
+
ok: false,
|
|
71
|
+
code: 'network_error',
|
|
72
|
+
message: error instanceof Error ? error.message : String(error),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/config.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
APIClient as ServerAPIClient,
|
|
11
11
|
} from '@agentuity/server';
|
|
12
12
|
import { YAML } from 'bun';
|
|
13
|
-
import
|
|
13
|
+
import { parseJSONC } from './utils/jsonc';
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import { clearProfileCache } from './cache';
|
|
16
16
|
import { getCatalystUrl } from './catalyst';
|
|
@@ -265,8 +265,19 @@ function formatYAML(obj: unknown, indent = 0): string {
|
|
|
265
265
|
} else if (typeof value === 'string') {
|
|
266
266
|
if (value === '') {
|
|
267
267
|
lines.push(`${spaces}${key}: ""`);
|
|
268
|
-
} else if (
|
|
269
|
-
|
|
268
|
+
} else if (
|
|
269
|
+
value.includes(':') ||
|
|
270
|
+
value.includes('#') ||
|
|
271
|
+
value.includes(' ') ||
|
|
272
|
+
value.includes('\\')
|
|
273
|
+
) {
|
|
274
|
+
// Use single quotes to avoid YAML escape-sequence processing.
|
|
275
|
+
// Double-quoted YAML strings interpret backslash sequences (\n, \t, etc.),
|
|
276
|
+
// which breaks Windows paths like C:\Users\... where \U would be invalid.
|
|
277
|
+
// Single-quoted strings treat backslashes literally.
|
|
278
|
+
// Escape any embedded single quotes by doubling them (YAML spec).
|
|
279
|
+
const escaped = value.replace(/'/g, "''");
|
|
280
|
+
lines.push(`${spaces}${key}: '${escaped}'`);
|
|
270
281
|
} else {
|
|
271
282
|
lines.push(`${spaces}${key}: ${value}`);
|
|
272
283
|
}
|
|
@@ -602,7 +613,7 @@ export async function loadProjectConfig(
|
|
|
602
613
|
throw new ProjectConfigNotFoundException({ message: 'project config not found' });
|
|
603
614
|
}
|
|
604
615
|
const text = await file.text();
|
|
605
|
-
const parsedConfig =
|
|
616
|
+
const parsedConfig = parseJSONC(text);
|
|
606
617
|
const result = ProjectSchema.safeParse(parsedConfig);
|
|
607
618
|
if (!result.success) {
|
|
608
619
|
tui.error(`Invalid project config at ${configPath}:`);
|
|
@@ -707,7 +718,7 @@ export async function updateProjectConfig(
|
|
|
707
718
|
}
|
|
708
719
|
|
|
709
720
|
const text = await file.text();
|
|
710
|
-
const existing =
|
|
721
|
+
const existing = parseJSONC(text) as Record<string, unknown>;
|
|
711
722
|
const updated = { ...existing, ...updates };
|
|
712
723
|
|
|
713
724
|
const result = ProjectSchema.safeParse(updated);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse JSON with Comments (JSONC).
|
|
3
|
+
*
|
|
4
|
+
* Strips single-line (`//`) and block (`/* */`) comments as well as trailing
|
|
5
|
+
* commas that appear before `}` or `]`, then delegates to the built-in
|
|
6
|
+
* `JSON.parse`. This covers the comment syntax used by `tsconfig.json` and
|
|
7
|
+
* similar config files without pulling in a full JSON5 parser.
|
|
8
|
+
*
|
|
9
|
+
* String literals are respected — comments and trailing commas inside quoted
|
|
10
|
+
* strings are left untouched.
|
|
11
|
+
*/
|
|
12
|
+
export function parseJSONC(text: string): unknown {
|
|
13
|
+
let result = '';
|
|
14
|
+
let i = 0;
|
|
15
|
+
const len = text.length;
|
|
16
|
+
|
|
17
|
+
while (i < len) {
|
|
18
|
+
const ch = text[i];
|
|
19
|
+
|
|
20
|
+
// --- quoted string: copy verbatim, including any escape sequences ---
|
|
21
|
+
if (ch === '"') {
|
|
22
|
+
const start = i;
|
|
23
|
+
i++; // skip opening quote
|
|
24
|
+
while (i < len) {
|
|
25
|
+
if (text[i] === '\\') {
|
|
26
|
+
i += i + 1 < len ? 2 : 1; // skip escaped character (guard end-of-input)
|
|
27
|
+
} else if (text[i] === '"') {
|
|
28
|
+
i++; // skip closing quote
|
|
29
|
+
break;
|
|
30
|
+
} else {
|
|
31
|
+
i++;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
result += text.slice(start, i);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// --- single-line comment: skip to end of line ---
|
|
39
|
+
if (ch === '/' && text[i + 1] === '/') {
|
|
40
|
+
i += 2;
|
|
41
|
+
while (i < len && text[i] !== '\n') {
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// --- block comment: skip to closing */ ---
|
|
48
|
+
if (ch === '/' && text[i + 1] === '*') {
|
|
49
|
+
i += 2;
|
|
50
|
+
while (i < len && !(text[i] === '*' && text[i + 1] === '/')) {
|
|
51
|
+
i++;
|
|
52
|
+
}
|
|
53
|
+
if (i < len) {
|
|
54
|
+
i += 2; // skip closing */
|
|
55
|
+
}
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
result += ch;
|
|
60
|
+
i++;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Strip trailing commas before } or ] (with optional whitespace between).
|
|
64
|
+
result = result.replace(/,(\s*[}\]])/g, '$1');
|
|
65
|
+
|
|
66
|
+
return JSON.parse(result);
|
|
67
|
+
}
|
|
@@ -697,7 +697,8 @@ export function performMigration(rootDir: string, routeFiles: string[]): Migrati
|
|
|
697
697
|
* Show the migration notice and optionally perform migration.
|
|
698
698
|
*
|
|
699
699
|
* Called during `dev` and `build` after dependency upgrades.
|
|
700
|
-
*
|
|
700
|
+
* Only prompts in interactive TTY sessions and only once — if the user
|
|
701
|
+
* dismisses the prompt, it won't be shown again.
|
|
701
702
|
*
|
|
702
703
|
* @returns true if migration was performed, false otherwise
|
|
703
704
|
*/
|
|
@@ -707,6 +708,12 @@ export async function promptRouteMigration(
|
|
|
707
708
|
options?: { interactive?: boolean }
|
|
708
709
|
): Promise<boolean> {
|
|
709
710
|
const interactive = options?.interactive ?? process.stdin.isTTY;
|
|
711
|
+
|
|
712
|
+
// Only show the interactive migration prompt in TTY sessions
|
|
713
|
+
if (!interactive) {
|
|
714
|
+
return false;
|
|
715
|
+
}
|
|
716
|
+
|
|
710
717
|
const eligibility = checkMigrationEligibility(rootDir);
|
|
711
718
|
|
|
712
719
|
if (!eligibility.available) {
|
|
@@ -715,48 +722,30 @@ export async function promptRouteMigration(
|
|
|
715
722
|
|
|
716
723
|
const { routeFiles, alreadyNotified } = eligibility;
|
|
717
724
|
|
|
718
|
-
//
|
|
719
|
-
if (
|
|
720
|
-
if (!alreadyNotified) {
|
|
721
|
-
logger.info(
|
|
722
|
-
'[migration] This project uses file-based routing with %d route files in src/api/. ' +
|
|
723
|
-
'Agentuity is moving to explicit routing, which will become the default in the next major release. ' +
|
|
724
|
-
'Run `agentuity dev --migrate-routes` to migrate.',
|
|
725
|
-
routeFiles.length
|
|
726
|
-
);
|
|
727
|
-
writeMigrationState(rootDir, 'notified');
|
|
728
|
-
}
|
|
725
|
+
// Only prompt once — if the user has already been notified or dismissed, don't ask again
|
|
726
|
+
if (alreadyNotified) {
|
|
729
727
|
return false;
|
|
730
728
|
}
|
|
731
729
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
'
|
|
737
|
-
'
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
{ centerTitle: false }
|
|
752
|
-
);
|
|
753
|
-
} else {
|
|
754
|
-
// Subsequent runs: shorter reminder
|
|
755
|
-
tui.newline();
|
|
756
|
-
tui.info(
|
|
757
|
-
`${tui.bold('Explicit routing migration available')} — run with ${tui.muted('--migrate-routes')} or choose below.`
|
|
758
|
-
);
|
|
759
|
-
}
|
|
730
|
+
tui.newline();
|
|
731
|
+
tui.banner(
|
|
732
|
+
'✨ Migrate to Explicit Routing',
|
|
733
|
+
'Agentuity is moving to explicit routing, which will become the\n' +
|
|
734
|
+
'default in the next major release. File-based route discovery\n' +
|
|
735
|
+
'will be deprecated.\n' +
|
|
736
|
+
'\n' +
|
|
737
|
+
`Your project has ${routeFiles.length} route files in src/api/ that are\n` +
|
|
738
|
+
'auto-discovered at build time. Explicit routing gives you a single\n' +
|
|
739
|
+
'src/api/index.ts that imports and mounts all sub-routers — just\n' +
|
|
740
|
+
'like a standard Hono application.\n' +
|
|
741
|
+
'\n' +
|
|
742
|
+
`${tui.muted('Before:')} ${routeFiles.length} files auto-discovered from src/api/**/*.ts\n` +
|
|
743
|
+
`${tui.muted('After:')} One src/api/index.ts that imports and mounts them\n` +
|
|
744
|
+
'\n' +
|
|
745
|
+
'Your existing route files are not modified. Your app.ts will be\n' +
|
|
746
|
+
'updated to import the router and pass it to createApp({ router }).',
|
|
747
|
+
{ centerTitle: false }
|
|
748
|
+
);
|
|
760
749
|
|
|
761
750
|
tui.newline();
|
|
762
751
|
|
package/src/utils/zip.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readFileSync, lstatSync } from 'node:fs';
|
|
1
2
|
import { relative } from 'node:path';
|
|
2
3
|
import { Glob } from 'bun';
|
|
3
4
|
import AdmZip from 'adm-zip';
|
|
@@ -11,7 +12,7 @@ interface Options {
|
|
|
11
12
|
export async function zipDir(dir: string, outdir: string, options?: Options) {
|
|
12
13
|
const zip = new AdmZip();
|
|
13
14
|
const files = await Array.fromAsync(
|
|
14
|
-
new Glob('**/*').scan({ cwd: dir, absolute: true, dot: true })
|
|
15
|
+
new Glob('**/*').scan({ cwd: dir, absolute: true, dot: true, followSymlinks: false })
|
|
15
16
|
);
|
|
16
17
|
const total = files.length;
|
|
17
18
|
let count = 0;
|
|
@@ -24,7 +25,21 @@ export async function zipDir(dir: string, outdir: string, options?: Options) {
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
if (!skip) {
|
|
27
|
-
|
|
28
|
+
try {
|
|
29
|
+
// Skip symlinks and directories — symlinks are workspace artefacts
|
|
30
|
+
// (e.g. bun's node_modules links) that cannot be resolved portably
|
|
31
|
+
// across machines and would cause EISDIR errors on extraction.
|
|
32
|
+
const stat = lstatSync(file);
|
|
33
|
+
if (!stat.isSymbolicLink() && !stat.isDirectory()) {
|
|
34
|
+
// Use addFile with explicit Unix permissions (0o644) instead of addLocalFile.
|
|
35
|
+
// On Windows, addLocalFile relies on OS file stats which may produce zip entries
|
|
36
|
+
// with incorrect Unix permission bits, causing EACCES errors when extracted on Linux.
|
|
37
|
+
const data = readFileSync(file);
|
|
38
|
+
zip.addFile(rel, data, '', 0o644);
|
|
39
|
+
}
|
|
40
|
+
} catch (err) {
|
|
41
|
+
throw new Error(`Failed to add file to zip: ${rel} (${file})`, { cause: err });
|
|
42
|
+
}
|
|
28
43
|
}
|
|
29
44
|
count++;
|
|
30
45
|
if (options?.progress) {
|