@jskit-ai/create-app 0.1.93 → 0.1.95

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 (60) hide show
  1. package/package.json +2 -2
  2. package/src/server/index.js +8 -1
  3. package/templates/base-shell/.jskit/lock.json +229 -0
  4. package/templates/base-shell/package.json +4 -2
  5. package/templates/base-shell/packages/main/src/client/providers/MainClientProvider.js +8 -0
  6. package/templates/base-shell/src/App.vue +7 -9
  7. package/templates/base-shell/src/components/ShellLayout.vue +12 -0
  8. package/templates/base-shell/src/components/menus/MenuLinkItem.vue +30 -0
  9. package/templates/base-shell/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
  10. package/templates/base-shell/src/components/menus/TabLinkItem.vue +42 -0
  11. package/templates/base-shell/src/error.js +19 -0
  12. package/templates/base-shell/src/pages/home/index.vue +85 -21
  13. package/templates/base-shell/src/pages/home/settings/general/index.vue +40 -0
  14. package/templates/base-shell/src/pages/home/settings/index.vue +7 -0
  15. package/templates/base-shell/src/pages/home/settings.vue +109 -0
  16. package/templates/base-shell/src/pages/home.vue +8 -1
  17. package/templates/base-shell/src/placement.js +56 -0
  18. package/templates/base-shell/src/placementTopology.js +149 -0
  19. package/templates/base-shell/tests/e2e/adaptive-shell.spec.ts +4 -0
  20. package/templates/base-shell/tests/e2e/base-shell.spec.ts +1 -1
  21. package/templates/base-shell/vite.config.mjs +14 -0
  22. package/templates/minimal-shell/.github/workflows/verify.yml +29 -0
  23. package/templates/minimal-shell/.jskit/lock.json +31 -0
  24. package/templates/minimal-shell/AGENTS.md +10 -0
  25. package/templates/minimal-shell/Procfile +2 -0
  26. package/templates/minimal-shell/app.json +14 -0
  27. package/templates/minimal-shell/bin/server.js +8 -0
  28. package/templates/minimal-shell/config/public.js +41 -0
  29. package/templates/minimal-shell/config/server.js +1 -0
  30. package/templates/minimal-shell/config/surfaceAccessPolicies.js +3 -0
  31. package/templates/minimal-shell/eslint.config.mjs +19 -0
  32. package/templates/minimal-shell/favicon.svg +7 -0
  33. package/templates/minimal-shell/gitignore +8 -0
  34. package/templates/minimal-shell/index.html +13 -0
  35. package/templates/minimal-shell/jsconfig.json +8 -0
  36. package/templates/minimal-shell/package.json +55 -0
  37. package/templates/minimal-shell/packages/main/package.descriptor.mjs +69 -0
  38. package/templates/minimal-shell/packages/main/package.json +12 -0
  39. package/templates/minimal-shell/packages/main/src/client/index.js +13 -0
  40. package/templates/minimal-shell/packages/main/src/client/providers/MainClientProvider.js +20 -0
  41. package/templates/minimal-shell/packages/main/src/server/MainServiceProvider.js +20 -0
  42. package/templates/minimal-shell/packages/main/src/server/index.js +1 -0
  43. package/templates/minimal-shell/packages/main/src/server/loadAppConfig.js +9 -0
  44. package/templates/minimal-shell/packages/main/src/shared/index.js +10 -0
  45. package/templates/minimal-shell/packages/main/src/shared/schemas/index.js +22 -0
  46. package/templates/minimal-shell/scripts/dokku-set-remote-envs-via-ssh.sh +210 -0
  47. package/templates/minimal-shell/server/lib/runtimeEnv.js +45 -0
  48. package/templates/minimal-shell/server/lib/surfaceRuntime.js +10 -0
  49. package/templates/minimal-shell/server.js +189 -0
  50. package/templates/minimal-shell/src/App.vue +13 -0
  51. package/templates/minimal-shell/src/main.js +85 -0
  52. package/templates/minimal-shell/src/pages/home/index.vue +48 -0
  53. package/templates/minimal-shell/src/pages/home.vue +13 -0
  54. package/templates/minimal-shell/src/views/NotFound.vue +13 -0
  55. package/templates/minimal-shell/tests/client/smoke.vitest.js +7 -0
  56. package/templates/minimal-shell/tests/e2e/base-shell.spec.ts +57 -0
  57. package/templates/minimal-shell/tests/server/minimalShell.validator.test.js +131 -0
  58. package/templates/minimal-shell/tests/server/smoke.test.js +16 -0
  59. package/templates/minimal-shell/vite.config.mjs +84 -0
  60. package/templates/minimal-shell/vite.shared.mjs +59 -0
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@jskit-ai/create-app",
3
- "version": "0.1.93",
4
- "description": "Scaffold minimal JSKIT app shells.",
3
+ "version": "0.1.95",
4
+ "description": "Scaffold JSKIT app shells.",
5
5
  "type": "module",
6
6
  "files": [
7
7
  "bin",
@@ -7,6 +7,7 @@ import { createCliError } from "./cliError.js";
7
7
  import { shellQuote } from "./cliEntrypoint.js";
8
8
 
9
9
  const DEFAULT_TEMPLATE = "base-shell";
10
+ const MINIMAL_TEMPLATE = "minimal-shell";
10
11
  const DEFAULT_INITIAL_BUNDLES = "none";
11
12
  const INITIAL_BUNDLE_PRESETS = new Set(["none", "auth"]);
12
13
  const TENANCY_MODES = new Set(["none", "personal", "workspaces"]);
@@ -128,6 +129,11 @@ function parseCliArgs(argv) {
128
129
  continue;
129
130
  }
130
131
 
132
+ if (arg === "--minimal") {
133
+ options.template = MINIMAL_TEMPLATE;
134
+ continue;
135
+ }
136
+
131
137
  if (arg === "--template") {
132
138
  const { value, nextIndex } = parseOptionWithValue(args, index, "--template");
133
139
  options.template = value;
@@ -221,8 +227,9 @@ function printUsage(stream = process.stderr) {
221
227
  stream.write("\n");
222
228
  stream.write("Options:\n");
223
229
  stream.write(
224
- ` --template <name> Template folder under templates/ (default: ${DEFAULT_TEMPLATE}; use ai-seed for the minimal AI seed flow)\n`
230
+ ` --template <name> Template folder under templates/ (default: ${DEFAULT_TEMPLATE}; use minimal-shell for the bare scaffold or ai-seed for the AI seed flow)\n`
225
231
  );
232
+ stream.write(" --minimal Use the bare minimal-shell template instead of the default shell-web app scaffold\n");
226
233
  stream.write(" --title <text> App title used for template replacements\n");
227
234
  stream.write(" --target <path> Target directory (default: ./<app-name>)\n");
228
235
  stream.write(" --initial-bundles <preset> Optional bundle preset: none | auth (default: none)\n");
@@ -26,6 +26,235 @@
26
26
  },
27
27
  "options": {},
28
28
  "installedAt": "1970-01-01T00:00:00.000Z"
29
+ },
30
+ "@jskit-ai/shell-web": {
31
+ "packageId": "@jskit-ai/shell-web",
32
+ "version": "0.1.85",
33
+ "source": {
34
+ "type": "catalog",
35
+ "descriptorPath": "../jskit-catalog/catalog/packages.json#@jskit-ai/shell-web"
36
+ },
37
+ "managed": {
38
+ "packageJson": {
39
+ "dependencies": {
40
+ "@mdi/js": {
41
+ "hadPrevious": false,
42
+ "previousValue": "",
43
+ "value": "^7.4.47"
44
+ },
45
+ "@jskit-ai/shell-web": {
46
+ "hadPrevious": false,
47
+ "previousValue": "",
48
+ "value": "0.x"
49
+ }
50
+ },
51
+ "devDependencies": {},
52
+ "scripts": {}
53
+ },
54
+ "text": {
55
+ "packages/main/src/client/providers/MainClientProvider.js::shell-web-main-client-provider-menu-link-item-import": {
56
+ "file": "packages/main/src/client/providers/MainClientProvider.js",
57
+ "op": "append-text",
58
+ "value": "import MenuLinkItem from \"/src/components/menus/MenuLinkItem.vue\";\n",
59
+ "position": "top",
60
+ "reason": "Bind app-owned shell menu link-item scaffold into local main client provider imports.",
61
+ "category": "shell-web",
62
+ "id": "shell-web-main-client-provider-menu-link-item-import"
63
+ },
64
+ "packages/main/src/client/providers/MainClientProvider.js::shell-web-main-client-provider-surface-aware-menu-link-item-import": {
65
+ "file": "packages/main/src/client/providers/MainClientProvider.js",
66
+ "op": "append-text",
67
+ "value": "import SurfaceAwareMenuLinkItem from \"/src/components/menus/SurfaceAwareMenuLinkItem.vue\";\n",
68
+ "position": "top",
69
+ "reason": "Bind app-owned shell surface-aware menu link-item scaffold into local main client provider imports.",
70
+ "category": "shell-web",
71
+ "id": "shell-web-main-client-provider-surface-aware-menu-link-item-import"
72
+ },
73
+ "packages/main/src/client/providers/MainClientProvider.js::shell-web-main-client-provider-tab-link-item-import": {
74
+ "file": "packages/main/src/client/providers/MainClientProvider.js",
75
+ "op": "append-text",
76
+ "value": "import TabLinkItem from \"/src/components/menus/TabLinkItem.vue\";\n",
77
+ "position": "top",
78
+ "reason": "Bind app-owned shell tab link-item scaffold into local main client provider imports.",
79
+ "category": "shell-web",
80
+ "id": "shell-web-main-client-provider-tab-link-item-import"
81
+ },
82
+ "packages/main/src/client/providers/MainClientProvider.js::shell-web-main-client-provider-menu-link-item-register": {
83
+ "file": "packages/main/src/client/providers/MainClientProvider.js",
84
+ "op": "append-text",
85
+ "value": "\nregisterMainClientComponent(\"local.main.ui.menu-link-item\", () => MenuLinkItem);\n",
86
+ "position": "bottom",
87
+ "reason": "Bind app-owned shell menu link-item token into local main client provider registry.",
88
+ "category": "shell-web",
89
+ "id": "shell-web-main-client-provider-menu-link-item-register"
90
+ },
91
+ "packages/main/src/client/providers/MainClientProvider.js::shell-web-main-client-provider-surface-aware-menu-link-item-register": {
92
+ "file": "packages/main/src/client/providers/MainClientProvider.js",
93
+ "op": "append-text",
94
+ "value": "\nregisterMainClientComponent(\"local.main.ui.surface-aware-menu-link-item\", () => SurfaceAwareMenuLinkItem);\n",
95
+ "position": "bottom",
96
+ "reason": "Bind app-owned shell surface-aware menu link-item token into local main client provider registry.",
97
+ "category": "shell-web",
98
+ "id": "shell-web-main-client-provider-surface-aware-menu-link-item-register"
99
+ },
100
+ "packages/main/src/client/providers/MainClientProvider.js::shell-web-main-client-provider-tab-link-item-register": {
101
+ "file": "packages/main/src/client/providers/MainClientProvider.js",
102
+ "op": "append-text",
103
+ "value": "\nregisterMainClientComponent(\"local.main.ui.tab-link-item\", () => TabLinkItem);\n",
104
+ "position": "bottom",
105
+ "reason": "Bind app-owned shell tab link-item token into local main client provider registry.",
106
+ "category": "shell-web",
107
+ "id": "shell-web-main-client-provider-tab-link-item-register"
108
+ }
109
+ },
110
+ "vite": {},
111
+ "files": [
112
+ {
113
+ "path": "src/App.vue",
114
+ "hash": "e8ad49df01c665c6453d783ea3b67deda05473870fd29faa039e9a38e28a7f2c",
115
+ "hadPrevious": true,
116
+ "previousContentBase64": "PHRlbXBsYXRlPgogIDx2LWFwcD4KICAgIDx2LW1haW4+CiAgICAgIDx2LWNvbnRhaW5lciBjbGFzcz0icHktMTAgcHktbWQtMTQiPgogICAgICAgIDx2LXJvdyBqdXN0aWZ5PSJjZW50ZXIiPgogICAgICAgICAgPHYtY29sIGNvbHM9IjEyIiBzbT0iMTEiIG1kPSIxMCIgbGc9IjgiIHhsPSI3Ij4KICAgICAgICAgICAgPFJvdXRlclZpZXcgLz4KICAgICAgICAgIDwvdi1jb2w+CiAgICAgICAgPC92LXJvdz4KICAgICAgPC92LWNvbnRhaW5lcj4KICAgIDwvdi1tYWluPgogIDwvdi1hcHA+CjwvdGVtcGxhdGU+Cg==",
117
+ "preserveOnRemove": false,
118
+ "reason": "Install full-width shell app root with shell-web error host and edge-to-edge layout.",
119
+ "category": "shell-web",
120
+ "id": "shell-web-app-root"
121
+ },
122
+ {
123
+ "path": "src/components/ShellLayout.vue",
124
+ "hash": "0c2c3b5439890e0822dab32b0a740927b7612df1510efe2254cb20d90fd7312c",
125
+ "hadPrevious": false,
126
+ "previousContentBase64": "",
127
+ "preserveOnRemove": false,
128
+ "reason": "Install app-owned shell layout component so apps can customize structure and slots.",
129
+ "category": "shell-web",
130
+ "id": "shell-web-component-shell-layout"
131
+ },
132
+ {
133
+ "path": "src/components/menus/MenuLinkItem.vue",
134
+ "hash": "91460689ede313da18352c5fd67f99f198433198906b276586c7f60742f042a1",
135
+ "hadPrevious": false,
136
+ "previousContentBase64": "",
137
+ "preserveOnRemove": false,
138
+ "reason": "Install app-owned shell menu link-item scaffold for local placement customization.",
139
+ "category": "shell-web",
140
+ "id": "shell-web-component-menu-link-item"
141
+ },
142
+ {
143
+ "path": "src/components/menus/SurfaceAwareMenuLinkItem.vue",
144
+ "hash": "63ad9112bf096974a6b268e2c719e9d5522fde179350f56dc640f8902c0e914e",
145
+ "hadPrevious": false,
146
+ "previousContentBase64": "",
147
+ "preserveOnRemove": false,
148
+ "reason": "Install app-owned surface-aware shell menu link-item scaffold for local placement customization.",
149
+ "category": "shell-web",
150
+ "id": "shell-web-component-surface-aware-menu-link-item"
151
+ },
152
+ {
153
+ "path": "src/components/menus/TabLinkItem.vue",
154
+ "hash": "6fc8405ca0e19516ce762e392733fd39e7c2af85d8483193b4ee52caac76f1f4",
155
+ "hadPrevious": false,
156
+ "previousContentBase64": "",
157
+ "preserveOnRemove": false,
158
+ "reason": "Install app-owned shell tab link-item scaffold for local placement customization.",
159
+ "category": "shell-web",
160
+ "id": "shell-web-component-tab-link-item"
161
+ },
162
+ {
163
+ "path": "src/error.js",
164
+ "hash": "dd7e2f4e32b83d1227135a0f224bb2c46854fe7fd9714c7cc56cf94f2f1eb55b",
165
+ "hadPrevious": false,
166
+ "previousContentBase64": "",
167
+ "preserveOnRemove": false,
168
+ "reason": "Install app-owned error runtime policy and presenter config scaffold.",
169
+ "category": "shell-web",
170
+ "id": "shell-web-error-config"
171
+ },
172
+ {
173
+ "path": "src/placement.js",
174
+ "hash": "39ef1011cc96c94e8b1778a199b2222bed9887b066331918633524515ca8b909",
175
+ "hadPrevious": false,
176
+ "previousContentBase64": "",
177
+ "preserveOnRemove": false,
178
+ "reason": "Install app-owned placement registry scaffold used by shell-web placement runtime.",
179
+ "category": "shell-web",
180
+ "id": "shell-web-placement-registry"
181
+ },
182
+ {
183
+ "path": "src/placementTopology.js",
184
+ "hash": "3e8a515abc359c61f28061c1c3d3df8b810ddc50b4a0c805c093394cc7693ffd",
185
+ "hadPrevious": false,
186
+ "previousContentBase64": "",
187
+ "preserveOnRemove": false,
188
+ "reason": "Install app-owned semantic placement topology used by shell-web placement runtime.",
189
+ "category": "shell-web",
190
+ "id": "shell-web-placement-topology"
191
+ },
192
+ {
193
+ "path": "src/pages/home.vue",
194
+ "hash": "52e99863be5b81fa9e5813bb10e912b4439446ebdcc5c543e46f223558b355cc",
195
+ "hadPrevious": true,
196
+ "previousContentBase64": "PHJvdXRlIGxhbmc9Impzb24iPgp7CiAgIm1ldGEiOiB7CiAgICAianNraXQiOiB7CiAgICAgICJzdXJmYWNlIjogImhvbWUiCiAgICB9CiAgfQp9Cjwvcm91dGU+Cgo8dGVtcGxhdGU+CiAgPFJvdXRlclZpZXcgLz4KPC90ZW1wbGF0ZT4K",
197
+ "preserveOnRemove": false,
198
+ "reason": "Install shell-driven home wrapper page.",
199
+ "category": "shell-web",
200
+ "id": "shell-web-page-home-wrapper"
201
+ },
202
+ {
203
+ "path": "src/pages/home/index.vue",
204
+ "hash": "3aff6e5d0430679bb4314af0920724b987e29ba487d5d93eb2a51aa79275f103",
205
+ "hadPrevious": true,
206
+ "previousContentBase64": "PHRlbXBsYXRlPgogIDxzZWN0aW9uIGNsYXNzPSJnZW5lcmF0ZWQtdWktc2NyZWVuIGdlbmVyYXRlZC11aS1zY3JlZW4tLWFwcCBob21lLXN0YXJ0LXNjcmVlbiBkLWZsZXggZmxleC1jb2x1bW4gZ2EtNCI+CiAgICA8aGVhZGVyPgogICAgICA8cCBjbGFzcz0idGV4dC1vdmVybGluZSB0ZXh0LW1lZGl1bS1lbXBoYXNpcyBtYi0xIj5Ib21lPC9wPgogICAgICA8aDEgY2xhc3M9ImhvbWUtc3RhcnQtc2NyZWVuX190aXRsZSI+SG9tZSBiYXNlPC9oMT4KICAgICAgPHAgY2xhc3M9InRleHQtYm9keS0yIHRleHQtbWVkaXVtLWVtcGhhc2lzIG1iLTAiPgogICAgICAgIFRoZSBhcHAgcnVudGltZSBpcyBvbmxpbmUgYW5kIHJlYWR5IGZvciB0aGUgZmlyc3QgcmVhbCB3b3JrZmxvdy4KICAgICAgPC9wPgogICAgPC9oZWFkZXI+CgogICAgPHYtc2hlZXQgcm91bmRlZD0ibGciIGJvcmRlciBjbGFzcz0iaG9tZS1zdGFydC1zY3JlZW5fX3BhbmVsIj4KICAgICAgPGgyIGNsYXNzPSJ0ZXh0LWg2IG1iLTIiPk5vIGFjdGl2aXR5IHlldDwvaDI+CiAgICAgIDxwIGNsYXNzPSJ0ZXh0LWJvZHktMiB0ZXh0LW1lZGl1bS1lbXBoYXNpcyBtYi0wIj4KICAgICAgICBSZWNlbnQgd29yaywgc2F2ZWQgcmVjb3JkcywgYW5kIG5leHQgYWN0aW9ucyB3aWxsIGFwcGVhciBoZXJlIG9uY2UgdGhpcyBhcHAgaGFzIGRhdGEuCiAgICAgIDwvcD4KICAgIDwvdi1zaGVldD4KICA8L3NlY3Rpb24+CjwvdGVtcGxhdGU+Cgo8c3R5bGUgc2NvcGVkPgouZ2VuZXJhdGVkLXVpLXNjcmVlbiB7CiAgLS1nZW5lcmF0ZWQtdWktc2NyZWVuLXRpdGxlLXNpemU6IGNsYW1wKDEuNXJlbSwgM3Z3LCAyLjVyZW0pOwogIC0tZ2VuZXJhdGVkLXVpLXNjcmVlbi1wYW5lbC1wYWRkaW5nOiAxcmVtOwp9CgouaG9tZS1zdGFydC1zY3JlZW4gewogIG1hcmdpbi1pbmxpbmU6IGF1dG87CiAgbWF4LXdpZHRoOiA0OHJlbTsKfQoKLmhvbWUtc3RhcnQtc2NyZWVuX190aXRsZSB7CiAgZm9udC1zaXplOiB2YXIoLS1nZW5lcmF0ZWQtdWktc2NyZWVuLXRpdGxlLXNpemUpOwogIGZvbnQtd2VpZ2h0OiA3MDA7CiAgbGV0dGVyLXNwYWNpbmc6IC0wLjAzZW07CiAgbGluZS1oZWlnaHQ6IDEuMDg7CiAgbWFyZ2luOiAwIDAgMC40NXJlbTsKfQoKLmhvbWUtc3RhcnQtc2NyZWVuX19wYW5lbCB7CiAgcGFkZGluZzogdmFyKC0tZ2VuZXJhdGVkLXVpLXNjcmVlbi1wYW5lbC1wYWRkaW5nKTsKfQo8L3N0eWxlPgo=",
207
+ "preserveOnRemove": false,
208
+ "reason": "Install shell-driven home surface starter page.",
209
+ "category": "shell-web",
210
+ "id": "shell-web-page-home"
211
+ },
212
+ {
213
+ "path": "src/pages/home/settings.vue",
214
+ "hash": "ebf4f694e3b52bf8f899f78f8211c3350fc48ba3f822d2b68406724e523a7e2a",
215
+ "hadPrevious": false,
216
+ "previousContentBase64": "",
217
+ "preserveOnRemove": false,
218
+ "reason": "Install shell-driven home settings shell route with section navigation.",
219
+ "category": "shell-web",
220
+ "id": "shell-web-page-home-settings-shell"
221
+ },
222
+ {
223
+ "path": "src/pages/home/settings/index.vue",
224
+ "hash": "e82040354f747a009887df7cf3f2f25911e42959f40d376ba254fa7e8fa69247",
225
+ "hadPrevious": false,
226
+ "previousContentBase64": "",
227
+ "preserveOnRemove": false,
228
+ "reason": "Install shell-driven home settings redirect so the starter settings shell lands on a real child page.",
229
+ "category": "shell-web",
230
+ "id": "shell-web-page-home-settings"
231
+ },
232
+ {
233
+ "path": "src/pages/home/settings/general/index.vue",
234
+ "hash": "ef2c566a83b707e5e69c9e821caf891f177ee344fa0c6ab7307b3031f618c3bf",
235
+ "hadPrevious": false,
236
+ "previousContentBase64": "",
237
+ "preserveOnRemove": false,
238
+ "reason": "Install shell-driven general settings child page with a tiny browser-local shell preference example.",
239
+ "category": "shell-web",
240
+ "id": "shell-web-page-home-settings-general"
241
+ },
242
+ {
243
+ "path": "tests/e2e/adaptive-shell.spec.ts",
244
+ "hash": "456cbb65ebd0b97052e4e171bf87081e89b293fe67b9250af2cf876969d4eafd",
245
+ "hadPrevious": false,
246
+ "previousContentBase64": "",
247
+ "preserveOnRemove": false,
248
+ "reason": "Install compact/medium/expanded Playwright smoke coverage for the adaptive shell.",
249
+ "category": "shell-web",
250
+ "id": "shell-web-test-adaptive-shell-smoke"
251
+ }
252
+ ],
253
+ "migrations": []
254
+ },
255
+ "options": {},
256
+ "installedAt": "1970-01-01T00:00:00.000Z",
257
+ "migrationSyncVersion": "0.1.85"
29
258
  }
30
259
  }
31
260
  }
@@ -3,7 +3,7 @@
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "type": "module",
6
- "description": "Minimal JSKIT base app (Fastify + Vue)",
6
+ "description": "JSKIT shell-web app (Fastify + Vue)",
7
7
  "engines": {
8
8
  "node": ">=20 <23"
9
9
  },
@@ -39,7 +39,9 @@
39
39
  "vue": "^3.5.13",
40
40
  "vue-router": "^5.0.4",
41
41
  "vuetify": "^4.0.0",
42
- "@jskit-ai/http-runtime": "0.x"
42
+ "@jskit-ai/http-runtime": "0.x",
43
+ "@mdi/js": "^7.4.47",
44
+ "@jskit-ai/shell-web": "0.x"
43
45
  },
44
46
  "devDependencies": {
45
47
  "@jskit-ai/agent-docs": "0.x",
@@ -1,3 +1,7 @@
1
+ import MenuLinkItem from "/src/components/menus/MenuLinkItem.vue";
2
+ import SurfaceAwareMenuLinkItem from "/src/components/menus/SurfaceAwareMenuLinkItem.vue";
3
+ import TabLinkItem from "/src/components/menus/TabLinkItem.vue";
4
+
1
5
  const mainClientComponents = [];
2
6
 
3
7
  function registerMainClientComponent(token, resolveComponent) {
@@ -18,3 +22,7 @@ export {
18
22
  MainClientProvider,
19
23
  registerMainClientComponent
20
24
  };
25
+
26
+ registerMainClientComponent("local.main.ui.menu-link-item", () => MenuLinkItem);
27
+ registerMainClientComponent("local.main.ui.surface-aware-menu-link-item", () => SurfaceAwareMenuLinkItem);
28
+ registerMainClientComponent("local.main.ui.tab-link-item", () => TabLinkItem);
@@ -1,13 +1,11 @@
1
+ <script setup>
2
+ import { RouterView } from "vue-router";
3
+ import ShellErrorHost from "@jskit-ai/shell-web/client/components/ShellErrorHost";
4
+ </script>
5
+
1
6
  <template>
2
7
  <v-app>
3
- <v-main>
4
- <v-container class="py-10 py-md-14">
5
- <v-row justify="center">
6
- <v-col cols="12" sm="11" md="10" lg="8" xl="7">
7
- <RouterView />
8
- </v-col>
9
- </v-row>
10
- </v-container>
11
- </v-main>
8
+ <RouterView />
9
+ <ShellErrorHost />
12
10
  </v-app>
13
11
  </template>
@@ -0,0 +1,12 @@
1
+ <script>
2
+ import { h } from "vue";
3
+ import PackageShellLayout from "@jskit-ai/shell-web/client/components/ShellLayout";
4
+
5
+ export default {
6
+ name: "ShellLayout",
7
+ inheritAttrs: false,
8
+ setup(_, { attrs, slots }) {
9
+ return () => h(PackageShellLayout, attrs, slots);
10
+ }
11
+ };
12
+ </script>
@@ -0,0 +1,30 @@
1
+ <script setup>
2
+ import ShellMenuLinkItem from "@jskit-ai/shell-web/client/components/ShellMenuLinkItem";
3
+
4
+ const props = defineProps({
5
+ label: {
6
+ type: String,
7
+ default: ""
8
+ },
9
+ to: {
10
+ type: String,
11
+ default: ""
12
+ },
13
+ icon: {
14
+ type: String,
15
+ default: ""
16
+ },
17
+ disabled: {
18
+ type: Boolean,
19
+ default: false
20
+ },
21
+ exact: {
22
+ type: Boolean,
23
+ default: false
24
+ }
25
+ });
26
+ </script>
27
+
28
+ <template>
29
+ <ShellMenuLinkItem v-bind="props" />
30
+ </template>
@@ -0,0 +1,42 @@
1
+ <script setup>
2
+ import ShellSurfaceAwareMenuLinkItem from "@jskit-ai/shell-web/client/components/ShellSurfaceAwareMenuLinkItem";
3
+
4
+ const props = defineProps({
5
+ label: {
6
+ type: String,
7
+ default: ""
8
+ },
9
+ to: {
10
+ type: String,
11
+ default: ""
12
+ },
13
+ icon: {
14
+ type: String,
15
+ default: ""
16
+ },
17
+ surface: {
18
+ type: String,
19
+ default: ""
20
+ },
21
+ scopedSuffix: {
22
+ type: String,
23
+ default: "/"
24
+ },
25
+ unscopedSuffix: {
26
+ type: String,
27
+ default: "/"
28
+ },
29
+ disabled: {
30
+ type: Boolean,
31
+ default: false
32
+ },
33
+ exact: {
34
+ type: Boolean,
35
+ default: false
36
+ }
37
+ });
38
+ </script>
39
+
40
+ <template>
41
+ <ShellSurfaceAwareMenuLinkItem v-bind="props" />
42
+ </template>
@@ -0,0 +1,42 @@
1
+ <script setup>
2
+ import ShellTabLinkItem from "@jskit-ai/shell-web/client/components/ShellTabLinkItem";
3
+
4
+ const props = defineProps({
5
+ label: {
6
+ type: String,
7
+ default: ""
8
+ },
9
+ to: {
10
+ type: String,
11
+ default: ""
12
+ },
13
+ icon: {
14
+ type: String,
15
+ default: ""
16
+ },
17
+ surface: {
18
+ type: String,
19
+ default: ""
20
+ },
21
+ scopedSuffix: {
22
+ type: String,
23
+ default: "/"
24
+ },
25
+ unscopedSuffix: {
26
+ type: String,
27
+ default: "/"
28
+ },
29
+ disabled: {
30
+ type: Boolean,
31
+ default: false
32
+ },
33
+ exact: {
34
+ type: Boolean,
35
+ default: false
36
+ }
37
+ });
38
+ </script>
39
+
40
+ <template>
41
+ <ShellTabLinkItem v-bind="props" />
42
+ </template>
@@ -0,0 +1,19 @@
1
+ import { createDefaultErrorPolicy } from "@jskit-ai/shell-web/client/error";
2
+
3
+ /**
4
+ * App-owned error handling contract.
5
+ * - intent chooses default presentation: resource-load, action-feedback, app-recoverable, blocking.
6
+ * - policy(event, ctx): decide channel + presenter + message.
7
+ * - defaultPresenterId: used when policy does not set presenterId.
8
+ * - presenters: optional custom presenters registered at boot.
9
+ */
10
+ export default Object.freeze({
11
+ defaultPresenterId: "material.snackbar",
12
+ policy: createDefaultErrorPolicy({
13
+ resourceLoadChannel: "silent",
14
+ actionFeedbackChannel: "snackbar",
15
+ appRecoverableChannel: "banner",
16
+ blockingChannel: "dialog"
17
+ }),
18
+ presenters: []
19
+ });
@@ -1,42 +1,106 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { useQuery } from "@tanstack/vue-query";
4
+
5
+ const healthQuery = useQuery({
6
+ queryKey: ["shell-web", "health"],
7
+ queryFn: async () => {
8
+ const response = await fetch("/api/health");
9
+ if (!response.ok) {
10
+ throw new Error("Health request failed.");
11
+ }
12
+ return response.json();
13
+ },
14
+ refetchOnWindowFocus: false
15
+ });
16
+
17
+ const health = computed(() => {
18
+ if (healthQuery.isPending.value || healthQuery.isFetching.value) {
19
+ return "loading...";
20
+ }
21
+
22
+ if (healthQuery.error.value) {
23
+ return "unreachable";
24
+ }
25
+
26
+ return healthQuery.data.value?.ok ? "ok" : "unhealthy";
27
+ });
28
+ </script>
29
+
1
30
  <template>
2
- <section class="generated-ui-screen generated-ui-screen--app home-start-screen d-flex flex-column ga-4">
3
- <header>
4
- <p class="text-overline text-medium-emphasis mb-1">Home</p>
5
- <h1 class="home-start-screen__title">Home base</h1>
6
- <p class="text-body-2 text-medium-emphasis mb-0">
7
- The app runtime is online and ready for the first real workflow.
8
- </p>
31
+ <section class="generated-ui-screen generated-ui-screen--app home-surface-screen d-flex flex-column ga-4">
32
+ <header class="home-surface-screen__header">
33
+ <div>
34
+ <p class="text-overline text-medium-emphasis mb-1">Home</p>
35
+ <h1 class="home-surface-screen__title">Ready</h1>
36
+ <p class="text-body-2 text-medium-emphasis mb-0">
37
+ Core services are available.
38
+ </p>
39
+ </div>
40
+ <v-btn color="primary" variant="flat" to="/home/settings/general">Settings</v-btn>
9
41
  </header>
10
42
 
11
- <v-sheet rounded="lg" border class="home-start-screen__panel">
12
- <h2 class="text-h6 mb-2">No activity yet</h2>
13
- <p class="text-body-2 text-medium-emphasis mb-0">
14
- Recent work, saved records, and next actions will appear here once this app has data.
15
- </p>
43
+ <v-sheet rounded="lg" border class="home-surface-screen__panel">
44
+ <div class="home-surface-screen__status">
45
+ <span class="text-caption text-medium-emphasis">Service health</span>
46
+ <strong>{{ health }}</strong>
47
+ </div>
48
+ <v-divider vertical class="d-none d-sm-block" />
49
+ <div class="home-surface-screen__status">
50
+ <span class="text-caption text-medium-emphasis">Route</span>
51
+ <strong>/home</strong>
52
+ </div>
16
53
  </v-sheet>
17
54
  </section>
18
55
  </template>
19
56
 
20
57
  <style scoped>
21
58
  .generated-ui-screen {
22
- --generated-ui-screen-title-size: clamp(1.5rem, 3vw, 2.5rem);
59
+ --generated-ui-screen-title-size: 2rem;
23
60
  --generated-ui-screen-panel-padding: 1rem;
24
61
  }
25
62
 
26
- .home-start-screen {
27
- margin-inline: auto;
28
- max-width: 48rem;
63
+ .home-surface-screen__header {
64
+ align-items: flex-start;
65
+ display: flex;
66
+ gap: 1rem;
67
+ justify-content: space-between;
29
68
  }
30
69
 
31
- .home-start-screen__title {
70
+ .home-surface-screen__title {
32
71
  font-size: var(--generated-ui-screen-title-size);
33
72
  font-weight: 700;
34
- letter-spacing: -0.03em;
35
- line-height: 1.08;
36
- margin: 0 0 0.45rem;
73
+ letter-spacing: 0;
74
+ line-height: 1.1;
75
+ margin: 0 0 0.4rem;
37
76
  }
38
77
 
39
- .home-start-screen__panel {
78
+ .home-surface-screen__panel {
79
+ align-items: stretch;
80
+ display: flex;
81
+ flex-wrap: wrap;
82
+ gap: 1rem;
40
83
  padding: var(--generated-ui-screen-panel-padding);
41
84
  }
85
+
86
+ .home-surface-screen__status {
87
+ display: grid;
88
+ gap: 0.15rem;
89
+ min-width: 9rem;
90
+ }
91
+
92
+ @media (max-width: 640px) {
93
+ .generated-ui-screen {
94
+ --generated-ui-screen-title-size: 1.5rem;
95
+ }
96
+
97
+ .home-surface-screen__header {
98
+ flex-direction: column;
99
+ }
100
+
101
+ .home-surface-screen__header :deep(.v-btn) {
102
+ min-height: 48px;
103
+ width: 100%;
104
+ }
105
+ }
42
106
  </style>
@@ -0,0 +1,40 @@
1
+ <script setup>
2
+ import { computed } from "vue";
3
+ import { useShellLayoutState } from "@jskit-ai/shell-web/client/composables/useShellLayoutState";
4
+
5
+ const { drawerDefaultOpen, setDrawerDefaultOpen } = useShellLayoutState();
6
+
7
+ const drawerDefaultOpenModel = computed({
8
+ get() {
9
+ return drawerDefaultOpen.value;
10
+ },
11
+ set(value) {
12
+ setDrawerDefaultOpen(Boolean(value));
13
+ }
14
+ });
15
+ </script>
16
+
17
+ <template>
18
+ <section class="generated-ui-screen generated-ui-screen--settings settings-general-screen d-flex flex-column ga-4">
19
+ <div>
20
+ <h2 class="text-h6 mb-2">Navigation</h2>
21
+ <p class="text-body-2 text-medium-emphasis mb-0">
22
+ Choose the default behavior for wider screens. Phone layouts keep primary navigation in the bottom bar.
23
+ </p>
24
+ </div>
25
+
26
+ <v-switch
27
+ v-model="drawerDefaultOpenModel"
28
+ color="primary"
29
+ inset
30
+ hide-details="auto"
31
+ label="Open drawer by default on wider screens"
32
+ />
33
+ </section>
34
+ </template>
35
+
36
+ <style scoped>
37
+ .settings-general-screen :deep(.v-switch) {
38
+ min-height: 48px;
39
+ }
40
+ </style>
@@ -0,0 +1,7 @@
1
+ <script setup>
2
+ import { redirectToChild } from "@jskit-ai/kernel/client/pageRedirects";
3
+
4
+ definePage({
5
+ redirect: redirectToChild("general")
6
+ });
7
+ </script>