@jskit-ai/agent-docs 0.1.118 → 0.1.120

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 (64) hide show
  1. package/guide/agent/app-extras/assistant.md +0 -1
  2. package/guide/agent/app-extras/mobile-capacitor.md +3 -3
  3. package/guide/agent/app-extras/realtime.md +1 -2
  4. package/guide/agent/app-setup/a-more-interesting-shell.md +36 -14
  5. package/guide/agent/app-setup/authentication.md +7 -15
  6. package/guide/agent/app-setup/console.md +0 -1
  7. package/guide/agent/app-setup/database-layer.md +15 -18
  8. package/guide/agent/app-setup/initial-scaffolding.md +61 -101
  9. package/guide/agent/app-setup/multi-homing.md +2 -10
  10. package/guide/agent/app-setup/quickstart.md +0 -1
  11. package/guide/agent/app-setup/upgrade-beta-1-to-final.md +134 -0
  12. package/guide/agent/app-setup/users.md +8 -15
  13. package/guide/agent/app-setup/working-with-the-jskit-cli.md +168 -997
  14. package/guide/agent/generators/advanced-cruds.md +2 -3
  15. package/guide/agent/generators/crud-generators.md +27 -54
  16. package/guide/agent/generators/row-policies.md +1 -1
  17. package/package.json +1 -1
  18. package/patterns/INDEX.md +1 -1
  19. package/patterns/crud-scaffolding.md +9 -10
  20. package/patterns/generated-ui-contract-tracking.md +3 -3
  21. package/patterns/live-actions.md +5 -4
  22. package/patterns/placements.md +2 -2
  23. package/patterns/ui-testing.md +8 -15
  24. package/reference/autogen/packages/assistant-core.md +0 -6
  25. package/reference/autogen/packages/assistant-runtime.md +0 -6
  26. package/reference/autogen/packages/assistant.md +0 -6
  27. package/reference/autogen/packages/auth-core.md +0 -6
  28. package/reference/autogen/packages/auth-provider-local-core.md +0 -6
  29. package/reference/autogen/packages/auth-provider-local-db-core.md +0 -6
  30. package/reference/autogen/packages/auth-provider-supabase-core.md +0 -6
  31. package/reference/autogen/packages/auth-web.md +0 -6
  32. package/reference/autogen/packages/console-core.md +0 -6
  33. package/reference/autogen/packages/console-web.md +0 -6
  34. package/reference/autogen/packages/crud-core.md +0 -6
  35. package/reference/autogen/packages/crud-server-generator.md +0 -10
  36. package/reference/autogen/packages/crud-ui-generator.md +1 -8
  37. package/reference/autogen/packages/database-runtime-mysql.md +0 -6
  38. package/reference/autogen/packages/database-runtime-postgres.md +0 -6
  39. package/reference/autogen/packages/database-runtime.md +0 -6
  40. package/reference/autogen/packages/feature-server-generator.md +1 -11
  41. package/reference/autogen/packages/google-rewarded-core.md +0 -6
  42. package/reference/autogen/packages/google-rewarded-web.md +0 -6
  43. package/reference/autogen/packages/http-runtime.md +0 -6
  44. package/reference/autogen/packages/json-rest-api-core.md +0 -6
  45. package/reference/autogen/packages/kernel.md +45 -42
  46. package/reference/autogen/packages/mobile-capacitor.md +0 -6
  47. package/reference/autogen/packages/realtime.md +0 -6
  48. package/reference/autogen/packages/resource-core.md +0 -6
  49. package/reference/autogen/packages/resource-crud-core.md +0 -6
  50. package/reference/autogen/packages/shell-web.md +0 -6
  51. package/reference/autogen/packages/storage-runtime.md +0 -6
  52. package/reference/autogen/packages/ui-generator.md +0 -6
  53. package/reference/autogen/packages/uploads-image-web.md +0 -6
  54. package/reference/autogen/packages/uploads-runtime.md +0 -6
  55. package/reference/autogen/packages/users-core.md +0 -14
  56. package/reference/autogen/packages/users-web.md +8 -6
  57. package/reference/autogen/packages/workspaces-core.md +0 -6
  58. package/reference/autogen/packages/workspaces-web.md +0 -6
  59. package/reference/autogen/tooling/create-app.md +0 -14
  60. package/reference/autogen/tooling/jskit-cli.md +65 -190
  61. package/reference/autogen/tooling/testUtils.md +14 -0
  62. package/skills/jskit/SKILL.md +4 -4
  63. package/skills/jskit/references/crud-operations.md +7 -6
  64. package/skills/jskit/references/ui-operations.md +16 -19
@@ -2,1144 +2,315 @@
2
2
 
3
3
  # Working with the JSKIT CLI
4
4
 
5
- In the first chapter, we used the JSKIT CLI, but only in passing. We created the app, installed dependencies, and moved on.
5
+ JSKIT uses normal npm state. `package.json` declares dependencies, `package-lock.json` fixes the installed graph, and each package publishes its JSKIT metadata in `package.json.jskit`.
6
6
 
7
- This chapter steps back and treats the CLI as a subject in its own right.
7
+ The CLI has four jobs:
8
8
 
9
- That matters because `jskit` is not just "the thing that installs packages". It is the tool that helps you:
9
+ 1. install packages and collect missing configuration;
10
+ 2. run generators;
11
+ 3. synchronize immutable migration files;
12
+ 4. generate the JSKIT CI workflow.
10
13
 
11
- - discover what JSKIT can do
12
- - inspect packages, generators, and any catalog shortcuts before using them
13
- - apply and re-apply JSKIT-managed mutations to your app
14
- - keep managed files and lock state healthy
15
- - create your own app-local runtime packages
14
+ Application source belongs to the application. Git records changes to it. JSKIT does not maintain a second project-state ledger.
16
15
 
17
- If you understand this chapter early, the rest of the guide becomes much easier to follow.
16
+ ## Package metadata
18
17
 
19
- ## What the CLI is actually managing
20
-
21
- The easiest way to understand `jskit` is to separate it from the other tools in the app.
22
-
23
- - `jskit` manages JSKIT-owned app mutations
24
- - `npm install` downloads dependencies from `package.json`
25
- - `npm run dev` and `npm run build` run Vite
26
- - `npm run server` runs the backend
27
- - `npm run db:migrate` runs Knex migrations against the database
28
-
29
- That separation is crucial.
30
-
31
- When you run a command such as `npx jskit add package auth-provider-local-core`, JSKIT updates app-owned files and records what it changed. It does **not** replace npm, Vite, or Knex.
32
-
33
- The most important record of that managed state lives here:
34
-
35
- ```text
36
- .jskit/lock.json
37
- ```
38
-
39
- That lock file is the source of truth for installed JSKIT-managed package state. It records things like:
40
-
41
- - which JSKIT packages are installed
42
- - which options were used when they were installed
43
- - which package.json fields were added or changed
44
- - which managed files or text mutations belong to each package
45
-
46
- That is why commands such as `update`, `remove`, `position`, `migrations`, and `doctor` all care about `.jskit/lock.json`.
47
-
48
- ### App-owned does not mean disposable
49
-
50
- A path recorded in `.jskit/lock.json` remains managed while its owning package
51
- is installed. “App-owned” means customizable, not disposable while the package
52
- remains installed. You may edit the file; you may not delete or rename it
53
- without changing the managed package contract.
54
-
55
- Never delete or rename a recorded managed path. Adapt generated infrastructure
56
- tests in place. If a starter product route is replaced, update the scaffold
57
- smoke test to exercise the new canonical route instead of deleting baseline
58
- browser coverage. In particular, preserve managed tests such as
59
- `tests/e2e/base-shell.spec.ts` and `tests/e2e/adaptive-shell.spec.ts`. Doctor
60
- must continue to flag a managed test that is missing.
61
-
62
- ## JSKIT-managed app maintenance scripts
63
-
64
- The scaffolded app also has a small set of `npm run` shortcuts that are really wrappers around JSKIT-owned maintenance behavior.
65
-
66
- The important examples are:
67
-
68
- - `npm run verify`
69
- - `npm run jskit:update`
70
- - `npm run release`
71
-
72
- In the current scaffold, those scripts are intentionally thin:
18
+ A JSKIT package is an ordinary npm package with a `jskit` object in `package.json`:
73
19
 
74
20
  ```json
75
21
  {
76
- "scripts": {
77
- "verify": "jskit app verify && npm run --if-present verify:app",
78
- "jskit:update": "jskit app update-packages",
79
- "release": "jskit app release"
22
+ "name": "@acme/example-core",
23
+ "version": "1.2.3",
24
+ "type": "module",
25
+ "dependencies": {
26
+ "@jskit-ai/kernel": "0.1.148"
27
+ },
28
+ "jskit": {
29
+ "kind": "runtime",
30
+ "capabilities": {
31
+ "provides": ["example.core"],
32
+ "requires": []
33
+ },
34
+ "options": {},
35
+ "runtime": {
36
+ "server": {
37
+ "providers": []
38
+ },
39
+ "client": {
40
+ "providers": []
41
+ }
42
+ },
43
+ "mutations": {
44
+ "dependencies": {
45
+ "runtime": {},
46
+ "dev": {}
47
+ },
48
+ "packageJson": {
49
+ "scripts": {}
50
+ },
51
+ "files": [],
52
+ "text": [],
53
+ "source": []
54
+ }
80
55
  }
81
56
  }
82
57
  ```
83
58
 
84
- That is a deliberate design choice.
85
-
86
- The app keeps the handy `npm run` names, but the real maintenance policy lives in the installed CLI package instead of copied shell scripts inside the app. That means if JSKIT later changes how package updates or baseline verification should work, apps can pick up the new behavior by updating `@jskit-ai/jskit-cli` instead of hand-editing frozen scaffold files.
87
-
88
- This gives you a clean ownership split:
89
-
90
- - app-owned scripts still describe how *this app* runs, builds, and tests
91
- - JSKIT-owned wrapper scripts delegate framework maintenance to `jskit app ...`
92
-
93
- That split is worth keeping in mind through the rest of the guide. When you see `npm run verify`, read it as "run the app's JSKIT baseline verification policy, then any app-specific extra verification hook".
94
-
95
- The starter scaffold also includes `.github/workflows/jskit-verify.yml`. This is a JSKIT-managed projection, not a static template. Installed package descriptors can contribute CI environment values, services, and preparation steps through their top-level `ci` contract. Published JSKIT libraries and tooling support Node.js 22 from 22.13.0 onward, Node.js 24, and Node.js 26, while newly generated applications require Node 26. The managed workflow enforces that application runtime for dependency installation and verification. JSKIT composes the contributions and renders the workflow in this order: checkout, Node 26 setup, `npm ci`, package-contributed `before-verify` steps, and `npm run verify`.
96
-
97
- For example, `database-runtime` contributes the `database-migrations` step. Its MySQL driver contributes a MariaDB service with `DB_CLIENT=mysql2`, while its Postgres driver contributes a Postgres service with `DB_CLIENT=pg`. Each driver supplies matching synthetic CI-only `DB_*` values; local `.env` values are never copied into the workflow.
98
-
99
- The workflow path and generated content hash live under `managed.ciWorkflow` in `.jskit/lock.json`. Package add, remove, update, and app-wide package updates refresh this projection. If the workflow no longer matches its recorded hash, JSKIT refuses to overwrite it during those operations. Move application-specific jobs to another workflow, then explicitly regenerate the managed projection with:
100
-
101
- ```bash
102
- npx jskit app sync-ci
103
- ```
104
-
105
- The command refuses to replace an edited workflow unless you explicitly run `npx jskit app sync-ci --force`. Even with `--force`, it replaces the file only when `.jskit/lock.json` already records JSKIT ownership. It does not claim an unrecorded `.github/workflows/jskit-verify.yml` or remove a customized legacy `.github/workflows/verify.yml`.
59
+ Package identity, version, description, exports, npm dependencies, peer dependencies, and optional dependencies stay in their standard `package.json` fields. Do not repeat npm dependencies in a JSKIT-specific dependency graph.
106
60
 
107
- If your app uses a non-default npm registry for JSKIT packages, pass it to the maintained CLI command rather than hard-coding it in the scaffold. For example:
61
+ `jskit.mutations.dependencies` has a narrower job: it adds direct dependencies
62
+ needed by generated application-owned source or application-level tooling. It
63
+ does not declare relationships between JSKIT packages and does not affect
64
+ package ordering.
108
65
 
109
- ```bash
110
- npm run jskit:update -- --registry https://registry.example.com
111
- npm run release -- --registry https://registry.example.com
112
- ```
66
+ `runtime.server.providers` and `runtime.client.providers` declare runtime entrypoints. A provider class may use `static dependsOn` to order providers inside the runtime container; that is provider boot ordering, not package installation.
113
67
 
114
- ### Update JSKIT packages across an app workspace
68
+ Use exact versions for `@jskit-ai/*` dependencies. npm's `package-lock.json` remains the reproducible installation record.
115
69
 
116
- `npx jskit app update-packages` owns the complete app-wide JSKIT update. At the app root, it installs the exact latest registry version of every `@jskit-ai/*` package listed in `dependencies`, `devDependencies`, `optionalDependencies`, or `peerDependencies`. Exact root versions keep the installed app and its managed lock state reproducible.
117
-
118
- When the app declares npm workspaces, the command asks npm for the workspace graph and aligns JSKIT references in each workspace `package.json` and `package.descriptor.mjs` to the latest major range, such as `0.x`. Descriptor dependency mutations are included whether they use a direct string or a conditional `{ version, when }` record. It then runs `npm update --workspaces` for those packages so `package-lock.json` reflects the aligned ranges. Non-JSKIT dependencies and the public descriptor format are left alone.
119
-
120
- Updating npm packages is only half of a JSKIT upgrade. Package descriptors also own managed files, source and text mutations, lock metadata, migrations, and CI contributions. After installing newer root packages, `update-packages` compares their target versions with the installed records in `.jskit/lock.json`. It reapplies each changed installed package through the same `jskit update package ...` lifecycle used for a manual update. The newly installed local CLI performs that work, saved package options are reused, and customized app-owned files remain protected by the normal ownership checks. The updater reloads the lock between packages, so a dependency already upgraded while reapplying another package is not applied twice.
121
-
122
- This means the normal existing-app upgrade is one command:
70
+ ## Install a package
123
71
 
124
72
  ```bash
125
- npm run jskit:update
73
+ npx jskit add package shell-web
126
74
  ```
127
75
 
128
- After it succeeds, npm dependencies and descriptor-managed app state are current together. If a managed app-owned file is missing, a required saved option can no longer be resolved, or another package update cannot be applied safely, the app-wide update fails instead of leaving that package silently stale. `--dry-run` reports which installed packages would be reapplied without invoking their update lifecycle.
129
-
130
- At the start of a real update, JSKIT resolves and installs the latest `@jskit-ai/jskit-cli`, then hands the rest of the operation to that app-local CLI process. This keeps the one-command contract even when the updater itself has changed: the current code, not the already-running older process, owns package reapplication, migrations, workspace refreshes, and CI synchronization.
131
-
132
- Do not pre-install the CLI separately and do not edit `.jskit/lock.json`. Run `npm run jskit:update`; the updater owns its bootstrap and writes managed state through the normal package lifecycle.
133
-
134
- The update reports elapsed progress for registry and install work. It also refreshes JSKIT-managed migrations and CI after root package changes. Preview the complete operation without changing manifests, descriptors, the lockfile, migrations, or CI with:
76
+ Short JSKIT ids resolve to their `@jskit-ai/*` package ids. A full package id also works:
135
77
 
136
78
  ```bash
137
- npx jskit app update-packages --dry-run
79
+ npx jskit add package @jskit-ai/shell-web
138
80
  ```
139
81
 
140
- For older apps that still carry copied maintenance scripts, the migration path is:
82
+ The command:
141
83
 
142
- ```bash
143
- npx jskit app adopt-managed-scripts
144
- ```
84
+ 1. resolves the requested package;
85
+ 2. computes the resulting npm package graph and validates capabilities and CI contributions;
86
+ 3. collects missing configuration for installed runtime packages in dependency order;
87
+ 4. asks for the requested package last;
88
+ 5. writes an exact direct dependency and runs `npm install` when needed;
89
+ 6. applies the requested package's initial app mutations;
90
+ 7. synchronizes package migrations;
91
+ 8. regenerates the JSKIT CI workflow.
145
92
 
146
- That command rewrites known old scaffold values to the thin wrapper form above.
93
+ Validation happens before application files or migrations are changed. A CI contribution conflict or incomplete capability graph stops the install.
147
94
 
148
- For older apps that were installed before JSKIT source mutations replaced raw source appends, run the source migration after updating JSKIT packages:
95
+ Use `--dry-run` to inspect a supported install without writing, and `--json` when another tool needs structured output.
149
96
 
150
97
  ```bash
151
- npx jskit app update-packages
152
- npx jskit app migrate-source-mutations --dry-run
153
- npx jskit app migrate-source-mutations
154
- npm run verify
98
+ npx jskit add package database-runtime-mysql --dry-run
99
+ npx jskit add package database-runtime-mysql --json
155
100
  ```
156
101
 
157
- That migration is the one upgrade script for JSKIT-owned legacy source mutation shapes. It currently normalizes:
158
-
159
- - `packages/main/src/client/providers/MainClientProvider.js`: moves legacy appended `registerMainClientComponent(...)` calls before `class MainClientProvider`, which is the layout produced by current descriptor `mutations.source` installs.
160
- - `src/pages/**` CRUD form field modules: folds legacy `UI_CREATE_FORM_FIELDS.push(...)` and `UI_EDIT_FORM_FIELDS.push(...)` calls into the corresponding array literals.
102
+ ## Configuration prompts
161
103
 
162
- The command is idempotent, so rerunning it should report that the source files are already current.
104
+ `jskit add` scans installed runtime packages for declared options. Packages with unresolved required configuration are prompted dependency-first. The requested package is prompted last.
163
105
 
164
- ## Discover first, change second
165
-
166
- One of the best habits in JSKIT is to inspect the catalog before mutating the app.
167
-
168
- ### Start with `help`
169
-
170
- The top-level overview is:
171
-
172
- ```bash
173
- npx jskit help
174
- ```
106
+ This means a partially configured app can recover during the next normal package addition. Configuration discovery comes from:
175
107
 
176
- That shows the available commands such as:
108
+ - the installed npm dependency graph;
109
+ - each installed package's `package.json.jskit.options`;
110
+ - current application config and environment values.
177
111
 
178
- - `app`
179
- - `list`
180
- - `show`
181
- - `add`
182
- - `update`
183
- - `remove`
184
- - `position`
185
- - `migrations`
186
- - `create`
187
- - `doctor`
112
+ Sensitive values can be written through the package's declared environment mutation. They are not stored in JSKIT project state.
188
113
 
189
- Every command in the CLI also has its own help page. For example:
114
+ For automation, pass package options inline:
190
115
 
191
116
  ```bash
192
- npx jskit help app
193
- npx jskit help add
194
- npx jskit help migrations
117
+ npx jskit add package database-runtime-mysql \
118
+ --db-host database \
119
+ --db-port 3306 \
120
+ --db-name app \
121
+ --db-user app \
122
+ --db-password "$DB_PASSWORD"
195
123
  ```
196
124
 
197
- That is the fastest way to check current usage without leaving the terminal.
125
+ ## Third-party packages
198
126
 
199
- ### Use `list` for discovery
127
+ Third-party authors publish an ordinary npm package containing `package.json.jskit`. No JSKIT registration step is required.
200
128
 
201
- The broad catalog view is:
129
+ Install it at an exact version, then target it by its npm id:
202
130
 
203
131
  ```bash
204
- npx jskit list
132
+ npm install --save-exact @acme/example-core@1.2.3
133
+ npx jskit add package @acme/example-core
205
134
  ```
206
135
 
207
- By default, this prints three groups:
136
+ The CLI reads the installed package manifest and its package files directly. Package templates referenced by `jskit.mutations.files` must be included in the npm package's `files` allowlist.
208
137
 
209
- - bundles
210
- - runtime packages
211
- - generators
138
+ If an ecosystem package should support a short id or appear in the built-in JSKIT list, it can additionally be included in the JSKIT catalog. That is discovery metadata for the built-in distribution, not a requirement for package execution.
212
139
 
213
- That distinction matters.
140
+ ## Bundles
214
141
 
215
- #### Bundles
216
-
217
- A bundle is a curated install shortcut for several runtime packages that are meant to go together. Bundles can still appear in the catalog for compatibility and quick inspection, but the guide uses explicit package installs so the real runtime packages stay visible.
218
-
219
- #### Runtime packages
220
-
221
- These are the actual packages that change how the app runs. Packages such as `shell-web`, `auth-web`, `users-web`, and `workspaces-web` belong here.
222
-
223
- These are the things you install with:
142
+ A bundle selects two or more runtime packages for one installation:
224
143
 
225
144
  ```bash
226
- npx jskit add package ...
145
+ npx jskit add bundle auth-local
227
146
  ```
228
147
 
229
- #### Generators
148
+ Bundle definitions contain package ids only. npm dependencies still define package dependency relationships. Configuration follows the same dependency-first order, with the explicitly requested packages last.
230
149
 
231
- Generators are tooling packages such as `ui-generator`, `crud-server-generator`, and `crud-ui-generator`.
150
+ ## Generators
232
151
 
233
- They are **not** runtime installs.
234
-
235
- You do **not** add them with `jskit add`. You run them with:
152
+ List and inspect generators:
236
153
 
237
154
  ```bash
238
- npx jskit generate ...
239
- ```
240
-
241
- That distinction is easy to miss at first, and it is one of the main reasons this chapter exists.
242
-
243
- If you only want one section of the catalog, use a mode:
244
-
245
- ```bash
246
- npx jskit list packages
247
155
  npx jskit list generators
156
+ npx jskit show package crud-server-generator
248
157
  ```
249
158
 
250
- Those two commands are especially useful later in the guide, once you already know roughly what kind of thing you are looking for.
251
-
252
- If you want bundle members printed inline too, `npx jskit list --full` expands the bundle view. That is useful when you are auditing a shortcut, but package ids are still the normal install vocabulary in this guide.
253
-
254
- One more detail is worth noticing. In repos that contain local package descriptors, `list packages` can also show app-local or repo-local packages in addition to the published catalog. So `list` is not only a remote catalog browser. It is also a view of what this app can currently see.
255
-
256
- ### Use `show` before you install
257
-
258
- Once `list` helps you find the right id, `show` is how you inspect it.
259
-
260
- The basic form is:
261
-
262
- ```bash
263
- npx jskit show <id>
264
- ```
265
-
266
- And the more useful inspection form is:
267
-
268
- ```bash
269
- npx jskit show <id> --details
270
- ```
271
-
272
- This command is unusually valuable in JSKIT because packages and catalog shortcuts do more than "add a dependency". They can:
273
-
274
- - provide or require capabilities
275
- - register runtime providers
276
- - contribute placement entries
277
- - write files into the app
278
- - mutate `package.json`, scripts, and text blocks
279
-
280
- So `show` is the command that answers:
281
-
282
- - what does this thing actually install?
283
- - what does it depend on?
284
- - what runtime surfaces does it contribute?
285
- - what app-owned files will it write or mutate?
286
- - what container tokens or import surfaces does it expose?
287
-
288
- The plain form is useful when you only want to identify something quickly. `--details` is what turns `show` into a real architecture-inspection command.
289
-
290
- ### What `show` is good at
291
-
292
- There are two especially common cases:
293
-
294
- - you found a package or shortcut in `jskit list` and want to know what it really does before you install it
295
- - you already know a package changed the shell, the runtime graph, or the app tree, and you want to see *how*
296
-
297
- That second case matters just as much as the first one. Later in the guide, chapters explain package behavior one feature at a time. `show --details` is the generic command that lets you inspect those same package contracts directly.
298
-
299
- ### A first example: inspect the local auth provider
300
-
301
- Run:
302
-
303
- ```bash
304
- npx jskit show auth-provider-local-core --details
305
- ```
306
-
307
- This output is short, but it already teaches something important:
308
-
309
- - `auth-provider-local-core` is a **runtime package**
310
- - it selects the local auth provider
311
- - it depends on the provider-neutral `auth-core`
312
-
313
- The default local auth install uses two direct package commands:
159
+ Run a generator:
314
160
 
315
161
  ```bash
316
- npx jskit add package auth-provider-local-core
317
- npx jskit add package auth-web
162
+ npx jskit generate crud-server-generator scaffold contacts \
163
+ --surface app \
164
+ --grant-policy workspace_member
318
165
  ```
319
166
 
320
- That is exactly the kind of thing you want to know before you mutate the app:
321
-
322
- - which package selects the active provider?
323
- - which package adds the web auth routes and login UI?
167
+ Generator packages are development dependencies. Their transitive dependencies are tooling dependencies and are not activated as application runtime packages.
324
168
 
325
- It also helps you keep the mental model straight:
169
+ Generated source belongs to the application immediately. Edit it normally and review it in Git.
326
170
 
327
- - runtime packages are the things that actually provide capabilities
328
- - `auth-provider-local-core` provides the selected `auth.provider`
329
- - `auth-web` consumes the selected provider and adds the web surface
171
+ ## App-local packages
330
172
 
331
- ### A richer example: what does `workspaces-web` contribute?
332
-
333
- Run:
173
+ Create a local package:
334
174
 
335
175
  ```bash
336
- npx jskit show @jskit-ai/workspaces-web --details
337
- ```
338
-
339
- This is where `--details` becomes much more powerful.
340
-
341
- The compact form of `show` is fine when you only want the package description. The detailed form can show things like:
342
-
343
- - provided and required capabilities
344
- - summary import surfaces / exported subpaths
345
- - container tokens
346
- - placement outlets
347
- - default placement contributions
348
- - dependency mutations
349
- - script mutations
350
- - text mutations
351
- - file writes
352
- - runtime providers
353
-
354
- That makes `show --details` one of the best "read before you write" commands in the whole CLI.
355
-
356
- ### Why `--details` matters
357
-
358
- The plain form:
359
-
360
- ```bash
361
- npx jskit show @jskit-ai/workspaces-web
362
- ```
363
-
364
- is mainly for identifying the package at a glance.
365
-
366
- The detailed form:
367
-
368
- ```bash
369
- npx jskit show @jskit-ai/workspaces-web --details
176
+ npx jskit create package contacts
370
177
  ```
371
178
 
372
- is for understanding the package as part of the app architecture. It lets you answer concrete questions from one command instead of hunting across descriptors and generated files.
373
-
374
- That is the version you should prefer when you are making a real install decision.
375
-
376
- ### What `show --details` teaches you
377
-
378
- The output is not one giant wall of metadata. It is answering several practical questions. You do not need to read every line. Read the sections that answer the question you currently have.
379
-
380
- #### "What capabilities does this package participate in?"
381
-
382
- The `Capabilities` section tells you:
383
-
384
- - what the package provides
385
- - what it requires from other packages
386
-
387
- That helps you reason about dependency direction and why some packages bring others with them.
388
-
389
- For `@jskit-ai/workspaces-web`, the detailed output shows:
390
-
391
- - it **provides** `workspaces.web`
392
- - it **requires** `users.web` and `workspaces.core`
393
-
394
- That immediately tells you this package is not just some loose UI helper. It is the web layer of the workspace feature set, and it expects the users and workspace core layers underneath it.
395
-
396
- #### "What UI does this package contribute?"
397
-
398
- The placement sections are often the most useful part of `show --details`.
399
-
400
- For `@jskit-ai/workspaces-web`, the detailed output shows placement contributions such as:
401
-
402
- - the workspace selector in `shell.identity`
403
- - the pending invites cue in `shell.status`
404
- - the workspace tools widget on the `admin` surface
405
- - the `Members` and workspace settings menu entries
406
-
407
- That lets you answer a very concrete question before installing anything:
408
-
409
- - *what will change in the shell if I add this package?*
410
-
411
- It also shows semantic placement topology, such as:
412
-
413
- - `page.section-nav` with owner `admin-settings`
414
- - `admin.tools-menu`
415
-
416
- which helps you understand where later app-owned pages or settings links can attach.
417
-
418
- #### "What import paths, tokens, or providers does it register?"
419
-
420
- The detailed output can also show:
421
-
422
- - summary import surfaces / exported subpaths
423
- - container tokens
424
- - runtime providers
425
-
426
- For `@jskit-ai/workspaces-web`, that includes client tokens such as:
427
-
428
- - `workspaces.web.workspace.selector`
429
- - `workspaces.web.workspace.tools.widget`
430
- - `workspaces.web.members-admin.element`
431
-
432
- It also shows a short `Summary` section with the main client import surfaces, such as:
433
-
434
- - `@jskit-ai/workspaces-web/client`
435
- - `@jskit-ai/workspaces-web/client/providers/WorkspacesWebClientProvider`
436
- - `@jskit-ai/workspaces-web/client/composables/useWorkspaceRouteContext`
437
-
438
- That gives you a quick view of the package's client integration surface without reading the source first.
439
-
440
- This is especially useful when you are asking questions like:
441
-
442
- - *does this package expose a client entrypoint I can import from?*
443
- - *does it register a provider, or am I expected to wire components myself?*
444
- - *what token name should I expect to see in placements or providers?*
445
-
446
- #### "What app-owned files will it touch?"
447
-
448
- The `File writes`, `Text mutations`, `Source mutations`, and `Script mutations` sections answer one of the most practical questions in JSKIT:
449
-
450
- - *what will this package actually do to my app tree?*
451
-
452
- For `@jskit-ai/workspaces-web`, the detailed view shows app-owned files such as:
453
-
454
- - workspace surface route scaffolds
455
- - workspace settings pages
456
- - `WorkspaceNotFoundCard.vue`
457
- - `useWorkspaceNotFoundState.js`
458
-
459
- It also shows text mutations such as:
460
-
461
- - appending placement entries to `src/placement.js`
462
-
463
- And it shows source mutations such as:
464
-
465
- - adding imports to `packages/main/src/client/providers/MainClientProvider.js`
466
- - registering component tokens in `packages/main/src/client/providers/MainClientProvider.js`
467
-
468
- That matters because JSKIT packages are not only libraries. Many of them also write scaffold files into the app and extend app-owned provider files.
469
-
470
- ### The kinds of questions this answers well
471
-
472
- Once you get used to it, `show --details` is the fast answer to questions like:
473
-
474
- - *what does this bundle really install?*
475
- - *why did this package add a new shell widget?*
476
- - *which capabilities does this package provide and require?*
477
- - *which app-owned files will JSKIT write if I install this?*
478
- - *where do later pages or placements plug into this package?*
479
- - *what container tokens or client entrypoints does this package expose?*
480
-
481
- ### How to read the output at a high level
179
+ This creates `packages/contacts/package.json` with a `jskit` object and adds an exact `file:` dependency to the application.
482
180
 
483
- Not every package shows every section, and that is normal. A good reading order is:
181
+ The package can use standard npm dependencies and exports. Put server and client providers in `package.json.jskit.runtime`.
484
182
 
485
- 1. `Information`
486
- - what is this thing?
487
- 2. `Summary`
488
- - what are the main import paths or public entrypoints?
489
- 3. `Depends on`
490
- - what else does it need?
491
- 4. `Capabilities`
492
- - what role does it play in the runtime graph?
493
- 5. `Placement contributions` / `Placement outlets`
494
- - what UI surfaces does it add?
495
- 6. `File writes`, `Text mutations`, and `Source mutations`
496
- - what app-owned files will change?
497
- 7. `Runtime providers` and `Container tokens`
498
- - what does it register internally?
183
+ ## Migrations
499
184
 
500
- That is enough to make `show --details` useful without treating it like a formal spec.
501
-
502
- ### A simple rule of thumb
503
-
504
- Use:
185
+ Packages declare migration templates with `install-migration` file mutations. Synchronize them into the application with:
505
186
 
506
187
  ```bash
507
- npx jskit show <id>
188
+ npx jskit migrations sync
508
189
  ```
509
190
 
510
- when you only want to identify a package or bundle quickly.
511
-
512
- Use:
191
+ Check without writing:
513
192
 
514
193
  ```bash
515
- npx jskit show <id> --details
194
+ npx jskit migrations sync --check
516
195
  ```
517
196
 
518
- when you are seriously considering installing it, or when you need to understand why a package changed the shell, the config, or the runtime in a particular way.
519
-
520
- ## Make the terminal nicer: `completion`
521
-
522
- The CLI also ships with Bash completion:
523
-
524
- ```bash
525
- npx jskit completion bash
526
- ```
527
-
528
- That prints the completion script to stdout.
529
-
530
- If you only want completion for the current shell session, run:
531
-
532
- ```bash
533
- source <(npx jskit completion bash)
534
- ```
197
+ Migration ids are immutable. The same package and migration id must always produce the same content. A conflict fails instead of overwriting migration history.
535
198
 
536
- If you want JSKIT completion to keep working in future Bash sessions too, run:
199
+ Synchronization changes files only. Apply database migrations separately:
537
200
 
538
201
  ```bash
539
- npx jskit completion bash --install
202
+ npm run db:migrate
540
203
  ```
541
204
 
542
- This is not required, but it is genuinely useful once you start using commands such as `add`, `generate`, and `show` frequently.
543
-
544
- ## Installing runtime capability: `add`
545
-
546
- The install command you will use most often is:
205
+ Create an app-owned package migration with:
547
206
 
548
207
  ```bash
549
- npx jskit add package users-web
208
+ npx jskit create migration \
209
+ --package @local/contacts \
210
+ --id add-contact-status
550
211
  ```
551
212
 
552
- That command installs one runtime package and its dependency chain.
213
+ Implement the package template, run `npx jskit migrations sync`, review the generated migration, and then run the database migration command.
553
214
 
554
- ### `add package`
215
+ ## CI generation
555
216
 
556
- Use this when you know the exact runtime package you want:
217
+ Generate the JSKIT verification workflow:
557
218
 
558
219
  ```bash
559
- npx jskit add package users-web
220
+ npx jskit ci generate
560
221
  ```
561
222
 
562
- This is the shape of the package install commands used throughout the rest of the guide.
563
-
564
- Important defaults:
565
-
566
- - short ids such as `users-web` resolve to `@jskit-ai/users-web` when available
567
- - JSKIT records the install in `.jskit/lock.json`
568
- - JSKIT rewrites app-owned managed files as needed
569
- - npm install does **not** run unless you ask for it with `--run-npm-install`
570
-
571
- That last point is why the normal guide flow after adding a runtime package is still:
223
+ Check it without writing:
572
224
 
573
225
  ```bash
574
- npx jskit add package users-web
575
- npm install
226
+ npx jskit ci generate --check
576
227
  ```
577
228
 
578
- `jskit add` changes the app. `npm install` downloads the dependencies that the changed app requires.
579
-
580
- ### `add bundle`
581
-
582
- Bundles are a convenience layer for catalog shortcuts. Prefer package commands in setup docs and normal app work, especially for auth, because provider ownership is clearer when the selected provider package is installed explicitly.
583
-
584
- If you do use a bundle shortcut, inspect it first with `npx jskit show <bundle-id> --details` so you can see the real packages and capabilities it will install.
585
-
586
- ### Generator packages are different
587
-
588
- This is worth saying one more time because it causes confusion early on.
589
-
590
- If `npx jskit list generators` shows a package such as `crud-ui-generator`, that does **not** mean you should run:
229
+ This command fully generates one file:
591
230
 
592
- ```bash
593
- npx jskit add package crud-ui-generator
231
+ ```text
232
+ .github/workflows/jskit-verify.yml
594
233
  ```
595
234
 
596
- Generators are tooling packages. You use them through `jskit generate`, not `jskit add`.
597
-
598
- ## Managed-file lifecycle: `update`, `remove`, and `position`
599
-
600
- Once a package is installed, JSKIT treats it as managed app state, not just as "one more dependency".
601
-
602
- That state lives in `.jskit/lock.json`, which is why lifecycle commands all start from the lock record for the installed package. In practice, that means JSKIT remembers:
603
-
604
- - which package is installed
605
- - which install options were used
606
- - which files, text mutations, dependency entries, and migrations it owns
607
- - the path and content hash of the composed JSKIT CI workflow
235
+ Do not edit that file. Put application-specific CI jobs in separate, application-owned workflow files.
608
236
 
609
- The easiest way to think about the lifecycle is:
237
+ Packages contribute CI environment values, services, and pre-verification steps through `package.json.jskit.ci`. Conflicting contributions fail with the contributing package ids.
610
238
 
611
- 1. `jskit add package ...` creates managed state
612
- 2. `jskit update package ...` reapplies that managed state
613
- 3. `jskit position element ...` reapplies just the positioning layer
614
- 4. `jskit remove package ...` removes the managed state
615
-
616
- Package add, update, and remove also recompose `.github/workflows/jskit-verify.yml` from the complete installed package set. No individual package owns that file through `mutations.files`; it is one app-level projection with contributions from many descriptors.
617
-
618
- That is a better mental model than thinking of these as three unrelated commands.
619
-
620
- ### `update` re-applies one installed package
621
-
622
- The basic shape is:
239
+ ## Update JSKIT packages
623
240
 
624
241
  ```bash
625
- npx jskit update package workspaces-web
242
+ npm run jskit:update
626
243
  ```
627
244
 
628
- This does **not** mean "fetch the newest npm version" in the way people often expect from other ecosystems.
629
-
630
- In JSKIT, `update package ...` means:
245
+ The script runs `jskit app update-packages`. It installs current `@jskit-ai/*` packages at exact versions, aligns JSKIT references in npm workspaces, refreshes npm resolution, synchronizes migrations, and regenerates CI.
631
246
 
632
- - find the installed package in `.jskit/lock.json`
633
- - reuse the saved lock options unless you override them inline
634
- - run the normal package-application flow again with forced reapply
635
-
636
- So `update` is for reapplying package-owned managed changes, not for generic dependency upgrades.
637
-
638
- The best guide example is the tenancy-mode recovery path from the multi-homing chapter. If you installed `workspaces-core` or `workspaces-web` while the app was still on `tenancyMode = "none"`, then later changed the app to `personal`, the missing gated scaffold does not backfill automatically. The recovery path is:
247
+ Preview registry changes with:
639
248
 
640
249
  ```bash
641
- npx jskit update package users-core
642
- npx jskit update package workspaces-core
643
- npx jskit update package workspaces-web
250
+ npx jskit app update-packages --dry-run
644
251
  ```
645
252
 
646
- That works because `update` reuses the saved install record and re-applies the package after the surrounding app state has changed.
647
-
648
- This is the main kind of problem `update` solves:
649
-
650
- - a package was installed correctly for the app state at the time
651
- - the app state changed later
652
- - the package's managed mutations need to be applied again
653
-
654
- ### `position` re-applies only the placement/positioning layer
253
+ Package updates do not regenerate application source. Review upstream release notes and make application changes explicitly.
655
254
 
656
- The positioning command is:
255
+ ## Remove a package
657
256
 
658
257
  ```bash
659
- npx jskit position element workspaces-web
258
+ npx jskit remove package @jskit-ai/example-core
660
259
  ```
661
260
 
662
- This is the focused version of reapply.
261
+ The command removes the application's direct npm dependency, runs npm install, and regenerates CI. App source and database migration history are retained. Delete application-owned source only when you have reviewed its remaining consumers.
663
262
 
664
- It reads the installed package from the lock file and reapplies only positioning mutations. That makes it especially useful for placement-heavy packages such as `shell-web` or `workspaces-web`, where a package contributes:
263
+ An npm-transitive package cannot be removed directly. Remove or replace the direct package that depends on it.
665
264
 
666
- - shell placements
667
- - menu entries
668
- - outlet-targeted UI elements
669
- - ordering-sensitive positioned elements
265
+ ## Inspect and validate
670
266
 
671
- Use `position` when:
672
-
673
- - the package itself is still installed
674
- - you only need the placement layer refreshed
675
- - you do **not** want a full package reapply
676
-
677
- A realistic example is a workspace-heavy shell where the placement registry or surrounding shell files were edited, merged, or recovered and you want JSKIT to re-apply the `workspaces-web` positioned contributions without rerunning the whole install flow:
267
+ Useful read-only commands:
678
268
 
679
269
  ```bash
680
- npx jskit position element workspaces-web
681
- ```
682
-
683
- That is why the target word is `element` rather than `package`. This command is about positioned UI contributions, not general package installation.
684
-
685
- It also does **not** run npm install. This is a focused managed-file repair command, not a dependency-install step.
686
-
687
- ### `remove` removes managed state for one installed package
688
-
689
- The removal form is:
690
-
691
- ```bash
692
- npx jskit remove package workspaces-web
270
+ npx jskit list packages
271
+ npx jskit list generators
272
+ npx jskit show package shell-web
273
+ npx jskit list-placements
274
+ npx jskit list-component-tokens
693
275
  ```
694
276
 
695
- This is the inverse side of the lifecycle.
696
-
697
- `remove` uses the lock record to tear out the managed state that package owns. In practice, that means it:
698
-
699
- - removes the package's lock entry
700
- - restores or removes the `package.json` fields JSKIT originally managed
701
- - removes managed files only when they still match the version JSKIT owns
702
-
703
- That last part is important. JSKIT is trying to remove package-owned managed state without blindly deleting user-owned edits.
704
-
705
- Two practical things to remember:
706
-
707
- - `remove` can refuse to run if other installed packages depend on the target package
708
- - it does **not** automatically delete app-owned local package directories such as `packages/contacts/`
709
-
710
- So if you created a local package yourself, `remove` cleans up the JSKIT-managed install state, but it does not assume it should delete the directory you own.
711
-
712
- ### The practical rule of thumb
713
-
714
- If a package is already installed and you are deciding which command to use, think like this:
715
-
716
- - use `update` when the package's full managed install state needs to be applied again
717
- - use `position` when only its placement/positioning contributions need to be refreshed
718
- - use `remove` when you want JSKIT to cleanly remove the managed package state from the app
719
-
720
- All three commands make more sense once you see them as one lifecycle around `.jskit/lock.json`, not as isolated CLI tricks.
721
-
722
- ### `doctor` checks managed-state health
723
-
724
- The health check is:
277
+ Validate package metadata:
725
278
 
726
279
  ```bash
727
- npx jskit doctor
728
- ```
729
-
730
- This is JSKIT's normal app-health check for JSKIT-managed state.
731
-
732
- It is not a linter, and it is not a test runner. It validates the things that only JSKIT itself can really verify.
733
-
734
- In the current CLI, that includes checks such as:
735
-
736
- - installed package entries in `.jskit/lock.json`
737
- - whether managed files recorded in the lock still exist
738
- - whether installed packages are still visible in the package registry
739
- - whether package CI contributions compose without conflicts and match the managed workflow service, environment, preparation steps, and ordering
740
- - explicit `transport` passed to high-level CRUD hooks such as `useCrudList()`, `useCrudView()`, and `useCrudAddEdit()`, where the shared CRUD resource should derive the JSON:API transport automatically
741
- - certain JSKIT-specific app checks, such as invalid raw `mdi-*` icon literals in Vue templates when the app uses Vuetify's `mdi-svg` iconset
742
- - UI verification receipts for current dirty UI files in git, via `.jskit/verification/ui.json`
743
-
744
- That last check is narrower than it sounds. `doctor` is looking for the broken case in direct Vue templates, such as:
745
-
746
- ```vue
747
- <v-icon icon="mdi-paw" />
280
+ npx jskit lint-packages
748
281
  ```
749
282
 
750
- It does not flag `src/placement.js` menu metadata because shell menu links normalize a small core icon map and also accept imported `@mdi/js` path constants. For app-specific icons, prefer a local import:
751
-
752
- ```js
753
- import { mdiPaw } from "@mdi/js";
754
-
755
- icon: mdiPaw
756
- ```
757
-
758
- So if you see a `doctor` icon warning, the fix is usually "switch this Vue component to `@mdi/js`", not "centralize every icon in the app."
759
-
760
- In other words, `doctor` helps catch drift between:
761
-
762
- - what JSKIT thinks it owns
763
- - what is actually present on disk
764
-
765
- That is a different job from:
766
-
767
- - `npm run lint`, which checks source style and static code rules
768
- - `npm run test`, which checks behavior
769
- - `npm run build`, which checks whether the app can compile successfully
770
-
771
- Those commands can all pass while JSKIT-managed state is still inconsistent. `doctor` is the command that checks that JSKIT's own view of the app still makes sense.
772
-
773
- That is exactly why the starter scaffold routes `npm run verify` through `jskit app verify`. CI structure is checked before lint, test, client-test, and build scripts, so a stale database service or missing migration step fails directly instead of surfacing later as an opaque provider boot failure.
774
-
775
- It belongs there because JSKIT apps are not only source trees. They also have:
776
-
777
- - descriptor-driven runtime installs
778
- - lock-file state under `.jskit/lock.json`
779
- - JSKIT-managed files and mutations written into the app
780
-
781
- `doctor` is the quick confirmation that those pieces still line up after all the normal quality checks pass.
782
-
783
- This command belongs in your normal quality gate, not only in emergency debugging.
784
-
785
- ### When to run it manually
786
-
787
- The most common manual use is simply:
283
+ Validate an application:
788
284
 
789
285
  ```bash
790
286
  npx jskit doctor
791
287
  ```
792
288
 
793
- after you have done something that changes JSKIT-managed state.
794
-
795
- Good times to run it manually include:
796
-
797
- - after `jskit add`, `update`, `remove`, `create package`, or generator commands
798
- - after rebasing or resolving conflicts that touched `.jskit/lock.json`, `package.json`, or app-owned managed files
799
- - after deleting, moving, or renaming files that may have been created by JSKIT
800
- - when a package appears installed in the lock but starts behaving as if it is missing
801
- - when you want a fast JSKIT-specific health check without waiting for a full test suite
802
-
803
- One important nuance: `doctor` is checking for broken JSKIT ownership and visibility, not trying to stop you from editing app-owned files. For example, a managed file that still exists but whose contents changed is normally fine. An app-owned file explicitly installed by a package can also live under `packages/main/src/server/` without being mistaken for undeclared domain logic. The file remains part of managed state, so deleting it is still an error. Unrelated server files under `packages/main` continue to receive the normal feature-lane warning.
804
-
805
- There is one intentional exception for user-facing UI work.
806
-
807
- If the current git working tree has changed UI files under the app's normal UI paths, `doctor` expects a matching `.jskit/verification/ui.json` receipt. The intended way to create that receipt is:
808
-
809
- ```bash
810
- npx jskit app verify-ui \
811
- --command "npx playwright test tests/e2e/contacts.spec.ts -g filters" \
812
- --feature "contacts filters" \
813
- --auth-mode dev-auth-login-as
814
- ```
815
-
816
- That command does two things:
817
-
818
- - runs the targeted Playwright command you give it
819
- - writes a receipt describing the verified feature, auth mode, and current dirty UI file set
820
-
821
- The auth mode is receipt metadata, not an authentication implementation. `jskit app verify-ui` does not log a user in, inject a secret, or rewrite the Playwright context. A direct local run uses `loginAsExistingUser()` from `@jskit-ai/auth-web/test/playwright`; Vibe64 supplies authenticated state through `VIBE64_PLAYWRIGHT_STORAGE_STATE`. The generated `playwright.config.mjs` consumes that state and honors `PLAYWRIGHT_BASE_URL` without starting a second server.
822
-
823
- `doctor` then compares the current changed UI files to that receipt. If you edit the UI again afterwards, the receipt is stale and `doctor` tells you to rerun `jskit app verify-ui`.
824
-
825
- For local pre-merge review, use `--against <base-ref>` so JSKIT compares against the branch delta instead of only the current dirty worktree. The common shape is:
826
-
827
- ```bash
828
- npx jskit doctor --against origin/main
829
- ```
830
-
831
- If the UI changed, the normal local sequence is:
832
-
833
- 1. run the targeted Playwright flow locally
834
- 2. record it with `jskit app verify-ui ...`
835
- 3. run `jskit doctor --against <base-ref>`
836
-
837
- Advanced CI pipelines can also use `--against <base-ref>`, but that is intentionally app-specific. JSKIT does not scaffold hosted browser/auth/database verification by default, because many real apps need secrets, seeded databases, local auth bypass, or environment-specific bootstrap paths that do not belong in a one-size-fits-all template.
838
-
839
- ### Why `--json` exists
840
-
841
- If you want machine-readable output, use:
842
-
843
- ```bash
844
- npx jskit doctor --json
845
- ```
846
-
847
- That prints a payload with:
848
-
849
- - `appRoot`
850
- - `lockVersion`
851
- - `installedPackages`
852
- - `issues`
853
-
854
- This is useful in CI, editor tooling, or custom scripts where you want to parse the result instead of reading plain text. The exit code still does the simple job, but `--json` gives you the exact issue list in a form that other tools can consume.
855
-
856
- ## Migrations: writing files is not the same as running the database
857
-
858
- This distinction is one of the most important things to understand in JSKIT.
859
-
860
- The explicit migration-materialization command is:
861
-
862
- ```bash
863
- npx jskit migrations changed
864
- ```
865
-
866
- This command does **not** run Knex against the database.
867
-
868
- What it does is:
869
-
870
- - look at installed packages in `.jskit/lock.json`
871
- - decide which installed packages have managed migrations that need to be materialized
872
- - write those migration files into your app
873
-
874
- So this command is about **managed migration files on disk**.
875
-
876
- In many normal `jskit add` flows, those migration files are already written as part of package application. `jskit migrations changed` is the explicit re-sync command when you want JSKIT to materialize the migration files again based on the current installed package state.
877
-
878
- The database execution step is still:
879
-
880
- ```bash
881
- npm run db:migrate
882
- ```
883
-
884
- That step is about **running** the migration files that already exist.
885
-
886
- The clean mental model is:
887
-
888
- 1. JSKIT materializes managed migration files
889
- 2. Knex executes them against the database
890
-
891
- If you remember only one thing from this section, make it this:
892
-
893
- - `jskit migrations ...` writes or refreshes managed migration files
894
- - `npm run db:migrate` actually applies migrations to the database
895
-
896
- Do not confuse those two steps.
897
-
898
- Here is the practical version:
899
-
900
- ```bash
901
- # Common install flow for a schema-bearing package
902
- npx jskit add package users-web
903
- npm install
904
- npm run db:migrate
905
-
906
- # Refresh flow when JSKIT needs to re-materialize managed migration files
907
- npx jskit migrations changed
908
- npm run db:migrate
909
- ```
910
-
911
- In the first flow, package installation usually already wrote the managed migration files. In the second flow, you are explicitly asking JSKIT to write or refresh them again before Knex applies them.
912
-
913
- ## Creating your own local package
914
-
915
- JSKIT can also scaffold a brand-new app-local runtime package:
916
-
917
- ```bash
918
- npx jskit create package contacts
919
- ```
920
-
921
- If your app is named `exampleapp`, that command creates a package id like:
922
-
923
- ```text
924
- @exampleapp/contacts
925
- ```
926
-
927
- and scaffolds a real local package under:
928
-
929
- ```text
930
- packages/contacts/
931
- ```
932
-
933
- This is the direct CLI path for creating your own runtime package inside the app.
934
-
935
- It is for the cases where you are authoring the package yourself:
936
-
937
- - you want a new package boundary under `packages/`
938
- - you want to define your own descriptor, providers, routes, or capabilities
939
- - you are building app-specific runtime code, not installing something prebuilt from the catalog
940
-
941
- That makes it different from both `add` and `generate`.
942
-
943
- - `jskit add package ...` installs an existing runtime package from the catalog or from `node_modules`
944
- - `jskit generate ...` runs a generator that writes app-owned scaffold files for a specific job such as CRUD
945
- - `jskit create package ...` gives you a blank but valid app-local runtime package to grow yourself
946
-
947
- ### What the command creates
948
-
949
- The new package is intentionally small. For `contacts`, the scaffold looks like this:
950
-
951
- ```text
952
- packages/contacts/
953
- README.md
954
- package.json
955
- package.descriptor.mjs
956
- src/index.js
957
- src/client/index.js
958
- src/server/index.js
959
- src/shared/index.js
960
- ```
961
-
962
- The command also updates two app-level files:
963
-
964
- - `package.json`
965
- - `.jskit/lock.json`
966
-
967
- That means `create package` is not just "make a folder". It creates a real local JSKIT package and registers it with the app.
968
-
969
- The important pieces are:
970
-
971
- - `package.json`
972
- defines a private local package with exports for `.`, `./client`, `./server`, and `./shared`
973
- - `package.descriptor.mjs`
974
- starts as a runtime descriptor with empty `dependsOn`, `capabilities`, `runtime`, `metadata`, and `mutations` sections ready for you to fill in
975
- - `src/index.js`
976
- gives the package a top-level module entrypoint, even before you decide what should be exported from it
977
- - `src/client/index.js`
978
- exports an empty `routeComponents` map and a no-op `bootClient()` so the package already has a valid client entrypoint
979
- - `src/server/index.js` and `src/shared/index.js`
980
- give you the server and shared entrypoints without assuming any implementation yet
981
- - `README.md`
982
- reminds you that the next step is to define runtime providers and real exports
983
-
984
- This is a deliberate contrast with generated CRUD packages. A CRUD generator writes a much more opinionated scaffold: repository code, routes, actions, migrations, and resource definitions. `create package` does not guess any of that. It gives you the smallest valid runtime package boundary.
985
-
986
- ### How the new package fits into the app
987
-
988
- When you create `contacts`, JSKIT also adds a file dependency to the app root `package.json`:
989
-
990
- ```json
991
- "@exampleapp/contacts": "file:packages/contacts"
992
- ```
993
-
994
- and records the package in `.jskit/lock.json` as a `local-package`.
995
-
996
- That has a few consequences:
997
-
998
- - the package becomes part of the app's managed JSKIT state
999
- - `jskit list packages` can see it alongside catalog packages
1000
- - later `update`, `remove`, and related lifecycle commands know this package exists
1001
- - the package is still app-owned, so JSKIT does not assume it can delete your directory just because managed state changes
1002
-
1003
- This is the same idea you already saw in the starter app's `packages/main/` package. `create package` is how you make another package like that on purpose, instead of waiting for a generator to create one indirectly.
289
+ `doctor` checks the installed package graph, capability closure, provider declarations, migrations, generated CI, surfaces, placements, CRUD ownership, and other architecture contracts.
1004
290
 
1005
- One practical point is easy to miss: the package exists immediately, but it does not do anything interesting until you give the descriptor real runtime hooks. In other words, after `create package`, you still need to add things such as:
1006
-
1007
- - client providers
1008
- - server providers
1009
- - routes or UI metadata
1010
- - capabilities or dependency declarations
1011
-
1012
- So think of `create package` as "establish the package boundary first, then implement the runtime behavior."
1013
-
1014
- Because the command adds a file dependency, the normal follow-up is still:
1015
-
1016
- ```bash
1017
- npm install
1018
- ```
1019
-
1020
- or:
291
+ The normal CI sequence is:
1021
292
 
1022
293
  ```bash
1023
- npx jskit create package contacts --run-npm-install
1024
- ```
1025
-
1026
- JSKIT updates the app files. npm refreshes dependency installation.
1027
-
1028
- ### When to use it instead of a generator
1029
-
1030
- Use `create package` when you are designing the package structure yourself.
1031
-
1032
- Good fits include:
1033
-
1034
- - a custom integration package that talks to one external API
1035
- - app-specific auth or policy behavior
1036
- - a local runtime package that owns both client and server behavior for one feature area
1037
- - a package that starts small but may later grow providers, shared helpers, and routes
1038
-
1039
- Use a generator when the problem is already understood well enough that JSKIT can scaffold the feature shape for you.
1040
-
1041
- For example:
1042
-
1043
- - `npx jskit create package contacts`
1044
- gives you an empty-but-valid `packages/contacts/` package boundary
1045
- - `npx jskit generate crud-server-generator scaffold contacts ...`
1046
- creates a CRUD-shaped package with repository, service, route, action, and migration files
1047
-
1048
- Those commands can both result in a package under `packages/contacts/`, but they start from very different assumptions.
1049
-
1050
- The other contrast is with catalog installs:
1051
-
1052
- - `npx jskit add package workspaces-web`
1053
- installs a package someone else already authored
1054
- - `npx jskit create package contacts`
1055
- creates a package that your app will author and own
1056
-
1057
- ### `--scope`, `--package-id`, and `--description` in practice
1058
-
1059
- The three most important inline options are about naming and identity.
1060
-
1061
- #### `--scope`
1062
-
1063
- By default, JSKIT derives the scope from the app package name.
1064
-
1065
- So if your app is `exampleapp`, this:
1066
-
1067
- ```bash
1068
- npx jskit create package contacts
1069
- ```
1070
-
1071
- produces:
1072
-
1073
- ```text
1074
- package id: @exampleapp/contacts
1075
- directory: packages/contacts
1076
- ```
1077
-
1078
- If you want a different scope, use `--scope`:
1079
-
1080
- ```bash
1081
- npx jskit create package contacts --scope local
294
+ npm ci
295
+ npx jskit migrations sync --check
296
+ npx jskit ci generate --check
297
+ npm run verify
1082
298
  ```
1083
299
 
1084
- which produces:
300
+ ## Command summary
1085
301
 
1086
302
  ```text
1087
- package id: @local/contacts
1088
- directory: packages/contacts
303
+ jskit add package <id>
304
+ jskit add bundle <id>
305
+ jskit generate <generator-id> [subcommand]
306
+ jskit create package <name>
307
+ jskit create migration --package <id> --id <migration-id>
308
+ jskit migrations sync [--check]
309
+ jskit ci generate [--check]
310
+ jskit remove package <id>
311
+ jskit app update-packages [--dry-run]
312
+ jskit doctor
313
+ jskit lint-packages
314
+ jskit list <packages|generators|bundles>
315
+ jskit show <package|bundle> <id>
1089
316
  ```
1090
-
1091
- Use this when you want the package id to follow a deliberate local naming convention instead of the app name.
1092
-
1093
- #### `--package-id`
1094
-
1095
- `--package-id` overrides the full package id directly:
1096
-
1097
- ```bash
1098
- npx jskit create package contacts --package-id @acme/contacts
1099
- ```
1100
-
1101
- This is the strongest naming override. Use it when you already know the exact package id you want.
1102
-
1103
- In practice, this matters when:
1104
-
1105
- - you want the package id to stay stable even if the app name changes
1106
- - you want a different scope than the default inference
1107
- - you are standardizing naming across several related local packages
1108
-
1109
- The package directory is derived from the package name part of the package id, so `@acme/contacts` still creates `packages/contacts/`.
1110
-
1111
- #### `--description`
1112
-
1113
- `--description` fills the generated descriptor description:
1114
-
1115
- ```bash
1116
- npx jskit create package contacts \
1117
- --description "App-local contact management runtime package."
1118
- ```
1119
-
1120
- That is useful because the description is part of the package metadata JSKIT can show later when you inspect local packages. It is a small option, but it makes local packages easier to identify once an app has several of them.
1121
-
1122
- So a practical mental model is:
1123
-
1124
- - `--scope` chooses the default namespace for the generated package id
1125
- - `--package-id` sets the exact package id directly
1126
- - `--description` makes the generated descriptor self-describing
1127
-
1128
- ## Summary
1129
-
1130
- The JSKIT CLI is easiest to understand if you separate four jobs:
1131
-
1132
- - `list`, `show`, and `help` are for discovery and inspection
1133
- - `add`, `update`, and `remove` manage installed JSKIT runtime packages
1134
- - `position`, `doctor`, and `migrations` maintain or repair JSKIT-managed state
1135
- - `create package` scaffolds a new app-local runtime package
1136
-
1137
- And then keep one more distinction in your head:
1138
-
1139
- - JSKIT manages app-owned package mutations and managed files
1140
- - npm installs dependencies
1141
- - Knex runs database migrations
1142
-
1143
- That is the mental model the rest of the guide assumes.
1144
-
1145
- The next chapter goes back to the normal hands-on flow and uses that model while inspecting the shell that default apps already include.