@timurproko/a1 0.2.5-dev.683 → 0.2.5-dev.704
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 +80 -23
- package/dist/app/session-shell/share-operation.d.ts +3 -0
- package/dist/app/session-shell/share-operation.js +11 -0
- package/dist/composition/owned-ui.js +2 -0
- package/dist/composition/settings-route-host.js +1 -1
- package/dist/contracts/presentation/index.d.ts +11 -1
- package/dist/contracts/presentation/index.js +6 -2
- 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.d.ts +1 -1
- package/dist/features/owned-ui/settings-app.js +342 -66
- 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 +19 -19
- 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 +55 -8
- 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 +21 -8
- 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/owned-editor.d.ts +4 -2
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +48 -12
- 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 +137 -110
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +9 -5
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +65 -26
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +31 -21
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +255 -214
- 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.d.ts +15 -0
- package/dist/ui/components/dialog-panel.js +55 -9
- package/dist/ui/components/index.d.ts +3 -3
- package/dist/ui/components/index.js +2 -2
- package/dist/ui/components/line-input.d.ts +2 -0
- package/dist/ui/components/line-input.js +2 -2
- package/dist/ui/components/list-view.d.ts +3 -3
- package/dist/ui/components/list-view.js +8 -9
- package/dist/ui/components/prompt-input.d.ts +2 -2
- package/dist/ui/components/prompt-input.js +5 -5
- package/dist/ui/components/shortcut-hints.d.ts +10 -3
- package/dist/ui/components/shortcut-hints.js +42 -6
- package/dist/ui/components/shortcuts.d.ts +1 -1
- package/dist/ui/components/shortcuts.js +4 -0
- package/dist/ui/components/theme.d.ts +1 -1
- package/dist/ui/components/value-menu.js +3 -1
- package/dist/ui/settings/manager.d.ts +1 -0
- package/dist/ui/settings/manager.js +9 -3
- 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(),
|
|
@@ -280,7 +285,7 @@ export class OwnedUiSessionShell {
|
|
|
280
285
|
}),
|
|
281
286
|
...(terminal === undefined ? {} : { terminal: terminal }),
|
|
282
287
|
hardwareCursor: this.backend.view().terminal.hardwareCursor,
|
|
283
|
-
wheelScrollLines: initialPiSettings.fullscreenWheelScrollLines,
|
|
288
|
+
...(this.#customViewport ? {} : { wheelScrollLines: initialPiSettings.fullscreenWheelScrollLines }),
|
|
284
289
|
};
|
|
285
290
|
runtime = new PiTuiRuntimeAdapter(runtimeOptions);
|
|
286
291
|
this.runtime = runtime;
|
|
@@ -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")
|
|
@@ -458,13 +470,14 @@ export class OwnedUiSessionShell {
|
|
|
458
470
|
if (typeof value !== "boolean")
|
|
459
471
|
throw new TypeError("Fullscreen copy-on-select setting is invalid");
|
|
460
472
|
this.root.setFullscreenCopyOnSelect(value);
|
|
461
|
-
} } } : {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
473
|
+
} } } : {
|
|
474
|
+
fullscreenWheelScrollLines: { apply: (value) => {
|
|
475
|
+
if (value !== "auto" && (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > 100)) {
|
|
476
|
+
throw new TypeError("Fullscreen wheel-scroll distance is invalid");
|
|
477
|
+
}
|
|
478
|
+
this.runtime.setWheelScrollLines(value);
|
|
479
|
+
} },
|
|
480
|
+
}),
|
|
468
481
|
});
|
|
469
482
|
if (this.#customViewport && promptHistory !== undefined) {
|
|
470
483
|
this.#promptHistoryImageSidecar = promptHistory.imageSidecar;
|
|
@@ -1065,12 +1078,14 @@ export class OwnedUiSessionShell {
|
|
|
1065
1078
|
},
|
|
1066
1079
|
onCancel: close,
|
|
1067
1080
|
onSelect: entryId => {
|
|
1068
|
-
close();
|
|
1069
1081
|
if (entryId === context.currentLeafId) {
|
|
1082
|
+
close();
|
|
1070
1083
|
this.root.appendWorkflowStatus("Already at this point");
|
|
1071
1084
|
this.runtime.requestRender();
|
|
1072
1085
|
return;
|
|
1073
1086
|
}
|
|
1087
|
+
if (context.skipSummaryPrompt)
|
|
1088
|
+
close();
|
|
1074
1089
|
void this.#completeTreeSelection(entryId, context.skipSummaryPrompt);
|
|
1075
1090
|
},
|
|
1076
1091
|
});
|
|
@@ -1206,6 +1221,19 @@ export class OwnedUiSessionShell {
|
|
|
1206
1221
|
async runWorkflow(request) {
|
|
1207
1222
|
if (request.command === "quit")
|
|
1208
1223
|
return this.shutdown();
|
|
1224
|
+
if (this.#customViewport && request.command === "name" && request.argument.trim().length === 0) {
|
|
1225
|
+
void this.#extensionBridge.input("Session Name", "Enter name").then(value => {
|
|
1226
|
+
if (this.#disposed || value === undefined || value.trim().length === 0)
|
|
1227
|
+
return;
|
|
1228
|
+
return this.runWorkflow({ ...request, argument: value });
|
|
1229
|
+
}).catch(error => {
|
|
1230
|
+
if (this.#disposed)
|
|
1231
|
+
return;
|
|
1232
|
+
this.root.appendWorkflowResult({ command: "name", outcome: "failed", message: error instanceof Error ? error.message : String(error) });
|
|
1233
|
+
this.runtime.requestRender();
|
|
1234
|
+
});
|
|
1235
|
+
return { outcome: "completed", diagnostic: null };
|
|
1236
|
+
}
|
|
1209
1237
|
const copyGeneration = request.command === "copy" ? this.backend.sessionBindingGeneration : undefined;
|
|
1210
1238
|
if (request.command === "login" && request.selection !== undefined) {
|
|
1211
1239
|
const setup = this.backend.pinnedAmbientAuthentication(request.selection);
|
|
@@ -1281,13 +1309,15 @@ export class OwnedUiSessionShell {
|
|
|
1281
1309
|
}
|
|
1282
1310
|
this.root.resetExtensionUi();
|
|
1283
1311
|
}
|
|
1284
|
-
const
|
|
1285
|
-
?
|
|
1312
|
+
const shareDialog = request.command === "share"
|
|
1313
|
+
? await import("./share-operation.js")
|
|
1314
|
+
: undefined;
|
|
1315
|
+
const shareSurface = shareDialog === undefined ? undefined
|
|
1316
|
+
: (this.#customViewport ? shareDialog.createPiShellShareOperationDialog : shareDialog.createPiShellOperationLoader)({
|
|
1286
1317
|
getColumns: () => this.runtime.viewport().columns,
|
|
1287
1318
|
getRows: () => this.runtime.viewport().rows,
|
|
1288
1319
|
requestRender: () => this.runtime.requestRender(),
|
|
1289
|
-
}, "Creating gist
|
|
1290
|
-
: undefined;
|
|
1320
|
+
}, "Creating gist…");
|
|
1291
1321
|
const operationSurface = shareSurface ?? (request.command === "reload" ? createPiShellReloadBox() : undefined);
|
|
1292
1322
|
const now = this.#reloadPresentation?.now ?? Date.now;
|
|
1293
1323
|
const shownAt = now();
|
|
@@ -1343,7 +1373,17 @@ export class OwnedUiSessionShell {
|
|
|
1343
1373
|
this.root.editor.reloadKeybindings();
|
|
1344
1374
|
this.#installAutocompleteCommands();
|
|
1345
1375
|
}
|
|
1346
|
-
|
|
1376
|
+
if (request.command === "tree" && result.outcome === "completed") {
|
|
1377
|
+
if (result.detail && !this.root.editor.getText().trim())
|
|
1378
|
+
this.root.editor.setText(result.detail);
|
|
1379
|
+
this.root.resumeViewportFollowing();
|
|
1380
|
+
}
|
|
1381
|
+
if (shareDialog !== undefined && this.#customViewport && result.outcome === "completed" && result.detail !== undefined) {
|
|
1382
|
+
this.root.appendWorkflowStatus(shareDialog.renderPiShellShareResult(result.message, result.detail));
|
|
1383
|
+
}
|
|
1384
|
+
else {
|
|
1385
|
+
this.root.appendWorkflowResult(result);
|
|
1386
|
+
}
|
|
1347
1387
|
this.runtime.requestRender();
|
|
1348
1388
|
return workflowAdapterResult(result);
|
|
1349
1389
|
}
|
|
@@ -1782,6 +1822,19 @@ export class OwnedUiSessionShell {
|
|
|
1782
1822
|
const removeInterruptWatch = this.runtime.addInputListener(data => {
|
|
1783
1823
|
if (!data.includes(INTERRUPT))
|
|
1784
1824
|
return undefined;
|
|
1825
|
+
// Protocol: route hosts decide whether one interrupt closes their app. Raw-input forwarding
|
|
1826
|
+
// is required because Pi handles Ctrl+C before the fullscreen overlay receives normal input.
|
|
1827
|
+
const consumedBySurface = surface.handleInput(INTERRUPT);
|
|
1828
|
+
if (surface.isClosed()) {
|
|
1829
|
+
armedAt = 0;
|
|
1830
|
+
closeSurface();
|
|
1831
|
+
return { consume: true };
|
|
1832
|
+
}
|
|
1833
|
+
if (consumedBySurface) {
|
|
1834
|
+
armedAt = 0;
|
|
1835
|
+
this.runtime.requestRender();
|
|
1836
|
+
return { consume: true };
|
|
1837
|
+
}
|
|
1785
1838
|
const now = Date.now();
|
|
1786
1839
|
if (armedAt !== 0 && now - armedAt <= INTERRUPT_CHORD_MS) {
|
|
1787
1840
|
armedAt = 0;
|
|
@@ -1970,7 +2023,7 @@ export class OwnedUiSessionShell {
|
|
|
1970
2023
|
}
|
|
1971
2024
|
return this.#submitSkillPrompt(skillPrompt(skill.name, separator < 0 ? "" : trimmed.slice(separator + 1)), text);
|
|
1972
2025
|
}
|
|
1973
|
-
// Rationale:
|
|
2026
|
+
// Rationale: engine expands skill arguments; history retains typed input for recall.
|
|
1974
2027
|
#submitSkillPrompt(prompt, typed) {
|
|
1975
2028
|
this.#rememberInput(typed, "slash");
|
|
1976
2029
|
this.root.resumeViewportFollowing();
|
|
@@ -1981,29 +2034,33 @@ export class OwnedUiSessionShell {
|
|
|
1981
2034
|
text: prompt,
|
|
1982
2035
|
});
|
|
1983
2036
|
}
|
|
2037
|
+
#treeSummary() {
|
|
2038
|
+
return new Promise(resolve => {
|
|
2039
|
+
this.root.setInputSurface(createPiShellExtensionSelector("Summarize Branch?", ["No summary", "Summarize", "Summarize with custom prompt"], resolve, () => resolve(undefined)), true, "opaque");
|
|
2040
|
+
this.runtime.requestRender();
|
|
2041
|
+
});
|
|
2042
|
+
}
|
|
1984
2043
|
async #completeTreeSelection(entryId, skipSummaryPrompt) {
|
|
1985
2044
|
let summarize = false;
|
|
1986
2045
|
let customInstructions;
|
|
1987
2046
|
if (!skipSummaryPrompt) {
|
|
1988
2047
|
while (true) {
|
|
1989
|
-
const choice = await this.#
|
|
1990
|
-
"No summary",
|
|
1991
|
-
"Summarize",
|
|
1992
|
-
"Summarize with custom prompt",
|
|
1993
|
-
]);
|
|
2048
|
+
const choice = await this.#treeSummary();
|
|
1994
2049
|
if (choice === undefined) {
|
|
1995
2050
|
await this.showTreeSelector(entryId);
|
|
1996
2051
|
return;
|
|
1997
2052
|
}
|
|
1998
2053
|
summarize = choice !== "No summary";
|
|
1999
2054
|
if (choice === "Summarize with custom prompt") {
|
|
2000
|
-
customInstructions = await this.#extensionBridge.
|
|
2055
|
+
customInstructions = await this.#extensionBridge.input("Custom Summarization Instructions", "", { retainSurfaceOnSettle: true });
|
|
2001
2056
|
if (customInstructions === undefined)
|
|
2002
2057
|
continue;
|
|
2003
2058
|
}
|
|
2004
2059
|
break;
|
|
2005
2060
|
}
|
|
2006
2061
|
}
|
|
2062
|
+
this.root.setInputSurface(null);
|
|
2063
|
+
this.runtime.requestRender();
|
|
2007
2064
|
const result = await this.runWorkflow({
|
|
2008
2065
|
command: "tree",
|
|
2009
2066
|
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
|
+
}
|
|
@@ -44,6 +44,8 @@ export async function composeOwnedUi(options = {}) {
|
|
|
44
44
|
configDir: resolveProductPaths().configDir,
|
|
45
45
|
profileId: options.profileId,
|
|
46
46
|
agentProvider: () => adapter.settingsPort(),
|
|
47
|
+
hiddenAgentSettingIds: ["fullscreenWheelScrollLines"],
|
|
48
|
+
agentSettingLabelOverrides: { fullscreenCopyOnSelect: "Copy on select" },
|
|
47
49
|
});
|
|
48
50
|
let releaseNotes = null;
|
|
49
51
|
let releaseNotesFailure;
|
|
@@ -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,16 @@ 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
|
+
}>;
|
|
12
|
+
/** Canonical return guidance for a nested step within a dialog surface. */
|
|
13
|
+
export declare const DIALOG_BACK_SHORTCUT_HINT: Readonly<{
|
|
14
|
+
key: string;
|
|
15
|
+
action: string;
|
|
16
|
+
}>;
|
|
7
17
|
export interface ShortcutHintRoles {
|
|
8
18
|
key(label: string): string;
|
|
9
19
|
action(name: string): string;
|
|
@@ -11,7 +21,7 @@ export interface ShortcutHintRoles {
|
|
|
11
21
|
/** Applies the common display casing to each named key and letter in a shortcut label. */
|
|
12
22
|
export declare function displayShortcutKeyLabel(label: string): string;
|
|
13
23
|
/** Renders the canonical semantic shortcut row independently of either presentation framework. */
|
|
14
|
-
export declare function renderSemanticShortcutHints(entries: readonly SemanticShortcutHint[], roles: ShortcutHintRoles, indent?: number): string;
|
|
24
|
+
export declare function renderSemanticShortcutHints(entries: readonly SemanticShortcutHint[], roles: ShortcutHintRoles, indent?: number, separator?: string): string;
|
|
15
25
|
export interface PresentationComponentPort {
|
|
16
26
|
render(width: number): readonly string[];
|
|
17
27
|
invalidate(): void;
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/** Canonical dismissal guidance for every A1-rendered dialog surface. */
|
|
2
|
+
export const DIALOG_CLOSE_SHORTCUT_HINT = Object.freeze({ key: "esc", action: "close" });
|
|
3
|
+
/** Canonical return guidance for a nested step within a dialog surface. */
|
|
4
|
+
export const DIALOG_BACK_SHORTCUT_HINT = Object.freeze({ key: "esc", action: "back" });
|
|
1
5
|
const SHORTCUT_KEY_NAMES = Object.freeze({
|
|
2
6
|
alt: "Alt", backspace: "Backspace", cmd: "Cmd", ctrl: "Ctrl", delete: "Delete", down: "Down", end: "End",
|
|
3
7
|
enter: "Enter", esc: "Esc", escape: "Escape", home: "Home", insert: "Insert", left: "Left", meta: "Meta",
|
|
@@ -16,7 +20,7 @@ export function displayShortcutKeyLabel(label) {
|
|
|
16
20
|
}).join("+")).join("/");
|
|
17
21
|
}
|
|
18
22
|
/** Renders the canonical semantic shortcut row independently of either presentation framework. */
|
|
19
|
-
export function renderSemanticShortcutHints(entries, roles, indent = 0) {
|
|
23
|
+
export function renderSemanticShortcutHints(entries, roles, indent = 0, separator = " ") {
|
|
20
24
|
const rendered = entries.flatMap(entry => {
|
|
21
25
|
if (entry.key === "" || (entry.key !== undefined && entry.key.trim().length === 0))
|
|
22
26
|
return [];
|
|
@@ -26,7 +30,7 @@ export function renderSemanticShortcutHints(entries, roles, indent = 0) {
|
|
|
26
30
|
const action = roles.action(entry.action);
|
|
27
31
|
return [entry.actionFirst ? `${action} ${key}` : `${key} ${action}`];
|
|
28
32
|
});
|
|
29
|
-
return `${" ".repeat(Math.max(0, indent))}${rendered.join(
|
|
33
|
+
return `${" ".repeat(Math.max(0, indent))}${rendered.join(separator)}`;
|
|
30
34
|
}
|
|
31
35
|
export function assertPresentationComponent(component) {
|
|
32
36
|
requiredFunctions(component, ["render", "invalidate"], "presentation component");
|
|
@@ -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.
|
|
@@ -2,7 +2,7 @@ import type { AppHostServices, UiApp } from "../../ui/apps/index.js";
|
|
|
2
2
|
import { ShortcutRegistry, type PaneInputResult, type PaneMouseEvent, type PaneRect } from "../../ui/components/index.js";
|
|
3
3
|
import type { OwnedSettingsManager } from "../../ui/settings/index.js";
|
|
4
4
|
export { SETTINGS_APP_ID, SETTINGS_ROUTE } from "./settings-route.js";
|
|
5
|
-
type Action = "move-up" | "move-down" | "block-up" | "block-down" | "first" | "last" | "page-up" | "page-down" | "previous-value" | "next-value" | "activate" | "open-filter" | "close" | "part-previous" | "part-next" | "part-change";
|
|
5
|
+
type Action = "move-up" | "move-down" | "block-up" | "block-down" | "first" | "last" | "page-up" | "page-down" | "previous-value" | "next-value" | "activate" | "open-filter" | "close" | "undo" | "part-previous" | "part-next" | "part-change";
|
|
6
6
|
export declare const SETTINGS_SHORTCUTS: ShortcutRegistry<Action>;
|
|
7
7
|
/**
|
|
8
8
|
* The settings screen. Rows, sticky headers, scrolling, and the keymap come from
|