@timurproko/a1 0.1.8-dev.134 → 0.1.8-dev.137
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/cli.js +13 -2
- package/bin/module-identity.js +23 -0
- package/dist/foundation/release/bootstrap.d.ts +10 -0
- package/dist/foundation/release/bootstrap.js +13 -1
- package/dist/foundation/release/update.js +13 -0
- 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/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -11,12 +11,23 @@ const capabilities = cliCapabilities(JSON.parse(await readFile(new URL("package.
|
|
|
11
11
|
|
|
12
12
|
process.exitCode = await dispatchCli(process.argv.slice(2), {
|
|
13
13
|
launch: async intent => {
|
|
14
|
-
const [{ prepareInteractiveLaunch }, { runBootstrap }] = await Promise.all([
|
|
14
|
+
const [{ prepareInteractiveLaunch }, { runBootstrap }, { healModuleIdentityAtLaunch, releaseCopyIsLaunchable }] = await Promise.all([
|
|
15
15
|
import("../dist/features/launch/index.js"),
|
|
16
16
|
import("../dist/foundation/release/index.js"),
|
|
17
|
+
import("./module-identity.js"),
|
|
17
18
|
]);
|
|
19
|
+
// Self-heal the installed tree before the release store copies it: npm 12
|
|
20
|
+
// blocks install scripts by default, so the postinstall that normally
|
|
21
|
+
// repairs module identity may never have run (see bin/module-identity.js).
|
|
22
|
+
const packageRootPath = fileURLToPath(packageRoot);
|
|
23
|
+
await healModuleIdentityAtLaunch(packageRootPath, message => process.stderr.write(message));
|
|
18
24
|
const prepared = await prepareInteractiveLaunch(intent);
|
|
19
|
-
return await runBootstrap({
|
|
25
|
+
return await runBootstrap({
|
|
26
|
+
packageRoot: packageRootPath,
|
|
27
|
+
launchIntent: intent,
|
|
28
|
+
environment: prepared.environment,
|
|
29
|
+
releaseIsLaunchable: releaseCopyIsLaunchable,
|
|
30
|
+
});
|
|
20
31
|
},
|
|
21
32
|
version: async () => {
|
|
22
33
|
const { runVersionStats } = await import("../dist/cli/index.js");
|
package/bin/module-identity.js
CHANGED
|
@@ -132,6 +132,29 @@ function message(error) {
|
|
|
132
132
|
return error instanceof Error ? error.message : String(error);
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Launch-entry self-heal: when A1 and pinned Pi disagree on the terminal
|
|
137
|
+
* module, rewrite the proxy to the copy Pi resolves before anything copies
|
|
138
|
+
* this tree. npm 12 blocks install scripts unless allowScripts covers the
|
|
139
|
+
* package, so the postinstall that normally rewrites the proxy may never
|
|
140
|
+
* have run and the installed tree may still carry the published placeholder
|
|
141
|
+
* path. Named neutrally so the launch entries that call it stay free of
|
|
142
|
+
* terminal implementation identifiers, as the bootstrap boundary requires.
|
|
143
|
+
*/
|
|
144
|
+
export async function healModuleIdentityAtLaunch(packageRoot, warn) {
|
|
145
|
+
if (inspectPiTuiModuleIdentity(packageRoot).kind === "unified") return;
|
|
146
|
+
const { syncPiTuiProxy } = await import("./sync-pi-tui-proxy.js");
|
|
147
|
+
const outcome = syncPiTuiProxy(packageRoot);
|
|
148
|
+
if (outcome.kind === "unresolved") {
|
|
149
|
+
warn(`a1: could not point the terminal module proxy at pinned Pi's copy (${outcome.message}); extension UI may not render.\n`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Whether a materialized release copy resolves one terminal module for both A1 and Pi. */
|
|
154
|
+
export function releaseCopyIsLaunchable(releaseRoot) {
|
|
155
|
+
return inspectPiTuiModuleIdentity(releaseRoot).kind === "unified";
|
|
156
|
+
}
|
|
157
|
+
|
|
135
158
|
/** Launch-entry wrapper: warn on stderr when the two sides disagree. */
|
|
136
159
|
export function assertSinglePiTuiModuleAtLaunch(packageRoot, warn) {
|
|
137
160
|
const outcome = inspectPiTuiModuleIdentity(packageRoot);
|
|
@@ -13,6 +13,16 @@ export interface BootstrapOptions {
|
|
|
13
13
|
};
|
|
14
14
|
readonly environment?: NodeJS.ProcessEnv;
|
|
15
15
|
readonly output?: Pick<NodeJS.WriteStream, "write">;
|
|
16
|
+
/**
|
|
17
|
+
* Whether a materialized release copy is fit to launch. The active release
|
|
18
|
+
* is normally reused while its version matches the installation, but a copy
|
|
19
|
+
* can be broken in ways a version cannot see — materialized from a tree a
|
|
20
|
+
* blocked postinstall never finished repairing. The probe is injected from
|
|
21
|
+
* the bin entry because deciding it requires inspecting dependency
|
|
22
|
+
* resolution, which stays out of production code. Absent means every
|
|
23
|
+
* release is fit.
|
|
24
|
+
*/
|
|
25
|
+
readonly releaseIsLaunchable?: (releaseRoot: string) => boolean;
|
|
16
26
|
}
|
|
17
27
|
export declare function runBootstrap(options: BootstrapOptions): Promise<number>;
|
|
18
28
|
export declare function certifyMaterializedRelease(release: MaterializedRelease, dataDir: string, verification?: VerifyMaterializedReleaseOptions): Promise<string>;
|
|
@@ -46,7 +46,8 @@ export async function runBootstrap(options) {
|
|
|
46
46
|
const installedVersion = await readInstalledVersion(options.packageRoot);
|
|
47
47
|
const activeId = state.references.active;
|
|
48
48
|
const active = activeId === null ? undefined : state.releases[activeId];
|
|
49
|
-
|
|
49
|
+
const activeIsLaunchable = active === undefined || (options.releaseIsLaunchable?.(active.releaseRoot) ?? true);
|
|
50
|
+
if (activeIsLaunchable && active?.approval === "approved" && active.packageVersion === installedVersion) {
|
|
50
51
|
const endpointMatches = endpoint?.releaseId === active.releaseId
|
|
51
52
|
&& endpoint.releaseRoot === active.releaseRoot
|
|
52
53
|
&& endpoint.contentDigest === active.contentDigest;
|
|
@@ -73,6 +74,17 @@ export async function runBootstrap(options) {
|
|
|
73
74
|
await stateStore.activate(candidate.releaseId);
|
|
74
75
|
state = await stateStore.read();
|
|
75
76
|
}
|
|
77
|
+
else if (!activeIsLaunchable && candidate.releaseId !== activeId
|
|
78
|
+
&& state.releases[candidate.releaseId]?.approval !== "approved") {
|
|
79
|
+
// The active reference points at a copy that cannot launch, so reusing it
|
|
80
|
+
// is off the table — but an unapproved candidate would lose the selection
|
|
81
|
+
// below to that same broken active (`start-active`). Approving the healed
|
|
82
|
+
// candidate here lets ordinary cohort selection activate it, while a live
|
|
83
|
+
// busy cohort still wins the endpoint checks and keeps its sessions.
|
|
84
|
+
const diagnosticsPath = await certifyMaterializedRelease(candidate, paths.dataDir);
|
|
85
|
+
await stateStore.approve(candidate.releaseId, diagnosticsPath);
|
|
86
|
+
state = await stateStore.read();
|
|
87
|
+
}
|
|
76
88
|
// The candidate's own endpoint decides whether this launch attaches or starts a supervisor.
|
|
77
89
|
// A cohort other than this one is not in the way: it listens somewhere else.
|
|
78
90
|
endpointPaths = resolveCohortEndpoint(paths, candidate.releaseId, environment);
|
|
@@ -403,6 +403,19 @@ export async function runSelfUpdate(options) {
|
|
|
403
403
|
}
|
|
404
404
|
transaction = await transactionStore.advance("package-installed");
|
|
405
405
|
}
|
|
406
|
+
// npm 12 blocks install scripts unless allowScripts covers the package, so
|
|
407
|
+
// the postinstall that points the #pi-tui proxy at the tree npm just built
|
|
408
|
+
// may never have run. Run the shipped script directly: the proxy must be
|
|
409
|
+
// correct before the release store copies this tree. A failure is reported
|
|
410
|
+
// and left to the launch-time self-heal rather than failing the update.
|
|
411
|
+
try {
|
|
412
|
+
const proxySync = await runner(process.execPath, [resolve(packageRoot, "bin", "sync-pi-tui-proxy.js")], { captureStdout: true });
|
|
413
|
+
if (proxySync.code !== 0)
|
|
414
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not point the #pi-tui proxy at the installed tree (exited ${formatExitCode(proxySync.code)}).`)}\n`);
|
|
415
|
+
}
|
|
416
|
+
catch (error) {
|
|
417
|
+
output.stderr(`${PRODUCT_TEXT.diagnostic(`could not point the #pi-tui proxy at the installed tree: ${errorMessage(error)}`)}\n`);
|
|
418
|
+
}
|
|
406
419
|
progress.set(70, 75);
|
|
407
420
|
// Ownership can be reacquired after an interrupted installation (for
|
|
408
421
|
// example, if bare A1 is launched before the update is resumed). Recheck
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "darwin",
|
|
6
6
|
"architecture": "arm64",
|
|
7
7
|
"capability": "unsupported",
|
|
8
|
-
"builtAt": "2026-08-
|
|
8
|
+
"builtAt": "2026-08-26T06:22:58.678Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "7524bf568992517f50ed53196c861c5edeba0d7275633bb4735ab45bd5963a28",
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"platform": "linux",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-08-
|
|
8
|
+
"builtAt": "2026-08-26T06:22:53.598Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian",
|
|
11
11
|
"sha256": "ee8a00eaaf79c707459bbbfb52518e9739314967049fbe5fa625f36ce33db9ee",
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
"platform": "win32",
|
|
6
6
|
"architecture": "x64",
|
|
7
7
|
"capability": "supported",
|
|
8
|
-
"builtAt": "2026-08-
|
|
8
|
+
"builtAt": "2026-08-26T06:23:46.974Z",
|
|
9
9
|
"artifact": {
|
|
10
10
|
"filename": "process-guardian.exe",
|
|
11
|
-
"sha256": "
|
|
11
|
+
"sha256": "7b6350b01d875ee3d0db81a1ed5126df5e4a796b93c9ea146e9f24d1f1ab5a2e",
|
|
12
12
|
"size": 172544
|
|
13
13
|
},
|
|
14
14
|
"provenance": {
|
|
Binary file
|