@timurproko/a1 0.2.7-dev.1275 → 0.2.7-dev.1285
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 +5 -1
- package/dist/app/session-shell/apps-dialog.d.ts +1 -1
- package/dist/app/session-shell/apps-dialog.js +2 -1
- package/dist/app/session-shell/dialog-coordinator.d.ts +4 -5
- package/dist/app/session-shell/dialog-coordinator.js +41 -12
- package/dist/app/session-shell/input-route.d.ts +23 -0
- package/dist/app/session-shell/input-route.js +59 -0
- package/dist/app/session-shell/session-selectors.d.ts +3 -3
- package/dist/app/session-shell/session-selectors.js +7 -2
- package/dist/app/session-shell/session-shell-root.d.ts +4 -68
- package/dist/app/session-shell/session-shell-root.js +6 -2
- package/dist/app/session-shell/session-shell.js +9 -13
- package/dist/app/session-shell/shell-host.js +2 -2
- package/dist/app/session-shell/shell-options.d.ts +65 -0
- package/dist/app/session-shell/shell-options.js +1 -0
- package/dist/app/session-shell/viewport-pointer.js +5 -1
- package/dist/app/session-shell/workflow-router.d.ts +4 -2
- package/dist/app/session-shell/workflow-router.js +12 -0
- package/dist/cli/dispatch.js +27 -1
- package/dist/cli/packages.js +18 -2
- package/dist/cli/session-context.js +6 -2
- package/dist/composition/owned-ui.js +20 -8
- package/dist/composition/session-naming.js +1 -1
- package/dist/composition/session-runtime-registry.d.ts +2 -0
- package/dist/composition/session-runtime-registry.js +49 -9
- package/dist/composition/settings-route-host.js +1 -0
- package/dist/contracts/agent-engine/package-ports.d.ts +10 -14
- package/dist/contracts/agent-engine/package-ports.js +5 -9
- package/dist/contracts/owned-ui/session-workflows.d.ts +6 -0
- package/dist/contracts/owned-ui/shell-components.d.ts +10 -0
- package/dist/contracts/presentation/component.d.ts +7 -0
- package/dist/contracts/presentation/index.d.ts +3 -0
- package/dist/contracts/presentation/index.js +4 -0
- package/dist/contracts/presentation/progress-palette.generated.d.ts +25 -1
- package/dist/contracts/presentation/progress-palette.generated.js +2 -135
- package/dist/contracts/presentation/progress-spinner.d.ts +7 -0
- package/dist/contracts/presentation/progress-spinner.js +1 -0
- package/dist/features/launch/session-context.d.ts +8 -0
- package/dist/features/launch/session-context.js +19 -10
- package/dist/features/owned-ui/project-trust-dialog.d.ts +1 -1
- package/dist/features/owned-ui/project-trust-dialog.js +5 -5
- package/dist/features/owned-ui/project-trust-prompt.js +2 -2
- package/dist/features/owned-ui/reference-screen-app.d.ts +2 -0
- package/dist/features/owned-ui/reference-screen-app.js +12 -5
- package/dist/features/owned-ui/session-fork-prompt.d.ts +2 -1
- package/dist/features/owned-ui/session-fork-prompt.js +11 -5
- package/dist/features/owned-ui/settings-app.d.ts +1 -1
- package/dist/features/owned-ui/settings-app.js +20 -13
- package/dist/features/owned-ui/settings-model-dialog.js +3 -3
- package/dist/features/owned-ui/settings-spinner-preview.d.ts +9 -0
- package/dist/features/owned-ui/settings-spinner-preview.js +29 -0
- package/dist/features/session-naming/context.d.ts +17 -0
- package/dist/features/session-naming/context.js +39 -0
- package/dist/features/session-naming/controller.d.ts +1 -5
- package/dist/features/session-naming/controller.js +7 -4
- package/dist/features/session-naming/generate.d.ts +2 -1
- package/dist/features/session-naming/generate.js +14 -10
- package/dist/features/session-naming/index.d.ts +1 -1
- package/dist/foundation/lifecycle/index.d.ts +3 -1
- package/dist/foundation/lifecycle/index.js +3 -1
- package/dist/foundation/lifecycle/session-claim-lock.d.ts +2 -2
- package/dist/foundation/lifecycle/session-claim-lock.js +36 -10
- package/dist/foundation/lifecycle/session-context-retry.d.ts +2 -0
- package/dist/foundation/lifecycle/session-context-retry.js +17 -0
- package/dist/foundation/lifecycle/session-repository-context.d.ts +7 -1
- package/dist/foundation/lifecycle/session-repository-context.js +105 -39
- package/dist/foundation/lifecycle/session-worktree-entry.d.ts +3 -0
- package/dist/foundation/lifecycle/session-worktree-entry.js +87 -0
- package/dist/foundation/release/automatic-update.js +2 -2
- package/dist/foundation/release/bootstrap.js +19 -3
- package/dist/foundation/release/release-gc.js +20 -5
- package/dist/foundation/release/release-state.d.ts +12 -3
- package/dist/foundation/release/release-state.js +55 -24
- package/dist/foundation/release/release-use.d.ts +10 -0
- package/dist/foundation/release/release-use.js +70 -0
- package/dist/foundation/release/update-activation.js +2 -2
- package/dist/foundation/release/update-recovery.js +2 -2
- package/dist/foundation/release/update.js +1 -1
- package/dist/foundation/release/warmup.js +8 -9
- package/dist/foundation/session-writer-lock/index.d.ts +2 -2
- package/dist/foundation/session-writer-lock/index.js +82 -12
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/foundation/terminal-cleanup/fatal-diagnostic.d.ts +2 -0
- package/dist/foundation/terminal-cleanup/fatal-diagnostic.js +59 -0
- package/dist/foundation/terminal-cleanup/fatal-exit.js +1 -29
- package/dist/integrations/pi/components/deferred-selector.d.ts +6 -0
- package/dist/integrations/pi/components/deferred-selector.js +40 -0
- package/dist/integrations/pi/components/login-dialog-loader.d.ts +3 -0
- package/dist/integrations/pi/components/login-dialog-loader.js +57 -0
- package/dist/integrations/pi/components/login-links.d.ts +6 -0
- package/dist/integrations/pi/components/login-links.js +31 -0
- package/dist/integrations/pi/components/login-text.d.ts +7 -0
- package/dist/integrations/pi/components/login-text.js +17 -0
- package/dist/integrations/pi/components/modal-frame.d.ts +5 -0
- package/dist/integrations/pi/components/modal-frame.js +30 -2
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
- package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
- package/dist/integrations/pi/components/share-operation-dialog.d.ts +2 -1
- package/dist/integrations/pi/components/share-operation-dialog.js +13 -5
- package/dist/integrations/pi/components/shell-footer-status.d.ts +2 -1
- package/dist/integrations/pi/components/shell-footer-status.js +15 -8
- package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +11 -8
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +36 -35
- package/dist/integrations/pi/components/shell-session-info-reference.d.ts +1 -1
- package/dist/integrations/pi/components/shell-session-info-reference.js +55 -49
- package/dist/integrations/pi/components/theme.d.ts +2 -0
- package/dist/integrations/pi/components/theme.js +4 -0
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
- package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
- package/dist/integrations/pi/components/upstream/components/auth-url.d.ts +16 -0
- package/dist/integrations/pi/components/upstream/components/auth-url.js +49 -0
- package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-input.js +1 -1
- package/dist/integrations/pi/components/upstream/components/extension-selector.d.ts +1 -0
- package/dist/integrations/pi/components/upstream/components/extension-selector.js +22 -11
- package/dist/integrations/pi/components/upstream/components/login-dialog.d.ts +3 -0
- package/dist/integrations/pi/components/upstream/components/login-dialog.js +216 -0
- package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
- package/dist/integrations/pi/components/upstream/components/oauth-selector.d.ts +19 -0
- package/dist/integrations/pi/components/upstream/components/oauth-selector.js +123 -0
- package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/owned-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
- package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/session-footer.js +22 -13
- package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
- package/dist/integrations/pi/components/upstream/components/session-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tool-execution.js +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/tree-selector.js +1 -1
- package/dist/integrations/pi/components/upstream/components/trust-selector.d.ts +2 -0
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +30 -13
- package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/editor-core.js +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
- package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
- package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
- package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
- package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
- package/dist/integrations/pi/engine/adapter.d.ts +3 -1
- package/dist/integrations/pi/engine/adapter.js +24 -6
- package/dist/integrations/pi/engine/changelog.js +5 -2
- package/dist/integrations/pi/engine/delivery-retention.d.ts +7 -0
- package/dist/integrations/pi/engine/delivery-retention.js +66 -0
- package/dist/integrations/pi/engine/event-delivery.d.ts +17 -1
- package/dist/integrations/pi/engine/event-delivery.js +25 -3
- package/dist/integrations/pi/engine/extension-ui-binding.d.ts +2 -1
- package/dist/integrations/pi/engine/extension-ui-binding.js +45 -0
- package/dist/integrations/pi/engine/host-ports.d.ts +2 -0
- package/dist/integrations/pi/engine/host.d.ts +3 -0
- package/dist/integrations/pi/engine/host.js +2 -0
- package/dist/integrations/pi/engine/package-integration.js +19 -4
- package/dist/integrations/pi/engine/pending-delivery.d.ts +4 -1
- package/dist/integrations/pi/engine/pending-delivery.js +51 -18
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/runtime-integration.d.ts +8 -0
- package/dist/integrations/pi/engine/runtime-integration.js +58 -9
- package/dist/integrations/pi/engine/session-cwd-recovery.d.ts +11 -0
- package/dist/integrations/pi/engine/session-cwd-recovery.js +18 -0
- package/dist/integrations/pi/engine/session-runtime.d.ts +3 -0
- package/dist/integrations/pi/engine/session-runtime.js +2 -0
- package/dist/integrations/pi/engine/session-selection.d.ts +3 -2
- package/dist/integrations/pi/engine/session-selection.js +25 -5
- package/dist/integrations/pi/engine/transcript-image-assets.d.ts +3 -0
- package/dist/integrations/pi/engine/transcript-image-assets.js +65 -14
- package/dist/integrations/pi/engine/view-state.d.ts +14 -0
- package/dist/integrations/pi/engine/view-state.js +17 -0
- package/dist/integrations/pi/engine/workflow-runner.d.ts +2 -0
- package/dist/integrations/pi/engine/workflow-runner.js +47 -26
- package/dist/integrations/pi/engine/worktree-tools.d.ts +4 -0
- package/dist/integrations/pi/engine/worktree-tools.js +26 -0
- package/dist/integrations/pi/session-presenters/components.d.ts +2 -1
- package/dist/integrations/pi/session-presenters/components.js +12 -10
- package/dist/integrations/pi/session-presenters/presenters.d.ts +3 -1
- package/dist/integrations/pi/session-presenters/presenters.js +2 -2
- package/dist/integrations/pi/startup-public.d.ts +1 -1
- package/dist/integrations/pi/startup-public.js +16 -20
- package/dist/integrations/pi/startup-public.manifest.json +29 -29
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +1 -1
- package/dist/product-identity.json +1 -1
- package/dist/runtime-payload-inventory.json +5027 -5027
- package/dist/ui/components/index.d.ts +1 -1
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/list-block.d.ts +2 -2
- package/dist/ui/components/list-block.js +4 -3
- package/dist/ui/components/progress-status.d.ts +7 -0
- package/dist/ui/components/progress-status.js +21 -0
- package/dist/ui/components/value-menu.d.ts +1 -1
- package/dist/ui/components/value-menu.js +4 -2
- package/dist/ui/settings/declarations.d.ts +16 -4
- package/dist/ui/settings/declarations.js +13 -4
- package/dist/ui/settings/early-accent.d.ts +24 -0
- package/docs/architecture/internal-naming.md +1 -1
- package/docs/architecture/project-structure.md +7 -11
- package/docs/features/session-exports.md +1 -1
- package/docs/features/session-naming.md +8 -6
- package/docs/features/worktrees.md +38 -0
- package/docs/local-worktree-cleanup.md +27 -4
- package/docs/openspec-archive-automation.md +30 -4
- package/docs/worktree-link-recovery.md +2 -2
- package/package.json +5 -5
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, readdir, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
/** Loaded only on a failure; persistence must never impede terminal restoration. */
|
|
5
|
+
export async function writeFatalDiagnostic(directory, origin, error, releaseId) {
|
|
6
|
+
try {
|
|
7
|
+
// Security: only known classifications and code locations are retained, never private messages or objects.
|
|
8
|
+
const cleanupFailed = error instanceof AggregateError && error.cause instanceof Error;
|
|
9
|
+
const primary = cleanupFailed ? error.cause : error;
|
|
10
|
+
const classification = primary instanceof TypeError ? "TypeError" : primary instanceof RangeError ? "RangeError" : "Error";
|
|
11
|
+
const stack = primary instanceof Error && typeof primary.stack === "string" ? primary.stack.slice(0, 32768) : "";
|
|
12
|
+
const locations = stack.split("\n").slice(1).flatMap(line => {
|
|
13
|
+
const match = /\/(?:dist|src)\/([a-zA-Z0-9_./-]+\.[cm]?[jt]s):(\d+):(\d+)\)?$/.exec(line.replaceAll("\\", "/"));
|
|
14
|
+
return match ? [{ file: match[1].slice(0, 160), line: Number(match[2]), column: Number(match[3]) }] : [];
|
|
15
|
+
}).slice(0, 16);
|
|
16
|
+
const delivery = deliveryFailure(primary);
|
|
17
|
+
const record = {
|
|
18
|
+
timestamp: new Date().toISOString(),
|
|
19
|
+
origin: ["uncaughtException", "unhandledRejection", "entry", "delivery"].includes(origin) ? origin : "entry",
|
|
20
|
+
...(delivery === null ? {} : { deliveryFailure: delivery }),
|
|
21
|
+
classification, cleanupFailed, locations, node: process.version, platform: process.platform,
|
|
22
|
+
releaseId: releaseId && /^[a-zA-Z0-9._-]{1,128}$/.test(releaseId) ? releaseId : "unknown",
|
|
23
|
+
};
|
|
24
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
25
|
+
const name = `${origin === "delivery" ? "delivery" : "fatal"}-${Date.now()}-${randomUUID()}.json`;
|
|
26
|
+
const path = join(directory, name);
|
|
27
|
+
const text = JSON.stringify(record, null, 2);
|
|
28
|
+
if (Buffer.byteLength(text) > 16 * 1024)
|
|
29
|
+
return null;
|
|
30
|
+
await writeFile(path, text, { flag: "wx", mode: 0o600 });
|
|
31
|
+
const names = (await readdir(directory)).filter(file => /^(?:fatal|delivery)-\d+-[a-f0-9-]+\.json$/.test(file))
|
|
32
|
+
.sort((a, b) => Number(b.split("-")[1]) - Number(a.split("-")[1]));
|
|
33
|
+
await Promise.all(names.slice(10).map(file => unlink(join(directory, file)).catch(() => undefined)));
|
|
34
|
+
return path;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function deliveryFailure(error) {
|
|
41
|
+
if (!(error instanceof Error) || !("deliveryFailure" in error))
|
|
42
|
+
return null;
|
|
43
|
+
const value = error.deliveryFailure;
|
|
44
|
+
if (!value || typeof value !== "object")
|
|
45
|
+
return null;
|
|
46
|
+
const record = value;
|
|
47
|
+
if (!["event-count", "retained-bytes", "listener"].includes(String(record.reason))
|
|
48
|
+
|| !["snapshot", "session-view", "transcript-block", "session-lifecycle", "status", "editor-state", "terminal-surface",
|
|
49
|
+
"agent-run-started", "agent-run-settled", "assistant-message-completed", "command-outcome", "diagnostic"].includes(String(record.event)))
|
|
50
|
+
return null;
|
|
51
|
+
const result = { reason: String(record.reason), event: String(record.event) };
|
|
52
|
+
for (const key of ["generation", "pending", "bytes"]) {
|
|
53
|
+
const number = record[key];
|
|
54
|
+
if (typeof number !== "number" || !Number.isSafeInteger(number) || number < 0)
|
|
55
|
+
return null;
|
|
56
|
+
result[key] = number;
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
@@ -1,36 +1,8 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { mkdir, readdir, unlink, writeFile } from "node:fs/promises";
|
|
3
1
|
import { writeSync } from "node:fs";
|
|
4
|
-
import { join } from "node:path";
|
|
5
2
|
import { boundedCleanup, restoreProcessTerminal } from "./terminal-reset.js";
|
|
6
3
|
export async function writeFatalDiagnostic(directory, origin, error, releaseId) {
|
|
7
4
|
try {
|
|
8
|
-
|
|
9
|
-
// function names, arbitrary paths, and request objects are never persisted.
|
|
10
|
-
const cleanupFailed = error instanceof AggregateError && error.cause instanceof Error;
|
|
11
|
-
const primary = cleanupFailed ? error.cause : error;
|
|
12
|
-
const classification = primary instanceof TypeError ? "TypeError" : primary instanceof RangeError ? "RangeError" : "Error";
|
|
13
|
-
const stack = primary instanceof Error && typeof primary.stack === "string" ? primary.stack.slice(0, 32768) : "";
|
|
14
|
-
const locations = stack.split("\n").slice(1).flatMap(line => {
|
|
15
|
-
const match = /\/(?:dist|src)\/([a-zA-Z0-9_./-]+\.[cm]?[jt]s):(\d+):(\d+)\)?$/.exec(line.replaceAll("\\", "/"));
|
|
16
|
-
return match ? [{ file: match[1].slice(0, 160), line: Number(match[2]), column: Number(match[3]) }] : [];
|
|
17
|
-
}).slice(0, 16);
|
|
18
|
-
const record = {
|
|
19
|
-
timestamp: new Date().toISOString(),
|
|
20
|
-
origin: ["uncaughtException", "unhandledRejection", "entry"].includes(origin) ? origin : "entry",
|
|
21
|
-
classification, cleanupFailed, locations, node: process.version, platform: process.platform,
|
|
22
|
-
releaseId: releaseId && /^[a-zA-Z0-9._-]{1,128}$/.test(releaseId) ? releaseId : "unknown",
|
|
23
|
-
};
|
|
24
|
-
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
25
|
-
const name = `fatal-${Date.now()}-${randomUUID()}.json`;
|
|
26
|
-
const path = join(directory, name);
|
|
27
|
-
const text = JSON.stringify(record, null, 2);
|
|
28
|
-
if (Buffer.byteLength(text) > 16 * 1024)
|
|
29
|
-
return null;
|
|
30
|
-
await writeFile(path, text, { flag: "wx", mode: 0o600 });
|
|
31
|
-
const names = (await readdir(directory)).filter(file => /^fatal-\d+-[a-f0-9-]+\.json$/.test(file)).sort().reverse();
|
|
32
|
-
await Promise.all(names.slice(10).map(file => unlink(join(directory, file)).catch(() => undefined)));
|
|
33
|
-
return path;
|
|
5
|
+
return await (await import("./fatal-diagnostic.js")).writeFatalDiagnostic(directory, origin, error, releaseId);
|
|
34
6
|
}
|
|
35
7
|
catch {
|
|
36
8
|
return null;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { PiShellSkillsSelectorOptions } from "./skills-dialog.js";
|
|
2
|
+
import type { OwnedUiShellComponentPort } from "../../../contracts/owned-ui/index.js";
|
|
3
|
+
/** Defers optional selector code while retaining focus, early input and cancellation. */
|
|
4
|
+
export declare function deferredSelector(load: () => Promise<OwnedUiShellComponentPort>, cancel: () => void): OwnedUiShellComponentPort;
|
|
5
|
+
/** Keeps Skills outside first-prompt loading. */
|
|
6
|
+
export declare function createPiShellSkillsSelector(options: PiShellSkillsSelectorOptions): OwnedUiShellComponentPort;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/** Defers optional selector code while retaining focus, early input and cancellation. */
|
|
2
|
+
export function deferredSelector(load, cancel) {
|
|
3
|
+
let delegate;
|
|
4
|
+
let closed = false;
|
|
5
|
+
let focused = false;
|
|
6
|
+
let failure;
|
|
7
|
+
const pending = [];
|
|
8
|
+
const ready = load().then(component => {
|
|
9
|
+
if (closed) {
|
|
10
|
+
component.dispose?.();
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
delegate = component;
|
|
14
|
+
delegate.setFocused?.(focused);
|
|
15
|
+
for (const key of pending.splice(0)) {
|
|
16
|
+
if (!closed)
|
|
17
|
+
delegate.handleInput?.(key);
|
|
18
|
+
}
|
|
19
|
+
}).catch(() => { if (!closed)
|
|
20
|
+
failure = "Selector unavailable — Esc close"; });
|
|
21
|
+
return {
|
|
22
|
+
ready,
|
|
23
|
+
render: width => delegate?.render(width) ?? (failure === undefined ? [] : [failure.slice(0, width)]),
|
|
24
|
+
invalidate: () => delegate?.invalidate(),
|
|
25
|
+
handleInput: data => {
|
|
26
|
+
if (delegate !== undefined)
|
|
27
|
+
delegate.handleInput?.(data);
|
|
28
|
+
else if (data === "\u001b" || data === "\u0003")
|
|
29
|
+
cancel();
|
|
30
|
+
else if (pending.length < 32)
|
|
31
|
+
pending.push(data);
|
|
32
|
+
},
|
|
33
|
+
setFocused: value => { focused = value; delegate?.setFocused?.(value); },
|
|
34
|
+
dispose: () => { closed = true; pending.length = 0; delegate?.dispose?.(); },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Keeps Skills outside first-prompt loading. */
|
|
38
|
+
export function createPiShellSkillsSelector(options) {
|
|
39
|
+
return deferredSelector(() => import("./skills-dialog.js").then(module => module.createPiShellSkillsSelector(options)), options.onCancel);
|
|
40
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { OwnedUiShellLoginDialogPort as Login } from "../../../contracts/owned-ui/index.js";
|
|
2
|
+
/** Queues optional login calls. */
|
|
3
|
+
export declare function deferredLoginDialog(...args: Parameters<typeof import("./upstream/components/login-dialog.js").createThemedLoginDialog>): Login;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/** Queues optional login calls. */
|
|
2
|
+
export function deferredLoginDialog(...args) {
|
|
3
|
+
const [runtime, , complete] = args;
|
|
4
|
+
let dialog, closed = false, focused = false, failed = false;
|
|
5
|
+
const pending = [];
|
|
6
|
+
const rejects = new Set();
|
|
7
|
+
const rejectAll = (message) => { for (const reject of rejects)
|
|
8
|
+
reject(new Error(message)); rejects.clear(); pending.length = 0; };
|
|
9
|
+
const ready = import("./upstream/components/login-dialog.js").then(module => {
|
|
10
|
+
if (closed)
|
|
11
|
+
return;
|
|
12
|
+
dialog = module.createThemedLoginDialog(...args);
|
|
13
|
+
dialog.setFocused?.(focused);
|
|
14
|
+
for (const action of pending.splice(0)) {
|
|
15
|
+
if (!closed)
|
|
16
|
+
action(dialog);
|
|
17
|
+
}
|
|
18
|
+
}).catch(() => { failed = true; rejectAll("Login unavailable"); }).finally(() => { if (!closed)
|
|
19
|
+
runtime.requestRender(); });
|
|
20
|
+
const call = (action) => { if (!closed && !failed) {
|
|
21
|
+
if (dialog)
|
|
22
|
+
action(dialog);
|
|
23
|
+
else
|
|
24
|
+
pending.push(action);
|
|
25
|
+
} };
|
|
26
|
+
const dispose = () => { closed = true; dialog?.dispose?.(); rejectAll("Login cancelled"); };
|
|
27
|
+
const answer = (action) => new Promise((resolve, reject) => {
|
|
28
|
+
if (closed || failed) {
|
|
29
|
+
reject(new Error("Login unavailable"));
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
rejects.add(reject);
|
|
33
|
+
call(target => { rejects.delete(reject); void action(target).then(resolve, reject); });
|
|
34
|
+
});
|
|
35
|
+
return {
|
|
36
|
+
ready, dispose,
|
|
37
|
+
render: width => dialog?.render(width) ?? (failed ? ["Login unavailable — Esc close".slice(0, width)] : []),
|
|
38
|
+
invalidate: () => dialog?.invalidate(),
|
|
39
|
+
setFocused: value => { focused = value; dialog?.setFocused?.(value); },
|
|
40
|
+
handleInput: data => {
|
|
41
|
+
if (!dialog && (data === "\u001b" || data === "\u0003")) {
|
|
42
|
+
dispose();
|
|
43
|
+
complete(false, "Login cancelled");
|
|
44
|
+
}
|
|
45
|
+
else
|
|
46
|
+
call(target => target.handleInput?.(data));
|
|
47
|
+
},
|
|
48
|
+
showAuth: (url, instructions) => call(target => target.showAuth(url, instructions)),
|
|
49
|
+
showDeviceCode: info => call(target => target.showDeviceCode(info)),
|
|
50
|
+
showManualInput: message => answer(target => target.showManualInput(message)),
|
|
51
|
+
showPrompt: (message, placeholder) => answer(target => target.showPrompt(message, placeholder)),
|
|
52
|
+
showDetails: lines => call(target => target.showDetails(lines)),
|
|
53
|
+
showInfo: (message, links) => call(target => target.showInfo(message, links)),
|
|
54
|
+
showWaiting: message => call(target => target.showWaiting(message)),
|
|
55
|
+
showProgress: message => call(target => target.showProgress(message)),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Login effects accept web URLs only; controls are encoded before any hyperlink or launcher sees them. */
|
|
2
|
+
export declare function loginWebUrl(value: string): string | undefined;
|
|
3
|
+
/** Keeps untrusted non-web instructions printable without granting them a hyperlink target. */
|
|
4
|
+
export declare function loginLink(value: string, label?: string): string;
|
|
5
|
+
/** Best-effort browser request with argv boundaries, no shell, and no dependency on the project cwd. */
|
|
6
|
+
export declare function openLoginBrowser(value: string): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { hyperlink, replaceControlCharacters } from "@earendil-works/pi-tui";
|
|
3
|
+
/** Login effects accept web URLs only; controls are encoded before any hyperlink or launcher sees them. */
|
|
4
|
+
export function loginWebUrl(value) {
|
|
5
|
+
try {
|
|
6
|
+
const url = new URL(value);
|
|
7
|
+
return ["http:", "https:"].includes(url.protocol) ? url.href : undefined;
|
|
8
|
+
}
|
|
9
|
+
catch {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** Keeps untrusted non-web instructions printable without granting them a hyperlink target. */
|
|
14
|
+
export function loginLink(value, label) {
|
|
15
|
+
const url = loginWebUrl(value);
|
|
16
|
+
const text = replaceControlCharacters(label ?? url ?? value);
|
|
17
|
+
return url === undefined ? text : hyperlink(text, url);
|
|
18
|
+
}
|
|
19
|
+
/** Best-effort browser request with argv boundaries, no shell, and no dependency on the project cwd. */
|
|
20
|
+
export function openLoginBrowser(value) {
|
|
21
|
+
const url = loginWebUrl(value);
|
|
22
|
+
if (url === undefined)
|
|
23
|
+
return;
|
|
24
|
+
const platform = process.platform;
|
|
25
|
+
const executable = platform === "win32" ? "rundll32" : platform === "darwin" ? "open" : "xdg-open";
|
|
26
|
+
const args = platform === "win32" ? ["url.dll,FileProtocolHandler", url] : [url];
|
|
27
|
+
try {
|
|
28
|
+
spawn(executable, args, { stdio: "ignore", detached: true, cwd: "/" }).on("error", () => { }).unref();
|
|
29
|
+
}
|
|
30
|
+
catch { /* Compatibility: a failed browser launch never interrupts provider authentication. */ }
|
|
31
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Component } from "@earendil-works/pi-tui";
|
|
2
|
+
type LoginTextRole = "accent" | "muted" | "warning" | "success" | "error" | "dim" | "text";
|
|
3
|
+
/** Preserves authored line breaks without replaying control payloads. */
|
|
4
|
+
export declare function loginPlainText(value: string): string;
|
|
5
|
+
/** A zero-inset login row that resolves its semantic role against the live theme on every frame. */
|
|
6
|
+
export declare function loginText(text: string | (() => string), role?: LoginTextRole, bold?: boolean): Component;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Text, replaceControlCharacters } from "@earendil-works/pi-tui";
|
|
2
|
+
import { piTheme } from "./theme.js";
|
|
3
|
+
/** Preserves authored line breaks without replaying control payloads. */
|
|
4
|
+
export function loginPlainText(value) {
|
|
5
|
+
return value.split("\n").map(line => replaceControlCharacters(line)).join("\n");
|
|
6
|
+
}
|
|
7
|
+
/** A zero-inset login row that resolves its semantic role against the live theme on every frame. */
|
|
8
|
+
export function loginText(text, role = "muted", bold = false) {
|
|
9
|
+
return {
|
|
10
|
+
render(width) {
|
|
11
|
+
const theme = piTheme();
|
|
12
|
+
const value = typeof text === "string" ? loginPlainText(text) : text();
|
|
13
|
+
return new Text(theme.fg(role, bold ? theme.bold(value) : value), 0, 0).render(width);
|
|
14
|
+
},
|
|
15
|
+
invalidate() { },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Container, Input, type Component, type Focusable } from "@earendil-works/pi-tui";
|
|
2
|
+
import type { OwnedUiShellComponentPort } from "../../../contracts/owned-ui/index.js";
|
|
2
3
|
export declare const PI_MODAL_CONTENT_PADDING_X = 1;
|
|
4
|
+
/** Applies standard primary/metadata roles without changing a pinned row's text or clipping. */
|
|
5
|
+
export declare function renderPiModalSelectedPrimary(row: string, width: number, labels: readonly string[]): string;
|
|
6
|
+
/** Standardizes internal legacy model/message choices without changing their controller or metadata. */
|
|
7
|
+
export declare function standardInternalChoicePort(port: OwnedUiShellComponentPort, metadata?: boolean): OwnedUiShellComponentPort;
|
|
3
8
|
/** Paints the standard Pi Input prompt as a live-themed dialog-search marker. */
|
|
4
9
|
export declare function renderPiModalSearchInput(input: Input, width: number): string[];
|
|
5
10
|
/** Replaces one explicitly identified direct Input child with the standard search presentation. */
|
|
@@ -1,7 +1,35 @@
|
|
|
1
|
-
import { Container, Input, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
1
|
+
import { Container, Input, Spacer, Text, sliceByColumn, stripTerminalSequences, visibleWidth, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { DIALOG_CONTENT_PADDING_X, dialogFrameGeometry, insetDialogContent } from "../../../contracts/presentation/index.js";
|
|
3
|
-
import { DIALOG_CLOSE_SHORTCUT_HINT, piTheme, renderPiModalShortcutHints } from "./theme.js";
|
|
3
|
+
import { DIALOG_CLOSE_SHORTCUT_HINT, piTheme, renderPiModalShortcutHints, renderPiModalListRow } from "./theme.js";
|
|
4
4
|
export const PI_MODAL_CONTENT_PADDING_X = DIALOG_CONTENT_PADDING_X;
|
|
5
|
+
/** Applies standard primary/metadata roles without changing a pinned row's text or clipping. */
|
|
6
|
+
export function renderPiModalSelectedPrimary(row, width, labels) {
|
|
7
|
+
const plain = stripTerminalSequences(row).trimEnd();
|
|
8
|
+
if (!plain.startsWith(" → "))
|
|
9
|
+
return row;
|
|
10
|
+
const primary = labels.filter(label => plain.slice(3).startsWith(label))
|
|
11
|
+
.sort((left, right) => visibleWidth(right) - visibleWidth(left))[0];
|
|
12
|
+
const length = primary === undefined ? Math.max(0, visibleWidth(plain) - 3) : visibleWidth(primary);
|
|
13
|
+
const label = stripTerminalSequences(sliceByColumn(row, 3, length));
|
|
14
|
+
const suffix = sliceByColumn(row, 3 + length, Math.max(0, visibleWidth(plain) - 3 - length));
|
|
15
|
+
const theme = piTheme();
|
|
16
|
+
return ` ${renderPiModalListRow(`${theme.fg("accent", "→ ")}${theme.fg("text", label)}${theme.fg("muted", stripTerminalSequences(suffix))}`, Math.max(0, width - 1), true)}`;
|
|
17
|
+
}
|
|
18
|
+
/** Standardizes internal legacy model/message choices without changing their controller or metadata. */
|
|
19
|
+
export function standardInternalChoicePort(port, metadata = false) {
|
|
20
|
+
return { ...port, render: width => port.render(width).map(row => {
|
|
21
|
+
const match = /^(\s*)[→›] (.*)$/u.exec(stripTerminalSequences(row).trimEnd());
|
|
22
|
+
if (match === null)
|
|
23
|
+
return row;
|
|
24
|
+
const indent = visibleWidth(match[1]);
|
|
25
|
+
const marker = metadata ? sliceByColumn(row, indent + 2, 2) : "";
|
|
26
|
+
const label = metadata ? match[2].slice(2).split(/ \[| \(/u, 1)[0] : match[2];
|
|
27
|
+
const suffixStart = indent + 2 + (metadata ? 2 : 0) + visibleWidth(label);
|
|
28
|
+
const suffix = metadata ? sliceByColumn(row, suffixStart, Math.max(0, visibleWidth(row) - suffixStart)).trimEnd() : "";
|
|
29
|
+
const theme = piTheme();
|
|
30
|
+
return `${match[1]}${renderPiModalListRow(`${theme.fg("accent", "→ ")}${marker}${theme.fg("text", label)}${suffix}`, Math.max(0, width - indent), true)}`;
|
|
31
|
+
}) };
|
|
32
|
+
}
|
|
5
33
|
/** Paints the standard Pi Input prompt as a live-themed dialog-search marker. */
|
|
6
34
|
export function renderPiModalSearchInput(input, width) {
|
|
7
35
|
return input.render(width).map(row => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Attributed owned theme resources adapted from @earendil-works/pi-coding-agent 1.5.
|
|
3
|
-
* commit
|
|
2
|
+
* Attributed owned theme resources adapted from @earendil-works/pi-coding-agent 1.5.2 (MIT),
|
|
3
|
+
* commit b4afdddf44e059c67ccf5097e5317d913521b470.
|
|
4
4
|
* Upstream dark.json SHA-256: e1f96982f8cb7d2a48eca7db03c9cb282cb1e14a243680cd855638ecd6a251b6
|
|
5
5
|
* Upstream light.json SHA-256: 2dee6a4be7f765e7fd7728166b7ebf8c29e4ce313f8ec6b38ae50699e3abc2f3
|
|
6
6
|
* Modifications: removed upstream schema/export metadata; runtime color data is unchanged.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Attributed owned theme resources adapted from @earendil-works/pi-coding-agent 1.5.
|
|
3
|
-
* commit
|
|
2
|
+
* Attributed owned theme resources adapted from @earendil-works/pi-coding-agent 1.5.2 (MIT),
|
|
3
|
+
* commit b4afdddf44e059c67ccf5097e5317d913521b470.
|
|
4
4
|
* Upstream dark.json SHA-256: e1f96982f8cb7d2a48eca7db03c9cb282cb1e14a243680cd855638ecd6a251b6
|
|
5
5
|
* Upstream light.json SHA-256: 2dee6a4be7f765e7fd7728166b7ebf8c29e4ce313f8ec6b38ae50699e3abc2f3
|
|
6
6
|
* Modifications: removed upstream schema/export metadata; runtime color data is unchanged.
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type { ProgressSpinnerSource } from "../../../contracts/presentation/index.js";
|
|
1
2
|
import { type PiShellComponentPort, type PiShellEditorOptions } from "./shell-shared-facade.js";
|
|
2
3
|
export interface PiShellOperationLoaderPort extends PiShellComponentPort {
|
|
3
4
|
readonly signal: AbortSignal;
|
|
4
5
|
/** Relabels the running operation; the pinned comparison loader keeps its first label. */
|
|
5
6
|
readonly setMessage?: (message: string) => void;
|
|
6
7
|
}
|
|
7
|
-
export declare function createPiShellShareOperationDialog(runtime: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">, message: string): PiShellOperationLoaderPort;
|
|
8
|
+
export declare function createPiShellShareOperationDialog(runtime: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">, message: string, spinner?: ProgressSpinnerSource): PiShellOperationLoaderPort;
|
|
8
9
|
export declare function createPiShellOperationLoader(runtime: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">, message: string): PiShellOperationLoaderPort;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CancellableLoader, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
2
2
|
import { BorderedLoader, DynamicBorder } from "../startup-public.js";
|
|
3
|
+
import { progressSpinnerFrame } from "../../../ui/components/index.js";
|
|
3
4
|
import { adoptPiModalFrame, PiModalFrame } from "./modal-frame.js";
|
|
4
5
|
import { DIALOG_CLOSE_SHORTCUT_HINT, paintPiBorder, piTheme, renderPiModalShortcutHints } from "./theme.js";
|
|
5
6
|
import { componentPort, createTuiFacade, ensureTheme, } from "./shell-shared-facade.js";
|
|
@@ -7,26 +8,33 @@ import { componentPort, createTuiFacade, ensureTheme, } from "./shell-shared-fac
|
|
|
7
8
|
class ShareOperationDialog {
|
|
8
9
|
#loader;
|
|
9
10
|
#frame;
|
|
10
|
-
|
|
11
|
+
#releaseSpinner;
|
|
12
|
+
constructor(runtime, message, spinner) {
|
|
11
13
|
const theme = piTheme();
|
|
12
|
-
|
|
14
|
+
let phase = -1;
|
|
15
|
+
this.#loader = new CancellableLoader(createTuiFacade(runtime), currentFrame => {
|
|
16
|
+
phase += 1;
|
|
17
|
+
const glyph = progressSpinnerFrame(spinner?.snapshot() ?? "current", phase, currentFrame);
|
|
18
|
+
return glyph === "" ? "" : piTheme().fg("accent", glyph);
|
|
19
|
+
}, text => piTheme().fg("muted", text), message);
|
|
13
20
|
this.#frame = new PiModalFrame(new DynamicBorder(paintPiBorder), [
|
|
14
21
|
new Text(theme.fg("accent", theme.bold("Share")), 0, 0),
|
|
15
22
|
this.#loader,
|
|
16
23
|
new Spacer(1),
|
|
17
24
|
new Text(renderPiModalShortcutHints([DIALOG_CLOSE_SHORTCUT_HINT]), 0, 0),
|
|
18
25
|
], new DynamicBorder(paintPiBorder));
|
|
26
|
+
this.#releaseSpinner = spinner?.onChange(() => this.#loader.invalidate());
|
|
19
27
|
}
|
|
20
28
|
get signal() { return this.#loader.signal; }
|
|
21
29
|
setMessage(message) { this.#loader.setMessage(message); }
|
|
22
30
|
invalidate() { this.#frame.invalidate(); }
|
|
23
31
|
render(width) { return this.#frame.render(width); }
|
|
24
32
|
handleInput(data) { this.#loader.handleInput(data); }
|
|
25
|
-
dispose() { this.#loader.dispose(); }
|
|
33
|
+
dispose() { this.#releaseSpinner?.(); this.#loader.dispose(); }
|
|
26
34
|
}
|
|
27
|
-
export function createPiShellShareOperationDialog(runtime, message) {
|
|
35
|
+
export function createPiShellShareOperationDialog(runtime, message, spinner) {
|
|
28
36
|
ensureTheme();
|
|
29
|
-
const dialog = new ShareOperationDialog(runtime, message);
|
|
37
|
+
const dialog = new ShareOperationDialog(runtime, message, spinner);
|
|
30
38
|
return { ...componentPort(dialog), signal: dialog.signal, setMessage: message => dialog.setMessage(message) };
|
|
31
39
|
}
|
|
32
40
|
export function createPiShellOperationLoader(runtime, message) {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { OwnedUiShellKeybindings } from "../../../contracts/owned-ui/index.js";
|
|
2
|
+
import type { ProgressSpinnerSource } from "../../../contracts/presentation/index.js";
|
|
2
3
|
import type { OwnedUiSessionViewModel } from "../../../contracts/owned-ui/index.js";
|
|
3
4
|
import { type PiShellViewComponentPort, type PiShellStatusPort, type PiShellProgressStatusPresentation, type PiShellQueuedInputPort, type PiShellHeaderPort, type PiShellResourceEntry, type PiShellLoadedResourcesPort, type PiShellHeaderOptions, type PiShellEditorOptions } from "./shell-shared-facade.js";
|
|
4
5
|
export declare function createPiShellHeader(options?: PiShellHeaderOptions): PiShellHeaderPort;
|
|
5
6
|
export declare function createPiShellLoadedResources(resources: readonly PiShellResourceEntry[], initialExpanded?: boolean): PiShellLoadedResourcesPort;
|
|
6
|
-
export declare function createPiShellStatus(view: OwnedUiSessionViewModel, progressStatus: PiShellProgressStatusPresentation, runtime?: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender"
|
|
7
|
+
export declare function createPiShellStatus(view: OwnedUiSessionViewModel, progressStatus: PiShellProgressStatusPresentation, runtime?: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">, spinner?: ProgressSpinnerSource): PiShellStatusPort;
|
|
7
8
|
export declare function createPiShellFooter(view: OwnedUiSessionViewModel, cwd: string, profile?: "pi" | "a1", showLevel?: () => boolean): PiShellViewComponentPort;
|
|
8
9
|
export declare function createPiQueuedInputStatus(submissions: readonly string[], presentation?: "pinned" | "custom-viewport", getKeybindings?: () => OwnedUiShellKeybindings): PiShellQueuedInputPort;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { progressSpinnerFrame } from "../../../ui/components/progress-status.js";
|
|
1
2
|
import { piKeybindings } from "./shell-shared-facade.js";
|
|
2
3
|
import { rawKeyHint, VERSION } from "../startup-public.js";
|
|
3
4
|
import { Spacer, Text, } from "@earendil-works/pi-tui";
|
|
@@ -74,7 +75,7 @@ export function createPiShellLoadedResources(resources, initialExpanded = false)
|
|
|
74
75
|
invalidate() { },
|
|
75
76
|
};
|
|
76
77
|
}
|
|
77
|
-
export function createPiShellStatus(view, progressStatus, runtime) {
|
|
78
|
+
export function createPiShellStatus(view, progressStatus, runtime, spinner) {
|
|
78
79
|
ensureTheme();
|
|
79
80
|
const statusUi = createTuiFacade(runtime ?? { getColumns: () => 80, getRows: () => 24, requestRender() { } });
|
|
80
81
|
let workingOverride;
|
|
@@ -83,7 +84,7 @@ export function createPiShellStatus(view, progressStatus, runtime) {
|
|
|
83
84
|
let progressPresentation = "pinned";
|
|
84
85
|
let placement = statusPlacement(view, workingOverride, workingOverrideActive);
|
|
85
86
|
const liveStatusText = () => progressStatus.text(liveWorkingText(view, workingOverride, progressPresentation), progressPresentation);
|
|
86
|
-
let component = statusComponent(view, statusUi, outputPad, liveStatusText, placement, progressPresentation, progressStatus);
|
|
87
|
+
let component = statusComponent(view, statusUi, outputPad, liveStatusText, placement, progressPresentation, progressStatus, spinner);
|
|
87
88
|
let signature = statusSignature(view, workingOverride, outputPad, placement, progressPresentation);
|
|
88
89
|
const rebuild = () => {
|
|
89
90
|
const nextPlacement = statusPlacement(view, workingOverride, workingOverrideActive);
|
|
@@ -105,8 +106,12 @@ export function createPiShellStatus(view, progressStatus, runtime) {
|
|
|
105
106
|
component.dispose();
|
|
106
107
|
placement = nextPlacement;
|
|
107
108
|
signature = nextSignature;
|
|
108
|
-
component = statusComponent(view, statusUi, outputPad, liveStatusText, placement, progressPresentation, progressStatus);
|
|
109
|
+
component = statusComponent(view, statusUi, outputPad, liveStatusText, placement, progressPresentation, progressStatus, spinner);
|
|
109
110
|
};
|
|
111
|
+
const releaseSpinner = spinner?.onChange(() => {
|
|
112
|
+
if (progressPresentation === "custom-viewport")
|
|
113
|
+
component?.invalidate();
|
|
114
|
+
});
|
|
110
115
|
return {
|
|
111
116
|
render: width => appendInstalledUpdateStatus(component?.render(width) ?? [], width, view, progressPresentation),
|
|
112
117
|
renderDock: width => placement === "dock" ? component?.render(width) ?? [] : [],
|
|
@@ -131,6 +136,7 @@ export function createPiShellStatus(view, progressStatus, runtime) {
|
|
|
131
136
|
rebuild();
|
|
132
137
|
},
|
|
133
138
|
dispose() {
|
|
139
|
+
releaseSpinner?.();
|
|
134
140
|
if (component !== undefined && "dispose" in component && typeof component.dispose === "function")
|
|
135
141
|
component.dispose();
|
|
136
142
|
component = undefined;
|
|
@@ -201,21 +207,22 @@ function liveWorkingText(view, workingOverride, progressPresentation) {
|
|
|
201
207
|
: message;
|
|
202
208
|
}
|
|
203
209
|
class OwnedWorkingStatusIndicator extends StatusIndicator {
|
|
204
|
-
constructor(ui, message, frame) {
|
|
210
|
+
constructor(ui, message, frame, spinner) {
|
|
205
211
|
let phase = -1;
|
|
206
|
-
super("working", ui,
|
|
212
|
+
super("working", ui, defaultFrame => {
|
|
207
213
|
phase += 1;
|
|
208
|
-
|
|
214
|
+
const glyph = progressSpinnerFrame(spinner?.snapshot() ?? "current", phase, defaultFrame);
|
|
215
|
+
return glyph === "" ? "" : piTheme().fg("accent", glyph);
|
|
209
216
|
}, text => frame(text, phase, {
|
|
210
217
|
muted: value => piTheme().fg("muted", value),
|
|
211
218
|
highlight: value => piTheme().fg("text", value),
|
|
212
219
|
}), message);
|
|
213
220
|
}
|
|
214
221
|
}
|
|
215
|
-
function statusComponent(view, ui, outputPad, liveStatusText, placement, progressPresentation, progressStatus) {
|
|
222
|
+
function statusComponent(view, ui, outputPad, liveStatusText, placement, progressPresentation, progressStatus, spinner) {
|
|
216
223
|
if (placement === "live") {
|
|
217
224
|
return progressPresentation === "custom-viewport"
|
|
218
|
-
? new OwnedWorkingStatusIndicator(ui, liveStatusText(), progressStatus.frame)
|
|
225
|
+
? new OwnedWorkingStatusIndicator(ui, liveStatusText(), progressStatus.frame, spinner)
|
|
219
226
|
: new WorkingStatusIndicator(ui, liveStatusText());
|
|
220
227
|
}
|
|
221
228
|
if (placement === "dock") {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { ModelSelectorComponent, type SessionInfo, type SettingsCallbacks, type SettingsConfig } from "../startup-public.js";
|
|
2
2
|
import type { OwnedUiDialog } from "../../../contracts/owned-ui/index.js";
|
|
3
3
|
import type { ModelsDialogCallbacks, ModelsDialogConfig } from "./models-dialog.js";
|
|
4
|
-
import {
|
|
4
|
+
import type { TrustDecision, TrustOption, TrustUpdate } from "./upstream/components/trust-selector.js";
|
|
5
5
|
import { type PiShellComponentPort, type PiShellEditorOptions, type PiShellSelectorOption, type PiShellSelectorOptions } from "./shell-shared-facade.js";
|
|
6
|
-
export { createPiShellSkillsSelector
|
|
7
|
-
export
|
|
6
|
+
export { createPiShellSkillsSelector } from "./deferred-selector.js";
|
|
7
|
+
export type { PiShellSkillsSelectorOptions } from "./skills-dialog.js";
|
|
8
|
+
export declare function createPiShellSelector(options: PiShellSelectorOptions, standard?: boolean): PiShellComponentPort;
|
|
8
9
|
export interface PiShellSettingsSelectorOptions {
|
|
9
10
|
readonly config: SettingsConfig;
|
|
10
11
|
readonly onChange: (callback: keyof SettingsCallbacks, value: unknown) => void;
|
|
@@ -13,6 +14,7 @@ export interface PiShellSettingsSelectorOptions {
|
|
|
13
14
|
export declare function createPiShellSettingsSelector(options: PiShellSettingsSelectorOptions): PiShellComponentPort;
|
|
14
15
|
type PiModelSelectorArguments = ConstructorParameters<typeof ModelSelectorComponent>;
|
|
15
16
|
export interface PiShellModelSelectorOptions {
|
|
17
|
+
readonly standardStyle?: boolean;
|
|
16
18
|
readonly currentModel: unknown;
|
|
17
19
|
readonly modelRuntime: unknown;
|
|
18
20
|
readonly scopedModels: readonly unknown[];
|
|
@@ -58,6 +60,7 @@ export interface PiShellModelsDialogPort extends PiShellComponentPort {
|
|
|
58
60
|
/** The bare-A1 unified Models dialog behind the owned component boundary; the pinned selectors above stay for `a1 pi`. */
|
|
59
61
|
export declare function createPiShellModelsDialog(options: PiShellModelsDialogOptions): PiShellModelsDialogPort;
|
|
60
62
|
export declare function createPiShellTrustSelector(options: {
|
|
63
|
+
readonly standardStyle?: boolean;
|
|
61
64
|
readonly cwd: string;
|
|
62
65
|
readonly savedDecision: TrustDecision | null;
|
|
63
66
|
readonly projectTrusted: boolean;
|
|
@@ -91,7 +94,7 @@ export declare function createPiShellTreeSelector(options: {
|
|
|
91
94
|
readonly initialSelectedId?: string;
|
|
92
95
|
readonly initialFilterMode?: "default" | "no-tools" | "user-only" | "labeled-only" | "all";
|
|
93
96
|
}): Promise<PiShellComponentPort>;
|
|
94
|
-
export declare function createPiShellUserMessageSelector(messages: readonly PiShellSelectorOption[], onSelect: (id: string) => void, onCancel: () => void, initialSelectedId?: string): PiShellComponentPort;
|
|
97
|
+
export declare function createPiShellUserMessageSelector(messages: readonly PiShellSelectorOption[], onSelect: (id: string) => void, onCancel: () => void, initialSelectedId?: string, standard?: boolean): PiShellComponentPort;
|
|
95
98
|
export interface PiShellLoginDialogPort extends PiShellComponentPort {
|
|
96
99
|
showAuth(url: string, instructions?: string): void;
|
|
97
100
|
showDeviceCode(info: {
|
|
@@ -108,7 +111,7 @@ export interface PiShellLoginDialogPort extends PiShellComponentPort {
|
|
|
108
111
|
showWaiting(message: string): void;
|
|
109
112
|
showProgress(message: string): void;
|
|
110
113
|
}
|
|
111
|
-
export declare function createPiShellLoginDialog(runtime: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">, providerId: string, onComplete: (success: boolean, message?: string) => void, providerName?: string, title?: string): PiShellLoginDialogPort;
|
|
114
|
+
export declare function createPiShellLoginDialog(runtime: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">, providerId: string, onComplete: (success: boolean, message?: string) => void, providerName?: string, title?: string, standard?: boolean): PiShellLoginDialogPort;
|
|
112
115
|
export declare function createPiShellArmin(runtime: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">): PiShellComponentPort;
|
|
113
116
|
export declare function createPiShellEarendilAnnouncement(): PiShellComponentPort;
|
|
114
117
|
export declare function createPiShellReloadBox(): PiShellComponentPort;
|
|
@@ -120,11 +123,11 @@ export interface PiShellAuthProviderOption extends PiShellSelectorOption {
|
|
|
120
123
|
readonly source?: string;
|
|
121
124
|
};
|
|
122
125
|
}
|
|
123
|
-
export declare function createPiShellAuthProviderSelector(mode: "login" | "logout", providers: readonly PiShellAuthProviderOption[], onSelect: (id: string) => void, onCancel: () => void, initialSearchInput?: string): PiShellComponentPort;
|
|
124
|
-
export declare function createPiShellExtensionSelector(title: string, options: readonly string[], onSelect: (value: string) => void, onCancel: () => void): PiShellComponentPort;
|
|
126
|
+
export declare function createPiShellAuthProviderSelector(mode: "login" | "logout", providers: readonly PiShellAuthProviderOption[], onSelect: (id: string) => void, onCancel: () => void, initialSearchInput?: string, standardStyle?: boolean): PiShellComponentPort;
|
|
127
|
+
export declare function createPiShellExtensionSelector(title: string, options: readonly string[], onSelect: (value: string) => void, onCancel: () => void, standardSelection?: boolean): PiShellComponentPort;
|
|
125
128
|
export declare function createPiShellThemeSelector(currentTheme: string, onSelect: (theme: string) => void, onCancel: () => void, onPreview: (theme: string) => void): PiShellComponentPort;
|
|
126
129
|
export declare function createPiShellShowImagesSelector(currentValue: boolean, onSelect: (show: boolean) => void, onCancel: () => void): PiShellComponentPort;
|
|
127
130
|
export declare function createPiShellDialog(dialog: OwnedUiDialog, handlers?: {
|
|
128
131
|
readonly onSelect?: (id: string) => void;
|
|
129
132
|
readonly onCancel?: () => void;
|
|
130
|
-
}): PiShellComponentPort;
|
|
133
|
+
}, standard?: boolean): PiShellComponentPort;
|