@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.
- package/guide/agent/app-extras/assistant-conversation.md +51 -2
- package/guide/agent/app-setup/multi-homing.md +29 -0
- package/guide/agent/framework/crud-operations.md +162 -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/shell-foundation/example/package.json +5 -5
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/ui-testing.md +7 -0
- package/reference/autogen/PATTERN_INDEX.md +35 -35
- package/reference/autogen/packages/assistant-core.md +1 -1
- package/reference/autogen/packages/assistant-voice-sherpa.md +1 -1
- package/reference/autogen/packages/workspaces-core.md +3 -3
- package/reference/autogen/packages/workspaces-web.md +11 -0
- package/skills/jskit/SKILL.md +9 -0
- package/skills/jskit/references/crud-operations.md +162 -0
- package/skills/jskit/references/multi-homing.md +29 -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/crud-screen-set/PATTERN.md +30 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookEditPage.vue +1 -0
- package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookNewPage.vue +1 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +5 -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
- package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +20 -0
- 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.
|
|
1489
|
-
|
|
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
|
@@ -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.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.
|
|
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.
|
|
51
|
-
"@jskit-ai/jskit-catalog": "0.1.
|
|
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.
|
|
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.
|
|
45
|
+
"@jskit-ai/http-runtime": "0.1.233",
|
|
46
46
|
"@mdi/js": "^7.4.47",
|
|
47
|
-
"@jskit-ai/shell-web": "0.1.
|
|
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.
|
|
53
|
-
"@jskit-ai/jskit-catalog": "0.1.
|
|
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",
|
package/patterns/ui-testing.md
CHANGED
|
@@ -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
|
|