context101-cli 0.1.0 → 0.1.2
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/context101.js +0 -0
- package/package.json +1 -4
- package/src/clone.js +29 -6
- package/src/config.js +2 -1
- package/src/defaults.js +1 -0
- package/src/deploy-env-load.js +5 -6
- package/src/init.js +37 -16
- package/src/main.js +4 -2
- package/src/parse-args.js +117 -65
- package/src/plan.js +1 -25
- package/src/prompt.js +15 -3
- package/src/stacks.js +20 -13
package/bin/context101.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context101-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Context101 self-host CLI. Use `npx context101-cli` or the `context101` bin. The public npm package named context101 is Context7's MCP, not this tool.",
|
|
6
6
|
"type": "module",
|
|
@@ -19,8 +19,5 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@inquirer/prompts": "^7.8.4"
|
|
22
|
-
},
|
|
23
|
-
"publishConfig": {
|
|
24
|
-
"access": "public"
|
|
25
22
|
}
|
|
26
23
|
}
|
package/src/clone.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
|
-
import { DEFAULT_AMPLIFY_REPO } from "./defaults.js";
|
|
4
|
+
import { DEFAULT_AMPLIFY_REPO, HOME_SRC_REL } from "./defaults.js";
|
|
4
5
|
import { findRepoRoot } from "./repo.js";
|
|
5
6
|
|
|
6
7
|
export const CLONE_URL = DEFAULT_AMPLIFY_REPO;
|
|
@@ -10,6 +11,10 @@ export function resolveCloneDir(cwd, dir) {
|
|
|
10
11
|
return path.resolve(cwd, dir || DEFAULT_CLONE_DIR);
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
export function homeSrcDir(homeDir = homedir()) {
|
|
15
|
+
return path.join(homeDir, HOME_SRC_REL);
|
|
16
|
+
}
|
|
17
|
+
|
|
13
18
|
export function ensureRepoRoot({
|
|
14
19
|
cwd,
|
|
15
20
|
dir,
|
|
@@ -17,16 +22,27 @@ export function ensureRepoRoot({
|
|
|
17
22
|
io,
|
|
18
23
|
dryRun = false,
|
|
19
24
|
exists = existsSync,
|
|
25
|
+
homeDir,
|
|
26
|
+
preferHomeClone = false,
|
|
20
27
|
} = {}) {
|
|
21
28
|
const existing = findRepoRoot(cwd, exists);
|
|
22
29
|
if (existing) return { repoRoot: existing, cloned: false };
|
|
23
30
|
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
31
|
+
const localTarget = resolveCloneDir(cwd, dir);
|
|
32
|
+
const alreadyLocal = findRepoRoot(localTarget, exists);
|
|
33
|
+
if (alreadyLocal) return { repoRoot: alreadyLocal, cloned: false };
|
|
34
|
+
|
|
35
|
+
const resolvedHome = homeDir ?? homedir();
|
|
36
|
+
const homeTarget = homeSrcDir(resolvedHome);
|
|
37
|
+
if (preferHomeClone) {
|
|
38
|
+
const alreadyHome = findRepoRoot(homeTarget, exists);
|
|
39
|
+
if (alreadyHome) return { repoRoot: alreadyHome, cloned: false };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const target = preferHomeClone && !dir ? homeTarget : localTarget;
|
|
27
43
|
|
|
28
44
|
if (dryRun) {
|
|
29
|
-
io?.write?.(`Would clone ${CLONE_URL} into ${
|
|
45
|
+
io?.write?.(`Would clone ${CLONE_URL} into ${displayCloneTarget(cwd, target, resolvedHome)}`);
|
|
30
46
|
return { repoRoot: target, cloned: false, wouldClone: true };
|
|
31
47
|
}
|
|
32
48
|
|
|
@@ -58,6 +74,13 @@ export function ensureRepoRoot({
|
|
|
58
74
|
error: `cloned ${target} but it is not a Context101 checkout (needs cdk/ and web/)`,
|
|
59
75
|
};
|
|
60
76
|
}
|
|
61
|
-
io?.ok?.(`cloned into ${
|
|
77
|
+
io?.ok?.(`cloned into ${displayCloneTarget(cwd, cloned, resolvedHome)}`);
|
|
62
78
|
return { repoRoot: cloned, cloned: true };
|
|
63
79
|
}
|
|
80
|
+
|
|
81
|
+
function displayCloneTarget(cwd, target, homeDir) {
|
|
82
|
+
if (homeDir && (target === homeDir || target.startsWith(homeDir + path.sep))) {
|
|
83
|
+
return `~${target.slice(homeDir.length)}`;
|
|
84
|
+
}
|
|
85
|
+
return path.relative(cwd, target) || target;
|
|
86
|
+
}
|
package/src/config.js
CHANGED
|
@@ -52,6 +52,7 @@ export async function runConfig(opts, ctx) {
|
|
|
52
52
|
envFile: opts.envFile,
|
|
53
53
|
home: opts.home,
|
|
54
54
|
cwd: ctx.cwd,
|
|
55
|
+
homeDir: ctx.homeDir,
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
if (opts.configAction === "set") {
|
|
@@ -85,7 +86,7 @@ async function writeConfig(opts, { io, filePath }) {
|
|
|
85
86
|
return 1;
|
|
86
87
|
}
|
|
87
88
|
if (!filePath) {
|
|
88
|
-
io.err("no deploy-env path.
|
|
89
|
+
io.err("no deploy-env path. Pass --home or --deploy-env.");
|
|
89
90
|
return 1;
|
|
90
91
|
}
|
|
91
92
|
|
package/src/defaults.js
CHANGED
|
@@ -10,6 +10,7 @@ export const BILLING_ENABLED = "false";
|
|
|
10
10
|
export const EXAMPLE_ENV_REL = "cdk/.deploy-env.example";
|
|
11
11
|
export const REPO_ENV_REL = "cdk/.deploy-env";
|
|
12
12
|
export const HOME_ENV_REL = ".context101/deploy-env";
|
|
13
|
+
export const HOME_SRC_REL = ".context101/src";
|
|
13
14
|
export const DEPLOY_CLI = "context101 deploy";
|
|
14
15
|
export const LIST_CLI = "context101 list";
|
|
15
16
|
export const DESTROY_CLI = "context101 destroy";
|
package/src/deploy-env-load.js
CHANGED
|
@@ -39,23 +39,22 @@ export function findDeployEnvPath({
|
|
|
39
39
|
home = false,
|
|
40
40
|
cwd,
|
|
41
41
|
exists = existsSync,
|
|
42
|
+
homeDir,
|
|
42
43
|
} = {}) {
|
|
44
|
+
const resolvedHome = homeDir ?? homedir();
|
|
43
45
|
if (envFile) {
|
|
44
46
|
return path.isAbsolute(envFile)
|
|
45
47
|
? envFile
|
|
46
48
|
: path.resolve(cwd ?? repoRoot ?? process.cwd(), envFile);
|
|
47
49
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return exists(homePath) ? homePath : homePath;
|
|
51
|
-
}
|
|
50
|
+
const homePath = path.join(resolvedHome, HOME_ENV_REL);
|
|
51
|
+
if (home) return homePath;
|
|
52
52
|
if (repoRoot) {
|
|
53
53
|
const repoPath = path.join(repoRoot, ...REPO_ENV_REL.split("/"));
|
|
54
54
|
if (exists(repoPath)) return repoPath;
|
|
55
55
|
}
|
|
56
|
-
const homePath = path.join(homedir(), HOME_ENV_REL);
|
|
57
56
|
if (exists(homePath)) return homePath;
|
|
58
|
-
return repoRoot ? path.join(repoRoot, ...REPO_ENV_REL.split("/")) :
|
|
57
|
+
return repoRoot ? path.join(repoRoot, ...REPO_ENV_REL.split("/")) : homePath;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
export function readDeployEnvFile(filePath, { readFile = readFileSync, exists = existsSync } = {}) {
|
package/src/init.js
CHANGED
|
@@ -15,10 +15,7 @@ import {
|
|
|
15
15
|
printChecks,
|
|
16
16
|
runChecks,
|
|
17
17
|
} from "./checks.js";
|
|
18
|
-
import {
|
|
19
|
-
formatAccessResult,
|
|
20
|
-
requestEmbeddingModelAccess,
|
|
21
|
-
} from "./bedrock-access.js";
|
|
18
|
+
import { requestEmbeddingModelAccess } from "./bedrock-access.js";
|
|
22
19
|
import {
|
|
23
20
|
isKnownEmbeddingModel,
|
|
24
21
|
listEmbeddingModels,
|
|
@@ -267,11 +264,22 @@ export async function runInit(opts, ctx) {
|
|
|
267
264
|
"no Amplify-capable GitHub PAT yet — set CTX_GH_TOKEN to a ghp_ or github_pat_ token before deploy"
|
|
268
265
|
);
|
|
269
266
|
}
|
|
270
|
-
io.write("");
|
|
271
|
-
io.write(nextSteps(plan));
|
|
272
|
-
io.write("");
|
|
273
267
|
|
|
274
|
-
|
|
268
|
+
let deploy = Boolean(answers.deploy);
|
|
269
|
+
if (!deploy && !opts.yes && tty) {
|
|
270
|
+
deploy = Boolean(
|
|
271
|
+
await askDeployNow(ctx, {
|
|
272
|
+
createRds: Boolean(answers.createRds),
|
|
273
|
+
seed: Boolean(answers.seed),
|
|
274
|
+
repository: answers.repository || "",
|
|
275
|
+
})
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (!deploy) {
|
|
280
|
+
io.write(nextSteps({ seed: answers.seed }));
|
|
281
|
+
return 0;
|
|
282
|
+
}
|
|
275
283
|
|
|
276
284
|
if (answers.repository && !githubReadyForAmplify(checks, answers)) {
|
|
277
285
|
io.err(
|
|
@@ -391,15 +399,28 @@ function withAwsAuth(env, { profile, accessKeyId, secretAccessKey } = {}) {
|
|
|
391
399
|
return next;
|
|
392
400
|
}
|
|
393
401
|
|
|
402
|
+
async function askDeployNow(ctx, details) {
|
|
403
|
+
if (typeof ctx.confirmDeploy === "function") {
|
|
404
|
+
return ctx.confirmDeploy(details);
|
|
405
|
+
}
|
|
406
|
+
const { promptDeployNow } = await import("./prompt.js");
|
|
407
|
+
return promptDeployNow(details);
|
|
408
|
+
}
|
|
409
|
+
|
|
394
410
|
function printBedrockAccess(results, io) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
411
|
+
const problems = (results || []).filter(
|
|
412
|
+
(result) => result.status === "needs-console" || result.status === "failed"
|
|
413
|
+
);
|
|
414
|
+
const granted = (results || []).filter((result) => result.status === "granted").length;
|
|
415
|
+
if (problems.length) {
|
|
416
|
+
const ids = problems
|
|
417
|
+
.slice(0, 2)
|
|
418
|
+
.map((result) => result.id)
|
|
419
|
+
.join(", ");
|
|
420
|
+
const extra = problems.length > 2 ? ` (+${problems.length - 2})` : "";
|
|
421
|
+
io.warn(`Bedrock: enable ${ids}${extra} in console → Model access`);
|
|
422
|
+
} else if (granted) {
|
|
423
|
+
io.ok("Bedrock access granted");
|
|
403
424
|
}
|
|
404
425
|
}
|
|
405
426
|
|
package/src/main.js
CHANGED
|
@@ -19,8 +19,10 @@ export async function main(argv, ctx) {
|
|
|
19
19
|
throw error;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
if (opts.help) {
|
|
23
|
-
|
|
22
|
+
if (opts.help || opts.command === "help") {
|
|
23
|
+
const topic =
|
|
24
|
+
opts.helpTopic ?? (opts.command !== "help" ? opts.command : null);
|
|
25
|
+
io.write(helpText(topic));
|
|
24
26
|
return 0;
|
|
25
27
|
}
|
|
26
28
|
|
package/src/parse-args.js
CHANGED
|
@@ -1,84 +1,90 @@
|
|
|
1
1
|
import { DRIVER_NEON, DRIVER_POSTGRES } from "./defaults.js";
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
npx context101-cli deploy
|
|
22
|
-
|
|
23
|
-
--dry-run print the plan; write nothing, deploy nothing
|
|
24
|
-
--yes, -y accept defaults (creates RDS if no --database-url)
|
|
3
|
+
const COMMAND_LINES = [
|
|
4
|
+
["init", "write deploy-env (default); TTY asks to deploy"],
|
|
5
|
+
["deploy", "deploy the AWS stack"],
|
|
6
|
+
["diff", "cdk diff with the same context"],
|
|
7
|
+
["synth", "cdk synth with the same context"],
|
|
8
|
+
["list", "list Context101 CloudFormation stacks"],
|
|
9
|
+
["destroy", "tear down a listed stack (name required)"],
|
|
10
|
+
["config", "show deploy-env keys (values redacted)"],
|
|
11
|
+
["config set", "write one key (chmod 600; value is not printed)"],
|
|
12
|
+
["help", "list commands"],
|
|
13
|
+
];
|
|
14
|
+
|
|
15
|
+
const TOPIC_HELP = {
|
|
16
|
+
init: `init — write deploy-env (default); TTY asks to deploy
|
|
17
|
+
|
|
18
|
+
--dry-run
|
|
19
|
+
--yes, -y accept defaults (creates RDS if no --database-url);
|
|
20
|
+
required --aws-profile when several exist
|
|
25
21
|
--force overwrite an existing env file
|
|
26
|
-
--dir <path> clone
|
|
22
|
+
--dir <path> clone here when not in a checkout
|
|
27
23
|
--deploy-env <path> default: <repo>/cdk/.deploy-env
|
|
28
|
-
--home
|
|
29
|
-
--database-url <url>
|
|
30
|
-
--create-rds
|
|
24
|
+
--home ~/.context101/deploy-env
|
|
25
|
+
--database-url <url>
|
|
26
|
+
--create-rds default when no URL
|
|
31
27
|
--database-driver ${DRIVER_NEON} | ${DRIVER_POSTGRES}
|
|
32
28
|
--database-prepare true | false
|
|
33
|
-
--aws-profile <name>
|
|
34
|
-
|
|
35
|
-
--aws-access-key-id used when no profile exists (also AWS_ACCESS_KEY_ID)
|
|
29
|
+
--aws-profile <name>
|
|
30
|
+
--aws-access-key-id
|
|
36
31
|
--aws-secret-access-key
|
|
37
|
-
|
|
38
|
-
--
|
|
39
|
-
|
|
40
|
-
--
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
deploy / diff / synth:
|
|
47
|
-
--seed upload knowledge/ once (first deploy only)
|
|
32
|
+
--repo <url> Amplify watch (skipped unless gh login is jginorio)
|
|
33
|
+
--embed-model <id>
|
|
34
|
+
--skip-bedrock-access
|
|
35
|
+
--seed
|
|
36
|
+
--deploy deploy after writing without asking`,
|
|
37
|
+
|
|
38
|
+
deploy: `deploy — deploy the AWS stack
|
|
39
|
+
|
|
40
|
+
--seed
|
|
48
41
|
--deploy-env <path>
|
|
49
42
|
--home
|
|
50
|
-
--dry-run
|
|
43
|
+
--dry-run`,
|
|
44
|
+
|
|
45
|
+
diff: `diff — cdk diff with the same context as deploy
|
|
46
|
+
|
|
47
|
+
--seed
|
|
48
|
+
--deploy-env <path>
|
|
49
|
+
--home
|
|
50
|
+
--dry-run`,
|
|
51
|
+
|
|
52
|
+
synth: `synth — cdk synth with the same context as deploy
|
|
53
|
+
|
|
54
|
+
--seed
|
|
55
|
+
--deploy-env <path>
|
|
56
|
+
--home
|
|
57
|
+
--dry-run`,
|
|
58
|
+
|
|
59
|
+
list: `list — list Context101 CloudFormation stacks (no checkout)
|
|
51
60
|
|
|
52
|
-
list:
|
|
53
61
|
--aws-profile <name>
|
|
54
62
|
--aws-access-key-id
|
|
55
|
-
--aws-secret-access-key
|
|
63
|
+
--aws-secret-access-key`,
|
|
56
64
|
|
|
57
|
-
destroy <
|
|
58
|
-
|
|
65
|
+
destroy: `destroy <name> — tear down a listed stack (clones if needed)
|
|
66
|
+
|
|
67
|
+
--yes, -y
|
|
59
68
|
--aws-profile <name>
|
|
60
69
|
--aws-access-key-id
|
|
61
70
|
--aws-secret-access-key
|
|
71
|
+
--dir <path>
|
|
62
72
|
--deploy-env <path>
|
|
63
73
|
--home
|
|
64
|
-
--dry-run
|
|
74
|
+
--dry-run`,
|
|
75
|
+
|
|
76
|
+
config: `config — show deploy-env keys (values redacted)
|
|
65
77
|
|
|
66
|
-
config:
|
|
67
78
|
--deploy-env <path>
|
|
68
|
-
--home
|
|
79
|
+
--home`,
|
|
69
80
|
|
|
70
|
-
|
|
71
|
-
npm run context101 -- init
|
|
72
|
-
npm run context101 -- deploy
|
|
73
|
-
npx context101-cli init
|
|
74
|
-
npx context101-cli deploy
|
|
75
|
-
context101 list
|
|
76
|
-
context101 destroy Context101Stack
|
|
77
|
-
context101 config
|
|
81
|
+
"config set": `config set KEY=value — write one key (chmod 600; value is not printed)
|
|
78
82
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
--deploy-env <path>
|
|
84
|
+
--home`,
|
|
85
|
+
|
|
86
|
+
help: `help [command] — list commands, or flags for one command`,
|
|
87
|
+
};
|
|
82
88
|
|
|
83
89
|
const INIT_ONLY = new Set([
|
|
84
90
|
"--yes",
|
|
@@ -101,6 +107,7 @@ const INIT_ONLY = new Set([
|
|
|
101
107
|
const DESTROY_FROM_INIT = new Set([
|
|
102
108
|
"--yes",
|
|
103
109
|
"-y",
|
|
110
|
+
"--dir",
|
|
104
111
|
"--aws-profile",
|
|
105
112
|
"--aws-access-key-id",
|
|
106
113
|
"--aws-secret-access-key",
|
|
@@ -125,10 +132,22 @@ const COMMANDS = {
|
|
|
125
132
|
remove: "destroy",
|
|
126
133
|
rm: "destroy",
|
|
127
134
|
config: "config",
|
|
135
|
+
help: "help",
|
|
128
136
|
};
|
|
129
137
|
|
|
130
|
-
export function helpText() {
|
|
131
|
-
|
|
138
|
+
export function helpText(topic) {
|
|
139
|
+
if (topic) {
|
|
140
|
+
const key = COMMANDS[topic] ?? topic;
|
|
141
|
+
return TOPIC_HELP[key] ?? helpText();
|
|
142
|
+
}
|
|
143
|
+
const nameW = Math.max(...COMMAND_LINES.map(([name]) => name.length));
|
|
144
|
+
return [
|
|
145
|
+
"Usage: context101 <command>",
|
|
146
|
+
"",
|
|
147
|
+
...COMMAND_LINES.map(([name, desc]) => ` ${name.padEnd(nameW)} ${desc}`),
|
|
148
|
+
"",
|
|
149
|
+
"npx context101 (unscoped) is Context7's MCP — use context101-cli.",
|
|
150
|
+
].join("\n");
|
|
132
151
|
}
|
|
133
152
|
|
|
134
153
|
export function parseArgs(argv) {
|
|
@@ -157,24 +176,30 @@ export function parseArgs(argv) {
|
|
|
157
176
|
configAction: "show",
|
|
158
177
|
configKey: null,
|
|
159
178
|
configValue: null,
|
|
179
|
+
helpTopic: null,
|
|
160
180
|
};
|
|
161
181
|
|
|
162
182
|
const args = [...argv];
|
|
163
183
|
if (args.length === 0) return opts;
|
|
164
184
|
|
|
165
185
|
const first = args[0];
|
|
166
|
-
if (
|
|
186
|
+
if (first === "--help" || first === "-h") {
|
|
187
|
+
opts.command = "help";
|
|
188
|
+
opts.help = true;
|
|
189
|
+
args.shift();
|
|
190
|
+
} else if (COMMANDS[first]) {
|
|
167
191
|
opts.command = COMMANDS[first];
|
|
168
192
|
args.shift();
|
|
169
|
-
} else if (first === "help" || first === "--help" || first === "-h") {
|
|
170
|
-
opts.help = true;
|
|
171
|
-
return opts;
|
|
172
193
|
} else if (!first.startsWith("-")) {
|
|
173
194
|
const err = new Error(`unknown command: ${first}`);
|
|
174
195
|
err.code = "USAGE";
|
|
175
196
|
throw err;
|
|
176
197
|
}
|
|
177
198
|
|
|
199
|
+
if (opts.command === "help") {
|
|
200
|
+
return parseHelpArgs(opts, args);
|
|
201
|
+
}
|
|
202
|
+
|
|
178
203
|
if (opts.command === "config" && args[0] === "set") {
|
|
179
204
|
args.shift();
|
|
180
205
|
const pair = args.shift();
|
|
@@ -283,6 +308,33 @@ export function parseArgs(argv) {
|
|
|
283
308
|
return opts;
|
|
284
309
|
}
|
|
285
310
|
|
|
311
|
+
function parseHelpArgs(opts, args) {
|
|
312
|
+
opts.help = true;
|
|
313
|
+
if (args[0] && !args[0].startsWith("-")) {
|
|
314
|
+
const topic = args.shift();
|
|
315
|
+
if (topic === "config" && args[0] === "set") {
|
|
316
|
+
args.shift();
|
|
317
|
+
opts.helpTopic = "config set";
|
|
318
|
+
} else if (COMMANDS[topic] && topic !== "help") {
|
|
319
|
+
opts.helpTopic = COMMANDS[topic];
|
|
320
|
+
} else if (topic === "help") {
|
|
321
|
+
opts.helpTopic = "help";
|
|
322
|
+
} else {
|
|
323
|
+
const err = new Error(`unknown command: ${topic}`);
|
|
324
|
+
err.code = "USAGE";
|
|
325
|
+
throw err;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
while (args.length) {
|
|
329
|
+
const arg = args.shift();
|
|
330
|
+
if (arg === "--help" || arg === "-h") continue;
|
|
331
|
+
const err = new Error(`unknown flag: ${arg}`);
|
|
332
|
+
err.code = "USAGE";
|
|
333
|
+
throw err;
|
|
334
|
+
}
|
|
335
|
+
return opts;
|
|
336
|
+
}
|
|
337
|
+
|
|
286
338
|
function flagAllowed(command, arg) {
|
|
287
339
|
if (!INIT_ONLY.has(arg)) return true;
|
|
288
340
|
if (command === "init") return true;
|
package/src/plan.js
CHANGED
|
@@ -83,29 +83,5 @@ function bootstrapLabel(plan) {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export function nextSteps(plan) {
|
|
86
|
-
|
|
87
|
-
? "CDK will create RDS Postgres and apply the control-plane schema. Fetch the secret via ControlPlaneDbSecretArn — the password is never printed."
|
|
88
|
-
: null;
|
|
89
|
-
const next = [
|
|
90
|
-
`Next: ${deployCommand(plan.seed)}`,
|
|
91
|
-
plan.seed ? null : "First time? add --seed to upload the example knowledge/ files once.",
|
|
92
|
-
rds,
|
|
93
|
-
];
|
|
94
|
-
if (plan.repository) {
|
|
95
|
-
return [
|
|
96
|
-
...next,
|
|
97
|
-
"After Amplify is up (~4 min), open /setup on WebAppDefaultDomain (or your own domain).",
|
|
98
|
-
"Leave BETTER_AUTH_URL / APP_URL unset unless you bring your own host. CDK fills the Amplify default.",
|
|
99
|
-
]
|
|
100
|
-
.filter(Boolean)
|
|
101
|
-
.join("\n");
|
|
102
|
-
}
|
|
103
|
-
return [
|
|
104
|
-
...next,
|
|
105
|
-
"Amplify is skipped — this deploy is the AWS stack only (no GitHub-watched web app).",
|
|
106
|
-
"Run the web app from web/, or re-run init with --repo when you want Amplify.",
|
|
107
|
-
"Leave BETTER_AUTH_URL / APP_URL unset unless you bring your own host.",
|
|
108
|
-
]
|
|
109
|
-
.filter(Boolean)
|
|
110
|
-
.join("\n");
|
|
86
|
+
return deployCommand(plan.seed);
|
|
111
87
|
}
|
package/src/prompt.js
CHANGED
|
@@ -6,12 +6,24 @@ import {
|
|
|
6
6
|
import { inferDriver, inferPrepare } from "./env-file.js";
|
|
7
7
|
import { normalizeRepoUrl } from "./repo.js";
|
|
8
8
|
|
|
9
|
+
export function deployNowMessage({ createRds = false } = {}) {
|
|
10
|
+
return createRds
|
|
11
|
+
? "Deploy the stack now? (CDK + Docker; creates RDS)"
|
|
12
|
+
: "Deploy the stack now?";
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function promptDeployNow(details = {}) {
|
|
16
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
17
|
+
return confirm({
|
|
18
|
+
message: deployNowMessage(details),
|
|
19
|
+
default: false,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
export async function promptAnswers({ defaults, io, exec, env }) {
|
|
10
24
|
const { confirm, input, password, select } = await import("@inquirer/prompts");
|
|
11
25
|
|
|
12
|
-
io.write("This writes a local secrets file.
|
|
13
|
-
io.write(" context101 deploy");
|
|
14
|
-
io.write("Press ^C to quit.");
|
|
26
|
+
io.write("This writes a local secrets file. Press ^C to quit.");
|
|
15
27
|
io.write("");
|
|
16
28
|
|
|
17
29
|
const region = await input({
|
package/src/stacks.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEPLOY_CLI, DESTROY_CLI, LIST_CLI, SMOOTH_REGION } from "./defaults.js";
|
|
2
2
|
import { runCdk } from "./cdk-invoke.js";
|
|
3
|
+
import { ensureRepoRoot } from "./clone.js";
|
|
3
4
|
import { createExec } from "./exec.js";
|
|
4
|
-
import { findRepoRoot } from "./repo.js";
|
|
5
5
|
import { banner, writers } from "./style.js";
|
|
6
6
|
|
|
7
7
|
export function parseStackSummaries(payload) {
|
|
@@ -70,12 +70,6 @@ export async function runList(opts, ctx) {
|
|
|
70
70
|
|
|
71
71
|
banner(ctx);
|
|
72
72
|
|
|
73
|
-
const repoRoot = findRepoRoot(ctx.cwd);
|
|
74
|
-
if (!repoRoot) {
|
|
75
|
-
io.err("run this from a Context101 checkout (needs cdk/ and web/).");
|
|
76
|
-
return 1;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
73
|
const env = withAwsAuth(ctx.env ?? {}, {
|
|
80
74
|
profile: opts.awsProfile,
|
|
81
75
|
accessKeyId: opts.awsAccessKeyId,
|
|
@@ -101,12 +95,6 @@ export async function runDestroy(opts, ctx) {
|
|
|
101
95
|
io.write("");
|
|
102
96
|
}
|
|
103
97
|
|
|
104
|
-
const repoRoot = findRepoRoot(ctx.cwd);
|
|
105
|
-
if (!repoRoot) {
|
|
106
|
-
io.err("run this from a Context101 checkout (needs cdk/ and web/).");
|
|
107
|
-
return 1;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
98
|
const stackName = String(opts.stackName || "").trim();
|
|
111
99
|
if (!stackName) {
|
|
112
100
|
io.err(`destroy needs a stack name from \`${LIST_CLI}\`.`);
|
|
@@ -157,6 +145,25 @@ export async function runDestroy(opts, ctx) {
|
|
|
157
145
|
io.warn(
|
|
158
146
|
"Non-default brains are not in CloudFormation — delete them from /brains first."
|
|
159
147
|
);
|
|
148
|
+
|
|
149
|
+
const checkout = ensureRepoRoot({
|
|
150
|
+
cwd: ctx.cwd,
|
|
151
|
+
dir: opts.dir,
|
|
152
|
+
exec,
|
|
153
|
+
io,
|
|
154
|
+
preferHomeClone: true,
|
|
155
|
+
homeDir: ctx.homeDir,
|
|
156
|
+
});
|
|
157
|
+
if (checkout.error) {
|
|
158
|
+
io.err(checkout.error);
|
|
159
|
+
return 1;
|
|
160
|
+
}
|
|
161
|
+
const repoRoot = checkout.repoRoot;
|
|
162
|
+
if (!repoRoot) {
|
|
163
|
+
io.err("could not find or clone a Context101 checkout (needs cdk/ and web/).");
|
|
164
|
+
return 1;
|
|
165
|
+
}
|
|
166
|
+
|
|
160
167
|
io.write(`Destroying ${stackName}…`);
|
|
161
168
|
return (ctx.runDeploy ?? runCdk)({
|
|
162
169
|
repoRoot,
|