@m6d/cortex-cli 0.13.0 → 0.15.0
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/README.md +94 -26
- package/package.json +1 -1
- package/src/cli.ts +2 -0
- package/src/commands/apply.ts +171 -44
- package/src/commands/management.ts +41 -22
- package/src/commands/new.ts +48 -25
- package/src/commands/setup.ts +611 -0
- package/src/contracts/datasets/dataset-sql.ts +22 -5
- package/src/contracts/datasets/datasets.ts +139 -16
- package/src/contracts/egress-policy/scrub.ts +11 -8
- package/src/contracts/json/index.ts +21 -0
- package/src/contracts/manifest/index.ts +223 -55
- package/src/contracts/server/index.ts +109 -9
- package/src/contracts/server/reserved-names.fixtures.json +1 -3
- package/src/contracts/wire/index.ts +42 -3
- package/src/management/client.ts +14 -0
- package/src/management/profiles.ts +6 -4
- package/src/scaffold/files.ts +183 -144
- package/src/scaffold/ports.ts +5 -6
- package/src/scaffold/templates/cspell.json.txt +41 -0
- package/src/scaffold/templates/dockerignore.txt +3 -4
- package/src/scaffold/templates/gitignore.txt +1 -2
- package/src/scaffold/templates/setup.ts.txt +18 -26
- package/src/ui/prompts.ts +32 -10
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "0.2",
|
|
3
|
+
"language": "en",
|
|
4
|
+
"words": ["mprocs"],
|
|
5
|
+
"ignorePaths": [
|
|
6
|
+
"node_modules/**",
|
|
7
|
+
"out/**",
|
|
8
|
+
"build/**",
|
|
9
|
+
"**/dist/**",
|
|
10
|
+
"coverage/**",
|
|
11
|
+
"*.tsbuildinfo",
|
|
12
|
+
"bun.lock",
|
|
13
|
+
"package-lock.json",
|
|
14
|
+
"pnpm-lock.yaml",
|
|
15
|
+
"yarn.lock",
|
|
16
|
+
"*.db",
|
|
17
|
+
"*.sqlite",
|
|
18
|
+
"scratch.*",
|
|
19
|
+
".env*",
|
|
20
|
+
"**/*.min.js",
|
|
21
|
+
"**/*.min.css",
|
|
22
|
+
"**/db/migrations/**",
|
|
23
|
+
"**/i18n/**",
|
|
24
|
+
"docs",
|
|
25
|
+
".claude",
|
|
26
|
+
".angular",
|
|
27
|
+
".vercel/**",
|
|
28
|
+
"vendor/**",
|
|
29
|
+
".gitignore"
|
|
30
|
+
],
|
|
31
|
+
"dictionaries": [
|
|
32
|
+
"typescript",
|
|
33
|
+
"node",
|
|
34
|
+
"npm",
|
|
35
|
+
"html",
|
|
36
|
+
"css",
|
|
37
|
+
"bash",
|
|
38
|
+
"companies",
|
|
39
|
+
"softwareTerms"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
#
|
|
1
|
+
# .env never goes into an image: it holds this checkout's secrets. With
|
|
2
|
+
# .env.example left out too, setup.ts writes none during the image's own
|
|
3
|
+
# `bun install`.
|
|
4
4
|
.env*
|
|
5
|
-
cortex.env*
|
|
6
5
|
node_modules/
|
|
7
6
|
.git/
|
|
@@ -2,14 +2,13 @@ import { randomBytes } from "node:crypto";
|
|
|
2
2
|
import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
|
|
4
4
|
/*
|
|
5
|
-
* Writes .env
|
|
6
|
-
*
|
|
7
|
-
* generated here, the Compose project this
|
|
8
|
-
* them. A value already set is never
|
|
9
|
-
* and secrets of its own, and a rerun
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* copies, as in an image build, it writes nothing.
|
|
5
|
+
* Writes .env on every `bun install`: it starts from the committed
|
|
6
|
+
* .env.example, or from .env when there is one, and each value left blank
|
|
7
|
+
* that is listed below is generated here, the Compose project this
|
|
8
|
+
* checkout's stack runs as among them. A value already set is never
|
|
9
|
+
* changed, so a fresh clone gets a stack and secrets of its own, and a rerun
|
|
10
|
+
* changes nothing. Without either file, as in an image build, it writes
|
|
11
|
+
* nothing.
|
|
13
12
|
*/
|
|
14
13
|
|
|
15
14
|
const token = () => randomBytes(32).toString("base64url");
|
|
@@ -24,29 +23,22 @@ const project =
|
|
|
24
23
|
.replace(/^-+|-+$/g, "") || "cortex";
|
|
25
24
|
|
|
26
25
|
const GENERATED = [
|
|
27
|
-
["
|
|
28
|
-
["
|
|
29
|
-
["
|
|
26
|
+
["COMPOSE_PROJECT_NAME", () => `${project}-${randomBytes(4).toString("hex")}`],
|
|
27
|
+
["CORTEX_SERVER_KEY", token],
|
|
28
|
+
["DEFAULT_ADMIN_PASSWORD", token],
|
|
30
29
|
// Cortex takes management keys only under this prefix. cspell:ignore mgmt
|
|
31
|
-
["
|
|
32
|
-
["
|
|
33
|
-
["
|
|
30
|
+
["BOOTSTRAP_MANAGEMENT_KEY", () => `cortex_mgmt_${token()}`],
|
|
31
|
+
["BETTER_AUTH_SECRET", key],
|
|
32
|
+
["SECRETS_MASTER_KEY", key],
|
|
34
33
|
] as const;
|
|
35
34
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
for (const file of [".env", "cortex.env"]) {
|
|
39
|
-
const source = existsSync(file) ? file : `${file}.example`;
|
|
40
|
-
if (!existsSync(source)) continue;
|
|
35
|
+
const source = existsSync(".env") ? ".env" : ".env.example";
|
|
36
|
+
if (existsSync(source)) {
|
|
41
37
|
// Only its owner reads a file of secrets, however it was first created.
|
|
42
|
-
if (source ===
|
|
38
|
+
if (source === ".env") chmodSync(".env", 0o600);
|
|
43
39
|
let text = readFileSync(source, "utf8");
|
|
44
|
-
|
|
45
|
-
text = text.replace(/^COMPOSE_PROJECT_NAME=.*$/m, "COMPOSE_PROJECT_NAME=");
|
|
46
|
-
}
|
|
47
|
-
for (const [target, variable, generate] of GENERATED) {
|
|
48
|
-
if (target !== file) continue;
|
|
40
|
+
for (const [variable, generate] of GENERATED) {
|
|
49
41
|
text = text.replace(new RegExp(`^${variable}=$`, "m"), `${variable}=${generate()}`);
|
|
50
42
|
}
|
|
51
|
-
writeFileSync(
|
|
43
|
+
writeFileSync(".env", text, { mode: 0o600 });
|
|
52
44
|
}
|
package/src/ui/prompts.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
log,
|
|
15
15
|
outro,
|
|
16
16
|
password,
|
|
17
|
+
select,
|
|
17
18
|
spinner,
|
|
18
19
|
text,
|
|
19
20
|
} from "@clack/prompts";
|
|
@@ -50,29 +51,50 @@ export function askName(check: (name: string) => string | undefined) {
|
|
|
50
51
|
);
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
/**
|
|
54
|
-
export function
|
|
55
|
-
|
|
54
|
+
/** One of `options`, by its value; the first is the default. */
|
|
55
|
+
export function askChoice<const TValue extends string>(
|
|
56
|
+
message: string,
|
|
57
|
+
options: Parameters<typeof select<TValue>>[0]["options"],
|
|
58
|
+
) {
|
|
59
|
+
return orExit(select({ message, options }));
|
|
56
60
|
}
|
|
57
61
|
|
|
58
|
-
/** A
|
|
59
|
-
export function
|
|
62
|
+
/** A yes-or-no question a flag left open, answered no unless the caller says otherwise. */
|
|
63
|
+
export function askConfirm(message: string, initialValue = false) {
|
|
64
|
+
return orExit(confirm({ message, initialValue }));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A required value a command was not given: asked by name, re-asked while
|
|
69
|
+
* empty or while `check` returns a complaint about the trimmed value.
|
|
70
|
+
*/
|
|
71
|
+
export function askValue(
|
|
72
|
+
name: string,
|
|
73
|
+
hint?: string,
|
|
74
|
+
check: (value: string) => string | undefined = () => undefined,
|
|
75
|
+
) {
|
|
60
76
|
return orExit(
|
|
61
77
|
text({
|
|
62
78
|
message: name,
|
|
63
79
|
placeholder: hint,
|
|
64
|
-
validate: (value)
|
|
65
|
-
(value ?? "").trim()
|
|
80
|
+
validate: function (value) {
|
|
81
|
+
const candidate = (value ?? "").trim();
|
|
82
|
+
return candidate.length === 0 ? `${name} is required.` : check(candidate);
|
|
83
|
+
},
|
|
66
84
|
}),
|
|
67
85
|
);
|
|
68
86
|
}
|
|
69
87
|
|
|
70
|
-
/** A credential: typed masked, never echoed. */
|
|
71
|
-
export function askSecret(
|
|
88
|
+
/** A credential: typed masked, never echoed, and re-asked while `check` complains. */
|
|
89
|
+
export function askSecret(
|
|
90
|
+
name: string,
|
|
91
|
+
check: (value: string) => string | undefined = () => undefined,
|
|
92
|
+
) {
|
|
72
93
|
return orExit(
|
|
73
94
|
password({
|
|
74
95
|
message: name,
|
|
75
|
-
validate: (value) =>
|
|
96
|
+
validate: (value) =>
|
|
97
|
+
(value ?? "").length === 0 ? `${name} is required.` : check(value ?? ""),
|
|
76
98
|
}),
|
|
77
99
|
);
|
|
78
100
|
}
|