jorgex-stack 1.9.59 → 1.9.61
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 +7 -7
- package/dist/chunk-2CBCBOP7.js +245 -0
- package/dist/{chunk-NNPFC6QV.js → chunk-4USZMJ3I.js} +6 -15
- package/dist/chunk-66WVKOU4.js +693 -0
- package/dist/chunk-B76ZJXXD.js +989 -0
- package/dist/{chunk-M6QX2F3A.js → chunk-BSHTDTJL.js} +5 -6
- package/dist/{chunk-GOLJ5PA3.js → chunk-KKN4OYHD.js} +5 -12
- package/dist/{claude-code-WY4JJAXP.js → claude-code-BBHLN5TD.js} +3 -2
- package/dist/cli.js +232 -217
- package/dist/{codex-WSWHXYJ3.js → codex-ALGP2YBC.js} +3 -2
- package/dist/official-engram-setup-4WIXM4EF.js +34 -0
- package/dist/{opencode-NUDGK6J7.js → opencode-VG2IZRRF.js} +3 -2
- package/dist/pi-CKFSPGJU.js +13 -0
- package/package.json +1 -1
- package/dist/chunk-KB5IQEKL.js +0 -1400
- package/stack/system-prompt/engram-protocol.md +0 -55
package/dist/cli.js
CHANGED
|
@@ -12,32 +12,27 @@ import {
|
|
|
12
12
|
inspectOpencodePluginFile,
|
|
13
13
|
opencodeAdapter,
|
|
14
14
|
shouldRetireLegacyEngram
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-BSHTDTJL.js";
|
|
16
16
|
import {
|
|
17
17
|
claudeCodeAdapter
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-4USZMJ3I.js";
|
|
19
19
|
import {
|
|
20
20
|
codexAdapter
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-KKN4OYHD.js";
|
|
22
22
|
import {
|
|
23
23
|
DEFAULT_MODEL_MAP,
|
|
24
24
|
DEVTOOLS_MCP_SERVER,
|
|
25
|
+
LEGACY_SYSTEM_PROMPT_SECTIONS,
|
|
25
26
|
SYSTEM_PROMPT_SECTIONS,
|
|
26
27
|
assertSystemPromptFile,
|
|
27
28
|
assertSystemPromptMarkers,
|
|
28
|
-
copyFile,
|
|
29
|
-
createBackup,
|
|
30
29
|
detectClaudeCode,
|
|
31
30
|
detectCodex,
|
|
32
31
|
detectEngram,
|
|
33
32
|
detectOpenCode,
|
|
34
33
|
engramVersion,
|
|
35
|
-
ensureDir,
|
|
36
34
|
ensureModelMapFile,
|
|
37
35
|
hasHealthyManagedMarkdownMarkers,
|
|
38
|
-
isContainedIn,
|
|
39
|
-
listBackups,
|
|
40
|
-
listFilesRecursive,
|
|
41
36
|
loadCanonicalAgents,
|
|
42
37
|
loadCanonicalHooks,
|
|
43
38
|
loadCanonicalMcp,
|
|
@@ -46,26 +41,37 @@ import {
|
|
|
46
41
|
lookPath,
|
|
47
42
|
modelMapFile,
|
|
48
43
|
planDetectedBinCommand,
|
|
49
|
-
pruneEmptyDirs,
|
|
50
44
|
readSystemPromptFile,
|
|
51
|
-
readTextIfExists,
|
|
52
45
|
removeMarkdownSection,
|
|
53
46
|
removeSystemPromptSections,
|
|
54
47
|
resolveAgentModel,
|
|
55
|
-
restoreBackup,
|
|
56
48
|
runDetectedBin,
|
|
49
|
+
stripLeadingHtmlComments,
|
|
50
|
+
upsertMarkdownSection
|
|
51
|
+
} from "./chunk-66WVKOU4.js";
|
|
52
|
+
import {
|
|
53
|
+
piAdapter,
|
|
54
|
+
piSystemPromptFile
|
|
55
|
+
} from "./chunk-2CBCBOP7.js";
|
|
56
|
+
import {
|
|
57
|
+
copyFile,
|
|
58
|
+
createBackup,
|
|
59
|
+
ensureDir,
|
|
60
|
+
isContainedIn,
|
|
61
|
+
listBackups,
|
|
62
|
+
listFilesRecursive,
|
|
63
|
+
pruneEmptyDirs,
|
|
64
|
+
readTextIfExists,
|
|
65
|
+
restoreBackup,
|
|
57
66
|
runOfficialSetupIfNeeded,
|
|
58
67
|
sameFileContent,
|
|
59
68
|
shouldRunOfficialSetup,
|
|
60
|
-
stripLeadingHtmlComments,
|
|
61
|
-
upsertMarkdownSection,
|
|
62
69
|
validateOfficialSetupDestination,
|
|
63
70
|
writeText
|
|
64
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-B76ZJXXD.js";
|
|
65
72
|
import {
|
|
66
73
|
HOME,
|
|
67
74
|
dataDir,
|
|
68
|
-
samePath,
|
|
69
75
|
stackRoot
|
|
70
76
|
} from "./chunk-NQZVJFV2.js";
|
|
71
77
|
|
|
@@ -355,7 +361,6 @@ function planSystemPrompt(adapter, ctx) {
|
|
|
355
361
|
);
|
|
356
362
|
const modules = {
|
|
357
363
|
"system-prompt": composeProgrammaticSystemPrompt(ctx.stackDir, readModule("AGENTS.md"), ctx.mode),
|
|
358
|
-
"engram-protocol": adapter.injectEngramProtocol(ctx) ? readModule("engram-protocol.md") : void 0,
|
|
359
364
|
context7: readModule("context7.md"),
|
|
360
365
|
playwright: ctx.playwrightCliEnabled ? readModule("browser-playwright.md") : void 0,
|
|
361
366
|
"chrome-devtools": ctx.enabledMcpServers?.has(DEVTOOLS_MCP_SERVER) ? readModule("browser-chrome-devtools.md") : void 0,
|
|
@@ -367,6 +372,9 @@ function planSystemPrompt(adapter, ctx) {
|
|
|
367
372
|
const body = sections[section];
|
|
368
373
|
content = body ? upsertMarkdownSection(content, section, body) : removeMarkdownSection(content, section);
|
|
369
374
|
}
|
|
375
|
+
for (const section of LEGACY_SYSTEM_PROMPT_SECTIONS) {
|
|
376
|
+
content = removeMarkdownSection(content, section);
|
|
377
|
+
}
|
|
370
378
|
return [{ kind: "write", target, content }];
|
|
371
379
|
}
|
|
372
380
|
|
|
@@ -457,12 +465,6 @@ function planPlugins(adapter, ctx) {
|
|
|
457
465
|
if (content.includes('"{{ENGRAM_BIN}}"')) {
|
|
458
466
|
content = content.replace(/"\{\{ENGRAM_BIN\}\}"/g, JSON.stringify(ctx.engramBin ?? "engram"));
|
|
459
467
|
}
|
|
460
|
-
if (content.includes('"{{ENGRAM_PROTOCOL}}"')) {
|
|
461
|
-
const protocol = stripLeadingHtmlComments(
|
|
462
|
-
fs7.readFileSync(path9.join(ctx.stackDir, "system-prompt", "engram-protocol.md"), "utf8").replace(/\r\n/g, "\n")
|
|
463
|
-
);
|
|
464
|
-
content = content.replace(/"\{\{ENGRAM_PROTOCOL\}\}"/g, JSON.stringify(protocol));
|
|
465
|
-
}
|
|
466
468
|
content = content.replace(/(from\s+["'])(\.{1,2}\/[^"']+?)\.js(["'])/g, "$1$2.ts$3");
|
|
467
469
|
if (content === raw) return { kind: "copy", source: sourceFile, target };
|
|
468
470
|
return { kind: "write", target, content };
|
|
@@ -1491,52 +1493,16 @@ async function runInstall(opts) {
|
|
|
1491
1493
|
|
|
1492
1494
|
// src/uninstall.ts
|
|
1493
1495
|
import fs12 from "fs";
|
|
1494
|
-
import
|
|
1496
|
+
import path15 from "path";
|
|
1495
1497
|
import * as p2 from "@clack/prompts";
|
|
1496
1498
|
|
|
1497
1499
|
// src/lib/pi-projection-lifecycle.ts
|
|
1498
1500
|
import fs11 from "fs";
|
|
1499
|
-
import
|
|
1501
|
+
import path14 from "path";
|
|
1500
1502
|
import { createHash } from "crypto";
|
|
1501
1503
|
|
|
1502
|
-
// src/adapters/pi.ts
|
|
1503
|
-
import path13 from "path";
|
|
1504
|
-
function piSystemPromptFile(targetDir) {
|
|
1505
|
-
const configDir = targetDir === void 0 ? process.env.PI_CODING_AGENT_DIR ?? path13.join(HOME, ".pi", "agent") : path13.join(path13.resolve(targetDir), "pi-agent");
|
|
1506
|
-
return path13.join(configDir, "AGENTS.md");
|
|
1507
|
-
}
|
|
1508
|
-
var piAdapter = {
|
|
1509
|
-
id: "pi",
|
|
1510
|
-
paths(configDir) {
|
|
1511
|
-
const piConfigDir = path13.dirname(piSystemPromptFile());
|
|
1512
|
-
const agentsHome = samePath(configDir, piConfigDir) ? HOME : path13.join(path13.dirname(configDir), "home");
|
|
1513
|
-
return {
|
|
1514
|
-
systemPromptFile: path13.join(configDir, "AGENTS.md"),
|
|
1515
|
-
agentsDir: path13.join(configDir, "agents"),
|
|
1516
|
-
skillsDir: path13.join(agentsHome, ".agents", "skills"),
|
|
1517
|
-
commandsDir: path13.join(configDir, "prompts"),
|
|
1518
|
-
pluginsDir: null,
|
|
1519
|
-
scriptsDir: path13.join(configDir, "scripts"),
|
|
1520
|
-
outputStylesDir: null,
|
|
1521
|
-
profilesDir: null
|
|
1522
|
-
};
|
|
1523
|
-
},
|
|
1524
|
-
renderCommand(file, content) {
|
|
1525
|
-
return { file, content: content.replace(/\{\{input\}\}/g, "$ARGUMENTS") };
|
|
1526
|
-
},
|
|
1527
|
-
injectEngramProtocol() {
|
|
1528
|
-
return true;
|
|
1529
|
-
},
|
|
1530
|
-
// La guía Context7 se habilita al adoptar su registro HTTP en Pi.
|
|
1531
|
-
adaptSystemPromptSections(sections) {
|
|
1532
|
-
const modular = { ...sections };
|
|
1533
|
-
delete modular.context7;
|
|
1534
|
-
return modular;
|
|
1535
|
-
}
|
|
1536
|
-
};
|
|
1537
|
-
|
|
1538
1504
|
// src/lib/pi-package-lifecycle.ts
|
|
1539
|
-
import
|
|
1505
|
+
import path13 from "path";
|
|
1540
1506
|
var REQUIRED_CAPABILITIES = /* @__PURE__ */ new Set([
|
|
1541
1507
|
"foundation-contract-v1",
|
|
1542
1508
|
"runner-json-v1",
|
|
@@ -1688,7 +1654,7 @@ function parseReceiptShape(receiptJson) {
|
|
|
1688
1654
|
return null;
|
|
1689
1655
|
}
|
|
1690
1656
|
if (engram === void 0) return "upgrade-required";
|
|
1691
|
-
if (engram === null || typeof engram !== "object" || Array.isArray(engram) || typeof Reflect.get(engram, "binary") !== "string" || !
|
|
1657
|
+
if (engram === null || typeof engram !== "object" || Array.isArray(engram) || typeof Reflect.get(engram, "binary") !== "string" || !path13.isAbsolute(Reflect.get(engram, "binary"))) {
|
|
1692
1658
|
return null;
|
|
1693
1659
|
}
|
|
1694
1660
|
return parsed;
|
|
@@ -1725,7 +1691,7 @@ function planPiPackageLifecycle(input) {
|
|
|
1725
1691
|
if (input.receiptJson !== null) {
|
|
1726
1692
|
const parsedReceipt = parseReceipt(input.receiptJson, input.candidate, {
|
|
1727
1693
|
kind: input.scope.kind,
|
|
1728
|
-
codingAgentDir:
|
|
1694
|
+
codingAgentDir: path13.resolve(input.scope.codingAgentDir)
|
|
1729
1695
|
}, input.engramBin);
|
|
1730
1696
|
if (parsedReceipt === "upgrade-required") return blocked(input, "receipt-upgrade-required");
|
|
1731
1697
|
if (parsedReceipt === null) return blocked(input, "receipt-corrupt");
|
|
@@ -1760,7 +1726,7 @@ function planPiPackageLifecycle(input) {
|
|
|
1760
1726
|
},
|
|
1761
1727
|
receipt: expectedReceipt(input.candidate, "installing", {
|
|
1762
1728
|
kind: input.scope.kind,
|
|
1763
|
-
codingAgentDir:
|
|
1729
|
+
codingAgentDir: path13.resolve(input.scope.codingAgentDir)
|
|
1764
1730
|
}, input.engramBin),
|
|
1765
1731
|
ownership: ownership(true)
|
|
1766
1732
|
};
|
|
@@ -1775,7 +1741,7 @@ function parseRunnerRecord(stdout, stderr, command, candidate, packageRunner) {
|
|
|
1775
1741
|
const parsed = JSON.parse(body);
|
|
1776
1742
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
1777
1743
|
const record = parsed;
|
|
1778
|
-
if (record.schemaVersion !== candidate.contract.runner.schemaVersion || record.command !== command || record.ok !== true || record.package === null || typeof record.package !== "object" || record.package.name !== candidate.package.name || record.package.version !== candidate.package.version || typeof record.package.root !== "string" || !
|
|
1744
|
+
if (record.schemaVersion !== candidate.contract.runner.schemaVersion || record.command !== command || record.ok !== true || record.package === null || typeof record.package !== "object" || record.package.name !== candidate.package.name || record.package.version !== candidate.package.version || typeof record.package.root !== "string" || !path13.isAbsolute(record.package.root) || path13.resolve(packageRunner) !== path13.resolve(record.package.root, "bin", "jorgex-pi.mjs")) {
|
|
1779
1745
|
return null;
|
|
1780
1746
|
}
|
|
1781
1747
|
return record;
|
|
@@ -1923,10 +1889,10 @@ function validateOwnedOperationState(input) {
|
|
|
1923
1889
|
}))) {
|
|
1924
1890
|
return { kind: "blocked", reason: "receipt-untrusted" };
|
|
1925
1891
|
}
|
|
1926
|
-
if (receipt.scope.kind !== (input.paths.targetDir ? "target-dir" : "real") ||
|
|
1892
|
+
if (receipt.scope.kind !== (input.paths.targetDir ? "target-dir" : "real") || path13.resolve(receipt.scope.codingAgentDir) !== path13.resolve(input.paths.codingAgentDir)) {
|
|
1927
1893
|
return { kind: "blocked", reason: "source-divergent" };
|
|
1928
1894
|
}
|
|
1929
|
-
if (input.engramBin !== null &&
|
|
1895
|
+
if (input.engramBin !== null && path13.resolve(receipt.engram.binary) !== path13.resolve(input.engramBin)) {
|
|
1930
1896
|
return { kind: "blocked", reason: "receipt-corrupt" };
|
|
1931
1897
|
}
|
|
1932
1898
|
const source = receipt.candidate.package.source;
|
|
@@ -2033,7 +1999,7 @@ var RETIRED_PLAYWRIGHT_FILES = [
|
|
|
2033
1999
|
"references/video-recording.md"
|
|
2034
2000
|
];
|
|
2035
2001
|
function retiredPlaywrightFiles(scope) {
|
|
2036
|
-
return RETIRED_PLAYWRIGHT_FILES.map((file) =>
|
|
2002
|
+
return RETIRED_PLAYWRIGHT_FILES.map((file) => path14.resolve(scope.home, ".agents", "skills", "playwright-cli", file));
|
|
2037
2003
|
}
|
|
2038
2004
|
function handoffEnabled(input, kind) {
|
|
2039
2005
|
return (kind === "devtools" ? input.devtoolsMcpEnabled : input.playwrightHandoffEnabled) === true;
|
|
@@ -2042,18 +2008,18 @@ var preparedPiProjectionUninstalls = /* @__PURE__ */ new WeakMap();
|
|
|
2042
2008
|
function projectionScope(scope) {
|
|
2043
2009
|
return {
|
|
2044
2010
|
...scope,
|
|
2045
|
-
settingsFile:
|
|
2011
|
+
settingsFile: path14.join(scope.codingAgentDir, "settings.json")
|
|
2046
2012
|
};
|
|
2047
2013
|
}
|
|
2048
2014
|
function isInside(root, file) {
|
|
2049
|
-
const relative =
|
|
2050
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
2015
|
+
const relative = path14.relative(path14.resolve(root), path14.resolve(file));
|
|
2016
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path14.sep}`) && !path14.isAbsolute(relative);
|
|
2051
2017
|
}
|
|
2052
2018
|
function isManagedPath(scope, file) {
|
|
2053
2019
|
return isInside(scope.home, file) || isInside(scope.codingAgentDir, file);
|
|
2054
2020
|
}
|
|
2055
2021
|
function isAllowedPath(scope, file) {
|
|
2056
|
-
return isManagedPath(scope, file) ||
|
|
2022
|
+
return isManagedPath(scope, file) || path14.resolve(file) === path14.resolve(scope.receiptFile);
|
|
2057
2023
|
}
|
|
2058
2024
|
function projectedPiAdapter(scope) {
|
|
2059
2025
|
const paths = piAdapter.paths(scope.codingAgentDir);
|
|
@@ -2061,7 +2027,7 @@ function projectedPiAdapter(scope) {
|
|
|
2061
2027
|
...piAdapter,
|
|
2062
2028
|
paths: () => ({
|
|
2063
2029
|
...paths,
|
|
2064
|
-
skillsDir:
|
|
2030
|
+
skillsDir: path14.join(scope.home, ".agents", "skills")
|
|
2065
2031
|
})
|
|
2066
2032
|
};
|
|
2067
2033
|
}
|
|
@@ -2105,7 +2071,7 @@ function projectionPlan(input, scope, includePrompt = true) {
|
|
|
2105
2071
|
return actions;
|
|
2106
2072
|
}
|
|
2107
2073
|
function handoffPath(scope, kind) {
|
|
2108
|
-
return
|
|
2074
|
+
return path14.resolve(scope.codingAgentDir, "jorgex-pi", `${kind}.v1.json`);
|
|
2109
2075
|
}
|
|
2110
2076
|
function contentHash(content) {
|
|
2111
2077
|
return createHash("sha256").update(content).digest("hex");
|
|
@@ -2118,7 +2084,7 @@ function hasActionDrift(action, deps) {
|
|
|
2118
2084
|
}
|
|
2119
2085
|
function applyActions(actions, deps, handoffs = []) {
|
|
2120
2086
|
for (const action of actions) {
|
|
2121
|
-
const handoff = handoffs.find((entry) =>
|
|
2087
|
+
const handoff = handoffs.find((entry) => path14.resolve(action.target) === entry.file);
|
|
2122
2088
|
if (handoff) {
|
|
2123
2089
|
try {
|
|
2124
2090
|
if (deps.readText(handoff.file) !== handoff.previous) return handoffConflict(handoff.kind, handoff.file);
|
|
@@ -2138,9 +2104,9 @@ function assertPlanContained(plan, scope) {
|
|
|
2138
2104
|
}
|
|
2139
2105
|
}
|
|
2140
2106
|
function receiptFor(plan, scope) {
|
|
2141
|
-
const systemPrompt =
|
|
2107
|
+
const systemPrompt = path14.join(scope.codingAgentDir, "AGENTS.md");
|
|
2142
2108
|
const owned = [...new Set(
|
|
2143
|
-
plan.map((action) =>
|
|
2109
|
+
plan.map((action) => path14.resolve(action.target)).filter((target) => target !== systemPrompt)
|
|
2144
2110
|
)];
|
|
2145
2111
|
const receipt = {
|
|
2146
2112
|
schemaVersion: 1,
|
|
@@ -2153,7 +2119,7 @@ function receiptFor(plan, scope) {
|
|
|
2153
2119
|
owned
|
|
2154
2120
|
};
|
|
2155
2121
|
for (const kind of HANDOFF_KINDS) {
|
|
2156
|
-
const action = plan.find((entry) =>
|
|
2122
|
+
const action = plan.find((entry) => path14.resolve(entry.target) === handoffPath(scope, kind));
|
|
2157
2123
|
if (action) receipt[kind] = { sha256: contentHash(canonicalActionContent(action)) };
|
|
2158
2124
|
}
|
|
2159
2125
|
return receipt;
|
|
@@ -2194,7 +2160,7 @@ function parseReceipt2(raw, expected) {
|
|
|
2194
2160
|
if (matches(expectedOwned)) return { schemaVersion: 1, scope: expected.scope, owned: expectedOwned, ...digests };
|
|
2195
2161
|
const retired = retiredPlaywrightFiles(expected.scope);
|
|
2196
2162
|
if (retired.some((file) => expectedOwned.includes(file))) return null;
|
|
2197
|
-
const skillsRoot = `${
|
|
2163
|
+
const skillsRoot = `${path14.resolve(expected.scope.home, ".agents", "skills")}${path14.sep}`;
|
|
2198
2164
|
const insertion = expectedOwned.findIndex((file) => !file.startsWith(skillsRoot) || file > retired[0]);
|
|
2199
2165
|
const legacyOwned = [...expectedOwned];
|
|
2200
2166
|
legacyOwned.splice(insertion === -1 ? legacyOwned.length : insertion, 0, ...retired);
|
|
@@ -2213,8 +2179,8 @@ function realPiProjectionScope() {
|
|
|
2213
2179
|
return {
|
|
2214
2180
|
kind: "real",
|
|
2215
2181
|
home: HOME,
|
|
2216
|
-
codingAgentDir:
|
|
2217
|
-
receiptFile:
|
|
2182
|
+
codingAgentDir: path14.dirname(piSystemPromptFile()),
|
|
2183
|
+
receiptFile: path14.join(dataDir(), "pi-projection-receipt.json")
|
|
2218
2184
|
};
|
|
2219
2185
|
}
|
|
2220
2186
|
function readTextOnlyIfMissing(file) {
|
|
@@ -2252,13 +2218,13 @@ function manifestOwned(manifest) {
|
|
|
2252
2218
|
return new Set([
|
|
2253
2219
|
...manifest.runtimes.codex?.owned ?? [],
|
|
2254
2220
|
...manifest.runtimes.opencode?.owned ?? []
|
|
2255
|
-
].map((file) =>
|
|
2221
|
+
].map((file) => path14.resolve(file)));
|
|
2256
2222
|
}
|
|
2257
2223
|
function withoutManagedPromptSections(content) {
|
|
2258
2224
|
return removeSystemPromptSections(content);
|
|
2259
2225
|
}
|
|
2260
2226
|
function uniquePaths(paths) {
|
|
2261
|
-
return [...new Set(paths.map((file) =>
|
|
2227
|
+
return [...new Set(paths.map((file) => path14.resolve(file)))];
|
|
2262
2228
|
}
|
|
2263
2229
|
function blocked2(reason, paths, remedy) {
|
|
2264
2230
|
return { kind: "blocked", reason, paths: uniquePaths(paths), remedy };
|
|
@@ -2365,7 +2331,7 @@ function preparePiProjectionUninstall(input, deps) {
|
|
|
2365
2331
|
}
|
|
2366
2332
|
const scope = projectionScope(input.scope);
|
|
2367
2333
|
const expectedReceipt2 = expectedProjectionReceipt(input, scope);
|
|
2368
|
-
const prompt =
|
|
2334
|
+
const prompt = path14.join(scope.codingAgentDir, "AGENTS.md");
|
|
2369
2335
|
let existingPrompt;
|
|
2370
2336
|
try {
|
|
2371
2337
|
existingPrompt = deps.readText(prompt);
|
|
@@ -2378,7 +2344,7 @@ function preparePiProjectionUninstall(input, deps) {
|
|
|
2378
2344
|
return blocked2("projection-prompt-markers", [prompt], error instanceof Error ? error.message : String(error));
|
|
2379
2345
|
}
|
|
2380
2346
|
const promptContent = existingPrompt === null ? null : withoutManagedPromptSections(existingPrompt);
|
|
2381
|
-
const promptUpdate = promptContent === null || promptContent === existingPrompt ? null : { file:
|
|
2347
|
+
const promptUpdate = promptContent === null || promptContent === existingPrompt ? null : { file: path14.resolve(prompt), content: promptContent };
|
|
2382
2348
|
const receiptRead = readProjectionReceipt(scope.receiptFile, deps);
|
|
2383
2349
|
if (receiptRead.kind === "unreadable") return receiptUnreadable(scope.receiptFile);
|
|
2384
2350
|
let ownedToRemove = [];
|
|
@@ -2396,7 +2362,7 @@ function preparePiProjectionUninstall(input, deps) {
|
|
|
2396
2362
|
return cleanupFailure([scope.receiptFile]);
|
|
2397
2363
|
}
|
|
2398
2364
|
ownedToRemove = receipt.owned.filter((owned) => !retained.has(owned));
|
|
2399
|
-
receiptFile =
|
|
2365
|
+
receiptFile = path14.resolve(scope.receiptFile);
|
|
2400
2366
|
backupTargets = [...backupTargets, ...receipt.owned, receiptFile];
|
|
2401
2367
|
}
|
|
2402
2368
|
const handoffs = [];
|
|
@@ -2474,16 +2440,16 @@ function runPiProjectionLifecycle(input, deps) {
|
|
|
2474
2440
|
const prepared = preparePiProjectionUninstall(input, deps);
|
|
2475
2441
|
return prepared.kind === "blocked" ? prepared : completePiProjectionUninstall(prepared.plan, deps);
|
|
2476
2442
|
}
|
|
2477
|
-
const prompt =
|
|
2443
|
+
const prompt = path14.join(scope.codingAgentDir, "AGENTS.md");
|
|
2478
2444
|
try {
|
|
2479
2445
|
assertSystemPromptMarkers(deps.readText(prompt), prompt);
|
|
2480
2446
|
} catch (error) {
|
|
2481
2447
|
return blocked2("projection-prompt-markers", [prompt], error instanceof Error ? error.message : String(error));
|
|
2482
2448
|
}
|
|
2483
|
-
if (input.devtoolsMcpEnabled && (!input.pnpmBin || !
|
|
2449
|
+
if (input.devtoolsMcpEnabled && (!input.pnpmBin || !path14.isAbsolute(input.pnpmBin))) {
|
|
2484
2450
|
return blocked2("projection-devtools-command", [handoffPath(scope, "devtools")], "DevTools requiere un ejecutable pnpm absoluto disponible en PATH.");
|
|
2485
2451
|
}
|
|
2486
|
-
if (input.playwrightHandoffEnabled && (!input.playwrightCliCommand || !
|
|
2452
|
+
if (input.playwrightHandoffEnabled && (!input.playwrightCliCommand || !path14.isAbsolute(input.playwrightCliCommand) || /[\u0000-\u001f\u007f]/.test(input.playwrightCliCommand))) {
|
|
2487
2453
|
return blocked2("projection-playwright-command", [handoffPath(scope, "playwright")], "Playwright requiere un ejecutable absoluto verificado. Abre una terminal nueva tras pnpm setup y reintenta install --playwright.");
|
|
2488
2454
|
}
|
|
2489
2455
|
const plan = projectionPlan(input, scope);
|
|
@@ -2496,12 +2462,12 @@ function runPiProjectionLifecycle(input, deps) {
|
|
|
2496
2462
|
const expectedReceipt2 = receiptContent(receipt);
|
|
2497
2463
|
const drifted = plan.filter((action) => hasActionDrift(action, deps));
|
|
2498
2464
|
for (const { kind, file } of checked.handoffs) {
|
|
2499
|
-
if (handoffEnabled(input, kind) && checked.previous?.[kind]?.sha256 !== receipt[kind]?.sha256 && !drifted.some((action) =>
|
|
2465
|
+
if (handoffEnabled(input, kind) && checked.previous?.[kind]?.sha256 !== receipt[kind]?.sha256 && !drifted.some((action) => path14.resolve(action.target) === file)) {
|
|
2500
2466
|
return input.operation === "doctor" ? { kind: "drift", paths: [file] } : handoffConflict(kind, file);
|
|
2501
2467
|
}
|
|
2502
2468
|
}
|
|
2503
2469
|
if (input.operation === "doctor") {
|
|
2504
|
-
const paths = drifted.map((action) =>
|
|
2470
|
+
const paths = drifted.map((action) => path14.resolve(action.target));
|
|
2505
2471
|
paths.push(...removedHandoffs.map(({ file }) => file), ...retiredSkills);
|
|
2506
2472
|
const currentSettings2 = deps.readText(scope.settingsFile);
|
|
2507
2473
|
if (currentSettings2 === null || filterProjectedPiPackage(currentSettings2, input.packageSource) !== currentSettings2) {
|
|
@@ -2560,12 +2526,12 @@ function runPiProjectionLifecycle(input, deps) {
|
|
|
2560
2526
|
return { kind: "synced", changed: drifted.length > 0 || packageWillChange || receiptChanged || removedHandoffs.length > 0 };
|
|
2561
2527
|
}
|
|
2562
2528
|
function systemProjectionLifecycle(input) {
|
|
2563
|
-
const targetRoot = input.targetDir === void 0 ? null :
|
|
2529
|
+
const targetRoot = input.targetDir === void 0 ? null : path14.resolve(input.targetDir);
|
|
2564
2530
|
const scope = targetRoot === null ? realPiProjectionScope() : {
|
|
2565
2531
|
kind: "target-dir",
|
|
2566
|
-
home:
|
|
2567
|
-
codingAgentDir:
|
|
2568
|
-
receiptFile:
|
|
2532
|
+
home: path14.join(targetRoot, "home"),
|
|
2533
|
+
codingAgentDir: path14.dirname(piSystemPromptFile(targetRoot)),
|
|
2534
|
+
receiptFile: path14.join(targetRoot, "state", "pi-projection-receipt.json")
|
|
2569
2535
|
};
|
|
2570
2536
|
return {
|
|
2571
2537
|
input: {
|
|
@@ -2586,14 +2552,14 @@ function systemProjectionLifecycle(input) {
|
|
|
2586
2552
|
backup: (paths) => createBackup(
|
|
2587
2553
|
paths,
|
|
2588
2554
|
`pi-projection-${input.operation}`,
|
|
2589
|
-
targetRoot === null ? void 0 :
|
|
2555
|
+
targetRoot === null ? void 0 : path14.join(targetRoot, "backups")
|
|
2590
2556
|
),
|
|
2591
2557
|
writeText,
|
|
2592
2558
|
copyFile,
|
|
2593
2559
|
removeFile: (file) => {
|
|
2594
2560
|
fs11.rmSync(file, { force: true });
|
|
2595
|
-
if (retiredPlaywrightFiles(scope).includes(
|
|
2596
|
-
pruneEmptyDirs(file,
|
|
2561
|
+
if (retiredPlaywrightFiles(scope).includes(path14.resolve(file))) {
|
|
2562
|
+
pruneEmptyDirs(file, path14.join(scope.home, ".agents", "skills"));
|
|
2597
2563
|
}
|
|
2598
2564
|
},
|
|
2599
2565
|
readManifest: targetRoot === null ? readManifest : () => ({ runtimes: {} })
|
|
@@ -2696,7 +2662,7 @@ async function runUninstall(opts) {
|
|
|
2696
2662
|
if (!detection.installed) continue;
|
|
2697
2663
|
const keepCtx = makeContext(keep, detection.configDir);
|
|
2698
2664
|
if (!keepCtx) continue;
|
|
2699
|
-
for (const action of buildContentPlan(keep, keepCtx)) retained.add(
|
|
2665
|
+
for (const action of buildContentPlan(keep, keepCtx)) retained.add(path15.resolve(action.target));
|
|
2700
2666
|
}
|
|
2701
2667
|
}
|
|
2702
2668
|
for (const id of opts.runtimes) {
|
|
@@ -2722,16 +2688,16 @@ async function runUninstall(opts) {
|
|
|
2722
2688
|
exitCode = 1;
|
|
2723
2689
|
continue;
|
|
2724
2690
|
}
|
|
2725
|
-
const mergedTargets = new Set(unmerge.map((a) =>
|
|
2691
|
+
const mergedTargets = new Set(unmerge.map((a) => path15.resolve(a.target)));
|
|
2726
2692
|
const usingRealConfig = opts.targetDir === void 0;
|
|
2727
2693
|
const prevOwned = usingRealConfig ? readManifest().runtimes[id]?.owned ?? [] : [];
|
|
2728
|
-
const pruneRoot = usingRealConfig ? HOME :
|
|
2694
|
+
const pruneRoot = usingRealConfig ? HOME : path15.dirname(configDir);
|
|
2729
2695
|
const planTargets = [
|
|
2730
|
-
.../* @__PURE__ */ new Set([...buildContentPlan(adapter, ctx).map((a) =>
|
|
2696
|
+
.../* @__PURE__ */ new Set([...buildContentPlan(adapter, ctx).map((a) => path15.resolve(a.target)), ...prevOwned.map((t) => path15.resolve(t))])
|
|
2731
2697
|
].filter((t) => !mergedTargets.has(t) && fs12.existsSync(t));
|
|
2732
2698
|
const deleteTargets = planTargets.filter((t) => {
|
|
2733
2699
|
if (retained.has(t) || !isContainedIn(t, pruneRoot)) return false;
|
|
2734
|
-
if (
|
|
2700
|
+
if (path15.basename(t) !== "engram.ts") return true;
|
|
2735
2701
|
const state = inspectOpencodePluginFile(t);
|
|
2736
2702
|
if (state === "official" || state === "unknown") return false;
|
|
2737
2703
|
return !ctx.preserveEngram;
|
|
@@ -2814,7 +2780,7 @@ async function runUninstall(opts) {
|
|
|
2814
2780
|
}
|
|
2815
2781
|
|
|
2816
2782
|
// src/doctor.ts
|
|
2817
|
-
import
|
|
2783
|
+
import path16 from "path";
|
|
2818
2784
|
import fs13 from "fs";
|
|
2819
2785
|
import * as p3 from "@clack/prompts";
|
|
2820
2786
|
function readDoctorTextIfExists(file) {
|
|
@@ -2828,12 +2794,12 @@ function readDoctorTextIfExists(file) {
|
|
|
2828
2794
|
var STALE_PERMISSIONS_MARKER = "differs from the stack default and was left untouched";
|
|
2829
2795
|
var UPGRADE_PERMISSIONS_REMEDY = "jorgex-stack sync --upgrade-permissions --dry-run";
|
|
2830
2796
|
function piAgentDir(targetDir) {
|
|
2831
|
-
return targetDir === void 0 ? process.env.PI_CODING_AGENT_DIR ??
|
|
2797
|
+
return targetDir === void 0 ? process.env.PI_CODING_AGENT_DIR ?? path16.join(HOME, ".pi", "agent") : path16.join(targetDir, "pi-agent");
|
|
2832
2798
|
}
|
|
2833
2799
|
function reportPiPermissions(targetDir) {
|
|
2834
2800
|
const agentDir = piAgentDir(targetDir);
|
|
2835
|
-
const configFile =
|
|
2836
|
-
const receiptFile =
|
|
2801
|
+
const configFile = path16.join(agentDir, "extensions", "pi-permission-system", "config.json");
|
|
2802
|
+
const receiptFile = path16.join(agentDir, "jorgex-pi", "permissions-lifecycle.v1.json");
|
|
2837
2803
|
let config;
|
|
2838
2804
|
let receipt;
|
|
2839
2805
|
try {
|
|
@@ -2870,7 +2836,7 @@ function resolvePlaywrightDoctorState(input) {
|
|
|
2870
2836
|
return { status: "healthy" };
|
|
2871
2837
|
}
|
|
2872
2838
|
function context7KeyConfigured(id, configDir) {
|
|
2873
|
-
const file = id === "codex" ?
|
|
2839
|
+
const file = id === "codex" ? path16.join(configDir, "config.toml") : id === "claude-code" ? path16.join(path16.dirname(configDir), `${path16.basename(configDir)}.json`) : path16.join(configDir, "opencode.json");
|
|
2874
2840
|
const content = readTextIfExists(file);
|
|
2875
2841
|
if (content === null) return null;
|
|
2876
2842
|
const match = /CONTEXT7_API_KEY"?\s*[:=]\s*"([^"]*)"/.exec(content);
|
|
@@ -2890,7 +2856,7 @@ function reportWritingStyle(options, style, mode) {
|
|
|
2890
2856
|
for (const id of runtimes) {
|
|
2891
2857
|
const adapter = id === "pi" ? piAdapter : ADAPTERS[id];
|
|
2892
2858
|
if (adapter === void 0) continue;
|
|
2893
|
-
const configDir = id === "pi" ? options.targetDir === void 0 ? process.env.PI_CODING_AGENT_DIR ??
|
|
2859
|
+
const configDir = id === "pi" ? options.targetDir === void 0 ? process.env.PI_CODING_AGENT_DIR ?? path16.join(HOME, ".pi", "agent") : path16.join(options.targetDir, "pi-agent") : options.targetDir ?? ADAPTERS[id].detect().configDir;
|
|
2894
2860
|
const file = adapter.paths(configDir).systemPromptFile;
|
|
2895
2861
|
try {
|
|
2896
2862
|
const content = readDoctorTextIfExists(file) ?? "";
|
|
@@ -2905,7 +2871,7 @@ function reportWritingStyle(options, style, mode) {
|
|
|
2905
2871
|
problems++;
|
|
2906
2872
|
}
|
|
2907
2873
|
if (id === "codex") {
|
|
2908
|
-
const override =
|
|
2874
|
+
const override = path16.join(configDir, "AGENTS.override.md");
|
|
2909
2875
|
if ((readDoctorTextIfExists(override) ?? "").trim() !== "") {
|
|
2910
2876
|
p3.log.warn(`Codex: ${override} no vac\xEDo puede ocultar el AGENTS.md gestionado; rev\xEDsalo sin modificarlo autom\xE1ticamente.`);
|
|
2911
2877
|
problems++;
|
|
@@ -2920,7 +2886,7 @@ function reportWritingStyle(options, style, mode) {
|
|
|
2920
2886
|
}
|
|
2921
2887
|
async function verifyOfficialForRuntime(runtime, configDir, engramBin, homeDir, isExplicitClaudeConfigDir) {
|
|
2922
2888
|
if (runtime === "claude-code") {
|
|
2923
|
-
const { verifyOfficialSetup: verifyOfficialSetup2 } = await import("./claude-code-
|
|
2889
|
+
const { verifyOfficialSetup: verifyOfficialSetup2 } = await import("./claude-code-BBHLN5TD.js");
|
|
2924
2890
|
const explicit = isExplicitClaudeConfigDir ?? process.env.CLAUDE_CONFIG_DIR !== void 0;
|
|
2925
2891
|
const report2 = await verifyOfficialSetup2({ configDir, engramBin, homeDir, isExplicitClaudeConfigDir: explicit });
|
|
2926
2892
|
return {
|
|
@@ -2930,7 +2896,7 @@ async function verifyOfficialForRuntime(runtime, configDir, engramBin, homeDir,
|
|
|
2930
2896
|
};
|
|
2931
2897
|
}
|
|
2932
2898
|
if (runtime === "codex") {
|
|
2933
|
-
const { verifyOfficialSetup: verifyOfficialSetup2 } = await import("./codex-
|
|
2899
|
+
const { verifyOfficialSetup: verifyOfficialSetup2 } = await import("./codex-ALGP2YBC.js");
|
|
2934
2900
|
const report2 = await verifyOfficialSetup2({ configDir, engramBin });
|
|
2935
2901
|
return {
|
|
2936
2902
|
ok: report2.ok,
|
|
@@ -2938,7 +2904,16 @@ async function verifyOfficialForRuntime(runtime, configDir, engramBin, homeDir,
|
|
|
2938
2904
|
...report2.reason === void 0 ? {} : { reason: report2.reason }
|
|
2939
2905
|
};
|
|
2940
2906
|
}
|
|
2941
|
-
|
|
2907
|
+
if (runtime === "pi") {
|
|
2908
|
+
const { verifyOfficialSetup: verifyOfficialSetup2 } = await import("./pi-CKFSPGJU.js");
|
|
2909
|
+
const report2 = await verifyOfficialSetup2({ configDir, engramBin, homeDir });
|
|
2910
|
+
return {
|
|
2911
|
+
ok: report2.ok,
|
|
2912
|
+
layers: report2.layers,
|
|
2913
|
+
...report2.reason === void 0 ? {} : { reason: report2.reason }
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
const { verifyOfficialSetup } = await import("./opencode-VG2IZRRF.js");
|
|
2942
2917
|
const report = await verifyOfficialSetup({ configDir, engramBin });
|
|
2943
2918
|
return {
|
|
2944
2919
|
ok: report.ok,
|
|
@@ -2981,8 +2956,8 @@ async function runDoctor(options = {}) {
|
|
|
2981
2956
|
engramBinAvailable = true;
|
|
2982
2957
|
}
|
|
2983
2958
|
}
|
|
2984
|
-
const engramDataDir = process.env.ENGRAM_DATA_DIR ??
|
|
2985
|
-
const engramDb =
|
|
2959
|
+
const engramDataDir = process.env.ENGRAM_DATA_DIR ?? path16.join(HOME, ".engram");
|
|
2960
|
+
const engramDb = path16.join(engramDataDir, "engram.db");
|
|
2986
2961
|
if (fs13.existsSync(engramDb)) {
|
|
2987
2962
|
const sizeMb = (fs13.statSync(engramDb).size / 1024 / 1024).toFixed(1);
|
|
2988
2963
|
p3.log.info(`Engram DB: ${engramDb} (${sizeMb} MB de memorias \u2014 el stack no la toca JAM\xC1S).`);
|
|
@@ -3087,7 +3062,7 @@ async function runDoctor(options = {}) {
|
|
|
3087
3062
|
p3.log.warn(`${adapter.name}: ${orphans.length} archivos hu\xE9rfanos de versiones previas \u2192 ejecuta 'sync'.`);
|
|
3088
3063
|
problems++;
|
|
3089
3064
|
}
|
|
3090
|
-
if (adapter.id === "codex" && fs13.existsSync(
|
|
3065
|
+
if (adapter.id === "codex" && fs13.existsSync(path16.join(detection.configDir, "hooks.json"))) {
|
|
3091
3066
|
p3.log.info("Codex: recuerda que los hooks requieren aprobaci\xF3n manual \u2014 verifica con /hooks dentro de codex.");
|
|
3092
3067
|
}
|
|
3093
3068
|
const key = context7KeyConfigured(adapter.id, detection.configDir);
|
|
@@ -3136,14 +3111,14 @@ async function runDoctor(options = {}) {
|
|
|
3136
3111
|
|
|
3137
3112
|
// src/update.ts
|
|
3138
3113
|
import fs16 from "fs";
|
|
3139
|
-
import
|
|
3114
|
+
import path19 from "path";
|
|
3140
3115
|
import os3 from "os";
|
|
3141
3116
|
import { execFileSync as execFileSync4 } from "child_process";
|
|
3142
3117
|
import * as p4 from "@clack/prompts";
|
|
3143
3118
|
|
|
3144
3119
|
// src/lib/github.ts
|
|
3145
3120
|
import fs14 from "fs";
|
|
3146
|
-
import
|
|
3121
|
+
import path17 from "path";
|
|
3147
3122
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
3148
3123
|
import os2 from "os";
|
|
3149
3124
|
import { Readable } from "stream";
|
|
@@ -3225,7 +3200,7 @@ async function latestGithubCommit(repo) {
|
|
|
3225
3200
|
}
|
|
3226
3201
|
}
|
|
3227
3202
|
function validateExtractedTree(destDir) {
|
|
3228
|
-
const resolved =
|
|
3203
|
+
const resolved = path17.resolve(destDir);
|
|
3229
3204
|
const walk = (dir) => {
|
|
3230
3205
|
let entries;
|
|
3231
3206
|
try {
|
|
@@ -3234,7 +3209,7 @@ function validateExtractedTree(destDir) {
|
|
|
3234
3209
|
return false;
|
|
3235
3210
|
}
|
|
3236
3211
|
for (const entry of entries) {
|
|
3237
|
-
const full =
|
|
3212
|
+
const full = path17.join(dir, entry.name);
|
|
3238
3213
|
let stat;
|
|
3239
3214
|
try {
|
|
3240
3215
|
stat = fs14.lstatSync(full);
|
|
@@ -3253,12 +3228,12 @@ function validateExtractedTree(destDir) {
|
|
|
3253
3228
|
}
|
|
3254
3229
|
function resolveTarBin() {
|
|
3255
3230
|
if (process.platform !== "win32") return "tar";
|
|
3256
|
-
const winTar =
|
|
3231
|
+
const winTar = path17.join(process.env["SystemRoot"] ?? "C:\\Windows", "System32", "tar.exe");
|
|
3257
3232
|
return fs14.existsSync(winTar) ? winTar : "tar";
|
|
3258
3233
|
}
|
|
3259
3234
|
async function downloadRepoTarball(repo, sha, destDir, validateSubdir) {
|
|
3260
3235
|
const url = `https://codeload.github.com/${repo}/tar.gz/${sha}`;
|
|
3261
|
-
const tmp =
|
|
3236
|
+
const tmp = path17.join(os2.tmpdir(), `jorgex-tarball-${Date.now()}.tar.gz`);
|
|
3262
3237
|
const fail = (reason) => {
|
|
3263
3238
|
try {
|
|
3264
3239
|
fs14.rmSync(destDir, { recursive: true, force: true });
|
|
@@ -3291,8 +3266,8 @@ async function downloadRepoTarball(repo, sha, destDir, validateSubdir) {
|
|
|
3291
3266
|
const detail = (e.stderr?.toString().trim() || e.message || "").split("\n")[0];
|
|
3292
3267
|
return fail(detail ? `tar fall\xF3: ${detail}` : "tar no disponible o fall\xF3 la extracci\xF3n");
|
|
3293
3268
|
}
|
|
3294
|
-
const resolvedDest =
|
|
3295
|
-
const validateRoot = validateSubdir ?
|
|
3269
|
+
const resolvedDest = path17.resolve(destDir);
|
|
3270
|
+
const validateRoot = validateSubdir ? path17.resolve(resolvedDest, validateSubdir) : resolvedDest;
|
|
3296
3271
|
if (validateRoot !== resolvedDest && !isContainedIn(validateRoot, resolvedDest)) {
|
|
3297
3272
|
return fail(`la ruta de validaci\xF3n "${validateSubdir}" escapa del destino`);
|
|
3298
3273
|
}
|
|
@@ -3314,7 +3289,7 @@ async function downloadRepoTarball(repo, sha, destDir, validateSubdir) {
|
|
|
3314
3289
|
|
|
3315
3290
|
// src/lib/skill-update.ts
|
|
3316
3291
|
import fs15 from "fs";
|
|
3317
|
-
import
|
|
3292
|
+
import path18 from "path";
|
|
3318
3293
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
3319
3294
|
var PROTECTED_SKILLS = /* @__PURE__ */ new Set([
|
|
3320
3295
|
"agent-delegation",
|
|
@@ -3334,10 +3309,10 @@ function sameTextContentNormalized(a, b) {
|
|
|
3334
3309
|
}
|
|
3335
3310
|
function diffSkillDirs(upstreamDir, localDir) {
|
|
3336
3311
|
const upstreamFiles = new Set(
|
|
3337
|
-
listFilesRecursive(upstreamDir).map((f) =>
|
|
3312
|
+
listFilesRecursive(upstreamDir).map((f) => path18.relative(upstreamDir, f))
|
|
3338
3313
|
);
|
|
3339
3314
|
const localFiles = new Set(
|
|
3340
|
-
listFilesRecursive(localDir).map((f) =>
|
|
3315
|
+
listFilesRecursive(localDir).map((f) => path18.relative(localDir, f))
|
|
3341
3316
|
);
|
|
3342
3317
|
const added = [];
|
|
3343
3318
|
const modified = [];
|
|
@@ -3345,7 +3320,7 @@ function diffSkillDirs(upstreamDir, localDir) {
|
|
|
3345
3320
|
for (const rel of upstreamFiles) {
|
|
3346
3321
|
if (!localFiles.has(rel)) {
|
|
3347
3322
|
added.push(rel);
|
|
3348
|
-
} else if (!sameTextContentNormalized(
|
|
3323
|
+
} else if (!sameTextContentNormalized(path18.join(upstreamDir, rel), path18.join(localDir, rel))) {
|
|
3349
3324
|
modified.push(rel);
|
|
3350
3325
|
}
|
|
3351
3326
|
}
|
|
@@ -3407,7 +3382,7 @@ function replaceSkill(name, upstreamSkillDir, newCommit, opts) {
|
|
|
3407
3382
|
if (PROTECTED_SKILLS.has(name)) {
|
|
3408
3383
|
throw new Error(`La skill "${name}" es propia del stack y no se actualiza desde upstream.`);
|
|
3409
3384
|
}
|
|
3410
|
-
const upstreamsFile = upstreamsFilePath ??
|
|
3385
|
+
const upstreamsFile = upstreamsFilePath ?? path18.join(path18.dirname(stackRoot()), "upstreams.json");
|
|
3411
3386
|
const raw = fs15.readFileSync(upstreamsFile, "utf8");
|
|
3412
3387
|
const data = JSON.parse(raw);
|
|
3413
3388
|
const skillEntry = data?.skills?.[name];
|
|
@@ -3417,8 +3392,8 @@ function replaceSkill(name, upstreamSkillDir, newCommit, opts) {
|
|
|
3417
3392
|
if (skillEntry.kind === "release") {
|
|
3418
3393
|
throw new Error(`La skill "${name}" es de tipo release y no se actualiza con replaceSkill.`);
|
|
3419
3394
|
}
|
|
3420
|
-
const skillsRoot = localSkillsRoot ??
|
|
3421
|
-
const localSkillDir =
|
|
3395
|
+
const skillsRoot = localSkillsRoot ?? path18.join(stackRoot(), "skills");
|
|
3396
|
+
const localSkillDir = path18.join(skillsRoot, name);
|
|
3422
3397
|
const localFiles = listFilesRecursive(localSkillDir);
|
|
3423
3398
|
if (localFiles.length > 0) {
|
|
3424
3399
|
createBackup(localFiles, `skill-update-${name}`, backupsRoot);
|
|
@@ -3431,9 +3406,9 @@ function replaceSkill(name, upstreamSkillDir, newCommit, opts) {
|
|
|
3431
3406
|
if (st.isSymbolicLink()) {
|
|
3432
3407
|
throw new Error(`Symlink rechazado en upstream de skill "${name}": ${src}`);
|
|
3433
3408
|
}
|
|
3434
|
-
const rel =
|
|
3435
|
-
const dest =
|
|
3436
|
-
ensureDir(
|
|
3409
|
+
const rel = path18.relative(upstreamSkillDir, src);
|
|
3410
|
+
const dest = path18.join(stagingDir, rel);
|
|
3411
|
+
ensureDir(path18.dirname(dest));
|
|
3437
3412
|
copyFile(src, dest);
|
|
3438
3413
|
}
|
|
3439
3414
|
const oldDir = `${localSkillDir}.old-${process.pid}`;
|
|
@@ -3458,7 +3433,7 @@ function rateLimitHint(prefix) {
|
|
|
3458
3433
|
return ghPresentButTokenFailed() ? `${prefix} Tienes gh instalado pero \`gh auth token\` no devolvi\xF3 credencial (\xBFsesi\xF3n caducada?) \u2014 prueba \`gh auth login\` o define GH_TOKEN.` : `${prefix} Define GH_TOKEN o inicia sesi\xF3n en gh CLI.`;
|
|
3459
3434
|
}
|
|
3460
3435
|
function loadUpstreams() {
|
|
3461
|
-
const file =
|
|
3436
|
+
const file = path19.join(path19.dirname(stackRoot()), "upstreams.json");
|
|
3462
3437
|
return JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
3463
3438
|
}
|
|
3464
3439
|
function skillsToScan(maintainer, upstreams) {
|
|
@@ -3690,8 +3665,8 @@ function isEngramRunning() {
|
|
|
3690
3665
|
return null;
|
|
3691
3666
|
}
|
|
3692
3667
|
}
|
|
3693
|
-
function isGitClone(projectRoot =
|
|
3694
|
-
return fs16.existsSync(
|
|
3668
|
+
function isGitClone(projectRoot = path19.dirname(stackRoot())) {
|
|
3669
|
+
return fs16.existsSync(path19.join(projectRoot, ".git"));
|
|
3695
3670
|
}
|
|
3696
3671
|
var STACK_METHOD_CLONE = "git pull + pnpm install + pnpm build";
|
|
3697
3672
|
function resolvePnpm() {
|
|
@@ -3706,7 +3681,7 @@ function cleanupTmp(dir) {
|
|
|
3706
3681
|
}
|
|
3707
3682
|
}
|
|
3708
3683
|
function updateStackGitClone() {
|
|
3709
|
-
const projectRoot =
|
|
3684
|
+
const projectRoot = path19.dirname(stackRoot());
|
|
3710
3685
|
const git = lookPath("git");
|
|
3711
3686
|
if (!git) throw new Error("git no encontrado en PATH.");
|
|
3712
3687
|
const pnpm = resolvePnpm();
|
|
@@ -3723,7 +3698,7 @@ function updateStackGlobal() {
|
|
|
3723
3698
|
execFileSync4(pnpm, ["add", "-g", "jorgex-stack@latest"], { stdio: "inherit" });
|
|
3724
3699
|
}
|
|
3725
3700
|
async function downloadSkillToTemp(repo, sha, skillPath) {
|
|
3726
|
-
const root = fs16.mkdtempSync(
|
|
3701
|
+
const root = fs16.mkdtempSync(path19.join(os3.tmpdir(), "jorgex-skill-"));
|
|
3727
3702
|
try {
|
|
3728
3703
|
const result = await downloadRepoTarball(repo, sha, root, skillPath);
|
|
3729
3704
|
if (!result.ok) {
|
|
@@ -3731,14 +3706,14 @@ async function downloadSkillToTemp(repo, sha, skillPath) {
|
|
|
3731
3706
|
return { error: result.reason };
|
|
3732
3707
|
}
|
|
3733
3708
|
if (skillPath) {
|
|
3734
|
-
const sub =
|
|
3709
|
+
const sub = path19.resolve(path19.join(root, skillPath));
|
|
3735
3710
|
if (!isContainedIn(sub, root)) {
|
|
3736
3711
|
cleanupTmp(root);
|
|
3737
3712
|
return { error: `la ruta "${skillPath}" escapa del directorio temporal` };
|
|
3738
3713
|
}
|
|
3739
3714
|
if (fs16.existsSync(sub)) return { dir: sub, root };
|
|
3740
3715
|
const lastSeg = skillPath.split("/").pop();
|
|
3741
|
-
const sub2 =
|
|
3716
|
+
const sub2 = path19.resolve(path19.join(root, lastSeg));
|
|
3742
3717
|
if (isContainedIn(sub2, root) && fs16.existsSync(sub2)) {
|
|
3743
3718
|
if (!validateExtractedTree(sub2)) {
|
|
3744
3719
|
cleanupTmp(root);
|
|
@@ -3759,10 +3734,10 @@ function pruneEngramDbBackups() {
|
|
|
3759
3734
|
try {
|
|
3760
3735
|
const dir = dataDir();
|
|
3761
3736
|
if (!fs16.existsSync(dir)) return;
|
|
3762
|
-
const backups = fs16.readdirSync(dir).filter((f) => f.startsWith("engram-db-backup-") && f.endsWith(".db")).map((f) => ({ name: f, mtime: fs16.statSync(
|
|
3737
|
+
const backups = fs16.readdirSync(dir).filter((f) => f.startsWith("engram-db-backup-") && f.endsWith(".db")).map((f) => ({ name: f, mtime: fs16.statSync(path19.join(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
3763
3738
|
for (const old of backups.slice(3)) {
|
|
3764
3739
|
try {
|
|
3765
|
-
fs16.rmSync(
|
|
3740
|
+
fs16.rmSync(path19.join(dir, old.name));
|
|
3766
3741
|
} catch {
|
|
3767
3742
|
}
|
|
3768
3743
|
}
|
|
@@ -3771,17 +3746,17 @@ function pruneEngramDbBackups() {
|
|
|
3771
3746
|
}
|
|
3772
3747
|
function rotateLockedBinary(binPath, sweepRoot = HOME) {
|
|
3773
3748
|
if (!fs16.existsSync(binPath)) return null;
|
|
3774
|
-
const dir =
|
|
3775
|
-
const base =
|
|
3749
|
+
const dir = path19.dirname(binPath);
|
|
3750
|
+
const base = path19.basename(binPath);
|
|
3776
3751
|
const escapedBase = base.replace(/[.*+?^$()|[\]{}\\]/g, "\\$&");
|
|
3777
3752
|
const oldPattern = new RegExp("^" + escapedBase + "\\.old-\\d+$");
|
|
3778
|
-
const resolvedDir =
|
|
3779
|
-
if (resolvedDir ===
|
|
3753
|
+
const resolvedDir = path19.resolve(dir);
|
|
3754
|
+
if (resolvedDir === path19.resolve(sweepRoot) || isContainedIn(resolvedDir, sweepRoot)) {
|
|
3780
3755
|
try {
|
|
3781
3756
|
for (const entry of fs16.readdirSync(dir)) {
|
|
3782
3757
|
if (oldPattern.test(entry)) {
|
|
3783
3758
|
try {
|
|
3784
|
-
fs16.rmSync(
|
|
3759
|
+
fs16.rmSync(path19.join(dir, entry), { force: true });
|
|
3785
3760
|
} catch {
|
|
3786
3761
|
}
|
|
3787
3762
|
}
|
|
@@ -3789,7 +3764,7 @@ function rotateLockedBinary(binPath, sweepRoot = HOME) {
|
|
|
3789
3764
|
} catch {
|
|
3790
3765
|
}
|
|
3791
3766
|
}
|
|
3792
|
-
const rotated =
|
|
3767
|
+
const rotated = path19.join(dir, `${base}.old-${Date.now()}`);
|
|
3793
3768
|
fs16.renameSync(binPath, rotated);
|
|
3794
3769
|
return rotated;
|
|
3795
3770
|
}
|
|
@@ -3799,8 +3774,8 @@ async function updateEngram(engramRepo, latestVersion) {
|
|
|
3799
3774
|
"Engram est\xE1 en ejecuci\xF3n: los procesos vivos seguir\xE1n usando la versi\xF3n antigua hasta que reinicies los clientes (Claude Code/OpenCode/Codex)."
|
|
3800
3775
|
);
|
|
3801
3776
|
}
|
|
3802
|
-
const engramDataDir = process.env.ENGRAM_DATA_DIR ??
|
|
3803
|
-
const engramDb =
|
|
3777
|
+
const engramDataDir = process.env.ENGRAM_DATA_DIR ?? path19.join(HOME, ".engram");
|
|
3778
|
+
const engramDb = path19.join(engramDataDir, "engram.db");
|
|
3804
3779
|
if (fs16.existsSync(engramDb)) {
|
|
3805
3780
|
const doBackup = await p4.confirm({
|
|
3806
3781
|
message: `\xBFHacer backup de la DB de Engram antes de actualizar? (${engramDb})`,
|
|
@@ -3808,7 +3783,7 @@ async function updateEngram(engramRepo, latestVersion) {
|
|
|
3808
3783
|
});
|
|
3809
3784
|
if (!p4.isCancel(doBackup) && doBackup) {
|
|
3810
3785
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
3811
|
-
const dest =
|
|
3786
|
+
const dest = path19.join(dataDir(), `engram-db-backup-${ts}.db`);
|
|
3812
3787
|
try {
|
|
3813
3788
|
if (!fs16.existsSync(dataDir())) fs16.mkdirSync(dataDir(), { recursive: true });
|
|
3814
3789
|
fs16.copyFileSync(engramDb, dest);
|
|
@@ -4146,7 +4121,7 @@ async function runInteractiveUpdate(localVersion, yes, dryRun = false, includeBr
|
|
|
4146
4121
|
continue;
|
|
4147
4122
|
}
|
|
4148
4123
|
const { dir: tmpDir, root: tmpRoot } = tmpResult;
|
|
4149
|
-
const localSkillDir =
|
|
4124
|
+
const localSkillDir = path19.join(stackRoot(), "skills", skillInfo.name);
|
|
4150
4125
|
const diff = renderSkillDiff(tmpDir, localSkillDir);
|
|
4151
4126
|
if (diff) {
|
|
4152
4127
|
p4.log.info(`Diff de ${skillInfo.name}:
|
|
@@ -4238,7 +4213,7 @@ ${diff}`);
|
|
|
4238
4213
|
}
|
|
4239
4214
|
|
|
4240
4215
|
// src/models-picker.ts
|
|
4241
|
-
import
|
|
4216
|
+
import path20 from "path";
|
|
4242
4217
|
import * as p5 from "@clack/prompts";
|
|
4243
4218
|
var TIERS = ["strong", "standard", "cheap"];
|
|
4244
4219
|
var EFFORTS = ["low", "medium", "high", "xhigh"];
|
|
@@ -4264,7 +4239,7 @@ function opencodeLiveModels(binPath) {
|
|
|
4264
4239
|
}
|
|
4265
4240
|
function agentsByTier() {
|
|
4266
4241
|
const grouped = { strong: [], standard: [], cheap: [] };
|
|
4267
|
-
for (const agent of loadCanonicalAgents(
|
|
4242
|
+
for (const agent of loadCanonicalAgents(path20.join(stackRoot(), "agents"))) {
|
|
4268
4243
|
if (agent.mode === "subagent") grouped[agent.tier].push(agent.name);
|
|
4269
4244
|
}
|
|
4270
4245
|
return grouped;
|
|
@@ -4450,15 +4425,15 @@ function cancelled() {
|
|
|
4450
4425
|
|
|
4451
4426
|
// src/lib/release.ts
|
|
4452
4427
|
import fs17 from "fs";
|
|
4453
|
-
import
|
|
4428
|
+
import path21 from "path";
|
|
4454
4429
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
4455
4430
|
import { fileURLToPath } from "url";
|
|
4456
4431
|
function findPackageJson() {
|
|
4457
|
-
let dir =
|
|
4432
|
+
let dir = path21.dirname(fileURLToPath(import.meta.url));
|
|
4458
4433
|
for (let i = 0; i < 6; i++) {
|
|
4459
|
-
const candidate =
|
|
4434
|
+
const candidate = path21.join(dir, "package.json");
|
|
4460
4435
|
if (fs17.existsSync(candidate)) return candidate;
|
|
4461
|
-
dir =
|
|
4436
|
+
dir = path21.dirname(dir);
|
|
4462
4437
|
}
|
|
4463
4438
|
throw new Error("No se encontr\xF3 package.json cerca del CLI.");
|
|
4464
4439
|
}
|
|
@@ -4479,7 +4454,7 @@ function readPackageMetadata() {
|
|
|
4479
4454
|
|
|
4480
4455
|
// src/lib/pi-runtime.ts
|
|
4481
4456
|
import os4 from "os";
|
|
4482
|
-
import
|
|
4457
|
+
import path22 from "path";
|
|
4483
4458
|
import fs18 from "fs";
|
|
4484
4459
|
import { spawnSync } from "child_process";
|
|
4485
4460
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -4488,16 +4463,16 @@ import { createHash as createHash2 } from "crypto";
|
|
|
4488
4463
|
var pi_runtime_pin_default = {
|
|
4489
4464
|
package: {
|
|
4490
4465
|
name: "jorgex-pi",
|
|
4491
|
-
version: "0.8.
|
|
4492
|
-
source: "npm:jorgex-pi@0.8.
|
|
4466
|
+
version: "0.8.29",
|
|
4467
|
+
source: "npm:jorgex-pi@0.8.29"
|
|
4493
4468
|
},
|
|
4494
4469
|
provenance: {
|
|
4495
|
-
commit: "
|
|
4470
|
+
commit: "bbaf80f09bd1512e21fe80f22b4aad61420a8800"
|
|
4496
4471
|
},
|
|
4497
4472
|
tarball: {
|
|
4498
|
-
bytes:
|
|
4499
|
-
sha256: "
|
|
4500
|
-
sha512: "
|
|
4473
|
+
bytes: 17991325,
|
|
4474
|
+
sha256: "e322f5e2d79974321ef5f3acf1e338c9f2a1e31d5b7796e8c3f5ff88fc886eca",
|
|
4475
|
+
sha512: "15ec2302958506fb0b6fc2acec55e8ce023dab72ef36b2feadfeb86785395e94e51af156374656694745070ad2855ed008b9c9a3bc2fd212de9261cfb93a1649"
|
|
4501
4476
|
}
|
|
4502
4477
|
};
|
|
4503
4478
|
|
|
@@ -4518,7 +4493,7 @@ var PI_RUNTIME_CANDIDATE = {
|
|
|
4518
4493
|
"structured-questions-v1",
|
|
4519
4494
|
"web-access-v1",
|
|
4520
4495
|
"goal-continuation-v1",
|
|
4521
|
-
"
|
|
4496
|
+
"engram-official-bridge-v1",
|
|
4522
4497
|
"engram-runtime-tools-v1",
|
|
4523
4498
|
"context7-http-v1",
|
|
4524
4499
|
"permissions-policy-v1",
|
|
@@ -4677,7 +4652,7 @@ function healthyDoctor(stdout, stderr, packageRunner, candidate) {
|
|
|
4677
4652
|
if (record === null || typeof record !== "object" || Array.isArray(record)) return false;
|
|
4678
4653
|
const packageValue = Reflect.get(record, "package");
|
|
4679
4654
|
const result = Reflect.get(record, "result");
|
|
4680
|
-
return Reflect.get(record, "schemaVersion") === 1 && Reflect.get(record, "command") === "doctor" && Reflect.get(record, "ok") === true && packageValue !== null && typeof packageValue === "object" && Reflect.get(packageValue, "name") === "jorgex-pi" && Reflect.get(packageValue, "version") === (candidate.package?.version ?? /^npm:jorgex-pi@([^\s]+)$/.exec(candidate.source)?.[1]) &&
|
|
4655
|
+
return Reflect.get(record, "schemaVersion") === 1 && Reflect.get(record, "command") === "doctor" && Reflect.get(record, "ok") === true && packageValue !== null && typeof packageValue === "object" && Reflect.get(packageValue, "name") === "jorgex-pi" && Reflect.get(packageValue, "version") === (candidate.package?.version ?? /^npm:jorgex-pi@([^\s]+)$/.exec(candidate.source)?.[1]) && path22.resolve(packageRunner) === path22.resolve(String(Reflect.get(packageValue, "root")), "bin", "jorgex-pi.mjs") && result !== null && typeof result === "object" && Reflect.get(result, "healthy") === true;
|
|
4681
4656
|
} catch {
|
|
4682
4657
|
return false;
|
|
4683
4658
|
}
|
|
@@ -4698,7 +4673,7 @@ function provisionalPendingDoctor(exitCode, stdout, stderr, packageRunner, candi
|
|
|
4698
4673
|
if (JSON.stringify(Object.keys(packageValue).sort()) !== JSON.stringify(["name", "root", "version"])) return false;
|
|
4699
4674
|
if (Reflect.get(packageValue, "name") !== "jorgex-pi") return false;
|
|
4700
4675
|
if (Reflect.get(packageValue, "version") !== (candidate.package?.version ?? /^npm:jorgex-pi@([^\s]+)$/.exec(candidate.source)?.[1])) return false;
|
|
4701
|
-
if (
|
|
4676
|
+
if (path22.resolve(packageRunner) !== path22.resolve(String(Reflect.get(packageValue, "root")), "bin", "jorgex-pi.mjs")) return false;
|
|
4702
4677
|
const result = Reflect.get(record, "result");
|
|
4703
4678
|
if (result === null || typeof result !== "object" || Array.isArray(result)) return false;
|
|
4704
4679
|
if (JSON.stringify(Object.keys(result).sort()) !== JSON.stringify(["checks", "healthy"])) return false;
|
|
@@ -4727,7 +4702,7 @@ function provisionalPendingDoctor(exitCode, stdout, stderr, packageRunner, candi
|
|
|
4727
4702
|
}
|
|
4728
4703
|
function installPiFromVerifiedTarball(input, deps) {
|
|
4729
4704
|
const paths = input.targetDir === void 0 ? userPaths(input.engramBin, input.piExecutable) : targetPaths(input.targetDir, input.engramBin, input.piExecutable);
|
|
4730
|
-
const destination = input.targetDir === void 0 ?
|
|
4705
|
+
const destination = input.targetDir === void 0 ? path22.join(dataDir(), "packages", `jorgex-pi-${PI_RUNTIME_CANDIDATE.package.version}.tgz`) : path22.join(path22.resolve(input.targetDir), "downloads", `jorgex-pi-${PI_RUNTIME_CANDIDATE.package.version}.tgz`);
|
|
4731
4706
|
const artifact = deps.download(destination);
|
|
4732
4707
|
if (artifact.bytes !== input.candidate.bytes || artifact.sha256 !== input.candidate.sha256 || artifact.sha512 !== input.candidate.sha512) {
|
|
4733
4708
|
return { kind: "blocked", reason: "tarball-integrity" };
|
|
@@ -4735,7 +4710,7 @@ function installPiFromVerifiedTarball(input, deps) {
|
|
|
4735
4710
|
deps.backupSettings();
|
|
4736
4711
|
const scope = {
|
|
4737
4712
|
kind: input.targetDir === void 0 ? "real" : "target-dir",
|
|
4738
|
-
codingAgentDir:
|
|
4713
|
+
codingAgentDir: path22.resolve(paths.codingAgentDir)
|
|
4739
4714
|
};
|
|
4740
4715
|
const installing = flatCandidateReceipt(input.candidate, scope, "installing", input.engramBin);
|
|
4741
4716
|
deps.writeReceiptAtomic(`${JSON.stringify(installing)}
|
|
@@ -4766,30 +4741,30 @@ function installPiFromVerifiedTarball(input, deps) {
|
|
|
4766
4741
|
return { kind: "installed", receipt };
|
|
4767
4742
|
}
|
|
4768
4743
|
function runtimePath(piExecutable) {
|
|
4769
|
-
const entries = process.platform === "win32" ? [piExecutable === void 0 ? null :
|
|
4770
|
-
return [...new Set(entries.filter((entry) => entry !== null))].join(
|
|
4744
|
+
const entries = process.platform === "win32" ? [piExecutable === void 0 ? null : path22.dirname(piExecutable), path22.dirname(process.execPath), process.env.SystemRoot ? path22.join(process.env.SystemRoot, "System32") : null] : [piExecutable === void 0 ? null : path22.dirname(piExecutable), path22.dirname(process.execPath), "/usr/local/bin", "/usr/bin", "/bin"];
|
|
4745
|
+
return [...new Set(entries.filter((entry) => entry !== null))].join(path22.delimiter);
|
|
4771
4746
|
}
|
|
4772
4747
|
function targetPaths(targetDir, engramBin, piExecutable) {
|
|
4773
|
-
const root =
|
|
4774
|
-
const codingAgentDir =
|
|
4775
|
-
const home =
|
|
4776
|
-
const temporary =
|
|
4748
|
+
const root = path22.resolve(targetDir);
|
|
4749
|
+
const codingAgentDir = path22.join(root, "pi-agent");
|
|
4750
|
+
const home = path22.join(root, "home");
|
|
4751
|
+
const temporary = path22.join(root, "tmp");
|
|
4777
4752
|
return {
|
|
4778
4753
|
codingAgentDir,
|
|
4779
|
-
receiptPath:
|
|
4780
|
-
packageRunner:
|
|
4754
|
+
receiptPath: path22.join(root, "state", "pi-receipt.json"),
|
|
4755
|
+
packageRunner: path22.join(codingAgentDir, "npm", "node_modules", "jorgex-pi", "bin", "jorgex-pi.mjs"),
|
|
4781
4756
|
environment: {
|
|
4782
4757
|
HOME: home,
|
|
4783
4758
|
USERPROFILE: home,
|
|
4784
|
-
APPDATA:
|
|
4785
|
-
LOCALAPPDATA:
|
|
4786
|
-
XDG_CONFIG_HOME:
|
|
4787
|
-
XDG_DATA_HOME:
|
|
4788
|
-
XDG_CACHE_HOME:
|
|
4759
|
+
APPDATA: path22.join(root, "appdata"),
|
|
4760
|
+
LOCALAPPDATA: path22.join(root, "localappdata"),
|
|
4761
|
+
XDG_CONFIG_HOME: path22.join(root, "xdg-config"),
|
|
4762
|
+
XDG_DATA_HOME: path22.join(root, "xdg-data"),
|
|
4763
|
+
XDG_CACHE_HOME: path22.join(root, "xdg-cache"),
|
|
4789
4764
|
TEMP: temporary,
|
|
4790
4765
|
TMP: temporary,
|
|
4791
4766
|
TMPDIR: temporary,
|
|
4792
|
-
npm_config_cache:
|
|
4767
|
+
npm_config_cache: path22.join(root, "npm-cache"),
|
|
4793
4768
|
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
4794
4769
|
NPM_CONFIG_UPDATE_NOTIFIER: "false",
|
|
4795
4770
|
PI_CODING_AGENT_DIR: codingAgentDir,
|
|
@@ -4800,15 +4775,15 @@ function targetPaths(targetDir, engramBin, piExecutable) {
|
|
|
4800
4775
|
}
|
|
4801
4776
|
function userPaths(engramBin, piExecutable) {
|
|
4802
4777
|
const home = os4.homedir();
|
|
4803
|
-
const codingAgentDir = process.env.PI_CODING_AGENT_DIR ??
|
|
4778
|
+
const codingAgentDir = process.env.PI_CODING_AGENT_DIR ?? path22.join(home, ".pi", "agent");
|
|
4804
4779
|
return {
|
|
4805
4780
|
codingAgentDir,
|
|
4806
|
-
receiptPath:
|
|
4807
|
-
packageRunner:
|
|
4781
|
+
receiptPath: path22.join(dataDir(), "pi-receipt.json"),
|
|
4782
|
+
packageRunner: path22.join(codingAgentDir, "npm", "node_modules", "jorgex-pi", "bin", "jorgex-pi.mjs"),
|
|
4808
4783
|
environment: {
|
|
4809
4784
|
HOME: home,
|
|
4810
|
-
XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME ??
|
|
4811
|
-
XDG_CACHE_HOME: process.env.XDG_CACHE_HOME ??
|
|
4785
|
+
XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME ?? path22.join(home, ".config"),
|
|
4786
|
+
XDG_CACHE_HOME: process.env.XDG_CACHE_HOME ?? path22.join(home, ".cache"),
|
|
4812
4787
|
TMPDIR: os4.tmpdir(),
|
|
4813
4788
|
NPM_CONFIG_IGNORE_SCRIPTS: "true",
|
|
4814
4789
|
NPM_CONFIG_UPDATE_NOTIFIER: "false",
|
|
@@ -4836,7 +4811,7 @@ function runPiRuntime(input, deps) {
|
|
|
4836
4811
|
return { kind: "blocked", reason: "tarball-integrity" };
|
|
4837
4812
|
}
|
|
4838
4813
|
const paths = input.targetDir === void 0 ? userPaths(input.engramBin, input.detected.executable) : targetPaths(input.targetDir, input.engramBin, input.detected.executable);
|
|
4839
|
-
const settingsJson = deps.readSettings(
|
|
4814
|
+
const settingsJson = deps.readSettings(path22.join(paths.codingAgentDir, "settings.json"));
|
|
4840
4815
|
const receiptJson = deps.readReceipt(paths.receiptPath);
|
|
4841
4816
|
const lifecycleInput = {
|
|
4842
4817
|
candidate: PI_RUNTIME_CANDIDATE,
|
|
@@ -4900,14 +4875,14 @@ function readJsonFile(file) {
|
|
|
4900
4875
|
function packageVersionFromExecutable(executable) {
|
|
4901
4876
|
let current;
|
|
4902
4877
|
try {
|
|
4903
|
-
current =
|
|
4878
|
+
current = path22.dirname(fs18.realpathSync(executable));
|
|
4904
4879
|
} catch {
|
|
4905
4880
|
return null;
|
|
4906
4881
|
}
|
|
4907
4882
|
for (let depth = 0; depth < 8; depth++) {
|
|
4908
4883
|
const manifests = [
|
|
4909
|
-
|
|
4910
|
-
|
|
4884
|
+
path22.join(current, "package.json"),
|
|
4885
|
+
path22.join(current, "node_modules", "@earendil-works", "pi-coding-agent", "package.json")
|
|
4911
4886
|
];
|
|
4912
4887
|
for (const manifest of manifests) {
|
|
4913
4888
|
try {
|
|
@@ -4918,7 +4893,7 @@ function packageVersionFromExecutable(executable) {
|
|
|
4918
4893
|
} catch {
|
|
4919
4894
|
}
|
|
4920
4895
|
}
|
|
4921
|
-
const parent =
|
|
4896
|
+
const parent = path22.dirname(current);
|
|
4922
4897
|
if (parent === current) break;
|
|
4923
4898
|
current = parent;
|
|
4924
4899
|
}
|
|
@@ -4933,16 +4908,16 @@ function detectPiRuntime() {
|
|
|
4933
4908
|
installed: executable !== null,
|
|
4934
4909
|
executable,
|
|
4935
4910
|
version: executable === null ? null : packageVersionFromExecutable(executable),
|
|
4936
|
-
codingAgentDir: process.env.PI_CODING_AGENT_DIR ??
|
|
4911
|
+
codingAgentDir: process.env.PI_CODING_AGENT_DIR ?? path22.join(home, ".pi", "agent")
|
|
4937
4912
|
};
|
|
4938
4913
|
}
|
|
4939
4914
|
function hasManagedPiRuntime(targetDir) {
|
|
4940
|
-
const receipt = targetDir === void 0 ?
|
|
4915
|
+
const receipt = targetDir === void 0 ? path22.join(dataDir(), "pi-receipt.json") : path22.join(path22.resolve(targetDir), "state", "pi-receipt.json");
|
|
4941
4916
|
return fs18.statSync(receipt, { throwIfNoEntry: false })?.isFile() === true;
|
|
4942
4917
|
}
|
|
4943
4918
|
function resolvePiEngramBin(targetDir) {
|
|
4944
4919
|
if (targetDir === void 0) return detectEngram();
|
|
4945
|
-
const candidate =
|
|
4920
|
+
const candidate = path22.join(path22.resolve(targetDir), "bin", process.platform === "win32" ? "engram.exe" : "engram");
|
|
4946
4921
|
return fs18.statSync(candidate, { throwIfNoEntry: false })?.isFile() ? candidate : null;
|
|
4947
4922
|
}
|
|
4948
4923
|
function readOptional(file, fallback) {
|
|
@@ -4982,7 +4957,7 @@ async function acquirePiTarball(destination) {
|
|
|
4982
4957
|
}
|
|
4983
4958
|
fs18.rmSync(destination, { force: true });
|
|
4984
4959
|
}
|
|
4985
|
-
fs18.mkdirSync(
|
|
4960
|
+
fs18.mkdirSync(path22.dirname(destination), { recursive: true });
|
|
4986
4961
|
const partial = `${destination}.partial-${process.pid}`;
|
|
4987
4962
|
const response = await fetch(`https://registry.npmjs.org/jorgex-pi/-/jorgex-pi-${PI_RUNTIME_CANDIDATE.package.version}.tgz`, {
|
|
4988
4963
|
redirect: "error",
|
|
@@ -5025,6 +5000,21 @@ function runProcess(invocation) {
|
|
|
5025
5000
|
stderr: result.stderr ?? (result.error?.message ?? "")
|
|
5026
5001
|
};
|
|
5027
5002
|
}
|
|
5003
|
+
function setupPiFailedRemedy(setup) {
|
|
5004
|
+
const detail = setup.reason ?? setup.stderr ?? "setup oficial Pi fall\xF3";
|
|
5005
|
+
const recovery = setup.recovery ?? "none";
|
|
5006
|
+
const backupId = setup.backupId ?? null;
|
|
5007
|
+
if (recovery === "complete") {
|
|
5008
|
+
return backupId !== null ? `${detail}. Se restaur\xF3 el backup ${backupId}; Pi no qued\xF3 activado.` : `${detail}. Se restaur\xF3 el backup previo; Pi no qued\xF3 activado.`;
|
|
5009
|
+
}
|
|
5010
|
+
if (recovery === "incomplete") {
|
|
5011
|
+
const id2 = backupId !== null ? ` (backup ${backupId})` : " (sin backup v\xE1lido)";
|
|
5012
|
+
const cause = setup.restoreError !== void 0 ? ` ${setup.restoreError}.` : "";
|
|
5013
|
+
return `${detail}. Recuperaci\xF3n incompleta${id2};${cause} revisa manualmente el estado y corrige la causa antes de reintentar; Pi no qued\xF3 activado.`;
|
|
5014
|
+
}
|
|
5015
|
+
const id = backupId !== null ? ` (backup ${backupId})` : " (sin backup v\xE1lido)";
|
|
5016
|
+
return `${detail}. Sin recuperaci\xF3n autom\xE1tica${id}; revisa manualmente el estado y corrige la causa antes de reintentar; Pi no qued\xF3 activado.`;
|
|
5017
|
+
}
|
|
5028
5018
|
async function runPiRuntimeSystem(input) {
|
|
5029
5019
|
if (input.engramBin === null && input.operation !== "uninstall") return runPiRuntime(input, {
|
|
5030
5020
|
readSettings: () => {
|
|
@@ -5055,7 +5045,32 @@ async function runPiRuntimeSystem(input) {
|
|
|
5055
5045
|
remedy: "Instala Engram o configura un ENGRAM_BIN absoluto antes de reintentar."
|
|
5056
5046
|
};
|
|
5057
5047
|
}
|
|
5058
|
-
|
|
5048
|
+
if (input.targetDir === void 0) {
|
|
5049
|
+
const { runOfficialSetupIfNeeded: runOfficialSetupIfNeeded2 } = await import("./official-engram-setup-4WIXM4EF.js");
|
|
5050
|
+
const setup = await runOfficialSetupIfNeeded2("pi", {
|
|
5051
|
+
command: "install",
|
|
5052
|
+
dryRun: false,
|
|
5053
|
+
targetDir: void 0,
|
|
5054
|
+
engramBin: input.engramBin,
|
|
5055
|
+
configDir: paths.codingAgentDir,
|
|
5056
|
+
homeDir: os4.homedir()
|
|
5057
|
+
});
|
|
5058
|
+
if (!setup.ran || !setup.ok) {
|
|
5059
|
+
if (!setup.ran) {
|
|
5060
|
+
return {
|
|
5061
|
+
kind: "blocked",
|
|
5062
|
+
reason: "setup-pi-failed",
|
|
5063
|
+
remedy: "setup oficial Pi omitido en install real. Sin recuperaci\xF3n autom\xE1tica (sin backup v\xE1lido); revisa manualmente el estado y corrige la causa antes de reintentar; Pi no qued\xF3 activado."
|
|
5064
|
+
};
|
|
5065
|
+
}
|
|
5066
|
+
return {
|
|
5067
|
+
kind: "blocked",
|
|
5068
|
+
reason: "setup-pi-failed",
|
|
5069
|
+
remedy: setupPiFailedRemedy(setup)
|
|
5070
|
+
};
|
|
5071
|
+
}
|
|
5072
|
+
}
|
|
5073
|
+
const destination = input.targetDir === void 0 ? path22.join(dataDir(), "packages", `jorgex-pi-${PI_RUNTIME_CANDIDATE.package.version}.tgz`) : path22.join(path22.resolve(input.targetDir), "downloads", `jorgex-pi-${PI_RUNTIME_CANDIDATE.package.version}.tgz`);
|
|
5059
5074
|
let artifact;
|
|
5060
5075
|
try {
|
|
5061
5076
|
artifact = await acquirePiTarball(destination);
|
|
@@ -5076,18 +5091,18 @@ async function runPiRuntimeSystem(input) {
|
|
|
5076
5091
|
}, {
|
|
5077
5092
|
download: () => artifact,
|
|
5078
5093
|
backupSettings: () => createBackup(
|
|
5079
|
-
[
|
|
5094
|
+
[path22.join(paths.codingAgentDir, "settings.json")],
|
|
5080
5095
|
"pi-package-install",
|
|
5081
|
-
input.targetDir === void 0 ? void 0 :
|
|
5096
|
+
input.targetDir === void 0 ? void 0 : path22.join(path22.resolve(input.targetDir), "backups")
|
|
5082
5097
|
),
|
|
5083
5098
|
run: runProcess,
|
|
5084
|
-
readSettings: () => readOptional(
|
|
5085
|
-
rewriteSettings: (content) => writeText(
|
|
5099
|
+
readSettings: () => readOptional(path22.join(paths.codingAgentDir, "settings.json"), '{"packages":[]}'),
|
|
5100
|
+
rewriteSettings: (content) => writeText(path22.join(paths.codingAgentDir, "settings.json"), `${content}
|
|
5086
5101
|
`),
|
|
5087
5102
|
writeReceiptAtomic: (content) => writeText(paths.receiptPath, content)
|
|
5088
5103
|
});
|
|
5089
5104
|
}
|
|
5090
|
-
const packageRoot =
|
|
5105
|
+
const packageRoot = path22.dirname(path22.dirname(paths.packageRunner));
|
|
5091
5106
|
const writeReceipt = (receipt) => {
|
|
5092
5107
|
writeText(paths.receiptPath, `${JSON.stringify(receipt, null, 2)}
|
|
5093
5108
|
`);
|
|
@@ -5105,9 +5120,9 @@ async function runPiRuntimeSystem(input) {
|
|
|
5105
5120
|
value,
|
|
5106
5121
|
{
|
|
5107
5122
|
backupSettings: () => createBackup(
|
|
5108
|
-
[
|
|
5123
|
+
[path22.join(paths.codingAgentDir, "settings.json")],
|
|
5109
5124
|
"pi-package-uninstall",
|
|
5110
|
-
input.targetDir === void 0 ? void 0 :
|
|
5125
|
+
input.targetDir === void 0 ? void 0 : path22.join(path22.resolve(input.targetDir), "backups")
|
|
5111
5126
|
),
|
|
5112
5127
|
run: runProcess,
|
|
5113
5128
|
isPackageAbsent: () => !fs18.existsSync(packageRoot),
|
|
@@ -5286,7 +5301,7 @@ async function runManagedPiSystem(input) {
|
|
|
5286
5301
|
}
|
|
5287
5302
|
|
|
5288
5303
|
// src/lib/quality-runner.ts
|
|
5289
|
-
import
|
|
5304
|
+
import path23 from "path";
|
|
5290
5305
|
import { spawn, spawnSync as spawnSync2 } from "child_process";
|
|
5291
5306
|
function normalizeLimit(value, name) {
|
|
5292
5307
|
if (value === void 0) return void 0;
|
|
@@ -5418,7 +5433,7 @@ function killProcessTree(child) {
|
|
|
5418
5433
|
if (pid === void 0) return;
|
|
5419
5434
|
if (process.platform === "win32") {
|
|
5420
5435
|
const systemRoot = process.env.SystemRoot ?? process.env.WINDIR ?? "C:\\Windows";
|
|
5421
|
-
const taskkill =
|
|
5436
|
+
const taskkill = path23.join(systemRoot, "System32", "taskkill.exe");
|
|
5422
5437
|
const result = spawnSync2(taskkill, ["/pid", String(pid), "/t", "/f"], {
|
|
5423
5438
|
shell: false,
|
|
5424
5439
|
stdio: "ignore",
|
|
@@ -5666,7 +5681,7 @@ async function runQualityPlan(input) {
|
|
|
5666
5681
|
// src/lib/engram-install.ts
|
|
5667
5682
|
import fs19 from "fs";
|
|
5668
5683
|
import os5 from "os";
|
|
5669
|
-
import
|
|
5684
|
+
import path24 from "path";
|
|
5670
5685
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
5671
5686
|
import { createHash as createHash3 } from "crypto";
|
|
5672
5687
|
var MAX_ENGRAM_ARCHIVE_BYTES = 64 * 1024 * 1024;
|
|
@@ -5675,9 +5690,9 @@ var DIGEST_RE = /^sha256:[0-9a-f]{64}$/;
|
|
|
5675
5690
|
async function installMissingEngram(options = {}) {
|
|
5676
5691
|
const platform = options.platform ?? process.platform;
|
|
5677
5692
|
const homeDir = options.homeDir ?? os5.homedir();
|
|
5678
|
-
if (!
|
|
5693
|
+
if (!path24.isAbsolute(homeDir)) return { ok: false, reason: "El directorio personal debe ser absoluto." };
|
|
5679
5694
|
const binaryName = platform === "win32" ? "engram.exe" : "engram";
|
|
5680
|
-
const bin =
|
|
5695
|
+
const bin = path24.join(homeDir, ".local", "bin", binaryName);
|
|
5681
5696
|
let staging;
|
|
5682
5697
|
let outcome;
|
|
5683
5698
|
try {
|
|
@@ -5797,9 +5812,9 @@ async function installMissingEngram(options = {}) {
|
|
|
5797
5812
|
if (size !== approvedSize || createHash3("sha256").update(archive).digest("hex") !== approvedSha) {
|
|
5798
5813
|
throw new Error("Engram: tama\xF1o o hash SHA-256 no coincide con el artefacto aprobado.");
|
|
5799
5814
|
}
|
|
5800
|
-
fs19.mkdirSync(
|
|
5801
|
-
staging = fs19.mkdtempSync(
|
|
5802
|
-
const archivePath =
|
|
5815
|
+
fs19.mkdirSync(path24.dirname(bin), { recursive: true });
|
|
5816
|
+
staging = fs19.mkdtempSync(path24.join(path24.dirname(bin), ".engram-install-"));
|
|
5817
|
+
const archivePath = path24.join(staging, expectedName);
|
|
5803
5818
|
fs19.writeFileSync(archivePath, archive, { flag: "wx", mode: 384 });
|
|
5804
5819
|
const binary = execFileSync6(resolveTarBin(), ["-xOf", archivePath, binaryName], {
|
|
5805
5820
|
maxBuffer: 64 * 1024 * 1024,
|
|
@@ -5807,7 +5822,7 @@ async function installMissingEngram(options = {}) {
|
|
|
5807
5822
|
stdio: ["ignore", "pipe", "pipe"]
|
|
5808
5823
|
});
|
|
5809
5824
|
if (binary.length === 0) throw new Error("El artefacto Engram no contiene un binario v\xE1lido.");
|
|
5810
|
-
const stagedBin =
|
|
5825
|
+
const stagedBin = path24.join(staging, binaryName);
|
|
5811
5826
|
fs19.writeFileSync(stagedBin, binary, { flag: "wx", mode: 493 });
|
|
5812
5827
|
fs19.linkSync(stagedBin, bin);
|
|
5813
5828
|
outcome = { ok: true, bin };
|