@jskit-ai/agent-docs 0.1.2 → 0.1.4
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/DISTR_AGENT.md +20 -3
- package/guide/agent/app-extras/assistant.md +1 -1
- package/guide/agent/app-extras/realtime.md +1 -1
- package/guide/agent/app-setup/a-more-interesting-shell.md +1 -1
- package/guide/agent/app-setup/authentication.md +9 -1
- package/guide/agent/app-setup/console.md +1 -1
- package/guide/agent/app-setup/database-layer.md +1 -1
- package/guide/agent/app-setup/initial-scaffolding.md +22 -5
- package/guide/agent/app-setup/multi-homing.md +3 -1
- package/guide/agent/app-setup/users.md +1 -1
- package/guide/agent/app-setup/working-with-the-jskit-cli.md +54 -2
- package/guide/agent/generators/advanced-cruds.md +163 -1
- package/guide/agent/generators/crud-generators.md +30 -1
- package/guide/agent/generators/intro.md +1 -1
- package/guide/agent/generators/ui-generators.md +1 -1
- package/guide/agent/index.md +1 -1
- package/package.json +2 -1
- package/reference/autogen/packages/agent-docs.md +18 -0
- package/reference/autogen/tooling/jskit-cli.md +61 -0
- package/skills/jskit-review/SKILL.md +94 -0
- package/skills/jskit-review/agents/openai.yaml +4 -0
- package/templates/APP_BLUEPRINT.md +23 -0
- package/templates/WORKBOARD.md +46 -0
- package/templates/app/AGENTS.md +28 -3
- package/workflow/app-state.md +2 -1
- package/workflow/bootstrap.md +38 -3
- package/workflow/feature-delivery.md +49 -7
- package/workflow/review.md +33 -8
- package/workflow/scoping.md +24 -3
- package/workflow/workboard.md +29 -0
- package/guide/human/app-extras/assistant.md +0 -695
- package/guide/human/app-extras/realtime.md +0 -270
- package/guide/human/app-setup/a-more-interesting-shell.md +0 -734
- package/guide/human/app-setup/authentication.md +0 -963
- package/guide/human/app-setup/console.md +0 -352
- package/guide/human/app-setup/database-layer.md +0 -822
- package/guide/human/app-setup/initial-scaffolding.md +0 -738
- package/guide/human/app-setup/multi-homing.md +0 -795
- package/guide/human/app-setup/users.md +0 -404
- package/guide/human/app-setup/working-with-the-jskit-cli.md +0 -997
- package/guide/human/generators/advanced-cruds.md +0 -923
- package/guide/human/generators/crud-generators.md +0 -556
- package/guide/human/generators/intro.md +0 -109
- package/guide/human/generators/ui-generators.md +0 -665
- package/guide/human/index.md +0 -39
package/DISTR_AGENT.md
CHANGED
|
@@ -5,21 +5,38 @@ Read these in order:
|
|
|
5
5
|
1. `workflow/app-state.md`
|
|
6
6
|
2. `workflow/bootstrap.md` if the workspace is empty or no JSKIT app exists yet
|
|
7
7
|
3. `workflow/scoping.md`
|
|
8
|
-
4. `workflow/
|
|
9
|
-
5. `workflow/
|
|
8
|
+
4. `workflow/workboard.md`
|
|
9
|
+
5. `workflow/feature-delivery.md`
|
|
10
|
+
6. `workflow/review.md`
|
|
10
11
|
|
|
11
12
|
Use these references on demand:
|
|
12
13
|
|
|
13
14
|
- `reference/autogen/KERNEL_MAP.md`
|
|
14
15
|
- `reference/autogen/README.md`
|
|
15
16
|
- `guide/agent/index.md`
|
|
16
|
-
- `guide/
|
|
17
|
+
- `site/guide/index.md` when compressed guidance is ambiguous or missing nuance
|
|
17
18
|
- `templates/APP_BLUEPRINT.md`
|
|
19
|
+
- `templates/WORKBOARD.md`
|
|
20
|
+
- `skills/jskit-review/SKILL.md` for review passes when your Codex environment supports packaged skills
|
|
18
21
|
|
|
19
22
|
Core rules:
|
|
20
23
|
|
|
21
24
|
- Inspect the workspace before assuming a JSKIT app exists.
|
|
25
|
+
- Before non-trivial edits, print a short visible checkpoint using this format:
|
|
26
|
+
- `Problem: ...`
|
|
27
|
+
- `Fix: ...`
|
|
28
|
+
- `Why this sticks: ...`
|
|
29
|
+
- `Not doing: ...`
|
|
30
|
+
- Keep that checkpoint compact. Do not expand it into a long preamble unless the developer asks for detail.
|
|
22
31
|
- Reuse existing JSKIT helpers and runtime seams before adding new local helpers.
|
|
32
|
+
- A freshly scaffolded JSKIT app can still be in Stage 1. If platform decisions are not settled yet, continue with the initialize workflow before adding runtime packages.
|
|
33
|
+
- Do not treat a missing `config.tenancyMode` line or an untouched minimal scaffold as a final tenancy decision.
|
|
34
|
+
- Do not install tenancy-sensitive packages until Stage 1 decisions are complete and the chosen tenancy is written into `config/public.js`.
|
|
35
|
+
- Treat standard JSKIT package-owned workflows as the default baseline once the relevant package stack is chosen. Do not ask the developer to redesign those flows unless they want overrides, restrictions, or custom additions.
|
|
36
|
+
- Example: if the app is workspace-capable and uses `workspaces-core` plus `workspaces-web`, assume the standard workspace invite flow is part of the baseline package behavior.
|
|
37
|
+
- For baseline package setup, ask plainly for the exact local development values needed for the next install step, but only for the modules or packages that are actually selected.
|
|
38
|
+
- Use the real env var names or option names instead of vague requests for "credentials". Values such as `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `AUTH_SUPABASE_URL`, `AUTH_SUPABASE_PUBLISHABLE_KEY`, and `APP_PUBLIC_URL` are routine setup inputs when the relevant package stack needs them.
|
|
23
39
|
- Do not implement app features before the blueprint has the database, surfaces, ownership model, and route/screen plan written down.
|
|
40
|
+
- For substantial or multi-chunk work, create or update `.jskit/WORKBOARD.md` as the per-request execution tracker.
|
|
24
41
|
- Use the compressed guide first for speed; fall back to the human guide when a workflow trap, migration caveat, or architectural boundary needs exact wording.
|
|
25
42
|
- Treat generated reference maps and guide copies as vendor reference. Do not edit them manually.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/a-more-interesting-shell.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/a-more-interesting-shell.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# A more interesting shell
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/authentication.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/authentication.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# Authentication
|
|
4
4
|
|
|
@@ -44,6 +44,14 @@ JSKIT uses the project URL as `AUTH_SUPABASE_URL`, the publishable key as `AUTH_
|
|
|
44
44
|
|
|
45
45
|
Use the **publishable** key here, not the secret key and not a service-role key. If you later run the app on a different host or port, update both Supabase's URL settings and `APP_PUBLIC_URL` to match the real browser URL exactly.
|
|
46
46
|
|
|
47
|
+
If you are guiding someone interactively, ask plainly for these exact values:
|
|
48
|
+
|
|
49
|
+
- `AUTH_SUPABASE_URL`
|
|
50
|
+
- `AUTH_SUPABASE_PUBLISHABLE_KEY`
|
|
51
|
+
- whether `APP_PUBLIC_URL` should stay `http://localhost:5173`
|
|
52
|
+
|
|
53
|
+
Do not hide behind vague language like "send the auth credentials later." In this local guide flow, those are routine setup values for the Supabase auth install step.
|
|
54
|
+
|
|
47
55
|
## Installing the auth layer
|
|
48
56
|
|
|
49
57
|
From inside `exampleapp`, run:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/database-layer.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/database-layer.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# Database layer
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/initial-scaffolding.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/initial-scaffolding.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# Initial scaffolding
|
|
4
4
|
|
|
@@ -14,6 +14,16 @@ npm install
|
|
|
14
14
|
|
|
15
15
|
The first command creates a new folder called `exampleapp` and fills it with JSKIT's base shell template. The `exampleapp` name is used in a few template replacements, such as the package name and the browser title. The `--tenancy-mode none` flag tells JSKIT to start with the smallest routing model. In this mode, the app is not workspace-aware (more of this later in the guide, when multihoming is introduced). That keeps the first scaffold easier to read because there is no workspace slug handling yet.
|
|
16
16
|
|
|
17
|
+
If you are working with an AI agent and want the agent to explain the platform options after the scaffold exists, there is also a safe guided path:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npx @jskit-ai/create-app exampleapp
|
|
21
|
+
cd exampleapp
|
|
22
|
+
npm install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
That produces the same minimal scaffold shape, but without writing an explicit `config.tenancyMode` line yet. The important rule is that this does **not** mean tenancy is already decided. Before installing tenancy-sensitive packages such as `workspaces-core` or `workspaces-web`, the agent still needs to finish the Stage 1 platform conversation and then write the chosen tenancy into `config/public.js`. If workspace packages are installed while the app is still effectively on `none`, you fall into the recovery path described later in the multi-homing chapter.
|
|
26
|
+
|
|
17
27
|
After creating the scaffolding (which comes with a package.json file), you will need to run `npm install` to install dependencies.
|
|
18
28
|
|
|
19
29
|
**Try Bash Completion!**
|
|
@@ -103,6 +113,7 @@ The most important parts look like this:
|
|
|
103
113
|
"server": "node ./bin/server.js",
|
|
104
114
|
"server:all": "node ./bin/server.js",
|
|
105
115
|
"server:home": "SERVER_SURFACE=home node ./bin/server.js",
|
|
116
|
+
"devlinks": "jskit app link-local-packages",
|
|
106
117
|
"dev": "vite",
|
|
107
118
|
"dev:all": "vite",
|
|
108
119
|
"dev:home": "VITE_SURFACE=home vite",
|
|
@@ -111,7 +122,9 @@ The most important parts look like this:
|
|
|
111
122
|
"build:home": "VITE_SURFACE=home vite build",
|
|
112
123
|
"test": "node --test",
|
|
113
124
|
"test:client": "vitest run tests/client",
|
|
114
|
-
"verify": "
|
|
125
|
+
"verify": "jskit app verify && npm run --if-present verify:app",
|
|
126
|
+
"release": "jskit app release",
|
|
127
|
+
"jskit:update": "jskit app update-packages"
|
|
115
128
|
},
|
|
116
129
|
"dependencies": {
|
|
117
130
|
"@local/main": "file:packages/main",
|
|
@@ -130,9 +143,13 @@ The most important parts look like this:
|
|
|
130
143
|
}
|
|
131
144
|
```
|
|
132
145
|
|
|
133
|
-
There are two details worth noticing immediately. The dependency on `@local/main` points at `file:packages/main`, which means your app already contains its own local JSKIT package. The
|
|
146
|
+
There are two details worth noticing immediately. The dependency on `@local/main` points at `file:packages/main`, which means your app already contains its own local JSKIT package. The maintenance scripts are also useful to notice early, because they show an important ownership boundary in JSKIT.
|
|
147
|
+
|
|
148
|
+
`verify`, `jskit:update`, `devlinks`, and `release` are intentionally thin wrappers. They stay in `package.json` because they are convenient app-local shortcuts, but the real implementation now lives in `jskit app ...`, not in copied scaffold scripts.
|
|
149
|
+
|
|
150
|
+
That matters because JSKIT maintenance policy changes over time. If the scaffold copied a large shell script into every app, existing apps would freeze the old behavior forever. By delegating to `jskit app verify`, `jskit app update-packages`, `jskit app link-local-packages`, and `jskit app release`, the app keeps the nice `npm run` shortcuts while the maintained behavior stays in the installed CLI package.
|
|
134
151
|
|
|
135
|
-
|
|
152
|
+
`jskit app verify` is worth noticing specifically. Linting, tests, and builds check your source code and runtime behavior. The JSKIT part of that flow runs `doctor`, which checks JSKIT-managed app state: installed package visibility, lock-file-backed managed files, and other JSKIT-specific health rules. It is there because a JSKIT app is not only code. It is also a descriptor-driven managed project.
|
|
136
153
|
|
|
137
154
|
The surface-specific script names are also worth noticing early, even in this tiny app. `dev:home`, `server:home`, and `build:home` are the first concrete places where surface selection shows up in the scaffold. They work by setting `VITE_SURFACE=home` on the client side and `SERVER_SURFACE=home` on the server side. In this first chapter, where `home` is the only surface, those variants behave almost the same as the default commands. Later, once more surfaces exist, those scripts become the simplest way to run or build just one surface at a time.
|
|
138
155
|
|
|
@@ -699,7 +716,7 @@ That is why you saw `@jskit-ai/kernel` and `@jskit-ai/http-runtime` earlier in `
|
|
|
699
716
|
|
|
700
717
|
### Other files and options
|
|
701
718
|
|
|
702
|
-
The remaining files are easier to understand once you know the core pieces above. `vite.config.mjs` configures the frontend build and the `/api` proxy used during development. `index.html` is the HTML shell Vite uses to mount Vue. `tests/` contains basic smoke tests so the app has a verification path from day one. The `scripts/` directory
|
|
719
|
+
The remaining files are easier to understand once you know the core pieces above. `vite.config.mjs` configures the frontend build and the `/api` proxy used during development. `index.html` is the HTML shell Vite uses to mount Vue. `tests/` contains basic smoke tests so the app has a verification path from day one. The `scripts/` directory is now much smaller than it used to be, because JSKIT maintenance helpers such as `verify`, `jskit:update`, `devlinks`, and `release` are package-owned CLI commands rather than copied app scripts.
|
|
703
720
|
|
|
704
721
|
The `create-app` command also accepts a few other flags that are useful without changing the basic meaning of this chapter's setup. `--title <text>` lets you replace the browser title and other template text with a friendlier app name. `--target <path>` lets you choose a different output directory instead of the default `./exampleapp`. `--tenancy-mode <mode>` can seed `none`, `personal`, or `workspaces`; for this chapter we intentionally use `none` so the first scaffold stays small and non-workspace. `--force` allows writing into a non-empty target directory when you know that is what you want. `--dry-run` prints the planned file writes without touching the filesystem, which is useful when you want to inspect what the generator would do. `-h` or `--help` prints the command help.
|
|
705
722
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/multi-homing.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/multi-homing.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# Multi-homing
|
|
4
4
|
|
|
@@ -33,6 +33,8 @@ This chapter teaches `personal`, not `workspaces`.
|
|
|
33
33
|
|
|
34
34
|
That is deliberate. `personal` gives the guide a much better first-run experience because the first workspace is auto-provisioned for the user. The app still becomes multi-homing-capable, because invitations and memberships can still put one user in several workspaces at once. The `personal` part only changes how the first workspace is provisioned and how its slug policy works.
|
|
35
35
|
|
|
36
|
+
Once `workspaces-core` and `workspaces-web` are installed, the baseline workspace invitation flow is already part of the package stack. Treat that as the default behavior unless the app explicitly needs custom invite rules or custom UI beyond what the packages already provide.
|
|
37
|
+
|
|
36
38
|
## Installing the workspace packages
|
|
37
39
|
|
|
38
40
|
If your app is already on `tenancyMode = "personal"`, run:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/app-setup/working-with-the-jskit-cli.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/app-setup/working-with-the-jskit-cli.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# Working with the JSKIT CLI
|
|
4
4
|
|
|
@@ -45,6 +45,56 @@ That lock file is the source of truth for installed JSKIT-managed package state.
|
|
|
45
45
|
|
|
46
46
|
That is why commands such as `update`, `remove`, `position`, `migrations`, and `doctor` all care about `.jskit/lock.json`.
|
|
47
47
|
|
|
48
|
+
## JSKIT-managed app maintenance scripts
|
|
49
|
+
|
|
50
|
+
The scaffolded app also has a small set of `npm run` shortcuts that are really wrappers around JSKIT-owned maintenance behavior.
|
|
51
|
+
|
|
52
|
+
The important examples are:
|
|
53
|
+
|
|
54
|
+
- `npm run verify`
|
|
55
|
+
- `npm run jskit:update`
|
|
56
|
+
- `npm run devlinks`
|
|
57
|
+
- `npm run release`
|
|
58
|
+
|
|
59
|
+
In the current scaffold, those scripts are intentionally thin:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"scripts": {
|
|
64
|
+
"verify": "jskit app verify && npm run --if-present verify:app",
|
|
65
|
+
"jskit:update": "jskit app update-packages",
|
|
66
|
+
"devlinks": "jskit app link-local-packages",
|
|
67
|
+
"release": "jskit app release"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
That is a deliberate design choice.
|
|
73
|
+
|
|
74
|
+
The app keeps the handy `npm run` names, but the real maintenance policy now lives in the installed CLI package instead of copied shell scripts inside the app. That means if JSKIT later changes how package updates, local linking, 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.
|
|
75
|
+
|
|
76
|
+
This gives you a clean ownership split:
|
|
77
|
+
|
|
78
|
+
- app-owned scripts still describe how *this app* runs, builds, and tests
|
|
79
|
+
- JSKIT-owned wrapper scripts delegate framework maintenance to `jskit app ...`
|
|
80
|
+
|
|
81
|
+
That split is worth keeping in mind through the rest of the guide. When you see `npm run verify`, that is now shorthand for "run the app's JSKIT baseline verification policy, then any app-specific extra verification hook".
|
|
82
|
+
|
|
83
|
+
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:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm run jskit:update -- --registry https://registry.example.com
|
|
87
|
+
npm run release -- --registry https://registry.example.com
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
For older apps that still carry copied maintenance scripts, the migration path is:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx jskit app adopt-managed-scripts
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
That command rewrites known old scaffold values to the thin wrapper form above.
|
|
97
|
+
|
|
48
98
|
## Discover first, change second
|
|
49
99
|
|
|
50
100
|
One of the best habits in JSKIT is to inspect the catalog before mutating the app.
|
|
@@ -59,6 +109,7 @@ npx jskit help
|
|
|
59
109
|
|
|
60
110
|
That shows the available commands such as:
|
|
61
111
|
|
|
112
|
+
- `app`
|
|
62
113
|
- `list`
|
|
63
114
|
- `show`
|
|
64
115
|
- `add`
|
|
@@ -72,6 +123,7 @@ That shows the available commands such as:
|
|
|
72
123
|
Every command in the CLI also has its own help page. For example:
|
|
73
124
|
|
|
74
125
|
```bash
|
|
126
|
+
npx jskit help app
|
|
75
127
|
npx jskit help add
|
|
76
128
|
npx jskit help migrations
|
|
77
129
|
```
|
|
@@ -642,7 +694,7 @@ That is a different job from:
|
|
|
642
694
|
|
|
643
695
|
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.
|
|
644
696
|
|
|
645
|
-
That is exactly why the starter scaffold
|
|
697
|
+
That is exactly why the starter scaffold now routes `npm run verify` through `jskit app verify`.
|
|
646
698
|
|
|
647
699
|
It belongs there because JSKIT apps are not only source trees. They also have:
|
|
648
700
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/advanced-cruds.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/generators/advanced-cruds.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# Advanced CRUDs
|
|
4
4
|
|
|
@@ -451,6 +451,168 @@ They usually:
|
|
|
451
451
|
|
|
452
452
|
These files are mostly containers. That is deliberate.
|
|
453
453
|
|
|
454
|
+
### CRUD link resolution
|
|
455
|
+
|
|
456
|
+
This deserves an explicit warning, because it was implemented incorrectly in a real app.
|
|
457
|
+
|
|
458
|
+
When you customize generated CRUD pages, use the CRUD runtime that owns the current route scope to resolve CRUD-bound links.
|
|
459
|
+
|
|
460
|
+
Use `paths.page()` for **surface-aware** navigation:
|
|
461
|
+
|
|
462
|
+
- `/account`
|
|
463
|
+
- `/assistant`
|
|
464
|
+
- `/lists`
|
|
465
|
+
- other links that only need normal surface params such as `workspaceSlug`
|
|
466
|
+
|
|
467
|
+
Do **not** use `paths.page()` with CRUD record placeholders inside the relative path or URL template, such as:
|
|
468
|
+
|
|
469
|
+
- `:contactId`
|
|
470
|
+
- `:addressId`
|
|
471
|
+
- `:todoListId`
|
|
472
|
+
- `:todoItemId`
|
|
473
|
+
|
|
474
|
+
For CRUD-bound links, use the runtime-provided resolvers instead:
|
|
475
|
+
|
|
476
|
+
- list pages:
|
|
477
|
+
- `records.resolveViewUrl(record)`
|
|
478
|
+
- `records.resolveEditUrl(record)`
|
|
479
|
+
- `records.resolveParams(template, extraParams)`
|
|
480
|
+
- view pages:
|
|
481
|
+
- `view.listUrl`
|
|
482
|
+
- `view.editUrl`
|
|
483
|
+
- `view.resolveParams(template, extraParams)`
|
|
484
|
+
- add/edit pages:
|
|
485
|
+
- `formRuntime.addEdit.resolveParams(template, extraParams)`
|
|
486
|
+
|
|
487
|
+
Why this matters:
|
|
488
|
+
|
|
489
|
+
- `paths.page()` only knows about the current surface route params
|
|
490
|
+
- CRUD runtimes also know about the current CRUD route shape, current record id, parent record ids, and nested child route context
|
|
491
|
+
- once a page is CRUD-bound, those runtime resolvers are the safe way to build record-scoped links
|
|
492
|
+
|
|
493
|
+
Scope rule:
|
|
494
|
+
|
|
495
|
+
- use the runtime anchored to the record that owns the action
|
|
496
|
+
- on a parent record view page with nested child routes, parent actions should still resolve from the parent `view` runtime even while a child route like `/items/new` is active
|
|
497
|
+
- child-item actions should resolve from the child/item runtime only when the current route is actually child-scoped
|
|
498
|
+
|
|
499
|
+
Examples:
|
|
500
|
+
|
|
501
|
+
- good: `view.resolveParams("./items/new")`
|
|
502
|
+
- good: `view.resolveParams("./items/:todoItemId/edit", { todoItemId: item.id })`
|
|
503
|
+
- good: `formRuntime.addEdit.resolveParams("../../..")`
|
|
504
|
+
- bad: `paths.page("/lists/:todoListId/items/new")`
|
|
505
|
+
- bad: `paths.page("/lists/:todoListId/edit")`
|
|
506
|
+
|
|
507
|
+
The safe mental model is:
|
|
508
|
+
|
|
509
|
+
- use `paths.page()` to get to the right surface
|
|
510
|
+
- use CRUD runtime resolvers to move around inside the CRUD
|
|
511
|
+
|
|
512
|
+
### Live actions and `useCommand()`
|
|
513
|
+
|
|
514
|
+
There is one more client-side pattern worth naming explicitly:
|
|
515
|
+
|
|
516
|
+
Use `useCommand()` for live actions such as:
|
|
517
|
+
|
|
518
|
+
- checkboxes that toggle a record field
|
|
519
|
+
- archive / publish / reopen buttons
|
|
520
|
+
- delete buttons
|
|
521
|
+
- small one-click PATCH / POST / DELETE actions that are not full forms
|
|
522
|
+
|
|
523
|
+
This is the pattern the `todo` app uses for "mark item done".
|
|
524
|
+
|
|
525
|
+
The page renders a checkbox like this:
|
|
526
|
+
|
|
527
|
+
```vue
|
|
528
|
+
<v-checkbox-btn
|
|
529
|
+
:model-value="item.done"
|
|
530
|
+
:disabled="!canUpdateItem || isItemBusy(item.id)"
|
|
531
|
+
@update:model-value="toggleItem(item, $event)"
|
|
532
|
+
/>
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
Then the page wires a command:
|
|
536
|
+
|
|
537
|
+
```js
|
|
538
|
+
const itemPatchModel = reactive({
|
|
539
|
+
id: "",
|
|
540
|
+
patch: {}
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
const updateItemCommand = useCommand({
|
|
544
|
+
model: itemPatchModel,
|
|
545
|
+
apiSuffix: ({ model }) => `/todo-items/${model?.id || ""}`,
|
|
546
|
+
writeMethod: "PATCH",
|
|
547
|
+
runPermissions: ["crud.todo_items.update"],
|
|
548
|
+
suppressSuccessMessage: true,
|
|
549
|
+
fallbackRunError: "Unable to update item.",
|
|
550
|
+
buildRawPayload(model) {
|
|
551
|
+
return model.patch;
|
|
552
|
+
},
|
|
553
|
+
async onRunSuccess(_payload, context = {}) {
|
|
554
|
+
if (context.queryClient) {
|
|
555
|
+
await context.queryClient.invalidateQueries({
|
|
556
|
+
queryKey: ["ui-generator", "todo_items"]
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
async function toggleItem(item = {}, nextValue = false) {
|
|
563
|
+
itemPatchModel.id = String(item.id || "");
|
|
564
|
+
itemPatchModel.patch = {
|
|
565
|
+
done: Boolean(nextValue)
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
await updateItemCommand.run();
|
|
569
|
+
}
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
That gives you a clean action pipeline:
|
|
573
|
+
|
|
574
|
+
1. the UI captures the click
|
|
575
|
+
2. the page writes a tiny action model
|
|
576
|
+
3. `useCommand()` resolves the correct scoped API path for the current route/surface
|
|
577
|
+
4. it sends the request through the standard HTTP runtime
|
|
578
|
+
5. on success, it invalidates the relevant query keys so the list/view refreshes
|
|
579
|
+
|
|
580
|
+
So yes: for this class of interaction, `useCommand()` is the right helper.
|
|
581
|
+
|
|
582
|
+
Use this rule of thumb:
|
|
583
|
+
|
|
584
|
+
- `useCommand()`
|
|
585
|
+
- for live actions
|
|
586
|
+
- button clicks
|
|
587
|
+
- toggles
|
|
588
|
+
- small PATCH/POST/DELETE interactions
|
|
589
|
+
- `useAddEdit()` / `useCrudAddEdit()`
|
|
590
|
+
- for real forms
|
|
591
|
+
- create/edit screens
|
|
592
|
+
- save/cancel flows
|
|
593
|
+
- `useCrudList()` / `useCrudView()`
|
|
594
|
+
- for routed list/view loading and CRUD URL resolution
|
|
595
|
+
|
|
596
|
+
Best practices for live CRUD actions:
|
|
597
|
+
|
|
598
|
+
- keep the payload narrow
|
|
599
|
+
- send the field change you mean, not a whole copied record
|
|
600
|
+
- disable the control while the command for that record is running
|
|
601
|
+
- `todo` does this with `isItemBusy(item.id)`
|
|
602
|
+
- invalidate the relevant list/view query keys on success
|
|
603
|
+
- do not hand-maintain parallel local record copies unless you really need optimistic UI
|
|
604
|
+
- suppress success toasts for high-frequency actions when they would become noisy
|
|
605
|
+
- a checkbox toggle usually does not need "Saved." every time
|
|
606
|
+
- keep business rules on the server
|
|
607
|
+
- in `todo`, the client sends `{ done: true|false }`
|
|
608
|
+
- the server service decides how `completedAt` should be set or cleared
|
|
609
|
+
|
|
610
|
+
The safe mental model is:
|
|
611
|
+
|
|
612
|
+
- use form runtimes for forms
|
|
613
|
+
- use command runtimes for actions
|
|
614
|
+
- keep the server as the source of truth for derived state
|
|
615
|
+
|
|
454
616
|
### `_components/CrudAddEditForm.vue`
|
|
455
617
|
|
|
456
618
|
This is the shared rendering shell for the add/edit form.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/crud-generators.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/generators/crud-generators.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# CRUD Generators
|
|
4
4
|
|
|
@@ -238,6 +238,7 @@ The exact fields will vary by app. What matters for the generator is:
|
|
|
238
238
|
- the table already exists
|
|
239
239
|
- the ownership columns match the ownership filter you are going to choose
|
|
240
240
|
- the column names are stable enough to become part of your app's resource contract
|
|
241
|
+
- if you are using `crud-server-generator`, do **not** hand-write a separate CRUD migration for this table; the server generator installs the CRUD migration scaffold itself
|
|
241
242
|
|
|
242
243
|
In this table, `workspace_id` is the important ownership clue. That is why the next step uses:
|
|
243
244
|
|
|
@@ -261,6 +262,13 @@ npx jskit generate crud-server-generator scaffold \
|
|
|
261
262
|
|
|
262
263
|
This creates an app-local package under `packages/contacts/`.
|
|
263
264
|
|
|
265
|
+
Before generating anything, decide these with the developer:
|
|
266
|
+
|
|
267
|
+
- which operations are allowed for this CRUD
|
|
268
|
+
- which fields belong in the list view if a list exists
|
|
269
|
+
- what the view form should look like
|
|
270
|
+
- what the edit/new form should look like
|
|
271
|
+
|
|
264
272
|
The most important file from the UI point of view is:
|
|
265
273
|
|
|
266
274
|
```text
|
|
@@ -505,6 +513,27 @@ The host page then renders the comment list directly, usually with lower-level C
|
|
|
505
513
|
- `useCrudAddEdit()`
|
|
506
514
|
- `useCrudView()` when needed
|
|
507
515
|
|
|
516
|
+
There is one more runtime worth knowing about early:
|
|
517
|
+
|
|
518
|
+
- `useCommand()`
|
|
519
|
+
|
|
520
|
+
Use it for live actions that are **not** full forms, such as:
|
|
521
|
+
|
|
522
|
+
- checkbox toggles
|
|
523
|
+
- archive / reopen buttons
|
|
524
|
+
- quick PATCH / POST / DELETE actions on one record
|
|
525
|
+
|
|
526
|
+
So the practical split is:
|
|
527
|
+
|
|
528
|
+
- `useCrudList()` / `useCrudView()`
|
|
529
|
+
- routed list/view loading
|
|
530
|
+
- `useCrudAddEdit()`
|
|
531
|
+
- real create/edit forms
|
|
532
|
+
- `useCommand()`
|
|
533
|
+
- live actions inside the page
|
|
534
|
+
|
|
535
|
+
The `todo` app uses that last pattern for "mark item done" checkboxes. The deeper best-practices explanation is in [Advanced CRUDs](/guide/generators/advanced-cruds).
|
|
536
|
+
|
|
508
537
|
That is the same general pattern already used in the real app for embedded child records like pet notes: the record list lives inside the main view page, while routed child pages handle the operations that still deserve their own URLs.
|
|
509
538
|
|
|
510
539
|
This pattern is useful when the child records are supporting detail rather than a destination in their own right.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated by `npm run agent-docs:build` from `docs/guide/generators/ui-generators.md`. Do not edit manually. -->
|
|
1
|
+
<!-- Generated by `npm run agent-docs:build` from `packages/agent-docs/site/guide/generators/ui-generators.md`. Do not edit manually. -->
|
|
2
2
|
|
|
3
3
|
# UI Generators
|
|
4
4
|
|
package/guide/agent/index.md
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/agent-docs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Distributed JSKIT agent workflows, guides, and generated reference maps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
7
7
|
"DISTR_AGENT.md",
|
|
8
8
|
"guide",
|
|
9
9
|
"reference",
|
|
10
|
+
"skills",
|
|
10
11
|
"templates",
|
|
11
12
|
"workflow"
|
|
12
13
|
],
|
|
@@ -11,3 +11,21 @@ Use this on demand; do not load the full index at startup.
|
|
|
11
11
|
- Excludes: `test/`, `tests/`, `__tests__/`, `*.test.*`, `*.spec.*`, `*.vitest.*`, `node_modules/`, `dist/`, `coverage/`, `docs/`, `LEGACY/`
|
|
12
12
|
|
|
13
13
|
## Sections
|
|
14
|
+
|
|
15
|
+
### site
|
|
16
|
+
|
|
17
|
+
### `site/.vitepress/config.mjs`
|
|
18
|
+
Exports
|
|
19
|
+
- None
|
|
20
|
+
|
|
21
|
+
### `site/.vitepress/theme/components/DocsInDepth.vue`
|
|
22
|
+
Exports
|
|
23
|
+
- None
|
|
24
|
+
|
|
25
|
+
### `site/.vitepress/theme/components/DocsTerminalTip.vue`
|
|
26
|
+
Exports
|
|
27
|
+
- None
|
|
28
|
+
|
|
29
|
+
### `site/.vitepress/theme/index.js`
|
|
30
|
+
Exports
|
|
31
|
+
- `default`
|
|
@@ -41,6 +41,8 @@ Exports
|
|
|
41
41
|
- `upsertEnvValue(content, key, value)`
|
|
42
42
|
- `removeEnvValue(content, key, expectedValue, previous)`
|
|
43
43
|
- `writeJsonFile`
|
|
44
|
+
Local functions
|
|
45
|
+
- `directoryLooksLikeJskitAppRoot(directoryPath)`
|
|
44
46
|
|
|
45
47
|
### `src/server/cliRuntime/capabilitySupport.js`
|
|
46
48
|
Exports
|
|
@@ -341,6 +343,65 @@ Exports
|
|
|
341
343
|
- `applyViteMutations(packageEntry, appRoot, viteMutations, options, managedVite, touchedFiles)`
|
|
342
344
|
- `removeManagedViteProxyEntries({ appRoot, packageId, managedViteChanges = {}, touchedFiles = null } = {})`
|
|
343
345
|
|
|
346
|
+
### `src/server/commandHandlers/app.js`
|
|
347
|
+
Exports
|
|
348
|
+
- `createAppCommands(ctx = {})`
|
|
349
|
+
Local functions
|
|
350
|
+
- `renderAppHelp(stream, definition = null)`
|
|
351
|
+
|
|
352
|
+
### `src/server/commandHandlers/appCommandCatalog.js`
|
|
353
|
+
Exports
|
|
354
|
+
- `APP_SCRIPT_WRAPPERS`
|
|
355
|
+
- `LEGACY_APP_SCRIPT_VALUES`
|
|
356
|
+
- `LEGACY_APP_SCRIPT_FILES`
|
|
357
|
+
- `APP_COMMAND_DEFINITIONS`
|
|
358
|
+
- `listAppCommandDefinitions()`
|
|
359
|
+
- `resolveAppCommandDefinition(rawName = "")`
|
|
360
|
+
- `buildAppCommandOptionMeta(subcommandName = "")`
|
|
361
|
+
|
|
362
|
+
### `src/server/commandHandlers/appCommands/adoptManagedScripts.js`
|
|
363
|
+
Exports
|
|
364
|
+
- `runAppAdoptManagedScriptsCommand(ctx = {}, { appRoot = "", options = {}, stdout })`
|
|
365
|
+
Local functions
|
|
366
|
+
- `shouldRewriteScript(currentValue = "", scriptName = "", force = false)`
|
|
367
|
+
|
|
368
|
+
### `src/server/commandHandlers/appCommands/linkLocalPackages.js`
|
|
369
|
+
Exports
|
|
370
|
+
- `runAppLinkLocalPackagesCommand(ctx = {}, { appRoot = "", options = {}, stdout })`
|
|
371
|
+
|
|
372
|
+
### `src/server/commandHandlers/appCommands/release.js`
|
|
373
|
+
Exports
|
|
374
|
+
- `runAppReleaseCommand(ctx = {}, { appRoot = "", options = {}, stdout, stderr })`
|
|
375
|
+
|
|
376
|
+
### `src/server/commandHandlers/appCommands/shared.js`
|
|
377
|
+
Exports
|
|
378
|
+
- `fileExists(filePath = "")`
|
|
379
|
+
- `normalizeText(value = "")`
|
|
380
|
+
- `isTruthyFlag(rawValue = "")`
|
|
381
|
+
- `runExternalCommand(command, args = [], { cwd = "", env = {}, stdout, stderr, quiet = false, createCliError } = {})`
|
|
382
|
+
- `formatUtcReleaseTimestamp(date = new Date())`
|
|
383
|
+
- `resolveLocalJskitBin(appRoot = "")`
|
|
384
|
+
- `runLocalJskit(appRoot, args = [], { stdout, stderr, createCliError, quiet = false } = {})`
|
|
385
|
+
- `resolveLocalRepoRoot({ appRoot = "", explicitRepoRoot = "" } = {})`
|
|
386
|
+
- `discoverLocalPackageMap(repoRoot = "")`
|
|
387
|
+
- `linkPackageBinEntries({ appRoot, packageDirName, sourceDir, stdout } = {})`
|
|
388
|
+
- `resolveSymlinkType()`
|
|
389
|
+
Local functions
|
|
390
|
+
- `ensureCommandSucceeded(result, label, { createCliError, cwd = "", stdout, stderr, quiet = false } = {})`
|
|
391
|
+
|
|
392
|
+
### `src/server/commandHandlers/appCommands/updatePackages.js`
|
|
393
|
+
Exports
|
|
394
|
+
- `runAppUpdatePackagesCommand(ctx = {}, { appRoot = "", options = {}, stdout, stderr })`
|
|
395
|
+
Local functions
|
|
396
|
+
- `collectJskitPackageNames(packageMap = {})`
|
|
397
|
+
- `resolveMajorRangeFromVersion(packageName = "", rawVersion = "", createCliError)`
|
|
398
|
+
- `resolveRegistryArgs(registryUrl = "")`
|
|
399
|
+
- `resolveInstallSpecs(packageNames = [], resolveMajorRange)`
|
|
400
|
+
|
|
401
|
+
### `src/server/commandHandlers/appCommands/verify.js`
|
|
402
|
+
Exports
|
|
403
|
+
- `runAppVerifyCommand(ctx = {}, { appRoot = "", options = {}, stdout, stderr })`
|
|
404
|
+
|
|
344
405
|
### `src/server/commandHandlers/completion.js`
|
|
345
406
|
Exports
|
|
346
407
|
- `createCompletionCommands(ctx = {})`
|