@jskit-ai/jskit-catalog 0.1.39 → 0.1.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/catalog/packages.json +625 -425
  2. package/package.json +1 -1
@@ -6,67 +6,78 @@
6
6
  "packages": [
7
7
  {
8
8
  "packageId": "@jskit-ai/assistant",
9
- "version": "0.1.40",
9
+ "version": "0.1.42",
10
10
  "descriptor": {
11
11
  "packageVersion": 1,
12
12
  "packageId": "@jskit-ai/assistant",
13
- "version": "0.1.40",
13
+ "version": "0.1.42",
14
14
  "kind": "generator",
15
- "description": "Generate an assistant page and per-surface assistant config using the shared assistant runtime.",
15
+ "description": "Install assistant runtime/config for one surface and scaffold assistant pages at explicit target files.",
16
16
  "options": {
17
17
  "surface": {
18
18
  "required": true,
19
19
  "inputType": "text",
20
+ "validationType": "enabled-surface-id",
20
21
  "defaultFromConfig": "surfaceDefaultId",
21
22
  "promptLabel": "Assistant surface",
22
- "promptHint": "Enabled surface id where the assistant page will run."
23
+ "promptHint": "Assistant runtime surface id. Used by setup, or selected assistant surface for settings-page.",
24
+ "helpHint": "For setup, this is the runtime surface receiving assistant wiring. For settings-page, this is the assistant runtime configured by that page."
23
25
  },
24
26
  "settings-surface": {
25
27
  "required": true,
26
28
  "inputType": "text",
29
+ "validationType": "enabled-surface-id",
27
30
  "defaultValue": "",
28
- "promptLabel": "Settings surface",
29
- "promptHint": "Enabled surface id whose settings pages will include the assistant settings section."
30
- },
31
- "settings-route-path": {
32
- "required": false,
33
- "inputType": "text",
34
- "defaultValue": "assistant",
35
- "promptLabel": "Settings route path",
36
- "promptHint": "Route segment to use for the assistant settings section page."
31
+ "promptLabel": "Which enabled surface should host the assistant settings UI?",
32
+ "helpHint": "Surface that hosts the settings UI for the selected assistant runtime."
37
33
  },
38
34
  "config-scope": {
39
35
  "required": true,
40
36
  "inputType": "text",
41
37
  "defaultValue": "global",
42
38
  "promptLabel": "Config scope",
43
- "promptHint": "global | workspace. Workspace scope requires both selected surfaces to requireWorkspace=true."
39
+ "promptHint": "global | workspace. Workspace scope requires both setup surfaces to requireWorkspace=true."
44
40
  },
45
- "placement": {
41
+ "name": {
46
42
  "required": false,
47
43
  "inputType": "text",
48
44
  "defaultValue": "",
49
- "promptLabel": "Menu placement",
50
- "promptHint": "Optional host:position target for the assistant page menu entry."
45
+ "promptLabel": "Page label",
46
+ "promptHint": "Optional page link label override for page and settings-page.",
47
+ "helpLabel": "Display label"
51
48
  },
52
- "placement-component-token": {
49
+ "force": {
50
+ "required": false,
51
+ "inputType": "flag",
52
+ "defaultValue": "",
53
+ "promptLabel": "Force overwrite",
54
+ "promptHint": "Overwrite the generated page file if it already exists."
55
+ },
56
+ "link-placement": {
53
57
  "required": false,
54
58
  "inputType": "text",
55
- "defaultValue": "users.web.shell.surface-aware-menu-link-item",
56
- "promptLabel": "Placement component token",
57
- "promptHint": "Menu placement component token for the assistant page entry."
59
+ "defaultValue": "",
60
+ "promptLabel": "Link placement",
61
+ "promptHint": "Optional host:position target for the generated page link placement."
58
62
  },
59
- "menu-label": {
63
+ "link-component-token": {
60
64
  "required": false,
61
65
  "inputType": "text",
62
- "defaultValue": "Assistant",
63
- "promptLabel": "Menu label",
64
- "promptHint": "Menu label for the assistant page entry."
66
+ "defaultValue": "",
67
+ "promptLabel": "Link component token",
68
+ "promptHint": "Optional component token override for the generated page link placement."
65
69
  },
66
- "ai-config-prefix": {
70
+ "link-to": {
67
71
  "required": false,
68
72
  "inputType": "text",
69
73
  "defaultValue": "",
74
+ "promptLabel": "Link to",
75
+ "promptHint": "Optional explicit props.to value for the generated page link placement."
76
+ },
77
+ "ai-config-prefix": {
78
+ "required": false,
79
+ "inputType": "text",
80
+ "defaultFromOptionTemplate": "${option:surface|snake|upper}_ASSISTANT",
70
81
  "promptLabel": "AI config prefix",
71
82
  "promptHint": "Optional env/config prefix override. Defaults to <SURFACE>_ASSISTANT."
72
83
  },
@@ -84,8 +95,7 @@
84
95
  "promptHint": "Leave empty to keep the assistant disabled until you add a key."
85
96
  },
86
97
  "ai-base-url": {
87
- "required": true,
88
- "allowEmpty": true,
98
+ "required": false,
89
99
  "defaultValue": "",
90
100
  "promptLabel": "AI base URL",
91
101
  "promptHint": "Optional provider-compatible base URL override."
@@ -115,11 +125,146 @@
115
125
  }
116
126
  },
117
127
  "metadata": {
128
+ "generatorPrimarySubcommand": "setup",
129
+ "generatorSubcommands": {
130
+ "setup": {
131
+ "description": "Install assistant runtime/config for one target surface without creating pages.",
132
+ "optionNames": [
133
+ "surface",
134
+ "settings-surface",
135
+ "config-scope",
136
+ "ai-config-prefix",
137
+ "ai-provider",
138
+ "ai-api-key",
139
+ "ai-base-url",
140
+ "ai-timeout-ms"
141
+ ],
142
+ "notes": [
143
+ "setup installs runtime/config only. It does not create assistant pages.",
144
+ "--surface selects the assistant runtime surface, and --settings-surface selects the surface that will host its settings UI."
145
+ ],
146
+ "examples": [
147
+ {
148
+ "label": "Common usage",
149
+ "lines": [
150
+ "npx jskit generate assistant setup \\",
151
+ " --surface admin \\",
152
+ " --settings-surface admin \\",
153
+ " --config-scope workspace \\",
154
+ " --ai-api-key \"$OPENAI_API_KEY\""
155
+ ]
156
+ },
157
+ {
158
+ "label": "More advanced usage",
159
+ "lines": [
160
+ "npx jskit generate assistant setup \\",
161
+ " --surface console \\",
162
+ " --settings-surface console \\",
163
+ " --config-scope global \\",
164
+ " --ai-config-prefix CONSOLE_ASSISTANT \\",
165
+ " --ai-provider openai \\",
166
+ " --ai-api-key \"$OPENAI_API_KEY\" \\",
167
+ " --ai-base-url \"http://localhost:11434/v1\" \\",
168
+ " --ai-timeout-ms 60000"
169
+ ]
170
+ }
171
+ ]
172
+ },
173
+ "page": {
174
+ "entrypoint": "src/server/subcommands/page.js",
175
+ "export": "runGeneratorSubcommand",
176
+ "description": "Create an assistant runtime page at an explicit target file relative to src/pages/.",
177
+ "positionalArgs": [
178
+ {
179
+ "name": "target-file",
180
+ "required": true,
181
+ "descriptionKey": "page-target-file"
182
+ }
183
+ ],
184
+ "optionNames": [
185
+ "name",
186
+ "link-placement",
187
+ "link-component-token",
188
+ "link-to",
189
+ "force"
190
+ ],
191
+ "notes": [
192
+ "The target file decides where the page lives.",
193
+ "Page-link placement follows the same inference rules as ui-generator page.",
194
+ "If the target page file already exists, rerun with --force to overwrite it."
195
+ ],
196
+ "examples": [
197
+ {
198
+ "label": "Common usage",
199
+ "lines": [
200
+ "npx jskit generate assistant page \\",
201
+ " admin/assistant/index.vue"
202
+ ]
203
+ },
204
+ {
205
+ "label": "More advanced usage",
206
+ "lines": [
207
+ "npx jskit generate assistant page \\",
208
+ " admin/ops/copilot/index.vue \\",
209
+ " --name \"Copilot\" \\",
210
+ " --link-placement shell-layout:top-right"
211
+ ]
212
+ }
213
+ ]
214
+ },
215
+ "settings-page": {
216
+ "entrypoint": "src/server/subcommands/settingsPage.js",
217
+ "export": "runGeneratorSubcommand",
218
+ "description": "Create an assistant settings page at an explicit target file relative to src/pages/.",
219
+ "positionalArgs": [
220
+ {
221
+ "name": "target-file",
222
+ "required": true,
223
+ "descriptionKey": "page-target-file"
224
+ }
225
+ ],
226
+ "optionNames": [
227
+ "surface",
228
+ "name",
229
+ "link-placement",
230
+ "link-component-token",
231
+ "link-to",
232
+ "force"
233
+ ],
234
+ "requiredOptionNames": [
235
+ "surface"
236
+ ],
237
+ "notes": [
238
+ "The target file decides where the settings page lives.",
239
+ "--surface selects the assistant runtime being configured. It does not place the file.",
240
+ "If the target page file already exists, rerun with --force to overwrite it."
241
+ ],
242
+ "examples": [
243
+ {
244
+ "label": "Common usage",
245
+ "lines": [
246
+ "npx jskit generate assistant settings-page \\",
247
+ " admin/settings/index/assistant/index.vue \\",
248
+ " --surface admin"
249
+ ]
250
+ },
251
+ {
252
+ "label": "More advanced usage",
253
+ "lines": [
254
+ "npx jskit generate assistant settings-page \\",
255
+ " admin/settings/index/app-assistant/index.vue \\",
256
+ " --surface app \\",
257
+ " --name \"App Assistant\""
258
+ ]
259
+ }
260
+ ]
261
+ }
262
+ },
118
263
  "apiSummary": {
119
264
  "surfaces": [
120
265
  {
121
266
  "subpath": "./server/buildTemplateContext",
122
- "summary": "Builds deterministic assistant generator template context values from app surface metadata."
267
+ "summary": "Builds deterministic assistant setup template context values from app surface metadata."
123
268
  }
124
269
  ],
125
270
  "containerTokens": {
@@ -137,88 +282,15 @@
137
282
  "scripts": {}
138
283
  },
139
284
  "procfile": {},
140
- "files": [
141
- {
142
- "from": "templates/src/pages/assistant/index.vue",
143
- "toSurface": "${option:surface|lower}",
144
- "toSurfacePath": "assistant/index.vue",
145
- "reason": "Install generated assistant runtime page.",
146
- "category": "assistant",
147
- "id": "assistant-page-runtime",
148
- "templateContext": {
149
- "entrypoint": "src/server/buildTemplateContext.js",
150
- "export": "buildTemplateContext"
151
- }
152
- },
153
- {
154
- "from": "templates/src/pages/settings/assistant/index.vue",
155
- "toSurface": "${option:settings-surface|lower}",
156
- "toSurfacePath": "settings/${option:settings-route-path|path}/index.vue",
157
- "reason": "Install generated assistant settings section page.",
158
- "category": "assistant",
159
- "id": "assistant-page-settings-standard",
160
- "when": {
161
- "option": "settings-surface",
162
- "notEquals": "admin"
163
- },
164
- "templateContext": {
165
- "entrypoint": "src/server/buildTemplateContext.js",
166
- "export": "buildTemplateContext"
167
- }
168
- },
169
- {
170
- "from": "templates/src/pages/settings/assistant/index.vue",
171
- "toSurface": "${option:settings-surface|lower}",
172
- "toSurfacePath": "workspace/settings/${option:settings-route-path|path}/index.vue",
173
- "reason": "Install generated assistant settings section page.",
174
- "category": "assistant",
175
- "id": "assistant-page-settings-admin",
176
- "when": {
177
- "option": "settings-surface",
178
- "equals": "admin"
179
- },
180
- "templateContext": {
181
- "entrypoint": "src/server/buildTemplateContext.js",
182
- "export": "buildTemplateContext"
183
- }
184
- }
185
- ],
285
+ "files": [],
186
286
  "text": [
187
- {
188
- "op": "append-text",
189
- "file": "src/placement.js",
190
- "position": "bottom",
191
- "skipIfContains": "assistant.generated.menu:${option:surface|lower}",
192
- "value": "\n// assistant.generated.menu:${option:surface|lower}\naddPlacement({\n id: \"assistant.generated.menu.${option:surface|kebab}\",\n host: \"__ASSISTANT_MENU_PLACEMENT_HOST__\",\n position: \"__ASSISTANT_MENU_PLACEMENT_POSITION__\",\n surfaces: [\"${option:surface|lower}\"],\n order: 310,\n componentToken: \"__ASSISTANT_MENU_COMPONENT_TOKEN__\",\n props: {\n label: \"__ASSISTANT_MENU_LABEL__\",\n surface: \"${option:surface|lower}\",\n workspaceSuffix: \"__ASSISTANT_MENU_WORKSPACE_SUFFIX__\",\n nonWorkspaceSuffix: \"__ASSISTANT_MENU_NON_WORKSPACE_SUFFIX__\"\n },\n when: ({ auth }) => Boolean(auth?.authenticated)\n});\n",
193
- "reason": "Append generated assistant runtime menu placement into app-owned placement registry.",
194
- "category": "assistant",
195
- "id": "assistant-placement-menu",
196
- "templateContext": {
197
- "entrypoint": "src/server/buildTemplateContext.js",
198
- "export": "buildTemplateContext"
199
- }
200
- },
201
- {
202
- "op": "append-text",
203
- "file": "src/placement.js",
204
- "position": "bottom",
205
- "skipIfContains": "assistant.generated.settings.menu:${option:surface|lower}",
206
- "value": "\n// assistant.generated.settings.menu:${option:surface|lower}\naddPlacement({\n id: \"assistant.generated.settings.menu.${option:surface|kebab}\",\n host: \"__ASSISTANT_SETTINGS_HOST__\",\n position: \"primary-menu\",\n surfaces: [\"${option:settings-surface|lower}\"],\n order: 250,\n componentToken: \"users.web.shell.surface-aware-menu-link-item\",\n props: {\n label: \"__ASSISTANT_SETTINGS_MENU_LABEL__\",\n surface: \"${option:settings-surface|lower}\",\n workspaceSuffix: \"__ASSISTANT_SETTINGS_MENU_WORKSPACE_SUFFIX__\",\n nonWorkspaceSuffix: \"__ASSISTANT_SETTINGS_MENU_NON_WORKSPACE_SUFFIX__\"\n },\n when: ({ auth }) => Boolean(auth?.authenticated)\n});\n",
207
- "reason": "Append generated assistant settings section menu placement into app-owned settings placements.",
208
- "category": "assistant",
209
- "id": "assistant-settings-menu-placement",
210
- "templateContext": {
211
- "entrypoint": "src/server/buildTemplateContext.js",
212
- "export": "buildTemplateContext"
213
- }
214
- },
215
287
  {
216
288
  "op": "append-text",
217
289
  "file": "config/public.js",
218
290
  "position": "bottom",
219
291
  "skipIfContains": "config.assistantSurfaces.${option:surface|lower} = {",
220
292
  "value": "\nconfig.assistantSurfaces.${option:surface|lower} = {\n settingsSurfaceId: \"__ASSISTANT_SETTINGS_SURFACE_ID__\",\n configScope: \"__ASSISTANT_CONFIG_SCOPE__\"\n};\n",
221
- "reason": "Register the generated assistant surface in public app config.",
293
+ "reason": "Register the assistant runtime surface in public app config.",
222
294
  "category": "assistant",
223
295
  "id": "assistant-public-surface-config",
224
296
  "templateContext": {
@@ -232,7 +304,7 @@
232
304
  "position": "bottom",
233
305
  "skipIfContains": "config.assistantServer.${option:surface|lower} = {",
234
306
  "value": "\nconfig.assistantServer.${option:surface|lower} = {\n aiConfigPrefix: \"__ASSISTANT_AI_CONFIG_PREFIX__\"\n};\n",
235
- "reason": "Register generated assistant server config for the selected surface.",
307
+ "reason": "Register assistant server config for the selected runtime surface.",
236
308
  "category": "assistant",
237
309
  "id": "assistant-server-surface-config",
238
310
  "templateContext": {
@@ -241,18 +313,40 @@
241
313
  }
242
314
  },
243
315
  {
244
- "op": "append-text",
245
316
  "file": ".env",
246
- "position": "bottom",
247
- "skipIfContains": "__ASSISTANT_AI_CONFIG_PREFIX___AI_PROVIDER=",
248
- "value": "\n__ASSISTANT_AI_CONFIG_PREFIX___AI_PROVIDER=${option:ai-provider}\n__ASSISTANT_AI_CONFIG_PREFIX___AI_API_KEY=${option:ai-api-key}\n__ASSISTANT_AI_CONFIG_PREFIX___AI_BASE_URL=${option:ai-base-url}\n__ASSISTANT_AI_CONFIG_PREFIX___AI_TIMEOUT_MS=${option:ai-timeout-ms}\n",
249
- "reason": "Append assistant AI env defaults for the generated surface prefix.",
317
+ "op": "upsert-env",
318
+ "key": "${option:ai-config-prefix}_AI_PROVIDER",
319
+ "value": "${option:ai-provider}",
320
+ "reason": "Configure the assistant AI provider for the selected surface.",
250
321
  "category": "runtime-config",
251
- "id": "assistant-ai-prefixed-env",
252
- "templateContext": {
253
- "entrypoint": "src/server/buildTemplateContext.js",
254
- "export": "buildTemplateContext"
255
- }
322
+ "id": "assistant-ai-provider"
323
+ },
324
+ {
325
+ "file": ".env",
326
+ "op": "upsert-env",
327
+ "key": "${option:ai-config-prefix}_AI_API_KEY",
328
+ "value": "${option:ai-api-key}",
329
+ "reason": "Configure the assistant AI API key for the selected surface.",
330
+ "category": "runtime-config",
331
+ "id": "assistant-ai-api-key"
332
+ },
333
+ {
334
+ "file": ".env",
335
+ "op": "upsert-env",
336
+ "key": "${option:ai-config-prefix}_AI_BASE_URL",
337
+ "value": "${option:ai-base-url}",
338
+ "reason": "Configure the optional assistant AI base URL override for the selected surface.",
339
+ "category": "runtime-config",
340
+ "id": "assistant-ai-base-url"
341
+ },
342
+ {
343
+ "file": ".env",
344
+ "op": "upsert-env",
345
+ "key": "${option:ai-config-prefix}_AI_TIMEOUT_MS",
346
+ "value": "${option:ai-timeout-ms}",
347
+ "reason": "Configure the assistant AI timeout for the selected surface.",
348
+ "category": "runtime-config",
349
+ "id": "assistant-ai-timeout-ms"
256
350
  }
257
351
  ]
258
352
  }
@@ -260,11 +354,11 @@
260
354
  },
261
355
  {
262
356
  "packageId": "@jskit-ai/assistant-core",
263
- "version": "0.1.7",
357
+ "version": "0.1.9",
264
358
  "descriptor": {
265
359
  "packageVersion": 1,
266
360
  "packageId": "@jskit-ai/assistant-core",
267
- "version": "0.1.7",
361
+ "version": "0.1.9",
268
362
  "kind": "runtime",
269
363
  "description": "Reusable assistant client/server/shared primitives without surface-specific routes or settings ownership.",
270
364
  "dependsOn": [
@@ -310,9 +404,9 @@
310
404
  "mutations": {
311
405
  "dependencies": {
312
406
  "runtime": {
313
- "@jskit-ai/http-runtime": "0.1.30",
314
- "@jskit-ai/kernel": "0.1.31",
315
- "@jskit-ai/users-core": "0.1.41",
407
+ "@jskit-ai/http-runtime": "0.1.32",
408
+ "@jskit-ai/kernel": "0.1.33",
409
+ "@jskit-ai/users-core": "0.1.43",
316
410
  "@tanstack/vue-query": "^5.90.5",
317
411
  "dompurify": "^3.3.3",
318
412
  "marked": "^17.0.4",
@@ -333,11 +427,11 @@
333
427
  },
334
428
  {
335
429
  "packageId": "@jskit-ai/assistant-runtime",
336
- "version": "0.1.2",
430
+ "version": "0.1.4",
337
431
  "descriptor": {
338
432
  "packageVersion": 1,
339
433
  "packageId": "@jskit-ai/assistant-runtime",
340
- "version": "0.1.2",
434
+ "version": "0.1.4",
341
435
  "kind": "runtime",
342
436
  "description": "Shared assistant runtime with per-surface assistant registration.",
343
437
  "dependsOn": [
@@ -412,13 +506,13 @@
412
506
  "mutations": {
413
507
  "dependencies": {
414
508
  "runtime": {
415
- "@jskit-ai/assistant-core": "0.1.7",
416
- "@jskit-ai/database-runtime": "0.1.31",
417
- "@jskit-ai/http-runtime": "0.1.30",
418
- "@jskit-ai/kernel": "0.1.31",
419
- "@jskit-ai/shell-web": "0.1.30",
420
- "@jskit-ai/users-core": "0.1.41",
421
- "@jskit-ai/users-web": "0.1.46",
509
+ "@jskit-ai/assistant-core": "0.1.9",
510
+ "@jskit-ai/database-runtime": "0.1.33",
511
+ "@jskit-ai/http-runtime": "0.1.32",
512
+ "@jskit-ai/kernel": "0.1.33",
513
+ "@jskit-ai/shell-web": "0.1.32",
514
+ "@jskit-ai/users-core": "0.1.43",
515
+ "@jskit-ai/users-web": "0.1.48",
422
516
  "@tanstack/vue-query": "^5.90.5",
423
517
  "vuetify": "^4.0.0"
424
518
  },
@@ -475,11 +569,11 @@
475
569
  },
476
570
  {
477
571
  "packageId": "@jskit-ai/auth-core",
478
- "version": "0.1.30",
572
+ "version": "0.1.32",
479
573
  "descriptor": {
480
574
  "packageVersion": 1,
481
575
  "packageId": "@jskit-ai/auth-core",
482
- "version": "0.1.30",
576
+ "version": "0.1.32",
483
577
  "kind": "runtime",
484
578
  "dependsOn": [
485
579
  "@jskit-ai/value-app-config-shared"
@@ -547,7 +641,7 @@
547
641
  "mutations": {
548
642
  "dependencies": {
549
643
  "runtime": {
550
- "@jskit-ai/kernel": "0.1.31",
644
+ "@jskit-ai/kernel": "0.1.33",
551
645
  "@fastify/cookie": "^11.0.2",
552
646
  "@fastify/csrf-protection": "^7.1.0",
553
647
  "@fastify/rate-limit": "^10.3.0"
@@ -565,11 +659,11 @@
565
659
  },
566
660
  {
567
661
  "packageId": "@jskit-ai/auth-provider-supabase-core",
568
- "version": "0.1.30",
662
+ "version": "0.1.32",
569
663
  "descriptor": {
570
664
  "packageVersion": 1,
571
665
  "packageId": "@jskit-ai/auth-provider-supabase-core",
572
- "version": "0.1.30",
666
+ "version": "0.1.32",
573
667
  "kind": "runtime",
574
668
  "options": {
575
669
  "auth-supabase-url": {
@@ -651,8 +745,8 @@
651
745
  "mutations": {
652
746
  "dependencies": {
653
747
  "runtime": {
654
- "@jskit-ai/auth-core": "0.1.30",
655
- "@jskit-ai/kernel": "0.1.31",
748
+ "@jskit-ai/auth-core": "0.1.32",
749
+ "@jskit-ai/kernel": "0.1.33",
656
750
  "dotenv": "^16.4.5",
657
751
  "@supabase/supabase-js": "^2.57.4",
658
752
  "jose": "^6.1.0"
@@ -717,11 +811,11 @@
717
811
  },
718
812
  {
719
813
  "packageId": "@jskit-ai/auth-web",
720
- "version": "0.1.32",
814
+ "version": "0.1.34",
721
815
  "descriptor": {
722
816
  "packageVersion": 1,
723
817
  "packageId": "@jskit-ai/auth-web",
724
- "version": "0.1.32",
818
+ "version": "0.1.34",
725
819
  "kind": "runtime",
726
820
  "description": "Auth web module: Fastify auth routes plus web login/sign-out scaffolds.",
727
821
  "dependsOn": [
@@ -951,10 +1045,10 @@
951
1045
  "@tanstack/vue-query": "5.92.12",
952
1046
  "@mdi/js": "^7.4.47",
953
1047
  "@fastify/type-provider-typebox": "^6.1.0",
954
- "@jskit-ai/auth-core": "0.1.30",
955
- "@jskit-ai/http-runtime": "0.1.30",
956
- "@jskit-ai/kernel": "0.1.31",
957
- "@jskit-ai/shell-web": "0.1.30",
1048
+ "@jskit-ai/auth-core": "0.1.32",
1049
+ "@jskit-ai/http-runtime": "0.1.32",
1050
+ "@jskit-ai/kernel": "0.1.33",
1051
+ "@jskit-ai/shell-web": "0.1.32",
958
1052
  "vuetify": "^4.0.0"
959
1053
  },
960
1054
  "dev": {}
@@ -1024,11 +1118,11 @@
1024
1118
  },
1025
1119
  {
1026
1120
  "packageId": "@jskit-ai/crud-core",
1027
- "version": "0.1.39",
1121
+ "version": "0.1.41",
1028
1122
  "descriptor": {
1029
1123
  "packageVersion": 1,
1030
1124
  "packageId": "@jskit-ai/crud-core",
1031
- "version": "0.1.39",
1125
+ "version": "0.1.41",
1032
1126
  "kind": "runtime",
1033
1127
  "description": "Shared CRUD helpers used by CRUD modules.",
1034
1128
  "dependsOn": [
@@ -1055,7 +1149,7 @@
1055
1149
  "mutations": {
1056
1150
  "dependencies": {
1057
1151
  "runtime": {
1058
- "@jskit-ai/crud-core": "0.1.39"
1152
+ "@jskit-ai/crud-core": "0.1.41"
1059
1153
  },
1060
1154
  "dev": {}
1061
1155
  },
@@ -1069,11 +1163,11 @@
1069
1163
  },
1070
1164
  {
1071
1165
  "packageId": "@jskit-ai/crud-server-generator",
1072
- "version": "0.1.39",
1166
+ "version": "0.1.41",
1073
1167
  "descriptor": {
1074
1168
  "packageVersion": 1,
1075
1169
  "packageId": "@jskit-ai/crud-server-generator",
1076
- "version": "0.1.39",
1170
+ "version": "0.1.41",
1077
1171
  "kind": "generator",
1078
1172
  "description": "CRUD server generator with routes, actions, and persistence scaffolding.",
1079
1173
  "options": {
@@ -1087,6 +1181,7 @@
1087
1181
  "surface": {
1088
1182
  "required": true,
1089
1183
  "inputType": "text",
1184
+ "validationType": "enabled-surface-id",
1090
1185
  "promptLabel": "Target surface",
1091
1186
  "promptHint": "Must match an enabled surface id."
1092
1187
  },
@@ -1117,6 +1212,13 @@
1117
1212
  "defaultValue": "id",
1118
1213
  "promptLabel": "Id column",
1119
1214
  "promptHint": "Primary key column used by CRUD endpoints (default: id)."
1215
+ },
1216
+ "force": {
1217
+ "required": false,
1218
+ "inputType": "flag",
1219
+ "defaultValue": "",
1220
+ "promptLabel": "Force overwrite",
1221
+ "promptHint": "Overwrite generated scaffold files if the namespace package directory already exists."
1120
1222
  }
1121
1223
  },
1122
1224
  "optionPolicies": {
@@ -1164,8 +1266,14 @@
1164
1266
  "ownership-filter",
1165
1267
  "table-name",
1166
1268
  "id-column",
1167
- "directory-prefix"
1168
- ]
1269
+ "directory-prefix",
1270
+ "force"
1271
+ ],
1272
+ "createTarget": {
1273
+ "pathTemplate": "packages/${option:namespace|kebab}",
1274
+ "label": "package directory",
1275
+ "allowExistingEmptyDirectory": false
1276
+ }
1169
1277
  },
1170
1278
  "scaffold-field": {
1171
1279
  "entrypoint": "src/server/subcommands/addField.js",
@@ -1208,13 +1316,13 @@
1208
1316
  "mutations": {
1209
1317
  "dependencies": {
1210
1318
  "runtime": {
1211
- "@jskit-ai/auth-core": "0.1.30",
1212
- "@jskit-ai/crud-core": "0.1.39",
1213
- "@jskit-ai/database-runtime": "0.1.31",
1214
- "@jskit-ai/http-runtime": "0.1.30",
1215
- "@jskit-ai/kernel": "0.1.31",
1216
- "@jskit-ai/realtime": "0.1.30",
1217
- "@jskit-ai/users-core": "0.1.41",
1319
+ "@jskit-ai/auth-core": "0.1.32",
1320
+ "@jskit-ai/crud-core": "0.1.41",
1321
+ "@jskit-ai/database-runtime": "0.1.33",
1322
+ "@jskit-ai/http-runtime": "0.1.32",
1323
+ "@jskit-ai/kernel": "0.1.33",
1324
+ "@jskit-ai/realtime": "0.1.32",
1325
+ "@jskit-ai/users-core": "0.1.43",
1218
1326
  "@local/${option:namespace|kebab}": "file:packages/${option:namespace|kebab}",
1219
1327
  "typebox": "^1.0.81"
1220
1328
  },
@@ -1277,6 +1385,17 @@
1277
1385
  "category": "crud",
1278
1386
  "id": "crud-local-package-server-action-ids-${option:namespace|snake}"
1279
1387
  },
1388
+ {
1389
+ "from": "templates/src/local-package/server/listConfig.js",
1390
+ "to": "packages/${option:namespace|kebab}/src/server/listConfig.js",
1391
+ "reason": "Install app-local CRUD list configuration.",
1392
+ "category": "crud",
1393
+ "id": "crud-local-package-server-list-config-${option:namespace|snake}",
1394
+ "templateContext": {
1395
+ "entrypoint": "src/server/buildTemplateContext.js",
1396
+ "export": "buildTemplateContext"
1397
+ }
1398
+ },
1280
1399
  {
1281
1400
  "from": "templates/src/local-package/server/registerRoutes.js",
1282
1401
  "to": "packages/${option:namespace|kebab}/src/server/registerRoutes.js",
@@ -1338,26 +1457,21 @@
1338
1457
  },
1339
1458
  {
1340
1459
  "packageId": "@jskit-ai/crud-ui-generator",
1341
- "version": "0.1.14",
1460
+ "version": "0.1.16",
1342
1461
  "descriptor": {
1343
1462
  "packageVersion": 1,
1344
1463
  "packageId": "@jskit-ai/crud-ui-generator",
1345
- "version": "0.1.14",
1464
+ "version": "0.1.16",
1346
1465
  "kind": "generator",
1347
- "description": "Generate app-local CRUD UI scaffolds from resource validators.",
1466
+ "description": "Generate CRUD route trees from resource validators at an explicit route root relative to src/pages/.",
1348
1467
  "options": {
1349
- "namespace": {
1468
+ "target-root": {
1350
1469
  "required": true,
1351
1470
  "inputType": "text",
1352
1471
  "defaultValue": "",
1353
- "promptLabel": "UI namespace",
1354
- "promptHint": "Required slug (example: contacts-alt, customers-ui, tickets-view)."
1355
- },
1356
- "surface": {
1357
- "required": true,
1358
- "inputType": "text",
1359
- "promptLabel": "Target surface",
1360
- "promptHint": "Must match an enabled surface id."
1472
+ "normalizationType": "pages-relative-target-root",
1473
+ "promptLabel": "Target route root",
1474
+ "promptHint": "Explicit route root relative to src/pages/ (example: admin/catalog/products)."
1361
1475
  },
1362
1476
  "resource-file": {
1363
1477
  "required": true,
@@ -1367,11 +1481,11 @@
1367
1481
  "promptHint": "Relative path from app root to the resource module."
1368
1482
  },
1369
1483
  "operations": {
1370
- "required": true,
1484
+ "required": false,
1371
1485
  "inputType": "text",
1372
- "defaultValue": "",
1486
+ "defaultValue": "list,view,new,edit",
1373
1487
  "promptLabel": "Operations",
1374
- "promptHint": "Required comma-separated values from: list, view, new, edit."
1488
+ "promptHint": "Optional comma-separated values from: list, view, new, edit. Defaults to all four."
1375
1489
  },
1376
1490
  "display-fields": {
1377
1491
  "required": false,
@@ -1380,27 +1494,6 @@
1380
1494
  "promptLabel": "Display fields",
1381
1495
  "promptHint": "Optional comma-separated field keys to render (must exist in selected operation schemas)."
1382
1496
  },
1383
- "api-path": {
1384
- "required": false,
1385
- "inputType": "text",
1386
- "defaultFromOptionTemplate": "/${option:namespace|kebab}",
1387
- "promptLabel": "API path",
1388
- "promptHint": "Base API path without trailing id (defaults to /<namespace>, example: /contacts)."
1389
- },
1390
- "route-path": {
1391
- "required": false,
1392
- "inputType": "text",
1393
- "defaultFromOptionTemplate": "${option:namespace|kebab}",
1394
- "promptLabel": "Route path",
1395
- "promptHint": "List route path under the target surface (defaults to <namespace>, example: contacts)."
1396
- },
1397
- "container": {
1398
- "required": false,
1399
- "inputType": "text",
1400
- "defaultValue": "",
1401
- "promptLabel": "Container host",
1402
- "promptHint": "Optional container host slug (example: practice). Routes are generated under this prefix and list menu placement defaults to <container>:sub-pages."
1403
- },
1404
1497
  "id-param": {
1405
1498
  "required": false,
1406
1499
  "inputType": "text",
@@ -1408,33 +1501,26 @@
1408
1501
  "promptLabel": "Route id param",
1409
1502
  "promptHint": "Route param used by view and edit pages (default: recordId)."
1410
1503
  },
1411
- "directory-prefix": {
1504
+ "force": {
1412
1505
  "required": false,
1413
- "inputType": "text",
1414
- "defaultValue": "",
1415
- "promptLabel": "Page directory prefix",
1416
- "promptHint": "Optional subpath under the selected surface pages root (example: crm or ops/team-a)."
1417
- },
1418
- "placement": {
1419
- "required": false,
1420
- "inputType": "text",
1506
+ "inputType": "flag",
1421
1507
  "defaultValue": "",
1422
- "promptLabel": "Menu placement",
1423
- "promptHint": "Optional host:position target (defaults to ShellLayout default outlet)."
1508
+ "promptLabel": "Force overwrite",
1509
+ "promptHint": "Overwrite generated CRUD files if the target root already exists."
1424
1510
  },
1425
- "placement-component-token": {
1511
+ "link-placement": {
1426
1512
  "required": false,
1427
1513
  "inputType": "text",
1428
1514
  "defaultValue": "",
1429
- "promptLabel": "Placement component token",
1430
- "promptHint": "Optional component token override for generated menu placement. Use local.main.ui.tab-link-item for routed tab links (auto-provisions src/components/TabLinkItem.vue + MainClientProvider registration)."
1515
+ "promptLabel": "Link placement",
1516
+ "promptHint": "Optional host:position override for the generated list-page link placement."
1431
1517
  },
1432
- "placement-to": {
1518
+ "namespace": {
1433
1519
  "required": false,
1434
1520
  "inputType": "text",
1435
1521
  "defaultValue": "",
1436
- "promptLabel": "Placement to",
1437
- "promptHint": "Optional explicit props.to value for generated menu placement (example: ./pets). Required when adding placement for dynamic directory-prefix/route-path values."
1522
+ "promptLabel": "Namespace override",
1523
+ "promptHint": "Optional CRUD namespace override when the resource export does not expose resource.resource."
1438
1524
  }
1439
1525
  },
1440
1526
  "dependsOn": [],
@@ -1455,6 +1541,63 @@
1455
1541
  "metadata": {
1456
1542
  "generatorPrimarySubcommand": "crud",
1457
1543
  "generatorSubcommands": {
1544
+ "crud": {
1545
+ "description": "Create CRUD pages at an explicit route root relative to src/pages/.",
1546
+ "longDescription": [
1547
+ "CRUD generation follows the same page-placement model as `ui-generator page`.",
1548
+ "That means the generated list page link uses the same nearest-parent-host inference, tab-link inference, and relative `props.to` inference as a normal generated page. If you want the detailed host behavior, read `jskit generate ui-generator page help`."
1549
+ ],
1550
+ "positionalArgs": [
1551
+ {
1552
+ "name": "target-root",
1553
+ "required": true,
1554
+ "descriptionKey": "crud-target-root"
1555
+ }
1556
+ ],
1557
+ "optionNames": [
1558
+ "resource-file",
1559
+ "operations",
1560
+ "display-fields",
1561
+ "id-param",
1562
+ "link-placement",
1563
+ "namespace",
1564
+ "force"
1565
+ ],
1566
+ "requiredOptionNames": [
1567
+ "resource-file"
1568
+ ],
1569
+ "createTarget": {
1570
+ "pathTemplate": "src/pages/${option:target-root|trim}",
1571
+ "label": "target root",
1572
+ "allowExistingEmptyDirectory": true
1573
+ },
1574
+ "notes": [
1575
+ "The target root is the real route root relative to src/pages/.... JSKIT derives the surface and route from that path.",
1576
+ "Operations default to list,view,new,edit. For list-page placement behavior, use the same mental model as ui-generator page.",
1577
+ "If the target root already exists and is not empty, rerun with --force to overwrite generated files."
1578
+ ],
1579
+ "examples": [
1580
+ {
1581
+ "label": "Common usage",
1582
+ "lines": [
1583
+ "npx jskit generate crud-ui-generator crud \\",
1584
+ " admin/catalog/index/products \\",
1585
+ " --resource-file packages/products/src/shared/productResource.js"
1586
+ ]
1587
+ },
1588
+ {
1589
+ "label": "More advanced usage",
1590
+ "lines": [
1591
+ "npx jskit generate crud-ui-generator crud \\",
1592
+ " admin/customers/[customerId]/index/pets \\",
1593
+ " --resource-file packages/pets/src/shared/petResource.js \\",
1594
+ " --id-param petId \\",
1595
+ " --display-fields name,breedId,sex \\",
1596
+ " --force"
1597
+ ]
1598
+ }
1599
+ ]
1600
+ },
1458
1601
  "field": {
1459
1602
  "entrypoint": "src/server/subcommands/addField.js",
1460
1603
  "export": "runGeneratorSubcommand"
@@ -1464,7 +1607,7 @@
1464
1607
  "surfaces": [
1465
1608
  {
1466
1609
  "subpath": "./server/buildTemplateContext",
1467
- "summary": "Builds deterministic template context values from selected resource operation validators."
1610
+ "summary": "Builds deterministic CRUD UI template context values from the explicit route root and resource validators."
1468
1611
  }
1469
1612
  ],
1470
1613
  "containerTokens": {
@@ -1476,7 +1619,7 @@
1476
1619
  "mutations": {
1477
1620
  "dependencies": {
1478
1621
  "runtime": {
1479
- "@jskit-ai/users-web": "0.1.46"
1622
+ "@jskit-ai/users-web": "0.1.48"
1480
1623
  },
1481
1624
  "dev": {}
1482
1625
  },
@@ -1487,11 +1630,10 @@
1487
1630
  "files": [
1488
1631
  {
1489
1632
  "from": "templates/src/pages/admin/ui-generator/ListElement.vue",
1490
- "toSurface": "${option:surface|lower}",
1491
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:container|pathprefix}${option:route-path|path}/index.vue",
1633
+ "to": "src/pages/${option:target-root|trim}/index.vue",
1492
1634
  "reason": "Install generated list page.",
1493
- "category": "ui-generator",
1494
- "id": "ui-generator-page-list-${option:namespace|snake}",
1635
+ "category": "crud-ui-generator",
1636
+ "id": "crud-ui-page-list-${option:target-root|snake}",
1495
1637
  "templateContext": {
1496
1638
  "entrypoint": "src/server/buildTemplateContext.js",
1497
1639
  "export": "buildUiTemplateContext"
@@ -1505,11 +1647,10 @@
1505
1647
  },
1506
1648
  {
1507
1649
  "from": "templates/src/pages/admin/ui-generator/ViewElement.vue",
1508
- "toSurface": "${option:surface|lower}",
1509
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:container|pathprefix}${option:route-path|path}/[${option:id-param|trim}]/index.vue",
1650
+ "to": "src/pages/${option:target-root|trim}/[${option:id-param|trim}]/index.vue",
1510
1651
  "reason": "Install generated view page.",
1511
- "category": "ui-generator",
1512
- "id": "ui-generator-page-view-${option:namespace|snake}",
1652
+ "category": "crud-ui-generator",
1653
+ "id": "crud-ui-page-view-${option:target-root|snake}",
1513
1654
  "templateContext": {
1514
1655
  "entrypoint": "src/server/buildTemplateContext.js",
1515
1656
  "export": "buildUiTemplateContext"
@@ -1523,11 +1664,10 @@
1523
1664
  },
1524
1665
  {
1525
1666
  "from": "templates/src/pages/admin/ui-generator/NewWrapperElement.vue",
1526
- "toSurface": "${option:surface|lower}",
1527
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:container|pathprefix}${option:route-path|path}/new.vue",
1667
+ "to": "src/pages/${option:target-root|trim}/new.vue",
1528
1668
  "reason": "Install generated new page.",
1529
- "category": "ui-generator",
1530
- "id": "ui-generator-page-new-${option:namespace|snake}",
1669
+ "category": "crud-ui-generator",
1670
+ "id": "crud-ui-page-new-${option:target-root|snake}",
1531
1671
  "templateContext": {
1532
1672
  "entrypoint": "src/server/buildTemplateContext.js",
1533
1673
  "export": "buildUiTemplateContext"
@@ -1551,11 +1691,10 @@
1551
1691
  },
1552
1692
  {
1553
1693
  "from": "templates/src/pages/admin/ui-generator/EditWrapperElement.vue",
1554
- "toSurface": "${option:surface|lower}",
1555
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:container|pathprefix}${option:route-path|path}/[${option:id-param|trim}]/edit.vue",
1694
+ "to": "src/pages/${option:target-root|trim}/[${option:id-param|trim}]/edit.vue",
1556
1695
  "reason": "Install generated edit page.",
1557
- "category": "ui-generator",
1558
- "id": "ui-generator-page-edit-${option:namespace|snake}",
1696
+ "category": "crud-ui-generator",
1697
+ "id": "crud-ui-page-edit-${option:target-root|snake}",
1559
1698
  "templateContext": {
1560
1699
  "entrypoint": "src/server/buildTemplateContext.js",
1561
1700
  "export": "buildUiTemplateContext"
@@ -1579,11 +1718,10 @@
1579
1718
  },
1580
1719
  {
1581
1720
  "from": "templates/src/pages/admin/ui-generator/AddEditForm.vue",
1582
- "toSurface": "${option:surface|lower}",
1583
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:container|pathprefix}${option:route-path|path}/_components/${option:namespace|singular|pascal|default(Record)}AddEditForm.vue",
1721
+ "to": "src/pages/${option:target-root|trim}/_components/CrudAddEditForm.vue",
1584
1722
  "reason": "Install generated shared add/edit form component.",
1585
- "category": "ui-generator",
1586
- "id": "ui-generator-page-add-edit-form-${option:namespace|snake}",
1723
+ "category": "crud-ui-generator",
1724
+ "id": "crud-ui-page-add-edit-form-${option:target-root|snake}",
1587
1725
  "templateContext": {
1588
1726
  "entrypoint": "src/server/buildTemplateContext.js",
1589
1727
  "export": "buildUiTemplateContext"
@@ -1607,11 +1745,10 @@
1607
1745
  },
1608
1746
  {
1609
1747
  "from": "templates/src/pages/admin/ui-generator/AddEditFormFields.js",
1610
- "toSurface": "${option:surface|lower}",
1611
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:container|pathprefix}${option:route-path|path}/_components/${option:namespace|singular|pascal|default(Record)}AddEditFormFields.js",
1748
+ "to": "src/pages/${option:target-root|trim}/_components/CrudAddEditFormFields.js",
1612
1749
  "reason": "Install generated shared add/edit form field definitions.",
1613
- "category": "ui-generator",
1614
- "id": "ui-generator-page-add-edit-form-fields-${option:namespace|snake}",
1750
+ "category": "crud-ui-generator",
1751
+ "id": "crud-ui-page-add-edit-form-fields-${option:target-root|snake}",
1615
1752
  "templateContext": {
1616
1753
  "entrypoint": "src/server/buildTemplateContext.js",
1617
1754
  "export": "buildUiTemplateContext"
@@ -1635,11 +1772,10 @@
1635
1772
  },
1636
1773
  {
1637
1774
  "from": "templates/src/pages/admin/ui-generator/NewElement.vue",
1638
- "toSurface": "${option:surface|lower}",
1639
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:container|pathprefix}${option:route-path|path}/new.vue",
1775
+ "to": "src/pages/${option:target-root|trim}/new.vue",
1640
1776
  "reason": "Install generated new page.",
1641
- "category": "ui-generator",
1642
- "id": "ui-generator-page-new-standalone-${option:namespace|snake}",
1777
+ "category": "crud-ui-generator",
1778
+ "id": "crud-ui-page-new-standalone-${option:target-root|snake}",
1643
1779
  "templateContext": {
1644
1780
  "entrypoint": "src/server/buildTemplateContext.js",
1645
1781
  "export": "buildUiTemplateContext"
@@ -1663,11 +1799,10 @@
1663
1799
  },
1664
1800
  {
1665
1801
  "from": "templates/src/pages/admin/ui-generator/EditElement.vue",
1666
- "toSurface": "${option:surface|lower}",
1667
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:container|pathprefix}${option:route-path|path}/[${option:id-param|trim}]/edit.vue",
1802
+ "to": "src/pages/${option:target-root|trim}/[${option:id-param|trim}]/edit.vue",
1668
1803
  "reason": "Install generated edit page.",
1669
- "category": "ui-generator",
1670
- "id": "ui-generator-page-edit-standalone-${option:namespace|snake}",
1804
+ "category": "crud-ui-generator",
1805
+ "id": "crud-ui-page-edit-standalone-${option:target-root|snake}",
1671
1806
  "templateContext": {
1672
1807
  "entrypoint": "src/server/buildTemplateContext.js",
1673
1808
  "export": "buildUiTemplateContext"
@@ -1695,51 +1830,19 @@
1695
1830
  "op": "append-text",
1696
1831
  "file": "src/placement.js",
1697
1832
  "position": "bottom",
1698
- "skipIfContains": "jskit:ui-generator.menu:${option:namespace|kebab}:${option:directory-prefix|path}:${option:container|path}:${option:route-path|path}",
1699
- "value": "\n// jskit:ui-generator.menu:${option:namespace|kebab}:${option:directory-prefix|path}:${option:container|path}:${option:route-path|path}\n{\n addPlacement({\n id: \"ui-generator.${option:namespace|kebab}.menu\",\n host: \"__JSKIT_UI_MENU_PLACEMENT_HOST__\",\n position: \"__JSKIT_UI_MENU_PLACEMENT_POSITION__\",\n surfaces: [\"${option:surface|lower}\"],\n order: 155,\n componentToken: \"__JSKIT_UI_MENU_COMPONENT_TOKEN__\",\n props: {\n label: \"${option:namespace|plural|pascal}\",\n surface: \"${option:surface|lower}\",\n workspaceSuffix: \"__JSKIT_UI_MENU_WORKSPACE_SUFFIX__\",\n nonWorkspaceSuffix: \"__JSKIT_UI_MENU_NON_WORKSPACE_SUFFIX__\",\n__JSKIT_UI_MENU_TO_PROP_LINE__ },\n when: ({ auth }) => Boolean(auth?.authenticated)\n });\n}\n",
1700
- "reason": "Append generated UI menu placement.",
1701
- "category": "ui-generator",
1702
- "id": "ui-generator-placement-menu",
1833
+ "skipIfContains": "__JSKIT_UI_MENU_MARKER__",
1834
+ "value": "\n// __JSKIT_UI_MENU_MARKER__\n{\n addPlacement({\n id: \"__JSKIT_UI_MENU_PLACEMENT_ID__\",\n host: \"__JSKIT_UI_MENU_PLACEMENT_HOST__\",\n position: \"__JSKIT_UI_MENU_PLACEMENT_POSITION__\",\n surfaces: [\"__JSKIT_UI_SURFACE_ID__\"],\n order: 155,\n componentToken: \"__JSKIT_UI_MENU_COMPONENT_TOKEN__\",\n props: {\n label: \"__JSKIT_UI_MENU_LABEL__\",\n surface: \"__JSKIT_UI_SURFACE_ID__\",\n workspaceSuffix: \"__JSKIT_UI_MENU_WORKSPACE_SUFFIX__\",\n nonWorkspaceSuffix: \"__JSKIT_UI_MENU_NON_WORKSPACE_SUFFIX__\",\n__JSKIT_UI_MENU_TO_PROP_LINE__ },\n when: ({ auth }) => Boolean(auth?.authenticated)\n });\n}\n",
1835
+ "reason": "Append generated CRUD list-page placement.",
1836
+ "category": "crud-ui-generator",
1837
+ "id": "crud-ui-placement-menu",
1703
1838
  "templateContext": {
1704
1839
  "entrypoint": "src/server/buildTemplateContext.js",
1705
1840
  "export": "buildUiTemplateContext"
1706
1841
  },
1707
1842
  "when": {
1708
- "all": [
1709
- {
1710
- "option": "operations",
1711
- "in": [
1712
- "list"
1713
- ]
1714
- },
1715
- {
1716
- "any": [
1717
- {
1718
- "all": [
1719
- {
1720
- "option": "route-path",
1721
- "notContains": "["
1722
- },
1723
- {
1724
- "option": "directory-prefix",
1725
- "notContains": "["
1726
- }
1727
- ]
1728
- },
1729
- {
1730
- "all": [
1731
- {
1732
- "option": "placement",
1733
- "contains": ":"
1734
- },
1735
- {
1736
- "option": "placement-to",
1737
- "notEquals": ""
1738
- }
1739
- ]
1740
- }
1741
- ]
1742
- }
1843
+ "option": "operations",
1844
+ "in": [
1845
+ "list"
1743
1846
  ]
1744
1847
  }
1745
1848
  }
@@ -1749,11 +1852,11 @@
1749
1852
  },
1750
1853
  {
1751
1854
  "packageId": "@jskit-ai/database-runtime",
1752
- "version": "0.1.31",
1855
+ "version": "0.1.33",
1753
1856
  "descriptor": {
1754
1857
  "packageVersion": 1,
1755
1858
  "packageId": "@jskit-ai/database-runtime",
1756
- "version": "0.1.31",
1859
+ "version": "0.1.33",
1757
1860
  "kind": "runtime",
1758
1861
  "dependsOn": [
1759
1862
  "@jskit-ai/kernel"
@@ -1810,7 +1913,7 @@
1810
1913
  "mutations": {
1811
1914
  "dependencies": {
1812
1915
  "runtime": {
1813
- "@jskit-ai/kernel": "0.1.31",
1916
+ "@jskit-ai/kernel": "0.1.33",
1814
1917
  "dotenv": "^16.4.5",
1815
1918
  "knex": "^3.1.0"
1816
1919
  },
@@ -1845,11 +1948,11 @@
1845
1948
  },
1846
1949
  {
1847
1950
  "packageId": "@jskit-ai/database-runtime-mysql",
1848
- "version": "0.1.30",
1951
+ "version": "0.1.32",
1849
1952
  "descriptor": {
1850
1953
  "packageVersion": 1,
1851
1954
  "packageId": "@jskit-ai/database-runtime-mysql",
1852
- "version": "0.1.30",
1955
+ "version": "0.1.32",
1853
1956
  "kind": "runtime",
1854
1957
  "options": {
1855
1958
  "db-host": {
@@ -1939,7 +2042,7 @@
1939
2042
  "mutations": {
1940
2043
  "dependencies": {
1941
2044
  "runtime": {
1942
- "@jskit-ai/database-runtime": "0.1.31",
2045
+ "@jskit-ai/database-runtime": "0.1.33",
1943
2046
  "mysql2": "^3.11.2"
1944
2047
  },
1945
2048
  "dev": {}
@@ -2010,11 +2113,11 @@
2010
2113
  },
2011
2114
  {
2012
2115
  "packageId": "@jskit-ai/database-runtime-postgres",
2013
- "version": "0.1.30",
2116
+ "version": "0.1.32",
2014
2117
  "descriptor": {
2015
2118
  "packageVersion": 1,
2016
2119
  "packageId": "@jskit-ai/database-runtime-postgres",
2017
- "version": "0.1.30",
2120
+ "version": "0.1.32",
2018
2121
  "kind": "runtime",
2019
2122
  "options": {
2020
2123
  "db-host": {
@@ -2104,7 +2207,7 @@
2104
2207
  "mutations": {
2105
2208
  "dependencies": {
2106
2209
  "runtime": {
2107
- "@jskit-ai/database-runtime": "0.1.31",
2210
+ "@jskit-ai/database-runtime": "0.1.33",
2108
2211
  "pg": "^8.13.1"
2109
2212
  },
2110
2213
  "dev": {}
@@ -2175,11 +2278,11 @@
2175
2278
  },
2176
2279
  {
2177
2280
  "packageId": "@jskit-ai/http-runtime",
2178
- "version": "0.1.30",
2281
+ "version": "0.1.32",
2179
2282
  "descriptor": {
2180
2283
  "packageVersion": 1,
2181
2284
  "packageId": "@jskit-ai/http-runtime",
2182
- "version": "0.1.30",
2285
+ "version": "0.1.32",
2183
2286
  "kind": "runtime",
2184
2287
  "dependsOn": [],
2185
2288
  "capabilities": {
@@ -2245,7 +2348,7 @@
2245
2348
  "mutations": {
2246
2349
  "dependencies": {
2247
2350
  "runtime": {
2248
- "@jskit-ai/kernel": "0.1.31",
2351
+ "@jskit-ai/kernel": "0.1.33",
2249
2352
  "@fastify/type-provider-typebox": "^6.1.0",
2250
2353
  "typebox": "^1.0.81"
2251
2354
  },
@@ -2261,11 +2364,11 @@
2261
2364
  },
2262
2365
  {
2263
2366
  "packageId": "@jskit-ai/realtime",
2264
- "version": "0.1.30",
2367
+ "version": "0.1.32",
2265
2368
  "descriptor": {
2266
2369
  "packageVersion": 1,
2267
2370
  "packageId": "@jskit-ai/realtime",
2268
- "version": "0.1.30",
2371
+ "version": "0.1.32",
2269
2372
  "kind": "runtime",
2270
2373
  "description": "Thin, generic realtime runtime wrappers for socket.io server and client.",
2271
2374
  "options": {
@@ -2361,7 +2464,7 @@
2361
2464
  "mutations": {
2362
2465
  "dependencies": {
2363
2466
  "runtime": {
2364
- "@jskit-ai/kernel": "0.1.31",
2467
+ "@jskit-ai/kernel": "0.1.33",
2365
2468
  "@socket.io/redis-adapter": "^8.3.0",
2366
2469
  "redis": "^5.8.2",
2367
2470
  "socket.io": "^4.8.3",
@@ -2410,11 +2513,11 @@
2410
2513
  },
2411
2514
  {
2412
2515
  "packageId": "@jskit-ai/shell-web",
2413
- "version": "0.1.30",
2516
+ "version": "0.1.32",
2414
2517
  "descriptor": {
2415
2518
  "packageVersion": 1,
2416
2519
  "packageId": "@jskit-ai/shell-web",
2417
- "version": "0.1.30",
2520
+ "version": "0.1.32",
2418
2521
  "kind": "runtime",
2419
2522
  "description": "Web shell layout runtime with outlet-based placement contributions.",
2420
2523
  "dependsOn": [],
@@ -2516,7 +2619,7 @@
2516
2619
  "dependencies": {
2517
2620
  "runtime": {
2518
2621
  "@tanstack/vue-query": "^5.90.5",
2519
- "@jskit-ai/kernel": "0.1.31",
2622
+ "@jskit-ai/kernel": "0.1.33",
2520
2623
  "vuetify": "^4.0.0"
2521
2624
  },
2522
2625
  "dev": {}
@@ -2613,11 +2716,11 @@
2613
2716
  },
2614
2717
  {
2615
2718
  "packageId": "@jskit-ai/storage-runtime",
2616
- "version": "0.1.30",
2719
+ "version": "0.1.32",
2617
2720
  "descriptor": {
2618
2721
  "packageVersion": 1,
2619
2722
  "packageId": "@jskit-ai/storage-runtime",
2620
- "version": "0.1.30",
2723
+ "version": "0.1.32",
2621
2724
  "kind": "runtime",
2622
2725
  "dependsOn": [
2623
2726
  "@jskit-ai/kernel"
@@ -2666,7 +2769,7 @@
2666
2769
  "mutations": {
2667
2770
  "dependencies": {
2668
2771
  "runtime": {
2669
- "@jskit-ai/kernel": "0.1.31",
2772
+ "@jskit-ai/kernel": "0.1.33",
2670
2773
  "unstorage": "^1.17.3"
2671
2774
  },
2672
2775
  "dev": {}
@@ -2682,97 +2785,91 @@
2682
2785
  },
2683
2786
  {
2684
2787
  "packageId": "@jskit-ai/ui-generator",
2685
- "version": "0.1.14",
2788
+ "version": "0.1.16",
2686
2789
  "descriptor": {
2687
2790
  "packageVersion": 1,
2688
2791
  "packageId": "@jskit-ai/ui-generator",
2689
- "version": "0.1.14",
2792
+ "version": "0.1.16",
2690
2793
  "kind": "generator",
2691
- "description": "Generate app-local non-CRUD UI pages and outlet elements.",
2794
+ "description": "Create non-CRUD pages, reusable UI elements, and subpage hosts.",
2692
2795
  "options": {
2693
2796
  "name": {
2694
- "required": true,
2797
+ "required": false,
2695
2798
  "inputType": "text",
2696
2799
  "defaultValue": "",
2697
- "promptLabel": "Element name",
2698
- "promptHint": "Display name and route slug source (example: Reports Dashboard)."
2800
+ "promptLabel": "Display label",
2801
+ "promptHint": "Display label used for generated page links and named UI elements. For page, if omitted, it is derived from the target file path."
2699
2802
  },
2700
2803
  "surface": {
2701
- "required": true,
2804
+ "required": false,
2702
2805
  "inputType": "text",
2806
+ "validationType": "enabled-surface-id",
2703
2807
  "defaultFromConfig": "surfaceDefaultId",
2704
2808
  "promptLabel": "Target surface",
2705
- "promptHint": "Defaults to config.public.surfaceDefaultId. Must match an enabled surface id."
2809
+ "promptHint": "Used by the placed-element subcommand. Must match an enabled surface id."
2706
2810
  },
2707
2811
  "path": {
2708
2812
  "required": false,
2709
2813
  "inputType": "text",
2710
2814
  "defaultValue": "src/components",
2711
2815
  "promptLabel": "Component path",
2712
- "promptHint": "Component directory relative to app root (used by element subcommand)."
2713
- },
2714
- "directory-prefix": {
2715
- "required": false,
2716
- "inputType": "text",
2717
- "defaultValue": "",
2718
- "promptLabel": "Page directory prefix",
2719
- "promptHint": "Optional subpath under the selected surface pages root (example: crm or ops/team-a)."
2816
+ "promptHint": "Component directory relative to app root (used by placed-element and add-subpages support scaffold)."
2720
2817
  },
2721
- "route-path": {
2818
+ "force": {
2722
2819
  "required": false,
2723
- "inputType": "text",
2820
+ "inputType": "flag",
2724
2821
  "defaultValue": "",
2725
- "promptLabel": "Route path",
2726
- "promptHint": "Optional explicit container route path (example: contact-tools or contacts/[contactId]). Defaults to --name."
2822
+ "promptLabel": "Force overwrite",
2823
+ "promptHint": "Overwrite the generated file if it already exists."
2727
2824
  },
2728
2825
  "placement": {
2729
2826
  "required": false,
2730
2827
  "inputType": "text",
2731
2828
  "defaultValue": "",
2732
2829
  "promptLabel": "Placement target",
2733
- "promptHint": "Optional host:position target (defaults to app ShellOutlet default target)."
2830
+ "promptHint": "Optional host:position target for placed-element placement (defaults to shell-layout:top-right)."
2734
2831
  },
2735
- "placement-component-token": {
2832
+ "link-placement": {
2736
2833
  "required": false,
2737
2834
  "inputType": "text",
2738
2835
  "defaultValue": "",
2739
- "promptLabel": "Placement component token",
2740
- "promptHint": "Optional component token override for generated menu placement (example: local.main.ui.tab-link-item)."
2836
+ "promptLabel": "Link placement",
2837
+ "promptHint": "Optional host:position target for the generated page link placement."
2741
2838
  },
2742
- "placement-to": {
2839
+ "link-component-token": {
2743
2840
  "required": false,
2744
2841
  "inputType": "text",
2745
2842
  "defaultValue": "",
2746
- "promptLabel": "Placement to",
2747
- "promptHint": "Optional explicit props.to value for generated menu placement (example: ./notes). If omitted and directory-prefix includes a nestedChildren route group, defaults to ./<page-slug>."
2843
+ "promptLabel": "Link component token",
2844
+ "promptHint": "Optional component token override for the generated page link placement (example: local.main.ui.tab-link-item)."
2748
2845
  },
2749
- "file": {
2846
+ "link-to": {
2750
2847
  "required": false,
2751
2848
  "inputType": "text",
2752
2849
  "defaultValue": "",
2753
- "promptLabel": "Target Vue file",
2754
- "promptHint": "Vue SFC path relative to app root (used by outlet subcommand)."
2850
+ "promptLabel": "Link to",
2851
+ "promptHint": "Optional explicit props.to value for the generated page link placement (example: ./notes). If omitted for pages under a detected parent subpages host, it is inferred from the page path."
2755
2852
  },
2756
- "host": {
2853
+ "target": {
2757
2854
  "required": false,
2758
2855
  "inputType": "text",
2759
2856
  "defaultValue": "",
2760
- "promptLabel": "Outlet host",
2761
- "promptHint": "ShellOutlet host value to inject into target file."
2857
+ "promptLabel": "Outlet target",
2858
+ "promptHint": "Used by add-subpages and outlet. Accepts host or host:position. If only host is given, position defaults to sub-pages."
2762
2859
  },
2763
- "position": {
2860
+ "title": {
2764
2861
  "required": false,
2765
2862
  "inputType": "text",
2766
- "defaultValue": "sub-pages",
2767
- "promptLabel": "Outlet position",
2768
- "promptHint": "ShellOutlet position value to inject into target file."
2863
+ "defaultValue": "",
2864
+ "promptLabel": "Section title",
2865
+ "promptHint": "Optional SectionContainerShell title override for add-subpages."
2769
2866
  },
2770
- "mode": {
2867
+ "subtitle": {
2771
2868
  "required": false,
2772
2869
  "inputType": "text",
2773
- "defaultValue": "routed",
2774
- "promptLabel": "Outlet mode",
2775
- "promptHint": "routed | outlet-only (routed injects RouterView when missing)."
2870
+ "defaultValue": "",
2871
+ "promptLabel": "Section subtitle",
2872
+ "promptHint": "Optional SectionContainerShell subtitle override for add-subpages."
2776
2873
  }
2777
2874
  },
2778
2875
  "dependsOn": [],
@@ -2794,53 +2891,180 @@
2794
2891
  "generatorPrimarySubcommand": "page",
2795
2892
  "generatorSubcommands": {
2796
2893
  "page": {
2797
- "description": "Scaffold a non-CRUD page and add a menu placement entry.",
2894
+ "entrypoint": "src/server/subcommands/page.js",
2895
+ "export": "runGeneratorSubcommand",
2896
+ "description": "Create a route page at an explicit target file and add a link placement entry for it.",
2897
+ "longDescription": [
2898
+ "This command always creates one route page file. By default, its page link is placed from the page path itself.",
2899
+ "If an ancestor page has already been enhanced with sub-pages, JSKIT treats that ancestor as the real host. In that case the new page is linked into the nearest parent sub-pages outlet instead of the shell menu.",
2900
+ "That means the generated link normally becomes a tab or child-page link under that ancestor host, and `props.to` is inferred relative to that host. If the host page is `index.vue`, child pages belong under `index/...` so the router keeps the parent page visible while the child route renders underneath it."
2901
+ ],
2902
+ "positionalArgs": [
2903
+ {
2904
+ "name": "target-file",
2905
+ "required": true,
2906
+ "descriptionKey": "page-target-file"
2907
+ }
2908
+ ],
2798
2909
  "optionNames": [
2799
2910
  "name",
2800
- "surface",
2801
- "directory-prefix",
2802
- "placement",
2803
- "placement-component-token",
2804
- "placement-to"
2911
+ "link-placement",
2912
+ "link-component-token",
2913
+ "link-to",
2914
+ "force"
2915
+ ],
2916
+ "notes": [
2917
+ "If a nearest parent subpages host is found, placement, link component token, and props.to are inferred automatically.",
2918
+ "If the parent host page is index.vue, child pages belong under index/...",
2919
+ "If the target page file already exists, rerun with --force to overwrite it."
2920
+ ],
2921
+ "examples": [
2922
+ {
2923
+ "label": "Common usage",
2924
+ "lines": [
2925
+ "npx jskit generate ui-generator page \\",
2926
+ " admin/reports/index.vue \\",
2927
+ " --name \"Reports\""
2928
+ ]
2929
+ },
2930
+ {
2931
+ "label": "More advanced usage",
2932
+ "lines": [
2933
+ "npx jskit generate ui-generator page \\",
2934
+ " admin/customers/[customerId]/index/notes/index.vue \\",
2935
+ " --name \"Notes\" \\",
2936
+ " --force"
2937
+ ]
2938
+ }
2805
2939
  ]
2806
2940
  },
2807
- "element": {
2941
+ "placed-element": {
2808
2942
  "entrypoint": "src/server/subcommands/element.js",
2809
2943
  "export": "runGeneratorSubcommand",
2810
- "description": "Scaffold a reusable UI element component and register a placement.",
2944
+ "description": "Create a Vue component file under the chosen component directory (default: src/components) and add a placement entry that renders it.",
2811
2945
  "optionNames": [
2812
2946
  "name",
2813
2947
  "surface",
2814
2948
  "path",
2815
- "placement"
2949
+ "placement",
2950
+ "force"
2951
+ ],
2952
+ "requiredOptionNames": [
2953
+ "name",
2954
+ "surface"
2955
+ ],
2956
+ "notes": [
2957
+ "If --placement is omitted, the placed element is added at shell-layout:top-right.",
2958
+ "If the component file already exists, rerun with --force to overwrite it."
2959
+ ],
2960
+ "examples": [
2961
+ {
2962
+ "label": "Common usage",
2963
+ "lines": [
2964
+ "npx jskit generate ui-generator placed-element \\",
2965
+ " --name \"Alerts Widget\" \\",
2966
+ " --surface admin"
2967
+ ]
2968
+ },
2969
+ {
2970
+ "label": "More advanced usage",
2971
+ "lines": [
2972
+ "npx jskit generate ui-generator placed-element \\",
2973
+ " --name \"Ops Panel\" \\",
2974
+ " --surface admin \\",
2975
+ " --path src/widgets \\",
2976
+ " --placement shell-layout:top-right \\",
2977
+ " --force"
2978
+ ]
2979
+ }
2816
2980
  ]
2817
2981
  },
2818
- "container": {
2819
- "entrypoint": "src/server/subcommands/container.js",
2982
+ "add-subpages": {
2983
+ "entrypoint": "src/server/subcommands/addSubpages.js",
2820
2984
  "export": "runGeneratorSubcommand",
2821
- "description": "Scaffold a routed section container page with a tab outlet. Adds a menu entry only when --placement is passed.",
2985
+ "description": "Upgrade an existing page into a routed subpage host with SectionContainerShell, ShellOutlet, and RouterView.",
2986
+ "positionalArgs": [
2987
+ {
2988
+ "name": "target-file",
2989
+ "required": true,
2990
+ "descriptionKey": "existing-page-target-file"
2991
+ }
2992
+ ],
2822
2993
  "optionNames": [
2823
- "name",
2824
- "surface",
2825
- "directory-prefix",
2826
- "route-path",
2994
+ "target",
2827
2995
  "path",
2828
- "placement"
2996
+ "title",
2997
+ "subtitle"
2998
+ ],
2999
+ "notes": [
3000
+ "Use this when the page should render shared content plus child routes below it.",
3001
+ "If the host page is index.vue, create child pages under index/..."
3002
+ ],
3003
+ "examples": [
3004
+ {
3005
+ "label": "Common usage",
3006
+ "lines": [
3007
+ "npx jskit generate ui-generator add-subpages \\",
3008
+ " admin/customers/[customerId]/index.vue \\",
3009
+ " --title \"Customer\" \\",
3010
+ " --subtitle \"View and manage this customer.\""
3011
+ ]
3012
+ },
3013
+ {
3014
+ "label": "More advanced usage",
3015
+ "lines": [
3016
+ "npx jskit generate ui-generator add-subpages \\",
3017
+ " admin/contacts/[contactId]/index.vue \\",
3018
+ " --target contact-view:summary-tabs \\",
3019
+ " --path src/components/admin \\",
3020
+ " --title \"Contact\" \\",
3021
+ " --subtitle \"Manage contact modules.\""
3022
+ ]
3023
+ }
2829
3024
  ]
2830
3025
  },
2831
3026
  "outlet": {
2832
3027
  "entrypoint": "src/server/subcommands/outlet.js",
2833
3028
  "export": "runGeneratorSubcommand",
2834
- "description": "Inject a ShellOutlet block into an existing Vue page/component.",
3029
+ "description": "Inject a generic ShellOutlet block into an existing Vue page/component.",
3030
+ "longDescription": [
3031
+ "A ShellOutlet creates a named placement target inside a Vue file. That target is what other parts of JSKIT render into later.",
3032
+ "After an outlet exists, `jskit list-placements` will discover it and show it as `host:position`. That makes the target visible to humans and to generators that need a placement destination.",
3033
+ "Commands that create placed UI, such as `ui-generator placed-element`, and commands that add page links can then target that outlet by writing placement entries that point at the same `host:position`."
3034
+ ],
3035
+ "positionalArgs": [
3036
+ {
3037
+ "name": "target-file",
3038
+ "required": true,
3039
+ "descriptionKey": "existing-vue-sfc-target-file"
3040
+ }
3041
+ ],
2835
3042
  "optionNames": [
2836
- "file",
2837
- "host",
2838
- "position",
2839
- "mode"
3043
+ "target"
2840
3044
  ],
2841
3045
  "requiredOptionNames": [
2842
- "file",
2843
- "host"
3046
+ "target"
3047
+ ],
3048
+ "notes": [
3049
+ "Use --target host or --target host:position. If only host is given, position defaults to sub-pages."
3050
+ ],
3051
+ "examples": [
3052
+ {
3053
+ "label": "Common usage",
3054
+ "lines": [
3055
+ "npx jskit generate ui-generator outlet \\",
3056
+ " src/components/ContactSummaryCard.vue \\",
3057
+ " --target contact-view"
3058
+ ]
3059
+ },
3060
+ {
3061
+ "label": "More advanced usage",
3062
+ "lines": [
3063
+ "npx jskit generate ui-generator outlet \\",
3064
+ " src/pages/admin/customers/[customerId]/index.vue \\",
3065
+ " --target customer-view:summary-actions"
3066
+ ]
3067
+ }
2844
3068
  ]
2845
3069
  }
2846
3070
  },
@@ -2860,7 +3084,7 @@
2860
3084
  "mutations": {
2861
3085
  "dependencies": {
2862
3086
  "runtime": {
2863
- "@jskit-ai/users-web": "0.1.46"
3087
+ "@jskit-ai/users-web": "0.1.48"
2864
3088
  },
2865
3089
  "dev": {}
2866
3090
  },
@@ -2868,42 +3092,18 @@
2868
3092
  "scripts": {}
2869
3093
  },
2870
3094
  "procfile": {},
2871
- "files": [
2872
- {
2873
- "from": "templates/src/pages/admin/ui-generator/Page.vue",
2874
- "toSurface": "${option:surface|lower}",
2875
- "toSurfacePath": "${option:directory-prefix|pathprefix}${option:name|path}/index.vue",
2876
- "reason": "Install generated UI page scaffold.",
2877
- "category": "ui-generator",
2878
- "id": "ui-generator-page-${option:name|snake}"
2879
- }
2880
- ],
2881
- "text": [
2882
- {
2883
- "op": "append-text",
2884
- "file": "src/placement.js",
2885
- "position": "bottom",
2886
- "skipIfContains": "jskit:ui-generator.page.menu:${option:surface|lower}:${option:directory-prefix|path}:${option:name|path}",
2887
- "value": "\n// jskit:ui-generator.page.menu:${option:surface|lower}:${option:directory-prefix|path}:${option:name|path}\n{\n addPlacement({\n id: \"__JSKIT_UI_MENU_PLACEMENT_ID__\",\n host: \"__JSKIT_UI_MENU_PLACEMENT_HOST__\",\n position: \"__JSKIT_UI_MENU_PLACEMENT_POSITION__\",\n surfaces: [\"${option:surface|lower}\"],\n order: 155,\n componentToken: \"__JSKIT_UI_MENU_COMPONENT_TOKEN__\",\n props: {\n label: \"${option:name|trim}\",\n surface: \"${option:surface|lower}\",\n workspaceSuffix: \"__JSKIT_UI_MENU_WORKSPACE_SUFFIX__\",\n nonWorkspaceSuffix: \"__JSKIT_UI_MENU_NON_WORKSPACE_SUFFIX__\",\n__JSKIT_UI_MENU_TO_PROP_LINE__ },\n when: ({ auth }) => Boolean(auth?.authenticated)\n });\n}\n",
2888
- "reason": "Append generated UI page menu placement.",
2889
- "category": "ui-generator",
2890
- "id": "ui-generator-page-placement-menu-${option:name|snake}",
2891
- "templateContext": {
2892
- "entrypoint": "src/server/buildTemplateContext.js",
2893
- "export": "buildUiPageTemplateContext"
2894
- }
2895
- }
2896
- ]
3095
+ "files": [],
3096
+ "text": []
2897
3097
  }
2898
3098
  }
2899
3099
  },
2900
3100
  {
2901
3101
  "packageId": "@jskit-ai/uploads-image-web",
2902
- "version": "0.1.9",
3102
+ "version": "0.1.11",
2903
3103
  "descriptor": {
2904
3104
  "packageVersion": 1,
2905
3105
  "packageId": "@jskit-ai/uploads-image-web",
2906
- "version": "0.1.9",
3106
+ "version": "0.1.11",
2907
3107
  "kind": "runtime",
2908
3108
  "description": "Reusable client-side image upload runtime with pre-upload image editing.",
2909
3109
  "dependsOn": [
@@ -2967,7 +3167,7 @@
2967
3167
  "mutations": {
2968
3168
  "dependencies": {
2969
3169
  "runtime": {
2970
- "@jskit-ai/uploads-runtime": "0.1.9",
3170
+ "@jskit-ai/uploads-runtime": "0.1.11",
2971
3171
  "@uppy/compressor": "^3.1.0",
2972
3172
  "@uppy/core": "^5.2.0",
2973
3173
  "@uppy/dashboard": "^5.1.1",
@@ -2987,11 +3187,11 @@
2987
3187
  },
2988
3188
  {
2989
3189
  "packageId": "@jskit-ai/uploads-runtime",
2990
- "version": "0.1.9",
3190
+ "version": "0.1.11",
2991
3191
  "descriptor": {
2992
3192
  "packageVersion": 1,
2993
3193
  "packageId": "@jskit-ai/uploads-runtime",
2994
- "version": "0.1.9",
3194
+ "version": "0.1.11",
2995
3195
  "kind": "runtime",
2996
3196
  "description": "Reusable upload runtime primitives for multipart parsing, policy validation, and blob storage.",
2997
3197
  "dependsOn": [
@@ -3061,7 +3261,7 @@
3061
3261
  "dependencies": {
3062
3262
  "runtime": {
3063
3263
  "@fastify/multipart": "^9.4.0",
3064
- "@jskit-ai/kernel": "0.1.31"
3264
+ "@jskit-ai/kernel": "0.1.33"
3065
3265
  },
3066
3266
  "dev": {}
3067
3267
  },
@@ -3076,11 +3276,11 @@
3076
3276
  },
3077
3277
  {
3078
3278
  "packageId": "@jskit-ai/users-core",
3079
- "version": "0.1.41",
3279
+ "version": "0.1.43",
3080
3280
  "descriptor": {
3081
3281
  "packageVersion": 1,
3082
3282
  "packageId": "@jskit-ai/users-core",
3083
- "version": "0.1.41",
3283
+ "version": "0.1.43",
3084
3284
  "kind": "runtime",
3085
3285
  "description": "Users/account runtime plus HTTP routes for account and console features.",
3086
3286
  "dependsOn": [
@@ -3216,11 +3416,11 @@
3216
3416
  "mutations": {
3217
3417
  "dependencies": {
3218
3418
  "runtime": {
3219
- "@jskit-ai/auth-core": "0.1.30",
3220
- "@jskit-ai/database-runtime": "0.1.31",
3221
- "@jskit-ai/http-runtime": "0.1.30",
3222
- "@jskit-ai/kernel": "0.1.31",
3223
- "@jskit-ai/uploads-runtime": "0.1.9",
3419
+ "@jskit-ai/auth-core": "0.1.32",
3420
+ "@jskit-ai/database-runtime": "0.1.33",
3421
+ "@jskit-ai/http-runtime": "0.1.32",
3422
+ "@jskit-ai/kernel": "0.1.33",
3423
+ "@jskit-ai/uploads-runtime": "0.1.11",
3224
3424
  "@fastify/type-provider-typebox": "^6.1.0",
3225
3425
  "typebox": "^1.0.81"
3226
3426
  },
@@ -3331,11 +3531,11 @@
3331
3531
  },
3332
3532
  {
3333
3533
  "packageId": "@jskit-ai/users-web",
3334
- "version": "0.1.46",
3534
+ "version": "0.1.48",
3335
3535
  "descriptor": {
3336
3536
  "packageVersion": 1,
3337
3537
  "packageId": "@jskit-ai/users-web",
3338
- "version": "0.1.46",
3538
+ "version": "0.1.48",
3339
3539
  "kind": "runtime",
3340
3540
  "description": "Users web module: account/profile UI plus shared shell link components.",
3341
3541
  "dependsOn": [
@@ -3495,12 +3695,12 @@
3495
3695
  "runtime": {
3496
3696
  "@tanstack/vue-query": "5.92.12",
3497
3697
  "@mdi/js": "^7.4.47",
3498
- "@jskit-ai/http-runtime": "0.1.30",
3499
- "@jskit-ai/realtime": "0.1.30",
3500
- "@jskit-ai/kernel": "0.1.31",
3501
- "@jskit-ai/shell-web": "0.1.30",
3502
- "@jskit-ai/uploads-image-web": "0.1.9",
3503
- "@jskit-ai/users-core": "0.1.41",
3698
+ "@jskit-ai/http-runtime": "0.1.32",
3699
+ "@jskit-ai/realtime": "0.1.32",
3700
+ "@jskit-ai/kernel": "0.1.33",
3701
+ "@jskit-ai/shell-web": "0.1.32",
3702
+ "@jskit-ai/uploads-image-web": "0.1.11",
3703
+ "@jskit-ai/users-core": "0.1.43",
3504
3704
  "vuetify": "^4.0.0"
3505
3705
  },
3506
3706
  "dev": {}
@@ -3620,11 +3820,11 @@
3620
3820
  },
3621
3821
  {
3622
3822
  "packageId": "@jskit-ai/workspaces-core",
3623
- "version": "0.1.7",
3823
+ "version": "0.1.9",
3624
3824
  "descriptor": {
3625
3825
  "packageVersion": 1,
3626
3826
  "packageId": "@jskit-ai/workspaces-core",
3627
- "version": "0.1.7",
3827
+ "version": "0.1.9",
3628
3828
  "kind": "runtime",
3629
3829
  "description": "Workspace tenancy runtime plus HTTP routes, role catalog, and workspace config scaffolding.",
3630
3830
  "dependsOn": [
@@ -3733,7 +3933,7 @@
3733
3933
  "mutations": {
3734
3934
  "dependencies": {
3735
3935
  "runtime": {
3736
- "@jskit-ai/users-core": "0.1.41"
3936
+ "@jskit-ai/users-core": "0.1.43"
3737
3937
  },
3738
3938
  "dev": {}
3739
3939
  },
@@ -3862,7 +4062,7 @@
3862
4062
  "file": "config/public.js",
3863
4063
  "position": "bottom",
3864
4064
  "skipIfContains": "config.workspaceSwitching =",
3865
- "value": "\nconfig.workspaceSwitching = true;\nconfig.workspaceInvitations = {\n enabled: true,\n allowInPersonalMode: true\n};\nconfig.assistantEnabled = false;\nconfig.assistantRequiredPermission = \"\";\nconfig.socialEnabled = false;\nconfig.socialFederationEnabled = false;\n",
4065
+ "value": "\nconfig.workspaceSwitching = true;\nconfig.workspaceInvitations = {\n enabled: true,\n allowInPersonalMode: true\n};\n",
3866
4066
  "reason": "Append default workspace feature toggles into app-owned config.",
3867
4067
  "category": "workspaces-core",
3868
4068
  "id": "users-core-public-config"
@@ -3923,11 +4123,11 @@
3923
4123
  },
3924
4124
  {
3925
4125
  "packageId": "@jskit-ai/workspaces-web",
3926
- "version": "0.1.7",
4126
+ "version": "0.1.9",
3927
4127
  "descriptor": {
3928
4128
  "packageVersion": 1,
3929
4129
  "packageId": "@jskit-ai/workspaces-web",
3930
- "version": "0.1.7",
4130
+ "version": "0.1.9",
3931
4131
  "kind": "runtime",
3932
4132
  "description": "Workspace web module: workspace selector, tools widget, workspace surfaces, and members/settings UI.",
3933
4133
  "dependsOn": [
@@ -4064,8 +4264,8 @@
4064
4264
  "mutations": {
4065
4265
  "dependencies": {
4066
4266
  "runtime": {
4067
- "@jskit-ai/workspaces-core": "0.1.7",
4068
- "@jskit-ai/users-web": "0.1.46"
4267
+ "@jskit-ai/workspaces-core": "0.1.9",
4268
+ "@jskit-ai/users-web": "0.1.48"
4069
4269
  },
4070
4270
  "dev": {}
4071
4271
  },