jorgex-stack 1.9.63 → 1.9.65
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/dist/cli.js +530 -460
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2115,6 +2115,12 @@ function isManagedOptionalStdioServer(server, value) {
|
|
|
2115
2115
|
const expectedCommand = [server.command, ...server.args ?? []];
|
|
2116
2116
|
return Object.keys(current).length === 2 && current.type === "local" && Array.isArray(current.command) && current.command.length === expectedCommand.length && current.command.every((arg, index) => arg === expectedCommand[index]);
|
|
2117
2117
|
}
|
|
2118
|
+
function isOwnedDevtoolsServer(name, server, value, ctx) {
|
|
2119
|
+
if (isManagedOptionalStdioServer(server, value)) return true;
|
|
2120
|
+
if (name !== DEVTOOLS_MCP_SERVER) return false;
|
|
2121
|
+
const template = loadCanonicalMcp(ctx.stackDir).servers[DEVTOOLS_MCP_SERVER];
|
|
2122
|
+
return template !== void 0 && isManagedOptionalStdioServer(materializeCanonicalDevtoolsServerForRemoval(template), value);
|
|
2123
|
+
}
|
|
2118
2124
|
function objectValue(value) {
|
|
2119
2125
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2120
2126
|
}
|
|
@@ -2654,16 +2660,14 @@ ${gitReadCommands.map((command) => `- \`${command}\``).join("\n")}
|
|
|
2654
2660
|
}
|
|
2655
2661
|
if (!isCanonicalMcpServerEnabled(name, server, ctx.enabledMcpServers)) {
|
|
2656
2662
|
if (owned) {
|
|
2657
|
-
if (
|
|
2663
|
+
if (isOwnedDevtoolsServer(name, server, existing, ctx)) delete mcp[name];
|
|
2658
2664
|
mcpOwnership.push({ server: name, owned: false });
|
|
2659
2665
|
}
|
|
2660
2666
|
continue;
|
|
2661
2667
|
}
|
|
2662
2668
|
if (server.optional && existing !== void 0) {
|
|
2663
|
-
if (!owned || !
|
|
2664
|
-
|
|
2665
|
-
ctx.warnings.push(`OpenCode: MCP opcional '${name}' ya pertenece a la configuraci\xF3n del usuario; se conserva.`);
|
|
2666
|
-
continue;
|
|
2669
|
+
if (!owned || !isOwnedDevtoolsServer(name, server, existing, ctx)) {
|
|
2670
|
+
throw new Error(`OpenCode: ${name}: conflicto con servidor MCP existente ajeno o modificado; se conserva. Retira esa entrada expl\xEDcitamente antes de activar DevTools gestionado.`);
|
|
2667
2671
|
}
|
|
2668
2672
|
}
|
|
2669
2673
|
if (server.transport === "stdio") {
|
|
@@ -2792,7 +2796,7 @@ ${gitReadCommands.map((command) => `- \`${command}\``).join("\n")}
|
|
|
2792
2796
|
continue;
|
|
2793
2797
|
}
|
|
2794
2798
|
if (ctx.ownedMcpServers?.has(name) === true) {
|
|
2795
|
-
if (
|
|
2799
|
+
if (isOwnedDevtoolsServer(name, server, mcpBlock[name], ctx)) delete mcpBlock[name];
|
|
2796
2800
|
mcpOwnership.push({ server: name, owned: false });
|
|
2797
2801
|
}
|
|
2798
2802
|
}
|
|
@@ -2938,6 +2942,12 @@ function isManagedOptionalStdioServer2(server, value) {
|
|
|
2938
2942
|
const expectedArgs = server.args ?? [];
|
|
2939
2943
|
return Object.keys(current).length === 3 && current.type === "stdio" && current.command === server.command && Array.isArray(current.args) && current.args.length === expectedArgs.length && current.args.every((arg, index) => arg === expectedArgs[index]);
|
|
2940
2944
|
}
|
|
2945
|
+
function isOwnedDevtoolsServer2(name, server, value, ctx) {
|
|
2946
|
+
if (isManagedOptionalStdioServer2(server, value)) return true;
|
|
2947
|
+
if (name !== DEVTOOLS_MCP_SERVER) return false;
|
|
2948
|
+
const template = loadCanonicalMcp(ctx.stackDir).servers[DEVTOOLS_MCP_SERVER];
|
|
2949
|
+
return template !== void 0 && isManagedOptionalStdioServer2(materializeCanonicalDevtoolsServerForRemoval(template), value);
|
|
2950
|
+
}
|
|
2941
2951
|
function errnoCodeOf(error) {
|
|
2942
2952
|
return error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : "UNKNOWN";
|
|
2943
2953
|
}
|
|
@@ -3288,16 +3298,14 @@ ${agent.body}`,
|
|
|
3288
3298
|
}
|
|
3289
3299
|
if (!isCanonicalMcpServerEnabled(name, server, ctx.enabledMcpServers)) {
|
|
3290
3300
|
if (owned) {
|
|
3291
|
-
if (
|
|
3301
|
+
if (isOwnedDevtoolsServer2(name, server, existing, ctx)) delete servers[name];
|
|
3292
3302
|
mcpOwnership.push({ server: name, owned: false });
|
|
3293
3303
|
}
|
|
3294
3304
|
continue;
|
|
3295
3305
|
}
|
|
3296
3306
|
if (server.optional && existing !== void 0) {
|
|
3297
|
-
if (!owned || !
|
|
3298
|
-
|
|
3299
|
-
ctx.warnings.push(`Claude Code: MCP opcional '${name}' ya pertenece a la configuraci\xF3n del usuario; se conserva.`);
|
|
3300
|
-
continue;
|
|
3307
|
+
if (!owned || !isOwnedDevtoolsServer2(name, server, existing, ctx)) {
|
|
3308
|
+
throw new Error(`Claude Code: ${name}: conflicto con servidor MCP existente ajeno o modificado; se conserva. Retira esa entrada expl\xEDcitamente antes de activar DevTools gestionado.`);
|
|
3301
3309
|
}
|
|
3302
3310
|
}
|
|
3303
3311
|
if (server.transport === "stdio") {
|
|
@@ -3378,7 +3386,7 @@ ${agent.body}`,
|
|
|
3378
3386
|
continue;
|
|
3379
3387
|
}
|
|
3380
3388
|
if (ctx.ownedMcpServers?.has(name) === true) {
|
|
3381
|
-
if (
|
|
3389
|
+
if (isOwnedDevtoolsServer2(name, server, servers[name], ctx)) delete servers[name];
|
|
3382
3390
|
mcpOwnership.push({ server: name, owned: false });
|
|
3383
3391
|
}
|
|
3384
3392
|
}
|
|
@@ -3427,6 +3435,12 @@ args = [${args}]`;
|
|
|
3427
3435
|
function isManagedOptionalStdioServer3(server, section) {
|
|
3428
3436
|
return server.optional === true && server.transport === "stdio" && section?.trim() === stdioMcpSection(server);
|
|
3429
3437
|
}
|
|
3438
|
+
function isOwnedDevtoolsServer3(name, server, section, ctx) {
|
|
3439
|
+
if (isManagedOptionalStdioServer3(server, section)) return true;
|
|
3440
|
+
if (name !== DEVTOOLS_MCP_SERVER) return false;
|
|
3441
|
+
const template = loadCanonicalMcp(ctx.stackDir).servers[DEVTOOLS_MCP_SERVER];
|
|
3442
|
+
return template !== void 0 && isManagedOptionalStdioServer3(materializeCanonicalDevtoolsServerForRemoval(template), section);
|
|
3443
|
+
}
|
|
3430
3444
|
function hasActiveEngramPlugin(configDir) {
|
|
3431
3445
|
const config = readTextIfExists(path14.join(configDir, "config.toml"));
|
|
3432
3446
|
if (config === null) return false;
|
|
@@ -3953,16 +3967,14 @@ ${body}`
|
|
|
3953
3967
|
}
|
|
3954
3968
|
if (!isCanonicalMcpServerEnabled(name, server, ctx.enabledMcpServers)) {
|
|
3955
3969
|
if (owned) {
|
|
3956
|
-
if (
|
|
3970
|
+
if (isOwnedDevtoolsServer3(name, server, existing, ctx)) content = removeTomlSection(content, section);
|
|
3957
3971
|
mcpOwnership.push({ server: name, owned: false });
|
|
3958
3972
|
}
|
|
3959
3973
|
continue;
|
|
3960
3974
|
}
|
|
3961
3975
|
if (server.optional && existing !== null) {
|
|
3962
|
-
if (!owned || !
|
|
3963
|
-
|
|
3964
|
-
ctx.warnings.push(`Codex: MCP opcional '${name}' ya pertenece a la configuraci\xF3n del usuario; se conserva.`);
|
|
3965
|
-
continue;
|
|
3976
|
+
if (!owned || !isOwnedDevtoolsServer3(name, server, existing, ctx)) {
|
|
3977
|
+
throw new Error(`Codex: ${name}: conflicto con servidor MCP existente ajeno o modificado; se conserva. Retira esa entrada expl\xEDcitamente antes de activar DevTools gestionado.`);
|
|
3966
3978
|
}
|
|
3967
3979
|
}
|
|
3968
3980
|
if (server.transport === "stdio") {
|
|
@@ -4054,7 +4066,7 @@ args = [${(server.args ?? []).map(tomlString).join(", ")}]`);
|
|
|
4054
4066
|
continue;
|
|
4055
4067
|
}
|
|
4056
4068
|
if (ctx.ownedMcpServers?.has(name) === true) {
|
|
4057
|
-
if (
|
|
4069
|
+
if (isOwnedDevtoolsServer3(name, server, readTomlSection(content, section), ctx)) {
|
|
4058
4070
|
content = removeTomlSection(content, section);
|
|
4059
4071
|
}
|
|
4060
4072
|
mcpOwnership.push({ server: name, owned: false });
|
|
@@ -4330,7 +4342,7 @@ var init_pi = __esm({
|
|
|
4330
4342
|
|
|
4331
4343
|
// src/cli.ts
|
|
4332
4344
|
import * as p6 from "@clack/prompts";
|
|
4333
|
-
import
|
|
4345
|
+
import fs44 from "fs";
|
|
4334
4346
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
4335
4347
|
|
|
4336
4348
|
// src/install.ts
|
|
@@ -7568,10 +7580,16 @@ function enabledMcpServers(runtime, explicitDevtoolsEnabled, useBrowserPreferenc
|
|
|
7568
7580
|
const devtoolsEnabled = explicitDevtoolsEnabled ?? (useBrowserPreferences && loadDevtoolsMcpPreference(devtoolsMcpPreferenceFile(), runtime));
|
|
7569
7581
|
return devtoolsEnabled ? /* @__PURE__ */ new Set([DEVTOOLS_MCP_SERVER]) : /* @__PURE__ */ new Set();
|
|
7570
7582
|
}
|
|
7571
|
-
function ownedMcpServers(runtime, useBrowserPreferences = true) {
|
|
7583
|
+
function ownedMcpServers(runtime, configDir, useBrowserPreferences = true) {
|
|
7572
7584
|
if (!useBrowserPreferences) return /* @__PURE__ */ new Set();
|
|
7573
7585
|
const file = devtoolsMcpPreferenceFile();
|
|
7574
|
-
|
|
7586
|
+
const marked = [DEVTOOLS_MCP_SERVER, "context7"].filter((server) => loadDevtoolsMcpOwnership(file, runtime, server));
|
|
7587
|
+
if (marked.length === 0) return /* @__PURE__ */ new Set();
|
|
7588
|
+
const recordedDir = readManifest().runtimes[runtime]?.configDir;
|
|
7589
|
+
if (typeof recordedDir !== "string" || !samePath(recordedDir, configDir)) {
|
|
7590
|
+
throw new Error(`${runtime}: MCP ownership configDir no coincide con el perfil actual; se conserva la configuraci\xF3n. Vuelve al perfil anterior o revisa el estado gestionado antes de reintentar.`);
|
|
7591
|
+
}
|
|
7592
|
+
return new Set(marked);
|
|
7575
7593
|
}
|
|
7576
7594
|
function persistConfigurationOwnershipChanges(runtime, configDir, plan) {
|
|
7577
7595
|
const latest = /* @__PURE__ */ new Map();
|
|
@@ -7600,7 +7618,7 @@ function makeContext(adapter, configDir, mode = DEFAULT_INSTALL_MODE_PREFERENCE,
|
|
|
7600
7618
|
const models = loadModelMap()[adapter.id];
|
|
7601
7619
|
if (!models) return null;
|
|
7602
7620
|
const enabled = enabledMcpServers(adapter.id, void 0, useBrowserPreferences);
|
|
7603
|
-
const owned = ownedMcpServers(adapter.id, useBrowserPreferences);
|
|
7621
|
+
const owned = ownedMcpServers(adapter.id, configDir, useBrowserPreferences);
|
|
7604
7622
|
let devtoolsMcpObservedVersion;
|
|
7605
7623
|
let devtoolsMcpInvocation;
|
|
7606
7624
|
if (useBrowserPreferences && (enabled.has(DEVTOOLS_MCP_SERVER) || owned.has(DEVTOOLS_MCP_SERVER))) {
|
|
@@ -7849,7 +7867,12 @@ async function runInstall(opts) {
|
|
|
7849
7867
|
}
|
|
7850
7868
|
}
|
|
7851
7869
|
const anyDevtoolsEnabled = opts.runtimes.some((id) => enabledMcpServers(id, opts.devtoolsMcpSelection?.[id], useManifest).has(DEVTOOLS_MCP_SERVER));
|
|
7852
|
-
const anyDevtoolsOwned = useManifest && opts.runtimes.some((id) =>
|
|
7870
|
+
const anyDevtoolsOwned = useManifest && opts.runtimes.some((id) => {
|
|
7871
|
+
const adapter = ADAPTERS[id];
|
|
7872
|
+
if (adapter === void 0) return false;
|
|
7873
|
+
const detection = adapter.detect();
|
|
7874
|
+
return detection.installed && ownedMcpServers(id, detection.configDir, true).has(DEVTOOLS_MCP_SERVER);
|
|
7875
|
+
});
|
|
7853
7876
|
if (anyDevtoolsEnabled && devtoolsManagedInvocation === void 0) {
|
|
7854
7877
|
const observed = isDevtoolsTargetDir ? devtoolsTargetDirObserved : devtoolsPersistedObserved;
|
|
7855
7878
|
try {
|
|
@@ -7955,7 +7978,7 @@ async function runInstall(opts) {
|
|
|
7955
7978
|
}
|
|
7956
7979
|
}
|
|
7957
7980
|
const enabledForRuntime = enabledMcpServers(id, opts.devtoolsMcpSelection?.[id], useManifest);
|
|
7958
|
-
const ownedForRuntime = ownedMcpServers(id, useManifest);
|
|
7981
|
+
const ownedForRuntime = ownedMcpServers(id, configDir, useManifest);
|
|
7959
7982
|
let devtoolsObservedForRuntime;
|
|
7960
7983
|
if (isDevtoolsTargetDir) {
|
|
7961
7984
|
if (enabledForRuntime.has(DEVTOOLS_MCP_SERVER)) {
|
|
@@ -8114,7 +8137,15 @@ async function runInstall(opts) {
|
|
|
8114
8137
|
const backup = useManifest ? createBackup([...updates.map((c) => c.action.target), ...orphans], `install-${id}`) : null;
|
|
8115
8138
|
if (backup) p.log.info(`Backup: ${backup.id} (${backup.files.length} archivos)`);
|
|
8116
8139
|
applyChanges(changes, useManifest ? (action) => persistConfigurationOwnershipChanges(id, configDir, [action]) : void 0);
|
|
8117
|
-
const
|
|
8140
|
+
const verifiedOwnedMcpServers = new Set(ctx.ownedMcpServers ?? []);
|
|
8141
|
+
for (const action of plan) {
|
|
8142
|
+
if (action.kind !== "write") continue;
|
|
8143
|
+
for (const change of action.mcpOwnership ?? []) {
|
|
8144
|
+
if (change.owned) verifiedOwnedMcpServers.add(change.server);
|
|
8145
|
+
else verifiedOwnedMcpServers.delete(change.server);
|
|
8146
|
+
}
|
|
8147
|
+
}
|
|
8148
|
+
const verifyCtx = { ...ctx, warnings: [], ownedMcpServers: verifiedOwnedMcpServers };
|
|
8118
8149
|
const dirty = diffPlan(buildPlan(adapter, verifyCtx)).filter((d) => d.status !== "unchanged");
|
|
8119
8150
|
if (dirty.length > 0) {
|
|
8120
8151
|
p.log.error(`${adapter.name}: verificaci\xF3n de idempotencia FALL\xD3 (${dirty.length} acciones inestables).`);
|
|
@@ -12734,8 +12765,8 @@ init_model_map();
|
|
|
12734
12765
|
|
|
12735
12766
|
// src/lib/pi-runtime.ts
|
|
12736
12767
|
import os6 from "os";
|
|
12737
|
-
import
|
|
12738
|
-
import
|
|
12768
|
+
import path48 from "path";
|
|
12769
|
+
import fs40 from "fs";
|
|
12739
12770
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
12740
12771
|
|
|
12741
12772
|
// src/lib/pi-runtime-pin.json
|
|
@@ -12789,8 +12820,8 @@ init_paths();
|
|
|
12789
12820
|
|
|
12790
12821
|
// src/lib/pi-install-preflight.ts
|
|
12791
12822
|
init_npm_provider();
|
|
12792
|
-
import
|
|
12793
|
-
import
|
|
12823
|
+
import fs36 from "fs";
|
|
12824
|
+
import path44 from "path";
|
|
12794
12825
|
|
|
12795
12826
|
// src/lib/pi-candidate.ts
|
|
12796
12827
|
import fs33 from "fs";
|
|
@@ -13490,18 +13521,121 @@ async function stageVerifiedPiTarball(input, run) {
|
|
|
13490
13521
|
return { stageDir, evidence, sourceAlias };
|
|
13491
13522
|
}
|
|
13492
13523
|
|
|
13493
|
-
// src/lib/pi-
|
|
13524
|
+
// src/lib/pi-host-version.ts
|
|
13525
|
+
import fs35 from "fs";
|
|
13526
|
+
import path43 from "path";
|
|
13494
13527
|
var PI_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
|
|
13528
|
+
function invalidManagedPi(diagnostic) {
|
|
13529
|
+
return { version: null, diagnostic };
|
|
13530
|
+
}
|
|
13531
|
+
function readJsonFile(file) {
|
|
13532
|
+
try {
|
|
13533
|
+
const stat = fs35.lstatSync(file, { throwIfNoEntry: false });
|
|
13534
|
+
if (!stat?.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024) return null;
|
|
13535
|
+
return JSON.parse(fs35.readFileSync(file, "utf8"));
|
|
13536
|
+
} catch {
|
|
13537
|
+
return null;
|
|
13538
|
+
}
|
|
13539
|
+
}
|
|
13540
|
+
function piPackageVersion(file) {
|
|
13541
|
+
try {
|
|
13542
|
+
const value = readJsonFile(file);
|
|
13543
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
13544
|
+
const packageName = Reflect.get(value, "name");
|
|
13545
|
+
const version = Reflect.get(value, "version");
|
|
13546
|
+
return packageName === PI_PACKAGE_NAME && typeof version === "string" && version !== "" && !/\s/.test(version) ? version : null;
|
|
13547
|
+
} catch {
|
|
13548
|
+
return null;
|
|
13549
|
+
}
|
|
13550
|
+
}
|
|
13551
|
+
function managedPiVersion(executable, resolved2) {
|
|
13552
|
+
const binDir = path43.dirname(resolved2);
|
|
13553
|
+
if (path43.basename(resolved2) !== "pi" || path43.basename(binDir) !== "bin") {
|
|
13554
|
+
return invalidManagedPi("launcher gestionado de Pi no reconocido");
|
|
13555
|
+
}
|
|
13556
|
+
const agentDir = path43.dirname(binDir);
|
|
13557
|
+
const installDir = path43.join(agentDir, "install");
|
|
13558
|
+
try {
|
|
13559
|
+
if (!fs35.lstatSync(executable).isSymbolicLink()) {
|
|
13560
|
+
return invalidManagedPi("el entrypoint gestionado de Pi no es un symlink");
|
|
13561
|
+
}
|
|
13562
|
+
const metadata = readJsonFile(path43.join(installDir, "managed-install.json"));
|
|
13563
|
+
if (metadata === null || typeof metadata !== "object" || Array.isArray(metadata)) {
|
|
13564
|
+
return invalidManagedPi("install/managed-install.json falta o no es JSON v\xE1lido");
|
|
13565
|
+
}
|
|
13566
|
+
const entrypoint = Reflect.get(metadata, "entrypoint");
|
|
13567
|
+
if (Reflect.get(metadata, "kind") !== "pi-managed-install" || Reflect.get(metadata, "schemaVersion") !== 1 || Reflect.get(metadata, "layout") !== "releases-v1" || entrypoint === null || typeof entrypoint !== "object" || Array.isArray(entrypoint) || Reflect.get(entrypoint, "type") !== "symlink" || Reflect.get(entrypoint, "path") !== executable) {
|
|
13568
|
+
return invalidManagedPi("install/managed-install.json no coincide con el entrypoint de Pi");
|
|
13569
|
+
}
|
|
13570
|
+
const currentPath = path43.join(installDir, "current-version");
|
|
13571
|
+
const currentStat = fs35.lstatSync(currentPath, { throwIfNoEntry: false });
|
|
13572
|
+
if (!currentStat?.isFile() || currentStat.isSymbolicLink() || currentStat.size > 128) {
|
|
13573
|
+
return invalidManagedPi("install/current-version falta o no es un archivo regular acotado");
|
|
13574
|
+
}
|
|
13575
|
+
const version = fs35.readFileSync(currentPath, "utf8").trim();
|
|
13576
|
+
if (version === "." || version === ".." || !/^[0-9A-Za-z._+-]+$/.test(version)) {
|
|
13577
|
+
return invalidManagedPi("install/current-version contiene una versi\xF3n inv\xE1lida");
|
|
13578
|
+
}
|
|
13579
|
+
const releaseDir = path43.join(installDir, "releases", version);
|
|
13580
|
+
if (fs35.realpathSync(releaseDir) !== releaseDir) {
|
|
13581
|
+
return invalidManagedPi("install/releases contiene un enlace fuera del release gestionado");
|
|
13582
|
+
}
|
|
13583
|
+
const packageDir = path43.join(releaseDir, "node_modules", "@earendil-works", "pi-coding-agent");
|
|
13584
|
+
if (fs35.realpathSync(packageDir) !== packageDir) {
|
|
13585
|
+
return invalidManagedPi("el paquete Pi del release gestionado es un symlink");
|
|
13586
|
+
}
|
|
13587
|
+
const packageVersion = piPackageVersion(path43.join(packageDir, "package.json"));
|
|
13588
|
+
return packageVersion === version ? { version, diagnostic: null } : invalidManagedPi("el manifest de @earendil-works/pi-coding-agent no coincide con install/current-version");
|
|
13589
|
+
} catch {
|
|
13590
|
+
return invalidManagedPi("no se pudo leer la metadata del release Pi gestionado");
|
|
13591
|
+
}
|
|
13592
|
+
}
|
|
13593
|
+
function hasManagedPiMarker(resolved2) {
|
|
13594
|
+
const binDir = path43.dirname(resolved2);
|
|
13595
|
+
if (path43.basename(resolved2) !== "pi" || path43.basename(binDir) !== "bin") return false;
|
|
13596
|
+
const installDir = path43.join(path43.dirname(binDir), "install");
|
|
13597
|
+
try {
|
|
13598
|
+
return fs35.lstatSync(path43.join(installDir, "managed-install.json"), { throwIfNoEntry: false }) !== void 0 || fs35.lstatSync(path43.join(installDir, "current-version"), { throwIfNoEntry: false }) !== void 0;
|
|
13599
|
+
} catch {
|
|
13600
|
+
return true;
|
|
13601
|
+
}
|
|
13602
|
+
}
|
|
13603
|
+
function inspectPiHostVersion(executable) {
|
|
13604
|
+
const absoluteExecutable = path43.resolve(executable);
|
|
13605
|
+
let resolved2;
|
|
13606
|
+
try {
|
|
13607
|
+
resolved2 = fs35.realpathSync(absoluteExecutable);
|
|
13608
|
+
} catch {
|
|
13609
|
+
return { version: null, diagnostic: "no se pudo resolver el ejecutable Pi" };
|
|
13610
|
+
}
|
|
13611
|
+
if (hasManagedPiMarker(resolved2)) return managedPiVersion(absoluteExecutable, resolved2);
|
|
13612
|
+
let current = path43.dirname(resolved2);
|
|
13613
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
13614
|
+
for (const manifest of [
|
|
13615
|
+
path43.join(current, "package.json"),
|
|
13616
|
+
path43.join(current, "node_modules", "@earendil-works", "pi-coding-agent", "package.json")
|
|
13617
|
+
]) {
|
|
13618
|
+
const version = piPackageVersion(manifest);
|
|
13619
|
+
if (version !== null) return { version, diagnostic: null };
|
|
13620
|
+
}
|
|
13621
|
+
const parent = path43.dirname(current);
|
|
13622
|
+
if (parent === current) break;
|
|
13623
|
+
current = parent;
|
|
13624
|
+
}
|
|
13625
|
+
return { version: null, diagnostic: "no se encontr\xF3 el manifest del paquete Pi instalado" };
|
|
13626
|
+
}
|
|
13627
|
+
|
|
13628
|
+
// src/lib/pi-install-preflight.ts
|
|
13495
13629
|
function fail9(message) {
|
|
13496
13630
|
throw new Error(`pi-install-preflight: ${message}`);
|
|
13497
13631
|
}
|
|
13498
13632
|
function isStrictChild3(child, root) {
|
|
13499
|
-
const rel =
|
|
13500
|
-
return rel !== "" && rel !== ".." && !rel.startsWith(`..${
|
|
13633
|
+
const rel = path44.relative(path44.resolve(root), path44.resolve(child));
|
|
13634
|
+
return rel !== "" && rel !== ".." && !rel.startsWith(`..${path44.sep}`) && !path44.isAbsolute(rel);
|
|
13501
13635
|
}
|
|
13502
13636
|
function lstatOrNull4(p7) {
|
|
13503
13637
|
try {
|
|
13504
|
-
return
|
|
13638
|
+
return fs36.lstatSync(p7);
|
|
13505
13639
|
} catch {
|
|
13506
13640
|
return null;
|
|
13507
13641
|
}
|
|
@@ -13517,24 +13651,24 @@ function validatePaths(paths) {
|
|
|
13517
13651
|
fail9("paths must be an object");
|
|
13518
13652
|
}
|
|
13519
13653
|
const { homeDir, agentDir, piExecutable, downloadsDir } = paths;
|
|
13520
|
-
if (typeof homeDir !== "string" || homeDir === "" || !
|
|
13654
|
+
if (typeof homeDir !== "string" || homeDir === "" || !path44.isAbsolute(homeDir)) {
|
|
13521
13655
|
fail9("homeDir must be a non-empty absolute path");
|
|
13522
13656
|
}
|
|
13523
|
-
if (typeof agentDir !== "string" || agentDir === "" || !
|
|
13657
|
+
if (typeof agentDir !== "string" || agentDir === "" || !path44.isAbsolute(agentDir)) {
|
|
13524
13658
|
fail9("agentDir must be a non-empty absolute path");
|
|
13525
13659
|
}
|
|
13526
|
-
if (typeof piExecutable !== "string" || piExecutable === "" || !
|
|
13660
|
+
if (typeof piExecutable !== "string" || piExecutable === "" || !path44.isAbsolute(piExecutable)) {
|
|
13527
13661
|
fail9("piExecutable must be a non-empty absolute path");
|
|
13528
13662
|
}
|
|
13529
13663
|
if (piExecutable === "npm") {
|
|
13530
13664
|
fail9("piExecutable must be the detected Pi CLI, never npm");
|
|
13531
13665
|
}
|
|
13532
|
-
if (typeof downloadsDir !== "string" || downloadsDir === "" || !
|
|
13666
|
+
if (typeof downloadsDir !== "string" || downloadsDir === "" || !path44.isAbsolute(downloadsDir)) {
|
|
13533
13667
|
fail9("downloadsDir must be a non-empty absolute path");
|
|
13534
13668
|
}
|
|
13535
|
-
const homeResolved =
|
|
13536
|
-
const agentResolved =
|
|
13537
|
-
const downloadsResolved =
|
|
13669
|
+
const homeResolved = path44.resolve(homeDir);
|
|
13670
|
+
const agentResolved = path44.resolve(agentDir);
|
|
13671
|
+
const downloadsResolved = path44.resolve(downloadsDir);
|
|
13538
13672
|
assertRealDir2(homeResolved, "homeDir");
|
|
13539
13673
|
assertRealDir2(agentResolved, "agentDir");
|
|
13540
13674
|
assertRealDir2(downloadsResolved, "downloadsDir");
|
|
@@ -13562,43 +13696,6 @@ function validateDeps(deps) {
|
|
|
13562
13696
|
}
|
|
13563
13697
|
return { fetchImpl, run };
|
|
13564
13698
|
}
|
|
13565
|
-
function readJsonFile(file) {
|
|
13566
|
-
return JSON.parse(fs35.readFileSync(file, "utf8"));
|
|
13567
|
-
}
|
|
13568
|
-
function detectPiHostVersion(piExecutable) {
|
|
13569
|
-
let current;
|
|
13570
|
-
try {
|
|
13571
|
-
current = path43.dirname(fs35.realpathSync(piExecutable));
|
|
13572
|
-
} catch {
|
|
13573
|
-
fail9(`cannot resolve Pi executable: ${piExecutable}`);
|
|
13574
|
-
}
|
|
13575
|
-
for (let depth = 0; depth < 8; depth++) {
|
|
13576
|
-
const manifests = [
|
|
13577
|
-
path43.join(current, "package.json"),
|
|
13578
|
-
path43.join(current, "node_modules", PI_PACKAGE_NAME, "package.json")
|
|
13579
|
-
];
|
|
13580
|
-
for (const manifest of manifests) {
|
|
13581
|
-
let parsed;
|
|
13582
|
-
try {
|
|
13583
|
-
parsed = readJsonFile(manifest);
|
|
13584
|
-
} catch {
|
|
13585
|
-
continue;
|
|
13586
|
-
}
|
|
13587
|
-
if (parsed !== null && typeof parsed === "object" && Reflect.get(parsed, "name") === PI_PACKAGE_NAME && typeof Reflect.get(parsed, "version") === "string") {
|
|
13588
|
-
const version = Reflect.get(parsed, "version");
|
|
13589
|
-
if (version !== "" && !/\s/.test(version)) {
|
|
13590
|
-
return version;
|
|
13591
|
-
}
|
|
13592
|
-
}
|
|
13593
|
-
}
|
|
13594
|
-
const parent = path43.dirname(current);
|
|
13595
|
-
if (parent === current) {
|
|
13596
|
-
break;
|
|
13597
|
-
}
|
|
13598
|
-
current = parent;
|
|
13599
|
-
}
|
|
13600
|
-
fail9(`cannot detect Pi host version from executable: ${piExecutable}`);
|
|
13601
|
-
}
|
|
13602
13699
|
async function preparePiManagedInstall(paths, deps) {
|
|
13603
13700
|
const { homeDir, agentDir, piExecutable, downloadsDir } = validatePaths(paths);
|
|
13604
13701
|
const { fetchImpl, run } = validateDeps(deps);
|
|
@@ -13627,8 +13724,8 @@ async function preparePiManagedInstall(paths, deps) {
|
|
|
13627
13724
|
`pi-install-preflight: producer commit resolution failed: ${error instanceof Error ? error.message : String(error)}`
|
|
13628
13725
|
);
|
|
13629
13726
|
}
|
|
13630
|
-
const downloadsResolved =
|
|
13631
|
-
const destination =
|
|
13727
|
+
const downloadsResolved = path44.resolve(downloadsDir);
|
|
13728
|
+
const destination = path44.join(downloadsResolved, `jorgex-pi-${release.version}.tgz`);
|
|
13632
13729
|
if (!isStrictChild3(destination, downloadsResolved)) {
|
|
13633
13730
|
fail9(`tarball destination escapes downloadsDir: ${destination}`);
|
|
13634
13731
|
}
|
|
@@ -13657,7 +13754,8 @@ async function preparePiManagedInstall(paths, deps) {
|
|
|
13657
13754
|
} catch (error) {
|
|
13658
13755
|
throw error;
|
|
13659
13756
|
}
|
|
13660
|
-
const
|
|
13757
|
+
const hostInspection = inspectPiHostVersion(piExecutable);
|
|
13758
|
+
const hostVersion = hostInspection.version ?? fail9(`cannot detect Pi host version: ${hostInspection.diagnostic ?? "unknown reason"}`);
|
|
13661
13759
|
let candidate;
|
|
13662
13760
|
try {
|
|
13663
13761
|
candidate = await buildStagedPiCandidate({
|
|
@@ -13679,16 +13777,16 @@ import { createHash as createHash8 } from "crypto";
|
|
|
13679
13777
|
|
|
13680
13778
|
// src/lib/pi-private-release.ts
|
|
13681
13779
|
import crypto2 from "crypto";
|
|
13682
|
-
import
|
|
13683
|
-
import
|
|
13780
|
+
import fs37 from "fs";
|
|
13781
|
+
import path45 from "path";
|
|
13684
13782
|
var RELEASE_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
13685
13783
|
var EXPECTED_ENTRY = "jorgex-pi";
|
|
13686
13784
|
function resolved(p7) {
|
|
13687
|
-
return
|
|
13785
|
+
return path45.resolve(p7);
|
|
13688
13786
|
}
|
|
13689
13787
|
function isStrictChild4(child, root) {
|
|
13690
|
-
const rel =
|
|
13691
|
-
return rel !== "" && rel !== ".." && !rel.startsWith(`..${
|
|
13788
|
+
const rel = path45.relative(resolved(root), resolved(child));
|
|
13789
|
+
return rel !== "" && rel !== ".." && !rel.startsWith(`..${path45.sep}`) && !path45.isAbsolute(rel);
|
|
13692
13790
|
}
|
|
13693
13791
|
function assertStrictChild(child, root, label) {
|
|
13694
13792
|
if (!isStrictChild4(child, root)) {
|
|
@@ -13697,7 +13795,7 @@ function assertStrictChild(child, root, label) {
|
|
|
13697
13795
|
}
|
|
13698
13796
|
function lstatOrNull5(p7) {
|
|
13699
13797
|
try {
|
|
13700
|
-
return
|
|
13798
|
+
return fs37.lstatSync(p7);
|
|
13701
13799
|
} catch {
|
|
13702
13800
|
return null;
|
|
13703
13801
|
}
|
|
@@ -13719,7 +13817,7 @@ function assertAncestorsClean(dir, stop, label) {
|
|
|
13719
13817
|
throw new Error(`${label} ancestor is a symlink: ${cur}`);
|
|
13720
13818
|
}
|
|
13721
13819
|
if (cur === stopResolved) break;
|
|
13722
|
-
const parent =
|
|
13820
|
+
const parent = path45.dirname(cur);
|
|
13723
13821
|
if (parent === cur) break;
|
|
13724
13822
|
cur = parent;
|
|
13725
13823
|
if (cur.length < stopResolved.length) break;
|
|
@@ -13731,7 +13829,7 @@ function assertFilePathClean(file, stop, label) {
|
|
|
13731
13829
|
if (st !== null && st.isSymbolicLink()) {
|
|
13732
13830
|
throw new Error(`${label} is a symlink: ${file}`);
|
|
13733
13831
|
}
|
|
13734
|
-
assertAncestorsClean(
|
|
13832
|
+
assertAncestorsClean(path45.dirname(resolved(file)), stop, label);
|
|
13735
13833
|
}
|
|
13736
13834
|
function assertDirClean(dir, stop, label) {
|
|
13737
13835
|
assertStrictChild(dir, stop, label);
|
|
@@ -13743,17 +13841,17 @@ function assertDirClean(dir, stop, label) {
|
|
|
13743
13841
|
}
|
|
13744
13842
|
function assertLinkInsideRoot(linkPath, allowedRoot, label, finalKind) {
|
|
13745
13843
|
const allowedResolved = resolved(allowedRoot);
|
|
13746
|
-
const linkParent =
|
|
13844
|
+
const linkParent = path45.dirname(resolved(linkPath));
|
|
13747
13845
|
if (linkParent !== allowedResolved && !isStrictChild4(linkParent, allowedResolved)) {
|
|
13748
13846
|
throw new Error(`${label} escapes owner root: ${linkPath}`);
|
|
13749
13847
|
}
|
|
13750
13848
|
let target;
|
|
13751
13849
|
try {
|
|
13752
|
-
target =
|
|
13850
|
+
target = fs37.readlinkSync(linkPath);
|
|
13753
13851
|
} catch {
|
|
13754
13852
|
throw new Error(`${label} is broken or unreadable: ${linkPath}`);
|
|
13755
13853
|
}
|
|
13756
|
-
if (target === "" ||
|
|
13854
|
+
if (target === "" || path45.isAbsolute(target)) {
|
|
13757
13855
|
throw new Error(`${label} must be a relative symlink: ${linkPath}`);
|
|
13758
13856
|
}
|
|
13759
13857
|
const parentStat = lstatOrNull5(linkParent);
|
|
@@ -13769,7 +13867,7 @@ function assertLinkInsideRoot(linkPath, allowedRoot, label, finalKind) {
|
|
|
13769
13867
|
const part = ops[i];
|
|
13770
13868
|
const isLast = i === ops.length - 1;
|
|
13771
13869
|
if (part === "..") {
|
|
13772
|
-
cur =
|
|
13870
|
+
cur = path45.dirname(cur);
|
|
13773
13871
|
if (cur !== allowedResolved && !isStrictChild4(cur, allowedResolved)) {
|
|
13774
13872
|
throw new Error(`${label} escapes owner root: ${linkPath} -> ${target}`);
|
|
13775
13873
|
}
|
|
@@ -13792,7 +13890,7 @@ function assertLinkInsideRoot(linkPath, allowedRoot, label, finalKind) {
|
|
|
13792
13890
|
}
|
|
13793
13891
|
continue;
|
|
13794
13892
|
}
|
|
13795
|
-
const next =
|
|
13893
|
+
const next = path45.join(cur, part);
|
|
13796
13894
|
if (next !== allowedResolved && !isStrictChild4(next, allowedResolved)) {
|
|
13797
13895
|
throw new Error(`${label} escapes owner root: ${linkPath} -> ${target}`);
|
|
13798
13896
|
}
|
|
@@ -13832,12 +13930,12 @@ function validateStageTree(stagedNpm) {
|
|
|
13832
13930
|
const dir = stack.pop();
|
|
13833
13931
|
let entries;
|
|
13834
13932
|
try {
|
|
13835
|
-
entries =
|
|
13933
|
+
entries = fs37.readdirSync(dir, { withFileTypes: true });
|
|
13836
13934
|
} catch {
|
|
13837
13935
|
throw new Error(`staged tree unreadable: ${dir}`);
|
|
13838
13936
|
}
|
|
13839
13937
|
for (const entry of entries) {
|
|
13840
|
-
const full =
|
|
13938
|
+
const full = path45.join(dir, entry.name);
|
|
13841
13939
|
if (entry.isSymbolicLink()) {
|
|
13842
13940
|
assertInternalSymlink(full, root, "staged symlink");
|
|
13843
13941
|
continue;
|
|
@@ -13849,39 +13947,39 @@ function validateStageTree(stagedNpm) {
|
|
|
13849
13947
|
}
|
|
13850
13948
|
}
|
|
13851
13949
|
function atomicWritePrivate(target, content) {
|
|
13852
|
-
const dir =
|
|
13853
|
-
|
|
13854
|
-
const tmp =
|
|
13950
|
+
const dir = path45.dirname(resolved(target));
|
|
13951
|
+
fs37.mkdirSync(dir, { recursive: true });
|
|
13952
|
+
const tmp = path45.join(dir, `.tmp-${crypto2.randomBytes(16).toString("hex")}`);
|
|
13855
13953
|
let fd = null;
|
|
13856
13954
|
try {
|
|
13857
|
-
fd =
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13955
|
+
fd = fs37.openSync(tmp, "wx", 384);
|
|
13956
|
+
fs37.writeFileSync(fd, content, "utf8");
|
|
13957
|
+
fs37.fsyncSync(fd);
|
|
13958
|
+
fs37.closeSync(fd);
|
|
13861
13959
|
fd = null;
|
|
13862
13960
|
} finally {
|
|
13863
13961
|
if (fd !== null) {
|
|
13864
13962
|
try {
|
|
13865
|
-
|
|
13963
|
+
fs37.closeSync(fd);
|
|
13866
13964
|
} catch {
|
|
13867
13965
|
}
|
|
13868
|
-
|
|
13966
|
+
fs37.rmSync(tmp, { force: true });
|
|
13869
13967
|
}
|
|
13870
13968
|
}
|
|
13871
13969
|
const tmpStat = lstatOrNull5(tmp);
|
|
13872
13970
|
if (tmpStat === null || !tmpStat.isFile()) {
|
|
13873
13971
|
try {
|
|
13874
|
-
|
|
13972
|
+
fs37.rmSync(tmp, { force: true });
|
|
13875
13973
|
} catch {
|
|
13876
13974
|
failIncomplete(`cannot clean private temp (recovery incomplete): ${tmp}`);
|
|
13877
13975
|
}
|
|
13878
13976
|
throw new Error(`private temp is not a regular file: ${target}`);
|
|
13879
13977
|
}
|
|
13880
13978
|
try {
|
|
13881
|
-
|
|
13979
|
+
fs37.renameSync(tmp, target);
|
|
13882
13980
|
} catch (err) {
|
|
13883
13981
|
try {
|
|
13884
|
-
|
|
13982
|
+
fs37.rmSync(tmp, { force: true });
|
|
13885
13983
|
} catch {
|
|
13886
13984
|
const original = err instanceof Error ? err.message : String(err ?? "rename failed");
|
|
13887
13985
|
failIncomplete(`cannot clean private temp after rename failure (recovery incomplete): ${tmp}: ${original}`);
|
|
@@ -13898,7 +13996,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
13898
13996
|
if (typeof input.homeDir !== "string" || input.homeDir === "") {
|
|
13899
13997
|
throw new Error(`homeDir must be a non-empty absolute path`);
|
|
13900
13998
|
}
|
|
13901
|
-
if (!
|
|
13999
|
+
if (!path45.isAbsolute(input.homeDir)) {
|
|
13902
14000
|
throw new Error(`homeDir must be absolute: ${input.homeDir}`);
|
|
13903
14001
|
}
|
|
13904
14002
|
if (!RELEASE_ID_PATTERN.test(releaseId)) {
|
|
@@ -13934,22 +14032,22 @@ async function activateVerifiedPiRelease(input) {
|
|
|
13934
14032
|
if (stageStat === null || !stageStat.isDirectory() || stageStat.isSymbolicLink()) {
|
|
13935
14033
|
throw new Error(`stageDir must be a real directory: ${input.stageDir}`);
|
|
13936
14034
|
}
|
|
13937
|
-
const settingsPath =
|
|
13938
|
-
const npmDir =
|
|
13939
|
-
const nodeModules =
|
|
13940
|
-
const linkPath =
|
|
13941
|
-
const stagedNpm =
|
|
13942
|
-
const stagedModules =
|
|
13943
|
-
const stagedEntry =
|
|
13944
|
-
const releaseRoot =
|
|
13945
|
-
const releaseDir =
|
|
13946
|
-
const managedRoot =
|
|
13947
|
-
const markerPath =
|
|
13948
|
-
const lockPath =
|
|
13949
|
-
const backupDir =
|
|
13950
|
-
const backupEntry =
|
|
13951
|
-
const backupSettings =
|
|
13952
|
-
const backupReceipt =
|
|
14035
|
+
const settingsPath = path45.join(agentDir, "settings.json");
|
|
14036
|
+
const npmDir = path45.join(agentDir, "npm");
|
|
14037
|
+
const nodeModules = path45.join(npmDir, "node_modules");
|
|
14038
|
+
const linkPath = path45.join(nodeModules, EXPECTED_ENTRY);
|
|
14039
|
+
const stagedNpm = path45.join(stageDir, "npm");
|
|
14040
|
+
const stagedModules = path45.join(stagedNpm, "node_modules");
|
|
14041
|
+
const stagedEntry = path45.join(stagedModules, EXPECTED_ENTRY);
|
|
14042
|
+
const releaseRoot = path45.join(npmDir, "jorgex-pi-managed", "releases");
|
|
14043
|
+
const releaseDir = path45.join(releaseRoot, releaseId);
|
|
14044
|
+
const managedRoot = path45.join(npmDir, "jorgex-pi-managed");
|
|
14045
|
+
const markerPath = path45.join(managedRoot, "active-transaction.json");
|
|
14046
|
+
const lockPath = path45.join(managedRoot, "transaction.lock");
|
|
14047
|
+
const backupDir = path45.join(stageDir, ".activate-backup");
|
|
14048
|
+
const backupEntry = path45.join(backupDir, "entry");
|
|
14049
|
+
const backupSettings = path45.join(backupDir, "settings.json");
|
|
14050
|
+
const backupReceipt = path45.join(backupDir, "receipt.json");
|
|
13953
14051
|
const expectedTarget = `../jorgex-pi-managed/releases/${releaseId}/node_modules/${EXPECTED_ENTRY}`;
|
|
13954
14052
|
assertStrictChild(agentDir, homeDir, "agentDir");
|
|
13955
14053
|
assertStrictChild(receiptPath, homeDir, "receiptPath");
|
|
@@ -14002,7 +14100,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14002
14100
|
let oldEntryExisted = false;
|
|
14003
14101
|
if (linkStat !== null) {
|
|
14004
14102
|
oldEntryExisted = true;
|
|
14005
|
-
assertAncestorsClean(
|
|
14103
|
+
assertAncestorsClean(path45.dirname(linkPath), homeDir, "managed entry");
|
|
14006
14104
|
if (linkStat.isSymbolicLink()) {
|
|
14007
14105
|
assertManagedEntrySymlink(linkPath, npmDir, "managed entry");
|
|
14008
14106
|
} else if (!linkStat.isDirectory()) {
|
|
@@ -14019,10 +14117,10 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14019
14117
|
let oldReceipt = null;
|
|
14020
14118
|
try {
|
|
14021
14119
|
if (lstatOrNull5(settingsPath) !== null) {
|
|
14022
|
-
oldSettings =
|
|
14120
|
+
oldSettings = fs37.readFileSync(settingsPath, "utf8");
|
|
14023
14121
|
}
|
|
14024
14122
|
if (lstatOrNull5(receiptPath) !== null) {
|
|
14025
|
-
oldReceipt =
|
|
14123
|
+
oldReceipt = fs37.readFileSync(receiptPath, "utf8");
|
|
14026
14124
|
}
|
|
14027
14125
|
} catch {
|
|
14028
14126
|
throw new Error(`cannot read previous settings/receipt`);
|
|
@@ -14034,7 +14132,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14034
14132
|
const ownedBackupFiles = /* @__PURE__ */ new Map();
|
|
14035
14133
|
const releaseLock = () => {
|
|
14036
14134
|
if (!lockAcquired) return;
|
|
14037
|
-
|
|
14135
|
+
fs37.rmSync(lockPath, { force: true });
|
|
14038
14136
|
lockAcquired = false;
|
|
14039
14137
|
};
|
|
14040
14138
|
const captureBackupDirIdentity = () => {
|
|
@@ -14060,7 +14158,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14060
14158
|
if (dirStat.dev !== backupDirDev || dirStat.ino !== backupDirIno) return "backup dir replaced";
|
|
14061
14159
|
let entries;
|
|
14062
14160
|
try {
|
|
14063
|
-
entries =
|
|
14161
|
+
entries = fs37.readdirSync(backupDir);
|
|
14064
14162
|
} catch {
|
|
14065
14163
|
return "cannot list backup";
|
|
14066
14164
|
}
|
|
@@ -14070,7 +14168,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14070
14168
|
if (!allowed.has(entry)) return `unknown backup entry: ${entry}`;
|
|
14071
14169
|
}
|
|
14072
14170
|
for (const entry of entries) {
|
|
14073
|
-
const full = resolved(
|
|
14171
|
+
const full = resolved(path45.join(backupDir, entry));
|
|
14074
14172
|
const owned = ownedBackupFiles.get(full);
|
|
14075
14173
|
if (!owned) return `unowned backup file: ${entry}`;
|
|
14076
14174
|
const st = lstatOrNull5(full);
|
|
@@ -14078,14 +14176,14 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14078
14176
|
if (st.dev !== owned.dev || st.ino !== owned.ino) return `backup file replaced: ${entry}`;
|
|
14079
14177
|
let cur;
|
|
14080
14178
|
try {
|
|
14081
|
-
cur =
|
|
14179
|
+
cur = fs37.readFileSync(full, "utf8");
|
|
14082
14180
|
} catch {
|
|
14083
14181
|
return `cannot read backup file: ${entry}`;
|
|
14084
14182
|
}
|
|
14085
14183
|
if (cur !== owned.content) return `backup file bytes drifted: ${entry}`;
|
|
14086
14184
|
}
|
|
14087
14185
|
for (const [fullPath] of ownedBackupFiles) {
|
|
14088
|
-
const base =
|
|
14186
|
+
const base = path45.basename(fullPath);
|
|
14089
14187
|
if (!entries.includes(base)) return `owned backup file missing: ${base}`;
|
|
14090
14188
|
}
|
|
14091
14189
|
return null;
|
|
@@ -14107,7 +14205,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14107
14205
|
}
|
|
14108
14206
|
let cur;
|
|
14109
14207
|
try {
|
|
14110
|
-
cur =
|
|
14208
|
+
cur = fs37.readFileSync(fullPath, "utf8");
|
|
14111
14209
|
} catch {
|
|
14112
14210
|
failIncomplete(
|
|
14113
14211
|
`backup drifted during cleanup, preserving foreign state (recovery incomplete): ${fullPath}: ${original}`
|
|
@@ -14119,7 +14217,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14119
14217
|
`backup drifted during cleanup, preserving foreign state (recovery incomplete): ${fullPath}: ${original}`
|
|
14120
14218
|
);
|
|
14121
14219
|
}
|
|
14122
|
-
|
|
14220
|
+
fs37.unlinkSync(fullPath);
|
|
14123
14221
|
}
|
|
14124
14222
|
} catch (err) {
|
|
14125
14223
|
if (err instanceof Error && err.recovery === "incomplete") throw err;
|
|
@@ -14129,13 +14227,13 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14129
14227
|
);
|
|
14130
14228
|
}
|
|
14131
14229
|
try {
|
|
14132
|
-
const remaining =
|
|
14230
|
+
const remaining = fs37.readdirSync(backupDir);
|
|
14133
14231
|
if (remaining.length !== 0) {
|
|
14134
14232
|
failIncomplete(
|
|
14135
14233
|
`backup dir not empty after owned cleanup, preserving foreign state (recovery incomplete): ${backupDir}: ${original}`
|
|
14136
14234
|
);
|
|
14137
14235
|
}
|
|
14138
|
-
|
|
14236
|
+
fs37.rmdirSync(backupDir);
|
|
14139
14237
|
} catch (err) {
|
|
14140
14238
|
if (err instanceof Error && err.recovery === "incomplete") throw err;
|
|
14141
14239
|
const msg = err instanceof Error ? err.message : String(err ?? "rmdir failed");
|
|
@@ -14144,7 +14242,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14144
14242
|
);
|
|
14145
14243
|
}
|
|
14146
14244
|
try {
|
|
14147
|
-
|
|
14245
|
+
fs37.rmSync(markerPath, { force: true });
|
|
14148
14246
|
releaseLock();
|
|
14149
14247
|
} catch {
|
|
14150
14248
|
failIncomplete(`cannot clear transaction state after rollback: ${original}`);
|
|
@@ -14160,7 +14258,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14160
14258
|
if (!backupCreated) {
|
|
14161
14259
|
const problems = [];
|
|
14162
14260
|
try {
|
|
14163
|
-
|
|
14261
|
+
fs37.rmSync(markerPath, { force: true });
|
|
14164
14262
|
} catch {
|
|
14165
14263
|
problems.push("cannot remove marker");
|
|
14166
14264
|
}
|
|
@@ -14179,7 +14277,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14179
14277
|
if (err instanceof Error) throw err;
|
|
14180
14278
|
throw new Error(original);
|
|
14181
14279
|
};
|
|
14182
|
-
|
|
14280
|
+
fs37.mkdirSync(managedRoot, { recursive: true });
|
|
14183
14281
|
assertAncestorsClean(managedRoot, homeDir, "managed root");
|
|
14184
14282
|
const managedRootStat = lstatOrNull5(managedRoot);
|
|
14185
14283
|
if (managedRootStat === null || !managedRootStat.isDirectory() || managedRootStat.isSymbolicLink()) {
|
|
@@ -14188,14 +14286,14 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14188
14286
|
const lockToken = `${JSON.stringify({ pid: process.pid, stageDir, releaseId, startedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
14189
14287
|
`;
|
|
14190
14288
|
try {
|
|
14191
|
-
|
|
14289
|
+
fs37.writeFileSync(lockPath, lockToken, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
14192
14290
|
lockAcquired = true;
|
|
14193
14291
|
} catch {
|
|
14194
14292
|
failIncomplete(`transaction lock busy: concurrent activation holds the exclusive lock (recovery incomplete): ${lockPath}`);
|
|
14195
14293
|
}
|
|
14196
14294
|
if (lstatOrNull5(markerPath) !== null) {
|
|
14197
14295
|
try {
|
|
14198
|
-
|
|
14296
|
+
fs37.rmSync(lockPath, { force: true });
|
|
14199
14297
|
lockAcquired = false;
|
|
14200
14298
|
} catch {
|
|
14201
14299
|
}
|
|
@@ -14204,10 +14302,10 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14204
14302
|
const markerContent = `${JSON.stringify({ stageDir, backupDir, releaseId, releaseDir, phase: "prepared", pid: process.pid }, null, 2)}
|
|
14205
14303
|
`;
|
|
14206
14304
|
try {
|
|
14207
|
-
|
|
14305
|
+
fs37.writeFileSync(markerPath, markerContent, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
14208
14306
|
} catch {
|
|
14209
14307
|
try {
|
|
14210
|
-
|
|
14308
|
+
fs37.rmSync(lockPath, { force: true });
|
|
14211
14309
|
lockAcquired = false;
|
|
14212
14310
|
} catch {
|
|
14213
14311
|
}
|
|
@@ -14225,7 +14323,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14225
14323
|
}
|
|
14226
14324
|
}
|
|
14227
14325
|
try {
|
|
14228
|
-
|
|
14326
|
+
fs37.mkdirSync(backupDir);
|
|
14229
14327
|
backupCreated = true;
|
|
14230
14328
|
captureBackupDirIdentity();
|
|
14231
14329
|
} catch (err) {
|
|
@@ -14245,7 +14343,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14245
14343
|
}
|
|
14246
14344
|
const persistBackupCopy = (target, content) => {
|
|
14247
14345
|
if (content === null) return;
|
|
14248
|
-
|
|
14346
|
+
fs37.writeFileSync(target, content, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
14249
14347
|
trackOwnedBackupFile(target, content);
|
|
14250
14348
|
};
|
|
14251
14349
|
let entryMoved = false;
|
|
@@ -14255,10 +14353,10 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14255
14353
|
try {
|
|
14256
14354
|
persistBackupCopy(backupSettings, oldSettings);
|
|
14257
14355
|
persistBackupCopy(backupReceipt, oldReceipt);
|
|
14258
|
-
const metaPath =
|
|
14356
|
+
const metaPath = path45.join(backupDir, "meta.json");
|
|
14259
14357
|
const metaContent = `${JSON.stringify({ releaseId, oldEntryExisted }, null, 2)}
|
|
14260
14358
|
`;
|
|
14261
|
-
|
|
14359
|
+
fs37.writeFileSync(metaPath, metaContent, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
14262
14360
|
trackOwnedBackupFile(metaPath, metaContent);
|
|
14263
14361
|
} catch {
|
|
14264
14362
|
abortBeforePublish(new Error(`cannot persist private backup`));
|
|
@@ -14274,7 +14372,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14274
14372
|
} else {
|
|
14275
14373
|
let target = null;
|
|
14276
14374
|
try {
|
|
14277
|
-
target =
|
|
14375
|
+
target = fs37.readlinkSync(linkPath);
|
|
14278
14376
|
} catch {
|
|
14279
14377
|
target = null;
|
|
14280
14378
|
}
|
|
@@ -14286,7 +14384,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14286
14384
|
if (drift === null && wroteSettings) {
|
|
14287
14385
|
let cur = null;
|
|
14288
14386
|
try {
|
|
14289
|
-
cur =
|
|
14387
|
+
cur = fs37.readFileSync(settingsPath, "utf8");
|
|
14290
14388
|
} catch {
|
|
14291
14389
|
cur = null;
|
|
14292
14390
|
}
|
|
@@ -14295,7 +14393,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14295
14393
|
if (drift === null && wroteReceipt) {
|
|
14296
14394
|
let cur = null;
|
|
14297
14395
|
try {
|
|
14298
|
-
cur =
|
|
14396
|
+
cur = fs37.readFileSync(receiptPath, "utf8");
|
|
14299
14397
|
} catch {
|
|
14300
14398
|
cur = null;
|
|
14301
14399
|
}
|
|
@@ -14311,7 +14409,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14311
14409
|
if (cur === null || !cur.isSymbolicLink()) {
|
|
14312
14410
|
problems.push("published entry link missing");
|
|
14313
14411
|
} else {
|
|
14314
|
-
|
|
14412
|
+
fs37.unlinkSync(linkPath);
|
|
14315
14413
|
}
|
|
14316
14414
|
} else if (lstatOrNull5(linkPath) !== null) {
|
|
14317
14415
|
problems.push("unexpected managed entry");
|
|
@@ -14327,7 +14425,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14327
14425
|
} else if (lstatOrNull5(linkPath) !== null) {
|
|
14328
14426
|
problems.push("managed entry still present");
|
|
14329
14427
|
} else {
|
|
14330
|
-
|
|
14428
|
+
fs37.renameSync(backupEntry, linkPath);
|
|
14331
14429
|
}
|
|
14332
14430
|
} else if (lstatOrNull5(linkPath) !== null) {
|
|
14333
14431
|
problems.push("unexpected managed entry");
|
|
@@ -14340,7 +14438,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14340
14438
|
if (oldSettings !== null) {
|
|
14341
14439
|
atomicWritePrivate(settingsPath, oldSettings);
|
|
14342
14440
|
} else {
|
|
14343
|
-
|
|
14441
|
+
fs37.rmSync(settingsPath, { force: true });
|
|
14344
14442
|
}
|
|
14345
14443
|
}
|
|
14346
14444
|
} catch {
|
|
@@ -14351,7 +14449,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14351
14449
|
if (oldReceipt !== null) {
|
|
14352
14450
|
atomicWritePrivate(receiptPath, oldReceipt);
|
|
14353
14451
|
} else {
|
|
14354
|
-
|
|
14452
|
+
fs37.rmSync(receiptPath, { force: true });
|
|
14355
14453
|
}
|
|
14356
14454
|
}
|
|
14357
14455
|
} catch {
|
|
@@ -14361,7 +14459,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14361
14459
|
const destStat = lstatOrNull5(releaseDir);
|
|
14362
14460
|
const stagedStat = lstatOrNull5(stagedNpm);
|
|
14363
14461
|
if (destStat !== null && stagedStat === null) {
|
|
14364
|
-
|
|
14462
|
+
fs37.renameSync(releaseDir, stagedNpm);
|
|
14365
14463
|
} else if (destStat !== null && stagedStat !== null) {
|
|
14366
14464
|
problems.push("staged tree and promoted release both present");
|
|
14367
14465
|
} else if (destStat === null && stagedStat === null) {
|
|
@@ -14381,7 +14479,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14381
14479
|
clearOwnedBackupThenCooperativeState(original);
|
|
14382
14480
|
} else {
|
|
14383
14481
|
try {
|
|
14384
|
-
|
|
14482
|
+
fs37.rmSync(markerPath, { force: true });
|
|
14385
14483
|
releaseLock();
|
|
14386
14484
|
} catch {
|
|
14387
14485
|
failIncomplete(`cannot clear transaction state after rollback: ${original}`);
|
|
@@ -14397,14 +14495,14 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14397
14495
|
};
|
|
14398
14496
|
try {
|
|
14399
14497
|
if (oldEntryExisted) {
|
|
14400
|
-
|
|
14498
|
+
fs37.renameSync(linkPath, backupEntry);
|
|
14401
14499
|
entryMoved = true;
|
|
14402
14500
|
}
|
|
14403
14501
|
} catch {
|
|
14404
14502
|
abortBeforePublish(new Error(`cannot backup previous managed entry`));
|
|
14405
14503
|
}
|
|
14406
14504
|
try {
|
|
14407
|
-
|
|
14505
|
+
fs37.mkdirSync(releaseRoot, { recursive: true });
|
|
14408
14506
|
assertAncestorsClean(releaseRoot, homeDir, "release root");
|
|
14409
14507
|
const rootStat = lstatOrNull5(releaseRoot);
|
|
14410
14508
|
if (rootStat === null || !rootStat.isDirectory() || rootStat.isSymbolicLink()) {
|
|
@@ -14413,8 +14511,8 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14413
14511
|
if (lstatOrNull5(releaseDir) !== null) {
|
|
14414
14512
|
throw new Error(`release already exists: ${releaseDir}`);
|
|
14415
14513
|
}
|
|
14416
|
-
|
|
14417
|
-
|
|
14514
|
+
fs37.renameSync(stagedNpm, releaseDir);
|
|
14515
|
+
fs37.symlinkSync(expectedTarget, linkPath, "dir");
|
|
14418
14516
|
publishedLink = true;
|
|
14419
14517
|
atomicWritePrivate(settingsPath, input.nextSettings);
|
|
14420
14518
|
wroteSettings = true;
|
|
@@ -14432,7 +14530,7 @@ async function activateVerifiedPiRelease(input) {
|
|
|
14432
14530
|
rollback(err);
|
|
14433
14531
|
}
|
|
14434
14532
|
try {
|
|
14435
|
-
|
|
14533
|
+
fs37.rmSync(markerPath, { force: true });
|
|
14436
14534
|
releaseLock();
|
|
14437
14535
|
} catch {
|
|
14438
14536
|
failIncomplete(`cannot clear transaction state after activation (recovery incomplete): ${markerPath}`);
|
|
@@ -14448,14 +14546,14 @@ function isManagedDependency(value) {
|
|
|
14448
14546
|
}
|
|
14449
14547
|
function readTextOrNull(p7) {
|
|
14450
14548
|
try {
|
|
14451
|
-
return
|
|
14549
|
+
return fs37.readFileSync(p7, "utf8");
|
|
14452
14550
|
} catch {
|
|
14453
14551
|
return null;
|
|
14454
14552
|
}
|
|
14455
14553
|
}
|
|
14456
14554
|
function safeReadlink(p7) {
|
|
14457
14555
|
try {
|
|
14458
|
-
return
|
|
14556
|
+
return fs37.readlinkSync(p7);
|
|
14459
14557
|
} catch {
|
|
14460
14558
|
return null;
|
|
14461
14559
|
}
|
|
@@ -14471,7 +14569,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14471
14569
|
if (typeof input.homeDir !== "string" || input.homeDir === "" || typeof input.agentDir !== "string" || input.agentDir === "" || typeof input.receiptPath !== "string" || input.receiptPath === "" || typeof mp.releaseDir !== "string" || mp.releaseDir === "" || typeof mp.linkPath !== "string" || mp.linkPath === "" || typeof mp.backupDir !== "string" || mp.backupDir === "") {
|
|
14472
14570
|
throw new Error(`homeDir, agentDir, receiptPath and managedPackage paths must be non-empty strings`);
|
|
14473
14571
|
}
|
|
14474
|
-
if (!
|
|
14572
|
+
if (!path45.isAbsolute(input.homeDir)) {
|
|
14475
14573
|
throw new Error(`homeDir must be absolute: ${input.homeDir}`);
|
|
14476
14574
|
}
|
|
14477
14575
|
if (typeof mp.lockSha256 !== "string" || !HEX64_PATTERN.test(mp.lockSha256)) {
|
|
@@ -14512,23 +14610,23 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14512
14610
|
if (agentStat === null || !agentStat.isDirectory() || agentStat.isSymbolicLink()) {
|
|
14513
14611
|
throw new Error(`agentDir must be a real directory: ${input.agentDir}`);
|
|
14514
14612
|
}
|
|
14515
|
-
const settingsPath =
|
|
14516
|
-
const npmDir =
|
|
14517
|
-
const nodeModules =
|
|
14518
|
-
const expectedLink =
|
|
14519
|
-
const releaseRoot =
|
|
14520
|
-
const managedRoot =
|
|
14521
|
-
const markerPath =
|
|
14522
|
-
const lockPath =
|
|
14613
|
+
const settingsPath = path45.join(agentDir, "settings.json");
|
|
14614
|
+
const npmDir = path45.join(agentDir, "npm");
|
|
14615
|
+
const nodeModules = path45.join(npmDir, "node_modules");
|
|
14616
|
+
const expectedLink = path45.join(nodeModules, EXPECTED_ENTRY);
|
|
14617
|
+
const releaseRoot = path45.join(npmDir, "jorgex-pi-managed", "releases");
|
|
14618
|
+
const managedRoot = path45.join(npmDir, "jorgex-pi-managed");
|
|
14619
|
+
const markerPath = path45.join(managedRoot, "active-transaction.json");
|
|
14620
|
+
const lockPath = path45.join(managedRoot, "transaction.lock");
|
|
14523
14621
|
if (linkPath !== expectedLink) {
|
|
14524
14622
|
throw new Error(`managed link must be the owned entry: ${expectedLink}`);
|
|
14525
14623
|
}
|
|
14526
|
-
const releaseId =
|
|
14527
|
-
if (
|
|
14624
|
+
const releaseId = path45.basename(releaseDir);
|
|
14625
|
+
if (path45.dirname(releaseDir) !== releaseRoot || !HEX64_PATTERN.test(releaseId)) {
|
|
14528
14626
|
throw new Error(`managed release must live under the private releases root: ${releaseDir}`);
|
|
14529
14627
|
}
|
|
14530
14628
|
const expectedTarget = `../jorgex-pi-managed/releases/${releaseId}/node_modules/${EXPECTED_ENTRY}`;
|
|
14531
|
-
const packageRoot =
|
|
14629
|
+
const packageRoot = path45.join(releaseDir, "node_modules", EXPECTED_ENTRY);
|
|
14532
14630
|
assertStrictChild(agentDir, homeDir, "agentDir");
|
|
14533
14631
|
assertStrictChild(receiptPath, homeDir, "receiptPath");
|
|
14534
14632
|
assertStrictChild(releaseDir, agentDir, "managed release");
|
|
@@ -14567,7 +14665,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14567
14665
|
if (linkStat === null || !linkStat.isSymbolicLink()) {
|
|
14568
14666
|
throw new Error(`managed entry must be the owned symlink: ${linkPath}`);
|
|
14569
14667
|
}
|
|
14570
|
-
assertAncestorsClean(
|
|
14668
|
+
assertAncestorsClean(path45.dirname(linkPath), homeDir, "managed entry");
|
|
14571
14669
|
const observedTarget = safeReadlink(linkPath);
|
|
14572
14670
|
if (observedTarget === null || observedTarget !== expectedTarget) {
|
|
14573
14671
|
throw new Error(`managed entry points outside the owned release: ${linkPath}`);
|
|
@@ -14579,7 +14677,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14579
14677
|
}
|
|
14580
14678
|
let liveRealpath = null;
|
|
14581
14679
|
try {
|
|
14582
|
-
liveRealpath =
|
|
14680
|
+
liveRealpath = fs37.realpathSync(linkPath);
|
|
14583
14681
|
} catch {
|
|
14584
14682
|
liveRealpath = null;
|
|
14585
14683
|
}
|
|
@@ -14596,7 +14694,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14596
14694
|
throw new Error(`activation backup must be a real directory: ${mp.backupDir}`);
|
|
14597
14695
|
}
|
|
14598
14696
|
assertAncestorsClean(activationBackupDir, homeDir, "activation backup");
|
|
14599
|
-
const lockFile =
|
|
14697
|
+
const lockFile = path45.join(releaseDir, "package-lock.json");
|
|
14600
14698
|
const lockStat = lstatOrNull5(lockFile);
|
|
14601
14699
|
if (lockStat === null || lockStat.isSymbolicLink() || !lockStat.isFile()) {
|
|
14602
14700
|
throw new Error(`managed lock must be a regular file: ${lockFile}`);
|
|
@@ -14606,7 +14704,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14606
14704
|
}
|
|
14607
14705
|
let lockBytes;
|
|
14608
14706
|
try {
|
|
14609
|
-
lockBytes =
|
|
14707
|
+
lockBytes = fs37.readFileSync(lockFile);
|
|
14610
14708
|
} catch {
|
|
14611
14709
|
throw new Error(`cannot read managed lock: ${lockFile}`);
|
|
14612
14710
|
}
|
|
@@ -14624,19 +14722,19 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14624
14722
|
let oldReceipt = null;
|
|
14625
14723
|
try {
|
|
14626
14724
|
if (lstatOrNull5(settingsPath) !== null) {
|
|
14627
|
-
oldSettings =
|
|
14725
|
+
oldSettings = fs37.readFileSync(settingsPath, "utf8");
|
|
14628
14726
|
}
|
|
14629
|
-
oldReceipt =
|
|
14727
|
+
oldReceipt = fs37.readFileSync(receiptPath, "utf8");
|
|
14630
14728
|
} catch {
|
|
14631
14729
|
throw new Error(`cannot read previous settings/receipt`);
|
|
14632
14730
|
}
|
|
14633
14731
|
let lockAcquired = false;
|
|
14634
14732
|
const releaseLock = () => {
|
|
14635
14733
|
if (!lockAcquired) return;
|
|
14636
|
-
|
|
14734
|
+
fs37.rmSync(lockPath, { force: true });
|
|
14637
14735
|
lockAcquired = false;
|
|
14638
14736
|
};
|
|
14639
|
-
|
|
14737
|
+
fs37.mkdirSync(managedRoot, { recursive: true });
|
|
14640
14738
|
assertAncestorsClean(managedRoot, homeDir, "managed root");
|
|
14641
14739
|
const managedRootStat = lstatOrNull5(managedRoot);
|
|
14642
14740
|
if (managedRootStat === null || !managedRootStat.isDirectory() || managedRootStat.isSymbolicLink()) {
|
|
@@ -14644,7 +14742,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14644
14742
|
}
|
|
14645
14743
|
let uninstallBackupDir = "";
|
|
14646
14744
|
for (let i = 0; i < 5 && uninstallBackupDir === ""; i++) {
|
|
14647
|
-
const candidateDir =
|
|
14745
|
+
const candidateDir = path45.join(managedRoot, `uninstall-backup-${crypto2.randomBytes(8).toString("hex")}`);
|
|
14648
14746
|
if (lstatOrNull5(candidateDir) === null) uninstallBackupDir = candidateDir;
|
|
14649
14747
|
}
|
|
14650
14748
|
if (uninstallBackupDir === "") {
|
|
@@ -14654,14 +14752,14 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14654
14752
|
const lockToken = `${JSON.stringify({ op: "uninstall", pid: process.pid, agentDir, releaseId, startedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
14655
14753
|
`;
|
|
14656
14754
|
try {
|
|
14657
|
-
|
|
14755
|
+
fs37.writeFileSync(lockPath, lockToken, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
14658
14756
|
lockAcquired = true;
|
|
14659
14757
|
} catch {
|
|
14660
14758
|
failIncomplete(`transaction lock busy: concurrent operation holds the exclusive lock (recovery incomplete): ${lockPath}`);
|
|
14661
14759
|
}
|
|
14662
14760
|
if (lstatOrNull5(markerPath) !== null) {
|
|
14663
14761
|
try {
|
|
14664
|
-
|
|
14762
|
+
fs37.rmSync(lockPath, { force: true });
|
|
14665
14763
|
lockAcquired = false;
|
|
14666
14764
|
} catch {
|
|
14667
14765
|
}
|
|
@@ -14670,10 +14768,10 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14670
14768
|
const markerContent = `${JSON.stringify({ phase: "uninstall", releaseDir, linkPath, receiptPath, backupDir: uninstallBackupDir, activationBackupDir, releaseId, pid: process.pid }, null, 2)}
|
|
14671
14769
|
`;
|
|
14672
14770
|
try {
|
|
14673
|
-
|
|
14771
|
+
fs37.writeFileSync(markerPath, markerContent, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
14674
14772
|
} catch {
|
|
14675
14773
|
try {
|
|
14676
|
-
|
|
14774
|
+
fs37.rmSync(lockPath, { force: true });
|
|
14677
14775
|
lockAcquired = false;
|
|
14678
14776
|
} catch {
|
|
14679
14777
|
}
|
|
@@ -14682,7 +14780,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14682
14780
|
const abortOwnTransaction = (err) => {
|
|
14683
14781
|
const problems = [];
|
|
14684
14782
|
try {
|
|
14685
|
-
|
|
14783
|
+
fs37.rmSync(markerPath, { force: true });
|
|
14686
14784
|
} catch {
|
|
14687
14785
|
problems.push("cannot remove marker");
|
|
14688
14786
|
}
|
|
@@ -14692,7 +14790,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14692
14790
|
problems.push("cannot release lock");
|
|
14693
14791
|
}
|
|
14694
14792
|
try {
|
|
14695
|
-
|
|
14793
|
+
fs37.rmSync(uninstallBackupDir, { recursive: true, force: true });
|
|
14696
14794
|
} catch {
|
|
14697
14795
|
problems.push("cannot clear backup");
|
|
14698
14796
|
}
|
|
@@ -14728,7 +14826,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14728
14826
|
}
|
|
14729
14827
|
if (drift !== null) {
|
|
14730
14828
|
try {
|
|
14731
|
-
|
|
14829
|
+
fs37.rmSync(markerPath, { force: true });
|
|
14732
14830
|
releaseLock();
|
|
14733
14831
|
} catch {
|
|
14734
14832
|
}
|
|
@@ -14737,7 +14835,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14737
14835
|
};
|
|
14738
14836
|
recheckLiveState();
|
|
14739
14837
|
try {
|
|
14740
|
-
|
|
14838
|
+
fs37.mkdirSync(uninstallBackupDir, { recursive: true });
|
|
14741
14839
|
} catch (err) {
|
|
14742
14840
|
abortOwnTransaction(err);
|
|
14743
14841
|
}
|
|
@@ -14747,22 +14845,22 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14747
14845
|
}
|
|
14748
14846
|
let backupEntries = [];
|
|
14749
14847
|
try {
|
|
14750
|
-
backupEntries =
|
|
14848
|
+
backupEntries = fs37.readdirSync(uninstallBackupDir);
|
|
14751
14849
|
} catch {
|
|
14752
14850
|
abortOwnTransaction(new Error(`cannot inspect uninstall backup: ${uninstallBackupDir}`));
|
|
14753
14851
|
}
|
|
14754
14852
|
if (backupEntries.length !== 0) {
|
|
14755
14853
|
abortOwnTransaction(new Error(`uninstall backup is not empty: ${uninstallBackupDir}`));
|
|
14756
14854
|
}
|
|
14757
|
-
const backupReleaseDir =
|
|
14758
|
-
const backupReceiptFile =
|
|
14759
|
-
const backupSettingsFile =
|
|
14855
|
+
const backupReleaseDir = path45.join(uninstallBackupDir, "release");
|
|
14856
|
+
const backupReceiptFile = path45.join(uninstallBackupDir, "pi-receipt.json");
|
|
14857
|
+
const backupSettingsFile = path45.join(uninstallBackupDir, "settings.json");
|
|
14760
14858
|
try {
|
|
14761
14859
|
if (oldSettings !== null) {
|
|
14762
|
-
|
|
14860
|
+
fs37.writeFileSync(backupSettingsFile, oldSettings, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
14763
14861
|
}
|
|
14764
|
-
|
|
14765
|
-
|
|
14862
|
+
fs37.writeFileSync(
|
|
14863
|
+
path45.join(uninstallBackupDir, "meta.json"),
|
|
14766
14864
|
`${JSON.stringify({ phase: "uninstall", releaseDir, linkPath, receiptPath, linkTarget: observedTarget }, null, 2)}
|
|
14767
14865
|
`,
|
|
14768
14866
|
{ encoding: "utf8", flag: "wx", mode: 384 }
|
|
@@ -14815,14 +14913,14 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14815
14913
|
const problems = [];
|
|
14816
14914
|
if (movedRelease) {
|
|
14817
14915
|
try {
|
|
14818
|
-
|
|
14916
|
+
fs37.renameSync(backupReleaseDir, releaseDir);
|
|
14819
14917
|
} catch {
|
|
14820
14918
|
problems.push("cannot restore release");
|
|
14821
14919
|
}
|
|
14822
14920
|
}
|
|
14823
14921
|
if (removedLink) {
|
|
14824
14922
|
try {
|
|
14825
|
-
|
|
14923
|
+
fs37.symlinkSync(observedTarget, linkPath, "dir");
|
|
14826
14924
|
} catch {
|
|
14827
14925
|
problems.push("cannot restore managed entry");
|
|
14828
14926
|
}
|
|
@@ -14832,7 +14930,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14832
14930
|
if (oldSettings !== null) {
|
|
14833
14931
|
atomicWritePrivate(settingsPath, oldSettings);
|
|
14834
14932
|
} else {
|
|
14835
|
-
|
|
14933
|
+
fs37.rmSync(settingsPath, { force: true });
|
|
14836
14934
|
}
|
|
14837
14935
|
} catch {
|
|
14838
14936
|
problems.push("cannot restore previous settings");
|
|
@@ -14840,7 +14938,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14840
14938
|
}
|
|
14841
14939
|
if (movedReceipt) {
|
|
14842
14940
|
try {
|
|
14843
|
-
|
|
14941
|
+
fs37.renameSync(backupReceiptFile, receiptPath);
|
|
14844
14942
|
} catch {
|
|
14845
14943
|
problems.push("cannot restore receipt");
|
|
14846
14944
|
}
|
|
@@ -14849,9 +14947,9 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14849
14947
|
failIncomplete(`uninstall rollback incomplete (${problems.join("; ")}): ${original}`);
|
|
14850
14948
|
}
|
|
14851
14949
|
try {
|
|
14852
|
-
|
|
14950
|
+
fs37.rmSync(markerPath, { force: true });
|
|
14853
14951
|
releaseLock();
|
|
14854
|
-
|
|
14952
|
+
fs37.rmSync(uninstallBackupDir, { recursive: true, force: true });
|
|
14855
14953
|
} catch {
|
|
14856
14954
|
failIncomplete(`cannot clear transaction state after rollback: ${original}`);
|
|
14857
14955
|
}
|
|
@@ -14864,11 +14962,11 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14864
14962
|
throw wrapped;
|
|
14865
14963
|
};
|
|
14866
14964
|
try {
|
|
14867
|
-
|
|
14965
|
+
fs37.unlinkSync(linkPath);
|
|
14868
14966
|
removedLink = true;
|
|
14869
|
-
|
|
14967
|
+
fs37.renameSync(releaseDir, backupReleaseDir);
|
|
14870
14968
|
movedRelease = true;
|
|
14871
|
-
|
|
14969
|
+
fs37.renameSync(receiptPath, backupReceiptFile);
|
|
14872
14970
|
movedReceipt = true;
|
|
14873
14971
|
atomicWritePrivate(settingsPath, input.nextSettings);
|
|
14874
14972
|
wroteSettings = true;
|
|
@@ -14890,7 +14988,7 @@ function deactivateVerifiedPiRelease(input) {
|
|
|
14890
14988
|
rollbackDeactivate(new Error(`verify must be synchronous and return void, got thenable`));
|
|
14891
14989
|
}
|
|
14892
14990
|
try {
|
|
14893
|
-
|
|
14991
|
+
fs37.rmSync(markerPath, { force: true });
|
|
14894
14992
|
releaseLock();
|
|
14895
14993
|
} catch {
|
|
14896
14994
|
failIncomplete(`cannot clear transaction state after uninstall (recovery incomplete): ${markerPath}`);
|
|
@@ -14931,7 +15029,7 @@ function readRegularTextLegacy(file, label) {
|
|
|
14931
15029
|
throw new Error(`${label} exceeds size bound: ${file}`);
|
|
14932
15030
|
}
|
|
14933
15031
|
try {
|
|
14934
|
-
return
|
|
15032
|
+
return fs37.readFileSync(file, "utf8");
|
|
14935
15033
|
} catch {
|
|
14936
15034
|
throw new Error(`cannot read ${label}: ${file}`);
|
|
14937
15035
|
}
|
|
@@ -14943,7 +15041,7 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
14943
15041
|
if (typeof input.homeDir !== "string" || input.homeDir === "" || typeof input.agentDir !== "string" || input.agentDir === "" || typeof input.receiptPath !== "string" || input.receiptPath === "" || typeof input.source !== "string" || input.source === "") {
|
|
14944
15042
|
throw new Error(`homeDir, agentDir, receiptPath and source must be non-empty strings`);
|
|
14945
15043
|
}
|
|
14946
|
-
if (!
|
|
15044
|
+
if (!path45.isAbsolute(input.homeDir)) {
|
|
14947
15045
|
throw new Error(`homeDir must be absolute: ${input.homeDir}`);
|
|
14948
15046
|
}
|
|
14949
15047
|
const sourceMatch = LEGACY_SOURCE_PATTERN.exec(input.source);
|
|
@@ -14977,13 +15075,13 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
14977
15075
|
if (agentStat === null || !agentStat.isDirectory() || agentStat.isSymbolicLink()) {
|
|
14978
15076
|
throw new Error(`agentDir must be a real directory: ${input.agentDir}`);
|
|
14979
15077
|
}
|
|
14980
|
-
const settingsPath =
|
|
14981
|
-
const npmDir =
|
|
14982
|
-
const nodeModules =
|
|
14983
|
-
const legacyEntry =
|
|
14984
|
-
const managedRoot =
|
|
14985
|
-
const markerPath =
|
|
14986
|
-
const lockPath =
|
|
15078
|
+
const settingsPath = path45.join(agentDir, "settings.json");
|
|
15079
|
+
const npmDir = path45.join(agentDir, "npm");
|
|
15080
|
+
const nodeModules = path45.join(npmDir, "node_modules");
|
|
15081
|
+
const legacyEntry = path45.join(nodeModules, EXPECTED_ENTRY);
|
|
15082
|
+
const managedRoot = path45.join(npmDir, "jorgex-pi-managed");
|
|
15083
|
+
const markerPath = path45.join(managedRoot, "active-transaction.json");
|
|
15084
|
+
const lockPath = path45.join(managedRoot, "transaction.lock");
|
|
14987
15085
|
assertStrictChild(agentDir, homeDir, "agentDir");
|
|
14988
15086
|
assertStrictChild(receiptPath, homeDir, "receiptPath");
|
|
14989
15087
|
assertStrictChild(managedRoot, agentDir, "managed root");
|
|
@@ -15016,8 +15114,8 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15016
15114
|
if (entryStat === null || !entryStat.isDirectory() || entryStat.isSymbolicLink()) {
|
|
15017
15115
|
throw new Error(`managed entry must be a real directory, not a symlink: ${legacyEntry}`);
|
|
15018
15116
|
}
|
|
15019
|
-
assertAncestorsClean(
|
|
15020
|
-
const manifestPath =
|
|
15117
|
+
assertAncestorsClean(path45.dirname(legacyEntry), homeDir, "managed entry");
|
|
15118
|
+
const manifestPath = path45.join(legacyEntry, "package.json");
|
|
15021
15119
|
const manifestStat = lstatOrNull5(manifestPath);
|
|
15022
15120
|
if (manifestStat === null || !manifestStat.isFile() || manifestStat.isSymbolicLink()) {
|
|
15023
15121
|
throw new Error(`managed entry manifest must be a regular file: ${manifestPath}`);
|
|
@@ -15114,10 +15212,10 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15114
15212
|
let lockAcquired = false;
|
|
15115
15213
|
const releaseLock = () => {
|
|
15116
15214
|
if (!lockAcquired) return;
|
|
15117
|
-
|
|
15215
|
+
fs37.rmSync(lockPath, { force: true });
|
|
15118
15216
|
lockAcquired = false;
|
|
15119
15217
|
};
|
|
15120
|
-
|
|
15218
|
+
fs37.mkdirSync(managedRoot, { recursive: true });
|
|
15121
15219
|
assertAncestorsClean(managedRoot, homeDir, "managed root");
|
|
15122
15220
|
const managedRootStat = lstatOrNull5(managedRoot);
|
|
15123
15221
|
if (managedRootStat === null || !managedRootStat.isDirectory() || managedRootStat.isSymbolicLink()) {
|
|
@@ -15125,7 +15223,7 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15125
15223
|
}
|
|
15126
15224
|
let uninstallBackupDir = "";
|
|
15127
15225
|
for (let i = 0; i < 5 && uninstallBackupDir === ""; i++) {
|
|
15128
|
-
const candidateDir =
|
|
15226
|
+
const candidateDir = path45.join(managedRoot, `uninstall-backup-${crypto2.randomBytes(8).toString("hex")}`);
|
|
15129
15227
|
if (lstatOrNull5(candidateDir) === null) uninstallBackupDir = candidateDir;
|
|
15130
15228
|
}
|
|
15131
15229
|
if (uninstallBackupDir === "") {
|
|
@@ -15135,14 +15233,14 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15135
15233
|
const lockToken = `${JSON.stringify({ op: "uninstall-legacy", pid: process.pid, agentDir, source: input.source, startedAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
15136
15234
|
`;
|
|
15137
15235
|
try {
|
|
15138
|
-
|
|
15236
|
+
fs37.writeFileSync(lockPath, lockToken, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
15139
15237
|
lockAcquired = true;
|
|
15140
15238
|
} catch {
|
|
15141
15239
|
failIncomplete(`transaction lock busy: concurrent operation holds the exclusive lock (recovery incomplete): ${lockPath}`);
|
|
15142
15240
|
}
|
|
15143
15241
|
if (lstatOrNull5(markerPath) !== null) {
|
|
15144
15242
|
try {
|
|
15145
|
-
|
|
15243
|
+
fs37.rmSync(lockPath, { force: true });
|
|
15146
15244
|
lockAcquired = false;
|
|
15147
15245
|
} catch {
|
|
15148
15246
|
}
|
|
@@ -15151,10 +15249,10 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15151
15249
|
const markerContent = `${JSON.stringify({ phase: "uninstall-legacy", legacyEntry, receiptPath, backupDir: uninstallBackupDir, source: input.source, pid: process.pid }, null, 2)}
|
|
15152
15250
|
`;
|
|
15153
15251
|
try {
|
|
15154
|
-
|
|
15252
|
+
fs37.writeFileSync(markerPath, markerContent, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
15155
15253
|
} catch {
|
|
15156
15254
|
try {
|
|
15157
|
-
|
|
15255
|
+
fs37.rmSync(lockPath, { force: true });
|
|
15158
15256
|
lockAcquired = false;
|
|
15159
15257
|
} catch {
|
|
15160
15258
|
}
|
|
@@ -15163,7 +15261,7 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15163
15261
|
const abortOwnTransaction = (err) => {
|
|
15164
15262
|
const problems = [];
|
|
15165
15263
|
try {
|
|
15166
|
-
|
|
15264
|
+
fs37.rmSync(markerPath, { force: true });
|
|
15167
15265
|
} catch {
|
|
15168
15266
|
problems.push("cannot remove marker");
|
|
15169
15267
|
}
|
|
@@ -15173,7 +15271,7 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15173
15271
|
problems.push("cannot release lock");
|
|
15174
15272
|
}
|
|
15175
15273
|
try {
|
|
15176
|
-
|
|
15274
|
+
fs37.rmSync(uninstallBackupDir, { recursive: true, force: true });
|
|
15177
15275
|
} catch {
|
|
15178
15276
|
problems.push("cannot clear backup");
|
|
15179
15277
|
}
|
|
@@ -15192,7 +15290,7 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15192
15290
|
abortOwnTransaction(new Error(`receipt or settings drifted before uninstall: ${legacyEntry}`));
|
|
15193
15291
|
}
|
|
15194
15292
|
try {
|
|
15195
|
-
|
|
15293
|
+
fs37.mkdirSync(uninstallBackupDir, { recursive: true });
|
|
15196
15294
|
} catch (err) {
|
|
15197
15295
|
abortOwnTransaction(err);
|
|
15198
15296
|
}
|
|
@@ -15202,20 +15300,20 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15202
15300
|
}
|
|
15203
15301
|
let backupEntries = [];
|
|
15204
15302
|
try {
|
|
15205
|
-
backupEntries =
|
|
15303
|
+
backupEntries = fs37.readdirSync(uninstallBackupDir);
|
|
15206
15304
|
} catch {
|
|
15207
15305
|
abortOwnTransaction(new Error(`cannot inspect uninstall backup: ${uninstallBackupDir}`));
|
|
15208
15306
|
}
|
|
15209
15307
|
if (backupEntries.length !== 0) {
|
|
15210
15308
|
abortOwnTransaction(new Error(`uninstall backup is not empty: ${uninstallBackupDir}`));
|
|
15211
15309
|
}
|
|
15212
|
-
const backupEntryDir =
|
|
15213
|
-
const backupReceiptFile =
|
|
15214
|
-
const backupSettingsFile =
|
|
15310
|
+
const backupEntryDir = path45.join(uninstallBackupDir, "entry");
|
|
15311
|
+
const backupReceiptFile = path45.join(uninstallBackupDir, "pi-receipt.json");
|
|
15312
|
+
const backupSettingsFile = path45.join(uninstallBackupDir, "settings.json");
|
|
15215
15313
|
try {
|
|
15216
|
-
|
|
15217
|
-
|
|
15218
|
-
|
|
15314
|
+
fs37.writeFileSync(backupSettingsFile, oldSettings, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
15315
|
+
fs37.writeFileSync(
|
|
15316
|
+
path45.join(uninstallBackupDir, "meta.json"),
|
|
15219
15317
|
`${JSON.stringify({ phase: "uninstall-legacy", legacyEntry, receiptPath, source: input.source }, null, 2)}
|
|
15220
15318
|
`,
|
|
15221
15319
|
{ encoding: "utf8", flag: "wx", mode: 384 }
|
|
@@ -15259,14 +15357,14 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15259
15357
|
const problems = [];
|
|
15260
15358
|
if (movedReceipt) {
|
|
15261
15359
|
try {
|
|
15262
|
-
|
|
15360
|
+
fs37.renameSync(backupReceiptFile, receiptPath);
|
|
15263
15361
|
} catch {
|
|
15264
15362
|
problems.push("cannot restore receipt");
|
|
15265
15363
|
}
|
|
15266
15364
|
}
|
|
15267
15365
|
if (movedEntry) {
|
|
15268
15366
|
try {
|
|
15269
|
-
|
|
15367
|
+
fs37.renameSync(backupEntryDir, legacyEntry);
|
|
15270
15368
|
} catch {
|
|
15271
15369
|
problems.push("cannot restore previous entry");
|
|
15272
15370
|
}
|
|
@@ -15282,9 +15380,9 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15282
15380
|
failIncomplete(`uninstall rollback incomplete (${problems.join("; ")}): ${original}`);
|
|
15283
15381
|
}
|
|
15284
15382
|
try {
|
|
15285
|
-
|
|
15383
|
+
fs37.rmSync(markerPath, { force: true });
|
|
15286
15384
|
releaseLock();
|
|
15287
|
-
|
|
15385
|
+
fs37.rmSync(uninstallBackupDir, { recursive: true, force: true });
|
|
15288
15386
|
} catch {
|
|
15289
15387
|
failIncomplete(`cannot clear transaction state after rollback: ${original}`);
|
|
15290
15388
|
}
|
|
@@ -15297,9 +15395,9 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15297
15395
|
throw wrapped;
|
|
15298
15396
|
};
|
|
15299
15397
|
try {
|
|
15300
|
-
|
|
15398
|
+
fs37.renameSync(legacyEntry, backupEntryDir);
|
|
15301
15399
|
movedEntry = true;
|
|
15302
|
-
|
|
15400
|
+
fs37.renameSync(receiptPath, backupReceiptFile);
|
|
15303
15401
|
movedReceipt = true;
|
|
15304
15402
|
atomicWritePrivate(settingsPath, input.nextSettings);
|
|
15305
15403
|
wroteSettings = true;
|
|
@@ -15321,7 +15419,7 @@ function deactivateVerifiedLegacyPiEntry(input) {
|
|
|
15321
15419
|
rollbackLegacy(new Error(`verify must be synchronous and return void, got thenable`));
|
|
15322
15420
|
}
|
|
15323
15421
|
try {
|
|
15324
|
-
|
|
15422
|
+
fs37.rmSync(markerPath, { force: true });
|
|
15325
15423
|
releaseLock();
|
|
15326
15424
|
} catch {
|
|
15327
15425
|
failIncomplete(`cannot clear transaction state after uninstall (recovery incomplete): ${markerPath}`);
|
|
@@ -15377,8 +15475,8 @@ async function activatePreparedPiInstall(input, deps) {
|
|
|
15377
15475
|
// src/lib/pi-stage-smoke.ts
|
|
15378
15476
|
init_detect();
|
|
15379
15477
|
import { spawn, spawnSync as spawnSync4 } from "child_process";
|
|
15380
|
-
import
|
|
15381
|
-
import
|
|
15478
|
+
import fs38 from "fs";
|
|
15479
|
+
import path46 from "path";
|
|
15382
15480
|
var REQUIRED_COMMANDS = ["goal", "subagents", "permission-system", "websearch", "jorgex:header"];
|
|
15383
15481
|
var EXPECTED_ARGV = ["--mode", "rpc", "--no-session", "--no-approve", "--offline", "--no-context-files"];
|
|
15384
15482
|
var KNOWN_STDERR_WARNING = "[pi-web-access] Dynamic tool activation requires Pi 0.86.1 or newer; web tools remain eagerly available.";
|
|
@@ -15395,13 +15493,13 @@ function isRecord12(value) {
|
|
|
15395
15493
|
}
|
|
15396
15494
|
function lstatOrNull6(p7) {
|
|
15397
15495
|
try {
|
|
15398
|
-
return
|
|
15496
|
+
return fs38.lstatSync(p7);
|
|
15399
15497
|
} catch {
|
|
15400
15498
|
return null;
|
|
15401
15499
|
}
|
|
15402
15500
|
}
|
|
15403
15501
|
function assertPiExecutable(piExecutable) {
|
|
15404
|
-
const absolute =
|
|
15502
|
+
const absolute = path46.resolve(piExecutable);
|
|
15405
15503
|
const linkStat = lstatOrNull6(absolute);
|
|
15406
15504
|
if (linkStat === null) {
|
|
15407
15505
|
fail10(`piExecutable must exist: ${piExecutable}`);
|
|
@@ -15409,13 +15507,13 @@ function assertPiExecutable(piExecutable) {
|
|
|
15409
15507
|
if (linkStat.isSymbolicLink()) {
|
|
15410
15508
|
let real;
|
|
15411
15509
|
try {
|
|
15412
|
-
real =
|
|
15510
|
+
real = fs38.realpathSync(absolute);
|
|
15413
15511
|
} catch {
|
|
15414
15512
|
fail10(`piExecutable symlink is broken: ${piExecutable}`);
|
|
15415
15513
|
}
|
|
15416
15514
|
let targetStat;
|
|
15417
15515
|
try {
|
|
15418
|
-
targetStat =
|
|
15516
|
+
targetStat = fs38.statSync(real);
|
|
15419
15517
|
} catch {
|
|
15420
15518
|
fail10(`piExecutable symlink target is missing: ${piExecutable}`);
|
|
15421
15519
|
}
|
|
@@ -15424,7 +15522,7 @@ function assertPiExecutable(piExecutable) {
|
|
|
15424
15522
|
}
|
|
15425
15523
|
if (process.platform !== "win32") {
|
|
15426
15524
|
try {
|
|
15427
|
-
|
|
15525
|
+
fs38.accessSync(real, fs38.constants.X_OK);
|
|
15428
15526
|
} catch {
|
|
15429
15527
|
fail10(`piExecutable symlink target is not executable: ${piExecutable}`);
|
|
15430
15528
|
}
|
|
@@ -15436,7 +15534,7 @@ function assertPiExecutable(piExecutable) {
|
|
|
15436
15534
|
}
|
|
15437
15535
|
if (process.platform !== "win32") {
|
|
15438
15536
|
try {
|
|
15439
|
-
|
|
15537
|
+
fs38.accessSync(absolute, fs38.constants.X_OK);
|
|
15440
15538
|
} catch {
|
|
15441
15539
|
fail10(`piExecutable is not executable: ${piExecutable}`);
|
|
15442
15540
|
}
|
|
@@ -15444,7 +15542,7 @@ function assertPiExecutable(piExecutable) {
|
|
|
15444
15542
|
return absolute;
|
|
15445
15543
|
}
|
|
15446
15544
|
function assertRealDir3(p7, label) {
|
|
15447
|
-
const resolved2 =
|
|
15545
|
+
const resolved2 = path46.resolve(p7);
|
|
15448
15546
|
const st = lstatOrNull6(resolved2);
|
|
15449
15547
|
if (st === null || !st.isDirectory() || st.isSymbolicLink()) {
|
|
15450
15548
|
fail10(`${label} must be a real directory: ${p7}`);
|
|
@@ -15459,24 +15557,24 @@ function sleep(ms) {
|
|
|
15459
15557
|
}
|
|
15460
15558
|
function runtimePath2(piExecutable) {
|
|
15461
15559
|
const entries = process.platform === "win32" ? [
|
|
15462
|
-
|
|
15463
|
-
|
|
15464
|
-
process.env.SystemRoot ?
|
|
15465
|
-
] : [
|
|
15466
|
-
return [...new Set(entries.filter((entry) => entry !== null))].join(
|
|
15560
|
+
path46.dirname(piExecutable),
|
|
15561
|
+
path46.dirname(process.execPath),
|
|
15562
|
+
process.env.SystemRoot ? path46.join(process.env.SystemRoot, "System32") : null
|
|
15563
|
+
] : [path46.dirname(piExecutable), path46.dirname(process.execPath), "/usr/local/bin", "/usr/bin", "/bin"];
|
|
15564
|
+
return [...new Set(entries.filter((entry) => entry !== null))].join(path46.delimiter);
|
|
15467
15565
|
}
|
|
15468
15566
|
function buildSandboxEnv(stageRoot, stageDir, piExecutable) {
|
|
15469
|
-
const home =
|
|
15470
|
-
const appdata =
|
|
15471
|
-
const localappdata =
|
|
15472
|
-
const xdgConfig =
|
|
15473
|
-
const xdgData =
|
|
15474
|
-
const xdgCache =
|
|
15475
|
-
const temporary =
|
|
15476
|
-
const npmCache =
|
|
15567
|
+
const home = path46.join(stageRoot, "home");
|
|
15568
|
+
const appdata = path46.join(stageRoot, "appdata");
|
|
15569
|
+
const localappdata = path46.join(stageRoot, "localappdata");
|
|
15570
|
+
const xdgConfig = path46.join(stageRoot, "xdg-config");
|
|
15571
|
+
const xdgData = path46.join(stageRoot, "xdg-data");
|
|
15572
|
+
const xdgCache = path46.join(stageRoot, "xdg-cache");
|
|
15573
|
+
const temporary = path46.join(stageRoot, "tmp");
|
|
15574
|
+
const npmCache = path46.join(stageRoot, "npm-cache");
|
|
15477
15575
|
for (const dir of [home, appdata, localappdata, xdgConfig, xdgData, xdgCache, temporary, npmCache]) {
|
|
15478
15576
|
try {
|
|
15479
|
-
|
|
15577
|
+
fs38.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
15480
15578
|
} catch {
|
|
15481
15579
|
fail10(`cannot prepare isolated stage dir: ${dir}`);
|
|
15482
15580
|
}
|
|
@@ -15553,7 +15651,7 @@ async function stopOwned(child) {
|
|
|
15553
15651
|
if (process.platform === "win32") {
|
|
15554
15652
|
try {
|
|
15555
15653
|
const systemRoot = process.env.SystemRoot ?? process.env.WINDIR ?? "C:\\Windows";
|
|
15556
|
-
const taskkill =
|
|
15654
|
+
const taskkill = path46.join(systemRoot, "System32", "taskkill.exe");
|
|
15557
15655
|
spawnSync4(taskkill, ["/pid", String(pid), "/t", "/f"], {
|
|
15558
15656
|
shell: false,
|
|
15559
15657
|
stdio: "ignore",
|
|
@@ -15702,26 +15800,26 @@ async function smokeStagedPiRuntime(input) {
|
|
|
15702
15800
|
async function runSmoke(input) {
|
|
15703
15801
|
if (!isRecord12(input)) fail10("input must be an object");
|
|
15704
15802
|
const { piExecutable, stageDir, timeoutMs } = input;
|
|
15705
|
-
if (typeof piExecutable !== "string" || piExecutable === "" || !
|
|
15803
|
+
if (typeof piExecutable !== "string" || piExecutable === "" || !path46.isAbsolute(piExecutable)) {
|
|
15706
15804
|
fail10("piExecutable must be a non-empty absolute path");
|
|
15707
15805
|
}
|
|
15708
|
-
if (typeof stageDir !== "string" || stageDir === "" || !
|
|
15806
|
+
if (typeof stageDir !== "string" || stageDir === "" || !path46.isAbsolute(stageDir)) {
|
|
15709
15807
|
fail10("stageDir must be a non-empty absolute path");
|
|
15710
15808
|
}
|
|
15711
15809
|
const piResolved = assertPiExecutable(piExecutable);
|
|
15712
15810
|
const stageResolved = assertRealDir3(stageDir, "stageDir");
|
|
15713
|
-
if (
|
|
15811
|
+
if (path46.basename(stageResolved) !== "pi-agent") {
|
|
15714
15812
|
fail10("stageDir must be the staged pi-agent dir (stageRoot/pi-agent)");
|
|
15715
15813
|
}
|
|
15716
|
-
const stageRoot =
|
|
15814
|
+
const stageRoot = path46.dirname(stageResolved);
|
|
15717
15815
|
const stageRootStat = lstatOrNull6(stageRoot);
|
|
15718
15816
|
if (stageRootStat === null || !stageRootStat.isDirectory() || stageRootStat.isSymbolicLink()) {
|
|
15719
15817
|
fail10("stageRoot must be a real directory");
|
|
15720
15818
|
}
|
|
15721
|
-
if (!
|
|
15819
|
+
if (!path46.basename(stageRoot).startsWith("stage-")) {
|
|
15722
15820
|
fail10("stageRoot must be a private stage- dir");
|
|
15723
15821
|
}
|
|
15724
|
-
const workspace =
|
|
15822
|
+
const workspace = path46.join(stageRoot, "workspace");
|
|
15725
15823
|
assertRealDir3(workspace, "stage workspace");
|
|
15726
15824
|
let timeout = DEFAULT_TIMEOUT_MS;
|
|
15727
15825
|
if (timeoutMs !== void 0) {
|
|
@@ -15900,8 +15998,8 @@ ${JSON.stringify({ id: commandsId, type: "get_commands" })}
|
|
|
15900
15998
|
// src/lib/pi-cached-artifact.ts
|
|
15901
15999
|
init_npm_provider();
|
|
15902
16000
|
import { createHash as createHash9, timingSafeEqual as timingSafeEqual6 } from "crypto";
|
|
15903
|
-
import
|
|
15904
|
-
import
|
|
16001
|
+
import fs39 from "fs";
|
|
16002
|
+
import path47 from "path";
|
|
15905
16003
|
var PACKAGE_NAME5 = "jorgex-pi";
|
|
15906
16004
|
var HEX643 = /^[0-9a-f]{64}$/;
|
|
15907
16005
|
var HEX1283 = /^[0-9a-f]{128}$/;
|
|
@@ -15912,14 +16010,14 @@ function isRecord13(value) {
|
|
|
15912
16010
|
}
|
|
15913
16011
|
function lstatOrNull7(p7) {
|
|
15914
16012
|
try {
|
|
15915
|
-
return
|
|
16013
|
+
return fs39.lstatSync(p7);
|
|
15916
16014
|
} catch {
|
|
15917
16015
|
return null;
|
|
15918
16016
|
}
|
|
15919
16017
|
}
|
|
15920
16018
|
function isStrictChild5(child, root) {
|
|
15921
|
-
const rel =
|
|
15922
|
-
return rel !== "" && rel !== ".." && !rel.startsWith(`..${
|
|
16019
|
+
const rel = path47.relative(root, child);
|
|
16020
|
+
return rel !== "" && rel !== ".." && !rel.startsWith(`..${path47.sep}`) && !path47.isAbsolute(rel);
|
|
15923
16021
|
}
|
|
15924
16022
|
function equalHex2(aHex, bHex) {
|
|
15925
16023
|
let a;
|
|
@@ -15936,12 +16034,12 @@ function verifyCachedPiArtifact(input) {
|
|
|
15936
16034
|
try {
|
|
15937
16035
|
if (!isRecord13(input)) return false;
|
|
15938
16036
|
const { receipt, homeDir, downloadsDir } = input;
|
|
15939
|
-
if (typeof homeDir !== "string" || homeDir === "" || !
|
|
15940
|
-
if (typeof downloadsDir !== "string" || downloadsDir === "" || !
|
|
16037
|
+
if (typeof homeDir !== "string" || homeDir === "" || !path47.isAbsolute(homeDir)) return false;
|
|
16038
|
+
if (typeof downloadsDir !== "string" || downloadsDir === "" || !path47.isAbsolute(downloadsDir)) {
|
|
15941
16039
|
return false;
|
|
15942
16040
|
}
|
|
15943
|
-
const homeResolved =
|
|
15944
|
-
const downloadsResolved =
|
|
16041
|
+
const homeResolved = path47.resolve(homeDir);
|
|
16042
|
+
const downloadsResolved = path47.resolve(downloadsDir);
|
|
15945
16043
|
const homeStat = lstatOrNull7(homeResolved);
|
|
15946
16044
|
if (homeStat === null || !homeStat.isDirectory() || homeStat.isSymbolicLink()) return false;
|
|
15947
16045
|
const downloadsStat = lstatOrNull7(downloadsResolved);
|
|
@@ -15949,12 +16047,12 @@ function verifyCachedPiArtifact(input) {
|
|
|
15949
16047
|
return false;
|
|
15950
16048
|
}
|
|
15951
16049
|
if (!isStrictChild5(downloadsResolved, homeResolved)) return false;
|
|
15952
|
-
const rel =
|
|
15953
|
-
const parts = rel.split(
|
|
16050
|
+
const rel = path47.relative(homeResolved, downloadsResolved);
|
|
16051
|
+
const parts = rel.split(path47.sep);
|
|
15954
16052
|
let cursor = homeResolved;
|
|
15955
16053
|
for (const part of parts) {
|
|
15956
16054
|
if (part === "" || part === "." || part === "..") return false;
|
|
15957
|
-
cursor =
|
|
16055
|
+
cursor = path47.join(cursor, part);
|
|
15958
16056
|
const st2 = lstatOrNull7(cursor);
|
|
15959
16057
|
if (st2 === null || !st2.isDirectory() || st2.isSymbolicLink()) return false;
|
|
15960
16058
|
}
|
|
@@ -15980,8 +16078,8 @@ function verifyCachedPiArtifact(input) {
|
|
|
15980
16078
|
if (typeof sha2562 !== "string" || !HEX643.test(sha2562)) return false;
|
|
15981
16079
|
if (typeof sha512 !== "string" || !HEX1283.test(sha512)) return false;
|
|
15982
16080
|
const fileName = `${PACKAGE_NAME5}-${version}.tgz`;
|
|
15983
|
-
const target =
|
|
15984
|
-
if (
|
|
16081
|
+
const target = path47.join(downloadsResolved, fileName);
|
|
16082
|
+
if (path47.dirname(target) !== downloadsResolved) return false;
|
|
15985
16083
|
const st = lstatOrNull7(target);
|
|
15986
16084
|
if (st === null) return false;
|
|
15987
16085
|
if (st.isSymbolicLink()) return false;
|
|
@@ -15990,7 +16088,7 @@ function verifyCachedPiArtifact(input) {
|
|
|
15990
16088
|
if (st.size > MAX_TARBALL_BYTES4) return false;
|
|
15991
16089
|
let fd;
|
|
15992
16090
|
try {
|
|
15993
|
-
fd =
|
|
16091
|
+
fd = fs39.openSync(target, "r");
|
|
15994
16092
|
} catch {
|
|
15995
16093
|
return false;
|
|
15996
16094
|
}
|
|
@@ -16002,7 +16100,7 @@ function verifyCachedPiArtifact(input) {
|
|
|
16002
16100
|
for (; ; ) {
|
|
16003
16101
|
let read;
|
|
16004
16102
|
try {
|
|
16005
|
-
read =
|
|
16103
|
+
read = fs39.readSync(fd, buffer, 0, buffer.length, null);
|
|
16006
16104
|
} catch {
|
|
16007
16105
|
return false;
|
|
16008
16106
|
}
|
|
@@ -16014,7 +16112,7 @@ function verifyCachedPiArtifact(input) {
|
|
|
16014
16112
|
}
|
|
16015
16113
|
} finally {
|
|
16016
16114
|
try {
|
|
16017
|
-
|
|
16115
|
+
fs39.closeSync(fd);
|
|
16018
16116
|
} catch {
|
|
16019
16117
|
}
|
|
16020
16118
|
}
|
|
@@ -16176,30 +16274,30 @@ async function resolvePiEngramRequirement(input, deps) {
|
|
|
16176
16274
|
} : { kind: "existing", bin: detected, scope: "host" };
|
|
16177
16275
|
}
|
|
16178
16276
|
function runtimePath3(piExecutable) {
|
|
16179
|
-
const entries = process.platform === "win32" ? [piExecutable === void 0 ? null :
|
|
16180
|
-
return [...new Set(entries.filter((entry) => entry !== null))].join(
|
|
16277
|
+
const entries = process.platform === "win32" ? [piExecutable === void 0 ? null : path48.dirname(piExecutable), path48.dirname(process.execPath), process.env.SystemRoot ? path48.join(process.env.SystemRoot, "System32") : null] : [piExecutable === void 0 ? null : path48.dirname(piExecutable), path48.dirname(process.execPath), "/usr/local/bin", "/usr/bin", "/bin"];
|
|
16278
|
+
return [...new Set(entries.filter((entry) => entry !== null))].join(path48.delimiter);
|
|
16181
16279
|
}
|
|
16182
16280
|
function targetPaths(targetDir, engramBin, piExecutable) {
|
|
16183
|
-
const root =
|
|
16184
|
-
const codingAgentDir =
|
|
16185
|
-
const home =
|
|
16186
|
-
const temporary =
|
|
16281
|
+
const root = path48.resolve(targetDir);
|
|
16282
|
+
const codingAgentDir = path48.join(root, "pi-agent");
|
|
16283
|
+
const home = path48.join(root, "home");
|
|
16284
|
+
const temporary = path48.join(root, "tmp");
|
|
16187
16285
|
return {
|
|
16188
16286
|
codingAgentDir,
|
|
16189
|
-
receiptPath:
|
|
16190
|
-
packageRunner:
|
|
16287
|
+
receiptPath: path48.join(root, "state", "pi-receipt.json"),
|
|
16288
|
+
packageRunner: path48.join(codingAgentDir, "npm", "node_modules", "jorgex-pi", "bin", "jorgex-pi.mjs"),
|
|
16191
16289
|
environment: {
|
|
16192
16290
|
HOME: home,
|
|
16193
16291
|
USERPROFILE: home,
|
|
16194
|
-
APPDATA:
|
|
16195
|
-
LOCALAPPDATA:
|
|
16196
|
-
XDG_CONFIG_HOME:
|
|
16197
|
-
XDG_DATA_HOME:
|
|
16198
|
-
XDG_CACHE_HOME:
|
|
16292
|
+
APPDATA: path48.join(root, "appdata"),
|
|
16293
|
+
LOCALAPPDATA: path48.join(root, "localappdata"),
|
|
16294
|
+
XDG_CONFIG_HOME: path48.join(root, "xdg-config"),
|
|
16295
|
+
XDG_DATA_HOME: path48.join(root, "xdg-data"),
|
|
16296
|
+
XDG_CACHE_HOME: path48.join(root, "xdg-cache"),
|
|
16199
16297
|
TEMP: temporary,
|
|
16200
16298
|
TMP: temporary,
|
|
16201
16299
|
TMPDIR: temporary,
|
|
16202
|
-
npm_config_cache:
|
|
16300
|
+
npm_config_cache: path48.join(root, "npm-cache"),
|
|
16203
16301
|
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
16204
16302
|
NPM_CONFIG_UPDATE_NOTIFIER: "false",
|
|
16205
16303
|
PI_CODING_AGENT_DIR: codingAgentDir,
|
|
@@ -16210,15 +16308,15 @@ function targetPaths(targetDir, engramBin, piExecutable) {
|
|
|
16210
16308
|
}
|
|
16211
16309
|
function userPaths(engramBin, piExecutable) {
|
|
16212
16310
|
const home = os6.homedir();
|
|
16213
|
-
const codingAgentDir = process.env.PI_CODING_AGENT_DIR ??
|
|
16311
|
+
const codingAgentDir = process.env.PI_CODING_AGENT_DIR ?? path48.join(home, ".pi", "agent");
|
|
16214
16312
|
return {
|
|
16215
16313
|
codingAgentDir,
|
|
16216
|
-
receiptPath:
|
|
16217
|
-
packageRunner:
|
|
16314
|
+
receiptPath: path48.join(dataDir(), "pi-receipt.json"),
|
|
16315
|
+
packageRunner: path48.join(codingAgentDir, "npm", "node_modules", "jorgex-pi", "bin", "jorgex-pi.mjs"),
|
|
16218
16316
|
environment: {
|
|
16219
16317
|
HOME: home,
|
|
16220
|
-
XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME ??
|
|
16221
|
-
XDG_CACHE_HOME: process.env.XDG_CACHE_HOME ??
|
|
16318
|
+
XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME ?? path48.join(home, ".config"),
|
|
16319
|
+
XDG_CACHE_HOME: process.env.XDG_CACHE_HOME ?? path48.join(home, ".cache"),
|
|
16222
16320
|
TMPDIR: os6.tmpdir(),
|
|
16223
16321
|
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
16224
16322
|
NPM_CONFIG_UPDATE_NOTIFIER: "false",
|
|
@@ -16254,7 +16352,7 @@ function runPiRuntime(input, deps) {
|
|
|
16254
16352
|
}
|
|
16255
16353
|
const candidate = input.candidate ?? PI_RUNTIME_CANDIDATE;
|
|
16256
16354
|
const paths = input.targetDir === void 0 ? userPaths(input.engramBin, input.detected.executable) : targetPaths(input.targetDir, input.engramBin, input.detected.executable);
|
|
16257
|
-
const settingsJson = deps.readSettings(
|
|
16355
|
+
const settingsJson = deps.readSettings(path48.join(paths.codingAgentDir, "settings.json"));
|
|
16258
16356
|
const receiptJson = deps.readReceipt(paths.receiptPath);
|
|
16259
16357
|
const lifecycleInput = {
|
|
16260
16358
|
candidate,
|
|
@@ -16319,60 +16417,32 @@ function runPiRuntime(input, deps) {
|
|
|
16319
16417
|
persistReturnedReceipt(result, paths, deps);
|
|
16320
16418
|
return result;
|
|
16321
16419
|
}
|
|
16322
|
-
function readJsonFile2(file) {
|
|
16323
|
-
return JSON.parse(fs39.readFileSync(file, "utf8"));
|
|
16324
|
-
}
|
|
16325
|
-
function packageVersionFromExecutable(executable) {
|
|
16326
|
-
let current;
|
|
16327
|
-
try {
|
|
16328
|
-
current = path47.dirname(fs39.realpathSync(executable));
|
|
16329
|
-
} catch {
|
|
16330
|
-
return null;
|
|
16331
|
-
}
|
|
16332
|
-
for (let depth = 0; depth < 8; depth++) {
|
|
16333
|
-
const manifests = [
|
|
16334
|
-
path47.join(current, "package.json"),
|
|
16335
|
-
path47.join(current, "node_modules", "@earendil-works", "pi-coding-agent", "package.json")
|
|
16336
|
-
];
|
|
16337
|
-
for (const manifest of manifests) {
|
|
16338
|
-
try {
|
|
16339
|
-
const parsed = readJsonFile2(manifest);
|
|
16340
|
-
if (parsed !== null && typeof parsed === "object" && Reflect.get(parsed, "name") === "@earendil-works/pi-coding-agent" && typeof Reflect.get(parsed, "version") === "string") {
|
|
16341
|
-
return Reflect.get(parsed, "version");
|
|
16342
|
-
}
|
|
16343
|
-
} catch {
|
|
16344
|
-
}
|
|
16345
|
-
}
|
|
16346
|
-
const parent = path47.dirname(current);
|
|
16347
|
-
if (parent === current) break;
|
|
16348
|
-
current = parent;
|
|
16349
|
-
}
|
|
16350
|
-
return null;
|
|
16351
|
-
}
|
|
16352
16420
|
function detectPiRuntime() {
|
|
16353
16421
|
const executable = lookPath("pi");
|
|
16354
16422
|
const home = os6.homedir();
|
|
16423
|
+
const inspection = executable === null ? null : inspectPiHostVersion(executable);
|
|
16355
16424
|
return {
|
|
16356
16425
|
id: "pi",
|
|
16357
16426
|
name: "Pi",
|
|
16358
16427
|
installed: executable !== null,
|
|
16359
16428
|
executable,
|
|
16360
|
-
version:
|
|
16361
|
-
|
|
16429
|
+
version: inspection?.version ?? null,
|
|
16430
|
+
versionDiagnostic: inspection?.diagnostic ?? null,
|
|
16431
|
+
codingAgentDir: process.env.PI_CODING_AGENT_DIR ?? path48.join(home, ".pi", "agent")
|
|
16362
16432
|
};
|
|
16363
16433
|
}
|
|
16364
16434
|
function hasManagedPiRuntime(targetDir) {
|
|
16365
|
-
const receipt = targetDir === void 0 ?
|
|
16366
|
-
return
|
|
16435
|
+
const receipt = targetDir === void 0 ? path48.join(dataDir(), "pi-receipt.json") : path48.join(path48.resolve(targetDir), "state", "pi-receipt.json");
|
|
16436
|
+
return fs40.statSync(receipt, { throwIfNoEntry: false })?.isFile() === true;
|
|
16367
16437
|
}
|
|
16368
16438
|
function resolvePiEngramBin(targetDir) {
|
|
16369
16439
|
if (targetDir === void 0) return detectEngram();
|
|
16370
|
-
const candidate =
|
|
16371
|
-
return
|
|
16440
|
+
const candidate = path48.join(path48.resolve(targetDir), "bin", process.platform === "win32" ? "engram.exe" : "engram");
|
|
16441
|
+
return fs40.statSync(candidate, { throwIfNoEntry: false })?.isFile() ? candidate : null;
|
|
16372
16442
|
}
|
|
16373
16443
|
function readOptional(file, fallback) {
|
|
16374
16444
|
try {
|
|
16375
|
-
return
|
|
16445
|
+
return fs40.readFileSync(file, "utf8");
|
|
16376
16446
|
} catch (error) {
|
|
16377
16447
|
if (error.code === "ENOENT") return fallback;
|
|
16378
16448
|
throw error;
|
|
@@ -16438,7 +16508,7 @@ function preparedInstallMismatch(candidate, prepared) {
|
|
|
16438
16508
|
return "la release preparada no coincide con la versi\xF3n/SRI del candidato";
|
|
16439
16509
|
}
|
|
16440
16510
|
const stageDir = prepared?.stageDir;
|
|
16441
|
-
if (typeof stageDir !== "string" || stageDir === "" || !/(^|[\\/])stage-[0-9a-f]{32}[\\/]pi-agent$/.test(
|
|
16511
|
+
if (typeof stageDir !== "string" || stageDir === "" || !/(^|[\\/])stage-[0-9a-f]{32}[\\/]pi-agent$/.test(path48.resolve(stageDir))) {
|
|
16442
16512
|
return "el stage preparado no tiene el layout aislado esperado (stage-<hex>/pi-agent)";
|
|
16443
16513
|
}
|
|
16444
16514
|
const evidence = prepared?.evidence;
|
|
@@ -16513,12 +16583,12 @@ function backupLegacyMigrationState(settingsPath, receiptPath, backupRoot) {
|
|
|
16513
16583
|
}
|
|
16514
16584
|
}
|
|
16515
16585
|
function verifyActivePiRelease(input) {
|
|
16516
|
-
const agentDir =
|
|
16517
|
-
const npmDir =
|
|
16518
|
-
const managedRoot =
|
|
16586
|
+
const agentDir = path48.resolve(input.agentDir);
|
|
16587
|
+
const npmDir = path48.join(agentDir, "npm");
|
|
16588
|
+
const managedRoot = path48.join(npmDir, "jorgex-pi-managed");
|
|
16519
16589
|
let receiptRaw;
|
|
16520
16590
|
try {
|
|
16521
|
-
receiptRaw =
|
|
16591
|
+
receiptRaw = fs40.readFileSync(input.receiptPath, "utf8");
|
|
16522
16592
|
} catch {
|
|
16523
16593
|
throw new Error(`pi-verify-active: no se pudo leer el receipt promovido: ${input.receiptPath}`);
|
|
16524
16594
|
}
|
|
@@ -16547,7 +16617,7 @@ function verifyActivePiRelease(input) {
|
|
|
16547
16617
|
throw new Error("pi-verify-active: el scope del receipt promovido no coincide con el esperado");
|
|
16548
16618
|
}
|
|
16549
16619
|
const scopeDir = scopeRecord["codingAgentDir"];
|
|
16550
|
-
if (typeof scopeDir !== "string" || !
|
|
16620
|
+
if (typeof scopeDir !== "string" || !path48.isAbsolute(scopeDir) || path48.resolve(scopeDir) !== agentDir) {
|
|
16551
16621
|
throw new Error("pi-verify-active: el codingAgentDir del receipt promovido no coincide con el agentDir");
|
|
16552
16622
|
}
|
|
16553
16623
|
const receiptEngram = record["engram"];
|
|
@@ -16578,40 +16648,40 @@ function verifyActivePiRelease(input) {
|
|
|
16578
16648
|
throw new Error("pi-verify-active: el receipt promovido no conserva las seis dependencias de la evidencia");
|
|
16579
16649
|
}
|
|
16580
16650
|
const linkPath = managedRecord["linkPath"];
|
|
16581
|
-
if (typeof linkPath !== "string" || !
|
|
16651
|
+
if (typeof linkPath !== "string" || !path48.isAbsolute(linkPath)) {
|
|
16582
16652
|
throw new Error("pi-verify-active: el receipt promovido no trae un linkPath absoluto");
|
|
16583
16653
|
}
|
|
16584
|
-
const linkResolved =
|
|
16585
|
-
if (linkResolved !==
|
|
16654
|
+
const linkResolved = path48.resolve(linkPath);
|
|
16655
|
+
if (linkResolved !== path48.join(npmDir, "node_modules", "jorgex-pi")) {
|
|
16586
16656
|
throw new Error("pi-verify-active: el enlace publicado sale del entry propio");
|
|
16587
16657
|
}
|
|
16588
16658
|
const releaseDir = managedRecord["releaseDir"];
|
|
16589
|
-
if (typeof releaseDir !== "string" || !
|
|
16659
|
+
if (typeof releaseDir !== "string" || !path48.isAbsolute(releaseDir)) {
|
|
16590
16660
|
throw new Error("pi-verify-active: el receipt promovido no trae un releaseDir absoluto");
|
|
16591
16661
|
}
|
|
16592
|
-
const releaseResolved =
|
|
16593
|
-
const releaseRel =
|
|
16594
|
-
if (releaseRel === "" || releaseRel === ".." || releaseRel.startsWith(`..${
|
|
16662
|
+
const releaseResolved = path48.resolve(releaseDir);
|
|
16663
|
+
const releaseRel = path48.relative(managedRoot, releaseResolved);
|
|
16664
|
+
if (releaseRel === "" || releaseRel === ".." || releaseRel.startsWith(`..${path48.sep}`) || path48.isAbsolute(releaseRel)) {
|
|
16595
16665
|
throw new Error("pi-verify-active: el release promovido sale del root gestionado");
|
|
16596
16666
|
}
|
|
16597
16667
|
let target;
|
|
16598
16668
|
try {
|
|
16599
|
-
const linkStat =
|
|
16669
|
+
const linkStat = fs40.lstatSync(linkResolved);
|
|
16600
16670
|
if (!linkStat.isSymbolicLink()) {
|
|
16601
16671
|
throw new Error("pi-verify-active: el entry publicado no es un enlace");
|
|
16602
16672
|
}
|
|
16603
|
-
target =
|
|
16673
|
+
target = fs40.readlinkSync(linkResolved);
|
|
16604
16674
|
} catch (error) {
|
|
16605
16675
|
if (error instanceof Error && error.message.startsWith("pi-verify-active: ")) throw error;
|
|
16606
16676
|
throw new Error("pi-verify-active: no se pudo leer el enlace publicado");
|
|
16607
16677
|
}
|
|
16608
|
-
const packageRoot =
|
|
16609
|
-
if (target === "" ||
|
|
16678
|
+
const packageRoot = path48.join(releaseResolved, "node_modules", "jorgex-pi");
|
|
16679
|
+
if (target === "" || path48.isAbsolute(target) || path48.resolve(path48.dirname(linkResolved), target) !== packageRoot) {
|
|
16610
16680
|
throw new Error("pi-verify-active: el enlace publicado no apunta al release promovido");
|
|
16611
16681
|
}
|
|
16612
16682
|
let realRoot;
|
|
16613
16683
|
try {
|
|
16614
|
-
realRoot =
|
|
16684
|
+
realRoot = fs40.realpathSync(linkResolved);
|
|
16615
16685
|
} catch {
|
|
16616
16686
|
throw new Error("pi-verify-active: no se pudo resolver el realpath del enlace publicado");
|
|
16617
16687
|
}
|
|
@@ -16629,8 +16699,8 @@ function verifyActivePiRelease(input) {
|
|
|
16629
16699
|
}
|
|
16630
16700
|
}
|
|
16631
16701
|
function isStrictChildPath(child, root) {
|
|
16632
|
-
const rel =
|
|
16633
|
-
return rel !== "" && rel !== ".." && !rel.startsWith(`..${
|
|
16702
|
+
const rel = path48.relative(path48.resolve(root), path48.resolve(child));
|
|
16703
|
+
return rel !== "" && rel !== ".." && !rel.startsWith(`..${path48.sep}`) && !path48.isAbsolute(rel);
|
|
16634
16704
|
}
|
|
16635
16705
|
async function preparePiRuntimeSystem(input) {
|
|
16636
16706
|
if (input.operation !== "install" && input.operation !== "update") {
|
|
@@ -16648,7 +16718,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16648
16718
|
remedy: "El update con --target-dir nunca ejecuta preflight de red; aporta un stage preverificado o usa update real."
|
|
16649
16719
|
};
|
|
16650
16720
|
}
|
|
16651
|
-
if (typeof input.engramBin !== "string" || input.engramBin === "" || !
|
|
16721
|
+
if (typeof input.engramBin !== "string" || input.engramBin === "" || !path48.isAbsolute(input.engramBin)) {
|
|
16652
16722
|
return {
|
|
16653
16723
|
kind: "blocked",
|
|
16654
16724
|
reason: "engram-required",
|
|
@@ -16656,7 +16726,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16656
16726
|
};
|
|
16657
16727
|
}
|
|
16658
16728
|
const updateExecutable = input.detected.executable;
|
|
16659
|
-
if (typeof updateExecutable !== "string" || updateExecutable === "" || !
|
|
16729
|
+
if (typeof updateExecutable !== "string" || updateExecutable === "" || !path48.isAbsolute(updateExecutable)) {
|
|
16660
16730
|
return {
|
|
16661
16731
|
kind: "blocked",
|
|
16662
16732
|
reason: "pi-executable-missing",
|
|
@@ -16671,16 +16741,16 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16671
16741
|
};
|
|
16672
16742
|
}
|
|
16673
16743
|
const updateHomeDir = os6.homedir();
|
|
16674
|
-
if (typeof updateHomeDir !== "string" || updateHomeDir === "" || !
|
|
16744
|
+
if (typeof updateHomeDir !== "string" || updateHomeDir === "" || !path48.isAbsolute(updateHomeDir)) {
|
|
16675
16745
|
return {
|
|
16676
16746
|
kind: "blocked",
|
|
16677
16747
|
reason: "preflight-failed",
|
|
16678
16748
|
remedy: "HOME ilegible para el preflight Pi; Pi no qued\xF3 activado."
|
|
16679
16749
|
};
|
|
16680
16750
|
}
|
|
16681
|
-
const updateAgentDir = process.env.PI_CODING_AGENT_DIR ??
|
|
16682
|
-
const updateReceiptPath =
|
|
16683
|
-
const updateDownloadsDir =
|
|
16751
|
+
const updateAgentDir = process.env.PI_CODING_AGENT_DIR ?? path48.join(updateHomeDir, ".pi", "agent");
|
|
16752
|
+
const updateReceiptPath = path48.join(updateHomeDir, ".jorgex-stack", "pi-receipt.json");
|
|
16753
|
+
const updateDownloadsDir = path48.join(updateHomeDir, ".jorgex-stack", "packages");
|
|
16684
16754
|
if (!isStrictChildPath(updateAgentDir, updateHomeDir)) {
|
|
16685
16755
|
return {
|
|
16686
16756
|
kind: "blocked",
|
|
@@ -16688,7 +16758,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16688
16758
|
remedy: `PI_CODING_AGENT_DIR (${updateAgentDir}) est\xE1 fuera de la frontera de restore HOME (${updateHomeDir}); corrige el destino antes de reintentar; Pi no qued\xF3 activado.`
|
|
16689
16759
|
};
|
|
16690
16760
|
}
|
|
16691
|
-
const updateSettingsPath =
|
|
16761
|
+
const updateSettingsPath = path48.join(updateAgentDir, "settings.json");
|
|
16692
16762
|
let updateReceiptRaw;
|
|
16693
16763
|
let updateSettingsRaw;
|
|
16694
16764
|
try {
|
|
@@ -16704,7 +16774,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16704
16774
|
const stripUpdateGateNewline = (value) => value.endsWith("\n") ? value.slice(0, -1) : value;
|
|
16705
16775
|
const updateReceiptJson = updateReceiptRaw === null ? null : stripUpdateGateNewline(updateReceiptRaw);
|
|
16706
16776
|
const updateSettingsJson = stripUpdateGateNewline(updateSettingsRaw);
|
|
16707
|
-
const updatePackageRunner =
|
|
16777
|
+
const updatePackageRunner = path48.join(updateAgentDir, "npm", "node_modules", "jorgex-pi", "bin", "jorgex-pi.mjs");
|
|
16708
16778
|
const updateGate = verifyOfflineManagedPiRelease(
|
|
16709
16779
|
{
|
|
16710
16780
|
detected: {
|
|
@@ -16732,7 +16802,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16732
16802
|
return "remedy" in updateGate && typeof updateGate.remedy === "string" ? updateGate : { kind: "blocked", reason: updateGate.reason, remedy: `Verificaci\xF3n offline del receipt Pi fall\xF3 (${updateGate.reason}); sin preflight ni cambios. Pi no qued\xF3 activado.` };
|
|
16733
16803
|
}
|
|
16734
16804
|
try {
|
|
16735
|
-
|
|
16805
|
+
fs40.mkdirSync(updateDownloadsDir, { recursive: true });
|
|
16736
16806
|
} catch (error) {
|
|
16737
16807
|
return {
|
|
16738
16808
|
kind: "blocked",
|
|
@@ -16788,7 +16858,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16788
16858
|
};
|
|
16789
16859
|
}
|
|
16790
16860
|
const piExecutable = input.detected.executable;
|
|
16791
|
-
if (typeof piExecutable !== "string" || piExecutable === "" || !
|
|
16861
|
+
if (typeof piExecutable !== "string" || piExecutable === "" || !path48.isAbsolute(piExecutable)) {
|
|
16792
16862
|
return {
|
|
16793
16863
|
kind: "blocked",
|
|
16794
16864
|
reason: "pi-executable-missing",
|
|
@@ -16804,7 +16874,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16804
16874
|
}
|
|
16805
16875
|
const homeDir = os6.homedir();
|
|
16806
16876
|
const agentDir = userPaths(input.engramBin, piExecutable).codingAgentDir;
|
|
16807
|
-
const downloadsDir =
|
|
16877
|
+
const downloadsDir = path48.join(dataDir(), "packages");
|
|
16808
16878
|
if (!isStrictChildPath(agentDir, homeDir)) {
|
|
16809
16879
|
return {
|
|
16810
16880
|
kind: "blocked",
|
|
@@ -16814,7 +16884,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16814
16884
|
}
|
|
16815
16885
|
let preflightReceipt;
|
|
16816
16886
|
try {
|
|
16817
|
-
preflightReceipt =
|
|
16887
|
+
preflightReceipt = fs40.lstatSync(path48.join(dataDir(), "pi-receipt.json"), { throwIfNoEntry: false });
|
|
16818
16888
|
} catch (error) {
|
|
16819
16889
|
if (error.code === "ENOENT") {
|
|
16820
16890
|
preflightReceipt = void 0;
|
|
@@ -16829,7 +16899,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16829
16899
|
if (preflightReceipt === void 0) {
|
|
16830
16900
|
let preflightEntry;
|
|
16831
16901
|
try {
|
|
16832
|
-
preflightEntry =
|
|
16902
|
+
preflightEntry = fs40.lstatSync(path48.join(agentDir, "npm", "node_modules", "jorgex-pi"), {
|
|
16833
16903
|
throwIfNoEntry: false
|
|
16834
16904
|
});
|
|
16835
16905
|
} catch (error) {
|
|
@@ -16852,7 +16922,7 @@ async function preparePiRuntimeSystem(input) {
|
|
|
16852
16922
|
}
|
|
16853
16923
|
}
|
|
16854
16924
|
try {
|
|
16855
|
-
|
|
16925
|
+
fs40.mkdirSync(downloadsDir, { recursive: true });
|
|
16856
16926
|
} catch (error) {
|
|
16857
16927
|
return {
|
|
16858
16928
|
kind: "blocked",
|
|
@@ -16948,7 +17018,7 @@ async function runPiRuntimeSystem(input) {
|
|
|
16948
17018
|
remedy: `${mismatch}; Pi no qued\xF3 activado y no se descarg\xF3 ni modific\xF3 nada.`
|
|
16949
17019
|
};
|
|
16950
17020
|
}
|
|
16951
|
-
const settingsPath =
|
|
17021
|
+
const settingsPath = path48.join(paths.codingAgentDir, "settings.json");
|
|
16952
17022
|
let settingsJson = readOptional(settingsPath, '{"packages":[]}');
|
|
16953
17023
|
const receiptJson = readOptional(paths.receiptPath, null);
|
|
16954
17024
|
const scopeKind = input.targetDir === void 0 ? "real" : "target-dir";
|
|
@@ -16991,8 +17061,8 @@ async function runPiRuntimeSystem(input) {
|
|
|
16991
17061
|
};
|
|
16992
17062
|
}
|
|
16993
17063
|
try {
|
|
16994
|
-
const freshEntry =
|
|
16995
|
-
if (
|
|
17064
|
+
const freshEntry = path48.join(paths.codingAgentDir, "npm", "node_modules", "jorgex-pi");
|
|
17065
|
+
if (fs40.lstatSync(freshEntry, { throwIfNoEntry: false }) !== void 0) {
|
|
16996
17066
|
return {
|
|
16997
17067
|
kind: "blocked",
|
|
16998
17068
|
reason: "unowned-entry",
|
|
@@ -17102,7 +17172,7 @@ async function runPiRuntimeSystem(input) {
|
|
|
17102
17172
|
backupLegacyMigrationState(
|
|
17103
17173
|
settingsPath,
|
|
17104
17174
|
paths.receiptPath,
|
|
17105
|
-
input.targetDir === void 0 ? void 0 :
|
|
17175
|
+
input.targetDir === void 0 ? void 0 : path48.join(path48.resolve(input.targetDir), "backups")
|
|
17106
17176
|
);
|
|
17107
17177
|
} catch (error) {
|
|
17108
17178
|
return {
|
|
@@ -17112,7 +17182,7 @@ async function runPiRuntimeSystem(input) {
|
|
|
17112
17182
|
};
|
|
17113
17183
|
}
|
|
17114
17184
|
}
|
|
17115
|
-
const homeDir = input.targetDir === void 0 ? os6.homedir() :
|
|
17185
|
+
const homeDir = input.targetDir === void 0 ? os6.homedir() : path48.resolve(input.targetDir);
|
|
17116
17186
|
const agentDir = paths.codingAgentDir;
|
|
17117
17187
|
const receiptPath = paths.receiptPath;
|
|
17118
17188
|
const stageDir = prepared.stageDir;
|
|
@@ -17165,7 +17235,7 @@ async function runPiRuntimeSystem(input) {
|
|
|
17165
17235
|
}
|
|
17166
17236
|
if (input.operation === "update") {
|
|
17167
17237
|
const engramBinForUpdate = input.engramBin;
|
|
17168
|
-
if (engramBinForUpdate === null || !
|
|
17238
|
+
if (engramBinForUpdate === null || !path48.isAbsolute(engramBinForUpdate)) {
|
|
17169
17239
|
return {
|
|
17170
17240
|
kind: "blocked",
|
|
17171
17241
|
reason: "engram-required",
|
|
@@ -17196,10 +17266,10 @@ async function runPiRuntimeSystem(input) {
|
|
|
17196
17266
|
remedy: `${updateMismatch}; Pi no qued\xF3 activado y no se descarg\xF3 ni modific\xF3 nada.`
|
|
17197
17267
|
};
|
|
17198
17268
|
}
|
|
17199
|
-
const updateSettingsPath =
|
|
17269
|
+
const updateSettingsPath = path48.join(paths.codingAgentDir, "settings.json");
|
|
17200
17270
|
const updateScopeKind = input.targetDir === void 0 ? "real" : "target-dir";
|
|
17201
|
-
const updateHomeDir = input.targetDir === void 0 ? os6.homedir() :
|
|
17202
|
-
const updateDownloadsDir = input.targetDir === void 0 ?
|
|
17271
|
+
const updateHomeDir = input.targetDir === void 0 ? os6.homedir() : path48.resolve(input.targetDir);
|
|
17272
|
+
const updateDownloadsDir = input.targetDir === void 0 ? path48.join(dataDir(), "packages") : path48.join(path48.resolve(input.targetDir), "downloads");
|
|
17203
17273
|
const stripUpdateNewline = (value) => value.endsWith("\n") ? value.slice(0, -1) : value;
|
|
17204
17274
|
let updateSettingsRaw;
|
|
17205
17275
|
let updateReceiptRaw;
|
|
@@ -17378,13 +17448,13 @@ async function runPiRuntimeSystem(input) {
|
|
|
17378
17448
|
};
|
|
17379
17449
|
}
|
|
17380
17450
|
}
|
|
17381
|
-
const packageRoot =
|
|
17451
|
+
const packageRoot = path48.dirname(path48.dirname(paths.packageRunner));
|
|
17382
17452
|
const writeReceipt = (receipt) => {
|
|
17383
17453
|
writeText(paths.receiptPath, `${JSON.stringify(receipt, null, 2)}
|
|
17384
17454
|
`);
|
|
17385
17455
|
};
|
|
17386
17456
|
if (input.operation === "sync") {
|
|
17387
|
-
const settingsJson = readOptional(
|
|
17457
|
+
const settingsJson = readOptional(path48.join(paths.codingAgentDir, "settings.json"), '{"packages":[]}');
|
|
17388
17458
|
const receiptJson = readOptional(paths.receiptPath, null);
|
|
17389
17459
|
if (receiptJson === null) {
|
|
17390
17460
|
return {
|
|
@@ -17435,11 +17505,11 @@ async function runPiRuntimeSystem(input) {
|
|
|
17435
17505
|
run: runProcess,
|
|
17436
17506
|
verifyManagedArtifact: (receipt) => verifyCachedPiArtifact({
|
|
17437
17507
|
receipt,
|
|
17438
|
-
homeDir: input.targetDir === void 0 ? os6.homedir() :
|
|
17439
|
-
downloadsDir: input.targetDir === void 0 ?
|
|
17508
|
+
homeDir: input.targetDir === void 0 ? os6.homedir() : path48.resolve(input.targetDir),
|
|
17509
|
+
downloadsDir: input.targetDir === void 0 ? path48.join(dataDir(), "packages") : path48.join(path48.resolve(input.targetDir), "downloads")
|
|
17440
17510
|
}),
|
|
17441
|
-
isPackageAbsent: () => !
|
|
17442
|
-
deleteReceipt: () =>
|
|
17511
|
+
isPackageAbsent: () => !fs40.existsSync(packageRoot),
|
|
17512
|
+
deleteReceipt: () => fs40.rmSync(paths.receiptPath, { force: true })
|
|
17443
17513
|
}
|
|
17444
17514
|
);
|
|
17445
17515
|
}
|
|
@@ -17451,7 +17521,7 @@ async function runPiRuntimeSystem(input) {
|
|
|
17451
17521
|
}
|
|
17452
17522
|
}
|
|
17453
17523
|
if (input.operation === "models") {
|
|
17454
|
-
const settingsJson = readOptional(
|
|
17524
|
+
const settingsJson = readOptional(path48.join(paths.codingAgentDir, "settings.json"), '{"packages":[]}');
|
|
17455
17525
|
const receiptJson = readOptional(paths.receiptPath, null);
|
|
17456
17526
|
if (receiptJson === null) {
|
|
17457
17527
|
return {
|
|
@@ -17502,11 +17572,11 @@ async function runPiRuntimeSystem(input) {
|
|
|
17502
17572
|
run: runProcess,
|
|
17503
17573
|
verifyManagedArtifact: (receipt) => verifyCachedPiArtifact({
|
|
17504
17574
|
receipt,
|
|
17505
|
-
homeDir: input.targetDir === void 0 ? os6.homedir() :
|
|
17506
|
-
downloadsDir: input.targetDir === void 0 ?
|
|
17575
|
+
homeDir: input.targetDir === void 0 ? os6.homedir() : path48.resolve(input.targetDir),
|
|
17576
|
+
downloadsDir: input.targetDir === void 0 ? path48.join(dataDir(), "packages") : path48.join(path48.resolve(input.targetDir), "downloads")
|
|
17507
17577
|
}),
|
|
17508
|
-
isPackageAbsent: () => !
|
|
17509
|
-
deleteReceipt: () =>
|
|
17578
|
+
isPackageAbsent: () => !fs40.existsSync(packageRoot),
|
|
17579
|
+
deleteReceipt: () => fs40.rmSync(paths.receiptPath, { force: true })
|
|
17510
17580
|
}
|
|
17511
17581
|
);
|
|
17512
17582
|
}
|
|
@@ -17523,17 +17593,17 @@ async function runPiRuntimeSystem(input) {
|
|
|
17523
17593
|
value,
|
|
17524
17594
|
{
|
|
17525
17595
|
backupSettings: () => createBackup(
|
|
17526
|
-
[
|
|
17596
|
+
[path48.join(paths.codingAgentDir, "settings.json")],
|
|
17527
17597
|
"pi-package-uninstall",
|
|
17528
|
-
input.targetDir === void 0 ? void 0 :
|
|
17598
|
+
input.targetDir === void 0 ? void 0 : path48.join(path48.resolve(input.targetDir), "backups")
|
|
17529
17599
|
),
|
|
17530
17600
|
run: runProcess,
|
|
17531
17601
|
verifyManagedArtifact: (receipt) => verifyCachedPiArtifact({
|
|
17532
17602
|
receipt,
|
|
17533
|
-
homeDir: input.targetDir === void 0 ? os6.homedir() :
|
|
17534
|
-
downloadsDir: input.targetDir === void 0 ?
|
|
17603
|
+
homeDir: input.targetDir === void 0 ? os6.homedir() : path48.resolve(input.targetDir),
|
|
17604
|
+
downloadsDir: input.targetDir === void 0 ? path48.join(dataDir(), "packages") : path48.join(path48.resolve(input.targetDir), "downloads")
|
|
17535
17605
|
}),
|
|
17536
|
-
readSettings: () =>
|
|
17606
|
+
readSettings: () => fs40.readFileSync(path48.join(paths.codingAgentDir, "settings.json"), "utf8"),
|
|
17537
17607
|
verifyLegacyPackage: (receipt) => {
|
|
17538
17608
|
const op = value;
|
|
17539
17609
|
let effectiveEngram = op.engramBin;
|
|
@@ -17542,7 +17612,7 @@ async function runPiRuntimeSystem(input) {
|
|
|
17542
17612
|
const engram = Reflect.get(receipt, "engram");
|
|
17543
17613
|
if (engram === null || typeof engram !== "object" || Array.isArray(engram)) return false;
|
|
17544
17614
|
const binary = Reflect.get(engram, "binary");
|
|
17545
|
-
if (typeof binary !== "string" || binary === "" || !
|
|
17615
|
+
if (typeof binary !== "string" || binary === "" || !path48.isAbsolute(binary)) return false;
|
|
17546
17616
|
effectiveEngram = binary;
|
|
17547
17617
|
}
|
|
17548
17618
|
if (typeof effectiveEngram !== "string" || effectiveEngram === "") return false;
|
|
@@ -17566,17 +17636,17 @@ async function runPiRuntimeSystem(input) {
|
|
|
17566
17636
|
}
|
|
17567
17637
|
let currentReceiptRaw = null;
|
|
17568
17638
|
try {
|
|
17569
|
-
currentReceiptRaw =
|
|
17639
|
+
currentReceiptRaw = fs40.readFileSync(paths.receiptPath, "utf8");
|
|
17570
17640
|
} catch {
|
|
17571
17641
|
return { kind: "blocked", reason: "remove-failed" };
|
|
17572
17642
|
}
|
|
17573
17643
|
if (typeof op.receiptJson === "string" && currentReceiptRaw !== op.receiptJson) {
|
|
17574
17644
|
return { kind: "blocked", reason: "receipt-untrusted" };
|
|
17575
17645
|
}
|
|
17576
|
-
const settingsPath =
|
|
17577
|
-
const legacyEntry =
|
|
17646
|
+
const settingsPath = path48.join(paths.codingAgentDir, "settings.json");
|
|
17647
|
+
const legacyEntry = path48.join(paths.codingAgentDir, "npm", "node_modules", "jorgex-pi");
|
|
17578
17648
|
return deactivateVerifiedLegacyPiEntry({
|
|
17579
|
-
homeDir: input.targetDir === void 0 ? os6.homedir() :
|
|
17649
|
+
homeDir: input.targetDir === void 0 ? os6.homedir() : path48.resolve(input.targetDir),
|
|
17580
17650
|
agentDir: paths.codingAgentDir,
|
|
17581
17651
|
receiptPath: paths.receiptPath,
|
|
17582
17652
|
source,
|
|
@@ -17584,19 +17654,19 @@ async function runPiRuntimeSystem(input) {
|
|
|
17584
17654
|
verify: () => {
|
|
17585
17655
|
let entryStat = null;
|
|
17586
17656
|
try {
|
|
17587
|
-
entryStat =
|
|
17657
|
+
entryStat = fs40.lstatSync(legacyEntry);
|
|
17588
17658
|
} catch (error) {
|
|
17589
17659
|
if (error.code !== "ENOENT") throw error;
|
|
17590
17660
|
}
|
|
17591
17661
|
if (entryStat !== null) throw new Error("managed entry still present after uninstall");
|
|
17592
17662
|
let receiptStat = null;
|
|
17593
17663
|
try {
|
|
17594
|
-
receiptStat =
|
|
17664
|
+
receiptStat = fs40.lstatSync(paths.receiptPath);
|
|
17595
17665
|
} catch (error) {
|
|
17596
17666
|
if (error.code !== "ENOENT") throw error;
|
|
17597
17667
|
}
|
|
17598
17668
|
if (receiptStat !== null) throw new Error("receipt still present after uninstall");
|
|
17599
|
-
if (
|
|
17669
|
+
if (fs40.readFileSync(settingsPath, "utf8") !== nextSettings) {
|
|
17600
17670
|
throw new Error("settings mismatch after uninstall");
|
|
17601
17671
|
}
|
|
17602
17672
|
}
|
|
@@ -17611,9 +17681,9 @@ async function runPiRuntimeSystem(input) {
|
|
|
17611
17681
|
if (typeof mp.releaseDir !== "string" || typeof mp.linkPath !== "string" || typeof mp.backupDir !== "string") {
|
|
17612
17682
|
return { kind: "blocked", reason: "remove-failed" };
|
|
17613
17683
|
}
|
|
17614
|
-
const settingsPath =
|
|
17684
|
+
const settingsPath = path48.join(paths.codingAgentDir, "settings.json");
|
|
17615
17685
|
return deactivateVerifiedPiRelease({
|
|
17616
|
-
homeDir: input.targetDir === void 0 ? os6.homedir() :
|
|
17686
|
+
homeDir: input.targetDir === void 0 ? os6.homedir() : path48.resolve(input.targetDir),
|
|
17617
17687
|
agentDir: paths.codingAgentDir,
|
|
17618
17688
|
receiptPath: paths.receiptPath,
|
|
17619
17689
|
managedPackage: mp,
|
|
@@ -17621,33 +17691,33 @@ async function runPiRuntimeSystem(input) {
|
|
|
17621
17691
|
verify: () => {
|
|
17622
17692
|
let entryStat = null;
|
|
17623
17693
|
try {
|
|
17624
|
-
entryStat =
|
|
17694
|
+
entryStat = fs40.lstatSync(mp.linkPath);
|
|
17625
17695
|
} catch (error) {
|
|
17626
17696
|
if (error.code !== "ENOENT") throw error;
|
|
17627
17697
|
}
|
|
17628
17698
|
if (entryStat !== null) throw new Error("managed entry still present after uninstall");
|
|
17629
17699
|
let releaseStat = null;
|
|
17630
17700
|
try {
|
|
17631
|
-
releaseStat =
|
|
17701
|
+
releaseStat = fs40.lstatSync(mp.releaseDir);
|
|
17632
17702
|
} catch (error) {
|
|
17633
17703
|
if (error.code !== "ENOENT") throw error;
|
|
17634
17704
|
}
|
|
17635
17705
|
if (releaseStat !== null) throw new Error("managed release still present after uninstall");
|
|
17636
17706
|
let receiptStat = null;
|
|
17637
17707
|
try {
|
|
17638
|
-
receiptStat =
|
|
17708
|
+
receiptStat = fs40.lstatSync(paths.receiptPath);
|
|
17639
17709
|
} catch (error) {
|
|
17640
17710
|
if (error.code !== "ENOENT") throw error;
|
|
17641
17711
|
}
|
|
17642
17712
|
if (receiptStat !== null) throw new Error("receipt still present after uninstall");
|
|
17643
|
-
if (
|
|
17713
|
+
if (fs40.readFileSync(settingsPath, "utf8") !== nextSettings) {
|
|
17644
17714
|
throw new Error("settings mismatch after uninstall");
|
|
17645
17715
|
}
|
|
17646
17716
|
}
|
|
17647
17717
|
});
|
|
17648
17718
|
},
|
|
17649
|
-
isPackageAbsent: () => !
|
|
17650
|
-
deleteReceipt: () =>
|
|
17719
|
+
isPackageAbsent: () => !fs40.existsSync(packageRoot),
|
|
17720
|
+
deleteReceipt: () => fs40.rmSync(paths.receiptPath, { force: true })
|
|
17651
17721
|
}
|
|
17652
17722
|
)
|
|
17653
17723
|
};
|
|
@@ -17660,8 +17730,8 @@ init_pi();
|
|
|
17660
17730
|
init_system_prompt_sections();
|
|
17661
17731
|
|
|
17662
17732
|
// src/lib/pi-browser-contract.ts
|
|
17663
|
-
import
|
|
17664
|
-
import
|
|
17733
|
+
import fs41 from "fs";
|
|
17734
|
+
import path49 from "path";
|
|
17665
17735
|
var CONTRACT_FILE = "browser-handoffs.v1.json";
|
|
17666
17736
|
var MAX_CONTRACT_BYTES = 4 * 1024;
|
|
17667
17737
|
function fail11(message) {
|
|
@@ -17672,23 +17742,23 @@ function validSchemas(value) {
|
|
|
17672
17742
|
}
|
|
17673
17743
|
function requirePiBrowserHandoffSchemas(packageRoot, required) {
|
|
17674
17744
|
if (required.playwright === void 0 && required.devtools === void 0) return;
|
|
17675
|
-
if (typeof packageRoot !== "string" || !
|
|
17745
|
+
if (typeof packageRoot !== "string" || !path49.isAbsolute(packageRoot)) fail11("package root is not absolute");
|
|
17676
17746
|
let realRoot;
|
|
17677
17747
|
try {
|
|
17678
|
-
realRoot =
|
|
17679
|
-
if (!
|
|
17748
|
+
realRoot = fs41.realpathSync(packageRoot);
|
|
17749
|
+
if (!fs41.statSync(realRoot).isDirectory()) fail11("package root is not a directory");
|
|
17680
17750
|
} catch {
|
|
17681
17751
|
fail11("installed Pi package root is unavailable");
|
|
17682
17752
|
}
|
|
17683
|
-
const contractDir =
|
|
17684
|
-
const file =
|
|
17753
|
+
const contractDir = path49.join(realRoot, "contract");
|
|
17754
|
+
const file = path49.join(contractDir, CONTRACT_FILE);
|
|
17685
17755
|
let raw;
|
|
17686
17756
|
try {
|
|
17687
|
-
const dirStat =
|
|
17688
|
-
const stat =
|
|
17757
|
+
const dirStat = fs41.lstatSync(contractDir);
|
|
17758
|
+
const stat = fs41.lstatSync(file);
|
|
17689
17759
|
if (!dirStat.isDirectory() || dirStat.isSymbolicLink() || !stat.isFile() || stat.isSymbolicLink() || stat.size > MAX_CONTRACT_BYTES) fail11("contract is not a bounded regular file");
|
|
17690
|
-
if (
|
|
17691
|
-
raw =
|
|
17760
|
+
if (fs41.realpathSync(file) !== file) fail11("contract path is not canonical");
|
|
17761
|
+
raw = fs41.readFileSync(file);
|
|
17692
17762
|
if (raw.byteLength > MAX_CONTRACT_BYTES || !Buffer.from(raw.toString("utf8"), "utf8").equals(raw)) {
|
|
17693
17763
|
fail11("contract is not bounded UTF-8");
|
|
17694
17764
|
}
|
|
@@ -17717,8 +17787,8 @@ function requirePiBrowserHandoffSchemas(packageRoot, required) {
|
|
|
17717
17787
|
|
|
17718
17788
|
// src/lib/pi-managed-runtime.ts
|
|
17719
17789
|
init_paths();
|
|
17720
|
-
import
|
|
17721
|
-
import
|
|
17790
|
+
import fs42 from "fs";
|
|
17791
|
+
import path50 from "path";
|
|
17722
17792
|
function projectionOperation(operation) {
|
|
17723
17793
|
return operation === "update" ? "sync" : operation;
|
|
17724
17794
|
}
|
|
@@ -17876,7 +17946,7 @@ async function runManagedPiSystem(input) {
|
|
|
17876
17946
|
const needsDevtoolsObservation = devtoolsMcpEnabled === true && input.operation !== "uninstall" && input.operation !== "models";
|
|
17877
17947
|
let devtoolsMcpObservedVersion = null;
|
|
17878
17948
|
let devtoolsVerifiedForPersist;
|
|
17879
|
-
const devtoolsManagedStateDir = input.targetDir === void 0 ? dataDir() :
|
|
17949
|
+
const devtoolsManagedStateDir = input.targetDir === void 0 ? dataDir() : path50.join(input.targetDir, "home", ".jorgex-stack");
|
|
17880
17950
|
if (needsDevtoolsObservation) {
|
|
17881
17951
|
if (input.targetDir !== void 0) {
|
|
17882
17952
|
devtoolsMcpObservedVersion = isValidObservedVersion(injectedDevtoolsObserved) ? { version: injectedDevtoolsObserved.version, integrity: injectedDevtoolsObserved.integrity } : null;
|
|
@@ -17924,8 +17994,8 @@ async function runManagedPiSystem(input) {
|
|
|
17924
17994
|
if (needsDevtoolsObservation) {
|
|
17925
17995
|
try {
|
|
17926
17996
|
if (input.targetDir !== void 0) {
|
|
17927
|
-
const target =
|
|
17928
|
-
const home =
|
|
17997
|
+
const target = fs42.lstatSync(input.targetDir);
|
|
17998
|
+
const home = fs42.lstatSync(path50.join(input.targetDir, "home"));
|
|
17929
17999
|
if (!target.isDirectory() || target.isSymbolicLink() || !home.isDirectory() || home.isSymbolicLink()) {
|
|
17930
18000
|
throw new Error("HOME del target Pi no es un directorio real aislado");
|
|
17931
18001
|
}
|
|
@@ -17949,7 +18019,7 @@ async function runManagedPiSystem(input) {
|
|
|
17949
18019
|
const playwrightCapabilityEffective = playwrightCapability?.effective === true;
|
|
17950
18020
|
const playwrightCliEnabled = input.targetDir === void 0 && supportsPlaywright && selectedPlaywright && playwrightCapabilityEffective;
|
|
17951
18021
|
const playwrightManagedStateDir = playwrightCliEnabled && input.operation !== "uninstall" && input.operation !== "models" ? dataDir() : void 0;
|
|
17952
|
-
const playwrightDispatcherPath = playwrightManagedStateDir === void 0 ? void 0 :
|
|
18022
|
+
const playwrightDispatcherPath = playwrightManagedStateDir === void 0 ? void 0 : path50.join(path50.dirname(stackRoot()), "dist", "browser-playwright.js");
|
|
17953
18023
|
let effectivePackageSource = PI_RUNTIME_CANDIDATE.package.source;
|
|
17954
18024
|
const projectionInput = {
|
|
17955
18025
|
writingStyle,
|
|
@@ -18006,7 +18076,7 @@ async function runManagedPiSystem(input) {
|
|
|
18006
18076
|
},
|
|
18007
18077
|
runProjection(operation) {
|
|
18008
18078
|
if (playwrightCliEnabled || devtoolsMcpEnabled) {
|
|
18009
|
-
const packageRoot =
|
|
18079
|
+
const packageRoot = path50.join(path50.dirname(piSystemPromptFile(input.targetDir)), "npm", "node_modules", "jorgex-pi");
|
|
18010
18080
|
try {
|
|
18011
18081
|
requirePiBrowserHandoffSchemas(packageRoot, {
|
|
18012
18082
|
...playwrightCliEnabled ? { playwright: 2 } : {},
|
|
@@ -18059,7 +18129,7 @@ init_fsx();
|
|
|
18059
18129
|
|
|
18060
18130
|
// src/lib/quality-runner.ts
|
|
18061
18131
|
init_detect();
|
|
18062
|
-
import
|
|
18132
|
+
import path51 from "path";
|
|
18063
18133
|
import { spawn as spawn2, spawnSync as spawnSync6 } from "child_process";
|
|
18064
18134
|
|
|
18065
18135
|
// src/lib/quality-policy.ts
|
|
@@ -18652,7 +18722,7 @@ function killProcessTree(child) {
|
|
|
18652
18722
|
if (pid === void 0) return;
|
|
18653
18723
|
if (process.platform === "win32") {
|
|
18654
18724
|
const systemRoot = process.env.SystemRoot ?? process.env.WINDIR ?? "C:\\Windows";
|
|
18655
|
-
const taskkill =
|
|
18725
|
+
const taskkill = path51.join(systemRoot, "System32", "taskkill.exe");
|
|
18656
18726
|
const result = spawnSync6(taskkill, ["/pid", String(pid), "/t", "/f"], {
|
|
18657
18727
|
shell: false,
|
|
18658
18728
|
stdio: "ignore",
|
|
@@ -18898,9 +18968,9 @@ async function runQualityPlan(input) {
|
|
|
18898
18968
|
}
|
|
18899
18969
|
|
|
18900
18970
|
// src/lib/engram-install.ts
|
|
18901
|
-
import
|
|
18971
|
+
import fs43 from "fs";
|
|
18902
18972
|
import os7 from "os";
|
|
18903
|
-
import
|
|
18973
|
+
import path52 from "path";
|
|
18904
18974
|
import { execFileSync as execFileSync8 } from "child_process";
|
|
18905
18975
|
import { createHash as createHash11 } from "crypto";
|
|
18906
18976
|
var MAX_ENGRAM_ARCHIVE_BYTES = 64 * 1024 * 1024;
|
|
@@ -18909,16 +18979,16 @@ var DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
|
18909
18979
|
async function installMissingEngram(options = {}) {
|
|
18910
18980
|
const platform = options.platform ?? process.platform;
|
|
18911
18981
|
const homeDir = options.homeDir ?? os7.homedir();
|
|
18912
|
-
if (!
|
|
18982
|
+
if (!path52.isAbsolute(homeDir)) return { ok: false, reason: "El directorio personal debe ser absoluto." };
|
|
18913
18983
|
const binaryName = platform === "win32" ? "engram.exe" : "engram";
|
|
18914
|
-
const bin =
|
|
18984
|
+
const bin = path52.join(homeDir, ".local", "bin", binaryName);
|
|
18915
18985
|
let staging;
|
|
18916
18986
|
let outcome;
|
|
18917
18987
|
try {
|
|
18918
|
-
const existing =
|
|
18988
|
+
const existing = fs43.lstatSync(bin, { throwIfNoEntry: false });
|
|
18919
18989
|
if (existing) {
|
|
18920
|
-
if (!
|
|
18921
|
-
|
|
18990
|
+
if (!fs43.statSync(bin).isFile()) throw new Error(`El destino Engram no es un archivo: ${bin}`);
|
|
18991
|
+
fs43.accessSync(bin, platform === "win32" ? fs43.constants.F_OK : fs43.constants.X_OK);
|
|
18922
18992
|
outcome = { ok: true, bin };
|
|
18923
18993
|
} else {
|
|
18924
18994
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
@@ -19031,19 +19101,19 @@ async function installMissingEngram(options = {}) {
|
|
|
19031
19101
|
if (size !== approvedSize || createHash11("sha256").update(archive).digest("hex") !== approvedSha) {
|
|
19032
19102
|
throw new Error("Engram: tama\xF1o o hash SHA-256 no coincide con el artefacto aprobado.");
|
|
19033
19103
|
}
|
|
19034
|
-
|
|
19035
|
-
staging =
|
|
19036
|
-
const archivePath =
|
|
19037
|
-
|
|
19104
|
+
fs43.mkdirSync(path52.dirname(bin), { recursive: true });
|
|
19105
|
+
staging = fs43.mkdtempSync(path52.join(path52.dirname(bin), ".engram-install-"));
|
|
19106
|
+
const archivePath = path52.join(staging, expectedName);
|
|
19107
|
+
fs43.writeFileSync(archivePath, archive, { flag: "wx", mode: 384 });
|
|
19038
19108
|
const binary = execFileSync8(resolveTarBin(), ["-xOf", archivePath, binaryName], {
|
|
19039
19109
|
maxBuffer: 64 * 1024 * 1024,
|
|
19040
19110
|
timeout: 3e4,
|
|
19041
19111
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19042
19112
|
});
|
|
19043
19113
|
if (binary.length === 0) throw new Error("El artefacto Engram no contiene un binario v\xE1lido.");
|
|
19044
|
-
const stagedBin =
|
|
19045
|
-
|
|
19046
|
-
|
|
19114
|
+
const stagedBin = path52.join(staging, binaryName);
|
|
19115
|
+
fs43.writeFileSync(stagedBin, binary, { flag: "wx", mode: 493 });
|
|
19116
|
+
fs43.linkSync(stagedBin, bin);
|
|
19047
19117
|
outcome = { ok: true, bin };
|
|
19048
19118
|
}
|
|
19049
19119
|
} catch (error) {
|
|
@@ -19051,7 +19121,7 @@ async function installMissingEngram(options = {}) {
|
|
|
19051
19121
|
}
|
|
19052
19122
|
if (staging !== void 0) {
|
|
19053
19123
|
try {
|
|
19054
|
-
|
|
19124
|
+
fs43.rmSync(staging, { recursive: true, force: true });
|
|
19055
19125
|
} catch (cleanupError) {
|
|
19056
19126
|
const cleanupMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
19057
19127
|
if (outcome !== void 0 && outcome.ok) {
|
|
@@ -19447,7 +19517,7 @@ async function runSelectedPi(options) {
|
|
|
19447
19517
|
return 1;
|
|
19448
19518
|
}
|
|
19449
19519
|
if (detected.version === null) {
|
|
19450
|
-
console.error(
|
|
19520
|
+
console.error(`No se pudo verificar la versi\xF3n instalada de Pi sin ejecutarlo: ${detected.versionDiagnostic ?? "causa desconocida"}. Repara Pi con su instalador oficial antes de reintentar.`);
|
|
19451
19521
|
return 1;
|
|
19452
19522
|
}
|
|
19453
19523
|
let engramBin = resolvedEngramBin === void 0 ? resolvePiEngramBin(targetDir) : resolvedEngramBin;
|
|
@@ -19618,7 +19688,7 @@ Flags disponibles: jorgex-stack --help`
|
|
|
19618
19688
|
return;
|
|
19619
19689
|
}
|
|
19620
19690
|
try {
|
|
19621
|
-
const plan = JSON.parse(
|
|
19691
|
+
const plan = JSON.parse(fs44.readFileSync(flags.positional[0], "utf8"));
|
|
19622
19692
|
const result = await runQualityPlan(plan);
|
|
19623
19693
|
const serialized = serializeQualityReceipt(result.receipt);
|
|
19624
19694
|
if (flags.receipt === void 0) process.stdout.write(`${serialized}
|