@timurproko/a1 0.2.7-dev.1252 → 0.2.7-dev.1264
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/ui.js +3 -3
- package/dist/app/session-shell/clipboard-diagnostics.d.ts +2 -2
- package/dist/app/session-shell/clipboard-image.d.ts +0 -1
- package/dist/app/session-shell/clipboard-image.js +1 -1
- package/dist/app/session-shell/dialog-coordinator.d.ts +6 -5
- package/dist/app/session-shell/dialog-coordinator.js +3 -4
- package/dist/app/session-shell/dock-chrome.d.ts +11 -6
- package/dist/app/session-shell/dock-chrome.js +5 -8
- package/dist/app/session-shell/editor-hyperlink-budget.d.ts +0 -2
- package/dist/app/session-shell/editor-hyperlink-budget.js +1 -1
- package/dist/app/session-shell/exit-notice.d.ts +2 -2
- package/dist/app/session-shell/exit-notice.js +1 -1
- package/dist/app/session-shell/extension-surface.d.ts +8 -7
- package/dist/app/session-shell/helper-pool.d.ts +3 -4
- package/dist/app/session-shell/helper-pool.js +1 -1
- package/dist/app/session-shell/image-preparation-client.d.ts +4 -3
- package/dist/app/session-shell/image-preparation.d.ts +0 -2
- package/dist/app/session-shell/image-preparation.js +2 -2
- package/dist/app/session-shell/image-source.d.ts +2 -3
- package/dist/app/session-shell/image-source.js +2 -2
- package/dist/app/session-shell/input-surface-switch.d.ts +9 -7
- package/dist/app/session-shell/input-surface-switch.js +1 -2
- package/dist/app/session-shell/login-interaction.d.ts +5 -4
- package/dist/app/session-shell/login-interaction.js +2 -3
- package/dist/app/session-shell/paste-executor.d.ts +4 -8
- package/dist/app/session-shell/paste-executor.js +2 -2
- package/dist/app/session-shell/paste-protocol.d.ts +2 -2
- package/dist/app/session-shell/path-chip-presentation.d.ts +0 -5
- package/dist/app/session-shell/path-chip-presentation.js +3 -3
- package/dist/app/session-shell/prompt-chips.d.ts +8 -7
- package/dist/app/session-shell/prompt-history-controller.d.ts +3 -3
- package/dist/app/session-shell/prompt-submission.d.ts +5 -2
- package/dist/app/session-shell/prompt-submission.js +13 -14
- package/dist/app/session-shell/quit-outro-effects.d.ts +3 -3
- package/dist/app/session-shell/quit-outro-effects.js +1 -4
- package/dist/app/session-shell/quit-outro.d.ts +9 -12
- package/dist/app/session-shell/quit-outro.js +11 -11
- package/dist/app/session-shell/resource-labels.d.ts +2 -0
- package/dist/app/session-shell/resource-labels.js +158 -0
- package/dist/app/session-shell/response-copy-protocol.d.ts +3 -2
- package/dist/app/session-shell/response-copy-transport.d.ts +2 -14
- package/dist/app/session-shell/response-copy-transport.js +1 -1
- package/dist/app/session-shell/session-lifecycle.d.ts +2 -1
- package/dist/app/session-shell/session-prompt-history.d.ts +29 -0
- package/dist/app/session-shell/session-prompt-history.js +80 -0
- package/dist/app/session-shell/session-selectors.d.ts +46 -0
- package/dist/app/session-shell/session-selectors.js +269 -0
- package/dist/app/session-shell/session-shell-root.d.ts +76 -113
- package/dist/app/session-shell/session-shell-root.js +103 -329
- package/dist/app/session-shell/session-shell.d.ts +14 -37
- package/dist/app/session-shell/session-shell.js +177 -612
- package/dist/app/session-shell/session-viewport-controller.d.ts +9 -16
- package/dist/app/session-shell/session-viewport-controller.js +42 -320
- package/dist/app/session-shell/settings-bindings.d.ts +25 -3
- package/dist/app/session-shell/settings-bindings.js +26 -2
- package/dist/app/session-shell/share-operation.d.ts +3 -3
- package/dist/app/session-shell/share-operation.js +4 -6
- package/dist/app/session-shell/shell-clipboard.d.ts +59 -0
- package/dist/app/session-shell/shell-clipboard.js +119 -0
- package/dist/app/session-shell/shell-editor-factory.d.ts +8 -4
- package/dist/app/session-shell/shell-editor-factory.js +13 -15
- package/dist/app/session-shell/shell-host.d.ts +16 -17
- package/dist/app/session-shell/shell-host.js +18 -19
- package/dist/app/session-shell/shell-layout.d.ts +2 -2
- package/dist/app/session-shell/shell-prompt-suggestions.d.ts +26 -0
- package/dist/app/session-shell/shell-prompt-suggestions.js +48 -0
- package/dist/app/session-shell/suggestion-surface.d.ts +1 -6
- package/dist/app/session-shell/suggestion-surface.js +1 -1
- package/dist/app/session-shell/system-clipboard.d.ts +2 -14
- package/dist/app/session-shell/system-clipboard.js +2 -7
- package/dist/app/session-shell/transcript-document.d.ts +11 -8
- package/dist/app/session-shell/transcript-document.js +13 -14
- package/dist/app/session-shell/viewport-layout.d.ts +2 -2
- package/dist/app/session-shell/viewport-pointer.d.ts +83 -0
- package/dist/app/session-shell/viewport-pointer.js +361 -0
- package/dist/app/session-shell/workflow-output.d.ts +5 -3
- package/dist/app/session-shell/workflow-output.js +13 -15
- package/dist/cli/package-messages.d.ts +0 -1
- package/dist/cli/package-messages.js +1 -1
- package/dist/cli/session-context.d.ts +1 -1
- package/dist/cli/uninstall.d.ts +3 -2
- package/dist/composition/owned-settings.d.ts +2 -1
- package/dist/composition/owned-settings.js +0 -3
- package/dist/composition/owned-ui.d.ts +1 -1
- package/dist/composition/owned-ui.js +77 -73
- package/dist/composition/reference-selection-options.d.ts +1 -1
- package/dist/composition/reference-selection-options.js +1 -1
- package/dist/composition/session-runtime-registry.d.ts +2 -1
- package/dist/composition/settings-route-host.js +3 -10
- package/dist/composition/settings-search-input.d.ts +2 -1
- package/dist/composition/startup-route.d.ts +2 -2
- package/dist/composition/startup-route.js +2 -2
- package/dist/contracts/owned-ui/extension-ui.d.ts +2 -1
- package/dist/contracts/owned-ui/index.d.ts +2 -1
- package/dist/contracts/owned-ui/index.js +1 -1
- package/dist/contracts/owned-ui/session-presenters.d.ts +3 -0
- package/dist/contracts/owned-ui/shell-components.d.ts +543 -0
- package/dist/contracts/owned-ui/validation.d.ts +1 -11
- package/dist/contracts/owned-ui/validation.js +8 -104
- package/dist/contracts/presentation/component.d.ts +17 -0
- package/dist/contracts/presentation/component.js +8 -0
- package/dist/contracts/presentation/index.d.ts +6 -15
- package/dist/contracts/presentation/index.js +2 -0
- package/dist/contracts/presentation/terminal.d.ts +284 -0
- package/dist/contracts/presentation/terminal.js +1 -0
- package/dist/contracts/presentation/theme.d.ts +46 -0
- package/dist/contracts/presentation/theme.js +1 -0
- package/dist/features/launch/development-launch.js +1 -1
- package/dist/features/launch/runtime-selection.d.ts +2 -2
- package/dist/features/launch/runtime-selection.js +2 -2
- package/dist/features/owned-ui/project-trust-prompt.d.ts +2 -2
- package/dist/features/owned-ui/project-trust-prompt.js +1 -1
- package/dist/features/owned-ui/release-note-state.d.ts +2 -1
- package/dist/features/owned-ui/settings-app.js +49 -425
- package/dist/features/owned-ui/settings-edits.d.ts +31 -0
- package/dist/features/owned-ui/settings-edits.js +139 -0
- package/dist/features/owned-ui/settings-model-dialog.d.ts +41 -0
- package/dist/features/owned-ui/settings-model-dialog.js +194 -0
- package/dist/features/owned-ui/settings-scroll-rail.d.ts +29 -0
- package/dist/features/owned-ui/settings-scroll-rail.js +79 -0
- package/dist/features/owned-ui/settings-search-input.d.ts +2 -1
- package/dist/features/prompt-history/service.d.ts +3 -2
- package/dist/foundation/lifecycle/claim-gate.d.ts +2 -1
- package/dist/foundation/release/automatic-update.d.ts +5 -14
- package/dist/foundation/release/automatic-update.js +15 -22
- package/dist/foundation/release/bootstrap.js +4 -4
- package/dist/foundation/release/dependency-certification.d.ts +0 -1
- package/dist/foundation/release/dependency-certification.js +1 -1
- package/dist/foundation/release/dependency-layer.js +3 -3
- package/dist/foundation/release/early-accent.d.ts +2 -2
- package/dist/foundation/release/early-accent.js +1 -1
- package/dist/foundation/release/index.d.ts +2 -2
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/latest-release.d.ts +3 -18
- package/dist/foundation/release/latest-release.js +11 -11
- package/dist/foundation/release/managed-path.d.ts +10 -0
- package/dist/foundation/release/managed-path.js +26 -0
- package/dist/foundation/release/ordinary-launch-selection.d.ts +1 -1
- package/dist/foundation/release/ordinary-launch-selection.js +1 -1
- package/dist/foundation/release/release-gc.d.ts +3 -3
- package/dist/foundation/release/release-gc.js +10 -12
- package/dist/foundation/release/{cohort-state.d.ts → release-state.d.ts} +23 -23
- package/dist/foundation/release/{cohort-state.js → release-state.js} +8 -8
- package/dist/foundation/release/restart-certification.js +3 -4
- package/dist/foundation/release/update-activation.js +3 -3
- package/dist/foundation/release/update-execution-lease.d.ts +2 -3
- package/dist/foundation/release/update-execution-lease.js +2 -8
- package/dist/foundation/release/update-installer.d.ts +45 -0
- package/dist/foundation/release/update-installer.js +57 -0
- package/dist/foundation/release/update-launch.d.ts +2 -2
- package/dist/foundation/release/update-recovery.js +2 -9
- package/dist/foundation/release/update.d.ts +4 -25
- package/dist/foundation/release/update.js +164 -183
- package/dist/foundation/startup/startup-budget.d.ts +5 -5
- package/dist/foundation/startup/startup-budget.js +2 -2
- package/dist/integrations/pi/components/bracketed-paste.d.ts +33 -0
- package/dist/integrations/pi/components/bracketed-paste.js +123 -0
- package/dist/integrations/pi/components/editor-interaction.d.ts +4 -12
- package/dist/integrations/pi/components/index.d.ts +15 -9
- package/dist/integrations/pi/components/index.js +9 -5
- package/dist/integrations/pi/components/lazy-selectors.d.ts +2 -10
- package/dist/integrations/pi/components/lazy-selectors.js +1 -1
- package/dist/integrations/pi/components/modal-frame.d.ts +5 -22
- package/dist/integrations/pi/components/modal-frame.js +3 -23
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +4 -3
- package/dist/integrations/pi/components/owned-editor-ux.js +46 -140
- package/dist/integrations/pi/components/prompt-input-port.d.ts +2 -19
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.d.ts +3 -2
- package/dist/integrations/pi/components/shell-footer-status.d.ts +2 -2
- package/dist/integrations/pi/components/shell-footer-status.js +3 -2
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +6 -5
- package/dist/integrations/pi/components/shell-presenters-info.js +2 -1
- package/dist/integrations/pi/components/shell-session-info-reference.d.ts +2 -1
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +33 -227
- package/dist/integrations/pi/components/shell-shared-facade.js +8 -1
- package/dist/integrations/pi/components/skills-command.d.ts +1 -9
- package/dist/integrations/pi/components/skills-command.js +5 -5
- package/dist/integrations/pi/components/theme.d.ts +9 -2
- package/dist/integrations/pi/components/theme.js +17 -2
- package/dist/integrations/pi/components/thinking-selector-dialog.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +2 -2
- package/dist/integrations/pi/engine/adapter.d.ts +4 -13
- package/dist/integrations/pi/engine/adapter.js +9 -61
- package/dist/integrations/pi/engine/changelog.d.ts +2 -2
- package/dist/integrations/pi/engine/changelog.js +3 -3
- package/dist/integrations/pi/engine/compaction-progress.d.ts +2 -3
- package/dist/integrations/pi/engine/compaction-progress.js +1 -1
- package/dist/integrations/pi/engine/conformance.d.ts +2 -1
- package/dist/integrations/pi/engine/default-model-setting.d.ts +0 -2
- package/dist/integrations/pi/engine/default-model-setting.js +1 -2
- package/dist/integrations/pi/engine/event-delivery.d.ts +2 -1
- package/dist/integrations/pi/engine/extension-ui-binding.d.ts +2 -1
- package/dist/integrations/pi/engine/host.js +3 -3
- package/dist/integrations/pi/engine/message-values.d.ts +0 -1
- package/dist/integrations/pi/engine/message-values.js +1 -1
- package/dist/integrations/pi/engine/pending-delivery.d.ts +0 -4
- package/dist/integrations/pi/engine/pending-delivery.js +3 -3
- package/dist/integrations/pi/engine/ports.d.ts +7 -1
- package/dist/integrations/pi/engine/ports.js +4 -0
- package/dist/integrations/pi/engine/project-trust-preflight.d.ts +2 -1
- package/dist/integrations/pi/engine/prompt-suggestions.d.ts +3 -2
- package/dist/integrations/pi/engine/provider-authentication.d.ts +1 -1
- package/dist/integrations/pi/engine/public-main-entry.d.ts +1 -5
- package/dist/integrations/pi/engine/public-main-entry.js +1 -1
- package/dist/integrations/pi/engine/repository-metadata.d.ts +49 -0
- package/dist/integrations/pi/engine/repository-metadata.js +189 -0
- package/dist/integrations/pi/engine/repository-pr-rest.d.ts +1 -9
- package/dist/integrations/pi/engine/repository-pr-rest.js +2 -2
- package/dist/integrations/pi/engine/repository-pr.d.ts +1 -3
- package/dist/integrations/pi/engine/repository-pr.js +1 -1
- package/dist/integrations/pi/engine/resource-catalog.d.ts +2 -1
- package/dist/integrations/pi/engine/session-integration.d.ts +1 -1
- package/dist/integrations/pi/engine/session-runtime.d.ts +7 -12
- package/dist/integrations/pi/engine/session-runtime.js +21 -178
- package/dist/integrations/pi/engine/settings-bridge.d.ts +0 -2
- package/dist/integrations/pi/engine/settings-bridge.js +1 -1
- package/dist/integrations/pi/engine/settings-port.d.ts +3 -2
- package/dist/integrations/pi/engine/transcript-projection.d.ts +2 -1
- package/dist/integrations/pi/engine/view-state.d.ts +21 -2
- package/dist/integrations/pi/engine/view-state.js +129 -1
- package/dist/integrations/pi/engine/workflow-contexts.d.ts +1 -1
- package/dist/integrations/pi/engine/workflow-runner.d.ts +1 -2
- package/dist/integrations/pi/engine/workflow-runner.js +254 -365
- package/dist/integrations/pi/engine/workflow-share.d.ts +9 -0
- package/dist/integrations/pi/engine/workflow-share.js +168 -0
- package/dist/integrations/pi/engine/workflow-support.d.ts +0 -20
- package/dist/integrations/pi/engine/workflow-support.js +4 -65
- package/dist/integrations/pi/engine/workflows.d.ts +5 -5
- package/dist/integrations/pi/session-presenters/components.d.ts +3 -0
- package/dist/integrations/pi/session-presenters/components.js +75 -0
- package/dist/integrations/pi/session-presenters/index.d.ts +1 -0
- package/dist/integrations/pi/session-presenters/index.js +1 -0
- package/dist/integrations/pi/session-presenters/presentation.d.ts +3 -0
- package/dist/integrations/pi/session-presenters/presentation.js +10 -0
- package/dist/integrations/pi/session-presenters/presenters.d.ts +2 -1
- package/dist/integrations/pi/session-presenters/presenters.js +3 -1
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +9 -19
- package/dist/integrations/pi/tui-runtime/adapter.js +56 -174
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +9 -44
- package/dist/integrations/pi/tui-runtime/index.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/index.js +1 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +4 -6
- package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +4 -10
- package/dist/integrations/pi/tui-runtime/overlay-geometry.js +3 -9
- package/dist/integrations/pi/tui-runtime/presentation-adapter.d.ts +2 -2
- package/dist/integrations/pi/tui-runtime/runtime-factory.d.ts +3 -0
- package/dist/integrations/pi/tui-runtime/runtime-factory.js +11 -0
- package/dist/ui/components/index.d.ts +2 -2
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/selection-copy.d.ts +0 -1
- package/dist/ui/components/selection-copy.js +0 -12
- package/dist/ui/components/theme.d.ts +4 -19
- package/dist/ui/components/theme.js +6 -0
- package/dist/ui/components/transcript-viewport-frame.d.ts +120 -0
- package/dist/ui/components/transcript-viewport-frame.js +314 -0
- package/dist/ui/components/transcript-viewport-types.d.ts +147 -0
- package/dist/ui/components/transcript-viewport-types.js +1 -0
- package/dist/ui/components/transcript-viewport.d.ts +2 -147
- package/dist/ui/components/transcript-viewport.js +87 -315
- package/dist/ui/settings/declarations.d.ts +2 -3
- package/dist/ui/settings/declarations.js +2 -3
- package/dist/ui/settings/early-accent.js +1 -1
- package/dist/ui/settings/index.d.ts +3 -5
- package/dist/ui/settings/index.js +2 -3
- package/dist/ui/settings/manager.d.ts +0 -4
- package/dist/ui/settings/manager.js +6 -62
- package/dist/ui/settings/resolution.d.ts +6 -18
- package/dist/ui/settings/resolution.js +4 -103
- package/dist/ui/settings/sections.d.ts +0 -4
- package/dist/ui/settings/sections.js +1 -1
- package/docs/architecture/boundaries.md +2 -2
- package/docs/architecture/internal-naming.md +2 -0
- package/docs/architecture/project-structure.md +4 -2
- package/docs/validation.md +1 -1
- package/package.json +3 -4
- package/dist/integrations/pi/components/components.d.ts +0 -4
- package/dist/integrations/pi/components/components.js +0 -48
- package/dist/integrations/pi/components/conformance.d.ts +0 -18
- package/dist/integrations/pi/components/conformance.js +0 -70
- package/dist/integrations/pi/components/shell-components.d.ts +0 -7
- package/dist/integrations/pi/components/shell-components.js +0 -7
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +0 -33
- package/dist/integrations/pi/components/upstream/theme/theme-controller.js +0 -114
- package/dist/integrations/pi/engine/diagnostics-state.d.ts +0 -9
- package/dist/integrations/pi/engine/diagnostics-state.js +0 -34
- package/dist/integrations/pi/engine/usage-view.d.ts +0 -4
- package/dist/integrations/pi/engine/usage-view.js +0 -56
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +0 -166
- package/dist/ui/settings/migrations.d.ts +0 -19
- package/dist/ui/settings/migrations.js +0 -225
- package/dist/ui/settings/progress-palette.generated.d.ts +0 -139
- package/dist/ui/settings/progress-palette.generated.js +0 -139
- /package/dist/{integrations/pi/tui-runtime/contracts.js → contracts/owned-ui/shell-components.js} +0 -0
- /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.d.ts +0 -0
- /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.js +0 -0
|
@@ -3,7 +3,7 @@ import { mkdir, open, readFile, rename, rm, stat } from "node:fs/promises";
|
|
|
3
3
|
import { dirname, resolve } from "node:path";
|
|
4
4
|
import { selectOrdinaryLaunchReleaseId } from "./ordinary-launch-selection.js";
|
|
5
5
|
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
6
|
-
export const
|
|
6
|
+
export const RELEASE_STATE_SCHEMA = PRODUCT_IDENTITY.protocol.releaseCohortSchema;
|
|
7
7
|
const RELEASE_ID_PATTERN = /^[0-9A-Za-z.+_-]+-[a-f0-9]{20}$/;
|
|
8
8
|
/** How long a release stays on disk after its approval, so processes started from it keep their files. */
|
|
9
9
|
export const RELEASE_RETENTION_MS = 7 * 24 * 60 * 60 * 1_000;
|
|
@@ -51,8 +51,8 @@ export function withinRetention(release, now, retentionMs = RELEASE_RETENTION_MS
|
|
|
51
51
|
const at = stamp === null ? Number.NaN : Date.parse(stamp);
|
|
52
52
|
return Number.isFinite(at) && now - at < retentionMs;
|
|
53
53
|
}
|
|
54
|
-
/** Serializes validated
|
|
55
|
-
export class
|
|
54
|
+
/** Serializes validated release-state revisions under a lock and commits each update atomically. */
|
|
55
|
+
export class ReleaseStateStore {
|
|
56
56
|
path;
|
|
57
57
|
constructor(dataDir) {
|
|
58
58
|
this.path = resolve(dataDir, "release-state.json");
|
|
@@ -317,7 +317,7 @@ export class CohortStateStore {
|
|
|
317
317
|
}
|
|
318
318
|
export function emptyState() {
|
|
319
319
|
return {
|
|
320
|
-
schema:
|
|
320
|
+
schema: RELEASE_STATE_SCHEMA,
|
|
321
321
|
revision: 0,
|
|
322
322
|
releases: {},
|
|
323
323
|
references: { active: null, pending: null, approved: null, rollback: null, retention: [] },
|
|
@@ -430,11 +430,11 @@ function normalizeState(value) {
|
|
|
430
430
|
};
|
|
431
431
|
}
|
|
432
432
|
function validateState(state) {
|
|
433
|
-
if (!state || state.schema !==
|
|
433
|
+
if (!state || state.schema !== RELEASE_STATE_SCHEMA || !Number.isSafeInteger(state.revision) || state.revision < 0
|
|
434
434
|
|| !state.releases || typeof state.releases !== "object" || !state.references || !Array.isArray(state.references.retention)
|
|
435
435
|
|| !state.cleanup || typeof state.cleanup.pending !== "object" || !Array.isArray(state.cleanup.diagnostics)
|
|
436
436
|
|| !Array.isArray(state.cleanup.workerRuns)) {
|
|
437
|
-
throw new Error("invalid release
|
|
437
|
+
throw new Error("invalid release state");
|
|
438
438
|
}
|
|
439
439
|
for (const run of state.cleanup.workerRuns) {
|
|
440
440
|
if (!run || typeof run.runId !== "string" || run.runId.length === 0
|
|
@@ -469,9 +469,9 @@ function validateReleaseRecord(releaseId, release) {
|
|
|
469
469
|
function validateTransition(current, next) {
|
|
470
470
|
validateState(next);
|
|
471
471
|
if (next.schema !== current.schema)
|
|
472
|
-
throw new Error("release
|
|
472
|
+
throw new Error("release schema cannot change during a state update");
|
|
473
473
|
if (next.revision !== current.revision)
|
|
474
|
-
throw new Error("release
|
|
474
|
+
throw new Error("release revision is controlled by the state store");
|
|
475
475
|
}
|
|
476
476
|
function boundedError(error) {
|
|
477
477
|
return (error instanceof Error ? error.message : String(error)).replace(/[\r\n]+/g, " ").slice(0, 1_000);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { lstat, readFile, realpath, stat } from "node:fs/promises";
|
|
3
|
-
import { basename,
|
|
3
|
+
import { basename, resolve } from "node:path";
|
|
4
4
|
import { PRODUCT_IDENTITY } from "../../product-identity.js";
|
|
5
5
|
import { PRIVATE_LAUNCH_CONTRACT, launchContractTarget } from "../launch-context/index.js";
|
|
6
6
|
import { DEPENDENCY_LAYER_MANIFEST, dependencyLayerCertificationPath, legacyDependencyLayerCertificationPath, readCertifiedDependencyLayer } from "./dependency-layer.js";
|
|
@@ -9,6 +9,7 @@ import { immutablePlatformPolicy } from "./immutable-platform.js";
|
|
|
9
9
|
import { PRODUCT_PACKAGE_NAME } from "./release.js";
|
|
10
10
|
import { RELEASE_MANIFEST_FILENAME } from "./release-store.js";
|
|
11
11
|
import { UpdateTransactionStore } from "./update-transaction.js";
|
|
12
|
+
import { isDirectChild } from "./managed-path.js";
|
|
12
13
|
const RESTART_SEAL_VERSION = 1;
|
|
13
14
|
const REQUIRED_LAUNCH_ENTRIES = ["bin/ui.js"];
|
|
14
15
|
/** Build compact restart authority after complete content verification established read-only payload files. */
|
|
@@ -219,9 +220,7 @@ async function observedRealpath(path, onEvent) {
|
|
|
219
220
|
return await realpath(path);
|
|
220
221
|
}
|
|
221
222
|
function assertDirectChild(parent, child, expectedName, kind) {
|
|
222
|
-
|
|
223
|
-
if (isAbsolute(fromParent) || fromParent === ".." || fromParent.startsWith(`..${sep}`) || fromParent.includes(sep)
|
|
224
|
-
|| basename(child) !== expectedName) {
|
|
223
|
+
if (!isDirectChild(parent, child) || basename(child) !== expectedName) {
|
|
225
224
|
throw new Error(`restart ${kind} is outside its managed store: ${child}`);
|
|
226
225
|
}
|
|
227
226
|
}
|
|
@@ -4,10 +4,11 @@ import { resolve } from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { PRODUCT_TEXT } from "../../product-identity.js";
|
|
6
6
|
import { certifyMaterializedRelease } from "./bootstrap.js";
|
|
7
|
-
import {
|
|
7
|
+
import { ReleaseStateStore } from "./release-state.js";
|
|
8
8
|
import { resolveProductPaths } from "../lifecycle/index.js";
|
|
9
9
|
import { materializeRelease } from "./release-store.js";
|
|
10
10
|
import { warmMaterializedRelease } from "./warmup.js";
|
|
11
|
+
import { errorMessage } from "./managed-path.js";
|
|
11
12
|
/**
|
|
12
13
|
* The one activation contract an installed tree can offer the updater that installed it.
|
|
13
14
|
* The updater knows nothing else about the tree: the manifest names the contracts the tree
|
|
@@ -27,7 +28,7 @@ const ACTIVATION_LINE_LIMIT = 64 * 1_024;
|
|
|
27
28
|
* its activation entry, and what an updater runs in-process for a tree older than the contract.
|
|
28
29
|
*/
|
|
29
30
|
export async function activateInstalledRelease(request, callbacks) {
|
|
30
|
-
const stateStore = new
|
|
31
|
+
const stateStore = new ReleaseStateStore(request.dataDir);
|
|
31
32
|
let total = 0;
|
|
32
33
|
let completed = 0;
|
|
33
34
|
const candidate = await materializeRelease(request.packageRoot, request.dataDir, {
|
|
@@ -211,4 +212,3 @@ function summarize(text) {
|
|
|
211
212
|
const lines = text.split(/\r?\n/).map(line => line.trim()).filter(line => line.length > 0);
|
|
212
213
|
return lines.length === 0 ? "" : `: ${lines.slice(0, 4).join(" | ")}`;
|
|
213
214
|
}
|
|
214
|
-
function errorMessage(error) { return error instanceof Error ? error.message : String(error); }
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type { UpdateChannel } from "./types.js";
|
|
2
2
|
import { type UpdateTransaction } from "./update-transaction.js";
|
|
3
|
-
export declare const UPDATE_EXECUTION_LEASE_FILENAME = "update-execution.json";
|
|
4
3
|
declare const LEASE_SCHEMA = 1;
|
|
5
|
-
|
|
4
|
+
type UpdateExecutionMode = "manual" | "automatic";
|
|
6
5
|
export interface UpdateExecutionOwner {
|
|
7
6
|
readonly schema: typeof LEASE_SCHEMA;
|
|
8
7
|
readonly ownerId: string;
|
|
@@ -14,7 +13,7 @@ export interface UpdateExecutionOwner {
|
|
|
14
13
|
readonly mode: UpdateExecutionMode;
|
|
15
14
|
readonly acquiredAt: string;
|
|
16
15
|
}
|
|
17
|
-
|
|
16
|
+
type UpdateExecutionLeaseResult = {
|
|
18
17
|
readonly status: "acquired";
|
|
19
18
|
readonly owner: UpdateExecutionOwner;
|
|
20
19
|
release(): Promise<void>;
|
|
@@ -4,7 +4,8 @@ import { dirname, resolve } from "node:path";
|
|
|
4
4
|
import lockfile from "proper-lockfile";
|
|
5
5
|
import { processIsAlive } from "./process-liveness.js";
|
|
6
6
|
import { UpdateTransactionStore } from "./update-transaction.js";
|
|
7
|
-
|
|
7
|
+
import { samePath } from "./managed-path.js";
|
|
8
|
+
const UPDATE_EXECUTION_LEASE_FILENAME = "update-execution.json";
|
|
8
9
|
const LEASE_SCHEMA = 1;
|
|
9
10
|
const MAX_LEASE_BYTES = 8_192;
|
|
10
11
|
/**
|
|
@@ -146,13 +147,6 @@ async function foreignActiveTransaction(dataDir, owner, requested) {
|
|
|
146
147
|
&& samePath(requested.packageRoot, owner.packageRoot);
|
|
147
148
|
return matches ? null : transaction;
|
|
148
149
|
}
|
|
149
|
-
function samePath(left, right) {
|
|
150
|
-
const canonicalLeft = resolve(left);
|
|
151
|
-
const canonicalRight = resolve(right);
|
|
152
|
-
return process.platform === "win32"
|
|
153
|
-
? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase()
|
|
154
|
-
: canonicalLeft === canonicalRight;
|
|
155
|
-
}
|
|
156
150
|
function currentProcessStartIdentity() {
|
|
157
151
|
return `${process.pid}:${Math.floor(Date.now() - process.uptime() * 1_000)}`;
|
|
158
152
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ProductPaths } from "../lifecycle/index.js";
|
|
2
|
+
import type { UpdateRecoveryState, UpdateTransaction } from "./update-transaction.js";
|
|
3
|
+
import { type ProtectedPackageReplacementResult } from "./update-recovery.js";
|
|
4
|
+
/** The approved release protected replacement restores when the new package cannot launch. */
|
|
5
|
+
export interface UpdatePriorRelease {
|
|
6
|
+
readonly releaseId: string;
|
|
7
|
+
readonly releaseRoot: string;
|
|
8
|
+
readonly contentDigest: string;
|
|
9
|
+
}
|
|
10
|
+
/** What an update knows about the release that was active when it began. */
|
|
11
|
+
export interface UpdatePriorReleaseProtection {
|
|
12
|
+
/** The active release to roll back to, or null when none was recorded. */
|
|
13
|
+
readonly priorActiveReleaseId: string | null;
|
|
14
|
+
/** The approved record for a release id, or undefined when it cannot protect replacement. */
|
|
15
|
+
approvedRelease(releaseId: string | null): UpdatePriorRelease | undefined;
|
|
16
|
+
}
|
|
17
|
+
export interface UpdatePackageReplacementInput {
|
|
18
|
+
readonly globalRoot: string;
|
|
19
|
+
readonly npmCliRoot: string;
|
|
20
|
+
readonly npmCli?: string;
|
|
21
|
+
readonly packageRoot: string;
|
|
22
|
+
readonly transaction: UpdateTransaction;
|
|
23
|
+
readonly priorRelease: UpdatePriorRelease;
|
|
24
|
+
readonly output: {
|
|
25
|
+
stderr(message: string): void;
|
|
26
|
+
};
|
|
27
|
+
readonly onRecoveryState: (state: UpdateRecoveryState) => Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The update steps that touch npm and release storage. Every update runs all of them in the same
|
|
31
|
+
* order; a test replaces a step's behaviour, never which steps run.
|
|
32
|
+
*/
|
|
33
|
+
export interface UpdateInstaller {
|
|
34
|
+
/** Resolve npm's CLI entry before anything changes; a throw stops the update with nothing changed. */
|
|
35
|
+
preflight(npmCliRoot: string): Promise<string | undefined>;
|
|
36
|
+
/** Make sure an approved release can launch while npm replaces the package. */
|
|
37
|
+
protectPriorRelease(packageRoot: string): Promise<UpdatePriorReleaseProtection>;
|
|
38
|
+
replacePackage(input: UpdatePackageReplacementInput): Promise<ProtectedPackageReplacementResult>;
|
|
39
|
+
/** Return to the prior release after a failure, describing what happened. "rolled back" means it did. */
|
|
40
|
+
rollback(priorReleaseId: string | null): Promise<string>;
|
|
41
|
+
/** Release cleanup committed after activation and before success is reported. */
|
|
42
|
+
maintenance(): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
/** The production installer: npm preflight, recovery release, protected replacement, rollback and release cleanup. */
|
|
45
|
+
export declare function createProtectedUpdateInstaller(paths: ProductPaths, environment: NodeJS.ProcessEnv): UpdateInstaller;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { certifyMaterializedRelease } from "./bootstrap.js";
|
|
2
|
+
import { scheduleReleaseCleanup } from "./release-gc.js";
|
|
3
|
+
import { ReleaseStateStore } from "./release-state.js";
|
|
4
|
+
import { materializeRelease, readMaterializedRelease } from "./release-store.js";
|
|
5
|
+
import { resolveNpmCli, runProtectedPackageReplacement } from "./update-recovery.js";
|
|
6
|
+
/** The production installer: npm preflight, recovery release, protected replacement, rollback and release cleanup. */
|
|
7
|
+
export function createProtectedUpdateInstaller(paths, environment) {
|
|
8
|
+
const dataDir = paths.dataDir;
|
|
9
|
+
return {
|
|
10
|
+
preflight: async (npmCliRoot) => await resolveNpmCli(npmCliRoot, environment),
|
|
11
|
+
protectPriorRelease: async (packageRoot) => await protectPriorRelease(dataDir, packageRoot),
|
|
12
|
+
replacePackage: async (input) => await runProtectedPackageReplacement({ ...input, dataDir, environment }),
|
|
13
|
+
rollback: async (priorReleaseId) => await rollbackPriorRelease(dataDir, priorReleaseId),
|
|
14
|
+
maintenance: async () => { await scheduleReleaseCleanup(dataDir, paths); },
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
async function protectPriorRelease(dataDir, packageRoot) {
|
|
18
|
+
const releaseStateStore = new ReleaseStateStore(dataDir);
|
|
19
|
+
let state = await releaseStateStore.read();
|
|
20
|
+
let priorActiveReleaseId = state.references.active;
|
|
21
|
+
if (priorActiveReleaseId === null || state.releases[priorActiveReleaseId]?.approval !== "approved") {
|
|
22
|
+
// Invariant: protected replacement needs an immutable launch authority that npm cannot rename.
|
|
23
|
+
const recoveryRelease = await materializeRelease(packageRoot, dataDir);
|
|
24
|
+
await releaseStateStore.recordCandidate(recoveryRelease);
|
|
25
|
+
const diagnostics = await certifyMaterializedRelease(recoveryRelease, dataDir);
|
|
26
|
+
await releaseStateStore.approve(recoveryRelease.releaseId, diagnostics);
|
|
27
|
+
await releaseStateStore.activate(recoveryRelease.releaseId);
|
|
28
|
+
state = await releaseStateStore.read();
|
|
29
|
+
priorActiveReleaseId = recoveryRelease.releaseId;
|
|
30
|
+
}
|
|
31
|
+
const releases = state.releases;
|
|
32
|
+
return {
|
|
33
|
+
priorActiveReleaseId,
|
|
34
|
+
approvedRelease: releaseId => {
|
|
35
|
+
const record = releaseId === null ? undefined : releases[releaseId];
|
|
36
|
+
return record?.approval === "approved" ? record : undefined;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
async function rollbackPriorRelease(dataDir, priorReleaseId) {
|
|
41
|
+
if (!priorReleaseId)
|
|
42
|
+
return "no prior release was available for rollback";
|
|
43
|
+
const stateStore = new ReleaseStateStore(dataDir);
|
|
44
|
+
const state = await stateStore.read();
|
|
45
|
+
const prior = state.releases[priorReleaseId];
|
|
46
|
+
if (!prior || prior.approval !== "approved")
|
|
47
|
+
return "prior release is not a verified rollback candidate";
|
|
48
|
+
if (state.references.active !== priorReleaseId) {
|
|
49
|
+
if (state.references.rollback === priorReleaseId)
|
|
50
|
+
await stateStore.rollback();
|
|
51
|
+
else
|
|
52
|
+
throw new Error(`prior release ${priorReleaseId} is not the recorded rollback release`);
|
|
53
|
+
}
|
|
54
|
+
// Invariant: rollback selects only a prior release whose retained content still verifies.
|
|
55
|
+
await readMaterializedRelease(prior.releaseRoot);
|
|
56
|
+
return "rolled back";
|
|
57
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ReleaseState, ReleaseRecord } from "./release-state.js";
|
|
2
2
|
import type { UpdateTransaction } from "./update-transaction.js";
|
|
3
3
|
/** Keep interactive launches on the last successful release until the update commits success. */
|
|
4
|
-
export declare function selectUpdateLaunchRelease(state:
|
|
4
|
+
export declare function selectUpdateLaunchRelease(state: ReleaseState, transaction: UpdateTransaction | null): ReleaseRecord | null;
|
|
@@ -6,6 +6,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
|
|
7
7
|
import { processIsAlive } from "./process-liveness.js";
|
|
8
8
|
import { PRIVATE_LAUNCH_CONTRACT, assertCurrentLaunchContract } from "../launch-context/index.js";
|
|
9
|
+
import { isDirectChild, samePath } from "./managed-path.js";
|
|
9
10
|
export const UPDATE_RECOVERY_SCHEMA = "a1-update-recovery-v1";
|
|
10
11
|
const WORKER_TIMEOUT_MS = 15 * 60 * 1_000;
|
|
11
12
|
const POLL_MS = 50;
|
|
@@ -429,9 +430,6 @@ async function writeDurableJson(path, value) {
|
|
|
429
430
|
await rename(temporary, path);
|
|
430
431
|
}
|
|
431
432
|
async function readJson(path) { return JSON.parse(await readFile(path, "utf8")); }
|
|
432
|
-
function samePath(left, right) {
|
|
433
|
-
return process.platform === "win32" ? resolve(left).toLowerCase() === resolve(right).toLowerCase() : resolve(left) === resolve(right);
|
|
434
|
-
}
|
|
435
433
|
function sameSegment(left, right, platform) {
|
|
436
434
|
return platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
437
435
|
}
|
|
@@ -443,11 +441,6 @@ function containedBy(parent, child) {
|
|
|
443
441
|
return fromParent.length > 0 && fromParent !== ".." && !fromParent.startsWith(`..${sep}`) && !isAbsolute(fromParent);
|
|
444
442
|
}
|
|
445
443
|
function assertDirectChild(parent, child) {
|
|
446
|
-
|
|
447
|
-
const actualParent = dirname(resolve(child));
|
|
448
|
-
const matches = process.platform === "win32"
|
|
449
|
-
? actualParent.toLowerCase() === expectedParent.toLowerCase()
|
|
450
|
-
: actualParent === expectedParent;
|
|
451
|
-
if (!matches)
|
|
444
|
+
if (!isDirectChild(parent, child))
|
|
452
445
|
throw new Error(`update recovery path is outside its managed root: ${child}`);
|
|
453
446
|
}
|
|
@@ -3,7 +3,8 @@ import { type RegistryFetcher } from "./latest-release.js";
|
|
|
3
3
|
import { type UpdateActivationPhase, type UpdateMaterializationProgress } from "./update-activation.js";
|
|
4
4
|
import { type UpdateRecoveryState, type UpdateTransaction, type UpdateTransactionPhase } from "./update-transaction.js";
|
|
5
5
|
import { type UpdateExecutionOwner } from "./update-execution-lease.js";
|
|
6
|
-
import {
|
|
6
|
+
import { type UpdateInstaller } from "./update-installer.js";
|
|
7
|
+
export type { UpdateInstaller, UpdatePackageReplacementInput, UpdatePriorRelease, UpdatePriorReleaseProtection, } from "./update-installer.js";
|
|
7
8
|
export declare const PRODUCT_PACKAGE: string;
|
|
8
9
|
export type { UpdateChannel } from "./types.js";
|
|
9
10
|
export interface ProcessRequest {
|
|
@@ -76,12 +77,8 @@ export interface SelfUpdateOptions {
|
|
|
76
77
|
fetcher?: RegistryFetcher;
|
|
77
78
|
lifecycle?: UpdateLifecycleCoordinator;
|
|
78
79
|
transactionStore?: UpdateTransactionJournal;
|
|
79
|
-
/**
|
|
80
|
-
|
|
81
|
-
/** Test seam for proving replacement-authority preflight ordering. */
|
|
82
|
-
npmCliResolver?: typeof resolveNpmCli;
|
|
83
|
-
/** Test or embedding seam for post-activation release maintenance. */
|
|
84
|
-
maintenance?: () => Promise<void>;
|
|
80
|
+
/** The npm and release-storage steps; defaults to protected replacement of the managed package. */
|
|
81
|
+
installer?: UpdateInstaller;
|
|
85
82
|
progress?: boolean;
|
|
86
83
|
onPhaseTiming?: (event: UpdatePhaseTimingEvent) => void;
|
|
87
84
|
now?: () => number;
|
|
@@ -107,22 +104,6 @@ export interface UpdateTransactionJournal {
|
|
|
107
104
|
finish(status: "completed" | "rolled-back" | "failed", error?: string | null): Promise<UpdateTransaction>;
|
|
108
105
|
clearCompleted(): Promise<void>;
|
|
109
106
|
}
|
|
110
|
-
export interface UpdatePackageReplacementInput {
|
|
111
|
-
readonly dataDir: string;
|
|
112
|
-
readonly globalRoot: string;
|
|
113
|
-
readonly npmCliRoot: string;
|
|
114
|
-
readonly npmCli?: string;
|
|
115
|
-
readonly packageRoot: string;
|
|
116
|
-
readonly transaction: UpdateTransaction;
|
|
117
|
-
readonly priorRelease: {
|
|
118
|
-
readonly releaseId: string;
|
|
119
|
-
readonly releaseRoot: string;
|
|
120
|
-
readonly contentDigest: string;
|
|
121
|
-
};
|
|
122
|
-
readonly output: UpdateOutput;
|
|
123
|
-
readonly environment: NodeJS.ProcessEnv;
|
|
124
|
-
readonly onRecoveryState: (state: UpdateRecoveryState) => Promise<void>;
|
|
125
|
-
}
|
|
126
107
|
/**
|
|
127
108
|
* The package tree is checked for holders by renaming it and renaming it back, because on
|
|
128
109
|
* Windows that is the one operation that fails while any file under it is open. A holder is
|
|
@@ -135,8 +116,6 @@ export declare const UPDATE_ALREADY_RUNNING_EXIT_CODE = 75;
|
|
|
135
116
|
export declare function isPackageLockError(error: unknown): boolean;
|
|
136
117
|
/** What the user reads when the package stayed held for the whole patience window. */
|
|
137
118
|
export declare function lockedPackageDiagnostic(packageRoot: string, waitedMs: number, attempts: number, error: unknown): string;
|
|
138
|
-
/** Bound on the child diagnostics an update keeps: enough for npm's failure reason, never a log. */
|
|
139
|
-
export declare const CHILD_DIAGNOSTIC_LIMIT = 8000;
|
|
140
119
|
export declare function createNpmProcessRunner(platform?: NodeJS.Platform): UpdateProcessRunner;
|
|
141
120
|
export declare function createUpdateLifecycleCoordinator(environment?: NodeJS.ProcessEnv, fileSystem?: UpdateFileSystem, _output?: UpdateOutput, patience?: UpdateUnlockPatience): UpdateLifecycleCoordinator;
|
|
142
121
|
/** Renders the terminal-only update meter; the visual preview shares this exact frame. */
|