@dforge-core/dforge-cli 0.1.0-test.5 → 0.1.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 CHANGED
@@ -17,12 +17,8 @@ macOS arm64/x64, Linux x64/arm64, Windows x64/arm64.
17
17
  ## Commands
18
18
 
19
19
  ```bash
20
- # STATIC checks: manifest identifiers, translation completeness, menu/folder/entity
21
- # coverage, folder paths. DB-bound checks (FK target resolution, package-filter SQL,
22
- # migration safety) only surface during `module install` against a live tenant —
23
- # a clean `validate` does NOT guarantee a clean install.
24
- dforge-cli module validate ./my-module
25
- dforge-cli module validate ./my-module-1.0.0.dforge
20
+ # Scaffold a new module interactively (see `Scaffolding a new module` below).
21
+ dforge-cli init module ./my-module
26
22
 
27
23
  # Package a module directory into a .dforge archive
28
24
  dforge-cli module pack ./my-module # writes my-module-1.0.0.dforge in cwd
@@ -32,7 +28,10 @@ dforge-cli module pack ./my-module -o pkg.dforge # writes ./pkg.dforge
32
28
  # Publish a .dforge to the marketplace (org-scoped)
33
29
  dforge-cli marketplace publish ./my-module-1.0.0.dforge --org acme
34
30
 
35
- # Install a .dforge (or source directory) to a running tenant over HTTP
31
+ # Install a .dforge (or source directory) to a running tenant over HTTP.
32
+ # Manifest, FK targets, package-filter SQL, and migration safety are all
33
+ # validated server-side during install — first install of a fresh scaffold
34
+ # is the smoke test that catches anything wrong.
36
35
  DFORGE_URL=https://app.example.com DFORGE_TOKEN=<jwt> \
37
36
  dforge-cli module install --path ./my-module-1.0.0.dforge
38
37
 
@@ -40,6 +39,94 @@ DFORGE_URL=https://app.example.com DFORGE_TOKEN=<jwt> \
40
39
  dforge-cli dbml-import --from-dbml ./schema.dbml
41
40
  ```
42
41
 
42
+ ## Scaffolding a new module
43
+
44
+ ```bash
45
+ dforge-cli init module ./my-module
46
+ ```
47
+
48
+ Walks you through an interactive setup and writes a fresh module that's
49
+ ready to `pack` and `install`.
50
+
51
+ ### What it asks
52
+
53
+ | Prompt | Default | Notes |
54
+ |---|---|---|
55
+ | Module code | (none) | `^[a-z][a-z0-9_-]*$` — becomes the DB schema name and `module_cd` |
56
+ | Display name | titlecased `code` | shown in the UI |
57
+ | Description | (empty) | optional |
58
+ | Author name | `git config user.name` | optional |
59
+ | License | `MIT` | |
60
+ | Version | `0.1.0` | semver |
61
+ | DB schema version | `0.0.1` | bumped when you alter physical columns |
62
+ | Dependencies | `admin`, `metadata` | toggle which system modules you depend on |
63
+ | Preset | Minimal | see below |
64
+ | First entity name | (none) | `^[a-z][a-z0-9_]*$` — table/entity code |
65
+ | First entity label | titlecased name | display label |
66
+ | Traits | `identity + audit` | see below |
67
+
68
+ `moduleId` (the immutable UUID) is auto-generated with `crypto.randomUUID()` — no prompt.
69
+
70
+ ### Presets
71
+
72
+ - **Minimal** — manifest + one entity + minimum UI (`data_views`, `folders`, `menus`, `actions`) + one admin role. ~8 files. Installs as-is; you add fields/views/roles from there.
73
+ - **Minimal + add more entities interactively** — same as Minimal, then loops to add additional entities (name + label + traits per entity) so you don't have to re-run.
74
+ - **Full template** — Minimal plus `settings.json`, `translations/en-US.json`, a `seed-data/01-<entity>.json` per entity, and a `logic/actions/` stub directory. Use this when you want the typical optional files scaffolded for you to fill in (or delete).
75
+
76
+ ### Entity traits
77
+
78
+ The "traits" choice controls which built-in columns the entity gets for free — both rendered by the platform, no need to declare in `fields`:
79
+
80
+ - **identity only** — primary key only. Use for lookup tables that don't need audit columns.
81
+ - **identity + audit** (recommended) — primary key + `created_date` + `last_updated` + `created_by` + `last_updated_by`. Standard for any business entity.
82
+
83
+ You can change traits later by editing the entity JSON.
84
+
85
+ ### After scaffold
86
+
87
+ ```bash
88
+ cd ./my-module
89
+ dforge-cli module install --path . --code <tenant> # full validation + install
90
+ ```
91
+
92
+ The first install runs the full server-side validator (manifest, FK targets, package-filter SQL, migration safety) — fix anything it flags, then re-run.
93
+
94
+ ### Programmatic use (subpath export)
95
+
96
+ The pure-TS builders behind `init module` are also exposed as a library entry, so downstream packages can compose module file maps without shelling to the CLI. Used by [`@dforge-core/dforge-mcp`](https://www.npmjs.com/package/@dforge-core/dforge-mcp) to drive AI-authored modules.
97
+
98
+ ```ts
99
+ import {
100
+ buildManifest,
101
+ buildEntity,
102
+ buildDataViews,
103
+ buildFolders,
104
+ buildMenus,
105
+ buildRoles,
106
+ } from "@dforge-core/dforge-cli/templates";
107
+ import type { ScaffoldOpts, EntitySpec } from "@dforge-core/dforge-cli/templates";
108
+ import { randomUUID } from "node:crypto";
109
+
110
+ const opts: ScaffoldOpts = {
111
+ path: "",
112
+ code: "smoke",
113
+ displayName: "Smoke",
114
+ description: "",
115
+ author: "",
116
+ license: "MIT",
117
+ version: "0.1.0",
118
+ dbSchemaVersion: "0.0.1",
119
+ dependencies: ["admin", "metadata"],
120
+ preset: "minimal",
121
+ entities: [{ name: "thing", label: "Thing", traits: "identity+audit" }],
122
+ };
123
+
124
+ const manifest = buildManifest(opts, randomUUID());
125
+ // → plain JS object, ready for JSON.stringify
126
+ ```
127
+
128
+ All builders are pure functions returning plain JS objects (no I/O). The subpath ships dual CJS + ESM + `.d.ts` types.
129
+
43
130
  ## Auth
44
131
 
45
132
  The remote `module install --url` and `marketplace publish` flows need a JWT
@@ -84,15 +171,106 @@ C# source lives in [`iash44/dForge-core`](https://github.com/iash44/dForge-core)
84
171
  under `server/src/dForge.Cli/`. This repo only ships the npm wrapper + 6
85
172
  platform sidecars. Release flow:
86
173
 
87
- 1. Tag `cli-vX.Y.Z` in `dForge-core` → `.github/workflows/release-cli.yml`
88
- cross-compiles 6 binaries and attaches them to a GitHub Release.
89
- 2. Run `gh workflow run publish.yml -f source_tag=cli-vX.Y.Z -f npm_version=X.Y.Z -f npm_tag=next`
90
- in this repo. `scripts/fetch-binaries.sh` pulls binaries from the source
91
- release; `scripts/publish.sh` aligns versions and publishes 7 packages.
92
- 3. After smoke-testing `npx -y @dforge-core/dforge-cli@next --version`, promote
93
- with another workflow run using `-f npm_tag=latest`.
174
+ 1. **Tag the source repo.** From a clean `main` in `iash44/dForge-core`:
175
+ ```bash
176
+ git checkout main && git pull
177
+ git tag cli-v0.1.0 # NOTE: prefix is cli-v, no `release/` etc.
178
+ git push origin cli-v0.1.0
179
+ ```
180
+ The `cli-v*` tag triggers `.github/workflows/release-cli.yml`, which
181
+ cross-compiles 6 binaries (3–4 min) and attaches them as assets to a
182
+ GitHub Release at that tag. Watch:
183
+ ```bash
184
+ gh run watch --repo iash44/dForge-core
185
+ gh release view cli-v0.1.0 --repo iash44/dForge-core # should list 6 assets
186
+ ```
187
+
188
+ 2. **Publish to npm under `next`.** From anywhere (workflow runs in CI):
189
+ ```bash
190
+ gh workflow run publish.yml --repo dforge-core/dforge-cli \
191
+ -f source_tag=cli-v0.1.0 \
192
+ -f npm_version=0.1.0 \
193
+ -f npm_tag=next
194
+ ```
195
+ `source_tag` is the source-repo git tag (with `cli-v` prefix);
196
+ `npm_version` is the npm semver (no prefix). They don't have to match
197
+ — pre-release suffixes are fine (`cli-v0.1.0-rc.1` → `0.1.0-rc.1`).
198
+
199
+ 3. **Smoke test, then promote.**
200
+ ```bash
201
+ npx -y @dforge-core/dforge-cli@next --version # exits 0, prints sha + build time
202
+ ```
203
+ If happy, promote the SAME version to `latest`:
204
+ ```bash
205
+ gh workflow run publish.yml --repo dforge-core/dforge-cli \
206
+ -f source_tag=cli-v0.1.0 \
207
+ -f npm_version=0.1.0 \
208
+ -f npm_tag=latest
209
+ ```
210
+ This re-publishes (idempotent for the same `npm_version`) and moves
211
+ the `latest` dist-tag. End users running `npm i -g @dforge-core/dforge-cli`
212
+ now get this version.
213
+
214
+ **Choosing the version number.** `npm_version` is permanent once published
215
+ — npm only allows unpublish within 72h and burns the version slot forever
216
+ after. Use the `0.X.Y-rc.N` / `0.X.Y-test.N` pattern for shake-out runs
217
+ (`npm_tag=next`), and reserve plain `0.X.Y` for what you actually want
218
+ people to install (`npm_tag=latest`).
94
219
 
95
220
  To test a freshly-built binary without going through the publish pipeline,
96
221
  set `DFORGE_CLI_BINARY=/path/to/dforge-cli` and `node index.js` will exec
97
222
  that path directly, skipping require.resolve and the sibling-packages
98
223
  fallback.
224
+
225
+ ### CI auth setup (non-obvious, easy to miss)
226
+
227
+ The `publish.yml` workflow uses two auth mechanisms that both have to be
228
+ configured outside the repo:
229
+
230
+ **1. npm Trusted Publisher — must be set up for ALL 7 package names**
231
+
232
+ OIDC publishing is configured per-package in the npm UI, not at the org
233
+ level. Each of these needs its own Trusted Publisher entry pointing at
234
+ `dforge-core/dforge-cli` / `publish.yml`:
235
+
236
+ - `@dforge-core/dforge-cli` (wrapper)
237
+ - `@dforge-core/dforge-cli-darwin-arm64`
238
+ - `@dforge-core/dforge-cli-darwin-x64`
239
+ - `@dforge-core/dforge-cli-linux-arm64`
240
+ - `@dforge-core/dforge-cli-linux-x64`
241
+ - `@dforge-core/dforge-cli-win32-arm64`
242
+ - `@dforge-core/dforge-cli-win32-x64`
243
+
244
+ Visit `npmjs.com/package/<name>/access` for each, scroll to **Trusted
245
+ Publisher**, click Add. Missing config produces a confusing **404** on
246
+ publish (npm returns 404 instead of 401 to avoid leaking package existence).
247
+
248
+ **2. `SOURCE_REPO_PAT` secret — private cross-owner read**
249
+
250
+ The source repo (`iash44/dForge-core`) is private and lives under a
251
+ different owner than this dist repo. The workflow-issued `GITHUB_TOKEN`
252
+ can't reach it. Create a fine-grained PAT with **Contents: Read** on
253
+ `iash44/dForge-core` and store it as a repo secret named exactly
254
+ `SOURCE_REPO_PAT`:
255
+
256
+ ```bash
257
+ gh secret set SOURCE_REPO_PAT --repo dforge-core/dforge-cli
258
+ ```
259
+
260
+ Fine-grained PATs can't be renewed — when it expires, regenerate and
261
+ re-run the `gh secret set` command.
262
+
263
+ ### Workflow gotchas worth knowing
264
+
265
+ - **Node 24, not 22.** Node 22 ships npm 10.9.7, which doesn't support
266
+ Trusted Publisher OIDC. `npm install -g npm@latest` on top of npm 10
267
+ fails on Ubuntu runners with `Cannot find module 'promise-retry'`
268
+ (arborist self-upgrade bug). Node 24 ships npm 11.x natively.
269
+ - **No `registry-url` in setup-node.** When set, it writes a `.npmrc`
270
+ with `_authToken=${NODE_AUTH_TOKEN}`. With no `NODE_AUTH_TOKEN` env,
271
+ the literal placeholder `XXXXX-XXXXX-XXXXX-XXXXX` ends up as the
272
+ token, and npm uses it instead of falling back to OIDC. Default
273
+ registry is npmjs.org anyway.
274
+ - **`npm publish`, not `pnpm publish`.** pnpm's OIDC Trusted Publisher
275
+ support lags npm's. The script uses pnpm for everything else and only
276
+ shells to `npm publish` for the actual upload.