jorgex-stack 1.9.27 → 1.9.29
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 +2 -2
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +297 -51
- 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
|
|
|
@@ -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
|
|
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" };
|
|
@@ -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
|
|
|
@@ -5155,16 +5224,16 @@ import { createHash } from "crypto";
|
|
|
5155
5224
|
var pi_runtime_pin_default = {
|
|
5156
5225
|
package: {
|
|
5157
5226
|
name: "jorgex-pi",
|
|
5158
|
-
version: "0.8.
|
|
5159
|
-
source: "npm:jorgex-pi@0.8.
|
|
5227
|
+
version: "0.8.12",
|
|
5228
|
+
source: "npm:jorgex-pi@0.8.12"
|
|
5160
5229
|
},
|
|
5161
5230
|
provenance: {
|
|
5162
|
-
commit: "
|
|
5231
|
+
commit: "a041e8f290021b5a6bb161db77e03663f37c82cb"
|
|
5163
5232
|
},
|
|
5164
5233
|
tarball: {
|
|
5165
|
-
bytes:
|
|
5166
|
-
sha256: "
|
|
5167
|
-
sha512: "
|
|
5234
|
+
bytes: 89141968,
|
|
5235
|
+
sha256: "eb7739852504bf4cd8cdd9f260c67da979728378a756db7f1ff6b0c1d60368c6",
|
|
5236
|
+
sha512: "a37b36e5c846e1694db3c7bd7e9acf23f39b8ba45d348bf039fd218f90f041a6d95268af2e3b6248fc4e759dfd6441df1c44490411c1e13c2b0cedbc0ef526b2"
|
|
5168
5237
|
}
|
|
5169
5238
|
};
|
|
5170
5239
|
|
|
@@ -6167,6 +6236,112 @@ async function runQualityPlan(input) {
|
|
|
6167
6236
|
return { evaluation, receipt };
|
|
6168
6237
|
}
|
|
6169
6238
|
|
|
6239
|
+
// src/lib/engram-install.ts
|
|
6240
|
+
import fs24 from "fs";
|
|
6241
|
+
import os5 from "os";
|
|
6242
|
+
import path33 from "path";
|
|
6243
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
6244
|
+
import { createHash as createHash2 } from "crypto";
|
|
6245
|
+
|
|
6246
|
+
// src/lib/engram-release.json
|
|
6247
|
+
var engram_release_default = {
|
|
6248
|
+
assets: {
|
|
6249
|
+
darwin_arm64: {
|
|
6250
|
+
name: "engram_1.20.0_darwin_arm64.tar.gz",
|
|
6251
|
+
sha256: "2363d5012f23e58878f86c3ddcc1f63cfe9dcf3eec7f413e70eaafcbb9d394cc",
|
|
6252
|
+
size: 6949031
|
|
6253
|
+
},
|
|
6254
|
+
darwin_x64: {
|
|
6255
|
+
name: "engram_1.20.0_darwin_amd64.tar.gz",
|
|
6256
|
+
sha256: "3b9015dcfcdd9f823eb7ad0b590b1dbc4c25bb5d81dda3f84e623709815afe80",
|
|
6257
|
+
size: 7367005
|
|
6258
|
+
},
|
|
6259
|
+
linux_arm64: {
|
|
6260
|
+
name: "engram_1.20.0_linux_arm64.tar.gz",
|
|
6261
|
+
sha256: "7eb815910a76ae6cfa9a5d0161d3701e293dcca71f7743cffa62e236e5af59af",
|
|
6262
|
+
size: 6673857
|
|
6263
|
+
},
|
|
6264
|
+
linux_x64: {
|
|
6265
|
+
name: "engram_1.20.0_linux_amd64.tar.gz",
|
|
6266
|
+
sha256: "7dc3003318e303bee269a4772144f3ce01c8ec700bfd524aaec76770acd389ca",
|
|
6267
|
+
size: 7236400
|
|
6268
|
+
},
|
|
6269
|
+
windows_arm64: {
|
|
6270
|
+
name: "engram_1.20.0_windows_arm64.zip",
|
|
6271
|
+
sha256: "eb93c6d7d5a4020ddcf1ff956909f3e90694f6447519433316b10f964f8f37b5",
|
|
6272
|
+
size: 6723366
|
|
6273
|
+
},
|
|
6274
|
+
windows_x64: {
|
|
6275
|
+
name: "engram_1.20.0_windows_amd64.zip",
|
|
6276
|
+
sha256: "c945c47d58367f943642cb8451fa45f208174407839f1dda33a975a05d6e465b",
|
|
6277
|
+
size: 7416778
|
|
6278
|
+
}
|
|
6279
|
+
},
|
|
6280
|
+
version: "1.20.0"
|
|
6281
|
+
};
|
|
6282
|
+
|
|
6283
|
+
// src/lib/engram-install.ts
|
|
6284
|
+
async function installMissingEngram(options = {}) {
|
|
6285
|
+
const platform = options.platform ?? process.platform;
|
|
6286
|
+
const homeDir = options.homeDir ?? os5.homedir();
|
|
6287
|
+
if (!path33.isAbsolute(homeDir)) return { ok: false, reason: "El directorio personal debe ser absoluto." };
|
|
6288
|
+
const binaryName = platform === "win32" ? "engram.exe" : "engram";
|
|
6289
|
+
const bin = path33.join(homeDir, ".local", "bin", binaryName);
|
|
6290
|
+
let staging;
|
|
6291
|
+
try {
|
|
6292
|
+
const existing = fs24.lstatSync(bin, { throwIfNoEntry: false });
|
|
6293
|
+
if (existing) {
|
|
6294
|
+
if (!fs24.statSync(bin).isFile()) throw new Error(`El destino Engram no es un archivo: ${bin}`);
|
|
6295
|
+
fs24.accessSync(bin, platform === "win32" ? fs24.constants.F_OK : fs24.constants.X_OK);
|
|
6296
|
+
return { ok: true, bin };
|
|
6297
|
+
}
|
|
6298
|
+
const key = `${platform === "win32" ? "windows" : platform}_${options.arch ?? process.arch}`;
|
|
6299
|
+
const asset = engram_release_default.assets[key];
|
|
6300
|
+
if (!asset) throw new Error(`Engram no dispone de un binario aprobado para ${key}.`);
|
|
6301
|
+
const response = await (options.fetch ?? globalThis.fetch)(
|
|
6302
|
+
`https://github.com/Gentleman-Programming/engram/releases/download/v${engram_release_default.version}/${asset.name}`,
|
|
6303
|
+
{ signal: AbortSignal.timeout(12e4) }
|
|
6304
|
+
);
|
|
6305
|
+
if (!response.ok || !response.body) throw new Error(`Descarga Engram fallida: HTTP ${response.status}.`);
|
|
6306
|
+
const reader = response.body.getReader();
|
|
6307
|
+
const chunks = [];
|
|
6308
|
+
let size = 0;
|
|
6309
|
+
try {
|
|
6310
|
+
while (true) {
|
|
6311
|
+
const chunk = await reader.read();
|
|
6312
|
+
if (chunk.done) break;
|
|
6313
|
+
size += chunk.value.byteLength;
|
|
6314
|
+
if (size > asset.size) throw new Error("El tama\xF1o descargado de Engram supera el aprobado.");
|
|
6315
|
+
chunks.push(chunk.value);
|
|
6316
|
+
}
|
|
6317
|
+
} finally {
|
|
6318
|
+
await reader.cancel();
|
|
6319
|
+
}
|
|
6320
|
+
const archive = Buffer.concat(chunks);
|
|
6321
|
+
if (size !== asset.size || createHash2("sha256").update(archive).digest("hex") !== asset.sha256) {
|
|
6322
|
+
throw new Error("Engram: tama\xF1o o hash SHA-256 no coincide con el artefacto aprobado.");
|
|
6323
|
+
}
|
|
6324
|
+
fs24.mkdirSync(path33.dirname(bin), { recursive: true });
|
|
6325
|
+
staging = fs24.mkdtempSync(path33.join(path33.dirname(bin), ".engram-install-"));
|
|
6326
|
+
const archivePath = path33.join(staging, asset.name);
|
|
6327
|
+
fs24.writeFileSync(archivePath, archive, { flag: "wx", mode: 384 });
|
|
6328
|
+
const binary = execFileSync7(resolveTarBin(), ["-xOf", archivePath, binaryName], {
|
|
6329
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
6330
|
+
timeout: 3e4,
|
|
6331
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
6332
|
+
});
|
|
6333
|
+
if (binary.length === 0) throw new Error("El artefacto Engram no contiene un binario v\xE1lido.");
|
|
6334
|
+
const stagedBin = path33.join(staging, binaryName);
|
|
6335
|
+
fs24.writeFileSync(stagedBin, binary, { flag: "wx", mode: 493 });
|
|
6336
|
+
fs24.linkSync(stagedBin, bin);
|
|
6337
|
+
return { ok: true, bin };
|
|
6338
|
+
} catch (error) {
|
|
6339
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
6340
|
+
} finally {
|
|
6341
|
+
if (staging) fs24.rmSync(staging, { recursive: true, force: true });
|
|
6342
|
+
}
|
|
6343
|
+
}
|
|
6344
|
+
|
|
6170
6345
|
// src/cli.ts
|
|
6171
6346
|
var VERSION = readPackageVersion();
|
|
6172
6347
|
var COMMANDS = ["install", "sync", "models", "update", "doctor", "restore", "uninstall", "quality"];
|
|
@@ -6201,6 +6376,7 @@ function parseFlags(args, allowReceipt = false) {
|
|
|
6201
6376
|
list: false,
|
|
6202
6377
|
check: false,
|
|
6203
6378
|
removeEngram: false,
|
|
6379
|
+
engram: false,
|
|
6204
6380
|
playwright: false,
|
|
6205
6381
|
removePlaywright: false,
|
|
6206
6382
|
devtools: false,
|
|
@@ -6263,6 +6439,7 @@ function parseFlags(args, allowReceipt = false) {
|
|
|
6263
6439
|
else if (arg === "--list") flags.list = true;
|
|
6264
6440
|
else if (arg === "--check") flags.check = true;
|
|
6265
6441
|
else if (arg === "--remove-engram") flags.removeEngram = true;
|
|
6442
|
+
else if (arg === "--engram") flags.engram = true;
|
|
6266
6443
|
else if (arg === "--playwright") flags.playwright = true;
|
|
6267
6444
|
else if (arg === "--remove-playwright") flags.removePlaywright = true;
|
|
6268
6445
|
else if (arg === "--devtools") flags.devtools = true;
|
|
@@ -6413,7 +6590,34 @@ async function resolveRuntimes(flags, includeAvailablePi = false) {
|
|
|
6413
6590
|
if (p6.isCancel(choice)) return null;
|
|
6414
6591
|
return choice;
|
|
6415
6592
|
}
|
|
6416
|
-
async function
|
|
6593
|
+
async function resolveHostEngramForInstall(flags) {
|
|
6594
|
+
if (flags.targetDir !== void 0) return { ok: true, bin: null };
|
|
6595
|
+
const existing = resolvePiEngramBin();
|
|
6596
|
+
if (flags.dryRun) return { ok: true, bin: existing };
|
|
6597
|
+
if (existing !== null) return { ok: true, bin: existing };
|
|
6598
|
+
let accepted = flags.engram;
|
|
6599
|
+
if (!accepted && !flags.yes && process.stdin.isTTY === true && process.stdout.isTTY === true) {
|
|
6600
|
+
const answer = await p6.confirm({
|
|
6601
|
+
message: "Engram no est\xE1 instalado. \xBFDescargar e instalar ahora el binario oficial verificado?",
|
|
6602
|
+
initialValue: false
|
|
6603
|
+
});
|
|
6604
|
+
if (!p6.isCancel(answer)) accepted = answer === true;
|
|
6605
|
+
}
|
|
6606
|
+
if (!accepted) {
|
|
6607
|
+
return {
|
|
6608
|
+
ok: false,
|
|
6609
|
+
message: "Engram no est\xE1 instalado. Usa --engram para autorizar su instalaci\xF3n o inst\xE1lalo antes de reintentar."
|
|
6610
|
+
};
|
|
6611
|
+
}
|
|
6612
|
+
try {
|
|
6613
|
+
const result = await installMissingEngram();
|
|
6614
|
+
if (result.ok) return { ok: true, bin: result.bin };
|
|
6615
|
+
return { ok: false, message: `Engram: ${result.reason}` };
|
|
6616
|
+
} catch (error) {
|
|
6617
|
+
return { ok: false, message: `Engram: ${error instanceof Error ? error.message : String(error)}` };
|
|
6618
|
+
}
|
|
6619
|
+
}
|
|
6620
|
+
async function runSelectedPi(operation, targetDir, yes = false, resolvedEngramBin) {
|
|
6417
6621
|
if (targetDir === void 0 && operation !== "models") {
|
|
6418
6622
|
const preferenceErrors = browserPreferenceErrors();
|
|
6419
6623
|
if (preferenceErrors.length > 0) {
|
|
@@ -6430,7 +6634,7 @@ async function runSelectedPi(operation, targetDir, yes = false) {
|
|
|
6430
6634
|
console.error("No se pudo verificar la versi\xF3n instalada de Pi sin ejecutarlo; revisa la instalaci\xF3n de Pi.");
|
|
6431
6635
|
return 1;
|
|
6432
6636
|
}
|
|
6433
|
-
let engramBin = resolvePiEngramBin(targetDir);
|
|
6637
|
+
let engramBin = resolvedEngramBin === void 0 ? resolvePiEngramBin(targetDir) : resolvedEngramBin;
|
|
6434
6638
|
if (operation === "install" && engramBin === null) {
|
|
6435
6639
|
const requirement = await resolvePiEngramRequirement({
|
|
6436
6640
|
targetDir,
|
|
@@ -6491,6 +6695,7 @@ Opciones:
|
|
|
6491
6695
|
--dry-run Muestra el plan sin escribir nada
|
|
6492
6696
|
--yes, -y No interactivo
|
|
6493
6697
|
--playwright Autoriza Playwright CLI global y sus navegadores (requerido con --yes/sin TTY)
|
|
6698
|
+
--engram (install) autoriza instalar el binario Engram si falta
|
|
6494
6699
|
--devtools (install/sync) activa Chrome DevTools MCP para los runtimes destino (opt-in)
|
|
6495
6700
|
--no-devtools (install/sync) desactiva Chrome DevTools MCP (incompatible con --devtools)
|
|
6496
6701
|
--remove-engram (uninstall) desregistra Engram de los runtimes;
|
|
@@ -6524,6 +6729,11 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6524
6729
|
return;
|
|
6525
6730
|
}
|
|
6526
6731
|
const { command, flags } = parsed;
|
|
6732
|
+
if (flags.engram && command !== "install") {
|
|
6733
|
+
console.error("--engram solo se admite durante install.");
|
|
6734
|
+
process.exitCode = 1;
|
|
6735
|
+
return;
|
|
6736
|
+
}
|
|
6527
6737
|
if (command !== "quality" && flags.targetDir !== void 0 && flags.agents.length !== 1) {
|
|
6528
6738
|
console.error("--target-dir requiere exactamente un runtime en --agents.");
|
|
6529
6739
|
process.exitCode = 1;
|
|
@@ -6531,7 +6741,7 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6531
6741
|
}
|
|
6532
6742
|
switch (command) {
|
|
6533
6743
|
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) {
|
|
6744
|
+
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
6745
|
console.error("quality solo admite <plan.json> y, opcionalmente, --receipt <path>.");
|
|
6536
6746
|
process.exitCode = 1;
|
|
6537
6747
|
return;
|
|
@@ -6547,7 +6757,7 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6547
6757
|
return;
|
|
6548
6758
|
}
|
|
6549
6759
|
try {
|
|
6550
|
-
const plan = JSON.parse(
|
|
6760
|
+
const plan = JSON.parse(fs25.readFileSync(flags.positional[0], "utf8"));
|
|
6551
6761
|
const result = await runQualityPlan(plan);
|
|
6552
6762
|
const serialized = serializeQualityReceipt(result.receipt);
|
|
6553
6763
|
if (flags.receipt === void 0) process.stdout.write(`${serialized}
|
|
@@ -6572,33 +6782,55 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6572
6782
|
}
|
|
6573
6783
|
const fileRuntimes = runtimes.filter(isFileManagedRuntime);
|
|
6574
6784
|
let exitCode = 0;
|
|
6575
|
-
|
|
6576
|
-
|
|
6785
|
+
let completed = false;
|
|
6786
|
+
p6.intro(`jorgex-stack ${command}${flags.dryRun ? " (dry-run)" : ""}`);
|
|
6787
|
+
try {
|
|
6788
|
+
if (flags.targetDir === void 0) {
|
|
6789
|
+
const errors = browserPreferenceErrors();
|
|
6790
|
+
if (errors.length > 0) {
|
|
6791
|
+
for (const error of errors) p6.log.error(error);
|
|
6792
|
+
exitCode = 1;
|
|
6793
|
+
return;
|
|
6794
|
+
}
|
|
6795
|
+
}
|
|
6796
|
+
const mode = fileRuntimes.length > 0 ? await resolveInstallMode(flags) : void 0;
|
|
6577
6797
|
if (mode === null) return;
|
|
6578
6798
|
const devtoolsMcpSelection = await resolveDevtoolsMcpSelection(command, flags, fileRuntimes);
|
|
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;
|
|
6799
|
+
if (devtoolsMcpSelection === null) {
|
|
6800
|
+
exitCode = process.exitCode === 1 ? 1 : 0;
|
|
6585
6801
|
return;
|
|
6586
6802
|
}
|
|
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
6803
|
const playwrightToolConsent = await resolvePlaywrightToolConsent(command, flags);
|
|
6600
6804
|
if (playwrightToolConsent === null) return;
|
|
6601
|
-
if (
|
|
6805
|
+
if (!await ensureOpenCodeModelsForInstall(command, flags, fileRuntimes)) {
|
|
6806
|
+
exitCode = 1;
|
|
6807
|
+
return;
|
|
6808
|
+
}
|
|
6809
|
+
let engramBin;
|
|
6810
|
+
if (command === "install") {
|
|
6811
|
+
const engram = await resolveHostEngramForInstall(flags);
|
|
6812
|
+
if (!engram.ok) {
|
|
6813
|
+
p6.log.error(engram.message);
|
|
6814
|
+
exitCode = 1;
|
|
6815
|
+
return;
|
|
6816
|
+
}
|
|
6817
|
+
engramBin = engram.bin;
|
|
6818
|
+
}
|
|
6819
|
+
if (fileRuntimes.length > 0) {
|
|
6820
|
+
exitCode = await runInstall({
|
|
6821
|
+
runtimes: fileRuntimes,
|
|
6822
|
+
targetDir: flags.targetDir,
|
|
6823
|
+
dryRun: flags.dryRun,
|
|
6824
|
+
yes: flags.yes,
|
|
6825
|
+
mode,
|
|
6826
|
+
playwrightToolConsent,
|
|
6827
|
+
devtoolsMcpSelection,
|
|
6828
|
+
engramBin,
|
|
6829
|
+
showSummary: false
|
|
6830
|
+
});
|
|
6831
|
+
}
|
|
6832
|
+
let piCanRun = true;
|
|
6833
|
+
if (command === "install" && fileRuntimes.length === 0 && runtimes.includes("pi") && resolvePlaywrightToolPlan(playwrightToolConsent).actions.length > 0) {
|
|
6602
6834
|
if (flags.dryRun) {
|
|
6603
6835
|
p6.log.info("Playwright CLI: instalaci\xF3n global y navegador previstos (dry-run; no se ejecutan).");
|
|
6604
6836
|
} else {
|
|
@@ -6607,17 +6839,31 @@ Flags disponibles: jorgex-stack --help`
|
|
|
6607
6839
|
targetDir: flags.targetDir,
|
|
6608
6840
|
dryRun: false,
|
|
6609
6841
|
yes: flags.yes,
|
|
6610
|
-
playwrightToolConsent
|
|
6842
|
+
playwrightToolConsent,
|
|
6843
|
+
engramBin,
|
|
6844
|
+
showSummary: false
|
|
6611
6845
|
});
|
|
6612
6846
|
piCanRun = exitCode === 0;
|
|
6613
6847
|
}
|
|
6614
6848
|
}
|
|
6849
|
+
if (runtimes.includes("pi") && piCanRun) {
|
|
6850
|
+
if (flags.dryRun) p6.log.info(`Pi: ${command} previsto; dry-run no ejecuta subprocess ni escribe receipt.`);
|
|
6851
|
+
else exitCode = Math.max(exitCode, await runSelectedPi(
|
|
6852
|
+
command,
|
|
6853
|
+
flags.targetDir,
|
|
6854
|
+
flags.yes,
|
|
6855
|
+
flags.targetDir === void 0 ? engramBin : void 0
|
|
6856
|
+
));
|
|
6857
|
+
}
|
|
6858
|
+
completed = true;
|
|
6859
|
+
} catch (error) {
|
|
6860
|
+
p6.log.error(error instanceof Error ? error.message : String(error));
|
|
6861
|
+
exitCode = 1;
|
|
6862
|
+
} finally {
|
|
6863
|
+
if (process.exitCode === 1) exitCode = 1;
|
|
6864
|
+
process.exitCode = exitCode;
|
|
6865
|
+
p6.outro(exitCode !== 0 ? `${command} completado con errores (revisa arriba).` : !completed ? `${command} cancelado.` : flags.dryRun ? "Dry-run: no se ha escrito nada." : "Hecho.");
|
|
6615
6866
|
}
|
|
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
6867
|
return;
|
|
6622
6868
|
}
|
|
6623
6869
|
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.29",
|
|
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",
|