@jskit-ai/agent-docs 0.1.112 → 0.1.114
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/generators/advanced-cruds.md +16 -7
- package/guide/agent/generators/crud-generators.md +8 -2
- package/package.json +1 -1
- package/patterns/crud-scaffolding.md +1 -0
- package/reference/autogen/packages/crud-server-generator.md +7 -4
- package/reference/autogen/packages/crud-ui-generator.md +2 -0
- package/reference/autogen/packages/json-rest-api-core.md +5 -0
- package/reference/autogen/packages/users-web.md +14 -2
- package/skills/jskit/SKILL.md +108 -0
- package/skills/jskit/agents/openai.yaml +4 -0
- package/skills/jskit/references/app-operations.md +41 -0
- package/skills/jskit/references/crud-operations.md +111 -0
- package/skills/jskit/references/ui-operations.md +74 -0
- package/skills/jskit-review/SKILL.md +0 -86
- package/skills/jskit-review/agents/openai.yaml +0 -4
|
@@ -265,8 +265,10 @@ src/pages/w/[workspaceSlug]/admin/contacts/
|
|
|
265
265
|
new.vue
|
|
266
266
|
[contactId]/index.vue
|
|
267
267
|
[contactId]/edit.vue
|
|
268
|
-
|
|
269
|
-
|
|
268
|
+
|
|
269
|
+
src/components/w/[workspaceSlug]/admin/contacts/
|
|
270
|
+
CrudAddEditForm.vue
|
|
271
|
+
CrudAddEditFormFields.js
|
|
270
272
|
|
|
271
273
|
config/roles.js
|
|
272
274
|
src/placement.js
|
|
@@ -454,10 +456,17 @@ src/pages/w/[workspaceSlug]/admin/contacts/
|
|
|
454
456
|
[contactId]/edit.vue
|
|
455
457
|
listBulkActions.js
|
|
456
458
|
listFilters.js
|
|
457
|
-
|
|
458
|
-
|
|
459
|
+
|
|
460
|
+
src/components/w/[workspaceSlug]/admin/contacts/
|
|
461
|
+
CrudAddEditForm.vue
|
|
462
|
+
CrudAddEditFormFields.js
|
|
459
463
|
```
|
|
460
464
|
|
|
465
|
+
The shared Vue form lives in the mirrored `src/components/` tree because the
|
|
466
|
+
file router treats every Vue file below `src/pages/` as a route. The normalized
|
|
467
|
+
CRUD target root keeps the helper scoped to the same configured surface and
|
|
468
|
+
route family without exposing another browser route.
|
|
469
|
+
|
|
461
470
|
### `index.vue`
|
|
462
471
|
|
|
463
472
|
This is the list-page container.
|
|
@@ -781,7 +790,7 @@ The safe mental model is:
|
|
|
781
790
|
- use `usePaths().api(...)` when you need a custom scoped API path and the higher-level runtime does not already resolve it for you
|
|
782
791
|
- keep `apiUrlTemplate` path-only and put endpoint query strings in `requestQueryParams`
|
|
783
792
|
|
|
784
|
-
### `
|
|
793
|
+
### `src/components/.../CrudAddEditForm.vue`
|
|
785
794
|
|
|
786
795
|
This is the generated field bridge for the shared add/edit screen.
|
|
787
796
|
|
|
@@ -792,7 +801,7 @@ It owns:
|
|
|
792
801
|
|
|
793
802
|
It does **not** own persistence logic or the shared screen chrome. `CrudAddEditScreen` from `users-web` owns the common title, load state, retry action, save/cancel action row, and form surface.
|
|
794
803
|
|
|
795
|
-
### `
|
|
804
|
+
### `src/components/.../CrudAddEditFormFields.js`
|
|
796
805
|
|
|
797
806
|
This is the generated field-definition module used by `useCrudAddEdit()`.
|
|
798
807
|
|
|
@@ -841,7 +850,7 @@ Use this rule of thumb when deciding where to edit:
|
|
|
841
850
|
| Add per-row commands to a generated list page | page-local `listRowActions.js`, usually calling `useCommand()`-backed composables | The shared list screen renders action chrome; the page owns explicit mutation behavior |
|
|
842
851
|
| Add non-CRUD display rows to a generated list page | route page `syntheticRows` input | Synthetic rows are presentation rows, not repository records |
|
|
843
852
|
| Change page-specific display behavior | the route pages, generated slots, and app-owned composables | This is presentation |
|
|
844
|
-
| Change form field layout and inputs | `
|
|
853
|
+
| Change form field layout and inputs | the mirrored `src/components/.../CrudAddEditForm.vue` and `CrudAddEditFormFields.js` | This is the generated non-routed form field layer |
|
|
845
854
|
|
|
846
855
|
## How mature CRUDs grow
|
|
847
856
|
|
|
@@ -458,7 +458,12 @@ That creates the baseline CRUD route tree:
|
|
|
458
458
|
- `w/[workspaceSlug]/admin/contacts/new.vue`
|
|
459
459
|
- `w/[workspaceSlug]/admin/contacts/[contactId]/index.vue`
|
|
460
460
|
- `w/[workspaceSlug]/admin/contacts/[contactId]/edit.vue`
|
|
461
|
-
- shared
|
|
461
|
+
- shared form files under the mirrored non-routed
|
|
462
|
+
`src/components/w/[workspaceSlug]/admin/contacts/` root
|
|
463
|
+
|
|
464
|
+
The mirrored component root is intentional. The configured file router scans
|
|
465
|
+
Vue files below `src/pages/`, so reusable Vue helpers must stay outside that
|
|
466
|
+
directory or they become browser routes.
|
|
462
467
|
|
|
463
468
|
Generated list, view, and lookup reads use the resource contract as their
|
|
464
469
|
response authority. They return every field declared for output by default,
|
|
@@ -620,7 +625,8 @@ That gives you a normal child route tree:
|
|
|
620
625
|
- `w/[workspaceSlug]/admin/contacts/[contactId]/addresses/new.vue`
|
|
621
626
|
- `w/[workspaceSlug]/admin/contacts/[contactId]/addresses/[addressId]/index.vue`
|
|
622
627
|
- `w/[workspaceSlug]/admin/contacts/[contactId]/addresses/[addressId]/edit.vue`
|
|
623
|
-
- shared
|
|
628
|
+
- shared form files under the mirrored non-routed
|
|
629
|
+
`src/components/w/[workspaceSlug]/admin/contacts/[contactId]/addresses/` root
|
|
624
630
|
|
|
625
631
|
### Step 5: remove the generated shell placement by hand
|
|
626
632
|
|
package/package.json
CHANGED
|
@@ -67,6 +67,7 @@ Rules:
|
|
|
67
67
|
- Generated CRUD UI must be compact-first. Lists need searchable cards on compact widths and tables only for medium/expanded layouts.
|
|
68
68
|
- Generated CRUD list screens need real loading, empty, and error states. Empty copy should name the resource, such as "No customers yet", and offer the create action when available.
|
|
69
69
|
- Generated CRUD view/new/edit screens should use page headers plus direct sheet panels. Do not use generic card shells as the page architecture.
|
|
70
|
+
- Keep generated reusable Vue helpers outside `src/pages/`; the file router inventories every Vue file below that root as a browser route. CRUD form helpers mirror the validated target root under `src/components/`.
|
|
70
71
|
- Permission-gated generated CRUD lists should pass `readEnabled` into `useCrudListScreen(...)` instead of replacing the shared list wrapper.
|
|
71
72
|
- Compact CRUD actions should be reachable without a drawer. Use a mobile-visible primary action or FAB for create flows.
|
|
72
73
|
- Row actions should be declared with `defineCrudListRowActions(...)` in a page-local `listRowActions.js` and passed into `useCrudListScreen(...)`; the shared list screen owns the compact/wide action rendering.
|
|
@@ -31,6 +31,8 @@ Local functions
|
|
|
31
31
|
- `resolveBooleanFlagOption(options = {}, optionName = "")`
|
|
32
32
|
- `resolveInternalRouteOption(options = {})`
|
|
33
33
|
- `resolveNoRoleGrantOption(options = {})`
|
|
34
|
+
- `normalizeCrudAccess(value, { strict = false } = {})`
|
|
35
|
+
- `assertCrudAccessCompatibility(access, { surfaceRequiresWorkspace = false, ownershipFilter = "" } = {})`
|
|
34
36
|
- `normalizeRequestedOwnershipFilter(value, { strict = false } = {})`
|
|
35
37
|
- `inferOwnershipFilterFromSnapshot(snapshot)`
|
|
36
38
|
- `assertOwnershipColumnsForFilter(snapshot, filter)`
|
|
@@ -80,6 +82,7 @@ Local functions
|
|
|
80
82
|
- `renderMigrationForeignKeyLines(snapshot)`
|
|
81
83
|
- `renderMigrationDropForeignKeyLine(foreignKey = {})`
|
|
82
84
|
- `renderMigrationDropForeignKeyLines(snapshot)`
|
|
85
|
+
- `renderMigrationForeignKeyBlock(snapshot, { drop = false } = {})`
|
|
83
86
|
- `renderMigrationCheckConstraintLines(snapshot)`
|
|
84
87
|
- `mergeFieldMetaEntries(...entryGroups)`
|
|
85
88
|
- `resolveLookupNamespaceFromTableName(tableName = "")`
|
|
@@ -95,8 +98,8 @@ Local functions
|
|
|
95
98
|
- `resolveCrudPermissionGrantRole(appConfig = {}, options = {}, { requiresNamedPermissions = true } = {})`
|
|
96
99
|
- `normalizeCrudOperation(operation = "", context = "CRUD operation")`
|
|
97
100
|
- `renderRoleCatalogPermissionGrants(namespace = "", { requiresNamedPermissions = true, grantRoleId = "" } = {})`
|
|
98
|
-
- `renderActionPermissionSupport(namespace = "", { requiresNamedPermissions = true } = {})`
|
|
99
|
-
- `renderActionPermissionExpression(operation = "", { requiresNamedPermissions = true } = {})`
|
|
101
|
+
- `renderActionPermissionSupport(namespace = "", { requiresNamedPermissions = true, access = ACCESS_DEFAULT } = {})`
|
|
102
|
+
- `renderActionPermissionExpression(operation = "", { requiresNamedPermissions = true, access = ACCESS_DEFAULT } = {})`
|
|
100
103
|
- `renderRouteWorkspaceSupportImports({ surfaceRequiresWorkspace = true } = {})`
|
|
101
104
|
- `renderActionWorkspaceValidatorImport({ surfaceRequiresWorkspace = true } = {})`
|
|
102
105
|
- `renderRouteParamsValidatorLine(operation = "", { surfaceRequiresWorkspace = true } = {})`
|
|
@@ -105,7 +108,7 @@ Local functions
|
|
|
105
108
|
- `renderActionInputSchemaDefinition(lines = [], { mode = "patch" } = {})`
|
|
106
109
|
- `renderActionInputExpressions({ surfaceRequiresWorkspace = true } = {})`
|
|
107
110
|
- `renderRouteValidatorConstants({ surfaceRequiresWorkspace = true } = {})`
|
|
108
|
-
- `buildReplacementsFromSnapshot({ namespace = "", snapshot, resolvedOwnershipFilter, surfaceRequiresWorkspace = true, surfaceId = "", routeInternal = false, permissionGrantRoleId = "" })`
|
|
111
|
+
- `buildReplacementsFromSnapshot({ namespace = "", snapshot, resolvedOwnershipFilter, surfaceRequiresWorkspace = true, surfaceId = "", access = ACCESS_DEFAULT, routeInternal = false, permissionGrantRoleId = "" })`
|
|
109
112
|
- `resolveCrudGenerationTableName(options = {})`
|
|
110
113
|
- `createCacheKey({ appRoot, options })`
|
|
111
114
|
- `buildCrudTemplateContext(input = {})`
|
|
@@ -216,7 +219,7 @@ Exports
|
|
|
216
219
|
- `resource`
|
|
217
220
|
- `createTemplateServerFixture(options = {})`
|
|
218
221
|
Local functions
|
|
219
|
-
- `buildTemplateReplacements({ surfaceRequiresWorkspace = true, requiresNamedPermissions = surfaceRequiresWorkspace === true, surfaceId = surfaceRequiresWorkspace ? "admin" : "home", routeInternal = false } = {})`
|
|
222
|
+
- `buildTemplateReplacements({ surfaceRequiresWorkspace = true, requiresNamedPermissions = surfaceRequiresWorkspace === true, surfaceId = surfaceRequiresWorkspace ? "admin" : "home", access = "authenticated", routeInternal = false } = {})`
|
|
220
223
|
- `applyTemplateReplacements(sourceText = "", options = {})`
|
|
221
224
|
- `buildResourceStubSource()`
|
|
222
225
|
- `renderServerTemplateFile(targetServerDirectory, fileName, options)`
|
|
@@ -29,6 +29,7 @@ Local functions
|
|
|
29
29
|
- `normalizeRelativeAppPath(value = "")`
|
|
30
30
|
- `requireTargetRootOption(options = {})`
|
|
31
31
|
- `resolveListTargetFile(targetRoot = "")`
|
|
32
|
+
- `resolveFormHelperPaths(targetRoot = "")`
|
|
32
33
|
- `parseOperationsOption(options)`
|
|
33
34
|
- `parseDisplayFieldsOption(options)`
|
|
34
35
|
- `parseParentTitleOption(options)`
|
|
@@ -138,6 +139,7 @@ Local functions
|
|
|
138
139
|
- `resolveAnchorScopeStart(source = "", { anchorIndex = -1, anchor = "" } = {})`
|
|
139
140
|
- `buildAnchorInsertions(operationName, field)`
|
|
140
141
|
- `resolveGeneratedTargetComment(source = "", commentName = "")`
|
|
142
|
+
- `resolveGeneratedTargetPath(appRoot, targetAbsolutePath, generatedTarget = "")`
|
|
141
143
|
- `resolveOperationTargetFiles({ appRoot, operationName, targetAbsolutePath, source = "" } = {})`
|
|
142
144
|
- `parseSubcommandArgs(args = [])`
|
|
143
145
|
|
|
@@ -39,6 +39,11 @@ Exports
|
|
|
39
39
|
Local functions
|
|
40
40
|
- `isPlainJsonRestObject(value)`
|
|
41
41
|
- `cloneJsonRestResourceValue(value, { writeSerializers = {} } = {})`
|
|
42
|
+
- `resolveCanonicalCalendarDate(value)`
|
|
43
|
+
- `serializeJsonRestCalendarDate(value)`
|
|
44
|
+
- `applyJsonRestCalendarDateWriteSerializers(scopeOptions = {})`
|
|
45
|
+
- `normalizeJsonRestCalendarDateEntry(entry = null, scopes = {})`
|
|
46
|
+
- `normalizeJsonRestCalendarDateDocument(document = null, scopes = {})`
|
|
42
47
|
- `normalizeScopeValue(value)`
|
|
43
48
|
- `normalizeJsonRestText(value, { fallback = "" } = {})`
|
|
44
49
|
- `normalizeJsonRestFilterValue(value)`
|
|
@@ -150,6 +150,13 @@ Exports
|
|
|
150
150
|
- `resolveCrudBindingValues(values, context = {})`
|
|
151
151
|
- `resolveCrudBoundValues({ binding = {}, routeValues = {}, context = {} } = {})`
|
|
152
152
|
|
|
153
|
+
### `src/client/composables/crud/crudHttpClientSupport.js`
|
|
154
|
+
Exports
|
|
155
|
+
- `CRUD_API_ACCESS_AUTHENTICATED`
|
|
156
|
+
- `CRUD_API_ACCESS_PUBLIC`
|
|
157
|
+
- `normalizeCrudApiAccess(value = "")`
|
|
158
|
+
- `resolveCrudHttpClient(resource = null, { client = null } = {})`
|
|
159
|
+
|
|
153
160
|
### `src/client/composables/crud/crudJsonApiTransportSupport.js`
|
|
154
161
|
Exports
|
|
155
162
|
- `inferCrudJsonApiTransport(resource = null, { mode = "", operationName = "" } = {})`
|
|
@@ -201,6 +208,7 @@ Local functions
|
|
|
201
208
|
- `normalizeTimeWhitespace(value)`
|
|
202
209
|
- `toTimeInputValue(value)`
|
|
203
210
|
- `toDateTimeLocalInputValue(value)`
|
|
211
|
+
- `toDateInputValue(value)`
|
|
204
212
|
- `toIsoUtcDateTimeValue(value)`
|
|
205
213
|
- `resolveFormFieldInitialValue(field = {})`
|
|
206
214
|
- `shouldSerializeClearedFieldAsNull(field = {})`
|
|
@@ -472,7 +480,7 @@ Exports
|
|
|
472
480
|
|
|
473
481
|
### `src/client/composables/useCommand.js`
|
|
474
482
|
Exports
|
|
475
|
-
- `useCommand({ ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", runPermissions = [], writeMethod = "POST", client = null, transport = null, placementSource = "users-web.command", fallbackRunError = "Unable to complete action.", fieldErrorKeys = [], clearOnRouteChange = true, model, input, buildRawPayload, buildCommandPayload, buildCommandOptions, onRunSuccess, onRunError, suppressSuccessMessage = false, messages = {}, realtime = null } = {})`
|
|
483
|
+
- `useCommand({ ownershipFilter = ROUTE_VISIBILITY_WORKSPACE, surfaceId = "", access = "auto", apiSuffix = "", runPermissions = [], writeMethod = "POST", client = null, resource: commandResource = null, transport = null, placementSource = "users-web.command", fallbackRunError = "Unable to complete action.", fieldErrorKeys = [], clearOnRouteChange = true, model, input, buildRawPayload, buildCommandPayload, buildCommandOptions, onRunSuccess, onRunError, suppressSuccessMessage = false, messages = {}, realtime = null } = {})`
|
|
476
484
|
|
|
477
485
|
### `src/client/composables/useCrudAddEditScreen.js`
|
|
478
486
|
Exports
|
|
@@ -525,8 +533,10 @@ Local functions
|
|
|
525
533
|
|
|
526
534
|
### `src/client/composables/useCrudListScreen.js`
|
|
527
535
|
Exports
|
|
528
|
-
- `
|
|
536
|
+
- `__testables`
|
|
537
|
+
- `useCrudListScreen({ adapter = null, client = null, resource = null, resourceNamespace = "resource", apiSuffix = "", recordIdParam = "recordId", recordIdSelector = null, titleFallbackFieldKey = "", viewUrlTemplate = "", editUrlTemplate = "", newUrlTemplate = "", recordChangedEvents = [], listFilters = {}, listBulkActions = [], listRowActions = [], syntheticRows = null, routeQueryBlacklist = Object.freeze(["include", "cursor", "limit"]), requestQueryParams = null, requestFieldsets = null, readEnabled = true, requestRecoveryLabel = "Records", fallbackLoadError = "Unable to load records." } = {})`
|
|
529
538
|
Local functions
|
|
539
|
+
- `buildCrudListActionContext(records, client)`
|
|
530
540
|
- `formatCrudListCardValue(value)`
|
|
531
541
|
- `asList(value = [])`
|
|
532
542
|
- `hasSyntheticRowGroups(value = null)`
|
|
@@ -604,6 +614,8 @@ Exports
|
|
|
604
614
|
- `CrudListFilterSurface`
|
|
605
615
|
- `CrudListScreen`
|
|
606
616
|
- `CrudViewScreen`
|
|
617
|
+
- `normalizeCrudApiAccess`
|
|
618
|
+
- `resolveCrudHttpClient`
|
|
607
619
|
- `clientProviders`
|
|
608
620
|
|
|
609
621
|
### `src/client/lib/bootstrap.js`
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: jskit
|
|
3
|
+
description: Build, extend, troubleshoot, review, deslop, and verify JSKIT applications using the JSKIT CLI, runtime packages, generators, surfaces, placements, and managed-app conventions. Use for JSKIT scaffolding, pages, routes, UI, authentication, databases, CRUDs, users, workspaces, console features, migrations, package changes, upgrades, or pre-sign-off review.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# JSKIT
|
|
7
|
+
|
|
8
|
+
Use JSKIT's native CLI, generators, installed packages, and app-local
|
|
9
|
+
contracts. This skill explains the technology; the request and application
|
|
10
|
+
files define the product.
|
|
11
|
+
|
|
12
|
+
## Exact caller lanes
|
|
13
|
+
|
|
14
|
+
Execute a caller-supplied complete exact JSKIT command lane with all option
|
|
15
|
+
values directly. Read the nearest `AGENTS.md` and relevant skill reference;
|
|
16
|
+
skip `help`, `list`, `show --details`, `list-placements`, sibling docs,
|
|
17
|
+
`node_modules` or generator-source inspection, plus any verification the
|
|
18
|
+
caller owns.
|
|
19
|
+
|
|
20
|
+
Discover only a missing fact or exact-command failure, then resume the lane.
|
|
21
|
+
|
|
22
|
+
## Establish context
|
|
23
|
+
|
|
24
|
+
1. Read the request and nearest `AGENTS.md`.
|
|
25
|
+
2. Inspect `package.json`, `.jskit/lock.json`, the existing tree, and the
|
|
26
|
+
current diff when reviewing changes.
|
|
27
|
+
3. Read `.jskit/APP_BLUEPRINT.md` when present for durable product and
|
|
28
|
+
architecture decisions. Do not invent or expand product requirements from
|
|
29
|
+
this skill.
|
|
30
|
+
4. Load only the task-relevant direct reference:
|
|
31
|
+
- For creation, package selection, CLI use, or generators, read
|
|
32
|
+
[application operations](references/app-operations.md).
|
|
33
|
+
- Before database, schema, CRUD, repository, or persistence work, read
|
|
34
|
+
[CRUD operations](references/crud-operations.md) completely.
|
|
35
|
+
- For routes, placements, user-facing UI, or browser verification, read
|
|
36
|
+
[UI operations](references/ui-operations.md).
|
|
37
|
+
|
|
38
|
+
Those files are the complete operational references required by this skill.
|
|
39
|
+
Do not depend on sibling package documentation being present. Do not load
|
|
40
|
+
irrelevant references.
|
|
41
|
+
|
|
42
|
+
Do not invent missing tenancy, authentication, database, surface, ownership,
|
|
43
|
+
or permission decisions when they would materially change the application.
|
|
44
|
+
|
|
45
|
+
## Discovery fallback
|
|
46
|
+
|
|
47
|
+
- For a missing fact, use only the narrowest applicable JSKIT CLI query.
|
|
48
|
+
- Prefer an existing JSKIT package, generator, placement, or high-level
|
|
49
|
+
composable over hand-wired local infrastructure.
|
|
50
|
+
- Treat `.jskit/lock.json` and JSKIT-owned projections as managed state. Do not
|
|
51
|
+
hand-edit the lock or bypass managed-file lifecycle checks.
|
|
52
|
+
|
|
53
|
+
## Implement a change
|
|
54
|
+
|
|
55
|
+
1. Use the caller-selected seam, or discover only a genuinely missing seam.
|
|
56
|
+
2. Read the matching local reference above.
|
|
57
|
+
3. Implement the smallest complete vertical slice at documented app-owned
|
|
58
|
+
seams.
|
|
59
|
+
4. Install dependencies and run migrations only when the selected operation
|
|
60
|
+
requires them.
|
|
61
|
+
5. For schema work, use only a fresh disposable development database; never
|
|
62
|
+
alter production, legacy, historical, or otherwise valuable data.
|
|
63
|
+
|
|
64
|
+
For user-facing work, respect the selected surface and semantic placements,
|
|
65
|
+
handle compact layouts and loading, empty, error, permission, and ownership
|
|
66
|
+
states, and verify meaningful behavior in the browser.
|
|
67
|
+
|
|
68
|
+
## Caller-owned verification
|
|
69
|
+
|
|
70
|
+
When a calling orchestrator explicitly owns final tests, migrations, server
|
|
71
|
+
lifecycle, browser checks, and sign-off, honor that division of work. Stay
|
|
72
|
+
within its wall-time and action limits, implement the requested slice, return
|
|
73
|
+
the requested manifest or summary, and stop. Do not start a dev server,
|
|
74
|
+
browser, Playwright, broad verifier, migration rebuild, or exploratory review
|
|
75
|
+
unless that caller asks for it in the current task.
|
|
76
|
+
|
|
77
|
+
## Review or deslop
|
|
78
|
+
|
|
79
|
+
Review the requested chunk or whole changeset. If the request is review-only,
|
|
80
|
+
report findings without editing.
|
|
81
|
+
|
|
82
|
+
Check for:
|
|
83
|
+
|
|
84
|
+
- Duplicated helpers, dead code, placeholders, accidental abstractions, and
|
|
85
|
+
incomplete states.
|
|
86
|
+
- Missed JSKIT packages, generators, high-level composables, placements, or
|
|
87
|
+
runtime seams.
|
|
88
|
+
- Invalid surface, route, ownership, permission, migration, or managed-file
|
|
89
|
+
choices.
|
|
90
|
+
- Weak Material Design or Vuetify hierarchy, responsiveness, actions, and
|
|
91
|
+
state handling.
|
|
92
|
+
- Verification proportional to scope, including Playwright for meaningful
|
|
93
|
+
user-facing flows.
|
|
94
|
+
|
|
95
|
+
Present findings first, ordered by severity, with file references. Say
|
|
96
|
+
explicitly when there are no findings.
|
|
97
|
+
|
|
98
|
+
## Verify
|
|
99
|
+
|
|
100
|
+
- Run focused tests for the changed slice and broad regression checks for a
|
|
101
|
+
whole changeset.
|
|
102
|
+
- Run `npx jskit doctor` when managed state changed.
|
|
103
|
+
- Run `npm run verify` before sign-off.
|
|
104
|
+
- Rebuild migrations from zero against a fresh disposable database when
|
|
105
|
+
schema or persistence changed.
|
|
106
|
+
- Run the relevant Playwright flow when user-facing behavior changed.
|
|
107
|
+
- Report files reviewed or changed, commands run, and anything still
|
|
108
|
+
unverified.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Application operations
|
|
2
|
+
|
|
3
|
+
Read this reference for application creation, CLI discovery, package changes,
|
|
4
|
+
and generator selection.
|
|
5
|
+
|
|
6
|
+
## Create an application
|
|
7
|
+
|
|
8
|
+
Confirm the application name and tenancy mode, then run:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npx @jskit-ai/create-app <app-name> --tenancy-mode <tenancy-mode>
|
|
12
|
+
cd <app-name>
|
|
13
|
+
npm install
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Generated applications require Node.js 26. Use `--target . --force` only to
|
|
17
|
+
promote a known JSKIT `ai-seed` directory, never to overwrite an arbitrary
|
|
18
|
+
application. Use `--minimal` only for a deliberately bare package-development
|
|
19
|
+
or unusual integration baseline. After creation, follow the generated
|
|
20
|
+
`AGENTS.md`.
|
|
21
|
+
|
|
22
|
+
Do not add authentication, users, workspaces, console, example routes, sample
|
|
23
|
+
records, or another database adapter unless the request requires them.
|
|
24
|
+
|
|
25
|
+
## Select and apply technology
|
|
26
|
+
|
|
27
|
+
- Inspect available capabilities with `npx jskit list` and inspect a specific
|
|
28
|
+
entry with `npx jskit show <id> --details`.
|
|
29
|
+
- Install reusable runtime capability with `npx jskit add package <id>`.
|
|
30
|
+
- Inspect a bundle before installing it with `npx jskit add bundle <id>`.
|
|
31
|
+
- Run tooling packages with
|
|
32
|
+
`npx jskit generate <generator> <action> ...`; do not install generators as
|
|
33
|
+
runtime packages.
|
|
34
|
+
- Let `jskit` own JSKIT application mutations, use `npm install` for dependency
|
|
35
|
+
installation, and use `npm run db:migrate` for database migrations.
|
|
36
|
+
- Review generated files and continue only at documented app-owned seams.
|
|
37
|
+
|
|
38
|
+
Packages own reusable framework behavior. Generators create application-owned
|
|
39
|
+
pages, components, placements, migrations, and support files. Prefer the
|
|
40
|
+
narrowest installed package or generator that implements the requested
|
|
41
|
+
vertical slice; do not build a parallel local framework around it.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# CRUD operations
|
|
2
|
+
|
|
3
|
+
Read this reference completely before database, schema, CRUD, repository, or
|
|
4
|
+
persistence work.
|
|
5
|
+
|
|
6
|
+
## Establish the contract
|
|
7
|
+
|
|
8
|
+
Determine the selected database adapter, surface, access rule, and ownership
|
|
9
|
+
model from the request and app authority. Inspect only a generator whose exact
|
|
10
|
+
lane or option values are missing, or whose supplied command failed:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npx jskit show crud-server-generator --details
|
|
14
|
+
npx jskit show crud-ui-generator --details
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Never run these merely to reconfirm caller-supplied facts.
|
|
18
|
+
|
|
19
|
+
For normal app-owned CRUD tables:
|
|
20
|
+
|
|
21
|
+
- Use one non-null integer primary key, normally
|
|
22
|
+
`id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY`.
|
|
23
|
+
- Make every foreign key single-column and target the referenced table's
|
|
24
|
+
single-column primary key. Use multi-column unique indexes only for business
|
|
25
|
+
uniqueness, never as relationship targets.
|
|
26
|
+
- Use only direct `workspace_id` and/or `user_id` columns for generated JSKIT
|
|
27
|
+
ownership and choose the ownership filter matching those columns exactly.
|
|
28
|
+
- Treat names such as `recipient_user_id`, `created_by_user_id`, and
|
|
29
|
+
`assignee_user_id` as domain relationships, not ownership aliases.
|
|
30
|
+
- Express tenant-safe relationships as direct ownership plus a normal
|
|
31
|
+
`parent_id -> parent.id` relation. Test both allowed and cross-workspace
|
|
32
|
+
cases.
|
|
33
|
+
|
|
34
|
+
Stop before generation if the schema uses composite relationship keys or if
|
|
35
|
+
the ownership filter and reserved ownership columns disagree.
|
|
36
|
+
|
|
37
|
+
## Conventional one-table CRUD
|
|
38
|
+
|
|
39
|
+
In a fresh disposable development database, create the validated table first.
|
|
40
|
+
The server generator reads its live shape. Scaffold the server contract before
|
|
41
|
+
the UI:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx jskit generate crud-server-generator scaffold \
|
|
45
|
+
--namespace <resource> \
|
|
46
|
+
--surface <surface> \
|
|
47
|
+
--ownership-filter <public|user|workspace|workspace_user> \
|
|
48
|
+
--access <public|authenticated> \
|
|
49
|
+
--table-name <table>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Use `--access public` only with a non-workspace surface and public ownership;
|
|
53
|
+
omit both role-grant flags. For workspace-required CRUDs, choose exactly one
|
|
54
|
+
of `--grant-role <role>` or `--no-role-grant`. Never invent a role to satisfy
|
|
55
|
+
the generator. Use `--internal` when the entity needs the generated
|
|
56
|
+
repository/service/resource/migration ownership chain but no public HTTP CRUD
|
|
57
|
+
routes.
|
|
58
|
+
|
|
59
|
+
Run `npm install`, then scaffold the UI from the generated shared resource:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npx jskit generate crud-ui-generator crud \
|
|
63
|
+
<pages-root>/<plural-route> \
|
|
64
|
+
--resource-file packages/<namespace>/src/shared/<singular>Resource.js \
|
|
65
|
+
--parent-title contextual
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The target is relative to `src/pages/`, starts with the selected surface's
|
|
69
|
+
nonempty configured `pagesRoot`, and has no leading slash (for example
|
|
70
|
+
`home/books`). For a surface deliberately configured with an empty root, use
|
|
71
|
+
only the plural route (for example `books`). Use the exact singular resource
|
|
72
|
+
filename emitted by the server generator; do not guess it.
|
|
73
|
+
|
|
74
|
+
Treat that shared resource as the canonical CRUD contract. Do not hand-build
|
|
75
|
+
routes, validators, HTTP helpers, or UI before the server resource exists.
|
|
76
|
+
|
|
77
|
+
Use generated high-level seams where they fit:
|
|
78
|
+
|
|
79
|
+
- `useCrudListScreen()`, `useCrudViewScreen()`, and
|
|
80
|
+
`useCrudAddEditScreen()` for routed screens.
|
|
81
|
+
- `useCrudList()`, `useCrudView()`, and `useCrudAddEdit()` for routed CRUD
|
|
82
|
+
behavior.
|
|
83
|
+
- `useList()`, `useView()`, `useAddEdit()`, `useCommand()`, and
|
|
84
|
+
`useEndpointResource()` for non-standard contracts.
|
|
85
|
+
|
|
86
|
+
CRUD hooks derive their JSON:API transport from the shared resource. Do not
|
|
87
|
+
pass a custom transport or use raw `fetch()` for standard CRUD behavior.
|
|
88
|
+
|
|
89
|
+
## Migration ownership
|
|
90
|
+
|
|
91
|
+
Do not hand-write a competing migration for a table the CRUD server generator
|
|
92
|
+
will own. Never modify or replace its installed baseline migration. Express a
|
|
93
|
+
later schema change as a new immutable additive migration owned by the
|
|
94
|
+
app-local package:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx jskit create migration \
|
|
98
|
+
--package <package-id> \
|
|
99
|
+
--id <migration-id>
|
|
100
|
+
npx jskit migrations package <package-id>
|
|
101
|
+
npm run db:migrate
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
If ordinary persisted data genuinely cannot use the generated CRUD lane, stop
|
|
105
|
+
and obtain explicit developer approval. Record the approved exception in
|
|
106
|
+
`.jskit/WORKBOARD.md` and `.jskit/table-ownership.json`; also record it in
|
|
107
|
+
`.jskit/APP_BLUEPRINT.md` when it changes durable architecture.
|
|
108
|
+
|
|
109
|
+
Before sign-off, rebuild the full migration chain in a fresh disposable
|
|
110
|
+
database, compare the recreated schema with the intended schema, test relevant
|
|
111
|
+
ownership boundaries, run JSKIT Doctor, and run the project verifier.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# UI operations
|
|
2
|
+
|
|
3
|
+
Read this reference for routes, pages, surfaces, placements, responsive UI, or
|
|
4
|
+
browser verification.
|
|
5
|
+
|
|
6
|
+
## Pages, surfaces, and placements
|
|
7
|
+
|
|
8
|
+
Take the intended surface from the request and app authority; do not silently
|
|
9
|
+
default new functionality to `app`. Surface choice controls routes, access,
|
|
10
|
+
placement visibility, and often ownership.
|
|
11
|
+
|
|
12
|
+
For a normal app-owned non-CRUD page, first inspect the generator and semantic
|
|
13
|
+
placements, then generate the page:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx jskit show ui-generator --details
|
|
17
|
+
npx jskit list-placements
|
|
18
|
+
npx jskit generate ui-generator page <route-file> --name <name>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Use `--navigation-role primary` for main destinations and `secondary`,
|
|
22
|
+
`detail`, `workflow`, or `none` as appropriate for other routes. Use
|
|
23
|
+
`--link-placement <semantic-id>` when the link belongs in a non-default slot.
|
|
24
|
+
Use `npx jskit list-placements --concrete` only when diagnosing concrete
|
|
25
|
+
outlets. Author normal app UI against semantic placements such as
|
|
26
|
+
`shell.primary-nav` or `page.section-nav`, not raw `host:position` outlets.
|
|
27
|
+
|
|
28
|
+
Let the generator create both the route and placement entry before adapting
|
|
29
|
+
app-owned output. If a normal page cannot use the generator, state the concrete
|
|
30
|
+
reason before hand-writing it.
|
|
31
|
+
|
|
32
|
+
## Screen behavior
|
|
33
|
+
|
|
34
|
+
- Keep app screens phone/task-first, primary actions drawer-independent, and
|
|
35
|
+
48 px tap targets.
|
|
36
|
+
- Use a page header and direct `v-sheet`, not nested-card architecture.
|
|
37
|
+
- Provide resource-named loading, empty, error, permission, and retry states.
|
|
38
|
+
- Use compact searchable cards and medium/expanded tables for generated CRUD
|
|
39
|
+
lists where appropriate.
|
|
40
|
+
- Extend shared CRUD screens through slots. For custom sibling/child links,
|
|
41
|
+
resolve current dynamic params with their runtime to an absolute URL/route
|
|
42
|
+
object; never bind its route-template/relative string raw to Vue Router `to`.
|
|
43
|
+
- Use `defineCrudListRowActions(...)` and the generated page-local row-action
|
|
44
|
+
seam for row commands. Use shared filter definitions for structured filters.
|
|
45
|
+
- Keep ordinary read failures local with runtime `loadError` and retry state.
|
|
46
|
+
Use `useCommand()` or `useUiFeedback()` for user-triggered action feedback.
|
|
47
|
+
|
|
48
|
+
## Browser verification
|
|
49
|
+
|
|
50
|
+
Any change to user-facing behavior needs a Playwright flow exercising that
|
|
51
|
+
behavior. Check compact, medium, and expanded widths for generated/template UI
|
|
52
|
+
changes, including overflow, clipped text, duplicate navigation, route
|
|
53
|
+
placement, primary actions, and tap targets.
|
|
54
|
+
|
|
55
|
+
Use relative URLs in tests. The shared JSKIT Playwright config owns the base
|
|
56
|
+
URL, server lifecycle, and storage state. When `PLAYWRIGHT_BASE_URL` is set,
|
|
57
|
+
do not start another server. When
|
|
58
|
+
`VIBE64_PLAYWRIGHT_STORAGE_STATE` is supplied, do not print, commit, or retain
|
|
59
|
+
it and do not use local login bypasses. Do not install a browser when the
|
|
60
|
+
environment supplies a managed runner.
|
|
61
|
+
|
|
62
|
+
For a direct localhost app with development auth bypass explicitly enabled,
|
|
63
|
+
use `loginAsExistingUser()` from `@jskit-ai/auth-web/test/playwright`; never
|
|
64
|
+
send the bypass secret through browser globals, query parameters, or client
|
|
65
|
+
environment variables.
|
|
66
|
+
|
|
67
|
+
After a successful UI test, record the verification when the app supports it:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npx jskit app verify-ui \
|
|
71
|
+
--command "<exact successful Playwright command>" \
|
|
72
|
+
--feature "<changed behavior>" \
|
|
73
|
+
--auth-mode <dev-auth-login-as|session-bootstrap>
|
|
74
|
+
```
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: jskit-review
|
|
3
|
-
description: Review or deslop a JSKIT chunk or whole changeset. Use when the user asks to review, deslop, run a JSKIT best-practices audit, or verify a JSKIT feature, chunk, or whole changeset before sign-off.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# JSKIT Review
|
|
7
|
-
|
|
8
|
-
Use this skill for independent review passes on JSKIT app work.
|
|
9
|
-
|
|
10
|
-
Preferred execution mode:
|
|
11
|
-
|
|
12
|
-
- Run this skill in a fresh review agent when the runtime supports delegation.
|
|
13
|
-
- Use the current agent only when delegation is unavailable.
|
|
14
|
-
- The same rule applies to chunk review and whole-changeset review.
|
|
15
|
-
|
|
16
|
-
## Read First
|
|
17
|
-
|
|
18
|
-
Use the user request, current diff, and app-local instructions as the source of truth for the review scope.
|
|
19
|
-
|
|
20
|
-
Read these on demand:
|
|
21
|
-
|
|
22
|
-
- `../../reference/autogen/KERNEL_MAP.md`
|
|
23
|
-
- `../../reference/autogen/README.md`
|
|
24
|
-
- `../../guide/agent/index.md`
|
|
25
|
-
- `../../site/guide/index.md` when compressed guidance is ambiguous
|
|
26
|
-
|
|
27
|
-
## Review target
|
|
28
|
-
|
|
29
|
-
Determine whether the target is:
|
|
30
|
-
|
|
31
|
-
- the current chunk
|
|
32
|
-
- or the whole changeset
|
|
33
|
-
|
|
34
|
-
## Required passes
|
|
35
|
-
|
|
36
|
-
1. Deslop review
|
|
37
|
-
2. JSKIT best-practices review
|
|
38
|
-
3. Material Design and Vuetify review
|
|
39
|
-
4. Verification review
|
|
40
|
-
|
|
41
|
-
## Deslop review
|
|
42
|
-
|
|
43
|
-
Check for:
|
|
44
|
-
|
|
45
|
-
- repeated functions or duplicated local helpers
|
|
46
|
-
- local helpers that should reuse kernel/runtime seams
|
|
47
|
-
- placeholder, fake-complete, or vague UI/copy/code
|
|
48
|
-
- dead code, unused imports/props, TODO-shaped gaps, or accidental abstractions
|
|
49
|
-
- missing loading, empty, error, permission, or ownership states
|
|
50
|
-
- broken route wiring, missing migrations, or incomplete flows
|
|
51
|
-
|
|
52
|
-
## JSKIT review
|
|
53
|
-
|
|
54
|
-
Check for:
|
|
55
|
-
|
|
56
|
-
- missed reuse of existing JSKIT helpers or runtime seams
|
|
57
|
-
- hand code that should have been a package, generator, or scaffold step
|
|
58
|
-
- surface, route, ownership, and migration choices that violate JSKIT conventions
|
|
59
|
-
- metadata that no longer matches actual behavior
|
|
60
|
-
|
|
61
|
-
## Material Design and Vuetify review
|
|
62
|
-
|
|
63
|
-
Check that user-facing screens:
|
|
64
|
-
|
|
65
|
-
- follow Material Design and Vuetify best practices
|
|
66
|
-
- use clear layout hierarchy, spacing, actions, and empty/error states
|
|
67
|
-
- use coherent list, table, and form patterns
|
|
68
|
-
- improve weak screens before sign-off rather than only recording the problem
|
|
69
|
-
|
|
70
|
-
## Verification review
|
|
71
|
-
|
|
72
|
-
Check that verification is appropriate for the target:
|
|
73
|
-
|
|
74
|
-
- focused verification for a chunk
|
|
75
|
-
- broad regression for a whole changeset
|
|
76
|
-
- Playwright for meaningful user-facing flows
|
|
77
|
-
- explicit handling of login/test-auth strategy when auth is required
|
|
78
|
-
|
|
79
|
-
## Output format
|
|
80
|
-
|
|
81
|
-
- Present findings first, ordered by severity, with file references.
|
|
82
|
-
- If there are no findings, say so explicitly.
|
|
83
|
-
- Always finish with:
|
|
84
|
-
- files reviewed
|
|
85
|
-
- commands run
|
|
86
|
-
- anything still unverified
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
interface:
|
|
2
|
-
display_name: "JSKIT Review"
|
|
3
|
-
short_description: "Deslop, audit JSKIT fit, and verify a chunk or changeset"
|
|
4
|
-
default_prompt: "Use $jskit-review to run a deslop pass, JSKIT best-practices audit, and verification review on the current JSKIT chunk or whole changeset."
|