jorgex-stack 1.9.28 → 1.9.30
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 +5 -3
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +455 -83
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ pnpm dlx jorgex-stack uninstall # remove managed files; keep Engram data i
|
|
|
56
56
|
|
|
57
57
|
For development from a clone, run the same commands through `pnpm cli <command>` (see [Development](#development)).
|
|
58
58
|
|
|
59
|
-
Every command supports `--dry-run`, `--yes`, and `--target-dir <dir>` for testing without touching the real config. Writes create automatic backups and verify idempotency; merges into user config are surgical (marked markdown sections, JSON/TOML upserts), so user-owned content is never touched.
|
|
59
|
+
Every command supports `--dry-run`, `--yes`, and `--target-dir <dir>` for testing without touching the real config. Writes create automatic backups and verify idempotency; merges into user config are surgical (marked markdown sections, JSON/TOML upserts), so user-owned content is never touched. `--yes` does not authorize downloading missing Engram; use `--engram` for that explicit consent. The interactive install asks before installing it, while dry-run and target-dir never download it.
|
|
60
60
|
|
|
61
61
|
Runtime defaults are documented in [docs/references/permissions.md](docs/references/permissions.md) for permissions and [docs/references/models.md](docs/references/models.md) for the Sol primary default, field-level ownership and independent subagent routing. The quality policy and `jorgex.quality.receipt` contract are documented in [docs/references/quality-receipt.md](docs/references/quality-receipt.md). OpenCode remains provider-agnostic for subagents; its primary defaults to the OpenAI OAuth model `openai/gpt-5.6-sol` unless the user replaces it.
|
|
62
62
|
|
|
@@ -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
|
|
|
@@ -132,7 +132,7 @@ Install, sync and uninstall back up every managed file before changing it and ar
|
|
|
132
132
|
|
|
133
133
|
The package owns Pi's native primary-model projection: `openai-codex/gpt-5.6-sol`, with a local `contextWindow` request of 872K. It merges only missing compatible fields, records field ownership in `PI_CODING_AGENT_DIR/jorgex-pi/sol-lifecycle.v1.json`, and cleanup removes only still-owned canonical values. Stack does not duplicate that package-owned settings/models logic. The 872K value is local OAuth metadata until a real long-context smoke test confirms backend acceptance; it is not the API context limit.
|
|
134
134
|
|
|
135
|
-
Engram remains mandatory and user-owned. An existing binary is preserved.
|
|
135
|
+
Engram remains mandatory and user-owned. An existing binary is preserved. `install` resolves or installs the verified official v1.20.0 release before configuring any selected runtime; use `--engram` to authorize that download in non-interactive flows. The release installer writes only `~/.local/bin/engram` (or the platform equivalent), checks the pinned size and SHA-256, and does not use Brew or Go. `sync`, dry-run and `--target-dir` never download it. The database and memories are never updated or deleted, and uninstall never deletes the Engram binary. Under `--target-dir`, Stack accepts only `<target>/bin/engram`, isolates Pi/Home/XDG/AppData/temp/npm-cache paths inside the target, and never consults the host Engram or Pi configuration.
|
|
136
136
|
|
|
137
137
|
Históricamente, Stack `1.9.7` reconocía el receipt exacto de Pi `npm:jorgex-pi@0.8.4`. Usa versiones exactas, nunca `latest`, y no edites receipts o hashes ni borres `HOME`, Engram o la proyección de otro runtime para forzar confianza. El pin y los comandos actuales de transición y rollback están en [docs/references/pi-runtime.md](docs/references/pi-runtime.md).
|
|
138
138
|
|
|
@@ -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.d.ts
CHANGED
package/dist/cli.js
CHANGED
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
|
|
16
16
|
// src/cli.ts
|
|
17
17
|
import * as p6 from "@clack/prompts";
|
|
18
|
-
import
|
|
18
|
+
import fs25 from "fs";
|
|
19
19
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
20
20
|
|
|
21
21
|
// src/install.ts
|
|
@@ -2154,7 +2154,7 @@ var PLAYWRIGHT_CLI = {
|
|
|
2154
2154
|
version: "0.1.18",
|
|
2155
2155
|
browserInstallAction: "install-browser"
|
|
2156
2156
|
};
|
|
2157
|
-
var PNPM_GLOBAL_BIN_REMEDY = "Ejecuta 'pnpm setup', abre una terminal nueva y reintenta.
|
|
2157
|
+
var PNPM_GLOBAL_BIN_REMEDY = "Ejecuta 'pnpm setup', abre una terminal nueva y reintenta. Sin consentimiento, el stack no modifica la configuraci\xF3n de la shell.";
|
|
2158
2158
|
function resolvePnpmFailureRemedy(reason) {
|
|
2159
2159
|
switch (reason) {
|
|
2160
2160
|
case "pnpm-unavailable":
|
|
@@ -2197,6 +2197,34 @@ function resolvePnpmBin() {
|
|
|
2197
2197
|
const pnpmCmd = lookPath("pnpm.cmd");
|
|
2198
2198
|
return pnpmCmd !== null && !pnpmCmd.toLowerCase().endsWith(".ps1") ? pnpmCmd : null;
|
|
2199
2199
|
}
|
|
2200
|
+
function resolvePnpmHome(env = process.env, platform = process.platform, homeDir = os.homedir()) {
|
|
2201
|
+
const paths = platform === "win32" ? path18.win32 : path18.posix;
|
|
2202
|
+
if (env.PNPM_HOME) return env.PNPM_HOME;
|
|
2203
|
+
if (env.XDG_DATA_HOME) return paths.join(env.XDG_DATA_HOME, "pnpm");
|
|
2204
|
+
if (platform === "darwin") return paths.join(homeDir, "Library", "pnpm");
|
|
2205
|
+
if (platform === "win32") return env.LOCALAPPDATA ? paths.join(env.LOCALAPPDATA, "pnpm") : paths.join(homeDir, ".pnpm");
|
|
2206
|
+
return paths.join(homeDir, ".local", "share", "pnpm");
|
|
2207
|
+
}
|
|
2208
|
+
function setupPnpmGlobal(pnpmBin, env = process.env, platform = process.platform, homeDir = os.homedir()) {
|
|
2209
|
+
const pnpmHome = resolvePnpmHome(env, platform, homeDir);
|
|
2210
|
+
const paths = platform === "win32" ? path18.win32 : path18.posix;
|
|
2211
|
+
if (!paths.isAbsolute(pnpmHome)) return { ok: false, reason: "PNPM_HOME debe ser una ruta absoluta; corrige la configuraci\xF3n antes de reintentar." };
|
|
2212
|
+
const pathEntries = [pnpmHome, paths.join(pnpmHome, "bin")];
|
|
2213
|
+
if (env.PATH !== void 0) pathEntries.push(env.PATH);
|
|
2214
|
+
const childEnv = {
|
|
2215
|
+
...env,
|
|
2216
|
+
PNPM_HOME: pnpmHome,
|
|
2217
|
+
PATH: pathEntries.join(platform === "win32" ? ";" : ":")
|
|
2218
|
+
};
|
|
2219
|
+
const invocation = planDetectedBinCommand(pnpmBin, ["setup"]);
|
|
2220
|
+
if (invocation === null) return { ok: false, reason: "No se pudo preparar la invocaci\xF3n de pnpm setup." };
|
|
2221
|
+
try {
|
|
2222
|
+
execFileSync2(invocation.command, invocation.args, { stdio: "inherit", env: childEnv });
|
|
2223
|
+
return { ok: true, env: childEnv };
|
|
2224
|
+
} catch (error) {
|
|
2225
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2200
2228
|
function isPlaywrightBrowserReady(env = process.env, platform = process.platform, homeDir = os.homedir()) {
|
|
2201
2229
|
const configuredPath = env.PLAYWRIGHT_BROWSERS_PATH;
|
|
2202
2230
|
const cacheDir = configuredPath ?? (platform === "win32" ? path18.join(env.LOCALAPPDATA ?? path18.join(homeDir, "AppData", "Local"), "ms-playwright") : platform === "darwin" ? path18.join(homeDir, "Library", "Caches", "ms-playwright") : path18.join(env.XDG_CACHE_HOME ?? path18.join(homeDir, ".cache"), "ms-playwright"));
|
|
@@ -2223,13 +2251,16 @@ function planPlaywrightCliCommand(action, pnpmBin) {
|
|
|
2223
2251
|
return { command: pnpmBin, args: ["dlx", pinnedPackage, PLAYWRIGHT_CLI.browserInstallAction] };
|
|
2224
2252
|
}
|
|
2225
2253
|
}
|
|
2226
|
-
function executePlaywrightToolAction(action, pnpmBin = resolvePnpmBin()) {
|
|
2254
|
+
function executePlaywrightToolAction(action, pnpmBin = resolvePnpmBin(), env) {
|
|
2227
2255
|
if (pnpmBin === null) return { ok: false, reason: "pnpm-unavailable" };
|
|
2228
2256
|
if (action !== "install-browser") {
|
|
2229
2257
|
const preflight = planDetectedBinCommand(pnpmBin, ["bin", "--global"]);
|
|
2230
2258
|
if (preflight === null) return { ok: false, reason: "pnpm-command" };
|
|
2231
2259
|
try {
|
|
2232
|
-
execFileSync2(preflight.command, preflight.args, {
|
|
2260
|
+
execFileSync2(preflight.command, preflight.args, {
|
|
2261
|
+
stdio: "inherit",
|
|
2262
|
+
...env === void 0 ? {} : { env }
|
|
2263
|
+
});
|
|
2233
2264
|
} catch (error) {
|
|
2234
2265
|
return { ok: false, reason: hasNonzeroProcessStatus(error) ? "pnpm-global-bin" : "pnpm-command" };
|
|
2235
2266
|
}
|
|
@@ -2238,7 +2269,10 @@ function executePlaywrightToolAction(action, pnpmBin = resolvePnpmBin()) {
|
|
|
2238
2269
|
const invocation = planDetectedBinCommand(command.command, command.args);
|
|
2239
2270
|
if (invocation === null) return { ok: false, reason: "pnpm-command" };
|
|
2240
2271
|
try {
|
|
2241
|
-
execFileSync2(invocation.command, invocation.args, {
|
|
2272
|
+
execFileSync2(invocation.command, invocation.args, {
|
|
2273
|
+
stdio: "inherit",
|
|
2274
|
+
...env === void 0 ? {} : { env }
|
|
2275
|
+
});
|
|
2242
2276
|
return { ok: true };
|
|
2243
2277
|
} catch {
|
|
2244
2278
|
return { ok: false, reason: "action-failed" };
|
|
@@ -2307,7 +2341,7 @@ function parseDevtoolsMcpState(raw) {
|
|
|
2307
2341
|
if (!isRecord2(value) || value.version !== DEVTOOLS_MCP_PREFERENCE_VERSION || !isRecord2(value.enabled) || !isRecord2(value.owned)) return null;
|
|
2308
2342
|
const enabled = {};
|
|
2309
2343
|
for (const [runtime, selected] of Object.entries(value.enabled)) {
|
|
2310
|
-
if (!isRuntimeId(runtime) || typeof selected !== "boolean") return null;
|
|
2344
|
+
if (!isRuntimeId(runtime) && runtime !== "pi" || typeof selected !== "boolean") return null;
|
|
2311
2345
|
enabled[runtime] = selected;
|
|
2312
2346
|
}
|
|
2313
2347
|
const owned = {};
|
|
@@ -2439,8 +2473,8 @@ var ADAPTERS = {
|
|
|
2439
2473
|
"claude-code": claudeCodeAdapter,
|
|
2440
2474
|
codex: codexAdapter
|
|
2441
2475
|
};
|
|
2442
|
-
function executePlaywrightToolAction2(action) {
|
|
2443
|
-
return executePlaywrightToolAction(action,
|
|
2476
|
+
function executePlaywrightToolAction2(action, pnpmBin = resolvePnpmBin(), env) {
|
|
2477
|
+
return executePlaywrightToolAction(action, pnpmBin, env);
|
|
2444
2478
|
}
|
|
2445
2479
|
function resolvePlaywrightToolPlan(consent) {
|
|
2446
2480
|
if (consent.command !== "install" || consent.targetDir) return { actions: [] };
|
|
@@ -2560,15 +2594,16 @@ function collectAllCurrentTargets(mode = DEFAULT_INSTALL_MODE_PREFERENCE) {
|
|
|
2560
2594
|
return { targets, complete, warnings };
|
|
2561
2595
|
}
|
|
2562
2596
|
async function runInstall(opts) {
|
|
2563
|
-
|
|
2597
|
+
const showSummary = opts.showSummary !== false;
|
|
2598
|
+
if (showSummary) p.intro(`jorgex-stack ${opts.dryRun ? "install (dry-run)" : "install"}`);
|
|
2564
2599
|
const stackDir = stackRoot();
|
|
2565
|
-
const engramBin = detectEngram();
|
|
2600
|
+
const engramBin = opts.engramBin === void 0 ? detectEngram() : opts.engramBin;
|
|
2566
2601
|
const modePreference = opts.mode === void 0 ? opts.targetDir === void 0 ? loadInstallModePreference() : DEFAULT_INSTALL_MODE_PREFERENCE : normalizeInstallModePreference(opts.mode);
|
|
2567
2602
|
const useManifest = opts.targetDir === void 0;
|
|
2568
2603
|
const preferenceErrors = useManifest ? [...browserPreferenceErrors(), primaryModelOwnershipError()].filter((error) => error !== null) : [];
|
|
2569
2604
|
if (preferenceErrors.length > 0) {
|
|
2570
2605
|
for (const error of preferenceErrors) p.log.error(error);
|
|
2571
|
-
p.outro("Install cancelado: corrige el estado de configuraci\xF3n indicado arriba antes de reintentar.");
|
|
2606
|
+
if (showSummary) p.outro("Install cancelado: corrige el estado de configuraci\xF3n indicado arriba antes de reintentar.");
|
|
2572
2607
|
return 1;
|
|
2573
2608
|
}
|
|
2574
2609
|
const toolPlan = opts.playwrightToolConsent === void 0 ? null : resolvePlaywrightToolPlan({
|
|
@@ -2708,9 +2743,41 @@ async function runInstall(opts) {
|
|
|
2708
2743
|
if (opts.dryRun) {
|
|
2709
2744
|
p.log.info("Playwright CLI: instalaci\xF3n global y navegador previstos (dry-run; no se ejecutan).");
|
|
2710
2745
|
} else if (exitCode === 0) {
|
|
2711
|
-
const
|
|
2712
|
-
run: async (action) =>
|
|
2713
|
-
|
|
2746
|
+
const baseDeps = opts.playwrightToolDeps ?? {
|
|
2747
|
+
run: async (action, env) => {
|
|
2748
|
+
const pnpmBin = resolvePnpmBin();
|
|
2749
|
+
return executePlaywrightToolAction2(action, pnpmBin, env);
|
|
2750
|
+
},
|
|
2751
|
+
persistEnabled: (enabled) => savePlaywrightCliPreference(playwrightCliPreferenceFile(), enabled),
|
|
2752
|
+
setupPnpm: (pnpmBin) => setupPnpmGlobal(pnpmBin)
|
|
2753
|
+
};
|
|
2754
|
+
let setupAttempted = false;
|
|
2755
|
+
let preparedEnv;
|
|
2756
|
+
const result = await runPlaywrightToolPlan(toolPlan, {
|
|
2757
|
+
...baseDeps,
|
|
2758
|
+
run: async (action) => {
|
|
2759
|
+
const first = await baseDeps.run(action, preparedEnv);
|
|
2760
|
+
if (first === true || first === false || first.ok || first.reason !== "pnpm-global-bin") return first;
|
|
2761
|
+
if (setupAttempted || opts.dryRun || opts.targetDir !== void 0) return first;
|
|
2762
|
+
const consent = opts.playwrightToolConsent;
|
|
2763
|
+
const canAskForSetup = consent?.interactive === true && !opts.yes;
|
|
2764
|
+
if (!canAskForSetup) return first;
|
|
2765
|
+
setupAttempted = true;
|
|
2766
|
+
const accepted = await p.confirm({
|
|
2767
|
+
message: "pnpm no tiene directorio global. \xBFEjecutar 'pnpm setup' ahora? Esto modificar\xE1 la configuraci\xF3n de tu shell.",
|
|
2768
|
+
initialValue: false
|
|
2769
|
+
});
|
|
2770
|
+
if (p.isCancel(accepted) || !accepted) return first;
|
|
2771
|
+
const pnpmBin = resolvePnpmBin();
|
|
2772
|
+
if (pnpmBin === null) return first;
|
|
2773
|
+
const setup = baseDeps.setupPnpm?.(pnpmBin) ?? setupPnpmGlobal(pnpmBin);
|
|
2774
|
+
if (!setup.ok) {
|
|
2775
|
+
p.log.error(`pnpm setup fall\xF3: ${setup.reason}`);
|
|
2776
|
+
return first;
|
|
2777
|
+
}
|
|
2778
|
+
preparedEnv = setup.env;
|
|
2779
|
+
return baseDeps.run(action, preparedEnv);
|
|
2780
|
+
}
|
|
2714
2781
|
});
|
|
2715
2782
|
if (!result.ok) {
|
|
2716
2783
|
const pnpmRemedy = result.reason === void 0 ? null : resolvePnpmFailureRemedy(result.reason);
|
|
@@ -2763,7 +2830,9 @@ async function runInstall(opts) {
|
|
|
2763
2830
|
if (useManifest && !opts.dryRun && exitCode === 0 && successfulRuns > 0) {
|
|
2764
2831
|
saveInstallModePreference(installModePreferenceFile(), modePreference);
|
|
2765
2832
|
}
|
|
2766
|
-
|
|
2833
|
+
if (showSummary) {
|
|
2834
|
+
p.outro(opts.dryRun ? exitCode === 0 ? "Dry-run: no se ha escrito nada." : "Dry-run completado con errores (revisa arriba)." : exitCode === 0 ? "Hecho." : "Install completado con errores (revisa arriba).");
|
|
2835
|
+
}
|
|
2767
2836
|
return exitCode;
|
|
2768
2837
|
}
|
|
2769
2838
|
|
|
@@ -2775,6 +2844,7 @@ import * as p2 from "@clack/prompts";
|
|
|
2775
2844
|
// src/lib/pi-projection-lifecycle.ts
|
|
2776
2845
|
import fs16 from "fs";
|
|
2777
2846
|
import path23 from "path";
|
|
2847
|
+
import { createHash } from "crypto";
|
|
2778
2848
|
|
|
2779
2849
|
// src/adapters/pi.ts
|
|
2780
2850
|
import path21 from "path";
|
|
@@ -3238,14 +3308,33 @@ function projectionPlan(input, scope) {
|
|
|
3238
3308
|
engramBin: input.engramBin,
|
|
3239
3309
|
models: DEFAULT_MODEL_MAP.codex,
|
|
3240
3310
|
warnings: [],
|
|
3241
|
-
playwrightCliEnabled: input.playwrightCliEnabled
|
|
3311
|
+
playwrightCliEnabled: input.playwrightCliEnabled,
|
|
3312
|
+
enabledMcpServers: input.devtoolsMcpEnabled ? /* @__PURE__ */ new Set([DEVTOOLS_MCP_SERVER]) : void 0
|
|
3242
3313
|
};
|
|
3243
3314
|
const adapter = projectedPiAdapter(scope);
|
|
3244
|
-
|
|
3315
|
+
const actions = [
|
|
3245
3316
|
...planSystemPrompt(adapter, ctx),
|
|
3246
3317
|
...planSkills(adapter, ctx),
|
|
3247
3318
|
...planCommands(adapter, ctx)
|
|
3248
3319
|
];
|
|
3320
|
+
if (input.devtoolsMcpEnabled && input.pnpmBin) {
|
|
3321
|
+
const server = loadCanonicalMcp(input.stackDir).servers[DEVTOOLS_MCP_SERVER];
|
|
3322
|
+
if (server?.transport !== "stdio" || !Array.isArray(server.args)) throw new Error("Falta la configuraci\xF3n can\xF3nica de DevTools.");
|
|
3323
|
+
actions.push({ kind: "write", target: devtoolsPath(scope), content: `${JSON.stringify({
|
|
3324
|
+
schemaVersion: 1,
|
|
3325
|
+
enabled: true,
|
|
3326
|
+
command: input.pnpmBin,
|
|
3327
|
+
args: server.args
|
|
3328
|
+
}, null, 2)}
|
|
3329
|
+
` });
|
|
3330
|
+
}
|
|
3331
|
+
return actions;
|
|
3332
|
+
}
|
|
3333
|
+
function devtoolsPath(scope) {
|
|
3334
|
+
return path23.resolve(scope.codingAgentDir, "jorgex-pi", "devtools.v1.json");
|
|
3335
|
+
}
|
|
3336
|
+
function contentHash(content) {
|
|
3337
|
+
return createHash("sha256").update(content).digest("hex");
|
|
3249
3338
|
}
|
|
3250
3339
|
function canonicalActionContent(action) {
|
|
3251
3340
|
return action.kind === "write" ? action.content : fs16.readFileSync(action.source, "utf8");
|
|
@@ -3253,8 +3342,15 @@ function canonicalActionContent(action) {
|
|
|
3253
3342
|
function hasActionDrift(action, deps) {
|
|
3254
3343
|
return deps.readText(action.target) !== canonicalActionContent(action);
|
|
3255
3344
|
}
|
|
3256
|
-
function applyActions(actions, deps) {
|
|
3345
|
+
function applyActions(actions, deps, handoff) {
|
|
3257
3346
|
for (const action of actions) {
|
|
3347
|
+
if (handoff && path23.resolve(action.target) === handoff.file) {
|
|
3348
|
+
try {
|
|
3349
|
+
if (deps.readText(handoff.file) !== handoff.previous) return devtoolsConflict(handoff.file);
|
|
3350
|
+
} catch {
|
|
3351
|
+
return devtoolsConflict(handoff.file);
|
|
3352
|
+
}
|
|
3353
|
+
}
|
|
3258
3354
|
if (action.kind === "write") deps.writeText(action.target, action.content);
|
|
3259
3355
|
else deps.copyFile(action.source, action.target);
|
|
3260
3356
|
}
|
|
@@ -3271,6 +3367,7 @@ function receiptFor(plan, scope) {
|
|
|
3271
3367
|
const owned = [...new Set(
|
|
3272
3368
|
plan.map((action) => path23.resolve(action.target)).filter((target) => target !== systemPrompt)
|
|
3273
3369
|
)];
|
|
3370
|
+
const handoff = plan.find((action) => path23.resolve(action.target) === devtoolsPath(scope));
|
|
3274
3371
|
return {
|
|
3275
3372
|
schemaVersion: 1,
|
|
3276
3373
|
scope: {
|
|
@@ -3279,7 +3376,8 @@ function receiptFor(plan, scope) {
|
|
|
3279
3376
|
codingAgentDir: scope.codingAgentDir,
|
|
3280
3377
|
receiptFile: scope.receiptFile
|
|
3281
3378
|
},
|
|
3282
|
-
owned
|
|
3379
|
+
owned,
|
|
3380
|
+
...handoff ? { devtools: { sha256: contentHash(canonicalActionContent(handoff)) } } : {}
|
|
3283
3381
|
};
|
|
3284
3382
|
}
|
|
3285
3383
|
function receiptContent(receipt) {
|
|
@@ -3298,16 +3396,25 @@ function parseReceipt2(raw, expected) {
|
|
|
3298
3396
|
const version = Reflect.get(receipt, "schemaVersion");
|
|
3299
3397
|
const receivedScope = Reflect.get(receipt, "scope");
|
|
3300
3398
|
const owned = Reflect.get(receipt, "owned");
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
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) {
|
|
3399
|
+
const devtools = Reflect.get(receipt, "devtools");
|
|
3400
|
+
const hasDevtools = Object.hasOwn(receipt, "devtools");
|
|
3401
|
+
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"])) {
|
|
3305
3402
|
return null;
|
|
3306
3403
|
}
|
|
3307
|
-
if (
|
|
3404
|
+
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)) {
|
|
3308
3405
|
return null;
|
|
3309
3406
|
}
|
|
3310
|
-
return
|
|
3407
|
+
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;
|
|
3408
|
+
const handoff = devtoolsPath(expected.scope);
|
|
3409
|
+
const expectedOwned = expected.owned.filter((file) => file !== handoff);
|
|
3410
|
+
if (hasDevtools) expectedOwned.push(handoff);
|
|
3411
|
+
if (owned.length !== expectedOwned.length || !owned.every((file, index) => typeof file === "string" && file === expectedOwned[index])) return null;
|
|
3412
|
+
return {
|
|
3413
|
+
schemaVersion: 1,
|
|
3414
|
+
scope: expected.scope,
|
|
3415
|
+
owned: expectedOwned,
|
|
3416
|
+
...hasDevtools ? { devtools: { sha256: Reflect.get(devtools, "sha256") } } : {}
|
|
3417
|
+
};
|
|
3311
3418
|
} catch {
|
|
3312
3419
|
return null;
|
|
3313
3420
|
}
|
|
@@ -3433,6 +3540,35 @@ function readProjectionReceipt(receiptFile, deps) {
|
|
|
3433
3540
|
return { kind: "unreadable" };
|
|
3434
3541
|
}
|
|
3435
3542
|
}
|
|
3543
|
+
function devtoolsConflict(file) {
|
|
3544
|
+
return blocked2(
|
|
3545
|
+
"projection-devtools-conflict",
|
|
3546
|
+
[file],
|
|
3547
|
+
"El handoff de DevTools es ajeno o fue modificado. Cons\xE9rvalo y revisa su propiedad antes de reintentar; Stack no lo sobrescribe ni elimina."
|
|
3548
|
+
);
|
|
3549
|
+
}
|
|
3550
|
+
function inspectDevtools(input, scope, expected, deps) {
|
|
3551
|
+
const file = devtoolsPath(scope);
|
|
3552
|
+
const read = readProjectionReceipt(scope.receiptFile, deps);
|
|
3553
|
+
if (read.kind === "unreadable") return receiptUnreadable(scope.receiptFile);
|
|
3554
|
+
const previous = read.kind === "present" ? parseReceipt2(read.content, expected) : null;
|
|
3555
|
+
let content;
|
|
3556
|
+
try {
|
|
3557
|
+
content = deps.readText(file);
|
|
3558
|
+
} catch {
|
|
3559
|
+
return devtoolsConflict(file);
|
|
3560
|
+
}
|
|
3561
|
+
let recordedDevtools = false;
|
|
3562
|
+
if (read.kind === "present") {
|
|
3563
|
+
try {
|
|
3564
|
+
recordedDevtools = Object.hasOwn(JSON.parse(read.content), "devtools");
|
|
3565
|
+
} catch {
|
|
3566
|
+
}
|
|
3567
|
+
if (!previous && (input.devtoolsMcpEnabled || content !== null || recordedDevtools)) return receiptInvalid(scope.receiptFile);
|
|
3568
|
+
}
|
|
3569
|
+
if (content !== null && (!previous?.devtools || contentHash(content) !== previous.devtools.sha256)) return devtoolsConflict(file);
|
|
3570
|
+
return { kind: "checked", previous, content };
|
|
3571
|
+
}
|
|
3436
3572
|
function preparePiProjectionUninstall(input, deps) {
|
|
3437
3573
|
if (input.operation !== "uninstall") {
|
|
3438
3574
|
return cleanupFailure([]);
|
|
@@ -3451,11 +3587,13 @@ function preparePiProjectionUninstall(input, deps) {
|
|
|
3451
3587
|
const receiptRead = readProjectionReceipt(scope.receiptFile, deps);
|
|
3452
3588
|
if (receiptRead.kind === "unreadable") return receiptUnreadable(scope.receiptFile);
|
|
3453
3589
|
let ownedToRemove = [];
|
|
3590
|
+
let ownedReceipt = null;
|
|
3454
3591
|
let receiptFile = null;
|
|
3455
3592
|
let backupTargets = promptUpdate === null ? [] : [promptUpdate.file];
|
|
3456
3593
|
if (receiptRead.kind === "present") {
|
|
3457
3594
|
const receipt = parseReceipt2(receiptRead.content, expectedReceipt2);
|
|
3458
3595
|
if (receipt === null) return receiptInvalid(scope.receiptFile);
|
|
3596
|
+
ownedReceipt = receipt;
|
|
3459
3597
|
let retained;
|
|
3460
3598
|
try {
|
|
3461
3599
|
retained = manifestOwned(deps.readManifest());
|
|
@@ -3466,13 +3604,22 @@ function preparePiProjectionUninstall(input, deps) {
|
|
|
3466
3604
|
receiptFile = path23.resolve(scope.receiptFile);
|
|
3467
3605
|
backupTargets = [...backupTargets, ...receipt.owned, receiptFile];
|
|
3468
3606
|
}
|
|
3607
|
+
const handoff = devtoolsPath(scope);
|
|
3608
|
+
let handoffContent;
|
|
3609
|
+
try {
|
|
3610
|
+
handoffContent = deps.readText(handoff);
|
|
3611
|
+
} catch {
|
|
3612
|
+
return devtoolsConflict(handoff);
|
|
3613
|
+
}
|
|
3614
|
+
if (handoffContent !== null && (!ownedReceipt?.devtools || contentHash(handoffContent) !== ownedReceipt.devtools.sha256)) return devtoolsConflict(handoff);
|
|
3469
3615
|
const backup = backupExisting(backupTargets, deps);
|
|
3470
3616
|
if (backup.kind === "backup-failed") return backupFailure(backup.paths);
|
|
3471
3617
|
const token = {};
|
|
3472
3618
|
preparedPiProjectionUninstalls.set(token, {
|
|
3473
3619
|
prompt: promptUpdate,
|
|
3474
3620
|
ownedToRemove,
|
|
3475
|
-
receiptFile
|
|
3621
|
+
receiptFile,
|
|
3622
|
+
...ownedReceipt?.devtools ? { devtools: { file: handoff, sha256: ownedReceipt.devtools.sha256 } } : {}
|
|
3476
3623
|
});
|
|
3477
3624
|
return { kind: "prepared", plan: token };
|
|
3478
3625
|
}
|
|
@@ -3484,6 +3631,15 @@ function completePiProjectionUninstall(plan, deps) {
|
|
|
3484
3631
|
if (prepared === void 0) {
|
|
3485
3632
|
return cleanupFailure([]);
|
|
3486
3633
|
}
|
|
3634
|
+
if (prepared.devtools) {
|
|
3635
|
+
let current;
|
|
3636
|
+
try {
|
|
3637
|
+
current = deps.readText(prepared.devtools.file);
|
|
3638
|
+
} catch {
|
|
3639
|
+
return devtoolsConflict(prepared.devtools.file);
|
|
3640
|
+
}
|
|
3641
|
+
if (current !== null && contentHash(current) !== prepared.devtools.sha256) return devtoolsConflict(prepared.devtools.file);
|
|
3642
|
+
}
|
|
3487
3643
|
if (prepared.prompt !== null) {
|
|
3488
3644
|
try {
|
|
3489
3645
|
deps.writeText(prepared.prompt.file, prepared.prompt.content);
|
|
@@ -3493,6 +3649,10 @@ function completePiProjectionUninstall(plan, deps) {
|
|
|
3493
3649
|
}
|
|
3494
3650
|
for (const owned of prepared.ownedToRemove) {
|
|
3495
3651
|
try {
|
|
3652
|
+
if (prepared.devtools?.file === owned) {
|
|
3653
|
+
const current = deps.readText(owned);
|
|
3654
|
+
if (current !== null && contentHash(current) !== prepared.devtools.sha256) return devtoolsConflict(owned);
|
|
3655
|
+
}
|
|
3496
3656
|
deps.removeFile(owned);
|
|
3497
3657
|
} catch {
|
|
3498
3658
|
return cleanupFailure([owned]);
|
|
@@ -3513,13 +3673,23 @@ function runPiProjectionLifecycle(input, deps) {
|
|
|
3513
3673
|
const prepared = preparePiProjectionUninstall(input, deps);
|
|
3514
3674
|
return prepared.kind === "blocked" ? prepared : completePiProjectionUninstall(prepared.plan, deps);
|
|
3515
3675
|
}
|
|
3676
|
+
if (input.devtoolsMcpEnabled && (!input.pnpmBin || !path23.isAbsolute(input.pnpmBin))) {
|
|
3677
|
+
return blocked2("projection-devtools-command", [devtoolsPath(scope)], "DevTools requiere un ejecutable pnpm absoluto disponible en PATH.");
|
|
3678
|
+
}
|
|
3516
3679
|
const plan = projectionPlan(input, scope);
|
|
3517
3680
|
assertPlanContained(plan, scope);
|
|
3518
3681
|
const receipt = receiptFor(plan, scope);
|
|
3682
|
+
const devtools = inspectDevtools(input, scope, receipt, deps);
|
|
3683
|
+
if (devtools.kind === "blocked") return input.operation === "doctor" ? { kind: "drift", paths: devtools.paths } : devtools;
|
|
3684
|
+
const removeHandoff = !input.devtoolsMcpEnabled && devtools.previous?.devtools !== void 0 && devtools.content !== null;
|
|
3519
3685
|
const expectedReceipt2 = receiptContent(receipt);
|
|
3520
3686
|
const drifted = plan.filter((action) => hasActionDrift(action, deps));
|
|
3687
|
+
if (input.devtoolsMcpEnabled && devtools.previous?.devtools?.sha256 !== receipt.devtools?.sha256 && !drifted.some((action) => path23.resolve(action.target) === devtoolsPath(scope))) {
|
|
3688
|
+
return input.operation === "doctor" ? { kind: "drift", paths: [devtoolsPath(scope)] } : devtoolsConflict(devtoolsPath(scope));
|
|
3689
|
+
}
|
|
3521
3690
|
if (input.operation === "doctor") {
|
|
3522
3691
|
const paths = drifted.map((action) => path23.resolve(action.target));
|
|
3692
|
+
if (removeHandoff) paths.push(devtoolsPath(scope));
|
|
3523
3693
|
const currentSettings2 = deps.readText(scope.settingsFile);
|
|
3524
3694
|
if (currentSettings2 === null || filterProjectedPiPackage(currentSettings2, input.packageSource) !== currentSettings2) {
|
|
3525
3695
|
paths.push(scope.settingsFile);
|
|
@@ -3535,19 +3705,30 @@ function runPiProjectionLifecycle(input, deps) {
|
|
|
3535
3705
|
}
|
|
3536
3706
|
const packageWillChange = filteredSettings !== null && filteredSettings !== currentSettings;
|
|
3537
3707
|
const receiptChanged = deps.readText(scope.receiptFile) !== expectedReceipt2;
|
|
3538
|
-
if (drifted.length > 0 || packageWillChange || receiptChanged) {
|
|
3708
|
+
if (drifted.length > 0 || packageWillChange || receiptChanged || removeHandoff) {
|
|
3539
3709
|
const backup = backupExisting([
|
|
3540
3710
|
...drifted.map((action) => action.target),
|
|
3711
|
+
...removeHandoff ? [devtoolsPath(scope)] : [],
|
|
3541
3712
|
...packageWillChange ? [scope.settingsFile] : [],
|
|
3542
3713
|
...receiptChanged ? [scope.receiptFile] : []
|
|
3543
3714
|
], deps);
|
|
3544
3715
|
if (backup.kind === "backup-failed") return backupFailure(backup.paths);
|
|
3545
3716
|
}
|
|
3546
|
-
|
|
3717
|
+
if (removeHandoff) {
|
|
3718
|
+
try {
|
|
3719
|
+
const current = deps.readText(devtoolsPath(scope));
|
|
3720
|
+
if (current !== null && contentHash(current) !== devtools.previous?.devtools?.sha256) return devtoolsConflict(devtoolsPath(scope));
|
|
3721
|
+
deps.removeFile(devtoolsPath(scope));
|
|
3722
|
+
} catch {
|
|
3723
|
+
return cleanupFailure([devtoolsPath(scope)]);
|
|
3724
|
+
}
|
|
3725
|
+
}
|
|
3726
|
+
const writeResult = applyActions(drifted, deps, input.devtoolsMcpEnabled ? { file: devtoolsPath(scope), previous: devtools.content } : void 0);
|
|
3727
|
+
if (writeResult) return writeResult;
|
|
3547
3728
|
if (packageWillChange && filteredSettings !== null) deps.writeText(scope.settingsFile, filteredSettings);
|
|
3548
3729
|
if (receiptChanged) deps.writeText(scope.receiptFile, expectedReceipt2);
|
|
3549
3730
|
if (input.operation === "install") return { kind: "installed", receipt };
|
|
3550
|
-
return { kind: "synced", changed: drifted.length > 0 || packageWillChange || receiptChanged };
|
|
3731
|
+
return { kind: "synced", changed: drifted.length > 0 || packageWillChange || receiptChanged || removeHandoff };
|
|
3551
3732
|
}
|
|
3552
3733
|
function systemProjectionLifecycle(input) {
|
|
3553
3734
|
const targetRoot = input.targetDir === void 0 ? null : path23.resolve(input.targetDir);
|
|
@@ -3564,7 +3745,9 @@ function systemProjectionLifecycle(input) {
|
|
|
3564
3745
|
packageSource: input.packageSource,
|
|
3565
3746
|
stackDir: stackRoot(),
|
|
3566
3747
|
engramBin: input.engramBin ?? "",
|
|
3567
|
-
playwrightCliEnabled: input.playwrightCliEnabled
|
|
3748
|
+
playwrightCliEnabled: input.playwrightCliEnabled,
|
|
3749
|
+
devtoolsMcpEnabled: input.devtoolsMcpEnabled,
|
|
3750
|
+
pnpmBin: input.pnpmBin
|
|
3568
3751
|
},
|
|
3569
3752
|
deps: {
|
|
3570
3753
|
readText: readTextOnlyIfMissing,
|
|
@@ -5149,22 +5332,22 @@ import os4 from "os";
|
|
|
5149
5332
|
import path31 from "path";
|
|
5150
5333
|
import fs23 from "fs";
|
|
5151
5334
|
import { spawnSync } from "child_process";
|
|
5152
|
-
import { createHash } from "crypto";
|
|
5335
|
+
import { createHash as createHash2 } from "crypto";
|
|
5153
5336
|
|
|
5154
5337
|
// src/lib/pi-runtime-pin.json
|
|
5155
5338
|
var pi_runtime_pin_default = {
|
|
5156
5339
|
package: {
|
|
5157
5340
|
name: "jorgex-pi",
|
|
5158
|
-
version: "0.8.
|
|
5159
|
-
source: "npm:jorgex-pi@0.8.
|
|
5341
|
+
version: "0.8.13",
|
|
5342
|
+
source: "npm:jorgex-pi@0.8.13"
|
|
5160
5343
|
},
|
|
5161
5344
|
provenance: {
|
|
5162
|
-
commit: "
|
|
5345
|
+
commit: "e28a677da0a112925251cf11269b70cb5c8aa15e"
|
|
5163
5346
|
},
|
|
5164
5347
|
tarball: {
|
|
5165
|
-
bytes:
|
|
5166
|
-
sha256: "
|
|
5167
|
-
sha512: "
|
|
5348
|
+
bytes: 89143404,
|
|
5349
|
+
sha256: "6bbe877249b900af582c8881e0dd7993951ea1cef6e7252522c626c078de7478",
|
|
5350
|
+
sha512: "bb527d1f3812406f2184f778b22cca00ead33692fecac0012cf8cdcdc469b7cccf3c789c35b4327dd599d06542162bd07eefeeaaa40de19662ec5fc422b14af8"
|
|
5168
5351
|
}
|
|
5169
5352
|
};
|
|
5170
5353
|
|
|
@@ -5186,6 +5369,7 @@ var PI_RUNTIME_CANDIDATE = {
|
|
|
5186
5369
|
"goal-continuation-v1",
|
|
5187
5370
|
"mcp-adapter-v1",
|
|
5188
5371
|
"engram-runtime-tools-v1",
|
|
5372
|
+
"chrome-devtools-handoff-v1",
|
|
5189
5373
|
"runner-json-v1",
|
|
5190
5374
|
"tui-branding-v1",
|
|
5191
5375
|
"managed-primary-model-v1",
|
|
@@ -5538,8 +5722,8 @@ function readOptional(file, fallback) {
|
|
|
5538
5722
|
}
|
|
5539
5723
|
function hashPiTarball(file) {
|
|
5540
5724
|
const descriptor = fs23.openSync(file, "r");
|
|
5541
|
-
const sha2562 =
|
|
5542
|
-
const sha512 =
|
|
5725
|
+
const sha2562 = createHash2("sha256");
|
|
5726
|
+
const sha512 = createHash2("sha512");
|
|
5543
5727
|
const buffer = Buffer.allocUnsafe(1024 * 1024);
|
|
5544
5728
|
let bytes = 0;
|
|
5545
5729
|
try {
|
|
@@ -5757,36 +5941,44 @@ function managedPackageResult(result) {
|
|
|
5757
5941
|
return result;
|
|
5758
5942
|
}
|
|
5759
5943
|
async function runManagedPiSystem(input) {
|
|
5944
|
+
const { devtoolsMcpEnabled: explicitDevtools, ...runtimeInput } = input;
|
|
5945
|
+
const devtoolsMcpEnabled = explicitDevtools ?? (input.targetDir === void 0 && loadDevtoolsMcpPreference(devtoolsMcpPreferenceFile(), "pi"));
|
|
5760
5946
|
const playwrightCliEnabled = input.targetDir === void 0 && loadPlaywrightCliPreference() === true;
|
|
5761
5947
|
const projectionInput = {
|
|
5762
5948
|
targetDir: input.targetDir,
|
|
5763
5949
|
packageSource: PI_RUNTIME_CANDIDATE.package.source,
|
|
5764
5950
|
engramBin: input.engramBin,
|
|
5765
|
-
playwrightCliEnabled
|
|
5951
|
+
playwrightCliEnabled,
|
|
5952
|
+
devtoolsMcpEnabled,
|
|
5953
|
+
pnpmBin: devtoolsMcpEnabled && input.operation !== "uninstall" ? resolvePnpmBin() : null
|
|
5766
5954
|
};
|
|
5767
|
-
|
|
5955
|
+
const result = await runManagedPiOperation(input.operation, {
|
|
5768
5956
|
async runPackage(operation) {
|
|
5769
|
-
return managedPackageResult(await runPiRuntimeSystem({ ...
|
|
5957
|
+
return managedPackageResult(await runPiRuntimeSystem({ ...runtimeInput, operation }));
|
|
5770
5958
|
},
|
|
5771
5959
|
runProjection(operation) {
|
|
5772
|
-
const
|
|
5960
|
+
const result2 = runPiProjectionLifecycleSystem({
|
|
5773
5961
|
operation,
|
|
5774
5962
|
...projectionInput
|
|
5775
5963
|
});
|
|
5776
|
-
return Promise.resolve(
|
|
5964
|
+
return Promise.resolve(result2.kind === "drift" ? {
|
|
5777
5965
|
kind: "drift",
|
|
5778
|
-
paths:
|
|
5966
|
+
paths: result2.paths,
|
|
5779
5967
|
remedy: "Ejecuta sync --agents pi para reparar la proyecci\xF3n de Pi."
|
|
5780
|
-
} :
|
|
5968
|
+
} : result2);
|
|
5781
5969
|
},
|
|
5782
5970
|
prepareProjectionUninstall() {
|
|
5783
|
-
const
|
|
5784
|
-
return Promise.resolve(
|
|
5971
|
+
const result2 = preparePiProjectionUninstallSystem({ operation: "uninstall", ...projectionInput });
|
|
5972
|
+
return Promise.resolve(result2.kind === "prepared" ? { kind: "prepared", token: result2.plan } : result2);
|
|
5785
5973
|
},
|
|
5786
5974
|
completeProjectionUninstall(token) {
|
|
5787
5975
|
return Promise.resolve(completePiProjectionUninstallSystem(token, { operation: "uninstall", ...projectionInput }));
|
|
5788
5976
|
}
|
|
5789
5977
|
});
|
|
5978
|
+
if (input.targetDir === void 0 && explicitDevtools !== void 0 && (input.operation === "install" || input.operation === "sync") && result.kind !== "blocked") {
|
|
5979
|
+
saveDevtoolsMcpPreference(devtoolsMcpPreferenceFile(), "pi", explicitDevtools);
|
|
5980
|
+
}
|
|
5981
|
+
return result;
|
|
5790
5982
|
}
|
|
5791
5983
|
|
|
5792
5984
|
// src/lib/quality-runner.ts
|
|
@@ -6167,6 +6359,112 @@ async function runQualityPlan(input) {
|
|
|
6167
6359
|
return { evaluation, receipt };
|
|
6168
6360
|
}
|
|
6169
6361
|
|
|
6362
|
+
// src/lib/engram-install.ts
|
|
6363
|
+
import fs24 from "fs";
|
|
6364
|
+
import os5 from "os";
|
|
6365
|
+
import path33 from "path";
|
|
6366
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
6367
|
+
import { createHash as createHash3 } from "crypto";
|
|
6368
|
+
|
|
6369
|
+
// src/lib/engram-release.json
|
|
6370
|
+
var engram_release_default = {
|
|
6371
|
+
assets: {
|
|
6372
|
+
darwin_arm64: {
|
|
6373
|
+
name: "engram_1.20.0_darwin_arm64.tar.gz",
|
|
6374
|
+
sha256: "2363d5012f23e58878f86c3ddcc1f63cfe9dcf3eec7f413e70eaafcbb9d394cc",
|
|
6375
|
+
size: 6949031
|
|
6376
|
+
},
|
|
6377
|
+
darwin_x64: {
|
|
6378
|
+
name: "engram_1.20.0_darwin_amd64.tar.gz",
|
|
6379
|
+
sha256: "3b9015dcfcdd9f823eb7ad0b590b1dbc4c25bb5d81dda3f84e623709815afe80",
|
|
6380
|
+
size: 7367005
|
|
6381
|
+
},
|
|
6382
|
+
linux_arm64: {
|
|
6383
|
+
name: "engram_1.20.0_linux_arm64.tar.gz",
|
|
6384
|
+
sha256: "7eb815910a76ae6cfa9a5d0161d3701e293dcca71f7743cffa62e236e5af59af",
|
|
6385
|
+
size: 6673857
|
|
6386
|
+
},
|
|
6387
|
+
linux_x64: {
|
|
6388
|
+
name: "engram_1.20.0_linux_amd64.tar.gz",
|
|
6389
|
+
sha256: "7dc3003318e303bee269a4772144f3ce01c8ec700bfd524aaec76770acd389ca",
|
|
6390
|
+
size: 7236400
|
|
6391
|
+
},
|
|
6392
|
+
windows_arm64: {
|
|
6393
|
+
name: "engram_1.20.0_windows_arm64.zip",
|
|
6394
|
+
sha256: "eb93c6d7d5a4020ddcf1ff956909f3e90694f6447519433316b10f964f8f37b5",
|
|
6395
|
+
size: 6723366
|
|
6396
|
+
},
|
|
6397
|
+
windows_x64: {
|
|
6398
|
+
name: "engram_1.20.0_windows_amd64.zip",
|
|
6399
|
+
sha256: "c945c47d58367f943642cb8451fa45f208174407839f1dda33a975a05d6e465b",
|
|
6400
|
+
size: 7416778
|
|
6401
|
+
}
|
|
6402
|
+
},
|
|
6403
|
+
version: "1.20.0"
|
|
6404
|
+
};
|
|
6405
|
+
|
|
6406
|
+
// src/lib/engram-install.ts
|
|
6407
|
+
async function installMissingEngram(options = {}) {
|
|
6408
|
+
const platform = options.platform ?? process.platform;
|
|
6409
|
+
const homeDir = options.homeDir ?? os5.homedir();
|
|
6410
|
+
if (!path33.isAbsolute(homeDir)) return { ok: false, reason: "El directorio personal debe ser absoluto." };
|
|
6411
|
+
const binaryName = platform === "win32" ? "engram.exe" : "engram";
|
|
6412
|
+
const bin = path33.join(homeDir, ".local", "bin", binaryName);
|
|
6413
|
+
let staging;
|
|
6414
|
+
try {
|
|
6415
|
+
const existing = fs24.lstatSync(bin, { throwIfNoEntry: false });
|
|
6416
|
+
if (existing) {
|
|
6417
|
+
if (!fs24.statSync(bin).isFile()) throw new Error(`El destino Engram no es un archivo: ${bin}`);
|
|
6418
|
+
fs24.accessSync(bin, platform === "win32" ? fs24.constants.F_OK : fs24.constants.X_OK);
|
|
6419
|
+
return { ok: true, bin };
|
|
6420
|
+
}
|
|
6421
|
+
const key = `${platform === "win32" ? "windows" : platform}_${options.arch ?? process.arch}`;
|
|
6422
|
+
const asset = engram_release_default.assets[key];
|
|
6423
|
+
if (!asset) throw new Error(`Engram no dispone de un binario aprobado para ${key}.`);
|
|
6424
|
+
const response = await (options.fetch ?? globalThis.fetch)(
|
|
6425
|
+
`https://github.com/Gentleman-Programming/engram/releases/download/v${engram_release_default.version}/${asset.name}`,
|
|
6426
|
+
{ signal: AbortSignal.timeout(12e4) }
|
|
6427
|
+
);
|
|
6428
|
+
if (!response.ok || !response.body) throw new Error(`Descarga Engram fallida: HTTP ${response.status}.`);
|
|
6429
|
+
const reader = response.body.getReader();
|
|
6430
|
+
const chunks = [];
|
|
6431
|
+
let size = 0;
|
|
6432
|
+
try {
|
|
6433
|
+
while (true) {
|
|
6434
|
+
const chunk = await reader.read();
|
|
6435
|
+
if (chunk.done) break;
|
|
6436
|
+
size += chunk.value.byteLength;
|
|
6437
|
+
if (size > asset.size) throw new Error("El tama\xF1o descargado de Engram supera el aprobado.");
|
|
6438
|
+
chunks.push(chunk.value);
|
|
6439
|
+
}
|
|
6440
|
+
} finally {
|
|
6441
|
+
await reader.cancel();
|
|
6442
|
+
}
|
|
6443
|
+
const archive = Buffer.concat(chunks);
|
|
6444
|
+
if (size !== asset.size || createHash3("sha256").update(archive).digest("hex") !== asset.sha256) {
|
|
6445
|
+
throw new Error("Engram: tama\xF1o o hash SHA-256 no coincide con el artefacto aprobado.");
|
|
6446
|
+
}
|
|
6447
|
+
fs24.mkdirSync(path33.dirname(bin), { recursive: true });
|
|
6448
|
+
staging = fs24.mkdtempSync(path33.join(path33.dirname(bin), ".engram-install-"));
|
|
6449
|
+
const archivePath = path33.join(staging, asset.name);
|
|
6450
|
+
fs24.writeFileSync(archivePath, archive, { flag: "wx", mode: 384 });
|
|
6451
|
+
const binary = execFileSync7(resolveTarBin(), ["-xOf", archivePath, binaryName], {
|
|
6452
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
6453
|
+
timeout: 3e4,
|
|
6454
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
6455
|
+
});
|
|
6456
|
+
if (binary.length === 0) throw new Error("El artefacto Engram no contiene un binario v\xE1lido.");
|
|
6457
|
+
const stagedBin = path33.join(staging, binaryName);
|
|
6458
|
+
fs24.writeFileSync(stagedBin, binary, { flag: "wx", mode: 493 });
|
|
6459
|
+
fs24.linkSync(stagedBin, bin);
|
|
6460
|
+
return { ok: true, bin };
|
|
6461
|
+
} catch (error) {
|
|
6462
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
6463
|
+
} finally {
|
|
6464
|
+
if (staging) fs24.rmSync(staging, { recursive: true, force: true });
|
|
6465
|
+
}
|
|
6466
|
+
}
|
|
6467
|
+
|
|
6170
6468
|
// src/cli.ts
|
|
6171
6469
|
var VERSION = readPackageVersion();
|
|
6172
6470
|
var COMMANDS = ["install", "sync", "models", "update", "doctor", "restore", "uninstall", "quality"];
|
|
@@ -6201,6 +6499,7 @@ function parseFlags(args, allowReceipt = false) {
|
|
|
6201
6499
|
list: false,
|
|
6202
6500
|
check: false,
|
|
6203
6501
|
removeEngram: false,
|
|
6502
|
+
engram: false,
|
|
6204
6503
|
playwright: false,
|
|
6205
6504
|
removePlaywright: false,
|
|
6206
6505
|
devtools: false,
|
|
@@ -6263,6 +6562,7 @@ function parseFlags(args, allowReceipt = false) {
|
|
|
6263
6562
|
else if (arg === "--list") flags.list = true;
|
|
6264
6563
|
else if (arg === "--check") flags.check = true;
|
|
6265
6564
|
else if (arg === "--remove-engram") flags.removeEngram = true;
|
|
6565
|
+
else if (arg === "--engram") flags.engram = true;
|
|
6266
6566
|
else if (arg === "--playwright") flags.playwright = true;
|
|
6267
6567
|
else if (arg === "--remove-playwright") flags.removePlaywright = true;
|
|
6268
6568
|
else if (arg === "--devtools") flags.devtools = true;
|
|
@@ -6367,8 +6667,9 @@ async function resolveDevtoolsMcpSelection(command, flags, runtimes) {
|
|
|
6367
6667
|
}
|
|
6368
6668
|
const file = devtoolsMcpPreferenceFile();
|
|
6369
6669
|
const selected = await p6.multiselect({
|
|
6370
|
-
message: "Chrome DevTools MCP avanzado (
|
|
6371
|
-
|
|
6670
|
+
message: "Chrome DevTools MCP avanzado (opcional). \xBFEn qu\xE9 runtimes activarlo?",
|
|
6671
|
+
required: false,
|
|
6672
|
+
options: runtimes.map((runtime) => ({ value: runtime, label: runtime === "pi" ? "Pi" : ADAPTERS[runtime]?.name ?? runtime })),
|
|
6372
6673
|
initialValues: runtimes.filter((runtime) => loadDevtoolsMcpPreference(file, runtime))
|
|
6373
6674
|
});
|
|
6374
6675
|
if (p6.isCancel(selected)) return null;
|
|
@@ -6413,7 +6714,34 @@ async function resolveRuntimes(flags, includeAvailablePi = false) {
|
|
|
6413
6714
|
if (p6.isCancel(choice)) return null;
|
|
6414
6715
|
return choice;
|
|
6415
6716
|
}
|
|
6416
|
-
async function
|
|
6717
|
+
async function resolveHostEngramForInstall(flags) {
|
|
6718
|
+
if (flags.targetDir !== void 0) return { ok: true, bin: null };
|
|
6719
|
+
const existing = resolvePiEngramBin();
|
|
6720
|
+
if (flags.dryRun) return { ok: true, bin: existing };
|
|
6721
|
+
if (existing !== null) return { ok: true, bin: existing };
|
|
6722
|
+
let accepted = flags.engram;
|
|
6723
|
+
if (!accepted && !flags.yes && process.stdin.isTTY === true && process.stdout.isTTY === true) {
|
|
6724
|
+
const answer = await p6.confirm({
|
|
6725
|
+
message: "Engram no est\xE1 instalado. \xBFDescargar e instalar ahora el binario oficial verificado?",
|
|
6726
|
+
initialValue: false
|
|
6727
|
+
});
|
|
6728
|
+
if (!p6.isCancel(answer)) accepted = answer === true;
|
|
6729
|
+
}
|
|
6730
|
+
if (!accepted) {
|
|
6731
|
+
return {
|
|
6732
|
+
ok: false,
|
|
6733
|
+
message: "Engram no est\xE1 instalado. Usa --engram para autorizar su instalaci\xF3n o inst\xE1lalo antes de reintentar."
|
|
6734
|
+
};
|
|
6735
|
+
}
|
|
6736
|
+
try {
|
|
6737
|
+
const result = await installMissingEngram();
|
|
6738
|
+
if (result.ok) return { ok: true, bin: result.bin };
|
|
6739
|
+
return { ok: false, message: `Engram: ${result.reason}` };
|
|
6740
|
+
} catch (error) {
|
|
6741
|
+
return { ok: false, message: `Engram: ${error instanceof Error ? error.message : String(error)}` };
|
|
6742
|
+
}
|
|
6743
|
+
}
|
|
6744
|
+
async function runSelectedPi(operation, targetDir, yes = false, resolvedEngramBin, devtoolsMcpEnabled) {
|
|
6417
6745
|
if (targetDir === void 0 && operation !== "models") {
|
|
6418
6746
|
const preferenceErrors = browserPreferenceErrors();
|
|
6419
6747
|
if (preferenceErrors.length > 0) {
|
|
@@ -6430,7 +6758,7 @@ async function runSelectedPi(operation, targetDir, yes = false) {
|
|
|
6430
6758
|
console.error("No se pudo verificar la versi\xF3n instalada de Pi sin ejecutarlo; revisa la instalaci\xF3n de Pi.");
|
|
6431
6759
|
return 1;
|
|
6432
6760
|
}
|
|
6433
|
-
let engramBin = resolvePiEngramBin(targetDir);
|
|
6761
|
+
let engramBin = resolvedEngramBin === void 0 ? resolvePiEngramBin(targetDir) : resolvedEngramBin;
|
|
6434
6762
|
if (operation === "install" && engramBin === null) {
|
|
6435
6763
|
const requirement = await resolvePiEngramRequirement({
|
|
6436
6764
|
targetDir,
|
|
@@ -6455,7 +6783,8 @@ async function runSelectedPi(operation, targetDir, yes = false) {
|
|
|
6455
6783
|
operation,
|
|
6456
6784
|
targetDir,
|
|
6457
6785
|
detected: { executable: detected.executable, version: detected.version },
|
|
6458
|
-
engramBin
|
|
6786
|
+
engramBin,
|
|
6787
|
+
...devtoolsMcpEnabled === void 0 ? {} : { devtoolsMcpEnabled }
|
|
6459
6788
|
});
|
|
6460
6789
|
if (result.kind === "blocked") {
|
|
6461
6790
|
const paths = "paths" in result ? `: ${result.paths.join(", ")}` : "";
|
|
@@ -6491,6 +6820,7 @@ Opciones:
|
|
|
6491
6820
|
--dry-run Muestra el plan sin escribir nada
|
|
6492
6821
|
--yes, -y No interactivo
|
|
6493
6822
|
--playwright Autoriza Playwright CLI global y sus navegadores (requerido con --yes/sin TTY)
|
|
6823
|
+
--engram (install) autoriza instalar el binario Engram si falta
|
|
6494
6824
|
--devtools (install/sync) activa Chrome DevTools MCP para los runtimes destino (opt-in)
|
|
6495
6825
|
--no-devtools (install/sync) desactiva Chrome DevTools MCP (incompatible con --devtools)
|
|
6496
6826
|
--remove-engram (uninstall) desregistra Engram de los runtimes;
|
|
@@ -6524,6 +6854,11 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6524
6854
|
return;
|
|
6525
6855
|
}
|
|
6526
6856
|
const { command, flags } = parsed;
|
|
6857
|
+
if (flags.engram && command !== "install") {
|
|
6858
|
+
console.error("--engram solo se admite durante install.");
|
|
6859
|
+
process.exitCode = 1;
|
|
6860
|
+
return;
|
|
6861
|
+
}
|
|
6527
6862
|
if (command !== "quality" && flags.targetDir !== void 0 && flags.agents.length !== 1) {
|
|
6528
6863
|
console.error("--target-dir requiere exactamente un runtime en --agents.");
|
|
6529
6864
|
process.exitCode = 1;
|
|
@@ -6531,7 +6866,7 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6531
6866
|
}
|
|
6532
6867
|
switch (command) {
|
|
6533
6868
|
case "quality": {
|
|
6534
|
-
if (flags.targetDir !== void 0 || flags.agents.length > 0 || flags.dryRun || flags.yes || flags.mode !== void 0 || flags.subagentConcurrency !== void 0 || flags.list || flags.check || flags.removeEngram || flags.playwright || flags.removePlaywright || flags.devtools || flags.noDevtools) {
|
|
6869
|
+
if (flags.targetDir !== void 0 || flags.agents.length > 0 || flags.dryRun || flags.yes || flags.mode !== void 0 || flags.subagentConcurrency !== void 0 || flags.list || flags.check || flags.removeEngram || flags.engram || flags.playwright || flags.removePlaywright || flags.devtools || flags.noDevtools) {
|
|
6535
6870
|
console.error("quality solo admite <plan.json> y, opcionalmente, --receipt <path>.");
|
|
6536
6871
|
process.exitCode = 1;
|
|
6537
6872
|
return;
|
|
@@ -6547,7 +6882,7 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6547
6882
|
return;
|
|
6548
6883
|
}
|
|
6549
6884
|
try {
|
|
6550
|
-
const plan = JSON.parse(
|
|
6885
|
+
const plan = JSON.parse(fs25.readFileSync(flags.positional[0], "utf8"));
|
|
6551
6886
|
const result = await runQualityPlan(plan);
|
|
6552
6887
|
const serialized = serializeQualityReceipt(result.receipt);
|
|
6553
6888
|
if (flags.receipt === void 0) process.stdout.write(`${serialized}
|
|
@@ -6572,33 +6907,55 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6572
6907
|
}
|
|
6573
6908
|
const fileRuntimes = runtimes.filter(isFileManagedRuntime);
|
|
6574
6909
|
let exitCode = 0;
|
|
6575
|
-
|
|
6576
|
-
|
|
6910
|
+
let completed = false;
|
|
6911
|
+
p6.intro(`jorgex-stack ${command}${flags.dryRun ? " (dry-run)" : ""}`);
|
|
6912
|
+
try {
|
|
6913
|
+
if (flags.targetDir === void 0) {
|
|
6914
|
+
const errors = browserPreferenceErrors();
|
|
6915
|
+
if (errors.length > 0) {
|
|
6916
|
+
for (const error of errors) p6.log.error(error);
|
|
6917
|
+
exitCode = 1;
|
|
6918
|
+
return;
|
|
6919
|
+
}
|
|
6920
|
+
}
|
|
6921
|
+
const mode = fileRuntimes.length > 0 ? await resolveInstallMode(flags) : void 0;
|
|
6577
6922
|
if (mode === null) return;
|
|
6578
|
-
const devtoolsMcpSelection = await resolveDevtoolsMcpSelection(command, flags,
|
|
6579
|
-
if (devtoolsMcpSelection === null)
|
|
6580
|
-
|
|
6581
|
-
if (playwrightToolConsent === null) return;
|
|
6582
|
-
const hasOpenCodeModels = await ensureOpenCodeModelsForInstall(command, flags, fileRuntimes);
|
|
6583
|
-
if (!hasOpenCodeModels) {
|
|
6584
|
-
process.exitCode = 1;
|
|
6923
|
+
const devtoolsMcpSelection = await resolveDevtoolsMcpSelection(command, flags, runtimes);
|
|
6924
|
+
if (devtoolsMcpSelection === null) {
|
|
6925
|
+
exitCode = process.exitCode === 1 ? 1 : 0;
|
|
6585
6926
|
return;
|
|
6586
6927
|
}
|
|
6587
|
-
exitCode = await runInstall({
|
|
6588
|
-
runtimes: fileRuntimes,
|
|
6589
|
-
targetDir: flags.targetDir,
|
|
6590
|
-
dryRun: flags.dryRun,
|
|
6591
|
-
yes: flags.yes,
|
|
6592
|
-
mode,
|
|
6593
|
-
playwrightToolConsent,
|
|
6594
|
-
devtoolsMcpSelection
|
|
6595
|
-
});
|
|
6596
|
-
}
|
|
6597
|
-
let piCanRun = true;
|
|
6598
|
-
if (command === "install" && fileRuntimes.length === 0 && runtimes.includes("pi")) {
|
|
6599
6928
|
const playwrightToolConsent = await resolvePlaywrightToolConsent(command, flags);
|
|
6600
6929
|
if (playwrightToolConsent === null) return;
|
|
6601
|
-
if (
|
|
6930
|
+
if (!await ensureOpenCodeModelsForInstall(command, flags, fileRuntimes)) {
|
|
6931
|
+
exitCode = 1;
|
|
6932
|
+
return;
|
|
6933
|
+
}
|
|
6934
|
+
let engramBin;
|
|
6935
|
+
if (command === "install") {
|
|
6936
|
+
const engram = await resolveHostEngramForInstall(flags);
|
|
6937
|
+
if (!engram.ok) {
|
|
6938
|
+
p6.log.error(engram.message);
|
|
6939
|
+
exitCode = 1;
|
|
6940
|
+
return;
|
|
6941
|
+
}
|
|
6942
|
+
engramBin = engram.bin;
|
|
6943
|
+
}
|
|
6944
|
+
if (fileRuntimes.length > 0) {
|
|
6945
|
+
exitCode = await runInstall({
|
|
6946
|
+
runtimes: fileRuntimes,
|
|
6947
|
+
targetDir: flags.targetDir,
|
|
6948
|
+
dryRun: flags.dryRun,
|
|
6949
|
+
yes: flags.yes,
|
|
6950
|
+
mode,
|
|
6951
|
+
playwrightToolConsent,
|
|
6952
|
+
devtoolsMcpSelection,
|
|
6953
|
+
engramBin,
|
|
6954
|
+
showSummary: false
|
|
6955
|
+
});
|
|
6956
|
+
}
|
|
6957
|
+
let piCanRun = true;
|
|
6958
|
+
if (command === "install" && fileRuntimes.length === 0 && runtimes.includes("pi") && resolvePlaywrightToolPlan(playwrightToolConsent).actions.length > 0) {
|
|
6602
6959
|
if (flags.dryRun) {
|
|
6603
6960
|
p6.log.info("Playwright CLI: instalaci\xF3n global y navegador previstos (dry-run; no se ejecutan).");
|
|
6604
6961
|
} else {
|
|
@@ -6607,17 +6964,32 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6607
6964
|
targetDir: flags.targetDir,
|
|
6608
6965
|
dryRun: false,
|
|
6609
6966
|
yes: flags.yes,
|
|
6610
|
-
playwrightToolConsent
|
|
6967
|
+
playwrightToolConsent,
|
|
6968
|
+
engramBin,
|
|
6969
|
+
showSummary: false
|
|
6611
6970
|
});
|
|
6612
6971
|
piCanRun = exitCode === 0;
|
|
6613
6972
|
}
|
|
6614
6973
|
}
|
|
6974
|
+
if (runtimes.includes("pi") && piCanRun) {
|
|
6975
|
+
if (flags.dryRun) p6.log.info(`Pi: ${command} previsto; dry-run no ejecuta subprocess ni escribe receipt.`);
|
|
6976
|
+
else exitCode = Math.max(exitCode, await runSelectedPi(
|
|
6977
|
+
command,
|
|
6978
|
+
flags.targetDir,
|
|
6979
|
+
flags.yes,
|
|
6980
|
+
flags.targetDir === void 0 ? engramBin : void 0,
|
|
6981
|
+
devtoolsMcpSelection.pi
|
|
6982
|
+
));
|
|
6983
|
+
}
|
|
6984
|
+
completed = true;
|
|
6985
|
+
} catch (error) {
|
|
6986
|
+
p6.log.error(error instanceof Error ? error.message : String(error));
|
|
6987
|
+
exitCode = 1;
|
|
6988
|
+
} finally {
|
|
6989
|
+
if (process.exitCode === 1) exitCode = 1;
|
|
6990
|
+
process.exitCode = exitCode;
|
|
6991
|
+
p6.outro(exitCode !== 0 ? `${command} completado con errores (revisa arriba).` : !completed ? `${command} cancelado.` : flags.dryRun ? "Dry-run: no se ha escrito nada." : "Hecho.");
|
|
6615
6992
|
}
|
|
6616
|
-
if (runtimes.includes("pi") && piCanRun) {
|
|
6617
|
-
if (flags.dryRun) p6.log.info(`Pi: ${command} previsto; dry-run no ejecuta subprocess ni escribe receipt.`);
|
|
6618
|
-
else exitCode = Math.max(exitCode, await runSelectedPi(command, flags.targetDir, flags.yes));
|
|
6619
|
-
}
|
|
6620
|
-
process.exitCode = exitCode;
|
|
6621
6993
|
return;
|
|
6622
6994
|
}
|
|
6623
6995
|
case "uninstall": {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jorgex-stack",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.30",
|
|
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",
|