@timurproko/a1 0.1.8-dev.528 → 0.1.8-dev.544
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/bin/update-recovery.js +25 -3
- package/dist/app/session-shell/session-shell-root.d.ts +1 -0
- package/dist/app/session-shell/session-shell-root.js +3 -1
- package/dist/app/session-shell/session-shell.d.ts +1 -1
- package/dist/app/session-shell/session-shell.js +10 -4
- package/dist/composition/owned-ui.js +4 -3
- package/dist/composition/settings-route-host.d.ts +5 -9
- package/dist/composition/settings-route-host.js +2 -2
- package/dist/contracts/owned-ui/model.d.ts +4 -0
- package/dist/contracts/owned-ui/validation.js +25 -0
- package/dist/features/owned-ui/index.d.ts +1 -1
- package/dist/features/owned-ui/reference-screen-app.d.ts +9 -3
- package/dist/features/owned-ui/reference-screen-app.js +68 -20
- package/dist/features/owned-ui/settings-app.js +69 -24
- package/dist/foundation/release/index.d.ts +2 -2
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/update-recovery.d.ts +7 -1
- package/dist/foundation/release/update-recovery.js +39 -9
- package/dist/foundation/release/update.d.ts +7 -0
- package/dist/foundation/release/update.js +115 -24
- package/dist/foundation/startup/startup-descriptor.js +2 -2
- package/dist/integrations/pi/components/index.d.ts +3 -1
- package/dist/integrations/pi/components/index.js +2 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.d.ts +9 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.js +10 -9
- package/dist/integrations/pi/components/shell-footer-status.d.ts +1 -1
- package/dist/integrations/pi/components/shell-footer-status.js +2 -2
- package/dist/integrations/pi/components/shell-hotkey-sections.d.ts +7 -0
- package/dist/integrations/pi/components/shell-hotkey-sections.js +29 -0
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +1 -0
- package/dist/integrations/pi/components/shell-presenters-info.js +1 -1
- package/dist/integrations/pi/components/shell-selectors-dialogs.d.ts +0 -1
- package/dist/integrations/pi/components/shell-selectors-dialogs.js +1 -7
- package/dist/integrations/pi/components/thinking-selector-dialog.d.ts +8 -0
- package/dist/integrations/pi/components/thinking-selector-dialog.js +22 -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/countdown-timer.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/daxnuts.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/daxnuts.js +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 +2 -1
- package/dist/integrations/pi/components/upstream/components/extension-editor.js +7 -2
- package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
- 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/scoped-models-selector.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/components/session-footer.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/components/session-footer.js +22 -11
- 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/thinking-selector.d.ts +33 -0
- package/dist/integrations/pi/components/upstream/components/thinking-selector.js +140 -0
- 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 +8 -1
- package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
- 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/theme/theme-controller.d.ts +1 -1
- package/dist/integrations/pi/components/upstream/theme/theme.js +1 -1
- package/dist/integrations/pi/engine/adapter.js +1 -0
- package/dist/integrations/pi/engine/repository-pr.d.ts +8 -0
- package/dist/integrations/pi/engine/repository-pr.js +62 -0
- package/dist/integrations/pi/engine/resources/changelog.json +4 -4
- package/dist/integrations/pi/engine/session-runtime.d.ts +5 -0
- package/dist/integrations/pi/engine/session-runtime.js +60 -1
- package/dist/integrations/pi/engine/workflow-support.js +3 -1
- package/dist/integrations/pi/engine/workflows.d.ts +1 -1
- package/dist/integrations/pi/engine/workflows.js +4 -2
- package/dist/integrations/pi/startup-public.js +63 -56
- package/dist/integrations/pi/startup-public.manifest.json +200 -169
- 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/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/product-identity.d.ts +1 -1
- package/dist/product-identity.js +1 -1
- package/dist/product-identity.json +1 -0
- package/dist/runtime-payload-inventory.json +2948 -2646
- package/dist/ui/components/index.d.ts +1 -1
- package/dist/ui/components/list-block.d.ts +10 -6
- package/dist/ui/components/list-block.js +28 -15
- package/dist/ui/components/list-view.d.ts +1 -1
- package/dist/ui/components/list-view.js +4 -2
- package/dist/ui/components/mouse.js +4 -2
- package/dist/ui/components/theme.d.ts +1 -5
- package/dist/ui/components/theme.js +0 -4
- package/dist/ui/components/value-menu.d.ts +3 -1
- package/dist/ui/components/value-menu.js +13 -5
- package/docs/local-worktree-cleanup.md +1 -1
- package/package.json +3 -3
|
@@ -21,11 +21,11 @@ export type { RestartSeal, RestartValidationEvent } from "./restart-certificatio
|
|
|
21
21
|
export { STABLE_RELEASE_SCHEMA, createStableReleaseEvidence, verifyStableRegistry } from "./stable-release.js";
|
|
22
22
|
export type { StableRegistryState, StableRegistryVerificationOptions, StableReleaseEvidence, StableReleaseEvidenceInput } from "./stable-release.js";
|
|
23
23
|
export { PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
|
|
24
|
-
export type { ProcessRequest, ProcessResult, SelfUpdateOptions, UpdateActivationPhase, UpdateChannel, UpdateFileSystem, UpdateLifecycleCoordinator, UpdateMaterializationProgress, UpdateMeasuredPhase, UpdateOutput, UpdateOwnershipAction, UpdatePackageReplacementInput, UpdatePerformanceEvidence, UpdatePhaseTimingEvent, UpdateProcessRunner, UpdateTransactionJournal, } from "./update.js";
|
|
24
|
+
export type { ProcessRequest, ProcessResult, SelfUpdateOptions, UpdateActivationPhase, UpdateChannel, UpdateFileMetadata, UpdateFileSystem, UpdateLifecycleCoordinator, UpdateMaterializationProgress, UpdateMeasuredPhase, UpdateOutput, UpdateOwnershipAction, UpdatePackageReplacementInput, UpdatePerformanceEvidence, UpdatePhaseTimingEvent, UpdateProcessRunner, UpdateTransactionJournal, } from "./update.js";
|
|
25
25
|
export { UPDATE_ACTIVATION_CONTRACT, UPDATE_ACTIVATION_ENTRY, UPDATE_ACTIVATION_MANIFEST_FIELD, activateInstalledRelease, delegateActivation, readActivationContracts, runActivationEntry, } from "./update-activation.js";
|
|
26
26
|
export type { UpdateActivationCallbacks, UpdateActivationEvent, UpdateActivationRequest } from "./update-activation.js";
|
|
27
27
|
export { selectSupervisorLaunchReleaseId, selectUpdateLaunchRelease } from "./update-launch.js";
|
|
28
|
-
export { UPDATE_RECOVERY_SCHEMA, cleanupUpdateRecoveryCapsules, inspectUpdateLauncherSet, prepareUpdateRecoveryCapsule, readUpdateRecoveryCapsule, removeUpdateRecoveryCapsule, runProtectedPackageReplacement, updateLauncherPaths, } from "./update-recovery.js";
|
|
28
|
+
export { UPDATE_RECOVERY_SCHEMA, cleanupUpdateRecoveryCapsules, inspectUpdateLauncherSet, npmPrefixForGlobalRoot, prepareUpdateRecoveryCapsule, readUpdateRecoveryCapsule, removeUpdateRecoveryCapsule, runProtectedPackageReplacement, updateLauncherPaths, updateNpmInstallArguments, } from "./update-recovery.js";
|
|
29
29
|
export type { ProtectedPackageReplacementOptions, ProtectedPackageReplacementResult, UpdateRecoveryCapsule, UpdateRecoveryResult } from "./update-recovery.js";
|
|
30
30
|
export { UPDATE_JOURNAL_SCHEMA, UpdateTransactionStore } from "./update-transaction.js";
|
|
31
31
|
export type { UpdateRecoveryState, UpdateTransaction, UpdateTransactionPhase } from "./update-transaction.js";
|
|
@@ -12,6 +12,6 @@ export { STABLE_RELEASE_SCHEMA, createStableReleaseEvidence, verifyStableRegistr
|
|
|
12
12
|
export { PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
|
|
13
13
|
export { UPDATE_ACTIVATION_CONTRACT, UPDATE_ACTIVATION_ENTRY, UPDATE_ACTIVATION_MANIFEST_FIELD, activateInstalledRelease, delegateActivation, readActivationContracts, runActivationEntry, } from "./update-activation.js";
|
|
14
14
|
export { selectSupervisorLaunchReleaseId, selectUpdateLaunchRelease } from "./update-launch.js";
|
|
15
|
-
export { UPDATE_RECOVERY_SCHEMA, cleanupUpdateRecoveryCapsules, inspectUpdateLauncherSet, prepareUpdateRecoveryCapsule, readUpdateRecoveryCapsule, removeUpdateRecoveryCapsule, runProtectedPackageReplacement, updateLauncherPaths, } from "./update-recovery.js";
|
|
15
|
+
export { UPDATE_RECOVERY_SCHEMA, cleanupUpdateRecoveryCapsules, inspectUpdateLauncherSet, npmPrefixForGlobalRoot, prepareUpdateRecoveryCapsule, readUpdateRecoveryCapsule, removeUpdateRecoveryCapsule, runProtectedPackageReplacement, updateLauncherPaths, updateNpmInstallArguments, } from "./update-recovery.js";
|
|
16
16
|
export { UPDATE_JOURNAL_SCHEMA, UpdateTransactionStore } from "./update-transaction.js";
|
|
17
17
|
export { warmMaterializedRelease } from "./warmup.js";
|
|
@@ -39,6 +39,8 @@ export interface UpdateRecoveryResult {
|
|
|
39
39
|
export interface ProtectedPackageReplacementOptions {
|
|
40
40
|
readonly dataDir: string;
|
|
41
41
|
readonly globalRoot: string;
|
|
42
|
+
/** Root used only to locate the active npm implementation; installation remains pinned to globalRoot. */
|
|
43
|
+
readonly npmCliRoot?: string;
|
|
42
44
|
readonly packageRoot: string;
|
|
43
45
|
readonly transaction: UpdateTransaction;
|
|
44
46
|
readonly priorRelease: {
|
|
@@ -58,7 +60,11 @@ export interface ProtectedPackageReplacementOptions {
|
|
|
58
60
|
export interface ProtectedPackageReplacementResult extends UpdateRecoveryResult {
|
|
59
61
|
readonly recovery: UpdateRecoveryState;
|
|
60
62
|
}
|
|
61
|
-
/**
|
|
63
|
+
/** Derive the only npm prefix that can own a platform's canonical global package root. */
|
|
64
|
+
export declare function npmPrefixForGlobalRoot(globalRoot: string, platform?: NodeJS.Platform): string;
|
|
65
|
+
/** Fixed replacement arguments pin npm to the installation that owns the invoked launcher. */
|
|
66
|
+
export declare function updateNpmInstallArguments(globalRoot: string, targetVersion: string, platform?: NodeJS.Platform): readonly string[];
|
|
67
|
+
/** Resolve the complete public launcher set npm owns for the selected platform and prefix. */
|
|
62
68
|
export declare function updateLauncherPaths(globalRoot: string, platform?: NodeJS.Platform): readonly string[];
|
|
63
69
|
/** Validate transaction-scoped recovery authority without trusting npm temporary names. */
|
|
64
70
|
export declare function readUpdateRecoveryCapsule(manifestPath: string, platform?: NodeJS.Platform): Promise<UpdateRecoveryCapsule>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { chmod, lstat, mkdir, open, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
|
|
4
|
-
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
|
|
7
7
|
import { processIsAlive } from "./process-cleanup.js";
|
|
@@ -9,9 +9,29 @@ import { PRIVATE_LAUNCH_CONTRACT, assertCurrentLaunchContract } from "../launch-
|
|
|
9
9
|
export const UPDATE_RECOVERY_SCHEMA = "a1-update-recovery-v1";
|
|
10
10
|
const WORKER_TIMEOUT_MS = 15 * 60 * 1_000;
|
|
11
11
|
const POLL_MS = 50;
|
|
12
|
-
/**
|
|
12
|
+
/** Derive the only npm prefix that can own a platform's canonical global package root. */
|
|
13
|
+
export function npmPrefixForGlobalRoot(globalRoot, platform = process.platform) {
|
|
14
|
+
const root = resolve(globalRoot);
|
|
15
|
+
if (!sameSegment(basename(root), "node_modules", platform))
|
|
16
|
+
throw new Error(`npm global root has an unsupported layout: ${globalRoot}`);
|
|
17
|
+
if (platform === "win32")
|
|
18
|
+
return dirname(root);
|
|
19
|
+
const libraryRoot = dirname(root);
|
|
20
|
+
if (!sameSegment(basename(libraryRoot), "lib", platform))
|
|
21
|
+
throw new Error(`npm global root has an unsupported layout: ${globalRoot}`);
|
|
22
|
+
return dirname(libraryRoot);
|
|
23
|
+
}
|
|
24
|
+
/** Fixed replacement arguments pin npm to the installation that owns the invoked launcher. */
|
|
25
|
+
export function updateNpmInstallArguments(globalRoot, targetVersion, platform = process.platform) {
|
|
26
|
+
return [
|
|
27
|
+
"install", "--global", "--prefix", npmPrefixForGlobalRoot(globalRoot, platform),
|
|
28
|
+
"--loglevel=error", "--no-fund", "--no-audit", `${PRODUCT_TEXT.packageName}@${targetVersion}`,
|
|
29
|
+
];
|
|
30
|
+
}
|
|
31
|
+
/** Resolve the complete public launcher set npm owns for the selected platform and prefix. */
|
|
13
32
|
export function updateLauncherPaths(globalRoot, platform = process.platform) {
|
|
14
|
-
const
|
|
33
|
+
const prefix = npmPrefixForGlobalRoot(globalRoot, platform);
|
|
34
|
+
const launcherRoot = platform === "win32" ? prefix : resolve(prefix, "bin");
|
|
15
35
|
return platform === "win32"
|
|
16
36
|
? [resolve(launcherRoot, "a1"), resolve(launcherRoot, "a1.cmd"), resolve(launcherRoot, "a1.ps1")]
|
|
17
37
|
: [resolve(launcherRoot, "a1")];
|
|
@@ -33,9 +53,11 @@ export async function readUpdateRecoveryCapsule(manifestPath, platform = process
|
|
|
33
53
|
const expectedPackage = resolve(canonicalGlobal, ...capsule.packageName.split("/"));
|
|
34
54
|
if (!samePath(canonicalPackage, expectedPackage) || !containedBy(canonicalGlobal, canonicalPackage))
|
|
35
55
|
throw new Error("recovery package root is outside npm global root");
|
|
36
|
-
const expectedNpmArguments =
|
|
37
|
-
|
|
38
|
-
|
|
56
|
+
const expectedNpmArguments = updateNpmInstallArguments(canonicalGlobal, capsule.targetVersion, platform);
|
|
57
|
+
const legacyNpmArguments = ["install", "--global", "--loglevel=error", "--no-fund", "--no-audit", `${capsule.packageName}@${capsule.targetVersion}`];
|
|
58
|
+
if (![expectedNpmArguments, legacyNpmArguments].some(arguments_ => sameArguments(capsule.npmArguments, arguments_))) {
|
|
59
|
+
throw new Error("recovery npm arguments differ from the selected target and prefix");
|
|
60
|
+
}
|
|
39
61
|
const expectedLaunchers = updateLauncherPaths(canonicalGlobal, platform);
|
|
40
62
|
if (JSON.stringify(capsule.launchers.map(path => resolve(path))) !== JSON.stringify(expectedLaunchers.map(path => resolve(path)))) {
|
|
41
63
|
throw new Error("recovery launcher set differs from the canonical npm launcher set");
|
|
@@ -94,8 +116,10 @@ export async function prepareUpdateRecoveryCapsule(options) {
|
|
|
94
116
|
await chmod(candidateEntry, 0o500);
|
|
95
117
|
const canonicalGlobal = await realpath(options.globalRoot);
|
|
96
118
|
const platform = options.platform ?? process.platform;
|
|
97
|
-
const
|
|
98
|
-
const
|
|
119
|
+
const prefix = npmPrefixForGlobalRoot(canonicalGlobal, platform);
|
|
120
|
+
const launcherRoot = platform === "win32" ? prefix : resolve(prefix, "bin");
|
|
121
|
+
const npmCliRoot = await realpath(options.npmCliRoot ?? canonicalGlobal);
|
|
122
|
+
const npmCli = await resolveNpmCli(npmCliRoot, options.environment ?? process.env);
|
|
99
123
|
const capsule = {
|
|
100
124
|
schema: UPDATE_RECOVERY_SCHEMA,
|
|
101
125
|
launchContract: PRIVATE_LAUNCH_CONTRACT,
|
|
@@ -114,7 +138,7 @@ export async function prepareUpdateRecoveryCapsule(options) {
|
|
|
114
138
|
recoveryEntryDigest: createHash("sha256").update(entryBytes).digest("hex"),
|
|
115
139
|
nodeExecutable: process.execPath,
|
|
116
140
|
npmCli,
|
|
117
|
-
npmArguments:
|
|
141
|
+
npmArguments: updateNpmInstallArguments(canonicalGlobal, options.transaction.targetVersion, platform),
|
|
118
142
|
cancellationPath: resolve(finalRoot, "cancel.json"),
|
|
119
143
|
resultPath: resolve(finalRoot, "result.json"),
|
|
120
144
|
ownerPath: resolve(finalRoot, "owner.json"),
|
|
@@ -341,6 +365,12 @@ async function readJson(path) { return JSON.parse(await readFile(path, "utf8"));
|
|
|
341
365
|
function samePath(left, right) {
|
|
342
366
|
return process.platform === "win32" ? resolve(left).toLowerCase() === resolve(right).toLowerCase() : resolve(left) === resolve(right);
|
|
343
367
|
}
|
|
368
|
+
function sameSegment(left, right, platform) {
|
|
369
|
+
return platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
370
|
+
}
|
|
371
|
+
function sameArguments(left, right) {
|
|
372
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
373
|
+
}
|
|
344
374
|
function containedBy(parent, child) {
|
|
345
375
|
const fromParent = relative(parent, child);
|
|
346
376
|
return fromParent.length > 0 && fromParent !== ".." && !fromParent.startsWith(`..${sep}`) && !isAbsolute(fromParent);
|
|
@@ -13,9 +13,15 @@ export interface ProcessResult {
|
|
|
13
13
|
stderr?: string;
|
|
14
14
|
}
|
|
15
15
|
export type UpdateProcessRunner = (command: string, arguments_: readonly string[], request: ProcessRequest) => Promise<ProcessResult>;
|
|
16
|
+
export interface UpdateFileMetadata {
|
|
17
|
+
readonly mode: number;
|
|
18
|
+
isFile(): boolean;
|
|
19
|
+
isSymbolicLink(): boolean;
|
|
20
|
+
}
|
|
16
21
|
export interface UpdateFileSystem {
|
|
17
22
|
readFile(path: string): Promise<string>;
|
|
18
23
|
realpath(path: string): Promise<string>;
|
|
24
|
+
lstat?(path: string): Promise<UpdateFileMetadata>;
|
|
19
25
|
access?(path: string): Promise<void>;
|
|
20
26
|
}
|
|
21
27
|
export interface UpdateOutput {
|
|
@@ -85,6 +91,7 @@ export interface UpdateTransactionJournal {
|
|
|
85
91
|
export interface UpdatePackageReplacementInput {
|
|
86
92
|
readonly dataDir: string;
|
|
87
93
|
readonly globalRoot: string;
|
|
94
|
+
readonly npmCliRoot: string;
|
|
88
95
|
readonly packageRoot: string;
|
|
89
96
|
readonly transaction: UpdateTransaction;
|
|
90
97
|
readonly priorRelease: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { access, readFile, realpath } from "node:fs/promises";
|
|
2
|
+
import { access, lstat, readFile, realpath } from "node:fs/promises";
|
|
3
3
|
import { connect } from "node:net";
|
|
4
|
-
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
5
5
|
import crossSpawn from "cross-spawn";
|
|
6
6
|
import { valid as validSemver } from "semver";
|
|
7
7
|
import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
|
|
@@ -15,12 +15,13 @@ import { materializeRelease, readMaterializedRelease } from "./release-store.js"
|
|
|
15
15
|
import { scheduleReleaseCleanup } from "./release-gc.js";
|
|
16
16
|
import { UPDATE_ACTIVATION_CONTRACT, activateInstalledRelease, delegateActivation, readActivationContracts, } from "./update-activation.js";
|
|
17
17
|
import { UpdateTransactionStore } from "./update-transaction.js";
|
|
18
|
-
import { removeUpdateRecoveryCapsule, runProtectedPackageReplacement } from "./update-recovery.js";
|
|
18
|
+
import { npmPrefixForGlobalRoot, removeUpdateRecoveryCapsule, runProtectedPackageReplacement, updateLauncherPaths, updateNpmInstallArguments, } from "./update-recovery.js";
|
|
19
19
|
export const PRODUCT_PACKAGE = PRODUCT_TEXT.packageName;
|
|
20
20
|
const UPDATE_DIST_TAGS = { stable: "latest", next: "next" };
|
|
21
21
|
const defaultFileSystem = {
|
|
22
22
|
async readFile(path) { return await readFile(path, "utf8"); },
|
|
23
23
|
realpath,
|
|
24
|
+
lstat,
|
|
24
25
|
access,
|
|
25
26
|
};
|
|
26
27
|
const defaultOutput = {
|
|
@@ -308,6 +309,106 @@ async function resolveRequestedPreview(runner, requested, output) {
|
|
|
308
309
|
output.stderr(`${PRODUCT_TEXT.diagnostic(`published no preview for ${requested}.`)}\n`);
|
|
309
310
|
return { version: null, exitCode: 1 };
|
|
310
311
|
}
|
|
312
|
+
async function resolveManagedNpmInstallation(requestedPackageRoot, fileSystem, runner, output) {
|
|
313
|
+
const rootLookup = await runNpm(runner, ["root", "--global"], true, output, "resolve npm's global package root");
|
|
314
|
+
if (rootLookup.result === null)
|
|
315
|
+
return { installation: null, exitCode: rootLookup.exitCode };
|
|
316
|
+
const activeRootText = rootLookup.result.stdout.trim();
|
|
317
|
+
if (activeRootText.length === 0) {
|
|
318
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic("could not verify its installation because npm returned an empty global package root.")}\n`);
|
|
319
|
+
return { installation: null, exitCode: 1 };
|
|
320
|
+
}
|
|
321
|
+
let packageRoot;
|
|
322
|
+
let activeGlobalRoot;
|
|
323
|
+
try {
|
|
324
|
+
[packageRoot, activeGlobalRoot] = await Promise.all([fileSystem.realpath(requestedPackageRoot), fileSystem.realpath(activeRootText)]);
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not canonicalize the running and global npm paths: ${errorMessage(error)}`)}\n`);
|
|
328
|
+
return { installation: null, exitCode: 1 };
|
|
329
|
+
}
|
|
330
|
+
const expectedActivePackage = resolve(activeGlobalRoot, ...PRODUCT_PACKAGE.split("/"));
|
|
331
|
+
if (samePath(packageRoot, expectedActivePackage)) {
|
|
332
|
+
try {
|
|
333
|
+
npmPrefixForGlobalRoot(activeGlobalRoot);
|
|
334
|
+
return {
|
|
335
|
+
installation: {
|
|
336
|
+
packageRoot,
|
|
337
|
+
globalRoot: activeGlobalRoot,
|
|
338
|
+
npmCliRoot: activeGlobalRoot,
|
|
339
|
+
},
|
|
340
|
+
exitCode: 0,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
catch (error) {
|
|
344
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not verify npm's active global package layout: ${errorMessage(error)}`)}\n`);
|
|
345
|
+
return { installation: null, exitCode: 1 };
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
let candidateGlobalRoot = packageRoot;
|
|
349
|
+
for (const _segment of PRODUCT_PACKAGE.split("/"))
|
|
350
|
+
candidateGlobalRoot = dirname(candidateGlobalRoot);
|
|
351
|
+
let candidatePrefix;
|
|
352
|
+
try {
|
|
353
|
+
candidatePrefix = npmPrefixForGlobalRoot(candidateGlobalRoot);
|
|
354
|
+
}
|
|
355
|
+
catch {
|
|
356
|
+
reportUnmanagedInstallation(output, packageRoot, activeGlobalRoot);
|
|
357
|
+
return { installation: null, exitCode: 1 };
|
|
358
|
+
}
|
|
359
|
+
if (!samePath(packageRoot, resolve(candidateGlobalRoot, ...PRODUCT_PACKAGE.split("/")))) {
|
|
360
|
+
reportUnmanagedInstallation(output, packageRoot, activeGlobalRoot);
|
|
361
|
+
return { installation: null, exitCode: 1 };
|
|
362
|
+
}
|
|
363
|
+
const confirmation = await runNpm(runner, ["root", "--global", "--prefix", candidatePrefix], true, output, "confirm npm ownership of the running installation");
|
|
364
|
+
if (confirmation.result === null)
|
|
365
|
+
return { installation: null, exitCode: confirmation.exitCode };
|
|
366
|
+
const confirmedRootText = confirmation.result.stdout.trim();
|
|
367
|
+
if (confirmedRootText.length === 0) {
|
|
368
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic("could not verify its installation because npm returned an empty global package root for the inferred prefix.")}\n`);
|
|
369
|
+
return { installation: null, exitCode: 1 };
|
|
370
|
+
}
|
|
371
|
+
let confirmedRoot;
|
|
372
|
+
try {
|
|
373
|
+
confirmedRoot = await fileSystem.realpath(confirmedRootText);
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not canonicalize npm's confirmed global package root: ${errorMessage(error)}`)}\n`);
|
|
377
|
+
return { installation: null, exitCode: 1 };
|
|
378
|
+
}
|
|
379
|
+
if (!samePath(confirmedRoot, candidateGlobalRoot)
|
|
380
|
+
|| !await launchersOwnPackage(candidateGlobalRoot, fileSystem)) {
|
|
381
|
+
reportUnmanagedInstallation(output, packageRoot, activeGlobalRoot);
|
|
382
|
+
return { installation: null, exitCode: 1 };
|
|
383
|
+
}
|
|
384
|
+
return {
|
|
385
|
+
installation: {
|
|
386
|
+
packageRoot,
|
|
387
|
+
globalRoot: candidateGlobalRoot,
|
|
388
|
+
npmCliRoot: activeGlobalRoot,
|
|
389
|
+
},
|
|
390
|
+
exitCode: 0,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
async function launchersOwnPackage(globalRoot, fileSystem) {
|
|
394
|
+
const token = `node_modules/${PRODUCT_PACKAGE}/bin/cli.js`;
|
|
395
|
+
try {
|
|
396
|
+
for (const launcher of updateLauncherPaths(globalRoot)) {
|
|
397
|
+
const metadata = await (fileSystem.lstat ?? lstat)(launcher);
|
|
398
|
+
if (!metadata.isFile() || metadata.isSymbolicLink() || (process.platform !== "win32" && (metadata.mode & 0o111) === 0))
|
|
399
|
+
return false;
|
|
400
|
+
if (!(await fileSystem.readFile(launcher)).replaceAll("\\", "/").includes(token))
|
|
401
|
+
return false;
|
|
402
|
+
}
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
catch {
|
|
406
|
+
return false;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
function reportUnmanagedInstallation(output, packageRoot, activeGlobalRoot) {
|
|
410
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic(`refused to update automatically because ${packageRoot} could not be verified as an npm-managed ${PRODUCT_PACKAGE} installation; npm's active global package root is ${activeGlobalRoot}. Run npm install --global ${PRODUCT_PACKAGE} to install it manually.`)}\n`);
|
|
411
|
+
}
|
|
311
412
|
export async function runSelfUpdate(options) {
|
|
312
413
|
const fileSystem = options.fileSystem ?? defaultFileSystem;
|
|
313
414
|
const output = options.output ?? defaultOutput;
|
|
@@ -328,6 +429,8 @@ export async function runSelfUpdate(options) {
|
|
|
328
429
|
try {
|
|
329
430
|
const packageJson = JSON.parse(await measure("package-version", async () => await fileSystem.readFile(resolve(options.packageRoot, "package.json"))));
|
|
330
431
|
const parsedVersion = typeof packageJson.version === "string" ? validSemver(packageJson.version) : null;
|
|
432
|
+
if (packageJson.name !== PRODUCT_PACKAGE)
|
|
433
|
+
throw new Error(`package.json does not identify ${PRODUCT_PACKAGE}`);
|
|
331
434
|
if (parsedVersion === null)
|
|
332
435
|
throw new Error("package.json does not contain a valid semantic version");
|
|
333
436
|
runningVersion = parsedVersion;
|
|
@@ -347,26 +450,10 @@ export async function runSelfUpdate(options) {
|
|
|
347
450
|
// and a trailing one reads as part of the version rather than as punctuation.
|
|
348
451
|
output.stdout(`${PRODUCT_TEXT.commandName} update: ${runningVersion} → ${targetVersion}\n`);
|
|
349
452
|
const progress = createUpdateProgress(output, options.progress ?? (options.output === undefined && process.stdout.isTTY === true));
|
|
350
|
-
const
|
|
351
|
-
if (
|
|
352
|
-
return
|
|
353
|
-
|
|
354
|
-
output.stderr(`${PRODUCT_TEXT.diagnostic("could not verify its installation because npm returned an empty global package root.")}\n`);
|
|
355
|
-
return 1;
|
|
356
|
-
}
|
|
357
|
-
let packageRoot;
|
|
358
|
-
let globalRoot;
|
|
359
|
-
try {
|
|
360
|
-
[packageRoot, globalRoot] = await Promise.all([fileSystem.realpath(options.packageRoot), fileSystem.realpath(rootLookup.result.stdout.trim())]);
|
|
361
|
-
}
|
|
362
|
-
catch (error) {
|
|
363
|
-
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not canonicalize the running and global npm paths: ${errorMessage(error)}`)}\n`);
|
|
364
|
-
return 1;
|
|
365
|
-
}
|
|
366
|
-
if (!isContainedBy(globalRoot, packageRoot)) {
|
|
367
|
-
output.stderr(`${PRODUCT_TEXT.diagnostic(`refused to update automatically because ${packageRoot} is not managed beneath npm's global package root ${globalRoot}.`)}\n`);
|
|
368
|
-
return 1;
|
|
369
|
-
}
|
|
453
|
+
const managed = await measure("global-root", async () => await resolveManagedNpmInstallation(options.packageRoot, fileSystem, runner, output));
|
|
454
|
+
if (managed.installation === null)
|
|
455
|
+
return managed.exitCode;
|
|
456
|
+
const { packageRoot, globalRoot, npmCliRoot } = managed.installation;
|
|
370
457
|
const environment = options.environment ?? process.env;
|
|
371
458
|
const paths = resolveProductPaths(environment);
|
|
372
459
|
const lifecycle = options.lifecycle ?? createUpdateLifecycleCoordinator(environment, fileSystem, output);
|
|
@@ -427,6 +514,7 @@ export async function runSelfUpdate(options) {
|
|
|
427
514
|
const replacement = await measure("npm-install", async () => await (options.packageReplacement ?? runProtectedPackageReplacement)({
|
|
428
515
|
dataDir: paths.dataDir,
|
|
429
516
|
globalRoot,
|
|
517
|
+
npmCliRoot,
|
|
430
518
|
packageRoot,
|
|
431
519
|
transaction: replacementTransaction,
|
|
432
520
|
priorRelease,
|
|
@@ -453,7 +541,7 @@ export async function runSelfUpdate(options) {
|
|
|
453
541
|
}
|
|
454
542
|
}
|
|
455
543
|
else {
|
|
456
|
-
const installation = await measure("npm-install", async () => await runNpm(runner,
|
|
544
|
+
const installation = await measure("npm-install", async () => await runNpm(runner, updateNpmInstallArguments(globalRoot, targetVersion), true, output, "start the global npm installation", false));
|
|
457
545
|
if (installation.result === null)
|
|
458
546
|
throw new UpdateFailure(installation.exitCode, "npm process failed");
|
|
459
547
|
if (installation.result.code !== 0) {
|
|
@@ -624,6 +712,9 @@ async function canonicalImmutableRoot(dataDir, releaseRoot) {
|
|
|
624
712
|
return false;
|
|
625
713
|
}
|
|
626
714
|
}
|
|
715
|
+
function samePath(left, right) {
|
|
716
|
+
return process.platform === "win32" ? resolve(left).toLowerCase() === resolve(right).toLowerCase() : resolve(left) === resolve(right);
|
|
717
|
+
}
|
|
627
718
|
function isContainedBy(parent, child) {
|
|
628
719
|
const pathFromParent = relative(parent, child);
|
|
629
720
|
return pathFromParent.length > 0 && pathFromParent !== ".." && !pathFromParent.startsWith(`..${sep}`) && !isAbsolute(pathFromParent);
|
|
@@ -10,7 +10,7 @@ export const STARTUP_DESCRIPTOR = Object.freeze({
|
|
|
10
10
|
],
|
|
11
11
|
"generatedArtifact": {
|
|
12
12
|
"path": "dist/integrations/pi/startup-public.js",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "fdd81188cf24be1f187fdcc18d131e7432b114c2094dc51543ef27edbe99b23c"
|
|
14
14
|
},
|
|
15
15
|
"dependencyLayerIdentity": {
|
|
16
16
|
"source": "A1_RELEASE_LAYERS",
|
|
@@ -19,7 +19,7 @@ export const STARTUP_DESCRIPTOR = Object.freeze({
|
|
|
19
19
|
"compileCacheNamespace": {
|
|
20
20
|
"strategy": "node-abi-version-and-ordered-layer-sha256-v1"
|
|
21
21
|
},
|
|
22
|
-
"identity": "
|
|
22
|
+
"identity": "4bf2be3027c6230ec34cfd8dab3df61030de6715ed1f1e9e9dd1fb83edba8522"
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export function loadDeclaredStartupGraph() {
|
|
@@ -2,7 +2,9 @@ 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 { OWNED_BUILTIN_SLASH_COMMANDS, PINNED_PI_BUILTIN_SLASH_COMMANDS, componentFromPort, componentPort, createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellShowImagesSelector, createPiShellSkillsSelector, createPiShellStatus, createPiShellThemeSelector,
|
|
5
|
+
export { OWNED_BUILTIN_SLASH_COMMANDS, PINNED_PI_BUILTIN_SLASH_COMMANDS, componentFromPort, componentPort, createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog, createPiShellOperationLoader, 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, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, validatedAssistantMessage, } from "./shell-components.js";
|
|
6
|
+
export { renderPiShellHotkeySections } from "./shell-hotkey-sections.js";
|
|
7
|
+
export type { PiShellHotkeySection } from "./shell-hotkey-sections.js";
|
|
6
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, PiShellOperationLoaderPort, PiShellPasteReservation, PiShellQueuedInputPort, PiShellResourceEntry, PiShellResourceSection, PiShellScopedModelDescriptor, PiShellScopedModelsSelectorOptions, PiShellScopedModelsSelectorPort, PiShellSelectorOption, PiShellSelectorOptions, PiShellSessionInfoPresentation, PiShellSettingsSelectorOptions, PiShellStartupNotice, PiShellStatusPlacement, PiShellStatusPort, PiShellSubmittedPromptComposer, PiShellTranscriptComponentPort, PiShellViewComponentPort, } from "./shell-components.js";
|
|
7
9
|
export { PINNED_PI_LAYOUT, applyConfiguredPiTheme, applyPiTheme, applyPiThemeInstance, currentPiThemeName, detectPiTerminalBackgroundFromEnv, detectPiTerminalBackgroundTheme, detectPiTerminalThemeForAuto, ensurePiTheme, getAvailablePiThemes, loadPiTheme, onPiThemeChange, parsePiAutoThemeSetting, piTheme, resolvePiThemeSetting, stopPiThemeWatcher, } from "./theme.js";
|
|
8
10
|
export type { PiColorMode, PiTerminalTheme, PiTerminalThemeDetection, PiTerminalThemeDetector, PiThemeBackground, PiThemeResult } from "./theme.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 { OWNED_BUILTIN_SLASH_COMMANDS, PINNED_PI_BUILTIN_SLASH_COMMANDS, componentFromPort, componentPort, createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog, createPiShellOperationLoader, createPiShellReloadBox, createPiShellScopedModelsSelector, createPiShellSelector, createPiShellSessionInfo, createPiShellSessionSelector, createPiShellSettingsSelector, createPiShellShowImagesSelector, createPiShellSkillsSelector, createPiShellStatus, createPiShellThemeSelector,
|
|
4
|
+
export { OWNED_BUILTIN_SLASH_COMMANDS, PINNED_PI_BUILTIN_SLASH_COMMANDS, componentFromPort, componentPort, createPiExtensionUiBridge, createPiQueuedInputStatus, createPiShellArmin, createPiShellAuthProviderSelector, createPiShellChangelog, createPiShellCollapsedChangelog, createPiShellDaxnuts, createPiShellDialog, createPiShellEarendilAnnouncement, createPiShellEditor, createPiShellExtensionSelector, createPiShellFooter, createPiShellHeader, createPiShellHotkeys, createPiShellLoadedResources, createPiShellLoginDialog, createPiShellModelSelector, createPiShellModelsDialog, createPiShellOperationLoader, 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, renderPiShellStartupDiagnostic, renderPiShellStatusText, renderPiShellTranscriptBlock, validatedAssistantMessage, } from "./shell-components.js";
|
|
5
|
+
export { renderPiShellHotkeySections } from "./shell-hotkey-sections.js";
|
|
5
6
|
export { PINNED_PI_LAYOUT, applyConfiguredPiTheme, applyPiTheme, applyPiThemeInstance, currentPiThemeName, detectPiTerminalBackgroundFromEnv, detectPiTerminalBackgroundTheme, detectPiTerminalThemeForAuto, ensurePiTheme, getAvailablePiThemes, loadPiTheme, onPiThemeChange, parsePiAutoThemeSetting, piTheme, resolvePiThemeSetting, stopPiThemeWatcher, } from "./theme.js";
|
|
6
7
|
export { OwnedPiThemeController } from "./upstream/theme/theme-controller.js";
|
|
7
8
|
export { ModelsDialogComponent } from "./models-dialog.js";
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type PiShellEditorPort, type PiShellEditorOptions } from "./shell-shared-facade.js";
|
|
2
2
|
export declare const PINNED_PI_BUILTIN_SLASH_COMMANDS: ({
|
|
3
|
+
readonly name: "thinking";
|
|
4
|
+
readonly description: "Set thinking level";
|
|
5
|
+
readonly argumentHint: "<level>";
|
|
6
|
+
} | {
|
|
3
7
|
name: string;
|
|
4
8
|
description: string;
|
|
5
9
|
argumentHint?: never;
|
|
@@ -8,8 +12,12 @@ export declare const PINNED_PI_BUILTIN_SLASH_COMMANDS: ({
|
|
|
8
12
|
description: string;
|
|
9
13
|
argumentHint: string;
|
|
10
14
|
})[];
|
|
11
|
-
/** Bare A1's built-in catalog:
|
|
15
|
+
/** Bare A1's built-in catalog: `models` replaces the pinned pair and is followed by `thinking`. */
|
|
12
16
|
export declare const OWNED_BUILTIN_SLASH_COMMANDS: ({
|
|
17
|
+
readonly name: "thinking";
|
|
18
|
+
readonly description: "Set thinking level";
|
|
19
|
+
readonly argumentHint: "<level>";
|
|
20
|
+
} | {
|
|
13
21
|
name: string;
|
|
14
22
|
description: string;
|
|
15
23
|
argumentHint?: never;
|
|
@@ -7,13 +7,14 @@ import { OwnedEditorUxInterception, createPromptSelectionInterceptor, editorVisu
|
|
|
7
7
|
import { PINNED_PI_LAYOUT, piTheme, } from "./theme.js";
|
|
8
8
|
import { createTuiFacade, ensureTheme, isAutocompleteProvider, } from "./shell-shared-facade.js";
|
|
9
9
|
import { SKILLS_COMMAND_NAME, collapseSkillCommands, createSkillsTunnelProvider, } from "./skills-command.js";
|
|
10
|
-
/** A selected
|
|
11
|
-
const
|
|
10
|
+
/** A selected autocomplete row: the accent primary column, then the aligned description. */
|
|
11
|
+
const SELECTED_DESCRIBED_ROW = /^(→ .*?\S)(\s{2,}.*)$/u;
|
|
12
|
+
const THINKING_SLASH_COMMAND = { name: "thinking", description: "Set thinking level", argumentHint: "<level>" };
|
|
12
13
|
export const PINNED_PI_BUILTIN_SLASH_COMMANDS = [
|
|
13
14
|
{ name: "settings", description: "Open settings menu" },
|
|
14
15
|
{ name: "model", description: "Select model (opens selector UI)", argumentHint: "<provider/model>" },
|
|
15
16
|
{ name: "tree", description: "Navigate session tree (switch branches)" },
|
|
16
|
-
|
|
17
|
+
THINKING_SLASH_COMMAND,
|
|
17
18
|
{ name: "scoped-models", description: "Enable/disable models for Ctrl+P cycling" },
|
|
18
19
|
{ name: "export", description: "Export session (HTML default, or specify path: .html/.jsonl)" },
|
|
19
20
|
{ name: "import", description: "Import and resume a session from a JSONL file" },
|
|
@@ -34,10 +35,10 @@ export const PINNED_PI_BUILTIN_SLASH_COMMANDS = [
|
|
|
34
35
|
{ name: "reload", description: "Reload keybindings, extensions, skills, prompts, themes, and context files" },
|
|
35
36
|
{ name: "quit", description: "Quit" },
|
|
36
37
|
];
|
|
37
|
-
/** Bare A1's built-in catalog:
|
|
38
|
+
/** Bare A1's built-in catalog: `models` replaces the pinned pair and is followed by `thinking`. */
|
|
38
39
|
export const OWNED_BUILTIN_SLASH_COMMANDS = PINNED_PI_BUILTIN_SLASH_COMMANDS.flatMap(command => command.name === "model"
|
|
39
|
-
? [{ name: "models", description: "Switch models and manage scoped model cycling" }]
|
|
40
|
-
: command.name === "scoped-models" ? [] : [command]);
|
|
40
|
+
? [{ name: "models", description: "Switch models and manage scoped model cycling" }, THINKING_SLASH_COMMAND]
|
|
41
|
+
: command.name === "thinking" || command.name === "scoped-models" ? [] : [command]);
|
|
41
42
|
export function createPiShellEditor(options) {
|
|
42
43
|
ensureTheme();
|
|
43
44
|
const tui = createTuiFacade(options);
|
|
@@ -64,9 +65,9 @@ export function createPiShellEditor(options) {
|
|
|
64
65
|
return selectListTheme.scrollInfo(text);
|
|
65
66
|
},
|
|
66
67
|
selectedText: text => {
|
|
67
|
-
// Rationale:
|
|
68
|
-
//
|
|
69
|
-
const row =
|
|
68
|
+
// Rationale: the pinned list styles a whole selected row at once. Bare A1 keeps the
|
|
69
|
+
// actionable primary column accented while every aligned description remains muted.
|
|
70
|
+
const row = SELECTED_DESCRIBED_ROW.exec(text);
|
|
70
71
|
return row === null ? selectListTheme.selectedText(text) : selectListTheme.selectedText(row[1]) + selectListTheme.description(row[2]);
|
|
71
72
|
},
|
|
72
73
|
},
|
|
@@ -3,5 +3,5 @@ import { type PiShellViewComponentPort, type PiShellStatusPort, type PiShellQueu
|
|
|
3
3
|
export declare function createPiShellHeader(options?: PiShellHeaderOptions): PiShellHeaderPort;
|
|
4
4
|
export declare function createPiShellLoadedResources(resources: readonly PiShellResourceEntry[], initialExpanded?: boolean): PiShellLoadedResourcesPort;
|
|
5
5
|
export declare function createPiShellStatus(view: OwnedUiSessionViewModel, formatProgressStatus: (message: string) => string, runtime?: Pick<PiShellEditorOptions, "getColumns" | "getRows" | "requestRender">): PiShellStatusPort;
|
|
6
|
-
export declare function createPiShellFooter(view: OwnedUiSessionViewModel, cwd: string, profile?: "pi" | "a1"): PiShellViewComponentPort;
|
|
6
|
+
export declare function createPiShellFooter(view: OwnedUiSessionViewModel, cwd: string, profile?: "pi" | "a1", showLevel?: () => boolean): PiShellViewComponentPort;
|
|
7
7
|
export declare function createPiQueuedInputStatus(submissions: readonly string[], presentation?: "pinned" | "custom-viewport"): PiShellQueuedInputPort;
|
|
@@ -128,9 +128,9 @@ export function createPiShellStatus(view, formatProgressStatus, runtime) {
|
|
|
128
128
|
},
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
|
-
export function createPiShellFooter(view, cwd, profile = "pi") {
|
|
131
|
+
export function createPiShellFooter(view, cwd, profile = "pi", showLevel = () => true) {
|
|
132
132
|
ensureTheme();
|
|
133
|
-
const footer = new SessionFooter(() => view, cwd, profile);
|
|
133
|
+
const footer = new SessionFooter(() => view, cwd, profile, showLevel);
|
|
134
134
|
return {
|
|
135
135
|
render: width => footer.render(width),
|
|
136
136
|
invalidate: () => footer.invalidate(),
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PiShellHotkeysPresentation } from "./shell-presenters-info.js";
|
|
2
|
+
export interface PiShellHotkeySection {
|
|
3
|
+
readonly title: string;
|
|
4
|
+
readonly rows: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
/** Turns heading-led hotkeys Markdown into reusable grouped-document data before row rendering. */
|
|
7
|
+
export declare function renderPiShellHotkeySections(presentation: PiShellHotkeysPresentation, width: number): readonly PiShellHotkeySection[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getMarkdownTheme } from "../startup-public.js";
|
|
2
|
+
import { Markdown } from "@earendil-works/pi-tui";
|
|
3
|
+
import { ensureTheme } from "./shell-shared-facade.js";
|
|
4
|
+
import { hotkeysMarkdown } from "./shell-presenters-info.js";
|
|
5
|
+
/** Turns heading-led hotkeys Markdown into reusable grouped-document data before row rendering. */
|
|
6
|
+
export function renderPiShellHotkeySections(presentation, width) {
|
|
7
|
+
ensureTheme();
|
|
8
|
+
const shortcuts = presentation.getShortcuts ?? (() => []);
|
|
9
|
+
const markdown = hotkeysMarkdown(presentation.bindings, shortcuts, presentation.profile ?? "pi");
|
|
10
|
+
const sections = [];
|
|
11
|
+
for (const line of markdown.split("\n")) {
|
|
12
|
+
const heading = /^\*\*(.+)\*\*$/.exec(line)?.[1];
|
|
13
|
+
if (heading !== undefined)
|
|
14
|
+
sections.push({ title: heading, lines: [] });
|
|
15
|
+
else
|
|
16
|
+
sections.at(-1)?.lines.push(line);
|
|
17
|
+
}
|
|
18
|
+
for (const section of sections)
|
|
19
|
+
while (section.lines.at(-1) === "")
|
|
20
|
+
section.lines.pop();
|
|
21
|
+
return sections.map(section => {
|
|
22
|
+
const rows = [...new Markdown(section.lines.join("\n"), 1, 1, getMarkdownTheme()).render(width)];
|
|
23
|
+
while (rows[0]?.trim().length === 0)
|
|
24
|
+
rows.shift();
|
|
25
|
+
while (rows.at(-1)?.trim().length === 0)
|
|
26
|
+
rows.pop();
|
|
27
|
+
return { title: section.title, rows };
|
|
28
|
+
});
|
|
29
|
+
}
|
|
@@ -70,3 +70,4 @@ export interface PiShellHotkeysPresentation {
|
|
|
70
70
|
export declare function createPiShellHotkeys(bindings?: KeybindingsConfig, getShortcuts?: NonNullable<PiShellExtensionRendererResolver["getShortcuts"]>, profile?: "pi" | "a1"): PiShellComponentPort;
|
|
71
71
|
/** The keyboard-shortcut document rows the feed presenter shows, without its spacer, borders, and heading. */
|
|
72
72
|
export declare function renderPiShellHotkeysLines(presentation: PiShellHotkeysPresentation, width: number): readonly string[];
|
|
73
|
+
export declare function hotkeysMarkdown(bindings: KeybindingsConfig | undefined, getShortcuts: NonNullable<PiShellExtensionRendererResolver["getShortcuts"]>, profile: "pi" | "a1"): string;
|
|
@@ -166,7 +166,7 @@ export function renderPiShellHotkeysLines(presentation, width) {
|
|
|
166
166
|
function hotkeysMarkdownComponent(markdown) {
|
|
167
167
|
return new Markdown(markdown, 1, 1, getMarkdownTheme());
|
|
168
168
|
}
|
|
169
|
-
function hotkeysMarkdown(bindings, getShortcuts, profile) {
|
|
169
|
+
export function hotkeysMarkdown(bindings, getShortcuts, profile) {
|
|
170
170
|
const keys = profile === "a1" ? KeybindingsManager.fromOwnedBindings(bindings) : new KeybindingsManager(bindings);
|
|
171
171
|
// Compatibility: the owned viewport consumes these physical chords before editor actions.
|
|
172
172
|
const display = (action) => keys.getKeys(action)
|
|
@@ -126,7 +126,6 @@ export interface PiShellAuthProviderOption extends PiShellSelectorOption {
|
|
|
126
126
|
}
|
|
127
127
|
export declare function createPiShellAuthProviderSelector(mode: "login" | "logout", providers: readonly PiShellAuthProviderOption[], onSelect: (id: string) => void, onCancel: () => void, initialSearchInput?: string): PiShellComponentPort;
|
|
128
128
|
export declare function createPiShellExtensionSelector(title: string, options: readonly string[], onSelect: (value: string) => void, onCancel: () => void): PiShellComponentPort;
|
|
129
|
-
export declare function createPiShellThinkingSelector(currentLevel: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max", availableLevels: readonly ("off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max")[], onSelect: (level: string) => void, onCancel: () => void, onSelectAsDefault?: (level: string) => void, defaultLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"): PiShellComponentPort;
|
|
130
129
|
export declare function createPiShellThemeSelector(currentTheme: string, onSelect: (theme: string) => void, onCancel: () => void, onPreview: (theme: string) => void): PiShellComponentPort;
|
|
131
130
|
export declare function createPiShellShowImagesSelector(currentValue: boolean, onSelect: (show: boolean) => void, onCancel: () => void): PiShellComponentPort;
|
|
132
131
|
export declare function createPiShellDialog(dialog: OwnedUiDialog, handlers?: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ArminComponent, BorderedLoader, DynamicBorder, ExtensionSelectorComponent, getSelectListTheme, LoginDialogComponent, ModelSelectorComponent, OAuthSelectorComponent, SettingsSelectorComponent, ShowImagesSelectorComponent, ThemeSelectorComponent,
|
|
1
|
+
import { ArminComponent, BorderedLoader, DynamicBorder, ExtensionSelectorComponent, getSelectListTheme, LoginDialogComponent, ModelSelectorComponent, OAuthSelectorComponent, SettingsSelectorComponent, ShowImagesSelectorComponent, ThemeSelectorComponent, UserMessageSelectorComponent, } from "../startup-public.js";
|
|
2
2
|
import { DaxnutsComponent, } from "./upstream/components/daxnuts.js";
|
|
3
3
|
import { EarendilAnnouncementComponent, } from "./upstream/components/earendil-announcement.js";
|
|
4
4
|
import { Box, Container, SelectList, Spacer, Text, } from "@earendil-works/pi-tui";
|
|
@@ -200,12 +200,6 @@ export function createPiShellExtensionSelector(title, options, onSelect, onCance
|
|
|
200
200
|
ensureTheme();
|
|
201
201
|
return componentPort(new ExtensionSelectorComponent(title, [...options], onSelect, onCancel));
|
|
202
202
|
}
|
|
203
|
-
export function createPiShellThinkingSelector(currentLevel, availableLevels, onSelect, onCancel, onSelectAsDefault, defaultLevel) {
|
|
204
|
-
ensureTheme();
|
|
205
|
-
const selector = new ThinkingSelectorComponent(currentLevel, [...availableLevels], onSelect, onCancel, onSelectAsDefault, defaultLevel);
|
|
206
|
-
const list = selector.getSelectList();
|
|
207
|
-
return componentPort(selector, data => list.handleInput(data));
|
|
208
|
-
}
|
|
209
203
|
export function createPiShellThemeSelector(currentTheme, onSelect, onCancel, onPreview) {
|
|
210
204
|
ensureTheme();
|
|
211
205
|
const selector = new ThemeSelectorComponent(currentTheme, onSelect, onCancel, onPreview);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ThinkingSelectorLevel } from "./upstream/components/thinking-selector.js";
|
|
2
|
+
import { type PiShellComponentPort } from "./shell-shared-facade.js";
|
|
3
|
+
export interface PiShellThinkingSelectorPresentation {
|
|
4
|
+
readonly profile: "bare";
|
|
5
|
+
readonly cycleBinding: string | readonly string[];
|
|
6
|
+
}
|
|
7
|
+
/** Lazily loaded because thinking-selector code does not belong to the startup graph before `/thinking` opens. */
|
|
8
|
+
export declare function createPiShellThinkingSelector(currentLevel: ThinkingSelectorLevel, availableLevels: readonly ThinkingSelectorLevel[], onSelect: (level: string) => void, onCancel: () => void, onSelectAsDefault?: (level: string) => void, defaultLevel?: ThinkingSelectorLevel, presentation?: PiShellThinkingSelectorPresentation): PiShellComponentPort;
|