@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
package/src/commands/new.ts
CHANGED
|
@@ -6,7 +6,8 @@ import type { Command } from "@commander-js/extra-typings";
|
|
|
6
6
|
import { CORTEX_MANIFEST_ID } from "@cortex/contracts/manifest";
|
|
7
7
|
|
|
8
8
|
import pkg from "../../package.json";
|
|
9
|
-
import {
|
|
9
|
+
import { askProvider } from "@/commands/setup";
|
|
10
|
+
import { AGENT_SLUG, manifestIdOf, scaffoldFiles } from "@/scaffold/files";
|
|
10
11
|
import { allocatePorts, type Ports } from "@/scaffold/ports";
|
|
11
12
|
import { askConfirm, askName, intro, log, outro, runSteps } from "@/ui/prompts";
|
|
12
13
|
import * as report from "@/ui/report";
|
|
@@ -24,12 +25,13 @@ export function registerNew(program: Command<[], { verbose?: true }>) {
|
|
|
24
25
|
.helpGroup("Project:")
|
|
25
26
|
.description("Scaffold a backend, its agent, and Cortex to run it on")
|
|
26
27
|
.argument("[name]", "Directory to create, and the generated package name")
|
|
27
|
-
// Both halves of the toggle, so the flag can answer its question either
|
|
28
|
-
// way and `--yes` is not the only way to say "no". Declaring the positive
|
|
29
|
-
// first leaves the value `undefined` when neither is passed, which is
|
|
30
|
-
// what marks the question as still unanswered.
|
|
31
28
|
.option("--datasets", "Serve an example table as a dataset host")
|
|
32
|
-
|
|
29
|
+
// Both halves of the toggle, so the flag can answer its question either
|
|
30
|
+
// way and `--yes` is not the only way to say "yes". Declaring the
|
|
31
|
+
// positive first leaves the value `undefined` when neither is passed,
|
|
32
|
+
// which is what marks the question as still unanswered.
|
|
33
|
+
.option("--setup", `Set up the ${AGENT_SLUG} agent on the first bun run dev`)
|
|
34
|
+
.option("--no-setup", "Leave Cortex empty; you register the backend yourself")
|
|
33
35
|
.option("--yes", "Accept the defaults instead of asking");
|
|
34
36
|
|
|
35
37
|
command.action(async function (name, options) {
|
|
@@ -39,7 +41,7 @@ export function registerNew(program: Command<[], { verbose?: true }>) {
|
|
|
39
41
|
});
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
type Options = { datasets?: boolean; yes?:
|
|
44
|
+
type Options = { datasets?: true; setup?: boolean; yes?: true; verbose: boolean };
|
|
43
45
|
|
|
44
46
|
async function scaffold(name: string | undefined, options: Options) {
|
|
45
47
|
const { verbose } = options;
|
|
@@ -61,17 +63,15 @@ async function scaffold(name: string | undefined, options: Options) {
|
|
|
61
63
|
|
|
62
64
|
const project = name ?? (await askName(checkName)).trim();
|
|
63
65
|
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
options.datasets ??
|
|
67
|
-
(interactive && (await askConfirm("Serve an example table as a dataset host?")));
|
|
66
|
+
const datasets = options.datasets === true;
|
|
67
|
+
const { setup, provider } = await askSetup(options.setup, interactive);
|
|
68
68
|
|
|
69
69
|
const target = resolve(process.cwd(), project);
|
|
70
70
|
|
|
71
71
|
// Drawn here rather than inside the generators, which stay pure: picking a
|
|
72
72
|
// port means probing the machine for a free one.
|
|
73
73
|
const ports = allocatePorts();
|
|
74
|
-
const files = scaffoldFiles({ name: project, datasets, ports });
|
|
74
|
+
const files = scaffoldFiles({ name: project, datasets, setup, ports, env: provider?.env });
|
|
75
75
|
let failedInstall: string | undefined;
|
|
76
76
|
|
|
77
77
|
await runSteps([
|
|
@@ -81,7 +81,8 @@ async function scaffold(name: string | undefined, options: Options) {
|
|
|
81
81
|
for (const [path, contents] of Object.entries(files)) {
|
|
82
82
|
const file = join(target, path);
|
|
83
83
|
mkdirSync(dirname(file), { recursive: true });
|
|
84
|
-
|
|
84
|
+
// .env holds the provider's key before setup.ts adds the rest.
|
|
85
|
+
writeFileSync(file, contents, { mode: path === ".env" ? 0o600 : 0o644 });
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
const summary = [
|
|
@@ -89,6 +90,7 @@ async function scaffold(name: string | undefined, options: Options) {
|
|
|
89
90
|
...(datasets ? ["dataset host"] : []),
|
|
90
91
|
"manifest",
|
|
91
92
|
"Cortex",
|
|
93
|
+
...(setup ? ["first-run setup"] : []),
|
|
92
94
|
];
|
|
93
95
|
return `Wrote ${Object.keys(files).length} files to ./${project}\n${summary.join(" · ")}`;
|
|
94
96
|
},
|
|
@@ -136,7 +138,25 @@ async function scaffold(name: string | undefined, options: Options) {
|
|
|
136
138
|
if (failedInstall !== undefined) warnInstall(project, failedInstall, verbose);
|
|
137
139
|
|
|
138
140
|
outro(`Done in ${seconds(started)}`);
|
|
139
|
-
process.stdout.write(nextSteps(project, ports));
|
|
141
|
+
process.stdout.write(nextSteps(project, ports, setup, provider !== undefined));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Whether the first `bun run dev` sets up the agent, and the model provider
|
|
146
|
+
* it runs on. A flag settles the first question; otherwise it is asked, or
|
|
147
|
+
* under `--yes` answered yes. The provider has no default, so only a terminal
|
|
148
|
+
* asks for one; without it, setup registers the server and stops.
|
|
149
|
+
*/
|
|
150
|
+
async function askSetup(flag: boolean | undefined, interactive: boolean) {
|
|
151
|
+
const setup =
|
|
152
|
+
flag ??
|
|
153
|
+
(!interactive ||
|
|
154
|
+
(await askConfirm(
|
|
155
|
+
`Set up the ${AGENT_SLUG} agent when you first run bun run dev?`,
|
|
156
|
+
true,
|
|
157
|
+
)));
|
|
158
|
+
const provider = setup && interactive ? await askProvider() : undefined;
|
|
159
|
+
return { setup, provider };
|
|
140
160
|
}
|
|
141
161
|
|
|
142
162
|
/**
|
|
@@ -156,17 +176,20 @@ function warnInstall(project: string, output: string, verbose: boolean) {
|
|
|
156
176
|
);
|
|
157
177
|
}
|
|
158
178
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
step(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
179
|
+
/** What the first `bun run dev` sets up: the agent, the server alone (no model yet), or nothing. */
|
|
180
|
+
function nextSteps(project: string, ports: Ports, setup: boolean, provider: boolean) {
|
|
181
|
+
const runs = {
|
|
182
|
+
agent: step("bun run dev", `→ sets up ${AGENT_SLUG}, then prints where to chat`),
|
|
183
|
+
server:
|
|
184
|
+
step("bun run dev", "→ registers the server") +
|
|
185
|
+
step("bun cortex setup", "adds a model provider, then applies"),
|
|
186
|
+
none:
|
|
187
|
+
step("bun run dev", `→ Cortex at http://localhost:${ports.cortex}`) +
|
|
188
|
+
step("README.md", "register the server, then bun cortex apply"),
|
|
189
|
+
};
|
|
190
|
+
const run = setup ? (provider ? runs.agent : runs.server) : runs.none;
|
|
191
|
+
|
|
192
|
+
return `\nNext steps:\n\n${step(`cd ${project}`)}${run}\n`;
|
|
170
193
|
}
|
|
171
194
|
|
|
172
195
|
async function install(cwd: string) {
|