@jskit-ai/assistant 0.1.74 → 0.1.75
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
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.75",
|
|
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,14 +49,7 @@ export default Object.freeze({
|
|
|
49
49
|
inputType: "text",
|
|
50
50
|
defaultValue: "",
|
|
51
51
|
promptLabel: "Link placement",
|
|
52
|
-
promptHint: "Optional target for the generated page link placement (format:
|
|
53
|
-
},
|
|
54
|
-
"link-component-token": {
|
|
55
|
-
required: false,
|
|
56
|
-
inputType: "text",
|
|
57
|
-
defaultValue: "",
|
|
58
|
-
promptLabel: "Link component token",
|
|
59
|
-
promptHint: "Optional component token override for the generated page link placement."
|
|
52
|
+
promptHint: "Optional semantic target for the generated page link placement (format: area.slot)."
|
|
60
53
|
},
|
|
61
54
|
"link-to": {
|
|
62
55
|
required: false,
|
|
@@ -169,7 +162,7 @@ export default Object.freeze({
|
|
|
169
162
|
descriptionKey: "page-target-file"
|
|
170
163
|
}
|
|
171
164
|
],
|
|
172
|
-
optionNames: ["name", "link-placement", "link-
|
|
165
|
+
optionNames: ["name", "link-placement", "link-to", "force"],
|
|
173
166
|
notes: [
|
|
174
167
|
"The target file decides where the page lives.",
|
|
175
168
|
"Page-link placement follows the same inference rules as ui-generator page.",
|
|
@@ -189,7 +182,7 @@ export default Object.freeze({
|
|
|
189
182
|
"npx jskit generate assistant page \\",
|
|
190
183
|
" admin/ops/copilot/index.vue \\",
|
|
191
184
|
" --name \"Copilot\" \\",
|
|
192
|
-
" --link-placement shell
|
|
185
|
+
" --link-placement shell.status"
|
|
193
186
|
]
|
|
194
187
|
}
|
|
195
188
|
]
|
|
@@ -206,7 +199,7 @@ export default Object.freeze({
|
|
|
206
199
|
descriptionKey: "page-target-file"
|
|
207
200
|
}
|
|
208
201
|
],
|
|
209
|
-
optionNames: ["surface", "name", "link-placement", "link-
|
|
202
|
+
optionNames: ["surface", "name", "link-placement", "link-to", "force"],
|
|
210
203
|
requiredOptionNames: ["surface"],
|
|
211
204
|
notes: [
|
|
212
205
|
"The target file decides where the settings page lives.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/assistant",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.75",
|
|
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.66"
|
|
13
13
|
}
|
|
14
14
|
}
|
|
@@ -16,6 +16,14 @@ function resolveLinkToPropLine(linkTo = "") {
|
|
|
16
16
|
return ` to: ${JSON.stringify(linkTo)},\n`;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function resolveOwnerLine(owner = "") {
|
|
20
|
+
const normalizedOwner = normalizeText(owner);
|
|
21
|
+
if (!normalizedOwner) {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
return ` owner: ${JSON.stringify(normalizedOwner)},\n`;
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
function resolveTemplateFilePath(relativePath = "") {
|
|
20
28
|
return fileURLToPath(new URL(relativePath, import.meta.url));
|
|
21
29
|
}
|
|
@@ -49,7 +57,6 @@ async function resolveAssistantPageGenerationContext({
|
|
|
49
57
|
targetFile,
|
|
50
58
|
context,
|
|
51
59
|
placement: options?.["link-placement"],
|
|
52
|
-
componentToken: options?.["link-component-token"],
|
|
53
60
|
linkTo: options?.["link-to"]
|
|
54
61
|
});
|
|
55
62
|
|
|
@@ -57,7 +64,7 @@ async function resolveAssistantPageGenerationContext({
|
|
|
57
64
|
pageTarget,
|
|
58
65
|
pageLabel: normalizeText(options?.name) || pageTarget.defaultName,
|
|
59
66
|
linkPlacementTarget: String(linkTarget.placementTarget?.id || ""),
|
|
60
|
-
|
|
67
|
+
linkOwnerLine: resolveOwnerLine(linkTarget.placementTarget?.owner || ""),
|
|
61
68
|
linkWorkspaceSuffix: pageTarget.routeUrlSuffix,
|
|
62
69
|
linkNonWorkspaceSuffix: pageTarget.routeUrlSuffix,
|
|
63
70
|
linkWhenLine: String(linkTarget.whenLine || ""),
|
|
@@ -76,9 +83,10 @@ function renderAssistantPageLinkPlacementBlock({
|
|
|
76
83
|
" addPlacement({\n" +
|
|
77
84
|
` id: "${String(pageTarget?.placementId || "")}",\n` +
|
|
78
85
|
` target: "${String(generationContext?.linkPlacementTarget || "")}",\n` +
|
|
86
|
+
`${String(generationContext?.linkOwnerLine || "")}` +
|
|
87
|
+
" kind: \"link\",\n" +
|
|
79
88
|
` surfaces: ["${String(pageTarget?.surfaceId || "")}"],\n` +
|
|
80
89
|
" order: 155,\n" +
|
|
81
|
-
` componentToken: "${String(generationContext?.linkComponentToken || "")}",\n` +
|
|
82
90
|
" props: {\n" +
|
|
83
91
|
` label: "${String(generationContext?.pageLabel || "")}",\n` +
|
|
84
92
|
` surface: "${String(pageTarget?.surfaceId || "")}",\n` +
|
|
@@ -30,7 +30,7 @@ async function runGeneratorSubcommand({
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const targetFile = requireSinglePositionalTargetFile(args, { context: "assistant page" });
|
|
33
|
-
rejectUnexpectedOptions(options, ["name", "link-placement", "link-
|
|
33
|
+
rejectUnexpectedOptions(options, ["name", "link-placement", "link-to", "force"], {
|
|
34
34
|
context: "assistant page"
|
|
35
35
|
});
|
|
36
36
|
const forceOverwrite = Object.prototype.hasOwnProperty.call(options, "force")
|
|
@@ -31,7 +31,7 @@ async function runGeneratorSubcommand({
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
const targetFile = requireSinglePositionalTargetFile(args, { context: "assistant settings-page" });
|
|
34
|
-
rejectUnexpectedOptions(options, ["surface", "name", "link-placement", "link-
|
|
34
|
+
rejectUnexpectedOptions(options, ["surface", "name", "link-placement", "link-to", "force"], {
|
|
35
35
|
context: "assistant settings-page"
|
|
36
36
|
});
|
|
37
37
|
const forceOverwrite = Object.prototype.hasOwnProperty.call(options, "force")
|
package/test/subcommands.test.js
CHANGED
|
@@ -25,6 +25,61 @@ function toPagePath(targetFile = "") {
|
|
|
25
25
|
return path.join("src/pages", targetFile);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
function renderTopologyVariant(outlet, { linkRenderer = "" } = {}) {
|
|
29
|
+
const rendererLines = linkRenderer
|
|
30
|
+
? `,
|
|
31
|
+
renderers: {
|
|
32
|
+
link: "${linkRenderer}"
|
|
33
|
+
}`
|
|
34
|
+
: "";
|
|
35
|
+
return `{
|
|
36
|
+
outlet: "${outlet}"${rendererLines}
|
|
37
|
+
}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function renderTopologyEntry({
|
|
41
|
+
id = "",
|
|
42
|
+
owner = "",
|
|
43
|
+
surfaces = ["*"],
|
|
44
|
+
defaultPlacement = false,
|
|
45
|
+
outlet = "",
|
|
46
|
+
linkRenderer = ""
|
|
47
|
+
} = {}) {
|
|
48
|
+
const ownerLine = owner ? ` owner: "${owner}",\n` : "";
|
|
49
|
+
const defaultLine = defaultPlacement ? " default: true,\n" : "";
|
|
50
|
+
return ` {
|
|
51
|
+
id: "${id}",
|
|
52
|
+
${ownerLine} surfaces: ${JSON.stringify(surfaces)},
|
|
53
|
+
${defaultLine} variants: {
|
|
54
|
+
compact: ${renderTopologyVariant(outlet, { linkRenderer })},
|
|
55
|
+
medium: ${renderTopologyVariant(outlet, { linkRenderer })},
|
|
56
|
+
expanded: ${renderTopologyVariant(outlet, { linkRenderer })}
|
|
57
|
+
}
|
|
58
|
+
}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function writePlacementTopology(appRoot, entries = []) {
|
|
62
|
+
const defaultEntries = [
|
|
63
|
+
renderTopologyEntry({
|
|
64
|
+
id: "shell.primary-nav",
|
|
65
|
+
surfaces: ["*"],
|
|
66
|
+
defaultPlacement: true,
|
|
67
|
+
outlet: "shell-layout:primary-menu",
|
|
68
|
+
linkRenderer: "local.main.ui.surface-aware-menu-link-item"
|
|
69
|
+
})
|
|
70
|
+
];
|
|
71
|
+
await writeFileInApp(
|
|
72
|
+
appRoot,
|
|
73
|
+
"src/placementTopology.js",
|
|
74
|
+
`export default {
|
|
75
|
+
placements: [
|
|
76
|
+
${[...defaultEntries, ...entries].join(",\n")}
|
|
77
|
+
]
|
|
78
|
+
};
|
|
79
|
+
`
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
28
83
|
async function writeAppFixture(appRoot, { configSource = "" } = {}) {
|
|
29
84
|
await writeFileInApp(
|
|
30
85
|
appRoot,
|
|
@@ -73,6 +128,7 @@ export default function getPlacements() {
|
|
|
73
128
|
}
|
|
74
129
|
`
|
|
75
130
|
);
|
|
131
|
+
await writePlacementTopology(appRoot);
|
|
76
132
|
}
|
|
77
133
|
|
|
78
134
|
test("assistant page subcommand creates a runtime page at an explicit target file", async () => {
|
|
@@ -96,7 +152,9 @@ test("assistant page subcommand creates a runtime page at an explicit target fil
|
|
|
96
152
|
const placementSource = await readFile(path.join(appRoot, "src/placement.js"), "utf8");
|
|
97
153
|
assert.match(placementSource, /jskit:assistant\.page\.link:admin:\/ops\/copilot/);
|
|
98
154
|
assert.match(placementSource, /id: "ui-generator\.page\.admin\.ops\.copilot\.link"/);
|
|
99
|
-
assert.match(placementSource, /target: "shell
|
|
155
|
+
assert.match(placementSource, /target: "shell\.primary-nav"/);
|
|
156
|
+
assert.match(placementSource, /kind: "link"/);
|
|
157
|
+
assert.doesNotMatch(placementSource, /componentToken:/);
|
|
100
158
|
assert.match(placementSource, /label: "Copilot"/);
|
|
101
159
|
assert.match(placementSource, /scopedSuffix: "\/ops\/copilot"/);
|
|
102
160
|
});
|
|
@@ -105,6 +163,15 @@ test("assistant page subcommand creates a runtime page at an explicit target fil
|
|
|
105
163
|
test("assistant settings-page subcommand uses the target assistant surface and infers parent subpage placement", async () => {
|
|
106
164
|
await withTempApp(async (appRoot) => {
|
|
107
165
|
await writeAppFixture(appRoot);
|
|
166
|
+
await writePlacementTopology(appRoot, [
|
|
167
|
+
renderTopologyEntry({
|
|
168
|
+
id: "page.section-nav",
|
|
169
|
+
owner: "admin-settings",
|
|
170
|
+
surfaces: ["admin"],
|
|
171
|
+
outlet: "admin-settings:sub-pages",
|
|
172
|
+
linkRenderer: "local.main.ui.surface-aware-menu-link-item"
|
|
173
|
+
})
|
|
174
|
+
]);
|
|
108
175
|
await writeFileInApp(
|
|
109
176
|
appRoot,
|
|
110
177
|
"src/pages/w/[workspaceSlug]/admin/settings/index.vue",
|
|
@@ -137,8 +204,9 @@ test("assistant settings-page subcommand uses the target assistant surface and i
|
|
|
137
204
|
|
|
138
205
|
const placementSource = await readFile(path.join(appRoot, "src/placement.js"), "utf8");
|
|
139
206
|
assert.match(placementSource, /jskit:assistant\.settings-page\.link:admin:\/settings\/assistant:console/);
|
|
140
|
-
assert.match(placementSource, /target: "
|
|
141
|
-
assert.match(placementSource, /
|
|
207
|
+
assert.match(placementSource, /target: "page\.section-nav"/);
|
|
208
|
+
assert.match(placementSource, /owner: "admin-settings"/);
|
|
209
|
+
assert.doesNotMatch(placementSource, /componentToken: "local\.main\.ui\.surface-aware-menu-link-item"/);
|
|
142
210
|
assert.match(placementSource, /to: "\.\/assistant"/);
|
|
143
211
|
assert.match(placementSource, /label: "Assistant"/);
|
|
144
212
|
});
|
|
@@ -241,6 +309,15 @@ test("assistant page subcommand overwrites an existing page when --force is pass
|
|
|
241
309
|
test("assistant settings-page subcommand overwrites an existing page when --force is passed", async () => {
|
|
242
310
|
await withTempApp(async (appRoot) => {
|
|
243
311
|
await writeAppFixture(appRoot);
|
|
312
|
+
await writePlacementTopology(appRoot, [
|
|
313
|
+
renderTopologyEntry({
|
|
314
|
+
id: "page.section-nav",
|
|
315
|
+
owner: "admin-settings",
|
|
316
|
+
surfaces: ["admin"],
|
|
317
|
+
outlet: "admin-settings:sub-pages",
|
|
318
|
+
linkRenderer: "local.main.ui.surface-aware-menu-link-item"
|
|
319
|
+
})
|
|
320
|
+
]);
|
|
244
321
|
await writeFileInApp(
|
|
245
322
|
appRoot,
|
|
246
323
|
"src/pages/w/[workspaceSlug]/admin/settings/index.vue",
|