@jskit-ai/agent-docs 0.1.148 → 0.1.150

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 (232) hide show
  1. package/guide/agent/app-setup/existing-application-migration.md +8 -6
  2. package/guide/agent/app-setup/initial-scaffolding.md +26 -7
  3. package/guide/agent/app-setup/quickstart.md +9 -6
  4. package/guide/agent/framework/application-operations.md +91 -0
  5. package/guide/agent/framework/crud-operations.md +83 -0
  6. package/guide/agent/framework/material-3.md +112 -0
  7. package/guide/agent/framework/ui-operations.md +78 -0
  8. package/guide/agent/index.md +13 -3
  9. package/package.json +1 -1
  10. package/patterns/feature-package/example/booking-engine/package.json +1 -1
  11. package/patterns/minimal-foundation/PATTERN.md +5 -0
  12. package/patterns/minimal-foundation/example/AGENTS.md +8 -8
  13. package/patterns/minimal-foundation/example/package.json +4 -5
  14. package/patterns/minimal-foundation/example/vite.config.mjs +0 -1
  15. package/patterns/shell-foundation/PATTERN.md +5 -0
  16. package/patterns/shell-foundation/example/AGENTS.md +8 -8
  17. package/patterns/shell-foundation/example/package.json +5 -6
  18. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  19. package/patterns/shell-foundation/example/vite.config.mjs +0 -1
  20. package/reference/autogen/PATTERN_INDEX.md +61 -61
  21. package/reference/autogen/tooling/testUtils.md +1 -1
  22. package/skills/jskit/SKILL.md +8 -5
  23. package/skills/jskit/references/app-operations.md +12 -11
  24. package/skills/jskit/references/crud-operations.md +10 -6
  25. package/skills/jskit/references/existing-application-migration.md +9 -12
  26. package/skills/jskit/references/material-3.md +2 -0
  27. package/skills/jskit/references/pattern-index.md +61 -61
  28. package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +105 -0
  29. package/skills/jskit/references/patterns/app/minimal-foundation/example/.nvmrc +1 -0
  30. package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +17 -0
  31. package/skills/jskit/references/patterns/app/minimal-foundation/example/Procfile +2 -0
  32. package/skills/jskit/references/patterns/app/minimal-foundation/example/app.json +14 -0
  33. package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +71 -0
  34. package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/server.js +8 -0
  35. package/skills/jskit/references/patterns/app/minimal-foundation/example/config/public.js +40 -0
  36. package/skills/jskit/references/patterns/app/minimal-foundation/example/config/server.js +1 -0
  37. package/skills/jskit/references/patterns/app/minimal-foundation/example/config/surfaceAccessPolicies.js +3 -0
  38. package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +19 -0
  39. package/skills/jskit/references/patterns/app/minimal-foundation/example/favicon.svg +7 -0
  40. package/skills/jskit/references/patterns/app/minimal-foundation/example/gitignore +9 -0
  41. package/skills/jskit/references/patterns/app/minimal-foundation/example/index.html +13 -0
  42. package/skills/jskit/references/patterns/app/minimal-foundation/example/jsconfig.json +8 -0
  43. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +62 -0
  44. package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/package.json +42 -0
  45. package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/src/shared/index.js +10 -0
  46. package/skills/jskit/references/patterns/app/minimal-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
  47. package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +31 -0
  48. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +45 -0
  49. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/surfaceRuntime.js +10 -0
  50. package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +195 -0
  51. package/skills/jskit/references/patterns/app/minimal-foundation/example/src/App.vue +13 -0
  52. package/skills/jskit/references/patterns/app/minimal-foundation/example/src/main.js +85 -0
  53. package/skills/jskit/references/patterns/app/minimal-foundation/example/src/pages/home/index.vue +48 -0
  54. package/skills/jskit/references/patterns/app/minimal-foundation/example/src/pages/home.vue +13 -0
  55. package/skills/jskit/references/patterns/app/minimal-foundation/example/src/views/NotFound.vue +13 -0
  56. package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/client/smoke.vitest.js +7 -0
  57. package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
  58. package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +16 -0
  59. package/skills/jskit/references/patterns/app/minimal-foundation/example/vite.config.mjs +80 -0
  60. package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +111 -0
  61. package/skills/jskit/references/patterns/app/shell-foundation/example/.nvmrc +1 -0
  62. package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +17 -0
  63. package/skills/jskit/references/patterns/app/shell-foundation/example/Procfile +2 -0
  64. package/skills/jskit/references/patterns/app/shell-foundation/example/app.json +14 -0
  65. package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +71 -0
  66. package/skills/jskit/references/patterns/app/shell-foundation/example/bin/server.js +8 -0
  67. package/skills/jskit/references/patterns/app/shell-foundation/example/config/public.js +40 -0
  68. package/skills/jskit/references/patterns/app/shell-foundation/example/config/server.js +1 -0
  69. package/skills/jskit/references/patterns/app/shell-foundation/example/config/surfaceAccessPolicies.js +3 -0
  70. package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +19 -0
  71. package/skills/jskit/references/patterns/app/shell-foundation/example/favicon.svg +7 -0
  72. package/skills/jskit/references/patterns/app/shell-foundation/example/gitignore +9 -0
  73. package/skills/jskit/references/patterns/app/shell-foundation/example/index.html +13 -0
  74. package/skills/jskit/references/patterns/app/shell-foundation/example/jsconfig.json +8 -0
  75. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +64 -0
  76. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +56 -0
  77. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/index.js +9 -0
  78. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +18 -0
  79. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/shared/index.js +10 -0
  80. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/shared/schemas/index.js +22 -0
  81. package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +31 -0
  82. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +45 -0
  83. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/surfaceRuntime.js +10 -0
  84. package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +195 -0
  85. package/skills/jskit/references/patterns/app/shell-foundation/example/src/App.vue +11 -0
  86. package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/ShellLayout.vue +12 -0
  87. package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/MenuLinkItem.vue +30 -0
  88. package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
  89. package/skills/jskit/references/patterns/app/shell-foundation/example/src/components/menus/TabLinkItem.vue +42 -0
  90. package/skills/jskit/references/patterns/app/shell-foundation/example/src/error.js +19 -0
  91. package/skills/jskit/references/patterns/app/shell-foundation/example/src/main.js +85 -0
  92. package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/index.vue +116 -0
  93. package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings/general/index.vue +40 -0
  94. package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings/index.vue +7 -0
  95. package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home/settings.vue +109 -0
  96. package/skills/jskit/references/patterns/app/shell-foundation/example/src/pages/home.vue +20 -0
  97. package/skills/jskit/references/patterns/app/shell-foundation/example/src/placement.js +56 -0
  98. package/skills/jskit/references/patterns/app/shell-foundation/example/src/placementTopology.js +149 -0
  99. package/skills/jskit/references/patterns/app/shell-foundation/example/src/views/NotFound.vue +13 -0
  100. package/skills/jskit/references/patterns/app/shell-foundation/example/tests/client/smoke.vitest.js +7 -0
  101. package/skills/jskit/references/patterns/app/shell-foundation/example/tests/e2e/adaptive-shell.spec.ts +10 -0
  102. package/skills/jskit/references/patterns/app/shell-foundation/example/tests/e2e/base-shell.spec.ts +23 -0
  103. package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +16 -0
  104. package/skills/jskit/references/patterns/app/shell-foundation/example/vite.config.mjs +80 -0
  105. package/skills/jskit/references/patterns/assistant/assistant-surface/PATTERN.md +77 -0
  106. package/skills/jskit/references/patterns/assistant/assistant-surface/example/config/public.js +19 -0
  107. package/skills/jskit/references/patterns/assistant/assistant-surface/example/config/server.js +9 -0
  108. package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/pages/admin/assistant/index.vue +7 -0
  109. package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/pages/admin/settings/assistant/index.vue +7 -0
  110. package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/placement.js +38 -0
  111. package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +90 -0
  112. package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/login.vue +17 -0
  113. package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/reset-password.vue +17 -0
  114. package/skills/jskit/references/patterns/auth/auth-surface/example/src/pages/auth/signout.vue +17 -0
  115. package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/authGuardRuntime.js +7 -0
  116. package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/authHttpClient.js +1 -0
  117. package/skills/jskit/references/patterns/auth/auth-surface/example/src/runtime/useSignOut.js +1 -0
  118. package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/LoginView.vue +7 -0
  119. package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/ResetPasswordView.vue +7 -0
  120. package/skills/jskit/references/patterns/auth/auth-surface/example/src/views/auth/SignOutView.vue +7 -0
  121. package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +5 -0
  122. package/skills/jskit/references/patterns/auth/supabase-auth/PATTERN.md +67 -0
  123. package/skills/jskit/references/patterns/auth/supabase-auth/example/.env.example +4 -0
  124. package/skills/jskit/references/patterns/auth/supabase-auth/example/config/server.js +11 -0
  125. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +7 -0
  126. package/skills/jskit/references/patterns/console/console-surface/PATTERN.md +58 -0
  127. package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/index.vue +62 -0
  128. package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/settings/index.vue +17 -0
  129. package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console/settings.vue +95 -0
  130. package/skills/jskit/references/patterns/console/console-surface/example/src/pages/console.vue +20 -0
  131. package/skills/jskit/references/patterns/crud/crud-screen-set/PATTERN.md +88 -0
  132. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookEditPage.vue +54 -0
  133. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookFormFields.vue +52 -0
  134. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookListPage.vue +54 -0
  135. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookNewPage.vue +45 -0
  136. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/BookViewPage.vue +50 -0
  137. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/formFields.js +31 -0
  138. package/skills/jskit/references/patterns/crud/crud-screen-set/example/books/listExtensions.js +9 -0
  139. package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +160 -0
  140. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/migrations/20260815000000_books.cjs +22 -0
  141. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +41 -0
  142. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/BooksFeature.js +13 -0
  143. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/bookResource.js +83 -0
  144. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/shared/index.js +1 -0
  145. package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +102 -0
  146. package/skills/jskit/references/patterns/crud/resource-contract/example/bookResource.js +87 -0
  147. package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +80 -0
  148. package/skills/jskit/references/patterns/database/mysql-application/example/.env.example +5 -0
  149. package/skills/jskit/references/patterns/database/mysql-application/example/.github/workflows/verify.yml +39 -0
  150. package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +11 -0
  151. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +13 -0
  152. package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +3 -0
  153. package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +80 -0
  154. package/skills/jskit/references/patterns/database/postgres-application/example/.env.example +5 -0
  155. package/skills/jskit/references/patterns/database/postgres-application/example/.github/workflows/verify.yml +38 -0
  156. package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +11 -0
  157. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +13 -0
  158. package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +3 -0
  159. package/skills/jskit/references/patterns/mobile/android-application/PATTERN.md +71 -0
  160. package/skills/jskit/references/patterns/mobile/android-application/example/capacitor.config.json +10 -0
  161. package/skills/jskit/references/patterns/realtime/realtime-application/PATTERN.md +69 -0
  162. package/skills/jskit/references/patterns/realtime/realtime-application/example/.env.example +1 -0
  163. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +8 -0
  164. package/skills/jskit/references/patterns/realtime/realtime-application/example/src/placement.js +17 -0
  165. package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +108 -0
  166. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +48 -0
  167. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +33 -0
  168. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +26 -0
  169. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +19 -0
  170. package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +31 -0
  171. package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +36 -0
  172. package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +34 -0
  173. package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +23 -0
  174. package/skills/jskit/references/patterns/shell/application-shell/PATTERN.md +66 -0
  175. package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/App.vue +13 -0
  176. package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/pages/home/index.vue +48 -0
  177. package/skills/jskit/references/patterns/shell/application-shell/example/expected-existing/src/pages/home.vue +13 -0
  178. package/skills/jskit/references/patterns/shell/application-shell/example/src/App.vue +11 -0
  179. package/skills/jskit/references/patterns/shell/application-shell/example/src/components/ShellLayout.vue +13 -0
  180. package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/MenuLinkItem.vue +30 -0
  181. package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/SurfaceAwareMenuLinkItem.vue +42 -0
  182. package/skills/jskit/references/patterns/shell/application-shell/example/src/components/menus/TabLinkItem.vue +42 -0
  183. package/skills/jskit/references/patterns/shell/application-shell/example/src/error.js +19 -0
  184. package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/index.vue +106 -0
  185. package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings/general/index.vue +40 -0
  186. package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings/index.vue +7 -0
  187. package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home/settings.vue +109 -0
  188. package/skills/jskit/references/patterns/shell/application-shell/example/src/pages/home.vue +20 -0
  189. package/skills/jskit/references/patterns/shell/application-shell/example/src/placement.js +56 -0
  190. package/skills/jskit/references/patterns/shell/application-shell/example/src/placementTopology.js +149 -0
  191. package/skills/jskit/references/patterns/shell/application-shell/example/tests/e2e/adaptive-shell.spec.ts +10 -0
  192. package/skills/jskit/references/patterns/ui/page-and-placement/PATTERN.md +76 -0
  193. package/skills/jskit/references/patterns/ui/page-and-placement/example/packages/main/src/client/providers/MainClientProvider.js +14 -0
  194. package/skills/jskit/references/patterns/ui/page-and-placement/example/src/components/SyncStatusElement.vue +16 -0
  195. package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/activity.vue +8 -0
  196. package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/index.vue +7 -0
  197. package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports/overview.vue +8 -0
  198. package/skills/jskit/references/patterns/ui/page-and-placement/example/src/pages/home/reports.vue +33 -0
  199. package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placement.js +52 -0
  200. package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placementTopology.js +29 -0
  201. package/skills/jskit/references/patterns/users/account-settings/PATTERN.md +61 -0
  202. package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsNotificationsSection.vue +81 -0
  203. package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsPreferencesSection.vue +151 -0
  204. package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsProfileSection.vue +120 -0
  205. package/skills/jskit/references/patterns/users/account-settings/example/src/pages/account/index.vue +17 -0
  206. package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +64 -0
  207. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +42 -0
  208. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/UsersFeature.js +13 -0
  209. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/index.js +1 -0
  210. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/shared/userResource.js +69 -0
  211. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +43 -0
  212. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +22 -0
  213. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/index.js +1 -0
  214. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/shared/userResource.js +56 -0
  215. package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +60 -0
  216. package/skills/jskit/references/patterns/workspaces/workspace-server/example/config/roles.js +27 -0
  217. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +23 -0
  218. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/PATTERN.md +63 -0
  219. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/packages/main/src/client/components/AccountPendingInvitesCue.vue +106 -0
  220. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/packages/main/src/client/components/AccountSettingsInvitesSection.vue +7 -0
  221. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/components/WorkspaceNotFoundCard.vue +53 -0
  222. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/composables/useWorkspaceNotFoundState.js +41 -0
  223. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/members/index.vue +7 -0
  224. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/workspace/settings/index.vue +23 -0
  225. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/admin/workspace/settings.vue +95 -0
  226. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/pages/invite/[token].vue +7 -0
  227. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/admin/index.vue +85 -0
  228. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/admin/root.vue +20 -0
  229. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/app/index.vue +46 -0
  230. package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/surfaces/app/root.vue +20 -0
  231. package/skills/jskit/references/ui-operations.md +5 -3
  232. package/templates/app/AGENTS.md +8 -8
@@ -0,0 +1,45 @@
1
+ import { createRequire } from "node:module";
2
+ import { surfaceRuntime } from "./surfaceRuntime.js";
3
+
4
+ const require = createRequire(import.meta.url);
5
+
6
+ function toPort(value, fallback = 3000) {
7
+ const parsed = Number.parseInt(String(value || "").trim(), 10);
8
+ if (Number.isInteger(parsed) && parsed > 0) {
9
+ return parsed;
10
+ }
11
+ return fallback;
12
+ }
13
+
14
+ let envLoaded = false;
15
+
16
+ function ensureRuntimeEnvLoaded() {
17
+ if (envLoaded) {
18
+ return;
19
+ }
20
+ try {
21
+ const dotenvModule = require("dotenv");
22
+ const loadDotEnv = dotenvModule?.config;
23
+ if (typeof loadDotEnv === "function") {
24
+ loadDotEnv();
25
+ }
26
+ } catch {
27
+ // dotenv is optional in base-shell; bundles can add it when needed.
28
+ }
29
+ envLoaded = true;
30
+ }
31
+
32
+ function resolveRuntimeEnv() {
33
+ ensureRuntimeEnvLoaded();
34
+ const serverSurface = surfaceRuntime.normalizeSurfaceMode(
35
+ process.env.JSKIT_SERVER_SURFACE || process.env.SERVER_SURFACE
36
+ );
37
+ return {
38
+ ...process.env,
39
+ SERVER_SURFACE: serverSurface,
40
+ PORT: toPort(process.env.PORT, 3000),
41
+ HOST: String(process.env.HOST || "").trim() || "0.0.0.0"
42
+ };
43
+ }
44
+
45
+ export { resolveRuntimeEnv };
@@ -0,0 +1,10 @@
1
+ import { createSurfaceRuntime } from "@jskit-ai/kernel/shared/surface/runtime";
2
+ import { config } from "../../config/public.js";
3
+
4
+ const surfaceRuntime = createSurfaceRuntime({
5
+ allMode: config.surfaceModeAll,
6
+ surfaces: config.surfaceDefinitions,
7
+ defaultSurfaceId: config.surfaceDefaultId
8
+ });
9
+
10
+ export { surfaceRuntime };
@@ -0,0 +1,195 @@
1
+ import Fastify from "fastify";
2
+ import fastifyStatic from "@fastify/static";
3
+ import { resolveRuntimeEnv } from "./server/lib/runtimeEnv.js";
4
+ import { existsSync, readFileSync } from "node:fs";
5
+ import path from "node:path";
6
+ import {
7
+ createInstalledRuntime,
8
+ registerSurfaceRequestConstraint,
9
+ resolveRuntimeProfileFromSurface
10
+ } from "@jskit-ai/kernel/server/platform";
11
+ import { loadAppConfigFromAppRoot } from "@jskit-ai/kernel/server/support";
12
+ import { matchesPathPrefix, normalizePathname } from "@jskit-ai/kernel/shared/surface/paths";
13
+ import { surfaceRuntime } from "./server/lib/surfaceRuntime.js";
14
+
15
+ const SPA_INDEX_FILE = "index.html";
16
+ const API_BASE_PATH = "/api";
17
+ const STATIC_GLOBAL_UI_PATHS = Object.freeze([
18
+ "/assets",
19
+ "/favicon.svg",
20
+ "/favicon.ico",
21
+ "/robots.txt",
22
+ "/manifest.webmanifest"
23
+ ]);
24
+
25
+ function toRequestPathname(urlValue) {
26
+ const rawUrl = String(urlValue || "").trim() || "/";
27
+ try {
28
+ return normalizePathname(new URL(rawUrl, "http://localhost").pathname || "/");
29
+ } catch {
30
+ return normalizePathname(rawUrl.split("?")[0] || "/");
31
+ }
32
+ }
33
+
34
+ function isApiPath(pathname) {
35
+ return matchesPathPrefix(pathname, API_BASE_PATH);
36
+ }
37
+
38
+ function hasFileExtension(pathname) {
39
+ return path.extname(normalizePathname(pathname)) !== "";
40
+ }
41
+
42
+ function resolveGlobalUiPaths(runtimeGlobalUiPaths = []) {
43
+ const paths = new Set(Array.isArray(runtimeGlobalUiPaths) ? runtimeGlobalUiPaths : []);
44
+ for (const staticPath of STATIC_GLOBAL_UI_PATHS) {
45
+ paths.add(staticPath);
46
+ }
47
+ return [...paths];
48
+ }
49
+
50
+ function resolveStaticFilePath(pathname) {
51
+ const normalizedPathname = normalizePathname(pathname);
52
+
53
+ const relativePath = normalizedPathname.replace(/^\/+/, "");
54
+ if (!relativePath || relativePath.endsWith("/")) {
55
+ return "";
56
+ }
57
+
58
+ const normalizedRelativePath = path.posix.normalize(relativePath);
59
+ if (
60
+ !normalizedRelativePath ||
61
+ normalizedRelativePath === "." ||
62
+ normalizedRelativePath === ".." ||
63
+ normalizedRelativePath.startsWith("../") ||
64
+ normalizedRelativePath.includes("/../")
65
+ ) {
66
+ return "";
67
+ }
68
+
69
+ return normalizedRelativePath;
70
+ }
71
+
72
+ function canServeStaticFile(distRoot, relativePath) {
73
+ if (!distRoot || !relativePath) {
74
+ return false;
75
+ }
76
+
77
+ const normalizedDistRoot = path.resolve(distRoot);
78
+ const resolvedPath = path.resolve(normalizedDistRoot, relativePath);
79
+ if (!(resolvedPath === normalizedDistRoot || resolvedPath.startsWith(`${normalizedDistRoot}${path.sep}`))) {
80
+ return false;
81
+ }
82
+
83
+ return existsSync(resolvedPath);
84
+ }
85
+
86
+ async function createServer({ runtimeEnv = resolveRuntimeEnv() } = {}) {
87
+ const app = Fastify({
88
+ logger: true,
89
+ ajv: {
90
+ customOptions: {
91
+ allowUnionTypes: true
92
+ }
93
+ }
94
+ });
95
+
96
+ app.get("/api/health", async () => {
97
+ return {
98
+ ok: true,
99
+ app: "reading-room"
100
+ };
101
+ });
102
+ const appRoot = path.resolve(process.cwd());
103
+ const distRoot = path.resolve(appRoot, "dist");
104
+ const hasWebBuild = existsSync(path.resolve(distRoot, SPA_INDEX_FILE));
105
+ const spaDocument = hasWebBuild ? readFileSync(path.resolve(distRoot, SPA_INDEX_FILE), "utf8") : "";
106
+ const runtime = await createInstalledRuntime({
107
+ appRoot,
108
+ profile: resolveRuntimeProfileFromSurface({
109
+ surfaceRuntime,
110
+ serverSurface: runtimeEnv.SERVER_SURFACE
111
+ }),
112
+ config: await loadAppConfigFromAppRoot({ appRoot }),
113
+ env: runtimeEnv,
114
+ logger: app.log,
115
+ fastify: app
116
+ });
117
+
118
+ registerSurfaceRequestConstraint({
119
+ fastify: app,
120
+ surfaceRuntime,
121
+ serverSurface: runtimeEnv.SERVER_SURFACE,
122
+ globalUiPaths: resolveGlobalUiPaths(runtime?.globalUiPaths || [])
123
+ });
124
+
125
+ if (hasWebBuild) {
126
+ await app.register(fastifyStatic, {
127
+ root: distRoot,
128
+ index: false,
129
+ serve: false
130
+ });
131
+ } else {
132
+ app.log.warn("Frontend build not found (dist/index.html). Page routes will return 404 until `npm run build`.");
133
+ }
134
+
135
+ app.setNotFoundHandler(async (request, reply) => {
136
+ const pathname = toRequestPathname(request?.url);
137
+ const method = String(request?.method || "GET")
138
+ .trim()
139
+ .toUpperCase();
140
+ if (isApiPath(pathname) || (method !== "GET" && method !== "HEAD")) {
141
+ return reply.code(404).send({
142
+ message: `Route ${method}:${pathname} not found`,
143
+ error: "Not Found",
144
+ statusCode: 404
145
+ });
146
+ }
147
+ if (hasFileExtension(pathname)) {
148
+ const staticFilePath = resolveStaticFilePath(pathname);
149
+ if (hasWebBuild && staticFilePath && canServeStaticFile(distRoot, staticFilePath)) {
150
+ return reply.sendFile(staticFilePath);
151
+ }
152
+ return reply.code(404).send({
153
+ message: `Route ${method}:${pathname} not found`,
154
+ error: "Not Found",
155
+ statusCode: 404
156
+ });
157
+ }
158
+ if (!hasWebBuild) {
159
+ return reply.code(404).send({
160
+ error: "Frontend build is not available. Run `npm run build`."
161
+ });
162
+ }
163
+ return reply.type("text/html; charset=utf-8").send(spaDocument);
164
+ });
165
+
166
+ app.log.info(
167
+ {
168
+ surface: surfaceRuntime.normalizeSurfaceMode(runtimeEnv.SERVER_SURFACE),
169
+ providerPackages: runtime.providerPackageOrder,
170
+ packageOrder: runtime.packageOrder,
171
+ capabilities: runtime.diagnostics.capabilityIds
172
+ },
173
+ "Started JSKIT installed runtime."
174
+ );
175
+
176
+ return app;
177
+ }
178
+
179
+ async function startServer(options = {}) {
180
+ const runtimeEnv = resolveRuntimeEnv();
181
+ const configuredPort = options?.port === undefined ? runtimeEnv.PORT : Number(options.port);
182
+ const port = Number.isInteger(configuredPort) && configuredPort >= 0 ? configuredPort : runtimeEnv.PORT;
183
+ const host = String(options?.host || "").trim() || runtimeEnv.HOST;
184
+ const app = await createServer({
185
+ runtimeEnv: {
186
+ ...runtimeEnv,
187
+ HOST: host,
188
+ PORT: port
189
+ }
190
+ });
191
+ await app.listen({ port, host });
192
+ return app;
193
+ }
194
+
195
+ export { createServer, startServer };
@@ -0,0 +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
+
6
+ <template>
7
+ <v-app>
8
+ <RouterView />
9
+ <ShellErrorHost />
10
+ </v-app>
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
+ });
@@ -0,0 +1,85 @@
1
+ import { createApp } from "vue";
2
+ import { createPinia } from "pinia";
3
+ import { QueryClient, VueQueryPlugin } from "@tanstack/vue-query";
4
+ import { createRouter, createWebHistory } from "vue-router/auto";
5
+ import { routes } from "vue-router/auto-routes";
6
+ import "vuetify/styles";
7
+ import { createVuetify } from "vuetify";
8
+ import { aliases as mdiAliases, mdi } from "vuetify/iconsets/mdi-svg";
9
+ import App from "./App.vue";
10
+ import NotFoundView from "./views/NotFound.vue";
11
+ import { bootInstalledClientModules } from "virtual:jskit-client-bootstrap";
12
+ import { createSurfaceRuntime } from "@jskit-ai/kernel/shared/surface/runtime";
13
+ import {
14
+ shouldRetryTransientQueryFailure,
15
+ transientQueryRetryDelay
16
+ } from "@jskit-ai/kernel/shared/support";
17
+ import {
18
+ bootstrapClientShellApp,
19
+ createShellRouter
20
+ } from "@jskit-ai/kernel/client";
21
+ import { config } from "../config/public.js";
22
+
23
+ const surfaceRuntime = createSurfaceRuntime({
24
+ allMode: config.surfaceModeAll,
25
+ surfaces: config.surfaceDefinitions,
26
+ defaultSurfaceId: config.surfaceDefaultId
27
+ });
28
+
29
+ const surfaceMode = surfaceRuntime.normalizeSurfaceMode(import.meta.env.VITE_SURFACE);
30
+ const { router, fallbackRoute } = createShellRouter({
31
+ createRouter,
32
+ history: createWebHistory(),
33
+ routes,
34
+ surfaceRuntime,
35
+ surfaceMode,
36
+ notFoundComponent: NotFoundView,
37
+ guard: {
38
+ surfaceDefinitions: config.surfaceDefinitions,
39
+ defaultSurfaceId: config.surfaceDefaultId,
40
+ webRootAllowed: config.webRootAllowed
41
+ }
42
+ });
43
+
44
+ const vuetify = createVuetify({
45
+ theme: {
46
+ defaultTheme: "light"
47
+ },
48
+ icons: {
49
+ defaultSet: "mdi",
50
+ aliases: mdiAliases,
51
+ sets: { mdi }
52
+ }
53
+ });
54
+ const pinia = createPinia();
55
+ const queryClient = new QueryClient({
56
+ defaultOptions: {
57
+ queries: {
58
+ refetchOnWindowFocus: false,
59
+ refetchOnReconnect: true,
60
+ retry: shouldRetryTransientQueryFailure,
61
+ retryDelay: transientQueryRetryDelay
62
+ }
63
+ }
64
+ });
65
+
66
+ void bootstrapClientShellApp({
67
+ createApp,
68
+ rootComponent: App,
69
+ appConfig: config,
70
+ appPlugins: [
71
+ pinia,
72
+ [VueQueryPlugin, { queryClient }],
73
+ vuetify
74
+ ],
75
+ pinia,
76
+ queryClient,
77
+ router,
78
+ bootClientModules: bootInstalledClientModules,
79
+ surfaceRuntime,
80
+ surfaceMode,
81
+ env: import.meta.env,
82
+ fallbackRoute
83
+ }).catch((error) => {
84
+ console.error("Failed to bootstrap client app.", error);
85
+ });
@@ -0,0 +1,116 @@
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.error.value) {
19
+ return "unreachable";
20
+ }
21
+
22
+ return healthQuery.data.value?.ok ? "ok" : "unhealthy";
23
+ });
24
+
25
+ const healthPending = computed(
26
+ () => healthQuery.isPending.value || healthQuery.isFetching.value
27
+ );
28
+ </script>
29
+
30
+ <template>
31
+ <section class="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>
41
+ </header>
42
+
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
+ <v-skeleton-loader
47
+ v-if="healthPending"
48
+ aria-label="Loading service health"
49
+ class="home-surface-screen__health-skeleton"
50
+ type="text"
51
+ />
52
+ <strong v-else>{{ health }}</strong>
53
+ </div>
54
+ <v-divider vertical class="d-none d-sm-block" />
55
+ <div class="home-surface-screen__status">
56
+ <span class="text-caption text-medium-emphasis">Route</span>
57
+ <strong>/home</strong>
58
+ </div>
59
+ </v-sheet>
60
+ </section>
61
+ </template>
62
+
63
+ <style scoped>
64
+ .home-surface-screen {
65
+ --home-surface-title-size: 2rem;
66
+ --home-surface-panel-padding: 1rem;
67
+ }
68
+
69
+ .home-surface-screen__header {
70
+ align-items: flex-start;
71
+ display: flex;
72
+ gap: 1rem;
73
+ justify-content: space-between;
74
+ }
75
+
76
+ .home-surface-screen__title {
77
+ font-size: var(--home-surface-title-size);
78
+ font-weight: 700;
79
+ letter-spacing: 0;
80
+ line-height: 1.1;
81
+ margin: 0 0 0.4rem;
82
+ }
83
+
84
+ .home-surface-screen__panel {
85
+ align-items: stretch;
86
+ display: flex;
87
+ flex-wrap: wrap;
88
+ gap: 1rem;
89
+ padding: var(--home-surface-panel-padding);
90
+ }
91
+
92
+ .home-surface-screen__status {
93
+ display: grid;
94
+ gap: 0.15rem;
95
+ min-width: 9rem;
96
+ }
97
+
98
+ .home-surface-screen__health-skeleton {
99
+ max-width: 5rem;
100
+ }
101
+
102
+ @media (max-width: 640px) {
103
+ .home-surface-screen {
104
+ --home-surface-title-size: 1.5rem;
105
+ }
106
+
107
+ .home-surface-screen__header {
108
+ flex-direction: column;
109
+ }
110
+
111
+ .home-surface-screen__header :deep(.v-btn) {
112
+ min-height: 48px;
113
+ width: 100%;
114
+ }
115
+ }
116
+ </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="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
+ On wider screens, collapsed navigation remains available as a rail. Phone layouts close the drawer and 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="Start with expanded navigation 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>