@jskit-ai/agent-docs 0.1.113 → 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.
@@ -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
- _components/CrudAddEditForm.vue
269
- _components/CrudAddEditFormFields.js
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
- _components/CrudAddEditForm.vue
458
- _components/CrudAddEditFormFields.js
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
- ### `_components/CrudAddEditForm.vue`
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
- ### `_components/CrudAddEditFormFields.js`
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 | `_components/CrudAddEditForm.vue` and `CrudAddEditFormFields.js` | This is the generated form field layer |
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 `_components` files under the same route root
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 `_components` files under the same route root
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/agent-docs",
3
- "version": "0.1.113",
3
+ "version": "0.1.114",
4
4
  "description": "Distributed JSKIT agent references, prompts, guides, and generated reference maps.",
5
5
  "type": "module",
6
6
  "files": [
@@ -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
- - `useCrudListScreen({ adapter = 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." } = {})`
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,4 @@
1
+ interface:
2
+ display_name: "JSKIT"
3
+ short_description: "Build, debug, verify, and review JSKIT apps"
4
+ default_prompt: "Use $jskit to build, extend, troubleshoot, verify, or review this JSKIT application."
@@ -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."