@nightowlsdev/cli 0.1.1 → 0.2.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 +22 -5
- package/dist/cli.js +15 -11
- package/dist/{mcp-3ZFDXVDT.js → mcp-AX7MPTKC.js} +1 -1
- package/package.json +15 -14
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@ npx @nightowlsdev/cli init
|
|
|
22
22
|
| `owl <plugin> <cmd>` | Run a plugin's own subcommand (e.g. `owl storage-supabase info`, `owl runner-nextjs routes`). `owl <plugin> --help` lists a plugin's commands; `owl <plugin> <cmd> --help` shows a command's flags. |
|
|
23
23
|
| `owl db install` | (Re-)install Night Owls' migrations into the host's classic `supabase/migrations/` as timestamped `.sql` files, so they run with the app's own via `supabase db push`. Useful after upgrading an adapter. Idempotent. Flag: `--out <dir>` (default `supabase/migrations`). |
|
|
24
24
|
| `owl db types` | Generate TypeScript types for the `nightowls` schema (`supabase gen types typescript --schema nightowls`). |
|
|
25
|
+
| `owl mcp` | Start the Night Owls MCP server on stdio (exposes `nightowls_*` tools to external coding agents such as Claude Code or Cursor). |
|
|
25
26
|
|
|
26
27
|
## Adapters and what `owl install` wires
|
|
27
28
|
|
|
@@ -45,6 +46,7 @@ provider wires `modelFactory` and `models.allow` is env-driven from it).
|
|
|
45
46
|
| `model-openrouter` | model | any model via OpenRouter. env `OPENROUTER_API_KEY`, `MODEL_ID`; config `modelFactory = openrouterModels()`. Command: `info`. |
|
|
46
47
|
| `model-anthropic` | model | Anthropic Claude models (native `@ai-sdk/anthropic`). env `ANTHROPIC_API_KEY`, `MODEL_ID`; config `modelFactory = anthropicModels()`. Command: `info`. |
|
|
47
48
|
| `model-openai` | model | OpenAI models (native `@ai-sdk/openai`). env `OPENAI_API_KEY`, `MODEL_ID`; config `modelFactory = openaiModels()`. Command: `info`. |
|
|
49
|
+
| `model-ollama` | model | Models via Ollama (OpenAI-compatible endpoint). Local needs **no API key**; Ollama Cloud uses one. env `OLLAMA_BASE_URL` (default `http://localhost:11434/v1`), `OLLAMA_API_KEY` (Cloud only), `MODEL_ID` (e.g. `llama3.1`); config `modelFactory = ollamaModels()`. Command: `info`. |
|
|
48
50
|
|
|
49
51
|
Telemetry composing is verified at the gate: the generated `nightowls.config.ts` with storage + runner + auth
|
|
50
52
|
+ a model provider (`modelFactory = anthropicModels()`) + **both** telemetry exporters **parses and
|
|
@@ -104,7 +106,7 @@ An adapter plugs into the CLI by exporting a `nightOwlsPlugin` plain object that
|
|
|
104
106
|
export interface NightOwlsPlugin {
|
|
105
107
|
name: string; // short name, e.g. "storage-supabase"
|
|
106
108
|
version: string;
|
|
107
|
-
kind?: "storage" | "runner" | "auth" | "telemetry" | "ui" | "connector";
|
|
109
|
+
kind?: "storage" | "runner" | "auth" | "telemetry" | "ui" | "connector" | "model";
|
|
108
110
|
pkg: string; // npm name, e.g. "@nightowlsdev/storage-supabase"
|
|
109
111
|
description?: string; // one-line summary shown by `owl plugins` + `owl <plugin> --help`
|
|
110
112
|
migrations?: { version: string; name: string; sql: string }[]; // installed into supabase/migrations/
|
|
@@ -113,7 +115,7 @@ export interface NightOwlsPlugin {
|
|
|
113
115
|
config?: { // inserted at the `// nightowls:<marker>` line
|
|
114
116
|
import: string;
|
|
115
117
|
snippet: string;
|
|
116
|
-
marker: "storage" | "auth" | "runner" | "telemetry" | "connector";
|
|
118
|
+
marker: "storage" | "auth" | "runner" | "telemetry" | "connector" | "model";
|
|
117
119
|
};
|
|
118
120
|
// Runs after the declarative wiring on init/install (idempotent; print-only — never applies DDL).
|
|
119
121
|
init?: (ctx: { cwd: string; log: (msg: string) => void }) => void | Promise<void>;
|
|
@@ -148,7 +150,22 @@ into your `supabase/migrations/` (via `owl install` / `owl db install`); your ho
|
|
|
148
150
|
There is one migration system — the host's — and Night Owls never runs DDL itself. See
|
|
149
151
|
`docs/spec/2026-06-03-owl-schema-and-cli.md`.
|
|
150
152
|
|
|
151
|
-
##
|
|
153
|
+
## `owl mcp`
|
|
152
154
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
Run the Night Owls MCP server on stdio. This exposes `nightowls_*` tools to external coding agents
|
|
156
|
+
(Claude Code, Cursor, or any MCP client) so they can query the local Night Owls environment without
|
|
157
|
+
running CLI subcommands manually.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
owl mcp
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The server starts on stdio (JSON-RPC frames on stdout; human-readable diagnostics on stderr). Currently
|
|
164
|
+
exposes one tool:
|
|
165
|
+
|
|
166
|
+
| Tool | Description |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `nightowls_doctor` | Read-only diagnostics: confirms the bootstrap store is reachable, reports Node version and cwd. `readOnlyHint: true`. |
|
|
169
|
+
|
|
170
|
+
Engine-wall §1 / Option B is enforced here: `owl mcp` uses the raw `@modelcontextprotocol/sdk` and
|
|
171
|
+
`@nightowlsdev/storage-local`'s factory — **zero `@mastra/*` imports** enter the CLI binary.
|
package/dist/cli.js
CHANGED
|
@@ -35,16 +35,17 @@ function migrationStamp(base, i) {
|
|
|
35
35
|
const p = (n) => String(n).padStart(2, "0");
|
|
36
36
|
return `${d.getUTCFullYear()}${p(d.getUTCMonth() + 1)}${p(d.getUTCDate())}${p(d.getUTCHours())}${p(d.getUTCMinutes())}${p(d.getUTCSeconds())}`;
|
|
37
37
|
}
|
|
38
|
-
var INSTALLED_FILE = /
|
|
38
|
+
var INSTALLED_FILE = /_nightowls_(.+)\.sql$/;
|
|
39
39
|
async function runDbInstall(deps) {
|
|
40
40
|
const migrations = collectMigrations(deps.plugins);
|
|
41
41
|
const dir = `${deps.root.replace(/\/$/, "")}/${deps.out.replace(/^\//, "")}`;
|
|
42
|
-
await deps.fs.mkdir(dir, { recursive: true }).catch(() => void 0);
|
|
42
|
+
if (!deps.dryRun) await deps.fs.mkdir(dir, { recursive: true }).catch(() => void 0);
|
|
43
43
|
const existing = await deps.fs.readdir(dir).catch(() => []);
|
|
44
44
|
const installed = new Set(
|
|
45
45
|
existing.map((f) => INSTALLED_FILE.exec(f)?.[1]).filter((v) => Boolean(v))
|
|
46
46
|
);
|
|
47
47
|
const base = deps.now();
|
|
48
|
+
const stamp = deps.stamp ?? ((_v, i2, b) => migrationStamp(b, i2));
|
|
48
49
|
const written = [];
|
|
49
50
|
const skipped = [];
|
|
50
51
|
let i = 0;
|
|
@@ -53,13 +54,13 @@ async function runDbInstall(deps) {
|
|
|
53
54
|
skipped.push(m.version);
|
|
54
55
|
continue;
|
|
55
56
|
}
|
|
56
|
-
const file = `${
|
|
57
|
-
await deps.fs.writeFile(`${dir}/${file}`, `${m.sql.trimStart()}
|
|
57
|
+
const file = `${stamp(m.version, i, base)}_nightowls_${m.version}.sql`;
|
|
58
|
+
if (!deps.dryRun) await deps.fs.writeFile(`${dir}/${file}`, `${m.sql.trimStart()}
|
|
58
59
|
`);
|
|
59
60
|
written.push({ version: m.version, file });
|
|
60
61
|
i += 1;
|
|
61
62
|
}
|
|
62
|
-
return { written, skipped };
|
|
63
|
+
return { written, skipped, dryRun: Boolean(deps.dryRun) };
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
// src/templates.ts
|
|
@@ -93,7 +94,7 @@ let telemetry: Extract<NonNullable<Parameters<typeof defineSwarm>[0]["telemetry"
|
|
|
93
94
|
// snippet can reassign it; the placeholder throws until a real provider is wired. \`models.allow\` is
|
|
94
95
|
// env-driven (\`MODEL_ID\`), so the scaffold is runnable once a model plugin + MODEL_ID are set.
|
|
95
96
|
let modelFactory: Parameters<typeof defineSwarm>[0]["modelFactory"] = () => {
|
|
96
|
-
throw new Error("Install a model provider: owl install model-anthropic (or model-openai / model-vercel-gateway / model-openrouter).");
|
|
97
|
+
throw new Error("Install a model provider: owl install model-anthropic (or model-openai / model-vercel-gateway / model-openrouter / model-ollama).");
|
|
97
98
|
};
|
|
98
99
|
// nightowls:model
|
|
99
100
|
|
|
@@ -386,19 +387,22 @@ db.command("types").description("Generate TypeScript types for the nightowls sch
|
|
|
386
387
|
const out = await runDbTypes({ exec });
|
|
387
388
|
process.stdout.write(out);
|
|
388
389
|
});
|
|
389
|
-
db.command("install").description("Install Night Owls' migrations into your supabase/migrations/ (timestamped, idempotent) \u2014 apply them with `supabase db push`.").option("--out <dir>", "target migrations dir (relative to cwd)", "supabase/migrations").action(async (opts) => {
|
|
390
|
+
db.command("install").description("Install Night Owls' migrations into your supabase/migrations/ (timestamped, idempotent) \u2014 apply them with `supabase db push`.").option("--out <dir>", "target migrations dir (relative to cwd)", "supabase/migrations").option("--dry-run", "preview the migration set without writing any files", false).action(async (opts) => {
|
|
390
391
|
const cwd = process.cwd();
|
|
391
392
|
const plugins = await discoverPlugins(nodeDiscoverDeps(cwd));
|
|
392
|
-
const { written, skipped } = await runDbInstall({
|
|
393
|
+
const { written, skipped, dryRun } = await runDbInstall({
|
|
393
394
|
plugins,
|
|
394
395
|
root: cwd,
|
|
395
396
|
out: opts.out,
|
|
396
397
|
fs: await nodeFs(),
|
|
397
|
-
now: () => /* @__PURE__ */ new Date()
|
|
398
|
+
now: () => /* @__PURE__ */ new Date(),
|
|
399
|
+
dryRun: opts.dryRun
|
|
398
400
|
});
|
|
399
|
-
|
|
401
|
+
const verb = dryRun ? "would write" : "wrote";
|
|
402
|
+
for (const w of written) console.log(`${verb} ${opts.out}/${w.file}`);
|
|
400
403
|
for (const version of skipped) console.log(`skipped ${version} (already installed)`);
|
|
401
404
|
if (!written.length) console.log("Nothing to install \u2014 all nightowls migrations already present.");
|
|
405
|
+
else if (dryRun) console.log(`Dry run \u2014 ${written.length} migration(s) would be written to ${opts.out}/. Re-run without --dry-run to apply.`);
|
|
402
406
|
});
|
|
403
407
|
program.command("plugins").description("List installed Night Owls plugins and the commands they expose.").action(async () => {
|
|
404
408
|
const cwd = process.cwd();
|
|
@@ -406,7 +410,7 @@ program.command("plugins").description("List installed Night Owls plugins and th
|
|
|
406
410
|
runPluginsList(plugins, console.log);
|
|
407
411
|
});
|
|
408
412
|
program.command("mcp").description("Run the Night Owls MCP server on stdio (exposes nightowls_* tools to external agents).").action(async () => {
|
|
409
|
-
const { runMcpServer } = await import("./mcp-
|
|
413
|
+
const { runMcpServer } = await import("./mcp-AX7MPTKC.js");
|
|
410
414
|
await runMcpServer();
|
|
411
415
|
});
|
|
412
416
|
async function main() {
|
|
@@ -30,7 +30,7 @@ async function runMcpServer() {
|
|
|
30
30
|
const server = buildMcpServer();
|
|
31
31
|
const transport = new StdioServerTransport();
|
|
32
32
|
await server.connect(transport);
|
|
33
|
-
console.error("[
|
|
33
|
+
console.error("[@nightowlsdev/cli] mcp server ready on stdio (nightowls_doctor)");
|
|
34
34
|
}
|
|
35
35
|
export {
|
|
36
36
|
buildMcpServer,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nightowlsdev/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
@@ -36,21 +36,22 @@
|
|
|
36
36
|
"tsup": "8.5.1",
|
|
37
37
|
"typescript": "6.0.3",
|
|
38
38
|
"vitest": "^3.2.0",
|
|
39
|
-
"@nightowlsdev/
|
|
40
|
-
"@nightowlsdev/
|
|
41
|
-
"@nightowlsdev/
|
|
42
|
-
"@nightowlsdev/
|
|
43
|
-
"@nightowlsdev/
|
|
44
|
-
"@nightowlsdev/runner-background": "
|
|
39
|
+
"@nightowlsdev/core": "0.5.0",
|
|
40
|
+
"@nightowlsdev/auth-supabase": "2.0.0",
|
|
41
|
+
"@nightowlsdev/storage-supabase": "2.0.0",
|
|
42
|
+
"@nightowlsdev/auth-auth0": "2.0.0",
|
|
43
|
+
"@nightowlsdev/telemetry-otel": "2.0.0",
|
|
44
|
+
"@nightowlsdev/runner-background": "2.0.0",
|
|
45
|
+
"@nightowlsdev/runner-nextjs": "2.0.0",
|
|
46
|
+
"@nightowlsdev/mcp": "2.0.0",
|
|
47
|
+
"@nightowlsdev/telemetry-langfuse": "2.0.0",
|
|
45
48
|
"@nightowlsdev/model-anthropic": "0.1.0",
|
|
46
|
-
"@nightowlsdev/
|
|
47
|
-
"@nightowlsdev/
|
|
48
|
-
"@nightowlsdev/eslint-config": "0.0.0",
|
|
49
|
-
"@nightowlsdev/mcp": "0.1.1",
|
|
50
|
-
"@nightowlsdev/tsconfig": "0.0.0",
|
|
51
|
-
"@nightowlsdev/model-openai": "0.1.0",
|
|
49
|
+
"@nightowlsdev/model-openai": "0.2.0",
|
|
50
|
+
"@nightowlsdev/model-openrouter": "0.2.0",
|
|
52
51
|
"@nightowlsdev/model-vercel-gateway": "0.1.0",
|
|
53
|
-
"@nightowlsdev/
|
|
52
|
+
"@nightowlsdev/tsconfig": "0.0.0",
|
|
53
|
+
"@nightowlsdev/eslint-config": "0.0.0",
|
|
54
|
+
"@nightowlsdev/model-ollama": "0.1.0"
|
|
54
55
|
},
|
|
55
56
|
"scripts": {
|
|
56
57
|
"build": "tsup",
|