@agentuity/cli 1.0.20 → 1.0.22
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/vite/static-renderer.d.ts +27 -0
- package/dist/cmd/build/vite/static-renderer.d.ts.map +1 -0
- package/dist/cmd/build/vite/static-renderer.js +182 -0
- package/dist/cmd/build/vite/static-renderer.js.map +1 -0
- package/dist/cmd/build/vite/vite-builder.d.ts +5 -0
- package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
- package/dist/cmd/build/vite/vite-builder.js +16 -0
- package/dist/cmd/build/vite/vite-builder.js.map +1 -1
- package/dist/cmd/build/vite-bundler.d.ts.map +1 -1
- package/dist/cmd/build/vite-bundler.js +3 -0
- package/dist/cmd/build/vite-bundler.js.map +1 -1
- package/dist/cmd/cloud/deploy.d.ts.map +1 -1
- package/dist/cmd/cloud/deploy.js +1 -1
- package/dist/cmd/cloud/deploy.js.map +1 -1
- package/dist/cmd/project/add/domain.d.ts.map +1 -1
- package/dist/cmd/project/add/domain.js +6 -4
- package/dist/cmd/project/add/domain.js.map +1 -1
- package/dist/cmd/project/domain/check.d.ts.map +1 -1
- package/dist/cmd/project/domain/check.js +10 -5
- package/dist/cmd/project/domain/check.js.map +1 -1
- package/dist/cmd/project/reconcile.d.ts.map +1 -1
- package/dist/cmd/project/reconcile.js +19 -7
- package/dist/cmd/project/reconcile.js.map +1 -1
- package/dist/cmd/project/template-flow.d.ts.map +1 -1
- package/dist/cmd/project/template-flow.js +2 -1
- package/dist/cmd/project/template-flow.js.map +1 -1
- package/dist/domain.d.ts +3 -2
- package/dist/domain.d.ts.map +1 -1
- package/dist/domain.js +90 -21
- package/dist/domain.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +6 -6
- package/src/cmd/build/vite/static-renderer.ts +236 -0
- package/src/cmd/build/vite/vite-builder.ts +18 -0
- package/src/cmd/build/vite-bundler.ts +7 -0
- package/src/cmd/cloud/deploy.ts +1 -0
- package/src/cmd/project/add/domain.ts +10 -4
- package/src/cmd/project/domain/check.ts +16 -5
- package/src/cmd/project/reconcile.ts +31 -13
- package/src/cmd/project/template-flow.ts +2 -1
- package/src/domain.ts +99 -21
- package/src/types.ts +8 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static Renderer
|
|
3
|
+
*
|
|
4
|
+
* When `render: 'static'` is set in agentuity.config.ts, this module:
|
|
5
|
+
* 1. Runs a Vite SSR build to create a server-side entry point
|
|
6
|
+
* 2. Imports the built entry-server.js
|
|
7
|
+
* 3. Discovers routes to pre-render:
|
|
8
|
+
* - If `routeTree` is exported: auto-discovers all non-parameterized routes
|
|
9
|
+
* - If `getStaticPaths()` is exported: merges those paths in (for parameterized routes)
|
|
10
|
+
* - If neither: throws an error
|
|
11
|
+
* 4. Calls render(url) for each route
|
|
12
|
+
* 5. Replaces <!--app-html--> in the client template with rendered HTML
|
|
13
|
+
* 6. Writes pre-rendered HTML files to .agentuity/client/
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { createRequire } from 'node:module';
|
|
18
|
+
import { mkdirSync, writeFileSync, readFileSync, existsSync, rmSync } from 'node:fs';
|
|
19
|
+
import type { Logger } from '../../../types';
|
|
20
|
+
import { hasFrameworkPlugin } from './config-loader';
|
|
21
|
+
|
|
22
|
+
/** Minimal shape of a TanStack Router route tree node. */
|
|
23
|
+
interface RouteTreeNode {
|
|
24
|
+
path?: string;
|
|
25
|
+
options?: { path?: string };
|
|
26
|
+
children?: Record<string, RouteTreeNode>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Walks a TanStack Router route tree and extracts all non-parameterized paths.
|
|
31
|
+
* Skips layout routes (no path) and parameterized routes (containing $).
|
|
32
|
+
*/
|
|
33
|
+
function extractRoutePaths(node: RouteTreeNode): string[] {
|
|
34
|
+
const paths = new Set<string>();
|
|
35
|
+
|
|
36
|
+
function walk(route: RouteTreeNode) {
|
|
37
|
+
const path: string | undefined = route.path ?? route.options?.path;
|
|
38
|
+
if (path && !path.includes('$')) {
|
|
39
|
+
// Normalize: strip trailing slashes, ensure leading slash
|
|
40
|
+
const normalized = path === '/' ? '/' : path.replace(/\/+$/, '');
|
|
41
|
+
if (normalized) {
|
|
42
|
+
paths.add(normalized);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Recurse into children (TanStack Router stores them as an object)
|
|
47
|
+
const children = route.children;
|
|
48
|
+
if (children && typeof children === 'object') {
|
|
49
|
+
for (const child of Object.values(children)) {
|
|
50
|
+
if (child) walk(child);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
walk(node);
|
|
56
|
+
return [...paths].sort();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface StaticRenderOptions {
|
|
60
|
+
rootDir: string;
|
|
61
|
+
logger: Logger;
|
|
62
|
+
/** User plugins from agentuity.config.ts */
|
|
63
|
+
userPlugins: import('vite').PluginOption[];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface StaticRenderResult {
|
|
67
|
+
routes: number;
|
|
68
|
+
duration: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function runStaticRender(options: StaticRenderOptions): Promise<StaticRenderResult> {
|
|
72
|
+
const { rootDir, logger, userPlugins } = options;
|
|
73
|
+
const started = Date.now();
|
|
74
|
+
|
|
75
|
+
const clientDir = join(rootDir, '.agentuity/client');
|
|
76
|
+
const ssrOutDir = join(rootDir, '.agentuity/ssr');
|
|
77
|
+
const entryServerPath = join(rootDir, 'src/web/entry-server.tsx');
|
|
78
|
+
const templatePath = join(clientDir, 'index.html');
|
|
79
|
+
|
|
80
|
+
// Verify prerequisites
|
|
81
|
+
if (!existsSync(entryServerPath)) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
'Static rendering requires src/web/entry-server.tsx. ' +
|
|
84
|
+
'This file must export a render(url: string) function and either ' +
|
|
85
|
+
'a routeTree for auto-discovery or getStaticPaths() for explicit paths.'
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!existsSync(templatePath)) {
|
|
90
|
+
throw new Error(
|
|
91
|
+
'Client build must complete before static rendering. ' +
|
|
92
|
+
'No index.html found in .agentuity/client/'
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Step 1: Vite SSR build
|
|
97
|
+
// This resolves import.meta.glob, MDX imports, and other Vite-specific APIs
|
|
98
|
+
logger.debug('Running Vite SSR build for static rendering...');
|
|
99
|
+
|
|
100
|
+
const projectRequire = createRequire(join(rootDir, 'package.json'));
|
|
101
|
+
let vitePath = 'vite';
|
|
102
|
+
let reactPluginPath = '@vitejs/plugin-react';
|
|
103
|
+
try {
|
|
104
|
+
vitePath = projectRequire.resolve('vite');
|
|
105
|
+
reactPluginPath = projectRequire.resolve('@vitejs/plugin-react');
|
|
106
|
+
} catch {
|
|
107
|
+
// Use CLI's bundled version
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const { build: viteBuild } = await import(vitePath);
|
|
111
|
+
const reactModule = await import(reactPluginPath);
|
|
112
|
+
const react = reactModule.default;
|
|
113
|
+
|
|
114
|
+
// Build plugin list: auto-add React if no framework plugin present
|
|
115
|
+
const plugins = [...(userPlugins || [])];
|
|
116
|
+
if (plugins.length === 0 || !hasFrameworkPlugin(plugins)) {
|
|
117
|
+
plugins.unshift(react());
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
await viteBuild({
|
|
121
|
+
root: rootDir,
|
|
122
|
+
plugins,
|
|
123
|
+
build: {
|
|
124
|
+
ssr: entryServerPath,
|
|
125
|
+
outDir: ssrOutDir,
|
|
126
|
+
rollupOptions: {
|
|
127
|
+
output: {
|
|
128
|
+
format: 'esm',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
ssr: {
|
|
133
|
+
// Bundle all dependencies for SSR — we need import.meta.glob, MDX, etc.
|
|
134
|
+
// resolved at build time. Node built-ins are still externalized.
|
|
135
|
+
noExternal: true,
|
|
136
|
+
},
|
|
137
|
+
logLevel: 'warn',
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Steps 2–4: wrapped in try-finally so SSR artifacts are always cleaned up,
|
|
141
|
+
// even if an exception is thrown during module import, validation, or rendering.
|
|
142
|
+
let routeCount = 0;
|
|
143
|
+
try {
|
|
144
|
+
// Step 2: Import the built SSR entry
|
|
145
|
+
const ssrEntryPath = join(ssrOutDir, 'entry-server.js');
|
|
146
|
+
if (!existsSync(ssrEntryPath)) {
|
|
147
|
+
throw new Error(`SSR build did not produce entry-server.js at ${ssrEntryPath}`);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const ssrModule = await import(ssrEntryPath);
|
|
151
|
+
|
|
152
|
+
if (typeof ssrModule.render !== 'function') {
|
|
153
|
+
throw new Error(
|
|
154
|
+
'entry-server.tsx must export a render(url: string) function that returns HTML string'
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Step 3: Discover routes
|
|
159
|
+
// Priority: auto-discover from routeTree + merge getStaticPaths() if present
|
|
160
|
+
const discovered = new Set<string>();
|
|
161
|
+
|
|
162
|
+
// 3a. Auto-discover from exported routeTree (skips parameterized routes)
|
|
163
|
+
if (ssrModule.routeTree) {
|
|
164
|
+
const autoRoutes = extractRoutePaths(ssrModule.routeTree);
|
|
165
|
+
for (const r of autoRoutes) {
|
|
166
|
+
discovered.add(r);
|
|
167
|
+
}
|
|
168
|
+
logger.debug(`Auto-discovered ${autoRoutes.length} routes from route tree`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 3b. Merge paths from getStaticPaths() if exported (for parameterized routes, etc.)
|
|
172
|
+
if (typeof ssrModule.getStaticPaths === 'function') {
|
|
173
|
+
const extraRoutes = await ssrModule.getStaticPaths();
|
|
174
|
+
if (!Array.isArray(extraRoutes)) {
|
|
175
|
+
throw new Error(
|
|
176
|
+
'getStaticPaths() must return an array of URL paths (e.g., ["/", "/about"])'
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
for (const r of extraRoutes) {
|
|
180
|
+
discovered.add(r);
|
|
181
|
+
}
|
|
182
|
+
logger.debug(`getStaticPaths() added ${extraRoutes.length} paths`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Must have at least one source of routes
|
|
186
|
+
if (discovered.size === 0) {
|
|
187
|
+
throw new Error(
|
|
188
|
+
'No routes to pre-render. Export routeTree from entry-server.tsx for auto-discovery, ' +
|
|
189
|
+
'or export getStaticPaths() returning an array of URL paths.'
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const routes: string[] = [...discovered].sort();
|
|
194
|
+
routeCount = routes.length;
|
|
195
|
+
logger.debug(`Total: ${routes.length} routes for pre-rendering`);
|
|
196
|
+
|
|
197
|
+
// Step 4: Read template and pre-render each route
|
|
198
|
+
const template = readFileSync(templatePath, 'utf-8');
|
|
199
|
+
if (!template.includes('<!--app-html-->')) {
|
|
200
|
+
logger.warn(
|
|
201
|
+
'index.html is missing the <!--app-html--> placeholder; ' +
|
|
202
|
+
'pre-rendered content will not be injected into the page.'
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
for (const route of routes) {
|
|
207
|
+
try {
|
|
208
|
+
const html = await ssrModule.render(route);
|
|
209
|
+
const page = template.replace('<!--app-html-->', html);
|
|
210
|
+
|
|
211
|
+
let outPath: string;
|
|
212
|
+
if (route === '/') {
|
|
213
|
+
outPath = join(clientDir, 'index.html');
|
|
214
|
+
} else {
|
|
215
|
+
const dir = join(clientDir, route.slice(1));
|
|
216
|
+
mkdirSync(dir, { recursive: true });
|
|
217
|
+
outPath = join(dir, 'index.html');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
writeFileSync(outPath, page, 'utf-8');
|
|
221
|
+
} catch (err) {
|
|
222
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
223
|
+
logger.warn(`Failed to render route ${route}: ${message}`);
|
|
224
|
+
// Continue rendering other routes
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
} finally {
|
|
228
|
+
// Step 5: Clean up SSR build artifacts (always runs, even on error)
|
|
229
|
+
rmSync(ssrOutDir, { recursive: true, force: true });
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const duration = Date.now() - started;
|
|
233
|
+
logger.debug(`Static rendering complete: ${routeCount} routes in ${duration}ms`);
|
|
234
|
+
|
|
235
|
+
return { routes: routeCount, duration };
|
|
236
|
+
}
|
|
@@ -302,6 +302,7 @@ interface BuildResult {
|
|
|
302
302
|
workbench: { included: boolean; duration: number };
|
|
303
303
|
client: { included: boolean; duration: number };
|
|
304
304
|
server: { included: boolean; duration: number };
|
|
305
|
+
static: { included: boolean; duration: number; routes: number };
|
|
305
306
|
}
|
|
306
307
|
|
|
307
308
|
/**
|
|
@@ -318,6 +319,7 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
318
319
|
workbench: { included: false, duration: 0 },
|
|
319
320
|
client: { included: false, duration: 0 },
|
|
320
321
|
server: { included: false, duration: 0 },
|
|
322
|
+
static: { included: false, duration: 0, routes: 0 },
|
|
321
323
|
};
|
|
322
324
|
|
|
323
325
|
// Load config to check if workbench is enabled (dev mode only)
|
|
@@ -382,6 +384,22 @@ export async function runAllBuilds(options: Omit<ViteBuildOptions, 'mode'>): Pro
|
|
|
382
384
|
logger.debug('Skipping client build - no src/web/index.html found');
|
|
383
385
|
}
|
|
384
386
|
|
|
387
|
+
// 2b. Static rendering (if configured)
|
|
388
|
+
if (config?.render === 'static' && hasWebFrontend) {
|
|
389
|
+
logger.debug('Running static rendering (pre-rendering all routes)...');
|
|
390
|
+
const endStaticDiagnostic = collector?.startDiagnostic('static-render');
|
|
391
|
+
const { runStaticRender } = await import('./static-renderer');
|
|
392
|
+
const staticResult = await runStaticRender({
|
|
393
|
+
rootDir,
|
|
394
|
+
logger,
|
|
395
|
+
userPlugins: config?.plugins || [],
|
|
396
|
+
});
|
|
397
|
+
result.static.included = true;
|
|
398
|
+
result.static.duration = staticResult.duration;
|
|
399
|
+
result.static.routes = staticResult.routes;
|
|
400
|
+
endStaticDiagnostic?.();
|
|
401
|
+
}
|
|
402
|
+
|
|
385
403
|
// 3. Build workbench (if enabled in config)
|
|
386
404
|
if (workbenchConfig.enabled) {
|
|
387
405
|
logger.debug('Building workbench assets...');
|
|
@@ -113,6 +113,13 @@ export async function viteBundle(options: ViteBundleOptions): Promise<{ output:
|
|
|
113
113
|
if (result.workbench.included) {
|
|
114
114
|
output.push(tui.muted(`✓ Workbench built in ${result.workbench.duration}ms`));
|
|
115
115
|
}
|
|
116
|
+
if (result.static.included) {
|
|
117
|
+
output.push(
|
|
118
|
+
tui.muted(
|
|
119
|
+
`✓ ${result.static.routes} routes pre-rendered in ${result.static.duration}ms`
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
}
|
|
116
123
|
if (result.server.included) {
|
|
117
124
|
output.push(tui.muted(`✓ Server built in ${result.server.duration}ms`));
|
|
118
125
|
}
|
package/src/cmd/cloud/deploy.ts
CHANGED
|
@@ -95,7 +95,7 @@ export const domainSubcommand = createSubcommand({
|
|
|
95
95
|
message: `Checking DNS for ${domain}`,
|
|
96
96
|
clearOnSuccess: true,
|
|
97
97
|
callback: async () => {
|
|
98
|
-
return checkCustomDomainForDNS(project.projectId, [domain], config);
|
|
98
|
+
return checkCustomDomainForDNS(project.projectId, [domain], project.region, config);
|
|
99
99
|
},
|
|
100
100
|
});
|
|
101
101
|
|
|
@@ -117,11 +117,17 @@ export const domainSubcommand = createSubcommand({
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
tui.newline();
|
|
120
|
-
tui.warning(
|
|
120
|
+
tui.warning(
|
|
121
|
+
'DNS record not yet configured. Please add one of the following DNS records:'
|
|
122
|
+
);
|
|
121
123
|
tui.newline();
|
|
122
124
|
tui.output(` ${tui.colorInfo('Domain:')} ${tui.colorPrimary(result.domain)}`);
|
|
123
|
-
tui.output(` ${tui.colorInfo('
|
|
124
|
-
|
|
125
|
+
tui.output(` ${tui.colorInfo('CNAME:')} ${tui.colorPrimary(result.target)}`);
|
|
126
|
+
if (result.aRecordTarget) {
|
|
127
|
+
tui.output(
|
|
128
|
+
` ${tui.colorInfo('A:')} ${tui.colorPrimary(result.aRecordTarget)}`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
125
131
|
tui.newline();
|
|
126
132
|
|
|
127
133
|
if (isMisconfigured(result)) {
|
|
@@ -39,6 +39,7 @@ export const checkSubcommand = createSubcommand({
|
|
|
39
39
|
domain: z.string(),
|
|
40
40
|
recordType: z.string(),
|
|
41
41
|
target: z.string(),
|
|
42
|
+
aRecordTarget: z.string().optional(),
|
|
42
43
|
status: z.string(),
|
|
43
44
|
success: z.boolean(),
|
|
44
45
|
})
|
|
@@ -69,11 +70,17 @@ export const checkSubcommand = createSubcommand({
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
const results = jsonMode
|
|
72
|
-
? await checkCustomDomainForDNS(project.projectId, domainsToCheck, config)
|
|
73
|
+
? await checkCustomDomainForDNS(project.projectId, domainsToCheck, project.region, config)
|
|
73
74
|
: await tui.spinner({
|
|
74
75
|
message: `Checking DNS for ${domainsToCheck.length} ${tui.plural(domainsToCheck.length, 'domain', 'domains')}`,
|
|
75
76
|
clearOnSuccess: true,
|
|
76
|
-
callback: () =>
|
|
77
|
+
callback: () =>
|
|
78
|
+
checkCustomDomainForDNS(
|
|
79
|
+
project.projectId,
|
|
80
|
+
domainsToCheck,
|
|
81
|
+
project.region,
|
|
82
|
+
config
|
|
83
|
+
),
|
|
77
84
|
});
|
|
78
85
|
|
|
79
86
|
const domainResults = results.map((r) => {
|
|
@@ -106,6 +113,7 @@ export const checkSubcommand = createSubcommand({
|
|
|
106
113
|
domain: r.domain,
|
|
107
114
|
recordType: r.recordType,
|
|
108
115
|
target: r.target,
|
|
116
|
+
aRecordTarget: r.aRecordTarget,
|
|
109
117
|
status,
|
|
110
118
|
statusRaw,
|
|
111
119
|
success,
|
|
@@ -116,8 +124,10 @@ export const checkSubcommand = createSubcommand({
|
|
|
116
124
|
tui.newline();
|
|
117
125
|
for (const r of domainResults) {
|
|
118
126
|
console.log(` ${tui.colorInfo('Domain:')} ${tui.colorPrimary(r.domain)}`);
|
|
119
|
-
console.log(` ${tui.colorInfo('
|
|
120
|
-
|
|
127
|
+
console.log(` ${tui.colorInfo('CNAME:')} ${tui.colorPrimary(r.target)}`);
|
|
128
|
+
if (r.aRecordTarget) {
|
|
129
|
+
console.log(` ${tui.colorInfo('A:')} ${tui.colorPrimary(r.aRecordTarget)}`);
|
|
130
|
+
}
|
|
121
131
|
console.log(` ${tui.colorInfo('Status:')} ${r.status}`);
|
|
122
132
|
console.log();
|
|
123
133
|
}
|
|
@@ -128,7 +138,7 @@ export const checkSubcommand = createSubcommand({
|
|
|
128
138
|
} else {
|
|
129
139
|
const failCount = domainResults.filter((r) => !r.success).length;
|
|
130
140
|
tui.warning(
|
|
131
|
-
`${failCount} ${tui.plural(failCount, 'domain has', 'domains have')} DNS issues — add a CNAME record pointing to the
|
|
141
|
+
`${failCount} ${tui.plural(failCount, 'domain has', 'domains have')} DNS issues — add a CNAME or A record pointing to one of the targets shown above`
|
|
132
142
|
);
|
|
133
143
|
}
|
|
134
144
|
}
|
|
@@ -138,6 +148,7 @@ export const checkSubcommand = createSubcommand({
|
|
|
138
148
|
domain: r.domain,
|
|
139
149
|
recordType: r.recordType,
|
|
140
150
|
target: r.target,
|
|
151
|
+
aRecordTarget: r.aRecordTarget,
|
|
141
152
|
status: r.statusRaw,
|
|
142
153
|
success: r.success,
|
|
143
154
|
})),
|
|
@@ -310,25 +310,28 @@ async function textPrompt(options: {
|
|
|
310
310
|
async function importExistingProject(
|
|
311
311
|
opts: ReconcileOptions,
|
|
312
312
|
existingConfig: Project,
|
|
313
|
-
orgs: OrganizationList
|
|
313
|
+
orgs: OrganizationList,
|
|
314
|
+
options?: { skipPrompt?: boolean }
|
|
314
315
|
): Promise<ReconcileResult> {
|
|
315
316
|
const { dir, apiClient, config, logger } = opts;
|
|
316
317
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
318
|
+
if (!options?.skipPrompt) {
|
|
319
|
+
tui.warning(
|
|
320
|
+
"You don't have access to this project. It may have been deleted or transferred to another organization."
|
|
321
|
+
);
|
|
322
|
+
tui.newline();
|
|
321
323
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
324
|
+
const shouldImport = await tui.confirm(
|
|
325
|
+
'Would you like to import this project to your organization?',
|
|
326
|
+
true
|
|
327
|
+
);
|
|
326
328
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
329
|
+
if (!shouldImport) {
|
|
330
|
+
return { status: 'skipped', message: 'Project import cancelled.' };
|
|
331
|
+
}
|
|
330
332
|
|
|
331
|
-
|
|
333
|
+
tui.newline();
|
|
334
|
+
}
|
|
332
335
|
|
|
333
336
|
// Select org
|
|
334
337
|
const orgId = await selectOrg(orgs, config, existingConfig.orgId);
|
|
@@ -605,6 +608,21 @@ export async function runProjectImport(opts: ReconcileOptions): Promise<Reconcil
|
|
|
605
608
|
|
|
606
609
|
if (hasAccess) {
|
|
607
610
|
tui.info('This project is already registered and you have access to it.');
|
|
611
|
+
|
|
612
|
+
if (interactive) {
|
|
613
|
+
tui.newline();
|
|
614
|
+
const shouldReimport = await tui.confirm(
|
|
615
|
+
'Would you like to import it to a different organization?',
|
|
616
|
+
false
|
|
617
|
+
);
|
|
618
|
+
if (shouldReimport) {
|
|
619
|
+
tui.newline();
|
|
620
|
+
return await importExistingProject(opts, projectConfig, userOrgs, {
|
|
621
|
+
skipPrompt: true,
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
608
626
|
return { status: 'valid', project: projectConfig };
|
|
609
627
|
}
|
|
610
628
|
|
|
@@ -768,7 +768,8 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
|
|
|
768
768
|
const ok = await tui.confirm('Would you like to configure DNS now?', true);
|
|
769
769
|
if (ok) {
|
|
770
770
|
tui.newline();
|
|
771
|
-
|
|
771
|
+
const cloudRegion = region ?? process.env.AGENTUITY_REGION ?? 'usc';
|
|
772
|
+
await promptForDNS(projectId, _domains, cloudRegion, config);
|
|
772
773
|
}
|
|
773
774
|
}
|
|
774
775
|
|