@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/README.md
CHANGED
|
@@ -24,13 +24,15 @@ npm install -g @timurproko/a1@0.1.8-dev.107
|
|
|
24
24
|
|
|
25
25
|
```sh
|
|
26
26
|
a1 # launch A1 (profile: ~/.a1/agent)
|
|
27
|
-
a1
|
|
28
|
-
a1
|
|
27
|
+
a1 help # show all commands
|
|
28
|
+
a1 version # show the version
|
|
29
29
|
a1 update # install the newest stable release
|
|
30
30
|
a1 update --develop # install the current development preview
|
|
31
31
|
a1 update --develop 107 # install numbered preview 107
|
|
32
32
|
a1 update --develop 0.1.8-dev.107 # install that exact preview
|
|
33
33
|
a1 update --models # refresh A1's model catalogs
|
|
34
|
+
a1 update --extensions # update every installed package
|
|
35
|
+
a1 update npm:pi-mcp-adapter # update one package
|
|
34
36
|
```
|
|
35
37
|
|
|
36
38
|
Stable builds print only their installed version. Development builds also show the
|
|
@@ -47,17 +49,17 @@ Unsupported commands exit quietly without launching anything. The removed
|
|
|
47
49
|
|
|
48
50
|
## Extensions
|
|
49
51
|
|
|
50
|
-
Pi extension packages install into A1's own profile (`~/.a1/agent`), so
|
|
51
|
-
loads them and `a1 pi` does not. Sources
|
|
52
|
-
local
|
|
52
|
+
Pi-compatible extension packages install into A1's own profile (`~/.a1/agent`), so
|
|
53
|
+
bare `a1` loads them and the `a1 pi` comparison profile does not. Sources use Pi's
|
|
54
|
+
`npm:`, git, or local-path grammar.
|
|
53
55
|
|
|
54
56
|
```sh
|
|
55
|
-
a1
|
|
56
|
-
a1
|
|
57
|
-
a1
|
|
58
|
-
a1
|
|
59
|
-
a1
|
|
60
|
-
a1
|
|
57
|
+
a1 install npm:pi-mcp-adapter # install a package
|
|
58
|
+
a1 remove npm:pi-mcp-adapter # remove it (alias: a1 uninstall)
|
|
59
|
+
a1 list # list installed packages
|
|
60
|
+
a1 update --extensions # update every installed package
|
|
61
|
+
a1 update npm:pi-mcp-adapter # update one
|
|
62
|
+
a1 update --models # refresh A1's model catalogs
|
|
61
63
|
```
|
|
62
64
|
|
|
63
65
|
A1 pins the Pi runtime carried by each release, so Pi self-update forms are refused.
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { canonicalizeClipboardImage } from "./clipboard-image.js";
|
|
4
|
-
import { assertImageEncodedSize, assertPromptImages, ImageAttachmentError } from "../../contracts/owned-ui/index.js";
|
|
4
|
+
import { assertImageEncodedSize, assertPromptImages, canonicalPromptChipMatches, ImageAttachmentError, replaceCanonicalPromptChips, } from "../../contracts/owned-ui/index.js";
|
|
5
5
|
import { ImagePreparationClient } from "./image-preparation-client.js";
|
|
6
6
|
import { preparePasteText } from "./paste-text-preparation.js";
|
|
7
7
|
import { pathChipTag } from "./path-chip-presentation.js";
|
|
8
8
|
import { PastePreparationClient } from "./paste-preparation-client.js";
|
|
9
|
-
const CHIP_PATTERN = /\[(?:paste #\d+ (?:\+\d+ lines|\d+ chars)|📷 [^\]]+|📁 [^\]]+|📄 [^\]]+|🖼 {1,2}[^\]]+|🔗 [^\]]+)\]/gu;
|
|
10
9
|
const URL_SUBSTRING_PATTERN = /https?:\/\/[^\s\u0000-\u001f\u007f\]]+/giu;
|
|
11
10
|
const IMAGE_CHIP_IDENTIFIER_PATTERN = /^\[📷 screenshot-([a-f0-9]+)(?:-resized)?\]$/u;
|
|
12
11
|
const URL_DISPLAY_LENGTH = 40;
|
|
@@ -259,10 +258,9 @@ export class PromptChipStore {
|
|
|
259
258
|
return ranges.sort((left, right) => left.start - right.start);
|
|
260
259
|
}
|
|
261
260
|
atomicRanges(line) {
|
|
262
|
-
return
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}));
|
|
261
|
+
return canonicalPromptChipMatches(line)
|
|
262
|
+
.filter(match => !match.text.startsWith("[paste #") || this.#chips.has(match.text))
|
|
263
|
+
.map(match => ({ start: match.start, end: match.end }));
|
|
266
264
|
}
|
|
267
265
|
hyperlinkRanges(text) {
|
|
268
266
|
const ranges = [];
|
|
@@ -306,8 +304,8 @@ export class PromptChipStore {
|
|
|
306
304
|
imageChipAttachments(text) {
|
|
307
305
|
const results = [];
|
|
308
306
|
const seen = new Set();
|
|
309
|
-
for (const match of text
|
|
310
|
-
const tag = match
|
|
307
|
+
for (const match of canonicalPromptChipMatches(text)) {
|
|
308
|
+
const tag = match.text;
|
|
311
309
|
if (seen.has(tag))
|
|
312
310
|
continue;
|
|
313
311
|
const chip = this.#chips.get(tag);
|
|
@@ -338,39 +336,32 @@ export class PromptChipStore {
|
|
|
338
336
|
// Rationale: resolve image chip tags in-place before further classification. Sidecar hits
|
|
339
337
|
// register a live image chip; misses silently strip the tag (no placeholder, no notice) per
|
|
340
338
|
// the durability contract.
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const identifier = imageChipIdentifier(tag);
|
|
339
|
+
const resolvedImages = replaceCanonicalPromptChips(text, match => {
|
|
340
|
+
const identifier = imageChipIdentifier(match.text);
|
|
344
341
|
if (identifier === null)
|
|
345
|
-
return
|
|
342
|
+
return match.text;
|
|
346
343
|
const attachment = resolveImage(identifier);
|
|
347
344
|
if (attachment === null)
|
|
348
345
|
return "";
|
|
349
|
-
this.#chips.set(
|
|
350
|
-
return
|
|
346
|
+
this.#chips.set(match.text, { kind: "image", tag: match.text, image: attachment });
|
|
347
|
+
return match.text;
|
|
351
348
|
});
|
|
352
349
|
// Rationale: split around any surviving image tags so paste-time classification runs on the
|
|
353
350
|
// intervening prose exactly as it would on a fresh clipboard payload, plus a substring URL
|
|
354
351
|
// scan so embedded links become atomic chips even in the middle of surrounding text.
|
|
355
|
-
CHIP_PATTERN.lastIndex = 0;
|
|
356
352
|
const segments = [];
|
|
357
353
|
let cursor = 0;
|
|
358
|
-
for (const match of resolvedImages
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
cursor = index + match[0].length;
|
|
354
|
+
for (const match of canonicalPromptChipMatches(resolvedImages)) {
|
|
355
|
+
if (match.start > cursor)
|
|
356
|
+
segments.push(resolvedImages.slice(cursor, match.start));
|
|
357
|
+
segments.push(match.text);
|
|
358
|
+
cursor = match.end;
|
|
364
359
|
}
|
|
365
360
|
if (cursor < resolvedImages.length)
|
|
366
361
|
segments.push(resolvedImages.slice(cursor));
|
|
367
|
-
CHIP_PATTERN.lastIndex = 0;
|
|
368
362
|
return segments.map(segment => {
|
|
369
|
-
if (segment.length === 0 ||
|
|
370
|
-
CHIP_PATTERN.lastIndex = 0;
|
|
363
|
+
if (segment.length === 0 || canonicalPromptChipMatches(segment).length > 0)
|
|
371
364
|
return segment;
|
|
372
|
-
}
|
|
373
|
-
CHIP_PATTERN.lastIndex = 0;
|
|
374
365
|
// Invariant: preserve original whitespace framing so the concatenated recall value
|
|
375
366
|
// remains stable across rehydration.
|
|
376
367
|
const leading = segment.match(/^\s+/)?.[0] ?? "";
|
|
@@ -434,7 +425,8 @@ export class PromptChipStore {
|
|
|
434
425
|
return chip.kind === "url" ? chip.url : chip.path;
|
|
435
426
|
};
|
|
436
427
|
// Invariant: scan only draft tokens (and resolved reservation tokens), never emitted payloads.
|
|
437
|
-
const expanded = text
|
|
428
|
+
const expanded = replaceCanonicalPromptChips(text, match => {
|
|
429
|
+
const tag = match.text;
|
|
438
430
|
const entry = this.#pending.get(tag) ?? this.#pending.get(tag.replace("failed-", "screenshot-"));
|
|
439
431
|
if (entry === undefined)
|
|
440
432
|
return resolveChip(tag);
|
|
@@ -442,7 +434,7 @@ export class PromptChipStore {
|
|
|
442
434
|
throw entry.error;
|
|
443
435
|
if (includeImages && entry.replacement === undefined)
|
|
444
436
|
throw new ImageAttachmentError("image-pending");
|
|
445
|
-
return entry.replacement === undefined ? tag : entry.replacement
|
|
437
|
+
return entry.replacement === undefined ? tag : replaceCanonicalPromptChips(entry.replacement, replacement => resolveChip(replacement.text));
|
|
446
438
|
});
|
|
447
439
|
return { text: expanded, images };
|
|
448
440
|
}
|
|
@@ -229,6 +229,8 @@ export declare class OwnedUiSessionShellRoot implements PiTuiComponentPort {
|
|
|
229
229
|
viewportTransientTailRowCount(): number;
|
|
230
230
|
hasActiveSelection(): boolean;
|
|
231
231
|
setViewportConfig(config: OwnedUiViewportSettings): void;
|
|
232
|
+
setFullscreenCopyOnSelect(enabled: boolean): void;
|
|
233
|
+
showCopyAcknowledgement(message: string): void;
|
|
232
234
|
resumeViewportFollowing(): void;
|
|
233
235
|
noteCompletedAssistantMessage(): void;
|
|
234
236
|
/** A new session binding owns new mounts even when it reuses semantic invocation ids. */
|
|
@@ -3,7 +3,7 @@ import { caretCell } from "../../ui/components/line-input.js";
|
|
|
3
3
|
import { PromptInput, promptArrow } from "../../ui/components/prompt-input.js";
|
|
4
4
|
import { composeSubmittedPromptRows, formatSubmittedPromptTime, submittedPromptLayout, } from "../../ui/components/submitted-prompt.js";
|
|
5
5
|
import { backgroundSgrSpan, heldNativeHyperlinkStyle, hyperlinkSgrSpan, nativeHyperlinkStyle, overlaySpan, } from "../../ui/components/spans.js";
|
|
6
|
-
import { progressStatusText } from "../../ui/components/progress-status.js";
|
|
6
|
+
import { progressStatusFrame, progressStatusText } from "../../ui/components/progress-status.js";
|
|
7
7
|
import { displayWidth, faint, stripAnsi } from "../../ui/components/text.js";
|
|
8
8
|
import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES } from "../../integrations/pi/engine/workflows.js";
|
|
9
9
|
import { createPiExtensionUiBridge } from "../../integrations/pi/components/shell-extension-ui.js";
|
|
@@ -62,6 +62,8 @@ export class OwnedUiSessionShellRoot {
|
|
|
62
62
|
#lastWorkflowStatusId;
|
|
63
63
|
// Invariant: the notice is dock chrome, never transcript content; the custom viewport alone uses it.
|
|
64
64
|
#dockNotice;
|
|
65
|
+
#copyAcknowledgement;
|
|
66
|
+
#copyAcknowledgementTimer;
|
|
65
67
|
#inputSurface;
|
|
66
68
|
#inputSurfaceCoordination = "editor";
|
|
67
69
|
#dockInputReuseEnabled;
|
|
@@ -106,10 +108,12 @@ export class OwnedUiSessionShellRoot {
|
|
|
106
108
|
...(this.#customViewport ? { getKeybindings: () => this.editor.keybindingConfig() } : {}),
|
|
107
109
|
});
|
|
108
110
|
this.resources = createPiShellLoadedResources(startup.resources ?? [], startup.expanded ?? false);
|
|
109
|
-
this.#status = createPiShellStatus(view,
|
|
111
|
+
this.#status = createPiShellStatus(view, {
|
|
112
|
+
text: (message, mode) => progressStatusText(message, mode === "custom-viewport" ? "…" : "..."),
|
|
113
|
+
frame: progressStatusFrame,
|
|
114
|
+
}, handlers);
|
|
110
115
|
this.#status.setProgressPresentation(this.#customViewport ? "custom-viewport" : "pinned");
|
|
111
116
|
this.#footer = createPiShellFooter(this.#viewWithExtensionStatuses(view), cwd, this.#customViewport ? "a1" : "pi", () => this.#footerLevel);
|
|
112
|
-
this.#queued = createPiQueuedInputStatus(view.editor.queuedSubmissions, this.#customViewport ? "custom-viewport" : "pinned");
|
|
113
117
|
this.editor = createPiShellEditor({
|
|
114
118
|
...handlers,
|
|
115
119
|
keybindingProfile: this.#customViewport ? "a1" : "pi",
|
|
@@ -183,6 +187,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
183
187
|
},
|
|
184
188
|
...(handlers.onPromptSuggestionAccepted === undefined ? {} : { onPromptSuggestionAccepted: handlers.onPromptSuggestionAccepted }),
|
|
185
189
|
});
|
|
190
|
+
this.#queued = createPiQueuedInputStatus(view.editor.queuedSubmissions, this.#customViewport ? "custom-viewport" : "pinned", this.#customViewport ? () => this.editor.keybindingConfig() : undefined);
|
|
186
191
|
this.#viewportController = new SessionViewportController({
|
|
187
192
|
enabled: this.#customViewport,
|
|
188
193
|
editor: this.editor,
|
|
@@ -371,13 +376,14 @@ export class OwnedUiSessionShellRoot {
|
|
|
371
376
|
}
|
|
372
377
|
const height = Math.max(0, this.#componentRuntime.getRows());
|
|
373
378
|
const dock = this.#renderDockLayout(width);
|
|
374
|
-
// Invariant:
|
|
375
|
-
//
|
|
376
|
-
|
|
377
|
-
|
|
379
|
+
// Invariant: auto/always own one stable final-column gutter. Every scrollable
|
|
380
|
+
// surface ends before it; the dock remains full-width and hidden mode returns it.
|
|
381
|
+
const documentWidth = this.#viewportController.config.scrollbarAppearance === "hidden"
|
|
382
|
+
? width
|
|
383
|
+
: Math.max(1, width - 1);
|
|
378
384
|
const document = this.#renderDocumentLayout(documentWidth);
|
|
379
|
-
const steeringRows = this.#renderQueued(
|
|
380
|
-
const statusRows = this.#renderStatus(
|
|
385
|
+
const steeringRows = this.#renderQueued(documentWidth);
|
|
386
|
+
const statusRows = this.#renderStatus(documentWidth);
|
|
381
387
|
const transientSignature = transientRowsSignature(steeringRows, statusRows);
|
|
382
388
|
const snapshot = this.#visibleViewportSnapshot;
|
|
383
389
|
const dockInputCandidate = this.#dockInputCandidate;
|
|
@@ -494,6 +500,25 @@ export class OwnedUiSessionShellRoot {
|
|
|
494
500
|
if (this.#viewportController.setConfig(config))
|
|
495
501
|
this.#documentLayouts.clear();
|
|
496
502
|
}
|
|
503
|
+
setFullscreenCopyOnSelect(enabled) {
|
|
504
|
+
this.#viewportController.setCopyOnSelect(enabled);
|
|
505
|
+
}
|
|
506
|
+
showCopyAcknowledgement(message) {
|
|
507
|
+
this.#clearCopyAcknowledgement(false);
|
|
508
|
+
this.#copyAcknowledgement = message;
|
|
509
|
+
const timer = setTimeout(() => {
|
|
510
|
+
if (this.#copyAcknowledgementTimer !== timer)
|
|
511
|
+
return;
|
|
512
|
+
this.#copyAcknowledgementTimer = undefined;
|
|
513
|
+
this.#copyAcknowledgement = undefined;
|
|
514
|
+
this.#invalidateChrome();
|
|
515
|
+
this.#componentRuntime.requestRender();
|
|
516
|
+
}, COPY_ACKNOWLEDGEMENT_DURATION_MS);
|
|
517
|
+
timer.unref?.();
|
|
518
|
+
this.#copyAcknowledgementTimer = timer;
|
|
519
|
+
this.#invalidateChrome();
|
|
520
|
+
this.#componentRuntime.requestRender();
|
|
521
|
+
}
|
|
497
522
|
resumeViewportFollowing() {
|
|
498
523
|
this.#viewportController.resumeFollowing();
|
|
499
524
|
}
|
|
@@ -534,18 +559,36 @@ export class OwnedUiSessionShellRoot {
|
|
|
534
559
|
const statusRows = this.#customViewport ? this.#status.renderDock(width) : this.#renderStatus(width);
|
|
535
560
|
const transientRows = [...queued, ...statusRows, ...this.#renderDockNotice(width)];
|
|
536
561
|
const aboveWidgets = this.#renderWidgets("aboveEditor", width);
|
|
562
|
+
const copyAcknowledgement = this.#renderCopyAcknowledgement(width);
|
|
537
563
|
const input = this.#inputSurface.render(width);
|
|
538
564
|
// Invariant: pointer rows describe the body, not the autocomplete block now preceding it.
|
|
539
565
|
const body = this.usesDefaultInputSurface() ? this.editor.bodyGeometry?.() : undefined;
|
|
540
566
|
const belowWidgets = this.#renderWidgets("belowEditor", width);
|
|
541
567
|
const footer = this.#renderFooter(width);
|
|
542
|
-
const rowsWithoutTransient = [...aboveWidgets, ...input, ...belowWidgets, ...footer];
|
|
568
|
+
const rowsWithoutTransient = [...aboveWidgets, ...copyAcknowledgement, ...input, ...belowWidgets, ...footer];
|
|
543
569
|
return {
|
|
544
570
|
rows: [...transientRows, ...rowsWithoutTransient],
|
|
545
|
-
editorOffset: transientRows.length + aboveWidgets.length + (body?.rowOffset ?? 0),
|
|
571
|
+
editorOffset: transientRows.length + aboveWidgets.length + copyAcknowledgement.length + (body?.rowOffset ?? 0),
|
|
546
572
|
inputRows: body?.rowCount ?? input.length,
|
|
547
573
|
};
|
|
548
574
|
}
|
|
575
|
+
#renderCopyAcknowledgement(width) {
|
|
576
|
+
if (this.#copyAcknowledgement === undefined || width <= 0)
|
|
577
|
+
return [];
|
|
578
|
+
const text = piShellTruncateToWidth(this.#copyAcknowledgement, width);
|
|
579
|
+
return [`${" ".repeat(Math.max(0, width - piShellVisibleWidth(text)))}${piTheme().fg("accent", text)}`];
|
|
580
|
+
}
|
|
581
|
+
#clearCopyAcknowledgement(requestRender) {
|
|
582
|
+
if (this.#copyAcknowledgementTimer !== undefined)
|
|
583
|
+
clearTimeout(this.#copyAcknowledgementTimer);
|
|
584
|
+
this.#copyAcknowledgementTimer = undefined;
|
|
585
|
+
if (this.#copyAcknowledgement === undefined)
|
|
586
|
+
return;
|
|
587
|
+
this.#copyAcknowledgement = undefined;
|
|
588
|
+
this.#invalidateChrome();
|
|
589
|
+
if (requestRender)
|
|
590
|
+
this.#componentRuntime.requestRender();
|
|
591
|
+
}
|
|
549
592
|
#renderDockNotice(width) {
|
|
550
593
|
const notice = this.#dockNotice;
|
|
551
594
|
if (notice === undefined)
|
|
@@ -651,12 +694,9 @@ export class OwnedUiSessionShellRoot {
|
|
|
651
694
|
continue;
|
|
652
695
|
const promptLike = block !== undefined
|
|
653
696
|
&& (block.kind === "user" || this.#customViewport && isPiPromptStyleCompaction(block));
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
&& width > 1
|
|
658
|
-
? width - 1
|
|
659
|
-
: width;
|
|
697
|
+
// Invariant: the custom viewport has already removed its rail gutter from this width.
|
|
698
|
+
// Prompt-like and ordinary blocks therefore share one right content edge.
|
|
699
|
+
const blockWidth = width;
|
|
660
700
|
const blockRows = this.#blockRows(id, block, blockWidth);
|
|
661
701
|
if (promptLike) {
|
|
662
702
|
// Compatibility: the first natural prompt gets one breathing row at the document top.
|
|
@@ -927,6 +967,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
927
967
|
}
|
|
928
968
|
resetWorkflowPresentation() {
|
|
929
969
|
this.#dockNotice = undefined;
|
|
970
|
+
this.#clearCopyAcknowledgement(false);
|
|
930
971
|
for (const id of this.#workflowStatusAnchors.keys()) {
|
|
931
972
|
this.#transcript.get(id)?.dispose?.();
|
|
932
973
|
this.#transcript.delete(id);
|
|
@@ -1035,6 +1076,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
1035
1076
|
this.#inputSurface.setFocused?.(focused);
|
|
1036
1077
|
}
|
|
1037
1078
|
dispose() {
|
|
1079
|
+
this.#clearCopyAcknowledgement(false);
|
|
1038
1080
|
this.clearViewportPointerState();
|
|
1039
1081
|
this.#themeUnsubscribe();
|
|
1040
1082
|
this.header.dispose?.();
|
|
@@ -1186,6 +1228,7 @@ export class OwnedUiSessionShellRoot {
|
|
|
1186
1228
|
this.invalidate();
|
|
1187
1229
|
}
|
|
1188
1230
|
}
|
|
1231
|
+
const COPY_ACKNOWLEDGEMENT_DURATION_MS = 1_000;
|
|
1189
1232
|
const SCROLLBAR_CELL_RESET = "\u001b[22;23;24;25;27;28;29;39;54;55m";
|
|
1190
1233
|
const KITTY_IMAGE_CONTROL = /\u001b_G[\s\S]*?\u001b\\/g;
|
|
1191
1234
|
const ITERM_IMAGE_CONTROL = /\u001b]1337;File=[^\u0007]*(?:\u0007|\u001b\\)/g;
|
|
@@ -61,6 +61,7 @@ export class OwnedUiSessionShell {
|
|
|
61
61
|
#responseCopy;
|
|
62
62
|
// Rationale: only an executor this shell created owns a spare copy helper worth warming and disposing.
|
|
63
63
|
#copyExecutor;
|
|
64
|
+
#copyIntentSequence = 0;
|
|
64
65
|
#unbindClipboardWriter;
|
|
65
66
|
#damageTerminal;
|
|
66
67
|
#quitOutro;
|
|
@@ -235,6 +236,10 @@ export class OwnedUiSessionShell {
|
|
|
235
236
|
root: this.root,
|
|
236
237
|
mode: tuiMode,
|
|
237
238
|
...(this.#customViewport ? {
|
|
239
|
+
// Invariant: the owned shell enables and routes mouse reports itself. Pi's
|
|
240
|
+
// enclosing fullscreen renderer must never establish a competing white selection.
|
|
241
|
+
mouse: false,
|
|
242
|
+
consumeUnhandledMouse: true,
|
|
238
243
|
onOverlayGeometry: surfaces => this.root.setViewportOverlaySurfaces(surfaces),
|
|
239
244
|
decorateTerminal: (terminal) => {
|
|
240
245
|
damageTerminal = new DamageAwareTerminalAdapter(terminal, {
|
|
@@ -356,7 +361,17 @@ export class OwnedUiSessionShell {
|
|
|
356
361
|
}
|
|
357
362
|
const routed = this.root.handleViewportPreInput(data, true, Date.now(), this.root.usesDefaultInputSurface() && !this.runtime.hasFocusedOverlay());
|
|
358
363
|
if (routed.copySelection !== undefined) {
|
|
359
|
-
|
|
364
|
+
const snapshot = routed.copySelection;
|
|
365
|
+
const acknowledgement = copyAcknowledgement(snapshot);
|
|
366
|
+
const intent = ++this.#copyIntentSequence;
|
|
367
|
+
void this.#responseCopy?.submit(snapshot, pendingClipboardWrite).then(result => {
|
|
368
|
+
if (this.#disposed || !runtime.active || intent !== this.#copyIntentSequence
|
|
369
|
+
|| result.outcome !== "delivered" && result.outcome !== "submitted-unverified")
|
|
370
|
+
return;
|
|
371
|
+
if (acknowledgement.hasNonWhitespace) {
|
|
372
|
+
this.root.showCopyAcknowledgement(`copied ${acknowledgement.characters} chars to clipboard`);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
360
375
|
}
|
|
361
376
|
if (!routed.consumed)
|
|
362
377
|
return routed.data === data ? undefined : { data: routed.data };
|
|
@@ -378,6 +393,7 @@ export class OwnedUiSessionShell {
|
|
|
378
393
|
this.root.setEditorPaddingX(initialPiSettings.editorPaddingX);
|
|
379
394
|
this.root.setAutocompleteMaxVisible(initialPiSettings.autocompleteMaxVisible);
|
|
380
395
|
this.root.setOutputPad(initialPiSettings.outputPad);
|
|
396
|
+
this.root.setFullscreenCopyOnSelect(initialPiSettings.fullscreenCopyOnSelect);
|
|
381
397
|
this.root.setHideThinkingBlock(initialPiSettings.hideThinkingBlock);
|
|
382
398
|
this.root.setMermaidRenderingMode(initialPiSettings.mermaidRenderingMode);
|
|
383
399
|
this.#showImages = initialPiSettings.showImages;
|
|
@@ -421,6 +437,11 @@ export class OwnedUiSessionShell {
|
|
|
421
437
|
this.#imageWidthCells = value;
|
|
422
438
|
this.root.setImagePresentation(this.#showImages, this.#imageWidthCells);
|
|
423
439
|
} },
|
|
440
|
+
...(this.#customViewport ? { fullscreenCopyOnSelect: { apply: (value) => {
|
|
441
|
+
if (typeof value !== "boolean")
|
|
442
|
+
throw new TypeError("Fullscreen copy-on-select setting is invalid");
|
|
443
|
+
this.root.setFullscreenCopyOnSelect(value);
|
|
444
|
+
} } } : {}),
|
|
424
445
|
});
|
|
425
446
|
if (this.#customViewport && promptHistory !== undefined) {
|
|
426
447
|
this.#promptHistoryImageSidecar = promptHistory.imageSidecar;
|
|
@@ -1516,6 +1537,7 @@ export class OwnedUiSessionShell {
|
|
|
1516
1537
|
}
|
|
1517
1538
|
async #dispose() {
|
|
1518
1539
|
this.#disposed = true;
|
|
1540
|
+
this.#copyIntentSequence += 1;
|
|
1519
1541
|
// Invariant: the outro frame is what the terminal shows now, before any cleanup writes.
|
|
1520
1542
|
const outroFrame = this.#captureQuitOutroFrame();
|
|
1521
1543
|
this.#responseCopy?.dispose();
|
|
@@ -1656,6 +1678,7 @@ export class OwnedUiSessionShell {
|
|
|
1656
1678
|
this.#streamPresentation.noteImmediatePresentation();
|
|
1657
1679
|
const view = this.view();
|
|
1658
1680
|
if (this.backend.sessionGeneration !== this.#sessionGeneration) {
|
|
1681
|
+
this.#copyIntentSequence += 1;
|
|
1659
1682
|
this.#responseCopy?.reset();
|
|
1660
1683
|
this.#cancelWaitingImages();
|
|
1661
1684
|
this.root.resetPendingPastes();
|
|
@@ -2072,6 +2095,17 @@ export class OwnedUiSessionShell {
|
|
|
2072
2095
|
function isCoalescedStreamBlock(kind) {
|
|
2073
2096
|
return kind === "assistant" || kind === "thinking" || kind === "tool-call" || kind === "tool-result";
|
|
2074
2097
|
}
|
|
2098
|
+
function copyAcknowledgement(snapshot) {
|
|
2099
|
+
if (snapshot.literal !== true)
|
|
2100
|
+
return { characters: snapshot.sourceUnits, hasNonWhitespace: true };
|
|
2101
|
+
let characters = Math.max(0, snapshot.rows.length - 1);
|
|
2102
|
+
let hasNonWhitespace = false;
|
|
2103
|
+
for (const row of snapshot.rows) {
|
|
2104
|
+
characters += row.text.length;
|
|
2105
|
+
hasNonWhitespace ||= /\S/u.test(row.text);
|
|
2106
|
+
}
|
|
2107
|
+
return { characters, hasNonWhitespace };
|
|
2108
|
+
}
|
|
2075
2109
|
export function formatSessionResumeCommand(metadata) {
|
|
2076
2110
|
const args = [PRODUCT_TEXT.commandName];
|
|
2077
2111
|
if (!metadata.usesDefaultSessionDir)
|
|
@@ -39,6 +39,7 @@ export declare class SessionViewportController {
|
|
|
39
39
|
readonly column: number;
|
|
40
40
|
readonly row: number;
|
|
41
41
|
} | undefined;
|
|
42
|
+
setCopyOnSelect(enabled: boolean): void;
|
|
42
43
|
get frame(): TranscriptViewportFrame | null;
|
|
43
44
|
setEditorPointerFrame(frame: {
|
|
44
45
|
readonly rowStart: number;
|
|
@@ -28,12 +28,14 @@ export class SessionViewportController {
|
|
|
28
28
|
#inputSurfacePending = false;
|
|
29
29
|
#overlays = [];
|
|
30
30
|
#pointerOwner;
|
|
31
|
-
// Invariant: a
|
|
31
|
+
// Invariant: a right-click editor gesture remains owned by the dock.
|
|
32
32
|
#dockPointerSuppressed = false;
|
|
33
|
-
// Invariant: a
|
|
33
|
+
// Invariant: a gesture begun on an explicit control remains owned by that control.
|
|
34
34
|
#tailPointerSuppressed = false;
|
|
35
35
|
// Invariant: editor selection remains true only while its left button is held.
|
|
36
36
|
#editorPointerSelecting = false;
|
|
37
|
+
// Invariant: no-drag editor presses replay on release; distinct motion promotes frame selection.
|
|
38
|
+
#pendingEditorClick;
|
|
37
39
|
// Invariant: pointer routing uses the most recently composed editor rows.
|
|
38
40
|
#editorPointerFrame;
|
|
39
41
|
#selectionAutoScrollTimer;
|
|
@@ -42,6 +44,7 @@ export class SessionViewportController {
|
|
|
42
44
|
#hoveredHyperlinkKey;
|
|
43
45
|
#lastRequestedSelectionRevision = -1;
|
|
44
46
|
#presentationRevision = 0;
|
|
47
|
+
#copyOnSelect = true;
|
|
45
48
|
#activityTimer;
|
|
46
49
|
constructor(options) {
|
|
47
50
|
this.#enabled = options.enabled;
|
|
@@ -77,6 +80,9 @@ export class SessionViewportController {
|
|
|
77
80
|
get pointerPosition() {
|
|
78
81
|
return this.#pointerPosition;
|
|
79
82
|
}
|
|
83
|
+
setCopyOnSelect(enabled) {
|
|
84
|
+
this.#copyOnSelect = enabled;
|
|
85
|
+
}
|
|
80
86
|
get frame() {
|
|
81
87
|
return this.#viewport.frame;
|
|
82
88
|
}
|
|
@@ -112,9 +118,19 @@ export class SessionViewportController {
|
|
|
112
118
|
this.#cancelGesture();
|
|
113
119
|
this.#viewport.setConfig(this.#config);
|
|
114
120
|
const selectionRevision = this.#viewport.selectionRevision;
|
|
121
|
+
const coveredSurfaces = [
|
|
122
|
+
...(this.#overlays ?? []),
|
|
123
|
+
...(this.#inputSurface === undefined ? [] : [this.#inputSurface]),
|
|
124
|
+
];
|
|
125
|
+
const coveredCells = coveredSurfaces.flatMap(surface => Array.from({ length: Math.max(0, surface.rowEnd - surface.rowStart + 1) }, (_value, index) => ({
|
|
126
|
+
row: surface.rowStart + index,
|
|
127
|
+
columnStart: surface.columnStart,
|
|
128
|
+
columnEnd: surface.columnEnd,
|
|
129
|
+
})));
|
|
115
130
|
const frame = this.#viewport.compose({
|
|
116
131
|
...input,
|
|
117
132
|
...(this.#pointerPosition === undefined ? {} : { pointerPosition: this.#pointerPosition }),
|
|
133
|
+
...(coveredCells.length === 0 ? {} : { coveredCells }),
|
|
118
134
|
});
|
|
119
135
|
// Concurrency: if selection changed during composition, this frame truthfully carries
|
|
120
136
|
// the older revision and exactly one ordinary follow-up render publishes the latest.
|
|
@@ -167,6 +183,7 @@ export class SessionViewportController {
|
|
|
167
183
|
this.#clearActivityTimer();
|
|
168
184
|
this.#stopSelectionAutoScroll();
|
|
169
185
|
this.#editorPointerSelecting = false;
|
|
186
|
+
this.#pendingEditorClick = undefined;
|
|
170
187
|
this.#editorPointerFrame = undefined;
|
|
171
188
|
this.#pointerPosition = undefined;
|
|
172
189
|
this.#hoveredHyperlinkKey = undefined;
|
|
@@ -183,6 +200,7 @@ export class SessionViewportController {
|
|
|
183
200
|
this.#dockPointerSuppressed = false;
|
|
184
201
|
this.#tailPointerSuppressed = false;
|
|
185
202
|
this.#editorPointerSelecting = false;
|
|
203
|
+
this.#pendingEditorClick = undefined;
|
|
186
204
|
this.#editorPointerFrame = undefined;
|
|
187
205
|
this.#pointerPosition = undefined;
|
|
188
206
|
this.#hoveredHyperlinkKey = undefined;
|
|
@@ -302,6 +320,7 @@ export class SessionViewportController {
|
|
|
302
320
|
let repaint = false;
|
|
303
321
|
let forceRepaint = false;
|
|
304
322
|
let activity = false;
|
|
323
|
+
let completedCopy;
|
|
305
324
|
const routed = routeMouseInput(data, (event, report) => {
|
|
306
325
|
const hits = frame.hits;
|
|
307
326
|
const overModal = this.#modalAt(event.column, event.row);
|
|
@@ -375,6 +394,10 @@ export class SessionViewportController {
|
|
|
375
394
|
return true;
|
|
376
395
|
if (this.#viewport.selectionActive) {
|
|
377
396
|
this.#viewport.extendSelection(event.column, event.row, now, false);
|
|
397
|
+
if (this.#pendingEditorClick !== undefined
|
|
398
|
+
&& (event.column !== this.#pendingEditorClick.column || event.row !== this.#pendingEditorClick.row)) {
|
|
399
|
+
this.#pendingEditorClick = undefined;
|
|
400
|
+
}
|
|
378
401
|
this.#updateSelectionAutoScroll(event.column, event.row, hits.viewportHeight);
|
|
379
402
|
activity = true;
|
|
380
403
|
return true;
|
|
@@ -415,17 +438,20 @@ export class SessionViewportController {
|
|
|
415
438
|
return false;
|
|
416
439
|
this.#dockPointerSuppressed = false;
|
|
417
440
|
this.#tailPointerSuppressed = false;
|
|
441
|
+
this.#pendingEditorClick = undefined;
|
|
418
442
|
this.#stopSelectionAutoScroll();
|
|
419
443
|
if (this.#viewport.clearSelection())
|
|
420
444
|
repaint = true;
|
|
421
445
|
if (overBottom) {
|
|
422
446
|
this.#viewport.scrollToEnd(now);
|
|
447
|
+
this.#tailPointerSuppressed = true;
|
|
423
448
|
activity = true;
|
|
424
449
|
repaint = true;
|
|
425
450
|
return true;
|
|
426
451
|
}
|
|
427
452
|
if (overSticky && hits.sticky !== null) {
|
|
428
453
|
this.#viewport.scrollTo(hits.sticky.target, now);
|
|
454
|
+
this.#tailPointerSuppressed = true;
|
|
429
455
|
activity = true;
|
|
430
456
|
repaint = true;
|
|
431
457
|
return true;
|
|
@@ -439,35 +465,19 @@ export class SessionViewportController {
|
|
|
439
465
|
}
|
|
440
466
|
else {
|
|
441
467
|
this.#viewport.scrollTo(scrollForTrackPage(geometry, trackRow, frame.scrollTop, hits.viewportHeight), now);
|
|
468
|
+
this.#tailPointerSuppressed = true;
|
|
442
469
|
}
|
|
443
470
|
activity = true;
|
|
444
471
|
repaint = true;
|
|
445
472
|
return true;
|
|
446
473
|
}
|
|
447
|
-
if (
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
button: event.button,
|
|
451
|
-
column: event.column,
|
|
452
|
-
row: event.row - editorFrame.rowStart + 1,
|
|
453
|
-
});
|
|
454
|
-
if (!handled)
|
|
455
|
-
this.#dockPointerSuppressed = true;
|
|
456
|
-
this.#editorPointerSelecting = handled;
|
|
457
|
-
repaint = true;
|
|
458
|
-
return true;
|
|
459
|
-
}
|
|
460
|
-
if (event.row > hits.viewportHeight) {
|
|
461
|
-
this.#dockPointerSuppressed = true;
|
|
462
|
-
return true;
|
|
463
|
-
}
|
|
464
|
-
if (event.row >= 1 && event.row <= hits.viewportHeight && event.column <= frame.contentWidth) {
|
|
465
|
-
if (!this.#viewport.pressSelection(event.column, event.row, now)) {
|
|
466
|
-
// Invariant: empty rows and transient tail rows must never start Pi selection.
|
|
467
|
-
this.#tailPointerSuppressed = true;
|
|
468
|
-
repaint = true;
|
|
469
|
-
return true;
|
|
474
|
+
if (event.row >= 1 && event.row <= frame.rows.length && event.column <= frame.descriptor.width) {
|
|
475
|
+
if (editorFrame !== undefined && event.row >= editorFrame.rowStart && event.row <= editorFrame.rowEnd) {
|
|
476
|
+
this.#pendingEditorClick = { column: event.column, row: event.row };
|
|
470
477
|
}
|
|
478
|
+
// Invariant: frame selection includes transient and dock rows without changing
|
|
479
|
+
// semantic ownership; no-drag editor presses replay on release.
|
|
480
|
+
this.#viewport.pressSelection(event.column, event.row, now);
|
|
471
481
|
repaint = true;
|
|
472
482
|
return true;
|
|
473
483
|
}
|
|
@@ -490,6 +500,17 @@ export class SessionViewportController {
|
|
|
490
500
|
}
|
|
491
501
|
if (this.#viewport.releaseSelection()) {
|
|
492
502
|
this.#stopSelectionAutoScroll();
|
|
503
|
+
const pendingEditorClick = this.#pendingEditorClick;
|
|
504
|
+
this.#pendingEditorClick = undefined;
|
|
505
|
+
if (pendingEditorClick !== undefined && this.#editorPointerFrame !== undefined) {
|
|
506
|
+
this.#viewport.clearSelection();
|
|
507
|
+
const editorRow = pendingEditorClick.row - this.#editorPointerFrame.rowStart + 1;
|
|
508
|
+
this.#editor.handlePointer({ kind: "press", button: 0, column: pendingEditorClick.column, row: editorRow });
|
|
509
|
+
this.#editor.handlePointer({ kind: "release", button: 0, column: pendingEditorClick.column, row: editorRow });
|
|
510
|
+
}
|
|
511
|
+
else if (this.#copyOnSelect) {
|
|
512
|
+
completedCopy = this.#viewport.captureSelectedText() ?? undefined;
|
|
513
|
+
}
|
|
493
514
|
// Platform: restore OSC 8 links only after the held-button selection paint has
|
|
494
515
|
// ended, then overwrite any terminal-cached hover cells immediately.
|
|
495
516
|
forceRepaint = true;
|
|
@@ -519,7 +540,7 @@ export class SessionViewportController {
|
|
|
519
540
|
this.#lastRequestedSelectionRevision = this.#viewport.selectionRevision;
|
|
520
541
|
this.#requestRender(forceRepaint);
|
|
521
542
|
}
|
|
522
|
-
return routed;
|
|
543
|
+
return completedCopy === undefined ? routed : { ...routed, copySelection: completedCopy };
|
|
523
544
|
}
|
|
524
545
|
#modalAt(column, row) {
|
|
525
546
|
const contains = (surface) => column >= surface.columnStart && column <= surface.columnEnd
|
|
@@ -534,13 +555,13 @@ export class SessionViewportController {
|
|
|
534
555
|
.find(candidate => column - 1 >= candidate.from && column - 1 < candidate.to);
|
|
535
556
|
return range === undefined ? undefined : JSON.stringify([row, range]);
|
|
536
557
|
}
|
|
537
|
-
#updateSelectionAutoScroll(column, row,
|
|
538
|
-
const beyondEdge = row <= 1 || row
|
|
558
|
+
#updateSelectionAutoScroll(column, row, frameHeight) {
|
|
559
|
+
const beyondEdge = row <= 1 || row >= frameHeight;
|
|
539
560
|
if (!beyondEdge) {
|
|
540
561
|
this.#stopSelectionAutoScroll();
|
|
541
562
|
return;
|
|
542
563
|
}
|
|
543
|
-
this.#selectionAutoScrollPointer = { column, row };
|
|
564
|
+
this.#selectionAutoScrollPointer = { column, row, direction: row <= 1 ? -1 : 1 };
|
|
544
565
|
if (this.#selectionAutoScrollTimer !== undefined)
|
|
545
566
|
return;
|
|
546
567
|
this.#selectionAutoScrollTimer = setTimeout(() => this.#selectionAutoScrollTick(), SELECTION_AUTO_SCROLL_INTERVAL_MS);
|
|
@@ -557,7 +578,8 @@ export class SessionViewportController {
|
|
|
557
578
|
const rowsPerTick = scrollbarSelectionRows(this.#config.scrollbarSpeed);
|
|
558
579
|
for (let row = 0; row < rowsPerTick; row += 1) {
|
|
559
580
|
const previous = this.#viewport.scrollTop;
|
|
560
|
-
this.#viewport.
|
|
581
|
+
this.#viewport.scrollBy(pointer.direction);
|
|
582
|
+
this.#viewport.extendSelection(pointer.column, pointer.row, undefined, false);
|
|
561
583
|
if (this.#viewport.scrollTop === previous)
|
|
562
584
|
break;
|
|
563
585
|
}
|
package/dist/cli/dispatch.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type InteractiveLaunchIntent, type LaunchProfileId, type SessionSelecti
|
|
|
2
2
|
import type { CliCapabilities } from "./capabilities.js";
|
|
3
3
|
import type { PackageCommandRequest } from "./packages.js";
|
|
4
4
|
import type { SessionContextRequest } from "./session-context.js";
|
|
5
|
-
import { type PackageCliVerb, type PackageSyntaxDiagnostic } from "./package-messages.js";
|
|
5
|
+
import { type PackageCliVerb, type PackageCommandNamespace, type PackageSyntaxDiagnostic } from "./package-messages.js";
|
|
6
6
|
export type UpdateChannel = "stable" | "next";
|
|
7
7
|
export interface CliHandlers {
|
|
8
8
|
readonly launch: (intent: InteractiveLaunchIntent) => Promise<number>;
|
|
@@ -25,9 +25,11 @@ export type CliCommand = {
|
|
|
25
25
|
} | {
|
|
26
26
|
readonly kind: "package-help";
|
|
27
27
|
readonly verb: PackageCliVerb;
|
|
28
|
+
readonly namespace: PackageCommandNamespace;
|
|
28
29
|
} | {
|
|
29
30
|
readonly kind: "package-error";
|
|
30
31
|
readonly diagnostic: PackageSyntaxDiagnostic;
|
|
32
|
+
readonly namespace: PackageCommandNamespace;
|
|
31
33
|
} | {
|
|
32
34
|
readonly kind: "launch";
|
|
33
35
|
readonly profileId: LaunchProfileId;
|