@timurproko/a1 0.2.7-dev.1234 → 0.2.7-dev.1236

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.
Files changed (36) hide show
  1. package/dist/app/session-shell/dock-chrome.js +8 -4
  2. package/dist/app/session-shell/transcript-document.js +1 -0
  3. package/dist/composition/release-update-observation.js +15 -7
  4. package/dist/contracts/owned-ui/session-workflows.d.ts +1 -1
  5. package/dist/foundation/release/automatic-update.d.ts +3 -1
  6. package/dist/foundation/release/automatic-update.js +29 -4
  7. package/dist/foundation/release/index.d.ts +2 -2
  8. package/dist/foundation/release/index.js +2 -2
  9. package/dist/foundation/release/prepared-update-activation.d.ts +3 -0
  10. package/dist/foundation/release/prepared-update-activation.js +27 -0
  11. package/dist/foundation/release/update-activation.d.ts +7 -0
  12. package/dist/foundation/release/update-activation.js +29 -10
  13. package/dist/foundation/release/update-transaction.d.ts +1 -0
  14. package/dist/foundation/release/update-transaction.js +5 -0
  15. package/dist/foundation/release/update.d.ts +3 -0
  16. package/dist/foundation/release/update.js +30 -12
  17. package/dist/integrations/pi/components/shell-footer-status.js +9 -4
  18. package/dist/integrations/pi/components/shell-shared-facade.d.ts +3 -0
  19. package/dist/integrations/pi/components/shell-shared-facade.js +8 -0
  20. package/dist/integrations/pi/engine/adapter.js +9 -1
  21. package/dist/integrations/pi/engine/diagnostics-state.d.ts +1 -0
  22. package/dist/integrations/pi/engine/diagnostics-state.js +15 -2
  23. package/dist/native/darwin-arm64/manifest.json +1 -1
  24. package/dist/native/darwin-arm64/terminal-host.manifest.json +3 -3
  25. package/dist/native/darwin-arm64/terminal-host.node +0 -0
  26. package/dist/native/darwin-x64/manifest.json +1 -1
  27. package/dist/native/darwin-x64/terminal-host.manifest.json +3 -3
  28. package/dist/native/darwin-x64/terminal-host.node +0 -0
  29. package/dist/native/linux-x64/manifest.json +1 -1
  30. package/dist/native/linux-x64/terminal-host.manifest.json +3 -3
  31. package/dist/native/linux-x64/terminal-host.node +0 -0
  32. package/dist/native/win32-x64/manifest.json +2 -2
  33. package/dist/native/win32-x64/process-guardian.node +0 -0
  34. package/dist/native/win32-x64/terminal-host.manifest.json +3 -3
  35. package/dist/native/win32-x64/terminal-host.node +0 -0
  36. package/package.json +3 -3
@@ -1,7 +1,7 @@
1
1
  import { COPY_ACKNOWLEDGEMENT_DURATION_MS } from "../../ui/components/selection-copy.js";
2
2
  import { renderPiShellCommandMessage, renderPiShellReleaseUpdateBanner, renderPiShellStatusText, } from "../../integrations/pi/components/shell-presenters-info.js";
3
3
  import { PINNED_PI_LAYOUT, piTheme } from "../../integrations/pi/components/upstream/theme/theme.js";
4
- import { piShellTruncateToWidth, renderPiShellInstalledUpdateStatus } from "../../integrations/pi/components/shell-shared-facade.js";
4
+ import { piShellTruncateToWidth, renderPiShellBlockedUpdateStatus, renderPiShellInstalledUpdateStatus } from "../../integrations/pi/components/shell-shared-facade.js";
5
5
  import { parseReleaseUpdateDiagnostic } from "./transcript-document.js";
6
6
  /**
7
7
  * The transient chrome around bare A1's dock: the one command notice above the editor, the release
@@ -84,9 +84,13 @@ export class DockChrome {
84
84
  const acknowledgement = this.renderCopyAcknowledgement(width);
85
85
  if (acknowledgement !== undefined)
86
86
  return acknowledgement;
87
- if (!diagnostics.some(diagnostic => diagnostic.code === "release-update-installed"))
88
- return undefined;
89
- return renderPiShellInstalledUpdateStatus(width) || undefined;
87
+ if (diagnostics.some(diagnostic => diagnostic.code === "release-update-installed")) {
88
+ return renderPiShellInstalledUpdateStatus(width) || undefined;
89
+ }
90
+ if (diagnostics.some(diagnostic => diagnostic.code === "release-update-blocked")) {
91
+ return renderPiShellBlockedUpdateStatus(width) || undefined;
92
+ }
93
+ return undefined;
90
94
  }
91
95
  renderReleaseBanner(diagnostics, width) {
92
96
  if (this.#releaseDismissed)
@@ -261,6 +261,7 @@ export class TranscriptDocument {
261
261
  rows.push(...diagnostics
262
262
  .filter(diagnostic => diagnostic.code !== "engine-startup" && diagnostic.code !== "project-trust"
263
263
  && diagnostic.code !== "release-update" && diagnostic.code !== "release-update-installed"
264
+ && diagnostic.code !== "release-update-blocked"
264
265
  && diagnostic.code !== "package-updates" && diagnostic.code !== "changelog-collapsed"
265
266
  && diagnostic.code !== "changelog-expanded")
266
267
  .slice(-3)
@@ -41,14 +41,22 @@ class ReleaseUpdateObservation {
41
41
  }
42
42
  if (input.mode !== "auto")
43
43
  return;
44
+ const announce = (status, version) => {
45
+ const actual = input.clientVersion?.();
46
+ const key = `${status}:${version}`;
47
+ if (key === this.#announced || this.#controller.signal.aborted
48
+ || status !== "blocked-cleared" && actual && !releases.isNewerRelease(version, actual))
49
+ return;
50
+ this.#announced = key;
51
+ input.backend.extensions.announceReleaseUpdate({ status, version });
52
+ };
44
53
  const installed = await import("../foundation/release/automatic-update.js")
45
- .then(module => module.requestAutomaticUpdate({ release, runningVersion, signal: this.#controller.signal }));
46
- const actual = input.clientVersion?.();
47
- if (installed === null || installed === this.#announced || this.#controller.signal.aborted
48
- || actual && !releases.isNewerRelease(installed, actual))
49
- return;
50
- this.#announced = installed;
51
- input.backend.extensions.announceReleaseUpdate({ status: "installed", version: installed });
54
+ .then(module => module.requestAutomaticUpdate({
55
+ release, runningVersion, signal: this.#controller.signal,
56
+ onActivationBlocked: version => announce(version === null ? "blocked-cleared" : "blocked", version ?? release.version),
57
+ }));
58
+ if (installed !== null)
59
+ announce("installed", installed);
52
60
  }
53
61
  async #run() {
54
62
  if (this.#running) {
@@ -347,6 +347,6 @@ export type OwnedUiReleaseUpdate = {
347
347
  readonly command: string;
348
348
  readonly changelogUrl: string | null;
349
349
  } | {
350
- readonly status: "installed";
350
+ readonly status: "blocked" | "blocked-cleared" | "installed";
351
351
  readonly version: string;
352
352
  };
@@ -1,11 +1,12 @@
1
1
  import { type AvailableRelease, type ReleaseChannel } from "./latest-release.js";
2
2
  export declare const AUTOMATIC_UPDATE_STATE_SCHEMA = 1;
3
3
  export declare const AUTOMATIC_UPDATE_RETRY_MS: number;
4
+ export declare const AUTOMATIC_UPDATE_ACTIVATION_RETRY_MS: number;
4
5
  export interface AutomaticUpdateState {
5
6
  readonly schema: typeof AUTOMATIC_UPDATE_STATE_SCHEMA;
6
7
  readonly channel: ReleaseChannel;
7
8
  readonly targetVersion: string;
8
- readonly status: "running" | "installed" | "failed";
9
+ readonly status: "running" | "blocked" | "installed" | "failed";
9
10
  readonly attemptedAt: number;
10
11
  readonly updatedAt: number;
11
12
  readonly installedVersion: string | null;
@@ -31,6 +32,7 @@ export interface AutomaticUpdateRequestOptions {
31
32
  readonly packageRoot: string;
32
33
  };
33
34
  readonly activeVersion?: () => Promise<string | null>;
35
+ readonly onActivationBlocked?: (version: string | null) => void;
34
36
  }
35
37
  /** Start or observe one silent update and resolve with the active newer version once restart is useful. */
36
38
  export declare function requestAutomaticUpdate(options: AutomaticUpdateRequestOptions): Promise<string | null>;
@@ -11,9 +11,10 @@ import { isNewerRelease, releaseChannelOf } from "./latest-release.js";
11
11
  import { readCertifiedReleaseManifest, resolveReleaseEntryPoint } from "./release-store.js";
12
12
  import { acquireUpdateExecutionLease, readUpdateExecutionOwner } from "./update-execution-lease.js";
13
13
  import { UpdateTransactionStore } from "./update-transaction.js";
14
- import { runSelfUpdate, UPDATE_ALREADY_RUNNING_EXIT_CODE } from "./update.js";
14
+ import { runSelfUpdate, UPDATE_ACTIVATION_BLOCKED_EXIT_CODE, UPDATE_ALREADY_RUNNING_EXIT_CODE } from "./update.js";
15
15
  export const AUTOMATIC_UPDATE_STATE_SCHEMA = 1;
16
16
  export const AUTOMATIC_UPDATE_RETRY_MS = 24 * 60 * 60_000;
17
+ export const AUTOMATIC_UPDATE_ACTIVATION_RETRY_MS = 15 * 60_000;
17
18
  const AUTOMATIC_UPDATE_STATE_FILENAME = "automatic-update.json";
18
19
  const MAX_STATE_BYTES = 16_384;
19
20
  const OBSERVER_POLL_MS = 250;
@@ -104,6 +105,14 @@ export async function requestAutomaticUpdate(options) {
104
105
  await store.write(existing).catch(() => undefined);
105
106
  }
106
107
  }
108
+ const blockedUpdatedAt = existing?.status === "blocked" && existing.channel === options.release.channel
109
+ && existing.targetVersion === options.release.version ? existing.updatedAt : null;
110
+ const observedBlocked = blockedUpdatedAt !== null;
111
+ if (observedBlocked) {
112
+ options.onActivationBlocked?.(options.release.version);
113
+ if (now() - blockedUpdatedAt >= 0 && now() - blockedUpdatedAt < AUTOMATIC_UPDATE_ACTIVATION_RETRY_MS)
114
+ return null;
115
+ }
107
116
  if (existing?.status === "failed" && existing.channel === options.release.channel && now() - existing.attemptedAt >= 0
108
117
  && now() - existing.attemptedAt < AUTOMATIC_UPDATE_RETRY_MS
109
118
  && !isNewerRelease(options.release.version, existing.targetVersion))
@@ -136,6 +145,8 @@ export async function requestAutomaticUpdate(options) {
136
145
  // Invariant: no worker began this attempt. Do not invent a successful install or an owner.
137
146
  await store.write(state({ packageRoot: worker.packageRoot, channel: options.release.channel,
138
147
  targetVersion: options.release.version, dataDir: paths.dataDir }, "failed", now(), null, "worker-start-failed")).catch(() => undefined);
148
+ if (observedBlocked)
149
+ options.onActivationBlocked?.(null);
139
150
  return null;
140
151
  }
141
152
  }
@@ -149,8 +160,15 @@ export async function requestAutomaticUpdate(options) {
149
160
  if (installed !== null)
150
161
  return installed;
151
162
  const state = await store.read().catch(() => null);
152
- if (state?.targetVersion === options.release.version && state.status === "failed" && state.attemptedAt >= startedAt)
163
+ if (state?.targetVersion === options.release.version && state.status === "blocked") {
164
+ options.onActivationBlocked?.(state.targetVersion);
153
165
  return null;
166
+ }
167
+ if (state?.targetVersion === options.release.version && state.status === "failed" && state.attemptedAt >= startedAt) {
168
+ if (observedBlocked)
169
+ options.onActivationBlocked?.(null);
170
+ return null;
171
+ }
154
172
  const owner = await readUpdateExecutionOwner(paths.dataDir).catch(() => null);
155
173
  if ((owner === null || !processIsAlive(owner.pid)) && now() - startedAt >= WORKER_START_GRACE_MS)
156
174
  return null;
@@ -200,6 +218,12 @@ export async function runAutomaticUpdateWorker(argv, environment = process.env)
200
218
  });
201
219
  if (code === UPDATE_ALREADY_RUNNING_EXIT_CODE)
202
220
  return 0;
221
+ if (code === UPDATE_ACTIVATION_BLOCKED_EXIT_CODE) {
222
+ await runningWrite;
223
+ if (acquired)
224
+ await store.write(state(parsed, "blocked", attemptedAt, null, "resident-continuity-blocked"));
225
+ return code;
226
+ }
203
227
  if (code !== 0) {
204
228
  await runningWrite;
205
229
  if (acquired)
@@ -313,10 +337,11 @@ function parseWorkerArguments(argv) {
313
337
  }
314
338
  function validateState(value) {
315
339
  if (value.schema !== AUTOMATIC_UPDATE_STATE_SCHEMA || (value.channel !== "stable" && value.channel !== "development")
316
- || validSemver(value.targetVersion) === null || !["running", "installed", "failed"].includes(value.status)
340
+ || validSemver(value.targetVersion) === null || !["running", "blocked", "installed", "failed"].includes(value.status)
317
341
  || !Number.isFinite(value.attemptedAt) || !Number.isFinite(value.updatedAt)
318
342
  || (value.installedVersion !== null && validSemver(value.installedVersion) === null)
319
- || (value.failure !== null && (typeof value.failure !== "string" || value.failure.length > 512))) {
343
+ || (value.failure !== null && (typeof value.failure !== "string" || value.failure.length > 512))
344
+ || value.status === "blocked" && (value.installedVersion !== null || value.failure !== "resident-continuity-blocked")) {
320
345
  throw new Error("invalid automatic update state");
321
346
  }
322
347
  }
@@ -21,9 +21,9 @@ export { createRestartSeal, readRestartCertifiedRelease, releaseCertificationDoc
21
21
  export type { RestartSeal, RestartValidationEvent } from "./restart-certification.js";
22
22
  export { STABLE_RELEASE_SCHEMA, createStableReleaseEvidence, verifyStableRegistry } from "./stable-release.js";
23
23
  export type { StableRegistryState, StableRegistryVerificationOptions, StableReleaseEvidence, StableReleaseEvidenceInput } from "./stable-release.js";
24
- export { PACKAGE_UNLOCK_PATIENCE_MS, UPDATE_ALREADY_RUNNING_EXIT_CODE, PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, isPackageLockError, lockedPackageDiagnostic, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
24
+ export { PACKAGE_UNLOCK_PATIENCE_MS, UPDATE_ACTIVATION_BLOCKED_EXIT_CODE, UPDATE_ALREADY_RUNNING_EXIT_CODE, PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, isPackageLockError, lockedPackageDiagnostic, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
25
25
  export type { ProcessRequest, ProcessResult, SelfUpdateOptions, UpdateActivationPhase, UpdateChannel, UpdateFileMetadata, UpdateFileSystem, UpdateLifecycleCoordinator, UpdateMaterializationProgress, UpdateMeasuredPhase, UpdateOutput, UpdateOwnershipAction, UpdatePackageReplacementInput, UpdatePerformanceEvidence, UpdatePhaseTimingEvent, UpdateProcessRunner, UpdateTransactionJournal, UpdateUnlockPatience, } from "./update.js";
26
- export { UPDATE_ACTIVATION_CONTRACT, UPDATE_ACTIVATION_ENTRY, UPDATE_ACTIVATION_MANIFEST_FIELD, activateInstalledRelease, delegateActivation, readActivationContracts, runActivationEntry, } from "./update-activation.js";
26
+ export { UPDATE_ACTIVATION_CONTRACT, UPDATE_ACTIVATION_ENTRY, UPDATE_ACTIVATION_MANIFEST_FIELD, UpdateActivationBlockedError, activateInstalledRelease, delegateActivation, readActivationContracts, runActivationEntry, } from "./update-activation.js";
27
27
  export type { UpdateActivationCallbacks, UpdateActivationEvent, UpdateActivationRequest } from "./update-activation.js";
28
28
  export { selectSupervisorLaunchReleaseId, selectUpdateLaunchRelease } from "./update-launch.js";
29
29
  export { UPDATE_RECOVERY_SCHEMA, cleanupUpdateRecoveryCapsules, inspectUpdateLauncherSet, npmPrefixForGlobalRoot, prepareUpdateRecoveryCapsule, readUpdateRecoveryCapsule, removeUpdateRecoveryCapsule, runProtectedPackageReplacement, updateLauncherPaths, updateNpmInstallArguments, } from "./update-recovery.js";
@@ -10,8 +10,8 @@ export { collectRelease, prepareReleaseCleanup, runBoundedReleaseCleanup, runRel
10
10
  export { RELEASE_MANIFEST_FILENAME, ReleaseRepairUnavailableError, assertCertifiedFilesPresent, assertImmutableExecutionRoot, consumeMaterializationProof, materializeRelease, readCertifiedReleaseManifest, readMaterializedRelease, repairMaterializedRelease, resolveReleaseEntryPoint, verifyMaterializedRelease, } from "./release-store.js";
11
11
  export { createRestartSeal, readRestartCertifiedRelease, releaseCertificationDocument, restartSealDigest } from "./restart-certification.js";
12
12
  export { STABLE_RELEASE_SCHEMA, createStableReleaseEvidence, verifyStableRegistry } from "./stable-release.js";
13
- export { PACKAGE_UNLOCK_PATIENCE_MS, UPDATE_ALREADY_RUNNING_EXIT_CODE, PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, isPackageLockError, lockedPackageDiagnostic, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
14
- export { UPDATE_ACTIVATION_CONTRACT, UPDATE_ACTIVATION_ENTRY, UPDATE_ACTIVATION_MANIFEST_FIELD, activateInstalledRelease, delegateActivation, readActivationContracts, runActivationEntry, } from "./update-activation.js";
13
+ export { PACKAGE_UNLOCK_PATIENCE_MS, UPDATE_ACTIVATION_BLOCKED_EXIT_CODE, UPDATE_ALREADY_RUNNING_EXIT_CODE, PRODUCT_PACKAGE, assertUpdatePerformanceBudget, createNpmProcessRunner, createUpdateLifecycleCoordinator, isPackageLockError, lockedPackageDiagnostic, planUpdateOwnership, renderUpdateProgressBar, runSelfUpdate, } from "./update.js";
14
+ export { UPDATE_ACTIVATION_CONTRACT, UPDATE_ACTIVATION_ENTRY, UPDATE_ACTIVATION_MANIFEST_FIELD, UpdateActivationBlockedError, activateInstalledRelease, delegateActivation, readActivationContracts, runActivationEntry, } from "./update-activation.js";
15
15
  export { selectSupervisorLaunchReleaseId, selectUpdateLaunchRelease } from "./update-launch.js";
16
16
  export { UPDATE_RECOVERY_SCHEMA, cleanupUpdateRecoveryCapsules, inspectUpdateLauncherSet, npmPrefixForGlobalRoot, prepareUpdateRecoveryCapsule, readUpdateRecoveryCapsule, removeUpdateRecoveryCapsule, runProtectedPackageReplacement, updateLauncherPaths, updateNpmInstallArguments, } from "./update-recovery.js";
17
17
  export { UPDATE_JOURNAL_SCHEMA, UpdateTransactionStore } from "./update-transaction.js";
@@ -0,0 +1,3 @@
1
+ import { type UpdateActivationCallbacks, type UpdateActivationRequest } from "./update-activation.js";
2
+ /** Retry only the selection boundary for an exact candidate already materialized and certified. */
3
+ export declare function activatePreparedRelease(request: Omit<UpdateActivationRequest, "packageRoot">, callbacks: UpdateActivationCallbacks): Promise<void>;
@@ -0,0 +1,27 @@
1
+ import { resolve } from "node:path";
2
+ import { PRODUCT_IDENTITY } from "../../product-identity.js";
3
+ import { assertContinuityOrBlock } from "./update-activation.js";
4
+ import { ensureSupervisor } from "./bootstrap.js";
5
+ import { CohortStateStore } from "./cohort-state.js";
6
+ import { resolveProductPaths } from "../lifecycle/index.js";
7
+ import { readCertifiedReleaseManifest } from "./release-store.js";
8
+ /** Retry only the selection boundary for an exact candidate already materialized and certified. */
9
+ export async function activatePreparedRelease(request, callbacks) {
10
+ const stateStore = new CohortStateStore(request.dataDir);
11
+ const state = await stateStore.read();
12
+ const releaseId = state.references.pending;
13
+ const record = releaseId === null ? undefined : state.releases[releaseId];
14
+ if (record === undefined || record.approval !== "approved" || record.packageVersion !== request.targetVersion
15
+ || state.references.approved !== releaseId) {
16
+ throw new Error(`no certified prepared release matches target ${request.targetVersion}`);
17
+ }
18
+ const candidate = await readCertifiedReleaseManifest(record, resolve(request.dataDir, "releases"));
19
+ const paths = resolveProductPaths(request.environment);
20
+ const continuity = { releaseRoot: candidate.releaseRoot, dataDir: request.dataDir, environment: request.environment,
21
+ profileRoot: request.environment[PRODUCT_IDENTITY.environment.profileHome] ?? paths.configDir, runtimeDir: paths.runtimeDir };
22
+ await assertContinuityOrBlock(continuity);
23
+ await ensureSupervisor(candidate, request.environment);
24
+ await assertContinuityOrBlock(continuity);
25
+ await stateStore.activate(candidate.releaseId);
26
+ await callbacks.phase("active-reference-committed");
27
+ }
@@ -1,3 +1,4 @@
1
+ import type { ContinuityOptions } from "../resident-tabs/index.js";
1
2
  /**
2
3
  * The one activation contract an installed tree can offer the updater that installed it.
3
4
  * The updater knows nothing else about the tree: the manifest names the contracts the tree
@@ -8,6 +9,10 @@ export declare const UPDATE_ACTIVATION_ENTRY = "bin/activate.js";
8
9
  /** Manifest field listing the activation contracts an installed tree serves. */
9
10
  export declare const UPDATE_ACTIVATION_MANIFEST_FIELD = "updateActivationContracts";
10
11
  export type UpdateActivationPhase = "materialized" | "certified" | "active-reference-committed";
12
+ /** A certified candidate is safe to retain, but resident control continuity blocks selection. */
13
+ export declare class UpdateActivationBlockedError extends Error {
14
+ readonly code: "resident-continuity-blocked";
15
+ }
11
16
  /**
12
17
  * Copying the release is the longest step with nothing to say for itself, so it
13
18
  * reports the files it has written against the files it must write. A caller that
@@ -44,6 +49,7 @@ export type UpdateActivationEvent = {
44
49
  } | {
45
50
  readonly event: "failed";
46
51
  readonly message: string;
52
+ readonly code?: UpdateActivationBlockedError["code"];
47
53
  };
48
54
  /**
49
55
  * Activate the installed tree at `packageRoot` with this process's own release code:
@@ -70,3 +76,4 @@ export declare function delegateActivation(request: UpdateActivationRequest, cal
70
76
  export declare function runActivationEntry(argv: readonly string[], entryUrl: string, io?: {
71
77
  write(line: string): void;
72
78
  }, environment?: NodeJS.ProcessEnv): Promise<number>;
79
+ export declare function assertContinuityOrBlock(context: ContinuityOptions): Promise<void>;
@@ -19,6 +19,10 @@ export const UPDATE_ACTIVATION_ENTRY = "bin/activate.js";
19
19
  /** Manifest field listing the activation contracts an installed tree serves. */
20
20
  export const UPDATE_ACTIVATION_MANIFEST_FIELD = "updateActivationContracts";
21
21
  const ACTIVATION_DIAGNOSTIC_LIMIT = 2_000;
22
+ /** A certified candidate is safe to retain, but resident control continuity blocks selection. */
23
+ export class UpdateActivationBlockedError extends Error {
24
+ code = "resident-continuity-blocked";
25
+ }
22
26
  /**
23
27
  * Activate the installed tree at `packageRoot` with this process's own release code:
24
28
  * materialize it into the immutable store, certify, warm, verify supervision, and only
@@ -51,14 +55,16 @@ export async function activateInstalledRelease(request, callbacks) {
51
55
  callbacks.onWarmup?.("started");
52
56
  await warmMaterializedRelease(candidate, request.environment);
53
57
  callbacks.onWarmup?.("completed");
54
- const { assertResidentContinuity } = await import("../resident-tabs/index.js");
58
+ await completeActivation(candidate, request, callbacks, stateStore);
59
+ }
60
+ async function completeActivation(candidate, request, callbacks, stateStore) {
55
61
  const paths = resolveProductPaths(request.environment);
56
62
  const continuity = { releaseRoot: candidate.releaseRoot, dataDir: request.dataDir, environment: request.environment,
57
63
  profileRoot: request.environment[PRODUCT_IDENTITY.environment.profileHome] ?? paths.configDir, runtimeDir: paths.runtimeDir };
58
- await assertResidentContinuity(continuity);
64
+ await assertContinuityOrBlock(continuity);
59
65
  await ensureSupervisor(candidate, request.environment);
60
66
  // Invariant: revalidate after supervision, before committing client activation or restart readiness.
61
- await assertResidentContinuity(continuity);
67
+ await assertContinuityOrBlock(continuity);
62
68
  await stateStore.activate(candidate.releaseId);
63
69
  await callbacks.phase("active-reference-committed");
64
70
  }
@@ -102,14 +108,14 @@ export async function delegateActivation(request, callbacks) {
102
108
  events = decoder.push(chunk);
103
109
  }
104
110
  catch (error) {
105
- failure ??= errorMessage(error);
111
+ failure ??= new Error(errorMessage(error));
106
112
  return;
107
113
  }
108
114
  for (const event of events) {
109
115
  relay = relay.then(async () => {
110
116
  const parsed = parseActivationEvent(event);
111
117
  if (!parsed) {
112
- failure ??= `unrecognized activation event ${JSON.stringify(event).slice(0, 200)}`;
118
+ failure ??= new Error(`unrecognized activation event ${JSON.stringify(event).slice(0, 200)}`);
113
119
  return;
114
120
  }
115
121
  if (parsed.event === "materializing")
@@ -121,8 +127,10 @@ export async function delegateActivation(request, callbacks) {
121
127
  else if (parsed.event === "completed")
122
128
  completed = true;
123
129
  else
124
- failure ??= parsed.message;
125
- }).catch(error => { failure ??= errorMessage(error); });
130
+ failure ??= parsed.code === "resident-continuity-blocked"
131
+ ? new UpdateActivationBlockedError(parsed.message)
132
+ : new Error(parsed.message);
133
+ }).catch(error => { failure ??= new Error(errorMessage(error)); });
126
134
  }
127
135
  });
128
136
  const exit = await new Promise((resolvePromise, rejectPromise) => {
@@ -131,7 +139,7 @@ export async function delegateActivation(request, callbacks) {
131
139
  });
132
140
  await relay;
133
141
  if (failure)
134
- throw new Error(failure);
142
+ throw failure;
135
143
  if (exit.code !== 0 || !completed) {
136
144
  const status = exit.code === null ? exit.signal ?? "unknown status" : `status ${exit.code}`;
137
145
  throw new Error(`installed release activation exited with ${status}${summarize(diagnostics)}`);
@@ -160,7 +168,7 @@ export async function runActivationEntry(argv, entryUrl, io = { write: line => p
160
168
  return 0;
161
169
  }
162
170
  catch (error) {
163
- emit({ event: "failed", message: errorMessage(error) });
171
+ emit({ event: "failed", message: errorMessage(error), ...(error instanceof UpdateActivationBlockedError ? { code: error.code } : {}) });
164
172
  return 1;
165
173
  }
166
174
  }
@@ -198,11 +206,22 @@ function parseActivationEvent(value) {
198
206
  case "completed":
199
207
  return { event: "completed" };
200
208
  case "failed":
201
- return typeof record.message === "string" ? { event: "failed", message: record.message } : null;
209
+ return typeof record.message === "string" && (record.code === undefined || record.code === "resident-continuity-blocked")
210
+ ? { event: "failed", message: record.message, ...(record.code === undefined ? {} : { code: record.code }) }
211
+ : null;
202
212
  default:
203
213
  return null;
204
214
  }
205
215
  }
216
+ export async function assertContinuityOrBlock(context) {
217
+ const { assertResidentContinuity } = await import("../resident-tabs/index.js");
218
+ try {
219
+ await assertResidentContinuity(context);
220
+ }
221
+ catch (error) {
222
+ throw new UpdateActivationBlockedError(errorMessage(error), { cause: error });
223
+ }
224
+ }
206
225
  function summarize(text) {
207
226
  const lines = text.split(/\r?\n/).map(line => line.trim()).filter(line => line.length > 0);
208
227
  return lines.length === 0 ? "" : `: ${lines.slice(0, 4).join(" | ")}`;
@@ -37,6 +37,7 @@ export declare class UpdateTransactionStore {
37
37
  }): Promise<UpdateTransaction>;
38
38
  advance(phase: UpdateTransactionPhase): Promise<UpdateTransaction>;
39
39
  setRecovery(recovery: UpdateRecoveryState): Promise<UpdateTransaction>;
40
+ recordActiveError(error: string): Promise<UpdateTransaction>;
40
41
  finish(status: "completed" | "rolled-back" | "failed", error?: string | null): Promise<UpdateTransaction>;
41
42
  clearCompleted(): Promise<void>;
42
43
  }
@@ -49,6 +49,10 @@ export class UpdateTransactionStore {
49
49
  const current = await this.#requiredActive();
50
50
  return await this.#write({ ...current, recovery, updatedAt: new Date().toISOString() });
51
51
  }
52
+ async recordActiveError(error) {
53
+ const current = await this.#requiredActive();
54
+ return await this.#write({ ...current, error: error.replace(/[\r\n]+/gu, " ").slice(0, 2_000), updatedAt: new Date().toISOString() });
55
+ }
52
56
  async finish(status, error = null) {
53
57
  const current = await this.read();
54
58
  if (!current)
@@ -89,6 +93,7 @@ function validate(value) {
89
93
  if (value.schema !== UPDATE_JOURNAL_SCHEMA || typeof value.transactionId !== "string" || !["stable", "next"].includes(value.channel)
90
94
  || typeof value.targetVersion !== "string" || typeof value.packageRoot !== "string" || typeof value.startedAt !== "string"
91
95
  || typeof value.updatedAt !== "string" || phaseOrder(value.phase) < 0 || !["active", "completed", "rolled-back", "failed"].includes(value.status)
96
+ || (value.error !== null && (typeof value.error !== "string" || value.error.length > 2_000))
92
97
  || (value.recovery !== undefined && !validRecovery(value.recovery))) {
93
98
  throw new Error(`invalid ${PRODUCT_TEXT.displayName} update transaction journal`);
94
99
  }
@@ -95,6 +95,7 @@ export interface UpdateLifecycleCoordinator {
95
95
  }>;
96
96
  verifyPackageUnlocked(packageRoot: string): Promise<void>;
97
97
  activateInstalled(packageRoot: string, targetVersion: string, phase: (phase: UpdateActivationPhase) => Promise<void>, onMaterializing?: (progress: UpdateMaterializationProgress) => void, onWarmup?: (state: "started" | "completed") => void): Promise<void>;
98
+ activatePrepared?(targetVersion: string, phase: (phase: UpdateActivationPhase) => Promise<void>): Promise<void>;
98
99
  }
99
100
  export interface UpdateTransactionJournal {
100
101
  readonly path: string;
@@ -107,6 +108,7 @@ export interface UpdateTransactionJournal {
107
108
  }): Promise<UpdateTransaction>;
108
109
  advance(phase: UpdateTransactionPhase): Promise<UpdateTransaction>;
109
110
  setRecovery?(recovery: UpdateRecoveryState): Promise<UpdateTransaction>;
111
+ recordActiveError?(error: string): Promise<UpdateTransaction>;
110
112
  finish(status: "completed" | "rolled-back" | "failed", error?: string | null): Promise<UpdateTransaction>;
111
113
  clearCompleted(): Promise<void>;
112
114
  }
@@ -134,6 +136,7 @@ export interface UpdatePackageReplacementInput {
134
136
  */
135
137
  export declare const PACKAGE_UNLOCK_PATIENCE_MS = 15000;
136
138
  export declare const UPDATE_ALREADY_RUNNING_EXIT_CODE = 75;
139
+ export declare const UPDATE_ACTIVATION_BLOCKED_EXIT_CODE = 76;
137
140
  /** Whether a rename failure means something holds the tree, as opposed to the tree being wrong. */
138
141
  export declare function isPackageLockError(error: unknown): boolean;
139
142
  /** What the user reads when the package stayed held for the whole patience window. */
@@ -16,7 +16,7 @@ import { CohortStateStore } from "./cohort-state.js";
16
16
  import { cleanupVerifiedOwner, processIsAlive } from "./process-cleanup.js";
17
17
  import { materializeRelease, readMaterializedRelease } from "./release-store.js";
18
18
  import { scheduleReleaseCleanup } from "./release-gc.js";
19
- import { UPDATE_ACTIVATION_CONTRACT, activateInstalledRelease, delegateActivation, readActivationContracts, } from "./update-activation.js";
19
+ import { UPDATE_ACTIVATION_CONTRACT, UpdateActivationBlockedError, activateInstalledRelease, delegateActivation, readActivationContracts, } from "./update-activation.js";
20
20
  import { UpdateTransactionStore } from "./update-transaction.js";
21
21
  import { acquireUpdateExecutionLease, reclaimDeadLease } from "./update-execution-lease.js";
22
22
  import { npmPrefixForGlobalRoot, removeUpdateRecoveryCapsule, resolveNpmCli, runProtectedPackageReplacement, updateLauncherPaths, updateNpmInstallArguments, } from "./update-recovery.js";
@@ -37,6 +37,7 @@ const defaultFileSystem = {
37
37
  */
38
38
  export const PACKAGE_UNLOCK_PATIENCE_MS = 15_000;
39
39
  export const UPDATE_ALREADY_RUNNING_EXIT_CODE = 75;
40
+ export const UPDATE_ACTIVATION_BLOCKED_EXIT_CODE = 76;
40
41
  /** A named preview reads the registry's whole package document, which is larger than a dist-tag lookup. */
41
42
  const PREVIEW_LOOKUP_TIMEOUT_MS = 30_000;
42
43
  const PACKAGE_UNLOCK_INITIAL_DELAY_MS = 100;
@@ -225,11 +226,7 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
225
226
  },
226
227
  async activateInstalled(packageRoot, targetVersion, phase, onMaterializing, onWarmup) {
227
228
  const request = { packageRoot, dataDir: paths.dataDir, targetVersion, environment };
228
- const callbacks = {
229
- phase,
230
- ...(onMaterializing ? { onMaterializing } : {}),
231
- ...(onWarmup ? { onWarmup } : {}),
232
- };
229
+ const callbacks = { phase, ...(onMaterializing ? { onMaterializing } : {}), ...(onWarmup ? { onWarmup } : {}) };
233
230
  // Compatibility: the tree npm just installed is newer than this updater, so its layout is
234
231
  // its own to know. A tree that serves the contract activates itself with its own code;
235
232
  // a tree from before the contract is activated here, with the layout it had then.
@@ -239,8 +236,13 @@ export function createUpdateLifecycleCoordinator(environment = process.env, file
239
236
  else
240
237
  await activateInstalledRelease(request, callbacks);
241
238
  },
239
+ async activatePrepared(targetVersion, phase) { await retryPreparedActivation(paths.dataDir, environment, targetVersion, phase); },
242
240
  };
243
241
  }
242
+ async function retryPreparedActivation(dataDir, environment, targetVersion, phase) {
243
+ await (await import("./prepared-update-activation.js"))
244
+ .activatePreparedRelease({ dataDir, targetVersion, environment }, { phase });
245
+ }
244
246
  const PROGRESS_BAR_WIDTH = 38;
245
247
  const PROGRESS_TICK_MS = 200;
246
248
  /**
@@ -716,16 +718,14 @@ export async function runSelfUpdate(options) {
716
718
  await measure("ownership-release", async () => { await lifecycle.shutdownVerifiedOwners(targetVersion); });
717
719
  progress.set(75, MATERIALIZE_PROGRESS.from);
718
720
  let activationPhaseStartedAt = now();
719
- await lifecycle.activateInstalled(packageRoot, targetVersion, async (phase) => {
721
+ const recordActivationPhase = async (phase) => {
720
722
  options.onPhaseTiming?.({ phase, durationMs: Math.max(0, now() - activationPhaseStartedAt) });
721
723
  transaction = await transactionStore.advance(phase);
722
724
  progress.set(ACTIVATION_PROGRESS[phase].at, ACTIVATION_PROGRESS[phase].creepTo);
723
725
  activationPhaseStartedAt = now();
724
- }, ({ completed, total }) => {
725
- const span = MATERIALIZE_PROGRESS.to - MATERIALIZE_PROGRESS.from;
726
- const done = total > 0 ? Math.min(1, completed / total) : 0;
727
- progress.set(MATERIALIZE_PROGRESS.from + span * done);
728
- }, state => {
726
+ };
727
+ await activateUpdateTransaction(lifecycle, transaction, packageRoot, targetVersion, recordActivationPhase, ({ completed, total }) => progress.set(MATERIALIZE_PROGRESS.from
728
+ + (MATERIALIZE_PROGRESS.to - MATERIALIZE_PROGRESS.from) * (total > 0 ? Math.min(1, completed / total) : 0)), state => {
729
729
  if (state === "started") {
730
730
  activationPhaseStartedAt = now();
731
731
  progress.set(98, 99);
@@ -757,6 +757,9 @@ export async function runSelfUpdate(options) {
757
757
  const message = errorMessage(error);
758
758
  if (error instanceof UpdateAutomaticDeferred)
759
759
  return 1;
760
+ const blockedExit = await preparedActivationExit(error, transaction, mode, output, transactionStore);
761
+ if (blockedExit !== null)
762
+ return blockedExit;
760
763
  if (error instanceof UpdatePreflightFailure) {
761
764
  output.stderr(`${PRODUCT_TEXT.diagnostic(`update could not start safely: ${message}. Nothing was changed. Retry with npm x -y -- ${PRODUCT_PACKAGE}-install`)}\n`);
762
765
  return 1;
@@ -859,6 +862,21 @@ async function rollbackPriorCohort(dataDir, environment, priorReleaseId) {
859
862
  await ensureSupervisor(release, environment);
860
863
  return "rolled back";
861
864
  }
865
+ async function activateUpdateTransaction(lifecycle, transaction, packageRoot, targetVersion, phase, materializing, warmup) {
866
+ if (!phaseBefore(transaction.phase, "certified") && phaseBefore(transaction.phase, "active-reference-committed")
867
+ && lifecycle.activatePrepared !== undefined)
868
+ await lifecycle.activatePrepared(targetVersion, phase);
869
+ else
870
+ await lifecycle.activateInstalled(packageRoot, targetVersion, phase, materializing, warmup);
871
+ }
872
+ async function preparedActivationExit(error, transaction, mode, output, journal) {
873
+ if (!(error instanceof UpdateActivationBlockedError) || transaction === null || phaseBefore(transaction.phase, "certified"))
874
+ return null;
875
+ if (mode === "manual")
876
+ output.stderr(`${PRODUCT_TEXT.diagnostic(`update prepared, but activation is blocked: ${error.message}. The prior client remains selected; run the update again after the resident blocker clears.`)}\n`);
877
+ await journal.recordActiveError?.(error.message);
878
+ return UPDATE_ACTIVATION_BLOCKED_EXIT_CODE;
879
+ }
862
880
  function phaseBefore(current, target) {
863
881
  const phases = ["shutdown-intent", "ownership-released", "package-installed", "materialized", "certified", "active-reference-committed", "supervisor-verified"];
864
882
  return phases.indexOf(current) < phases.indexOf(target);
@@ -7,7 +7,7 @@ import { KeybindingsManager } from "./upstream/adjacent/core/keybindings.js";
7
7
  import { StatusIndicator, WorkingStatusIndicator } from "./upstream/components/status-indicator.js";
8
8
  import { protectPiPromptChipPresentation } from "./prompt-chip-presentation.js";
9
9
  import { PINNED_PI_LAYOUT, piTheme, } from "./theme.js";
10
- import { createTuiFacade, ensureTheme, renderPiShellInstalledUpdateStatus, piShellVisibleWidth, } from "./shell-shared-facade.js";
10
+ import { createTuiFacade, ensureTheme, renderPiShellBlockedUpdateStatus, renderPiShellInstalledUpdateStatus, piShellVisibleWidth, } from "./shell-shared-facade.js";
11
11
  export function createPiShellHeader(options = {}) {
12
12
  ensureTheme();
13
13
  let expanded = options.expanded ?? false;
@@ -229,10 +229,15 @@ function statusSignature(view, workingOverride, outputPad, placement, progressPr
229
229
  return `${placement}\u0000${outputPad}\u0000${view.lifecycle}\u0000${progressPresentation}\u0000${message}\u0000${view.status.diagnostics.at(-1) ?? ""}`;
230
230
  }
231
231
  function appendInstalledUpdateStatus(rows, width, view, progressPresentation) {
232
- if (progressPresentation === "custom-viewport" || width <= 0
233
- || !view.diagnostics.some(diagnostic => diagnostic.code === "release-update-installed"))
232
+ if (progressPresentation === "custom-viewport" || width <= 0)
233
+ return rows;
234
+ const status = view.diagnostics.some(diagnostic => diagnostic.code === "release-update-installed")
235
+ ? renderPiShellInstalledUpdateStatus(width)
236
+ : view.diagnostics.some(diagnostic => diagnostic.code === "release-update-blocked")
237
+ ? renderPiShellBlockedUpdateStatus(width)
238
+ : "";
239
+ if (status.length === 0)
234
240
  return rows;
235
- const status = renderPiShellInstalledUpdateStatus(width);
236
241
  const statusWidth = piShellVisibleWidth(status);
237
242
  const target = rows.findLastIndex(row => piShellVisibleWidth(row.trimEnd()) > 0);
238
243
  if (target < 0)
@@ -9,8 +9,11 @@ import { KeybindingsManager } from "./upstream/adjacent/core/keybindings.js";
9
9
  export declare const piShellVisibleWidth: typeof visibleWidth;
10
10
  export declare const piShellTruncateToWidth: (text: string, width: number) => string;
11
11
  export declare const INSTALLED_UPDATE_STATUS_TEXT = "Update installed, restart to update";
12
+ export declare const BLOCKED_UPDATE_STATUS_TEXT = "Update prepared; activation blocked";
12
13
  /** Shared green restart notice for the pinned status and bare-A1 prompt overlay. */
13
14
  export declare function renderPiShellInstalledUpdateStatus(width: number): string;
15
+ /** Sanitized warning for a certified candidate that cannot yet preserve resident continuity. */
16
+ export declare function renderPiShellBlockedUpdateStatus(width: number): string;
14
17
  /** A clickable URL in pinned Pi's grammar: an OSC 8 link where the terminal supports one, the plain URL otherwise. */
15
18
  export declare const piShellHyperlink: (url: string, text?: string) => string;
16
19
  export interface PiShellComponentPort extends PresentationComponentPort {
@@ -5,6 +5,7 @@ import { ensurePiTheme, piTheme, } from "./theme.js";
5
5
  export const piShellVisibleWidth = visibleWidth;
6
6
  export const piShellTruncateToWidth = (text, width) => truncateToWidth(text, width, "");
7
7
  export const INSTALLED_UPDATE_STATUS_TEXT = "Update installed, restart to update";
8
+ export const BLOCKED_UPDATE_STATUS_TEXT = "Update prepared; activation blocked";
8
9
  /** Shared green restart notice for the pinned status and bare-A1 prompt overlay. */
9
10
  export function renderPiShellInstalledUpdateStatus(width) {
10
11
  if (width <= 0)
@@ -12,6 +13,13 @@ export function renderPiShellInstalledUpdateStatus(width) {
12
13
  ensurePiTheme();
13
14
  return piShellTruncateToWidth(piTheme().fg("success", INSTALLED_UPDATE_STATUS_TEXT), width);
14
15
  }
16
+ /** Sanitized warning for a certified candidate that cannot yet preserve resident continuity. */
17
+ export function renderPiShellBlockedUpdateStatus(width) {
18
+ if (width <= 0)
19
+ return "";
20
+ ensurePiTheme();
21
+ return piShellTruncateToWidth(piTheme().fg("warning", BLOCKED_UPDATE_STATUS_TEXT), width);
22
+ }
15
23
  /** A clickable URL in pinned Pi's grammar: an OSC 8 link where the terminal supports one, the plain URL otherwise. */
16
24
  export const piShellHyperlink = (url, text = url) => hyperlink(url, text);
17
25
  // Provenance: pinned from packages/coding-agent/src/core/slash-commands.ts at 914cf14.
@@ -217,9 +217,17 @@ export class PiEngineAdapter {
217
217
  return;
218
218
  }
219
219
  if (release.status === "installed") {
220
+ this.#state.diagnosticsState.clearCodes(["release-update-installed", "release-update-blocked"]);
220
221
  this.#addDiagnostic("info", "release-update-installed", `Update ${release.version} installed; restart to update.`, true);
221
222
  }
222
- else {
223
+ else if (release.status === "blocked") {
224
+ this.#state.diagnosticsState.clearCodes(["release-update-installed", "release-update-blocked"]);
225
+ this.#addDiagnostic("info", "release-update-blocked", `Update ${release.version} prepared; activation blocked.`, true);
226
+ }
227
+ else if (release.status === "blocked-cleared") {
228
+ this.#state.diagnosticsState.clearCodes(["release-update-blocked"]);
229
+ }
230
+ else if (release.status === undefined || release.status === "available") {
223
231
  const changelog = release.changelogUrl === null ? "" : `\nChangelog: ${release.changelogUrl}`;
224
232
  this.#addDiagnostic("info", "release-update", `New version ${release.version} is available. Run ${release.command}${changelog}`, true);
225
233
  }
@@ -5,5 +5,6 @@ export declare class EngineDiagnostics {
5
5
  get values(): readonly OwnedUiDiagnostics[];
6
6
  get messages(): readonly string[];
7
7
  record(severity: OwnedUiDiagnostics["severity"], code: string, message: string, recoverable: boolean): OwnedUiDiagnostics;
8
+ clearCodes(codes: readonly string[]): boolean;
8
9
  acknowledgeClientVersion(version: string): boolean;
9
10
  }
@@ -14,14 +14,27 @@ export class EngineDiagnostics {
14
14
  this.#messages = [...this.#messages, message].slice(-8);
15
15
  return diagnostic;
16
16
  }
17
+ clearCodes(codes) {
18
+ const selected = new Set(codes);
19
+ return this.#remove(diagnostic => selected.has(diagnostic.code));
20
+ }
17
21
  acknowledgeClientVersion(version) {
18
22
  if (validSemver(version) === null)
19
23
  return false;
24
+ return this.#remove(diagnostic => {
25
+ const target = diagnostic.code === "release-update-installed"
26
+ ? /^Update (\S+) installed; restart to update\.$/u.exec(diagnostic.message)?.[1]
27
+ : diagnostic.code === "release-update-blocked"
28
+ ? /^Update (\S+) prepared; activation blocked\.$/u.exec(diagnostic.message)?.[1]
29
+ : undefined;
30
+ return target !== undefined && validSemver(target) !== null && gte(version, target);
31
+ });
32
+ }
33
+ #remove(predicate) {
20
34
  const removed = new Set();
21
35
  for (let index = this.#values.length - 1; index >= 0; index--) {
22
36
  const diagnostic = this.#values[index];
23
- const installed = diagnostic.code === "release-update-installed" ? /^Update (\S+) installed; restart to update\.$/u.exec(diagnostic.message)?.[1] : undefined;
24
- if (installed !== undefined && validSemver(installed) !== null && gte(version, installed)) {
37
+ if (predicate(diagnostic)) {
25
38
  removed.add(diagnostic.message);
26
39
  this.#values.splice(index, 1);
27
40
  }
@@ -7,7 +7,7 @@
7
7
  "platform": "darwin",
8
8
  "architecture": "arm64",
9
9
  "capability": "supported",
10
- "builtAt": "2026-11-03T09:20:07.813Z",
10
+ "builtAt": "2026-11-03T12:34:41.201Z",
11
11
  "artifact": {
12
12
  "filename": "process-guardian.node",
13
13
  "sha256": "a87eaaffcd986b624c8b044b756446cc1bdaf4334a1775b97820542fe34f9fb7",
@@ -9,11 +9,11 @@
9
9
  "architecture": "arm64",
10
10
  "target": "aarch64-apple-darwin",
11
11
  "capability": "supported",
12
- "builtAt": "2026-11-03T09:22:58.021Z",
12
+ "builtAt": "2026-11-03T12:38:29.199Z",
13
13
  "artifact": {
14
14
  "filename": "terminal-host.node",
15
- "sha256": "61ed28a1cb8a7e65c8b963a672917864b607f12b418468700e214663b9506b61",
16
- "size": 6566864
15
+ "sha256": "f340571d5eef45a551e7c53f8c31d91dd75c948fe11c97bda0c23a2d9bbfa2a4",
16
+ "size": 6585248
17
17
  },
18
18
  "entry": {
19
19
  "filename": "dist/foundation/resident-tabs/host-entry.js",
@@ -7,7 +7,7 @@
7
7
  "platform": "darwin",
8
8
  "architecture": "x64",
9
9
  "capability": "supported",
10
- "builtAt": "2026-11-03T09:20:14.161Z",
10
+ "builtAt": "2026-11-03T12:34:49.251Z",
11
11
  "artifact": {
12
12
  "filename": "process-guardian.node",
13
13
  "sha256": "783a65f0de287a1c02cd5429dbe97bc8633f4cc8a7b92e3e961180b9bdcff814",
@@ -9,11 +9,11 @@
9
9
  "architecture": "x64",
10
10
  "target": "x86_64-apple-darwin",
11
11
  "capability": "supported",
12
- "builtAt": "2026-11-03T09:25:42.863Z",
12
+ "builtAt": "2026-11-03T12:41:50.549Z",
13
13
  "artifact": {
14
14
  "filename": "terminal-host.node",
15
- "sha256": "4e257b645cda56dce14b3c442b673da98049ec91fa7d8c7cd7d265ddd61d9c5b",
16
- "size": 7159480
15
+ "sha256": "92cceb0cf8a8b955b86762fc677396586f0e32569923827a96281fc5a29a3add",
16
+ "size": 7173680
17
17
  },
18
18
  "entry": {
19
19
  "filename": "dist/foundation/resident-tabs/host-entry.js",
@@ -7,7 +7,7 @@
7
7
  "platform": "linux",
8
8
  "architecture": "x64",
9
9
  "capability": "supported",
10
- "builtAt": "2026-11-03T09:19:45.383Z",
10
+ "builtAt": "2026-11-03T12:33:48.123Z",
11
11
  "artifact": {
12
12
  "filename": "process-guardian.node",
13
13
  "sha256": "118e5954e3864672bd8482ab7edf419cb27dcdf2533720316979b7f5cc5a53a5",
@@ -9,11 +9,11 @@
9
9
  "architecture": "x64",
10
10
  "target": "x86_64-unknown-linux-gnu",
11
11
  "capability": "supported",
12
- "builtAt": "2026-11-03T09:23:17.644Z",
12
+ "builtAt": "2026-11-03T12:37:02.302Z",
13
13
  "artifact": {
14
14
  "filename": "terminal-host.node",
15
- "sha256": "913e106efd96c5d59b33cdeea2261873a1e4a1bb73b3e94fbb847c6af5f941ba",
16
- "size": 7936048
15
+ "sha256": "e5d97e8f613e7ca960f541861f9ae61435fb5e1cff1a5e80e34000665e5afecf",
16
+ "size": 7954680
17
17
  },
18
18
  "entry": {
19
19
  "filename": "dist/foundation/resident-tabs/host-entry.js",
@@ -7,10 +7,10 @@
7
7
  "platform": "win32",
8
8
  "architecture": "x64",
9
9
  "capability": "supported",
10
- "builtAt": "2026-11-03T09:20:55.204Z",
10
+ "builtAt": "2026-11-03T12:34:57.755Z",
11
11
  "artifact": {
12
12
  "filename": "process-guardian.node",
13
- "sha256": "f20404d4aba004e8c9e48150360f88c2d1a82814ef63205fa36927073f0d5feb",
13
+ "sha256": "037cc7426ed420a010993dcd7fda7001707fc87d0c6104f93c01e32c789bd748",
14
14
  "size": 402432
15
15
  },
16
16
  "provenance": {
@@ -9,11 +9,11 @@
9
9
  "architecture": "x64",
10
10
  "target": "x86_64-pc-windows-msvc",
11
11
  "capability": "supported",
12
- "builtAt": "2026-11-03T09:24:46.830Z",
12
+ "builtAt": "2026-11-03T12:36:35.360Z",
13
13
  "artifact": {
14
14
  "filename": "terminal-host.node",
15
- "sha256": "e2f95819afd458d162b02a28f0d27f021609451dd87e98822aa05a443650972c",
16
- "size": 7048192
15
+ "sha256": "2dd46801648d082efbf5c6122ed76a059a6fee052ca0364dea517ddb3f1f6ba9",
16
+ "size": 7071232
17
17
  },
18
18
  "entry": {
19
19
  "filename": "dist/foundation/resident-tabs/host-entry.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timurproko/a1",
3
- "version": "0.2.7-dev.1234",
3
+ "version": "0.2.7-dev.1236",
4
4
  "description": "Standalone terminal workspace for supervised native and managed agents",
5
5
  "type": "module",
6
6
  "privateLaunchContract": "neutral-launch-v1",
@@ -123,7 +123,7 @@
123
123
  "@mariozechner/clipboard": "^0.3.9"
124
124
  },
125
125
  "publication": {
126
- "source": "47164524aec4085b000995eb692875e4ab80b190",
127
- "pullRequest": 859
126
+ "source": "ebe579aafe67e84a7d77b1769d8e8a972d5a30dc",
127
+ "pullRequest": 861
128
128
  }
129
129
  }