@timurproko/a1 0.1.8-dev.563 → 0.1.8-dev.573
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/README.md +13 -11
- package/dist/app/session-shell/prompt-chips.js +20 -28
- package/dist/app/session-shell/session-shell-root.d.ts +2 -0
- package/dist/app/session-shell/session-shell-root.js +60 -17
- package/dist/app/session-shell/session-shell.js +35 -1
- package/dist/app/session-shell/session-viewport-controller.d.ts +1 -0
- package/dist/app/session-shell/session-viewport-controller.js +52 -30
- package/dist/cli/dispatch.d.ts +3 -1
- package/dist/cli/dispatch.js +56 -56
- package/dist/cli/package-messages.d.ts +4 -3
- package/dist/cli/package-messages.js +23 -11
- package/dist/contracts/owned-ui/index.d.ts +2 -0
- package/dist/contracts/owned-ui/index.js +1 -0
- package/dist/contracts/owned-ui/prompt-chips.d.ts +15 -0
- package/dist/contracts/owned-ui/prompt-chips.js +59 -0
- package/dist/contracts/owned-ui/validation.js +1 -1
- package/dist/integrations/pi/components/index.d.ts +1 -0
- package/dist/integrations/pi/components/index.js +1 -0
- package/dist/integrations/pi/components/modal-frame.d.ts +41 -0
- package/dist/integrations/pi/components/modal-frame.js +110 -0
- package/dist/integrations/pi/components/models-dialog.js +19 -5
- package/dist/integrations/pi/components/shell-footer-status.d.ts +4 -3
- package/dist/integrations/pi/components/shell-footer-status.js +53 -15
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +38 -2
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +9 -1
- package/dist/integrations/pi/components/skills-dialog.js +3 -3
- package/dist/integrations/pi/components/submitted-prompt-adapter.d.ts +1 -1
- package/dist/integrations/pi/components/submitted-prompt-adapter.js +5 -2
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +2 -2
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +3 -2
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +7 -6
- package/dist/integrations/pi/components/upstream/components/extension-input.js +9 -8
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +10 -9
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +3 -3
- package/dist/integrations/pi/components/upstream/components/session-selector.js +13 -6
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +7 -6
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +15 -12
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +13 -6
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +9 -9
- package/dist/integrations/pi/engine/compaction-progress.d.ts +3 -7
- package/dist/integrations/pi/engine/compaction-progress.js +11 -10
- package/dist/integrations/pi/engine/repository-pr.d.ts +3 -3
- package/dist/integrations/pi/engine/repository-pr.js +6 -6
- package/dist/integrations/pi/engine/session-runtime.js +5 -4
- package/dist/integrations/pi/engine/settings-bridge.js +1 -1
- package/dist/integrations/pi/engine/settings-port.js +1 -1
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +2 -0
- package/dist/integrations/pi/tui-runtime/adapter.js +11 -2
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +2 -0
- package/dist/integrations/pi/tui-runtime/mouse-report-input.d.ts +6 -0
- package/dist/integrations/pi/tui-runtime/mouse-report-input.js +34 -0
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/win32-x64/manifest.json +3 -3
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/ui/components/dialog-panel.js +10 -6
- package/dist/ui/components/index.d.ts +2 -1
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/mouse.d.ts +2 -2
- package/dist/ui/components/mouse.js +2 -2
- package/dist/ui/components/progress-status.d.ts +9 -2
- package/dist/ui/components/progress-status.js +24 -3
- package/dist/ui/components/transcript-viewport.d.ts +9 -3
- package/dist/ui/components/transcript-viewport.js +116 -136
- package/docs/architecture/ui-reference-provenance.md +8 -5
- package/docs/openspec-archive-automation.md +2 -2
- package/docs/validation.md +1 -1
- package/package.json +1 -1
package/dist/cli/dispatch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { interactiveLaunchIntent, parseSessionSelection } from "../features/launch/index.js";
|
|
2
|
-
import { packageCommandHelp, renderPackageSyntax } from "./package-messages.js";
|
|
2
|
+
import { packageCommandHelp, renderPackageSyntax, } from "./package-messages.js";
|
|
3
3
|
import { PRODUCT_TEXT } from "../product-identity.js";
|
|
4
4
|
export function cliUsage(capabilities) {
|
|
5
5
|
return PRODUCT_TEXT.usage([
|
|
@@ -7,22 +7,19 @@ export function cliUsage(capabilities) {
|
|
|
7
7
|
"--session <path|id>",
|
|
8
8
|
"--session-dir <dir> --session <path|id>",
|
|
9
9
|
...(capabilities.developmentComparison ? ["pi"] : []),
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"--version",
|
|
13
|
-
"-v",
|
|
10
|
+
"help",
|
|
11
|
+
"version",
|
|
14
12
|
"update",
|
|
15
13
|
"update --develop [preview-or-version]",
|
|
16
14
|
"update --models",
|
|
15
|
+
"update --extensions",
|
|
16
|
+
"update <source>",
|
|
17
|
+
"install <source>",
|
|
18
|
+
"remove <source>",
|
|
19
|
+
"uninstall <source>",
|
|
20
|
+
"list",
|
|
17
21
|
"session link-worktree <path>",
|
|
18
22
|
"session unlink-worktree",
|
|
19
|
-
"pi install <source>",
|
|
20
|
-
"pi remove <source>",
|
|
21
|
-
"pi uninstall <source>",
|
|
22
|
-
"pi list",
|
|
23
|
-
"pi update --extensions",
|
|
24
|
-
"pi update --models",
|
|
25
|
-
"pi update <source>",
|
|
26
23
|
]);
|
|
27
24
|
}
|
|
28
25
|
export function cliHelp(capabilities) {
|
|
@@ -33,29 +30,26 @@ export function cliHelp(capabilities) {
|
|
|
33
30
|
` ${command} --session <path|id>`,
|
|
34
31
|
` ${command} --session-dir <dir> --session <path|id>`,
|
|
35
32
|
...(capabilities.developmentComparison ? [` ${command} pi`] : []),
|
|
36
|
-
` ${command}
|
|
37
|
-
` ${command}
|
|
38
|
-
` ${command} --version`,
|
|
39
|
-
` ${command} -v`,
|
|
33
|
+
` ${command} help`,
|
|
34
|
+
` ${command} version`,
|
|
40
35
|
"",
|
|
41
36
|
"Update:",
|
|
42
37
|
` ${command} update`,
|
|
43
38
|
` ${command} update --develop [preview-or-version]`,
|
|
44
39
|
` ${command} update --models`,
|
|
40
|
+
` ${command} update --extensions`,
|
|
41
|
+
` ${command} update <source>`,
|
|
42
|
+
"",
|
|
43
|
+
"Packages:",
|
|
44
|
+
` ${command} install <source>`,
|
|
45
|
+
` ${command} remove <source>`,
|
|
46
|
+
` ${command} uninstall <source>`,
|
|
47
|
+
` ${command} list`,
|
|
45
48
|
"",
|
|
46
49
|
"Session context:",
|
|
47
50
|
` ${command} session link-worktree <path>`,
|
|
48
51
|
` ${command} session unlink-worktree`,
|
|
49
52
|
"",
|
|
50
|
-
"Pi-compatible packages:",
|
|
51
|
-
` ${command} pi install <source>`,
|
|
52
|
-
` ${command} pi remove <source>`,
|
|
53
|
-
` ${command} pi uninstall <source>`,
|
|
54
|
-
` ${command} pi list`,
|
|
55
|
-
` ${command} pi update --extensions`,
|
|
56
|
-
` ${command} pi update --models`,
|
|
57
|
-
` ${command} pi update <source>`,
|
|
58
|
-
"",
|
|
59
53
|
].join("\n");
|
|
60
54
|
}
|
|
61
55
|
const PROFILE_WORDS = new Set(["pi"]);
|
|
@@ -68,11 +62,11 @@ export async function dispatchCli(arguments_, handlers, output, capabilities) {
|
|
|
68
62
|
return 0;
|
|
69
63
|
}
|
|
70
64
|
if (command.kind === "package-help") {
|
|
71
|
-
output.stdout(packageCommandHelp(command.verb));
|
|
65
|
+
output.stdout(packageCommandHelp(command.verb, command.namespace));
|
|
72
66
|
return 0;
|
|
73
67
|
}
|
|
74
68
|
if (command.kind === "package-error") {
|
|
75
|
-
output.stderr(renderPackageSyntax(command.diagnostic));
|
|
69
|
+
output.stderr(renderPackageSyntax(command.diagnostic, command.namespace));
|
|
76
70
|
return 2;
|
|
77
71
|
}
|
|
78
72
|
if (command.kind === "error") {
|
|
@@ -102,13 +96,16 @@ export function parseCliCommand(arguments_, capabilities) {
|
|
|
102
96
|
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`could not parse session launch: ${error instanceof Error ? error.message : String(error)}`) };
|
|
103
97
|
}
|
|
104
98
|
}
|
|
105
|
-
if (command === "--help" || command === "-h")
|
|
99
|
+
if (command === "help" || command === "--help" || command === "-h")
|
|
106
100
|
return withoutArguments(rest, { kind: "help" });
|
|
107
|
-
if (command === "--version" || command === "-v")
|
|
101
|
+
if (command === "version" || command === "--version" || command === "-v")
|
|
108
102
|
return withoutArguments(rest, { kind: "version" });
|
|
103
|
+
if (command === "install" || command === "remove" || command === "uninstall" || command === "list") {
|
|
104
|
+
return parsePackageCommand(arguments_, "direct");
|
|
105
|
+
}
|
|
109
106
|
if (command === "pi") {
|
|
110
107
|
if (rest.length > 0)
|
|
111
|
-
return
|
|
108
|
+
return parsePackageCommand(rest, "pi");
|
|
112
109
|
return capabilities.developmentComparison ? { kind: "launch", profileId: "pi" } : { kind: "noop" };
|
|
113
110
|
}
|
|
114
111
|
if (command === "update")
|
|
@@ -143,6 +140,9 @@ function parseSessionContext(rest) {
|
|
|
143
140
|
* operation that cannot be combined with either update channel.
|
|
144
141
|
*/
|
|
145
142
|
function parseUpdate(rest) {
|
|
143
|
+
if (rest.some(value => value === "--help" || value === "-h")) {
|
|
144
|
+
return { kind: "package-help", verb: "update", namespace: "direct" };
|
|
145
|
+
}
|
|
146
146
|
if (rest.length === 0)
|
|
147
147
|
return { kind: "update", channel: "stable" };
|
|
148
148
|
const [selector, ...values] = rest;
|
|
@@ -167,10 +167,9 @@ function parseUpdate(rest) {
|
|
|
167
167
|
}
|
|
168
168
|
if (selector === "pi")
|
|
169
169
|
return pinnedPiUpdateError();
|
|
170
|
-
if (selector
|
|
170
|
+
if (selector === "--self" || selector === "--all")
|
|
171
171
|
return unknownOption(selector, "update");
|
|
172
|
-
|
|
173
|
-
return { kind: "noop" };
|
|
172
|
+
return parsePackageUpdate(rest, "direct");
|
|
174
173
|
}
|
|
175
174
|
function isDevelopmentTarget(target) {
|
|
176
175
|
return /^[1-9]\d*$/.test(target) || /^\d+\.\d+\.\d+-dev\.[1-9]\d*$/.test(target);
|
|
@@ -178,48 +177,49 @@ function isDevelopmentTarget(target) {
|
|
|
178
177
|
function updateGrammarError(detail) {
|
|
179
178
|
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`could not parse update: ${detail}`) };
|
|
180
179
|
}
|
|
181
|
-
function
|
|
180
|
+
function parsePackageCommand(arguments_, namespace) {
|
|
182
181
|
const [verb, ...rest] = arguments_;
|
|
183
182
|
if ((verb === "install" || verb === "remove" || verb === "uninstall" || verb === "list" || verb === "update")
|
|
184
183
|
&& rest.some(value => value === "--help" || value === "-h")) {
|
|
185
|
-
return { kind: "package-help", verb: verb === "uninstall" ? "remove" : verb };
|
|
184
|
+
return { kind: "package-help", verb: verb === "uninstall" ? "remove" : verb, namespace };
|
|
186
185
|
}
|
|
187
186
|
if (verb === "install" || verb === "remove" || verb === "uninstall") {
|
|
188
|
-
return parseSourceCommand(verb === "install" ? "install" : "remove", rest);
|
|
187
|
+
return parseSourceCommand(verb === "install" ? "install" : "remove", rest, namespace);
|
|
189
188
|
}
|
|
190
189
|
if (verb === "list") {
|
|
191
190
|
const flag = rest.find(argument => argument.startsWith("-"));
|
|
192
191
|
if (flag !== undefined)
|
|
193
|
-
return packageOptionError(flag, "list");
|
|
192
|
+
return packageOptionError(flag, "list", namespace);
|
|
194
193
|
if (rest[0] !== undefined)
|
|
195
|
-
return packageSyntax({ verb: "list", kind: "unexpected-argument", value: rest[0] });
|
|
194
|
+
return packageSyntax({ verb: "list", kind: "unexpected-argument", value: rest[0] }, namespace);
|
|
196
195
|
return { kind: "packages", request: { verb: "list", source: null } };
|
|
197
196
|
}
|
|
198
197
|
if (verb === "update")
|
|
199
|
-
return
|
|
198
|
+
return parsePackageUpdate(rest, namespace);
|
|
200
199
|
return { kind: "noop" };
|
|
201
200
|
}
|
|
202
|
-
function
|
|
201
|
+
function parsePackageUpdate(rest, namespace) {
|
|
203
202
|
if (rest.length === 0)
|
|
204
203
|
return pinnedPiUpdateError();
|
|
205
204
|
if (rest.length > 1) {
|
|
206
205
|
const unknown = rest.find(value => value.startsWith("-") && !["--extensions", "--models", "--self", "--all"].includes(value));
|
|
207
206
|
if (unknown !== undefined)
|
|
208
|
-
return packageOptionError(unknown, "update");
|
|
207
|
+
return packageOptionError(unknown, "update", namespace);
|
|
209
208
|
if (rest.includes("--self") || rest.includes("--all") || rest.includes("self") || rest.includes("pi"))
|
|
210
209
|
return pinnedPiUpdateError();
|
|
211
210
|
if (rest.every(value => value === rest[0]) && rest[0]?.startsWith("-")) {
|
|
212
|
-
|
|
211
|
+
const command = namespace === "direct" ? "update" : "pi update";
|
|
212
|
+
return { kind: "error", message: PRODUCT_TEXT.diagnostic(`${command} accepts one target.`) };
|
|
213
213
|
}
|
|
214
214
|
const sources = rest.filter(value => !value.startsWith("-"));
|
|
215
215
|
if (sources[1] !== undefined)
|
|
216
|
-
return packageSyntax({ verb: "update", kind: "unexpected-argument", value: sources[1] });
|
|
216
|
+
return packageSyntax({ verb: "update", kind: "unexpected-argument", value: sources[1] }, namespace);
|
|
217
217
|
const message = rest.includes("--models")
|
|
218
218
|
? rest.includes("--extensions")
|
|
219
219
|
? "--models cannot be combined with --self, --extensions, --all, or --extension"
|
|
220
220
|
: "--models cannot be combined with a positional source"
|
|
221
221
|
: "positional update targets cannot be combined with --self, --extensions, or --all";
|
|
222
|
-
return packageSyntax({ verb: "update", kind: "conflict", message });
|
|
222
|
+
return packageSyntax({ verb: "update", kind: "conflict", message }, namespace);
|
|
223
223
|
}
|
|
224
224
|
const [target] = rest;
|
|
225
225
|
if (target === "--extensions")
|
|
@@ -229,7 +229,7 @@ function parsePiPackageUpdate(rest) {
|
|
|
229
229
|
if (target === "--self" || target === "--all" || target === "self" || target === "pi")
|
|
230
230
|
return pinnedPiUpdateError();
|
|
231
231
|
if (target === undefined || target.startsWith("-"))
|
|
232
|
-
return packageOptionError(target ?? "", "update");
|
|
232
|
+
return packageOptionError(target ?? "", "update", namespace);
|
|
233
233
|
return { kind: "packages", request: { verb: "update", source: target } };
|
|
234
234
|
}
|
|
235
235
|
function pinnedPiUpdateError() {
|
|
@@ -239,35 +239,35 @@ function pinnedPiUpdateError() {
|
|
|
239
239
|
PRODUCT_TEXT.diagnostic("pins its certified Pi runtime and cannot update it independently."),
|
|
240
240
|
"Use:",
|
|
241
241
|
` ${PRODUCT_TEXT.commandName} update Update a1`,
|
|
242
|
-
` ${PRODUCT_TEXT.commandName}
|
|
243
|
-
` ${PRODUCT_TEXT.commandName}
|
|
242
|
+
` ${PRODUCT_TEXT.commandName} update --extensions Update Pi-compatible packages`,
|
|
243
|
+
` ${PRODUCT_TEXT.commandName} update --models Refresh model catalogs`,
|
|
244
244
|
].join("\n"),
|
|
245
245
|
};
|
|
246
246
|
}
|
|
247
|
-
function parseSourceCommand(verb, rest) {
|
|
247
|
+
function parseSourceCommand(verb, rest, namespace) {
|
|
248
248
|
const flag = rest.find(argument => argument.startsWith("-"));
|
|
249
249
|
if (flag !== undefined)
|
|
250
|
-
return packageOptionError(flag, verb);
|
|
250
|
+
return packageOptionError(flag, verb, namespace);
|
|
251
251
|
const [source, extra] = rest;
|
|
252
252
|
if (extra !== undefined)
|
|
253
|
-
return packageSyntax({ verb, kind: "unexpected-argument", value: extra });
|
|
253
|
+
return packageSyntax({ verb, kind: "unexpected-argument", value: extra }, namespace);
|
|
254
254
|
if (source === undefined)
|
|
255
|
-
return packageSyntax({ verb, kind: "missing-source" });
|
|
255
|
+
return packageSyntax({ verb, kind: "missing-source" }, namespace);
|
|
256
256
|
if (PROFILE_WORDS.has(source))
|
|
257
257
|
return profileRejection(verb);
|
|
258
258
|
return { kind: "packages", request: { verb, source } };
|
|
259
259
|
}
|
|
260
|
-
function packageSyntax(diagnostic) {
|
|
261
|
-
return { kind: "package-error", diagnostic };
|
|
260
|
+
function packageSyntax(diagnostic, namespace) {
|
|
261
|
+
return { kind: "package-error", diagnostic, namespace };
|
|
262
262
|
}
|
|
263
|
-
function packageOptionError(option, verb) {
|
|
263
|
+
function packageOptionError(option, verb, namespace) {
|
|
264
264
|
if (option.startsWith("--profile") || option === "-l" || option === "--local")
|
|
265
265
|
return profileRejection(verb);
|
|
266
266
|
// Compatibility: these recognized Pi flags remain outside A1's supported subset.
|
|
267
267
|
if (["--extension", "--approve", "--no-approve", "-a", "-na", "--force"].includes(option)) {
|
|
268
|
-
return unknownOption(option, `pi ${verb}`);
|
|
268
|
+
return unknownOption(option, namespace === "direct" ? verb : `pi ${verb}`);
|
|
269
269
|
}
|
|
270
|
-
return packageSyntax({ verb, kind: "unknown-option", value: option });
|
|
270
|
+
return packageSyntax({ verb, kind: "unknown-option", value: option }, namespace);
|
|
271
271
|
}
|
|
272
272
|
function withoutArguments(rest, command) {
|
|
273
273
|
if (rest.length === 0)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
/** Supported subset of pinned Pi's package-manager CLI presentation. */
|
|
3
3
|
export type PackageCliVerb = "install" | "remove" | "list" | "update";
|
|
4
|
+
export type PackageCommandNamespace = "direct" | "pi";
|
|
4
5
|
export type PackageSyntaxDiagnostic = {
|
|
5
6
|
readonly verb: PackageCliVerb;
|
|
6
7
|
readonly kind: "missing-source";
|
|
@@ -18,9 +19,9 @@ export type PackageSyntaxDiagnostic = {
|
|
|
18
19
|
readonly message: string;
|
|
19
20
|
};
|
|
20
21
|
type MessageStyle = Pick<typeof chalk, "red" | "dim" | "bold">;
|
|
21
|
-
export declare function packageCommandUsage(verb: PackageCliVerb): string;
|
|
22
|
+
export declare function packageCommandUsage(verb: PackageCliVerb, namespace?: PackageCommandNamespace): string;
|
|
22
23
|
/** Diagnostic facts stay unstyled until the terminal boundary decides color support. */
|
|
23
|
-
export declare function renderPackageSyntax(diagnostic: PackageSyntaxDiagnostic, style?: MessageStyle): string;
|
|
24
|
+
export declare function renderPackageSyntax(diagnostic: PackageSyntaxDiagnostic, namespace?: PackageCommandNamespace, style?: MessageStyle): string;
|
|
24
25
|
/** Pi's help layout, with unsupported options and examples deliberately absent. */
|
|
25
|
-
export declare function packageCommandHelp(verb: PackageCliVerb, style?: MessageStyle): string;
|
|
26
|
+
export declare function packageCommandHelp(verb: PackageCliVerb, namespace?: PackageCommandNamespace, style?: MessageStyle): string;
|
|
26
27
|
export {};
|
|
@@ -2,21 +2,26 @@
|
|
|
2
2
|
// at 914cf1472e715297caa30db4b9535d534a9eb718 (MIT); grammar is restricted to A1's supported subset.
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { PRODUCT_TEXT } from "../product-identity.js";
|
|
5
|
-
export function packageCommandUsage(verb) {
|
|
6
|
-
const command =
|
|
5
|
+
export function packageCommandUsage(verb, namespace = "pi") {
|
|
6
|
+
const command = namespace === "direct"
|
|
7
|
+
? `${PRODUCT_TEXT.commandName} ${verb}`
|
|
8
|
+
: `${PRODUCT_TEXT.commandName} pi ${verb}`;
|
|
7
9
|
if (verb === "install" || verb === "remove")
|
|
8
10
|
return `${command} <source>`;
|
|
11
|
+
if (verb === "update" && namespace === "direct") {
|
|
12
|
+
return `${command} [--develop [preview-or-version]|--models|--extensions|source]`;
|
|
13
|
+
}
|
|
9
14
|
if (verb === "update")
|
|
10
15
|
return `${command} [source|--extensions|--models]`;
|
|
11
16
|
return command;
|
|
12
17
|
}
|
|
13
18
|
/** Diagnostic facts stay unstyled until the terminal boundary decides color support. */
|
|
14
|
-
export function renderPackageSyntax(diagnostic, style = chalk) {
|
|
15
|
-
const usage = packageCommandUsage(diagnostic.verb);
|
|
19
|
+
export function renderPackageSyntax(diagnostic, namespace = "pi", style = chalk) {
|
|
20
|
+
const usage = packageCommandUsage(diagnostic.verb, namespace);
|
|
16
21
|
let message;
|
|
17
22
|
if (diagnostic.kind === "unknown-option") {
|
|
18
23
|
return `${style.red(`Unknown option ${diagnostic.value} for "${diagnostic.verb}".`)}\n`
|
|
19
|
-
+ `${style.dim(`Use "${PRODUCT_TEXT.commandName}
|
|
24
|
+
+ `${style.dim(`Use "${PRODUCT_TEXT.commandName} help" or "${usage}".`)}\n`;
|
|
20
25
|
}
|
|
21
26
|
if (diagnostic.kind === "missing-source")
|
|
22
27
|
message = `Missing ${diagnostic.verb} source.`;
|
|
@@ -27,9 +32,16 @@ export function renderPackageSyntax(diagnostic, style = chalk) {
|
|
|
27
32
|
return `${style.red(message)}\n${style.dim(`Usage: ${usage}`)}\n`;
|
|
28
33
|
}
|
|
29
34
|
/** Pi's help layout, with unsupported options and examples deliberately absent. */
|
|
30
|
-
export function packageCommandHelp(verb, style = chalk) {
|
|
31
|
-
const command = `${PRODUCT_TEXT.commandName} pi`;
|
|
32
|
-
const header =
|
|
35
|
+
export function packageCommandHelp(verb, namespace = "pi", style = chalk) {
|
|
36
|
+
const command = namespace === "direct" ? PRODUCT_TEXT.commandName : `${PRODUCT_TEXT.commandName} pi`;
|
|
37
|
+
const header = verb === "update" && namespace === "direct"
|
|
38
|
+
? `${style.bold("Usage:")}\n`
|
|
39
|
+
+ ` ${command} update\n`
|
|
40
|
+
+ ` ${command} update --develop [preview-or-version]\n`
|
|
41
|
+
+ ` ${command} update --models\n`
|
|
42
|
+
+ ` ${command} update --extensions\n`
|
|
43
|
+
+ ` ${command} update <source>\n\n`
|
|
44
|
+
: `${style.bold("Usage:")}\n ${packageCommandUsage(verb, namespace)}\n\n`;
|
|
33
45
|
switch (verb) {
|
|
34
46
|
case "install":
|
|
35
47
|
return header + `Install a package and add it to settings.
|
|
@@ -55,14 +67,14 @@ Examples:
|
|
|
55
67
|
case "list":
|
|
56
68
|
return header + "List installed packages from user settings.\n\n";
|
|
57
69
|
case "update":
|
|
58
|
-
return header +
|
|
70
|
+
return header + `${namespace === "direct" ? "Update A1, installed packages, or model catalogs." : "Update installed packages or model catalogs."}
|
|
59
71
|
|
|
60
72
|
Options:
|
|
61
|
-
--extensions Update installed packages only
|
|
73
|
+
${namespace === "direct" ? " --develop [target] Update to the development channel or one preview\n" : ""} --extensions Update installed packages only
|
|
62
74
|
--models Refresh model catalogs only
|
|
63
75
|
|
|
64
76
|
Short forms:
|
|
65
|
-
${command} update --extensions Update installed packages only
|
|
77
|
+
${namespace === "direct" ? ` ${command} update Update A1 to the stable release\n ${command} update --develop Update A1 to the development preview\n` : ""} ${command} update --extensions Update installed packages only
|
|
66
78
|
${command} update --models Refresh model catalogs only
|
|
67
79
|
${command} update <source> Update one package
|
|
68
80
|
|
|
@@ -5,6 +5,8 @@ export type { OwnedUiBlockStatus, OwnedUiCommand, OwnedUiCommandOutcome, OwnedUi
|
|
|
5
5
|
export { acceptsTranscriptUpdate, transcriptToolState } from "./transcript-lifecycle.js";
|
|
6
6
|
export { ImageAttachmentError, MAX_CLIPBOARD_TEXT_BYTES, MAX_IMAGE_DATA_BYTES, MAX_PROMPT_IMAGES, assertImageEncodedSize, assertPromptImages, } from "./image-attachments.js";
|
|
7
7
|
export { CONTEXTUAL_PROMPT_SUGGESTION_INSTRUCTION, normalizePromptSuggestionCandidate } from "./prompt-suggestions.js";
|
|
8
|
+
export { canonicalPromptChipMatches, protectPromptChipWrapping, replaceCanonicalPromptChips } from "./prompt-chips.js";
|
|
9
|
+
export type { PromptChipTextMatch, PromptChipWrapProtection } from "./prompt-chips.js";
|
|
8
10
|
export { SUGGESTION_DECISION_REASONS, SUGGESTION_DIAGNOSTIC_EVENTS } from "./suggestion-diagnostics.js";
|
|
9
11
|
export type { SuggestionDecision, SuggestionDecisionReason, SuggestionDiagnosticEvent, SuggestionDiagnosticObserver, SuggestionDiagnosticRecord, } from "./suggestion-diagnostics.js";
|
|
10
12
|
export { PROMPT_HISTORY_EDITOR_REPLACEMENT, PROMPT_HISTORY_MAX_ENTRY_BYTES, PROMPT_HISTORY_MAX_PENDING, PROMPT_HISTORY_MAX_TEXT_BYTES, assertPromptHistorySubmission, } from "./prompt-history.js";
|
|
@@ -3,6 +3,7 @@ export { OWNED_UI_CONTRACT_VERSION } from "./model.js";
|
|
|
3
3
|
export { acceptsTranscriptUpdate, transcriptToolState } from "./transcript-lifecycle.js";
|
|
4
4
|
export { ImageAttachmentError, MAX_CLIPBOARD_TEXT_BYTES, MAX_IMAGE_DATA_BYTES, MAX_PROMPT_IMAGES, assertImageEncodedSize, assertPromptImages, } from "./image-attachments.js";
|
|
5
5
|
export { CONTEXTUAL_PROMPT_SUGGESTION_INSTRUCTION, normalizePromptSuggestionCandidate } from "./prompt-suggestions.js";
|
|
6
|
+
export { canonicalPromptChipMatches, protectPromptChipWrapping, replaceCanonicalPromptChips } from "./prompt-chips.js";
|
|
6
7
|
export { SUGGESTION_DECISION_REASONS, SUGGESTION_DIAGNOSTIC_EVENTS } from "./suggestion-diagnostics.js";
|
|
7
8
|
export { PROMPT_HISTORY_EDITOR_REPLACEMENT, PROMPT_HISTORY_MAX_ENTRY_BYTES, PROMPT_HISTORY_MAX_PENDING, PROMPT_HISTORY_MAX_TEXT_BYTES, assertPromptHistorySubmission, } from "./prompt-history.js";
|
|
8
9
|
export { assertOwnedUiCommand, assertOwnedUiCustomization, assertOwnedUiDiagnostics, assertOwnedUiEditorState, assertOwnedUiEvent, assertOwnedUiPromptSuggestionIdentity, assertOwnedUiPromptSuggestionRequest, assertOwnedUiPromptSuggestionResult, assertOwnedUiPromptSuggestionState, assertOwnedUiSessionViewModel, assertOwnedUiSnapshot, assertOwnedUiStatusView, assertOwnedUiTerminalSurface, assertOwnedUiTranscriptBlock, } from "./validation.js";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface PromptChipTextMatch {
|
|
2
|
+
readonly text: string;
|
|
3
|
+
readonly start: number;
|
|
4
|
+
readonly end: number;
|
|
5
|
+
}
|
|
6
|
+
export interface PromptChipWrapProtection {
|
|
7
|
+
readonly text: string;
|
|
8
|
+
restore(rendered: string): string;
|
|
9
|
+
}
|
|
10
|
+
/** Finds canonical prompt-chip labels without requiring their process-local backing values. */
|
|
11
|
+
export declare function canonicalPromptChipMatches(text: string): readonly PromptChipTextMatch[];
|
|
12
|
+
/** Replaces only canonical prompt-chip labels while preserving every intervening source byte. */
|
|
13
|
+
export declare function replaceCanonicalPromptChips(text: string, replacement: (match: PromptChipTextMatch) => string): string;
|
|
14
|
+
/** Protects fitting chip labels for Markdown wrapping and restores their exact visible source text. */
|
|
15
|
+
export declare function protectPromptChipWrapping(text: string): PromptChipWrapProtection;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const PROMPT_CHIP_PATTERN = /\[(?:paste #\d+ (?:\+\d+ lines|\d+ chars)|📷 [^\]]+|📁 [^\]]+|📄 [^\]]+|🖼 {1,2}[^\]]+|🔗 [^\]]+)\]/gu;
|
|
2
|
+
const ZERO_WIDTH_MARKERS = ["\u2060", "\u200b", "\u200c", "\u200d", "\ufeff"];
|
|
3
|
+
/** Finds canonical prompt-chip labels without requiring their process-local backing values. */
|
|
4
|
+
export function canonicalPromptChipMatches(text) {
|
|
5
|
+
return [...text.matchAll(PROMPT_CHIP_PATTERN)].map(match => ({
|
|
6
|
+
text: match[0], start: match.index, end: match.index + match[0].length,
|
|
7
|
+
}));
|
|
8
|
+
}
|
|
9
|
+
/** Replaces only canonical prompt-chip labels while preserving every intervening source byte. */
|
|
10
|
+
export function replaceCanonicalPromptChips(text, replacement) {
|
|
11
|
+
return text.replace(PROMPT_CHIP_PATTERN, (value, offset) => replacement({
|
|
12
|
+
text: value, start: offset, end: offset + value.length,
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
/** Protects fitting chip labels for Markdown wrapping and restores their exact visible source text. */
|
|
16
|
+
export function protectPromptChipWrapping(text) {
|
|
17
|
+
const matches = canonicalPromptChipMatches(text);
|
|
18
|
+
if (matches.length === 0)
|
|
19
|
+
return { text, restore: identity };
|
|
20
|
+
const spaceMarker = unusedPrivateMarker(text);
|
|
21
|
+
const boundaryMarker = unusedZeroWidthMarker(text);
|
|
22
|
+
let protectedText = "", cursor = 0;
|
|
23
|
+
for (const match of matches) {
|
|
24
|
+
protectedText += text.slice(cursor, match.start);
|
|
25
|
+
// Rationale: adjacent chips need a temporary break opportunity or Markdown treats the complete run as one word.
|
|
26
|
+
if (match.start === cursor && cursor > 0)
|
|
27
|
+
protectedText += `${boundaryMarker} `;
|
|
28
|
+
protectedText += match.text.replaceAll(" ", spaceMarker);
|
|
29
|
+
cursor = match.end;
|
|
30
|
+
}
|
|
31
|
+
protectedText += text.slice(cursor);
|
|
32
|
+
return {
|
|
33
|
+
text: protectedText,
|
|
34
|
+
restore: rendered => rendered
|
|
35
|
+
.replaceAll(`${boundaryMarker} `, "")
|
|
36
|
+
.replaceAll(boundaryMarker, "")
|
|
37
|
+
.replaceAll(spaceMarker, " "),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function unusedPrivateMarker(text) {
|
|
41
|
+
for (let codePoint = 0xe000; codePoint <= 0xf8ff; codePoint++) {
|
|
42
|
+
const marker = String.fromCodePoint(codePoint);
|
|
43
|
+
if (!text.includes(marker))
|
|
44
|
+
return marker;
|
|
45
|
+
}
|
|
46
|
+
throw new Error("Prompt chip text exhausts the private presentation marker range");
|
|
47
|
+
}
|
|
48
|
+
function unusedZeroWidthMarker(text) {
|
|
49
|
+
for (const marker of ZERO_WIDTH_MARKERS)
|
|
50
|
+
if (!text.includes(marker))
|
|
51
|
+
return marker;
|
|
52
|
+
for (const left of ZERO_WIDTH_MARKERS) {
|
|
53
|
+
for (const right of ZERO_WIDTH_MARKERS)
|
|
54
|
+
if (!text.includes(left + right))
|
|
55
|
+
return left + right;
|
|
56
|
+
}
|
|
57
|
+
throw new Error("Prompt chip text exhausts the zero-width presentation marker range");
|
|
58
|
+
}
|
|
59
|
+
function identity(value) { return value; }
|
|
@@ -353,7 +353,7 @@ export function assertOwnedUiStatusView(status) {
|
|
|
353
353
|
assertBoundedText(status.title, "owned-UI status title", MAX_LABEL_LENGTH);
|
|
354
354
|
assertOptionalText(status.workingMessage, "owned-UI working message", MAX_MESSAGE_LENGTH);
|
|
355
355
|
if (status.workingProgress !== undefined && status.workingProgress !== null) {
|
|
356
|
-
assertIntegerInRange(status.workingProgress, 0,
|
|
356
|
+
assertIntegerInRange(status.workingProgress, 0, 100, "owned-UI working progress");
|
|
357
357
|
}
|
|
358
358
|
assertCollection(status.diagnostics, "owned-UI status diagnostics", MAX_STATUS_DIAGNOSTICS);
|
|
359
359
|
for (const diagnostic of status.diagnostics) {
|
|
@@ -10,6 +10,7 @@ export { PINNED_PI_LAYOUT, applyConfiguredPiTheme, applyPiTheme, applyPiThemeIns
|
|
|
10
10
|
export type { PiColorMode, PiTerminalTheme, PiTerminalThemeDetection, PiTerminalThemeDetector, PiThemeBackground, PiThemeResult } from "./theme.js";
|
|
11
11
|
export { OwnedPiThemeController } from "./upstream/theme/theme-controller.js";
|
|
12
12
|
export type { PiThemeRuntimePort, PiThemeSettingsPort } from "./upstream/theme/theme-controller.js";
|
|
13
|
+
export { PI_MODAL_CONTENT_PADDING_X, PiModalFrame, PiModalHeader, addPiModalHeader, adoptPiModalFrame, adoptPiModalHeader, } from "./modal-frame.js";
|
|
13
14
|
export { ModelsDialogComponent } from "./models-dialog.js";
|
|
14
15
|
export type { ModelsDialogCallbacks, ModelsDialogConfig, ModelsDialogFilter, ModelsDialogModel } from "./models-dialog.js";
|
|
15
16
|
export { CountdownTimer } from "./upstream/components/countdown-timer.js";
|
|
@@ -5,6 +5,7 @@ export { OWNED_BUILTIN_SLASH_COMMANDS, PINNED_PI_BUILTIN_SLASH_COMMANDS, compone
|
|
|
5
5
|
export { renderPiShellHotkeySections } from "./shell-hotkey-sections.js";
|
|
6
6
|
export { PINNED_PI_LAYOUT, applyConfiguredPiTheme, applyPiTheme, applyPiThemeInstance, currentPiThemeName, detectPiTerminalBackgroundFromEnv, detectPiTerminalBackgroundTheme, detectPiTerminalThemeForAuto, ensurePiTheme, getAvailablePiThemes, loadPiTheme, onPiThemeChange, parsePiAutoThemeSetting, piTheme, resolvePiThemeSetting, stopPiThemeWatcher, } from "./theme.js";
|
|
7
7
|
export { OwnedPiThemeController } from "./upstream/theme/theme-controller.js";
|
|
8
|
+
export { PI_MODAL_CONTENT_PADDING_X, PiModalFrame, PiModalHeader, addPiModalHeader, adoptPiModalFrame, adoptPiModalHeader, } from "./modal-frame.js";
|
|
8
9
|
export { ModelsDialogComponent } from "./models-dialog.js";
|
|
9
10
|
export { CountdownTimer } from "./upstream/components/countdown-timer.js";
|
|
10
11
|
export { ExtensionEditorComponent } from "./upstream/components/extension-editor.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Container, type Component } from "@earendil-works/pi-tui";
|
|
2
|
+
export declare const PI_MODAL_CONTENT_PADDING_X = 1;
|
|
3
|
+
/** The semantic top rule/title pair used while a modal assembles its frame. */
|
|
4
|
+
export declare class PiModalHeader implements Component {
|
|
5
|
+
readonly rule: Component;
|
|
6
|
+
readonly title: Component;
|
|
7
|
+
constructor(rule: Component, title: Component);
|
|
8
|
+
invalidate(): void;
|
|
9
|
+
render(width: number): string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Complete framed-modal chrome. Rules remain frame-wide; every semantic content component renders
|
|
13
|
+
* in the same one-cell-smaller rectangle and receives the same left inset.
|
|
14
|
+
*/
|
|
15
|
+
export declare class PiModalFrame implements Component {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(topRule: Component, content: readonly Component[], bottomRule: Component, fullWidthContent?: readonly Component[], preInsetContent?: readonly Component[]);
|
|
18
|
+
invalidate(): void;
|
|
19
|
+
render(width: number): string[];
|
|
20
|
+
}
|
|
21
|
+
/** Add compact titled-modal chrome while a component assembles its semantic body. */
|
|
22
|
+
export declare function addPiModalHeader(container: Container, rule: Component, title: Component): PiModalHeader;
|
|
23
|
+
export interface PiModalFrameAdoption {
|
|
24
|
+
readonly topIndex: number;
|
|
25
|
+
readonly bottomIndex: number;
|
|
26
|
+
readonly header?: PiModalHeader;
|
|
27
|
+
readonly fullWidthContent?: readonly Component[];
|
|
28
|
+
/** Public pinned children that already own the same one-cell outer inset. */
|
|
29
|
+
readonly preInsetContent?: readonly Component[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Replace explicitly identified structural modal children with the shared padded frame. Callers
|
|
33
|
+
* identify semantic rules/components; rendered text is never inspected or rewritten.
|
|
34
|
+
*/
|
|
35
|
+
export declare function adoptPiModalFrame(container: Container, adoption: PiModalFrameAdoption): PiModalFrame;
|
|
36
|
+
/**
|
|
37
|
+
* Adopt a public component's semantic rule/title children at the bare-A1 boundary. Only an optional
|
|
38
|
+
* structural Spacer between those explicitly identified children is accepted; rendered text is
|
|
39
|
+
* never inspected or rewritten. The pinned comparison profile does not call this adapter.
|
|
40
|
+
*/
|
|
41
|
+
export declare function adoptPiModalHeader(container: Container, ruleIndex: number, titleIndex: number): PiModalHeader;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { Container, Spacer } from "@earendil-works/pi-tui";
|
|
2
|
+
export const PI_MODAL_CONTENT_PADDING_X = 1;
|
|
3
|
+
/** The semantic top rule/title pair used while a modal assembles its frame. */
|
|
4
|
+
export class PiModalHeader {
|
|
5
|
+
rule;
|
|
6
|
+
title;
|
|
7
|
+
constructor(rule, title) {
|
|
8
|
+
this.rule = rule;
|
|
9
|
+
this.title = title;
|
|
10
|
+
}
|
|
11
|
+
invalidate() {
|
|
12
|
+
this.rule.invalidate();
|
|
13
|
+
this.title.invalidate();
|
|
14
|
+
}
|
|
15
|
+
render(width) {
|
|
16
|
+
return [...this.rule.render(width), ...this.title.render(width)];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Complete framed-modal chrome. Rules remain frame-wide; every semantic content component renders
|
|
21
|
+
* in the same one-cell-smaller rectangle and receives the same left inset.
|
|
22
|
+
*/
|
|
23
|
+
export class PiModalFrame {
|
|
24
|
+
#topRule;
|
|
25
|
+
#content;
|
|
26
|
+
#bottomRule;
|
|
27
|
+
#fullWidthContent;
|
|
28
|
+
#preInsetContent;
|
|
29
|
+
constructor(topRule, content, bottomRule, fullWidthContent = [], preInsetContent = []) {
|
|
30
|
+
this.#topRule = topRule;
|
|
31
|
+
this.#content = content;
|
|
32
|
+
this.#bottomRule = bottomRule;
|
|
33
|
+
this.#fullWidthContent = new Set(fullWidthContent);
|
|
34
|
+
this.#preInsetContent = new Set(preInsetContent);
|
|
35
|
+
}
|
|
36
|
+
invalidate() {
|
|
37
|
+
this.#topRule.invalidate();
|
|
38
|
+
for (const component of this.#content)
|
|
39
|
+
component.invalidate();
|
|
40
|
+
this.#bottomRule.invalidate();
|
|
41
|
+
}
|
|
42
|
+
render(width) {
|
|
43
|
+
const padding = Math.min(PI_MODAL_CONTENT_PADDING_X, Math.max(0, width));
|
|
44
|
+
const contentWidth = Math.max(0, width - padding);
|
|
45
|
+
const rows = [...this.#topRule.render(width)];
|
|
46
|
+
for (const component of this.#content) {
|
|
47
|
+
if (this.#fullWidthContent.has(component) || this.#preInsetContent.has(component)) {
|
|
48
|
+
rows.push(...component.render(width));
|
|
49
|
+
}
|
|
50
|
+
else if (component instanceof Spacer) {
|
|
51
|
+
rows.push(...component.render(contentWidth));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
rows.push(...component.render(contentWidth).map(row => `${" ".repeat(padding)}${row}`));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
rows.push(...this.#bottomRule.render(width));
|
|
58
|
+
return rows;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Add compact titled-modal chrome while a component assembles its semantic body. */
|
|
62
|
+
export function addPiModalHeader(container, rule, title) {
|
|
63
|
+
const header = new PiModalHeader(rule, title);
|
|
64
|
+
container.addChild(header);
|
|
65
|
+
return header;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Replace explicitly identified structural modal children with the shared padded frame. Callers
|
|
69
|
+
* identify semantic rules/components; rendered text is never inspected or rewritten.
|
|
70
|
+
*/
|
|
71
|
+
export function adoptPiModalFrame(container, adoption) {
|
|
72
|
+
const { topIndex, bottomIndex, header, fullWidthContent = [], preInsetContent = [] } = adoption;
|
|
73
|
+
if (topIndex < 0 || bottomIndex <= topIndex || bottomIndex >= container.children.length) {
|
|
74
|
+
throw new TypeError("invalid modal frame child positions");
|
|
75
|
+
}
|
|
76
|
+
const top = container.children[topIndex];
|
|
77
|
+
const bottom = container.children[bottomIndex];
|
|
78
|
+
const contentStart = topIndex + 1;
|
|
79
|
+
let topRule = top;
|
|
80
|
+
const content = [];
|
|
81
|
+
if (header !== undefined) {
|
|
82
|
+
if (top !== header)
|
|
83
|
+
throw new TypeError("modal header is not at the declared top position");
|
|
84
|
+
topRule = header.rule;
|
|
85
|
+
content.push(header.title);
|
|
86
|
+
}
|
|
87
|
+
content.push(...container.children.slice(contentStart, bottomIndex));
|
|
88
|
+
const frame = new PiModalFrame(topRule, content, bottom, fullWidthContent, preInsetContent);
|
|
89
|
+
container.children.splice(topIndex, bottomIndex - topIndex + 1, frame);
|
|
90
|
+
return frame;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Adopt a public component's semantic rule/title children at the bare-A1 boundary. Only an optional
|
|
94
|
+
* structural Spacer between those explicitly identified children is accepted; rendered text is
|
|
95
|
+
* never inspected or rewritten. The pinned comparison profile does not call this adapter.
|
|
96
|
+
*/
|
|
97
|
+
export function adoptPiModalHeader(container, ruleIndex, titleIndex) {
|
|
98
|
+
if (ruleIndex < 0 || titleIndex <= ruleIndex || titleIndex >= container.children.length) {
|
|
99
|
+
throw new TypeError("invalid modal rule/title child positions");
|
|
100
|
+
}
|
|
101
|
+
const between = container.children.slice(ruleIndex + 1, titleIndex);
|
|
102
|
+
if (between.length > 1 || between.some(child => !(child instanceof Spacer))) {
|
|
103
|
+
throw new TypeError("modal rule and title are not separated by an optional single Spacer");
|
|
104
|
+
}
|
|
105
|
+
const rule = container.children[ruleIndex];
|
|
106
|
+
const title = container.children[titleIndex];
|
|
107
|
+
const header = new PiModalHeader(rule, title);
|
|
108
|
+
container.children.splice(ruleIndex, titleIndex - ruleIndex + 1, header);
|
|
109
|
+
return header;
|
|
110
|
+
}
|