@jskit-ai/agent-docs 0.1.207 → 0.1.208
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/guide/agent/app-extras/assistant-conversation.md +534 -6
- package/guide/agent/app-extras/assistant-voice.md +16 -1
- package/guide/agent/app-extras/assistant.md +8 -0
- package/guide/agent/framework/application-operations.md +29 -0
- package/guide/agent/framework/crud-operations.md +100 -0
- package/package.json +1 -1
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/minimal-foundation/example/package.json +4 -4
- package/patterns/server-search.md +16 -0
- package/patterns/shell-foundation/example/package.json +5 -5
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/ui-testing.md +13 -0
- package/reference/autogen/PATTERN_INDEX.md +35 -35
- package/reference/autogen/packages/assistant-core.md +33 -10
- package/reference/autogen/packages/assistant-runtime.md +3 -2
- package/reference/autogen/packages/assistant-voice-sherpa.md +1 -0
- package/reference/autogen/packages/assistant-voice.md +1 -0
- package/reference/autogen/packages/shell-web.md +15 -0
- package/skills/jskit/SKILL.md +20 -7
- package/skills/jskit/references/app-operations.md +29 -0
- package/skills/jskit/references/crud-operations.md +100 -0
- package/skills/jskit/references/pattern-index.md +35 -35
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +4 -4
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +5 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +33 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
|
@@ -175,7 +175,13 @@ committing or sending messages. An optional synchronous `transfer(text)` must
|
|
|
175
175
|
recheck the host's empty typed draft, set it through its original setter, and
|
|
176
176
|
return true; false leaves speech untouched. Taking an active partial uses the
|
|
177
177
|
original capture cancellation and guarded hands-free restart, preserving the
|
|
178
|
-
session and playback. Taking a pending review clears only that review.
|
|
178
|
+
session and playback. Taking a pending review clears only that review. Once an
|
|
179
|
+
interrupted review is resolved, stale partial words from its idle capture do not
|
|
180
|
+
block a fresh Talk gesture or become a new request. If capture interrupts an
|
|
181
|
+
endpoint commitment, only that recording's unfinished commitment is retired;
|
|
182
|
+
its retained words stay available for explicit Send, Edit or Discard. Late finals
|
|
183
|
+
and resets cannot admit or replace the retained review. Active capture, including
|
|
184
|
+
transcription, and pending startup, review and delivery retain their guards. Hosts
|
|
179
185
|
also gate these controls while their canonical delivery has uncertain admission.
|
|
180
186
|
|
|
181
187
|
For custom compositions, its optional `toolsTarget` is a DOM element belonging
|
|
@@ -381,6 +387,15 @@ models; one synthesis worker retains only the selected model. Changing models
|
|
|
381
387
|
releases the previous worker and its native caches before loading the next, while
|
|
382
388
|
recognition and the connection stay running. The first reply after a change
|
|
383
389
|
includes loading time. Extra choices require disk space, not resident model RAM.
|
|
390
|
+
The native engine advertises a bounded 120-second first-audio allowance at each
|
|
391
|
+
new phrase's acquired queue slot: its unchanged load and generation requests each
|
|
392
|
+
have a 60-second deadline. The browser returns to its original 20-second progress
|
|
393
|
+
watchdog on actual PCM and after chunk completion. This allowance does not change
|
|
394
|
+
microphone controls, playback cancellation or the separate connection heartbeat.
|
|
395
|
+
Other engines omit `synthesisTimeoutMs` and retain the original 20-second policy;
|
|
396
|
+
optional segment metadata must be an integer above 20,000 and at most 120,000 ms.
|
|
397
|
+
Only the current turn's advancing segment can arm it; duplicate or stale metadata
|
|
398
|
+
and pongs cannot extend generation indefinitely.
|
|
384
399
|
`kokoro` supplies Heart, Bella,
|
|
385
400
|
Emma, Michael, Adam, George and Daniel. `kokoro-q8f16` offers all 28 English
|
|
386
401
|
Kokoro voices using the exact pinned `model_q8f16.onnx` (86 MB). Its preparation
|
|
@@ -188,6 +188,8 @@ the application operator to inspect the reported rows and any affected action
|
|
|
188
188
|
target. Do not delete a request claim or infer that an action with no result did
|
|
189
189
|
nothing. Repairs require the application's offline upgrade procedure and a
|
|
190
190
|
database backup; requests and startup never backfill these rows.
|
|
191
|
+
Retrying the same rejected message ID preserves that inspection code and its row
|
|
192
|
+
IDs without running inference or actions again. A retry is not a history repair.
|
|
191
193
|
|
|
192
194
|
New runtime metadata uses the existing JSON fields, so this ownership move adds
|
|
193
195
|
no database schema migration. Stop old assistant requests before switching
|
|
@@ -487,6 +489,12 @@ message-ID key. The database arbitrates concurrent requests across server
|
|
|
487
489
|
processes before provider or tool execution. A reused ID with a different request
|
|
488
490
|
returns a conflict. An identical retry replays the recorded answer or failure
|
|
489
491
|
without calling the provider or tools again, including after a process restart.
|
|
492
|
+
Pre-stream `AppError` failures retain their public code and details in the same
|
|
493
|
+
request receipt. `ACTION_PERMISSION_DENIED` details remain private, and arbitrary
|
|
494
|
+
non-`AppError` diagnostics are not added to the receipt. Older failure receipts
|
|
495
|
+
without these optional fields replay their original message and status; missing
|
|
496
|
+
diagnostics are not invented or backfilled. No database schema upgrade is needed
|
|
497
|
+
for these optional fields in the existing response JSON.
|
|
490
498
|
|
|
491
499
|
The acceptance receipt is stored before execution; completion is stored before
|
|
492
500
|
sending the final stream event. If a request is still running, or its process
|
|
@@ -43,6 +43,35 @@ their own exact versions in dependency declarations; do not replace them with
|
|
|
43
43
|
The copied files immediately belong to the application. Do not add pattern
|
|
44
44
|
receipts, generator provenance, completion ledgers, or hidden operation state.
|
|
45
45
|
|
|
46
|
+
## Implement before investigating internals
|
|
47
|
+
|
|
48
|
+
Use the relevant public API contract and one matching example to build the
|
|
49
|
+
smallest working slice, then verify its observable result. When the documented
|
|
50
|
+
contract answers the task, stop reading and implement it. Do not trace framework
|
|
51
|
+
or dependency internals to confirm documented options, routing, package
|
|
52
|
+
discovery, transport, or lifecycle behaviour before trying that API.
|
|
53
|
+
|
|
54
|
+
Implementation source is for a concrete failure or an API question the guide
|
|
55
|
+
and example cannot answer. Name that failure or question before investigating,
|
|
56
|
+
inspect only the relevant owner, and return to implementation and verification
|
|
57
|
+
as soon as it is resolved. Do not tour a dependency tree for confidence. This
|
|
58
|
+
applies to all features and dependencies, not only CRUD screens.
|
|
59
|
+
|
|
60
|
+
## Discover files before reading them
|
|
61
|
+
|
|
62
|
+
Discover the file, then read it. Do not infer its location from a convention.
|
|
63
|
+
Use paths identified in the current tree, installed metadata, or the relevant
|
|
64
|
+
example. When inspecting an unfamiliar package, list its files with
|
|
65
|
+
`rg --files <observed-package-directory>` and select the relevant paths from
|
|
66
|
+
that inventory before reading or searching source. Do not try guessed source
|
|
67
|
+
directories. An import subpath is an `exports` alias, not necessarily a physical
|
|
68
|
+
path; resolve it through the installed `package.json#exports` or
|
|
69
|
+
`import.meta.resolve()` when following an import.
|
|
70
|
+
|
|
71
|
+
This applies to every package and task, including third-party dependencies.
|
|
72
|
+
Use a documented option directly when it already answers the question; source
|
|
73
|
+
inspection is a fallback for a concrete unresolved fact.
|
|
74
|
+
|
|
46
75
|
## Install and compose capabilities
|
|
47
76
|
|
|
48
77
|
Install selected capabilities together at the exact versions in the matching
|
|
@@ -85,6 +85,15 @@ const bookResource = defineCrudResource({
|
|
|
85
85
|
create: { required: true }
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
|
+
},
|
|
89
|
+
searchSchema: {
|
|
90
|
+
q: {
|
|
91
|
+
type: "string",
|
|
92
|
+
oneOf: ["title"],
|
|
93
|
+
filterOperator: "like",
|
|
94
|
+
splitBy: " ",
|
|
95
|
+
matchAll: true
|
|
96
|
+
}
|
|
88
97
|
}
|
|
89
98
|
});
|
|
90
99
|
```
|
|
@@ -170,6 +179,90 @@ When the same create action appears in more than one visible location, choose
|
|
|
170
179
|
one visible action deliberately; do not relax the expected label to accept an
|
|
171
180
|
unrelated fallback.
|
|
172
181
|
|
|
182
|
+
## Browser tests verify validation and persistence
|
|
183
|
+
|
|
184
|
+
Exercise rejected and accepted input through the same form. Check the rendered
|
|
185
|
+
validation message and that rejection keeps the form open; then save an accepted
|
|
186
|
+
value and prove it appears in the list after reloading. Use the resource's
|
|
187
|
+
configured messages, the screen's `saveLabel`, and its actual browser routes.
|
|
188
|
+
Do not infer an `aria-invalid` attribute from the fact that validation exists:
|
|
189
|
+
the chosen field must actually implement that attribute contract before a test
|
|
190
|
+
can assert it.
|
|
191
|
+
|
|
192
|
+
For the public title-only Books variant above, using the pattern's
|
|
193
|
+
`saveLabel: "Save book"`, default minimum-length message, and a root public
|
|
194
|
+
surface:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
await page.goto("/books");
|
|
198
|
+
await page.getByRole("link", { name: "Add book", exact: true }).filter({ visible: true }).first().click();
|
|
199
|
+
await expect(page).toHaveURL(/\/books\/new$/);
|
|
200
|
+
await page.reload();
|
|
201
|
+
const title = page.getByRole("textbox", { name: "Title", exact: true });
|
|
202
|
+
const save = page.getByRole("button", { name: "Save book", exact: true });
|
|
203
|
+
await title.fill("");
|
|
204
|
+
await save.click();
|
|
205
|
+
await expect(page.getByText("Length must be at least 1 characters.", { exact: true })).toBeVisible();
|
|
206
|
+
await expect(page).toHaveURL(/\/books\/new$/);
|
|
207
|
+
|
|
208
|
+
await title.fill("A saved book");
|
|
209
|
+
await save.click();
|
|
210
|
+
await expect(page).toHaveURL(/\/books$/);
|
|
211
|
+
await expect(page.getByText("A saved book", { exact: true }).filter({ visible: true })).toBeVisible();
|
|
212
|
+
await page.reload();
|
|
213
|
+
await expect(page.getByText("A saved book", { exact: true }).filter({ visible: true })).toBeVisible();
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
For client-side routing, a click finishing does not prove the route has changed.
|
|
217
|
+
Before reloading after a navigation control, wait for the destination with
|
|
218
|
+
`await expect(page).toHaveURL(...)`, as above. Otherwise reload can reopen the
|
|
219
|
+
origin page and a later form or Back locator waits on the wrong screen. Use the
|
|
220
|
+
actual destination URL, including required context; do not add fixed sleeps or
|
|
221
|
+
increase timeouts to hide this race. For a contextual Back check, wait for the
|
|
222
|
+
form route, reload, click Back, and assert the original list URL. Test direct
|
|
223
|
+
entry separately against the configured fallback.
|
|
224
|
+
|
|
225
|
+
Keep the application's existing browser configuration and isolated fixtures.
|
|
226
|
+
Adapt the route, labels and configured error message to that application's
|
|
227
|
+
contract, and retain compact, medium and expanded layout coverage. Direct API
|
|
228
|
+
checks additionally prove rejected input is not persisted.
|
|
229
|
+
|
|
230
|
+
## Wire list search with the initial resource
|
|
231
|
+
|
|
232
|
+
`useCrudListScreen()` enables query search and the shared list renders a Search
|
|
233
|
+
box. When using that screen, configure `resource.searchSchema.q` with the
|
|
234
|
+
searchable fields from the start, as in the title-only Books resource above.
|
|
235
|
+
Showing a Search box alone does not implement storage filtering. Keep the
|
|
236
|
+
mapping in the resource; do not add page-local filtering or duplicate request
|
|
237
|
+
code. The full Books source example maps `q` to title, author and notes; narrow
|
|
238
|
+
it when adapting the example to fewer fields.
|
|
239
|
+
|
|
240
|
+
The browser page's route query and internal CRUD query use plain `q`. The
|
|
241
|
+
JSON:API HTTP transport uses `filter[q]`. Shared CRUD clients encode and decode
|
|
242
|
+
this automatically. Raw HTTP/API tests must send the transport key themselves:
|
|
243
|
+
|
|
244
|
+
```ts
|
|
245
|
+
const headers = { Accept: "application/vnd.api+json" };
|
|
246
|
+
const matches = await request.get("/api/books", {
|
|
247
|
+
headers, params: { "filter[q]": "A saved book" }
|
|
248
|
+
});
|
|
249
|
+
expect(matches.status()).toBe(200);
|
|
250
|
+
expect((await matches.json()).data.some(book => book.attributes.title === "A saved book")).toBe(true);
|
|
251
|
+
|
|
252
|
+
const noMatches = await request.get("/api/books", {
|
|
253
|
+
headers, params: { "filter[q]": "no-matching-fixture-title" }
|
|
254
|
+
});
|
|
255
|
+
expect(noMatches.status()).toBe(200);
|
|
256
|
+
expect((await noMatches.json()).data).toEqual([]);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Use controlled fixtures with a known matching and nonmatching value. A matching
|
|
260
|
+
row alone does not prove search works: an unfiltered response also includes it.
|
|
261
|
+
In the browser, fill Search, assert the expected visible rows and excluded rows,
|
|
262
|
+
then clear it and assert the list returns. Verify route/reload behaviour when
|
|
263
|
+
the screen synchronizes search to the route. Add these checks to the initial
|
|
264
|
+
create/list flow rather than discovering an unwired control at final review.
|
|
265
|
+
|
|
173
266
|
## Direct API tests use JSON:API documents
|
|
174
267
|
|
|
175
268
|
JSKIT's CRUD screens and HTTP client apply the resource's JSON:API transport
|
|
@@ -216,6 +309,13 @@ decision. Use `CrudDeleteAction` and `useCrudDeleteAction()` through the view
|
|
|
216
309
|
actions slot; do not rebuild their confirmation, request, invalidation, and
|
|
217
310
|
navigation flow.
|
|
218
311
|
|
|
312
|
+
The delete action resolves its HTTP client from the resource's `apiAccess`, just
|
|
313
|
+
like the list, view and form helpers. For `apiAccess: "public"`, DELETE requests
|
|
314
|
+
skip session CSRF discovery; no `/api/session` endpoint or page-local client
|
|
315
|
+
wiring is required. Authenticated resources retain the configured client's CSRF
|
|
316
|
+
behavior. An explicit `client` override is supported and receives the same
|
|
317
|
+
resource-aware public request options. This does not change server authorization.
|
|
318
|
+
|
|
219
319
|
For custom form actions, see
|
|
220
320
|
[record form actions](https://mobily-enterprises.github.io/jskit-ai/guide/framework/crud-form-actions).
|
|
221
321
|
|
package/package.json
CHANGED
|
@@ -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.
|
|
37
|
+
"@jskit-ai/kernel": "0.1.236",
|
|
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.
|
|
45
|
+
"@jskit-ai/http-runtime": "0.1.234",
|
|
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.
|
|
51
|
-
"@jskit-ai/jskit-catalog": "0.1.
|
|
50
|
+
"@jskit-ai/config-eslint": "0.1.233",
|
|
51
|
+
"@jskit-ai/jskit-catalog": "0.1.261",
|
|
52
52
|
"@playwright/test": "1.61.1",
|
|
53
53
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
54
54
|
"eslint": "^10.8.0",
|
|
@@ -26,6 +26,22 @@ The normal layer split is:
|
|
|
26
26
|
2. `repository.js`: add internal-only filter keys such as visibility scope, or call `listFilterContract.toJsonRestQuery(query)` for structured filters
|
|
27
27
|
3. provider/resource registration: merge backend filter behavior into JSON REST with `createJsonRestResourceScopeOptions(resource, { searchSchema })`
|
|
28
28
|
|
|
29
|
+
### Shared list and HTTP transport
|
|
30
|
+
|
|
31
|
+
`useCrudListScreen()` enables query-backed search. Configure
|
|
32
|
+
`resource.searchSchema.q` when composing the initial resource so its visible
|
|
33
|
+
Search control actually filters storage. Narrow the example's `oneOf` fields
|
|
34
|
+
when adapting a resource; do not drop search while retaining the control.
|
|
35
|
+
|
|
36
|
+
Names in this pattern's schemas and internal queries are plain keys such as
|
|
37
|
+
`q` and `archived`. Public JSON:API HTTP queries encode them as `filter[q]`
|
|
38
|
+
and `filter[archived]`. The browser page route may still use `?q=...`; it is
|
|
39
|
+
not the API transport. Shared CRUD clients perform the conversion. Direct
|
|
40
|
+
HTTP clients use, for example, `params: { "filter[q]": "Ada" }` against the
|
|
41
|
+
actual scoped API URL. Standard CRUD query validators already accept `q`
|
|
42
|
+
through this transport; only additional public filter keys need their own
|
|
43
|
+
filter validator. Verify matching and nonmatching results plus clearing Search.
|
|
44
|
+
|
|
29
45
|
## Decision Rules
|
|
30
46
|
|
|
31
47
|
Use `search: true` on a schema field when:
|
|
@@ -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.
|
|
37
|
+
"@jskit-ai/kernel": "0.1.236",
|
|
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.
|
|
45
|
+
"@jskit-ai/http-runtime": "0.1.234",
|
|
46
46
|
"@mdi/js": "^7.4.47",
|
|
47
|
-
"@jskit-ai/shell-web": "0.1.
|
|
47
|
+
"@jskit-ai/shell-web": "0.1.240",
|
|
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.
|
|
53
|
-
"@jskit-ai/jskit-catalog": "0.1.
|
|
52
|
+
"@jskit-ai/config-eslint": "0.1.233",
|
|
53
|
+
"@jskit-ai/jskit-catalog": "0.1.261",
|
|
54
54
|
"@playwright/test": "1.61.1",
|
|
55
55
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
56
56
|
"eslint": "^10.8.0",
|
package/patterns/ui-testing.md
CHANGED
|
@@ -18,6 +18,11 @@ Rules:
|
|
|
18
18
|
app-owned. Do not duplicate base-URL, web-server, or storage-state logic in
|
|
19
19
|
individual tests.
|
|
20
20
|
- Use relative paths such as `page.goto("/home")`. The shared config owns the browser base URL.
|
|
21
|
+
- After clicking a client-side navigation control, wait for its destination
|
|
22
|
+
with `await expect(page).toHaveURL(...)` before reloading. Awaiting the click
|
|
23
|
+
alone does not wait for Vue Router to complete. Contextual Back tests must
|
|
24
|
+
reach the form before reload, then assert the original list URL; direct entry
|
|
25
|
+
checks the configured fallback separately. Do not replace this wait with sleeps.
|
|
21
26
|
- A managed runner supplies `PLAYWRIGHT_BASE_URL`. When it is set, JSKIT does not start another app server.
|
|
22
27
|
- 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
28
|
- Do not install a browser when the environment provides a managed browser runner.
|
|
@@ -28,6 +33,14 @@ Rules:
|
|
|
28
33
|
Keep the expected text and persistence assertion. If repeated create controls
|
|
29
34
|
perform the same action, select one visible control deliberately rather than
|
|
30
35
|
accepting a different label to make a test pass.
|
|
36
|
+
- For CRUD validation, follow the generic CRUD guide's **Browser tests verify
|
|
37
|
+
validation and persistence** example: assert the visible configured error,
|
|
38
|
+
retained form, accepted save and reload persistence. Assert `aria-invalid`
|
|
39
|
+
only when the selected field implements that contract.
|
|
40
|
+
- Include the shared list's Search control in the initial feature flow: prove
|
|
41
|
+
matching rows, excluded rows and clearing the query. Raw JSON:API requests
|
|
42
|
+
send `filter[q]`; page-route and internal queries use plain `q`. See the CRUD
|
|
43
|
+
guide's **Wire list search with the initial resource** example.
|
|
31
44
|
|
|
32
45
|
## Keep startup incremental
|
|
33
46
|
|