@timurproko/a1 0.2.5-dev.683 → 0.2.5-dev.698
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/dist/app/session-shell/prompt-suggestion-controller.d.ts +2 -0
- package/dist/app/session-shell/prompt-suggestion-controller.js +10 -0
- package/dist/app/session-shell/session-shell-root.js +15 -2
- package/dist/app/session-shell/session-shell.js +71 -15
- package/dist/app/session-shell/share-operation.d.ts +3 -0
- package/dist/app/session-shell/share-operation.js +11 -0
- package/dist/composition/settings-route-host.js +1 -1
- package/dist/contracts/presentation/index.d.ts +5 -0
- package/dist/contracts/presentation/index.js +2 -0
- package/dist/features/owned-ui/project-trust-dialog.js +7 -5
- package/dist/features/owned-ui/reference-screen-app.d.ts +2 -2
- package/dist/features/owned-ui/reference-screen-app.js +10 -6
- package/dist/features/owned-ui/settings-app.js +10 -5
- package/dist/integrations/pi/components/index.d.ts +3 -2
- package/dist/integrations/pi/components/index.js +2 -1
- package/dist/integrations/pi/components/modal-frame.d.ts +11 -1
- package/dist/integrations/pi/components/modal-frame.js +29 -1
- package/dist/integrations/pi/components/models-dialog.js +17 -17
- package/dist/integrations/pi/components/share-operation-dialog.d.ts +6 -0
- package/dist/integrations/pi/components/share-operation-dialog.js +40 -0
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +15 -6
- package/dist/integrations/pi/components/shell-extension-ui.d.ts +3 -0
- package/dist/integrations/pi/components/shell-extension-ui.js +8 -4
- package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +0 -4
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +56 -34
- package/dist/integrations/pi/components/shell-session-info-reference.js +35 -2
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +3 -1
- package/dist/integrations/pi/components/shell-shared-facade.js +13 -1
- package/dist/integrations/pi/components/skills-dialog.js +19 -6
- package/dist/integrations/pi/components/theme.d.ts +8 -1
- package/dist/integrations/pi/components/theme.js +28 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +10 -2
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +20 -6
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +2 -2
- package/dist/integrations/pi/components/upstream/components/extension-input.js +4 -5
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +2 -3
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +3 -2
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +4 -15
- package/dist/integrations/pi/components/upstream/components/session-selector.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/components/session-selector.js +136 -109
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +8 -5
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +63 -26
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +29 -20
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +245 -210
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +13 -15
- package/dist/integrations/pi/engine/adapter.js +21 -2
- package/dist/integrations/pi/engine/workflow-runner.js +2 -1
- 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 +2 -2
- package/dist/native/win32-x64/process-guardian.exe +0 -0
- package/dist/ui/apps/host.d.ts +4 -3
- package/dist/ui/apps/host.js +9 -4
- package/dist/ui/components/dialog-panel.js +6 -7
- package/dist/ui/components/index.d.ts +1 -1
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/list-view.d.ts +3 -3
- package/dist/ui/components/list-view.js +8 -9
- package/dist/ui/components/shortcut-hints.d.ts +2 -0
- package/dist/ui/components/shortcut-hints.js +17 -1
- package/dist/ui/components/theme.d.ts +1 -1
- package/package.json +1 -1
|
@@ -31,6 +31,8 @@ export declare class ContextualPromptSuggestionController {
|
|
|
31
31
|
invalidate(): void;
|
|
32
32
|
/** Retires only a generating request; a prepared or available suggestion survives the draft edit. */
|
|
33
33
|
abortPending(): void;
|
|
34
|
+
/** Reasserts retained ghost text after an editor mutation makes the prompt eligible again. */
|
|
35
|
+
restoreAvailable(): void;
|
|
34
36
|
dispose(): void;
|
|
35
37
|
}
|
|
36
38
|
export declare function samePromptSuggestionIdentity(left: OwnedUiPromptSuggestionIdentity, right: OwnedUiPromptSuggestionIdentity): boolean;
|
|
@@ -100,6 +100,16 @@ export class ContextualPromptSuggestionController {
|
|
|
100
100
|
this.#finish(request, "cancelled");
|
|
101
101
|
request.abort.abort();
|
|
102
102
|
}
|
|
103
|
+
/** Reasserts retained ghost text after an editor mutation makes the prompt eligible again. */
|
|
104
|
+
restoreAvailable() {
|
|
105
|
+
if (this.#disposed || !this.#enabled || this.#state.status !== "available")
|
|
106
|
+
return;
|
|
107
|
+
const reason = this.options.surface.presentationBlockReason?.(this.#state.identity)
|
|
108
|
+
?? (this.options.surface.canPresent(this.#state.identity) ? null : "presentation-unavailable");
|
|
109
|
+
if (reason !== null || !this.options.surface.present(this.#state.text))
|
|
110
|
+
return;
|
|
111
|
+
this.options.surface.requestRender();
|
|
112
|
+
}
|
|
103
113
|
dispose() {
|
|
104
114
|
this.#disposed = true;
|
|
105
115
|
this.invalidate();
|
|
@@ -9,7 +9,7 @@ import { PINNED_PI_HIDDEN_COMMAND_NAMES, PINNED_PI_WORKFLOW_COMMAND_NAMES } from
|
|
|
9
9
|
import { createPiExtensionUiBridge } from "../../integrations/pi/components/shell-extension-ui.js";
|
|
10
10
|
import { createPiShellEditor } from "../../integrations/pi/components/shell-editor-autocomplete.js";
|
|
11
11
|
import { createPiQueuedInputStatus, createPiShellFooter, createPiShellHeader, createPiShellLoadedResources, createPiShellStatus, } from "../../integrations/pi/components/shell-footer-status.js";
|
|
12
|
-
import { createPiShellArmin, createPiShellAuthProviderSelector, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellExtensionSelector, createPiShellLoginDialog, createPiShellModelSelector,
|
|
12
|
+
import { createPiShellArmin, createPiShellAuthProviderSelector, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellExtensionSelector, createPiShellLoginDialog, createPiShellModelSelector, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, } from "../../integrations/pi/components/shell-selectors-dialogs.js";
|
|
13
13
|
import { createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellHotkeys, createPiShellSessionInfo, renderPiShellCommandMessage, renderPiShellPackageUpdateNotice, renderPiShellReleaseUpdateBanner, renderPiShellReleaseUpdateNotice, renderPiShellStatusText, } from "../../integrations/pi/components/shell-presenters-info.js";
|
|
14
14
|
import { createPiShellTranscriptComponent, isPiPromptStyleCompaction, paintPiSubmittedPromptTimestamp, renderPiShellStartupDiagnostic, renderPiShellTranscriptBlock, } from "../../integrations/pi/components/shell-presenters-transcript.js";
|
|
15
15
|
import { onPiThemeChange, PINNED_PI_LAYOUT, piTheme } from "../../integrations/pi/components/upstream/theme/theme.js";
|
|
@@ -333,6 +333,10 @@ export class OwnedUiSessionShellRoot {
|
|
|
333
333
|
}
|
|
334
334
|
const promptAccepted = this.#view.lifecycle !== "busy" && view.lifecycle === "busy";
|
|
335
335
|
this.#view = view;
|
|
336
|
+
// Invariant: the idle new-session confirmation yields to the first truthful live status;
|
|
337
|
+
// ordinary dock notices deliberately remain visible below Working during a run.
|
|
338
|
+
if (promptAccepted && this.#dockNotice?.kind === "new-session")
|
|
339
|
+
this.#dockNotice = undefined;
|
|
336
340
|
if (promptAccepted && this.#imageSubmissionsSending > 0) {
|
|
337
341
|
this.#imageSubmissionsSending = 0;
|
|
338
342
|
this.#syncWorkingOverride();
|
|
@@ -657,7 +661,10 @@ export class OwnedUiSessionShellRoot {
|
|
|
657
661
|
// Compatibility: Pi pads its status text by one cell regardless of the output pad setting.
|
|
658
662
|
return ["", ...renderPiShellStatusText(notice.message, width, PINNED_PI_LAYOUT.outputPad)];
|
|
659
663
|
}
|
|
660
|
-
return renderPiShellCommandMessage({
|
|
664
|
+
return renderPiShellCommandMessage({
|
|
665
|
+
kind: notice.kind === "new-session" ? "accent" : notice.kind,
|
|
666
|
+
message: notice.message,
|
|
667
|
+
}, width, this.#outputPad);
|
|
661
668
|
}
|
|
662
669
|
dismissNotice() {
|
|
663
670
|
if (this.#dockNotice === undefined)
|
|
@@ -960,6 +967,12 @@ export class OwnedUiSessionShellRoot {
|
|
|
960
967
|
}
|
|
961
968
|
if (result.outcome === "completed" && (result.command === "quit" || result.command === "compact"))
|
|
962
969
|
return;
|
|
970
|
+
if (result.outcome === "completed" && result.command === "new" && this.#customViewport) {
|
|
971
|
+
// Rationale: bare A1 keeps the replacement session visually empty while preserving Pi's accent notice shape.
|
|
972
|
+
this.#dockNotice = { kind: "new-session", message: result.message };
|
|
973
|
+
this.#invalidateChrome();
|
|
974
|
+
return;
|
|
975
|
+
}
|
|
963
976
|
if (result.outcome === "completed" && (result.command === "new" || result.command === "name" || result.command === "debug")) {
|
|
964
977
|
this.#lastWorkflowStatusId = undefined;
|
|
965
978
|
const presentation = { kind: result.command, message: result.message, ...(result.detail === undefined ? {} : { detail: result.detail }) };
|
|
@@ -14,7 +14,7 @@ import { createPiExtensionUiBridge } from "../../integrations/pi/components/shel
|
|
|
14
14
|
import { createPiShellEditor } from "../../integrations/pi/components/shell-editor-autocomplete.js";
|
|
15
15
|
import { SKILLS_COMMAND_NAME, findSkillByArgument, rewriteSkillsTunnelSubmission, skillPrompt, skillsFromCommands, } from "../../integrations/pi/components/skills-command.js";
|
|
16
16
|
import { createPiQueuedInputStatus, createPiShellFooter, createPiShellHeader, createPiShellLoadedResources, createPiShellStatus, } from "../../integrations/pi/components/shell-footer-status.js";
|
|
17
|
-
import { createPiShellArmin, createPiShellAuthProviderSelector, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellExtensionSelector, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog,
|
|
17
|
+
import { createPiShellArmin, createPiShellAuthProviderSelector, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellExtensionSelector, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellSkillsSelector, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, } from "../../integrations/pi/components/shell-selectors-dialogs.js";
|
|
18
18
|
import { createPiShellChangelog, createPiShellHotkeys, createPiShellSessionInfo, renderPiShellPackageUpdateNotice, renderPiShellStatusText, } from "../../integrations/pi/components/shell-presenters-info.js";
|
|
19
19
|
import { createPiShellTranscriptComponent, renderPiShellStartupDiagnostic, renderPiShellTranscriptBlock, } from "../../integrations/pi/components/shell-presenters-transcript.js";
|
|
20
20
|
import { onPiThemeChange, piTheme } from "../../integrations/pi/components/upstream/theme/theme.js";
|
|
@@ -188,6 +188,11 @@ export class OwnedUiSessionShell {
|
|
|
188
188
|
onEditorChange: text => {
|
|
189
189
|
this.#editorRevision++;
|
|
190
190
|
promptSuggestionController?.abortPending();
|
|
191
|
+
if (text.length === 0) {
|
|
192
|
+
// Concurrency: the editor synchronizes deletion-owned autocomplete after onChange.
|
|
193
|
+
// Reassert retained ghost text in the microtask before Pi emits its scheduled frame.
|
|
194
|
+
queueMicrotask(() => promptSuggestionController?.restoreAvailable());
|
|
195
|
+
}
|
|
191
196
|
this.root.reconcilePromptImageLimitNotice(text);
|
|
192
197
|
},
|
|
193
198
|
onPromptSuggestionAccepted: () => promptSuggestionController?.accept(),
|
|
@@ -358,8 +363,15 @@ export class OwnedUiSessionShell {
|
|
|
358
363
|
? this.runtime.addPreInputListener(data => {
|
|
359
364
|
if (inputPresentation?.coordination === false)
|
|
360
365
|
this.#streamPresentation.noteImmediatePresentation();
|
|
361
|
-
// Compatibility: route boundary keys before Pi.
|
|
366
|
+
// Compatibility: route modal paging and boundary keys before Pi's fullscreen handlers.
|
|
362
367
|
const isDefault = this.root.usesDefaultInputSurface();
|
|
368
|
+
if (!this.runtime.hasOverlay() && !isDefault
|
|
369
|
+
&& (this.root.editor.matchesTerminalKey(data, "pageUp")
|
|
370
|
+
|| this.root.editor.matchesTerminalKey(data, "pageDown"))) {
|
|
371
|
+
this.root.handleInput(data);
|
|
372
|
+
this.runtime.requestRender();
|
|
373
|
+
return { consume: true };
|
|
374
|
+
}
|
|
363
375
|
if (!this.runtime.hasOverlay() && (this.root.editor.matchesTerminalKey(data, "home")
|
|
364
376
|
|| this.root.editor.matchesTerminalKey(data, "end")
|
|
365
377
|
|| !isDefault && (this.root.editor.matchesTerminalKey(data, "ctrl+home")
|
|
@@ -1065,12 +1077,14 @@ export class OwnedUiSessionShell {
|
|
|
1065
1077
|
},
|
|
1066
1078
|
onCancel: close,
|
|
1067
1079
|
onSelect: entryId => {
|
|
1068
|
-
close();
|
|
1069
1080
|
if (entryId === context.currentLeafId) {
|
|
1081
|
+
close();
|
|
1070
1082
|
this.root.appendWorkflowStatus("Already at this point");
|
|
1071
1083
|
this.runtime.requestRender();
|
|
1072
1084
|
return;
|
|
1073
1085
|
}
|
|
1086
|
+
if (context.skipSummaryPrompt)
|
|
1087
|
+
close();
|
|
1074
1088
|
void this.#completeTreeSelection(entryId, context.skipSummaryPrompt);
|
|
1075
1089
|
},
|
|
1076
1090
|
});
|
|
@@ -1206,6 +1220,19 @@ export class OwnedUiSessionShell {
|
|
|
1206
1220
|
async runWorkflow(request) {
|
|
1207
1221
|
if (request.command === "quit")
|
|
1208
1222
|
return this.shutdown();
|
|
1223
|
+
if (this.#customViewport && request.command === "name" && request.argument.trim().length === 0) {
|
|
1224
|
+
void this.#extensionBridge.input("Session Name", "Enter name").then(value => {
|
|
1225
|
+
if (this.#disposed || value === undefined || value.trim().length === 0)
|
|
1226
|
+
return;
|
|
1227
|
+
return this.runWorkflow({ ...request, argument: value });
|
|
1228
|
+
}).catch(error => {
|
|
1229
|
+
if (this.#disposed)
|
|
1230
|
+
return;
|
|
1231
|
+
this.root.appendWorkflowResult({ command: "name", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
1232
|
+
this.runtime.requestRender();
|
|
1233
|
+
});
|
|
1234
|
+
return { outcome: "completed", diagnostic: null };
|
|
1235
|
+
}
|
|
1209
1236
|
const copyGeneration = request.command === "copy" ? this.backend.sessionBindingGeneration : undefined;
|
|
1210
1237
|
if (request.command === "login" && request.selection !== undefined) {
|
|
1211
1238
|
const setup = this.backend.pinnedAmbientAuthentication(request.selection);
|
|
@@ -1281,13 +1308,15 @@ export class OwnedUiSessionShell {
|
|
|
1281
1308
|
}
|
|
1282
1309
|
this.root.resetExtensionUi();
|
|
1283
1310
|
}
|
|
1284
|
-
const
|
|
1285
|
-
?
|
|
1311
|
+
const shareDialog = request.command === "share"
|
|
1312
|
+
? await import("./share-operation.js")
|
|
1313
|
+
: undefined;
|
|
1314
|
+
const shareSurface = shareDialog === undefined ? undefined
|
|
1315
|
+
: (this.#customViewport ? shareDialog.createPiShellShareOperationDialog : shareDialog.createPiShellOperationLoader)({
|
|
1286
1316
|
getColumns: () => this.runtime.viewport().columns,
|
|
1287
1317
|
getRows: () => this.runtime.viewport().rows,
|
|
1288
1318
|
requestRender: () => this.runtime.requestRender(),
|
|
1289
|
-
}, "Creating gist
|
|
1290
|
-
: undefined;
|
|
1319
|
+
}, "Creating gist…");
|
|
1291
1320
|
const operationSurface = shareSurface ?? (request.command === "reload" ? createPiShellReloadBox() : undefined);
|
|
1292
1321
|
const now = this.#reloadPresentation?.now ?? Date.now;
|
|
1293
1322
|
const shownAt = now();
|
|
@@ -1343,7 +1372,17 @@ export class OwnedUiSessionShell {
|
|
|
1343
1372
|
this.root.editor.reloadKeybindings();
|
|
1344
1373
|
this.#installAutocompleteCommands();
|
|
1345
1374
|
}
|
|
1346
|
-
|
|
1375
|
+
if (request.command === "tree" && result.outcome === "completed") {
|
|
1376
|
+
if (result.detail && !this.root.editor.getText().trim())
|
|
1377
|
+
this.root.editor.setText(result.detail);
|
|
1378
|
+
this.root.resumeViewportFollowing();
|
|
1379
|
+
}
|
|
1380
|
+
if (shareDialog !== undefined && this.#customViewport && result.outcome === "completed" && result.detail !== undefined) {
|
|
1381
|
+
this.root.appendWorkflowStatus(shareDialog.renderPiShellShareResult(result.message, result.detail));
|
|
1382
|
+
}
|
|
1383
|
+
else {
|
|
1384
|
+
this.root.appendWorkflowResult(result);
|
|
1385
|
+
}
|
|
1347
1386
|
this.runtime.requestRender();
|
|
1348
1387
|
return workflowAdapterResult(result);
|
|
1349
1388
|
}
|
|
@@ -1782,6 +1821,19 @@ export class OwnedUiSessionShell {
|
|
|
1782
1821
|
const removeInterruptWatch = this.runtime.addInputListener(data => {
|
|
1783
1822
|
if (!data.includes(INTERRUPT))
|
|
1784
1823
|
return undefined;
|
|
1824
|
+
// Protocol: route hosts decide whether one interrupt closes their app. Raw-input forwarding
|
|
1825
|
+
// is required because Pi handles Ctrl+C before the fullscreen overlay receives normal input.
|
|
1826
|
+
const consumedBySurface = surface.handleInput(INTERRUPT);
|
|
1827
|
+
if (surface.isClosed()) {
|
|
1828
|
+
armedAt = 0;
|
|
1829
|
+
closeSurface();
|
|
1830
|
+
return { consume: true };
|
|
1831
|
+
}
|
|
1832
|
+
if (consumedBySurface) {
|
|
1833
|
+
armedAt = 0;
|
|
1834
|
+
this.runtime.requestRender();
|
|
1835
|
+
return { consume: true };
|
|
1836
|
+
}
|
|
1785
1837
|
const now = Date.now();
|
|
1786
1838
|
if (armedAt !== 0 && now - armedAt <= INTERRUPT_CHORD_MS) {
|
|
1787
1839
|
armedAt = 0;
|
|
@@ -1970,7 +2022,7 @@ export class OwnedUiSessionShell {
|
|
|
1970
2022
|
}
|
|
1971
2023
|
return this.#submitSkillPrompt(skillPrompt(skill.name, separator < 0 ? "" : trimmed.slice(separator + 1)), text);
|
|
1972
2024
|
}
|
|
1973
|
-
// Rationale:
|
|
2025
|
+
// Rationale: engine expands skill arguments; history retains typed input for recall.
|
|
1974
2026
|
#submitSkillPrompt(prompt, typed) {
|
|
1975
2027
|
this.#rememberInput(typed, "slash");
|
|
1976
2028
|
this.root.resumeViewportFollowing();
|
|
@@ -1981,29 +2033,33 @@ export class OwnedUiSessionShell {
|
|
|
1981
2033
|
text: prompt,
|
|
1982
2034
|
});
|
|
1983
2035
|
}
|
|
2036
|
+
#treeSummary() {
|
|
2037
|
+
return new Promise(resolve => {
|
|
2038
|
+
this.root.setInputSurface(createPiShellExtensionSelector("Summarize Branch?", ["No summary", "Summarize", "Summarize with custom prompt"], resolve, () => resolve(undefined)), true, "opaque");
|
|
2039
|
+
this.runtime.requestRender();
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
1984
2042
|
async #completeTreeSelection(entryId, skipSummaryPrompt) {
|
|
1985
2043
|
let summarize = false;
|
|
1986
2044
|
let customInstructions;
|
|
1987
2045
|
if (!skipSummaryPrompt) {
|
|
1988
2046
|
while (true) {
|
|
1989
|
-
const choice = await this.#
|
|
1990
|
-
"No summary",
|
|
1991
|
-
"Summarize",
|
|
1992
|
-
"Summarize with custom prompt",
|
|
1993
|
-
]);
|
|
2047
|
+
const choice = await this.#treeSummary();
|
|
1994
2048
|
if (choice === undefined) {
|
|
1995
2049
|
await this.showTreeSelector(entryId);
|
|
1996
2050
|
return;
|
|
1997
2051
|
}
|
|
1998
2052
|
summarize = choice !== "No summary";
|
|
1999
2053
|
if (choice === "Summarize with custom prompt") {
|
|
2000
|
-
customInstructions = await this.#extensionBridge.
|
|
2054
|
+
customInstructions = await this.#extensionBridge.input("Custom Summarization Instructions", "", { retainSurfaceOnSettle: true });
|
|
2001
2055
|
if (customInstructions === undefined)
|
|
2002
2056
|
continue;
|
|
2003
2057
|
}
|
|
2004
2058
|
break;
|
|
2005
2059
|
}
|
|
2006
2060
|
}
|
|
2061
|
+
this.root.setInputSurface(null);
|
|
2062
|
+
this.runtime.requestRender();
|
|
2007
2063
|
const result = await this.runWorkflow({
|
|
2008
2064
|
command: "tree",
|
|
2009
2065
|
argument: "",
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { createPiShellOperationLoader, createPiShellShareOperationDialog } from "../../integrations/pi/components/index.js";
|
|
2
|
+
export { createPiShellOperationLoader, createPiShellShareOperationDialog };
|
|
3
|
+
export declare function renderPiShellShareResult(message: string, gistUrl: string): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createPiShellOperationLoader, createPiShellShareOperationDialog, piShellHyperlink, piTheme, } from "../../integrations/pi/components/index.js";
|
|
2
|
+
import { nativeHyperlinkStyle } from "../../ui/components/index.js";
|
|
3
|
+
export { createPiShellOperationLoader, createPiShellShareOperationDialog };
|
|
4
|
+
export function renderPiShellShareResult(message, gistUrl) {
|
|
5
|
+
const theme = piTheme();
|
|
6
|
+
const match = /^Share URL: (\S+)$/u.exec(message);
|
|
7
|
+
const linked = match === null
|
|
8
|
+
? theme.fg("dim", message)
|
|
9
|
+
: `${theme.fg("dim", "Share URL: ")}${piShellHyperlink(match[1])}`;
|
|
10
|
+
return nativeHyperlinkStyle(`${linked}\n${theme.fg("dim", "Gist: ")}${piShellHyperlink(gistUrl)}`, text => theme.fg("mdLink", text));
|
|
11
|
+
}
|
|
@@ -131,7 +131,7 @@ function pinnedTheme() {
|
|
|
131
131
|
bold: (text) => piTheme().bold(text),
|
|
132
132
|
plain: (text) => text,
|
|
133
133
|
disabled: (text) => faint(piTheme().fg("dim", text)),
|
|
134
|
-
highlight: (text) =>
|
|
134
|
+
highlight: (text) => piTheme().bg("selectedBg", text),
|
|
135
135
|
panel: (text) => `\u001b[48;2;55;55;55m${text}\u001b[49m`,
|
|
136
136
|
};
|
|
137
137
|
}
|
|
@@ -4,6 +4,11 @@ export interface SemanticShortcutHint {
|
|
|
4
4
|
readonly action: string;
|
|
5
5
|
readonly actionFirst?: boolean;
|
|
6
6
|
}
|
|
7
|
+
/** Canonical dismissal guidance for every A1-rendered dialog surface. */
|
|
8
|
+
export declare const DIALOG_CLOSE_SHORTCUT_HINT: Readonly<{
|
|
9
|
+
key: string;
|
|
10
|
+
action: string;
|
|
11
|
+
}>;
|
|
7
12
|
export interface ShortcutHintRoles {
|
|
8
13
|
key(label: string): string;
|
|
9
14
|
action(name: string): string;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Canonical dismissal guidance for every A1-rendered dialog surface. */
|
|
2
|
+
export const DIALOG_CLOSE_SHORTCUT_HINT = Object.freeze({ key: "esc", action: "close" });
|
|
1
3
|
const SHORTCUT_KEY_NAMES = Object.freeze({
|
|
2
4
|
alt: "Alt", backspace: "Backspace", cmd: "Cmd", ctrl: "Ctrl", delete: "Delete", down: "Down", end: "End",
|
|
3
5
|
enter: "Enter", esc: "Esc", escape: "Escape", home: "Home", insert: "Insert", left: "Left", meta: "Meta",
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
1
|
+
import { DIALOG_CLOSE_SHORTCUT_HINT, displayShortcutKeyLabel } from "../../contracts/presentation/index.js";
|
|
2
|
+
const ACCENT = "\u001b[38;2;167;152;215m";
|
|
3
|
+
const BORDER = "\u001b[38;2;97;133;204m";
|
|
4
|
+
const MUTED = "\u001b[38;2;157;165;169m";
|
|
5
|
+
const DIM = "\u001b[38;2;126;136;142m";
|
|
5
6
|
const RESET_FG = "\u001b[39m";
|
|
6
7
|
const BOLD = "\u001b[1m";
|
|
7
8
|
const RESET_BOLD = "\u001b[22m";
|
|
@@ -13,7 +14,8 @@ export function renderProjectTrustDialog(cwd, options, selected, terminalWidth,
|
|
|
13
14
|
const title = ` ${BOLD}${ACCENT}Trust project folder?${RESET_FG}${RESET_BOLD}`;
|
|
14
15
|
const path = ` ${MUTED}${sanitize(cwd)}${RESET_FG}`;
|
|
15
16
|
const choices = options.map((label, index) => choice(label, selected === index));
|
|
16
|
-
const
|
|
17
|
+
const closeKey = displayShortcutKeyLabel(DIALOG_CLOSE_SHORTCUT_HINT.key);
|
|
18
|
+
const hint = ` ${DIM}↑↓${MUTED} navigate ${DIM}Enter${MUTED} select ${DIM}${closeKey}${MUTED} ${DIALOG_CLOSE_SHORTCUT_HINT.action}${RESET_FG}`;
|
|
17
19
|
const explanation = wrap(EXPLANATION, Math.max(1, width - 2)).map(line => ` ${line}`);
|
|
18
20
|
const preferred = [rule, title, path, "", ...explanation, "", ...choices, "", hint, rule];
|
|
19
21
|
if (preferred.length <= terminalRows)
|
|
@@ -29,8 +29,8 @@ export interface ReferenceScreenOptions {
|
|
|
29
29
|
* Presents one read-only document full screen between two accent rules: the bold
|
|
30
30
|
* title leads the scrolled rows, the shared scrollbar rail runs beside them, and
|
|
31
31
|
* the hint line closes the frame. Rows come from a provider per content width and
|
|
32
|
-
* are cached until the width changes;
|
|
33
|
-
*
|
|
32
|
+
* are cached until the width changes; Escape closes locally, while an opted-in
|
|
33
|
+
* host closes on Ctrl+C before dispatching it into the screen.
|
|
34
34
|
*/
|
|
35
35
|
export declare class ReferenceScreenApp implements UiApp {
|
|
36
36
|
#private;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DIALOG_CLOSE_SHORTCUT_HINT } from "../../contracts/presentation/index.js";
|
|
2
|
+
import { GLOBAL_SCOPE, PLAIN_THEME, RAIL_COLUMNS, ShortcutRegistry, ScrollbarRails, assertNoShortcutConflicts, displayWidth, layoutList, padToWidth, renderGroupHeader, renderShortcutHintsWithClose, scrollForTrackPage, scrollbarGeometry, scrollbarPresentation, scrollbarWheelRows, truncateToWidth, withScrollbarRail, } from "../../ui/components/index.js";
|
|
2
3
|
const SCOPE = "reference-screen";
|
|
3
4
|
/** Rows above the document: the top rule. */
|
|
4
5
|
const HEADER_ROWS = 1;
|
|
@@ -9,14 +10,17 @@ const SCROLL_LINGER_MS = 900;
|
|
|
9
10
|
const SCROLL_LINGER_REPAINT_MS = 925;
|
|
10
11
|
const LOADING_NOTICE = "Loading…";
|
|
11
12
|
export const REFERENCE_SCREEN_SHORTCUTS = new ShortcutRegistry();
|
|
12
|
-
// Compatibility: Ctrl+C remains the A1 interrupt chord here rather than a close key.
|
|
13
|
-
REFERENCE_SCREEN_SHORTCUTS.declare({ key: "escape", scope: GLOBAL_SCOPE, description: "Close", section: "Screen", hint: { keys: "esc", does: "close" } }, "close");
|
|
14
13
|
REFERENCE_SCREEN_SHORTCUTS.declare({ key: "up", scope: SCOPE, description: "Scroll up", section: "Navigate", hint: { keys: "↑↓", does: "scroll" } }, "up");
|
|
15
14
|
REFERENCE_SCREEN_SHORTCUTS.declare({ key: "down", scope: SCOPE, description: "Scroll down", section: "Navigate", hint: { keys: "↑↓", does: "scroll" } }, "down");
|
|
16
15
|
REFERENCE_SCREEN_SHORTCUTS.declare({ key: "pageUp", scope: SCOPE, description: "Up a page", section: "Navigate" }, "page-up");
|
|
17
16
|
REFERENCE_SCREEN_SHORTCUTS.declare({ key: "pageDown", scope: SCOPE, description: "Down a page", section: "Navigate" }, "page-down");
|
|
18
17
|
REFERENCE_SCREEN_SHORTCUTS.declare({ key: "home", scope: SCOPE, description: "First row", section: "Navigate" }, "first");
|
|
19
18
|
REFERENCE_SCREEN_SHORTCUTS.declare({ key: "end", scope: SCOPE, description: "Last row", section: "Navigate" }, "last");
|
|
19
|
+
// Compatibility: Ctrl+C remains the A1 interrupt chord here rather than a visible close key.
|
|
20
|
+
REFERENCE_SCREEN_SHORTCUTS.declare({
|
|
21
|
+
key: "escape", scope: GLOBAL_SCOPE, description: "Close", section: "Screen",
|
|
22
|
+
hint: { keys: DIALOG_CLOSE_SHORTCUT_HINT.key, does: DIALOG_CLOSE_SHORTCUT_HINT.action },
|
|
23
|
+
}, "close");
|
|
20
24
|
assertNoShortcutConflicts(REFERENCE_SCREEN_SHORTCUTS.assemble());
|
|
21
25
|
const KEYS = {
|
|
22
26
|
"\u001b[A": "up",
|
|
@@ -36,8 +40,8 @@ const KEYS = {
|
|
|
36
40
|
* Presents one read-only document full screen between two accent rules: the bold
|
|
37
41
|
* title leads the scrolled rows, the shared scrollbar rail runs beside them, and
|
|
38
42
|
* the hint line closes the frame. Rows come from a provider per content width and
|
|
39
|
-
* are cached until the width changes;
|
|
40
|
-
*
|
|
43
|
+
* are cached until the width changes; Escape closes locally, while an opted-in
|
|
44
|
+
* host closes on Ctrl+C before dispatching it into the screen.
|
|
41
45
|
*/
|
|
42
46
|
export class ReferenceScreenApp {
|
|
43
47
|
id;
|
|
@@ -135,7 +139,7 @@ export class ReferenceScreenApp {
|
|
|
135
139
|
const withRail = withScrollbarRail(body.slice(0, bodyHeight), geometry, contentWidth, theme, { presentation });
|
|
136
140
|
const hint = this.#interruptArmed
|
|
137
141
|
? theme.fg("dim", " press ctrl+c again to exit a1")
|
|
138
|
-
:
|
|
142
|
+
: renderShortcutHintsWithClose(REFERENCE_SCREEN_SHORTCUTS.hintEntries(SCOPE), theme, rect.width, 1);
|
|
139
143
|
// Compatibility: the v2 reference screen frames its document between two border-coloured rules.
|
|
140
144
|
const rule = theme.fg("border", "─".repeat(rect.width));
|
|
141
145
|
// Invariant: dialog chrome shares the title's one-cell inset; document content keeps its own layout.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DIALOG_CLOSE_SHORTCUT_HINT } from "../../contracts/presentation/index.js";
|
|
2
|
+
import { GLOBAL_SCOPE, LineInput, PLAIN_THEME, ShortcutRegistry, assertNoShortcutConflicts, blockJumpTarget, dialogValueColumn, numericValues, RAIL_COLUMNS, renderDialogPanel, renderEmptyState, renderGroupHeader, renderInputRow, renderListRow, renderNote, renderShortcutHintsWithClose, dialogRowAt, menuRowAt, regionAt, renderValueMenu, withScrollbarRail, stepperEnds, steppedValue, truncateToWidth, valueColumnFor, valueMenuFrame, blockRowSpan, displayWidth, handleLineInputKey, humanizeLabel, humanizeTitle, indexOfKey, isThumbRow, layoutList, moveSelection, rowKey, scrollForSelection, scrollForTrackPage, scrollbarGeometry, scrollbarPresentation, ScrollbarRails, scrollbarWheelRows, selectableIndexes, } from "../../ui/components/index.js";
|
|
2
3
|
import { SETTINGS_APP_ID, SETTINGS_ROUTE } from "./settings-route.js";
|
|
3
4
|
export { SETTINGS_APP_ID, SETTINGS_ROUTE } from "./settings-route.js";
|
|
4
5
|
const SCOPE = SETTINGS_APP_ID;
|
|
@@ -35,13 +36,16 @@ SETTINGS_SHORTCUTS.declare({ key: "enter", scope: SCOPE, description: "Change va
|
|
|
35
36
|
SETTINGS_SHORTCUTS.declare({ key: "space", scope: SCOPE, description: "Change value", section: "Change", hint: { keys: "Enter/Space", does: "to change" } }, "activate");
|
|
36
37
|
SETTINGS_SHORTCUTS.declare({ key: "left", scope: SCOPE, description: "Previous value", section: "Change", hint: { keys: "←→", does: "to adjust" } }, "previous-value");
|
|
37
38
|
SETTINGS_SHORTCUTS.declare({ key: "right", scope: SCOPE, description: "Next value", section: "Change", hint: { keys: "←→", does: "to adjust" } }, "next-value");
|
|
38
|
-
SETTINGS_SHORTCUTS.declare({ key: "escape", scope: GLOBAL_SCOPE, description: "Close", section: "Screen", hint: { keys: "Esc", does: "to cancel" } }, "close");
|
|
39
39
|
SETTINGS_SHORTCUTS.declare({ key: "enter", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts", hint: { keys: "Enter/Space", does: "to change" } }, "part-change");
|
|
40
40
|
SETTINGS_SHORTCUTS.declare({ key: "space", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts", hint: { keys: "Enter/Space", does: "to change" } }, "part-change");
|
|
41
41
|
SETTINGS_SHORTCUTS.declare({ key: "left", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts" }, "part-change");
|
|
42
42
|
SETTINGS_SHORTCUTS.declare({ key: "right", scope: DIALOG_SCOPE, description: "Change this part", section: "Parts" }, "part-change");
|
|
43
43
|
SETTINGS_SHORTCUTS.declare({ key: "up", scope: DIALOG_SCOPE, description: "Previous part", section: "Parts" }, "part-previous");
|
|
44
44
|
SETTINGS_SHORTCUTS.declare({ key: "down", scope: DIALOG_SCOPE, description: "Next part", section: "Parts" }, "part-next");
|
|
45
|
+
SETTINGS_SHORTCUTS.declare({
|
|
46
|
+
key: "escape", scope: GLOBAL_SCOPE, description: "Close", section: "Screen",
|
|
47
|
+
hint: { keys: DIALOG_CLOSE_SHORTCUT_HINT.key, does: DIALOG_CLOSE_SHORTCUT_HINT.action },
|
|
48
|
+
}, "close");
|
|
45
49
|
assertNoShortcutConflicts(SETTINGS_SHORTCUTS.assemble());
|
|
46
50
|
const KEYS = {
|
|
47
51
|
"\u001b[A": "up",
|
|
@@ -451,8 +455,9 @@ export class SettingsApp {
|
|
|
451
455
|
return;
|
|
452
456
|
}
|
|
453
457
|
const current = shown === null ? 0 : Math.max(0, entry.choices.indexOf(shown));
|
|
454
|
-
//
|
|
455
|
-
|
|
458
|
+
// Invariant: the opening press targeted the setting value, not an option. Keep the
|
|
459
|
+
// effective value as the keyboard origin without painting it as pointer-picked.
|
|
460
|
+
this.#menu = { entry, current, anchorKey: `${entry.backend}:${entry.id}`, choices: entry.choices, index: -1 };
|
|
456
461
|
}
|
|
457
462
|
// Rationale: a structured setting opens as its own flag list rather than a value menu.
|
|
458
463
|
#openStructured(entry) {
|
|
@@ -797,7 +802,7 @@ export class SettingsApp {
|
|
|
797
802
|
? notice
|
|
798
803
|
: this.#interruptArmed ? "press ctrl+c again to exit a1" : null;
|
|
799
804
|
const status = plainStatus === null
|
|
800
|
-
?
|
|
805
|
+
? renderShortcutHintsWithClose(SETTINGS_SHORTCUTS.hintEntries(SCOPE), theme, width, width > 0 ? 1 : 0)
|
|
801
806
|
: truncateToWidth(`${width > 0 ? " " : ""}${theme.fg("dim", plainStatus)}`, width);
|
|
802
807
|
const input = this.#filter;
|
|
803
808
|
if (input === null)
|
|
@@ -2,10 +2,11 @@ export { adaptPiAssistantMessage, adaptPiToolExecution, adaptPiUserMessage } fro
|
|
|
2
2
|
export { loadHistoryEditor, type HistoryEditorConstructor } from "./history-editor-loader.js";
|
|
3
3
|
export { PiComponentConformanceError, runPiComponentConformance } from "./conformance.js";
|
|
4
4
|
export type { PiComponentConformanceReport, PiComponentConformanceResult } from "./conformance.js";
|
|
5
|
-
export {
|
|
5
|
+
export { createPiShellOperationLoader, createPiShellShareOperationDialog, type PiShellOperationLoaderPort, } from "./share-operation-dialog.js";
|
|
6
|
+
export { OWNED_BUILTIN_SLASH_COMMANDS, PINNED_PI_BUILTIN_SLASH_COMMANDS, componentFromPort, componentPort, createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellShowImagesSelector, createPiShellSkillsSelector, createPiShellStatus, createPiShellThemeSelector, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, createTuiFacade, ensureTheme, formatSessionTokens, isAutocompleteProvider, isPiPromptStyleCompaction, isRecord, paintPiSubmittedPromptTimestamp, piShellHyperlink, piShellTruncateToWidth, piShellVisibleWidth, renderPiShellChangelogLines, renderPiShellCommandMessage, renderPiShellHotkeysLines, renderPiShellPackageUpdateNotice, renderPiShellReleaseUpdateBanner, renderPiShellReleaseUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, validatedAssistantMessage, } from "./shell-components.js";
|
|
6
7
|
export { renderPiShellHotkeySections } from "./shell-hotkey-sections.js";
|
|
7
8
|
export type { PiShellHotkeySection } from "./shell-hotkey-sections.js";
|
|
8
|
-
export type { PiExtensionUiBridge, PiExtensionUiBridgeHost, PiShellAuthProviderOption, PiShellAutocompleteCommand, PiShellClipboardContent, PiShellCommandMessagePresentation, PiShellComponentPort, PiShellEditorBodyGeometry, PiShellEditorOptions, PiShellEditorPointerEvent, PiShellEditorPort, PiShellEditorTextRange, PiShellExtensionRendererResolver, PiShellHeaderOptions, PiShellHeaderPort, PiShellHotkeysPresentation, PiShellImageAssetResolver, PiShellLoadedResourcesPort, PiShellLoginDialogPort, PiShellModelSelectorOptions, PiShellModelsDialogOptions, PiShellModelsDialogPort,
|
|
9
|
+
export type { PiExtensionUiBridge, PiExtensionUiBridgeHost, PiShellAuthProviderOption, PiShellAutocompleteCommand, PiShellClipboardContent, PiShellCommandMessagePresentation, PiShellComponentPort, PiShellEditorBodyGeometry, PiShellEditorOptions, PiShellEditorPointerEvent, PiShellEditorPort, PiShellEditorTextRange, PiShellExtensionRendererResolver, PiShellHeaderOptions, PiShellHeaderPort, PiShellHotkeysPresentation, PiShellImageAssetResolver, PiShellLoadedResourcesPort, PiShellLoginDialogPort, PiShellModelSelectorOptions, PiShellModelsDialogOptions, PiShellModelsDialogPort, PiShellPasteReservation, PiShellQueuedInputPort, PiShellResourceEntry, PiShellResourceSection, PiShellScopedModelDescriptor, PiShellScopedModelsSelectorOptions, PiShellScopedModelsSelectorPort, PiShellSelectorOption, PiShellSelectorOptions, PiShellSessionInfoPresentation, PiShellSettingsSelectorOptions, PiShellStartupNotice, PiShellStatusPlacement, PiShellStatusPort, PiShellSubmittedPromptComposer, PiShellTranscriptComponentPort, PiShellViewComponentPort, } from "./shell-components.js";
|
|
9
10
|
export { PINNED_PI_LAYOUT, applyConfiguredPiTheme, applyPiTheme, applyPiThemeInstance, currentPiThemeName, detectPiTerminalBackgroundFromEnv, detectPiTerminalBackgroundTheme, detectPiTerminalThemeForAuto, ensurePiTheme, getAvailablePiThemes, loadPiTheme, onPiThemeChange, parsePiAutoThemeSetting, piTheme, resolvePiThemeSetting, stopPiThemeWatcher, } from "./theme.js";
|
|
10
11
|
export type { PiColorMode, PiTerminalTheme, PiTerminalThemeDetection, PiTerminalThemeDetector, PiThemeBackground, PiThemeResult } from "./theme.js";
|
|
11
12
|
export { OwnedPiThemeController } from "./upstream/theme/theme-controller.js";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { adaptPiAssistantMessage, adaptPiToolExecution, adaptPiUserMessage } from "./components.js";
|
|
2
2
|
export { loadHistoryEditor } from "./history-editor-loader.js";
|
|
3
3
|
export { PiComponentConformanceError, runPiComponentConformance } from "./conformance.js";
|
|
4
|
-
export {
|
|
4
|
+
export { createPiShellOperationLoader, createPiShellShareOperationDialog, } from "./share-operation-dialog.js";
|
|
5
|
+
export { OWNED_BUILTIN_SLASH_COMMANDS, PINNED_PI_BUILTIN_SLASH_COMMANDS, componentFromPort, componentPort, createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellShowImagesSelector, createPiShellSkillsSelector, createPiShellStatus, createPiShellThemeSelector, createPiShellTranscriptComponent, createPiShellTreeSelector, createPiShellTrustSelector, createPiShellUserMessageSelector, createTuiFacade, ensureTheme, formatSessionTokens, isAutocompleteProvider, isPiPromptStyleCompaction, isRecord, paintPiSubmittedPromptTimestamp, piShellHyperlink, piShellTruncateToWidth, piShellVisibleWidth, renderPiShellChangelogLines, renderPiShellCommandMessage, renderPiShellHotkeysLines, renderPiShellPackageUpdateNotice, renderPiShellReleaseUpdateBanner, renderPiShellReleaseUpdateNotice, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, validatedAssistantMessage, } from "./shell-components.js";
|
|
5
6
|
export { renderPiShellHotkeySections } from "./shell-hotkey-sections.js";
|
|
6
7
|
export { PINNED_PI_LAYOUT, applyConfiguredPiTheme, applyPiTheme, applyPiThemeInstance, currentPiThemeName, detectPiTerminalBackgroundFromEnv, detectPiTerminalBackgroundTheme, detectPiTerminalThemeForAuto, ensurePiTheme, getAvailablePiThemes, loadPiTheme, onPiThemeChange, parsePiAutoThemeSetting, piTheme, resolvePiThemeSetting, stopPiThemeWatcher, } from "./theme.js";
|
|
7
8
|
export { OwnedPiThemeController } from "./upstream/theme/theme-controller.js";
|
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
import { Container, type Component } from "@earendil-works/pi-tui";
|
|
1
|
+
import { Container, type Component, type TUI } from "@earendil-works/pi-tui";
|
|
2
2
|
export declare const PI_MODAL_CONTENT_PADDING_X = 1;
|
|
3
|
+
/** Adds the standard navigation/select/close footer before a dependency component's bottom rule. */
|
|
4
|
+
export declare function addPiModalSelectFooter(container: Container): void;
|
|
5
|
+
/** Owned cancellable operation frame with the canonical dialog close guidance. */
|
|
6
|
+
export declare class PiCancellableOperationFrame extends Container {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(tui: TUI, message: string);
|
|
9
|
+
get signal(): AbortSignal;
|
|
10
|
+
handleInput(data: string): void;
|
|
11
|
+
dispose(): void;
|
|
12
|
+
}
|
|
3
13
|
/** The semantic top rule/title pair used while a modal assembles its frame. */
|
|
4
14
|
export declare class PiModalHeader implements Component {
|
|
5
15
|
readonly rule: Component;
|
|
@@ -1,5 +1,33 @@
|
|
|
1
|
-
import { Container, Spacer } from "@earendil-works/pi-tui";
|
|
1
|
+
import { CancellableLoader, Container, Spacer, Text } from "@earendil-works/pi-tui";
|
|
2
|
+
import { DynamicBorder } from "../startup-public.js";
|
|
3
|
+
import { DIALOG_CLOSE_SHORTCUT_HINT, piTheme, renderPiModalShortcutHints } from "./theme.js";
|
|
2
4
|
export const PI_MODAL_CONTENT_PADDING_X = 1;
|
|
5
|
+
/** Adds the standard navigation/select/close footer before a dependency component's bottom rule. */
|
|
6
|
+
export function addPiModalSelectFooter(container) {
|
|
7
|
+
container.children.splice(container.children.length - 1, 0, new Text(renderPiModalShortcutHints([
|
|
8
|
+
{ key: "↑↓", action: "navigate" }, { key: "enter", action: "select" }, DIALOG_CLOSE_SHORTCUT_HINT,
|
|
9
|
+
]), 0, 0));
|
|
10
|
+
}
|
|
11
|
+
/** Owned cancellable operation frame with the canonical dialog close guidance. */
|
|
12
|
+
export class PiCancellableOperationFrame extends Container {
|
|
13
|
+
#loader;
|
|
14
|
+
constructor(tui, message) {
|
|
15
|
+
super();
|
|
16
|
+
const theme = piTheme();
|
|
17
|
+
const border = (text) => theme.fg("border", text);
|
|
18
|
+
this.#loader = new CancellableLoader(tui, text => theme.fg("accent", text), text => theme.fg("muted", text), message);
|
|
19
|
+
this.addChild(new DynamicBorder(border));
|
|
20
|
+
this.addChild(this.#loader);
|
|
21
|
+
this.addChild(new Spacer(1));
|
|
22
|
+
this.addChild(new Text(renderPiModalShortcutHints([DIALOG_CLOSE_SHORTCUT_HINT]), 0, 0));
|
|
23
|
+
this.addChild(new Spacer(1));
|
|
24
|
+
this.addChild(new DynamicBorder(border));
|
|
25
|
+
adoptPiModalFrame(this, { topIndex: 0, bottomIndex: this.children.length - 1 });
|
|
26
|
+
}
|
|
27
|
+
get signal() { return this.#loader.signal; }
|
|
28
|
+
handleInput(data) { this.#loader.handleInput(data); }
|
|
29
|
+
dispose() { this.#loader.dispose(); }
|
|
30
|
+
}
|
|
3
31
|
/** The semantic top rule/title pair used while a modal assembles its frame. */
|
|
4
32
|
export class PiModalHeader {
|
|
5
33
|
rule;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
import { Input,
|
|
1
|
+
import { Input, getKeybindings, matchesKey, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { DynamicBorder } from "../startup-public.js";
|
|
3
3
|
import { PiModalFrame } from "./modal-frame.js";
|
|
4
|
-
import { piTheme, renderPiModalShortcutHints } from "./theme.js";
|
|
4
|
+
import { DIALOG_CLOSE_SHORTCUT_HINT, piTheme, renderPiModalListRow, renderPiModalShortcutHints, } from "./theme.js";
|
|
5
|
+
function renderHintsWithClose(entries, width) {
|
|
6
|
+
const body = renderPiModalShortcutHints(entries.slice(0, -1));
|
|
7
|
+
const close = renderPiModalShortcutHints([DIALOG_CLOSE_SHORTCUT_HINT]);
|
|
8
|
+
const closeWidth = visibleWidth(close);
|
|
9
|
+
if (width <= closeWidth)
|
|
10
|
+
return truncateToWidth(close, width, "");
|
|
11
|
+
const clippedBody = truncateToWidth(body, Math.max(0, width - closeWidth - 2), "…");
|
|
12
|
+
return visibleWidth(clippedBody) === 0 ? close : `${clippedBody} ${close}`;
|
|
13
|
+
}
|
|
5
14
|
const MAX_VISIBLE_ROWS = 10;
|
|
6
15
|
const MODELS_TITLE = "Models";
|
|
7
16
|
const REFRESHING_TITLE_MIN_DURATION_MS = 1_000;
|
|
@@ -166,7 +175,7 @@ export class ModelsDialogComponent {
|
|
|
166
175
|
this.#selectedIndex = this.#selectedIndex === rows.length - 1 ? 0 : this.#selectedIndex + 1;
|
|
167
176
|
return;
|
|
168
177
|
}
|
|
169
|
-
if (kb.matches(data, "tui.input.tab")) {
|
|
178
|
+
if (matchesKey(data, "shift+tab") || kb.matches(data, "tui.input.tab")) {
|
|
170
179
|
this.#filter = this.#filter === "all" ? "scoped" : "all";
|
|
171
180
|
this.#restoreSelection(preferredId);
|
|
172
181
|
return;
|
|
@@ -221,15 +230,6 @@ export class ModelsDialogComponent {
|
|
|
221
230
|
this.#setScope(next, selected.fullId);
|
|
222
231
|
return;
|
|
223
232
|
}
|
|
224
|
-
if (matchesKey(data, Key.ctrl("c"))) {
|
|
225
|
-
if (this.#input.getValue().length > 0) {
|
|
226
|
-
this.#input.setValue("");
|
|
227
|
-
this.#selectedIndex = 0;
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
this.#callbacks.onCancel();
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
233
|
if (kb.matches(data, "tui.select.cancel")) {
|
|
234
234
|
this.#callbacks.onCancel();
|
|
235
235
|
return;
|
|
@@ -305,11 +305,11 @@ export class ModelsDialogComponent {
|
|
|
305
305
|
const scoped = this.#scopeIds.includes(row.fullId);
|
|
306
306
|
// Invariant: arrow, scope marker, model id, [provider], then the active checkmark, in that order.
|
|
307
307
|
const prefix = selected ? theme.fg("accent", "→ ") : " ";
|
|
308
|
-
const marker = scoped ? theme.fg("
|
|
309
|
-
const label = selected ? theme.fg("
|
|
308
|
+
const marker = scoped ? theme.fg("accent", "●") : theme.fg("dim", "○");
|
|
309
|
+
const label = selected ? theme.fg("text", row.model.id) : row.model.id;
|
|
310
310
|
const provider = theme.fg("muted", `[${row.model.provider}]`);
|
|
311
311
|
const active = row.fullId === this.#activeModelId ? ` ${theme.fg("success", "✓")}` : "";
|
|
312
|
-
push(`${prefix}${marker} ${label} ${provider}${active}
|
|
312
|
+
push(renderPiModalListRow(`${prefix}${marker} ${label} ${provider}${active}`, width, selected));
|
|
313
313
|
}
|
|
314
314
|
if (startIndex > 0 || endIndex < rows.length)
|
|
315
315
|
push(theme.fg("muted", ` (${this.#selectedIndex + 1}/${rows.length})`));
|
|
@@ -322,7 +322,7 @@ export class ModelsDialogComponent {
|
|
|
322
322
|
push();
|
|
323
323
|
if (this.#refreshStatus !== undefined)
|
|
324
324
|
push(theme.fg(this.#refreshStatus.kind, ` ${this.#refreshStatus.message}`));
|
|
325
|
-
push(
|
|
325
|
+
push(renderHintsWithClose(this.#hints(), width));
|
|
326
326
|
return lines;
|
|
327
327
|
}
|
|
328
328
|
#hints() {
|
|
@@ -336,7 +336,7 @@ export class ModelsDialogComponent {
|
|
|
336
336
|
...(confirm.length === 0 ? [] : [{ key: confirm, action: "switch" }]),
|
|
337
337
|
{ key: "space", action: "scope" },
|
|
338
338
|
...(save.length === 0 ? [] : [{ key: save, action: "save" }]),
|
|
339
|
-
|
|
339
|
+
DIALOG_CLOSE_SHORTCUT_HINT,
|
|
340
340
|
];
|
|
341
341
|
}
|
|
342
342
|
#emptyText() {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type PiShellComponentPort, type PiShellEditorOptions } from "./shell-shared-facade.js";
|
|
2
|
+
export interface PiShellOperationLoaderPort extends PiShellComponentPort {
|
|
3
|
+
readonly signal: AbortSignal;
|
|
4
|
+
}
|
|
5
|
+
export declare function createPiShellShareOperationDialog(runtime: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">, message: string): PiShellOperationLoaderPort;
|
|
6
|
+
export declare function createPiShellOperationLoader(runtime: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">, message: string): PiShellOperationLoaderPort;
|