@nekostack/cli 1.0.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/CHANGELOG.md +42 -0
- package/LICENSE +202 -0
- package/README.md +89 -0
- package/bin/neko +6 -0
- package/dist/.build.tsbuildinfo +1 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/cli.d.ts +60 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +355 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +11 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/schema/check.d.ts +55 -0
- package/dist/commands/schema/check.d.ts.map +1 -0
- package/dist/commands/schema/check.js +197 -0
- package/dist/commands/schema/check.js.map +1 -0
- package/dist/commands/schema/diff.d.ts +48 -0
- package/dist/commands/schema/diff.d.ts.map +1 -0
- package/dist/commands/schema/diff.js +245 -0
- package/dist/commands/schema/diff.js.map +1 -0
- package/dist/commands/schema/generate.d.ts +59 -0
- package/dist/commands/schema/generate.d.ts.map +1 -0
- package/dist/commands/schema/generate.js +135 -0
- package/dist/commands/schema/generate.js.map +1 -0
- package/dist/commands/schema/list.d.ts +50 -0
- package/dist/commands/schema/list.d.ts.map +1 -0
- package/dist/commands/schema/list.js +115 -0
- package/dist/commands/schema/list.js.map +1 -0
- package/dist/commands/schema/migrate/list.d.ts +65 -0
- package/dist/commands/schema/migrate/list.d.ts.map +1 -0
- package/dist/commands/schema/migrate/list.js +148 -0
- package/dist/commands/schema/migrate/list.js.map +1 -0
- package/dist/commands/schema/migrate/plan.d.ts +79 -0
- package/dist/commands/schema/migrate/plan.d.ts.map +1 -0
- package/dist/commands/schema/migrate/plan.js +255 -0
- package/dist/commands/schema/migrate/plan.js.map +1 -0
- package/dist/commands/schema/migrate/stub.d.ts +59 -0
- package/dist/commands/schema/migrate/stub.d.ts.map +1 -0
- package/dist/commands/schema/migrate/stub.js +195 -0
- package/dist/commands/schema/migrate/stub.js.map +1 -0
- package/dist/commands/schema/migrate/verify.d.ts +59 -0
- package/dist/commands/schema/migrate/verify.d.ts.map +1 -0
- package/dist/commands/schema/migrate/verify.js +268 -0
- package/dist/commands/schema/migrate/verify.js.map +1 -0
- package/dist/exit-codes.d.ts +47 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +46 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/formatters/json.d.ts +25 -0
- package/dist/formatters/json.d.ts.map +1 -0
- package/dist/formatters/json.js +27 -0
- package/dist/formatters/json.js.map +1 -0
- package/dist/formatters/pretty.d.ts +131 -0
- package/dist/formatters/pretty.d.ts.map +1 -0
- package/dist/formatters/pretty.js +229 -0
- package/dist/formatters/pretty.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/loaders/read-artifacts.d.ts +55 -0
- package/dist/loaders/read-artifacts.d.ts.map +1 -0
- package/dist/loaders/read-artifacts.js +99 -0
- package/dist/loaders/read-artifacts.js.map +1 -0
- package/dist/loaders/read-migrations.d.ts +70 -0
- package/dist/loaders/read-migrations.d.ts.map +1 -0
- package/dist/loaders/read-migrations.js +206 -0
- package/dist/loaders/read-migrations.js.map +1 -0
- package/dist/loaders/tsx-loader.d.ts +116 -0
- package/dist/loaders/tsx-loader.d.ts.map +1 -0
- package/dist/loaders/tsx-loader.js +250 -0
- package/dist/loaders/tsx-loader.js.map +1 -0
- package/dist/loaders/walk-workspace.d.ts +62 -0
- package/dist/loaders/walk-workspace.d.ts.map +1 -0
- package/dist/loaders/walk-workspace.js +133 -0
- package/dist/loaders/walk-workspace.js.map +1 -0
- package/docs/SCOPE.md +42 -0
- package/package.json +39 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `walkWorkspace({ root, pattern? })` — discover `*.schema.{ts,js}`
|
|
3
|
+
* files under a workspace root and load each one into a
|
|
4
|
+
* `RegistrySourceEntry`. v0.7 Step 23.
|
|
5
|
+
*
|
|
6
|
+
* The CLI is the only filesystem walker (Master plan / CLI plan
|
|
7
|
+
* Decision #2). This function:
|
|
8
|
+
*
|
|
9
|
+
* 1. Glob-walks `pattern` (default `**/*.schema.{ts,js}`) under
|
|
10
|
+
* `root` using Node's built-in `fs/promises.glob` (Node 22+).
|
|
11
|
+
* No external glob dep.
|
|
12
|
+
* 2. Reads each match's UTF-8 source text.
|
|
13
|
+
* 3. Hands the absolute path to `loadSchemaModule` from
|
|
14
|
+
* `tsx-loader.ts`.
|
|
15
|
+
* 4. Builds one `RegistrySourceEntry` per successfully loaded module.
|
|
16
|
+
* 5. Collects every per-file failure into a separate `failures`
|
|
17
|
+
* array — never short-circuits. The CLI dispatch layer (Steps
|
|
18
|
+
* 25+) decides whether to surface them and what exit code to
|
|
19
|
+
* pick; this loader is silent.
|
|
20
|
+
*
|
|
21
|
+
* No `console.*`, no `process.exit`, no stderr / stdout writes —
|
|
22
|
+
* static-scan asserted by [`../../tests/loaders/walk-workspace.test.ts`](../../tests/loaders/walk-workspace.test.ts).
|
|
23
|
+
*
|
|
24
|
+
* This module does NOT:
|
|
25
|
+
* - Build a `Registry` (that's `buildRegistry` on the schema side).
|
|
26
|
+
* - Call any schema-side handler (`listHandler` etc. — Steps 29+).
|
|
27
|
+
* - Format output (Steps 27 / 28).
|
|
28
|
+
* - Decide exit codes (Step 25 dispatch + Step 26 exit-codes enum).
|
|
29
|
+
*
|
|
30
|
+
* Pattern semantics: a caller-supplied `pattern` **replaces** the
|
|
31
|
+
* default — it does not extend it. The CLI surface (Master plan CLI
|
|
32
|
+
* companion §"Locked subcommand surface") spells this out for the
|
|
33
|
+
* `[pattern]` positional on `generate` / `check`.
|
|
34
|
+
*
|
|
35
|
+
* Deterministic ordering: discovered paths are sorted ascending by
|
|
36
|
+
* their workspace-relative form (forward-slash-normalized) before
|
|
37
|
+
* loading. Downstream sort by `schemaId` is still required for
|
|
38
|
+
* registry order (the listHandler does that); this sort is purely so
|
|
39
|
+
* walk-time errors and CLI output have a stable order across runs.
|
|
40
|
+
*/
|
|
41
|
+
import { readFile } from "node:fs/promises";
|
|
42
|
+
import { glob } from "node:fs/promises";
|
|
43
|
+
import { isAbsolute, resolve, sep } from "node:path";
|
|
44
|
+
import { loadSchemaModule } from "./tsx-loader.js";
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// Public types
|
|
47
|
+
// =============================================================================
|
|
48
|
+
export const DEFAULT_SCHEMA_PATTERN = "**/*.schema.{ts,js}";
|
|
49
|
+
// =============================================================================
|
|
50
|
+
// Walker
|
|
51
|
+
// =============================================================================
|
|
52
|
+
export async function walkWorkspace(opts) {
|
|
53
|
+
const pattern = opts.pattern ?? DEFAULT_SCHEMA_PATTERN;
|
|
54
|
+
const rootAbs = isAbsolute(opts.root) ? opts.root : resolve(opts.root);
|
|
55
|
+
// Glob walk. `cwd` keeps relative output in sync with `rootAbs` so
|
|
56
|
+
// we can compute both forms cheaply below.
|
|
57
|
+
let relativePaths;
|
|
58
|
+
try {
|
|
59
|
+
relativePaths = await collectGlob(pattern, rootAbs);
|
|
60
|
+
}
|
|
61
|
+
catch (cause) {
|
|
62
|
+
return {
|
|
63
|
+
entries: [],
|
|
64
|
+
failures: [
|
|
65
|
+
{
|
|
66
|
+
path: rootAbs,
|
|
67
|
+
reason: "io_error",
|
|
68
|
+
message: errorMessageOf(cause),
|
|
69
|
+
cause,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// Deterministic ordering: alphabetical on forward-slash-normalized
|
|
75
|
+
// relative paths. Stable across Windows/POSIX and stable across runs.
|
|
76
|
+
const normalized = relativePaths
|
|
77
|
+
.map((p) => p.split(sep).join("/"))
|
|
78
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
79
|
+
const entries = [];
|
|
80
|
+
const failures = [];
|
|
81
|
+
for (const rel of normalized) {
|
|
82
|
+
const abs = resolve(rootAbs, rel);
|
|
83
|
+
let sourceText;
|
|
84
|
+
try {
|
|
85
|
+
sourceText = await readFile(abs, "utf8");
|
|
86
|
+
}
|
|
87
|
+
catch (cause) {
|
|
88
|
+
failures.push({
|
|
89
|
+
path: rel,
|
|
90
|
+
reason: "io_error",
|
|
91
|
+
message: errorMessageOf(cause),
|
|
92
|
+
cause,
|
|
93
|
+
});
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const r = await loadSchemaModule(abs);
|
|
97
|
+
if (!r.success) {
|
|
98
|
+
// Re-key the failure path to the workspace-relative form so
|
|
99
|
+
// downstream output is consistent with `sourcePath` on the
|
|
100
|
+
// successful entries.
|
|
101
|
+
failures.push({ ...r.failure, path: rel });
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
entries.push({
|
|
105
|
+
sourcePath: rel,
|
|
106
|
+
sourceText,
|
|
107
|
+
schemas: r.data.schemas,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return { entries, failures };
|
|
111
|
+
}
|
|
112
|
+
// =============================================================================
|
|
113
|
+
// Helpers
|
|
114
|
+
// =============================================================================
|
|
115
|
+
async function collectGlob(pattern, cwd) {
|
|
116
|
+
const out = [];
|
|
117
|
+
for await (const p of glob(pattern, { cwd }))
|
|
118
|
+
out.push(p);
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
function errorMessageOf(err) {
|
|
122
|
+
if (err instanceof Error)
|
|
123
|
+
return err.message;
|
|
124
|
+
if (typeof err === "string")
|
|
125
|
+
return err;
|
|
126
|
+
try {
|
|
127
|
+
return JSON.stringify(err);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return String(err);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=walk-workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-workspace.js","sourceRoot":"","sources":["../../src/loaders/walk-workspace.ts"],"names":[],"mappings":"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"}
|
package/docs/SCOPE.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# @nekostack/cli — Scope & Invariants
|
|
2
|
+
|
|
3
|
+
## What this package is
|
|
4
|
+
|
|
5
|
+
The `neko` CLI binary. Installed via `npm install -g @nekostack/cli` or `npx neko`. Dispatches schema commands through `@nekostack/schema`. Commander-based, fully testable in-process.
|
|
6
|
+
|
|
7
|
+
## Commands (v1.0)
|
|
8
|
+
|
|
9
|
+
| Command | Description |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `neko schema list [globs]` | Discover schema files |
|
|
12
|
+
| `neko schema diff [globs]` | Diff against stored snapshots |
|
|
13
|
+
| `neko schema check [globs]` | Validate against schema contract rules |
|
|
14
|
+
| `neko schema generate [globs]` | Generate Zod / TS / JSON Schema / OpenAPI |
|
|
15
|
+
| `neko schema migrate list` | List available migration files |
|
|
16
|
+
| `neko schema migrate plan` | Plan a migration chain |
|
|
17
|
+
| `neko schema migrate stub` | Generate a migration file stub |
|
|
18
|
+
| `neko schema migrate verify` | Verify a migration chain is well-formed |
|
|
19
|
+
| `neko init <name>` | Scaffold a project (stub in v1.0 — requires monorepo) |
|
|
20
|
+
|
|
21
|
+
## Invariants
|
|
22
|
+
|
|
23
|
+
1. **`dispatch()` never calls `process.exit`** — only `run()` (the bin entry) does. Enforced by the test suite.
|
|
24
|
+
2. **Every command returns an `EXIT_CODES` value** — `SUCCESS (0)`, `USAGE_ERROR (1)`, `LOGICAL_FAILURE (2)`, `IO_ERROR (3)`, `INTERNAL_ERROR (5)`.
|
|
25
|
+
3. **`--json` flag** produces machine-readable output for all schema commands.
|
|
26
|
+
4. **Stdout/stderr writers are injected** — `buildCli(opts)` accepts `{ stdout, stderr }` so all output is capturable in tests without subprocess spawn.
|
|
27
|
+
5. **Test coverage: 504 tests, 19 test files.**
|
|
28
|
+
|
|
29
|
+
## What is in scope (v1.0)
|
|
30
|
+
|
|
31
|
+
- `neko schema *` command group (8 verbs)
|
|
32
|
+
- Commander-based argv parsing + dispatch
|
|
33
|
+
- JSON output mode (`--json`)
|
|
34
|
+
- Programmatic API (`dispatch`, `buildCli`, `EXIT_CODES`)
|
|
35
|
+
|
|
36
|
+
## What is NOT in scope (v1.0)
|
|
37
|
+
|
|
38
|
+
- Plugin system (packages registering their own subcommands) → future
|
|
39
|
+
- `neko init` fully wired to published project templates → future
|
|
40
|
+
- `neko new <kind> <name>` scaffolding → future
|
|
41
|
+
- `neko lint`, `neko sim`, `neko codex` → those packages not yet published
|
|
42
|
+
- Interactive prompt UX (clack) → future
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nekostack/cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/cli.js",
|
|
8
|
+
"types": "./dist/cli.d.ts",
|
|
9
|
+
"bin": {
|
|
10
|
+
"neko": "./bin/neko"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"bin",
|
|
15
|
+
"docs/*.md",
|
|
16
|
+
"CHANGELOG.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.build.json",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"lint": "eslint ."
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"commander": "^12.1.0",
|
|
27
|
+
"tsx": "^4.19.2"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@nekostack/schema": "^1.0.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@nekostack/schema": "*",
|
|
34
|
+
"@nekostack/templates": "*",
|
|
35
|
+
"@types/node": "^22.10.0",
|
|
36
|
+
"typescript": "^5.7.2",
|
|
37
|
+
"vitest": "^2.1.8"
|
|
38
|
+
}
|
|
39
|
+
}
|