jorgex-stack 1.9.58 → 1.9.59
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.js +181 -97
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -146,9 +146,9 @@ Install, sync and uninstall back up every managed file before changing it and ar
|
|
|
146
146
|
|
|
147
147
|
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.
|
|
148
148
|
|
|
149
|
-
Engram remains mandatory and user-owned. An existing binary is preserved. `
|
|
149
|
+
Engram remains mandatory and user-owned. An existing binary is always preserved. When it is missing and the user authorizes installation, Stack resolves GitHub's current official latest stable release at runtime; GitHub's `releases/latest` endpoint excludes prereleases and drafts, and the installer never uses a branch. It matches the exact platform/architecture asset and validates its live metadata —published state, expected name, positive size and SHA-256— before publishing; missing network or metadata fails closed, with no static or offline fallback. Use `--engram` to authorize that download in non-interactive flows. The release installer writes only `~/.local/bin/engram` (or the platform equivalent) and does not use Brew or Go. `sync`, dry-run and `--target-dir` never download it. Update remains explicit and does not replace an existing binary implicitly. The database and memories are never updated or deleted, and uninstall preserves the official Engram artifacts and never removes 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. This rolling channel does not mean that every upstream release was pre-reviewed by Stack.
|
|
150
150
|
|
|
151
|
-
|
|
151
|
+
Claude's official plugin still requires stable Engram 2.0.0 or newer: an existing binary below that minimum would make its setup write the obsolete `mcp/engram.json`, so the Claude preflight blocks it before setup. Stack never replaces an existing binary automatically; update it explicitly and rerun `install`. The official Claude plugin contributes hooks and its skill; `engram setup claude-code` registers a separate user-scoped MCP, not a bundled MCP. This integration does not claim an authenticated model-tool smoke.
|
|
152
152
|
|
|
153
153
|
### Integración oficial de Engram
|
|
154
154
|
|
package/dist/cli.js
CHANGED
|
@@ -3180,16 +3180,28 @@ function githubHeaders() {
|
|
|
3180
3180
|
...authHeaders()
|
|
3181
3181
|
};
|
|
3182
3182
|
}
|
|
3183
|
+
var ENGRAM_REPO = "Gentleman-Programming/engram";
|
|
3184
|
+
var ENGRAM_RELEASES_LATEST_URL = `https://api.github.com/repos/${ENGRAM_REPO}/releases/latest`;
|
|
3185
|
+
var ENGRAM_DOWNLOAD_PREFIX = `https://github.com/${ENGRAM_REPO}/releases/download/`;
|
|
3186
|
+
function expectedEngramAssetName(version, platform, arch) {
|
|
3187
|
+
const osPart = platform === "win32" ? "windows" : platform === "linux" ? "linux" : platform === "darwin" ? "darwin" : null;
|
|
3188
|
+
const archPart = arch === "x64" ? "amd64" : arch === "arm64" ? "arm64" : null;
|
|
3189
|
+
if (osPart === null || archPart === null) return null;
|
|
3190
|
+
const ext = osPart === "windows" ? "zip" : "tar.gz";
|
|
3191
|
+
return `engram_${version}_${osPart}_${archPart}.${ext}`;
|
|
3192
|
+
}
|
|
3193
|
+
async function fetchLatestGithubRelease(repo, fetchFn = globalThis.fetch) {
|
|
3194
|
+
const res = await fetchFn(`https://api.github.com/repos/${repo}/releases/latest`, {
|
|
3195
|
+
headers: githubHeaders(),
|
|
3196
|
+
signal: AbortSignal.timeout(1e4)
|
|
3197
|
+
});
|
|
3198
|
+
if (!res.ok && (res.status === 403 || res.status === 429)) rateLimitHit = true;
|
|
3199
|
+
return res;
|
|
3200
|
+
}
|
|
3183
3201
|
async function latestGithubRelease(repo) {
|
|
3184
3202
|
try {
|
|
3185
|
-
const res = await
|
|
3186
|
-
|
|
3187
|
-
signal: AbortSignal.timeout(1e4)
|
|
3188
|
-
});
|
|
3189
|
-
if (!res.ok) {
|
|
3190
|
-
if (res.status === 403 || res.status === 429) rateLimitHit = true;
|
|
3191
|
-
return null;
|
|
3192
|
-
}
|
|
3203
|
+
const res = await fetchLatestGithubRelease(repo);
|
|
3204
|
+
if (!res.ok) return null;
|
|
3193
3205
|
const data = await res.json();
|
|
3194
3206
|
return data.tag_name?.replace(/^v/, "") ?? null;
|
|
3195
3207
|
} catch {
|
|
@@ -4603,16 +4615,16 @@ async function resolvePiEngramRequirement(input, deps) {
|
|
|
4603
4615
|
};
|
|
4604
4616
|
}
|
|
4605
4617
|
const accepted = await deps.confirm({
|
|
4606
|
-
message: "Engram es obligatorio para JorgeX Pi. \xBFInstalar ahora el binario
|
|
4618
|
+
message: "Engram es obligatorio para JorgeX Pi. \xBFInstalar ahora el binario oficial verificado?",
|
|
4607
4619
|
initialValue: false
|
|
4608
4620
|
});
|
|
4609
4621
|
if (!accepted) return { kind: "offer", accepted: false };
|
|
4610
|
-
const installed = await deps.
|
|
4611
|
-
if (!installed) {
|
|
4622
|
+
const installed = await deps.installShared();
|
|
4623
|
+
if (!installed.ok) {
|
|
4612
4624
|
return {
|
|
4613
4625
|
kind: "blocked",
|
|
4614
4626
|
reason: "engram-install-failed",
|
|
4615
|
-
remedy:
|
|
4627
|
+
remedy: `La instalaci\xF3n de Engram fall\xF3: ${installed.reason} Instala Engram manualmente o configura ENGRAM_BIN antes de reintentar.`
|
|
4616
4628
|
};
|
|
4617
4629
|
}
|
|
4618
4630
|
const detected = deps.detectHost();
|
|
@@ -5657,45 +5669,9 @@ import os5 from "os";
|
|
|
5657
5669
|
import path25 from "path";
|
|
5658
5670
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
5659
5671
|
import { createHash as createHash3 } from "crypto";
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
var
|
|
5663
|
-
assets: {
|
|
5664
|
-
darwin_arm64: {
|
|
5665
|
-
name: "engram_2.0.0_darwin_arm64.tar.gz",
|
|
5666
|
-
sha256: "793c695153e0e76144dc53b006a7039771bd24115385856578bc4d6506d46d7f",
|
|
5667
|
-
size: 7210321
|
|
5668
|
-
},
|
|
5669
|
-
darwin_x64: {
|
|
5670
|
-
name: "engram_2.0.0_darwin_amd64.tar.gz",
|
|
5671
|
-
sha256: "f1dcc343ac241c5001617113279b49dec698005550b538250ccf21655fc728ac",
|
|
5672
|
-
size: 7678428
|
|
5673
|
-
},
|
|
5674
|
-
linux_arm64: {
|
|
5675
|
-
name: "engram_2.0.0_linux_arm64.tar.gz",
|
|
5676
|
-
sha256: "a942e73ab424faaa6e2785d1563e0d9d7f20739944dae0c50071223301d44333",
|
|
5677
|
-
size: 6926960
|
|
5678
|
-
},
|
|
5679
|
-
linux_x64: {
|
|
5680
|
-
name: "engram_2.0.0_linux_amd64.tar.gz",
|
|
5681
|
-
sha256: "23be1c2ce9739c455097ff864736213717b925b3e8821a988dfc619685a5abd5",
|
|
5682
|
-
size: 7544949
|
|
5683
|
-
},
|
|
5684
|
-
windows_arm64: {
|
|
5685
|
-
name: "engram_2.0.0_windows_arm64.zip",
|
|
5686
|
-
sha256: "e4d9074ebf8a839573f62d7bd2719421fc428ab25a9affe82ca4b2d5555183d1",
|
|
5687
|
-
size: 6980876
|
|
5688
|
-
},
|
|
5689
|
-
windows_x64: {
|
|
5690
|
-
name: "engram_2.0.0_windows_amd64.zip",
|
|
5691
|
-
sha256: "fba31e7221702f213954c2081aa83b38833e0e9b824a981f976f8cee2c74548c",
|
|
5692
|
-
size: 7738896
|
|
5693
|
-
}
|
|
5694
|
-
},
|
|
5695
|
-
version: "2.0.0"
|
|
5696
|
-
};
|
|
5697
|
-
|
|
5698
|
-
// src/lib/engram-install.ts
|
|
5672
|
+
var MAX_ENGRAM_ARCHIVE_BYTES = 64 * 1024 * 1024;
|
|
5673
|
+
var STABLE_TAG = /^v\d+\.\d+\.\d+$/;
|
|
5674
|
+
var DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
5699
5675
|
async function installMissingEngram(options = {}) {
|
|
5700
5676
|
const platform = options.platform ?? process.platform;
|
|
5701
5677
|
const homeDir = options.homeDir ?? os5.homedir();
|
|
@@ -5703,58 +5679,159 @@ async function installMissingEngram(options = {}) {
|
|
|
5703
5679
|
const binaryName = platform === "win32" ? "engram.exe" : "engram";
|
|
5704
5680
|
const bin = path25.join(homeDir, ".local", "bin", binaryName);
|
|
5705
5681
|
let staging;
|
|
5682
|
+
let outcome;
|
|
5706
5683
|
try {
|
|
5707
5684
|
const existing = fs19.lstatSync(bin, { throwIfNoEntry: false });
|
|
5708
5685
|
if (existing) {
|
|
5709
5686
|
if (!fs19.statSync(bin).isFile()) throw new Error(`El destino Engram no es un archivo: ${bin}`);
|
|
5710
5687
|
fs19.accessSync(bin, platform === "win32" ? fs19.constants.F_OK : fs19.constants.X_OK);
|
|
5711
|
-
|
|
5712
|
-
}
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
5716
|
-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
const chunks = [];
|
|
5723
|
-
let size = 0;
|
|
5724
|
-
try {
|
|
5725
|
-
while (true) {
|
|
5726
|
-
const chunk = await reader.read();
|
|
5727
|
-
if (chunk.done) break;
|
|
5728
|
-
size += chunk.value.byteLength;
|
|
5729
|
-
if (size > asset.size) throw new Error("El tama\xF1o descargado de Engram supera el aprobado.");
|
|
5730
|
-
chunks.push(chunk.value);
|
|
5688
|
+
outcome = { ok: true, bin };
|
|
5689
|
+
} else {
|
|
5690
|
+
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
5691
|
+
let releaseRes;
|
|
5692
|
+
try {
|
|
5693
|
+
releaseRes = await fetchLatestGithubRelease(ENGRAM_REPO, fetchFn);
|
|
5694
|
+
} catch (error) {
|
|
5695
|
+
const cause = error instanceof Error ? error.message : String(error);
|
|
5696
|
+
throw new Error(
|
|
5697
|
+
`Engram: error de red al consultar los metadatos del release (latest): ${cause}. Reintenta la instalaci\xF3n.`
|
|
5698
|
+
);
|
|
5731
5699
|
}
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5700
|
+
if (!releaseRes.ok) {
|
|
5701
|
+
if (releaseRes.status === 429) {
|
|
5702
|
+
throw new Error(
|
|
5703
|
+
"Engram: metadatos del release no disponibles (HTTP 429 rate limit en la consulta latest/metadatos). Espera y reintenta; define GH_TOKEN o inicia sesi\xF3n con gh auth login para elevar el l\xEDmite."
|
|
5704
|
+
);
|
|
5705
|
+
}
|
|
5706
|
+
if (releaseRes.status === 403) {
|
|
5707
|
+
throw new Error(
|
|
5708
|
+
"Engram: metadatos del release no disponibles (HTTP 403 en la consulta latest/metadatos). Posible rate limit o falta de autenticaci\xF3n; define GH_TOKEN o usa gh auth login y reintenta."
|
|
5709
|
+
);
|
|
5710
|
+
}
|
|
5711
|
+
throw new Error(
|
|
5712
|
+
`Engram: metadatos del release no disponibles (HTTP ${releaseRes.status} en la consulta latest).`
|
|
5713
|
+
);
|
|
5714
|
+
}
|
|
5715
|
+
let raw;
|
|
5716
|
+
try {
|
|
5717
|
+
raw = await releaseRes.json();
|
|
5718
|
+
} catch (error) {
|
|
5719
|
+
if (error instanceof SyntaxError) {
|
|
5720
|
+
throw new Error("Engram: metadatos del release inv\xE1lidos: JSON no parseable.");
|
|
5721
|
+
}
|
|
5722
|
+
const cause = error instanceof Error ? error.message : String(error);
|
|
5723
|
+
const hint = error instanceof Error && error.name === "AbortError" ? "interrumpida (red/cancelada)" : "de red";
|
|
5724
|
+
throw new Error(
|
|
5725
|
+
`Engram: lectura de metadatos del release ${hint}: ${cause}. Reintenta la instalaci\xF3n.`
|
|
5726
|
+
);
|
|
5727
|
+
}
|
|
5728
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
5729
|
+
throw new Error("Engram: metadatos del release inv\xE1lidos: se esperaba un objeto JSON.");
|
|
5730
|
+
}
|
|
5731
|
+
const releaseJson = raw;
|
|
5732
|
+
const tag = releaseJson.tag_name;
|
|
5733
|
+
if (typeof tag !== "string" || !STABLE_TAG.test(tag)) {
|
|
5734
|
+
throw new Error(`Engram: tag del release inv\xE1lido: ${String(tag)}.`);
|
|
5735
|
+
}
|
|
5736
|
+
const version = tag.slice(1);
|
|
5737
|
+
const expectedName = expectedEngramAssetName(version, platform, options.arch ?? process.arch);
|
|
5738
|
+
if (expectedName === null) {
|
|
5739
|
+
throw new Error(`Engram no dispone de un binario aprobado para ${platform}_${options.arch ?? process.arch}.`);
|
|
5740
|
+
}
|
|
5741
|
+
if (!Array.isArray(releaseJson.assets)) throw new Error("Engram: metadatos del release sin assets.");
|
|
5742
|
+
const matches = releaseJson.assets.filter((asset2) => asset2?.name === expectedName);
|
|
5743
|
+
if (matches.length !== 1) throw new Error("Engram: asset exacto ausente o ambiguo en el release.");
|
|
5744
|
+
const asset = matches[0];
|
|
5745
|
+
if (asset.state !== "uploaded") throw new Error("Engram: asset no publicado.");
|
|
5746
|
+
if (!Number.isInteger(asset.size) || asset.size <= 0) {
|
|
5747
|
+
throw new Error("Engram: tama\xF1o del asset inv\xE1lido.");
|
|
5748
|
+
}
|
|
5749
|
+
const expectedUrl = `${ENGRAM_DOWNLOAD_PREFIX}${tag}/${expectedName}`;
|
|
5750
|
+
if (typeof asset.browser_download_url !== "string" || asset.browser_download_url !== expectedUrl) {
|
|
5751
|
+
throw new Error("Engram: URL del asset no oficial.");
|
|
5752
|
+
}
|
|
5753
|
+
if (typeof asset.digest !== "string" || !DIGEST_RE.test(asset.digest)) {
|
|
5754
|
+
throw new Error("Engram: digest del asset inv\xE1lido.");
|
|
5755
|
+
}
|
|
5756
|
+
const approvedSize = asset.size;
|
|
5757
|
+
if (approvedSize > MAX_ENGRAM_ARCHIVE_BYTES) {
|
|
5758
|
+
throw new Error(
|
|
5759
|
+
`Engram: tama\xF1o del asset aprobado (${approvedSize} bytes) excede el l\xEDmite de 64 MiB (${MAX_ENGRAM_ARCHIVE_BYTES} bytes).`
|
|
5760
|
+
);
|
|
5761
|
+
}
|
|
5762
|
+
const approvedSha = asset.digest.slice("sha256:".length);
|
|
5763
|
+
const response = await fetchFn(asset.browser_download_url, {
|
|
5764
|
+
signal: AbortSignal.timeout(12e4)
|
|
5765
|
+
});
|
|
5766
|
+
if (!response.ok || !response.body) throw new Error(`Descarga Engram fallida: HTTP ${response.status}.`);
|
|
5767
|
+
const reader = response.body.getReader();
|
|
5768
|
+
const chunks = [];
|
|
5769
|
+
let size = 0;
|
|
5770
|
+
let readError;
|
|
5771
|
+
try {
|
|
5772
|
+
try {
|
|
5773
|
+
while (true) {
|
|
5774
|
+
const chunk = await reader.read();
|
|
5775
|
+
if (chunk.done) break;
|
|
5776
|
+
size += chunk.value.byteLength;
|
|
5777
|
+
if (size > approvedSize) throw new Error("El tama\xF1o descargado de Engram supera el aprobado.");
|
|
5778
|
+
chunks.push(chunk.value);
|
|
5779
|
+
}
|
|
5780
|
+
} catch (error) {
|
|
5781
|
+
readError = error;
|
|
5782
|
+
throw error;
|
|
5783
|
+
}
|
|
5784
|
+
} finally {
|
|
5785
|
+
try {
|
|
5786
|
+
await reader.cancel();
|
|
5787
|
+
} catch (cancelError) {
|
|
5788
|
+
const cancelMsg = cancelError instanceof Error ? cancelError.message : String(cancelError);
|
|
5789
|
+
if (readError !== void 0) {
|
|
5790
|
+
const primaryMsg = readError instanceof Error ? readError.message : String(readError);
|
|
5791
|
+
throw new Error(`${primaryMsg} (adem\xE1s fall\xF3 la cancelaci\xF3n del stream: ${cancelMsg})`);
|
|
5792
|
+
}
|
|
5793
|
+
throw cancelError;
|
|
5794
|
+
}
|
|
5795
|
+
}
|
|
5796
|
+
const archive = Buffer.concat(chunks);
|
|
5797
|
+
if (size !== approvedSize || createHash3("sha256").update(archive).digest("hex") !== approvedSha) {
|
|
5798
|
+
throw new Error("Engram: tama\xF1o o hash SHA-256 no coincide con el artefacto aprobado.");
|
|
5799
|
+
}
|
|
5800
|
+
fs19.mkdirSync(path25.dirname(bin), { recursive: true });
|
|
5801
|
+
staging = fs19.mkdtempSync(path25.join(path25.dirname(bin), ".engram-install-"));
|
|
5802
|
+
const archivePath = path25.join(staging, expectedName);
|
|
5803
|
+
fs19.writeFileSync(archivePath, archive, { flag: "wx", mode: 384 });
|
|
5804
|
+
const binary = execFileSync6(resolveTarBin(), ["-xOf", archivePath, binaryName], {
|
|
5805
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
5806
|
+
timeout: 3e4,
|
|
5807
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
5808
|
+
});
|
|
5809
|
+
if (binary.length === 0) throw new Error("El artefacto Engram no contiene un binario v\xE1lido.");
|
|
5810
|
+
const stagedBin = path25.join(staging, binaryName);
|
|
5811
|
+
fs19.writeFileSync(stagedBin, binary, { flag: "wx", mode: 493 });
|
|
5812
|
+
fs19.linkSync(stagedBin, bin);
|
|
5813
|
+
outcome = { ok: true, bin };
|
|
5814
|
+
}
|
|
5753
5815
|
} catch (error) {
|
|
5754
|
-
|
|
5755
|
-
}
|
|
5756
|
-
|
|
5816
|
+
outcome = { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
5817
|
+
}
|
|
5818
|
+
if (staging !== void 0) {
|
|
5819
|
+
try {
|
|
5820
|
+
fs19.rmSync(staging, { recursive: true, force: true });
|
|
5821
|
+
} catch (cleanupError) {
|
|
5822
|
+
const cleanupMsg = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
|
|
5823
|
+
if (outcome !== void 0 && outcome.ok) {
|
|
5824
|
+
outcome = {
|
|
5825
|
+
ok: true,
|
|
5826
|
+
bin: outcome.bin,
|
|
5827
|
+
warning: `Limpieza del directorio temporal ${staging} fallida tras instalar Engram: ${cleanupMsg}. El binario qued\xF3 instalado en ${outcome.bin}.`
|
|
5828
|
+
};
|
|
5829
|
+
} else if (outcome !== void 0 && !outcome.ok) {
|
|
5830
|
+
outcome = { ok: false, reason: `${outcome.reason} (adem\xE1s fall\xF3 la limpieza temporal: ${cleanupMsg})` };
|
|
5831
|
+
}
|
|
5832
|
+
}
|
|
5757
5833
|
}
|
|
5834
|
+
return outcome ?? { ok: false, reason: "Engram: instalaci\xF3n finaliz\xF3 sin resultado verificable." };
|
|
5758
5835
|
}
|
|
5759
5836
|
|
|
5760
5837
|
// src/cli.ts
|
|
@@ -6088,7 +6165,10 @@ async function resolveHostEngramForInstall(flags) {
|
|
|
6088
6165
|
}
|
|
6089
6166
|
try {
|
|
6090
6167
|
const result = await installMissingEngram();
|
|
6091
|
-
if (result.ok)
|
|
6168
|
+
if (result.ok) {
|
|
6169
|
+
if (result.warning) p6.log.warn(result.warning);
|
|
6170
|
+
return { ok: true, bin: result.bin };
|
|
6171
|
+
}
|
|
6092
6172
|
return { ok: false, message: `Engram: ${result.reason}` };
|
|
6093
6173
|
} catch (error) {
|
|
6094
6174
|
return { ok: false, message: `Engram: ${error instanceof Error ? error.message : String(error)}` };
|
|
@@ -6143,7 +6223,11 @@ async function runSelectedPi(options) {
|
|
|
6143
6223
|
const answer = await p6.confirm({ message, initialValue });
|
|
6144
6224
|
return !p6.isCancel(answer) && answer;
|
|
6145
6225
|
},
|
|
6146
|
-
|
|
6226
|
+
installShared: async () => {
|
|
6227
|
+
const result2 = await installMissingEngram();
|
|
6228
|
+
if (result2.ok && result2.warning) p6.log.warn(result2.warning);
|
|
6229
|
+
return result2;
|
|
6230
|
+
}
|
|
6147
6231
|
});
|
|
6148
6232
|
if (requirement.kind !== "existing") {
|
|
6149
6233
|
console.error(requirement.kind === "offer" ? "Pi: instalaci\xF3n cancelada; Engram sigue siendo obligatorio." : `Pi: ${requirement.reason}. ${requirement.remedy}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jorgex-stack",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.59",
|
|
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",
|