jorgex-stack 1.9.29 → 1.9.31
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/README.md +3 -1
- package/dist/cli.js +172 -44
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -120,7 +120,7 @@ pnpm dlx jorgex-stack@1.9.7 sync --agents pi
|
|
|
120
120
|
pnpm dlx jorgex-stack@1.9.7 uninstall --agents pi
|
|
121
121
|
```
|
|
122
122
|
|
|
123
|
-
Stack downloads the frozen registry tarball, verifies its exact size plus SHA-256/SHA-512, backs up Pi's `settings.json`, and only then asks Pi to install that local file. The historical `0.8.0` tarball was `89128340` bytes; the exact adopted artifact and integrity values are authoritative in `src/lib/pi-runtime-pin.json`, while the lifecycle remains authoritative in `src/lib/pi-runtime.ts`. Pi's own package-manager invocation is the narrow runtime exception to the repository's pnpm-only rule; the Stack lifecycle never launches npm directly. After the package is healthy, Stack projects the shared resources into Pi: marked `jorgex:system-prompt` and `jorgex:engram-protocol` sections in `~/.pi/agent/AGENTS.md`, canonical skills under `~/.agents/skills`, and `~/.pi/agent/prompts/lean-audit.md`. When the managed Playwright preference is active, the projection also adds or removes the marked `jorgex:browser` section dynamically. The Pi-only `install --agents pi --playwright` flow installs and persists that Playwright capability just like the other harnesses. Chrome DevTools
|
|
123
|
+
Stack downloads the frozen registry tarball, verifies its exact size plus SHA-256/SHA-512, backs up Pi's `settings.json`, and only then asks Pi to install that local file. The historical `0.8.0` tarball was `89128340` bytes; the exact adopted artifact and integrity values are authoritative in `src/lib/pi-runtime-pin.json`, while the lifecycle remains authoritative in `src/lib/pi-runtime.ts`. Pi's own package-manager invocation is the narrow runtime exception to the repository's pnpm-only rule; the Stack lifecycle never launches npm directly. After the package is healthy, Stack projects the shared resources into Pi: marked `jorgex:system-prompt` and `jorgex:engram-protocol` sections in `~/.pi/agent/AGENTS.md`, canonical skills under `~/.agents/skills`, and `~/.pi/agent/prompts/lean-audit.md`. When the managed Playwright preference is active, the projection also adds or removes the marked `jorgex:browser` section dynamically. The Pi-only `install --agents pi --playwright` flow installs and persists that Playwright capability just like the other harnesses. The adopted Pi `0.8.13` candidate also supports the optional Chrome DevTools handoff; Stack persists the selected handoff as part of the Pi projection and records its SHA-256 in the optional `devtools.sha256` field of `~/.jorgex-stack/pi-projection-receipt.json` after a successful operation. Context7 remains outside the Pi scope. The published `1.9.7` entry `{ "source": "npm:jorgex-pi@0.8.4", "skills": [], "prompts": [] }` and the `0.8.5` snapshot reference are historical; they do not describe the adopted pin. Filters are applied only after this projection exists, so the package does not duplicate shared resources. Package ownership is recorded separately in `~/.jorgex-stack/pi-receipt.json`; projection ownership is recorded in `~/.jorgex-stack/pi-projection-receipt.json`. Package receipts reject manual, duplicate, divergent, partial, corrupt, copied-to-another-scope, or unknown-history state. Projection cleanup requires an exact scope-bound ownership receipt; DevTools conflicts preserve the handoff for review.
|
|
124
124
|
|
|
125
125
|
Historically, the published Pi 0.8.0 direct-package snapshot added `work-audit`: the snapshot grew from **17 to 18 skill trees** (96 to 97 files), and the active runtime allowlist grew from **16 to 17 skills**. The historical Pi 0.8.5 snapshot reference records 18 skill trees and 98 files; it does not describe the adopted pin. Reference F2-A is included while the private F1 skills remain preserved. `playwright-cli` remains in the snapshot but inactive because browser automation is a separate opt-in integration.
|
|
126
126
|
|
|
@@ -159,6 +159,8 @@ pnpm dlx jorgex-stack install --yes --playwright
|
|
|
159
159
|
# Enable Chrome DevTools MCP explicitly per runtime.
|
|
160
160
|
pnpm dlx jorgex-stack install --devtools
|
|
161
161
|
pnpm dlx jorgex-stack install --no-devtools
|
|
162
|
+
pnpm dlx jorgex-stack install --agents pi --devtools
|
|
163
|
+
pnpm dlx jorgex-stack sync --agents pi --no-devtools
|
|
162
164
|
```
|
|
163
165
|
|
|
164
166
|
Under the hood, `--playwright` runs two `pnpm` argv-only plans back to back: `pnpm add --global @playwright/cli@0.1.18` (the package) and then `pnpm dlx @playwright/cli@0.1.18 install-browser` (the browser binary cache). Removal is `pnpm remove --global @playwright/cli` (no version suffix). If installation fails, the error identifies the failed phase — global package, browser download, or preference persistence — and recommends `jorgex-stack install --playwright`; the preference is not marked enabled unless the complete plan succeeds.
|
package/dist/cli.js
CHANGED
|
@@ -2257,10 +2257,12 @@ function executePlaywrightToolAction(action, pnpmBin = resolvePnpmBin(), env) {
|
|
|
2257
2257
|
const preflight = planDetectedBinCommand(pnpmBin, ["bin", "--global"]);
|
|
2258
2258
|
if (preflight === null) return { ok: false, reason: "pnpm-command" };
|
|
2259
2259
|
try {
|
|
2260
|
-
execFileSync2(preflight.command, preflight.args, {
|
|
2261
|
-
|
|
2260
|
+
const globalBin = execFileSync2(preflight.command, preflight.args, {
|
|
2261
|
+
encoding: "utf8",
|
|
2262
|
+
stdio: ["ignore", "pipe", "inherit"],
|
|
2262
2263
|
...env === void 0 ? {} : { env }
|
|
2263
2264
|
});
|
|
2265
|
+
if (globalBin.trim() === "") return { ok: false, reason: "pnpm-global-bin" };
|
|
2264
2266
|
} catch (error) {
|
|
2265
2267
|
return { ok: false, reason: hasNonzeroProcessStatus(error) ? "pnpm-global-bin" : "pnpm-command" };
|
|
2266
2268
|
}
|
|
@@ -2341,7 +2343,7 @@ function parseDevtoolsMcpState(raw) {
|
|
|
2341
2343
|
if (!isRecord2(value) || value.version !== DEVTOOLS_MCP_PREFERENCE_VERSION || !isRecord2(value.enabled) || !isRecord2(value.owned)) return null;
|
|
2342
2344
|
const enabled = {};
|
|
2343
2345
|
for (const [runtime, selected] of Object.entries(value.enabled)) {
|
|
2344
|
-
if (!isRuntimeId(runtime) || typeof selected !== "boolean") return null;
|
|
2346
|
+
if (!isRuntimeId(runtime) && runtime !== "pi" || typeof selected !== "boolean") return null;
|
|
2345
2347
|
enabled[runtime] = selected;
|
|
2346
2348
|
}
|
|
2347
2349
|
const owned = {};
|
|
@@ -2844,6 +2846,7 @@ import * as p2 from "@clack/prompts";
|
|
|
2844
2846
|
// src/lib/pi-projection-lifecycle.ts
|
|
2845
2847
|
import fs16 from "fs";
|
|
2846
2848
|
import path23 from "path";
|
|
2849
|
+
import { createHash } from "crypto";
|
|
2847
2850
|
|
|
2848
2851
|
// src/adapters/pi.ts
|
|
2849
2852
|
import path21 from "path";
|
|
@@ -3307,14 +3310,33 @@ function projectionPlan(input, scope) {
|
|
|
3307
3310
|
engramBin: input.engramBin,
|
|
3308
3311
|
models: DEFAULT_MODEL_MAP.codex,
|
|
3309
3312
|
warnings: [],
|
|
3310
|
-
playwrightCliEnabled: input.playwrightCliEnabled
|
|
3313
|
+
playwrightCliEnabled: input.playwrightCliEnabled,
|
|
3314
|
+
enabledMcpServers: input.devtoolsMcpEnabled ? /* @__PURE__ */ new Set([DEVTOOLS_MCP_SERVER]) : void 0
|
|
3311
3315
|
};
|
|
3312
3316
|
const adapter = projectedPiAdapter(scope);
|
|
3313
|
-
|
|
3317
|
+
const actions = [
|
|
3314
3318
|
...planSystemPrompt(adapter, ctx),
|
|
3315
3319
|
...planSkills(adapter, ctx),
|
|
3316
3320
|
...planCommands(adapter, ctx)
|
|
3317
3321
|
];
|
|
3322
|
+
if (input.devtoolsMcpEnabled && input.pnpmBin) {
|
|
3323
|
+
const server = loadCanonicalMcp(input.stackDir).servers[DEVTOOLS_MCP_SERVER];
|
|
3324
|
+
if (server?.transport !== "stdio" || !Array.isArray(server.args)) throw new Error("Falta la configuraci\xF3n can\xF3nica de DevTools.");
|
|
3325
|
+
actions.push({ kind: "write", target: devtoolsPath(scope), content: `${JSON.stringify({
|
|
3326
|
+
schemaVersion: 1,
|
|
3327
|
+
enabled: true,
|
|
3328
|
+
command: input.pnpmBin,
|
|
3329
|
+
args: server.args
|
|
3330
|
+
}, null, 2)}
|
|
3331
|
+
` });
|
|
3332
|
+
}
|
|
3333
|
+
return actions;
|
|
3334
|
+
}
|
|
3335
|
+
function devtoolsPath(scope) {
|
|
3336
|
+
return path23.resolve(scope.codingAgentDir, "jorgex-pi", "devtools.v1.json");
|
|
3337
|
+
}
|
|
3338
|
+
function contentHash(content) {
|
|
3339
|
+
return createHash("sha256").update(content).digest("hex");
|
|
3318
3340
|
}
|
|
3319
3341
|
function canonicalActionContent(action) {
|
|
3320
3342
|
return action.kind === "write" ? action.content : fs16.readFileSync(action.source, "utf8");
|
|
@@ -3322,8 +3344,15 @@ function canonicalActionContent(action) {
|
|
|
3322
3344
|
function hasActionDrift(action, deps) {
|
|
3323
3345
|
return deps.readText(action.target) !== canonicalActionContent(action);
|
|
3324
3346
|
}
|
|
3325
|
-
function applyActions(actions, deps) {
|
|
3347
|
+
function applyActions(actions, deps, handoff) {
|
|
3326
3348
|
for (const action of actions) {
|
|
3349
|
+
if (handoff && path23.resolve(action.target) === handoff.file) {
|
|
3350
|
+
try {
|
|
3351
|
+
if (deps.readText(handoff.file) !== handoff.previous) return devtoolsConflict(handoff.file);
|
|
3352
|
+
} catch {
|
|
3353
|
+
return devtoolsConflict(handoff.file);
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3327
3356
|
if (action.kind === "write") deps.writeText(action.target, action.content);
|
|
3328
3357
|
else deps.copyFile(action.source, action.target);
|
|
3329
3358
|
}
|
|
@@ -3340,6 +3369,7 @@ function receiptFor(plan, scope) {
|
|
|
3340
3369
|
const owned = [...new Set(
|
|
3341
3370
|
plan.map((action) => path23.resolve(action.target)).filter((target) => target !== systemPrompt)
|
|
3342
3371
|
)];
|
|
3372
|
+
const handoff = plan.find((action) => path23.resolve(action.target) === devtoolsPath(scope));
|
|
3343
3373
|
return {
|
|
3344
3374
|
schemaVersion: 1,
|
|
3345
3375
|
scope: {
|
|
@@ -3348,7 +3378,8 @@ function receiptFor(plan, scope) {
|
|
|
3348
3378
|
codingAgentDir: scope.codingAgentDir,
|
|
3349
3379
|
receiptFile: scope.receiptFile
|
|
3350
3380
|
},
|
|
3351
|
-
owned
|
|
3381
|
+
owned,
|
|
3382
|
+
...handoff ? { devtools: { sha256: contentHash(canonicalActionContent(handoff)) } } : {}
|
|
3352
3383
|
};
|
|
3353
3384
|
}
|
|
3354
3385
|
function receiptContent(receipt) {
|
|
@@ -3367,16 +3398,25 @@ function parseReceipt2(raw, expected) {
|
|
|
3367
3398
|
const version = Reflect.get(receipt, "schemaVersion");
|
|
3368
3399
|
const receivedScope = Reflect.get(receipt, "scope");
|
|
3369
3400
|
const owned = Reflect.get(receipt, "owned");
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
if (Reflect.get(receivedScope, "kind") !== expected.scope.kind || Reflect.get(receivedScope, "home") !== expected.scope.home || Reflect.get(receivedScope, "codingAgentDir") !== expected.scope.codingAgentDir || Reflect.get(receivedScope, "receiptFile") !== expected.scope.receiptFile || !Array.isArray(owned) || owned.length !== expected.owned.length) {
|
|
3401
|
+
const devtools = Reflect.get(receipt, "devtools");
|
|
3402
|
+
const hasDevtools = Object.hasOwn(receipt, "devtools");
|
|
3403
|
+
if (version !== expected.schemaVersion || !hasExactKeys(receipt, ["schemaVersion", "scope", "owned", ...hasDevtools ? ["devtools"] : []]) || receivedScope === null || typeof receivedScope !== "object" || Array.isArray(receivedScope) || !hasExactKeys(receivedScope, ["kind", "home", "codingAgentDir", "receiptFile"])) {
|
|
3374
3404
|
return null;
|
|
3375
3405
|
}
|
|
3376
|
-
if (
|
|
3406
|
+
if (Reflect.get(receivedScope, "kind") !== expected.scope.kind || Reflect.get(receivedScope, "home") !== expected.scope.home || Reflect.get(receivedScope, "codingAgentDir") !== expected.scope.codingAgentDir || Reflect.get(receivedScope, "receiptFile") !== expected.scope.receiptFile || !Array.isArray(owned)) {
|
|
3377
3407
|
return null;
|
|
3378
3408
|
}
|
|
3379
|
-
return
|
|
3409
|
+
if (hasDevtools && (devtools === null || typeof devtools !== "object" || Array.isArray(devtools) || !hasExactKeys(devtools, ["sha256"]) || typeof Reflect.get(devtools, "sha256") !== "string" || !/^[a-f0-9]{64}$/.test(Reflect.get(devtools, "sha256")))) return null;
|
|
3410
|
+
const handoff = devtoolsPath(expected.scope);
|
|
3411
|
+
const expectedOwned = expected.owned.filter((file) => file !== handoff);
|
|
3412
|
+
if (hasDevtools) expectedOwned.push(handoff);
|
|
3413
|
+
if (owned.length !== expectedOwned.length || !owned.every((file, index) => typeof file === "string" && file === expectedOwned[index])) return null;
|
|
3414
|
+
return {
|
|
3415
|
+
schemaVersion: 1,
|
|
3416
|
+
scope: expected.scope,
|
|
3417
|
+
owned: expectedOwned,
|
|
3418
|
+
...hasDevtools ? { devtools: { sha256: Reflect.get(devtools, "sha256") } } : {}
|
|
3419
|
+
};
|
|
3380
3420
|
} catch {
|
|
3381
3421
|
return null;
|
|
3382
3422
|
}
|
|
@@ -3502,6 +3542,35 @@ function readProjectionReceipt(receiptFile, deps) {
|
|
|
3502
3542
|
return { kind: "unreadable" };
|
|
3503
3543
|
}
|
|
3504
3544
|
}
|
|
3545
|
+
function devtoolsConflict(file) {
|
|
3546
|
+
return blocked2(
|
|
3547
|
+
"projection-devtools-conflict",
|
|
3548
|
+
[file],
|
|
3549
|
+
"El handoff de DevTools es ajeno o fue modificado. Cons\xE9rvalo y revisa su propiedad antes de reintentar; Stack no lo sobrescribe ni elimina."
|
|
3550
|
+
);
|
|
3551
|
+
}
|
|
3552
|
+
function inspectDevtools(input, scope, expected, deps) {
|
|
3553
|
+
const file = devtoolsPath(scope);
|
|
3554
|
+
const read = readProjectionReceipt(scope.receiptFile, deps);
|
|
3555
|
+
if (read.kind === "unreadable") return receiptUnreadable(scope.receiptFile);
|
|
3556
|
+
const previous = read.kind === "present" ? parseReceipt2(read.content, expected) : null;
|
|
3557
|
+
let content;
|
|
3558
|
+
try {
|
|
3559
|
+
content = deps.readText(file);
|
|
3560
|
+
} catch {
|
|
3561
|
+
return devtoolsConflict(file);
|
|
3562
|
+
}
|
|
3563
|
+
let recordedDevtools = false;
|
|
3564
|
+
if (read.kind === "present") {
|
|
3565
|
+
try {
|
|
3566
|
+
recordedDevtools = Object.hasOwn(JSON.parse(read.content), "devtools");
|
|
3567
|
+
} catch {
|
|
3568
|
+
}
|
|
3569
|
+
if (!previous && (input.devtoolsMcpEnabled || content !== null || recordedDevtools)) return receiptInvalid(scope.receiptFile);
|
|
3570
|
+
}
|
|
3571
|
+
if (content !== null && (!previous?.devtools || contentHash(content) !== previous.devtools.sha256)) return devtoolsConflict(file);
|
|
3572
|
+
return { kind: "checked", previous, content };
|
|
3573
|
+
}
|
|
3505
3574
|
function preparePiProjectionUninstall(input, deps) {
|
|
3506
3575
|
if (input.operation !== "uninstall") {
|
|
3507
3576
|
return cleanupFailure([]);
|
|
@@ -3520,11 +3589,13 @@ function preparePiProjectionUninstall(input, deps) {
|
|
|
3520
3589
|
const receiptRead = readProjectionReceipt(scope.receiptFile, deps);
|
|
3521
3590
|
if (receiptRead.kind === "unreadable") return receiptUnreadable(scope.receiptFile);
|
|
3522
3591
|
let ownedToRemove = [];
|
|
3592
|
+
let ownedReceipt = null;
|
|
3523
3593
|
let receiptFile = null;
|
|
3524
3594
|
let backupTargets = promptUpdate === null ? [] : [promptUpdate.file];
|
|
3525
3595
|
if (receiptRead.kind === "present") {
|
|
3526
3596
|
const receipt = parseReceipt2(receiptRead.content, expectedReceipt2);
|
|
3527
3597
|
if (receipt === null) return receiptInvalid(scope.receiptFile);
|
|
3598
|
+
ownedReceipt = receipt;
|
|
3528
3599
|
let retained;
|
|
3529
3600
|
try {
|
|
3530
3601
|
retained = manifestOwned(deps.readManifest());
|
|
@@ -3535,13 +3606,22 @@ function preparePiProjectionUninstall(input, deps) {
|
|
|
3535
3606
|
receiptFile = path23.resolve(scope.receiptFile);
|
|
3536
3607
|
backupTargets = [...backupTargets, ...receipt.owned, receiptFile];
|
|
3537
3608
|
}
|
|
3609
|
+
const handoff = devtoolsPath(scope);
|
|
3610
|
+
let handoffContent;
|
|
3611
|
+
try {
|
|
3612
|
+
handoffContent = deps.readText(handoff);
|
|
3613
|
+
} catch {
|
|
3614
|
+
return devtoolsConflict(handoff);
|
|
3615
|
+
}
|
|
3616
|
+
if (handoffContent !== null && (!ownedReceipt?.devtools || contentHash(handoffContent) !== ownedReceipt.devtools.sha256)) return devtoolsConflict(handoff);
|
|
3538
3617
|
const backup = backupExisting(backupTargets, deps);
|
|
3539
3618
|
if (backup.kind === "backup-failed") return backupFailure(backup.paths);
|
|
3540
3619
|
const token = {};
|
|
3541
3620
|
preparedPiProjectionUninstalls.set(token, {
|
|
3542
3621
|
prompt: promptUpdate,
|
|
3543
3622
|
ownedToRemove,
|
|
3544
|
-
receiptFile
|
|
3623
|
+
receiptFile,
|
|
3624
|
+
...ownedReceipt?.devtools ? { devtools: { file: handoff, sha256: ownedReceipt.devtools.sha256 } } : {}
|
|
3545
3625
|
});
|
|
3546
3626
|
return { kind: "prepared", plan: token };
|
|
3547
3627
|
}
|
|
@@ -3553,6 +3633,15 @@ function completePiProjectionUninstall(plan, deps) {
|
|
|
3553
3633
|
if (prepared === void 0) {
|
|
3554
3634
|
return cleanupFailure([]);
|
|
3555
3635
|
}
|
|
3636
|
+
if (prepared.devtools) {
|
|
3637
|
+
let current;
|
|
3638
|
+
try {
|
|
3639
|
+
current = deps.readText(prepared.devtools.file);
|
|
3640
|
+
} catch {
|
|
3641
|
+
return devtoolsConflict(prepared.devtools.file);
|
|
3642
|
+
}
|
|
3643
|
+
if (current !== null && contentHash(current) !== prepared.devtools.sha256) return devtoolsConflict(prepared.devtools.file);
|
|
3644
|
+
}
|
|
3556
3645
|
if (prepared.prompt !== null) {
|
|
3557
3646
|
try {
|
|
3558
3647
|
deps.writeText(prepared.prompt.file, prepared.prompt.content);
|
|
@@ -3562,6 +3651,10 @@ function completePiProjectionUninstall(plan, deps) {
|
|
|
3562
3651
|
}
|
|
3563
3652
|
for (const owned of prepared.ownedToRemove) {
|
|
3564
3653
|
try {
|
|
3654
|
+
if (prepared.devtools?.file === owned) {
|
|
3655
|
+
const current = deps.readText(owned);
|
|
3656
|
+
if (current !== null && contentHash(current) !== prepared.devtools.sha256) return devtoolsConflict(owned);
|
|
3657
|
+
}
|
|
3565
3658
|
deps.removeFile(owned);
|
|
3566
3659
|
} catch {
|
|
3567
3660
|
return cleanupFailure([owned]);
|
|
@@ -3582,13 +3675,23 @@ function runPiProjectionLifecycle(input, deps) {
|
|
|
3582
3675
|
const prepared = preparePiProjectionUninstall(input, deps);
|
|
3583
3676
|
return prepared.kind === "blocked" ? prepared : completePiProjectionUninstall(prepared.plan, deps);
|
|
3584
3677
|
}
|
|
3678
|
+
if (input.devtoolsMcpEnabled && (!input.pnpmBin || !path23.isAbsolute(input.pnpmBin))) {
|
|
3679
|
+
return blocked2("projection-devtools-command", [devtoolsPath(scope)], "DevTools requiere un ejecutable pnpm absoluto disponible en PATH.");
|
|
3680
|
+
}
|
|
3585
3681
|
const plan = projectionPlan(input, scope);
|
|
3586
3682
|
assertPlanContained(plan, scope);
|
|
3587
3683
|
const receipt = receiptFor(plan, scope);
|
|
3684
|
+
const devtools = inspectDevtools(input, scope, receipt, deps);
|
|
3685
|
+
if (devtools.kind === "blocked") return input.operation === "doctor" ? { kind: "drift", paths: devtools.paths } : devtools;
|
|
3686
|
+
const removeHandoff = !input.devtoolsMcpEnabled && devtools.previous?.devtools !== void 0 && devtools.content !== null;
|
|
3588
3687
|
const expectedReceipt2 = receiptContent(receipt);
|
|
3589
3688
|
const drifted = plan.filter((action) => hasActionDrift(action, deps));
|
|
3689
|
+
if (input.devtoolsMcpEnabled && devtools.previous?.devtools?.sha256 !== receipt.devtools?.sha256 && !drifted.some((action) => path23.resolve(action.target) === devtoolsPath(scope))) {
|
|
3690
|
+
return input.operation === "doctor" ? { kind: "drift", paths: [devtoolsPath(scope)] } : devtoolsConflict(devtoolsPath(scope));
|
|
3691
|
+
}
|
|
3590
3692
|
if (input.operation === "doctor") {
|
|
3591
3693
|
const paths = drifted.map((action) => path23.resolve(action.target));
|
|
3694
|
+
if (removeHandoff) paths.push(devtoolsPath(scope));
|
|
3592
3695
|
const currentSettings2 = deps.readText(scope.settingsFile);
|
|
3593
3696
|
if (currentSettings2 === null || filterProjectedPiPackage(currentSettings2, input.packageSource) !== currentSettings2) {
|
|
3594
3697
|
paths.push(scope.settingsFile);
|
|
@@ -3604,19 +3707,30 @@ function runPiProjectionLifecycle(input, deps) {
|
|
|
3604
3707
|
}
|
|
3605
3708
|
const packageWillChange = filteredSettings !== null && filteredSettings !== currentSettings;
|
|
3606
3709
|
const receiptChanged = deps.readText(scope.receiptFile) !== expectedReceipt2;
|
|
3607
|
-
if (drifted.length > 0 || packageWillChange || receiptChanged) {
|
|
3710
|
+
if (drifted.length > 0 || packageWillChange || receiptChanged || removeHandoff) {
|
|
3608
3711
|
const backup = backupExisting([
|
|
3609
3712
|
...drifted.map((action) => action.target),
|
|
3713
|
+
...removeHandoff ? [devtoolsPath(scope)] : [],
|
|
3610
3714
|
...packageWillChange ? [scope.settingsFile] : [],
|
|
3611
3715
|
...receiptChanged ? [scope.receiptFile] : []
|
|
3612
3716
|
], deps);
|
|
3613
3717
|
if (backup.kind === "backup-failed") return backupFailure(backup.paths);
|
|
3614
3718
|
}
|
|
3615
|
-
|
|
3719
|
+
if (removeHandoff) {
|
|
3720
|
+
try {
|
|
3721
|
+
const current = deps.readText(devtoolsPath(scope));
|
|
3722
|
+
if (current !== null && contentHash(current) !== devtools.previous?.devtools?.sha256) return devtoolsConflict(devtoolsPath(scope));
|
|
3723
|
+
deps.removeFile(devtoolsPath(scope));
|
|
3724
|
+
} catch {
|
|
3725
|
+
return cleanupFailure([devtoolsPath(scope)]);
|
|
3726
|
+
}
|
|
3727
|
+
}
|
|
3728
|
+
const writeResult = applyActions(drifted, deps, input.devtoolsMcpEnabled ? { file: devtoolsPath(scope), previous: devtools.content } : void 0);
|
|
3729
|
+
if (writeResult) return writeResult;
|
|
3616
3730
|
if (packageWillChange && filteredSettings !== null) deps.writeText(scope.settingsFile, filteredSettings);
|
|
3617
3731
|
if (receiptChanged) deps.writeText(scope.receiptFile, expectedReceipt2);
|
|
3618
3732
|
if (input.operation === "install") return { kind: "installed", receipt };
|
|
3619
|
-
return { kind: "synced", changed: drifted.length > 0 || packageWillChange || receiptChanged };
|
|
3733
|
+
return { kind: "synced", changed: drifted.length > 0 || packageWillChange || receiptChanged || removeHandoff };
|
|
3620
3734
|
}
|
|
3621
3735
|
function systemProjectionLifecycle(input) {
|
|
3622
3736
|
const targetRoot = input.targetDir === void 0 ? null : path23.resolve(input.targetDir);
|
|
@@ -3633,7 +3747,9 @@ function systemProjectionLifecycle(input) {
|
|
|
3633
3747
|
packageSource: input.packageSource,
|
|
3634
3748
|
stackDir: stackRoot(),
|
|
3635
3749
|
engramBin: input.engramBin ?? "",
|
|
3636
|
-
playwrightCliEnabled: input.playwrightCliEnabled
|
|
3750
|
+
playwrightCliEnabled: input.playwrightCliEnabled,
|
|
3751
|
+
devtoolsMcpEnabled: input.devtoolsMcpEnabled,
|
|
3752
|
+
pnpmBin: input.pnpmBin
|
|
3637
3753
|
},
|
|
3638
3754
|
deps: {
|
|
3639
3755
|
readText: readTextOnlyIfMissing,
|
|
@@ -5218,22 +5334,22 @@ import os4 from "os";
|
|
|
5218
5334
|
import path31 from "path";
|
|
5219
5335
|
import fs23 from "fs";
|
|
5220
5336
|
import { spawnSync } from "child_process";
|
|
5221
|
-
import { createHash } from "crypto";
|
|
5337
|
+
import { createHash as createHash2 } from "crypto";
|
|
5222
5338
|
|
|
5223
5339
|
// src/lib/pi-runtime-pin.json
|
|
5224
5340
|
var pi_runtime_pin_default = {
|
|
5225
5341
|
package: {
|
|
5226
5342
|
name: "jorgex-pi",
|
|
5227
|
-
version: "0.8.
|
|
5228
|
-
source: "npm:jorgex-pi@0.8.
|
|
5343
|
+
version: "0.8.13",
|
|
5344
|
+
source: "npm:jorgex-pi@0.8.13"
|
|
5229
5345
|
},
|
|
5230
5346
|
provenance: {
|
|
5231
|
-
commit: "
|
|
5347
|
+
commit: "e28a677da0a112925251cf11269b70cb5c8aa15e"
|
|
5232
5348
|
},
|
|
5233
5349
|
tarball: {
|
|
5234
|
-
bytes:
|
|
5235
|
-
sha256: "
|
|
5236
|
-
sha512: "
|
|
5350
|
+
bytes: 89143404,
|
|
5351
|
+
sha256: "6bbe877249b900af582c8881e0dd7993951ea1cef6e7252522c626c078de7478",
|
|
5352
|
+
sha512: "bb527d1f3812406f2184f778b22cca00ead33692fecac0012cf8cdcdc469b7cccf3c789c35b4327dd599d06542162bd07eefeeaaa40de19662ec5fc422b14af8"
|
|
5237
5353
|
}
|
|
5238
5354
|
};
|
|
5239
5355
|
|
|
@@ -5255,6 +5371,7 @@ var PI_RUNTIME_CANDIDATE = {
|
|
|
5255
5371
|
"goal-continuation-v1",
|
|
5256
5372
|
"mcp-adapter-v1",
|
|
5257
5373
|
"engram-runtime-tools-v1",
|
|
5374
|
+
"chrome-devtools-handoff-v1",
|
|
5258
5375
|
"runner-json-v1",
|
|
5259
5376
|
"tui-branding-v1",
|
|
5260
5377
|
"managed-primary-model-v1",
|
|
@@ -5607,8 +5724,8 @@ function readOptional(file, fallback) {
|
|
|
5607
5724
|
}
|
|
5608
5725
|
function hashPiTarball(file) {
|
|
5609
5726
|
const descriptor = fs23.openSync(file, "r");
|
|
5610
|
-
const sha2562 =
|
|
5611
|
-
const sha512 =
|
|
5727
|
+
const sha2562 = createHash2("sha256");
|
|
5728
|
+
const sha512 = createHash2("sha512");
|
|
5612
5729
|
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
5613
5730
|
let bytes = 0;
|
|
5614
5731
|
try {
|
|
@@ -5826,36 +5943,44 @@ function managedPackageResult(result) {
|
|
|
5826
5943
|
return result;
|
|
5827
5944
|
}
|
|
5828
5945
|
async function runManagedPiSystem(input) {
|
|
5946
|
+
const { devtoolsMcpEnabled: explicitDevtools, ...runtimeInput } = input;
|
|
5947
|
+
const devtoolsMcpEnabled = explicitDevtools ?? (input.targetDir === void 0 && loadDevtoolsMcpPreference(devtoolsMcpPreferenceFile(), "pi"));
|
|
5829
5948
|
const playwrightCliEnabled = input.targetDir === void 0 && loadPlaywrightCliPreference() === true;
|
|
5830
5949
|
const projectionInput = {
|
|
5831
5950
|
targetDir: input.targetDir,
|
|
5832
5951
|
packageSource: PI_RUNTIME_CANDIDATE.package.source,
|
|
5833
5952
|
engramBin: input.engramBin,
|
|
5834
|
-
playwrightCliEnabled
|
|
5953
|
+
playwrightCliEnabled,
|
|
5954
|
+
devtoolsMcpEnabled,
|
|
5955
|
+
pnpmBin: devtoolsMcpEnabled && input.operation !== "uninstall" ? resolvePnpmBin() : null
|
|
5835
5956
|
};
|
|
5836
|
-
|
|
5957
|
+
const result = await runManagedPiOperation(input.operation, {
|
|
5837
5958
|
async runPackage(operation) {
|
|
5838
|
-
return managedPackageResult(await runPiRuntimeSystem({ ...
|
|
5959
|
+
return managedPackageResult(await runPiRuntimeSystem({ ...runtimeInput, operation }));
|
|
5839
5960
|
},
|
|
5840
5961
|
runProjection(operation) {
|
|
5841
|
-
const
|
|
5962
|
+
const result2 = runPiProjectionLifecycleSystem({
|
|
5842
5963
|
operation,
|
|
5843
5964
|
...projectionInput
|
|
5844
5965
|
});
|
|
5845
|
-
return Promise.resolve(
|
|
5966
|
+
return Promise.resolve(result2.kind === "drift" ? {
|
|
5846
5967
|
kind: "drift",
|
|
5847
|
-
paths:
|
|
5968
|
+
paths: result2.paths,
|
|
5848
5969
|
remedy: "Ejecuta sync --agents pi para reparar la proyecci\xF3n de Pi."
|
|
5849
|
-
} :
|
|
5970
|
+
} : result2);
|
|
5850
5971
|
},
|
|
5851
5972
|
prepareProjectionUninstall() {
|
|
5852
|
-
const
|
|
5853
|
-
return Promise.resolve(
|
|
5973
|
+
const result2 = preparePiProjectionUninstallSystem({ operation: "uninstall", ...projectionInput });
|
|
5974
|
+
return Promise.resolve(result2.kind === "prepared" ? { kind: "prepared", token: result2.plan } : result2);
|
|
5854
5975
|
},
|
|
5855
5976
|
completeProjectionUninstall(token) {
|
|
5856
5977
|
return Promise.resolve(completePiProjectionUninstallSystem(token, { operation: "uninstall", ...projectionInput }));
|
|
5857
5978
|
}
|
|
5858
5979
|
});
|
|
5980
|
+
if (input.targetDir === void 0 && explicitDevtools !== void 0 && (input.operation === "install" || input.operation === "sync") && result.kind !== "blocked") {
|
|
5981
|
+
saveDevtoolsMcpPreference(devtoolsMcpPreferenceFile(), "pi", explicitDevtools);
|
|
5982
|
+
}
|
|
5983
|
+
return result;
|
|
5859
5984
|
}
|
|
5860
5985
|
|
|
5861
5986
|
// src/lib/quality-runner.ts
|
|
@@ -6241,7 +6366,7 @@ import fs24 from "fs";
|
|
|
6241
6366
|
import os5 from "os";
|
|
6242
6367
|
import path33 from "path";
|
|
6243
6368
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
6244
|
-
import { createHash as
|
|
6369
|
+
import { createHash as createHash3 } from "crypto";
|
|
6245
6370
|
|
|
6246
6371
|
// src/lib/engram-release.json
|
|
6247
6372
|
var engram_release_default = {
|
|
@@ -6318,7 +6443,7 @@ async function installMissingEngram(options = {}) {
|
|
|
6318
6443
|
await reader.cancel();
|
|
6319
6444
|
}
|
|
6320
6445
|
const archive = Buffer.concat(chunks);
|
|
6321
|
-
if (size !== asset.size ||
|
|
6446
|
+
if (size !== asset.size || createHash3("sha256").update(archive).digest("hex") !== asset.sha256) {
|
|
6322
6447
|
throw new Error("Engram: tama\xF1o o hash SHA-256 no coincide con el artefacto aprobado.");
|
|
6323
6448
|
}
|
|
6324
6449
|
fs24.mkdirSync(path33.dirname(bin), { recursive: true });
|
|
@@ -6544,8 +6669,9 @@ async function resolveDevtoolsMcpSelection(command, flags, runtimes) {
|
|
|
6544
6669
|
}
|
|
6545
6670
|
const file = devtoolsMcpPreferenceFile();
|
|
6546
6671
|
const selected = await p6.multiselect({
|
|
6547
|
-
message: "Chrome DevTools MCP avanzado (
|
|
6548
|
-
|
|
6672
|
+
message: "Chrome DevTools MCP avanzado (opcional). \xBFEn qu\xE9 runtimes activarlo?",
|
|
6673
|
+
required: false,
|
|
6674
|
+
options: runtimes.map((runtime) => ({ value: runtime, label: runtime === "pi" ? "Pi" : ADAPTERS[runtime]?.name ?? runtime })),
|
|
6549
6675
|
initialValues: runtimes.filter((runtime) => loadDevtoolsMcpPreference(file, runtime))
|
|
6550
6676
|
});
|
|
6551
6677
|
if (p6.isCancel(selected)) return null;
|
|
@@ -6617,7 +6743,7 @@ async function resolveHostEngramForInstall(flags) {
|
|
|
6617
6743
|
return { ok: false, message: `Engram: ${error instanceof Error ? error.message : String(error)}` };
|
|
6618
6744
|
}
|
|
6619
6745
|
}
|
|
6620
|
-
async function runSelectedPi(operation, targetDir, yes = false, resolvedEngramBin) {
|
|
6746
|
+
async function runSelectedPi(operation, targetDir, yes = false, resolvedEngramBin, devtoolsMcpEnabled) {
|
|
6621
6747
|
if (targetDir === void 0 && operation !== "models") {
|
|
6622
6748
|
const preferenceErrors = browserPreferenceErrors();
|
|
6623
6749
|
if (preferenceErrors.length > 0) {
|
|
@@ -6659,7 +6785,8 @@ async function runSelectedPi(operation, targetDir, yes = false, resolvedEngramBi
|
|
|
6659
6785
|
operation,
|
|
6660
6786
|
targetDir,
|
|
6661
6787
|
detected: { executable: detected.executable, version: detected.version },
|
|
6662
|
-
engramBin
|
|
6788
|
+
engramBin,
|
|
6789
|
+
...devtoolsMcpEnabled === void 0 ? {} : { devtoolsMcpEnabled }
|
|
6663
6790
|
});
|
|
6664
6791
|
if (result.kind === "blocked") {
|
|
6665
6792
|
const paths = "paths" in result ? `: ${result.paths.join(", ")}` : "";
|
|
@@ -6795,7 +6922,7 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6795
6922
|
}
|
|
6796
6923
|
const mode = fileRuntimes.length > 0 ? await resolveInstallMode(flags) : void 0;
|
|
6797
6924
|
if (mode === null) return;
|
|
6798
|
-
const devtoolsMcpSelection = await resolveDevtoolsMcpSelection(command, flags,
|
|
6925
|
+
const devtoolsMcpSelection = await resolveDevtoolsMcpSelection(command, flags, runtimes);
|
|
6799
6926
|
if (devtoolsMcpSelection === null) {
|
|
6800
6927
|
exitCode = process.exitCode === 1 ? 1 : 0;
|
|
6801
6928
|
return;
|
|
@@ -6852,7 +6979,8 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6852
6979
|
command,
|
|
6853
6980
|
flags.targetDir,
|
|
6854
6981
|
flags.yes,
|
|
6855
|
-
flags.targetDir === void 0 ? engramBin : void 0
|
|
6982
|
+
flags.targetDir === void 0 ? engramBin : void 0,
|
|
6983
|
+
devtoolsMcpSelection.pi
|
|
6856
6984
|
));
|
|
6857
6985
|
}
|
|
6858
6986
|
completed = true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jorgex-stack",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.31",
|
|
4
4
|
"description": "Harness multi-agente portable: instala la config JorgeX (agentes, skills, hooks, Engram, MCPs) en Claude Code, Codex CLI, OpenCode y Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|