plugnz 0.0.22 → 0.0.23
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/dist/hook-runtime.mjs +52 -8
- package/dist/plugnz.mjs +723 -611
- package/package.json +1 -1
package/dist/plugnz.mjs
CHANGED
|
@@ -6957,8 +6957,17 @@ var require_public_api = __commonJS(function(exports) {
|
|
|
6957
6957
|
});
|
|
6958
6958
|
|
|
6959
6959
|
// src/hooks.ts
|
|
6960
|
-
import {
|
|
6960
|
+
import { lstatSync as lstatSync8, readFileSync as readFileSync14 } from "node:fs";
|
|
6961
6961
|
import { isAbsolute as isAbsolute7, join as join19, resolve as resolve10 } from "node:path";
|
|
6962
|
+
function hookEffectGap(required, supported) {
|
|
6963
|
+
for (const effect of HOOK_EFFECTS) {
|
|
6964
|
+
if (required?.[effect] !== true)
|
|
6965
|
+
continue;
|
|
6966
|
+
if (supported?.[effect] !== true)
|
|
6967
|
+
return { effect, status: supported?.[effect] === false ? "unsupported" : "unverified" };
|
|
6968
|
+
}
|
|
6969
|
+
return null;
|
|
6970
|
+
}
|
|
6962
6971
|
function record(value, label) {
|
|
6963
6972
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
6964
6973
|
throw new Error(label + " must be an object");
|
|
@@ -6977,8 +6986,9 @@ function text2(value, label, nonblank = true) {
|
|
|
6977
6986
|
function validateHookConfig(value) {
|
|
6978
6987
|
const root = record(value, "Hook configuration");
|
|
6979
6988
|
keys(root, ["version", "hooks"], "Hook configuration");
|
|
6980
|
-
|
|
6981
|
-
|
|
6989
|
+
const version = root["version"];
|
|
6990
|
+
if (version !== 1 && version !== 2)
|
|
6991
|
+
throw new Error("Hook configuration version must be 1 or 2");
|
|
6982
6992
|
const sourceHooks = record(root["hooks"], "hooks");
|
|
6983
6993
|
keys(sourceHooks, HOOK_EVENTS, "hooks");
|
|
6984
6994
|
const hooks = {};
|
|
@@ -6991,7 +7001,22 @@ function validateHookConfig(value) {
|
|
|
6991
7001
|
hooks[event] = handlers.map((value, index) => {
|
|
6992
7002
|
const label = event + "[" + index + "]";
|
|
6993
7003
|
const handler = record(value, label);
|
|
6994
|
-
keys(handler, ["command", "tools", "timeoutMs"], label);
|
|
7004
|
+
keys(handler, version === 1 ? ["command", "tools", "timeoutMs"] : ["command", "tools", "timeoutMs", "requires"], label);
|
|
7005
|
+
let requires;
|
|
7006
|
+
if (version === 2) {
|
|
7007
|
+
const effects = handler["requires"] === undefined ? {} : record(handler["requires"], label + ".requires");
|
|
7008
|
+
keys(effects, HOOK_EFFECTS, label + ".requires");
|
|
7009
|
+
for (const effect of HOOK_EFFECTS) {
|
|
7010
|
+
if (effects[effect] !== undefined && typeof effects[effect] !== "boolean")
|
|
7011
|
+
throw new Error(label + ".requires." + effect + " must be boolean");
|
|
7012
|
+
}
|
|
7013
|
+
requires = { ...effects };
|
|
7014
|
+
if (requires.continue === true && event !== "turn.stop")
|
|
7015
|
+
throw new Error(label + ": continue is only available at turn.stop");
|
|
7016
|
+
if (event === "turn.stop" && requires.context === true !== (requires.continue === true)) {
|
|
7017
|
+
throw new Error(label + ": turn.stop requires context:true and continue:true together");
|
|
7018
|
+
}
|
|
7019
|
+
}
|
|
6995
7020
|
const command = handler["command"];
|
|
6996
7021
|
if (!Array.isArray(command) || command.length === 0)
|
|
6997
7022
|
throw new Error(label + ".command must be a nonempty argv array");
|
|
@@ -7009,15 +7034,25 @@ function validateHookConfig(value) {
|
|
|
7009
7034
|
if (timeout !== undefined && (typeof timeout !== "number" || !Number.isInteger(timeout) || timeout < 1 || timeout > MAX_HOOK_TIMEOUT_MS)) {
|
|
7010
7035
|
throw new Error(label + ".timeoutMs must be an integer from 1 to " + MAX_HOOK_TIMEOUT_MS);
|
|
7011
7036
|
}
|
|
7012
|
-
return { command: argv, ...tools === undefined ? {} : { tools }, ...timeout === undefined ? {} : { timeoutMs: timeout } };
|
|
7037
|
+
return { command: argv, ...tools === undefined ? {} : { tools }, ...timeout === undefined ? {} : { timeoutMs: timeout }, ...requires === undefined ? {} : { requires } };
|
|
7013
7038
|
});
|
|
7014
7039
|
}
|
|
7015
|
-
return { version
|
|
7040
|
+
return { version, hooks };
|
|
7016
7041
|
}
|
|
7017
7042
|
function readHookConfig(pluginRoot) {
|
|
7018
7043
|
const path = join19(pluginRoot, HOOK_CONFIG_FILE);
|
|
7019
|
-
|
|
7020
|
-
|
|
7044
|
+
let stat;
|
|
7045
|
+
try {
|
|
7046
|
+
stat = lstatSync8(path);
|
|
7047
|
+
} catch (error) {
|
|
7048
|
+
if (error.code === "ENOENT")
|
|
7049
|
+
return;
|
|
7050
|
+
throw error;
|
|
7051
|
+
}
|
|
7052
|
+
if (stat.isSymbolicLink())
|
|
7053
|
+
throw new Error("Hook source symlinks are unsupported: " + path);
|
|
7054
|
+
if (!stat.isFile())
|
|
7055
|
+
throw new Error("Hook manifest must be a regular file: " + path);
|
|
7021
7056
|
let value;
|
|
7022
7057
|
try {
|
|
7023
7058
|
value = JSON.parse(readFileSync14(path, "utf8"));
|
|
@@ -7026,9 +7061,10 @@ function readHookConfig(pluginRoot) {
|
|
|
7026
7061
|
}
|
|
7027
7062
|
return validateHookConfig(value);
|
|
7028
7063
|
}
|
|
7029
|
-
var HOOK_EVENTS, HOOK_CONFIG_FILE = "plugnz.hooks.json", DEFAULT_HOOK_TIMEOUT_MS = 1e4, MAX_HOOK_TIMEOUT_MS = 60000;
|
|
7064
|
+
var HOOK_EVENTS, HOOK_CONFIG_FILE = "plugnz.hooks.json", DEFAULT_HOOK_TIMEOUT_MS = 1e4, MAX_HOOK_TIMEOUT_MS = 60000, HOOK_EFFECTS;
|
|
7030
7065
|
var init_hooks = __esm(() => {
|
|
7031
7066
|
HOOK_EVENTS = ["session.start", "turn.stop", "tool.before", "tool.after"];
|
|
7067
|
+
HOOK_EFFECTS = ["context", "continue"];
|
|
7032
7068
|
});
|
|
7033
7069
|
|
|
7034
7070
|
// src/hosts/command-hooks.ts
|
|
@@ -7111,7 +7147,7 @@ var init_command_hooks = __esm(() => {
|
|
|
7111
7147
|
});
|
|
7112
7148
|
|
|
7113
7149
|
// src/hosts/command-hook-manifest.ts
|
|
7114
|
-
import { existsSync as
|
|
7150
|
+
import { existsSync as existsSync15, mkdirSync, readFileSync as readFileSync15, rmSync, writeFileSync } from "node:fs";
|
|
7115
7151
|
import { dirname as dirname4, join as join20 } from "node:path";
|
|
7116
7152
|
function manifest(path) {
|
|
7117
7153
|
let parsed;
|
|
@@ -7134,13 +7170,13 @@ function manifest(path) {
|
|
|
7134
7170
|
function prepareCommandHookManifest(stagingRoot, relativeNativePath, removeRoot) {
|
|
7135
7171
|
const rootPath = join20(stagingRoot, "plugin.json");
|
|
7136
7172
|
const nativePath = join20(stagingRoot, relativeNativePath);
|
|
7137
|
-
const root =
|
|
7173
|
+
const root = existsSync15(rootPath) ? manifest(rootPath) : undefined;
|
|
7138
7174
|
if (root) {
|
|
7139
7175
|
const unsupported = Object.keys(root).find((key) => !IDENTITY_FIELDS.includes(key));
|
|
7140
7176
|
if (unsupported)
|
|
7141
7177
|
throw new Error('Hook build cannot project root plugin.json field "' + unsupported + '"; use an explicit native plugin manifest');
|
|
7142
7178
|
}
|
|
7143
|
-
const native =
|
|
7179
|
+
const native = existsSync15(nativePath) ? manifest(nativePath) : undefined;
|
|
7144
7180
|
if (!native && !root)
|
|
7145
7181
|
throw new Error("Hook build requires a plugin identity in plugin.json or " + relativeNativePath);
|
|
7146
7182
|
if (native) {
|
|
@@ -7187,6 +7223,33 @@ var init_claude_code_hooks = __esm(() => {
|
|
|
7187
7223
|
hookAdapter = { ...adapter, prepare: prepareHookPlugin };
|
|
7188
7224
|
});
|
|
7189
7225
|
|
|
7226
|
+
// src/compatibility.ts
|
|
7227
|
+
function requireCompatible(profile, capability) {
|
|
7228
|
+
const status = profile.capabilities[capability];
|
|
7229
|
+
if (status !== "supported")
|
|
7230
|
+
throw new CompatibilityError(profile.id, capability, status, profile.evidence);
|
|
7231
|
+
}
|
|
7232
|
+
function compatibilityEvidenceId(evidence) {
|
|
7233
|
+
return typeof evidence === "string" && evidence.trim().length > 0 ? evidence : null;
|
|
7234
|
+
}
|
|
7235
|
+
var CompatibilityError;
|
|
7236
|
+
var init_compatibility = __esm(() => {
|
|
7237
|
+
CompatibilityError = class CompatibilityError extends Error {
|
|
7238
|
+
target;
|
|
7239
|
+
capability;
|
|
7240
|
+
status;
|
|
7241
|
+
evidence;
|
|
7242
|
+
constructor(target, capability, status, evidence, diagnostic) {
|
|
7243
|
+
super(diagnostic ?? `target '${target}' is ${status} for ${capability}; evidence: ${evidence}`);
|
|
7244
|
+
this.target = target;
|
|
7245
|
+
this.capability = capability;
|
|
7246
|
+
this.status = status;
|
|
7247
|
+
this.evidence = evidence;
|
|
7248
|
+
this.name = "CompatibilityError";
|
|
7249
|
+
}
|
|
7250
|
+
};
|
|
7251
|
+
});
|
|
7252
|
+
|
|
7190
7253
|
// src/hosts/codex-hooks.ts
|
|
7191
7254
|
function prepareHookPlugin2(stagingRoot) {
|
|
7192
7255
|
prepareCommandHookManifest(stagingRoot, ".codex-plugin/plugin.json", true);
|
|
@@ -7530,13 +7593,13 @@ var init_zcode_cli_hooks = __esm(() => {
|
|
|
7530
7593
|
|
|
7531
7594
|
// src/hook-build.ts
|
|
7532
7595
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
7533
|
-
import { cpSync, existsSync as
|
|
7596
|
+
import { cpSync, existsSync as existsSync17, lstatSync as lstatSync10, mkdirSync as mkdirSync2, mkdtempSync, readFileSync as readFileSync17, readdirSync as readdirSync10, realpathSync as realpathSync3, renameSync, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
7534
7597
|
import { dirname as dirname6, isAbsolute as isAbsolute8, join as join22, relative as relative4, resolve as resolve11 } from "node:path";
|
|
7535
7598
|
import { fileURLToPath } from "node:url";
|
|
7536
7599
|
function hookRuntimeSource() {
|
|
7537
7600
|
const moduleDir = dirname6(fileURLToPath(import.meta.url));
|
|
7538
7601
|
const source = join22(moduleDir, "hooks.ts");
|
|
7539
|
-
if (
|
|
7602
|
+
if (existsSync17(source) && process.versions["bun"]) {
|
|
7540
7603
|
if (developmentRuntime !== undefined)
|
|
7541
7604
|
return developmentRuntime;
|
|
7542
7605
|
const built = spawnSync3(process.execPath, ["build", source, "--target=node", "--format=esm"], {
|
|
@@ -7553,14 +7616,14 @@ function hookRuntimeSource() {
|
|
|
7553
7616
|
return output;
|
|
7554
7617
|
}
|
|
7555
7618
|
for (const path of [join22(moduleDir, RUNTIME_FILE), join22(moduleDir, "..", "dist", RUNTIME_FILE)]) {
|
|
7556
|
-
if (
|
|
7619
|
+
if (existsSync17(path))
|
|
7557
7620
|
return readFileSync17(path, "utf8");
|
|
7558
7621
|
}
|
|
7559
7622
|
throw new Error("Hook runtime is missing from the distribution; rebuild with bun run build");
|
|
7560
7623
|
}
|
|
7561
7624
|
function entryExists2(path) {
|
|
7562
7625
|
try {
|
|
7563
|
-
|
|
7626
|
+
lstatSync10(path);
|
|
7564
7627
|
return true;
|
|
7565
7628
|
} catch (error) {
|
|
7566
7629
|
if (error.code === "ENOENT")
|
|
@@ -7576,7 +7639,7 @@ function artifactPath(root, path) {
|
|
|
7576
7639
|
let current = root;
|
|
7577
7640
|
for (const part of path.split("/").slice(0, -1)) {
|
|
7578
7641
|
current = join22(current, part);
|
|
7579
|
-
if (entryExists2(current) && (
|
|
7642
|
+
if (entryExists2(current) && (lstatSync10(current).isSymbolicLink() || !lstatSync10(current).isDirectory())) {
|
|
7580
7643
|
throw new Error("Generated hook artifact parent is not an owned directory: " + current);
|
|
7581
7644
|
}
|
|
7582
7645
|
}
|
|
@@ -7584,8 +7647,15 @@ function artifactPath(root, path) {
|
|
|
7584
7647
|
}
|
|
7585
7648
|
function emitHooksToDirectory(adapter, configValue, stagingRoot) {
|
|
7586
7649
|
const config = validateHookConfig(configValue);
|
|
7650
|
+
for (const event of HOOK_EVENTS) {
|
|
7651
|
+
for (const [index, handler] of (config.hooks[event] ?? []).entries()) {
|
|
7652
|
+
const gap = hookEffectGap(handler.requires, adapter.capabilities[event]);
|
|
7653
|
+
if (gap !== null)
|
|
7654
|
+
throw new CompatibilityError(adapter.id, "hooks", gap.status, "docs/hooks.md", `${adapter.id}: ${event}[${index}] requires ${gap.effect}, but that effect is ${gap.status}`);
|
|
7655
|
+
}
|
|
7656
|
+
}
|
|
7587
7657
|
const root = resolve11(stagingRoot);
|
|
7588
|
-
if (!
|
|
7658
|
+
if (!existsSync17(root) || lstatSync10(root).isSymbolicLink() || !lstatSync10(root).isDirectory())
|
|
7589
7659
|
throw new Error("Hook staging root must be a directory");
|
|
7590
7660
|
adapter.prepare?.(root);
|
|
7591
7661
|
const artifacts = adapter.emit(config);
|
|
@@ -7616,7 +7686,7 @@ function copyAuthoredTree(source, destination, top = true) {
|
|
|
7616
7686
|
continue;
|
|
7617
7687
|
const from = join22(source, name);
|
|
7618
7688
|
const to = join22(destination, name);
|
|
7619
|
-
const stat =
|
|
7689
|
+
const stat = lstatSync10(from);
|
|
7620
7690
|
if (stat.isSymbolicLink())
|
|
7621
7691
|
throw new Error("Hook source symlinks are unsupported: " + from);
|
|
7622
7692
|
if (stat.isDirectory())
|
|
@@ -7630,7 +7700,7 @@ function copyAuthoredTree(source, destination, top = true) {
|
|
|
7630
7700
|
function prospectivePath(path) {
|
|
7631
7701
|
const suffix = [];
|
|
7632
7702
|
let parent = resolve11(path);
|
|
7633
|
-
while (!
|
|
7703
|
+
while (!existsSync17(parent)) {
|
|
7634
7704
|
const next = dirname6(parent);
|
|
7635
7705
|
if (next === parent)
|
|
7636
7706
|
throw new Error("Cannot resolve output ancestor: " + path);
|
|
@@ -7641,7 +7711,7 @@ function prospectivePath(path) {
|
|
|
7641
7711
|
}
|
|
7642
7712
|
function buildHooks(pluginDir, targets, outputDir) {
|
|
7643
7713
|
const requestedSource = resolve11(pluginDir);
|
|
7644
|
-
if (!
|
|
7714
|
+
if (!existsSync17(requestedSource) || lstatSync10(requestedSource).isSymbolicLink() || !lstatSync10(requestedSource).isDirectory()) {
|
|
7645
7715
|
throw new Error("Hook source must be a directory: " + requestedSource);
|
|
7646
7716
|
}
|
|
7647
7717
|
const source = realpathSync3(requestedSource);
|
|
@@ -7664,7 +7734,7 @@ function buildHooks(pluginDir, targets, outputDir) {
|
|
|
7664
7734
|
const physicalOutput = prospectivePath(output);
|
|
7665
7735
|
if (physicalOutput === source || physicalOutput.startsWith(source + "/"))
|
|
7666
7736
|
throw new Error("Hook output must be outside the plugin source");
|
|
7667
|
-
if (entryExists2(output) && (
|
|
7737
|
+
if (entryExists2(output) && (lstatSync10(output).isSymbolicLink() || !lstatSync10(output).isDirectory() || readdirSync10(output).length !== 0)) {
|
|
7668
7738
|
throw new Error("Hook output must be absent or an empty directory: " + output);
|
|
7669
7739
|
}
|
|
7670
7740
|
mkdirSync2(dirname6(output), { recursive: true });
|
|
@@ -7686,6 +7756,7 @@ function buildHooks(pluginDir, targets, outputDir) {
|
|
|
7686
7756
|
var hookAdapters, RUNTIME_FILE = "hook-runtime.mjs", developmentRuntime;
|
|
7687
7757
|
var init_hook_build = __esm(() => {
|
|
7688
7758
|
init_hooks();
|
|
7759
|
+
init_compatibility();
|
|
7689
7760
|
init_claude_code_hooks();
|
|
7690
7761
|
init_codex_hooks();
|
|
7691
7762
|
init_omp_hooks();
|
|
@@ -7708,6 +7779,7 @@ function runHookCli(args) {
|
|
|
7708
7779
|
throw new Error("targets takes no arguments");
|
|
7709
7780
|
console.log(JSON.stringify({
|
|
7710
7781
|
version: 1,
|
|
7782
|
+
configVersions: [1, 2],
|
|
7711
7783
|
targets: hookAdapters.map(({ id, baselineVersion, capabilities }) => ({ id, baselineVersion, capabilities }))
|
|
7712
7784
|
}, null, 2));
|
|
7713
7785
|
return 0;
|
|
@@ -13085,28 +13157,21 @@ function formatFinding(f) {
|
|
|
13085
13157
|
// src/hosts/claude-code-writer.ts
|
|
13086
13158
|
init_claude_code_hooks();
|
|
13087
13159
|
|
|
13088
|
-
// src/
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
}
|
|
13103
|
-
function requireCompatible(profile, capability) {
|
|
13104
|
-
const status = profile.capabilities[capability];
|
|
13105
|
-
if (status !== "supported")
|
|
13106
|
-
throw new CompatibilityError(profile.id, capability, status, profile.evidence);
|
|
13107
|
-
}
|
|
13108
|
-
function compatibilityEvidenceId(evidence) {
|
|
13109
|
-
return typeof evidence === "string" && evidence.trim().length > 0 ? evidence : null;
|
|
13160
|
+
// src/capability-evidence.ts
|
|
13161
|
+
init_compatibility();
|
|
13162
|
+
|
|
13163
|
+
// src/installation-verification.ts
|
|
13164
|
+
function installationVerification(report) {
|
|
13165
|
+
return {
|
|
13166
|
+
schemaVersion: 1,
|
|
13167
|
+
operations: report.outcomes.filter((outcome) => outcome.coverage === "desired-pair").map((outcome) => ({
|
|
13168
|
+
operationId: outcome.operationId,
|
|
13169
|
+
compatibility: outcome.reason?.code === "capability.unsupported" ? "unsupported" : outcome.reason?.code === "capability.unverified" ? "unverified" : outcome.result === "succeeded" ? "admitted" : "unknown",
|
|
13170
|
+
registration: report.command.dryRun ? "not-checked" : outcome.result === "succeeded" && outcome.resourceState === "present" && outcome.activationState === "active-conforming" ? "verified" : "unknown",
|
|
13171
|
+
executionApproval: "not-checked",
|
|
13172
|
+
delivery: "not-observed"
|
|
13173
|
+
}))
|
|
13174
|
+
};
|
|
13110
13175
|
}
|
|
13111
13176
|
|
|
13112
13177
|
// src/error-diagnostic.ts
|
|
@@ -13209,7 +13274,7 @@ function parseLifecycleReport(value) {
|
|
|
13209
13274
|
if (!isObject2(value)) {
|
|
13210
13275
|
throw invalid4("lifecycle report must be an object");
|
|
13211
13276
|
}
|
|
13212
|
-
exactFields3(value, ["schemaVersion", "command", "plan", "outcomes", "summary", "recovery", "adoptions"], "lifecycle report");
|
|
13277
|
+
exactFields3(value, ["schemaVersion", "command", "plan", "outcomes", "summary", "recovery", "adoptions", "verification"], "lifecycle report");
|
|
13213
13278
|
if (value["schemaVersion"] !== LIFECYCLE_REPORT_SCHEMA_VERSION) {
|
|
13214
13279
|
throw invalid4("lifecycle report schemaVersion must be 1");
|
|
13215
13280
|
}
|
|
@@ -13321,6 +13386,14 @@ function parseLifecycleReport(value) {
|
|
|
13321
13386
|
assertAdoptionRecoveryStatus(receipt, modern);
|
|
13322
13387
|
}
|
|
13323
13388
|
assertSummary(summary, outcomes, command["dryRun"], receipts, adoptions);
|
|
13389
|
+
if (value["verification"] !== undefined) {
|
|
13390
|
+
if (commandName !== "add" && commandName !== "update")
|
|
13391
|
+
throw invalid4("installation verification only applies to add/update");
|
|
13392
|
+
const expected = installationVerification(value);
|
|
13393
|
+
if (canonicalAdoptionJson(value["verification"]) !== canonicalAdoptionJson(expected)) {
|
|
13394
|
+
throw contradiction("installation verification contradicts its outcomes or claims unobserved approval/delivery");
|
|
13395
|
+
}
|
|
13396
|
+
}
|
|
13324
13397
|
return value;
|
|
13325
13398
|
}
|
|
13326
13399
|
function matchesAdoptionRecovery(record, receipt) {
|
|
@@ -13820,7 +13893,7 @@ function isObject2(value) {
|
|
|
13820
13893
|
|
|
13821
13894
|
// src/semantic-inventory.ts
|
|
13822
13895
|
init_hooks();
|
|
13823
|
-
import { existsSync as
|
|
13896
|
+
import { existsSync as existsSync16, lstatSync as lstatSync9, readFileSync as readFileSync16, readdirSync as readdirSync9 } from "node:fs";
|
|
13824
13897
|
import { dirname as dirname5, join as join21, relative as relative3 } from "node:path";
|
|
13825
13898
|
var PACKAGE_SEMANTICS = [
|
|
13826
13899
|
"ordinary-skills",
|
|
@@ -13874,7 +13947,14 @@ function inventoryPackageSemantics(plugin) {
|
|
|
13874
13947
|
events,
|
|
13875
13948
|
handlerTypes: ["command"],
|
|
13876
13949
|
handlerFacets: [],
|
|
13877
|
-
groups: events.map((event) => ({ event, matcher: null, matcherKind: "all", handlerTypes: ["command"], handlerFacets: [] }))
|
|
13950
|
+
groups: portableHooks.version === 1 ? events.map((event) => ({ event, matcher: null, matcherKind: "all", handlerTypes: ["command"], handlerFacets: [] })) : events.flatMap((event) => (portableHooks.hooks[event] ?? []).map((handler) => ({
|
|
13951
|
+
event,
|
|
13952
|
+
matcher: null,
|
|
13953
|
+
matcherKind: "all",
|
|
13954
|
+
handlerTypes: ["command"],
|
|
13955
|
+
handlerFacets: [],
|
|
13956
|
+
requiredEffects: handler.requires ?? {}
|
|
13957
|
+
})))
|
|
13878
13958
|
});
|
|
13879
13959
|
}
|
|
13880
13960
|
const resources = files.filter((path) => (["assets/", "references/", "resources/"].some((root) => path.startsWith(root)) || path.startsWith("skills/") && !path.endsWith("/SKILL.md") || path.startsWith("hooks/") || path.startsWith(".claude/hooks/")) && !sidecars.has(path) && !hookInventory.configPaths.has(path));
|
|
@@ -14011,7 +14091,7 @@ function inventorySkillPolicy(root, skill) {
|
|
|
14011
14091
|
}
|
|
14012
14092
|
}
|
|
14013
14093
|
const sidecar = `${dirname5(skill)}/agents/openai.yaml`;
|
|
14014
|
-
if (
|
|
14094
|
+
if (existsSync16(join21(root, sidecar))) {
|
|
14015
14095
|
const parsed = parseYamlObject(readFileSync16(join21(root, sidecar), "utf8"), `Codex invocation sidecar ${sidecar}`);
|
|
14016
14096
|
const policy = parsed["policy"];
|
|
14017
14097
|
if (policy !== undefined) {
|
|
@@ -14095,7 +14175,7 @@ function readSemanticManifests(root) {
|
|
|
14095
14175
|
".plugin/plugin.json",
|
|
14096
14176
|
".claude-plugin/plugin.json",
|
|
14097
14177
|
".codex-plugin/plugin.json"
|
|
14098
|
-
].filter((path) =>
|
|
14178
|
+
].filter((path) => existsSync16(join21(root, path))).map((path) => ({
|
|
14099
14179
|
...parseJsonObject(join21(root, path), `plugin manifest ${path}`),
|
|
14100
14180
|
path
|
|
14101
14181
|
}));
|
|
@@ -14183,13 +14263,13 @@ function declaredHookPath(root, declaration) {
|
|
|
14183
14263
|
invalid5(`declared hook path must be a canonical file inside the plugin root: ${declaration}`);
|
|
14184
14264
|
}
|
|
14185
14265
|
const absolute = join21(root, path);
|
|
14186
|
-
if (!
|
|
14266
|
+
if (!existsSync16(absolute))
|
|
14187
14267
|
invalid5(`declared hook configuration does not exist: ${declaration}`);
|
|
14188
|
-
const stat =
|
|
14268
|
+
const stat = lstatSync9(absolute);
|
|
14189
14269
|
if (stat.isDirectory()) {
|
|
14190
14270
|
const document = `${path}/hooks.json`;
|
|
14191
14271
|
const documentPath = join21(root, document);
|
|
14192
|
-
if (!
|
|
14272
|
+
if (!existsSync16(documentPath) || !lstatSync9(documentPath).isFile()) {
|
|
14193
14273
|
invalid5(`declared hook directory must contain hooks.json: ${declaration}`);
|
|
14194
14274
|
}
|
|
14195
14275
|
return { path: document, directory: true };
|
|
@@ -14301,7 +14381,7 @@ function walkFiles(root) {
|
|
|
14301
14381
|
if (entry === ".git" || entry === "node_modules" || entry === ".plgnz-install.json")
|
|
14302
14382
|
continue;
|
|
14303
14383
|
const path = join21(dir, entry);
|
|
14304
|
-
const stat =
|
|
14384
|
+
const stat = lstatSync9(path);
|
|
14305
14385
|
if (stat.isSymbolicLink())
|
|
14306
14386
|
invalid5(`package semantic inventory refuses symlink: ${portable(relative3(root, path))}`);
|
|
14307
14387
|
if (stat.isDirectory())
|
|
@@ -14324,7 +14404,7 @@ var COMPONENT_ROOT_SPECS = [
|
|
|
14324
14404
|
var UNSUPPORTED_COMPONENT_ROOTS = [".codex/commands", ".codex/agents"];
|
|
14325
14405
|
function inventoryComponentRoots(root) {
|
|
14326
14406
|
for (const unsupported of UNSUPPORTED_COMPONENT_ROOTS) {
|
|
14327
|
-
if (
|
|
14407
|
+
if (existsSync16(join21(root, unsupported)))
|
|
14328
14408
|
invalid5(`unsupported component root: ${unsupported}`);
|
|
14329
14409
|
}
|
|
14330
14410
|
const definitions = [];
|
|
@@ -14332,9 +14412,9 @@ function inventoryComponentRoots(root) {
|
|
|
14332
14412
|
const permissionPaths = new Set;
|
|
14333
14413
|
for (const spec of COMPONENT_ROOT_SPECS) {
|
|
14334
14414
|
const directory = join21(root, spec.root);
|
|
14335
|
-
if (!
|
|
14415
|
+
if (!existsSync16(directory))
|
|
14336
14416
|
continue;
|
|
14337
|
-
const rootStat =
|
|
14417
|
+
const rootStat = lstatSync9(directory);
|
|
14338
14418
|
if (!rootStat.isDirectory())
|
|
14339
14419
|
invalid5(`component root must be a directory: ${spec.root}`);
|
|
14340
14420
|
const entries = readdirSync9(directory).sort();
|
|
@@ -14344,7 +14424,7 @@ function inventoryComponentRoots(root) {
|
|
|
14344
14424
|
for (const entry of entries) {
|
|
14345
14425
|
const absolute = join21(directory, entry);
|
|
14346
14426
|
const path = `${spec.root}/${entry}`;
|
|
14347
|
-
const stat =
|
|
14427
|
+
const stat = lstatSync9(absolute);
|
|
14348
14428
|
if (!stat.isFile())
|
|
14349
14429
|
invalid5(`component root entries must be regular files: ${path}`);
|
|
14350
14430
|
const suffix = Object.keys(spec.dialects).find((candidate) => entry.endsWith(candidate));
|
|
@@ -14474,6 +14554,8 @@ var PERMISSION_FIELDS = [
|
|
|
14474
14554
|
];
|
|
14475
14555
|
|
|
14476
14556
|
// src/capability-evidence.ts
|
|
14557
|
+
init_hooks();
|
|
14558
|
+
|
|
14477
14559
|
class PackageCapabilityError extends CompatibilityError {
|
|
14478
14560
|
gaps;
|
|
14479
14561
|
constructor(target, admission) {
|
|
@@ -14704,6 +14786,9 @@ function hookDeclarationProblem(declaration, selectedManifest, policy) {
|
|
|
14704
14786
|
const unsupportedFacet = group.handlerFacets.find((facet) => policy.unsupportedHandlerFacets.includes(facet));
|
|
14705
14787
|
if (unsupportedFacet !== undefined)
|
|
14706
14788
|
return unsupportedHookProblem(hookHandlerFacetProblem(unsupportedFacet));
|
|
14789
|
+
const gap = hookEffectGap(group.requiredEffects, policy.supportedEffects?.[group.event]);
|
|
14790
|
+
if (gap !== null)
|
|
14791
|
+
return { status: gap.status, diagnostic: `event '${group.event}' requires ${gap.effect}, but that effect is ${gap.status}` };
|
|
14707
14792
|
}
|
|
14708
14793
|
return null;
|
|
14709
14794
|
}
|
|
@@ -14737,7 +14822,16 @@ function normalizeHookPolicy(input) {
|
|
|
14737
14822
|
const matcherlessEvents = uniqueStrings(input.matcherlessEvents, "matcherless hook event").sort();
|
|
14738
14823
|
const supportedMatcherKinds = uniqueStrings(input.supportedMatcherKinds, "hook matcher kind").sort();
|
|
14739
14824
|
const unsupportedHandlerFacets = uniqueStrings(input.unsupportedHandlerFacets, "unsupported hook handler facet").sort();
|
|
14825
|
+
let supportedEffects;
|
|
14826
|
+
if (input.supportedEffects !== undefined) {
|
|
14827
|
+
supportedEffects = Object.freeze(Object.fromEntries(Object.entries(input.supportedEffects).sort(([a], [b]) => a.localeCompare(b)).map(([event, effects]) => {
|
|
14828
|
+
if (!supportedEvents.includes(event) || effects === null || typeof effects !== "object" || Array.isArray(effects) || Object.keys(effects).some((key) => !HOOK_EFFECTS.includes(key)) || Object.values(effects).some((value) => typeof value !== "boolean"))
|
|
14829
|
+
throw new Error("Invalid hook effect evidence for " + event);
|
|
14830
|
+
return [event, Object.freeze(Object.fromEntries(HOOK_EFFECTS.filter((effect) => effects[effect] !== undefined).map((effect) => [effect, effects[effect]])))];
|
|
14831
|
+
})));
|
|
14832
|
+
}
|
|
14740
14833
|
return Object.freeze({
|
|
14834
|
+
...supportedEffects === undefined ? {} : { supportedEffects },
|
|
14741
14835
|
manifestPrecedence: Object.freeze(manifestPrecedence),
|
|
14742
14836
|
supportedForms: Object.freeze(supportedForms),
|
|
14743
14837
|
supportedEvents: Object.freeze(supportedEvents),
|
|
@@ -14788,6 +14882,7 @@ function portableHookProfile(adapter, route, operations) {
|
|
|
14788
14882
|
supported.has(semantic) ? "supported" : "unsupported"
|
|
14789
14883
|
])),
|
|
14790
14884
|
hookPolicy: {
|
|
14885
|
+
supportedEffects: Object.fromEntries(HOOK_EVENTS.map((event) => [event, { context: adapter.capabilities[event].context, continue: adapter.capabilities[event].continue }])),
|
|
14791
14886
|
manifestPrecedence: ["plugin.json", ".plugin/plugin.json", ".claude-plugin/plugin.json", ".codex-plugin/plugin.json", ".zcode-plugin/plugin.json"],
|
|
14792
14887
|
supportedForms: ["portable-hooks"],
|
|
14793
14888
|
supportedEvents: HOOK_EVENTS,
|
|
@@ -14803,7 +14898,7 @@ function portableHookProfile(adapter, route, operations) {
|
|
|
14803
14898
|
// src/hook-install.ts
|
|
14804
14899
|
init_hook_build();
|
|
14805
14900
|
init_hooks();
|
|
14806
|
-
import { cpSync as cpSync2, existsSync as
|
|
14901
|
+
import { cpSync as cpSync2, existsSync as existsSync18, mkdirSync as mkdirSync3, mkdtempSync as mkdtempSync2, readFileSync as readFileSync18, rmSync as rmSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
14807
14902
|
import { join as join23 } from "node:path";
|
|
14808
14903
|
import { tmpdir } from "node:os";
|
|
14809
14904
|
function preflightPortableHooks(adapter, source) {
|
|
@@ -14820,9 +14915,9 @@ function compilePortableHooksInStage(adapter, stage, options = {}) {
|
|
|
14820
14915
|
const config = readHookConfig(stage);
|
|
14821
14916
|
if (config === undefined)
|
|
14822
14917
|
return false;
|
|
14823
|
-
if (options.retainCanonicalIdentity &&
|
|
14918
|
+
if (options.retainCanonicalIdentity && existsSync18(join23(stage, "plugin.json"))) {
|
|
14824
14919
|
const identity = join23(stage, ".plugin", "plugin.json");
|
|
14825
|
-
if (!
|
|
14920
|
+
if (!existsSync18(identity)) {
|
|
14826
14921
|
mkdirSync3(join23(stage, ".plugin"), { recursive: true });
|
|
14827
14922
|
cpSync2(join23(stage, "plugin.json"), identity);
|
|
14828
14923
|
}
|
|
@@ -14844,18 +14939,18 @@ function registerProjectedExtension(stage, key, entry) {
|
|
|
14844
14939
|
}
|
|
14845
14940
|
|
|
14846
14941
|
// src/hosts/claude-code-writer.ts
|
|
14847
|
-
import { cpSync as cpSync5, existsSync as
|
|
14942
|
+
import { cpSync as cpSync5, existsSync as existsSync21, lstatSync as lstatSync13, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync5, readFileSync as readFileSync21, readdirSync as readdirSync13, renameSync as renameSync3, rmSync as rmSync6, statSync as statSync9, writeFileSync as writeFileSync6 } from "node:fs";
|
|
14848
14943
|
import { dirname as dirname8, join as join27, relative as relative7, resolve as resolve15 } from "node:path";
|
|
14849
14944
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
14850
14945
|
|
|
14851
14946
|
// src/conversion.ts
|
|
14852
|
-
import { cpSync as cpSync4, existsSync as
|
|
14947
|
+
import { cpSync as cpSync4, existsSync as existsSync20, lstatSync as lstatSync12, mkdirSync as mkdirSync5, mkdtempSync as mkdtempSync4, readFileSync as readFileSync20, readdirSync as readdirSync12, rmSync as rmSync5, statSync as statSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
14853
14948
|
import { basename as basename3, dirname as dirname7, join as join25, resolve as resolve13 } from "node:path";
|
|
14854
14949
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
14855
14950
|
|
|
14856
14951
|
// src/source.ts
|
|
14857
14952
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
14858
|
-
import { cpSync as cpSync3, existsSync as
|
|
14953
|
+
import { cpSync as cpSync3, existsSync as existsSync19, lstatSync as lstatSync11, mkdirSync as mkdirSync4, mkdtempSync as mkdtempSync3, readFileSync as readFileSync19, readdirSync as readdirSync11, renameSync as renameSync2, rmSync as rmSync4, statSync as statSync7 } from "node:fs";
|
|
14859
14954
|
import { join as join24, basename as basename2, isAbsolute as isAbsolute9, relative as relative5, resolve as resolve12 } from "node:path";
|
|
14860
14955
|
function resolveSource(source) {
|
|
14861
14956
|
const parsed = parseSource(source);
|
|
@@ -14870,7 +14965,7 @@ function resolveSource(source) {
|
|
|
14870
14965
|
targetDir = freezeRemoteSource(parsed.fetchLocator, sha, parsed.binding.locator);
|
|
14871
14966
|
} else {
|
|
14872
14967
|
targetDir = sourceUri;
|
|
14873
|
-
if (!
|
|
14968
|
+
if (!existsSync19(targetDir))
|
|
14874
14969
|
throw new Error(`Local source not found: ${targetDir}`);
|
|
14875
14970
|
targetDir = assertSafeSourceTree(targetDir);
|
|
14876
14971
|
sourceRoot = targetDir;
|
|
@@ -14895,7 +14990,7 @@ function resolveSource(source) {
|
|
|
14895
14990
|
const mp1 = join24(targetDir, ".claude-plugin", "marketplace.json");
|
|
14896
14991
|
const mp2 = join24(targetDir, ".omp-plugin", "marketplace.json");
|
|
14897
14992
|
const mp3 = join24(targetDir, "marketplace.json");
|
|
14898
|
-
const mpPath =
|
|
14993
|
+
const mpPath = existsSync19(mp1) ? mp1 : existsSync19(mp2) ? mp2 : existsSync19(mp3) ? mp3 : null;
|
|
14899
14994
|
if (mpPath !== null) {
|
|
14900
14995
|
const data = parseMarketplace(mpPath);
|
|
14901
14996
|
const marketplaceName = typeof data["name"] === "string" ? data["name"] : "local";
|
|
@@ -14912,7 +15007,7 @@ function resolveSource(source) {
|
|
|
14912
15007
|
const pDir = resolve12(targetDir, entry["source"]);
|
|
14913
15008
|
if (!isInside(targetDir, pDir))
|
|
14914
15009
|
throw new Error(`Marketplace plugin source escapes collection root: ${entry["source"]}`);
|
|
14915
|
-
if (!
|
|
15010
|
+
if (!existsSync19(pDir) || !statSync7(pDir).isDirectory())
|
|
14916
15011
|
throw new Error(`Marketplace plugin source is not a directory: ${entry["source"]}`);
|
|
14917
15012
|
plugins.push(pluginFromDir(pDir, marketplaceName, targetDir, sourceRoot));
|
|
14918
15013
|
}
|
|
@@ -14967,7 +15062,7 @@ function freezeLocalSource(source) {
|
|
|
14967
15062
|
if (fingerprintTree(verification) !== fingerprint)
|
|
14968
15063
|
throw new Error(`Local source changed while it was being frozen: ${source}`);
|
|
14969
15064
|
const target = join24(snapshots, fingerprint);
|
|
14970
|
-
if (
|
|
15065
|
+
if (existsSync19(target)) {
|
|
14971
15066
|
if (fingerprintTree(assertSafeSourceTree(target)) !== fingerprint)
|
|
14972
15067
|
throw new Error(`Cached Source snapshot is corrupt: ${target}`);
|
|
14973
15068
|
return target;
|
|
@@ -14985,7 +15080,7 @@ function copySourceTree(source, destination) {
|
|
|
14985
15080
|
continue;
|
|
14986
15081
|
const from = join24(source, entry);
|
|
14987
15082
|
const to = join24(destination, entry);
|
|
14988
|
-
const stat =
|
|
15083
|
+
const stat = lstatSync11(from);
|
|
14989
15084
|
if (stat.isSymbolicLink())
|
|
14990
15085
|
throw new Error(`Symlink resources are not supported: ${from}`);
|
|
14991
15086
|
if (stat.isDirectory()) {
|
|
@@ -15034,9 +15129,9 @@ function parseSource(source) {
|
|
|
15034
15129
|
}
|
|
15035
15130
|
function canonicalLocalArgument(source) {
|
|
15036
15131
|
const path = resolve12(source);
|
|
15037
|
-
if (!
|
|
15132
|
+
if (!existsSync19(path))
|
|
15038
15133
|
return path;
|
|
15039
|
-
if (
|
|
15134
|
+
if (lstatSync11(path).isSymbolicLink())
|
|
15040
15135
|
throw new Error(`Symlink resources are not supported: ${path}`);
|
|
15041
15136
|
return realpath(path);
|
|
15042
15137
|
}
|
|
@@ -15108,7 +15203,7 @@ function freezeRemoteSource(fetchLocator, revision, displayLocator) {
|
|
|
15108
15203
|
rmSync4(join24(candidate, ".git"), { recursive: true, force: true });
|
|
15109
15204
|
const fingerprint = fingerprintTree(candidate);
|
|
15110
15205
|
const target = join24(snapshots, fingerprint);
|
|
15111
|
-
if (
|
|
15206
|
+
if (existsSync19(target)) {
|
|
15112
15207
|
if (fingerprintTree(assertSafeSourceTree(target)) !== fingerprint)
|
|
15113
15208
|
throw new Error(`Cached Source snapshot is corrupt: ${target}`);
|
|
15114
15209
|
return target;
|
|
@@ -15167,12 +15262,12 @@ function isRecord3(value) {
|
|
|
15167
15262
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15168
15263
|
}
|
|
15169
15264
|
function isPluginDir(dir) {
|
|
15170
|
-
return manifestPaths(dir).some(
|
|
15265
|
+
return manifestPaths(dir).some(existsSync19) || existsSync19(join24(dir, ".mcp.json")) || existsSync19(join24(dir, "mcp.json"));
|
|
15171
15266
|
}
|
|
15172
15267
|
function readPluginManifest(dir) {
|
|
15173
15268
|
let selected;
|
|
15174
15269
|
for (const path of manifestPaths(dir)) {
|
|
15175
|
-
if (!
|
|
15270
|
+
if (!existsSync19(path))
|
|
15176
15271
|
continue;
|
|
15177
15272
|
const current = parsePluginManifest(path);
|
|
15178
15273
|
if (selected === undefined) {
|
|
@@ -15221,7 +15316,7 @@ var UNSUPPORTED_CLAUDE_COMPONENTS = new Set(["agents", "hooks", "mcpServers", "o
|
|
|
15221
15316
|
function projectPluginForCodex(sourceDir, destinationDir) {
|
|
15222
15317
|
const source = resolve13(sourceDir);
|
|
15223
15318
|
const destination = resolve13(destinationDir);
|
|
15224
|
-
if (!
|
|
15319
|
+
if (!existsSync20(source) || !statSync8(source).isDirectory())
|
|
15225
15320
|
throw new Error(`plugin source is not a directory: ${source}`);
|
|
15226
15321
|
if (destination === source || destination.startsWith(`${source}/`))
|
|
15227
15322
|
throw new Error("destination must not be inside the plugin source");
|
|
@@ -15250,7 +15345,7 @@ function projectPluginForCodex(sourceDir, destinationDir) {
|
|
|
15250
15345
|
function projectPluginForOmp(sourceDir, destinationDir, options) {
|
|
15251
15346
|
const source = resolve13(sourceDir);
|
|
15252
15347
|
const destination = resolve13(destinationDir);
|
|
15253
|
-
if (!
|
|
15348
|
+
if (!existsSync20(source) || !statSync8(source).isDirectory())
|
|
15254
15349
|
throw new Error(`plugin source is not a directory: ${source}`);
|
|
15255
15350
|
if (destination === source || destination.startsWith(`${source}/`))
|
|
15256
15351
|
throw new Error("destination must not be inside the plugin source");
|
|
@@ -15275,11 +15370,11 @@ function projectPluginForOmp(sourceDir, destinationDir, options) {
|
|
|
15275
15370
|
writeOmpCommand(destination, `${options.namespace}:${command.name}`, command.description, command.argumentHint, rewriteOmpCommandReferences(command.body, commandNames, options.namespace), join25(options.activeRoot, ".plgnz", "source", relativeCommandBase(source, command.source)), projected);
|
|
15276
15371
|
}
|
|
15277
15372
|
const skills = join25(source, "skills");
|
|
15278
|
-
if (
|
|
15373
|
+
if (existsSync20(skills)) {
|
|
15279
15374
|
for (const entry of readdirSync12(skills).sort()) {
|
|
15280
15375
|
const skillDir = join25(skills, entry);
|
|
15281
15376
|
const skillFile = join25(skillDir, "SKILL.md");
|
|
15282
|
-
if (!statSync8(skillDir).isDirectory() || !
|
|
15377
|
+
if (!statSync8(skillDir).isDirectory() || !existsSync20(skillFile))
|
|
15283
15378
|
continue;
|
|
15284
15379
|
const parsed = parseManualSkill(skillDir);
|
|
15285
15380
|
if (parsed.userInvocable === false)
|
|
@@ -15348,7 +15443,7 @@ function parseManualSkill(directory) {
|
|
|
15348
15443
|
if (hint !== undefined && typeof hint !== "string")
|
|
15349
15444
|
throw new Error(`argument hint must be text: ${path}`);
|
|
15350
15445
|
const sidecar = join25(directory, "agents", "openai.yaml");
|
|
15351
|
-
const implicit =
|
|
15446
|
+
const implicit = existsSync20(sidecar) ? readImplicitPolicy(sidecar) : undefined;
|
|
15352
15447
|
if (implicit !== undefined && typeof manual === "boolean" && implicit === manual)
|
|
15353
15448
|
throw new Error(`conflicting invocation policy for native skill ${name}`);
|
|
15354
15449
|
return { name, description, ...typeof hint === "string" ? { argumentHint: hint } : {}, ...typeof userInvocable === "boolean" ? { userInvocable } : {}, manual: manual === true || implicit === false, body: match[2] ?? "", metadata };
|
|
@@ -15369,7 +15464,7 @@ ${match[2] ?? ""}`);
|
|
|
15369
15464
|
function projectPluginForHermes(sourceDir, destinationDir, companionDir) {
|
|
15370
15465
|
const source = resolve13(sourceDir);
|
|
15371
15466
|
const destination = resolve13(destinationDir);
|
|
15372
|
-
if (!
|
|
15467
|
+
if (!existsSync20(source) || !statSync8(source).isDirectory())
|
|
15373
15468
|
throw new Error(`plugin source is not a directory: ${source}`);
|
|
15374
15469
|
if (destination === source || destination.startsWith(`${source}/`))
|
|
15375
15470
|
throw new Error("destination must not be inside the plugin source");
|
|
@@ -15490,11 +15585,11 @@ Use skill_view with the exact qualified name when a listed skill matches the tas
|
|
|
15490
15585
|
}
|
|
15491
15586
|
function projectHermesSkills(stage) {
|
|
15492
15587
|
const root = join25(stage, "skills");
|
|
15493
|
-
if (!
|
|
15588
|
+
if (!existsSync20(root))
|
|
15494
15589
|
return [];
|
|
15495
15590
|
const result = readdirSync12(root).sort().flatMap((entry) => {
|
|
15496
15591
|
const skill = join25(root, entry, "SKILL.md");
|
|
15497
|
-
if (!
|
|
15592
|
+
if (!existsSync20(skill))
|
|
15498
15593
|
return [];
|
|
15499
15594
|
const match = readFileSync20(skill, "utf8").match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
15500
15595
|
if (match === null)
|
|
@@ -15515,7 +15610,7 @@ function projectHermesSkills(stage) {
|
|
|
15515
15610
|
}
|
|
15516
15611
|
function validateClaudeNativeSemantics(source, commands) {
|
|
15517
15612
|
const file = join25(source, ".claude-plugin", "plugin.json");
|
|
15518
|
-
if (!
|
|
15613
|
+
if (!existsSync20(file))
|
|
15519
15614
|
return;
|
|
15520
15615
|
const parsed = JSON.parse(readFileSync20(file, "utf8"));
|
|
15521
15616
|
if (!isRecord4(parsed))
|
|
@@ -15527,7 +15622,7 @@ function validateClaudeNativeSemantics(source, commands) {
|
|
|
15527
15622
|
if (parsed["skills"] !== undefined && parsed["skills"] !== "./skills" && parsed["skills"] !== "./skills/") {
|
|
15528
15623
|
throw new Error(`Claude native skills pointer is unsupported for Codex conversion: ${file}`);
|
|
15529
15624
|
}
|
|
15530
|
-
if (parsed["skills"] !== undefined && (!
|
|
15625
|
+
if (parsed["skills"] !== undefined && (!existsSync20(join25(source, "skills")) || !statSync8(join25(source, "skills")).isDirectory())) {
|
|
15531
15626
|
throw new Error(`Claude native skills pointer cannot be preserved for Codex conversion: ${file}`);
|
|
15532
15627
|
}
|
|
15533
15628
|
if (parsed["commands"] === undefined)
|
|
@@ -15550,10 +15645,10 @@ function assertSafeTree(root) {
|
|
|
15550
15645
|
}
|
|
15551
15646
|
function discoverCommands(source) {
|
|
15552
15647
|
const claude = join25(source, ".claude", "commands");
|
|
15553
|
-
if (
|
|
15648
|
+
if (existsSync20(claude))
|
|
15554
15649
|
return readCommandDirectory(claude, "markdown");
|
|
15555
15650
|
const root = join25(source, "commands");
|
|
15556
|
-
if (!
|
|
15651
|
+
if (!existsSync20(root))
|
|
15557
15652
|
return [];
|
|
15558
15653
|
const markdown = readCommandDirectory(root, "markdown");
|
|
15559
15654
|
return markdown.length > 0 ? markdown : readCommandDirectory(root, "toml");
|
|
@@ -15626,7 +15721,7 @@ function commandFrom(path, description, argumentHint, userInvocable, disableMode
|
|
|
15626
15721
|
}
|
|
15627
15722
|
function normalizeCommandSources(root) {
|
|
15628
15723
|
const dir = join25(root, "commands");
|
|
15629
|
-
if (!
|
|
15724
|
+
if (!existsSync20(dir))
|
|
15630
15725
|
return;
|
|
15631
15726
|
if (!statSync8(dir).isDirectory())
|
|
15632
15727
|
throw new Error(`commands path is not a directory: ${dir}`);
|
|
@@ -15635,7 +15730,7 @@ function normalizeCommandSources(root) {
|
|
|
15635
15730
|
function normalizeCommandTree(dir) {
|
|
15636
15731
|
const stats = readdirSync12(dir).sort().map((name) => {
|
|
15637
15732
|
const path = join25(dir, name);
|
|
15638
|
-
const stat =
|
|
15733
|
+
const stat = lstatSync12(path);
|
|
15639
15734
|
if (stat.isSymbolicLink())
|
|
15640
15735
|
throw new Error(`command source contains symlink: ${path}`);
|
|
15641
15736
|
return { name, path, isDirectory: stat.isDirectory(), isFile: stat.isFile() };
|
|
@@ -15673,7 +15768,7 @@ ${body}` };
|
|
|
15673
15768
|
function projectPluginForPi(sourceDir, destinationDir, namespace) {
|
|
15674
15769
|
const source = resolve13(sourceDir);
|
|
15675
15770
|
const destination = resolve13(destinationDir);
|
|
15676
|
-
if (!
|
|
15771
|
+
if (!existsSync20(source) || !statSync8(source).isDirectory())
|
|
15677
15772
|
throw new Error(`plugin source is not a directory: ${source}`);
|
|
15678
15773
|
if (destination === source || destination.startsWith(`${source}/`))
|
|
15679
15774
|
throw new Error("destination must not be inside the plugin source");
|
|
@@ -15691,7 +15786,7 @@ function writePiCommandSkill(stage, command, namespace, names) {
|
|
|
15691
15786
|
if (command.userInvocable === false)
|
|
15692
15787
|
throw new Error(`user-invocable: false has no proven Pi skill equivalent: ${command.source}`);
|
|
15693
15788
|
const skillDir = join25(stage, "skills", command.name);
|
|
15694
|
-
if (
|
|
15789
|
+
if (existsSync20(skillDir))
|
|
15695
15790
|
throw new Error(`collision: command ${command.name} would replace an existing skill`);
|
|
15696
15791
|
const body = command.body.replace(/\$ARGUMENTS\b/gu, "the text after this /skill invocation").replace(/(^|[^A-Za-z0-9_-])\/([a-z0-9][a-z0-9-]*)(?=\s|$|[.,:;!?])/giu, (whole, prefix, name) => names.has(name) ? `${prefix}/skill:${namespace}-${name}` : whole);
|
|
15697
15792
|
mkdirSync5(skillDir, { recursive: true });
|
|
@@ -15718,7 +15813,7 @@ function validateMetadata(metadata, path) {
|
|
|
15718
15813
|
}
|
|
15719
15814
|
function writeCommandSkill(stage, command, namespace, commandNames) {
|
|
15720
15815
|
const skillDir = join25(stage, "skills", command.name);
|
|
15721
|
-
if (
|
|
15816
|
+
if (existsSync20(skillDir))
|
|
15722
15817
|
throw new Error(`collision: command ${command.name} would replace an existing skill`);
|
|
15723
15818
|
const body = command.body.replace(/\$ARGUMENTS\b/gu, "the invocation tail").replace(/(^|[^A-Za-z0-9_-])\/([a-z0-9][a-z0-9-]*)(?=\s|$|[.,:;!?])/giu, (whole, prefix, name) => commandNames.has(name) ? `${prefix}$${namespace}:${name}` : whole);
|
|
15724
15819
|
const hint = command.argumentHint === undefined ? "" : `argument-hint: ${yamlString(command.argumentHint)}
|
|
@@ -15755,7 +15850,7 @@ function hermesSkillUserOnly(skill, metadata) {
|
|
|
15755
15850
|
if (user === false)
|
|
15756
15851
|
throw new Error(`Hermes cannot preserve user-invocable: false: ${skill}`);
|
|
15757
15852
|
const sidecar = join25(dirname7(skill), "agents", "openai.yaml");
|
|
15758
|
-
const implicit =
|
|
15853
|
+
const implicit = existsSync20(sidecar) ? readImplicitPolicy(sidecar) : undefined;
|
|
15759
15854
|
if (disable !== undefined && implicit !== undefined && implicit !== !disable)
|
|
15760
15855
|
throw new Error(`conflicting invocation policy for Hermes skill ${skill}`);
|
|
15761
15856
|
const userOnly = disable === true || implicit === false;
|
|
@@ -15781,14 +15876,14 @@ ${yamlStringify(metadata).trimEnd()}
|
|
|
15781
15876
|
}
|
|
15782
15877
|
function translateNativeSkillPolicies(stage) {
|
|
15783
15878
|
const skills = join25(stage, "skills");
|
|
15784
|
-
if (!
|
|
15879
|
+
if (!existsSync20(skills))
|
|
15785
15880
|
return;
|
|
15786
15881
|
for (const entry of readdirSync12(skills)) {
|
|
15787
15882
|
const skill = join25(skills, entry);
|
|
15788
15883
|
if (!statSync8(skill).isDirectory())
|
|
15789
15884
|
continue;
|
|
15790
15885
|
const file = join25(skill, "SKILL.md");
|
|
15791
|
-
if (!
|
|
15886
|
+
if (!existsSync20(file))
|
|
15792
15887
|
continue;
|
|
15793
15888
|
const source = readFileSync20(file, "utf8");
|
|
15794
15889
|
const match = source.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
@@ -15796,7 +15891,7 @@ function translateNativeSkillPolicies(stage) {
|
|
|
15796
15891
|
const manual = metadata["disable-model-invocation"] === true;
|
|
15797
15892
|
const automatic = metadata["disable-model-invocation"] === false;
|
|
15798
15893
|
const sidecar = join25(skill, "agents", "openai.yaml");
|
|
15799
|
-
if (
|
|
15894
|
+
if (existsSync20(sidecar)) {
|
|
15800
15895
|
const policy = readImplicitPolicy(sidecar);
|
|
15801
15896
|
if (policy !== undefined && (manual && policy !== false || automatic && policy !== true)) {
|
|
15802
15897
|
throw new Error(`conflicting invocation policy for native skill ${entry}`);
|
|
@@ -15824,7 +15919,7 @@ function readImplicitPolicy(path) {
|
|
|
15824
15919
|
return policy["allow_implicit_invocation"];
|
|
15825
15920
|
}
|
|
15826
15921
|
function writePolicy(path, allowImplicit) {
|
|
15827
|
-
const existing =
|
|
15922
|
+
const existing = existsSync20(path) ? readFileSync20(path, "utf8").replace(/\s*$/u, "") : "";
|
|
15828
15923
|
const suffix = `policy:
|
|
15829
15924
|
allow_implicit_invocation: ${allowImplicit}
|
|
15830
15925
|
`;
|
|
@@ -17658,7 +17753,7 @@ var claudeCodeWriter = {
|
|
|
17658
17753
|
const marketplacesFile = join27(pluginsDir(), "known_marketplaces.json");
|
|
17659
17754
|
const snapshotRoot = resolved.snapshotDir ?? resolved.sourceUri;
|
|
17660
17755
|
const frozenSource = resolved.snapshot !== undefined;
|
|
17661
|
-
const wrapper = frozenSource || !
|
|
17756
|
+
const wrapper = frozenSource || !existsSync21(join27(snapshotRoot, ".claude-plugin", "marketplace.json")) ? join27(pluginsDir(), "marketplaces", `.plgnz-${marketplace}`) : undefined;
|
|
17662
17757
|
for (const path of [slot, registryFile, settingsFile, marketplacesFile])
|
|
17663
17758
|
assertManagedPath(path);
|
|
17664
17759
|
const registry = readRegistry(registryFile);
|
|
@@ -17669,9 +17764,9 @@ var claudeCodeWriter = {
|
|
|
17669
17764
|
const owned = ownedRegistryTarget(registry, id, resolved.sourceUri, slot, version);
|
|
17670
17765
|
const matchedCatalogMember = legacy === undefined && !alreadyOwned && !hasUserRegistryInstall(registry, id) && matchesNativeCatalogMember(marketplaces, marketplace, plugin, resolved);
|
|
17671
17766
|
const preserveNativeMarketplace = legacy !== undefined || alreadyOwned || matchedCatalogMember;
|
|
17672
|
-
const target = owned ?? (legacy !== undefined &&
|
|
17767
|
+
const target = owned ?? (legacy !== undefined && existsSync21(join27(slot, version)) && readOwnership(join27(slot, version)) === null ? join27(slot, `${version}.plgnz`) : join27(slot, version));
|
|
17673
17768
|
assertManagedPath(target);
|
|
17674
|
-
if (
|
|
17769
|
+
if (existsSync21(target))
|
|
17675
17770
|
assertNoSymlinks2(target);
|
|
17676
17771
|
const existing = readOwnership(target);
|
|
17677
17772
|
assertTargetIsReplaceable(target, existing, id, resolved.sourceUri);
|
|
@@ -17742,7 +17837,7 @@ var claudeCodeWriter = {
|
|
|
17742
17837
|
}
|
|
17743
17838
|
},
|
|
17744
17839
|
async pin(plugin, opts) {
|
|
17745
|
-
if (plugin.path === undefined || !
|
|
17840
|
+
if (plugin.path === undefined || !existsSync21(plugin.path))
|
|
17746
17841
|
return { changes: [], refusals: [] };
|
|
17747
17842
|
return pinPluginMcpFiles(plugin.path, mcpCandidates(), opts);
|
|
17748
17843
|
},
|
|
@@ -17752,7 +17847,7 @@ var claudeCodeWriter = {
|
|
|
17752
17847
|
for (const path of [registryFile, settingsFile])
|
|
17753
17848
|
assertManagedPath(path);
|
|
17754
17849
|
const settings = readSettings(settingsFile);
|
|
17755
|
-
if (!
|
|
17850
|
+
if (!existsSync21(registryFile)) {
|
|
17756
17851
|
const enabled = settings["enabledPlugins"];
|
|
17757
17852
|
if (typeof enabled === "object" && enabled !== null && !Array.isArray(enabled) && enabled[id] === true)
|
|
17758
17853
|
writeSettings(settingsFile, settingsWithEnabled(settings, id, false));
|
|
@@ -17803,7 +17898,7 @@ var claudeCodeWriter = {
|
|
|
17803
17898
|
if (readOwnership(copy)?.pluginId === id) {
|
|
17804
17899
|
rmSync6(copy, { recursive: true, force: true });
|
|
17805
17900
|
const manifest = join27(path, ".claude-plugin", "marketplace.json");
|
|
17806
|
-
if (
|
|
17901
|
+
if (existsSync21(manifest)) {
|
|
17807
17902
|
const document = JSON.parse(readFileSync21(manifest, "utf8"));
|
|
17808
17903
|
if (typeof document === "object" && document !== null && !Array.isArray(document)) {
|
|
17809
17904
|
const current = document;
|
|
@@ -17827,14 +17922,14 @@ function stagePlugin(source, stage, fallbackName, fallbackVersion) {
|
|
|
17827
17922
|
compilePortableHooksInStage(hookAdapter, stage);
|
|
17828
17923
|
const root = join27(stage, "plugin.json");
|
|
17829
17924
|
const canonical = join27(stage, ".plugin", "plugin.json");
|
|
17830
|
-
const manifest =
|
|
17925
|
+
const manifest = existsSync21(canonical) ? canonical : existsSync21(root) ? root : undefined;
|
|
17831
17926
|
if (manifest === undefined)
|
|
17832
17927
|
throw new Error("Claude Code stage has no Agent Plugins manifest");
|
|
17833
17928
|
const canonicalManifest = parseManifest(manifest, "canonical");
|
|
17834
17929
|
if (canonicalManifest.name !== fallbackName)
|
|
17835
17930
|
throw new Error(`Claude Code canonical manifest name ${canonicalManifest.name} does not match selected plugin ${fallbackName}`);
|
|
17836
17931
|
const native = join27(stage, ".claude-plugin", "plugin.json");
|
|
17837
|
-
if (!
|
|
17932
|
+
if (!existsSync21(native)) {
|
|
17838
17933
|
mkdirSync6(dirname8(native), { recursive: true });
|
|
17839
17934
|
writeFileSync6(native, JSON.stringify({ name: canonicalManifest.name, version: canonicalManifest.version ?? fallbackVersion, description: canonicalManifest.description, skills: "./skills/" }));
|
|
17840
17935
|
}
|
|
@@ -17844,7 +17939,7 @@ function stagePlugin(source, stage, fallbackName, fallbackVersion) {
|
|
|
17844
17939
|
if (nativeManifest.name !== canonicalManifest.name || canonicalManifest.version !== undefined && nativeManifest.version !== canonicalManifest.version)
|
|
17845
17940
|
throw new Error("Claude Code native manifest identity does not match the canonical manifest");
|
|
17846
17941
|
for (const path of [join27(stage, "skills"), join27(stage, "commands"), join27(stage, ".claude", "commands")]) {
|
|
17847
|
-
if (
|
|
17942
|
+
if (existsSync21(path) && !statSync9(path).isDirectory())
|
|
17848
17943
|
throw new Error(`Claude Code stage native content path is not a directory: ${path}`);
|
|
17849
17944
|
}
|
|
17850
17945
|
if (fallbackName.length === 0)
|
|
@@ -17852,10 +17947,10 @@ function stagePlugin(source, stage, fallbackName, fallbackVersion) {
|
|
|
17852
17947
|
}
|
|
17853
17948
|
function projectRootCommandsToNative(stage) {
|
|
17854
17949
|
const nativeCommands = join27(stage, ".claude", "commands");
|
|
17855
|
-
if (
|
|
17950
|
+
if (existsSync21(nativeCommands))
|
|
17856
17951
|
return;
|
|
17857
17952
|
const rootCommands = join27(stage, "commands");
|
|
17858
|
-
if (!
|
|
17953
|
+
if (!existsSync21(rootCommands))
|
|
17859
17954
|
return;
|
|
17860
17955
|
const entries = readdirSync13(rootCommands).sort();
|
|
17861
17956
|
const markdown = entries.filter((file) => file.endsWith(".md"));
|
|
@@ -17874,7 +17969,7 @@ function projectRootCommandsToNative(stage) {
|
|
|
17874
17969
|
}
|
|
17875
17970
|
function projectNativeCommands(stage, native) {
|
|
17876
17971
|
const commandsRoot = join27(stage, ".claude", "commands");
|
|
17877
|
-
if (!
|
|
17972
|
+
if (!existsSync21(commandsRoot))
|
|
17878
17973
|
return;
|
|
17879
17974
|
const commands = readdirSync13(commandsRoot).filter((file) => file.endsWith(".md")).sort().map((file) => `./.claude/commands/${file}`);
|
|
17880
17975
|
if (commands.length === 0)
|
|
@@ -17909,7 +18004,7 @@ function parseManifest(file, kind) {
|
|
|
17909
18004
|
return { name: manifest["name"], ...typeof manifest["version"] === "string" ? { version: manifest["version"] } : {}, ...typeof manifest["description"] === "string" ? { description: manifest["description"] } : {} };
|
|
17910
18005
|
}
|
|
17911
18006
|
function readRegistry(file) {
|
|
17912
|
-
if (!
|
|
18007
|
+
if (!existsSync21(file))
|
|
17913
18008
|
return { version: 2, plugins: {} };
|
|
17914
18009
|
let value;
|
|
17915
18010
|
try {
|
|
@@ -17925,7 +18020,7 @@ function readRegistry(file) {
|
|
|
17925
18020
|
return { version: typeof root["version"] === "number" ? root["version"] : 2, plugins: root["plugins"] };
|
|
17926
18021
|
}
|
|
17927
18022
|
function readSettings(file) {
|
|
17928
|
-
if (!
|
|
18023
|
+
if (!existsSync21(file))
|
|
17929
18024
|
return {};
|
|
17930
18025
|
let value;
|
|
17931
18026
|
try {
|
|
@@ -17941,7 +18036,7 @@ function readSettings(file) {
|
|
|
17941
18036
|
return settings;
|
|
17942
18037
|
}
|
|
17943
18038
|
function readMarketplaces(file) {
|
|
17944
|
-
if (!
|
|
18039
|
+
if (!existsSync21(file))
|
|
17945
18040
|
return {};
|
|
17946
18041
|
let value;
|
|
17947
18042
|
try {
|
|
@@ -17972,14 +18067,14 @@ function assertLifecycleMarketplaceEnvelope(version) {
|
|
|
17972
18067
|
function marketplacesWithLocalSource(marketplaces, name, sourcePath, sourceIdentity, plugin, forceWrapper) {
|
|
17973
18068
|
const manifest = join27(sourcePath, ".claude-plugin", "marketplace.json");
|
|
17974
18069
|
const catalog = validateMarketplaceRegistration(marketplaces, name, sourcePath, sourceIdentity, plugin, forceWrapper);
|
|
17975
|
-
if (forceWrapper || !
|
|
18070
|
+
if (forceWrapper || !existsSync21(manifest)) {
|
|
17976
18071
|
const marker = join27(catalog, OWNERSHIP);
|
|
17977
18072
|
const copy = join27(catalog, "plugins", plugin.name);
|
|
17978
18073
|
rmSync6(copy, { recursive: true, force: true });
|
|
17979
18074
|
cpSync5(plugin.dir, copy, { recursive: true });
|
|
17980
18075
|
writeFileSync6(join27(copy, OWNERSHIP), JSON.stringify({ source: sourceIdentity, pluginId: `${plugin.name}@${name}`, fingerprint: plugin.contentFingerprint ?? "" }));
|
|
17981
18076
|
mkdirSync6(join27(catalog, ".claude-plugin"), { recursive: true });
|
|
17982
|
-
const current =
|
|
18077
|
+
const current = existsSync21(join27(catalog, ".claude-plugin", "marketplace.json")) ? JSON.parse(readFileSync21(join27(catalog, ".claude-plugin", "marketplace.json"), "utf8")) : {};
|
|
17983
18078
|
const plugins = Array.isArray(current.plugins) ? current.plugins.filter((entry) => !(typeof entry === "object" && entry !== null && entry["name"] === plugin.name)) : [];
|
|
17984
18079
|
plugins.push({ name: plugin.name, source: `./plugins/${plugin.name}` });
|
|
17985
18080
|
writeFileSync6(join27(catalog, ".claude-plugin", "marketplace.json"), JSON.stringify({ name, owner: { name: "plgnz" }, plugins }));
|
|
@@ -17999,17 +18094,17 @@ function validateMarketplaceRegistration(marketplaces, name, sourcePath, sourceI
|
|
|
17999
18094
|
if (!sourcePath.startsWith("/"))
|
|
18000
18095
|
throw new Error(`Claude Code marketplace registration for remote source ${name} is unverified`);
|
|
18001
18096
|
const manifest = join27(sourcePath, ".claude-plugin", "marketplace.json");
|
|
18002
|
-
const catalog = !forceWrapper &&
|
|
18003
|
-
if (!
|
|
18097
|
+
const catalog = !forceWrapper && existsSync21(manifest) ? sourcePath : join27(pluginsDir(), "marketplaces", `.plgnz-${name}`);
|
|
18098
|
+
if (!existsSync21(manifest) && existsSync21(catalog)) {
|
|
18004
18099
|
assertNoSymlinks2(catalog);
|
|
18005
18100
|
const wrapper = readOwnership(catalog);
|
|
18006
18101
|
if (wrapper?.pluginId !== `marketplace@${name}` || wrapper.source !== "plgnz-wrapper")
|
|
18007
18102
|
throw new Error(`Claude Code marketplace wrapper ${catalog} is foreign; refusing to replace it`);
|
|
18008
18103
|
const copy = join27(catalog, "plugins", plugin.name);
|
|
18009
|
-
if (
|
|
18104
|
+
if (existsSync21(copy) && readOwnership(copy)?.source !== sourceIdentity)
|
|
18010
18105
|
throw new Error(`Claude Code marketplace wrapper plugin ${copy} is foreign; refusing to replace it`);
|
|
18011
18106
|
}
|
|
18012
|
-
if (
|
|
18107
|
+
if (existsSync21(join27(catalog, ".claude-plugin", "marketplace.json"))) {
|
|
18013
18108
|
let document;
|
|
18014
18109
|
try {
|
|
18015
18110
|
document = JSON.parse(readFileSync21(join27(catalog, ".claude-plugin", "marketplace.json"), "utf8"));
|
|
@@ -18041,7 +18136,7 @@ function restoreMetadata(registryFile, registry, settingsFile, settings, marketp
|
|
|
18041
18136
|
}
|
|
18042
18137
|
}
|
|
18043
18138
|
function snapshotDirectory(directory) {
|
|
18044
|
-
if (!
|
|
18139
|
+
if (!existsSync21(directory))
|
|
18045
18140
|
return;
|
|
18046
18141
|
assertNoSymlinks2(directory);
|
|
18047
18142
|
const snapshot = mkdtempSync5(join27(tmpdir2(), "plgnz-claude-wrapper-"));
|
|
@@ -18053,7 +18148,7 @@ function restoreDirectory(directory, snapshot) {
|
|
|
18053
18148
|
return;
|
|
18054
18149
|
rmSync6(directory, { recursive: true, force: true });
|
|
18055
18150
|
const previous = snapshot === undefined ? undefined : join27(snapshot, "previous");
|
|
18056
|
-
if (previous !== undefined &&
|
|
18151
|
+
if (previous !== undefined && existsSync21(previous)) {
|
|
18057
18152
|
mkdirSync6(dirname8(directory), { recursive: true });
|
|
18058
18153
|
renameSync3(previous, directory);
|
|
18059
18154
|
}
|
|
@@ -18117,7 +18212,7 @@ function assertNoForeignRegistryEntry(registry, id, target, source, adoptedLegac
|
|
|
18117
18212
|
if (typeof row !== "object" || row === null || row["scope"] !== "user")
|
|
18118
18213
|
continue;
|
|
18119
18214
|
const path = row["installPath"];
|
|
18120
|
-
if (typeof path !== "string" || path === target || !
|
|
18215
|
+
if (typeof path !== "string" || path === target || !existsSync21(path))
|
|
18121
18216
|
continue;
|
|
18122
18217
|
if (path === adoptedLegacy)
|
|
18123
18218
|
continue;
|
|
@@ -18135,7 +18230,7 @@ function validateLegacyUserInstall(registry, id, slot, plugin) {
|
|
|
18135
18230
|
throw new Error(`claude-code user install ${id} is ambiguous; refusing adoption`);
|
|
18136
18231
|
const row = users[0];
|
|
18137
18232
|
const path = row["installPath"];
|
|
18138
|
-
if (typeof path !== "string" || dirname8(path) !== slot || !
|
|
18233
|
+
if (typeof path !== "string" || dirname8(path) !== slot || !existsSync21(path))
|
|
18139
18234
|
throw new Error(`claude-code user install ${id} is outside its native cache slot; refusing adoption`);
|
|
18140
18235
|
assertNoSymlinks2(path);
|
|
18141
18236
|
if (readOwnership(path) !== null)
|
|
@@ -18153,7 +18248,7 @@ function ownedRegistryTarget(registry, id, source, slot, version) {
|
|
|
18153
18248
|
if (users.length !== 1)
|
|
18154
18249
|
return;
|
|
18155
18250
|
const path = users[0]["installPath"];
|
|
18156
|
-
if (typeof path !== "string" || dirname8(path) !== slot || path !== join27(slot, `${version}.plgnz`) || !
|
|
18251
|
+
if (typeof path !== "string" || dirname8(path) !== slot || path !== join27(slot, `${version}.plgnz`) || !existsSync21(path))
|
|
18157
18252
|
return;
|
|
18158
18253
|
const ownership = readOwnership(path);
|
|
18159
18254
|
return ownership?.pluginId === id && ownership.source === source ? path : undefined;
|
|
@@ -18164,7 +18259,7 @@ function hasAdoptedRegistryInstall(registry, id, source, slot) {
|
|
|
18164
18259
|
if (users.length !== 1)
|
|
18165
18260
|
return false;
|
|
18166
18261
|
const path = users[0]["installPath"];
|
|
18167
|
-
if (typeof path !== "string" || dirname8(path) !== slot || !
|
|
18262
|
+
if (typeof path !== "string" || dirname8(path) !== slot || !existsSync21(path))
|
|
18168
18263
|
return false;
|
|
18169
18264
|
const ownership = readOwnership(path);
|
|
18170
18265
|
return ownership?.pluginId === id && ownership.source === source && ownership.adopted === true;
|
|
@@ -18188,7 +18283,7 @@ function matchesNativeCatalogMember(marketplaces, name, plugin, resolved) {
|
|
|
18188
18283
|
if (!containedPath(resolved.sourceUri, plugin.sourceDir ?? plugin.dir))
|
|
18189
18284
|
return false;
|
|
18190
18285
|
const manifest = join27(catalog, ".claude-plugin", "marketplace.json");
|
|
18191
|
-
if (!
|
|
18286
|
+
if (!existsSync21(manifest))
|
|
18192
18287
|
return false;
|
|
18193
18288
|
assertCatalogPath(catalog, manifest);
|
|
18194
18289
|
let document;
|
|
@@ -18212,7 +18307,7 @@ function matchesNativeCatalogMember(marketplaces, name, plugin, resolved) {
|
|
|
18212
18307
|
if (!containedPath(catalog, nativeDir) || nativeDir === resolve15(catalog))
|
|
18213
18308
|
return false;
|
|
18214
18309
|
assertCatalogPath(catalog, nativeDir);
|
|
18215
|
-
if (!
|
|
18310
|
+
if (!existsSync21(nativeDir) || !lstatSync13(nativeDir).isDirectory())
|
|
18216
18311
|
return false;
|
|
18217
18312
|
const stages = mkdtempSync5(join27(tmpdir2(), "plgnz-claude-catalog-proof-"));
|
|
18218
18313
|
try {
|
|
@@ -18239,7 +18334,7 @@ function assertCatalogPath(root, path) {
|
|
|
18239
18334
|
for (const part of ["", ...relative7(current, target).split("/").filter(Boolean)]) {
|
|
18240
18335
|
if (part !== "")
|
|
18241
18336
|
current = join27(current, part);
|
|
18242
|
-
const stat =
|
|
18337
|
+
const stat = lstatSync13(current);
|
|
18243
18338
|
if (stat.isSymbolicLink())
|
|
18244
18339
|
throw new Error(`Claude Code native catalog path contains symlink: ${current}`);
|
|
18245
18340
|
if (current !== target && !stat.isDirectory())
|
|
@@ -18247,7 +18342,7 @@ function assertCatalogPath(root, path) {
|
|
|
18247
18342
|
}
|
|
18248
18343
|
}
|
|
18249
18344
|
function assertTargetIsReplaceable(target, ownership, id, source) {
|
|
18250
|
-
if (
|
|
18345
|
+
if (existsSync21(target) && ownership === null)
|
|
18251
18346
|
throw new Error(`claude-code cache slot ${target} is unowned; refusing to replace it`);
|
|
18252
18347
|
if (ownership !== null && (ownership.pluginId !== id || ownership.source !== source))
|
|
18253
18348
|
throw new Error(`claude-code cache slot ${target} has a different owned source identity; refusing to replace it`);
|
|
@@ -18264,7 +18359,7 @@ function assertManagedPath(path) {
|
|
|
18264
18359
|
current = join27(current, part);
|
|
18265
18360
|
let stat;
|
|
18266
18361
|
try {
|
|
18267
|
-
stat =
|
|
18362
|
+
stat = lstatSync13(current);
|
|
18268
18363
|
} catch (error) {
|
|
18269
18364
|
if (error.code === "ENOENT")
|
|
18270
18365
|
return;
|
|
@@ -18284,7 +18379,7 @@ function cleanupPriorOwnedPaths(registry, id, active, source) {
|
|
|
18284
18379
|
if (typeof row !== "object" || row === null)
|
|
18285
18380
|
continue;
|
|
18286
18381
|
const path = row["installPath"];
|
|
18287
|
-
if (typeof path !== "string" || path === active || !
|
|
18382
|
+
if (typeof path !== "string" || path === active || !existsSync21(path))
|
|
18288
18383
|
continue;
|
|
18289
18384
|
const ownership = readOwnership(path);
|
|
18290
18385
|
if (ownership?.pluginId === id && ownership.source === source)
|
|
@@ -18293,7 +18388,7 @@ function cleanupPriorOwnedPaths(registry, id, active, source) {
|
|
|
18293
18388
|
}
|
|
18294
18389
|
function readOwnership(dir) {
|
|
18295
18390
|
const file = join27(dir, OWNERSHIP);
|
|
18296
|
-
if (!
|
|
18391
|
+
if (!existsSync21(file))
|
|
18297
18392
|
return null;
|
|
18298
18393
|
try {
|
|
18299
18394
|
const parsed = JSON.parse(readFileSync21(file, "utf8"));
|
|
@@ -18318,7 +18413,7 @@ function readOwnership(dir) {
|
|
|
18318
18413
|
}
|
|
18319
18414
|
}
|
|
18320
18415
|
function activate(stage, target, slot) {
|
|
18321
|
-
if (!
|
|
18416
|
+
if (!existsSync21(target)) {
|
|
18322
18417
|
renameSync3(stage, target);
|
|
18323
18418
|
return { commit: () => {}, rollback: () => rmSync6(target, { recursive: true, force: true }) };
|
|
18324
18419
|
}
|
|
@@ -18339,13 +18434,13 @@ function moveAside(path, parent = dirname8(path)) {
|
|
|
18339
18434
|
const backup = join27(backupRoot, "previous");
|
|
18340
18435
|
renameSync3(path, backup);
|
|
18341
18436
|
return { commit: () => rmSync6(backupRoot, { recursive: true, force: true }), rollback: () => {
|
|
18342
|
-
if (
|
|
18437
|
+
if (existsSync21(backup))
|
|
18343
18438
|
renameSync3(backup, path);
|
|
18344
18439
|
rmSync6(backupRoot, { recursive: true, force: true });
|
|
18345
18440
|
} };
|
|
18346
18441
|
}
|
|
18347
18442
|
function sameTree(left, right) {
|
|
18348
|
-
if (!
|
|
18443
|
+
if (!existsSync21(right))
|
|
18349
18444
|
return false;
|
|
18350
18445
|
const listing = (root) => {
|
|
18351
18446
|
const out = [];
|
|
@@ -18373,11 +18468,11 @@ function bytesKey(path) {
|
|
|
18373
18468
|
return hash.digest("hex");
|
|
18374
18469
|
}
|
|
18375
18470
|
function assertNoSymlinks2(dir) {
|
|
18376
|
-
if (
|
|
18471
|
+
if (lstatSync13(dir).isSymbolicLink())
|
|
18377
18472
|
throw new Error(`Claude Code cache contains symlink: ${dir}`);
|
|
18378
18473
|
for (const entry of readdirSync13(dir)) {
|
|
18379
18474
|
const path = join27(dir, entry);
|
|
18380
|
-
const stat =
|
|
18475
|
+
const stat = lstatSync13(path);
|
|
18381
18476
|
if (stat.isSymbolicLink())
|
|
18382
18477
|
throw new Error(`Claude Code cache contains symlink: ${path}`);
|
|
18383
18478
|
if (stat.isDirectory())
|
|
@@ -18538,7 +18633,7 @@ function claudeCodeLifecycleDefinition(contracts) {
|
|
|
18538
18633
|
retire: async (prepared) => {
|
|
18539
18634
|
retireLifecycleCatalog(prepared.handle.nativeId, prepared.handle.scopeId);
|
|
18540
18635
|
const installPath = recordedInstallPath(prepared.handle.nativeId);
|
|
18541
|
-
const existed = installPath !== undefined &&
|
|
18636
|
+
const existed = installPath !== undefined && existsSync21(installPath);
|
|
18542
18637
|
if (installPath !== undefined)
|
|
18543
18638
|
rmSync6(installPath, { recursive: true, force: true });
|
|
18544
18639
|
dropUserRow(prepared.handle.nativeId);
|
|
@@ -18693,7 +18788,7 @@ function observeClaudeInstallations(target, version) {
|
|
|
18693
18788
|
if (typeof recordedPath !== "string")
|
|
18694
18789
|
continue;
|
|
18695
18790
|
const installPath = resolve15(recordedPath);
|
|
18696
|
-
if (!
|
|
18791
|
+
if (!existsSync21(installPath))
|
|
18697
18792
|
continue;
|
|
18698
18793
|
const marker = readOwnership(installPath);
|
|
18699
18794
|
const digest = fingerprintTree(installPath);
|
|
@@ -18770,7 +18865,7 @@ function activationIdentity(activation) {
|
|
|
18770
18865
|
function claudeReadback(identity, absentRoute, version) {
|
|
18771
18866
|
assertLifecycleMarketplaceEnvelope(version);
|
|
18772
18867
|
const installPath = recordedInstallPath(identity.nativeId);
|
|
18773
|
-
const present = installPath !== undefined &&
|
|
18868
|
+
const present = installPath !== undefined && existsSync21(installPath);
|
|
18774
18869
|
const retention = {
|
|
18775
18870
|
pluginData: retained(resolve15(join27(pluginsDir(), "plugin-data", identity.nativeId))),
|
|
18776
18871
|
inactiveMetadata: retained(resolve15(join27(pluginsDir(), "inactive-metadata", identity.nativeId)))
|
|
@@ -18804,7 +18899,7 @@ function claudeReadback(identity, absentRoute, version) {
|
|
|
18804
18899
|
}
|
|
18805
18900
|
function installedRoute(installPath) {
|
|
18806
18901
|
const file = join27(installPath, ".plgnz-lifecycle.json");
|
|
18807
|
-
if (!
|
|
18902
|
+
if (!existsSync21(file))
|
|
18808
18903
|
return "managed";
|
|
18809
18904
|
try {
|
|
18810
18905
|
const parsed = JSON.parse(readFileSync21(file, "utf8"));
|
|
@@ -18817,7 +18912,7 @@ function installedRoute(installPath) {
|
|
|
18817
18912
|
}
|
|
18818
18913
|
function observedOwnedRoute(installPath) {
|
|
18819
18914
|
const file = join27(installPath, ".plgnz-lifecycle.json");
|
|
18820
|
-
if (!
|
|
18915
|
+
if (!existsSync21(file))
|
|
18821
18916
|
return;
|
|
18822
18917
|
const value = JSON.parse(readFileSync21(file, "utf8"));
|
|
18823
18918
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
@@ -18828,7 +18923,7 @@ function observedOwnedRoute(installPath) {
|
|
|
18828
18923
|
return route;
|
|
18829
18924
|
}
|
|
18830
18925
|
function retained(path) {
|
|
18831
|
-
if (!
|
|
18926
|
+
if (!existsSync21(path))
|
|
18832
18927
|
return { state: "absent", fingerprint: null };
|
|
18833
18928
|
return { state: "present", fingerprint: fingerprintTree(path) };
|
|
18834
18929
|
}
|
|
@@ -18875,14 +18970,14 @@ function registeredLifecycleCatalogMember(nativeId) {
|
|
|
18875
18970
|
if (!isRecord6(entry) || !isRecord6(entry["source"]) || entry["source"]["source"] !== "directory" || typeof entry["source"]["path"] !== "string" || entry["installLocation"] !== entry["source"]["path"])
|
|
18876
18971
|
return null;
|
|
18877
18972
|
const root = entry["source"]["path"];
|
|
18878
|
-
if (!root.startsWith("/") || resolve15(root) !== root || !
|
|
18973
|
+
if (!root.startsWith("/") || resolve15(root) !== root || !existsSync21(root))
|
|
18879
18974
|
return null;
|
|
18880
18975
|
assertCatalogPath(root, join27(root, ".claude-plugin", "marketplace.json"));
|
|
18881
18976
|
const selected = catalogEntries(lifecycleCatalogDocument(root, market)).filter((item) => isCatalogMember(item, nativeId));
|
|
18882
18977
|
if (selected.length !== 1 || !isRecord6(selected[0]) || typeof selected[0]["source"] !== "string" || !selected[0]["source"].startsWith("./"))
|
|
18883
18978
|
return null;
|
|
18884
18979
|
const member = resolve15(root, selected[0]["source"]);
|
|
18885
|
-
if (!containedPath(root, member) || root === member || !
|
|
18980
|
+
if (!containedPath(root, member) || root === member || !existsSync21(member))
|
|
18886
18981
|
return null;
|
|
18887
18982
|
assertCatalogPath(root, member);
|
|
18888
18983
|
assertNoSymlinks2(member);
|
|
@@ -18896,7 +18991,7 @@ function matchingForeignLifecycleCatalog(nativeId, scopeId, target, packageRoot,
|
|
|
18896
18991
|
return null;
|
|
18897
18992
|
if (!foreignLifecycleEntryEquivalent(catalog.entry))
|
|
18898
18993
|
return null;
|
|
18899
|
-
if (!
|
|
18994
|
+
if (!existsSync21(join27(catalog.member, ".claude-plugin", "plugin.json")))
|
|
18900
18995
|
return null;
|
|
18901
18996
|
const proof = mkdtempSync5(join27(tmpdir2(), "plgnz-claude-native-member-"));
|
|
18902
18997
|
try {
|
|
@@ -18913,7 +19008,7 @@ function matchingForeignLifecycleCatalog(nativeId, scopeId, target, packageRoot,
|
|
|
18913
19008
|
}
|
|
18914
19009
|
function lifecycleCatalogDocument(root, market) {
|
|
18915
19010
|
const file = join27(root, ".claude-plugin", "marketplace.json");
|
|
18916
|
-
if (!
|
|
19011
|
+
if (!existsSync21(file))
|
|
18917
19012
|
return null;
|
|
18918
19013
|
const parsed = JSON.parse(readFileSync21(file, "utf8"));
|
|
18919
19014
|
if (!isRecord6(parsed) || parsed["name"] !== market || !Array.isArray(parsed["plugins"]))
|
|
@@ -18961,7 +19056,7 @@ function validateLifecycleCatalog(nativeId, scopeId) {
|
|
|
18961
19056
|
assertManagedPath(join27(root, ".claude-plugin", "marketplace.json"));
|
|
18962
19057
|
assertManagedPath(join27(root, OWNERSHIP));
|
|
18963
19058
|
assertManagedPath(copy);
|
|
18964
|
-
if (
|
|
19059
|
+
if (existsSync21(root)) {
|
|
18965
19060
|
const owner = readOwnership(root);
|
|
18966
19061
|
if (owner?.source !== "plgnz-wrapper" || owner.pluginId !== `marketplace@${market}`)
|
|
18967
19062
|
throw new Error(`Claude Code marketplace wrapper ${root} is foreign; refusing to replace it`);
|
|
@@ -18970,7 +19065,7 @@ function validateLifecycleCatalog(nativeId, scopeId) {
|
|
|
18970
19065
|
const selected = catalogEntries(document).filter((entry) => isCatalogMember(entry, nativeId));
|
|
18971
19066
|
if (selected.length > 1 || selected.some((entry) => !isRecord6(entry) || entry["source"] !== `./plugins/${nativeId.slice(0, nativeId.indexOf("@"))}`))
|
|
18972
19067
|
throw new Error(`Claude Code marketplace member ${nativeId} is foreign or ambiguous; refusing to replace it`);
|
|
18973
|
-
if (
|
|
19068
|
+
if (existsSync21(copy)) {
|
|
18974
19069
|
assertNoSymlinks2(copy);
|
|
18975
19070
|
const owner = readOwnership(copy);
|
|
18976
19071
|
if (owner?.pluginId !== nativeId || owner.scopeId !== scopeId)
|
|
@@ -19016,7 +19111,7 @@ function lifecycleCatalogConforms(nativeId, installPath, target) {
|
|
|
19016
19111
|
if (registered !== null && registered.root !== lifecycleCatalogRoot(nativeId)) {
|
|
19017
19112
|
if (owner?.scopeId === undefined)
|
|
19018
19113
|
return false;
|
|
19019
|
-
const manifest =
|
|
19114
|
+
const manifest = existsSync21(join27(installPath, ".plugin", "plugin.json")) ? join27(installPath, ".plugin", "plugin.json") : join27(installPath, "plugin.json");
|
|
19020
19115
|
return matchingForeignLifecycleCatalog(nativeId, owner.scopeId, target, installPath, parseManifest(manifest, "canonical").version ?? "") !== null;
|
|
19021
19116
|
}
|
|
19022
19117
|
const known = readMarketplaces(join27(pluginsDir(), "known_marketplaces.json"))[market];
|
|
@@ -19026,7 +19121,7 @@ function lifecycleCatalogConforms(nativeId, installPath, target) {
|
|
|
19026
19121
|
if (entries.length !== 1 || catalogEntryFingerprint(entries[0]) !== catalogEntryFingerprint(ownedLifecycleCatalogEntry(nativeId)))
|
|
19027
19122
|
return false;
|
|
19028
19123
|
const copy = lifecycleCatalogCopy(nativeId);
|
|
19029
|
-
if (!
|
|
19124
|
+
if (!existsSync21(copy))
|
|
19030
19125
|
return false;
|
|
19031
19126
|
assertManagedPath(copy);
|
|
19032
19127
|
assertNoSymlinks2(copy);
|
|
@@ -19035,13 +19130,13 @@ function lifecycleCatalogConforms(nativeId, installPath, target) {
|
|
|
19035
19130
|
}
|
|
19036
19131
|
function lifecycleContentRoots(nativeId, installPath, digest) {
|
|
19037
19132
|
const copy = registeredLifecycleCatalogMember(nativeId)?.member ?? lifecycleCatalogCopy(nativeId);
|
|
19038
|
-
return [{ label: "plugin", path: installPath, fingerprint: digest }, ...
|
|
19133
|
+
return [{ label: "plugin", path: installPath, fingerprint: digest }, ...existsSync21(copy) ? [{ label: "catalog-plugin", path: copy, fingerprint: fingerprintTree(copy) }] : [], ...lifecycleCatalogEntryObservation(nativeId)];
|
|
19039
19134
|
}
|
|
19040
19135
|
function retireLifecycleCatalog(nativeId, scopeId) {
|
|
19041
19136
|
validateLifecycleCatalogRetirement(nativeId, scopeId);
|
|
19042
19137
|
const root = lifecycleCatalogRoot(nativeId);
|
|
19043
19138
|
const copy = lifecycleCatalogCopy(nativeId);
|
|
19044
|
-
if (!
|
|
19139
|
+
if (!existsSync21(root))
|
|
19045
19140
|
return;
|
|
19046
19141
|
assertManagedPath(root);
|
|
19047
19142
|
const market = marketplaceName(nativeId);
|
|
@@ -19049,7 +19144,7 @@ function retireLifecycleCatalog(nativeId, scopeId) {
|
|
|
19049
19144
|
if (owner?.source !== "plgnz-wrapper" || owner.pluginId !== `marketplace@${market}`)
|
|
19050
19145
|
return;
|
|
19051
19146
|
const document = lifecycleCatalogDocument(root, market);
|
|
19052
|
-
if (
|
|
19147
|
+
if (existsSync21(copy)) {
|
|
19053
19148
|
const member = readOwnership(copy);
|
|
19054
19149
|
if (member?.pluginId !== nativeId || member.scopeId !== scopeId)
|
|
19055
19150
|
throw new Error(`Claude Code catalog retirement cannot prove ownership: ${copy}`);
|
|
@@ -19071,17 +19166,17 @@ function retireLifecycleCatalog(nativeId, scopeId) {
|
|
|
19071
19166
|
}
|
|
19072
19167
|
}
|
|
19073
19168
|
function emptyOwnedCatalogContainer(root) {
|
|
19074
|
-
if (!
|
|
19169
|
+
if (!existsSync21(root))
|
|
19075
19170
|
return true;
|
|
19076
19171
|
if (readdirSync13(root).some((name) => ![OWNERSHIP, ".claude-plugin", "plugins"].includes(name)))
|
|
19077
19172
|
return false;
|
|
19078
|
-
if (
|
|
19173
|
+
if (existsSync21(join27(root, ".claude-plugin")) && readdirSync13(join27(root, ".claude-plugin")).some((name) => name !== "marketplace.json"))
|
|
19079
19174
|
return false;
|
|
19080
|
-
return !
|
|
19175
|
+
return !existsSync21(join27(root, "plugins")) || readdirSync13(join27(root, "plugins")).length === 0;
|
|
19081
19176
|
}
|
|
19082
19177
|
function validateLifecycleCatalogRetirement(nativeId, scopeId) {
|
|
19083
19178
|
const root = lifecycleCatalogRoot(nativeId);
|
|
19084
|
-
if (!
|
|
19179
|
+
if (!existsSync21(root))
|
|
19085
19180
|
return;
|
|
19086
19181
|
assertManagedPath(root);
|
|
19087
19182
|
assertManagedPath(join27(root, OWNERSHIP));
|
|
@@ -19098,7 +19193,7 @@ function validateLifecycleCatalogRetirement(nativeId, scopeId) {
|
|
|
19098
19193
|
const selected = catalogEntries(lifecycleCatalogDocument(root, marketplaceName(nativeId))).filter((entry) => isCatalogMember(entry, nativeId));
|
|
19099
19194
|
if (selected.length > 1 || selected.some((entry) => !isRecord6(entry) || entry["source"] !== `./plugins/${nativeId.slice(0, nativeId.indexOf("@"))}`))
|
|
19100
19195
|
throw new Error(`Claude Code catalog retirement found a foreign or ambiguous member: ${nativeId}`);
|
|
19101
|
-
if (
|
|
19196
|
+
if (existsSync21(copy)) {
|
|
19102
19197
|
assertNoSymlinks2(copy);
|
|
19103
19198
|
const member = readOwnership(copy);
|
|
19104
19199
|
if (member?.pluginId !== nativeId || member.scopeId !== scopeId)
|
|
@@ -19109,9 +19204,9 @@ function captureLifecycleCatalog(reference, nativeId) {
|
|
|
19109
19204
|
const root = lifecycleCatalogRoot(nativeId);
|
|
19110
19205
|
const market = marketplaceName(nativeId);
|
|
19111
19206
|
const document = lifecycleCatalogDocument(root, market);
|
|
19112
|
-
writeFileSync6(join27(reference, "catalog.json"), JSON.stringify({ document, selected: catalogEntries(document).filter((entry) => isCatalogMember(entry, nativeId)), marker:
|
|
19207
|
+
writeFileSync6(join27(reference, "catalog.json"), JSON.stringify({ document, selected: catalogEntries(document).filter((entry) => isCatalogMember(entry, nativeId)), marker: existsSync21(join27(root, OWNERSHIP)) ? readFileSync21(join27(root, OWNERSHIP), "utf8") : null }));
|
|
19113
19208
|
const copy = lifecycleCatalogCopy(nativeId);
|
|
19114
|
-
if (
|
|
19209
|
+
if (existsSync21(copy)) {
|
|
19115
19210
|
assertNoSymlinks2(copy);
|
|
19116
19211
|
cpSync5(copy, join27(reference, "catalog-plugin"), { recursive: true });
|
|
19117
19212
|
}
|
|
@@ -19120,7 +19215,7 @@ function restoreLifecycleCatalog(reference, nativeId, scopeId) {
|
|
|
19120
19215
|
const saved = JSON.parse(readFileSync21(join27(reference, "catalog.json"), "utf8"));
|
|
19121
19216
|
const root = lifecycleCatalogRoot(nativeId);
|
|
19122
19217
|
assertManagedPath(root);
|
|
19123
|
-
if (
|
|
19218
|
+
if (existsSync21(root)) {
|
|
19124
19219
|
assertManagedPath(join27(root, OWNERSHIP));
|
|
19125
19220
|
const owner = readOwnership(root);
|
|
19126
19221
|
if (owner?.source !== "plgnz-wrapper" || owner.pluginId !== `marketplace@${marketplaceName(nativeId)}`)
|
|
@@ -19132,14 +19227,14 @@ function restoreLifecycleCatalog(reference, nativeId, scopeId) {
|
|
|
19132
19227
|
const siblings = catalogEntries(current).filter((entry) => !isCatalogMember(entry, nativeId));
|
|
19133
19228
|
const copy = lifecycleCatalogCopy(nativeId);
|
|
19134
19229
|
assertManagedPath(copy);
|
|
19135
|
-
if (
|
|
19230
|
+
if (existsSync21(copy)) {
|
|
19136
19231
|
assertNoSymlinks2(copy);
|
|
19137
19232
|
const owner = readOwnership(copy);
|
|
19138
19233
|
if (owner?.pluginId !== nativeId || owner.scopeId !== scopeId)
|
|
19139
19234
|
throw new Error(`Claude Code rollback refuses a foreign catalog member: ${copy}`);
|
|
19140
19235
|
}
|
|
19141
19236
|
rmSync6(copy, { recursive: true, force: true });
|
|
19142
|
-
if (
|
|
19237
|
+
if (existsSync21(join27(reference, "catalog-plugin"))) {
|
|
19143
19238
|
mkdirSync6(dirname8(copy), { recursive: true });
|
|
19144
19239
|
cpSync5(join27(reference, "catalog-plugin"), copy, { recursive: true });
|
|
19145
19240
|
}
|
|
@@ -19182,7 +19277,7 @@ function captureRollback(attemptId, operationId, nativeId) {
|
|
|
19182
19277
|
writeFileSync6(join27(reference, "known-marketplace.json"), JSON.stringify({ marketplace: marketplace ?? null, entry: knownEntry }));
|
|
19183
19278
|
captureLifecycleCatalog(reference, nativeId);
|
|
19184
19279
|
const installPath = recordedInstallPath(nativeId);
|
|
19185
|
-
if (installPath !== undefined &&
|
|
19280
|
+
if (installPath !== undefined && existsSync21(installPath)) {
|
|
19186
19281
|
cpSync5(installPath, join27(reference, "install"), { recursive: true });
|
|
19187
19282
|
writeFileSync6(join27(reference, "install-path.txt"), installPath);
|
|
19188
19283
|
}
|
|
@@ -19204,7 +19299,7 @@ function mutateInstall(handle, stagingRoot) {
|
|
|
19204
19299
|
}
|
|
19205
19300
|
const beforeCatalog = lifecycleSelectedMutationState(handle.nativeId);
|
|
19206
19301
|
const installPath = cacheSlot(handle.nativeId, slotVersion(handle.packageVersion, handle.sourceRevision));
|
|
19207
|
-
const before =
|
|
19302
|
+
const before = existsSync21(installPath) ? fingerprintTree(installPath) : null;
|
|
19208
19303
|
rmSync6(installPath, { recursive: true, force: true });
|
|
19209
19304
|
mkdirSync6(dirname8(installPath), { recursive: true });
|
|
19210
19305
|
cpSync5(stagingRoot, installPath, { recursive: true });
|
|
@@ -19239,7 +19334,7 @@ function lifecycleSelectedMutationState(nativeId) {
|
|
|
19239
19334
|
const member = registeredLifecycleCatalogMember(nativeId)?.member ?? lifecycleCatalogCopy(nativeId);
|
|
19240
19335
|
return catalogEntryFingerprint({
|
|
19241
19336
|
catalogEntry: lifecycleCatalogEntryObservation(nativeId),
|
|
19242
|
-
member:
|
|
19337
|
+
member: existsSync21(member) ? fingerprintTree(member) : null,
|
|
19243
19338
|
registration: known[market] ?? null,
|
|
19244
19339
|
extraRegistration: isRecord6(extra) ? extra[market] ?? null : null,
|
|
19245
19340
|
installedRows: readRegistry(join27(pluginsDir(), "installed_plugins.json")).plugins[nativeId] ?? null,
|
|
@@ -19271,15 +19366,15 @@ function restoreRollback(handle) {
|
|
|
19271
19366
|
const registryFile = join27(pluginsDir(), "installed_plugins.json");
|
|
19272
19367
|
const appliedSlot = cacheSlot(handle.nativeId, slotVersion(handle.packageVersion, handle.sourceRevision));
|
|
19273
19368
|
const savedPath = join27(reference, "install-path.txt");
|
|
19274
|
-
const previousSlot =
|
|
19275
|
-
if (previousSlot !== undefined && resolve15(previousSlot) !== appliedSlot && !
|
|
19369
|
+
const previousSlot = existsSync21(savedPath) ? readFileSync21(savedPath, "utf8") : undefined;
|
|
19370
|
+
if (previousSlot !== undefined && resolve15(previousSlot) !== appliedSlot && !existsSync21(appliedSlot)) {
|
|
19276
19371
|
throw new Error(`claude-code rollback cannot remove the updated cache slot: ${appliedSlot}`);
|
|
19277
19372
|
}
|
|
19278
19373
|
const beforeEntry = JSON.stringify(readRegistry(registryFile).plugins[handle.nativeId] ?? null);
|
|
19279
19374
|
const beforeEnabled = JSON.stringify(enabledPlugins()[handle.nativeId] ?? null);
|
|
19280
|
-
const beforeMarkets =
|
|
19281
|
-
const beforeApplied =
|
|
19282
|
-
const beforePrevious = previousSlot !== undefined &&
|
|
19375
|
+
const beforeMarkets = existsSync21(join27(pluginsDir(), "known_marketplaces.json")) ? readFileSync21(join27(pluginsDir(), "known_marketplaces.json"), "utf8") : "";
|
|
19376
|
+
const beforeApplied = existsSync21(appliedSlot) ? fingerprintTree(appliedSlot) : null;
|
|
19377
|
+
const beforePrevious = previousSlot !== undefined && existsSync21(previousSlot) ? fingerprintTree(previousSlot) : null;
|
|
19283
19378
|
restoreLifecycleCatalog(reference, handle.nativeId, handle.scopeId);
|
|
19284
19379
|
restorePluginSlice(handle.nativeId, reference);
|
|
19285
19380
|
if (previousSlot !== undefined && resolve15(previousSlot) !== appliedSlot)
|
|
@@ -19287,15 +19382,15 @@ function restoreRollback(handle) {
|
|
|
19287
19382
|
const installPath = previousSlot ?? recordedInstallPath(handle.nativeId) ?? appliedSlot;
|
|
19288
19383
|
const backup = join27(reference, "install");
|
|
19289
19384
|
rmSync6(installPath, { recursive: true, force: true });
|
|
19290
|
-
if (
|
|
19385
|
+
if (existsSync21(backup)) {
|
|
19291
19386
|
mkdirSync6(dirname8(installPath), { recursive: true });
|
|
19292
19387
|
cpSync5(backup, installPath, { recursive: true });
|
|
19293
19388
|
}
|
|
19294
19389
|
const afterEntry = JSON.stringify(readRegistry(registryFile).plugins[handle.nativeId] ?? null);
|
|
19295
19390
|
const afterEnabled = JSON.stringify(enabledPlugins()[handle.nativeId] ?? null);
|
|
19296
|
-
const afterMarkets =
|
|
19297
|
-
const afterApplied =
|
|
19298
|
-
const afterPrevious = previousSlot !== undefined &&
|
|
19391
|
+
const afterMarkets = existsSync21(join27(pluginsDir(), "known_marketplaces.json")) ? readFileSync21(join27(pluginsDir(), "known_marketplaces.json"), "utf8") : "";
|
|
19392
|
+
const afterApplied = existsSync21(appliedSlot) ? fingerprintTree(appliedSlot) : null;
|
|
19393
|
+
const afterPrevious = previousSlot !== undefined && existsSync21(previousSlot) ? fingerprintTree(previousSlot) : null;
|
|
19299
19394
|
return {
|
|
19300
19395
|
receiptId: `claude-rollback-${handle.operationId}`,
|
|
19301
19396
|
changed: beforeEntry !== afterEntry || beforeEnabled !== afterEnabled || beforeMarkets !== afterMarkets || beforeApplied !== afterApplied || beforePrevious !== afterPrevious
|
|
@@ -19343,13 +19438,13 @@ function restoreKnownMarketplace(reference) {
|
|
|
19343
19438
|
if (typeof saved.marketplace !== "string")
|
|
19344
19439
|
return;
|
|
19345
19440
|
const file = join27(pluginsDir(), "known_marketplaces.json");
|
|
19346
|
-
const hadFile =
|
|
19441
|
+
const hadFile = existsSync21(file);
|
|
19347
19442
|
const current = hadFile ? readMarketplaces(file) : {};
|
|
19348
19443
|
if (saved.entry === null) {
|
|
19349
19444
|
if (!hadFile || !Object.hasOwn(current, saved.marketplace))
|
|
19350
19445
|
return;
|
|
19351
19446
|
const root = lifecycleCatalogRoot(`rollback@${saved.marketplace}`);
|
|
19352
|
-
if (
|
|
19447
|
+
if (existsSync21(root) && (catalogEntries(lifecycleCatalogDocument(root, saved.marketplace)).length > 0 || !emptyOwnedCatalogContainer(root)))
|
|
19353
19448
|
return;
|
|
19354
19449
|
const next = { ...current };
|
|
19355
19450
|
delete next[saved.marketplace];
|
|
@@ -19405,7 +19500,7 @@ function hasForeignMarketplaceSibling(nativeId, marketplace) {
|
|
|
19405
19500
|
if (!isRecord6(registration) || !isRecord6(registration["source"]) || registration["source"]["source"] !== "directory" || typeof registration["source"]["path"] !== "string")
|
|
19406
19501
|
return false;
|
|
19407
19502
|
const root = registration["source"]["path"];
|
|
19408
|
-
if (!root.startsWith("/") || !
|
|
19503
|
+
if (!root.startsWith("/") || !existsSync21(root))
|
|
19409
19504
|
return false;
|
|
19410
19505
|
const document = lifecycleCatalogDocument(root, marketplace);
|
|
19411
19506
|
return catalogEntries(document).some((entry) => {
|
|
@@ -19414,14 +19509,14 @@ function hasForeignMarketplaceSibling(nativeId, marketplace) {
|
|
|
19414
19509
|
if (!isRecord6(entry) || typeof entry["name"] !== "string" || typeof entry["source"] !== "string" || !entry["source"].startsWith("./"))
|
|
19415
19510
|
return true;
|
|
19416
19511
|
const member = resolve15(root, entry["source"]);
|
|
19417
|
-
if (!containedPath(root, member) || member === root || !
|
|
19512
|
+
if (!containedPath(root, member) || member === root || !existsSync21(member))
|
|
19418
19513
|
return true;
|
|
19419
19514
|
assertCatalogPath(root, member);
|
|
19420
19515
|
return readOwnership(member)?.pluginId !== `${entry["name"]}@${marketplace}`;
|
|
19421
19516
|
});
|
|
19422
19517
|
}
|
|
19423
19518
|
function plgnzOwnedInstall(id, installPath) {
|
|
19424
|
-
if (typeof installPath !== "string" || !
|
|
19519
|
+
if (typeof installPath !== "string" || !existsSync21(installPath))
|
|
19425
19520
|
return false;
|
|
19426
19521
|
return readOwnership(installPath)?.pluginId === id;
|
|
19427
19522
|
}
|
|
@@ -19451,19 +19546,19 @@ function disableMarketplaceAutoUpdate(nativeId) {
|
|
|
19451
19546
|
|
|
19452
19547
|
// src/hosts/codex-writer.ts
|
|
19453
19548
|
init_codex_hooks();
|
|
19454
|
-
import { chmodSync, cpSync as cpSync6, existsSync as
|
|
19549
|
+
import { chmodSync, cpSync as cpSync6, existsSync as existsSync22, lstatSync as lstatSync15, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync6, readFileSync as readFileSync23, readdirSync as readdirSync14, renameSync as renameSync4, rmSync as rmSync7, statSync as statSync10, writeFileSync as writeFileSync7 } from "node:fs";
|
|
19455
19550
|
import { dirname as dirname9, join as join29, resolve as resolve16 } from "node:path";
|
|
19456
19551
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
19457
19552
|
|
|
19458
19553
|
// src/hosts/codex-marketplace-proof.ts
|
|
19459
|
-
import { lstatSync as
|
|
19554
|
+
import { lstatSync as lstatSync14, readFileSync as readFileSync22 } from "node:fs";
|
|
19460
19555
|
import { join as join28 } from "node:path";
|
|
19461
19556
|
var codexMarketplaceMetadataFile = ".codex-marketplace-install.json";
|
|
19462
19557
|
function codexMarketplaceSourceFingerprint(checkout, expected) {
|
|
19463
19558
|
try {
|
|
19464
19559
|
let stat;
|
|
19465
19560
|
try {
|
|
19466
|
-
stat =
|
|
19561
|
+
stat = lstatSync14(join28(checkout, codexMarketplaceMetadataFile));
|
|
19467
19562
|
} catch (error) {
|
|
19468
19563
|
if (error.code === "ENOENT")
|
|
19469
19564
|
return fingerprintSourceTree(checkout);
|
|
@@ -19509,13 +19604,13 @@ var codexWriter = {
|
|
|
19509
19604
|
validateStage(stage);
|
|
19510
19605
|
writeFileSync7(join29(stage, OWNERSHIP2), JSON.stringify({ source: resolved.sourceUri, pluginId: id, fingerprint: plugin.contentFingerprint ?? "" }));
|
|
19511
19606
|
assertManagedPath2(codexHome(), slot);
|
|
19512
|
-
if (
|
|
19607
|
+
if (existsSync22(slot)) {
|
|
19513
19608
|
assertNoSymlinks3(slot);
|
|
19514
19609
|
assertNoWinningForeignVersion(slot, version, id, resolved.sourceUri);
|
|
19515
19610
|
const marker = readOwnership2(targetDir);
|
|
19516
19611
|
if (marker !== null && (marker.source !== resolved.sourceUri || marker.pluginId !== id))
|
|
19517
19612
|
throw new Error(`codex cache slot ${targetDir} has a different owned source identity; refusing to replace it`);
|
|
19518
|
-
if (
|
|
19613
|
+
if (existsSync22(targetDir) && marker === null && !sameTree2(stage, targetDir)) {
|
|
19519
19614
|
if (!opts.adoptExisting)
|
|
19520
19615
|
throw new Error(`codex cache slot ${targetDir} is unowned and differs from the staged representation; pass --adopt-existing to take ownership explicitly`);
|
|
19521
19616
|
validateCachedIdentity(targetDir, plugin.name, version);
|
|
@@ -19541,8 +19636,8 @@ var codexWriter = {
|
|
|
19541
19636
|
ensureNativeManifest(stage, plugin.name, version);
|
|
19542
19637
|
validateStage(stage);
|
|
19543
19638
|
writeFileSync7(join29(stage, OWNERSHIP2), JSON.stringify({ source: resolved.sourceUri, pluginId: id, fingerprint: plugin.contentFingerprint ?? "" }));
|
|
19544
|
-
const identicalUnowned =
|
|
19545
|
-
if (
|
|
19639
|
+
const identicalUnowned = existsSync22(targetDir) && marker === null && sameTree2(stage, targetDir);
|
|
19640
|
+
if (existsSync22(targetDir) && marker === null && !identicalUnowned) {
|
|
19546
19641
|
if (!opts?.adoptExisting)
|
|
19547
19642
|
throw new Error(`codex cache slot ${targetDir} is unowned and differs from the staged representation; pass --adopt-existing to take ownership explicitly`);
|
|
19548
19643
|
validateCachedIdentity(targetDir, plugin.name, version);
|
|
@@ -19579,7 +19674,7 @@ var codexWriter = {
|
|
|
19579
19674
|
}
|
|
19580
19675
|
},
|
|
19581
19676
|
async pin(plugin, opts) {
|
|
19582
|
-
if (plugin.path === undefined || !
|
|
19677
|
+
if (plugin.path === undefined || !existsSync22(plugin.path))
|
|
19583
19678
|
return { changes: [], refusals: [] };
|
|
19584
19679
|
return pinPluginMcpFiles(plugin.path, mcpCandidates2(), opts);
|
|
19585
19680
|
},
|
|
@@ -19590,7 +19685,7 @@ var codexWriter = {
|
|
|
19590
19685
|
const owned = [];
|
|
19591
19686
|
if (at !== -1) {
|
|
19592
19687
|
const slot = join29(codexHome(), "plugins", "cache", id.slice(at + 1), id.slice(0, at));
|
|
19593
|
-
if (
|
|
19688
|
+
if (existsSync22(slot)) {
|
|
19594
19689
|
assertNoSymlinks3(slot);
|
|
19595
19690
|
for (const version of readdirSync14(slot)) {
|
|
19596
19691
|
const candidate = join29(slot, version);
|
|
@@ -19601,7 +19696,7 @@ var codexWriter = {
|
|
|
19601
19696
|
}
|
|
19602
19697
|
}
|
|
19603
19698
|
}
|
|
19604
|
-
if (
|
|
19699
|
+
if (existsSync22(configPath)) {
|
|
19605
19700
|
const toml = readFileSync23(configPath, "utf8");
|
|
19606
19701
|
const header = `[plugins."${id}"]`;
|
|
19607
19702
|
const idx = toml.indexOf(header);
|
|
@@ -19623,7 +19718,7 @@ enabled = false
|
|
|
19623
19718
|
}
|
|
19624
19719
|
};
|
|
19625
19720
|
function enable(configPath, id) {
|
|
19626
|
-
let toml =
|
|
19721
|
+
let toml = existsSync22(configPath) ? readFileSync23(configPath, "utf8") : "";
|
|
19627
19722
|
parseConfigToml(toml, configPath);
|
|
19628
19723
|
let newToml = toml;
|
|
19629
19724
|
const header = `[plugins."${id}"]`;
|
|
@@ -19667,7 +19762,7 @@ function parseConfigToml(text, path) {
|
|
|
19667
19762
|
}
|
|
19668
19763
|
}
|
|
19669
19764
|
function isEnabled(configPath, id) {
|
|
19670
|
-
if (!
|
|
19765
|
+
if (!existsSync22(configPath))
|
|
19671
19766
|
return false;
|
|
19672
19767
|
const toml = readFileSync23(configPath, "utf8");
|
|
19673
19768
|
const header = `[plugins."${id}"]`;
|
|
@@ -19680,7 +19775,7 @@ function isEnabled(configPath, id) {
|
|
|
19680
19775
|
return !/^enabled\s*=\s*false\s*$/mu.test(block);
|
|
19681
19776
|
}
|
|
19682
19777
|
function readConfigSnapshot(path) {
|
|
19683
|
-
if (!
|
|
19778
|
+
if (!existsSync22(path))
|
|
19684
19779
|
return { existed: false };
|
|
19685
19780
|
const read = readFileSync23;
|
|
19686
19781
|
return { existed: true, bytes: read(path) };
|
|
@@ -19701,7 +19796,7 @@ function validVersionSegment(value) {
|
|
|
19701
19796
|
}
|
|
19702
19797
|
function readOwnership2(dir) {
|
|
19703
19798
|
const file = join29(dir, OWNERSHIP2);
|
|
19704
|
-
if (!
|
|
19799
|
+
if (!existsSync22(file))
|
|
19705
19800
|
return null;
|
|
19706
19801
|
try {
|
|
19707
19802
|
const value = JSON.parse(readFileSync23(file, "utf8"));
|
|
@@ -19725,12 +19820,12 @@ function validateStage(stage) {
|
|
|
19725
19820
|
if (readPluginManifest(stage) === undefined)
|
|
19726
19821
|
throw new Error("Codex stage has no Agent Plugins manifest");
|
|
19727
19822
|
const skills = join29(stage, "skills");
|
|
19728
|
-
if (
|
|
19823
|
+
if (existsSync22(skills) && !statSync10(skills).isDirectory())
|
|
19729
19824
|
throw new Error("Codex stage skills path is not a directory");
|
|
19730
19825
|
}
|
|
19731
19826
|
function validateCachedIdentity(target, expectedName, expectedVersion) {
|
|
19732
19827
|
const candidates = [join29(target, ".codex-plugin", "plugin.json"), join29(target, "plugin.json"), join29(target, ".plugin", "plugin.json")];
|
|
19733
|
-
const manifest = candidates.find(
|
|
19828
|
+
const manifest = candidates.find(existsSync22);
|
|
19734
19829
|
if (manifest === undefined)
|
|
19735
19830
|
throw new Error(`unowned Codex cache slot has no manifest: ${target}`);
|
|
19736
19831
|
const value = JSON.parse(readFileSync23(manifest, "utf8"));
|
|
@@ -19740,7 +19835,7 @@ function validateCachedIdentity(target, expectedName, expectedVersion) {
|
|
|
19740
19835
|
if (record["name"] === expectedName && record["version"] === expectedVersion)
|
|
19741
19836
|
return;
|
|
19742
19837
|
if (manifest === candidates[0] && record["name"] === expectedName && nativeBuildVariant(expectedVersion, record["version"])) {
|
|
19743
|
-
const canonical = candidates.slice(1).find(
|
|
19838
|
+
const canonical = candidates.slice(1).find(existsSync22);
|
|
19744
19839
|
if (canonical !== undefined) {
|
|
19745
19840
|
const canonicalValue = JSON.parse(readFileSync23(canonical, "utf8"));
|
|
19746
19841
|
if (typeof canonicalValue === "object" && canonicalValue !== null && !Array.isArray(canonicalValue)) {
|
|
@@ -19765,7 +19860,7 @@ function ensureNativeManifest(stage, fallbackName, fallbackVersion) {
|
|
|
19765
19860
|
throw new Error("Codex stage has no Agent Plugins manifest");
|
|
19766
19861
|
for (const path of ["plugin.json", ".plugin/plugin.json", ".claude-plugin/plugin.json"]) {
|
|
19767
19862
|
const file = join29(stage, path);
|
|
19768
|
-
if (
|
|
19863
|
+
if (existsSync22(file) && JSON.parse(readFileSync23(file, "utf8")).mcpServers !== undefined) {
|
|
19769
19864
|
throw new Error("Codex inline manifest MCP projection is unverified; use mcp.json or .mcp.json");
|
|
19770
19865
|
}
|
|
19771
19866
|
}
|
|
@@ -19773,7 +19868,7 @@ function ensureNativeManifest(stage, fallbackName, fallbackVersion) {
|
|
|
19773
19868
|
const version = sourceManifest.version ?? fallbackVersion;
|
|
19774
19869
|
const description = sourceManifest.description ?? `Plugin ${name}`;
|
|
19775
19870
|
let overlay = {};
|
|
19776
|
-
if (
|
|
19871
|
+
if (existsSync22(native)) {
|
|
19777
19872
|
const value = JSON.parse(readFileSync23(native, "utf8"));
|
|
19778
19873
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
19779
19874
|
throw new Error("Codex native plugin manifest must be an object");
|
|
@@ -19787,10 +19882,10 @@ function ensureNativeManifest(stage, fallbackName, fallbackVersion) {
|
|
|
19787
19882
|
}
|
|
19788
19883
|
}
|
|
19789
19884
|
const pointer = overlay["mcpServers"];
|
|
19790
|
-
if (pointer !== undefined && (typeof pointer !== "string" || !pointer.startsWith("./") || pointer.includes("\\") || pointer.split("/").includes("..") || !
|
|
19885
|
+
if (pointer !== undefined && (typeof pointer !== "string" || !pointer.startsWith("./") || pointer.includes("\\") || pointer.split("/").includes("..") || !existsSync22(join29(stage, pointer)))) {
|
|
19791
19886
|
throw new Error("Codex native MCP pointer must name an existing plugin-local file");
|
|
19792
19887
|
}
|
|
19793
|
-
const mcpFiles = ["mcp.json", ".mcp.json", ...typeof pointer === "string" ? [pointer] : []].map((path) => join29(stage, path)).filter(
|
|
19888
|
+
const mcpFiles = ["mcp.json", ".mcp.json", ...typeof pointer === "string" ? [pointer] : []].map((path) => join29(stage, path)).filter(existsSync22);
|
|
19794
19889
|
const declarations = mcpFiles.map((file) => {
|
|
19795
19890
|
const value = JSON.parse(readFileSync23(file, "utf8"));
|
|
19796
19891
|
if (value === null || typeof value !== "object" || Array.isArray(value) || !("mcpServers" in value) || value.mcpServers === null || typeof value.mcpServers !== "object" || Array.isArray(value.mcpServers)) {
|
|
@@ -19807,7 +19902,7 @@ function ensureNativeManifest(stage, fallbackName, fallbackVersion) {
|
|
|
19807
19902
|
version,
|
|
19808
19903
|
description,
|
|
19809
19904
|
skills: overlay["skills"] ?? "./skills/",
|
|
19810
|
-
...overlay["mcpServers"] === undefined &&
|
|
19905
|
+
...overlay["mcpServers"] === undefined && existsSync22(join29(stage, "mcp.json")) && !existsSync22(join29(stage, ".mcp.json")) ? { mcpServers: "./mcp.json" } : {}
|
|
19811
19906
|
}));
|
|
19812
19907
|
}
|
|
19813
19908
|
function mcpDeclarationIdentity(value) {
|
|
@@ -19825,9 +19920,9 @@ function assertManagedPath2(root, target) {
|
|
|
19825
19920
|
for (const part of ["", ...suffix.split("/").filter(Boolean)]) {
|
|
19826
19921
|
if (part !== "")
|
|
19827
19922
|
current = join29(current, part);
|
|
19828
|
-
if (!
|
|
19923
|
+
if (!existsSync22(current))
|
|
19829
19924
|
continue;
|
|
19830
|
-
const stat =
|
|
19925
|
+
const stat = lstatSync15(current);
|
|
19831
19926
|
if (stat.isSymbolicLink())
|
|
19832
19927
|
throw new Error(`Codex managed path component is a symlink: ${current}`);
|
|
19833
19928
|
if (!stat.isDirectory())
|
|
@@ -19836,16 +19931,16 @@ function assertManagedPath2(root, target) {
|
|
|
19836
19931
|
}
|
|
19837
19932
|
function assertManagedConfigPath(root, path) {
|
|
19838
19933
|
assertManagedPath2(root, dirname9(path));
|
|
19839
|
-
if (!
|
|
19934
|
+
if (!existsSync22(path))
|
|
19840
19935
|
return;
|
|
19841
|
-
const stat =
|
|
19936
|
+
const stat = lstatSync15(path);
|
|
19842
19937
|
if (stat.isSymbolicLink())
|
|
19843
19938
|
throw new Error(`Codex managed config is a symlink: ${path}`);
|
|
19844
19939
|
if (!stat.isFile())
|
|
19845
19940
|
throw new Error(`Codex managed config is not a file: ${path}`);
|
|
19846
19941
|
}
|
|
19847
19942
|
function activate2(stage, target, slot) {
|
|
19848
|
-
if (!
|
|
19943
|
+
if (!existsSync22(target)) {
|
|
19849
19944
|
renameSync4(stage, target);
|
|
19850
19945
|
return { commit: () => {}, rollback: () => rmSync7(target, { recursive: true, force: true }) };
|
|
19851
19946
|
}
|
|
@@ -19920,7 +20015,7 @@ function assertNoSymlinks3(dir) {
|
|
|
19920
20015
|
const walk = (current) => {
|
|
19921
20016
|
for (const entry of readdirSync14(current)) {
|
|
19922
20017
|
const path = join29(current, entry);
|
|
19923
|
-
const stat =
|
|
20018
|
+
const stat = lstatSync15(path);
|
|
19924
20019
|
if (stat.isSymbolicLink())
|
|
19925
20020
|
throw new Error(`Codex managed slot contains symlink: ${path}`);
|
|
19926
20021
|
if (stat.isDirectory())
|
|
@@ -20049,10 +20144,10 @@ function revalidateCodexTarget(handle) {
|
|
|
20049
20144
|
for (const root of handle.expected.contentRoots)
|
|
20050
20145
|
assertRequestedCacheOwnership(root.path, handle.prior.contentRoots);
|
|
20051
20146
|
}
|
|
20052
|
-
if (
|
|
20147
|
+
if (existsSync22(join29(bundle, "marketplace.json"))) {
|
|
20053
20148
|
const metadata = JSON.parse(readFileSync23(join29(bundle, "marketplace.json"), "utf8"));
|
|
20054
20149
|
const checkout = marketplaceCheckout(metadata.marketplace);
|
|
20055
|
-
const actual =
|
|
20150
|
+
const actual = existsSync22(checkout) ? fingerprintTree(checkout) : null;
|
|
20056
20151
|
if (actual !== metadata.fingerprint)
|
|
20057
20152
|
throw new Error("Codex marketplace checkout changed after rollback capture");
|
|
20058
20153
|
}
|
|
@@ -20249,13 +20344,13 @@ async function retireCodex(prepared) {
|
|
|
20249
20344
|
}
|
|
20250
20345
|
function restampNativeUpgrade(prepared) {
|
|
20251
20346
|
const markerPath = join29(prepared.stagingRoot, OWNERSHIP2);
|
|
20252
|
-
if (!
|
|
20347
|
+
if (!existsSync22(markerPath))
|
|
20253
20348
|
return;
|
|
20254
20349
|
const marker = readFileSync23(markerPath, "utf8");
|
|
20255
20350
|
const version = pluginVersion(prepared.stagingRoot);
|
|
20256
20351
|
if (validVersionSegment(version)) {
|
|
20257
20352
|
const destination = cacheDestination(prepared.handle.nativeId, version);
|
|
20258
|
-
if (
|
|
20353
|
+
if (existsSync22(destination) && statSync10(destination).isDirectory()) {
|
|
20259
20354
|
assertManagedPath2(codexHome(), destination);
|
|
20260
20355
|
writeFileSync7(join29(destination, OWNERSHIP2), marker);
|
|
20261
20356
|
}
|
|
@@ -20264,7 +20359,7 @@ function restampNativeUpgrade(prepared) {
|
|
|
20264
20359
|
if (nativeId === prepared.handle.nativeId)
|
|
20265
20360
|
continue;
|
|
20266
20361
|
const path = codex.listInstalled().find((plugin) => plugin.id === nativeId)?.path;
|
|
20267
|
-
if (path === undefined || !
|
|
20362
|
+
if (path === undefined || !existsSync22(path))
|
|
20268
20363
|
continue;
|
|
20269
20364
|
const existing = readOwnership2(path);
|
|
20270
20365
|
if (existing?.pluginId === nativeId)
|
|
@@ -20283,7 +20378,7 @@ function restampNativeUpgrade(prepared) {
|
|
|
20283
20378
|
function priorInstallMarker(prepared, nativeId) {
|
|
20284
20379
|
const bundle = rollbackBundle(prepared.handle.attemptId, prepared.handle.operationId);
|
|
20285
20380
|
const manifestPath = join29(bundle, "manifest.json");
|
|
20286
|
-
if (!
|
|
20381
|
+
if (!existsSync22(manifestPath))
|
|
20287
20382
|
return null;
|
|
20288
20383
|
const manifest = parseRollbackManifest(readFileSync23(manifestPath, "utf8"));
|
|
20289
20384
|
const install = manifest.installs.find((item) => item.nativeId === nativeId);
|
|
@@ -20320,11 +20415,11 @@ function readCodexInstall(handle) {
|
|
|
20320
20415
|
function cleanupCodexStage(reference) {
|
|
20321
20416
|
releasePriorSourceRepair(reference);
|
|
20322
20417
|
const stage = resolve16(join29(codexHome(), ".plgnz-lifecycle", `${reference.attemptId}:${reference.operationId}`));
|
|
20323
|
-
if (
|
|
20418
|
+
if (existsSync22(stage))
|
|
20324
20419
|
rmSync7(stage, { recursive: true, force: true });
|
|
20325
20420
|
const rollback = rollbackBundle(reference.attemptId, reference.operationId);
|
|
20326
20421
|
assertManagedPath2(codexHome(), rollback);
|
|
20327
|
-
if (
|
|
20422
|
+
if (existsSync22(rollback))
|
|
20328
20423
|
rmSync7(rollback, { recursive: true, force: true });
|
|
20329
20424
|
return { cleanupId: `cleanup:${reference.attemptId}:${reference.operationId}`, completed: true };
|
|
20330
20425
|
}
|
|
@@ -20384,7 +20479,7 @@ function pluginDataRoots(nativeId) {
|
|
|
20384
20479
|
];
|
|
20385
20480
|
}
|
|
20386
20481
|
function retainedTree(paths) {
|
|
20387
|
-
const present = paths.filter((path) =>
|
|
20482
|
+
const present = paths.filter((path) => existsSync22(path));
|
|
20388
20483
|
const [only, ...rest] = present;
|
|
20389
20484
|
if (only === undefined)
|
|
20390
20485
|
return { state: "absent", fingerprint: null };
|
|
@@ -20425,7 +20520,7 @@ function cacheDestination(nativeId, version) {
|
|
|
20425
20520
|
}
|
|
20426
20521
|
function cacheFingerprint(nativeId) {
|
|
20427
20522
|
const path = codex.listInstalled().find((plugin) => plugin.id === nativeId)?.path;
|
|
20428
|
-
if (path === undefined || !
|
|
20523
|
+
if (path === undefined || !existsSync22(path))
|
|
20429
20524
|
return null;
|
|
20430
20525
|
try {
|
|
20431
20526
|
return fingerprintTree(path);
|
|
@@ -20476,7 +20571,7 @@ function codexRollbackReference(attemptId, operationId) {
|
|
|
20476
20571
|
const reference = `codex:${attemptId}:${operationId}`;
|
|
20477
20572
|
const bundle = rollbackBundle(attemptId, operationId);
|
|
20478
20573
|
const capture = join29(bundle, "native-cache.json");
|
|
20479
|
-
if (!
|
|
20574
|
+
if (!existsSync22(capture))
|
|
20480
20575
|
return reference;
|
|
20481
20576
|
const digest = new CryptoHasher("sha256").update(readFileSync23(capture, "utf8")).update("\x00").update(readFileSync23(join29(bundle, "manifest.json"), "utf8")).digest("hex");
|
|
20482
20577
|
return `${reference}:native-cache-sha256:${digest}`;
|
|
@@ -20488,14 +20583,14 @@ function nativeCacheFingerprint(root, ignoreOwnership = false) {
|
|
|
20488
20583
|
const hash = new CryptoHasher("sha256");
|
|
20489
20584
|
const read = readFileSync23;
|
|
20490
20585
|
const walk = (path, relative) => {
|
|
20491
|
-
const stat =
|
|
20586
|
+
const stat = lstatSync15(path);
|
|
20492
20587
|
if (stat.isSymbolicLink() || !stat.isDirectory() && !stat.isFile())
|
|
20493
20588
|
throw new Error(`Codex native cache contains an unsafe resource: ${path}`);
|
|
20494
20589
|
hash.update(`${stat.isDirectory() ? "d" : "f"}\x00${relative}\x00${stat.mode & 4095}\x00`);
|
|
20495
20590
|
if (stat.isDirectory()) {
|
|
20496
20591
|
for (const entry of readdirSync14(path).sort()) {
|
|
20497
20592
|
if (ignoreOwnership && relative === "" && entry === OWNERSHIP2) {
|
|
20498
|
-
const marker =
|
|
20593
|
+
const marker = lstatSync15(join29(path, entry));
|
|
20499
20594
|
if (marker.isSymbolicLink() || !marker.isFile())
|
|
20500
20595
|
throw new Error("Codex attempted cache ownership marker is unsafe");
|
|
20501
20596
|
continue;
|
|
@@ -20525,7 +20620,7 @@ function nativeSlotIsOwned(installation, source) {
|
|
|
20525
20620
|
const activeProof = nativeCacheFingerprint(active.path);
|
|
20526
20621
|
return readdirSync14(slot).every((version) => {
|
|
20527
20622
|
const path = join29(slot, version);
|
|
20528
|
-
const stat =
|
|
20623
|
+
const stat = lstatSync15(path);
|
|
20529
20624
|
if (stat.isSymbolicLink())
|
|
20530
20625
|
throw new Error("Codex native cache slot is redirected");
|
|
20531
20626
|
if (!validVersionSegment(version) || !stat.isDirectory())
|
|
@@ -20574,7 +20669,7 @@ function captureNativeCacheSnapshots(projection) {
|
|
|
20574
20669
|
}
|
|
20575
20670
|
function readNativeCacheSnapshots(handle) {
|
|
20576
20671
|
const file = join29(rollbackBundle(handle.attemptId, handle.operationId), "native-cache.json");
|
|
20577
|
-
if (!
|
|
20672
|
+
if (!existsSync22(file))
|
|
20578
20673
|
throw new Error("Codex complete native cache rollback capture is missing");
|
|
20579
20674
|
if (handle.rollbackReference !== codexRollbackReference(handle.attemptId, handle.operationId))
|
|
20580
20675
|
throw new Error("Codex complete native cache authority differs from its sealed rollback reference");
|
|
@@ -20615,7 +20710,7 @@ function saveCodexRollback(attemptId, operationId, nativeIds) {
|
|
|
20615
20710
|
assertManagedPath2(codexHome(), bundle);
|
|
20616
20711
|
rmSync7(bundle, { recursive: true, force: true });
|
|
20617
20712
|
mkdirSync7(bundle, { recursive: true });
|
|
20618
|
-
const toml =
|
|
20713
|
+
const toml = existsSync22(configFile()) ? readFileSync23(configFile(), "utf8") : "";
|
|
20619
20714
|
const tables = nativeIds.map((nativeId) => ({ nativeId, block: extractPluginTable(toml, nativeId) }));
|
|
20620
20715
|
const installs = nativeIds.map((nativeId, index) => {
|
|
20621
20716
|
const slot = pluginSlot(nativeId);
|
|
@@ -20632,7 +20727,7 @@ function saveCodexRollback(attemptId, operationId, nativeIds) {
|
|
|
20632
20727
|
function restoreCodexRollback(handle) {
|
|
20633
20728
|
const bundle = rollbackBundle(handle.attemptId, handle.operationId);
|
|
20634
20729
|
const manifestPath = join29(bundle, "manifest.json");
|
|
20635
|
-
if (!
|
|
20730
|
+
if (!existsSync22(manifestPath))
|
|
20636
20731
|
throw new Error(`codex lifecycle rollback bundle is missing: ${handle.operationId}`);
|
|
20637
20732
|
const manifest = parseRollbackManifest(readFileSync23(manifestPath, "utf8"));
|
|
20638
20733
|
assertMarketplaceRollbackCurrent(handle);
|
|
@@ -20669,7 +20764,7 @@ function marketplaceCheckout(marketplace) {
|
|
|
20669
20764
|
return path;
|
|
20670
20765
|
}
|
|
20671
20766
|
function assertNativeRollbackSurfaces(handle, manifest, bundle) {
|
|
20672
|
-
const config =
|
|
20767
|
+
const config = existsSync22(configFile()) ? readFileSync23(configFile(), "utf8") : "";
|
|
20673
20768
|
for (const table of manifest.tables) {
|
|
20674
20769
|
if (extractPluginTable(config, table.nativeId) !== table.block)
|
|
20675
20770
|
throw new Error("Codex affected plugin config changed outside the captured native attempt; refusing rollback before any restore write");
|
|
@@ -20684,14 +20779,14 @@ function assertNativeRollbackSurfaces(handle, manifest, bundle) {
|
|
|
20684
20779
|
const currentFingerprint = nativeCacheFingerprint(slot.path);
|
|
20685
20780
|
if (currentFingerprint === slot.fingerprint)
|
|
20686
20781
|
return { ...slot, currentFingerprint };
|
|
20687
|
-
const projected = projections.find((path) =>
|
|
20782
|
+
const projected = projections.find((path) => existsSync22(path) && readOwnership2(path)?.pluginId === slot.nativeId);
|
|
20688
20783
|
let containsCandidate = false;
|
|
20689
20784
|
for (const version of readdirSync14(slot.path)) {
|
|
20690
20785
|
const path = join29(slot.path, version);
|
|
20691
|
-
if (!validVersionSegment(version) || !
|
|
20786
|
+
if (!validVersionSegment(version) || !lstatSync15(path).isDirectory())
|
|
20692
20787
|
throw new Error("Codex complete cache contains an unproven resource; refusing rollback before any restore write");
|
|
20693
20788
|
const priorVersion = join29(saved, version);
|
|
20694
|
-
if (
|
|
20789
|
+
if (existsSync22(priorVersion) && nativeCacheFingerprint(path) === nativeCacheFingerprint(priorVersion))
|
|
20695
20790
|
continue;
|
|
20696
20791
|
if (projected === undefined || version !== pluginVersion(projected) || (readOwnership2(path) === null ? nativeCacheFingerprint(path, true) !== nativeCacheFingerprint(projected, true) : nativeCacheFingerprint(path) !== nativeCacheFingerprint(projected))) {
|
|
20697
20792
|
throw new Error("Codex complete cache changed outside the captured native attempt; refusing rollback before any restore write");
|
|
@@ -20710,7 +20805,7 @@ function captureMarketplaceRollback(projection) {
|
|
|
20710
20805
|
throw new Error("native Codex mutation has no bounded marketplace");
|
|
20711
20806
|
const checkout = marketplaceCheckout(marketplace);
|
|
20712
20807
|
const bundle = rollbackBundle(projection.attemptId, projection.operationId);
|
|
20713
|
-
const fingerprint =
|
|
20808
|
+
const fingerprint = existsSync22(checkout) ? fingerprintTree(checkout) : null;
|
|
20714
20809
|
if (fingerprint !== null) {
|
|
20715
20810
|
const snapshot = join29(bundle, "marketplace");
|
|
20716
20811
|
cpSync6(checkout, snapshot, { recursive: true });
|
|
@@ -20721,13 +20816,13 @@ function captureMarketplaceRollback(projection) {
|
|
|
20721
20816
|
}
|
|
20722
20817
|
function captureAttemptedMarketplace(handle) {
|
|
20723
20818
|
const metadata = join29(rollbackBundle(handle.attemptId, handle.operationId), "marketplace.json");
|
|
20724
|
-
if (!
|
|
20819
|
+
if (!existsSync22(metadata))
|
|
20725
20820
|
return;
|
|
20726
20821
|
const marketplace = marketplaceOf(handle.nativeId);
|
|
20727
20822
|
if (marketplace === null || handle.sourceLocator === null)
|
|
20728
20823
|
return;
|
|
20729
20824
|
const checkout = marketplaceCheckout(marketplace);
|
|
20730
|
-
if (!
|
|
20825
|
+
if (!existsSync22(checkout))
|
|
20731
20826
|
return;
|
|
20732
20827
|
const capture = JSON.parse(readFileSync23(metadata, "utf8"));
|
|
20733
20828
|
if (typeof capture["sourceFingerprint"] !== "string" || !/^[0-9a-f]{64}$/u.test(capture["sourceFingerprint"]))
|
|
@@ -20742,14 +20837,14 @@ function captureAttemptedMarketplace(handle) {
|
|
|
20742
20837
|
}
|
|
20743
20838
|
function assertMarketplaceRollbackCurrent(handle) {
|
|
20744
20839
|
const metadata = join29(rollbackBundle(handle.attemptId, handle.operationId), "marketplace.json");
|
|
20745
|
-
if (!
|
|
20840
|
+
if (!existsSync22(metadata))
|
|
20746
20841
|
return;
|
|
20747
20842
|
const row = JSON.parse(readFileSync23(metadata, "utf8"));
|
|
20748
20843
|
const marketplace = marketplaceOf(handle.nativeId);
|
|
20749
20844
|
if (marketplace === null || row["marketplace"] !== marketplace || row["fingerprint"] !== null && (typeof row["fingerprint"] !== "string" || !/^[0-9a-f]{64}$/u.test(row["fingerprint"])) || row["attemptedFingerprint"] !== undefined && (typeof row["attemptedFingerprint"] !== "string" || !/^[0-9a-f]{64}$/u.test(row["attemptedFingerprint"])))
|
|
20750
20845
|
throw new Error("invalid Codex marketplace rollback capture");
|
|
20751
20846
|
const checkout = marketplaceCheckout(marketplace);
|
|
20752
|
-
const current =
|
|
20847
|
+
const current = existsSync22(checkout) ? fingerprintTree(checkout) : null;
|
|
20753
20848
|
if (current !== row["fingerprint"] && current !== row["attemptedFingerprint"]) {
|
|
20754
20849
|
throw new Error("Codex marketplace checkout changed outside the captured native attempt; refusing rollback before any restore write");
|
|
20755
20850
|
}
|
|
@@ -20760,7 +20855,7 @@ function assertMarketplaceRollbackCurrent(handle) {
|
|
|
20760
20855
|
function restoreMarketplaceRollback(handle) {
|
|
20761
20856
|
const bundle = rollbackBundle(handle.attemptId, handle.operationId);
|
|
20762
20857
|
const metadata = join29(bundle, "marketplace.json");
|
|
20763
|
-
if (!
|
|
20858
|
+
if (!existsSync22(metadata))
|
|
20764
20859
|
return;
|
|
20765
20860
|
const capture = JSON.parse(readFileSync23(metadata, "utf8"));
|
|
20766
20861
|
if (typeof capture !== "object" || capture === null || Array.isArray(capture))
|
|
@@ -20771,7 +20866,7 @@ function restoreMarketplaceRollback(handle) {
|
|
|
20771
20866
|
throw new Error("invalid Codex marketplace rollback identity");
|
|
20772
20867
|
const checkout = marketplaceCheckout(marketplace);
|
|
20773
20868
|
if (row["fingerprint"] === null) {
|
|
20774
|
-
if (
|
|
20869
|
+
if (existsSync22(checkout))
|
|
20775
20870
|
rmSync7(checkout, { recursive: true });
|
|
20776
20871
|
return;
|
|
20777
20872
|
}
|
|
@@ -20803,18 +20898,18 @@ function pluginSlot(nativeId) {
|
|
|
20803
20898
|
return join29(codexHome(), "plugins", "cache", marketplace, name);
|
|
20804
20899
|
}
|
|
20805
20900
|
function slotVersions(slot) {
|
|
20806
|
-
if (!
|
|
20901
|
+
if (!existsSync22(slot))
|
|
20807
20902
|
return [];
|
|
20808
20903
|
return readdirSync14(slot).filter((version) => {
|
|
20809
20904
|
try {
|
|
20810
|
-
return
|
|
20905
|
+
return lstatSync15(join29(slot, version)).isDirectory();
|
|
20811
20906
|
} catch {
|
|
20812
20907
|
return false;
|
|
20813
20908
|
}
|
|
20814
20909
|
}).sort();
|
|
20815
20910
|
}
|
|
20816
20911
|
function removeUnsnapshotVersions(slot, versions) {
|
|
20817
|
-
if (slot === null || !
|
|
20912
|
+
if (slot === null || !existsSync22(slot))
|
|
20818
20913
|
return;
|
|
20819
20914
|
assertManagedPath2(codexHome(), slot);
|
|
20820
20915
|
const kept = new Set(versions);
|
|
@@ -20827,10 +20922,10 @@ function removeUnsnapshotVersions(slot, versions) {
|
|
|
20827
20922
|
}
|
|
20828
20923
|
}
|
|
20829
20924
|
function rollbackSurface(nativeIds) {
|
|
20830
|
-
const config =
|
|
20925
|
+
const config = existsSync22(configFile()) ? readFileSync23(configFile(), "utf8") : "absent";
|
|
20831
20926
|
const slots = nativeIds.map((nativeId) => {
|
|
20832
20927
|
const slot = pluginSlot(nativeId);
|
|
20833
|
-
if (slot === null || !
|
|
20928
|
+
if (slot === null || !existsSync22(slot))
|
|
20834
20929
|
return `${nativeId}:`;
|
|
20835
20930
|
return `${nativeId}:${slotVersions(slot).map((version) => {
|
|
20836
20931
|
const path = join29(slot, version);
|
|
@@ -20860,7 +20955,7 @@ function extractPluginTable(toml, id) {
|
|
|
20860
20955
|
}
|
|
20861
20956
|
function restorePluginTables(tables) {
|
|
20862
20957
|
const configPath = configFile();
|
|
20863
|
-
const current =
|
|
20958
|
+
const current = existsSync22(configPath) ? readFileSync23(configPath, "utf8") : "";
|
|
20864
20959
|
let next = current;
|
|
20865
20960
|
for (const table of tables)
|
|
20866
20961
|
next = applyPluginTable(next, table.nativeId, table.block);
|
|
@@ -20998,7 +21093,7 @@ function nativeProjection2(request) {
|
|
|
20998
21093
|
}
|
|
20999
21094
|
if (request.pins.length > 0)
|
|
21000
21095
|
return { kind: "requires-managed", reasonId: "pins-present" };
|
|
21001
|
-
if (
|
|
21096
|
+
if (existsSync22(join29(request.snapshot.snapshotRoot, codexMarketplaceMetadataFile))) {
|
|
21002
21097
|
return { kind: "requires-managed", reasonId: "native-reserved-source-metadata" };
|
|
21003
21098
|
}
|
|
21004
21099
|
const marketplace = marketplaceOf(request.snapshot.nativeId);
|
|
@@ -21024,16 +21119,16 @@ function nativeProjection2(request) {
|
|
|
21024
21119
|
}
|
|
21025
21120
|
function assertRequestedCacheOwnership(destination, observedRoots) {
|
|
21026
21121
|
assertManagedPath2(codexHome(), destination);
|
|
21027
|
-
if (
|
|
21122
|
+
if (existsSync22(destination) && !observedRoots.some((root) => root.path === destination)) {
|
|
21028
21123
|
throw new Error("Codex inactive requested version has no captured active ownership; refusing to replace it");
|
|
21029
21124
|
}
|
|
21030
21125
|
const slot = dirname9(destination);
|
|
21031
|
-
if (!
|
|
21126
|
+
if (!existsSync22(slot))
|
|
21032
21127
|
return;
|
|
21033
21128
|
const requested = destination.slice(slot.length + 1);
|
|
21034
21129
|
for (const version of readdirSync14(slot)) {
|
|
21035
21130
|
const path = join29(slot, version);
|
|
21036
|
-
if (
|
|
21131
|
+
if (lstatSync15(path).isDirectory() && wins(version, requested) && !observedRoots.some((root) => root.path === path)) {
|
|
21037
21132
|
throw new Error(`Codex inactive cache version ${version} has no captured retirement authority and would remain active over ${requested}`);
|
|
21038
21133
|
}
|
|
21039
21134
|
}
|
|
@@ -21083,7 +21178,7 @@ function marketplaceOf(nativeId) {
|
|
|
21083
21178
|
return nativeId.slice(at + 1);
|
|
21084
21179
|
}
|
|
21085
21180
|
function readConfigDocument() {
|
|
21086
|
-
if (!
|
|
21181
|
+
if (!existsSync22(configFile()))
|
|
21087
21182
|
return null;
|
|
21088
21183
|
try {
|
|
21089
21184
|
const parsed = parse(readFileSync23(configFile(), "utf8"));
|
|
@@ -21121,7 +21216,7 @@ function comparePrerelease2(left, right) {
|
|
|
21121
21216
|
}
|
|
21122
21217
|
|
|
21123
21218
|
// src/hosts/kimi-writer.ts
|
|
21124
|
-
import { cpSync as cpSync7, existsSync as
|
|
21219
|
+
import { cpSync as cpSync7, existsSync as existsSync23, lstatSync as lstatSync16, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync7, readFileSync as readFileSync24, readdirSync as readdirSync15, realpathSync as realpathSync4, renameSync as renameSync5, rmSync as rmSync8, statSync as statSync11, writeFileSync as writeFileSync8 } from "node:fs";
|
|
21125
21220
|
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join30, resolve as resolve17 } from "node:path";
|
|
21126
21221
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
21127
21222
|
var MARKER4 = ".plgnz-install.json";
|
|
@@ -21137,7 +21232,7 @@ var samePhysicalKimiNativeIdentity = (plugin, prior, observation) => {
|
|
|
21137
21232
|
const managed = managedPluginPath(plugin.name);
|
|
21138
21233
|
const registryFile = join30(pluginsDir2(), "installed.json");
|
|
21139
21234
|
assertKimiManaged(plugin.name, managed, registryFile);
|
|
21140
|
-
if (!
|
|
21235
|
+
if (!existsSync23(managed))
|
|
21141
21236
|
return null;
|
|
21142
21237
|
const rows = readRegistry2(registryFile).plugins.filter((row) => row.id === plugin.name || sameRoot(row.root, managed));
|
|
21143
21238
|
if (rows.length !== 1 || rows[0].id !== plugin.name || rows[0].enabled !== true || !sameRoot(rows[0].root, managed))
|
|
@@ -21188,8 +21283,8 @@ var kimiWriter = {
|
|
|
21188
21283
|
const differentSource = marker !== null && !lifecycleLocalSource && marker.source !== resolved.sourceUri;
|
|
21189
21284
|
if (marker !== null && (differentSource || !markerHasExpectedIdentity))
|
|
21190
21285
|
throw new Error(`Kimi plugin ${id} belongs to another source; refusing to replace it`);
|
|
21191
|
-
const same =
|
|
21192
|
-
if (
|
|
21286
|
+
const same = existsSync23(target) && sameTree3(stage, target);
|
|
21287
|
+
if (existsSync23(target) && marker === null && !same) {
|
|
21193
21288
|
if (!opts?.adoptExisting)
|
|
21194
21289
|
throw new Error(`Kimi managed plugin ${id} is unowned and differs from the staged representation; pass --adopt-existing to take ownership explicitly`);
|
|
21195
21290
|
validateNativeIdentity(target, id);
|
|
@@ -21207,13 +21302,13 @@ var kimiWriter = {
|
|
|
21207
21302
|
}
|
|
21208
21303
|
if (unchanged)
|
|
21209
21304
|
return "unchanged";
|
|
21210
|
-
const registryBefore =
|
|
21305
|
+
const registryBefore = existsSync23(registryFile) ? readFileSync24(registryFile, "utf8") : undefined;
|
|
21211
21306
|
const backup = moveAside2(target, managedRoot);
|
|
21212
21307
|
try {
|
|
21213
21308
|
await nativeInstall(stage, kimiRootPath(), resolveKimiBinary());
|
|
21214
21309
|
const after = readRegistry2(registryFile);
|
|
21215
21310
|
const row = after.plugins.find((candidate) => candidate.id === id);
|
|
21216
|
-
if (row === undefined || row.enabled !== true || !sameRoot(row.root, target) || !
|
|
21311
|
+
if (row === undefined || row.enabled !== true || !sameRoot(row.root, target) || !existsSync23(target) || !sameTree3(stage, target)) {
|
|
21217
21312
|
throw new Error(`Kimi native install did not produce enabled managed plugin ${id}`);
|
|
21218
21313
|
}
|
|
21219
21314
|
} catch (error) {
|
|
@@ -21228,7 +21323,7 @@ var kimiWriter = {
|
|
|
21228
21323
|
}
|
|
21229
21324
|
},
|
|
21230
21325
|
async pin(plugin, opts) {
|
|
21231
|
-
if (plugin.path === undefined || !
|
|
21326
|
+
if (plugin.path === undefined || !existsSync23(plugin.path))
|
|
21232
21327
|
return { changes: [], refusals: [] };
|
|
21233
21328
|
return pinPluginMcpFiles(plugin.path, mcpCandidates3(), opts);
|
|
21234
21329
|
},
|
|
@@ -21272,7 +21367,7 @@ function sameRoot(value, target) {
|
|
|
21272
21367
|
}
|
|
21273
21368
|
}
|
|
21274
21369
|
function readRegistry2(path) {
|
|
21275
|
-
if (!
|
|
21370
|
+
if (!existsSync23(path))
|
|
21276
21371
|
return { version: 1, plugins: [] };
|
|
21277
21372
|
let raw;
|
|
21278
21373
|
try {
|
|
@@ -21292,18 +21387,18 @@ function restore(path, value) {
|
|
|
21292
21387
|
}
|
|
21293
21388
|
function restoreRegistryRow(registryFile, id, reference) {
|
|
21294
21389
|
const rowFile = join30(reference, "registry.row.json");
|
|
21295
|
-
const priorRow =
|
|
21390
|
+
const priorRow = existsSync23(rowFile) ? parseJson(rowFile, "Kimi registry row") : undefined;
|
|
21296
21391
|
if (priorRow !== undefined && priorRow.id !== id)
|
|
21297
21392
|
throw new Error(`Kimi rollback row is not ${id}`);
|
|
21298
|
-
const live =
|
|
21393
|
+
const live = existsSync23(registryFile) ? readRegistry2(registryFile) : { version: 1, plugins: [] };
|
|
21299
21394
|
const plugins = live.plugins.filter((row) => row.id !== id);
|
|
21300
21395
|
if (priorRow !== undefined)
|
|
21301
21396
|
plugins.push(priorRow);
|
|
21302
|
-
if (plugins.length === 0 &&
|
|
21397
|
+
if (plugins.length === 0 && existsSync23(join30(reference, "registry.absent"))) {
|
|
21303
21398
|
rmSync8(registryFile, { force: true });
|
|
21304
21399
|
return;
|
|
21305
21400
|
}
|
|
21306
|
-
if (!
|
|
21401
|
+
if (!existsSync23(registryFile) && plugins.length === 0)
|
|
21307
21402
|
return;
|
|
21308
21403
|
writeFileSync8(registryFile, JSON.stringify({ version: 1, plugins }));
|
|
21309
21404
|
}
|
|
@@ -21324,13 +21419,13 @@ function projectStagedKimi(stage, expectedName) {
|
|
|
21324
21419
|
if (manifest[key] !== undefined)
|
|
21325
21420
|
throw new Error(`Kimi root manifest ${key} is unsupported without an explicit native declaration`);
|
|
21326
21421
|
const skills = join30(stage, "skills");
|
|
21327
|
-
if (
|
|
21422
|
+
if (existsSync23(skills) && !statSync11(skills).isDirectory())
|
|
21328
21423
|
throw new Error(`Kimi skills path is not a directory: ${skills}`);
|
|
21329
|
-
if (
|
|
21424
|
+
if (existsSync23(skills))
|
|
21330
21425
|
assertKimiSkillPolicies(skills);
|
|
21331
21426
|
const native = join30(stage, "kimi.plugin.json");
|
|
21332
21427
|
let supplied = {};
|
|
21333
|
-
if (
|
|
21428
|
+
if (existsSync23(native)) {
|
|
21334
21429
|
supplied = parseJson(native, "Kimi native manifest");
|
|
21335
21430
|
if (supplied.name !== undefined && supplied.name !== expectedName)
|
|
21336
21431
|
throw new Error(`Kimi native manifest name conflicts with ${expectedName}`);
|
|
@@ -21348,7 +21443,7 @@ function projectStagedKimi(stage, expectedName) {
|
|
|
21348
21443
|
}
|
|
21349
21444
|
const commands = prepareCommands(stage, typeof supplied.commands === "string" ? supplied.commands : undefined);
|
|
21350
21445
|
const mcpServers = collectMcpServers(stage, manifest, supplied);
|
|
21351
|
-
const nativeManifest = { name: expectedName, ...typeof manifest.version === "string" ? { version: manifest.version } : {}, ...typeof manifest.description === "string" ? { description: manifest.description } : {}, ...
|
|
21446
|
+
const nativeManifest = { name: expectedName, ...typeof manifest.version === "string" ? { version: manifest.version } : {}, ...typeof manifest.description === "string" ? { description: manifest.description } : {}, ...existsSync23(skills) ? { skills: "./skills/" } : {}, ...commands !== undefined ? { commands } : {}, ...mcpServers !== undefined ? { mcpServers } : {} };
|
|
21352
21447
|
writeFileSync8(native, JSON.stringify(nativeManifest, null, 2));
|
|
21353
21448
|
assertNoSymlinks4(stage);
|
|
21354
21449
|
}
|
|
@@ -21371,12 +21466,12 @@ function collectMcpServers(stage, manifest, supplied) {
|
|
|
21371
21466
|
};
|
|
21372
21467
|
add("native manifest", supplied.mcpServers);
|
|
21373
21468
|
const legacyNative = join30(stage, ".kimi-plugin", "plugin.json");
|
|
21374
|
-
if (
|
|
21469
|
+
if (existsSync23(legacyNative))
|
|
21375
21470
|
add(".kimi-plugin/plugin.json", parseJson(legacyNative, ".kimi-plugin/plugin.json").mcpServers);
|
|
21376
21471
|
add("root plugin manifest", manifest.mcpServers);
|
|
21377
21472
|
for (const file of [".mcp.json", "mcp.json"]) {
|
|
21378
21473
|
const path = join30(stage, file);
|
|
21379
|
-
if (!
|
|
21474
|
+
if (!existsSync23(path))
|
|
21380
21475
|
continue;
|
|
21381
21476
|
add(file, parseJson(path, file).mcpServers);
|
|
21382
21477
|
}
|
|
@@ -21384,14 +21479,14 @@ function collectMcpServers(stage, manifest, supplied) {
|
|
|
21384
21479
|
}
|
|
21385
21480
|
function prepareCommands(stage, supplied) {
|
|
21386
21481
|
const commands = join30(stage, "commands");
|
|
21387
|
-
if (
|
|
21482
|
+
if (existsSync23(commands) && !statSync11(commands).isDirectory())
|
|
21388
21483
|
throw new Error(`Kimi commands path is not a directory: ${commands}`);
|
|
21389
21484
|
const claude = join30(stage, ".claude", "commands");
|
|
21390
|
-
const selected = supplied === undefined ?
|
|
21485
|
+
const selected = supplied === undefined ? existsSync23(claude) ? "./.claude/commands/" : existsSync23(commands) ? "./commands/" : undefined : supplied.endsWith("/") ? supplied : `${supplied}/`;
|
|
21391
21486
|
if (selected === undefined)
|
|
21392
21487
|
return;
|
|
21393
21488
|
const dir = selected.startsWith("./.claude/") ? claude : commands;
|
|
21394
|
-
if (!
|
|
21489
|
+
if (!existsSync23(dir))
|
|
21395
21490
|
throw new Error(`Kimi native commands pointer has no directory: ${selected}`);
|
|
21396
21491
|
assertMarkdownCommandTree(dir);
|
|
21397
21492
|
if (!containsMarkdown(dir))
|
|
@@ -21401,7 +21496,7 @@ function prepareCommands(stage, supplied) {
|
|
|
21401
21496
|
function assertKimiSkillPolicies(dir) {
|
|
21402
21497
|
for (const name of readdirSync15(dir)) {
|
|
21403
21498
|
const path = join30(dir, name);
|
|
21404
|
-
const stat =
|
|
21499
|
+
const stat = lstatSync16(path);
|
|
21405
21500
|
if (stat.isDirectory())
|
|
21406
21501
|
assertKimiSkillPolicies(path);
|
|
21407
21502
|
else if (stat.isFile() && name === "SKILL.md") {
|
|
@@ -21434,7 +21529,7 @@ function openingFrontmatter2(raw, path) {
|
|
|
21434
21529
|
function assertMarkdownCommandTree(dir) {
|
|
21435
21530
|
for (const name of readdirSync15(dir)) {
|
|
21436
21531
|
const path = join30(dir, name);
|
|
21437
|
-
const stat =
|
|
21532
|
+
const stat = lstatSync16(path);
|
|
21438
21533
|
if (stat.isSymbolicLink())
|
|
21439
21534
|
throw new Error(`Kimi command source contains symlink: ${path}`);
|
|
21440
21535
|
if (stat.isDirectory())
|
|
@@ -21465,7 +21560,7 @@ function containsMarkdown(dir) {
|
|
|
21465
21560
|
});
|
|
21466
21561
|
}
|
|
21467
21562
|
function readSourceManifest(stage) {
|
|
21468
|
-
const file = [join30(stage, "plugin.json"), join30(stage, ".plugin", "plugin.json")].find(
|
|
21563
|
+
const file = [join30(stage, "plugin.json"), join30(stage, ".plugin", "plugin.json")].find(existsSync23);
|
|
21469
21564
|
if (file === undefined)
|
|
21470
21565
|
throw new Error("Kimi stage has no Agent Plugins manifest");
|
|
21471
21566
|
return parseJson(file, "Agent Plugins manifest");
|
|
@@ -21482,7 +21577,7 @@ function parseJson(path, label) {
|
|
|
21482
21577
|
}
|
|
21483
21578
|
function validateNativeIdentity(target, id) {
|
|
21484
21579
|
const file = join30(target, "kimi.plugin.json");
|
|
21485
|
-
if (!
|
|
21580
|
+
if (!existsSync23(file) || parseJson(file, "Kimi native manifest").name !== id)
|
|
21486
21581
|
throw new Error(`unowned Kimi managed plugin has no matching native manifest: ${target}`);
|
|
21487
21582
|
}
|
|
21488
21583
|
function readOwnership3(target) {
|
|
@@ -21514,7 +21609,7 @@ function rewriteOwnership(target, ownership) {
|
|
|
21514
21609
|
}
|
|
21515
21610
|
}
|
|
21516
21611
|
function sameTree3(left, right) {
|
|
21517
|
-
if (!
|
|
21612
|
+
if (!existsSync23(right))
|
|
21518
21613
|
return false;
|
|
21519
21614
|
const readBytes = readFileSync24;
|
|
21520
21615
|
const list = (root) => {
|
|
@@ -21525,7 +21620,7 @@ function sameTree3(left, right) {
|
|
|
21525
21620
|
continue;
|
|
21526
21621
|
const path = join30(dir, name);
|
|
21527
21622
|
const rel = prefix ? `${prefix}/${name}` : name;
|
|
21528
|
-
const stat =
|
|
21623
|
+
const stat = lstatSync16(path);
|
|
21529
21624
|
if (stat.isSymbolicLink())
|
|
21530
21625
|
throw new Error(`Kimi plugin contains symlink: ${path}`);
|
|
21531
21626
|
if (stat.isDirectory())
|
|
@@ -21543,14 +21638,14 @@ function sameTree3(left, right) {
|
|
|
21543
21638
|
}
|
|
21544
21639
|
function assertNoSymlinks4(root) {
|
|
21545
21640
|
const walk = (dir) => {
|
|
21546
|
-
const stat =
|
|
21641
|
+
const stat = lstatSync16(dir);
|
|
21547
21642
|
if (stat.isSymbolicLink())
|
|
21548
21643
|
throw new Error(`Kimi plugin contains symlink: ${dir}`);
|
|
21549
21644
|
if (!stat.isDirectory())
|
|
21550
21645
|
throw new Error(`Kimi plugin path is not a directory: ${dir}`);
|
|
21551
21646
|
for (const name of readdirSync15(dir)) {
|
|
21552
21647
|
const path = join30(dir, name);
|
|
21553
|
-
const child =
|
|
21648
|
+
const child = lstatSync16(path);
|
|
21554
21649
|
if (child.isSymbolicLink())
|
|
21555
21650
|
throw new Error(`Kimi plugin contains symlink: ${path}`);
|
|
21556
21651
|
if (child.isDirectory())
|
|
@@ -21562,7 +21657,7 @@ function assertNoSymlinks4(root) {
|
|
|
21562
21657
|
walk(root);
|
|
21563
21658
|
}
|
|
21564
21659
|
function moveAside2(target, root) {
|
|
21565
|
-
if (!
|
|
21660
|
+
if (!existsSync23(target))
|
|
21566
21661
|
return { commit: () => {}, rollback: () => {} };
|
|
21567
21662
|
mkdirSync8(root, { recursive: true });
|
|
21568
21663
|
const dir = mkdtempSync7(join30(root, ".plgnz-kimi-backup-"));
|
|
@@ -21575,7 +21670,7 @@ function moveAside2(target, root) {
|
|
|
21575
21670
|
}
|
|
21576
21671
|
function lstatIfPresent(path) {
|
|
21577
21672
|
try {
|
|
21578
|
-
return
|
|
21673
|
+
return lstatSync16(path);
|
|
21579
21674
|
} catch (error) {
|
|
21580
21675
|
if (error.code === "ENOENT")
|
|
21581
21676
|
return;
|
|
@@ -21591,7 +21686,7 @@ function assertManagedPath3(root, target) {
|
|
|
21591
21686
|
for (const part of selected.slice(base.length).split("/").filter(Boolean)) {
|
|
21592
21687
|
if (lstatIfPresent(current) === undefined)
|
|
21593
21688
|
break;
|
|
21594
|
-
const stat =
|
|
21689
|
+
const stat = lstatSync16(current);
|
|
21595
21690
|
if (stat.isSymbolicLink())
|
|
21596
21691
|
throw new Error(`Kimi managed path component is a symlink: ${current}`);
|
|
21597
21692
|
if (!stat.isDirectory())
|
|
@@ -21632,7 +21727,7 @@ function currentKimiVersion(exitCode, version) {
|
|
|
21632
21727
|
}
|
|
21633
21728
|
function resolveKimiBinary() {
|
|
21634
21729
|
const binary = kimiBinaryPath();
|
|
21635
|
-
if (!
|
|
21730
|
+
if (!existsSync23(binary))
|
|
21636
21731
|
throw new Error(`current Kimi Code binary not found: ${binary}`);
|
|
21637
21732
|
const probed = readKimiBinaryVersion(binary);
|
|
21638
21733
|
if (currentKimiVersion(probed.exitCode, probed.version) === undefined)
|
|
@@ -21842,11 +21937,11 @@ var kimiLifecycle = {
|
|
|
21842
21937
|
const managed = managedPluginPath(projection.packageName);
|
|
21843
21938
|
const registryFile = join30(pluginsDir2(), "installed.json");
|
|
21844
21939
|
assertKimiManaged(projection.packageName, managed, registryFile);
|
|
21845
|
-
if (
|
|
21940
|
+
if (existsSync23(managed))
|
|
21846
21941
|
cpSync7(managed, join30(rollbackReference, "managed"), { recursive: true });
|
|
21847
|
-
const priorRow =
|
|
21942
|
+
const priorRow = existsSync23(registryFile) ? readRegistry2(registryFile).plugins.find((row) => row.id === projection.packageName) : undefined;
|
|
21848
21943
|
if (priorRow === undefined) {
|
|
21849
|
-
if (!
|
|
21944
|
+
if (!existsSync23(registryFile))
|
|
21850
21945
|
writeFileSync8(join30(rollbackReference, "registry.absent"), "");
|
|
21851
21946
|
} else
|
|
21852
21947
|
writeFileSync8(join30(rollbackReference, "registry.row.json"), JSON.stringify(priorRow));
|
|
@@ -21874,10 +21969,10 @@ var kimiLifecycle = {
|
|
|
21874
21969
|
const managed = managedPluginPath(id);
|
|
21875
21970
|
const registryFile = join30(pluginsDir2(), "installed.json");
|
|
21876
21971
|
assertKimiManaged(id, managed, registryFile);
|
|
21877
|
-
const priorRow =
|
|
21878
|
-
const marker =
|
|
21972
|
+
const priorRow = existsSync23(registryFile) ? readRegistry2(registryFile).plugins.find((row) => row.id === id) : undefined;
|
|
21973
|
+
const marker = existsSync23(managed) ? readOwnership3(managed) : null;
|
|
21879
21974
|
const legacyMarker = marker !== null && !marker.pluginId.includes("@") && prepared.handle.nativeId.startsWith(`${marker.pluginId}@`);
|
|
21880
|
-
if (
|
|
21975
|
+
if (existsSync23(managed) && priorRow?.enabled === true && sameRoot(priorRow.root, managed) && sameTree3(prepared.stagingRoot, managed)) {
|
|
21881
21976
|
if (legacyMarker) {
|
|
21882
21977
|
rewriteOwnership(managed, {
|
|
21883
21978
|
...marker,
|
|
@@ -21888,12 +21983,12 @@ var kimiLifecycle = {
|
|
|
21888
21983
|
}
|
|
21889
21984
|
return { receiptId: `kimi-apply:${prepared.handle.attemptId}:${prepared.handle.operationId}`, changed: false };
|
|
21890
21985
|
}
|
|
21891
|
-
const registryBefore =
|
|
21986
|
+
const registryBefore = existsSync23(registryFile) ? readFileSync24(registryFile, "utf8") : undefined;
|
|
21892
21987
|
const backup = moveAside2(managed, dirname10(managed));
|
|
21893
21988
|
try {
|
|
21894
21989
|
await nativeInstall(prepared.stagingRoot, kimiRootPath(), resolveKimiBinary());
|
|
21895
21990
|
const row = readRegistry2(registryFile).plugins.find((candidate) => candidate.id === id);
|
|
21896
|
-
if (row === undefined || row.enabled !== true || !sameRoot(row.root, managed) || !
|
|
21991
|
+
if (row === undefined || row.enabled !== true || !sameRoot(row.root, managed) || !existsSync23(managed) || !sameTree3(prepared.stagingRoot, managed)) {
|
|
21897
21992
|
throw new Error(`Kimi native install did not produce enabled managed plugin ${id}`);
|
|
21898
21993
|
}
|
|
21899
21994
|
backup.commit();
|
|
@@ -21916,7 +22011,7 @@ var kimiLifecycle = {
|
|
|
21916
22011
|
const reference = handle.rollbackReference;
|
|
21917
22012
|
rmSync8(managed, { recursive: true, force: true });
|
|
21918
22013
|
const backup = join30(reference, "managed");
|
|
21919
|
-
if (
|
|
22014
|
+
if (existsSync23(backup))
|
|
21920
22015
|
cpSync7(backup, managed, { recursive: true });
|
|
21921
22016
|
restoreRegistryRow(registryFile, id, reference);
|
|
21922
22017
|
return { receiptId: `kimi-rollback:${handle.attemptId}:${handle.operationId}`, changed: true };
|
|
@@ -21924,7 +22019,7 @@ var kimiLifecycle = {
|
|
|
21924
22019
|
cleanup: async (reference) => {
|
|
21925
22020
|
const root = join30(pluginsDir2(), ".plgnz-kimi-lifecycle");
|
|
21926
22021
|
rmSync8(join30(root, safeSegment(reference.attemptId)), { recursive: true, force: true });
|
|
21927
|
-
if (
|
|
22022
|
+
if (existsSync23(root) && readdirSync15(root).length === 0)
|
|
21928
22023
|
rmSync8(root, { recursive: true, force: true });
|
|
21929
22024
|
return { cleanupId: `kimi-cleanup:${reference.attemptId}:${reference.operationId}`, completed: true };
|
|
21930
22025
|
}
|
|
@@ -21948,8 +22043,8 @@ function assertKimiManaged(packageName, managed, registryFile) {
|
|
|
21948
22043
|
function kimiReadback(handle) {
|
|
21949
22044
|
const managed = managedPluginPath(handle.packageName);
|
|
21950
22045
|
const registryFile = join30(pluginsDir2(), "installed.json");
|
|
21951
|
-
const row =
|
|
21952
|
-
const present = row !== undefined &&
|
|
22046
|
+
const row = existsSync23(registryFile) ? readRegistry2(registryFile).plugins.find((candidate) => candidate.id === handle.packageName) : undefined;
|
|
22047
|
+
const present = row !== undefined && existsSync23(managed) && sameRoot(row.root, managed);
|
|
21953
22048
|
const enabled = present && row?.enabled === true;
|
|
21954
22049
|
const digest = present ? fingerprintTree(managed) : null;
|
|
21955
22050
|
return {
|
|
@@ -21970,7 +22065,7 @@ function kimiReadback(handle) {
|
|
|
21970
22065
|
}
|
|
21971
22066
|
function probeKimiBinary() {
|
|
21972
22067
|
const binary = kimiBinaryPath();
|
|
21973
|
-
if (!
|
|
22068
|
+
if (!existsSync23(binary))
|
|
21974
22069
|
return { kind: "unknown" };
|
|
21975
22070
|
const probed = readKimiBinaryVersion(binary);
|
|
21976
22071
|
const version = currentKimiVersion(probed.exitCode, probed.version);
|
|
@@ -22113,12 +22208,12 @@ function unexposed(phase) {
|
|
|
22113
22208
|
}
|
|
22114
22209
|
|
|
22115
22210
|
// src/hosts/cursor-writer.ts
|
|
22116
|
-
import { accessSync as accessSync5, constants as constants5, cpSync as cpSync8, existsSync as
|
|
22211
|
+
import { accessSync as accessSync5, constants as constants5, cpSync as cpSync8, existsSync as existsSync24, lstatSync as lstatSync18, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync8, readFileSync as readFileSync26, readdirSync as readdirSync17, renameSync as renameSync6, rmSync as rmSync9, statSync as statSync12, writeFileSync as writeFileSync9 } from "node:fs";
|
|
22117
22212
|
import { delimiter as delimiter4, join as join32, resolve as resolve19 } from "node:path";
|
|
22118
22213
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
22119
22214
|
|
|
22120
22215
|
// src/hosts/cursor-adoption.ts
|
|
22121
|
-
import { accessSync as accessSync4, constants as constants4, lstatSync as
|
|
22216
|
+
import { accessSync as accessSync4, constants as constants4, lstatSync as lstatSync17, readFileSync as readFileSync25, readdirSync as readdirSync16 } from "node:fs";
|
|
22122
22217
|
import { dirname as dirname11, join as join31, resolve as resolve18 } from "node:path";
|
|
22123
22218
|
var MARKER5 = ".plgnz-install.json";
|
|
22124
22219
|
function proveCursorLegacyAdoption(request) {
|
|
@@ -22279,7 +22374,7 @@ function readTree(root) {
|
|
|
22279
22374
|
const tree = new Map;
|
|
22280
22375
|
const walk = (dir, prefix) => {
|
|
22281
22376
|
for (const name of readdirSync16(dir).sort()) {
|
|
22282
|
-
const path = join31(dir, name), relative = prefix === "" ? name : `${prefix}/${name}`, stat =
|
|
22377
|
+
const path = join31(dir, name), relative = prefix === "" ? name : `${prefix}/${name}`, stat = lstatSync17(path);
|
|
22283
22378
|
if (stat.isSymbolicLink())
|
|
22284
22379
|
fail3(`symlink resource: ${relative}`);
|
|
22285
22380
|
if (stat.isDirectory()) {
|
|
@@ -22297,7 +22392,7 @@ function readTree(root) {
|
|
|
22297
22392
|
function safeAncestors(root, allowMissing) {
|
|
22298
22393
|
for (let path = resolve18(root);; path = dirname11(path)) {
|
|
22299
22394
|
if (!allowMissing || present(path)) {
|
|
22300
|
-
const stat =
|
|
22395
|
+
const stat = lstatSync17(path);
|
|
22301
22396
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
22302
22397
|
fail3(`unsafe directory: ${path}`);
|
|
22303
22398
|
}
|
|
@@ -22349,7 +22444,7 @@ function parseManifest2(entry) {
|
|
|
22349
22444
|
}
|
|
22350
22445
|
function present(path) {
|
|
22351
22446
|
try {
|
|
22352
|
-
|
|
22447
|
+
lstatSync17(path);
|
|
22353
22448
|
return true;
|
|
22354
22449
|
} catch (error) {
|
|
22355
22450
|
if (error.code === "ENOENT")
|
|
@@ -22410,8 +22505,8 @@ var cursorWriter = {
|
|
|
22410
22505
|
if (marker !== null && (differentSource || !matchesOwnership(marker.pluginId, id, ownershipId))) {
|
|
22411
22506
|
throw new Error(`Cursor local plugin ${id} belongs to another source; refusing to replace it`);
|
|
22412
22507
|
}
|
|
22413
|
-
const identicalUnowned =
|
|
22414
|
-
if (
|
|
22508
|
+
const identicalUnowned = existsSync24(target) && marker === null && sameTree4(stage, target);
|
|
22509
|
+
if (existsSync24(target) && marker === null && !identicalUnowned) {
|
|
22415
22510
|
if (!opts?.adoptExisting)
|
|
22416
22511
|
throw new Error(`Cursor local plugin ${id} is unowned and differs from the staged representation; pass --adopt-existing to take ownership explicitly`);
|
|
22417
22512
|
validateExistingIdentity(target, id, sourceVersion(plugin.dir));
|
|
@@ -22430,7 +22525,7 @@ var cursorWriter = {
|
|
|
22430
22525
|
}
|
|
22431
22526
|
},
|
|
22432
22527
|
async pin(plugin, opts) {
|
|
22433
|
-
if (plugin.path === undefined || !
|
|
22528
|
+
if (plugin.path === undefined || !existsSync24(plugin.path))
|
|
22434
22529
|
return { changes: [], refusals: [] };
|
|
22435
22530
|
return pinPluginMcpFiles(plugin.path, mcpCandidates4(), opts);
|
|
22436
22531
|
},
|
|
@@ -22464,7 +22559,7 @@ function projectCommandsToSkills(stage) {
|
|
|
22464
22559
|
throw new Error(`Cursor command projection collision: ${command.name}`);
|
|
22465
22560
|
seen.add(command.name);
|
|
22466
22561
|
const target = join32(stage, "skills", command.name, "SKILL.md");
|
|
22467
|
-
if (
|
|
22562
|
+
if (existsSync24(target))
|
|
22468
22563
|
throw new Error(`Cursor command collides with an existing skill: ${command.name}`);
|
|
22469
22564
|
mkdirSync9(join32(stage, "skills", command.name), { recursive: true });
|
|
22470
22565
|
const body = command.body.endsWith(`
|
|
@@ -22482,13 +22577,13 @@ ${body}`);
|
|
|
22482
22577
|
}
|
|
22483
22578
|
}
|
|
22484
22579
|
function hasCommands(root) {
|
|
22485
|
-
return
|
|
22580
|
+
return existsSync24(join32(root, "commands")) || existsSync24(join32(root, ".claude", "commands"));
|
|
22486
22581
|
}
|
|
22487
22582
|
function ensureCursorManifest(stage, expectedName) {
|
|
22488
22583
|
const cursorManifest = join32(stage, ".cursor-plugin", "plugin.json");
|
|
22489
|
-
if (
|
|
22584
|
+
if (existsSync24(cursorManifest))
|
|
22490
22585
|
return;
|
|
22491
|
-
const source = manifestCandidates(stage).find(
|
|
22586
|
+
const source = manifestCandidates(stage).find(existsSync24);
|
|
22492
22587
|
if (source === undefined)
|
|
22493
22588
|
throw new Error("Cursor stage has no Agent Plugins manifest");
|
|
22494
22589
|
mkdirSync9(join32(stage, ".cursor-plugin"), { recursive: true });
|
|
@@ -22501,7 +22596,7 @@ function validateStage2(stage, expectedName) {
|
|
|
22501
22596
|
const native = parseManifest3(join32(stage, ".cursor-plugin", "plugin.json"));
|
|
22502
22597
|
if (native.name !== expectedName)
|
|
22503
22598
|
throw new Error(`Cursor manifest identity does not match ${expectedName}`);
|
|
22504
|
-
const canonicalPath = manifestCandidates(stage).find(
|
|
22599
|
+
const canonicalPath = manifestCandidates(stage).find(existsSync24);
|
|
22505
22600
|
if (canonicalPath !== undefined) {
|
|
22506
22601
|
const canonical = parseManifest3(canonicalPath);
|
|
22507
22602
|
if (native.name !== canonical.name || canonical.version !== undefined && native.version !== canonical.version) {
|
|
@@ -22509,14 +22604,14 @@ function validateStage2(stage, expectedName) {
|
|
|
22509
22604
|
}
|
|
22510
22605
|
}
|
|
22511
22606
|
const skills = join32(stage, "skills");
|
|
22512
|
-
if (
|
|
22607
|
+
if (existsSync24(skills) && !statSync12(skills).isDirectory())
|
|
22513
22608
|
throw new Error("Cursor stage skills path is not a directory");
|
|
22514
22609
|
}
|
|
22515
22610
|
function manifestCandidates(root) {
|
|
22516
22611
|
return [join32(root, ".claude-plugin", "plugin.json"), join32(root, "plugin.json"), join32(root, ".plugin", "plugin.json")];
|
|
22517
22612
|
}
|
|
22518
22613
|
function sourceVersion(root) {
|
|
22519
|
-
const manifest = [join32(root, ".cursor-plugin", "plugin.json"), ...manifestCandidates(root)].find(
|
|
22614
|
+
const manifest = [join32(root, ".cursor-plugin", "plugin.json"), ...manifestCandidates(root)].find(existsSync24);
|
|
22520
22615
|
return manifest === undefined ? undefined : parseManifest3(manifest).version;
|
|
22521
22616
|
}
|
|
22522
22617
|
function parseManifest3(path) {
|
|
@@ -22537,7 +22632,7 @@ function parseManifest3(path) {
|
|
|
22537
22632
|
}
|
|
22538
22633
|
function validateExistingIdentity(target, expectedName, expectedVersion) {
|
|
22539
22634
|
const manifest = join32(target, ".cursor-plugin", "plugin.json");
|
|
22540
|
-
if (!
|
|
22635
|
+
if (!existsSync24(manifest))
|
|
22541
22636
|
throw new Error(`unowned Cursor local plugin has no native manifest: ${target}`);
|
|
22542
22637
|
const parsed = parseManifest3(manifest);
|
|
22543
22638
|
if (parsed.name !== expectedName || parsed.version !== expectedVersion)
|
|
@@ -22545,7 +22640,7 @@ function validateExistingIdentity(target, expectedName, expectedVersion) {
|
|
|
22545
22640
|
}
|
|
22546
22641
|
function readOwnership4(target) {
|
|
22547
22642
|
const marker = join32(target, OWNERSHIP3);
|
|
22548
|
-
if (!
|
|
22643
|
+
if (!existsSync24(marker))
|
|
22549
22644
|
return null;
|
|
22550
22645
|
try {
|
|
22551
22646
|
const value = JSON.parse(readFileSync26(marker, "utf8"));
|
|
@@ -22589,7 +22684,7 @@ function ownsNativeDirectory(markerId, nativeId) {
|
|
|
22589
22684
|
return markerId.startsWith(prefix) && validIdentity2(markerId.slice(prefix.length));
|
|
22590
22685
|
}
|
|
22591
22686
|
function activate3(stage, target, root) {
|
|
22592
|
-
if (!
|
|
22687
|
+
if (!existsSync24(target)) {
|
|
22593
22688
|
renameSync6(stage, target);
|
|
22594
22689
|
return { commit: () => {} };
|
|
22595
22690
|
}
|
|
@@ -22606,7 +22701,7 @@ function activate3(stage, target, root) {
|
|
|
22606
22701
|
return { commit: () => rmSync9(backupRoot, { recursive: true, force: true }) };
|
|
22607
22702
|
}
|
|
22608
22703
|
function sameTree4(left, right) {
|
|
22609
|
-
if (!
|
|
22704
|
+
if (!existsSync24(right))
|
|
22610
22705
|
return false;
|
|
22611
22706
|
const entries = (root) => {
|
|
22612
22707
|
const out = [];
|
|
@@ -22616,7 +22711,7 @@ function sameTree4(left, right) {
|
|
|
22616
22711
|
continue;
|
|
22617
22712
|
const path = join32(dir, name);
|
|
22618
22713
|
const relative = prefix === "" ? name : `${prefix}/${name}`;
|
|
22619
|
-
const stat =
|
|
22714
|
+
const stat = lstatSync18(path);
|
|
22620
22715
|
if (stat.isSymbolicLink())
|
|
22621
22716
|
throw new Error(`Cursor managed plugin contains symlink: ${path}`);
|
|
22622
22717
|
if (stat.isDirectory())
|
|
@@ -22643,15 +22738,15 @@ function assertManagedDirectory(root, target) {
|
|
|
22643
22738
|
throw new Error(`Cursor managed path escapes its store: ${target}`);
|
|
22644
22739
|
let current = resolvedRoot;
|
|
22645
22740
|
for (const part of resolvedTarget.slice(resolvedRoot.length).split("/").filter(Boolean)) {
|
|
22646
|
-
if (
|
|
22741
|
+
if (existsSync24(current))
|
|
22647
22742
|
assertDirectoryNotLink(current);
|
|
22648
22743
|
current = join32(current, part);
|
|
22649
22744
|
}
|
|
22650
|
-
if (
|
|
22745
|
+
if (existsSync24(current))
|
|
22651
22746
|
assertDirectoryNotLink(current);
|
|
22652
22747
|
}
|
|
22653
22748
|
function assertDirectoryNotLink(path) {
|
|
22654
|
-
const stat =
|
|
22749
|
+
const stat = lstatSync18(path);
|
|
22655
22750
|
if (stat.isSymbolicLink())
|
|
22656
22751
|
throw new Error(`Cursor managed path component is a symlink: ${path}`);
|
|
22657
22752
|
if (!stat.isDirectory())
|
|
@@ -22659,14 +22754,14 @@ function assertDirectoryNotLink(path) {
|
|
|
22659
22754
|
}
|
|
22660
22755
|
function assertNoSymlinks5(root) {
|
|
22661
22756
|
const walk = (dir) => {
|
|
22662
|
-
const stat =
|
|
22757
|
+
const stat = lstatSync18(dir);
|
|
22663
22758
|
if (stat.isSymbolicLink())
|
|
22664
22759
|
throw new Error(`Cursor plugin source contains symlink: ${dir}`);
|
|
22665
22760
|
if (!stat.isDirectory())
|
|
22666
22761
|
throw new Error(`Cursor plugin source is not a directory: ${dir}`);
|
|
22667
22762
|
for (const name of readdirSync17(dir)) {
|
|
22668
22763
|
const path = join32(dir, name);
|
|
22669
|
-
const entry =
|
|
22764
|
+
const entry = lstatSync18(path);
|
|
22670
22765
|
if (entry.isSymbolicLink())
|
|
22671
22766
|
throw new Error(`Cursor plugin source contains symlink: ${path}`);
|
|
22672
22767
|
if (entry.isDirectory())
|
|
@@ -22866,7 +22961,7 @@ var cursorLifecycleDefinition = {
|
|
|
22866
22961
|
const handle = prepared.handle;
|
|
22867
22962
|
const target = managedPluginDir(handle.target.instance, handle.nativeId);
|
|
22868
22963
|
refuseForeignScope(target, handle.scopeId, handle.nativeId);
|
|
22869
|
-
if (
|
|
22964
|
+
if (existsSync24(target) && fingerprintTree(target) === fingerprintTree(prepared.stagingRoot)) {
|
|
22870
22965
|
return { receiptId: receipt("apply", handle), changed: false };
|
|
22871
22966
|
}
|
|
22872
22967
|
const root = localDir(handle.target.instance);
|
|
@@ -22887,7 +22982,7 @@ var cursorLifecycleDefinition = {
|
|
|
22887
22982
|
async retire(prepared) {
|
|
22888
22983
|
const handle = prepared.handle;
|
|
22889
22984
|
const target = managedPluginDir(handle.target.instance, handle.nativeId);
|
|
22890
|
-
if (!
|
|
22985
|
+
if (!existsSync24(target))
|
|
22891
22986
|
return { receiptId: receipt("retire", handle), changed: false };
|
|
22892
22987
|
refuseForeignScope(target, handle.scopeId, handle.nativeId);
|
|
22893
22988
|
rmSync9(target, { recursive: true, force: true });
|
|
@@ -22909,15 +23004,15 @@ var cursorLifecycleDefinition = {
|
|
|
22909
23004
|
const root = localDir(handle.target.instance);
|
|
22910
23005
|
const target = managedPluginDir(handle.target.instance, handle.nativeId);
|
|
22911
23006
|
const backup = join32(handle.rollbackReference, "active");
|
|
22912
|
-
const restore = prior.presence === "present" &&
|
|
23007
|
+
const restore = prior.presence === "present" && existsSync24(backup);
|
|
22913
23008
|
if (!restore) {
|
|
22914
|
-
if (prior.presence === "present" || !
|
|
23009
|
+
if (prior.presence === "present" || !existsSync24(target))
|
|
22915
23010
|
return { receiptId: receipt("rollback", handle), changed: false };
|
|
22916
23011
|
refuseForeignScope(target, handle.scopeId, handle.nativeId);
|
|
22917
23012
|
rmSync9(target, { recursive: true, force: true });
|
|
22918
23013
|
return { receiptId: receipt("rollback", handle), changed: true };
|
|
22919
23014
|
}
|
|
22920
|
-
if (
|
|
23015
|
+
if (existsSync24(target)) {
|
|
22921
23016
|
refuseForeignScope(target, handle.scopeId, handle.nativeId);
|
|
22922
23017
|
if (fingerprintTree(target) === fingerprintTree(backup))
|
|
22923
23018
|
return { receiptId: receipt("rollback", handle), changed: false };
|
|
@@ -22969,7 +23064,7 @@ function probeCursorVersion() {
|
|
|
22969
23064
|
function locateCursorProbeBinary() {
|
|
22970
23065
|
const override = process.env["OPEN_PLUGIN_CURSOR_BIN"];
|
|
22971
23066
|
if (override !== undefined) {
|
|
22972
|
-
if (override.length === 0 || !
|
|
23067
|
+
if (override.length === 0 || !existsSync24(override))
|
|
22973
23068
|
return { kind: "refused" };
|
|
22974
23069
|
return { kind: "path", path: override };
|
|
22975
23070
|
}
|
|
@@ -23012,7 +23107,7 @@ function decodeStdout(bytes) {
|
|
|
23012
23107
|
}
|
|
23013
23108
|
function inventoryLocalStore(target) {
|
|
23014
23109
|
const root = localDir(target.instance);
|
|
23015
|
-
if (!
|
|
23110
|
+
if (!existsSync24(root))
|
|
23016
23111
|
return { target, installations: [] };
|
|
23017
23112
|
const installations = [];
|
|
23018
23113
|
for (const entry of readdirSync17(root)) {
|
|
@@ -23033,7 +23128,7 @@ function inventoryLocalStore(target) {
|
|
|
23033
23128
|
}
|
|
23034
23129
|
function readLocalInstallation(entry, dir) {
|
|
23035
23130
|
const manifestPath = join32(dir, ".cursor-plugin", "plugin.json");
|
|
23036
|
-
if (!
|
|
23131
|
+
if (!existsSync24(manifestPath))
|
|
23037
23132
|
return;
|
|
23038
23133
|
let manifest;
|
|
23039
23134
|
let marker = null;
|
|
@@ -23135,7 +23230,7 @@ function applyRecordedPins(stage, pins) {
|
|
|
23135
23230
|
for (const pin of pins) {
|
|
23136
23231
|
let found = false;
|
|
23137
23232
|
for (const file of [join32(stage, ".mcp.json"), join32(stage, "mcp.json")]) {
|
|
23138
|
-
if (!
|
|
23233
|
+
if (!existsSync24(file))
|
|
23139
23234
|
continue;
|
|
23140
23235
|
const parsed = JSON.parse(readFileSync26(file, "utf8"));
|
|
23141
23236
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
@@ -23164,7 +23259,7 @@ function projectReadback(identity) {
|
|
|
23164
23259
|
inactiveMetadata: retainedResource(instance, identity.nativeId, "metadata")
|
|
23165
23260
|
};
|
|
23166
23261
|
const dir = join32(localDir(instance), identity.nativeId);
|
|
23167
|
-
if (!
|
|
23262
|
+
if (!existsSync24(dir)) {
|
|
23168
23263
|
return {
|
|
23169
23264
|
adapterId: identity.adapterId,
|
|
23170
23265
|
target: identity.target,
|
|
@@ -23200,9 +23295,9 @@ function projectReadback(identity) {
|
|
|
23200
23295
|
}
|
|
23201
23296
|
function retainedResource(instance, nativeId, kind) {
|
|
23202
23297
|
const dir = retentionDir(instance, nativeId, kind);
|
|
23203
|
-
if (!
|
|
23298
|
+
if (!existsSync24(dir))
|
|
23204
23299
|
return { state: "absent", fingerprint: null };
|
|
23205
|
-
const stat =
|
|
23300
|
+
const stat = lstatSync18(dir);
|
|
23206
23301
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
23207
23302
|
throw new Error(`Cursor retained ${kind} is not a directory: ${dir}`);
|
|
23208
23303
|
return { state: "present", fingerprint: fingerprintTree(dir) };
|
|
@@ -23220,7 +23315,7 @@ function captureRollback2(instance, attemptId, operationId, nativeId, prior) {
|
|
|
23220
23315
|
rmSync9(reference, { recursive: true, force: true });
|
|
23221
23316
|
mkdirSync9(reference, { recursive: true });
|
|
23222
23317
|
const active = join32(localDir(instance), nativeId);
|
|
23223
|
-
if (
|
|
23318
|
+
if (existsSync24(active))
|
|
23224
23319
|
cpSync8(active, join32(reference, "active"), { recursive: true });
|
|
23225
23320
|
writeFileSync9(join32(reference, "prior.json"), `${JSON.stringify(prior)}
|
|
23226
23321
|
`);
|
|
@@ -23253,7 +23348,7 @@ function absentRoute(action, route) {
|
|
|
23253
23348
|
}
|
|
23254
23349
|
}
|
|
23255
23350
|
function refuseForeignScope(target, scopeId, nativeId) {
|
|
23256
|
-
if (!
|
|
23351
|
+
if (!existsSync24(target))
|
|
23257
23352
|
return;
|
|
23258
23353
|
const marker = readOwnership4(target);
|
|
23259
23354
|
if (marker === null || !ownsNativeDirectory(marker.pluginId, nativeId)) {
|
|
@@ -23282,7 +23377,7 @@ function receipt(kind, handle) {
|
|
|
23282
23377
|
|
|
23283
23378
|
// src/hosts/omp-writer.ts
|
|
23284
23379
|
init_omp_hooks();
|
|
23285
|
-
import { cpSync as cpSync9, existsSync as
|
|
23380
|
+
import { cpSync as cpSync9, existsSync as existsSync25, lstatSync as lstatSync19, mkdirSync as mkdirSync10, mkdtempSync as mkdtempSync9, readFileSync as readFileSync27, readdirSync as readdirSync18, readlinkSync as readlinkSync2, renameSync as renameSync7, rmSync as rmSync10, symlinkSync, writeFileSync as writeFileSync10 } from "node:fs";
|
|
23286
23381
|
import { dirname as dirname12, join as join33, resolve as resolve20 } from "node:path";
|
|
23287
23382
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
23288
23383
|
var MARKER6 = ".plgnz-install.json";
|
|
@@ -23378,7 +23473,7 @@ var ompWriter = {
|
|
|
23378
23473
|
}
|
|
23379
23474
|
},
|
|
23380
23475
|
async pin(plugin, opts) {
|
|
23381
|
-
if (plugin.path === undefined || !
|
|
23476
|
+
if (plugin.path === undefined || !existsSync25(plugin.path))
|
|
23382
23477
|
return { changes: [], refusals: [] };
|
|
23383
23478
|
return pinPluginMcpFiles(plugin.path, mcpCandidates5(), opts);
|
|
23384
23479
|
},
|
|
@@ -23472,7 +23567,7 @@ function registryInstallPaths(registry) {
|
|
|
23472
23567
|
}
|
|
23473
23568
|
function findOwned(id) {
|
|
23474
23569
|
const root = join33(pluginsDir3(), MANAGED);
|
|
23475
|
-
if (!
|
|
23570
|
+
if (!existsSync25(root))
|
|
23476
23571
|
return null;
|
|
23477
23572
|
for (const name of readdirSync18(root)) {
|
|
23478
23573
|
const path = join33(root, name);
|
|
@@ -23490,7 +23585,7 @@ function assertOwnedLink(path, target, owned) {
|
|
|
23490
23585
|
}
|
|
23491
23586
|
function lstatExists(path) {
|
|
23492
23587
|
try {
|
|
23493
|
-
|
|
23588
|
+
lstatSync19(path);
|
|
23494
23589
|
return true;
|
|
23495
23590
|
} catch {
|
|
23496
23591
|
return false;
|
|
@@ -23498,7 +23593,7 @@ function lstatExists(path) {
|
|
|
23498
23593
|
}
|
|
23499
23594
|
function linkPointsTo(path, target) {
|
|
23500
23595
|
try {
|
|
23501
|
-
return
|
|
23596
|
+
return lstatSync19(path).isSymbolicLink() && resolve20(dirname12(path), readlinkSync2(path)) === resolve20(target);
|
|
23502
23597
|
} catch {
|
|
23503
23598
|
return false;
|
|
23504
23599
|
}
|
|
@@ -23538,7 +23633,7 @@ function mkdirSafe(path) {
|
|
|
23538
23633
|
const parentBoundary = dirname12(boundary);
|
|
23539
23634
|
for (let current = target;; current = dirname12(current)) {
|
|
23540
23635
|
if (lstatExists(current)) {
|
|
23541
|
-
const stat =
|
|
23636
|
+
const stat = lstatSync19(current);
|
|
23542
23637
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
23543
23638
|
throw new Error(`OMP managed path is unsafe: ${current}`);
|
|
23544
23639
|
}
|
|
@@ -23548,7 +23643,7 @@ function mkdirSafe(path) {
|
|
|
23548
23643
|
mkdirSync10(path, { recursive: true });
|
|
23549
23644
|
let current = target;
|
|
23550
23645
|
while (true) {
|
|
23551
|
-
const stat =
|
|
23646
|
+
const stat = lstatSync19(current);
|
|
23552
23647
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
23553
23648
|
throw new Error(`OMP managed path is unsafe: ${current}`);
|
|
23554
23649
|
if (current === boundary)
|
|
@@ -23564,7 +23659,7 @@ function assertExistingDirectoryTree(boundaryPath, targetPath, label) {
|
|
|
23564
23659
|
for (let current = target;; current = dirname12(current)) {
|
|
23565
23660
|
if (!lstatExists(current))
|
|
23566
23661
|
throw new Error(`${label} has no safe native copy`);
|
|
23567
|
-
const stat =
|
|
23662
|
+
const stat = lstatSync19(current);
|
|
23568
23663
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
23569
23664
|
throw new Error(`${label} contains a symlink or non-directory component: ${current}`);
|
|
23570
23665
|
if (current === boundary)
|
|
@@ -23572,7 +23667,7 @@ function assertExistingDirectoryTree(boundaryPath, targetPath, label) {
|
|
|
23572
23667
|
}
|
|
23573
23668
|
}
|
|
23574
23669
|
function sameTree5(left, right) {
|
|
23575
|
-
if (!
|
|
23670
|
+
if (!existsSync25(right))
|
|
23576
23671
|
return false;
|
|
23577
23672
|
const bytes = readFileSync27;
|
|
23578
23673
|
const list = (root) => {
|
|
@@ -23583,7 +23678,7 @@ function sameTree5(left, right) {
|
|
|
23583
23678
|
continue;
|
|
23584
23679
|
const path = join33(dir, name);
|
|
23585
23680
|
const rel = prefix ? `${prefix}/${name}` : name;
|
|
23586
|
-
const stat =
|
|
23681
|
+
const stat = lstatSync19(path);
|
|
23587
23682
|
if (stat.isSymbolicLink())
|
|
23588
23683
|
throw new Error(`OMP managed plugin contains symlink: ${path}`);
|
|
23589
23684
|
if (stat.isDirectory())
|
|
@@ -23601,7 +23696,7 @@ function sameTree5(left, right) {
|
|
|
23601
23696
|
}
|
|
23602
23697
|
function ownership2(path) {
|
|
23603
23698
|
const marker = join33(path, MARKER6);
|
|
23604
|
-
if (!
|
|
23699
|
+
if (!existsSync25(marker))
|
|
23605
23700
|
return null;
|
|
23606
23701
|
const value = readDoc(marker, {}, "ownership marker");
|
|
23607
23702
|
if (typeof value.source !== "string" || typeof value.pluginId !== "string" || typeof value.fingerprint !== "string" || typeof value.packageName !== "string")
|
|
@@ -23620,7 +23715,7 @@ function ownership2(path) {
|
|
|
23620
23715
|
};
|
|
23621
23716
|
}
|
|
23622
23717
|
function readDoc(path, fallback, label) {
|
|
23623
|
-
if (!
|
|
23718
|
+
if (!existsSync25(path))
|
|
23624
23719
|
return fallback;
|
|
23625
23720
|
try {
|
|
23626
23721
|
const value = JSON.parse(readFileSync27(path, "utf8"));
|
|
@@ -23650,7 +23745,7 @@ function writeDoc(path, value) {
|
|
|
23650
23745
|
writeFileSync10(path, JSON.stringify(value, null, 2));
|
|
23651
23746
|
}
|
|
23652
23747
|
function snapshot(path) {
|
|
23653
|
-
return
|
|
23748
|
+
return existsSync25(path) ? readFileSync27(path, "utf8") : undefined;
|
|
23654
23749
|
}
|
|
23655
23750
|
function restore2(path, value) {
|
|
23656
23751
|
if (value === undefined)
|
|
@@ -23872,7 +23967,7 @@ async function observeInventory(target) {
|
|
|
23872
23967
|
return { target, installations: omp.listInstalled().map((plugin) => installationOf(plugin)) };
|
|
23873
23968
|
}
|
|
23874
23969
|
function installationOf(plugin) {
|
|
23875
|
-
const path = plugin.path !== undefined &&
|
|
23970
|
+
const path = plugin.path !== undefined && existsSync25(plugin.path) ? resolve20(plugin.path) : undefined;
|
|
23876
23971
|
if (path === undefined) {
|
|
23877
23972
|
return {
|
|
23878
23973
|
nativeId: plugin.id,
|
|
@@ -23913,7 +24008,7 @@ function sourceOf2(owner) {
|
|
|
23913
24008
|
}
|
|
23914
24009
|
function observeReadback(identity) {
|
|
23915
24010
|
const target = managedPackageDir(identity.nativeId);
|
|
23916
|
-
const present =
|
|
24011
|
+
const present = existsSync25(target) && linkPointsTo(managedLink(identity.nativeId), target);
|
|
23917
24012
|
const retention = retentionOf(identity.nativeId);
|
|
23918
24013
|
if (!present) {
|
|
23919
24014
|
return {
|
|
@@ -23957,17 +24052,17 @@ function retentionOf(nativeId) {
|
|
|
23957
24052
|
};
|
|
23958
24053
|
}
|
|
23959
24054
|
function resourceObservation(path) {
|
|
23960
|
-
if (!
|
|
24055
|
+
if (!existsSync25(path))
|
|
23961
24056
|
return { state: "absent", fingerprint: null };
|
|
23962
24057
|
return { state: "present", fingerprint: fingerprintTree(path) };
|
|
23963
24058
|
}
|
|
23964
24059
|
function lockMetadataObservation(nativeId) {
|
|
23965
|
-
if (!
|
|
24060
|
+
if (!existsSync25(lockPath()))
|
|
23966
24061
|
return { state: "absent", fingerprint: null };
|
|
23967
24062
|
return { state: "present", fingerprint: sha256(canonical3(metadataView(readDoc(lockPath(), {}, "lockfile"), npmName(nativeId)))) };
|
|
23968
24063
|
}
|
|
23969
24064
|
function plannedLockMetadata(nativeId, version) {
|
|
23970
|
-
const lock =
|
|
24065
|
+
const lock = existsSync25(lockPath()) ? readDoc(lockPath(), {}, "lockfile") : { plugins: {}, settings: {} };
|
|
23971
24066
|
const plugins = isDoc(lock.plugins) ? lock.plugins : {};
|
|
23972
24067
|
const npm = npmName(nativeId);
|
|
23973
24068
|
const next = { ...lock, plugins: { ...plugins, [npm]: activatedEntry(entry(plugins[npm]), version) } };
|
|
@@ -24005,7 +24100,7 @@ function captureRollback3(nativeId, attemptId, operationId) {
|
|
|
24005
24100
|
mkdirSafe(preparationDir2(attemptId, operationId));
|
|
24006
24101
|
mkdirSync10(reference, { recursive: true });
|
|
24007
24102
|
const target = managedPackageDir(nativeId);
|
|
24008
|
-
if (
|
|
24103
|
+
if (existsSync25(target))
|
|
24009
24104
|
cpSync9(target, join33(reference, "package"), { recursive: true });
|
|
24010
24105
|
writeFileSync10(join33(reference, "state.json"), JSON.stringify({ lock: captureLockRow(nativeId), link: currentLinkTarget(managedLink(nativeId)) }));
|
|
24011
24106
|
return resolve20(reference);
|
|
@@ -24015,7 +24110,7 @@ function restoreRollback2(nativeId, reference) {
|
|
|
24015
24110
|
const target = managedPackageDir(nativeId);
|
|
24016
24111
|
rmSync10(target, { recursive: true, force: true });
|
|
24017
24112
|
const backup = join33(reference, "package");
|
|
24018
|
-
if (
|
|
24113
|
+
if (existsSync25(backup)) {
|
|
24019
24114
|
mkdirSafe(dirname12(target));
|
|
24020
24115
|
cpSync9(backup, target, { recursive: true });
|
|
24021
24116
|
}
|
|
@@ -24029,7 +24124,7 @@ function restoreRollback2(nativeId, reference) {
|
|
|
24029
24124
|
}
|
|
24030
24125
|
function captureLockRow(nativeId) {
|
|
24031
24126
|
const packageName = npmName(nativeId);
|
|
24032
|
-
if (!
|
|
24127
|
+
if (!existsSync25(lockPath()))
|
|
24033
24128
|
return { packageName, present: false, row: null };
|
|
24034
24129
|
const lock = readDoc(lockPath(), {}, "lockfile");
|
|
24035
24130
|
const plugins = isDoc(lock.plugins) ? lock.plugins : {};
|
|
@@ -24039,7 +24134,7 @@ function captureLockRow(nativeId) {
|
|
|
24039
24134
|
}
|
|
24040
24135
|
function restoreLockRow(saved) {
|
|
24041
24136
|
const file = lockPath();
|
|
24042
|
-
if (!
|
|
24137
|
+
if (!existsSync25(file)) {
|
|
24043
24138
|
if (!saved.present)
|
|
24044
24139
|
return;
|
|
24045
24140
|
writeDoc(file, { plugins: { [saved.packageName]: saved.row } });
|
|
@@ -24055,7 +24150,7 @@ function restoreLockRow(saved) {
|
|
|
24055
24150
|
}
|
|
24056
24151
|
function currentLinkTarget(path) {
|
|
24057
24152
|
try {
|
|
24058
|
-
return
|
|
24153
|
+
return lstatSync19(path).isSymbolicLink() ? resolve20(dirname12(path), readlinkSync2(path)) : null;
|
|
24059
24154
|
} catch {
|
|
24060
24155
|
return null;
|
|
24061
24156
|
}
|
|
@@ -24097,7 +24192,7 @@ async function applyManaged(handle, stagingRoot) {
|
|
|
24097
24192
|
}
|
|
24098
24193
|
function activationAlreadyCurrent(nativeId, stage, version) {
|
|
24099
24194
|
const target = managedPackageDir(nativeId);
|
|
24100
|
-
if (!
|
|
24195
|
+
if (!existsSync25(target) || !existsSync25(stage) || fingerprintTree(stage) !== fingerprintTree(target) || !linkPointsTo(managedLink(nativeId), target))
|
|
24101
24196
|
return false;
|
|
24102
24197
|
const lock = readDoc(lockPath(), { plugins: {}, settings: {} }, "lockfile");
|
|
24103
24198
|
const plugins = object8(lock.plugins, "lockfile plugins");
|
|
@@ -24158,9 +24253,10 @@ function captureRecorded(activation, route, attemptId, operationId, affectedOper
|
|
|
24158
24253
|
// src/native-hook-writer.ts
|
|
24159
24254
|
init_hooks();
|
|
24160
24255
|
init_hook_build();
|
|
24161
|
-
import { chmodSync as chmodSync2, cpSync as cpSync10, existsSync as
|
|
24256
|
+
import { chmodSync as chmodSync2, cpSync as cpSync10, existsSync as existsSync26, lstatSync as lstatSync20, mkdirSync as mkdirSync11, mkdtempSync as mkdtempSync10, renameSync as renameSync8, rmSync as rmSync11, writeFileSync as writeFileSync11 } from "node:fs";
|
|
24162
24257
|
import { dirname as dirname13, join as join34 } from "node:path";
|
|
24163
24258
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
24259
|
+
init_compatibility();
|
|
24164
24260
|
function probeHookHostVersion(command, override) {
|
|
24165
24261
|
const binary = process.env[override] ?? which(command);
|
|
24166
24262
|
if (!binary)
|
|
@@ -24182,8 +24278,8 @@ function createNativeHookWriter(options) {
|
|
|
24182
24278
|
if (reader.listInstalled().some((item) => item.id === id && item.path !== target)) {
|
|
24183
24279
|
throw new Error("Native hook identity already belongs to a historical standalone install; remove that owned install before retrying: " + id);
|
|
24184
24280
|
}
|
|
24185
|
-
const owner =
|
|
24186
|
-
if (
|
|
24281
|
+
const owner = existsSync26(target) ? readHookOwner(target) : null;
|
|
24282
|
+
if (existsSync26(target) && (owner === null || owner.pluginId !== id || owner.source !== source)) {
|
|
24187
24283
|
throw new Error("Native hook package is not owned for this source: " + target);
|
|
24188
24284
|
}
|
|
24189
24285
|
const raw = registrationText(registration);
|
|
@@ -24207,7 +24303,7 @@ function createNativeHookWriter(options) {
|
|
|
24207
24303
|
}, [profile]);
|
|
24208
24304
|
if (admission.status === "refused")
|
|
24209
24305
|
throw new PackageCapabilityError(store.id, admission);
|
|
24210
|
-
if (
|
|
24306
|
+
if (existsSync26(join34(plugin.dir, NATIVE_HOOK_MARKER)))
|
|
24211
24307
|
throw new Error("Source contains reserved native hook ownership metadata");
|
|
24212
24308
|
preflightPortableHooks(adapter, plugin.dir);
|
|
24213
24309
|
checkTarget(idFor(plugin), resolved.sourceUri);
|
|
@@ -24232,7 +24328,7 @@ function createNativeHookWriter(options) {
|
|
|
24232
24328
|
fingerprint: plugin.contentFingerprint ?? fingerprintTree(plugin.dir)
|
|
24233
24329
|
}) + `
|
|
24234
24330
|
`);
|
|
24235
|
-
const unchanged =
|
|
24331
|
+
const unchanged = existsSync26(target) && fingerprintTree(target) === fingerprintTree(compiled) && registrationEnabled(registration);
|
|
24236
24332
|
if (opts?.dryRun) {
|
|
24237
24333
|
console.log("[" + store.id + "] would register native hooks: " + target);
|
|
24238
24334
|
return unchanged ? "unchanged" : undefined;
|
|
@@ -24249,7 +24345,7 @@ function createNativeHookWriter(options) {
|
|
|
24249
24345
|
const expectedFingerprint = fingerprintTree(stage);
|
|
24250
24346
|
let activated = false, moved = false, committed = false;
|
|
24251
24347
|
try {
|
|
24252
|
-
if (
|
|
24348
|
+
if (existsSync26(target)) {
|
|
24253
24349
|
renameSync8(target, backup);
|
|
24254
24350
|
moved = true;
|
|
24255
24351
|
}
|
|
@@ -24268,7 +24364,7 @@ function createNativeHookWriter(options) {
|
|
|
24268
24364
|
renameSync8(backup, target);
|
|
24269
24365
|
throw error;
|
|
24270
24366
|
} finally {
|
|
24271
|
-
if (committed || !
|
|
24367
|
+
if (committed || !existsSync26(backup))
|
|
24272
24368
|
rmSync11(transaction, { recursive: true, force: true });
|
|
24273
24369
|
}
|
|
24274
24370
|
} finally {
|
|
@@ -24278,7 +24374,7 @@ function createNativeHookWriter(options) {
|
|
|
24278
24374
|
async remove(id, removeOptions) {
|
|
24279
24375
|
const target = hookPackagePath(store, id);
|
|
24280
24376
|
assertHookPath(store, target);
|
|
24281
|
-
if (!
|
|
24377
|
+
if (!existsSync26(target))
|
|
24282
24378
|
return options.legacyRemove(id, removeOptions);
|
|
24283
24379
|
const owner = readHookOwner(target);
|
|
24284
24380
|
if (owner === null || owner.pluginId !== id || removeOptions?.source !== undefined && owner.source !== removeOptions.source) {
|
|
@@ -24301,12 +24397,12 @@ function createNativeHookWriter(options) {
|
|
|
24301
24397
|
committed = true;
|
|
24302
24398
|
} catch (error) {
|
|
24303
24399
|
restoreRegistration(registration, before, after);
|
|
24304
|
-
if (!
|
|
24400
|
+
if (!existsSync26(target))
|
|
24305
24401
|
renameSync8(backup, target);
|
|
24306
24402
|
throw error;
|
|
24307
24403
|
}
|
|
24308
24404
|
} finally {
|
|
24309
|
-
if (committed || !
|
|
24405
|
+
if (committed || !existsSync26(backup))
|
|
24310
24406
|
rmSync11(transaction, { recursive: true, force: true });
|
|
24311
24407
|
}
|
|
24312
24408
|
},
|
|
@@ -24320,11 +24416,10 @@ function nextRegistration(registration, raw, enabled) {
|
|
|
24320
24416
|
return enabled ? registration.content : undefined;
|
|
24321
24417
|
const value = registrationDocument(registration, raw);
|
|
24322
24418
|
const previous = value[registration.field] ?? [];
|
|
24323
|
-
const
|
|
24324
|
-
if (enabled)
|
|
24325
|
-
entries.push(registration.entry);
|
|
24326
|
-
if (entries.length === 0 && !Object.hasOwn(value, registration.field) && !enabled)
|
|
24419
|
+
const present = previous.includes(registration.entry);
|
|
24420
|
+
if (enabled === present)
|
|
24327
24421
|
return raw;
|
|
24422
|
+
const entries = enabled ? [...previous, registration.entry] : previous.filter((entry) => entry !== registration.entry);
|
|
24328
24423
|
value[registration.field] = entries;
|
|
24329
24424
|
return JSON.stringify(value, null, 2) + `
|
|
24330
24425
|
`;
|
|
@@ -24349,7 +24444,7 @@ function writeExactFile(path, text) {
|
|
|
24349
24444
|
rmSync11(path, { force: true });
|
|
24350
24445
|
return;
|
|
24351
24446
|
}
|
|
24352
|
-
const mode =
|
|
24447
|
+
const mode = existsSync26(path) ? lstatSync20(path).mode & 511 : 420;
|
|
24353
24448
|
mkdirSync11(dirname13(path), { recursive: true });
|
|
24354
24449
|
const temporary = mkdtempSync10(join34(dirname13(path), ".plugnz-hook-write-"));
|
|
24355
24450
|
try {
|
|
@@ -24363,7 +24458,7 @@ function writeExactFile(path, text) {
|
|
|
24363
24458
|
}
|
|
24364
24459
|
|
|
24365
24460
|
// src/hosts/pi-writer.ts
|
|
24366
|
-
import { existsSync as
|
|
24461
|
+
import { existsSync as existsSync27, lstatSync as lstatSync21, mkdirSync as mkdirSync12, mkdtempSync as mkdtempSync11, readFileSync as readFileSync29, readdirSync as readdirSync19, renameSync as renameSync9, rmSync as rmSync12, writeFileSync as writeFileSync12 } from "node:fs";
|
|
24367
24462
|
import { basename as basename4, dirname as dirname14, join as join35, resolve as resolve21 } from "node:path";
|
|
24368
24463
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
24369
24464
|
var MARKER7 = ".plgnz-install.json";
|
|
@@ -24397,7 +24492,7 @@ var piWriter = {
|
|
|
24397
24492
|
const backups = [];
|
|
24398
24493
|
try {
|
|
24399
24494
|
for (const candidate of [...new Set([target, ...prior])]) {
|
|
24400
|
-
if (!
|
|
24495
|
+
if (!existsSync27(candidate)) {
|
|
24401
24496
|
backups.push({ target: candidate });
|
|
24402
24497
|
continue;
|
|
24403
24498
|
}
|
|
@@ -24454,7 +24549,7 @@ var piWriter = {
|
|
|
24454
24549
|
function stagePlugin4(source, stage, plugin, market) {
|
|
24455
24550
|
assertTree(source);
|
|
24456
24551
|
const root = join35(source, "skills");
|
|
24457
|
-
if (!
|
|
24552
|
+
if (!existsSync27(root) || !lstatSync21(root).isDirectory())
|
|
24458
24553
|
throw new Error("Pi standalone delivery requires plugin skills/ directories");
|
|
24459
24554
|
const destination = join35(stage, packageName(plugin, market));
|
|
24460
24555
|
projectPluginForPi(source, destination, plugin);
|
|
@@ -24462,7 +24557,7 @@ function stagePlugin4(source, stage, plugin, market) {
|
|
|
24462
24557
|
const walk = (dir) => {
|
|
24463
24558
|
for (const entry of readdirSync19(dir)) {
|
|
24464
24559
|
const path = join35(dir, entry);
|
|
24465
|
-
const stat =
|
|
24560
|
+
const stat = lstatSync21(path);
|
|
24466
24561
|
if (stat.isDirectory())
|
|
24467
24562
|
walk(path);
|
|
24468
24563
|
else if (entry === "SKILL.md")
|
|
@@ -24506,7 +24601,7 @@ function packageName(plugin, market) {
|
|
|
24506
24601
|
}
|
|
24507
24602
|
function owner2(dir) {
|
|
24508
24603
|
const file = join35(dir, MARKER7);
|
|
24509
|
-
if (!
|
|
24604
|
+
if (!existsSync27(file))
|
|
24510
24605
|
return null;
|
|
24511
24606
|
try {
|
|
24512
24607
|
const x = JSON.parse(readFileSync29(file, "utf8"));
|
|
@@ -24522,12 +24617,12 @@ function owner2(dir) {
|
|
|
24522
24617
|
}
|
|
24523
24618
|
function ownedFor(id, source) {
|
|
24524
24619
|
assertPiStore();
|
|
24525
|
-
if (!
|
|
24620
|
+
if (!existsSync27(skillsDir()))
|
|
24526
24621
|
return [];
|
|
24527
24622
|
const out = [];
|
|
24528
24623
|
for (const name of readdirSync19(skillsDir())) {
|
|
24529
24624
|
const path = join35(skillsDir(), name);
|
|
24530
|
-
if (!
|
|
24625
|
+
if (!lstatSync21(path).isDirectory())
|
|
24531
24626
|
continue;
|
|
24532
24627
|
const mark = owner2(path);
|
|
24533
24628
|
if (mark?.pluginId === id && (source === undefined || mark.source === source))
|
|
@@ -24537,7 +24632,7 @@ function ownedFor(id, source) {
|
|
|
24537
24632
|
}
|
|
24538
24633
|
function checkTarget(target, id, source) {
|
|
24539
24634
|
assertUnder(skillsDir(), target);
|
|
24540
|
-
if (!
|
|
24635
|
+
if (!existsSync27(target))
|
|
24541
24636
|
return;
|
|
24542
24637
|
const mark = owner2(target);
|
|
24543
24638
|
if (mark === null)
|
|
@@ -24546,7 +24641,7 @@ function checkTarget(target, id, source) {
|
|
|
24546
24641
|
throw new Error(`Pi standalone skill belongs to another source; refusing to replace it: ${target}`);
|
|
24547
24642
|
}
|
|
24548
24643
|
function sameTree6(stage, target) {
|
|
24549
|
-
if (!
|
|
24644
|
+
if (!existsSync27(target))
|
|
24550
24645
|
return false;
|
|
24551
24646
|
const bytes = readFileSync29;
|
|
24552
24647
|
const list = (root) => {
|
|
@@ -24555,7 +24650,7 @@ function sameTree6(stage, target) {
|
|
|
24555
24650
|
for (const name of readdirSync19(dir).sort()) {
|
|
24556
24651
|
if (name === MARKER7)
|
|
24557
24652
|
continue;
|
|
24558
|
-
const path = join35(dir, name), relative = prefix ? `${prefix}/${name}` : name, stat =
|
|
24653
|
+
const path = join35(dir, name), relative = prefix ? `${prefix}/${name}` : name, stat = lstatSync21(path);
|
|
24559
24654
|
if (stat.isDirectory())
|
|
24560
24655
|
walk(path, relative);
|
|
24561
24656
|
else if (stat.isFile())
|
|
@@ -24570,11 +24665,11 @@ function sameTree6(stage, target) {
|
|
|
24570
24665
|
return JSON.stringify(list(stage)) === JSON.stringify(list(target));
|
|
24571
24666
|
}
|
|
24572
24667
|
function assertTree(root) {
|
|
24573
|
-
const stat =
|
|
24668
|
+
const stat = lstatSync21(root);
|
|
24574
24669
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
24575
24670
|
throw new Error(`Pi plugin root is not a real directory: ${root}`);
|
|
24576
24671
|
for (const name of readdirSync19(root)) {
|
|
24577
|
-
const path = join35(root, name), child =
|
|
24672
|
+
const path = join35(root, name), child = lstatSync21(path);
|
|
24578
24673
|
if (child.isSymbolicLink())
|
|
24579
24674
|
throw new Error(`Pi plugin contains symlink: ${path}`);
|
|
24580
24675
|
if (child.isDirectory())
|
|
@@ -24604,18 +24699,18 @@ function assertPiStore() {
|
|
|
24604
24699
|
let current = home;
|
|
24605
24700
|
for (const part of [basename4(dirname14(root)), basename4(root)]) {
|
|
24606
24701
|
current = join35(current, part);
|
|
24607
|
-
if (
|
|
24702
|
+
if (existsSync27(current) && lstatSync21(current).isSymbolicLink())
|
|
24608
24703
|
throw new Error(`Pi managed path component is a symlink: ${current}`);
|
|
24609
24704
|
}
|
|
24610
|
-
if (
|
|
24705
|
+
if (existsSync27(root))
|
|
24611
24706
|
assertRealDirectory(root);
|
|
24612
|
-
if (
|
|
24707
|
+
if (existsSync27(skillsDir())) {
|
|
24613
24708
|
assertUnder(root, skillsDir());
|
|
24614
24709
|
assertRealDirectory(skillsDir());
|
|
24615
24710
|
}
|
|
24616
24711
|
}
|
|
24617
24712
|
function assertRealDirectory(path) {
|
|
24618
|
-
const stat =
|
|
24713
|
+
const stat = lstatSync21(path);
|
|
24619
24714
|
if (stat.isSymbolicLink())
|
|
24620
24715
|
throw new Error(`Pi managed path component is a symlink: ${path}`);
|
|
24621
24716
|
if (!stat.isDirectory())
|
|
@@ -24628,7 +24723,7 @@ function assertUnder(root, path) {
|
|
|
24628
24723
|
let current = base;
|
|
24629
24724
|
for (const part of candidate.slice(base.length).split("/").filter(Boolean)) {
|
|
24630
24725
|
current = join35(current, part);
|
|
24631
|
-
if (
|
|
24726
|
+
if (existsSync27(current) && lstatSync21(current).isSymbolicLink())
|
|
24632
24727
|
throw new Error(`Pi managed path component is a symlink: ${current}`);
|
|
24633
24728
|
}
|
|
24634
24729
|
}
|
|
@@ -24644,7 +24739,7 @@ var piHookWriter = createNativeHookWriter({
|
|
|
24644
24739
|
});
|
|
24645
24740
|
|
|
24646
24741
|
// src/hosts/dcode-writer.ts
|
|
24647
|
-
import { cpSync as cpSync11, existsSync as
|
|
24742
|
+
import { cpSync as cpSync11, existsSync as existsSync28, lstatSync as lstatSync22, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync12, readFileSync as readFileSync30, readdirSync as readdirSync20, realpathSync as realpathSync5, renameSync as renameSync10, rmSync as rmSync13, writeFileSync as writeFileSync13 } from "node:fs";
|
|
24648
24743
|
import { basename as basename5, dirname as dirname15, join as join36, resolve as resolve22 } from "node:path";
|
|
24649
24744
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
24650
24745
|
import { spawn as spawnChild } from "node:child_process";
|
|
@@ -24673,7 +24768,7 @@ function nativePython() {
|
|
|
24673
24768
|
throw new Error("dcode native lock runtime is unavailable");
|
|
24674
24769
|
const shebang = readFileSync30(binary, "utf8").split(/\r?\n/, 1)[0] ?? "";
|
|
24675
24770
|
const match = /^#!(\/[^\s]+python(?:\d+(?:\.\d+)?)?)$/u.exec(shebang);
|
|
24676
|
-
if (match?.[1] === undefined || !
|
|
24771
|
+
if (match?.[1] === undefined || !existsSync28(match[1]))
|
|
24677
24772
|
throw new Error("dcode native Python interpreter is unverified; set OPEN_PLUGIN_DCODE_PYTHON_BIN to its verified interpreter");
|
|
24678
24773
|
return match[1];
|
|
24679
24774
|
}
|
|
@@ -24774,7 +24869,7 @@ function observeDcodeTarget(target) {
|
|
|
24774
24869
|
throw new Error(`dcode install record ${nativeId} has duplicate rows`);
|
|
24775
24870
|
const path = rowInstall(rows[0], nativeId);
|
|
24776
24871
|
assertCachePath(path);
|
|
24777
|
-
const present =
|
|
24872
|
+
const present = existsSync28(path);
|
|
24778
24873
|
const marker = present ? ownership3(path) : null;
|
|
24779
24874
|
const body = present ? readDoc2(join36(path, MARKER8), {}, "ownership marker") : {};
|
|
24780
24875
|
const owned = marker?.pluginId === nativeId;
|
|
@@ -24795,7 +24890,7 @@ function observeDcodeTarget(target) {
|
|
|
24795
24890
|
});
|
|
24796
24891
|
}
|
|
24797
24892
|
function dcodeLifecycleReadback(binding) {
|
|
24798
|
-
if (
|
|
24893
|
+
if (existsSync28(join36(dcodeStateDir(), READBACK_FAULT)))
|
|
24799
24894
|
throw new Error(`dcode readback failed for ${binding.nativeId}`);
|
|
24800
24895
|
const installations = observeDcodeTarget(binding.target);
|
|
24801
24896
|
const row = installations.find((item) => item.nativeId === binding.nativeId);
|
|
@@ -24816,7 +24911,7 @@ function dcodeLifecycleReadback(binding) {
|
|
|
24816
24911
|
transition: { requirement: present ? "restart" : "none", status: "effective" },
|
|
24817
24912
|
installedFingerprint: present ? row.installedFingerprint : null,
|
|
24818
24913
|
contentRoots: present ? row.contentRoots : [],
|
|
24819
|
-
retention: { pluginData:
|
|
24914
|
+
retention: { pluginData: existsSync28(dataRoot) ? { state: "present", fingerprint: fingerprintTree(dataRoot) } : { state: "absent", fingerprint: null }, inactiveMetadata: { state: "absent", fingerprint: null } }
|
|
24820
24915
|
};
|
|
24821
24916
|
}
|
|
24822
24917
|
function captureDcodeRollback(binding, attemptId, operationId) {
|
|
@@ -24825,13 +24920,13 @@ function captureDcodeRollback(binding, attemptId, operationId) {
|
|
|
24825
24920
|
const registry = readRegistry3(dcodeRegistryFile());
|
|
24826
24921
|
const enabled = boolObject(readEnablement(dcodeEnablementFile()).enabledPlugins, "enabledPlugins");
|
|
24827
24922
|
const row = object9(registry.plugins, "registry plugins")[binding.nativeId];
|
|
24828
|
-
const state = { row: row ?? null, enabled: enabled[binding.nativeId] ?? null, registryExisted:
|
|
24923
|
+
const state = { row: row ?? null, enabled: enabled[binding.nativeId] ?? null, registryExisted: existsSync28(dcodeRegistryFile()), enablementExisted: existsSync28(dcodeEnablementFile()) };
|
|
24829
24924
|
writeFileSync13(join36(dir, "state.json"), JSON.stringify(state));
|
|
24830
24925
|
for (const [index, item] of rowsFor(row).entries()) {
|
|
24831
24926
|
const path = rowInstall(item, binding.nativeId);
|
|
24832
24927
|
assertCachePath(path);
|
|
24833
24928
|
assertNoSymlinks6(path);
|
|
24834
|
-
if (
|
|
24929
|
+
if (existsSync28(path))
|
|
24835
24930
|
cpSync11(path, join36(dir, `content-${index}`), { recursive: true });
|
|
24836
24931
|
}
|
|
24837
24932
|
return dir;
|
|
@@ -24917,7 +25012,7 @@ var dcodeDefinition = {
|
|
|
24917
25012
|
stageActivation: async (request) => {
|
|
24918
25013
|
const dir = lifecycleDirectory(request.snapshot.attemptId, request.snapshot.operationId);
|
|
24919
25014
|
const stagingRoot = join36(dir, "stage");
|
|
24920
|
-
if (
|
|
25015
|
+
if (existsSync28(stagingRoot))
|
|
24921
25016
|
throw new Error("dcode preparation stage already exists");
|
|
24922
25017
|
mkdirSync13(stagingRoot, { recursive: true });
|
|
24923
25018
|
const manifest = declaredManifest(request.snapshot.packageRoot, request.snapshot.packageName);
|
|
@@ -24939,7 +25034,7 @@ var dcodeDefinition = {
|
|
|
24939
25034
|
const found = new Set;
|
|
24940
25035
|
for (const candidate of dcodeMcpCandidates()) {
|
|
24941
25036
|
const file = join36(projection.stagingRoot, candidate.kind === "spec" ? candidate.file : candidate.manifest);
|
|
24942
|
-
if (!
|
|
25037
|
+
if (!existsSync28(file))
|
|
24943
25038
|
continue;
|
|
24944
25039
|
const body = readDoc2(file, {}, "MCP document");
|
|
24945
25040
|
if (typeof body.mcpServers !== "object" || body.mcpServers === null || Array.isArray(body.mcpServers))
|
|
@@ -24979,7 +25074,7 @@ var dcodeDefinition = {
|
|
|
24979
25074
|
if (manifest.version !== projection.packageVersion)
|
|
24980
25075
|
throw new Error("dcode legacy version differs; refusing adoption");
|
|
24981
25076
|
}
|
|
24982
|
-
if (
|
|
25077
|
+
if (existsSync28(target) && ownership3(target)?.pluginId !== projection.nativeId)
|
|
24983
25078
|
throw new Error("dcode lifecycle target is not owned");
|
|
24984
25079
|
const rollbackReference = captureDcodeRollback(projection, projection.attemptId, projection.operationId);
|
|
24985
25080
|
writeFileSync13(join36(rollbackReference, "next-path.json"), JSON.stringify({ target }));
|
|
@@ -24998,7 +25093,7 @@ var dcodeDefinition = {
|
|
|
24998
25093
|
const target = lifecycleSlot(prepared.handle.nativeId, prepared.handle.projectedFingerprint);
|
|
24999
25094
|
assertCachePath(target);
|
|
25000
25095
|
mkdirSync13(dirname15(target), { recursive: true });
|
|
25001
|
-
if (
|
|
25096
|
+
if (existsSync28(target)) {
|
|
25002
25097
|
const marker = ownership3(target);
|
|
25003
25098
|
if (marker?.pluginId !== prepared.handle.nativeId)
|
|
25004
25099
|
throw new Error("dcode lifecycle activation would overwrite foreign content");
|
|
@@ -25038,22 +25133,22 @@ var dcodeDefinition = {
|
|
|
25038
25133
|
},
|
|
25039
25134
|
rollback: async (handle) => {
|
|
25040
25135
|
await acquireNativeLock(handle.attemptId, handle.operationId);
|
|
25041
|
-
if (!
|
|
25136
|
+
if (!existsSync28(join36(handle.rollbackReference, "state.json")))
|
|
25042
25137
|
throw new Error("dcode rollback snapshot is missing; recovery refused");
|
|
25043
25138
|
const state = readDoc2(join36(handle.rollbackReference, "state.json"), {}, "rollback state");
|
|
25044
25139
|
if (recoveringNativeLocks.has(`${handle.attemptId}:${handle.operationId}`))
|
|
25045
25140
|
assertRecoveryRollbackMetadata(handle, state);
|
|
25046
25141
|
for (const [index, root] of handle.prior.contentRoots.entries()) {
|
|
25047
25142
|
const backup = join36(handle.rollbackReference, `content-${index}`);
|
|
25048
|
-
if (!
|
|
25143
|
+
if (!existsSync28(backup) || fingerprintTree(backup) !== root.fingerprint)
|
|
25049
25144
|
throw new Error("dcode rollback snapshot bytes do not match the sealed prior");
|
|
25050
|
-
if (recoveringNativeLocks.has(`${handle.attemptId}:${handle.operationId}`) &&
|
|
25145
|
+
if (recoveringNativeLocks.has(`${handle.attemptId}:${handle.operationId}`) && existsSync28(root.path) && fingerprintTree(root.path) !== root.fingerprint)
|
|
25051
25146
|
throw new Error("dcode prior root changed outside the sealed operation; refusing stale overwrite");
|
|
25052
25147
|
}
|
|
25053
25148
|
const target = handle.projectedFingerprint === null ? undefined : lifecycleSlot(handle.nativeId, handle.projectedFingerprint);
|
|
25054
25149
|
if (target !== undefined)
|
|
25055
25150
|
assertCachePath(target);
|
|
25056
|
-
if (target !== undefined &&
|
|
25151
|
+
if (target !== undefined && existsSync28(target) && !handle.prior.contentRoots.some((root) => resolve22(root.path) === resolve22(target))) {
|
|
25057
25152
|
if (ownership3(target)?.pluginId !== handle.nativeId || recoveringNativeLocks.has(`${handle.attemptId}:${handle.operationId}`) && fingerprintTree(target) !== handle.projectedFingerprint)
|
|
25058
25153
|
throw new Error("dcode rollback candidate differs from the sealed operation; refusing stale overwrite");
|
|
25059
25154
|
rmSync13(target, { recursive: true });
|
|
@@ -25062,7 +25157,7 @@ var dcodeDefinition = {
|
|
|
25062
25157
|
const path = rowInstall(row, handle.nativeId);
|
|
25063
25158
|
assertCachePath(path);
|
|
25064
25159
|
const backup = join36(handle.rollbackReference, `content-${index}`);
|
|
25065
|
-
if (
|
|
25160
|
+
if (existsSync28(backup)) {
|
|
25066
25161
|
mkdirSync13(dirname15(path), { recursive: true });
|
|
25067
25162
|
cpSync11(backup, path, { recursive: true });
|
|
25068
25163
|
}
|
|
@@ -25096,14 +25191,14 @@ var dcodeDefinition = {
|
|
|
25096
25191
|
const next = readDoc2(nextFile, {}, "cleanup target");
|
|
25097
25192
|
if (disposition === "verified-commit" && recovering !== undefined) {
|
|
25098
25193
|
const retiredRoots = recovering.prior.contentRoots.filter((root) => !recovering.expected.contentRoots.some((next) => resolve22(next.path) === resolve22(root.path)));
|
|
25099
|
-
if (
|
|
25194
|
+
if (existsSync28(priorFile))
|
|
25100
25195
|
assertRecoveryRollbackMetadata(recovering, readDoc2(priorFile, {}, "rollback state"));
|
|
25101
|
-
else if (retiredRoots.some((root) =>
|
|
25196
|
+
else if (retiredRoots.some((root) => existsSync28(root.path)))
|
|
25102
25197
|
throw new Error("dcode cleanup prior metadata is missing; recovery refused");
|
|
25103
|
-
if (
|
|
25198
|
+
if (existsSync28(nextFile) && (typeof next.target !== "string" || !recovering.expected.contentRoots.some((root) => resolve22(root.path) === resolve22(next.target))))
|
|
25104
25199
|
throw new Error("dcode cleanup target differs from the sealed expected root; recovery refused");
|
|
25105
25200
|
for (const root of retiredRoots) {
|
|
25106
|
-
if (
|
|
25201
|
+
if (existsSync28(root.path) && fingerprintTree(root.path) !== root.fingerprint)
|
|
25107
25202
|
throw new Error("dcode cleanup prior root changed; refusing stale deletion");
|
|
25108
25203
|
}
|
|
25109
25204
|
for (const root of retiredRoots)
|
|
@@ -25185,7 +25280,7 @@ var dcodeWriter = {
|
|
|
25185
25280
|
const slot = ownership3(target);
|
|
25186
25281
|
if (slot !== null && (slot.source !== resolved.sourceUri || slot.pluginId !== id))
|
|
25187
25282
|
throw new Error(`dcode plugin ${id} belongs to another source; refusing to replace it`);
|
|
25188
|
-
if (
|
|
25283
|
+
if (existsSync28(target) && slot === null)
|
|
25189
25284
|
throw new Error(`dcode cache target is unowned; refusing to replace it: ${target}`);
|
|
25190
25285
|
const former = prior.kind === "none" ? undefined : prior.path;
|
|
25191
25286
|
const unchanged = (former === undefined || resolve22(former) === resolve22(target)) && slot?.kind === "current" && slot.fingerprint === sourceFingerprint && slot.projectedFingerprint === projected && slot.sourceRevision === resolved.sha && sameTree7(stage, target);
|
|
@@ -25229,13 +25324,13 @@ var dcodeWriter = {
|
|
|
25229
25324
|
}
|
|
25230
25325
|
} finally {
|
|
25231
25326
|
rmSync13(stage, { recursive: true, force: true });
|
|
25232
|
-
if (opts?.dryRun !== true &&
|
|
25327
|
+
if (opts?.dryRun !== true && existsSync28(managedRoot) && readdirSync20(managedRoot).every((name) => name.startsWith(".plgnz-dcode-"))) {
|
|
25233
25328
|
rmSync13(managedRoot, { recursive: true, force: true });
|
|
25234
25329
|
}
|
|
25235
25330
|
}
|
|
25236
25331
|
},
|
|
25237
25332
|
async pin(plugin, opts) {
|
|
25238
|
-
if (plugin.path === undefined || !
|
|
25333
|
+
if (plugin.path === undefined || !existsSync28(plugin.path))
|
|
25239
25334
|
return { changes: [], refusals: [] };
|
|
25240
25335
|
assertCachePath(plugin.path);
|
|
25241
25336
|
if (ownership3(plugin.path)?.pluginId !== plugin.id)
|
|
@@ -25319,7 +25414,7 @@ function assessPrior(value, id, source, adopt, name, version, sourceDir) {
|
|
|
25319
25414
|
throw new Error(`dcode plugin ${id} has a conflicting ownership marker`);
|
|
25320
25415
|
if (!adopt)
|
|
25321
25416
|
throw new Error(`dcode install record ${id} is not plgnz-owned; refusing to replace it`);
|
|
25322
|
-
if (!
|
|
25417
|
+
if (!existsSync28(install) || lstatSync22(install).isSymbolicLink() || !lstatSync22(install).isDirectory()) {
|
|
25323
25418
|
throw new Error(`dcode install record ${id} is not plgnz-owned; refusing to replace it`);
|
|
25324
25419
|
}
|
|
25325
25420
|
assertNoSymlinks6(install);
|
|
@@ -25342,7 +25437,7 @@ function assessPrior(value, id, source, adopt, name, version, sourceDir) {
|
|
|
25342
25437
|
return { kind: "adoptable", path: install };
|
|
25343
25438
|
}
|
|
25344
25439
|
function declaredManifest(dir, expectedName) {
|
|
25345
|
-
const manifest = MANIFESTS.map((relative) => join36(dir, relative)).find((file) =>
|
|
25440
|
+
const manifest = MANIFESTS.map((relative) => join36(dir, relative)).find((file) => existsSync28(file));
|
|
25346
25441
|
if (manifest === undefined)
|
|
25347
25442
|
throw new Error("dcode stage has no supported plugin manifest");
|
|
25348
25443
|
let parsed;
|
|
@@ -25367,7 +25462,7 @@ function stagePlugin5(source, stage, name, version) {
|
|
|
25367
25462
|
throw new Error(`dcode manifest identity does not match ${name}`);
|
|
25368
25463
|
}
|
|
25369
25464
|
function forceAutoUpdateOff(dir) {
|
|
25370
|
-
const manifest = MANIFESTS.map((relative) => join36(dir, relative)).find((file) =>
|
|
25465
|
+
const manifest = MANIFESTS.map((relative) => join36(dir, relative)).find((file) => existsSync28(file));
|
|
25371
25466
|
if (manifest === undefined)
|
|
25372
25467
|
throw new Error("dcode stage has no supported plugin manifest");
|
|
25373
25468
|
const parsed = object9(JSON.parse(readFileSync30(manifest, "utf8")), "manifest");
|
|
@@ -25381,7 +25476,7 @@ function forceAutoUpdateOff(dir) {
|
|
|
25381
25476
|
`);
|
|
25382
25477
|
}
|
|
25383
25478
|
function assertReadback(id, registryFile, enablementFile, target, version, projected, sourceRevision) {
|
|
25384
|
-
if (
|
|
25479
|
+
if (existsSync28(join36(dcodeStateDir(), READBACK_FAULT)))
|
|
25385
25480
|
throw new Error(`dcode readback failed for ${id}`);
|
|
25386
25481
|
const registry = readRegistry3(registryFile);
|
|
25387
25482
|
const enablement = readEnablement(enablementFile);
|
|
@@ -25407,18 +25502,18 @@ function assertReadback(id, registryFile, enablementFile, target, version, proje
|
|
|
25407
25502
|
function retireFormer(path) {
|
|
25408
25503
|
try {
|
|
25409
25504
|
assertCachePath(path);
|
|
25410
|
-
const stat =
|
|
25505
|
+
const stat = lstatSync22(path);
|
|
25411
25506
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
25412
25507
|
throw new Error("former cache is not a directory");
|
|
25413
25508
|
const backup = join36(dirname15(path), `.plgnz-dcode-retire-${basename5(path)}`);
|
|
25414
|
-
if (
|
|
25415
|
-
if (!
|
|
25509
|
+
if (existsSync28(backup)) {
|
|
25510
|
+
if (!lstatSync22(backup).isDirectory())
|
|
25416
25511
|
throw new Error("retire destination is not a directory");
|
|
25417
25512
|
rmSync13(backup, { recursive: true, force: true });
|
|
25418
25513
|
}
|
|
25419
25514
|
renameSync10(path, backup);
|
|
25420
25515
|
rmSync13(backup, { recursive: true, force: true });
|
|
25421
|
-
if (
|
|
25516
|
+
if (existsSync28(path))
|
|
25422
25517
|
throw new Error("former cache remains");
|
|
25423
25518
|
return;
|
|
25424
25519
|
} catch {
|
|
@@ -25440,7 +25535,7 @@ function listTree(root) {
|
|
|
25440
25535
|
continue;
|
|
25441
25536
|
const file = join36(dir, entry);
|
|
25442
25537
|
const relative = prefix ? `${prefix}/${entry}` : entry;
|
|
25443
|
-
const stat =
|
|
25538
|
+
const stat = lstatSync22(file);
|
|
25444
25539
|
if (stat.isSymbolicLink())
|
|
25445
25540
|
throw new Error(`dcode plugin contains symlink: ${file}`);
|
|
25446
25541
|
if (stat.isDirectory())
|
|
@@ -25455,12 +25550,12 @@ function listTree(root) {
|
|
|
25455
25550
|
return out;
|
|
25456
25551
|
}
|
|
25457
25552
|
function sameTree7(left, right) {
|
|
25458
|
-
if (!
|
|
25553
|
+
if (!existsSync28(right))
|
|
25459
25554
|
return false;
|
|
25460
25555
|
return JSON.stringify(listTree(left)) === JSON.stringify(listTree(right));
|
|
25461
25556
|
}
|
|
25462
25557
|
function readDoc2(file, fallback, label) {
|
|
25463
|
-
if (!
|
|
25558
|
+
if (!existsSync28(file))
|
|
25464
25559
|
return fallback;
|
|
25465
25560
|
try {
|
|
25466
25561
|
const value = JSON.parse(readFileSync30(file, "utf8"));
|
|
@@ -25520,7 +25615,7 @@ function ownership3(dir) {
|
|
|
25520
25615
|
assertManagedPath4(dir);
|
|
25521
25616
|
const file = join36(dir, MARKER8);
|
|
25522
25617
|
assertManagedPath4(file);
|
|
25523
|
-
if (!
|
|
25618
|
+
if (!existsSync28(file))
|
|
25524
25619
|
return null;
|
|
25525
25620
|
try {
|
|
25526
25621
|
const value = object9(JSON.parse(readFileSync30(file, "utf8")), "ownership marker");
|
|
@@ -25550,7 +25645,7 @@ function writeDoc2(file, value) {
|
|
|
25550
25645
|
}
|
|
25551
25646
|
function snapshot2(file) {
|
|
25552
25647
|
const read = readFileSync30;
|
|
25553
|
-
return
|
|
25648
|
+
return existsSync28(file) ? read(file) : undefined;
|
|
25554
25649
|
}
|
|
25555
25650
|
function restore3(file, before) {
|
|
25556
25651
|
try {
|
|
@@ -25563,7 +25658,7 @@ function restore3(file, before) {
|
|
|
25563
25658
|
} catch {}
|
|
25564
25659
|
}
|
|
25565
25660
|
function activate5(stage, target, parent) {
|
|
25566
|
-
if (!
|
|
25661
|
+
if (!existsSync28(target)) {
|
|
25567
25662
|
renameSync10(stage, target);
|
|
25568
25663
|
return { commit: () => {}, rollback: () => rmSync13(target, { recursive: true, force: true }) };
|
|
25569
25664
|
}
|
|
@@ -25589,7 +25684,7 @@ function moveAside3(path, parent = dirname15(path)) {
|
|
|
25589
25684
|
return {
|
|
25590
25685
|
commit: () => rmSync13(backupRoot, { recursive: true, force: true }),
|
|
25591
25686
|
rollback: () => {
|
|
25592
|
-
if (
|
|
25687
|
+
if (existsSync28(backup))
|
|
25593
25688
|
renameSync10(backup, path);
|
|
25594
25689
|
rmSync13(backupRoot, { recursive: true, force: true });
|
|
25595
25690
|
}
|
|
@@ -25598,7 +25693,7 @@ function moveAside3(path, parent = dirname15(path)) {
|
|
|
25598
25693
|
function assertNoSymlinks6(dir) {
|
|
25599
25694
|
for (const entry of readdirSync20(dir)) {
|
|
25600
25695
|
const file = join36(dir, entry);
|
|
25601
|
-
const stat =
|
|
25696
|
+
const stat = lstatSync22(file);
|
|
25602
25697
|
if (stat.isSymbolicLink())
|
|
25603
25698
|
throw new Error(`dcode plugin contains symlink: ${file}`);
|
|
25604
25699
|
if (stat.isDirectory())
|
|
@@ -25615,19 +25710,19 @@ function assertCachePath(path) {
|
|
|
25615
25710
|
if (target === root || !target.startsWith(`${root}/`))
|
|
25616
25711
|
throw new Error(`dcode path escapes managed cache: ${path}`);
|
|
25617
25712
|
let current = root;
|
|
25618
|
-
if (
|
|
25713
|
+
if (existsSync28(current) && lstatSync22(current).isSymbolicLink())
|
|
25619
25714
|
throw new Error(`dcode native path contains symlink: ${current}`);
|
|
25620
25715
|
const relative = target.slice(root.length).replace(/^\//, "");
|
|
25621
25716
|
for (const part of relative.length === 0 ? [] : relative.split("/")) {
|
|
25622
25717
|
if (part === "" || part === "." || part === "..")
|
|
25623
25718
|
throw new Error(`dcode path escapes managed cache: ${path}`);
|
|
25624
25719
|
current = join36(current, part);
|
|
25625
|
-
if (!
|
|
25720
|
+
if (!existsSync28(current))
|
|
25626
25721
|
return;
|
|
25627
|
-
if (
|
|
25722
|
+
if (lstatSync22(current).isSymbolicLink())
|
|
25628
25723
|
throw new Error(`dcode native path contains symlink: ${current}`);
|
|
25629
25724
|
}
|
|
25630
|
-
if (!
|
|
25725
|
+
if (!existsSync28(target) || !existsSync28(root))
|
|
25631
25726
|
return;
|
|
25632
25727
|
const realRoot = realpathSync5(root);
|
|
25633
25728
|
const realTarget = realpathSync5(target);
|
|
@@ -25640,18 +25735,18 @@ function assertManagedPath4(path) {
|
|
|
25640
25735
|
if (target !== root && !target.startsWith(`${root}/`))
|
|
25641
25736
|
throw new Error(`dcode path escapes native root: ${path}`);
|
|
25642
25737
|
let current = root;
|
|
25643
|
-
if (
|
|
25738
|
+
if (existsSync28(current) && lstatSync22(current).isSymbolicLink())
|
|
25644
25739
|
throw new Error(`dcode native path contains symlink: ${current}`);
|
|
25645
25740
|
const relative = target.slice(root.length).replace(/^\//, "");
|
|
25646
25741
|
for (const part of relative ? relative.split("/") : []) {
|
|
25647
25742
|
current = join36(current, part);
|
|
25648
|
-
if (
|
|
25743
|
+
if (existsSync28(current) && lstatSync22(current).isSymbolicLink())
|
|
25649
25744
|
throw new Error(`dcode native path contains symlink: ${current}`);
|
|
25650
25745
|
}
|
|
25651
25746
|
}
|
|
25652
25747
|
|
|
25653
25748
|
// src/hosts/opencode-writer.ts
|
|
25654
|
-
import { cpSync as cpSync12, existsSync as
|
|
25749
|
+
import { cpSync as cpSync12, existsSync as existsSync29, lstatSync as lstatSync23, mkdirSync as mkdirSync14, mkdtempSync as mkdtempSync13, readFileSync as readFileSync31, readdirSync as readdirSync21, renameSync as renameSync11, rmSync as rmSync14, writeFileSync as writeFileSync14 } from "node:fs";
|
|
25655
25750
|
import { dirname as dirname16, join as join37 } from "node:path";
|
|
25656
25751
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
25657
25752
|
var MARKER9 = ".plgnz-install.json";
|
|
@@ -25683,7 +25778,7 @@ var opencodeWriter = {
|
|
|
25683
25778
|
try {
|
|
25684
25779
|
for (const key of keys2()) {
|
|
25685
25780
|
const target = targets[key];
|
|
25686
|
-
if (!
|
|
25781
|
+
if (!existsSync29(target)) {
|
|
25687
25782
|
moves.push({ target });
|
|
25688
25783
|
continue;
|
|
25689
25784
|
}
|
|
@@ -25722,7 +25817,7 @@ var opencodeWriter = {
|
|
|
25722
25817
|
const targets = targetsFor(name, plugin);
|
|
25723
25818
|
assertStore();
|
|
25724
25819
|
for (const key of keys2())
|
|
25725
|
-
if (
|
|
25820
|
+
if (existsSync29(targets[key])) {
|
|
25726
25821
|
assertManagedTree(targets[key]);
|
|
25727
25822
|
if (!owned(targets[key], id))
|
|
25728
25823
|
throw new Error(`OpenCode target is not owned by ${id}: ${targets[key]}`);
|
|
@@ -25731,7 +25826,7 @@ var opencodeWriter = {
|
|
|
25731
25826
|
try {
|
|
25732
25827
|
for (const key of keys2()) {
|
|
25733
25828
|
const target = targets[key];
|
|
25734
|
-
if (!
|
|
25829
|
+
if (!existsSync29(target))
|
|
25735
25830
|
continue;
|
|
25736
25831
|
const root = mkdtempSync13(join37(dirname16(target), ".plgnz-opencode-remove-"));
|
|
25737
25832
|
const backup = join37(root, "previous");
|
|
@@ -25777,13 +25872,13 @@ function stagePackage(source, stage, name, activePrivateRoot, ownerValue) {
|
|
|
25777
25872
|
return { private: privateRoot, skills, commands };
|
|
25778
25873
|
}
|
|
25779
25874
|
function sourceCommands(source) {
|
|
25780
|
-
const root =
|
|
25781
|
-
if (!
|
|
25875
|
+
const root = existsSync29(join37(source, ".claude", "commands")) ? join37(source, ".claude", "commands") : join37(source, "commands");
|
|
25876
|
+
if (!existsSync29(root))
|
|
25782
25877
|
return [];
|
|
25783
25878
|
const out = [];
|
|
25784
25879
|
const walk = (dir) => {
|
|
25785
25880
|
for (const entry of readdirSync21(dir).sort()) {
|
|
25786
|
-
const path = join37(dir, entry), stat =
|
|
25881
|
+
const path = join37(dir, entry), stat = lstatSync23(path);
|
|
25787
25882
|
if (stat.isDirectory()) {
|
|
25788
25883
|
walk(path);
|
|
25789
25884
|
continue;
|
|
@@ -25804,12 +25899,12 @@ function sourceCommands(source) {
|
|
|
25804
25899
|
}
|
|
25805
25900
|
function manualSkills(source) {
|
|
25806
25901
|
const root = join37(source, "skills");
|
|
25807
|
-
if (!
|
|
25902
|
+
if (!existsSync29(root))
|
|
25808
25903
|
return [];
|
|
25809
25904
|
const out = [];
|
|
25810
25905
|
const walk = (dir) => {
|
|
25811
25906
|
for (const entry of readdirSync21(dir).sort()) {
|
|
25812
|
-
const path = join37(dir, entry), stat =
|
|
25907
|
+
const path = join37(dir, entry), stat = lstatSync23(path);
|
|
25813
25908
|
if (stat.isDirectory())
|
|
25814
25909
|
walk(path);
|
|
25815
25910
|
else if (stat.isFile() && entry === "SKILL.md") {
|
|
@@ -25915,7 +26010,7 @@ function targetsFor(name, commandNamespace) {
|
|
|
25915
26010
|
}
|
|
25916
26011
|
function owner3(path) {
|
|
25917
26012
|
const file = join37(path, MARKER9);
|
|
25918
|
-
if (!
|
|
26013
|
+
if (!existsSync29(file))
|
|
25919
26014
|
return null;
|
|
25920
26015
|
try {
|
|
25921
26016
|
const value = JSON.parse(readFileSync31(file, "utf8"));
|
|
@@ -25935,7 +26030,7 @@ function owned(privateTarget, id, source) {
|
|
|
25935
26030
|
}
|
|
25936
26031
|
function checkTargets(targets, id, source) {
|
|
25937
26032
|
for (const key of keys2())
|
|
25938
|
-
if (
|
|
26033
|
+
if (existsSync29(targets[key])) {
|
|
25939
26034
|
assertManagedTree(targets[key]);
|
|
25940
26035
|
if (!owned(targets[key], id, source))
|
|
25941
26036
|
throw new Error(`OpenCode target is unowned or belongs to another source: ${targets[key]}`);
|
|
@@ -25945,7 +26040,7 @@ function allSame(staged, targets) {
|
|
|
25945
26040
|
return keys2().every((key) => sameTree8(staged[key], targets[key]));
|
|
25946
26041
|
}
|
|
25947
26042
|
function sameTree8(a, b) {
|
|
25948
|
-
if (!
|
|
26043
|
+
if (!existsSync29(a) || !existsSync29(b))
|
|
25949
26044
|
return false;
|
|
25950
26045
|
const bytes = readFileSync31;
|
|
25951
26046
|
const list = (root) => {
|
|
@@ -25954,7 +26049,7 @@ function sameTree8(a, b) {
|
|
|
25954
26049
|
for (const name of readdirSync21(dir).sort()) {
|
|
25955
26050
|
if (name === MARKER9)
|
|
25956
26051
|
continue;
|
|
25957
|
-
const path = join37(dir, name), rel = prefix ? `${prefix}/${name}` : name, stat =
|
|
26052
|
+
const path = join37(dir, name), rel = prefix ? `${prefix}/${name}` : name, stat = lstatSync23(path);
|
|
25958
26053
|
if (stat.isDirectory())
|
|
25959
26054
|
walk(path, rel);
|
|
25960
26055
|
else if (stat.isFile())
|
|
@@ -25969,11 +26064,11 @@ function sameTree8(a, b) {
|
|
|
25969
26064
|
return JSON.stringify(list(a)) === JSON.stringify(list(b));
|
|
25970
26065
|
}
|
|
25971
26066
|
function assertTree2(root) {
|
|
25972
|
-
const stat =
|
|
26067
|
+
const stat = lstatSync23(root);
|
|
25973
26068
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
25974
26069
|
throw new Error(`OpenCode plugin root is not a real directory: ${root}`);
|
|
25975
26070
|
for (const name of readdirSync21(root)) {
|
|
25976
|
-
const path = join37(root, name), child =
|
|
26071
|
+
const path = join37(root, name), child = lstatSync23(path);
|
|
25977
26072
|
if (name === MARKER9)
|
|
25978
26073
|
throw new Error(`OpenCode plugin reserves ${MARKER9}: ${path}`);
|
|
25979
26074
|
if (child.isSymbolicLink())
|
|
@@ -25985,11 +26080,11 @@ function assertTree2(root) {
|
|
|
25985
26080
|
}
|
|
25986
26081
|
}
|
|
25987
26082
|
function assertManagedTree(root) {
|
|
25988
|
-
const stat =
|
|
26083
|
+
const stat = lstatSync23(root);
|
|
25989
26084
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
25990
26085
|
throw new Error(`OpenCode managed tree is unsafe: ${root}`);
|
|
25991
26086
|
for (const name of readdirSync21(root)) {
|
|
25992
|
-
const path = join37(root, name), child =
|
|
26087
|
+
const path = join37(root, name), child = lstatSync23(path);
|
|
25993
26088
|
if (child.isSymbolicLink())
|
|
25994
26089
|
throw new Error(`OpenCode managed tree contains symlink: ${path}`);
|
|
25995
26090
|
if (child.isDirectory())
|
|
@@ -26000,11 +26095,11 @@ function assertManagedTree(root) {
|
|
|
26000
26095
|
}
|
|
26001
26096
|
function assertSupportedRoot(source) {
|
|
26002
26097
|
for (const entry of ["agents", "hooks", ".claude/agents", ".claude/hooks", "mcp.json", ".mcp.json"])
|
|
26003
|
-
if (
|
|
26098
|
+
if (existsSync29(join37(source, entry)))
|
|
26004
26099
|
throw new Error(`OpenCode cannot preserve root ${entry} semantics: ${join37(source, entry)}`);
|
|
26005
26100
|
for (const file of ["plugin.json", ".plugin/plugin.json", ".claude-plugin/plugin.json"]) {
|
|
26006
26101
|
const path = join37(source, file);
|
|
26007
|
-
if (!
|
|
26102
|
+
if (!existsSync29(path))
|
|
26008
26103
|
continue;
|
|
26009
26104
|
let manifest;
|
|
26010
26105
|
try {
|
|
@@ -26021,7 +26116,7 @@ function assertSupportedRoot(source) {
|
|
|
26021
26116
|
}
|
|
26022
26117
|
function assertStore() {
|
|
26023
26118
|
for (const path of [opencodeRoot(), join37(opencodeRoot(), ".plgnz"), opencodePackagesDir(), opencodeSkillsDir(), opencodeCommandsDir()])
|
|
26024
|
-
if (
|
|
26119
|
+
if (existsSync29(path) && (!lstatSync23(path).isDirectory() || lstatSync23(path).isSymbolicLink()))
|
|
26025
26120
|
throw new Error(`OpenCode managed path is unsafe: ${path}`);
|
|
26026
26121
|
}
|
|
26027
26122
|
function ensureStore2() {
|
|
@@ -26043,7 +26138,7 @@ var opencodeHookWriter = createNativeHookWriter({
|
|
|
26043
26138
|
|
|
26044
26139
|
// src/hosts/grok-writer.ts
|
|
26045
26140
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
26046
|
-
import { cpSync as cpSync13, existsSync as
|
|
26141
|
+
import { cpSync as cpSync13, existsSync as existsSync30, lstatSync as lstatSync24, mkdirSync as mkdirSync15, mkdtempSync as mkdtempSync14, readFileSync as readFileSync32, readdirSync as readdirSync22, readlinkSync as readlinkSync3, renameSync as renameSync12, rmSync as rmSync15, symlinkSync as symlinkSync2, writeFileSync as writeFileSync15 } from "node:fs";
|
|
26047
26142
|
import { dirname as dirname17, join as join38, resolve as resolve24 } from "node:path";
|
|
26048
26143
|
import { tmpdir as tmpdir11 } from "node:os";
|
|
26049
26144
|
var stableId = (plugin) => plugin.marketplace === undefined ? plugin.name : `${plugin.name}@${plugin.marketplace}`;
|
|
@@ -26082,7 +26177,7 @@ var grokWriter = {
|
|
|
26082
26177
|
const activation = join38(grokRoot(), "plugins", plugin.name);
|
|
26083
26178
|
const existingNative = grok.listInstalled().find((candidate) => candidate.name === plugin.name)?.path;
|
|
26084
26179
|
assertActivationLink(activation, existingNative);
|
|
26085
|
-
const unchanged = lstatExists2(activation) && prior !== undefined && priorMarker?.fingerprint === plugin.contentFingerprint && priorMarker?.nativeFingerprint === nativeFingerprint &&
|
|
26180
|
+
const unchanged = lstatExists2(activation) && prior !== undefined && priorMarker?.fingerprint === plugin.contentFingerprint && priorMarker?.nativeFingerprint === nativeFingerprint && existsSync30(join38(prior, "plugins", plugin.name)) && fingerprintTree(join38(prior, "plugins", plugin.name)) === nativeFingerprint && current(id, prior, plugin.name, nativeFingerprint);
|
|
26086
26181
|
if (opts?.dryRun)
|
|
26087
26182
|
return unchanged ? "unchanged" : undefined;
|
|
26088
26183
|
if (unchanged)
|
|
@@ -26228,7 +26323,7 @@ function basename6(path) {
|
|
|
26228
26323
|
function assertActivationLink(link, nativePath) {
|
|
26229
26324
|
if (!lstatExists2(link))
|
|
26230
26325
|
return;
|
|
26231
|
-
if (nativePath === undefined || !
|
|
26326
|
+
if (nativePath === undefined || !lstatSync24(link).isSymbolicLink() || canonical(nativePath) === undefined || canonical(link) !== canonical(nativePath)) {
|
|
26232
26327
|
throw new Error(`Grok activation path is not the registered native plugin: ${link}`);
|
|
26233
26328
|
}
|
|
26234
26329
|
}
|
|
@@ -26294,7 +26389,7 @@ function validateGrokSource(dir) {
|
|
|
26294
26389
|
}
|
|
26295
26390
|
function projectGrokSource(dir) {
|
|
26296
26391
|
const manifest = join38(dir, "plugin.json");
|
|
26297
|
-
if (
|
|
26392
|
+
if (existsSync30(manifest)) {
|
|
26298
26393
|
const doc = JSON.parse(readFileSync32(manifest, "utf8"));
|
|
26299
26394
|
if (doc["permissions"] !== undefined)
|
|
26300
26395
|
throw new Error(`Grok permission semantics are unverified: ${manifest}`);
|
|
@@ -26302,13 +26397,13 @@ function projectGrokSource(dir) {
|
|
|
26302
26397
|
throw new Error(`Grok custom command path is unverified: ${manifest}`);
|
|
26303
26398
|
}
|
|
26304
26399
|
const skills = join38(dir, "skills");
|
|
26305
|
-
if (
|
|
26400
|
+
if (existsSync30(skills))
|
|
26306
26401
|
for (const name of readdirSync22(skills)) {
|
|
26307
26402
|
const skill = join38(skills, name);
|
|
26308
|
-
if (!
|
|
26403
|
+
if (!lstatSync24(skill).isDirectory())
|
|
26309
26404
|
continue;
|
|
26310
26405
|
const file = join38(skill, "SKILL.md");
|
|
26311
|
-
if (!
|
|
26406
|
+
if (!existsSync30(file))
|
|
26312
26407
|
continue;
|
|
26313
26408
|
const raw = readFileSync32(file, "utf8");
|
|
26314
26409
|
const fm = openingFrontmatter3(raw, file);
|
|
@@ -26318,7 +26413,7 @@ function projectGrokSource(dir) {
|
|
|
26318
26413
|
normalizeBooleanPolicy(fm, "user-invocable", "user_invocable", file);
|
|
26319
26414
|
const sidecar = join38(skill, "agents", "openai.yaml");
|
|
26320
26415
|
let sidecarManual;
|
|
26321
|
-
if (
|
|
26416
|
+
if (existsSync30(sidecar)) {
|
|
26322
26417
|
const parsed = yamlParse(readFileSync32(sidecar, "utf8"));
|
|
26323
26418
|
const policy = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed["policy"] : undefined;
|
|
26324
26419
|
if (policy !== undefined) {
|
|
@@ -26340,19 +26435,19 @@ function projectGrokSource(dir) {
|
|
|
26340
26435
|
const commands = join38(dir, "commands");
|
|
26341
26436
|
const claudeCommands = join38(dir, ".claude", "commands");
|
|
26342
26437
|
const seen = new Set;
|
|
26343
|
-
for (const source of [
|
|
26344
|
-
if (!
|
|
26438
|
+
for (const source of [existsSync30(commands) ? commands : claudeCommands]) {
|
|
26439
|
+
if (!existsSync30(source))
|
|
26345
26440
|
continue;
|
|
26346
26441
|
for (const entry of readdirSync22(source)) {
|
|
26347
26442
|
const path = join38(source, entry);
|
|
26348
|
-
const stat =
|
|
26443
|
+
const stat = lstatSync24(path);
|
|
26349
26444
|
if (!stat.isFile() || !/\.(md|toml)$/u.test(entry))
|
|
26350
26445
|
continue;
|
|
26351
26446
|
const name = entry.replace(/\.(md|toml)$/u, "");
|
|
26352
26447
|
if (seen.has(name))
|
|
26353
26448
|
throw new Error(`duplicate Grok command ${name}`);
|
|
26354
26449
|
seen.add(name);
|
|
26355
|
-
if (
|
|
26450
|
+
if (existsSync30(join38(skills, name, "SKILL.md")))
|
|
26356
26451
|
throw new Error(`Grok command ${name} collides with a native skill`);
|
|
26357
26452
|
const output = join38(commands, `${name}.md`);
|
|
26358
26453
|
if (entry.endsWith(".md")) {
|
|
@@ -26403,11 +26498,11 @@ ${doc.prompt}`);
|
|
|
26403
26498
|
}
|
|
26404
26499
|
const legacyMcp = join38(dir, "mcp.json");
|
|
26405
26500
|
const nativeMcp = join38(dir, ".mcp.json");
|
|
26406
|
-
if (
|
|
26501
|
+
if (existsSync30(legacyMcp) && existsSync30(nativeMcp) && canonicalJson2(JSON.parse(readFileSync32(legacyMcp, "utf8")).mcpServers) !== canonicalJson2(JSON.parse(readFileSync32(nativeMcp, "utf8")).mcpServers))
|
|
26407
26502
|
throw new Error(`conflicting Grok MCP declarations: ${legacyMcp} and ${nativeMcp}`);
|
|
26408
|
-
if (
|
|
26503
|
+
if (existsSync30(legacyMcp) && !existsSync30(nativeMcp))
|
|
26409
26504
|
cpSync13(legacyMcp, nativeMcp);
|
|
26410
|
-
if (
|
|
26505
|
+
if (existsSync30(nativeMcp)) {
|
|
26411
26506
|
const value = JSON.parse(readFileSync32(nativeMcp, "utf8"));
|
|
26412
26507
|
const servers = value?.["mcpServers"];
|
|
26413
26508
|
if (!value || typeof value !== "object" || !servers || typeof servers !== "object" || Array.isArray(servers))
|
|
@@ -26457,28 +26552,28 @@ function legacyCandidate(plugin, adopt, prior) {
|
|
|
26457
26552
|
throw new Error(`Grok ${plugin.name}: an existing native install is not plgnz-owned; refusing to replace it`);
|
|
26458
26553
|
const installed = canonical(matches[0].path);
|
|
26459
26554
|
const base = canonical(join38(grokRoot(), "installed-plugins"));
|
|
26460
|
-
if (installed === undefined || base === undefined || !installed.startsWith(`${base}/`) ||
|
|
26555
|
+
if (installed === undefined || base === undefined || !installed.startsWith(`${base}/`) || lstatSync24(matches[0].path).isSymbolicLink())
|
|
26461
26556
|
throw new Error(`Grok ${plugin.name}: legacy native path is unsafe`);
|
|
26462
26557
|
const rows = repos().filter(([, repo]) => canonical(typeof repo.path === "string" ? repo.path : "") === installed);
|
|
26463
26558
|
if (rows.length !== 1 || provenanceOf(rows[0][1]) !== null || namesOf(rows[0][1]).length !== 1 || namesOf(rows[0][1])[0] !== plugin.name)
|
|
26464
26559
|
throw new Error(`Grok ${plugin.name}: legacy native identity is ambiguous`);
|
|
26465
26560
|
const source = localSourceOf(rows[0][1]);
|
|
26466
|
-
if (source === undefined || !
|
|
26561
|
+
if (source === undefined || !existsSync30(source) || lstatSync24(source).isSymbolicLink())
|
|
26467
26562
|
throw new Error(`Grok ${plugin.name}: legacy source is missing or unsafe`);
|
|
26468
26563
|
const oldManifest = JSON.parse(readFileSync32(join38(installed, "plugin.json"), "utf8"));
|
|
26469
26564
|
const newManifest = JSON.parse(readFileSync32(join38(plugin.dir, "plugin.json"), "utf8"));
|
|
26470
26565
|
if (oldManifest.name !== plugin.name || newManifest.name !== plugin.name || oldManifest.version !== newManifest.version || fingerprintTree(source) !== fingerprintTree(installed))
|
|
26471
26566
|
throw new Error(`Grok ${plugin.name}: legacy source, version, and native bytes must match before adoption`);
|
|
26472
26567
|
const link = join38(grokRoot(), "plugins", plugin.name);
|
|
26473
|
-
if (
|
|
26474
|
-
if (!
|
|
26568
|
+
if (existsSync30(link) || lstatExists2(link)) {
|
|
26569
|
+
if (!lstatSync24(link).isSymbolicLink() || canonical(resolve24(dirname17(link), readlinkSync3(link))) !== installed)
|
|
26475
26570
|
throw new Error(`Grok ${plugin.name}: unmanaged same-name plugin link blocks adoption`);
|
|
26476
26571
|
}
|
|
26477
26572
|
return { source, fingerprint: fingerprintTree(installed), ...lstatExists2(link) ? { link } : {} };
|
|
26478
26573
|
}
|
|
26479
26574
|
function lstatExists2(path) {
|
|
26480
26575
|
try {
|
|
26481
|
-
|
|
26576
|
+
lstatSync24(path);
|
|
26482
26577
|
return true;
|
|
26483
26578
|
} catch {
|
|
26484
26579
|
return false;
|
|
@@ -26505,7 +26600,7 @@ function assertOwnedRoot(root) {
|
|
|
26505
26600
|
let current = base;
|
|
26506
26601
|
for (const part of relative) {
|
|
26507
26602
|
current = join38(current, part);
|
|
26508
|
-
const stat =
|
|
26603
|
+
const stat = lstatSync24(current);
|
|
26509
26604
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
26510
26605
|
throw new Error(`Grok marketplace root is not a safe owned directory: ${current}`);
|
|
26511
26606
|
}
|
|
@@ -26697,7 +26792,7 @@ function configPriorRecord(attemptId, operationId) {
|
|
|
26697
26792
|
}
|
|
26698
26793
|
function discardStage(attemptId, operationId) {
|
|
26699
26794
|
const record = stageRecord(attemptId, operationId);
|
|
26700
|
-
if (
|
|
26795
|
+
if (existsSync30(record)) {
|
|
26701
26796
|
const stage = readFileSync32(record, "utf8").trim();
|
|
26702
26797
|
if (stage !== "")
|
|
26703
26798
|
rmSync15(stage, { recursive: true, force: true });
|
|
@@ -26763,7 +26858,7 @@ function marketplacePathOf(repo) {
|
|
|
26763
26858
|
}
|
|
26764
26859
|
function savedRegistryRepo(directory) {
|
|
26765
26860
|
const file = join38(directory, "registry-repo.json");
|
|
26766
|
-
if (!
|
|
26861
|
+
if (!existsSync30(file))
|
|
26767
26862
|
return { key: null, repo: null };
|
|
26768
26863
|
const value = JSON.parse(readFileSync32(file, "utf8"));
|
|
26769
26864
|
const key = typeof value.key === "string" ? value.key : null;
|
|
@@ -26833,7 +26928,7 @@ function captureHostSnapshot(directory, nativeId, packageName, attemptId, operat
|
|
|
26833
26928
|
rmSync15(directory, { recursive: true, force: true });
|
|
26834
26929
|
mkdirSync15(directory, { recursive: true });
|
|
26835
26930
|
const priorConfig = configPriorRecord(attemptId, operationId);
|
|
26836
|
-
if (
|
|
26931
|
+
if (existsSync30(priorConfig))
|
|
26837
26932
|
cpSync13(priorConfig, join38(directory, "config-prior.json"));
|
|
26838
26933
|
const plugin = grok.listInstalled().find((candidate) => candidate.id === nativeId);
|
|
26839
26934
|
if (plugin?.path !== undefined) {
|
|
@@ -26851,7 +26946,7 @@ function captureHostSnapshot(directory, nativeId, packageName, attemptId, operat
|
|
|
26851
26946
|
const matched = matchingRegistryRepo(nativeId, packageName);
|
|
26852
26947
|
writeFileSync15(join38(directory, "registry-repo.json"), JSON.stringify(matched === undefined ? { key: null } : { key: matched[0], repo: matched[1] }));
|
|
26853
26948
|
const link = join38(grokRoot(), "plugins", packageName);
|
|
26854
|
-
if (lstatExists2(link) &&
|
|
26949
|
+
if (lstatExists2(link) && lstatSync24(link).isSymbolicLink())
|
|
26855
26950
|
writeFileSync15(join38(directory, "link.txt"), readlinkSync3(link));
|
|
26856
26951
|
}
|
|
26857
26952
|
function freshNativePaths(directory, marketplacePath) {
|
|
@@ -26870,17 +26965,17 @@ function freshNativePaths(directory, marketplacePath) {
|
|
|
26870
26965
|
}
|
|
26871
26966
|
function restoreActivationLink(directory, packageName) {
|
|
26872
26967
|
const link = join38(grokRoot(), "plugins", packageName);
|
|
26873
|
-
if (
|
|
26968
|
+
if (existsSync30(join38(directory, "link.txt"))) {
|
|
26874
26969
|
if (lstatExists2(link))
|
|
26875
26970
|
rmSync15(link);
|
|
26876
26971
|
symlinkSync2(readFileSync32(join38(directory, "link.txt"), "utf8"), link);
|
|
26877
26972
|
return;
|
|
26878
26973
|
}
|
|
26879
|
-
if (lstatExists2(link) &&
|
|
26974
|
+
if (lstatExists2(link) && lstatSync24(link).isSymbolicLink())
|
|
26880
26975
|
rmSync15(link);
|
|
26881
26976
|
}
|
|
26882
26977
|
function restoreConfigFile(record) {
|
|
26883
|
-
if (!
|
|
26978
|
+
if (!existsSync30(record))
|
|
26884
26979
|
return;
|
|
26885
26980
|
const value = JSON.parse(readFileSync32(record, "utf8"));
|
|
26886
26981
|
const file = configFile3();
|
|
@@ -26898,8 +26993,8 @@ function restoreHostSnapshot(directory, scopeId, nativeId, packageName) {
|
|
|
26898
26993
|
const finalPath = lifecycleMarketplace(scopeId, nativeId);
|
|
26899
26994
|
const backupPath = join38(directory, "backup-path.txt");
|
|
26900
26995
|
const nativePathFile = join38(directory, "native-path.txt");
|
|
26901
|
-
const hadNative =
|
|
26902
|
-
const hadMarketplace =
|
|
26996
|
+
const hadNative = existsSync30(nativePathFile);
|
|
26997
|
+
const hadMarketplace = existsSync30(join38(directory, "marketplace"));
|
|
26903
26998
|
if (!hadNative)
|
|
26904
26999
|
for (const native of freshNativePaths(directory, finalPath))
|
|
26905
27000
|
rmSync15(native, { recursive: true, force: true });
|
|
@@ -26919,7 +27014,7 @@ function restoreHostSnapshot(directory, scopeId, nativeId, packageName) {
|
|
|
26919
27014
|
restoreRegistryKey(directory, finalPath, packageName);
|
|
26920
27015
|
restoreActivationLink(directory, packageName);
|
|
26921
27016
|
restoreRecordedConfig(directory);
|
|
26922
|
-
if (
|
|
27017
|
+
if (existsSync30(backupPath))
|
|
26923
27018
|
rmSync15(readFileSync32(backupPath, "utf8"), { recursive: true, force: true });
|
|
26924
27019
|
if (hadNative) {
|
|
26925
27020
|
run(["plugin", "update", packageName]);
|
|
@@ -26946,7 +27041,7 @@ ${tail}`;
|
|
|
26946
27041
|
}
|
|
26947
27042
|
function pinPluginAutoUpdate(attemptId, operationId) {
|
|
26948
27043
|
const file = configFile3();
|
|
26949
|
-
const present =
|
|
27044
|
+
const present = existsSync30(file);
|
|
26950
27045
|
const current = present ? readFileSync32(file, "utf8") : "";
|
|
26951
27046
|
const record = configPriorRecord(attemptId, operationId);
|
|
26952
27047
|
mkdirSync15(dirname17(record), { recursive: true });
|
|
@@ -27048,7 +27143,7 @@ var grokLifecycleDefinition = {
|
|
|
27048
27143
|
refreshStagedFingerprint(prepared.stagingRoot, nativeFingerprint);
|
|
27049
27144
|
const finalPath = lifecycleMarketplace(prepared.handle.scopeId, prepared.handle.nativeId);
|
|
27050
27145
|
const stagedRoot = dirname17(dirname17(prepared.stagingRoot));
|
|
27051
|
-
const backup =
|
|
27146
|
+
const backup = existsSync30(finalPath) ? `${finalPath}.plgnz-backup-${prepared.handle.attemptId}` : undefined;
|
|
27052
27147
|
if (backup !== undefined)
|
|
27053
27148
|
renameSync12(finalPath, backup);
|
|
27054
27149
|
renameSync12(stagedRoot, finalPath);
|
|
@@ -27136,25 +27231,25 @@ function createGrokLifecycleAdapter() {
|
|
|
27136
27231
|
|
|
27137
27232
|
// src/hosts/zcode-cli-writer.ts
|
|
27138
27233
|
init_zcode_cli_hooks();
|
|
27139
|
-
import { chmodSync as chmodSync3, cpSync as cpSync14, existsSync as
|
|
27234
|
+
import { chmodSync as chmodSync3, cpSync as cpSync14, existsSync as existsSync31, lstatSync as lstatSync26, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync15, readFileSync as readFileSync34, readdirSync as readdirSync24, realpathSync as realpathSync6, renameSync as renameSync13, rmSync as rmSync16, statSync as statSync13, writeFileSync as writeFileSync16 } from "node:fs";
|
|
27140
27235
|
import { basename as basename7, dirname as dirname19, join as join40, resolve as resolve26 } from "node:path";
|
|
27141
27236
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
27142
27237
|
|
|
27143
27238
|
// src/hosts/zcode-cli-projection.ts
|
|
27144
|
-
import { lstatSync as
|
|
27239
|
+
import { lstatSync as lstatSync25, readFileSync as readFileSync33, readdirSync as readdirSync23 } from "node:fs";
|
|
27145
27240
|
import { dirname as dirname18, join as join39, relative as relative8, resolve as resolve25 } from "node:path";
|
|
27146
27241
|
var encode2 = (value) => new TextEncoder().encode(value);
|
|
27147
27242
|
var decode = (value) => new TextDecoder().decode(value);
|
|
27148
27243
|
function readZcodeProjectionTree(root) {
|
|
27149
27244
|
const tree = new Map;
|
|
27150
27245
|
const walk = (path, prefix) => {
|
|
27151
|
-
const stat =
|
|
27246
|
+
const stat = lstatSync25(path);
|
|
27152
27247
|
if (stat.isSymbolicLink())
|
|
27153
27248
|
throw new Error(`ZCode projection contains symlink: ${path}`);
|
|
27154
27249
|
if (!stat.isDirectory())
|
|
27155
27250
|
throw new Error(`ZCode projection root is not a directory: ${path}`);
|
|
27156
27251
|
for (const name of readdirSync23(path).sort()) {
|
|
27157
|
-
const file = join39(path, name), key = prefix === "" ? name : `${prefix}/${name}`, child =
|
|
27252
|
+
const file = join39(path, name), key = prefix === "" ? name : `${prefix}/${name}`, child = lstatSync25(file);
|
|
27158
27253
|
if (child.isSymbolicLink())
|
|
27159
27254
|
throw new Error(`ZCode projection contains symlink: ${file}`);
|
|
27160
27255
|
if (child.isDirectory()) {
|
|
@@ -27426,7 +27521,7 @@ function projectZcodePlugin(source, destination, resourceCopy, resourceLinkRoot,
|
|
|
27426
27521
|
const target = resolve26(destination);
|
|
27427
27522
|
const ownedResources = resolve26(resourceCopy);
|
|
27428
27523
|
const links = resolve26(resourceLinkRoot);
|
|
27429
|
-
if (!
|
|
27524
|
+
if (!existsSync31(input) || !statSync13(input).isDirectory())
|
|
27430
27525
|
throw new Error(`ZCode plugin source is not a directory: ${input}`);
|
|
27431
27526
|
if (target === input || ownedResources === input || target.startsWith(`${input}/`) || ownedResources.startsWith(`${input}/`))
|
|
27432
27527
|
throw new Error("ZCode projected outputs must not be inside the source");
|
|
@@ -27438,7 +27533,7 @@ function projectZcodePlugin(source, destination, resourceCopy, resourceLinkRoot,
|
|
|
27438
27533
|
}
|
|
27439
27534
|
for (const output of [target, ownedResources]) {
|
|
27440
27535
|
try {
|
|
27441
|
-
|
|
27536
|
+
lstatSync26(output);
|
|
27442
27537
|
assertNoSymlinks7(output);
|
|
27443
27538
|
} catch (error) {
|
|
27444
27539
|
if (error.code !== "ENOENT")
|
|
@@ -27487,7 +27582,7 @@ function readJson3(file) {
|
|
|
27487
27582
|
}
|
|
27488
27583
|
}
|
|
27489
27584
|
function commandNames(dir, prefix = "") {
|
|
27490
|
-
if (!
|
|
27585
|
+
if (!existsSync31(dir))
|
|
27491
27586
|
return [];
|
|
27492
27587
|
const out = [];
|
|
27493
27588
|
for (const name of readdirSync24(dir)) {
|
|
@@ -27532,7 +27627,7 @@ function nativeForLogical(logicalId) {
|
|
|
27532
27627
|
}
|
|
27533
27628
|
function sameCandidate(prior, market, resources, resourceRoot, logical, native, source, fingerprint) {
|
|
27534
27629
|
const marker = readZcodeOwnership(prior.installPath);
|
|
27535
|
-
if (marker?.logicalId !== logical || marker.nativeId !== native || marker.source !== source || marker.fingerprint !== fingerprint || marker.resourcePath !== resourceRoot || !
|
|
27630
|
+
if (marker?.logicalId !== logical || marker.nativeId !== native || marker.source !== source || marker.fingerprint !== fingerprint || marker.resourcePath !== resourceRoot || !existsSync31(resourceRoot))
|
|
27536
27631
|
return false;
|
|
27537
27632
|
try {
|
|
27538
27633
|
return fingerprintTree(join40(market, "plugins", prior.name)) === fingerprintTree(prior.installPath) && fingerprintTree(resources) === fingerprintTree(resourceRoot);
|
|
@@ -27541,21 +27636,21 @@ function sameCandidate(prior, market, resources, resourceRoot, logical, native,
|
|
|
27541
27636
|
}
|
|
27542
27637
|
}
|
|
27543
27638
|
function assertReplaceableOwnedRoots(market, resources, name, prior, logical, native, source) {
|
|
27544
|
-
if (!
|
|
27639
|
+
if (!existsSync31(market) && !existsSync31(resources))
|
|
27545
27640
|
return;
|
|
27546
27641
|
if (prior === undefined)
|
|
27547
|
-
throw new Error(`Official ZCode owned path already exists without a proven native install: ${
|
|
27642
|
+
throw new Error(`Official ZCode owned path already exists without a proven native install: ${existsSync31(market) ? market : resources}`);
|
|
27548
27643
|
const priorRoot = zcodeSafeInstallRoot(prior.installPath);
|
|
27549
27644
|
const marker = priorRoot === undefined ? null : readZcodeOwnership(priorRoot);
|
|
27550
27645
|
if (marker?.logicalId !== logical || marker.nativeId !== native || marker.source !== source)
|
|
27551
27646
|
throw new Error(`Official ZCode existing paths are not proven owned: ${native}`);
|
|
27552
|
-
if (
|
|
27647
|
+
if (existsSync31(market)) {
|
|
27553
27648
|
assertNoSymlinks7(market);
|
|
27554
27649
|
const staged = readZcodeOwnership(join40(market, "plugins", name));
|
|
27555
27650
|
if (staged?.logicalId !== logical || staged.nativeId !== native || staged.source !== source)
|
|
27556
27651
|
throw new Error(`Official ZCode marketplace root is not proven owned: ${market}`);
|
|
27557
27652
|
}
|
|
27558
|
-
if (
|
|
27653
|
+
if (existsSync31(resources) && marker.resourcePath !== resources)
|
|
27559
27654
|
throw new Error(`Official ZCode resource root is not proven owned: ${resources}`);
|
|
27560
27655
|
}
|
|
27561
27656
|
function provePrior(prior, logical, native, source) {
|
|
@@ -27613,12 +27708,12 @@ function requireFingerprint(plugin) {
|
|
|
27613
27708
|
return fp.toLowerCase();
|
|
27614
27709
|
}
|
|
27615
27710
|
function moveAside4(path) {
|
|
27616
|
-
if (!
|
|
27711
|
+
if (!existsSync31(path))
|
|
27617
27712
|
return { rollback: () => {}, commit: () => {} };
|
|
27618
27713
|
const backup = `${path}.plgnz-backup-${Date.now()}`;
|
|
27619
27714
|
renameSync13(path, backup);
|
|
27620
27715
|
return { rollback: () => {
|
|
27621
|
-
if (!
|
|
27716
|
+
if (!existsSync31(path))
|
|
27622
27717
|
renameSync13(backup, path);
|
|
27623
27718
|
}, commit: () => rmSync16(backup, { recursive: true, force: true }) };
|
|
27624
27719
|
}
|
|
@@ -27628,7 +27723,7 @@ function assertName(value, label) {
|
|
|
27628
27723
|
}
|
|
27629
27724
|
function assertNoSymlinks7(root) {
|
|
27630
27725
|
const visit = (path) => {
|
|
27631
|
-
const stat =
|
|
27726
|
+
const stat = lstatSync26(path);
|
|
27632
27727
|
if (stat.isSymbolicLink())
|
|
27633
27728
|
throw new Error(`ZCode source contains symlink: ${path}`);
|
|
27634
27729
|
if (stat.isDirectory())
|
|
@@ -27745,7 +27840,7 @@ function capturedNativeRoot(reference, attemptId, operationId) {
|
|
|
27745
27840
|
const root = dirname19(dirname19(dirname19(reference)));
|
|
27746
27841
|
for (const ancestor of [join40(root, "plgnz-lifecycle"), join40(root, "plgnz-lifecycle", attemptId), reference]) {
|
|
27747
27842
|
try {
|
|
27748
|
-
if (
|
|
27843
|
+
if (lstatSync26(ancestor).isSymbolicLink())
|
|
27749
27844
|
throw new Error("ZCode captured snapshot ancestor was redirected");
|
|
27750
27845
|
} catch (error) {
|
|
27751
27846
|
if (!isObject4(error) || error["code"] !== "ENOENT")
|
|
@@ -27757,7 +27852,7 @@ function capturedNativeRoot(reference, attemptId, operationId) {
|
|
|
27757
27852
|
return root;
|
|
27758
27853
|
}
|
|
27759
27854
|
function assertStageCleanupAuthority(stage, reference) {
|
|
27760
|
-
if (
|
|
27855
|
+
if (lstatSync26(dirname19(stage)).isSymbolicLink() || lstatSync26(stage).isSymbolicLink())
|
|
27761
27856
|
throw new Error("ZCode cleanup stage is redirected");
|
|
27762
27857
|
assertNoSymlinks7(stage);
|
|
27763
27858
|
const artifact = reference.artifactId;
|
|
@@ -27796,7 +27891,7 @@ function assertStageCleanupAuthority(stage, reference) {
|
|
|
27796
27891
|
}
|
|
27797
27892
|
function readConfigObject() {
|
|
27798
27893
|
const file = join40(zcodeCliConfigRoot(), "config.json");
|
|
27799
|
-
if (!
|
|
27894
|
+
if (!existsSync31(file))
|
|
27800
27895
|
return null;
|
|
27801
27896
|
const value = JSON.parse(readFileSync34(file, "utf8"));
|
|
27802
27897
|
if (!isObject4(value))
|
|
@@ -27814,7 +27909,7 @@ function optionValue(nativeId) {
|
|
|
27814
27909
|
}
|
|
27815
27910
|
function retainedState(nativeId) {
|
|
27816
27911
|
const dataDir = zcodePluginDataDir(nativeId);
|
|
27817
|
-
const pluginData =
|
|
27912
|
+
const pluginData = existsSync31(dataDir) && statSync13(dataDir).isDirectory() ? { state: "present", fingerprint: fingerprintTree(dataDir) } : { state: "absent", fingerprint: null };
|
|
27818
27913
|
const options = optionValue(nativeId);
|
|
27819
27914
|
const inactiveMetadata = options === undefined ? { state: "absent", fingerprint: null } : { state: "present", fingerprint: sha2562(canonicalJson3(options)) };
|
|
27820
27915
|
return { pluginData, inactiveMetadata };
|
|
@@ -27906,9 +28001,9 @@ function resourceObservation2(root, digest) {
|
|
|
27906
28001
|
const expected = join40(zcodeResourceRoot(), marketplaceName2(marker.nativeId), marker.fingerprint);
|
|
27907
28002
|
if (canonicalExistingPath(resourcePath) !== canonicalExistingPath(expected))
|
|
27908
28003
|
throw new Error("ZCode resource receipt names a foreign root");
|
|
27909
|
-
if (!
|
|
28004
|
+
if (!existsSync31(resourcePath))
|
|
27910
28005
|
return { roots, conforming: false };
|
|
27911
|
-
if (
|
|
28006
|
+
if (lstatSync26(resourcePath).isSymbolicLink())
|
|
27912
28007
|
throw new Error("ZCode resource receipt root is redirected");
|
|
27913
28008
|
const resource = realpathSync6(resourcePath);
|
|
27914
28009
|
const owned = realpathSync6(zcodeResourceRoot());
|
|
@@ -27922,7 +28017,7 @@ function retirementSnapshot(attemptId, operationId, nativeId) {
|
|
|
27922
28017
|
const dir = join40(realpathSync6(zcodeCliRoot()), "plgnz-lifecycle", attemptId, operationId);
|
|
27923
28018
|
if (canonicalExistingPath(dir) !== dir)
|
|
27924
28019
|
throw new Error("ZCode rollback snapshot path is redirected");
|
|
27925
|
-
if (
|
|
28020
|
+
if (existsSync31(dir)) {
|
|
27926
28021
|
if (!statSync13(dir).isDirectory())
|
|
27927
28022
|
throw new Error(`ZCode rollback snapshot already exists and is not a directory: ${dir}`);
|
|
27928
28023
|
return dir;
|
|
@@ -27934,17 +28029,17 @@ function retirementSnapshot(attemptId, operationId, nativeId) {
|
|
|
27934
28029
|
cpSync14(root, join40(dir, "cache"), { recursive: true });
|
|
27935
28030
|
writeFileSync16(join40(dir, "install-path.txt"), root ?? "");
|
|
27936
28031
|
const registry = zcodeRegistryFile();
|
|
27937
|
-
if (
|
|
28032
|
+
if (existsSync31(registry))
|
|
27938
28033
|
cpSync14(registry, join40(dir, "installed_plugins.json"));
|
|
27939
28034
|
const config = join40(zcodeCliConfigRoot(), "config.json");
|
|
27940
|
-
if (
|
|
28035
|
+
if (existsSync31(config))
|
|
27941
28036
|
cpSync14(config, join40(dir, "config.json"));
|
|
27942
28037
|
return dir;
|
|
27943
28038
|
}
|
|
27944
28039
|
function canonicalExistingPath(path) {
|
|
27945
28040
|
const missing = [];
|
|
27946
28041
|
let current = path;
|
|
27947
|
-
while (!
|
|
28042
|
+
while (!existsSync31(current)) {
|
|
27948
28043
|
const parent = dirname19(current);
|
|
27949
28044
|
if (parent === current)
|
|
27950
28045
|
throw new Error(`ZCode path does not exist: ${path}`);
|
|
@@ -27960,7 +28055,7 @@ function isCacheInstallPath(path) {
|
|
|
27960
28055
|
}
|
|
27961
28056
|
function removeRegistryPlugin(nativeId) {
|
|
27962
28057
|
const file = zcodeRegistryFile();
|
|
27963
|
-
if (!
|
|
28058
|
+
if (!existsSync31(file))
|
|
27964
28059
|
return false;
|
|
27965
28060
|
const value = JSON.parse(readFileSync34(file, "utf8"));
|
|
27966
28061
|
if (!isObject4(value) || !Array.isArray(value["plugins"]))
|
|
@@ -27976,7 +28071,7 @@ function removeRegistryPlugin(nativeId) {
|
|
|
27976
28071
|
}
|
|
27977
28072
|
function removeEnabledFlag(nativeId) {
|
|
27978
28073
|
const file = join40(zcodeCliConfigRoot(), "config.json");
|
|
27979
|
-
if (!
|
|
28074
|
+
if (!existsSync31(file))
|
|
27980
28075
|
return;
|
|
27981
28076
|
const value = readConfigObject();
|
|
27982
28077
|
if (value === null || !isObject4(value["plugins"]) || !isObject4(value["plugins"]["enabledPlugins"]))
|
|
@@ -27988,7 +28083,7 @@ function removeEnabledFlag(nativeId) {
|
|
|
27988
28083
|
`);
|
|
27989
28084
|
}
|
|
27990
28085
|
function snapshotRegistryRow(file, nativeId) {
|
|
27991
|
-
if (!
|
|
28086
|
+
if (!existsSync31(file))
|
|
27992
28087
|
return;
|
|
27993
28088
|
const value = JSON.parse(readFileSync34(file, "utf8"));
|
|
27994
28089
|
if (!isObject4(value) || !Array.isArray(value["plugins"]))
|
|
@@ -28001,9 +28096,9 @@ function snapshotRegistryRow(file, nativeId) {
|
|
|
28001
28096
|
function restoreRegistryPlugin(nativeId, snapshotFile) {
|
|
28002
28097
|
const saved = snapshotRegistryRow(snapshotFile, nativeId);
|
|
28003
28098
|
const file = zcodeRegistryFile();
|
|
28004
|
-
if (!
|
|
28099
|
+
if (!existsSync31(file) && saved === undefined)
|
|
28005
28100
|
return;
|
|
28006
|
-
const live =
|
|
28101
|
+
const live = existsSync31(file) ? JSON.parse(readFileSync34(file, "utf8")) : { version: 1, plugins: [] };
|
|
28007
28102
|
if (!isObject4(live) || !Array.isArray(live["plugins"]))
|
|
28008
28103
|
throw new Error(`Official ZCode registry is unsupported: ${file}`);
|
|
28009
28104
|
const plugins = live["plugins"].filter((row) => !isObject4(row) || row["id"] !== nativeId);
|
|
@@ -28023,8 +28118,8 @@ function configSection(config, key) {
|
|
|
28023
28118
|
}
|
|
28024
28119
|
function restorePluginConfig(nativeId, snapshotFile) {
|
|
28025
28120
|
const file = join40(zcodeCliConfigRoot(), "config.json");
|
|
28026
|
-
const snapshot =
|
|
28027
|
-
const live =
|
|
28121
|
+
const snapshot = existsSync31(snapshotFile) ? readConfigObjectFrom(snapshotFile) : null;
|
|
28122
|
+
const live = existsSync31(file) ? readConfigObject() : {};
|
|
28028
28123
|
if (live === null)
|
|
28029
28124
|
throw new Error(`Official ZCode config is unsupported: ${file}`);
|
|
28030
28125
|
const savedPlugins = snapshot !== null && isObject4(snapshot["plugins"]) ? snapshot["plugins"] : undefined;
|
|
@@ -28067,7 +28162,7 @@ function stageLayout(stagingRoot) {
|
|
|
28067
28162
|
return { marketStage, resourcesStage: join40(dirname19(marketStage), "resources") };
|
|
28068
28163
|
}
|
|
28069
28164
|
function recordTree(dir, name, path) {
|
|
28070
|
-
const existed =
|
|
28165
|
+
const existed = existsSync31(path);
|
|
28071
28166
|
writeFileSync16(join40(dir, `${name}-path.txt`), path);
|
|
28072
28167
|
writeFileSync16(join40(dir, `${name}-existed.txt`), existed ? "1" : "0");
|
|
28073
28168
|
if (existed)
|
|
@@ -28078,7 +28173,7 @@ function knownMarketplacesFile() {
|
|
|
28078
28173
|
}
|
|
28079
28174
|
function readKnownMarketplaces() {
|
|
28080
28175
|
const file = knownMarketplacesFile();
|
|
28081
|
-
if (!
|
|
28176
|
+
if (!existsSync31(file))
|
|
28082
28177
|
return {};
|
|
28083
28178
|
const value = JSON.parse(readFileSync34(file, "utf8"));
|
|
28084
28179
|
if (!isObject4(value))
|
|
@@ -28097,7 +28192,7 @@ function writeKnownMarketplaces(markets) {
|
|
|
28097
28192
|
}
|
|
28098
28193
|
function recordMarketplaceEntry(dir, market) {
|
|
28099
28194
|
const flag = join40(dir, "marketplace-entry.txt");
|
|
28100
|
-
if (
|
|
28195
|
+
if (existsSync31(flag))
|
|
28101
28196
|
return;
|
|
28102
28197
|
const markets = readKnownMarketplaces();
|
|
28103
28198
|
const present = Object.hasOwn(markets, market);
|
|
@@ -28107,7 +28202,7 @@ function recordMarketplaceEntry(dir, market) {
|
|
|
28107
28202
|
}
|
|
28108
28203
|
function restoreMarketplaceEntry(dir, market) {
|
|
28109
28204
|
const flag = join40(dir, "marketplace-entry.txt");
|
|
28110
|
-
if (!
|
|
28205
|
+
if (!existsSync31(flag))
|
|
28111
28206
|
return;
|
|
28112
28207
|
const markets = readKnownMarketplaces();
|
|
28113
28208
|
if (readFileSync34(flag, "utf8") !== "1") {
|
|
@@ -28118,7 +28213,7 @@ function restoreMarketplaceEntry(dir, market) {
|
|
|
28118
28213
|
return;
|
|
28119
28214
|
}
|
|
28120
28215
|
const savedFile = join40(dir, "marketplace-entry.json");
|
|
28121
|
-
if (!
|
|
28216
|
+
if (!existsSync31(savedFile))
|
|
28122
28217
|
throw new Error("ZCode rollback marketplace entry is missing");
|
|
28123
28218
|
const saved = JSON.parse(readFileSync34(savedFile, "utf8"));
|
|
28124
28219
|
markets[market] = saved;
|
|
@@ -28126,9 +28221,9 @@ function restoreMarketplaceEntry(dir, market) {
|
|
|
28126
28221
|
}
|
|
28127
28222
|
function activationSnapshot(attemptId, operationId, nativeId, marketplace, resources) {
|
|
28128
28223
|
const dir = retirementSnapshot(attemptId, operationId, nativeId);
|
|
28129
|
-
if (!
|
|
28224
|
+
if (!existsSync31(join40(dir, "marketplace-path.txt")))
|
|
28130
28225
|
recordTree(dir, "marketplace", marketplace);
|
|
28131
|
-
if (!
|
|
28226
|
+
if (!existsSync31(join40(dir, "resources-path.txt")))
|
|
28132
28227
|
recordTree(dir, "resources", resources);
|
|
28133
28228
|
recordMarketplaceEntry(dir, marketplaceName2(nativeId));
|
|
28134
28229
|
return dir;
|
|
@@ -28136,7 +28231,7 @@ function activationSnapshot(attemptId, operationId, nativeId, marketplace, resou
|
|
|
28136
28231
|
function restoreRecordedTree(dir, name, ownedRoot) {
|
|
28137
28232
|
const pathFile = join40(dir, `${name}-path.txt`);
|
|
28138
28233
|
const existedFile = join40(dir, `${name}-existed.txt`);
|
|
28139
|
-
if (!
|
|
28234
|
+
if (!existsSync31(pathFile) || !existsSync31(existedFile))
|
|
28140
28235
|
return;
|
|
28141
28236
|
const path = readFileSync34(pathFile, "utf8");
|
|
28142
28237
|
const existed = readFileSync34(existedFile, "utf8") === "1";
|
|
@@ -28147,9 +28242,9 @@ function restoreRecordedTree(dir, name, ownedRoot) {
|
|
|
28147
28242
|
if (!target.startsWith(`${owned}/`))
|
|
28148
28243
|
throw new Error(`ZCode rollback ${name} path is outside its root`);
|
|
28149
28244
|
const copy = join40(dir, name);
|
|
28150
|
-
if (existed && !
|
|
28245
|
+
if (existed && !existsSync31(copy))
|
|
28151
28246
|
throw new Error(`ZCode rollback ${name} copy is missing`);
|
|
28152
|
-
if (!existed &&
|
|
28247
|
+
if (!existed && existsSync31(copy))
|
|
28153
28248
|
throw new Error(`ZCode rollback ${name} copy has no path`);
|
|
28154
28249
|
rmSync16(target, { recursive: true, force: true });
|
|
28155
28250
|
if (!existed)
|
|
@@ -28219,7 +28314,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28219
28314
|
const resourceRoot = join40(realpathSync6(zcodeCliRoot()), "plgnz-resources", market, snapshot.packageFingerprint);
|
|
28220
28315
|
const stageParent = join40(zcodeCliRoot(), ".plgnz-zcode-stage");
|
|
28221
28316
|
mkdirSync16(stageParent, { recursive: true });
|
|
28222
|
-
if (
|
|
28317
|
+
if (lstatSync26(stageParent).isSymbolicLink())
|
|
28223
28318
|
throw new Error("ZCode staging parent is redirected");
|
|
28224
28319
|
const stage = activationStage(request.selection.attemptId, request.selection.operationId);
|
|
28225
28320
|
mkdirSync16(stage);
|
|
@@ -28311,7 +28406,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28311
28406
|
const resourceRoot = marker.resourcePath;
|
|
28312
28407
|
const prior = nativeById(nativeId);
|
|
28313
28408
|
const priorRoot = prior === undefined ? undefined : zcodeSafeInstallRoot(prior.installPath);
|
|
28314
|
-
const unchanged = prior !== undefined && priorRoot !== undefined && prior.version === nativeVersion && readZcodeEnabledPluginIds().get(nativeId) === true && fingerprintTree(priorRoot) === fingerprintTree(prepared.stagingRoot) &&
|
|
28409
|
+
const unchanged = prior !== undefined && priorRoot !== undefined && prior.version === nativeVersion && readZcodeEnabledPluginIds().get(nativeId) === true && fingerprintTree(priorRoot) === fingerprintTree(prepared.stagingRoot) && existsSync31(resourceRoot) && fingerprintTree(resourceRoot) === fingerprintTree(resourcesStage);
|
|
28315
28410
|
if (unchanged)
|
|
28316
28411
|
return { receiptId: `apply:${prepared.handle.attemptId}:${prepared.handle.operationId}`, changed: false };
|
|
28317
28412
|
const marketBackup = moveAside4(marketRoot);
|
|
@@ -28364,11 +28459,11 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28364
28459
|
rollback: async (handle) => {
|
|
28365
28460
|
capturedNativeRoot(handle.rollbackReference, handle.attemptId, handle.operationId);
|
|
28366
28461
|
const dir = handle.rollbackReference;
|
|
28367
|
-
if (!
|
|
28462
|
+
if (!existsSync31(dir) || !statSync13(dir).isDirectory())
|
|
28368
28463
|
throw new Error("ZCode rollback snapshot is missing");
|
|
28369
|
-
const installPath =
|
|
28464
|
+
const installPath = existsSync31(join40(dir, "install-path.txt")) ? readFileSync34(join40(dir, "install-path.txt"), "utf8") : "";
|
|
28370
28465
|
const cache = join40(dir, "cache");
|
|
28371
|
-
const cachePresent =
|
|
28466
|
+
const cachePresent = existsSync31(cache);
|
|
28372
28467
|
if (installPath.length > 0 && !cachePresent)
|
|
28373
28468
|
throw new Error("ZCode rollback cache copy is missing");
|
|
28374
28469
|
if (installPath.length === 0 && cachePresent)
|
|
@@ -28406,7 +28501,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28406
28501
|
const parent = join40(realpathSync6(zcodeCliRoot()), "plgnz-lifecycle");
|
|
28407
28502
|
for (const candidate of [parent, join40(parent, reference.attemptId), join40(parent, reference.attemptId, reference.operationId)]) {
|
|
28408
28503
|
try {
|
|
28409
|
-
const stat =
|
|
28504
|
+
const stat = lstatSync26(candidate);
|
|
28410
28505
|
if (stat.isSymbolicLink() || candidate === join40(parent, reference.attemptId, reference.operationId))
|
|
28411
28506
|
throw new Error("ZCode pre-seal cleanup has no captured snapshot authority");
|
|
28412
28507
|
} catch (error) {
|
|
@@ -28416,7 +28511,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28416
28511
|
}
|
|
28417
28512
|
}
|
|
28418
28513
|
try {
|
|
28419
|
-
if (
|
|
28514
|
+
if (lstatSync26(dirname19(stage)).isSymbolicLink())
|
|
28420
28515
|
throw new Error("ZCode cleanup staging parent is redirected");
|
|
28421
28516
|
} catch (error) {
|
|
28422
28517
|
if (!isObject4(error) || error["code"] !== "ENOENT")
|
|
@@ -28424,7 +28519,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28424
28519
|
}
|
|
28425
28520
|
let stagePresent = true;
|
|
28426
28521
|
try {
|
|
28427
|
-
|
|
28522
|
+
lstatSync26(stage);
|
|
28428
28523
|
} catch (error) {
|
|
28429
28524
|
if (!isObject4(error) || error["code"] !== "ENOENT")
|
|
28430
28525
|
throw error;
|
|
@@ -28442,7 +28537,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28442
28537
|
var zcodeCliLifecycle = createLifecycleHostAdapter(zcodeCliLifecycleDefinition);
|
|
28443
28538
|
|
|
28444
28539
|
// src/hosts/hermes-writer.ts
|
|
28445
|
-
import { chmodSync as chmodSync4, cpSync as cpSync15, existsSync as
|
|
28540
|
+
import { chmodSync as chmodSync4, cpSync as cpSync15, existsSync as existsSync32, lstatSync as lstatSync27, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync16, readFileSync as readFileSync35, readdirSync as readdirSync25, realpathSync as realpathSync7, renameSync as renameSync14, rmSync as rmSync17, statSync as statSync14, writeFileSync as writeFileSync17 } from "node:fs";
|
|
28446
28541
|
import { basename as basename8, dirname as dirname20, isAbsolute as isAbsolute12, join as join41, resolve as resolve27 } from "node:path";
|
|
28447
28542
|
import { tmpdir as tmpdir13 } from "node:os";
|
|
28448
28543
|
|
|
@@ -28714,12 +28809,12 @@ var hermesWriter = {
|
|
|
28714
28809
|
assertReplaceable(target, packageStage, id, ownershipId, resolved.sourceUri, opts?.adoptExisting === true, validatePackage);
|
|
28715
28810
|
if (hasCompanion)
|
|
28716
28811
|
assertReplaceable(companion, companionStage, companionId, ownershipId, resolved.sourceUri, opts?.adoptExisting === true, validateCompanion);
|
|
28717
|
-
else if (
|
|
28812
|
+
else if (existsSync32(companion))
|
|
28718
28813
|
assertReplaceable(companion, undefined, companionId, ownershipId, resolved.sourceUri, opts?.adoptExisting === true, validateCompanion);
|
|
28719
28814
|
const primaryMarker = readOwnership5(target);
|
|
28720
28815
|
const companionMarker = readOwnership5(companion);
|
|
28721
28816
|
const unchangedPrimary = primaryMarker?.pluginId === ownershipId && primaryMarker.fingerprint === ownership.fingerprint && sameTree9(packageStage, target);
|
|
28722
|
-
const unchangedCompanion = hasCompanion ? companionMarker?.pluginId === ownershipId && companionMarker.fingerprint === ownership.fingerprint && sameTree9(companionStage, companion) : !
|
|
28817
|
+
const unchangedCompanion = hasCompanion ? companionMarker?.pluginId === ownershipId && companionMarker.fingerprint === ownership.fingerprint && sameTree9(companionStage, companion) : !existsSync32(companion);
|
|
28723
28818
|
if (opts?.dryRun)
|
|
28724
28819
|
return unchangedPrimary && unchangedCompanion ? "unchanged" : undefined;
|
|
28725
28820
|
if (unchangedPrimary && unchangedCompanion) {
|
|
@@ -28731,7 +28826,7 @@ var hermesWriter = {
|
|
|
28731
28826
|
changes.push(replaceTarget(packageStage, target, root));
|
|
28732
28827
|
if (hasCompanion)
|
|
28733
28828
|
changes.push(replaceTarget(companionStage, companion, root));
|
|
28734
|
-
else if (
|
|
28829
|
+
else if (existsSync32(companion))
|
|
28735
28830
|
changes.push(removeTarget(companion, root));
|
|
28736
28831
|
updatePluginConfig(effectiveConfigPath(), [id, ...hasCompanion ? [companionId] : []], hasCompanion ? [] : [companionId]);
|
|
28737
28832
|
for (const change of changes)
|
|
@@ -28763,14 +28858,14 @@ var hermesWriter = {
|
|
|
28763
28858
|
return;
|
|
28764
28859
|
const changes = [];
|
|
28765
28860
|
try {
|
|
28766
|
-
if (
|
|
28861
|
+
if (existsSync32(target))
|
|
28767
28862
|
changes.push(removeTarget(target, root));
|
|
28768
28863
|
const companionMarker = readOwnership5(companion);
|
|
28769
28864
|
const disable = [nativeId];
|
|
28770
28865
|
if (companionMarker !== null && companionMarker.pluginId === marker.pluginId && companionMarker.source === marker.source && companionMarker.fingerprint === marker.fingerprint) {
|
|
28771
28866
|
changes.push(removeTarget(companion, root));
|
|
28772
28867
|
disable.push(companionId);
|
|
28773
|
-
} else if (!
|
|
28868
|
+
} else if (!existsSync32(companion))
|
|
28774
28869
|
disable.push(companionId);
|
|
28775
28870
|
updatePluginConfig(effectiveConfigPath(), [], disable);
|
|
28776
28871
|
for (const change of changes)
|
|
@@ -28783,7 +28878,7 @@ var hermesWriter = {
|
|
|
28783
28878
|
}
|
|
28784
28879
|
};
|
|
28785
28880
|
function assertReplaceable(target, stage, expected, ownershipId, source, adopt, validate) {
|
|
28786
|
-
if (!
|
|
28881
|
+
if (!existsSync32(target))
|
|
28787
28882
|
return;
|
|
28788
28883
|
const marker = readOwnership5(target);
|
|
28789
28884
|
if (marker !== null) {
|
|
@@ -28801,7 +28896,7 @@ function assertReplaceable(target, stage, expected, ownershipId, source, adopt,
|
|
|
28801
28896
|
function validatePackage(root, expected) {
|
|
28802
28897
|
assertTree3(root);
|
|
28803
28898
|
const manifest = join41(root, "plugin.json");
|
|
28804
|
-
if (!
|
|
28899
|
+
if (!existsSync32(manifest))
|
|
28805
28900
|
throw new Error("Hermes stage has no Agent Plugins manifest");
|
|
28806
28901
|
let value;
|
|
28807
28902
|
try {
|
|
@@ -28817,7 +28912,7 @@ function validatePackage(root, expected) {
|
|
|
28817
28912
|
function validateCompanion(root, expected) {
|
|
28818
28913
|
assertTree3(root);
|
|
28819
28914
|
const manifest = join41(root, "plugin.yaml");
|
|
28820
|
-
if (!
|
|
28915
|
+
if (!existsSync32(manifest) || !existsSync32(join41(root, "__init__.py")))
|
|
28821
28916
|
throw new Error(`Hermes native companion is incomplete: ${root}`);
|
|
28822
28917
|
const value = yamlParse(readFileSync35(manifest, "utf8"));
|
|
28823
28918
|
if (!value || typeof value !== "object" || Array.isArray(value) || value.name !== expected)
|
|
@@ -28825,7 +28920,7 @@ function validateCompanion(root, expected) {
|
|
|
28825
28920
|
}
|
|
28826
28921
|
function readOwnership5(target) {
|
|
28827
28922
|
const file = join41(target, MARKER11);
|
|
28828
|
-
if (!
|
|
28923
|
+
if (!existsSync32(file))
|
|
28829
28924
|
return null;
|
|
28830
28925
|
try {
|
|
28831
28926
|
const value = JSON.parse(readFileSync35(file, "utf8"));
|
|
@@ -28840,7 +28935,7 @@ function readOwnership5(target) {
|
|
|
28840
28935
|
}
|
|
28841
28936
|
}
|
|
28842
28937
|
function replaceTarget(stage, target, root) {
|
|
28843
|
-
if (!
|
|
28938
|
+
if (!existsSync32(target)) {
|
|
28844
28939
|
renameSync14(stage, target);
|
|
28845
28940
|
return { commit: () => {}, rollback: () => rmSync17(target, { recursive: true, force: true }) };
|
|
28846
28941
|
}
|
|
@@ -28865,14 +28960,14 @@ function removeTarget(target, root) {
|
|
|
28865
28960
|
const backup = join41(backupRoot, "previous");
|
|
28866
28961
|
renameSync14(target, backup);
|
|
28867
28962
|
return { commit: () => rmSync17(backupRoot, { recursive: true, force: true }), rollback: () => {
|
|
28868
|
-
if (!
|
|
28963
|
+
if (!existsSync32(target))
|
|
28869
28964
|
renameSync14(backup, target);
|
|
28870
28965
|
rmSync17(backupRoot, { recursive: true, force: true });
|
|
28871
28966
|
} };
|
|
28872
28967
|
}
|
|
28873
28968
|
function updatePluginConfig(configured, enable, disable) {
|
|
28874
|
-
const actual =
|
|
28875
|
-
const exists =
|
|
28969
|
+
const actual = existsSync32(configured) && lstatSync27(configured).isSymbolicLink() ? realpathSync7(configured) : configured;
|
|
28970
|
+
const exists = existsSync32(actual);
|
|
28876
28971
|
const original = exists ? readFileSync35(actual, "utf8") : "";
|
|
28877
28972
|
let parsed = {};
|
|
28878
28973
|
if (original.trim() !== "") {
|
|
@@ -28930,7 +29025,7 @@ function effectiveConfigPath() {
|
|
|
28930
29025
|
const configured = resolve27(hermesConfigPath());
|
|
28931
29026
|
if (native === configured)
|
|
28932
29027
|
return configured;
|
|
28933
|
-
if (!
|
|
29028
|
+
if (!existsSync32(native) || !existsSync32(configured))
|
|
28934
29029
|
throw new Error(`Hermes only reads ${native}; configured path ${configured} must already resolve to the same file`);
|
|
28935
29030
|
const nativeReal = realpathSync7(native);
|
|
28936
29031
|
const configuredReal = realpathSync7(configured);
|
|
@@ -28939,7 +29034,7 @@ function effectiveConfigPath() {
|
|
|
28939
29034
|
throw new Error(`Hermes only reads ${native}; configured path ${configured} is a different file`);
|
|
28940
29035
|
}
|
|
28941
29036
|
function sameTree9(left, right) {
|
|
28942
|
-
if (!
|
|
29037
|
+
if (!existsSync32(right))
|
|
28943
29038
|
return false;
|
|
28944
29039
|
const list = (root) => {
|
|
28945
29040
|
const out = [];
|
|
@@ -28947,7 +29042,7 @@ function sameTree9(left, right) {
|
|
|
28947
29042
|
for (const name of readdirSync25(dir).sort()) {
|
|
28948
29043
|
if (name === MARKER11)
|
|
28949
29044
|
continue;
|
|
28950
|
-
const path = join41(dir, name), relative = prefix ? `${prefix}/${name}` : name, stat =
|
|
29045
|
+
const path = join41(dir, name), relative = prefix ? `${prefix}/${name}` : name, stat = lstatSync27(path);
|
|
28951
29046
|
if (stat.isSymbolicLink())
|
|
28952
29047
|
throw new Error(`Hermes plugin contains symlink: ${path}`);
|
|
28953
29048
|
if (stat.isDirectory())
|
|
@@ -28967,13 +29062,13 @@ function readBytes2(path) {
|
|
|
28967
29062
|
return readFileSync35(path);
|
|
28968
29063
|
}
|
|
28969
29064
|
function assertTree3(root) {
|
|
28970
|
-
const stat =
|
|
29065
|
+
const stat = lstatSync27(root);
|
|
28971
29066
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
28972
29067
|
throw new Error(`Hermes plugin source is not a real directory: ${root}`);
|
|
28973
29068
|
for (const name of readdirSync25(root)) {
|
|
28974
29069
|
if (name === MARKER11)
|
|
28975
29070
|
continue;
|
|
28976
|
-
const path = join41(root, name), entry =
|
|
29071
|
+
const path = join41(root, name), entry = lstatSync27(path);
|
|
28977
29072
|
if (entry.isSymbolicLink())
|
|
28978
29073
|
throw new Error(`Hermes plugin contains symlink: ${path}`);
|
|
28979
29074
|
if (entry.isDirectory())
|
|
@@ -28988,15 +29083,15 @@ function assertManagedPath5(root, target) {
|
|
|
28988
29083
|
throw new Error(`Hermes managed path escapes its store: ${target}`);
|
|
28989
29084
|
let current = base;
|
|
28990
29085
|
for (const part of selected.slice(base.length).split("/").filter(Boolean)) {
|
|
28991
|
-
if (
|
|
28992
|
-
const stat =
|
|
29086
|
+
if (existsSync32(current)) {
|
|
29087
|
+
const stat = lstatSync27(current);
|
|
28993
29088
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
28994
29089
|
throw new Error(`Hermes managed path component is unsafe: ${current}`);
|
|
28995
29090
|
}
|
|
28996
29091
|
current = join41(current, part);
|
|
28997
29092
|
}
|
|
28998
|
-
if (
|
|
28999
|
-
const stat =
|
|
29093
|
+
if (existsSync32(current)) {
|
|
29094
|
+
const stat = lstatSync27(current);
|
|
29000
29095
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
29001
29096
|
throw new Error(`Hermes managed path component is unsafe: ${current}`);
|
|
29002
29097
|
}
|
|
@@ -29144,7 +29239,7 @@ function verifiedSourceImportClosure(root) {
|
|
|
29144
29239
|
if (entry.startsWith(".") || entry === "__pycache__" || entry === "node_modules")
|
|
29145
29240
|
continue;
|
|
29146
29241
|
const path = join41(directory, entry);
|
|
29147
|
-
const stat =
|
|
29242
|
+
const stat = lstatSync27(path);
|
|
29148
29243
|
if (stat.isSymbolicLink()) {
|
|
29149
29244
|
if (entry.endsWith(".py") || statSync14(path).isDirectory())
|
|
29150
29245
|
return false;
|
|
@@ -29156,7 +29251,7 @@ function verifiedSourceImportClosure(root) {
|
|
|
29156
29251
|
return visit(root, true);
|
|
29157
29252
|
}
|
|
29158
29253
|
function hermesExecutableSource(binary, depth = 0) {
|
|
29159
|
-
if (depth > 4 || !isAbsolute12(binary) || !
|
|
29254
|
+
if (depth > 4 || !isAbsolute12(binary) || !existsSync32(binary))
|
|
29160
29255
|
return;
|
|
29161
29256
|
const executable = realpathSync7(binary);
|
|
29162
29257
|
if (!statSync14(executable).isFile())
|
|
@@ -29168,7 +29263,7 @@ exec `)) {
|
|
|
29168
29263
|
exec `.length));
|
|
29169
29264
|
if (args?.length === 2 && args[1] === "$@")
|
|
29170
29265
|
return hermesExecutableSource(args[0], depth + 1);
|
|
29171
|
-
if (args?.length !== 5 || args[1] !== "-I" || args[2] !== "-c" || args[4] !== "$@" || !isAbsolute12(args[0]) || !/^python(?:\d+(?:\.\d+)*)?$/u.test(basename8(args[0])) || !
|
|
29266
|
+
if (args?.length !== 5 || args[1] !== "-I" || args[2] !== "-c" || args[4] !== "$@" || !isAbsolute12(args[0]) || !/^python(?:\d+(?:\.\d+)*)?$/u.test(basename8(args[0])) || !existsSync32(args[0]))
|
|
29172
29267
|
return;
|
|
29173
29268
|
const code = args[3];
|
|
29174
29269
|
if (!code.startsWith(`import os, re, sys
|
|
@@ -29180,26 +29275,26 @@ exec `.length));
|
|
|
29180
29275
|
const root = literalPythonPath(bindings[0][1]);
|
|
29181
29276
|
if (root === undefined || code.replaceAll(bindings[0][1], "'/__PLUGNZ_HERMES_ROOT__'") !== hermesNativeBootstrap)
|
|
29182
29277
|
return;
|
|
29183
|
-
return root !== undefined && isAbsolute12(root) &&
|
|
29278
|
+
return root !== undefined && isAbsolute12(root) && existsSync32(join41(root, "hermes_cli", "main.py")) && realpathSync7(join41(root, "hermes_cli", "main.py")).startsWith(`${realpathSync7(root)}/`) && verifiedSourceImportClosure(realpathSync7(root)) ? realpathSync7(root) : undefined;
|
|
29184
29279
|
}
|
|
29185
29280
|
const interpreter = /^#!([^\n]+)\n/u.exec(text)?.[1];
|
|
29186
|
-
if (interpreter === undefined || !isAbsolute12(interpreter) || !
|
|
29281
|
+
if (interpreter === undefined || !isAbsolute12(interpreter) || !existsSync32(interpreter) || !/^python(?:\d+(?:\.\d+)*)?$/u.test(basename8(interpreter)) || text.slice(text.indexOf(`
|
|
29187
29282
|
`) + 1) !== hermesUvConsoleBody)
|
|
29188
29283
|
return;
|
|
29189
29284
|
const venv = dirname20(dirname20(executable));
|
|
29190
|
-
if (dirname20(interpreter) !== join41(venv, "bin") || !
|
|
29285
|
+
if (dirname20(interpreter) !== join41(venv, "bin") || !existsSync32(join41(venv, "pyvenv.cfg")))
|
|
29191
29286
|
return;
|
|
29192
|
-
if (
|
|
29287
|
+
if (existsSync32(join41(venv, "bin", "pyvenv.cfg")) || !isolatedVenvConfig(readFileSync35(join41(venv, "pyvenv.cfg"), "utf8")) || process.env["PYTHONHOME"] || process.env["PYTHONPATH"])
|
|
29193
29288
|
return;
|
|
29194
29289
|
if (hasImportShadow(join41(venv, "bin"), ["hermes_cli", "sitecustomize", "usercustomize", "_virtualenv"]))
|
|
29195
29290
|
return;
|
|
29196
29291
|
const lib = join41(venv, "lib");
|
|
29197
|
-
if (!
|
|
29292
|
+
if (!existsSync32(lib))
|
|
29198
29293
|
return;
|
|
29199
29294
|
const roots = [];
|
|
29200
29295
|
for (const python of readdirSync25(lib).filter((name) => /^python\d+\.\d+$/u.test(name))) {
|
|
29201
29296
|
const packages = join41(lib, python, "site-packages");
|
|
29202
|
-
if (!
|
|
29297
|
+
if (!existsSync32(packages))
|
|
29203
29298
|
continue;
|
|
29204
29299
|
if (hasImportShadow(packages, ["hermes_cli", "sitecustomize", "usercustomize", "_virtualenv"], ["_virtualenv.py"]))
|
|
29205
29300
|
return;
|
|
@@ -29207,13 +29302,13 @@ exec `.length));
|
|
|
29207
29302
|
const distribution = join41(packages, name);
|
|
29208
29303
|
const metadata = join41(distribution, "direct_url.json");
|
|
29209
29304
|
const entry = join41(distribution, "entry_points.txt");
|
|
29210
|
-
if (!
|
|
29305
|
+
if (!existsSync32(metadata) || !existsSync32(entry) || !/^hermes\s*=\s*hermes_cli\.main:main$/mu.test(readFileSync35(entry, "utf8")))
|
|
29211
29306
|
continue;
|
|
29212
29307
|
const direct = JSON.parse(readFileSync35(metadata, "utf8"));
|
|
29213
29308
|
if (typeof direct !== "object" || direct === null || !("url" in direct) || typeof direct.url !== "string" || !("dir_info" in direct) || typeof direct.dir_info !== "object" || direct.dir_info === null || !("editable" in direct.dir_info) || direct.dir_info.editable !== true || !direct.url.startsWith("file:///"))
|
|
29214
29309
|
continue;
|
|
29215
29310
|
const root = decodeURIComponent(direct.url.slice("file://".length));
|
|
29216
|
-
if (!isAbsolute12(root) || !
|
|
29311
|
+
if (!isAbsolute12(root) || !existsSync32(join41(root, "hermes_cli", "main.py")))
|
|
29217
29312
|
continue;
|
|
29218
29313
|
const sourceModules = [
|
|
29219
29314
|
"hermes_cli",
|
|
@@ -29221,7 +29316,7 @@ exec `.length));
|
|
|
29221
29316
|
"hermes_constants",
|
|
29222
29317
|
"pm",
|
|
29223
29318
|
...readdirSync25(root).filter((name) => name.endsWith(".py")).map((name) => name.slice(0, -3)),
|
|
29224
|
-
...readdirSync25(root).filter((name) =>
|
|
29319
|
+
...readdirSync25(root).filter((name) => existsSync32(join41(root, name, "__init__.py")))
|
|
29225
29320
|
];
|
|
29226
29321
|
if (hasImportShadow(packages, sourceModules) || hasImportShadow(join41(venv, "bin"), sourceModules))
|
|
29227
29322
|
return;
|
|
@@ -29236,11 +29331,11 @@ exec `.length));
|
|
|
29236
29331
|
const pth = readFileSync35(join41(packages, pthName), "utf8").trim();
|
|
29237
29332
|
if (pthName === `_virtualenv.pth` && pth === "import _virtualenv") {
|
|
29238
29333
|
const helper = join41(packages, "_virtualenv.py");
|
|
29239
|
-
if (!
|
|
29334
|
+
if (!existsSync32(helper) || new CryptoHasher("sha256").update(readFileSync35(helper, "utf8")).digest("hex") !== "cfb3db86aaa53bb62b5ff764970bec2d71c9228590a0ebec57f6ec926cc0bf1a")
|
|
29240
29335
|
return;
|
|
29241
29336
|
} else if (pthName === `__editable__.hermes_agent-${version}.pth` && pth === root)
|
|
29242
29337
|
binding = true;
|
|
29243
|
-
else if (pthName === `__editable__.hermes_agent-${version}.pth` && pth === `import ${finder}; ${finder}.install()` &&
|
|
29338
|
+
else if (pthName === `__editable__.hermes_agent-${version}.pth` && pth === `import ${finder}; ${finder}.install()` && existsSync32(join41(packages, `${finder}.py`)) && verifiedEditableFinder(readFileSync35(join41(packages, `${finder}.py`), "utf8"), root, version))
|
|
29244
29339
|
binding = true;
|
|
29245
29340
|
else
|
|
29246
29341
|
return;
|
|
@@ -29253,7 +29348,7 @@ exec `.length));
|
|
|
29253
29348
|
}
|
|
29254
29349
|
function observeHermesRevision() {
|
|
29255
29350
|
const binary = process.env["OPEN_PLUGIN_HERMES_BIN"] ?? which("hermes");
|
|
29256
|
-
if (!binary || !
|
|
29351
|
+
if (!binary || !existsSync32(binary))
|
|
29257
29352
|
return { kind: "unknown", diagnostic: "Select an existing Hermes launcher with OPEN_PLUGIN_HERMES_BIN; a profile config does not identify its runtime" };
|
|
29258
29353
|
try {
|
|
29259
29354
|
const root = hermesExecutableSource(binary);
|
|
@@ -29327,14 +29422,14 @@ function resolveInstanceConfig(root, configPath) {
|
|
|
29327
29422
|
const configured = resolve27(configPath);
|
|
29328
29423
|
if (native === configured)
|
|
29329
29424
|
return configured;
|
|
29330
|
-
if (!
|
|
29425
|
+
if (!existsSync32(native) || !existsSync32(configured))
|
|
29331
29426
|
throw new Error(`Hermes only reads ${native}; configured path ${configured} must already resolve to the same file`);
|
|
29332
29427
|
if (realpathSync7(native) === realpathSync7(configured))
|
|
29333
29428
|
return configured;
|
|
29334
29429
|
throw new Error(`Hermes only reads ${native}; configured path ${configured} is a different file`);
|
|
29335
29430
|
}
|
|
29336
29431
|
function actualConfig(configPath) {
|
|
29337
|
-
return
|
|
29432
|
+
return existsSync32(configPath) && lstatSync27(configPath).isSymbolicLink() ? realpathSync7(configPath) : configPath;
|
|
29338
29433
|
}
|
|
29339
29434
|
function workDir(store, attemptId, operationId) {
|
|
29340
29435
|
return join41(store.root, ".plgnz-lifecycle", encodeURIComponent(attemptId), encodeURIComponent(operationId));
|
|
@@ -29403,7 +29498,7 @@ function sameLifecycleOwner(marker, claim) {
|
|
|
29403
29498
|
return installed !== null && installed.pluginId === claim.pluginId && installed.scopeId === claim.scopeId && installed.sourceType === claim.sourceType && installed.locator === claim.locator;
|
|
29404
29499
|
}
|
|
29405
29500
|
function assertLifecycleOwned(target, claim, handle) {
|
|
29406
|
-
if (!
|
|
29501
|
+
if (!existsSync32(target))
|
|
29407
29502
|
return;
|
|
29408
29503
|
const marker = readMarker(target);
|
|
29409
29504
|
if (marker === null)
|
|
@@ -29433,7 +29528,7 @@ function copyReplace(stage, target, root) {
|
|
|
29433
29528
|
}
|
|
29434
29529
|
function flagSet(configPath, key) {
|
|
29435
29530
|
const actual = actualConfig(configPath);
|
|
29436
|
-
if (!
|
|
29531
|
+
if (!existsSync32(actual))
|
|
29437
29532
|
return new Set;
|
|
29438
29533
|
const parsed = yamlParse(readFileSync35(actual, "utf8"));
|
|
29439
29534
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
@@ -29459,7 +29554,7 @@ function activationMatches(configPath, packageName, companionId, hasCompanion) {
|
|
|
29459
29554
|
}
|
|
29460
29555
|
function entryValue(configPath, packageName) {
|
|
29461
29556
|
const actual = actualConfig(configPath);
|
|
29462
|
-
if (!
|
|
29557
|
+
if (!existsSync32(actual))
|
|
29463
29558
|
return;
|
|
29464
29559
|
const parsed = yamlParse(readFileSync35(actual, "utf8"));
|
|
29465
29560
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
@@ -29492,7 +29587,7 @@ function sha2563(value) {
|
|
|
29492
29587
|
}
|
|
29493
29588
|
function retentionFor(store, packageName) {
|
|
29494
29589
|
const dataDir = join41(store.root, "plugin-data", hermesPluginDataNamespace(packageName));
|
|
29495
|
-
const pluginData =
|
|
29590
|
+
const pluginData = existsSync32(dataDir) && lstatSync27(dataDir).isDirectory() ? { state: "present", fingerprint: fingerprintTree(dataDir) } : { state: "absent", fingerprint: null };
|
|
29496
29591
|
const entry = entryValue(store.configPath, packageName);
|
|
29497
29592
|
const inactiveMetadata = entry === undefined ? { state: "absent", fingerprint: null } : { state: "present", fingerprint: sha2563(JSON.stringify(canonicalValue(entry))) };
|
|
29498
29593
|
return { pluginData, inactiveMetadata };
|
|
@@ -29501,7 +29596,7 @@ function atomicFingerprint(packageDir, companionDir) {
|
|
|
29501
29596
|
const temp = mkdtempSync16(join41(tmpdir13(), "plgnz-hermes-atomic-"));
|
|
29502
29597
|
try {
|
|
29503
29598
|
cpSync15(packageDir, join41(temp, "package"), { recursive: true });
|
|
29504
|
-
if (companionDir !== undefined &&
|
|
29599
|
+
if (companionDir !== undefined && existsSync32(companionDir))
|
|
29505
29600
|
cpSync15(companionDir, join41(temp, "commands"), { recursive: true });
|
|
29506
29601
|
return fingerprintTree(temp);
|
|
29507
29602
|
} finally {
|
|
@@ -29510,7 +29605,7 @@ function atomicFingerprint(packageDir, companionDir) {
|
|
|
29510
29605
|
}
|
|
29511
29606
|
function readConfigDocument2(configPath) {
|
|
29512
29607
|
const actual = actualConfig(configPath);
|
|
29513
|
-
if (!
|
|
29608
|
+
if (!existsSync32(actual))
|
|
29514
29609
|
return null;
|
|
29515
29610
|
const text = readFileSync35(actual, "utf8");
|
|
29516
29611
|
if (text.trim() === "")
|
|
@@ -29568,7 +29663,7 @@ function membership(list, id, present) {
|
|
|
29568
29663
|
}
|
|
29569
29664
|
function writeConfigDocument(configPath, doc) {
|
|
29570
29665
|
const actual = actualConfig(configPath);
|
|
29571
|
-
const exists =
|
|
29666
|
+
const exists = existsSync32(actual);
|
|
29572
29667
|
const mode = exists ? statSync14(actual).mode & 511 : null;
|
|
29573
29668
|
mkdirSync17(dirname20(actual), { recursive: true });
|
|
29574
29669
|
const temp = join41(dirname20(actual), `.plgnz-hermes-rollback-${Date.now()}-${Math.random().toString(16).slice(2)}.yaml`);
|
|
@@ -29616,18 +29711,18 @@ function saveRollback(store, reference, packageName, packageDir, companionDir) {
|
|
|
29616
29711
|
mkdirSync17(reference, { recursive: true });
|
|
29617
29712
|
const companionId = hermesCommandCompanionId(packageName);
|
|
29618
29713
|
writeFileSync17(join41(reference, "config-slice.json"), JSON.stringify(captureConfigSlice(store.configPath, packageName, companionId)));
|
|
29619
|
-
if (
|
|
29714
|
+
if (existsSync32(packageDir))
|
|
29620
29715
|
cpSync15(packageDir, join41(reference, "package"), { recursive: true });
|
|
29621
|
-
if (
|
|
29716
|
+
if (existsSync32(companionDir))
|
|
29622
29717
|
cpSync15(companionDir, join41(reference, "commands"), { recursive: true });
|
|
29623
29718
|
}
|
|
29624
29719
|
function restoreRollback3(store, reference, packageDir, companionDir) {
|
|
29625
29720
|
const slice = JSON.parse(readFileSync35(join41(reference, "config-slice.json"), "utf8"));
|
|
29626
29721
|
rmSync17(packageDir, { recursive: true, force: true });
|
|
29627
29722
|
rmSync17(companionDir, { recursive: true, force: true });
|
|
29628
|
-
if (
|
|
29723
|
+
if (existsSync32(join41(reference, "package")))
|
|
29629
29724
|
cpSync15(join41(reference, "package"), packageDir, { recursive: true });
|
|
29630
|
-
if (
|
|
29725
|
+
if (existsSync32(join41(reference, "commands")))
|
|
29631
29726
|
cpSync15(join41(reference, "commands"), companionDir, { recursive: true });
|
|
29632
29727
|
restoreConfigSlice(store.configPath, slice);
|
|
29633
29728
|
}
|
|
@@ -29676,7 +29771,7 @@ var hermesLifecycleDefinition = {
|
|
|
29676
29771
|
try {
|
|
29677
29772
|
const store = storeFor(target);
|
|
29678
29773
|
const actual = actualConfig(store.configPath);
|
|
29679
|
-
if (!
|
|
29774
|
+
if (!existsSync32(actual) || !statSync14(actual).isFile())
|
|
29680
29775
|
return { kind: "unknown" };
|
|
29681
29776
|
const text = readFileSync35(actual, "utf8");
|
|
29682
29777
|
if (text.trim() !== "") {
|
|
@@ -29759,9 +29854,9 @@ var hermesLifecycleDefinition = {
|
|
|
29759
29854
|
const companionStage = join41(stagingRoot, "commands");
|
|
29760
29855
|
mkdirSync17(packageStage, { recursive: true });
|
|
29761
29856
|
projectPluginForHermes(request.snapshot.packageRoot, packageStage, companionStage);
|
|
29762
|
-
if (
|
|
29857
|
+
if (existsSync32(companionStage) && readdirSync25(companionStage).length === 0)
|
|
29763
29858
|
rmSync17(companionStage, { recursive: true });
|
|
29764
|
-
const hasCompanion =
|
|
29859
|
+
const hasCompanion = existsSync32(companionStage);
|
|
29765
29860
|
validatePackage(packageStage, request.snapshot.packageName);
|
|
29766
29861
|
if (hasCompanion)
|
|
29767
29862
|
validateCompanion(companionStage, hermesCommandCompanionId(request.snapshot.packageName));
|
|
@@ -29785,7 +29880,7 @@ var hermesLifecycleDefinition = {
|
|
|
29785
29880
|
if (projection.pins.length === 0)
|
|
29786
29881
|
return [];
|
|
29787
29882
|
const mcp = join41(projection.stagingRoot, "package", "mcp.json");
|
|
29788
|
-
if (!
|
|
29883
|
+
if (!existsSync32(mcp))
|
|
29789
29884
|
throw new Error(`Hermes pin set has no mcp.json: ${mcp}`);
|
|
29790
29885
|
const value = JSON.parse(readFileSync35(mcp, "utf8"));
|
|
29791
29886
|
const servers = value.mcpServers ?? {};
|
|
@@ -29804,7 +29899,7 @@ var hermesLifecycleDefinition = {
|
|
|
29804
29899
|
const paths = packagePaths(store, projection.packageName);
|
|
29805
29900
|
const prior = withIdentity(inspect(store, projection.nativeId, projection.packageName, "none"), projection.target, projection.scopeId, projection.packageName, projection.nativeId);
|
|
29806
29901
|
capturePriorSourceRepair(projection, prior.installedFingerprint);
|
|
29807
|
-
const hasCompanion =
|
|
29902
|
+
const hasCompanion = existsSync32(join41(projection.stagingRoot, "commands"));
|
|
29808
29903
|
const contentRoots = [{ label: "package", path: paths.packageDir, fingerprint: fingerprintTree(join41(projection.stagingRoot, "package")) }];
|
|
29809
29904
|
if (hasCompanion)
|
|
29810
29905
|
contentRoots.push({ label: "commands", path: paths.companionDir, fingerprint: fingerprintTree(join41(projection.stagingRoot, "commands")) });
|
|
@@ -29841,15 +29936,15 @@ var hermesLifecycleDefinition = {
|
|
|
29841
29936
|
assertManagedPath5(store.pluginsDir, paths.companionDir);
|
|
29842
29937
|
const stagedPackage = join41(prepared.stagingRoot, "package");
|
|
29843
29938
|
const stagedCompanion = join41(prepared.stagingRoot, "commands");
|
|
29844
|
-
const hasCompanion =
|
|
29939
|
+
const hasCompanion = existsSync32(stagedCompanion);
|
|
29845
29940
|
const owner = ownerFromHandle(prepared.handle);
|
|
29846
29941
|
assertLifecycleOwned(paths.packageDir, owner, prepared.handle);
|
|
29847
29942
|
if (hasCompanion)
|
|
29848
29943
|
assertLifecycleOwned(paths.companionDir, owner, prepared.handle);
|
|
29849
|
-
else if (
|
|
29944
|
+
else if (existsSync32(paths.companionDir))
|
|
29850
29945
|
assertLifecycleOwned(paths.companionDir, owner, prepared.handle);
|
|
29851
29946
|
mkdirSync17(store.pluginsDir, { recursive: true });
|
|
29852
|
-
const unchanged =
|
|
29947
|
+
const unchanged = existsSync32(paths.packageDir) && atomicFingerprint(paths.packageDir, hasCompanion ? paths.companionDir : undefined) === fingerprintTree(prepared.stagingRoot) && activationMatches(store.configPath, prepared.handle.packageName, paths.companionId, hasCompanion);
|
|
29853
29948
|
if (unchanged)
|
|
29854
29949
|
return { receiptId: `apply:${prepared.handle.attemptId}:${prepared.handle.operationId}`, changed: false };
|
|
29855
29950
|
const changes = [];
|
|
@@ -29857,7 +29952,7 @@ var hermesLifecycleDefinition = {
|
|
|
29857
29952
|
changes.push(copyReplace(stagedPackage, paths.packageDir, store.pluginsDir));
|
|
29858
29953
|
if (hasCompanion)
|
|
29859
29954
|
changes.push(copyReplace(stagedCompanion, paths.companionDir, store.pluginsDir));
|
|
29860
|
-
else if (
|
|
29955
|
+
else if (existsSync32(paths.companionDir))
|
|
29861
29956
|
changes.push(removeTarget(paths.companionDir, store.pluginsDir));
|
|
29862
29957
|
updatePluginConfig(store.configPath, [prepared.handle.packageName, ...hasCompanion ? [paths.companionId] : []], hasCompanion ? [] : [paths.companionId]);
|
|
29863
29958
|
for (const change of changes)
|
|
@@ -29883,11 +29978,11 @@ var hermesLifecycleDefinition = {
|
|
|
29883
29978
|
const source = prepared.handle.sourceLocator ?? prepared.handle.sourceRevision;
|
|
29884
29979
|
const changes = [];
|
|
29885
29980
|
try {
|
|
29886
|
-
if (
|
|
29981
|
+
if (existsSync32(paths.packageDir)) {
|
|
29887
29982
|
assertLifecycleOwned(paths.packageDir, ownerFromHandle(prepared.handle));
|
|
29888
29983
|
changes.push(removeTarget(paths.packageDir, store.pluginsDir));
|
|
29889
29984
|
}
|
|
29890
|
-
if (
|
|
29985
|
+
if (existsSync32(paths.companionDir)) {
|
|
29891
29986
|
const marker = readMarker(paths.companionDir);
|
|
29892
29987
|
if (marker !== null && marker.pluginId === prepared.handle.nativeId && marker.source === source)
|
|
29893
29988
|
changes.push(removeTarget(paths.companionDir, store.pluginsDir));
|
|
@@ -30234,7 +30329,7 @@ function invalidSelection2(diagnostic) {
|
|
|
30234
30329
|
}
|
|
30235
30330
|
|
|
30236
30331
|
// src/recorded-pins.ts
|
|
30237
|
-
import { existsSync as
|
|
30332
|
+
import { existsSync as existsSync33, readFileSync as readFileSync36 } from "node:fs";
|
|
30238
30333
|
import { isAbsolute as isAbsolute13, join as join42, resolve as resolve28 } from "node:path";
|
|
30239
30334
|
function resolveRecordedPinExecutables(packageRoot, servers) {
|
|
30240
30335
|
const pins = [];
|
|
@@ -30257,7 +30352,7 @@ function resolveRecordedPinExecutables(packageRoot, servers) {
|
|
|
30257
30352
|
function recordedPinCommand(packageRoot, server) {
|
|
30258
30353
|
for (const name of [".mcp.json", "mcp.json"]) {
|
|
30259
30354
|
const file = join42(packageRoot, name);
|
|
30260
|
-
if (!
|
|
30355
|
+
if (!existsSync33(file))
|
|
30261
30356
|
continue;
|
|
30262
30357
|
let parsed;
|
|
30263
30358
|
try {
|
|
@@ -31434,6 +31529,14 @@ function writeState(records, file = stateFile()) {
|
|
|
31434
31529
|
validateLegacyInstallRecords(records);
|
|
31435
31530
|
atomicWrite(file, JSON.stringify({ version: 1, installs: records }, null, 2));
|
|
31436
31531
|
}
|
|
31532
|
+
function writeInstallLedger(records, changed, binding) {
|
|
31533
|
+
const loaded = readLifecycleState();
|
|
31534
|
+
if (loaded.sourceVersion !== 2) {
|
|
31535
|
+
writeState(records);
|
|
31536
|
+
return;
|
|
31537
|
+
}
|
|
31538
|
+
writeLifecycleState(withLegacyWriterRecord(loaded.state, changed, binding), { globalPreflight: "succeeded" });
|
|
31539
|
+
}
|
|
31437
31540
|
function withLegacyWriterRecord(state, record, binding) {
|
|
31438
31541
|
const source = persistedSource(binding);
|
|
31439
31542
|
const scope = createDeploymentScopeIdentity(source, { kind: record.host, instance: "default" });
|
|
@@ -33446,6 +33549,9 @@ function selectTargets(all, options) {
|
|
|
33446
33549
|
return defaultPinTargets(all);
|
|
33447
33550
|
}
|
|
33448
33551
|
|
|
33552
|
+
// src/update.ts
|
|
33553
|
+
init_compatibility();
|
|
33554
|
+
|
|
33449
33555
|
// src/native-identity.ts
|
|
33450
33556
|
function captureNativeIdentity(writer, plugin) {
|
|
33451
33557
|
let nativeId = null;
|
|
@@ -33497,7 +33603,12 @@ function shortSha2(sha) {
|
|
|
33497
33603
|
async function runUpdate(name, options = {}) {
|
|
33498
33604
|
const hosts = options.writers ?? writers;
|
|
33499
33605
|
let state = options.state ?? readState();
|
|
33500
|
-
const save =
|
|
33606
|
+
const save = (records, changed, binding) => {
|
|
33607
|
+
if (options.writeState !== undefined)
|
|
33608
|
+
options.writeState(records);
|
|
33609
|
+
else
|
|
33610
|
+
writeInstallLedger(records, changed, binding);
|
|
33611
|
+
};
|
|
33501
33612
|
const prefix = options.dryRun === true ? "[dry-run] " : "";
|
|
33502
33613
|
const findings = [];
|
|
33503
33614
|
let mutationStarted = false;
|
|
@@ -33626,7 +33737,7 @@ async function runUpdate(name, options = {}) {
|
|
|
33626
33737
|
const pending = { ...record, pending: "install" };
|
|
33627
33738
|
record = pending;
|
|
33628
33739
|
const next = state.map((candidate) => candidate === persistedRecord ? pending : candidate);
|
|
33629
|
-
save(next);
|
|
33740
|
+
save(next, pending, resolved.snapshot.binding);
|
|
33630
33741
|
state = next;
|
|
33631
33742
|
recordMutationStarted = true;
|
|
33632
33743
|
mutationStarted = true;
|
|
@@ -33713,7 +33824,7 @@ async function runUpdate(name, options = {}) {
|
|
|
33713
33824
|
delete finalized.pending;
|
|
33714
33825
|
const next = state.map((candidate) => candidate === record ? finalized : candidate);
|
|
33715
33826
|
try {
|
|
33716
|
-
save(next);
|
|
33827
|
+
save(next, finalized, resolved.snapshot.binding);
|
|
33717
33828
|
} catch (error) {
|
|
33718
33829
|
findings.push(findingFor(record, {
|
|
33719
33830
|
mark: "✗",
|
|
@@ -33847,6 +33958,9 @@ function findConsumerProfile(id) {
|
|
|
33847
33958
|
return byId.get(id);
|
|
33848
33959
|
}
|
|
33849
33960
|
|
|
33961
|
+
// src/cli.ts
|
|
33962
|
+
init_compatibility();
|
|
33963
|
+
|
|
33850
33964
|
// src/legacy-install-outcome.ts
|
|
33851
33965
|
function serializeLegacyInstallOutcomes(report) {
|
|
33852
33966
|
const rows = report.outcomes.map((outcome) => ({
|
|
@@ -33903,7 +34017,7 @@ function legacyCommandAction(command) {
|
|
|
33903
34017
|
// package.json
|
|
33904
34018
|
var package_default = {
|
|
33905
34019
|
name: "plugnz",
|
|
33906
|
-
version: "0.0.
|
|
34020
|
+
version: "0.0.23",
|
|
33907
34021
|
description: "Install, diagnose and update agent plugins (Agent Plugins spec) and MCP configs across Claude Code, Codex, Cursor, Kimi and more",
|
|
33908
34022
|
license: "MIT",
|
|
33909
34023
|
type: "module",
|
|
@@ -34361,6 +34475,10 @@ function printReport(report, mode) {
|
|
|
34361
34475
|
const legacy = serializeLegacyInstallOutcomes(report);
|
|
34362
34476
|
for (const item of legacy)
|
|
34363
34477
|
console.log(`${item.target} ${item.status} ${item.plugin}${item.diagnostic ? ` ${item.diagnostic}` : ""}`);
|
|
34478
|
+
for (const facts of report.verification?.operations ?? []) {
|
|
34479
|
+
const outcome = report.outcomes.find((row) => row.operationId === facts.operationId);
|
|
34480
|
+
console.log(`${outcome.scope.target.kind} ${outcome.package} compatibility=${facts.compatibility} registration=${facts.registration} executionApproval=${facts.executionApproval} delivery=${facts.delivery}`);
|
|
34481
|
+
}
|
|
34364
34482
|
}
|
|
34365
34483
|
}
|
|
34366
34484
|
function select(available, targets) {
|
|
@@ -34663,14 +34781,6 @@ async function runPlannerAdd(source, binding, targets, flags) {
|
|
|
34663
34781
|
command: { ...executed.report.command, name: "add" }
|
|
34664
34782
|
});
|
|
34665
34783
|
}
|
|
34666
|
-
function writeInstallLedger(records, changed, binding) {
|
|
34667
|
-
const loaded = readLifecycleState();
|
|
34668
|
-
if (loaded.sourceVersion !== 2) {
|
|
34669
|
-
writeState(records);
|
|
34670
|
-
return;
|
|
34671
|
-
}
|
|
34672
|
-
writeLifecycleState(withLegacyWriterRecord(loaded.state, changed, binding), { globalPreflight: "succeeded" });
|
|
34673
|
-
}
|
|
34674
34784
|
async function runWriterAdd(source, selectedWriters, flags, mode) {
|
|
34675
34785
|
let resolved;
|
|
34676
34786
|
try {
|
|
@@ -35002,7 +35112,8 @@ async function runRecordedLifecycleUpdate(flags, state) {
|
|
|
35002
35112
|
const scope = scopes.get(activation.scopeId);
|
|
35003
35113
|
if (scope === undefined || scope.target.instance !== "default" || !kinds.has(scope.target.kind))
|
|
35004
35114
|
return [];
|
|
35005
|
-
|
|
35115
|
+
const writer = present.selected.find((candidate) => candidate.id === scope.target.kind);
|
|
35116
|
+
if (!requestedPersistedIdentityMatches(writer, activation.packageId, activation.nativeId, requested))
|
|
35006
35117
|
return [];
|
|
35007
35118
|
return [{ scope, packageId: activation.packageId }];
|
|
35008
35119
|
});
|
|
@@ -35080,6 +35191,7 @@ async function runRecordedLifecycleUpdate(flags, state) {
|
|
|
35080
35191
|
});
|
|
35081
35192
|
}
|
|
35082
35193
|
function emitAddReport(report, mode) {
|
|
35194
|
+
report = parseLifecycleReport({ ...report, verification: installationVerification(report) });
|
|
35083
35195
|
if (mode === "json")
|
|
35084
35196
|
return emitValidatedReport(report, true);
|
|
35085
35197
|
printReport(report, mode);
|