@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.
Files changed (80) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +202 -0
  3. package/README.md +89 -0
  4. package/bin/neko +6 -0
  5. package/dist/.build.tsbuildinfo +1 -0
  6. package/dist/.tsbuildinfo +1 -0
  7. package/dist/cli.d.ts +60 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +355 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands/init.d.ts +8 -0
  12. package/dist/commands/init.d.ts.map +1 -0
  13. package/dist/commands/init.js +11 -0
  14. package/dist/commands/init.js.map +1 -0
  15. package/dist/commands/schema/check.d.ts +55 -0
  16. package/dist/commands/schema/check.d.ts.map +1 -0
  17. package/dist/commands/schema/check.js +197 -0
  18. package/dist/commands/schema/check.js.map +1 -0
  19. package/dist/commands/schema/diff.d.ts +48 -0
  20. package/dist/commands/schema/diff.d.ts.map +1 -0
  21. package/dist/commands/schema/diff.js +245 -0
  22. package/dist/commands/schema/diff.js.map +1 -0
  23. package/dist/commands/schema/generate.d.ts +59 -0
  24. package/dist/commands/schema/generate.d.ts.map +1 -0
  25. package/dist/commands/schema/generate.js +135 -0
  26. package/dist/commands/schema/generate.js.map +1 -0
  27. package/dist/commands/schema/list.d.ts +50 -0
  28. package/dist/commands/schema/list.d.ts.map +1 -0
  29. package/dist/commands/schema/list.js +115 -0
  30. package/dist/commands/schema/list.js.map +1 -0
  31. package/dist/commands/schema/migrate/list.d.ts +65 -0
  32. package/dist/commands/schema/migrate/list.d.ts.map +1 -0
  33. package/dist/commands/schema/migrate/list.js +148 -0
  34. package/dist/commands/schema/migrate/list.js.map +1 -0
  35. package/dist/commands/schema/migrate/plan.d.ts +79 -0
  36. package/dist/commands/schema/migrate/plan.d.ts.map +1 -0
  37. package/dist/commands/schema/migrate/plan.js +255 -0
  38. package/dist/commands/schema/migrate/plan.js.map +1 -0
  39. package/dist/commands/schema/migrate/stub.d.ts +59 -0
  40. package/dist/commands/schema/migrate/stub.d.ts.map +1 -0
  41. package/dist/commands/schema/migrate/stub.js +195 -0
  42. package/dist/commands/schema/migrate/stub.js.map +1 -0
  43. package/dist/commands/schema/migrate/verify.d.ts +59 -0
  44. package/dist/commands/schema/migrate/verify.d.ts.map +1 -0
  45. package/dist/commands/schema/migrate/verify.js +268 -0
  46. package/dist/commands/schema/migrate/verify.js.map +1 -0
  47. package/dist/exit-codes.d.ts +47 -0
  48. package/dist/exit-codes.d.ts.map +1 -0
  49. package/dist/exit-codes.js +46 -0
  50. package/dist/exit-codes.js.map +1 -0
  51. package/dist/formatters/json.d.ts +25 -0
  52. package/dist/formatters/json.d.ts.map +1 -0
  53. package/dist/formatters/json.js +27 -0
  54. package/dist/formatters/json.js.map +1 -0
  55. package/dist/formatters/pretty.d.ts +131 -0
  56. package/dist/formatters/pretty.d.ts.map +1 -0
  57. package/dist/formatters/pretty.js +229 -0
  58. package/dist/formatters/pretty.js.map +1 -0
  59. package/dist/index.d.ts +2 -0
  60. package/dist/index.d.ts.map +1 -0
  61. package/dist/index.js +2 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/loaders/read-artifacts.d.ts +55 -0
  64. package/dist/loaders/read-artifacts.d.ts.map +1 -0
  65. package/dist/loaders/read-artifacts.js +99 -0
  66. package/dist/loaders/read-artifacts.js.map +1 -0
  67. package/dist/loaders/read-migrations.d.ts +70 -0
  68. package/dist/loaders/read-migrations.d.ts.map +1 -0
  69. package/dist/loaders/read-migrations.js +206 -0
  70. package/dist/loaders/read-migrations.js.map +1 -0
  71. package/dist/loaders/tsx-loader.d.ts +116 -0
  72. package/dist/loaders/tsx-loader.d.ts.map +1 -0
  73. package/dist/loaders/tsx-loader.js +250 -0
  74. package/dist/loaders/tsx-loader.js.map +1 -0
  75. package/dist/loaders/walk-workspace.d.ts +62 -0
  76. package/dist/loaders/walk-workspace.d.ts.map +1 -0
  77. package/dist/loaders/walk-workspace.js +133 -0
  78. package/dist/loaders/walk-workspace.js.map +1 -0
  79. package/docs/SCOPE.md +42 -0
  80. 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
+ }