@jskit-ai/assistant 0.1.42 → 0.1.44
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/package.descriptor.mjs +4 -2
- package/package.json +2 -2
- package/src/server/pageSupport.js +4 -5
- package/test/subcommands.test.js +56 -21
- package/README.md +0 -91
package/package.descriptor.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export default Object.freeze({
|
|
2
2
|
packageVersion: 1,
|
|
3
3
|
packageId: "@jskit-ai/assistant",
|
|
4
|
-
version: "0.1.
|
|
4
|
+
version: "0.1.44",
|
|
5
5
|
kind: "generator",
|
|
6
6
|
description: "Install assistant runtime/config for one surface and scaffold assistant pages at explicit target files.",
|
|
7
7
|
options: {
|
|
@@ -49,7 +49,7 @@ export default Object.freeze({
|
|
|
49
49
|
inputType: "text",
|
|
50
50
|
defaultValue: "",
|
|
51
51
|
promptLabel: "Link placement",
|
|
52
|
-
promptHint: "Optional
|
|
52
|
+
promptHint: "Optional target for the generated page link placement (format: host:position)."
|
|
53
53
|
},
|
|
54
54
|
"link-component-token": {
|
|
55
55
|
required: false,
|
|
@@ -158,6 +158,7 @@ export default Object.freeze({
|
|
|
158
158
|
]
|
|
159
159
|
},
|
|
160
160
|
page: {
|
|
161
|
+
requiresShellWeb: true,
|
|
161
162
|
entrypoint: "src/server/subcommands/page.js",
|
|
162
163
|
export: "runGeneratorSubcommand",
|
|
163
164
|
description: "Create an assistant runtime page at an explicit target file relative to src/pages/.",
|
|
@@ -194,6 +195,7 @@ export default Object.freeze({
|
|
|
194
195
|
]
|
|
195
196
|
},
|
|
196
197
|
"settings-page": {
|
|
198
|
+
requiresShellWeb: true,
|
|
197
199
|
entrypoint: "src/server/subcommands/settingsPage.js",
|
|
198
200
|
export: "runGeneratorSubcommand",
|
|
199
201
|
description: "Create an assistant settings page at an explicit target file relative to src/pages/.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/assistant",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.44",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "node --test"
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
"./server/buildTemplateContext": "./src/server/buildTemplateContext.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@jskit-ai/kernel": "0.1.
|
|
12
|
+
"@jskit-ai/kernel": "0.1.35"
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -56,11 +56,11 @@ async function resolveAssistantPageGenerationContext({
|
|
|
56
56
|
return Object.freeze({
|
|
57
57
|
pageTarget,
|
|
58
58
|
pageLabel: normalizeText(options?.name) || pageTarget.defaultName,
|
|
59
|
-
|
|
60
|
-
linkPlacementPosition: String(linkTarget.placementTarget?.position || ""),
|
|
59
|
+
linkPlacementTarget: String(linkTarget.placementTarget?.id || ""),
|
|
61
60
|
linkComponentToken: String(linkTarget.componentToken || ""),
|
|
62
61
|
linkWorkspaceSuffix: pageTarget.routeUrlSuffix,
|
|
63
62
|
linkNonWorkspaceSuffix: pageTarget.routeUrlSuffix,
|
|
63
|
+
linkWhenLine: String(linkTarget.whenLine || ""),
|
|
64
64
|
linkToPropLine: resolveLinkToPropLine(linkTarget.linkTo)
|
|
65
65
|
});
|
|
66
66
|
}
|
|
@@ -75,8 +75,7 @@ function renderAssistantPageLinkPlacementBlock({
|
|
|
75
75
|
"{\n" +
|
|
76
76
|
" addPlacement({\n" +
|
|
77
77
|
` id: "${String(pageTarget?.placementId || "")}",\n` +
|
|
78
|
-
`
|
|
79
|
-
` position: "${String(generationContext?.linkPlacementPosition || "")}",\n` +
|
|
78
|
+
` target: "${String(generationContext?.linkPlacementTarget || "")}",\n` +
|
|
80
79
|
` surfaces: ["${String(pageTarget?.surfaceId || "")}"],\n` +
|
|
81
80
|
" order: 155,\n" +
|
|
82
81
|
` componentToken: "${String(generationContext?.linkComponentToken || "")}",\n` +
|
|
@@ -86,7 +85,7 @@ function renderAssistantPageLinkPlacementBlock({
|
|
|
86
85
|
` workspaceSuffix: "${String(generationContext?.linkWorkspaceSuffix || "")}",\n` +
|
|
87
86
|
` nonWorkspaceSuffix: "${String(generationContext?.linkNonWorkspaceSuffix || "")}",\n` +
|
|
88
87
|
`${String(generationContext?.linkToPropLine || "")} },\n` +
|
|
89
|
-
|
|
88
|
+
`${String(generationContext?.linkWhenLine || "")}` +
|
|
90
89
|
" });\n" +
|
|
91
90
|
"}\n"
|
|
92
91
|
);
|
package/test/subcommands.test.js
CHANGED
|
@@ -25,11 +25,12 @@ function toPagePath(targetFile = "") {
|
|
|
25
25
|
return path.join("src/pages", targetFile);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
async function writeAppFixture(appRoot) {
|
|
28
|
+
async function writeAppFixture(appRoot, { configSource = "" } = {}) {
|
|
29
29
|
await writeFileInApp(
|
|
30
30
|
appRoot,
|
|
31
31
|
"config/public.js",
|
|
32
|
-
|
|
32
|
+
configSource ||
|
|
33
|
+
`export const config = {
|
|
33
34
|
surfaceDefinitions: {
|
|
34
35
|
admin: {
|
|
35
36
|
id: "admin",
|
|
@@ -55,8 +56,8 @@ async function writeAppFixture(appRoot) {
|
|
|
55
56
|
"src/components/ShellLayout.vue",
|
|
56
57
|
`<template>
|
|
57
58
|
<div>
|
|
58
|
-
<ShellOutlet
|
|
59
|
-
<ShellOutlet
|
|
59
|
+
<ShellOutlet target="shell-layout:primary-menu" default />
|
|
60
|
+
<ShellOutlet target="shell-layout:top-right" />
|
|
60
61
|
</div>
|
|
61
62
|
</template>
|
|
62
63
|
`
|
|
@@ -95,8 +96,7 @@ test("assistant page subcommand creates a runtime page at an explicit target fil
|
|
|
95
96
|
const placementSource = await readFile(path.join(appRoot, "src/placement.js"), "utf8");
|
|
96
97
|
assert.match(placementSource, /jskit:assistant\.page\.link:admin:\/ops\/copilot/);
|
|
97
98
|
assert.match(placementSource, /id: "ui-generator\.page\.admin\.ops\.copilot\.link"/);
|
|
98
|
-
assert.match(placementSource, /
|
|
99
|
-
assert.match(placementSource, /position: "primary-menu"/);
|
|
99
|
+
assert.match(placementSource, /target: "shell-layout:primary-menu"/);
|
|
100
100
|
assert.match(placementSource, /label: "Copilot"/);
|
|
101
101
|
assert.match(placementSource, /workspaceSuffix: "\/ops\/copilot"/);
|
|
102
102
|
});
|
|
@@ -111,7 +111,7 @@ test("assistant settings-page subcommand uses the target assistant surface and i
|
|
|
111
111
|
`<template>
|
|
112
112
|
<SectionContainerShell>
|
|
113
113
|
<template #tabs>
|
|
114
|
-
<ShellOutlet
|
|
114
|
+
<ShellOutlet target="admin-settings:sub-pages" />
|
|
115
115
|
</template>
|
|
116
116
|
<RouterView />
|
|
117
117
|
</SectionContainerShell>
|
|
@@ -137,14 +137,48 @@ test("assistant settings-page subcommand uses the target assistant surface and i
|
|
|
137
137
|
|
|
138
138
|
const placementSource = await readFile(path.join(appRoot, "src/placement.js"), "utf8");
|
|
139
139
|
assert.match(placementSource, /jskit:assistant\.settings-page\.link:admin:\/settings\/assistant:console/);
|
|
140
|
-
assert.match(placementSource, /
|
|
141
|
-
assert.match(placementSource, /position: "sub-pages"/);
|
|
140
|
+
assert.match(placementSource, /target: "admin-settings:sub-pages"/);
|
|
142
141
|
assert.match(placementSource, /componentToken: "local\.main\.ui\.tab-link-item"/);
|
|
143
142
|
assert.match(placementSource, /to: "\.\/assistant"/);
|
|
144
143
|
assert.match(placementSource, /label: "Assistant"/);
|
|
145
144
|
});
|
|
146
145
|
});
|
|
147
146
|
|
|
147
|
+
test("assistant page subcommand omits the auth guard for a public surface link", async () => {
|
|
148
|
+
await withTempApp(async (appRoot) => {
|
|
149
|
+
await writeAppFixture(appRoot, {
|
|
150
|
+
configSource: `export const config = {
|
|
151
|
+
surfaceAccessPolicies: {
|
|
152
|
+
public: {}
|
|
153
|
+
},
|
|
154
|
+
surfaceDefinitions: {
|
|
155
|
+
home: {
|
|
156
|
+
id: "home",
|
|
157
|
+
pagesRoot: "home",
|
|
158
|
+
enabled: true,
|
|
159
|
+
requiresWorkspace: false,
|
|
160
|
+
accessPolicyId: "public"
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
assistantSurfaces: {}
|
|
164
|
+
};
|
|
165
|
+
`
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const targetFile = "home/assistant/index.vue";
|
|
169
|
+
await runPageSubcommand({
|
|
170
|
+
appRoot,
|
|
171
|
+
subcommand: "page",
|
|
172
|
+
args: [targetFile],
|
|
173
|
+
options: {}
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const placementSource = await readFile(path.join(appRoot, "src", "placement.js"), "utf8");
|
|
177
|
+
assert.match(placementSource, /id: "ui-generator\.page\.home\.assistant\.link"/);
|
|
178
|
+
assert.doesNotMatch(placementSource, /when: \(\{ auth \}\) => Boolean\(auth\?\.authenticated\)/);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
148
182
|
test("assistant page subcommand refuses to overwrite an existing user-owned page", async () => {
|
|
149
183
|
await withTempApp(async (appRoot) => {
|
|
150
184
|
await writeAppFixture(appRoot);
|
|
@@ -213,7 +247,7 @@ test("assistant settings-page subcommand overwrites an existing page when --forc
|
|
|
213
247
|
`<template>
|
|
214
248
|
<SectionContainerShell>
|
|
215
249
|
<template #tabs>
|
|
216
|
-
<ShellOutlet
|
|
250
|
+
<ShellOutlet target="admin-settings:sub-pages" />
|
|
217
251
|
</template>
|
|
218
252
|
<RouterView />
|
|
219
253
|
</SectionContainerShell>
|
|
@@ -267,19 +301,20 @@ test("assistant settings-page subcommand requires the target assistant surface o
|
|
|
267
301
|
});
|
|
268
302
|
});
|
|
269
303
|
|
|
270
|
-
test("assistant page subcommand
|
|
304
|
+
test("assistant page subcommand accepts target files with a src/pages prefix", async () => {
|
|
271
305
|
await withTempApp(async (appRoot) => {
|
|
272
306
|
await writeAppFixture(appRoot);
|
|
273
307
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
);
|
|
308
|
+
const targetFile = "src/pages/w/[workspaceSlug]/admin/assistant/index.vue";
|
|
309
|
+
const result = await runPageSubcommand({
|
|
310
|
+
appRoot,
|
|
311
|
+
subcommand: "page",
|
|
312
|
+
args: [targetFile],
|
|
313
|
+
options: {}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
assert.deepEqual(result.touchedFiles, [targetFile, "src/placement.js"]);
|
|
317
|
+
const pageSource = await readFile(path.join(appRoot, targetFile), "utf8");
|
|
318
|
+
assert.match(pageSource, /<AssistantSurfaceClientElement surface-id="admin" \/>/);
|
|
284
319
|
});
|
|
285
320
|
});
|
package/README.md
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# @jskit-ai/assistant
|
|
2
|
-
|
|
3
|
-
Install assistant runtime/config for one surface, then scaffold assistant pages at explicit page files.
|
|
4
|
-
|
|
5
|
-
## Mental Model
|
|
6
|
-
|
|
7
|
-
`@jskit-ai/assistant` is the generator package.
|
|
8
|
-
|
|
9
|
-
- `setup` installs the assistant runtime/config/env wiring.
|
|
10
|
-
- `page <target-file>` creates the assistant runtime page anywhere relative to `src/pages/...`.
|
|
11
|
-
- `settings-page <target-file>` creates the assistant settings page anywhere relative to `src/pages/...`.
|
|
12
|
-
|
|
13
|
-
There is no separate server command and no separate client command.
|
|
14
|
-
|
|
15
|
-
The layering is:
|
|
16
|
-
|
|
17
|
-
- `@jskit-ai/assistant`: generator package with `setup`, `page`, and `settings-page`
|
|
18
|
-
- `@jskit-ai/assistant-runtime`: runtime package installed by `setup`
|
|
19
|
-
- `@jskit-ai/assistant-core`: lower-level provider/client library pulled in by `assistant-runtime`
|
|
20
|
-
|
|
21
|
-
So the normal flow is:
|
|
22
|
-
|
|
23
|
-
- run `setup`
|
|
24
|
-
- optionally create `page`
|
|
25
|
-
- optionally create `settings-page`
|
|
26
|
-
|
|
27
|
-
Page placement follows the same file-driven model as `@jskit-ai/ui-generator`.
|
|
28
|
-
|
|
29
|
-
- The surface comes from where the page file lives.
|
|
30
|
-
- The route URL comes from that file path.
|
|
31
|
-
- The default page-link placement comes from the nearest real parent subpages host when there is one.
|
|
32
|
-
|
|
33
|
-
Only one assistant can be installed per target surface. That rule is enforced by `setup`, which writes the per-surface config entries.
|
|
34
|
-
|
|
35
|
-
## Setup
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npx jskit generate @jskit-ai/assistant setup \
|
|
39
|
-
--surface admin \
|
|
40
|
-
--settings-surface console \
|
|
41
|
-
--config-scope global \
|
|
42
|
-
--ai-provider openai \
|
|
43
|
-
--ai-api-key "$OPENAI_API_KEY" \
|
|
44
|
-
--ai-base-url "" \
|
|
45
|
-
--ai-timeout-ms 120000
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
`setup` does not create pages.
|
|
49
|
-
|
|
50
|
-
It only registers:
|
|
51
|
-
|
|
52
|
-
- `config.assistantSurfaces.<surface>`
|
|
53
|
-
- `config.assistantServer.<surface>`
|
|
54
|
-
- prefixed AI env defaults in `.env`
|
|
55
|
-
- the `@jskit-ai/assistant-runtime` dependency chain, including `@jskit-ai/assistant-core`
|
|
56
|
-
|
|
57
|
-
## Runtime Page
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
npx jskit generate @jskit-ai/assistant page \
|
|
61
|
-
admin/ops/copilot/index.vue
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
The page surface id comes from the target file path.
|
|
65
|
-
|
|
66
|
-
Optional page-link overrides:
|
|
67
|
-
|
|
68
|
-
- `--name`
|
|
69
|
-
- `--link-placement`
|
|
70
|
-
- `--link-component-token`
|
|
71
|
-
- `--link-to`
|
|
72
|
-
|
|
73
|
-
## Settings Page
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
npx jskit generate @jskit-ai/assistant settings-page \
|
|
77
|
-
admin/settings/index/assistant/index.vue \
|
|
78
|
-
--surface admin
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
For `settings-page`, the page location and the assistant target surface are separate concerns:
|
|
82
|
-
|
|
83
|
-
- `<target-file>` decides where the settings page lives and how its page link is placed
|
|
84
|
-
- `--surface` decides which assistant surface the settings page edits
|
|
85
|
-
|
|
86
|
-
The same optional page-link overrides are supported:
|
|
87
|
-
|
|
88
|
-
- `--name`
|
|
89
|
-
- `--link-placement`
|
|
90
|
-
- `--link-component-token`
|
|
91
|
-
- `--link-to`
|