@jskit-ai/agent-docs 0.1.205 → 0.1.207

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 (36) hide show
  1. package/guide/agent/app-extras/assistant-conversation.md +51 -2
  2. package/guide/agent/app-setup/multi-homing.md +29 -0
  3. package/guide/agent/framework/crud-operations.md +162 -0
  4. package/package.json +1 -1
  5. package/patterns/feature-package/example/booking-engine/package.json +1 -1
  6. package/patterns/minimal-foundation/example/package.json +4 -4
  7. package/patterns/shell-foundation/example/package.json +5 -5
  8. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  9. package/patterns/ui-testing.md +7 -0
  10. package/reference/autogen/PATTERN_INDEX.md +35 -35
  11. package/reference/autogen/packages/assistant-core.md +1 -1
  12. package/reference/autogen/packages/assistant-voice-sherpa.md +1 -1
  13. package/reference/autogen/packages/workspaces-core.md +3 -3
  14. package/reference/autogen/packages/workspaces-web.md +11 -0
  15. package/skills/jskit/SKILL.md +9 -0
  16. package/skills/jskit/references/crud-operations.md +162 -0
  17. package/skills/jskit/references/multi-homing.md +29 -0
  18. package/skills/jskit/references/pattern-index.md +35 -35
  19. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +4 -4
  20. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +5 -5
  21. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  22. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  23. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  24. package/skills/jskit/references/patterns/crud/crud-screen-set/PATTERN.md +30 -0
  25. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookEditPage.vue +1 -0
  26. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookNewPage.vue +1 -0
  27. package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +5 -0
  28. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
  29. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
  30. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
  31. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  32. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
  33. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
  34. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
  35. package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +20 -0
  36. package/skills/jskit/references/patterns/workspaces/workspace-server/example/config/roles.js +2 -0
@@ -1485,8 +1485,37 @@ does not abort that newer input. Owned executor failure stops its still-current
1485
1485
  native turn; Stop and disposal drain and close
1486
1486
  only its private bridge under the original owner. Unconfigured bound and scoped
1487
1487
  conversations retain their original behavior. These source tests do not establish
1488
- an application's composition or installed/native acceptance. Bound Claude
1489
- application-tool dispatch remains unavailable.
1488
+ an application's composition or installed/native acceptance.
1489
+
1490
+ An opted-in supplied Claude conversation uses its original retained owner/store
1491
+ and SDK MCP control pipe. The owner exposes `applicationToolsSupported: true`;
1492
+ that capability does not authorize an application action. Its configured command
1493
+ is attached before native process configuration. The host must expose the same
1494
+ application SDK declaration through `process.configure` using the owner's tool
1495
+ schemas, without selecting standalone execution-release or isolated policy.
1496
+ Original native ACK, canonical admission/publication and the common accepted
1497
+ request callback precede tool effects. Each call matches the exact recorded
1498
+ native tool-use ID, name, arguments and originating accepted message. Optional
1499
+ supplied-owner checks at the same executor boundary refuse retired input before
1500
+ execution and report only a still-current owned executor failure through the
1501
+ original Stop/drain path. Already invoked old work cannot fail a later accepted
1502
+ input. The common ordered tool-work catch attributes a failure only to its
1503
+ still-current Claude request; prior action error receipts and once-only execution remain
1504
+ unchanged. This successor-query exception is specific to Claude. Codex retains
1505
+ its active-turn failure guard across steering: an unconfirmed application effect
1506
+ cannot be reported as a successful turn, even if an answer has arrived.
1507
+ The original retained-turn reader's opt-in current mode requires the exact
1508
+ live process, account, command and native tuple; its default retained/history
1509
+ projection is unchanged. Stop and completion join existing tool work; clearing custody leaves the original supplied
1510
+ process/storage lifecycle intact. Unconfigured supplied conversations keep their
1511
+ original behavior.
1512
+
1513
+ `claudeCodeArguments({ applicationTools: true })` adds the existing SDK MCP config
1514
+ also for normal Claude execution. It does not change native source tools or
1515
+ permission defaults; existing tool-free and isolated branches are unchanged.
1516
+ Applications still supply exact action authorization, native instruction/account
1517
+ configuration and checkpoints. Source/component proofs do not establish a host's
1518
+ installed or real CLI/application acceptance.
1490
1519
 
1491
1520
  Such a server integration may open a handle with `representation: "native"` when
1492
1521
  its existing command contract requires the original result. The option belongs
@@ -1776,6 +1805,13 @@ selecting that segment's engine; recovery never revives a rewound turn. Neither
1776
1805
  inspection nor reopening sends the message again. If native process cleanup fails,
1777
1806
  the handle reports unavailable and rejects new work; `cancel()` retries that exact
1778
1807
  owned cleanup rather than starting another process.
1808
+ Claude streaming startup can fail after the host admits an execution but before
1809
+ it returns a stream. The adapter preserves that execution identity and the host's
1810
+ actual cleanup proof; a rejected startup never supplies a successful stop proof.
1811
+ Unconfirmed cleanup retains the identity through the existing native binding for
1812
+ Stop/recovery. If binding publication also fails, the original startup failure and
1813
+ in-memory custody remain, with the persistence error in `bindingError`; durable
1814
+ restart recovery is not established until that binding can be saved.
1779
1815
  An optional `limits.timeoutMs` deadline aborts work and waits for owned cleanup;
1780
1816
  a failed cleanup is still reported as unavailable rather than as a successful stop.
1781
1817
 
@@ -2838,6 +2874,19 @@ An exact native acknowledgement ends its ACK deadline before the admission
2838
2874
  writer runs; a slow write remains awaited, and a rejected write rejects admission.
2839
2875
  A missing acknowledgement remains uncertain. Native failure-result text stays
2840
2876
  in the turn's error rather than becoming an assistant answer.
2877
+ The retained owner also exposes
2878
+ `readFinalAssistantResult(contextKey, conversationId, turnId)` for a trusted host
2879
+ that returns its canonical turn from a successful complete-message publication.
2880
+ This synchronous lookup clones the current native receipt; it does not acquire
2881
+ a conversation, read history, resume, or resend work. It requires the exact
2882
+ current context, conversation, turn, accepted input, process, execution and account,
2883
+ and successful native settlement after pending commands and background tasks.
2884
+ The receipt becomes readable before the original before-state checkpoint; a
2885
+ failed publication or checkpoint invalidates it. Default event sinks and saved
2886
+ completion metadata cannot supply this proof. New input, steering, account
2887
+ changes, interruption and cleanup invalidate it. Pending or failed native Stop
2888
+ cannot revive an older receipt. This optional getter preserves existing storage,
2889
+ checkpoint and cleanup behavior; the host still owns question or grading policy.
2841
2890
  The turn owner preserves the production receiver's block lifecycle: deltas are
2842
2891
  temporary, block-stop removes them, and completed snapshots use their native
2843
2892
  UUIDs. It does not group distinct history snapshots into a synthetic reply.
@@ -39,6 +39,35 @@ before an operation discloses records or record existence.
39
39
  membership semantics exactly; do not synthesize memberships to compensate for
40
40
  a policy/runtime mismatch.
41
41
 
42
+ ## Role display labels
43
+
44
+ Set optional `label` strings in the existing `roleCatalog.roles` definitions,
45
+ usually exported by `config/roles.js` and composed into application config.
46
+ For example, the package-owned `workspaces/workspace-server` example labels
47
+ `admin` as **Administrator** and `member` as **Team member**. Any application
48
+ role id can have its own label.
49
+
50
+ Labels are trimmed; missing, blank or non-string labels use the previous
51
+ display fallback. Labels do not inherit. They survive catalogue creation,
52
+ cloning and descriptor listing, and the Members, Invitations and Workspace
53
+ Settings API response schemas preserve them. Descriptors have optional
54
+ `label`; pending/resolved invitation and workspace-list records have optional
55
+ `roleLabel` beside `roleSid`.
56
+
57
+ On **Members**, both the invitation **Role** selector and each member's role
58
+ selector display configured labels. Choose a label, enter the invite email
59
+ and select **Send invite**, or choose a member's new role. Requests and stored
60
+ memberships still use role ids. Reloading shows the selected role's label.
61
+ Pending invitation captions, workspace role captions and the default
62
+ invitation email use configured labels too. Custom email renderers receive
63
+ optional `roleLabel` in addition to `roleSid`.
64
+
65
+ Add labels without changing existing permissions, inheritance, assignability
66
+ or `workspace.defaultInviteRole`. This supports application-specific and
67
+ Training roles without renaming them. `owner` is never assignable. An
68
+ application whose default invitation role is `worker` keeps that default even
69
+ if its display label is **Member**. No database migration is needed.
70
+
42
71
  ## Transactional invitation participation
43
72
 
44
73
  Use `workspaces.core` to connect application records during the built-in
@@ -47,6 +47,168 @@ Add resource service methods with `decorateService`; expose commands such as
47
47
  services and hooks orchestrate. Use a transactional outbox for durable
48
48
  external work.
49
49
 
50
+ ## Choose ownership, API access and client access independently
51
+
52
+ These controls answer different questions:
53
+
54
+ | Control | Purpose | Public records | Owner-scoped records |
55
+ | --- | --- | --- | --- |
56
+ | Resource `autofilter` | Which rows belong to the request scope | `"public"`; no ownership column | `"user"`; real non-null `userId` column |
57
+ | Resource `apiAccess` | Who may call the API | `"public"` | `"authenticated"` |
58
+ | Feature `ownershipFilter` | Server route/action ownership scope | `"public"` | `"user"` |
59
+ | Client `access` | Whether to require bootstrap permissions | Default `"auto"` with no permission requirements | Default `"auto"`; declare permissions when required |
60
+
61
+ `access` accepts `auto`, `always`, or `never`, not `public`. With `auto`, a
62
+ screen with no permission requirements does not require a permissions bootstrap.
63
+ `always` does require it. Do not add authentication or workspace machinery to
64
+ compensate for an unnecessary `always` override. Server access and ownership
65
+ remain authoritative.
66
+
67
+ The Books source patterns demonstrate user ownership. For an intentionally
68
+ public create/list resource, use the same patterns with this resource contract:
69
+
70
+ ```js
71
+ const bookResource = defineCrudResource({
72
+ namespace: "books",
73
+ tableName: "books",
74
+ apiAccess: "public",
75
+ autofilter: "public",
76
+ crudOperations: ["list", "view", "create"],
77
+ schema: {
78
+ title: {
79
+ type: "string",
80
+ required: true,
81
+ minLength: 1,
82
+ maxLength: 255,
83
+ operations: {
84
+ output: { required: true },
85
+ create: { required: true }
86
+ }
87
+ }
88
+ }
89
+ });
90
+ ```
91
+
92
+ Import `defineCrudResource` from
93
+ `@jskit-ai/resource-crud-core/shared/crudResource`. Its app-owned migration
94
+ creates `books` with an integer primary key `id` and non-null `title`; omit
95
+ `userId` and its foreign key for this public variant. `list` requires `view`
96
+ in the shared resource contract, even when the UI has no detail page. A create
97
+ response uses the resource output contract. Keep operation names such as
98
+ `list`, `view` and `create`; do not invent output-operation aliases.
99
+
100
+ Bind `defineCrudJsonApiFeature()` with this resource, `ownershipFilter:
101
+ "public"`, `relativePath: "/books"` and the application's configured public
102
+ surface. Keep the existing package/provider and migration registration from
103
+ `crud/json-api-resource-package`.
104
+
105
+ For the list, keep `BookListPage.vue` thin: use `resourceNamespace: "books"`
106
+ in `useCrudListScreen()` on the configured public surface, remove unsupported
107
+ edit/delete actions and optional author/notes filters, and point **New** to
108
+ the create route. For the new page, use the title field only and set:
109
+
110
+ ```js
111
+ addEditOptions: {
112
+ apiSuffix: "/books",
113
+ ownershipFilter: "public",
114
+ queryKeyFactory: (surfaceId = "") => ["crud", "books", surfaceId, "new"],
115
+ readEnabled: false,
116
+ writeMethod: "POST",
117
+ listUrlTemplate: "/books"
118
+ },
119
+ saveSuccess: {
120
+ invalidateQueryKey: ["crud", "books"],
121
+ navigateToView: false,
122
+ listUrlTemplate: "/books"
123
+ }
124
+ ```
125
+
126
+ List/view screen wrappers derive request scope from the configured surface;
127
+ they do not expose an `ownershipFilter` option. Use a surface without workspace
128
+ route parameters for this public example. Form options and lower-level request
129
+ composables accept `ownershipFilter` explicitly.
130
+
131
+ New/Edit form runtimes require `queryKeyFactory` even with reads disabled.
132
+ For editing, include the reactive record id; for workspace-scoped resources,
133
+ include the route scope too. List/view screen wrappers derive standard keys
134
+ from `resourceNamespace`. Leave `access` at its default when no permissions
135
+ are declared. Verify create, list, blank-name rejection and reload persistence
136
+ without signing in for this public variant; owner-scoped variants additionally
137
+ need cross-owner denial tests.
138
+
139
+ ## Save navigation
140
+
141
+ `useCrudAddEditScreen()` accepts `saveSuccess` at the top level. After saving,
142
+ the default behaviour invalidates `saveSuccess.invalidateQueryKey`, navigates
143
+ to a configured record-view URL when one resolves, and otherwise falls back to
144
+ the list URL. For a create-and-list app, use `navigateToView: false` and the
145
+ configured `listUrlTemplate`, as in the public example above. The list URL may
146
+ also come from `addEditOptions.listUrlTemplate`.
147
+
148
+ To keep the saved form open, set both `saveSuccess.navigateToView` and
149
+ `saveSuccess.navigateToList` to `false`. `addEditOptions.onSaveSuccess` replaces
150
+ the default success handling, including query invalidation and navigation;
151
+ reserve it for custom success behaviour. Returning to the list needs only the
152
+ documented `saveSuccess` options, not a custom router callback or inspection of
153
+ the shared form implementation.
154
+
155
+ ## Browser routes and responsive lists
156
+
157
+ `newUrlTemplate`, `viewUrlTemplate`, `editUrlTemplate`, `listUrlTemplate`, and
158
+ `cancelTo` describe browser routes, not surface-relative API suffixes. Include
159
+ the configured surface prefix: if a public library lives at `/library`, its new
160
+ page is `/library/new` and its list is `/library`, not `/new` and `/`. For links
161
+ without record placeholders, `paths.page()` can resolve the configured surface;
162
+ for record placeholders use the current CRUD runtime's `resolveParams()`.
163
+ Request-scope inference does not add missing prefixes to browser links.
164
+
165
+ `CrudListScreen` uses `createLabel` for its toolbar, empty-state and compact
166
+ create actions. Its card and table layouts coexist in the DOM, with CSS choosing
167
+ the visible layout. Browser assertions on record text must select the visible
168
+ match, for example `page.getByText(title, { exact: true }).filter({ visible: true })`.
169
+ When the same create action appears in more than one visible location, choose
170
+ one visible action deliberately; do not relax the expected label to accept an
171
+ unrelated fallback.
172
+
173
+ ## Direct API tests use JSON:API documents
174
+
175
+ JSKIT's CRUD screens and HTTP client apply the resource's JSON:API transport
176
+ automatically. Direct Playwright `request` calls and other raw HTTP clients must
177
+ supply that transport themselves. An ordinary JSON body such as `{ title }`
178
+ with `Content-Type: application/json` does not test field validation on a
179
+ JSON:API route; it is rejected as an unsupported media type (HTTP 415).
180
+
181
+ Use the application's actual API base and scope, not its page URL. For the
182
+ public Books resource above, with API base `/api` and transport type `books`:
183
+
184
+ ```js
185
+ const headers = {
186
+ "Content-Type": "application/vnd.api+json",
187
+ Accept: "application/vnd.api+json"
188
+ };
189
+ const response = await request.post("/api/books", {
190
+ headers,
191
+ data: {
192
+ data: {
193
+ type: "books",
194
+ attributes: { title: "Kindred" }
195
+ }
196
+ }
197
+ });
198
+ expect(response.status()).toBe(201);
199
+ const document = await response.json();
200
+ expect(document.data.attributes.title).toBe("Kindred");
201
+ ```
202
+
203
+ Keep the same headers and `data.type/attributes` envelope when testing invalid
204
+ field values; for this contract, an empty `title` or one over 255 characters
205
+ should return HTTP 400. Raw responses contain fields under `data.attributes`,
206
+ while the shared client simplifies resource responses. A collection response
207
+ has an array in `data`. Match `data.type` to the configured resource transport;
208
+ retain the application's existing identity and CSRF fixture for protected APIs.
209
+ Prefer the shared resource client for application requests rather than copying
210
+ this raw test encoding into page code.
211
+
50
212
  ## Record deletion
51
213
 
52
214
  Deletion requires an explicit shared `DELETE` operation and confirmation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.205",
3
+ "version": "0.1.207",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -5,7 +5,7 @@
5
5
  "private": true,
6
6
  "type": "module",
7
7
  "dependencies": {
8
- "@jskit-ai/kernel": "0.1.233",
8
+ "@jskit-ai/kernel": "0.1.235",
9
9
  "json-rest-schema": "^1.0.17"
10
10
  },
11
11
  "exports": {
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
- "@jskit-ai/kernel": "0.1.233",
37
+ "@jskit-ai/kernel": "0.1.235",
38
38
  "@tanstack/vue-query": "^5.101.0",
39
39
  "fastify": "^5.8.5",
40
40
  "json-rest-schema": "^1.0.17",
@@ -42,13 +42,13 @@
42
42
  "vue": "^3.5.43",
43
43
  "vue-router": "^5.3.1",
44
44
  "vuetify": "^4.1.2",
45
- "@jskit-ai/http-runtime": "0.1.231",
45
+ "@jskit-ai/http-runtime": "0.1.233",
46
46
  "@fastify/fast-json-stringify-compiler": "^5.1.0",
47
47
  "@vue/devtools-api": "^8.2.1"
48
48
  },
49
49
  "devDependencies": {
50
- "@jskit-ai/config-eslint": "0.1.230",
51
- "@jskit-ai/jskit-catalog": "0.1.258",
50
+ "@jskit-ai/config-eslint": "0.1.232",
51
+ "@jskit-ai/jskit-catalog": "0.1.260",
52
52
  "@playwright/test": "1.61.1",
53
53
  "@vitejs/plugin-vue": "^6.0.7",
54
54
  "eslint": "^10.8.0",
@@ -34,7 +34,7 @@
34
34
  "dependencies": {
35
35
  "@local/main": "0.1.0",
36
36
  "@fastify/static": "^10.1.3",
37
- "@jskit-ai/kernel": "0.1.233",
37
+ "@jskit-ai/kernel": "0.1.235",
38
38
  "@tanstack/vue-query": "^5.101.0",
39
39
  "fastify": "^5.8.5",
40
40
  "json-rest-schema": "^1.0.17",
@@ -42,15 +42,15 @@
42
42
  "vue": "^3.5.43",
43
43
  "vue-router": "^5.3.1",
44
44
  "vuetify": "^4.1.2",
45
- "@jskit-ai/http-runtime": "0.1.231",
45
+ "@jskit-ai/http-runtime": "0.1.233",
46
46
  "@mdi/js": "^7.4.47",
47
- "@jskit-ai/shell-web": "0.1.237",
47
+ "@jskit-ai/shell-web": "0.1.239",
48
48
  "@fastify/fast-json-stringify-compiler": "^5.1.0",
49
49
  "@vue/devtools-api": "^8.2.1"
50
50
  },
51
51
  "devDependencies": {
52
- "@jskit-ai/config-eslint": "0.1.230",
53
- "@jskit-ai/jskit-catalog": "0.1.258",
52
+ "@jskit-ai/config-eslint": "0.1.232",
53
+ "@jskit-ai/jskit-catalog": "0.1.260",
54
54
  "@playwright/test": "1.61.1",
55
55
  "@vitejs/plugin-vue": "^6.0.7",
56
56
  "eslint": "^10.8.0",
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "description": "App-local runtime composition and lightweight glue.",
11
11
  "dependencies": {
12
- "@jskit-ai/kernel": "0.1.233"
12
+ "@jskit-ai/kernel": "0.1.235"
13
13
  },
14
14
  "jskit": {
15
15
  "kind": "runtime",
@@ -21,6 +21,13 @@ Rules:
21
21
  - A managed runner supplies `PLAYWRIGHT_BASE_URL`. When it is set, JSKIT does not start another app server.
22
22
  - Vibe64 supplies an authenticated context through `VIBE64_PLAYWRIGHT_STORAGE_STATE`. Treat that file as a temporary secret: do not commit it, print it, or retain it after the run.
23
23
  - Do not install a browser when the environment provides a managed browser runner.
24
+ - Shared CRUD lists retain both card and table markup and hide the inactive
25
+ layout with CSS. Select visible record text with
26
+ `page.getByText(title, { exact: true }).filter({ visible: true })`; asserting on
27
+ an unfiltered text locator can fail with a strict-mode duplicate after saving.
28
+ Keep the expected text and persistence assertion. If repeated create controls
29
+ perform the same action, select one visible control deliberately rather than
30
+ accepting a different label to make a test pass.
24
31
 
25
32
  ## Keep startup incremental
26
33