@jskit-ai/agent-docs 0.1.47 → 0.1.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/guide/agent/app-setup/a-more-interesting-shell.md +41 -35
- package/guide/agent/app-setup/authentication.md +0 -3
- package/guide/agent/app-setup/initial-scaffolding.md +42 -26
- package/guide/agent/app-setup/multi-homing.md +3 -2
- package/guide/agent/app-setup/quickstart.md +0 -2
- package/guide/agent/app-setup/working-with-the-jskit-cli.md +8 -8
- package/guide/agent/index.md +1 -1
- package/package.json +1 -1
- package/reference/autogen/packages/kernel.md +20 -0
- package/reference/autogen/packages/shell-web.md +22 -4
- package/reference/autogen/tooling/create-app.md +150 -0
|
@@ -2,43 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# A more interesting shell
|
|
4
4
|
|
|
5
|
-
In the first chapter, the app
|
|
5
|
+
In the first chapter, the app started with `shell-web` already installed. That is the normal JSKIT starting point: a real layout, navigation outlets, a first settings area, and a proper app-level error host.
|
|
6
6
|
|
|
7
7
|
This still is not authentication, not database work, and not multi-surface routing. The app remains small. But it starts to look and behave like something you could actually grow.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Running the shell
|
|
10
10
|
|
|
11
11
|
From inside `exampleapp`, run:
|
|
12
12
|
|
|
13
|
-
```bash
|
|
14
|
-
npx jskit add package shell-web
|
|
15
|
-
npm install
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
`jskit add` rewrites part of the scaffold and records the installed runtime package in `.jskit/lock.json`. The following `npm install` is what actually downloads the new package and its supporting dependencies.
|
|
19
|
-
|
|
20
|
-
To see the result, run:
|
|
21
|
-
|
|
22
13
|
```bash
|
|
23
14
|
npm run dev
|
|
24
15
|
npm run server
|
|
25
16
|
```
|
|
26
17
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
**Important: Install It Early**
|
|
30
|
-
|
|
31
|
-
`shell-web` is not just adding new files. It also **claims and replaces part of the original scaffold** so the app can switch from the plain starter layout to the real shell layout.
|
|
18
|
+
You want both processes running. The starter home page fetches `/api/health`, so the browser-facing dev server on port `5173` expects the backend on port `3000` to be alive as well.
|
|
32
19
|
|
|
33
|
-
|
|
20
|
+
**Minimal: Adding `shell-web` To A Bare Scaffold**
|
|
34
21
|
|
|
35
|
-
|
|
22
|
+
The normal `create-app` template already has `shell-web`. If you deliberately created the bare scaffold with `--minimal` or `--template minimal-shell`, install the shell before you personalize the files it claims:
|
|
36
23
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
```bash
|
|
25
|
+
npx jskit add package shell-web
|
|
26
|
+
npm install
|
|
27
|
+
```
|
|
40
28
|
|
|
41
|
-
|
|
29
|
+
That install is intentionally strict: `shell-web` only takes over scaffold files if they are still **exactly** the same as the files that `create-app --minimal` originally wrote. If you have already edited those starter files, `shell-web` refuses to claim them instead of overwriting your work.
|
|
42
30
|
|
|
43
31
|
Open `http://localhost:5173/` in the browser. The app lands in the `home` surface inside a real shell with an app bar, a navigation drawer, and a settings route at `/home/settings`.
|
|
44
32
|
|
|
@@ -285,7 +273,7 @@ So the shell story in this chapter is:
|
|
|
285
273
|
|
|
286
274
|
That is the first real example of JSKIT behaving like an extension system rather than just a scaffold generator.
|
|
287
275
|
|
|
288
|
-
## What `shell-web`
|
|
276
|
+
## What `shell-web` owns in the app
|
|
289
277
|
|
|
290
278
|
The most interesting files look roughly like this:
|
|
291
279
|
|
|
@@ -315,11 +303,11 @@ src/
|
|
|
315
303
|
index.vue
|
|
316
304
|
```
|
|
317
305
|
|
|
318
|
-
This chapter is the
|
|
306
|
+
This chapter is where the default scaffold starts to feel layered instead of flat.
|
|
319
307
|
|
|
320
308
|
### `package.json` and `.jskit/lock.json`
|
|
321
309
|
|
|
322
|
-
The first file worth reopening is still `package.json`.
|
|
310
|
+
The first file worth reopening is still `package.json`. Because the default app includes `shell-web`, the important shell dependency entries are already present:
|
|
323
311
|
|
|
324
312
|
```json
|
|
325
313
|
{
|
|
@@ -334,15 +322,15 @@ The important part is not just that `@jskit-ai/shell-web` appears. The package b
|
|
|
334
322
|
|
|
335
323
|
It is also worth noticing what does **not** happen here. The `placed-element` and `page` commands from this chapter mutate app-owned files, but they do not add a permanent runtime dependency to `package.json`. They are tooling actions, not runtime package installs.
|
|
336
324
|
|
|
337
|
-
The lock file
|
|
325
|
+
The lock file records this too. In a default app, `.jskit/lock.json` already records `@local/main`, `@jskit-ai/shell-web`, and the exact files and text mutations that the shell package owns.
|
|
338
326
|
|
|
339
|
-
That is worth noticing because
|
|
327
|
+
That is worth noticing because the default scaffold is not just copied files. It starts with a JSKIT-managed runtime package that owns concrete changes in your app tree.
|
|
340
328
|
|
|
341
329
|
### The `home` surface gets a real wrapper
|
|
342
330
|
|
|
343
331
|
The surface itself did not change. `home` is still the same surface defined in `config/public.js`. What changed is the page tree inside it.
|
|
344
332
|
|
|
345
|
-
|
|
333
|
+
In the shell-web scaffold, `src/pages/home.vue` is more than a tiny route owner with a `RouterView`. It wraps the surface in the app-owned shell layout:
|
|
346
334
|
|
|
347
335
|
```vue
|
|
348
336
|
<route lang="json">
|
|
@@ -369,9 +357,9 @@ import { RouterView } from "vue-router";
|
|
|
369
357
|
|
|
370
358
|
That one change explains a lot. The `home` surface is a shell-wrapped surface. Every child page under `src/pages/home/` renders inside that app-owned `ShellLayout`.
|
|
371
359
|
|
|
372
|
-
### `src/placement.js`
|
|
360
|
+
### `src/placement.js` is the placement registry
|
|
373
361
|
|
|
374
|
-
|
|
362
|
+
The app has a placement registry file:
|
|
375
363
|
|
|
376
364
|
```js
|
|
377
365
|
import { createPlacementRegistry } from "@jskit-ai/shell-web/client/placement";
|
|
@@ -388,7 +376,7 @@ export default function getPlacements() {
|
|
|
388
376
|
|
|
389
377
|
That file is the app-owned seam for placements. `shell-web` owns the runtime that can render placements, but the app owns the registry source that lists what should appear in those targets.
|
|
390
378
|
|
|
391
|
-
After the
|
|
379
|
+
After the scaffold's shell entries plus the `placed-element` and `page` commands from this chapter, the bottom of the file contains real placement entries:
|
|
392
380
|
|
|
393
381
|
```js
|
|
394
382
|
addPlacement({
|
|
@@ -498,7 +486,7 @@ So the shell itself remains stable. What changes is the registry that feeds it.
|
|
|
498
486
|
|
|
499
487
|
The placement registry only points at tokens. Those tokens still need to resolve to real Vue components somewhere. That happens in the app-local client provider in `packages/main/src/client/providers/MainClientProvider.js`.
|
|
500
488
|
|
|
501
|
-
After the
|
|
489
|
+
After the scaffold's shell registrations and the `Alerts Widget` generator command, that file contains registrations like these:
|
|
502
490
|
|
|
503
491
|
```js
|
|
504
492
|
import AlertsWidgetElement from "/src/components/AlertsWidgetElement.vue";
|
|
@@ -566,13 +554,31 @@ The default error policy is intent-based. Runtime code reports what kind of erro
|
|
|
566
554
|
- `app-recoverable` uses `banner`; shell refresh and recoverable navigation failures stay visible without blocking the app.
|
|
567
555
|
- `blocking` uses `dialog`; unexpected UI failures and other blocking errors require explicit attention.
|
|
568
556
|
|
|
557
|
+
When app code catches a dynamic import failure itself, report it through the shell async module recovery runtime so it uses the same reload banner as router chunk failures:
|
|
558
|
+
|
|
559
|
+
```js
|
|
560
|
+
import { useShellAsyncModuleRecoveryRuntime } from "@jskit-ai/shell-web/client";
|
|
561
|
+
|
|
562
|
+
const asyncModuleRecovery = useShellAsyncModuleRecoveryRuntime();
|
|
563
|
+
|
|
564
|
+
try {
|
|
565
|
+
await import("@xterm/xterm");
|
|
566
|
+
} catch (error) {
|
|
567
|
+
asyncModuleRecovery?.notify(error, {
|
|
568
|
+
label: "Terminal"
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
`useShellAsyncModuleRecoveryRuntime()` returns `null` when the shell runtime is not available in the current Vue context. That lets app-owned components use optional chaining instead of duplicating shell-web's internal injection token.
|
|
574
|
+
|
|
569
575
|
### The home page talks to the backend
|
|
570
576
|
|
|
571
577
|
`src/pages/home/index.vue` uses Vue Query to fetch `/api/health` and display the result in the UI.
|
|
572
578
|
|
|
573
|
-
That is why this chapter
|
|
579
|
+
That is why this chapter keeps running both `npm run dev` and `npm run server`. The page expects the backend to be alive.
|
|
574
580
|
|
|
575
|
-
This matters because it is
|
|
581
|
+
This matters because it is a tiny example of the frontend and backend participating in the same shell. The request itself is simple, but it proves the shell can surface runtime status instead of only rendering static chrome.
|
|
576
582
|
|
|
577
583
|
### The first client stores appear
|
|
578
584
|
|
|
@@ -676,6 +682,6 @@ The app is still structurally simple. `shell-web` just makes that simple app beh
|
|
|
676
682
|
|
|
677
683
|
## Summary
|
|
678
684
|
|
|
679
|
-
After this chapter, the app is still small, but
|
|
685
|
+
After this chapter, the app is still small, but you have inspected the shell shape it starts with. `shell-web` provides an app-owned shell layout, a placement registry, a shell error host, menu-link tokens in the local client provider, real drawer navigation, and the first nested settings section under `home`.
|
|
680
686
|
|
|
681
687
|
More importantly, this chapter is where placements stop being theory. The shell already uses them for `Home`, `Settings`, and the starter `General` settings page. Then you inspect the available targets, place real UI into the outer shell, and add more child settings pages that automatically land in the nested settings menu. That is the first real example of JSKIT working as an extension system rather than just a scaffold generator.
|
|
@@ -12,9 +12,6 @@ To get back to the same starting point as the end of the previous chapter, run:
|
|
|
12
12
|
npx @jskit-ai/create-app exampleapp --tenancy-mode none
|
|
13
13
|
cd exampleapp
|
|
14
14
|
npm install
|
|
15
|
-
|
|
16
|
-
npx jskit add package shell-web
|
|
17
|
-
npm install
|
|
18
15
|
```
|
|
19
16
|
|
|
20
17
|
If you are already continuing from the previous chapter, you are already in the right place and can skip that setup.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Initial scaffolding
|
|
4
4
|
|
|
5
|
-
In this first chapter, we are going to create the smallest useful JSKIT app, install its dependencies, run it locally, and read the scaffold it gives us. The goal of this chapter is to explain how to get started with JSKIT and to understand what the generator produced, which files matter, and why the project already has concepts like _surfaces_, a local runtime package, and a server even before we add any real features.
|
|
5
|
+
In this first chapter, we are going to create the smallest useful JSKIT app, install its dependencies, run it locally, and read the scaffold it gives us. The default scaffold already includes `shell-web`, so the app starts with a real shell, placements, settings routes, and the app-level error host. The goal of this chapter is to explain how to get started with JSKIT and to understand what the generator produced, which files matter, and why the project already has concepts like _surfaces_, a local runtime package, and a server even before we add any real features.
|
|
6
6
|
|
|
7
7
|
Start in a working directory and run:
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ cd exampleapp
|
|
|
12
12
|
npm install
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
The first command creates a new folder called `exampleapp` and fills it with JSKIT's
|
|
15
|
+
The first command creates a new folder called `exampleapp` and fills it with JSKIT's default shell-web app template. The `exampleapp` name is used in a few template replacements, such as the package name and the browser title. The `--tenancy-mode none` flag tells JSKIT to start with the smallest routing model. In this mode, the app is not workspace-aware (more of this later in the guide, when multihoming is introduced). That keeps the first scaffold easier to read because there is no workspace slug handling yet.
|
|
16
16
|
|
|
17
17
|
If you are working with an AI agent and want the agent to drive the initial JSKIT setup conversation, use the dedicated seed path:
|
|
18
18
|
|
|
@@ -30,7 +30,15 @@ npm install
|
|
|
30
30
|
|
|
31
31
|
After that promotion, the overwritten app `AGENTS.md` stays deliberately small. Use it with the distributed JSKIT agent docs when planning or implementing app changes. The durable app memory lives in `.jskit/APP_BLUEPRINT.md` and should describe product and architecture decisions, not become an implementation task list.
|
|
32
32
|
|
|
33
|
-
After creating the real app scaffolding (the
|
|
33
|
+
After creating the real app scaffolding (the default shell-web app, not the seed wrapper), you will need to run `npm install` to install dependencies.
|
|
34
|
+
|
|
35
|
+
If you deliberately need the older bare scaffold, use `--minimal` or `--template minimal-shell`. That is useful for descriptor tests or unusual package-development flows, but it is not the normal starting point for a JSKIT app:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @jskit-ai/create-app exampleapp --minimal --tenancy-mode none
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Minimal apps can still install the standard shell later with `npx jskit add package shell-web`, as long as the starter files it claims have not been edited first.
|
|
34
42
|
|
|
35
43
|
If you already know you want a small non-workspace baseline right after the scaffold, this is the shortest reproducible path:
|
|
36
44
|
|
|
@@ -47,8 +55,6 @@ npx @jskit-ai/create-app exampleapp --tenancy-mode none
|
|
|
47
55
|
cd exampleapp
|
|
48
56
|
npm install
|
|
49
57
|
|
|
50
|
-
npx jskit add package shell-web
|
|
51
|
-
|
|
52
58
|
npx jskit add package auth-provider-supabase-core \
|
|
53
59
|
--auth-supabase-url "$SUPABASE_URL" \
|
|
54
60
|
--auth-supabase-publishable-key "$SUPABASE_KEY" \
|
|
@@ -108,21 +114,19 @@ and press Tab, JSKIT will complete that subcommand argument to `package`.
|
|
|
108
114
|
|
|
109
115
|
The `jskit` command is central in the use of JSKIT. The autocompletion will help speeding things up.
|
|
110
116
|
|
|
111
|
-
To see the app in the browser, the
|
|
117
|
+
To see the app in the browser with the starter health check working, run the frontend and backend in two terminals:
|
|
112
118
|
|
|
113
119
|
```bash
|
|
114
120
|
npm run dev
|
|
115
121
|
```
|
|
116
122
|
|
|
117
|
-
Then open `http://localhost:5173/` in the browser. The starter screen is intentionally plain. That is a good thing. It proves the shell is wired correctly before we start adding packages.
|
|
118
|
-
|
|
119
|
-
For the very first page, `npm run dev` is enough because the scaffold does not make any real API calls yet. For normal JSKIT development, though, you will usually keep a second terminal open and run the backend as well:
|
|
120
|
-
|
|
121
123
|
```bash
|
|
122
124
|
npm run server
|
|
123
125
|
```
|
|
124
126
|
|
|
125
|
-
|
|
127
|
+
Then open `http://localhost:5173/` in the browser. The starter screen is intentionally small. That is a good thing. It proves the shell is wired correctly before we start adding packages.
|
|
128
|
+
|
|
129
|
+
`npm run server` starts the Fastify server on port `3000`. The default home page already uses the Vite proxy to request `/api/health`, so keep the backend running when you want the starter status to be fully green. A good habit is to treat `npm run dev` as the browser-facing process and `npm run server` as the app runtime behind it.
|
|
126
130
|
|
|
127
131
|
If you want a fast sanity check that the backend is alive, open `http://localhost:3000/api/health` or request it from the terminal:
|
|
128
132
|
|
|
@@ -383,7 +387,7 @@ surfaceRuntime.listEnabledSurfaceIds(); // ["home"]
|
|
|
383
387
|
surfaceRuntime.resolveSurfaceFromPathname("/home"); // "home"
|
|
384
388
|
```
|
|
385
389
|
|
|
386
|
-
`surfaceMode` is not another surface definition. It is the current viewing mode for the app. In a
|
|
390
|
+
`surfaceMode` is not another surface definition. It is the current viewing mode for the app. In a starter app, `VITE_SURFACE` is usually unset, so `surfaceMode` becomes `"all"`, meaning "do not restrict the router to one specific surface". Later, when you run surface-specific profiles, the same runtime can narrow the active routes to just one surface. In the scaffold scripts, `npm run dev:home` is simply setting `VITE_SURFACE=home`, while `npm run dev` and `npm run dev:all` leave the client in unrestricted `"all"` mode.
|
|
387
391
|
|
|
388
392
|
`createShellRouter(...)` uses that `surfaceRuntime` object to assemble the actual router. Concretely, it does this:
|
|
389
393
|
|
|
@@ -403,7 +407,7 @@ In the starter app, with only `home`, this is almost boring. It mostly means:
|
|
|
403
407
|
|
|
404
408
|
`createPinia()` is the standard shared-state layer for the client app. JSKIT installs it from day 0 so later packages can expose Vue-facing stores without each app having to bolt Pinia on afterward.
|
|
405
409
|
|
|
406
|
-
|
|
410
|
+
The default scaffold already has the `shell-web` client stores available, such as `useShellLayoutStore()` and the shell error presentation store behind `ShellErrorHost`. Pinia is also there from day 0 so later packages, such as `auth-web`, can add their own stores without changing the app bootstrap.
|
|
407
411
|
|
|
408
412
|
`createVuetify(...)` is the ordinary UI plugin setup. There is nothing especially JSKIT-specific there; it configures theme settings and icon aliases before the router is mounted. Vuetify components are auto-imported by `vite-plugin-vuetify`, so the scaffold does not register the full Vuetify component namespace in the client bundle.
|
|
409
413
|
|
|
@@ -521,7 +525,7 @@ export {
|
|
|
521
525
|
};
|
|
522
526
|
```
|
|
523
527
|
|
|
524
|
-
The important idea is that this provider is not rendering UI directly. It is registering token-addressable client components into the application container. In the
|
|
528
|
+
The important idea is that this provider is not rendering UI directly. It is registering token-addressable client components into the application container. In the default scaffold, the list starts with shell link components that the placement runtime can use for menus and tabs. Later package installs and generators can extend this file by adding imports and `registerMainClientComponent(...)` calls for more app-owned client components. In other words, this file is the app's local registration seam.
|
|
525
529
|
|
|
526
530
|
```js
|
|
527
531
|
import MenuLinkItem from "/src/components/menus/MenuLinkItem.vue";
|
|
@@ -574,7 +578,7 @@ So the order is:
|
|
|
574
578
|
2. the generated route record gets a normal `meta` object
|
|
575
579
|
3. JSKIT reads that `meta` during routing
|
|
576
580
|
|
|
577
|
-
`src/App.vue` is deliberately small. It is
|
|
581
|
+
`src/App.vue` is deliberately small. It is the outer Vuetify app shell, the top-level `RouterView`, and `ShellErrorHost`. That is another pattern you should get used to in JSKIT: the app root stays thin, and most behavior is pushed toward packages, page files, and runtime providers.
|
|
578
582
|
|
|
579
583
|
**Container: App Methods**
|
|
580
584
|
|
|
@@ -686,7 +690,7 @@ async function createServer() {
|
|
|
686
690
|
|
|
687
691
|
The health route is built in, but the more important idea is that the server is already prepared to validate HTTP input with Fastify's normal JSON Schema path, load the JSKIT provider runtime from the app itself, and constrain requests by surface.
|
|
688
692
|
|
|
689
|
-
You will also notice `config/server.js`. In the base
|
|
693
|
+
You will also notice `config/server.js`. In the base app it is intentionally almost empty. It is there to reserve a clear place for server-side configuration as backend features are added, without pretending the starter app already has feature-specific server configuration.
|
|
690
694
|
|
|
691
695
|
The small `server/lib/` directory exists to keep that server boot code tidy. `runtimeEnv.js` reads environment variables such as port and host. `surfaceRuntime.js` builds the same surface runtime that the client uses, so the server and browser agree on what surfaces exist. In the scaffold scripts, `npm run server:home` is simply setting `SERVER_SURFACE=home`, while `npm run server` and `npm run server:all` leave the server unrestricted.
|
|
692
696
|
|
|
@@ -760,7 +764,7 @@ The `.jskit/lock.json` file is also important. Treat it like JSKIT's own lock an
|
|
|
760
764
|
|
|
761
765
|
This file is narrower than `package.json`. `package.json` lists every npm dependency the app needs, including plain libraries such as Vue, Fastify, and Vuetify. `.jskit/lock.json` only tracks JSKIT package-install state: which JSKIT runtime packages were installed into the app and which files, text mutations, and dependency entries JSKIT is managing on their behalf.
|
|
762
766
|
|
|
763
|
-
On a brand-new app, the lock file is telling you that
|
|
767
|
+
On a brand-new default app, the lock file is telling you that the app-local package and the standard shell package are installed from the start:
|
|
764
768
|
|
|
765
769
|
```json
|
|
766
770
|
{
|
|
@@ -774,35 +778,47 @@ On a brand-new app, the lock file is telling you that only the local app package
|
|
|
774
778
|
"packagePath": "packages/main",
|
|
775
779
|
"descriptorPath": "packages/main/package.descriptor.mjs"
|
|
776
780
|
},
|
|
781
|
+
"managed": { "...": "..." }
|
|
782
|
+
},
|
|
783
|
+
"@jskit-ai/shell-web": {
|
|
784
|
+
"packageId": "@jskit-ai/shell-web",
|
|
785
|
+
"source": {
|
|
786
|
+
"type": "catalog"
|
|
787
|
+
},
|
|
777
788
|
"managed": {
|
|
778
789
|
"packageJson": {
|
|
779
790
|
"dependencies": {
|
|
780
|
-
"@
|
|
781
|
-
"value": "
|
|
791
|
+
"@jskit-ai/shell-web": {
|
|
792
|
+
"value": "0.x"
|
|
793
|
+
},
|
|
794
|
+
"@mdi/js": {
|
|
795
|
+
"value": "^7.4.47"
|
|
782
796
|
}
|
|
783
797
|
}
|
|
784
|
-
}
|
|
798
|
+
},
|
|
799
|
+
"files": { "...": "..." },
|
|
800
|
+
"text": { "...": "..." }
|
|
785
801
|
}
|
|
786
802
|
}
|
|
787
803
|
}
|
|
788
804
|
}
|
|
789
805
|
```
|
|
790
806
|
|
|
791
|
-
That is a useful anchor point. Before you add anything else, JSKIT already knows about
|
|
807
|
+
That is a useful anchor point. Before you add anything else, JSKIT already knows about the runtime package that belongs to your app and the shell runtime package that owns the default shell files, placement config, and error host wiring.
|
|
792
808
|
|
|
793
|
-
That is why you saw `@jskit-ai/kernel` and `@jskit-ai/http-runtime` earlier in `package.json`, but you do not see them here. They are npm dependencies of the scaffold,
|
|
809
|
+
That is why you saw `@jskit-ai/kernel` and `@jskit-ai/http-runtime` earlier in `package.json`, but you do not see them as separate installed packages here. They are npm dependencies of the scaffold, while `.jskit/lock.json` records JSKIT package install state and managed app mutations.
|
|
794
810
|
|
|
795
811
|
### Other files and options
|
|
796
812
|
|
|
797
813
|
The remaining files are easier to understand once you know the core pieces above. `vite.config.mjs` configures the frontend build and the `/api` proxy used during development. `index.html` is the HTML shell Vite uses to mount Vue. `tests/` contains basic smoke tests so the app has a verification path from day one. The `scripts/` directory is intentionally small because JSKIT maintenance helpers such as `verify`, `jskit:update`, `devlinks`, and `release` are package-owned CLI commands rather than copied app scripts.
|
|
798
814
|
|
|
799
|
-
The `create-app` command also accepts a few other flags that are useful without changing the basic meaning of this chapter's setup. `--title <text>` lets you replace the browser title and other template text with a friendlier app name. `--target <path>` lets you choose a different output directory instead of the default `./exampleapp`. `--tenancy-mode <mode>` can seed `none`, `personal`, or `workspaces`; for this chapter we intentionally use `none` so the first scaffold stays small and non-workspace. `--force` allows writing into a non-empty target directory when you know that is what you want. `--dry-run` prints the planned file writes without touching the filesystem, which is useful when you want to inspect what the generator would do. `-h` or `--help` prints the command help.
|
|
815
|
+
The `create-app` command also accepts a few other flags that are useful without changing the basic meaning of this chapter's setup. `--title <text>` lets you replace the browser title and other template text with a friendlier app name. `--target <path>` lets you choose a different output directory instead of the default `./exampleapp`. `--tenancy-mode <mode>` can seed `none`, `personal`, or `workspaces`; for this chapter we intentionally use `none` so the first scaffold stays small and non-workspace. `--minimal` selects the bare `minimal-shell` template instead of the default shell-web app template. `--force` allows writing into a non-empty target directory when you know that is what you want. `--dry-run` prints the planned file writes without touching the filesystem, which is useful when you want to inspect what the generator would do. `-h` or `--help` prints the command help.
|
|
800
816
|
|
|
801
|
-
**
|
|
817
|
+
**Template: Use The Default Shell Unless You Need Minimal**
|
|
802
818
|
|
|
803
|
-
|
|
819
|
+
The default app already includes `shell-web`. Start there for normal JSKIT apps because it gives you placement-aware navigation, settings routes, and shell-level error presentation immediately.
|
|
804
820
|
|
|
805
|
-
`
|
|
821
|
+
Use `--minimal` only when you deliberately need the bare scaffold. If you later add `shell-web` to a minimal app, do it before editing files such as `src/App.vue`, `src/pages/home.vue`, and `src/pages/home/index.vue`, because the package only claims files that still match the untouched minimal baseline exactly.
|
|
806
822
|
|
|
807
823
|
## Summary
|
|
808
824
|
|
|
@@ -510,7 +510,7 @@ The other returned values are there for more advanced cases.
|
|
|
510
510
|
- `placementContext` matters when a page needs to read the current shell/bootstrap context directly, for example available workspaces or current permissions already in the shell state.
|
|
511
511
|
- `mergePlacementContext` is for pages that need to push refreshed workspace data back into the shell runtime after a fetch or save.
|
|
512
512
|
|
|
513
|
-
That second case is real, but it is more advanced. It is
|
|
513
|
+
That second case is real, but it is more advanced. It is available for app-owned workspace pages that intentionally need to push refreshed workspace state back into shell-visible context after a save.
|
|
514
514
|
|
|
515
515
|
For normal custom page code, you usually do **not** start there. Start with `workspaceSlugFromRoute`.
|
|
516
516
|
|
|
@@ -589,7 +589,8 @@ That one block explains a lot of the workspace shell behavior.
|
|
|
589
589
|
- `shell.identity` carries the workspace selector
|
|
590
590
|
- `shell.status` can show a pending-invites cue
|
|
591
591
|
- the admin surface gets workspace tools through `shell.status`
|
|
592
|
-
- the admin
|
|
592
|
+
- the admin surface gets a workspace tools menu with `Settings` and `Members`
|
|
593
|
+
- the workspace settings shell exposes its own nested menu host for app-owned settings child pages
|
|
593
594
|
|
|
594
595
|
If you want to add your own app-owned page into that top cog menu, first ask JSKIT which semantic placements exist:
|
|
595
596
|
|
|
@@ -50,8 +50,6 @@ npx @jskit-ai/create-app testapp --tenancy-mode personal
|
|
|
50
50
|
cd testapp
|
|
51
51
|
npm install
|
|
52
52
|
|
|
53
|
-
npx jskit add package shell-web
|
|
54
|
-
|
|
55
53
|
npx jskit add package auth-provider-supabase-core \
|
|
56
54
|
--auth-supabase-url "$SUPABASE_URL" \
|
|
57
55
|
--auth-supabase-publishable-key "$SUPABASE_KEY" \
|
|
@@ -28,7 +28,7 @@ The easiest way to understand `jskit` is to separate it from the other tools in
|
|
|
28
28
|
|
|
29
29
|
That separation is crucial.
|
|
30
30
|
|
|
31
|
-
When you run a command such as `npx jskit add package
|
|
31
|
+
When you run a command such as `npx jskit add package auth-provider-supabase-core`, JSKIT updates app-owned files and records what it changed. It does **not** replace npm, Vite, or Knex.
|
|
32
32
|
|
|
33
33
|
The most important record of that managed state lives here:
|
|
34
34
|
|
|
@@ -476,7 +476,7 @@ This is not required, but it is genuinely useful once you start using commands s
|
|
|
476
476
|
The install command comes in two main forms:
|
|
477
477
|
|
|
478
478
|
```bash
|
|
479
|
-
npx jskit add package
|
|
479
|
+
npx jskit add package auth-provider-supabase-core
|
|
480
480
|
npx jskit add bundle auth-base
|
|
481
481
|
```
|
|
482
482
|
|
|
@@ -487,22 +487,22 @@ Those two examples look similar, but they do different things.
|
|
|
487
487
|
Use this when you know the exact runtime package you want:
|
|
488
488
|
|
|
489
489
|
```bash
|
|
490
|
-
npx jskit add package
|
|
490
|
+
npx jskit add package users-web
|
|
491
491
|
```
|
|
492
492
|
|
|
493
|
-
This is the
|
|
493
|
+
This is the shape of the package install commands used throughout the rest of the guide.
|
|
494
494
|
|
|
495
495
|
Important defaults:
|
|
496
496
|
|
|
497
|
-
- short ids such as `
|
|
497
|
+
- short ids such as `users-web` resolve to `@jskit-ai/users-web` when available
|
|
498
498
|
- JSKIT records the install in `.jskit/lock.json`
|
|
499
499
|
- JSKIT rewrites app-owned managed files as needed
|
|
500
500
|
- npm install does **not** run unless you ask for it with `--run-npm-install`
|
|
501
501
|
|
|
502
|
-
That last point is why the normal guide flow is still:
|
|
502
|
+
That last point is why the normal guide flow after adding a runtime package is still:
|
|
503
503
|
|
|
504
504
|
```bash
|
|
505
|
-
npx jskit add package
|
|
505
|
+
npx jskit add package users-web
|
|
506
506
|
npm install
|
|
507
507
|
```
|
|
508
508
|
|
|
@@ -1079,4 +1079,4 @@ And then keep one more distinction in your head:
|
|
|
1079
1079
|
|
|
1080
1080
|
That is the mental model the rest of the guide assumes.
|
|
1081
1081
|
|
|
1082
|
-
The next chapter goes back to the normal hands-on flow and uses that model
|
|
1082
|
+
The next chapter goes back to the normal hands-on flow and uses that model while inspecting the shell that default apps already include.
|
package/guide/agent/index.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
This guide is the main hands-on path through JSKIT.
|
|
6
6
|
|
|
7
|
-
It starts with a fast reproducible Quickstart, then steps back to the
|
|
7
|
+
It starts with a fast reproducible Quickstart, then steps back to the scaffold-first chapters that explain the default shell and runtime shape. After that, it introduces the database-backed users layer, expands into console and workspace-aware app structure, and adds a small `App extras` section for optional runtime packages such as the Android Capacitor shell, realtime, and assistant. Finally, the guide breaks out generator-specific workflows into their own section.
|
|
8
8
|
|
|
9
9
|
## Table of Contents
|
|
10
10
|
|
package/package.json
CHANGED
|
@@ -657,6 +657,19 @@ Exports
|
|
|
657
657
|
Local functions
|
|
658
658
|
- `normalizeClientAppConfig(source = {})`
|
|
659
659
|
|
|
660
|
+
### `client/asyncModuleRecovery.js`
|
|
661
|
+
Exports
|
|
662
|
+
- `createAsyncModuleRecoveryState({ label = "App module", message = "", retry = null } = {})`
|
|
663
|
+
- `dismissAsyncModuleRecovery(state)`
|
|
664
|
+
- `dynamicImportErrorMessage(error = null, { label = "App module", stale = isDynamicImportError(error) } = {})`
|
|
665
|
+
- `guardedReloadApp({ browserWindow = typeof window !== "undefined" ? window : null, fetchFn = typeof fetch === "function" ? fetch : null, state = null, label = "App", message = "The app cannot reload because the app server is not reachable. Restart the server, then click Retry or Reload." } = {})`
|
|
666
|
+
- `installAsyncModuleRecoveryHandlers({ router = null, state, label = "App module", onNotify = null, windowObject = typeof window !== "undefined" ? window : null } = {})`
|
|
667
|
+
- `isDynamicImportError(error = null)`
|
|
668
|
+
- `notifyAsyncModuleLoadError(state, error = null, { label = "App module", message = "", retry = null, stale = isDynamicImportError(error) } = {})`
|
|
669
|
+
Local functions
|
|
670
|
+
- `isRecord(value)`
|
|
671
|
+
- `errorText(error = null)`
|
|
672
|
+
|
|
660
673
|
### `client/componentInteraction.js`
|
|
661
674
|
Exports
|
|
662
675
|
- `createComponentInteractionEmitter(emit)`
|
|
@@ -673,6 +686,13 @@ Exports
|
|
|
673
686
|
- `getClientAppConfig`
|
|
674
687
|
- `resolveMobileConfig`
|
|
675
688
|
- `resolveClientAssetMode`
|
|
689
|
+
- `createAsyncModuleRecoveryState`
|
|
690
|
+
- `dismissAsyncModuleRecovery`
|
|
691
|
+
- `dynamicImportErrorMessage`
|
|
692
|
+
- `guardedReloadApp`
|
|
693
|
+
- `installAsyncModuleRecoveryHandlers`
|
|
694
|
+
- `isDynamicImportError`
|
|
695
|
+
- `notifyAsyncModuleLoadError`
|
|
676
696
|
- `normalizeIncomingAppUrl`
|
|
677
697
|
- `registerMobileLaunchRouting`
|
|
678
698
|
- `resolveClientBootstrapDebugEnabled`
|
|
@@ -14,6 +14,17 @@ Use this on demand; do not load the full index at startup.
|
|
|
14
14
|
|
|
15
15
|
### src
|
|
16
16
|
|
|
17
|
+
### `src/client/asyncModuleRecovery/index.js`
|
|
18
|
+
Exports
|
|
19
|
+
- `SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY`
|
|
20
|
+
- `useShellAsyncModuleRecoveryRuntime`
|
|
21
|
+
|
|
22
|
+
### `src/client/asyncModuleRecovery/inject.js`
|
|
23
|
+
Exports
|
|
24
|
+
- `SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY`
|
|
25
|
+
- `isShellAsyncModuleRecoveryRuntime(value)`
|
|
26
|
+
- `useShellAsyncModuleRecoveryRuntime()`
|
|
27
|
+
|
|
17
28
|
### `src/client/bootstrap/bootstrapErrorStatus.js`
|
|
18
29
|
Exports
|
|
19
30
|
- `resolveBootstrapErrorStatusCode(error)`
|
|
@@ -194,6 +205,8 @@ Exports
|
|
|
194
205
|
- `useShellLayoutState`
|
|
195
206
|
- `useShellLayoutStore`
|
|
196
207
|
- `useShellErrorPresentationStore`
|
|
208
|
+
- `SHELL_ASYNC_MODULE_RECOVERY_RUNTIME_KEY`
|
|
209
|
+
- `useShellAsyncModuleRecoveryRuntime`
|
|
197
210
|
- `BOOTSTRAP_PAYLOAD_HANDLER_TAG`
|
|
198
211
|
- `registerBootstrapPayloadHandler`
|
|
199
212
|
- `resolveBootstrapPayloadHandlers`
|
|
@@ -308,21 +321,26 @@ Local functions
|
|
|
308
321
|
- `isValidSurfaceIdToken(value = "")`
|
|
309
322
|
- `toInteger(value, fallback = 1000)`
|
|
310
323
|
|
|
324
|
+
### `src/client/providers/appModuleLoadFailure.js`
|
|
325
|
+
Exports
|
|
326
|
+
- `isMissingDynamicModule(error, moduleSpecifier)`
|
|
327
|
+
- `notifyDynamicImportFailure(asyncModuleRecoveryRuntime, error, { label = "App module" } = {})`
|
|
328
|
+
|
|
311
329
|
### `src/client/providers/ShellWebClientProvider.js`
|
|
312
330
|
Exports
|
|
313
331
|
- `ShellWebClientProvider`
|
|
314
332
|
- `resolveAppPlacementTopologyExport(exported, logger)`
|
|
315
333
|
Local functions
|
|
316
|
-
- `
|
|
317
|
-
- `
|
|
318
|
-
- `loadAppPlacementTopology(logger)`
|
|
334
|
+
- `loadAppPlacementDefinitions(logger, asyncModuleRecoveryRuntime = null)`
|
|
335
|
+
- `loadAppPlacementTopology(logger, asyncModuleRecoveryRuntime = null)`
|
|
319
336
|
- `createErrorConfigToolkit(errorRuntime)`
|
|
320
|
-
- `loadAppErrorConfig(logger, errorRuntime)`
|
|
337
|
+
- `loadAppErrorConfig(logger, errorRuntime, asyncModuleRecoveryRuntime = null)`
|
|
321
338
|
- `applyAppErrorConfig(errorRuntime, errorConfig = {})`
|
|
322
339
|
- `isPullRefreshQuery(query = null)`
|
|
323
340
|
- `createShellRefreshRuntime({ app, logger = null } = {})`
|
|
324
341
|
- `installVueErrorBridge(vueApp, errorRuntime, logger)`
|
|
325
342
|
- `installRouterErrorBridge(app, errorRuntime, logger)`
|
|
343
|
+
- `createShellAsyncModuleRecoveryRuntime({ app, logger = null } = {})`
|
|
326
344
|
|
|
327
345
|
### `src/client/runtime/bootstrapRuntime.js`
|
|
328
346
|
Exports
|
|
@@ -142,6 +142,26 @@ Exports
|
|
|
142
142
|
Exports
|
|
143
143
|
- None
|
|
144
144
|
|
|
145
|
+
### `templates/base-shell/src/components/menus/MenuLinkItem.vue`
|
|
146
|
+
Exports
|
|
147
|
+
- None
|
|
148
|
+
|
|
149
|
+
### `templates/base-shell/src/components/menus/SurfaceAwareMenuLinkItem.vue`
|
|
150
|
+
Exports
|
|
151
|
+
- None
|
|
152
|
+
|
|
153
|
+
### `templates/base-shell/src/components/menus/TabLinkItem.vue`
|
|
154
|
+
Exports
|
|
155
|
+
- None
|
|
156
|
+
|
|
157
|
+
### `templates/base-shell/src/components/ShellLayout.vue`
|
|
158
|
+
Exports
|
|
159
|
+
- `default`
|
|
160
|
+
|
|
161
|
+
### `templates/base-shell/src/error.js`
|
|
162
|
+
Exports
|
|
163
|
+
- None
|
|
164
|
+
|
|
145
165
|
### `templates/base-shell/src/main.js`
|
|
146
166
|
Exports
|
|
147
167
|
- None
|
|
@@ -154,6 +174,28 @@ Exports
|
|
|
154
174
|
Exports
|
|
155
175
|
- None
|
|
156
176
|
|
|
177
|
+
### `templates/base-shell/src/pages/home/settings.vue`
|
|
178
|
+
Exports
|
|
179
|
+
- None
|
|
180
|
+
|
|
181
|
+
### `templates/base-shell/src/pages/home/settings/general/index.vue`
|
|
182
|
+
Exports
|
|
183
|
+
- None
|
|
184
|
+
|
|
185
|
+
### `templates/base-shell/src/pages/home/settings/index.vue`
|
|
186
|
+
Exports
|
|
187
|
+
- None
|
|
188
|
+
|
|
189
|
+
### `templates/base-shell/src/placement.js`
|
|
190
|
+
Exports
|
|
191
|
+
- `addPlacement`
|
|
192
|
+
- `getPlacements()`
|
|
193
|
+
|
|
194
|
+
### `templates/base-shell/src/placementTopology.js`
|
|
195
|
+
Exports
|
|
196
|
+
- `addPlacementTopology(value = {})`
|
|
197
|
+
- `default`
|
|
198
|
+
|
|
157
199
|
### `templates/base-shell/src/views/NotFound.vue`
|
|
158
200
|
Exports
|
|
159
201
|
- None
|
|
@@ -169,6 +211,114 @@ Exports
|
|
|
169
211
|
- `toPositiveInt(value, fallback)`
|
|
170
212
|
- `loadViteDevProxyEntries({ appRootUrl = import.meta.url, fallbackTarget = "" } = {})`
|
|
171
213
|
|
|
214
|
+
### `templates/minimal-shell/bin/server.js`
|
|
215
|
+
Exports
|
|
216
|
+
- None
|
|
217
|
+
|
|
218
|
+
### `templates/minimal-shell/config/public.js`
|
|
219
|
+
Exports
|
|
220
|
+
- `config`
|
|
221
|
+
|
|
222
|
+
### `templates/minimal-shell/config/server.js`
|
|
223
|
+
Exports
|
|
224
|
+
- `config`
|
|
225
|
+
|
|
226
|
+
### `templates/minimal-shell/config/surfaceAccessPolicies.js`
|
|
227
|
+
Exports
|
|
228
|
+
- `surfaceAccessPolicies`
|
|
229
|
+
|
|
230
|
+
### `templates/minimal-shell/eslint.config.mjs`
|
|
231
|
+
Exports
|
|
232
|
+
- None
|
|
233
|
+
|
|
234
|
+
### `templates/minimal-shell/packages/main/package.descriptor.mjs`
|
|
235
|
+
Exports
|
|
236
|
+
- None
|
|
237
|
+
|
|
238
|
+
### `templates/minimal-shell/packages/main/src/client/index.js`
|
|
239
|
+
Exports
|
|
240
|
+
- `MainClientProvider`
|
|
241
|
+
- `registerMainClientComponent`
|
|
242
|
+
|
|
243
|
+
### `templates/minimal-shell/packages/main/src/client/providers/MainClientProvider.js`
|
|
244
|
+
Exports
|
|
245
|
+
- `MainClientProvider`
|
|
246
|
+
- `registerMainClientComponent(token, resolveComponent)`
|
|
247
|
+
|
|
248
|
+
### `templates/minimal-shell/packages/main/src/server/index.js`
|
|
249
|
+
Exports
|
|
250
|
+
- `MainServiceProvider`
|
|
251
|
+
|
|
252
|
+
### `templates/minimal-shell/packages/main/src/server/loadAppConfig.js`
|
|
253
|
+
Exports
|
|
254
|
+
- `loadAppConfig({ moduleUrl = import.meta.url } = {})`
|
|
255
|
+
|
|
256
|
+
### `templates/minimal-shell/packages/main/src/server/MainServiceProvider.js`
|
|
257
|
+
Exports
|
|
258
|
+
- `MainServiceProvider`
|
|
259
|
+
|
|
260
|
+
### `templates/minimal-shell/packages/main/src/shared/index.js`
|
|
261
|
+
Exports
|
|
262
|
+
- None
|
|
263
|
+
|
|
264
|
+
### `templates/minimal-shell/packages/main/src/shared/schemas/index.js`
|
|
265
|
+
Exports
|
|
266
|
+
- None
|
|
267
|
+
|
|
268
|
+
### `templates/minimal-shell/server.js`
|
|
269
|
+
Exports
|
|
270
|
+
- `createServer()`
|
|
271
|
+
- `startServer(options = {})`
|
|
272
|
+
Local functions
|
|
273
|
+
- `toRequestPathname(urlValue)`
|
|
274
|
+
- `isApiPath(pathname)`
|
|
275
|
+
- `hasFileExtension(pathname)`
|
|
276
|
+
- `resolveGlobalUiPaths(runtimeGlobalUiPaths = [])`
|
|
277
|
+
- `resolveStaticFilePath(pathname)`
|
|
278
|
+
- `canServeStaticFile(distRoot, relativePath)`
|
|
279
|
+
|
|
280
|
+
### `templates/minimal-shell/server/lib/runtimeEnv.js`
|
|
281
|
+
Exports
|
|
282
|
+
- `resolveRuntimeEnv()`
|
|
283
|
+
Local functions
|
|
284
|
+
- `toPort(value, fallback = 3000)`
|
|
285
|
+
- `ensureRuntimeEnvLoaded()`
|
|
286
|
+
|
|
287
|
+
### `templates/minimal-shell/server/lib/surfaceRuntime.js`
|
|
288
|
+
Exports
|
|
289
|
+
- `surfaceRuntime`
|
|
290
|
+
|
|
291
|
+
### `templates/minimal-shell/src/App.vue`
|
|
292
|
+
Exports
|
|
293
|
+
- None
|
|
294
|
+
|
|
295
|
+
### `templates/minimal-shell/src/main.js`
|
|
296
|
+
Exports
|
|
297
|
+
- None
|
|
298
|
+
|
|
299
|
+
### `templates/minimal-shell/src/pages/home.vue`
|
|
300
|
+
Exports
|
|
301
|
+
- None
|
|
302
|
+
|
|
303
|
+
### `templates/minimal-shell/src/pages/home/index.vue`
|
|
304
|
+
Exports
|
|
305
|
+
- None
|
|
306
|
+
|
|
307
|
+
### `templates/minimal-shell/src/views/NotFound.vue`
|
|
308
|
+
Exports
|
|
309
|
+
- None
|
|
310
|
+
|
|
311
|
+
### `templates/minimal-shell/vite.config.mjs`
|
|
312
|
+
Exports
|
|
313
|
+
- None
|
|
314
|
+
Local functions
|
|
315
|
+
- `clientEntry(()`
|
|
316
|
+
|
|
317
|
+
### `templates/minimal-shell/vite.shared.mjs`
|
|
318
|
+
Exports
|
|
319
|
+
- `toPositiveInt(value, fallback)`
|
|
320
|
+
- `loadViteDevProxyEntries({ appRootUrl = import.meta.url, fallbackTarget = "" } = {})`
|
|
321
|
+
|
|
172
322
|
### bin
|
|
173
323
|
|
|
174
324
|
### `bin/jskit-create-app.js`
|