plugnz 0.0.22 → 0.0.24
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 +730 -614
- 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);
|
|
@@ -19610,7 +19705,7 @@ var codexWriter = {
|
|
|
19610
19705
|
[`, idx + header.length);
|
|
19611
19706
|
const end = nextTable === -1 ? toml.length : nextTable;
|
|
19612
19707
|
const block = toml.slice(idx, end);
|
|
19613
|
-
const withoutEnabled = block.replace(
|
|
19708
|
+
const withoutEnabled = block.replace(enabledAssignment("true|false", true), "");
|
|
19614
19709
|
const remaining = withoutEnabled.slice(header.length).trim();
|
|
19615
19710
|
const replacement = remaining === "" ? "" : `${withoutEnabled.trimEnd()}
|
|
19616
19711
|
enabled = false
|
|
@@ -19622,8 +19717,12 @@ enabled = false
|
|
|
19622
19717
|
rmSync7(candidate, { recursive: true, force: true });
|
|
19623
19718
|
}
|
|
19624
19719
|
};
|
|
19720
|
+
var ENABLED_ASSIGNMENT_TAIL = String.raw`[ \t]*(?:#.*)?`;
|
|
19721
|
+
function enabledAssignment(value, consumeNewline = false) {
|
|
19722
|
+
return new RegExp(`^enabled\\s*=\\s*(?:${value})${ENABLED_ASSIGNMENT_TAIL}$${consumeNewline ? "\\n?" : ""}`, "mu");
|
|
19723
|
+
}
|
|
19625
19724
|
function enable(configPath, id) {
|
|
19626
|
-
let toml =
|
|
19725
|
+
let toml = existsSync22(configPath) ? readFileSync23(configPath, "utf8") : "";
|
|
19627
19726
|
parseConfigToml(toml, configPath);
|
|
19628
19727
|
let newToml = toml;
|
|
19629
19728
|
const header = `[plugins."${id}"]`;
|
|
@@ -19633,7 +19732,7 @@ function enable(configPath, id) {
|
|
|
19633
19732
|
[`, idx + header.length);
|
|
19634
19733
|
const blockEnd = nextTable !== -1 ? nextTable : toml.length;
|
|
19635
19734
|
const block = toml.slice(idx, blockEnd);
|
|
19636
|
-
const enabled =
|
|
19735
|
+
const enabled = new RegExp(`^([ \\t]*enabled[ \\t]*=[ \\t]*)(true|false)(${ENABLED_ASSIGNMENT_TAIL})$`, "gmu");
|
|
19637
19736
|
const matches = [...block.matchAll(enabled)];
|
|
19638
19737
|
if (matches.length > 1)
|
|
19639
19738
|
throw new Error(`duplicate enabled keys in Codex plugin config: ${id}`);
|
|
@@ -19667,7 +19766,7 @@ function parseConfigToml(text, path) {
|
|
|
19667
19766
|
}
|
|
19668
19767
|
}
|
|
19669
19768
|
function isEnabled(configPath, id) {
|
|
19670
|
-
if (!
|
|
19769
|
+
if (!existsSync22(configPath))
|
|
19671
19770
|
return false;
|
|
19672
19771
|
const toml = readFileSync23(configPath, "utf8");
|
|
19673
19772
|
const header = `[plugins."${id}"]`;
|
|
@@ -19677,10 +19776,10 @@ function isEnabled(configPath, id) {
|
|
|
19677
19776
|
const nextTable = toml.indexOf(`
|
|
19678
19777
|
[`, idx + header.length);
|
|
19679
19778
|
const block = toml.slice(idx, nextTable === -1 ? toml.length : nextTable);
|
|
19680
|
-
return
|
|
19779
|
+
return !enabledAssignment("false").test(block);
|
|
19681
19780
|
}
|
|
19682
19781
|
function readConfigSnapshot(path) {
|
|
19683
|
-
if (!
|
|
19782
|
+
if (!existsSync22(path))
|
|
19684
19783
|
return { existed: false };
|
|
19685
19784
|
const read = readFileSync23;
|
|
19686
19785
|
return { existed: true, bytes: read(path) };
|
|
@@ -19701,7 +19800,7 @@ function validVersionSegment(value) {
|
|
|
19701
19800
|
}
|
|
19702
19801
|
function readOwnership2(dir) {
|
|
19703
19802
|
const file = join29(dir, OWNERSHIP2);
|
|
19704
|
-
if (!
|
|
19803
|
+
if (!existsSync22(file))
|
|
19705
19804
|
return null;
|
|
19706
19805
|
try {
|
|
19707
19806
|
const value = JSON.parse(readFileSync23(file, "utf8"));
|
|
@@ -19725,12 +19824,12 @@ function validateStage(stage) {
|
|
|
19725
19824
|
if (readPluginManifest(stage) === undefined)
|
|
19726
19825
|
throw new Error("Codex stage has no Agent Plugins manifest");
|
|
19727
19826
|
const skills = join29(stage, "skills");
|
|
19728
|
-
if (
|
|
19827
|
+
if (existsSync22(skills) && !statSync10(skills).isDirectory())
|
|
19729
19828
|
throw new Error("Codex stage skills path is not a directory");
|
|
19730
19829
|
}
|
|
19731
19830
|
function validateCachedIdentity(target, expectedName, expectedVersion) {
|
|
19732
19831
|
const candidates = [join29(target, ".codex-plugin", "plugin.json"), join29(target, "plugin.json"), join29(target, ".plugin", "plugin.json")];
|
|
19733
|
-
const manifest = candidates.find(
|
|
19832
|
+
const manifest = candidates.find(existsSync22);
|
|
19734
19833
|
if (manifest === undefined)
|
|
19735
19834
|
throw new Error(`unowned Codex cache slot has no manifest: ${target}`);
|
|
19736
19835
|
const value = JSON.parse(readFileSync23(manifest, "utf8"));
|
|
@@ -19740,7 +19839,7 @@ function validateCachedIdentity(target, expectedName, expectedVersion) {
|
|
|
19740
19839
|
if (record["name"] === expectedName && record["version"] === expectedVersion)
|
|
19741
19840
|
return;
|
|
19742
19841
|
if (manifest === candidates[0] && record["name"] === expectedName && nativeBuildVariant(expectedVersion, record["version"])) {
|
|
19743
|
-
const canonical = candidates.slice(1).find(
|
|
19842
|
+
const canonical = candidates.slice(1).find(existsSync22);
|
|
19744
19843
|
if (canonical !== undefined) {
|
|
19745
19844
|
const canonicalValue = JSON.parse(readFileSync23(canonical, "utf8"));
|
|
19746
19845
|
if (typeof canonicalValue === "object" && canonicalValue !== null && !Array.isArray(canonicalValue)) {
|
|
@@ -19765,7 +19864,7 @@ function ensureNativeManifest(stage, fallbackName, fallbackVersion) {
|
|
|
19765
19864
|
throw new Error("Codex stage has no Agent Plugins manifest");
|
|
19766
19865
|
for (const path of ["plugin.json", ".plugin/plugin.json", ".claude-plugin/plugin.json"]) {
|
|
19767
19866
|
const file = join29(stage, path);
|
|
19768
|
-
if (
|
|
19867
|
+
if (existsSync22(file) && JSON.parse(readFileSync23(file, "utf8")).mcpServers !== undefined) {
|
|
19769
19868
|
throw new Error("Codex inline manifest MCP projection is unverified; use mcp.json or .mcp.json");
|
|
19770
19869
|
}
|
|
19771
19870
|
}
|
|
@@ -19773,7 +19872,7 @@ function ensureNativeManifest(stage, fallbackName, fallbackVersion) {
|
|
|
19773
19872
|
const version = sourceManifest.version ?? fallbackVersion;
|
|
19774
19873
|
const description = sourceManifest.description ?? `Plugin ${name}`;
|
|
19775
19874
|
let overlay = {};
|
|
19776
|
-
if (
|
|
19875
|
+
if (existsSync22(native)) {
|
|
19777
19876
|
const value = JSON.parse(readFileSync23(native, "utf8"));
|
|
19778
19877
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
19779
19878
|
throw new Error("Codex native plugin manifest must be an object");
|
|
@@ -19787,10 +19886,10 @@ function ensureNativeManifest(stage, fallbackName, fallbackVersion) {
|
|
|
19787
19886
|
}
|
|
19788
19887
|
}
|
|
19789
19888
|
const pointer = overlay["mcpServers"];
|
|
19790
|
-
if (pointer !== undefined && (typeof pointer !== "string" || !pointer.startsWith("./") || pointer.includes("\\") || pointer.split("/").includes("..") || !
|
|
19889
|
+
if (pointer !== undefined && (typeof pointer !== "string" || !pointer.startsWith("./") || pointer.includes("\\") || pointer.split("/").includes("..") || !existsSync22(join29(stage, pointer)))) {
|
|
19791
19890
|
throw new Error("Codex native MCP pointer must name an existing plugin-local file");
|
|
19792
19891
|
}
|
|
19793
|
-
const mcpFiles = ["mcp.json", ".mcp.json", ...typeof pointer === "string" ? [pointer] : []].map((path) => join29(stage, path)).filter(
|
|
19892
|
+
const mcpFiles = ["mcp.json", ".mcp.json", ...typeof pointer === "string" ? [pointer] : []].map((path) => join29(stage, path)).filter(existsSync22);
|
|
19794
19893
|
const declarations = mcpFiles.map((file) => {
|
|
19795
19894
|
const value = JSON.parse(readFileSync23(file, "utf8"));
|
|
19796
19895
|
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 +19906,7 @@ function ensureNativeManifest(stage, fallbackName, fallbackVersion) {
|
|
|
19807
19906
|
version,
|
|
19808
19907
|
description,
|
|
19809
19908
|
skills: overlay["skills"] ?? "./skills/",
|
|
19810
|
-
...overlay["mcpServers"] === undefined &&
|
|
19909
|
+
...overlay["mcpServers"] === undefined && existsSync22(join29(stage, "mcp.json")) && !existsSync22(join29(stage, ".mcp.json")) ? { mcpServers: "./mcp.json" } : {}
|
|
19811
19910
|
}));
|
|
19812
19911
|
}
|
|
19813
19912
|
function mcpDeclarationIdentity(value) {
|
|
@@ -19825,9 +19924,9 @@ function assertManagedPath2(root, target) {
|
|
|
19825
19924
|
for (const part of ["", ...suffix.split("/").filter(Boolean)]) {
|
|
19826
19925
|
if (part !== "")
|
|
19827
19926
|
current = join29(current, part);
|
|
19828
|
-
if (!
|
|
19927
|
+
if (!existsSync22(current))
|
|
19829
19928
|
continue;
|
|
19830
|
-
const stat =
|
|
19929
|
+
const stat = lstatSync15(current);
|
|
19831
19930
|
if (stat.isSymbolicLink())
|
|
19832
19931
|
throw new Error(`Codex managed path component is a symlink: ${current}`);
|
|
19833
19932
|
if (!stat.isDirectory())
|
|
@@ -19836,16 +19935,16 @@ function assertManagedPath2(root, target) {
|
|
|
19836
19935
|
}
|
|
19837
19936
|
function assertManagedConfigPath(root, path) {
|
|
19838
19937
|
assertManagedPath2(root, dirname9(path));
|
|
19839
|
-
if (!
|
|
19938
|
+
if (!existsSync22(path))
|
|
19840
19939
|
return;
|
|
19841
|
-
const stat =
|
|
19940
|
+
const stat = lstatSync15(path);
|
|
19842
19941
|
if (stat.isSymbolicLink())
|
|
19843
19942
|
throw new Error(`Codex managed config is a symlink: ${path}`);
|
|
19844
19943
|
if (!stat.isFile())
|
|
19845
19944
|
throw new Error(`Codex managed config is not a file: ${path}`);
|
|
19846
19945
|
}
|
|
19847
19946
|
function activate2(stage, target, slot) {
|
|
19848
|
-
if (!
|
|
19947
|
+
if (!existsSync22(target)) {
|
|
19849
19948
|
renameSync4(stage, target);
|
|
19850
19949
|
return { commit: () => {}, rollback: () => rmSync7(target, { recursive: true, force: true }) };
|
|
19851
19950
|
}
|
|
@@ -19920,7 +20019,7 @@ function assertNoSymlinks3(dir) {
|
|
|
19920
20019
|
const walk = (current) => {
|
|
19921
20020
|
for (const entry of readdirSync14(current)) {
|
|
19922
20021
|
const path = join29(current, entry);
|
|
19923
|
-
const stat =
|
|
20022
|
+
const stat = lstatSync15(path);
|
|
19924
20023
|
if (stat.isSymbolicLink())
|
|
19925
20024
|
throw new Error(`Codex managed slot contains symlink: ${path}`);
|
|
19926
20025
|
if (stat.isDirectory())
|
|
@@ -20049,10 +20148,10 @@ function revalidateCodexTarget(handle) {
|
|
|
20049
20148
|
for (const root of handle.expected.contentRoots)
|
|
20050
20149
|
assertRequestedCacheOwnership(root.path, handle.prior.contentRoots);
|
|
20051
20150
|
}
|
|
20052
|
-
if (
|
|
20151
|
+
if (existsSync22(join29(bundle, "marketplace.json"))) {
|
|
20053
20152
|
const metadata = JSON.parse(readFileSync23(join29(bundle, "marketplace.json"), "utf8"));
|
|
20054
20153
|
const checkout = marketplaceCheckout(metadata.marketplace);
|
|
20055
|
-
const actual =
|
|
20154
|
+
const actual = existsSync22(checkout) ? fingerprintTree(checkout) : null;
|
|
20056
20155
|
if (actual !== metadata.fingerprint)
|
|
20057
20156
|
throw new Error("Codex marketplace checkout changed after rollback capture");
|
|
20058
20157
|
}
|
|
@@ -20249,13 +20348,13 @@ async function retireCodex(prepared) {
|
|
|
20249
20348
|
}
|
|
20250
20349
|
function restampNativeUpgrade(prepared) {
|
|
20251
20350
|
const markerPath = join29(prepared.stagingRoot, OWNERSHIP2);
|
|
20252
|
-
if (!
|
|
20351
|
+
if (!existsSync22(markerPath))
|
|
20253
20352
|
return;
|
|
20254
20353
|
const marker = readFileSync23(markerPath, "utf8");
|
|
20255
20354
|
const version = pluginVersion(prepared.stagingRoot);
|
|
20256
20355
|
if (validVersionSegment(version)) {
|
|
20257
20356
|
const destination = cacheDestination(prepared.handle.nativeId, version);
|
|
20258
|
-
if (
|
|
20357
|
+
if (existsSync22(destination) && statSync10(destination).isDirectory()) {
|
|
20259
20358
|
assertManagedPath2(codexHome(), destination);
|
|
20260
20359
|
writeFileSync7(join29(destination, OWNERSHIP2), marker);
|
|
20261
20360
|
}
|
|
@@ -20264,7 +20363,7 @@ function restampNativeUpgrade(prepared) {
|
|
|
20264
20363
|
if (nativeId === prepared.handle.nativeId)
|
|
20265
20364
|
continue;
|
|
20266
20365
|
const path = codex.listInstalled().find((plugin) => plugin.id === nativeId)?.path;
|
|
20267
|
-
if (path === undefined || !
|
|
20366
|
+
if (path === undefined || !existsSync22(path))
|
|
20268
20367
|
continue;
|
|
20269
20368
|
const existing = readOwnership2(path);
|
|
20270
20369
|
if (existing?.pluginId === nativeId)
|
|
@@ -20283,7 +20382,7 @@ function restampNativeUpgrade(prepared) {
|
|
|
20283
20382
|
function priorInstallMarker(prepared, nativeId) {
|
|
20284
20383
|
const bundle = rollbackBundle(prepared.handle.attemptId, prepared.handle.operationId);
|
|
20285
20384
|
const manifestPath = join29(bundle, "manifest.json");
|
|
20286
|
-
if (!
|
|
20385
|
+
if (!existsSync22(manifestPath))
|
|
20287
20386
|
return null;
|
|
20288
20387
|
const manifest = parseRollbackManifest(readFileSync23(manifestPath, "utf8"));
|
|
20289
20388
|
const install = manifest.installs.find((item) => item.nativeId === nativeId);
|
|
@@ -20320,11 +20419,11 @@ function readCodexInstall(handle) {
|
|
|
20320
20419
|
function cleanupCodexStage(reference) {
|
|
20321
20420
|
releasePriorSourceRepair(reference);
|
|
20322
20421
|
const stage = resolve16(join29(codexHome(), ".plgnz-lifecycle", `${reference.attemptId}:${reference.operationId}`));
|
|
20323
|
-
if (
|
|
20422
|
+
if (existsSync22(stage))
|
|
20324
20423
|
rmSync7(stage, { recursive: true, force: true });
|
|
20325
20424
|
const rollback = rollbackBundle(reference.attemptId, reference.operationId);
|
|
20326
20425
|
assertManagedPath2(codexHome(), rollback);
|
|
20327
|
-
if (
|
|
20426
|
+
if (existsSync22(rollback))
|
|
20328
20427
|
rmSync7(rollback, { recursive: true, force: true });
|
|
20329
20428
|
return { cleanupId: `cleanup:${reference.attemptId}:${reference.operationId}`, completed: true };
|
|
20330
20429
|
}
|
|
@@ -20384,7 +20483,7 @@ function pluginDataRoots(nativeId) {
|
|
|
20384
20483
|
];
|
|
20385
20484
|
}
|
|
20386
20485
|
function retainedTree(paths) {
|
|
20387
|
-
const present = paths.filter((path) =>
|
|
20486
|
+
const present = paths.filter((path) => existsSync22(path));
|
|
20388
20487
|
const [only, ...rest] = present;
|
|
20389
20488
|
if (only === undefined)
|
|
20390
20489
|
return { state: "absent", fingerprint: null };
|
|
@@ -20425,7 +20524,7 @@ function cacheDestination(nativeId, version) {
|
|
|
20425
20524
|
}
|
|
20426
20525
|
function cacheFingerprint(nativeId) {
|
|
20427
20526
|
const path = codex.listInstalled().find((plugin) => plugin.id === nativeId)?.path;
|
|
20428
|
-
if (path === undefined || !
|
|
20527
|
+
if (path === undefined || !existsSync22(path))
|
|
20429
20528
|
return null;
|
|
20430
20529
|
try {
|
|
20431
20530
|
return fingerprintTree(path);
|
|
@@ -20476,7 +20575,7 @@ function codexRollbackReference(attemptId, operationId) {
|
|
|
20476
20575
|
const reference = `codex:${attemptId}:${operationId}`;
|
|
20477
20576
|
const bundle = rollbackBundle(attemptId, operationId);
|
|
20478
20577
|
const capture = join29(bundle, "native-cache.json");
|
|
20479
|
-
if (!
|
|
20578
|
+
if (!existsSync22(capture))
|
|
20480
20579
|
return reference;
|
|
20481
20580
|
const digest = new CryptoHasher("sha256").update(readFileSync23(capture, "utf8")).update("\x00").update(readFileSync23(join29(bundle, "manifest.json"), "utf8")).digest("hex");
|
|
20482
20581
|
return `${reference}:native-cache-sha256:${digest}`;
|
|
@@ -20488,14 +20587,14 @@ function nativeCacheFingerprint(root, ignoreOwnership = false) {
|
|
|
20488
20587
|
const hash = new CryptoHasher("sha256");
|
|
20489
20588
|
const read = readFileSync23;
|
|
20490
20589
|
const walk = (path, relative) => {
|
|
20491
|
-
const stat =
|
|
20590
|
+
const stat = lstatSync15(path);
|
|
20492
20591
|
if (stat.isSymbolicLink() || !stat.isDirectory() && !stat.isFile())
|
|
20493
20592
|
throw new Error(`Codex native cache contains an unsafe resource: ${path}`);
|
|
20494
20593
|
hash.update(`${stat.isDirectory() ? "d" : "f"}\x00${relative}\x00${stat.mode & 4095}\x00`);
|
|
20495
20594
|
if (stat.isDirectory()) {
|
|
20496
20595
|
for (const entry of readdirSync14(path).sort()) {
|
|
20497
20596
|
if (ignoreOwnership && relative === "" && entry === OWNERSHIP2) {
|
|
20498
|
-
const marker =
|
|
20597
|
+
const marker = lstatSync15(join29(path, entry));
|
|
20499
20598
|
if (marker.isSymbolicLink() || !marker.isFile())
|
|
20500
20599
|
throw new Error("Codex attempted cache ownership marker is unsafe");
|
|
20501
20600
|
continue;
|
|
@@ -20525,7 +20624,7 @@ function nativeSlotIsOwned(installation, source) {
|
|
|
20525
20624
|
const activeProof = nativeCacheFingerprint(active.path);
|
|
20526
20625
|
return readdirSync14(slot).every((version) => {
|
|
20527
20626
|
const path = join29(slot, version);
|
|
20528
|
-
const stat =
|
|
20627
|
+
const stat = lstatSync15(path);
|
|
20529
20628
|
if (stat.isSymbolicLink())
|
|
20530
20629
|
throw new Error("Codex native cache slot is redirected");
|
|
20531
20630
|
if (!validVersionSegment(version) || !stat.isDirectory())
|
|
@@ -20574,7 +20673,7 @@ function captureNativeCacheSnapshots(projection) {
|
|
|
20574
20673
|
}
|
|
20575
20674
|
function readNativeCacheSnapshots(handle) {
|
|
20576
20675
|
const file = join29(rollbackBundle(handle.attemptId, handle.operationId), "native-cache.json");
|
|
20577
|
-
if (!
|
|
20676
|
+
if (!existsSync22(file))
|
|
20578
20677
|
throw new Error("Codex complete native cache rollback capture is missing");
|
|
20579
20678
|
if (handle.rollbackReference !== codexRollbackReference(handle.attemptId, handle.operationId))
|
|
20580
20679
|
throw new Error("Codex complete native cache authority differs from its sealed rollback reference");
|
|
@@ -20615,7 +20714,7 @@ function saveCodexRollback(attemptId, operationId, nativeIds) {
|
|
|
20615
20714
|
assertManagedPath2(codexHome(), bundle);
|
|
20616
20715
|
rmSync7(bundle, { recursive: true, force: true });
|
|
20617
20716
|
mkdirSync7(bundle, { recursive: true });
|
|
20618
|
-
const toml =
|
|
20717
|
+
const toml = existsSync22(configFile()) ? readFileSync23(configFile(), "utf8") : "";
|
|
20619
20718
|
const tables = nativeIds.map((nativeId) => ({ nativeId, block: extractPluginTable(toml, nativeId) }));
|
|
20620
20719
|
const installs = nativeIds.map((nativeId, index) => {
|
|
20621
20720
|
const slot = pluginSlot(nativeId);
|
|
@@ -20632,7 +20731,7 @@ function saveCodexRollback(attemptId, operationId, nativeIds) {
|
|
|
20632
20731
|
function restoreCodexRollback(handle) {
|
|
20633
20732
|
const bundle = rollbackBundle(handle.attemptId, handle.operationId);
|
|
20634
20733
|
const manifestPath = join29(bundle, "manifest.json");
|
|
20635
|
-
if (!
|
|
20734
|
+
if (!existsSync22(manifestPath))
|
|
20636
20735
|
throw new Error(`codex lifecycle rollback bundle is missing: ${handle.operationId}`);
|
|
20637
20736
|
const manifest = parseRollbackManifest(readFileSync23(manifestPath, "utf8"));
|
|
20638
20737
|
assertMarketplaceRollbackCurrent(handle);
|
|
@@ -20669,7 +20768,7 @@ function marketplaceCheckout(marketplace) {
|
|
|
20669
20768
|
return path;
|
|
20670
20769
|
}
|
|
20671
20770
|
function assertNativeRollbackSurfaces(handle, manifest, bundle) {
|
|
20672
|
-
const config =
|
|
20771
|
+
const config = existsSync22(configFile()) ? readFileSync23(configFile(), "utf8") : "";
|
|
20673
20772
|
for (const table of manifest.tables) {
|
|
20674
20773
|
if (extractPluginTable(config, table.nativeId) !== table.block)
|
|
20675
20774
|
throw new Error("Codex affected plugin config changed outside the captured native attempt; refusing rollback before any restore write");
|
|
@@ -20684,14 +20783,14 @@ function assertNativeRollbackSurfaces(handle, manifest, bundle) {
|
|
|
20684
20783
|
const currentFingerprint = nativeCacheFingerprint(slot.path);
|
|
20685
20784
|
if (currentFingerprint === slot.fingerprint)
|
|
20686
20785
|
return { ...slot, currentFingerprint };
|
|
20687
|
-
const projected = projections.find((path) =>
|
|
20786
|
+
const projected = projections.find((path) => existsSync22(path) && readOwnership2(path)?.pluginId === slot.nativeId);
|
|
20688
20787
|
let containsCandidate = false;
|
|
20689
20788
|
for (const version of readdirSync14(slot.path)) {
|
|
20690
20789
|
const path = join29(slot.path, version);
|
|
20691
|
-
if (!validVersionSegment(version) || !
|
|
20790
|
+
if (!validVersionSegment(version) || !lstatSync15(path).isDirectory())
|
|
20692
20791
|
throw new Error("Codex complete cache contains an unproven resource; refusing rollback before any restore write");
|
|
20693
20792
|
const priorVersion = join29(saved, version);
|
|
20694
|
-
if (
|
|
20793
|
+
if (existsSync22(priorVersion) && nativeCacheFingerprint(path) === nativeCacheFingerprint(priorVersion))
|
|
20695
20794
|
continue;
|
|
20696
20795
|
if (projected === undefined || version !== pluginVersion(projected) || (readOwnership2(path) === null ? nativeCacheFingerprint(path, true) !== nativeCacheFingerprint(projected, true) : nativeCacheFingerprint(path) !== nativeCacheFingerprint(projected))) {
|
|
20697
20796
|
throw new Error("Codex complete cache changed outside the captured native attempt; refusing rollback before any restore write");
|
|
@@ -20710,7 +20809,7 @@ function captureMarketplaceRollback(projection) {
|
|
|
20710
20809
|
throw new Error("native Codex mutation has no bounded marketplace");
|
|
20711
20810
|
const checkout = marketplaceCheckout(marketplace);
|
|
20712
20811
|
const bundle = rollbackBundle(projection.attemptId, projection.operationId);
|
|
20713
|
-
const fingerprint =
|
|
20812
|
+
const fingerprint = existsSync22(checkout) ? fingerprintTree(checkout) : null;
|
|
20714
20813
|
if (fingerprint !== null) {
|
|
20715
20814
|
const snapshot = join29(bundle, "marketplace");
|
|
20716
20815
|
cpSync6(checkout, snapshot, { recursive: true });
|
|
@@ -20721,13 +20820,13 @@ function captureMarketplaceRollback(projection) {
|
|
|
20721
20820
|
}
|
|
20722
20821
|
function captureAttemptedMarketplace(handle) {
|
|
20723
20822
|
const metadata = join29(rollbackBundle(handle.attemptId, handle.operationId), "marketplace.json");
|
|
20724
|
-
if (!
|
|
20823
|
+
if (!existsSync22(metadata))
|
|
20725
20824
|
return;
|
|
20726
20825
|
const marketplace = marketplaceOf(handle.nativeId);
|
|
20727
20826
|
if (marketplace === null || handle.sourceLocator === null)
|
|
20728
20827
|
return;
|
|
20729
20828
|
const checkout = marketplaceCheckout(marketplace);
|
|
20730
|
-
if (!
|
|
20829
|
+
if (!existsSync22(checkout))
|
|
20731
20830
|
return;
|
|
20732
20831
|
const capture = JSON.parse(readFileSync23(metadata, "utf8"));
|
|
20733
20832
|
if (typeof capture["sourceFingerprint"] !== "string" || !/^[0-9a-f]{64}$/u.test(capture["sourceFingerprint"]))
|
|
@@ -20742,14 +20841,14 @@ function captureAttemptedMarketplace(handle) {
|
|
|
20742
20841
|
}
|
|
20743
20842
|
function assertMarketplaceRollbackCurrent(handle) {
|
|
20744
20843
|
const metadata = join29(rollbackBundle(handle.attemptId, handle.operationId), "marketplace.json");
|
|
20745
|
-
if (!
|
|
20844
|
+
if (!existsSync22(metadata))
|
|
20746
20845
|
return;
|
|
20747
20846
|
const row = JSON.parse(readFileSync23(metadata, "utf8"));
|
|
20748
20847
|
const marketplace = marketplaceOf(handle.nativeId);
|
|
20749
20848
|
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
20849
|
throw new Error("invalid Codex marketplace rollback capture");
|
|
20751
20850
|
const checkout = marketplaceCheckout(marketplace);
|
|
20752
|
-
const current =
|
|
20851
|
+
const current = existsSync22(checkout) ? fingerprintTree(checkout) : null;
|
|
20753
20852
|
if (current !== row["fingerprint"] && current !== row["attemptedFingerprint"]) {
|
|
20754
20853
|
throw new Error("Codex marketplace checkout changed outside the captured native attempt; refusing rollback before any restore write");
|
|
20755
20854
|
}
|
|
@@ -20760,7 +20859,7 @@ function assertMarketplaceRollbackCurrent(handle) {
|
|
|
20760
20859
|
function restoreMarketplaceRollback(handle) {
|
|
20761
20860
|
const bundle = rollbackBundle(handle.attemptId, handle.operationId);
|
|
20762
20861
|
const metadata = join29(bundle, "marketplace.json");
|
|
20763
|
-
if (!
|
|
20862
|
+
if (!existsSync22(metadata))
|
|
20764
20863
|
return;
|
|
20765
20864
|
const capture = JSON.parse(readFileSync23(metadata, "utf8"));
|
|
20766
20865
|
if (typeof capture !== "object" || capture === null || Array.isArray(capture))
|
|
@@ -20771,7 +20870,7 @@ function restoreMarketplaceRollback(handle) {
|
|
|
20771
20870
|
throw new Error("invalid Codex marketplace rollback identity");
|
|
20772
20871
|
const checkout = marketplaceCheckout(marketplace);
|
|
20773
20872
|
if (row["fingerprint"] === null) {
|
|
20774
|
-
if (
|
|
20873
|
+
if (existsSync22(checkout))
|
|
20775
20874
|
rmSync7(checkout, { recursive: true });
|
|
20776
20875
|
return;
|
|
20777
20876
|
}
|
|
@@ -20803,18 +20902,18 @@ function pluginSlot(nativeId) {
|
|
|
20803
20902
|
return join29(codexHome(), "plugins", "cache", marketplace, name);
|
|
20804
20903
|
}
|
|
20805
20904
|
function slotVersions(slot) {
|
|
20806
|
-
if (!
|
|
20905
|
+
if (!existsSync22(slot))
|
|
20807
20906
|
return [];
|
|
20808
20907
|
return readdirSync14(slot).filter((version) => {
|
|
20809
20908
|
try {
|
|
20810
|
-
return
|
|
20909
|
+
return lstatSync15(join29(slot, version)).isDirectory();
|
|
20811
20910
|
} catch {
|
|
20812
20911
|
return false;
|
|
20813
20912
|
}
|
|
20814
20913
|
}).sort();
|
|
20815
20914
|
}
|
|
20816
20915
|
function removeUnsnapshotVersions(slot, versions) {
|
|
20817
|
-
if (slot === null || !
|
|
20916
|
+
if (slot === null || !existsSync22(slot))
|
|
20818
20917
|
return;
|
|
20819
20918
|
assertManagedPath2(codexHome(), slot);
|
|
20820
20919
|
const kept = new Set(versions);
|
|
@@ -20827,10 +20926,10 @@ function removeUnsnapshotVersions(slot, versions) {
|
|
|
20827
20926
|
}
|
|
20828
20927
|
}
|
|
20829
20928
|
function rollbackSurface(nativeIds) {
|
|
20830
|
-
const config =
|
|
20929
|
+
const config = existsSync22(configFile()) ? readFileSync23(configFile(), "utf8") : "absent";
|
|
20831
20930
|
const slots = nativeIds.map((nativeId) => {
|
|
20832
20931
|
const slot = pluginSlot(nativeId);
|
|
20833
|
-
if (slot === null || !
|
|
20932
|
+
if (slot === null || !existsSync22(slot))
|
|
20834
20933
|
return `${nativeId}:`;
|
|
20835
20934
|
return `${nativeId}:${slotVersions(slot).map((version) => {
|
|
20836
20935
|
const path = join29(slot, version);
|
|
@@ -20860,7 +20959,7 @@ function extractPluginTable(toml, id) {
|
|
|
20860
20959
|
}
|
|
20861
20960
|
function restorePluginTables(tables) {
|
|
20862
20961
|
const configPath = configFile();
|
|
20863
|
-
const current =
|
|
20962
|
+
const current = existsSync22(configPath) ? readFileSync23(configPath, "utf8") : "";
|
|
20864
20963
|
let next = current;
|
|
20865
20964
|
for (const table of tables)
|
|
20866
20965
|
next = applyPluginTable(next, table.nativeId, table.block);
|
|
@@ -20998,7 +21097,7 @@ function nativeProjection2(request) {
|
|
|
20998
21097
|
}
|
|
20999
21098
|
if (request.pins.length > 0)
|
|
21000
21099
|
return { kind: "requires-managed", reasonId: "pins-present" };
|
|
21001
|
-
if (
|
|
21100
|
+
if (existsSync22(join29(request.snapshot.snapshotRoot, codexMarketplaceMetadataFile))) {
|
|
21002
21101
|
return { kind: "requires-managed", reasonId: "native-reserved-source-metadata" };
|
|
21003
21102
|
}
|
|
21004
21103
|
const marketplace = marketplaceOf(request.snapshot.nativeId);
|
|
@@ -21024,16 +21123,16 @@ function nativeProjection2(request) {
|
|
|
21024
21123
|
}
|
|
21025
21124
|
function assertRequestedCacheOwnership(destination, observedRoots) {
|
|
21026
21125
|
assertManagedPath2(codexHome(), destination);
|
|
21027
|
-
if (
|
|
21126
|
+
if (existsSync22(destination) && !observedRoots.some((root) => root.path === destination)) {
|
|
21028
21127
|
throw new Error("Codex inactive requested version has no captured active ownership; refusing to replace it");
|
|
21029
21128
|
}
|
|
21030
21129
|
const slot = dirname9(destination);
|
|
21031
|
-
if (!
|
|
21130
|
+
if (!existsSync22(slot))
|
|
21032
21131
|
return;
|
|
21033
21132
|
const requested = destination.slice(slot.length + 1);
|
|
21034
21133
|
for (const version of readdirSync14(slot)) {
|
|
21035
21134
|
const path = join29(slot, version);
|
|
21036
|
-
if (
|
|
21135
|
+
if (lstatSync15(path).isDirectory() && wins(version, requested) && !observedRoots.some((root) => root.path === path)) {
|
|
21037
21136
|
throw new Error(`Codex inactive cache version ${version} has no captured retirement authority and would remain active over ${requested}`);
|
|
21038
21137
|
}
|
|
21039
21138
|
}
|
|
@@ -21083,7 +21182,7 @@ function marketplaceOf(nativeId) {
|
|
|
21083
21182
|
return nativeId.slice(at + 1);
|
|
21084
21183
|
}
|
|
21085
21184
|
function readConfigDocument() {
|
|
21086
|
-
if (!
|
|
21185
|
+
if (!existsSync22(configFile()))
|
|
21087
21186
|
return null;
|
|
21088
21187
|
try {
|
|
21089
21188
|
const parsed = parse(readFileSync23(configFile(), "utf8"));
|
|
@@ -21121,7 +21220,7 @@ function comparePrerelease2(left, right) {
|
|
|
21121
21220
|
}
|
|
21122
21221
|
|
|
21123
21222
|
// src/hosts/kimi-writer.ts
|
|
21124
|
-
import { cpSync as cpSync7, existsSync as
|
|
21223
|
+
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
21224
|
import { dirname as dirname10, isAbsolute as isAbsolute11, join as join30, resolve as resolve17 } from "node:path";
|
|
21126
21225
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
21127
21226
|
var MARKER4 = ".plgnz-install.json";
|
|
@@ -21137,7 +21236,7 @@ var samePhysicalKimiNativeIdentity = (plugin, prior, observation) => {
|
|
|
21137
21236
|
const managed = managedPluginPath(plugin.name);
|
|
21138
21237
|
const registryFile = join30(pluginsDir2(), "installed.json");
|
|
21139
21238
|
assertKimiManaged(plugin.name, managed, registryFile);
|
|
21140
|
-
if (!
|
|
21239
|
+
if (!existsSync23(managed))
|
|
21141
21240
|
return null;
|
|
21142
21241
|
const rows = readRegistry2(registryFile).plugins.filter((row) => row.id === plugin.name || sameRoot(row.root, managed));
|
|
21143
21242
|
if (rows.length !== 1 || rows[0].id !== plugin.name || rows[0].enabled !== true || !sameRoot(rows[0].root, managed))
|
|
@@ -21188,8 +21287,8 @@ var kimiWriter = {
|
|
|
21188
21287
|
const differentSource = marker !== null && !lifecycleLocalSource && marker.source !== resolved.sourceUri;
|
|
21189
21288
|
if (marker !== null && (differentSource || !markerHasExpectedIdentity))
|
|
21190
21289
|
throw new Error(`Kimi plugin ${id} belongs to another source; refusing to replace it`);
|
|
21191
|
-
const same =
|
|
21192
|
-
if (
|
|
21290
|
+
const same = existsSync23(target) && sameTree3(stage, target);
|
|
21291
|
+
if (existsSync23(target) && marker === null && !same) {
|
|
21193
21292
|
if (!opts?.adoptExisting)
|
|
21194
21293
|
throw new Error(`Kimi managed plugin ${id} is unowned and differs from the staged representation; pass --adopt-existing to take ownership explicitly`);
|
|
21195
21294
|
validateNativeIdentity(target, id);
|
|
@@ -21207,13 +21306,13 @@ var kimiWriter = {
|
|
|
21207
21306
|
}
|
|
21208
21307
|
if (unchanged)
|
|
21209
21308
|
return "unchanged";
|
|
21210
|
-
const registryBefore =
|
|
21309
|
+
const registryBefore = existsSync23(registryFile) ? readFileSync24(registryFile, "utf8") : undefined;
|
|
21211
21310
|
const backup = moveAside2(target, managedRoot);
|
|
21212
21311
|
try {
|
|
21213
21312
|
await nativeInstall(stage, kimiRootPath(), resolveKimiBinary());
|
|
21214
21313
|
const after = readRegistry2(registryFile);
|
|
21215
21314
|
const row = after.plugins.find((candidate) => candidate.id === id);
|
|
21216
|
-
if (row === undefined || row.enabled !== true || !sameRoot(row.root, target) || !
|
|
21315
|
+
if (row === undefined || row.enabled !== true || !sameRoot(row.root, target) || !existsSync23(target) || !sameTree3(stage, target)) {
|
|
21217
21316
|
throw new Error(`Kimi native install did not produce enabled managed plugin ${id}`);
|
|
21218
21317
|
}
|
|
21219
21318
|
} catch (error) {
|
|
@@ -21228,7 +21327,7 @@ var kimiWriter = {
|
|
|
21228
21327
|
}
|
|
21229
21328
|
},
|
|
21230
21329
|
async pin(plugin, opts) {
|
|
21231
|
-
if (plugin.path === undefined || !
|
|
21330
|
+
if (plugin.path === undefined || !existsSync23(plugin.path))
|
|
21232
21331
|
return { changes: [], refusals: [] };
|
|
21233
21332
|
return pinPluginMcpFiles(plugin.path, mcpCandidates3(), opts);
|
|
21234
21333
|
},
|
|
@@ -21272,7 +21371,7 @@ function sameRoot(value, target) {
|
|
|
21272
21371
|
}
|
|
21273
21372
|
}
|
|
21274
21373
|
function readRegistry2(path) {
|
|
21275
|
-
if (!
|
|
21374
|
+
if (!existsSync23(path))
|
|
21276
21375
|
return { version: 1, plugins: [] };
|
|
21277
21376
|
let raw;
|
|
21278
21377
|
try {
|
|
@@ -21292,18 +21391,18 @@ function restore(path, value) {
|
|
|
21292
21391
|
}
|
|
21293
21392
|
function restoreRegistryRow(registryFile, id, reference) {
|
|
21294
21393
|
const rowFile = join30(reference, "registry.row.json");
|
|
21295
|
-
const priorRow =
|
|
21394
|
+
const priorRow = existsSync23(rowFile) ? parseJson(rowFile, "Kimi registry row") : undefined;
|
|
21296
21395
|
if (priorRow !== undefined && priorRow.id !== id)
|
|
21297
21396
|
throw new Error(`Kimi rollback row is not ${id}`);
|
|
21298
|
-
const live =
|
|
21397
|
+
const live = existsSync23(registryFile) ? readRegistry2(registryFile) : { version: 1, plugins: [] };
|
|
21299
21398
|
const plugins = live.plugins.filter((row) => row.id !== id);
|
|
21300
21399
|
if (priorRow !== undefined)
|
|
21301
21400
|
plugins.push(priorRow);
|
|
21302
|
-
if (plugins.length === 0 &&
|
|
21401
|
+
if (plugins.length === 0 && existsSync23(join30(reference, "registry.absent"))) {
|
|
21303
21402
|
rmSync8(registryFile, { force: true });
|
|
21304
21403
|
return;
|
|
21305
21404
|
}
|
|
21306
|
-
if (!
|
|
21405
|
+
if (!existsSync23(registryFile) && plugins.length === 0)
|
|
21307
21406
|
return;
|
|
21308
21407
|
writeFileSync8(registryFile, JSON.stringify({ version: 1, plugins }));
|
|
21309
21408
|
}
|
|
@@ -21324,13 +21423,13 @@ function projectStagedKimi(stage, expectedName) {
|
|
|
21324
21423
|
if (manifest[key] !== undefined)
|
|
21325
21424
|
throw new Error(`Kimi root manifest ${key} is unsupported without an explicit native declaration`);
|
|
21326
21425
|
const skills = join30(stage, "skills");
|
|
21327
|
-
if (
|
|
21426
|
+
if (existsSync23(skills) && !statSync11(skills).isDirectory())
|
|
21328
21427
|
throw new Error(`Kimi skills path is not a directory: ${skills}`);
|
|
21329
|
-
if (
|
|
21428
|
+
if (existsSync23(skills))
|
|
21330
21429
|
assertKimiSkillPolicies(skills);
|
|
21331
21430
|
const native = join30(stage, "kimi.plugin.json");
|
|
21332
21431
|
let supplied = {};
|
|
21333
|
-
if (
|
|
21432
|
+
if (existsSync23(native)) {
|
|
21334
21433
|
supplied = parseJson(native, "Kimi native manifest");
|
|
21335
21434
|
if (supplied.name !== undefined && supplied.name !== expectedName)
|
|
21336
21435
|
throw new Error(`Kimi native manifest name conflicts with ${expectedName}`);
|
|
@@ -21348,7 +21447,7 @@ function projectStagedKimi(stage, expectedName) {
|
|
|
21348
21447
|
}
|
|
21349
21448
|
const commands = prepareCommands(stage, typeof supplied.commands === "string" ? supplied.commands : undefined);
|
|
21350
21449
|
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 } : {}, ...
|
|
21450
|
+
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
21451
|
writeFileSync8(native, JSON.stringify(nativeManifest, null, 2));
|
|
21353
21452
|
assertNoSymlinks4(stage);
|
|
21354
21453
|
}
|
|
@@ -21371,12 +21470,12 @@ function collectMcpServers(stage, manifest, supplied) {
|
|
|
21371
21470
|
};
|
|
21372
21471
|
add("native manifest", supplied.mcpServers);
|
|
21373
21472
|
const legacyNative = join30(stage, ".kimi-plugin", "plugin.json");
|
|
21374
|
-
if (
|
|
21473
|
+
if (existsSync23(legacyNative))
|
|
21375
21474
|
add(".kimi-plugin/plugin.json", parseJson(legacyNative, ".kimi-plugin/plugin.json").mcpServers);
|
|
21376
21475
|
add("root plugin manifest", manifest.mcpServers);
|
|
21377
21476
|
for (const file of [".mcp.json", "mcp.json"]) {
|
|
21378
21477
|
const path = join30(stage, file);
|
|
21379
|
-
if (!
|
|
21478
|
+
if (!existsSync23(path))
|
|
21380
21479
|
continue;
|
|
21381
21480
|
add(file, parseJson(path, file).mcpServers);
|
|
21382
21481
|
}
|
|
@@ -21384,14 +21483,14 @@ function collectMcpServers(stage, manifest, supplied) {
|
|
|
21384
21483
|
}
|
|
21385
21484
|
function prepareCommands(stage, supplied) {
|
|
21386
21485
|
const commands = join30(stage, "commands");
|
|
21387
|
-
if (
|
|
21486
|
+
if (existsSync23(commands) && !statSync11(commands).isDirectory())
|
|
21388
21487
|
throw new Error(`Kimi commands path is not a directory: ${commands}`);
|
|
21389
21488
|
const claude = join30(stage, ".claude", "commands");
|
|
21390
|
-
const selected = supplied === undefined ?
|
|
21489
|
+
const selected = supplied === undefined ? existsSync23(claude) ? "./.claude/commands/" : existsSync23(commands) ? "./commands/" : undefined : supplied.endsWith("/") ? supplied : `${supplied}/`;
|
|
21391
21490
|
if (selected === undefined)
|
|
21392
21491
|
return;
|
|
21393
21492
|
const dir = selected.startsWith("./.claude/") ? claude : commands;
|
|
21394
|
-
if (!
|
|
21493
|
+
if (!existsSync23(dir))
|
|
21395
21494
|
throw new Error(`Kimi native commands pointer has no directory: ${selected}`);
|
|
21396
21495
|
assertMarkdownCommandTree(dir);
|
|
21397
21496
|
if (!containsMarkdown(dir))
|
|
@@ -21401,7 +21500,7 @@ function prepareCommands(stage, supplied) {
|
|
|
21401
21500
|
function assertKimiSkillPolicies(dir) {
|
|
21402
21501
|
for (const name of readdirSync15(dir)) {
|
|
21403
21502
|
const path = join30(dir, name);
|
|
21404
|
-
const stat =
|
|
21503
|
+
const stat = lstatSync16(path);
|
|
21405
21504
|
if (stat.isDirectory())
|
|
21406
21505
|
assertKimiSkillPolicies(path);
|
|
21407
21506
|
else if (stat.isFile() && name === "SKILL.md") {
|
|
@@ -21434,7 +21533,7 @@ function openingFrontmatter2(raw, path) {
|
|
|
21434
21533
|
function assertMarkdownCommandTree(dir) {
|
|
21435
21534
|
for (const name of readdirSync15(dir)) {
|
|
21436
21535
|
const path = join30(dir, name);
|
|
21437
|
-
const stat =
|
|
21536
|
+
const stat = lstatSync16(path);
|
|
21438
21537
|
if (stat.isSymbolicLink())
|
|
21439
21538
|
throw new Error(`Kimi command source contains symlink: ${path}`);
|
|
21440
21539
|
if (stat.isDirectory())
|
|
@@ -21465,7 +21564,7 @@ function containsMarkdown(dir) {
|
|
|
21465
21564
|
});
|
|
21466
21565
|
}
|
|
21467
21566
|
function readSourceManifest(stage) {
|
|
21468
|
-
const file = [join30(stage, "plugin.json"), join30(stage, ".plugin", "plugin.json")].find(
|
|
21567
|
+
const file = [join30(stage, "plugin.json"), join30(stage, ".plugin", "plugin.json")].find(existsSync23);
|
|
21469
21568
|
if (file === undefined)
|
|
21470
21569
|
throw new Error("Kimi stage has no Agent Plugins manifest");
|
|
21471
21570
|
return parseJson(file, "Agent Plugins manifest");
|
|
@@ -21482,7 +21581,7 @@ function parseJson(path, label) {
|
|
|
21482
21581
|
}
|
|
21483
21582
|
function validateNativeIdentity(target, id) {
|
|
21484
21583
|
const file = join30(target, "kimi.plugin.json");
|
|
21485
|
-
if (!
|
|
21584
|
+
if (!existsSync23(file) || parseJson(file, "Kimi native manifest").name !== id)
|
|
21486
21585
|
throw new Error(`unowned Kimi managed plugin has no matching native manifest: ${target}`);
|
|
21487
21586
|
}
|
|
21488
21587
|
function readOwnership3(target) {
|
|
@@ -21514,7 +21613,7 @@ function rewriteOwnership(target, ownership) {
|
|
|
21514
21613
|
}
|
|
21515
21614
|
}
|
|
21516
21615
|
function sameTree3(left, right) {
|
|
21517
|
-
if (!
|
|
21616
|
+
if (!existsSync23(right))
|
|
21518
21617
|
return false;
|
|
21519
21618
|
const readBytes = readFileSync24;
|
|
21520
21619
|
const list = (root) => {
|
|
@@ -21525,7 +21624,7 @@ function sameTree3(left, right) {
|
|
|
21525
21624
|
continue;
|
|
21526
21625
|
const path = join30(dir, name);
|
|
21527
21626
|
const rel = prefix ? `${prefix}/${name}` : name;
|
|
21528
|
-
const stat =
|
|
21627
|
+
const stat = lstatSync16(path);
|
|
21529
21628
|
if (stat.isSymbolicLink())
|
|
21530
21629
|
throw new Error(`Kimi plugin contains symlink: ${path}`);
|
|
21531
21630
|
if (stat.isDirectory())
|
|
@@ -21543,14 +21642,14 @@ function sameTree3(left, right) {
|
|
|
21543
21642
|
}
|
|
21544
21643
|
function assertNoSymlinks4(root) {
|
|
21545
21644
|
const walk = (dir) => {
|
|
21546
|
-
const stat =
|
|
21645
|
+
const stat = lstatSync16(dir);
|
|
21547
21646
|
if (stat.isSymbolicLink())
|
|
21548
21647
|
throw new Error(`Kimi plugin contains symlink: ${dir}`);
|
|
21549
21648
|
if (!stat.isDirectory())
|
|
21550
21649
|
throw new Error(`Kimi plugin path is not a directory: ${dir}`);
|
|
21551
21650
|
for (const name of readdirSync15(dir)) {
|
|
21552
21651
|
const path = join30(dir, name);
|
|
21553
|
-
const child =
|
|
21652
|
+
const child = lstatSync16(path);
|
|
21554
21653
|
if (child.isSymbolicLink())
|
|
21555
21654
|
throw new Error(`Kimi plugin contains symlink: ${path}`);
|
|
21556
21655
|
if (child.isDirectory())
|
|
@@ -21562,7 +21661,7 @@ function assertNoSymlinks4(root) {
|
|
|
21562
21661
|
walk(root);
|
|
21563
21662
|
}
|
|
21564
21663
|
function moveAside2(target, root) {
|
|
21565
|
-
if (!
|
|
21664
|
+
if (!existsSync23(target))
|
|
21566
21665
|
return { commit: () => {}, rollback: () => {} };
|
|
21567
21666
|
mkdirSync8(root, { recursive: true });
|
|
21568
21667
|
const dir = mkdtempSync7(join30(root, ".plgnz-kimi-backup-"));
|
|
@@ -21575,7 +21674,7 @@ function moveAside2(target, root) {
|
|
|
21575
21674
|
}
|
|
21576
21675
|
function lstatIfPresent(path) {
|
|
21577
21676
|
try {
|
|
21578
|
-
return
|
|
21677
|
+
return lstatSync16(path);
|
|
21579
21678
|
} catch (error) {
|
|
21580
21679
|
if (error.code === "ENOENT")
|
|
21581
21680
|
return;
|
|
@@ -21591,7 +21690,7 @@ function assertManagedPath3(root, target) {
|
|
|
21591
21690
|
for (const part of selected.slice(base.length).split("/").filter(Boolean)) {
|
|
21592
21691
|
if (lstatIfPresent(current) === undefined)
|
|
21593
21692
|
break;
|
|
21594
|
-
const stat =
|
|
21693
|
+
const stat = lstatSync16(current);
|
|
21595
21694
|
if (stat.isSymbolicLink())
|
|
21596
21695
|
throw new Error(`Kimi managed path component is a symlink: ${current}`);
|
|
21597
21696
|
if (!stat.isDirectory())
|
|
@@ -21632,7 +21731,7 @@ function currentKimiVersion(exitCode, version) {
|
|
|
21632
21731
|
}
|
|
21633
21732
|
function resolveKimiBinary() {
|
|
21634
21733
|
const binary = kimiBinaryPath();
|
|
21635
|
-
if (!
|
|
21734
|
+
if (!existsSync23(binary))
|
|
21636
21735
|
throw new Error(`current Kimi Code binary not found: ${binary}`);
|
|
21637
21736
|
const probed = readKimiBinaryVersion(binary);
|
|
21638
21737
|
if (currentKimiVersion(probed.exitCode, probed.version) === undefined)
|
|
@@ -21842,11 +21941,11 @@ var kimiLifecycle = {
|
|
|
21842
21941
|
const managed = managedPluginPath(projection.packageName);
|
|
21843
21942
|
const registryFile = join30(pluginsDir2(), "installed.json");
|
|
21844
21943
|
assertKimiManaged(projection.packageName, managed, registryFile);
|
|
21845
|
-
if (
|
|
21944
|
+
if (existsSync23(managed))
|
|
21846
21945
|
cpSync7(managed, join30(rollbackReference, "managed"), { recursive: true });
|
|
21847
|
-
const priorRow =
|
|
21946
|
+
const priorRow = existsSync23(registryFile) ? readRegistry2(registryFile).plugins.find((row) => row.id === projection.packageName) : undefined;
|
|
21848
21947
|
if (priorRow === undefined) {
|
|
21849
|
-
if (!
|
|
21948
|
+
if (!existsSync23(registryFile))
|
|
21850
21949
|
writeFileSync8(join30(rollbackReference, "registry.absent"), "");
|
|
21851
21950
|
} else
|
|
21852
21951
|
writeFileSync8(join30(rollbackReference, "registry.row.json"), JSON.stringify(priorRow));
|
|
@@ -21874,10 +21973,10 @@ var kimiLifecycle = {
|
|
|
21874
21973
|
const managed = managedPluginPath(id);
|
|
21875
21974
|
const registryFile = join30(pluginsDir2(), "installed.json");
|
|
21876
21975
|
assertKimiManaged(id, managed, registryFile);
|
|
21877
|
-
const priorRow =
|
|
21878
|
-
const marker =
|
|
21976
|
+
const priorRow = existsSync23(registryFile) ? readRegistry2(registryFile).plugins.find((row) => row.id === id) : undefined;
|
|
21977
|
+
const marker = existsSync23(managed) ? readOwnership3(managed) : null;
|
|
21879
21978
|
const legacyMarker = marker !== null && !marker.pluginId.includes("@") && prepared.handle.nativeId.startsWith(`${marker.pluginId}@`);
|
|
21880
|
-
if (
|
|
21979
|
+
if (existsSync23(managed) && priorRow?.enabled === true && sameRoot(priorRow.root, managed) && sameTree3(prepared.stagingRoot, managed)) {
|
|
21881
21980
|
if (legacyMarker) {
|
|
21882
21981
|
rewriteOwnership(managed, {
|
|
21883
21982
|
...marker,
|
|
@@ -21888,12 +21987,12 @@ var kimiLifecycle = {
|
|
|
21888
21987
|
}
|
|
21889
21988
|
return { receiptId: `kimi-apply:${prepared.handle.attemptId}:${prepared.handle.operationId}`, changed: false };
|
|
21890
21989
|
}
|
|
21891
|
-
const registryBefore =
|
|
21990
|
+
const registryBefore = existsSync23(registryFile) ? readFileSync24(registryFile, "utf8") : undefined;
|
|
21892
21991
|
const backup = moveAside2(managed, dirname10(managed));
|
|
21893
21992
|
try {
|
|
21894
21993
|
await nativeInstall(prepared.stagingRoot, kimiRootPath(), resolveKimiBinary());
|
|
21895
21994
|
const row = readRegistry2(registryFile).plugins.find((candidate) => candidate.id === id);
|
|
21896
|
-
if (row === undefined || row.enabled !== true || !sameRoot(row.root, managed) || !
|
|
21995
|
+
if (row === undefined || row.enabled !== true || !sameRoot(row.root, managed) || !existsSync23(managed) || !sameTree3(prepared.stagingRoot, managed)) {
|
|
21897
21996
|
throw new Error(`Kimi native install did not produce enabled managed plugin ${id}`);
|
|
21898
21997
|
}
|
|
21899
21998
|
backup.commit();
|
|
@@ -21916,7 +22015,7 @@ var kimiLifecycle = {
|
|
|
21916
22015
|
const reference = handle.rollbackReference;
|
|
21917
22016
|
rmSync8(managed, { recursive: true, force: true });
|
|
21918
22017
|
const backup = join30(reference, "managed");
|
|
21919
|
-
if (
|
|
22018
|
+
if (existsSync23(backup))
|
|
21920
22019
|
cpSync7(backup, managed, { recursive: true });
|
|
21921
22020
|
restoreRegistryRow(registryFile, id, reference);
|
|
21922
22021
|
return { receiptId: `kimi-rollback:${handle.attemptId}:${handle.operationId}`, changed: true };
|
|
@@ -21924,7 +22023,7 @@ var kimiLifecycle = {
|
|
|
21924
22023
|
cleanup: async (reference) => {
|
|
21925
22024
|
const root = join30(pluginsDir2(), ".plgnz-kimi-lifecycle");
|
|
21926
22025
|
rmSync8(join30(root, safeSegment(reference.attemptId)), { recursive: true, force: true });
|
|
21927
|
-
if (
|
|
22026
|
+
if (existsSync23(root) && readdirSync15(root).length === 0)
|
|
21928
22027
|
rmSync8(root, { recursive: true, force: true });
|
|
21929
22028
|
return { cleanupId: `kimi-cleanup:${reference.attemptId}:${reference.operationId}`, completed: true };
|
|
21930
22029
|
}
|
|
@@ -21948,8 +22047,8 @@ function assertKimiManaged(packageName, managed, registryFile) {
|
|
|
21948
22047
|
function kimiReadback(handle) {
|
|
21949
22048
|
const managed = managedPluginPath(handle.packageName);
|
|
21950
22049
|
const registryFile = join30(pluginsDir2(), "installed.json");
|
|
21951
|
-
const row =
|
|
21952
|
-
const present = row !== undefined &&
|
|
22050
|
+
const row = existsSync23(registryFile) ? readRegistry2(registryFile).plugins.find((candidate) => candidate.id === handle.packageName) : undefined;
|
|
22051
|
+
const present = row !== undefined && existsSync23(managed) && sameRoot(row.root, managed);
|
|
21953
22052
|
const enabled = present && row?.enabled === true;
|
|
21954
22053
|
const digest = present ? fingerprintTree(managed) : null;
|
|
21955
22054
|
return {
|
|
@@ -21970,7 +22069,7 @@ function kimiReadback(handle) {
|
|
|
21970
22069
|
}
|
|
21971
22070
|
function probeKimiBinary() {
|
|
21972
22071
|
const binary = kimiBinaryPath();
|
|
21973
|
-
if (!
|
|
22072
|
+
if (!existsSync23(binary))
|
|
21974
22073
|
return { kind: "unknown" };
|
|
21975
22074
|
const probed = readKimiBinaryVersion(binary);
|
|
21976
22075
|
const version = currentKimiVersion(probed.exitCode, probed.version);
|
|
@@ -22113,12 +22212,12 @@ function unexposed(phase) {
|
|
|
22113
22212
|
}
|
|
22114
22213
|
|
|
22115
22214
|
// src/hosts/cursor-writer.ts
|
|
22116
|
-
import { accessSync as accessSync5, constants as constants5, cpSync as cpSync8, existsSync as
|
|
22215
|
+
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
22216
|
import { delimiter as delimiter4, join as join32, resolve as resolve19 } from "node:path";
|
|
22118
22217
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
22119
22218
|
|
|
22120
22219
|
// src/hosts/cursor-adoption.ts
|
|
22121
|
-
import { accessSync as accessSync4, constants as constants4, lstatSync as
|
|
22220
|
+
import { accessSync as accessSync4, constants as constants4, lstatSync as lstatSync17, readFileSync as readFileSync25, readdirSync as readdirSync16 } from "node:fs";
|
|
22122
22221
|
import { dirname as dirname11, join as join31, resolve as resolve18 } from "node:path";
|
|
22123
22222
|
var MARKER5 = ".plgnz-install.json";
|
|
22124
22223
|
function proveCursorLegacyAdoption(request) {
|
|
@@ -22279,7 +22378,7 @@ function readTree(root) {
|
|
|
22279
22378
|
const tree = new Map;
|
|
22280
22379
|
const walk = (dir, prefix) => {
|
|
22281
22380
|
for (const name of readdirSync16(dir).sort()) {
|
|
22282
|
-
const path = join31(dir, name), relative = prefix === "" ? name : `${prefix}/${name}`, stat =
|
|
22381
|
+
const path = join31(dir, name), relative = prefix === "" ? name : `${prefix}/${name}`, stat = lstatSync17(path);
|
|
22283
22382
|
if (stat.isSymbolicLink())
|
|
22284
22383
|
fail3(`symlink resource: ${relative}`);
|
|
22285
22384
|
if (stat.isDirectory()) {
|
|
@@ -22297,7 +22396,7 @@ function readTree(root) {
|
|
|
22297
22396
|
function safeAncestors(root, allowMissing) {
|
|
22298
22397
|
for (let path = resolve18(root);; path = dirname11(path)) {
|
|
22299
22398
|
if (!allowMissing || present(path)) {
|
|
22300
|
-
const stat =
|
|
22399
|
+
const stat = lstatSync17(path);
|
|
22301
22400
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
22302
22401
|
fail3(`unsafe directory: ${path}`);
|
|
22303
22402
|
}
|
|
@@ -22349,7 +22448,7 @@ function parseManifest2(entry) {
|
|
|
22349
22448
|
}
|
|
22350
22449
|
function present(path) {
|
|
22351
22450
|
try {
|
|
22352
|
-
|
|
22451
|
+
lstatSync17(path);
|
|
22353
22452
|
return true;
|
|
22354
22453
|
} catch (error) {
|
|
22355
22454
|
if (error.code === "ENOENT")
|
|
@@ -22410,8 +22509,8 @@ var cursorWriter = {
|
|
|
22410
22509
|
if (marker !== null && (differentSource || !matchesOwnership(marker.pluginId, id, ownershipId))) {
|
|
22411
22510
|
throw new Error(`Cursor local plugin ${id} belongs to another source; refusing to replace it`);
|
|
22412
22511
|
}
|
|
22413
|
-
const identicalUnowned =
|
|
22414
|
-
if (
|
|
22512
|
+
const identicalUnowned = existsSync24(target) && marker === null && sameTree4(stage, target);
|
|
22513
|
+
if (existsSync24(target) && marker === null && !identicalUnowned) {
|
|
22415
22514
|
if (!opts?.adoptExisting)
|
|
22416
22515
|
throw new Error(`Cursor local plugin ${id} is unowned and differs from the staged representation; pass --adopt-existing to take ownership explicitly`);
|
|
22417
22516
|
validateExistingIdentity(target, id, sourceVersion(plugin.dir));
|
|
@@ -22430,7 +22529,7 @@ var cursorWriter = {
|
|
|
22430
22529
|
}
|
|
22431
22530
|
},
|
|
22432
22531
|
async pin(plugin, opts) {
|
|
22433
|
-
if (plugin.path === undefined || !
|
|
22532
|
+
if (plugin.path === undefined || !existsSync24(plugin.path))
|
|
22434
22533
|
return { changes: [], refusals: [] };
|
|
22435
22534
|
return pinPluginMcpFiles(plugin.path, mcpCandidates4(), opts);
|
|
22436
22535
|
},
|
|
@@ -22464,7 +22563,7 @@ function projectCommandsToSkills(stage) {
|
|
|
22464
22563
|
throw new Error(`Cursor command projection collision: ${command.name}`);
|
|
22465
22564
|
seen.add(command.name);
|
|
22466
22565
|
const target = join32(stage, "skills", command.name, "SKILL.md");
|
|
22467
|
-
if (
|
|
22566
|
+
if (existsSync24(target))
|
|
22468
22567
|
throw new Error(`Cursor command collides with an existing skill: ${command.name}`);
|
|
22469
22568
|
mkdirSync9(join32(stage, "skills", command.name), { recursive: true });
|
|
22470
22569
|
const body = command.body.endsWith(`
|
|
@@ -22482,13 +22581,13 @@ ${body}`);
|
|
|
22482
22581
|
}
|
|
22483
22582
|
}
|
|
22484
22583
|
function hasCommands(root) {
|
|
22485
|
-
return
|
|
22584
|
+
return existsSync24(join32(root, "commands")) || existsSync24(join32(root, ".claude", "commands"));
|
|
22486
22585
|
}
|
|
22487
22586
|
function ensureCursorManifest(stage, expectedName) {
|
|
22488
22587
|
const cursorManifest = join32(stage, ".cursor-plugin", "plugin.json");
|
|
22489
|
-
if (
|
|
22588
|
+
if (existsSync24(cursorManifest))
|
|
22490
22589
|
return;
|
|
22491
|
-
const source = manifestCandidates(stage).find(
|
|
22590
|
+
const source = manifestCandidates(stage).find(existsSync24);
|
|
22492
22591
|
if (source === undefined)
|
|
22493
22592
|
throw new Error("Cursor stage has no Agent Plugins manifest");
|
|
22494
22593
|
mkdirSync9(join32(stage, ".cursor-plugin"), { recursive: true });
|
|
@@ -22501,7 +22600,7 @@ function validateStage2(stage, expectedName) {
|
|
|
22501
22600
|
const native = parseManifest3(join32(stage, ".cursor-plugin", "plugin.json"));
|
|
22502
22601
|
if (native.name !== expectedName)
|
|
22503
22602
|
throw new Error(`Cursor manifest identity does not match ${expectedName}`);
|
|
22504
|
-
const canonicalPath = manifestCandidates(stage).find(
|
|
22603
|
+
const canonicalPath = manifestCandidates(stage).find(existsSync24);
|
|
22505
22604
|
if (canonicalPath !== undefined) {
|
|
22506
22605
|
const canonical = parseManifest3(canonicalPath);
|
|
22507
22606
|
if (native.name !== canonical.name || canonical.version !== undefined && native.version !== canonical.version) {
|
|
@@ -22509,14 +22608,14 @@ function validateStage2(stage, expectedName) {
|
|
|
22509
22608
|
}
|
|
22510
22609
|
}
|
|
22511
22610
|
const skills = join32(stage, "skills");
|
|
22512
|
-
if (
|
|
22611
|
+
if (existsSync24(skills) && !statSync12(skills).isDirectory())
|
|
22513
22612
|
throw new Error("Cursor stage skills path is not a directory");
|
|
22514
22613
|
}
|
|
22515
22614
|
function manifestCandidates(root) {
|
|
22516
22615
|
return [join32(root, ".claude-plugin", "plugin.json"), join32(root, "plugin.json"), join32(root, ".plugin", "plugin.json")];
|
|
22517
22616
|
}
|
|
22518
22617
|
function sourceVersion(root) {
|
|
22519
|
-
const manifest = [join32(root, ".cursor-plugin", "plugin.json"), ...manifestCandidates(root)].find(
|
|
22618
|
+
const manifest = [join32(root, ".cursor-plugin", "plugin.json"), ...manifestCandidates(root)].find(existsSync24);
|
|
22520
22619
|
return manifest === undefined ? undefined : parseManifest3(manifest).version;
|
|
22521
22620
|
}
|
|
22522
22621
|
function parseManifest3(path) {
|
|
@@ -22537,7 +22636,7 @@ function parseManifest3(path) {
|
|
|
22537
22636
|
}
|
|
22538
22637
|
function validateExistingIdentity(target, expectedName, expectedVersion) {
|
|
22539
22638
|
const manifest = join32(target, ".cursor-plugin", "plugin.json");
|
|
22540
|
-
if (!
|
|
22639
|
+
if (!existsSync24(manifest))
|
|
22541
22640
|
throw new Error(`unowned Cursor local plugin has no native manifest: ${target}`);
|
|
22542
22641
|
const parsed = parseManifest3(manifest);
|
|
22543
22642
|
if (parsed.name !== expectedName || parsed.version !== expectedVersion)
|
|
@@ -22545,7 +22644,7 @@ function validateExistingIdentity(target, expectedName, expectedVersion) {
|
|
|
22545
22644
|
}
|
|
22546
22645
|
function readOwnership4(target) {
|
|
22547
22646
|
const marker = join32(target, OWNERSHIP3);
|
|
22548
|
-
if (!
|
|
22647
|
+
if (!existsSync24(marker))
|
|
22549
22648
|
return null;
|
|
22550
22649
|
try {
|
|
22551
22650
|
const value = JSON.parse(readFileSync26(marker, "utf8"));
|
|
@@ -22589,7 +22688,7 @@ function ownsNativeDirectory(markerId, nativeId) {
|
|
|
22589
22688
|
return markerId.startsWith(prefix) && validIdentity2(markerId.slice(prefix.length));
|
|
22590
22689
|
}
|
|
22591
22690
|
function activate3(stage, target, root) {
|
|
22592
|
-
if (!
|
|
22691
|
+
if (!existsSync24(target)) {
|
|
22593
22692
|
renameSync6(stage, target);
|
|
22594
22693
|
return { commit: () => {} };
|
|
22595
22694
|
}
|
|
@@ -22606,7 +22705,7 @@ function activate3(stage, target, root) {
|
|
|
22606
22705
|
return { commit: () => rmSync9(backupRoot, { recursive: true, force: true }) };
|
|
22607
22706
|
}
|
|
22608
22707
|
function sameTree4(left, right) {
|
|
22609
|
-
if (!
|
|
22708
|
+
if (!existsSync24(right))
|
|
22610
22709
|
return false;
|
|
22611
22710
|
const entries = (root) => {
|
|
22612
22711
|
const out = [];
|
|
@@ -22616,7 +22715,7 @@ function sameTree4(left, right) {
|
|
|
22616
22715
|
continue;
|
|
22617
22716
|
const path = join32(dir, name);
|
|
22618
22717
|
const relative = prefix === "" ? name : `${prefix}/${name}`;
|
|
22619
|
-
const stat =
|
|
22718
|
+
const stat = lstatSync18(path);
|
|
22620
22719
|
if (stat.isSymbolicLink())
|
|
22621
22720
|
throw new Error(`Cursor managed plugin contains symlink: ${path}`);
|
|
22622
22721
|
if (stat.isDirectory())
|
|
@@ -22643,15 +22742,15 @@ function assertManagedDirectory(root, target) {
|
|
|
22643
22742
|
throw new Error(`Cursor managed path escapes its store: ${target}`);
|
|
22644
22743
|
let current = resolvedRoot;
|
|
22645
22744
|
for (const part of resolvedTarget.slice(resolvedRoot.length).split("/").filter(Boolean)) {
|
|
22646
|
-
if (
|
|
22745
|
+
if (existsSync24(current))
|
|
22647
22746
|
assertDirectoryNotLink(current);
|
|
22648
22747
|
current = join32(current, part);
|
|
22649
22748
|
}
|
|
22650
|
-
if (
|
|
22749
|
+
if (existsSync24(current))
|
|
22651
22750
|
assertDirectoryNotLink(current);
|
|
22652
22751
|
}
|
|
22653
22752
|
function assertDirectoryNotLink(path) {
|
|
22654
|
-
const stat =
|
|
22753
|
+
const stat = lstatSync18(path);
|
|
22655
22754
|
if (stat.isSymbolicLink())
|
|
22656
22755
|
throw new Error(`Cursor managed path component is a symlink: ${path}`);
|
|
22657
22756
|
if (!stat.isDirectory())
|
|
@@ -22659,14 +22758,14 @@ function assertDirectoryNotLink(path) {
|
|
|
22659
22758
|
}
|
|
22660
22759
|
function assertNoSymlinks5(root) {
|
|
22661
22760
|
const walk = (dir) => {
|
|
22662
|
-
const stat =
|
|
22761
|
+
const stat = lstatSync18(dir);
|
|
22663
22762
|
if (stat.isSymbolicLink())
|
|
22664
22763
|
throw new Error(`Cursor plugin source contains symlink: ${dir}`);
|
|
22665
22764
|
if (!stat.isDirectory())
|
|
22666
22765
|
throw new Error(`Cursor plugin source is not a directory: ${dir}`);
|
|
22667
22766
|
for (const name of readdirSync17(dir)) {
|
|
22668
22767
|
const path = join32(dir, name);
|
|
22669
|
-
const entry =
|
|
22768
|
+
const entry = lstatSync18(path);
|
|
22670
22769
|
if (entry.isSymbolicLink())
|
|
22671
22770
|
throw new Error(`Cursor plugin source contains symlink: ${path}`);
|
|
22672
22771
|
if (entry.isDirectory())
|
|
@@ -22866,7 +22965,7 @@ var cursorLifecycleDefinition = {
|
|
|
22866
22965
|
const handle = prepared.handle;
|
|
22867
22966
|
const target = managedPluginDir(handle.target.instance, handle.nativeId);
|
|
22868
22967
|
refuseForeignScope(target, handle.scopeId, handle.nativeId);
|
|
22869
|
-
if (
|
|
22968
|
+
if (existsSync24(target) && fingerprintTree(target) === fingerprintTree(prepared.stagingRoot)) {
|
|
22870
22969
|
return { receiptId: receipt("apply", handle), changed: false };
|
|
22871
22970
|
}
|
|
22872
22971
|
const root = localDir(handle.target.instance);
|
|
@@ -22887,7 +22986,7 @@ var cursorLifecycleDefinition = {
|
|
|
22887
22986
|
async retire(prepared) {
|
|
22888
22987
|
const handle = prepared.handle;
|
|
22889
22988
|
const target = managedPluginDir(handle.target.instance, handle.nativeId);
|
|
22890
|
-
if (!
|
|
22989
|
+
if (!existsSync24(target))
|
|
22891
22990
|
return { receiptId: receipt("retire", handle), changed: false };
|
|
22892
22991
|
refuseForeignScope(target, handle.scopeId, handle.nativeId);
|
|
22893
22992
|
rmSync9(target, { recursive: true, force: true });
|
|
@@ -22909,15 +23008,15 @@ var cursorLifecycleDefinition = {
|
|
|
22909
23008
|
const root = localDir(handle.target.instance);
|
|
22910
23009
|
const target = managedPluginDir(handle.target.instance, handle.nativeId);
|
|
22911
23010
|
const backup = join32(handle.rollbackReference, "active");
|
|
22912
|
-
const restore = prior.presence === "present" &&
|
|
23011
|
+
const restore = prior.presence === "present" && existsSync24(backup);
|
|
22913
23012
|
if (!restore) {
|
|
22914
|
-
if (prior.presence === "present" || !
|
|
23013
|
+
if (prior.presence === "present" || !existsSync24(target))
|
|
22915
23014
|
return { receiptId: receipt("rollback", handle), changed: false };
|
|
22916
23015
|
refuseForeignScope(target, handle.scopeId, handle.nativeId);
|
|
22917
23016
|
rmSync9(target, { recursive: true, force: true });
|
|
22918
23017
|
return { receiptId: receipt("rollback", handle), changed: true };
|
|
22919
23018
|
}
|
|
22920
|
-
if (
|
|
23019
|
+
if (existsSync24(target)) {
|
|
22921
23020
|
refuseForeignScope(target, handle.scopeId, handle.nativeId);
|
|
22922
23021
|
if (fingerprintTree(target) === fingerprintTree(backup))
|
|
22923
23022
|
return { receiptId: receipt("rollback", handle), changed: false };
|
|
@@ -22969,7 +23068,7 @@ function probeCursorVersion() {
|
|
|
22969
23068
|
function locateCursorProbeBinary() {
|
|
22970
23069
|
const override = process.env["OPEN_PLUGIN_CURSOR_BIN"];
|
|
22971
23070
|
if (override !== undefined) {
|
|
22972
|
-
if (override.length === 0 || !
|
|
23071
|
+
if (override.length === 0 || !existsSync24(override))
|
|
22973
23072
|
return { kind: "refused" };
|
|
22974
23073
|
return { kind: "path", path: override };
|
|
22975
23074
|
}
|
|
@@ -23012,7 +23111,7 @@ function decodeStdout(bytes) {
|
|
|
23012
23111
|
}
|
|
23013
23112
|
function inventoryLocalStore(target) {
|
|
23014
23113
|
const root = localDir(target.instance);
|
|
23015
|
-
if (!
|
|
23114
|
+
if (!existsSync24(root))
|
|
23016
23115
|
return { target, installations: [] };
|
|
23017
23116
|
const installations = [];
|
|
23018
23117
|
for (const entry of readdirSync17(root)) {
|
|
@@ -23033,7 +23132,7 @@ function inventoryLocalStore(target) {
|
|
|
23033
23132
|
}
|
|
23034
23133
|
function readLocalInstallation(entry, dir) {
|
|
23035
23134
|
const manifestPath = join32(dir, ".cursor-plugin", "plugin.json");
|
|
23036
|
-
if (!
|
|
23135
|
+
if (!existsSync24(manifestPath))
|
|
23037
23136
|
return;
|
|
23038
23137
|
let manifest;
|
|
23039
23138
|
let marker = null;
|
|
@@ -23135,7 +23234,7 @@ function applyRecordedPins(stage, pins) {
|
|
|
23135
23234
|
for (const pin of pins) {
|
|
23136
23235
|
let found = false;
|
|
23137
23236
|
for (const file of [join32(stage, ".mcp.json"), join32(stage, "mcp.json")]) {
|
|
23138
|
-
if (!
|
|
23237
|
+
if (!existsSync24(file))
|
|
23139
23238
|
continue;
|
|
23140
23239
|
const parsed = JSON.parse(readFileSync26(file, "utf8"));
|
|
23141
23240
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
|
|
@@ -23164,7 +23263,7 @@ function projectReadback(identity) {
|
|
|
23164
23263
|
inactiveMetadata: retainedResource(instance, identity.nativeId, "metadata")
|
|
23165
23264
|
};
|
|
23166
23265
|
const dir = join32(localDir(instance), identity.nativeId);
|
|
23167
|
-
if (!
|
|
23266
|
+
if (!existsSync24(dir)) {
|
|
23168
23267
|
return {
|
|
23169
23268
|
adapterId: identity.adapterId,
|
|
23170
23269
|
target: identity.target,
|
|
@@ -23200,9 +23299,9 @@ function projectReadback(identity) {
|
|
|
23200
23299
|
}
|
|
23201
23300
|
function retainedResource(instance, nativeId, kind) {
|
|
23202
23301
|
const dir = retentionDir(instance, nativeId, kind);
|
|
23203
|
-
if (!
|
|
23302
|
+
if (!existsSync24(dir))
|
|
23204
23303
|
return { state: "absent", fingerprint: null };
|
|
23205
|
-
const stat =
|
|
23304
|
+
const stat = lstatSync18(dir);
|
|
23206
23305
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
23207
23306
|
throw new Error(`Cursor retained ${kind} is not a directory: ${dir}`);
|
|
23208
23307
|
return { state: "present", fingerprint: fingerprintTree(dir) };
|
|
@@ -23220,7 +23319,7 @@ function captureRollback2(instance, attemptId, operationId, nativeId, prior) {
|
|
|
23220
23319
|
rmSync9(reference, { recursive: true, force: true });
|
|
23221
23320
|
mkdirSync9(reference, { recursive: true });
|
|
23222
23321
|
const active = join32(localDir(instance), nativeId);
|
|
23223
|
-
if (
|
|
23322
|
+
if (existsSync24(active))
|
|
23224
23323
|
cpSync8(active, join32(reference, "active"), { recursive: true });
|
|
23225
23324
|
writeFileSync9(join32(reference, "prior.json"), `${JSON.stringify(prior)}
|
|
23226
23325
|
`);
|
|
@@ -23253,7 +23352,7 @@ function absentRoute(action, route) {
|
|
|
23253
23352
|
}
|
|
23254
23353
|
}
|
|
23255
23354
|
function refuseForeignScope(target, scopeId, nativeId) {
|
|
23256
|
-
if (!
|
|
23355
|
+
if (!existsSync24(target))
|
|
23257
23356
|
return;
|
|
23258
23357
|
const marker = readOwnership4(target);
|
|
23259
23358
|
if (marker === null || !ownsNativeDirectory(marker.pluginId, nativeId)) {
|
|
@@ -23282,7 +23381,7 @@ function receipt(kind, handle) {
|
|
|
23282
23381
|
|
|
23283
23382
|
// src/hosts/omp-writer.ts
|
|
23284
23383
|
init_omp_hooks();
|
|
23285
|
-
import { cpSync as cpSync9, existsSync as
|
|
23384
|
+
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
23385
|
import { dirname as dirname12, join as join33, resolve as resolve20 } from "node:path";
|
|
23287
23386
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
23288
23387
|
var MARKER6 = ".plgnz-install.json";
|
|
@@ -23378,7 +23477,7 @@ var ompWriter = {
|
|
|
23378
23477
|
}
|
|
23379
23478
|
},
|
|
23380
23479
|
async pin(plugin, opts) {
|
|
23381
|
-
if (plugin.path === undefined || !
|
|
23480
|
+
if (plugin.path === undefined || !existsSync25(plugin.path))
|
|
23382
23481
|
return { changes: [], refusals: [] };
|
|
23383
23482
|
return pinPluginMcpFiles(plugin.path, mcpCandidates5(), opts);
|
|
23384
23483
|
},
|
|
@@ -23472,7 +23571,7 @@ function registryInstallPaths(registry) {
|
|
|
23472
23571
|
}
|
|
23473
23572
|
function findOwned(id) {
|
|
23474
23573
|
const root = join33(pluginsDir3(), MANAGED);
|
|
23475
|
-
if (!
|
|
23574
|
+
if (!existsSync25(root))
|
|
23476
23575
|
return null;
|
|
23477
23576
|
for (const name of readdirSync18(root)) {
|
|
23478
23577
|
const path = join33(root, name);
|
|
@@ -23490,7 +23589,7 @@ function assertOwnedLink(path, target, owned) {
|
|
|
23490
23589
|
}
|
|
23491
23590
|
function lstatExists(path) {
|
|
23492
23591
|
try {
|
|
23493
|
-
|
|
23592
|
+
lstatSync19(path);
|
|
23494
23593
|
return true;
|
|
23495
23594
|
} catch {
|
|
23496
23595
|
return false;
|
|
@@ -23498,7 +23597,7 @@ function lstatExists(path) {
|
|
|
23498
23597
|
}
|
|
23499
23598
|
function linkPointsTo(path, target) {
|
|
23500
23599
|
try {
|
|
23501
|
-
return
|
|
23600
|
+
return lstatSync19(path).isSymbolicLink() && resolve20(dirname12(path), readlinkSync2(path)) === resolve20(target);
|
|
23502
23601
|
} catch {
|
|
23503
23602
|
return false;
|
|
23504
23603
|
}
|
|
@@ -23538,7 +23637,7 @@ function mkdirSafe(path) {
|
|
|
23538
23637
|
const parentBoundary = dirname12(boundary);
|
|
23539
23638
|
for (let current = target;; current = dirname12(current)) {
|
|
23540
23639
|
if (lstatExists(current)) {
|
|
23541
|
-
const stat =
|
|
23640
|
+
const stat = lstatSync19(current);
|
|
23542
23641
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
23543
23642
|
throw new Error(`OMP managed path is unsafe: ${current}`);
|
|
23544
23643
|
}
|
|
@@ -23548,7 +23647,7 @@ function mkdirSafe(path) {
|
|
|
23548
23647
|
mkdirSync10(path, { recursive: true });
|
|
23549
23648
|
let current = target;
|
|
23550
23649
|
while (true) {
|
|
23551
|
-
const stat =
|
|
23650
|
+
const stat = lstatSync19(current);
|
|
23552
23651
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
23553
23652
|
throw new Error(`OMP managed path is unsafe: ${current}`);
|
|
23554
23653
|
if (current === boundary)
|
|
@@ -23564,7 +23663,7 @@ function assertExistingDirectoryTree(boundaryPath, targetPath, label) {
|
|
|
23564
23663
|
for (let current = target;; current = dirname12(current)) {
|
|
23565
23664
|
if (!lstatExists(current))
|
|
23566
23665
|
throw new Error(`${label} has no safe native copy`);
|
|
23567
|
-
const stat =
|
|
23666
|
+
const stat = lstatSync19(current);
|
|
23568
23667
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
23569
23668
|
throw new Error(`${label} contains a symlink or non-directory component: ${current}`);
|
|
23570
23669
|
if (current === boundary)
|
|
@@ -23572,7 +23671,7 @@ function assertExistingDirectoryTree(boundaryPath, targetPath, label) {
|
|
|
23572
23671
|
}
|
|
23573
23672
|
}
|
|
23574
23673
|
function sameTree5(left, right) {
|
|
23575
|
-
if (!
|
|
23674
|
+
if (!existsSync25(right))
|
|
23576
23675
|
return false;
|
|
23577
23676
|
const bytes = readFileSync27;
|
|
23578
23677
|
const list = (root) => {
|
|
@@ -23583,7 +23682,7 @@ function sameTree5(left, right) {
|
|
|
23583
23682
|
continue;
|
|
23584
23683
|
const path = join33(dir, name);
|
|
23585
23684
|
const rel = prefix ? `${prefix}/${name}` : name;
|
|
23586
|
-
const stat =
|
|
23685
|
+
const stat = lstatSync19(path);
|
|
23587
23686
|
if (stat.isSymbolicLink())
|
|
23588
23687
|
throw new Error(`OMP managed plugin contains symlink: ${path}`);
|
|
23589
23688
|
if (stat.isDirectory())
|
|
@@ -23601,7 +23700,7 @@ function sameTree5(left, right) {
|
|
|
23601
23700
|
}
|
|
23602
23701
|
function ownership2(path) {
|
|
23603
23702
|
const marker = join33(path, MARKER6);
|
|
23604
|
-
if (!
|
|
23703
|
+
if (!existsSync25(marker))
|
|
23605
23704
|
return null;
|
|
23606
23705
|
const value = readDoc(marker, {}, "ownership marker");
|
|
23607
23706
|
if (typeof value.source !== "string" || typeof value.pluginId !== "string" || typeof value.fingerprint !== "string" || typeof value.packageName !== "string")
|
|
@@ -23620,7 +23719,7 @@ function ownership2(path) {
|
|
|
23620
23719
|
};
|
|
23621
23720
|
}
|
|
23622
23721
|
function readDoc(path, fallback, label) {
|
|
23623
|
-
if (!
|
|
23722
|
+
if (!existsSync25(path))
|
|
23624
23723
|
return fallback;
|
|
23625
23724
|
try {
|
|
23626
23725
|
const value = JSON.parse(readFileSync27(path, "utf8"));
|
|
@@ -23650,7 +23749,7 @@ function writeDoc(path, value) {
|
|
|
23650
23749
|
writeFileSync10(path, JSON.stringify(value, null, 2));
|
|
23651
23750
|
}
|
|
23652
23751
|
function snapshot(path) {
|
|
23653
|
-
return
|
|
23752
|
+
return existsSync25(path) ? readFileSync27(path, "utf8") : undefined;
|
|
23654
23753
|
}
|
|
23655
23754
|
function restore2(path, value) {
|
|
23656
23755
|
if (value === undefined)
|
|
@@ -23872,7 +23971,7 @@ async function observeInventory(target) {
|
|
|
23872
23971
|
return { target, installations: omp.listInstalled().map((plugin) => installationOf(plugin)) };
|
|
23873
23972
|
}
|
|
23874
23973
|
function installationOf(plugin) {
|
|
23875
|
-
const path = plugin.path !== undefined &&
|
|
23974
|
+
const path = plugin.path !== undefined && existsSync25(plugin.path) ? resolve20(plugin.path) : undefined;
|
|
23876
23975
|
if (path === undefined) {
|
|
23877
23976
|
return {
|
|
23878
23977
|
nativeId: plugin.id,
|
|
@@ -23913,7 +24012,7 @@ function sourceOf2(owner) {
|
|
|
23913
24012
|
}
|
|
23914
24013
|
function observeReadback(identity) {
|
|
23915
24014
|
const target = managedPackageDir(identity.nativeId);
|
|
23916
|
-
const present =
|
|
24015
|
+
const present = existsSync25(target) && linkPointsTo(managedLink(identity.nativeId), target);
|
|
23917
24016
|
const retention = retentionOf(identity.nativeId);
|
|
23918
24017
|
if (!present) {
|
|
23919
24018
|
return {
|
|
@@ -23957,17 +24056,17 @@ function retentionOf(nativeId) {
|
|
|
23957
24056
|
};
|
|
23958
24057
|
}
|
|
23959
24058
|
function resourceObservation(path) {
|
|
23960
|
-
if (!
|
|
24059
|
+
if (!existsSync25(path))
|
|
23961
24060
|
return { state: "absent", fingerprint: null };
|
|
23962
24061
|
return { state: "present", fingerprint: fingerprintTree(path) };
|
|
23963
24062
|
}
|
|
23964
24063
|
function lockMetadataObservation(nativeId) {
|
|
23965
|
-
if (!
|
|
24064
|
+
if (!existsSync25(lockPath()))
|
|
23966
24065
|
return { state: "absent", fingerprint: null };
|
|
23967
24066
|
return { state: "present", fingerprint: sha256(canonical3(metadataView(readDoc(lockPath(), {}, "lockfile"), npmName(nativeId)))) };
|
|
23968
24067
|
}
|
|
23969
24068
|
function plannedLockMetadata(nativeId, version) {
|
|
23970
|
-
const lock =
|
|
24069
|
+
const lock = existsSync25(lockPath()) ? readDoc(lockPath(), {}, "lockfile") : { plugins: {}, settings: {} };
|
|
23971
24070
|
const plugins = isDoc(lock.plugins) ? lock.plugins : {};
|
|
23972
24071
|
const npm = npmName(nativeId);
|
|
23973
24072
|
const next = { ...lock, plugins: { ...plugins, [npm]: activatedEntry(entry(plugins[npm]), version) } };
|
|
@@ -24005,7 +24104,7 @@ function captureRollback3(nativeId, attemptId, operationId) {
|
|
|
24005
24104
|
mkdirSafe(preparationDir2(attemptId, operationId));
|
|
24006
24105
|
mkdirSync10(reference, { recursive: true });
|
|
24007
24106
|
const target = managedPackageDir(nativeId);
|
|
24008
|
-
if (
|
|
24107
|
+
if (existsSync25(target))
|
|
24009
24108
|
cpSync9(target, join33(reference, "package"), { recursive: true });
|
|
24010
24109
|
writeFileSync10(join33(reference, "state.json"), JSON.stringify({ lock: captureLockRow(nativeId), link: currentLinkTarget(managedLink(nativeId)) }));
|
|
24011
24110
|
return resolve20(reference);
|
|
@@ -24015,7 +24114,7 @@ function restoreRollback2(nativeId, reference) {
|
|
|
24015
24114
|
const target = managedPackageDir(nativeId);
|
|
24016
24115
|
rmSync10(target, { recursive: true, force: true });
|
|
24017
24116
|
const backup = join33(reference, "package");
|
|
24018
|
-
if (
|
|
24117
|
+
if (existsSync25(backup)) {
|
|
24019
24118
|
mkdirSafe(dirname12(target));
|
|
24020
24119
|
cpSync9(backup, target, { recursive: true });
|
|
24021
24120
|
}
|
|
@@ -24029,7 +24128,7 @@ function restoreRollback2(nativeId, reference) {
|
|
|
24029
24128
|
}
|
|
24030
24129
|
function captureLockRow(nativeId) {
|
|
24031
24130
|
const packageName = npmName(nativeId);
|
|
24032
|
-
if (!
|
|
24131
|
+
if (!existsSync25(lockPath()))
|
|
24033
24132
|
return { packageName, present: false, row: null };
|
|
24034
24133
|
const lock = readDoc(lockPath(), {}, "lockfile");
|
|
24035
24134
|
const plugins = isDoc(lock.plugins) ? lock.plugins : {};
|
|
@@ -24039,7 +24138,7 @@ function captureLockRow(nativeId) {
|
|
|
24039
24138
|
}
|
|
24040
24139
|
function restoreLockRow(saved) {
|
|
24041
24140
|
const file = lockPath();
|
|
24042
|
-
if (!
|
|
24141
|
+
if (!existsSync25(file)) {
|
|
24043
24142
|
if (!saved.present)
|
|
24044
24143
|
return;
|
|
24045
24144
|
writeDoc(file, { plugins: { [saved.packageName]: saved.row } });
|
|
@@ -24055,7 +24154,7 @@ function restoreLockRow(saved) {
|
|
|
24055
24154
|
}
|
|
24056
24155
|
function currentLinkTarget(path) {
|
|
24057
24156
|
try {
|
|
24058
|
-
return
|
|
24157
|
+
return lstatSync19(path).isSymbolicLink() ? resolve20(dirname12(path), readlinkSync2(path)) : null;
|
|
24059
24158
|
} catch {
|
|
24060
24159
|
return null;
|
|
24061
24160
|
}
|
|
@@ -24097,7 +24196,7 @@ async function applyManaged(handle, stagingRoot) {
|
|
|
24097
24196
|
}
|
|
24098
24197
|
function activationAlreadyCurrent(nativeId, stage, version) {
|
|
24099
24198
|
const target = managedPackageDir(nativeId);
|
|
24100
|
-
if (!
|
|
24199
|
+
if (!existsSync25(target) || !existsSync25(stage) || fingerprintTree(stage) !== fingerprintTree(target) || !linkPointsTo(managedLink(nativeId), target))
|
|
24101
24200
|
return false;
|
|
24102
24201
|
const lock = readDoc(lockPath(), { plugins: {}, settings: {} }, "lockfile");
|
|
24103
24202
|
const plugins = object8(lock.plugins, "lockfile plugins");
|
|
@@ -24158,9 +24257,10 @@ function captureRecorded(activation, route, attemptId, operationId, affectedOper
|
|
|
24158
24257
|
// src/native-hook-writer.ts
|
|
24159
24258
|
init_hooks();
|
|
24160
24259
|
init_hook_build();
|
|
24161
|
-
import { chmodSync as chmodSync2, cpSync as cpSync10, existsSync as
|
|
24260
|
+
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
24261
|
import { dirname as dirname13, join as join34 } from "node:path";
|
|
24163
24262
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
24263
|
+
init_compatibility();
|
|
24164
24264
|
function probeHookHostVersion(command, override) {
|
|
24165
24265
|
const binary = process.env[override] ?? which(command);
|
|
24166
24266
|
if (!binary)
|
|
@@ -24182,8 +24282,8 @@ function createNativeHookWriter(options) {
|
|
|
24182
24282
|
if (reader.listInstalled().some((item) => item.id === id && item.path !== target)) {
|
|
24183
24283
|
throw new Error("Native hook identity already belongs to a historical standalone install; remove that owned install before retrying: " + id);
|
|
24184
24284
|
}
|
|
24185
|
-
const owner =
|
|
24186
|
-
if (
|
|
24285
|
+
const owner = existsSync26(target) ? readHookOwner(target) : null;
|
|
24286
|
+
if (existsSync26(target) && (owner === null || owner.pluginId !== id || owner.source !== source)) {
|
|
24187
24287
|
throw new Error("Native hook package is not owned for this source: " + target);
|
|
24188
24288
|
}
|
|
24189
24289
|
const raw = registrationText(registration);
|
|
@@ -24207,7 +24307,7 @@ function createNativeHookWriter(options) {
|
|
|
24207
24307
|
}, [profile]);
|
|
24208
24308
|
if (admission.status === "refused")
|
|
24209
24309
|
throw new PackageCapabilityError(store.id, admission);
|
|
24210
|
-
if (
|
|
24310
|
+
if (existsSync26(join34(plugin.dir, NATIVE_HOOK_MARKER)))
|
|
24211
24311
|
throw new Error("Source contains reserved native hook ownership metadata");
|
|
24212
24312
|
preflightPortableHooks(adapter, plugin.dir);
|
|
24213
24313
|
checkTarget(idFor(plugin), resolved.sourceUri);
|
|
@@ -24232,7 +24332,7 @@ function createNativeHookWriter(options) {
|
|
|
24232
24332
|
fingerprint: plugin.contentFingerprint ?? fingerprintTree(plugin.dir)
|
|
24233
24333
|
}) + `
|
|
24234
24334
|
`);
|
|
24235
|
-
const unchanged =
|
|
24335
|
+
const unchanged = existsSync26(target) && fingerprintTree(target) === fingerprintTree(compiled) && registrationEnabled(registration);
|
|
24236
24336
|
if (opts?.dryRun) {
|
|
24237
24337
|
console.log("[" + store.id + "] would register native hooks: " + target);
|
|
24238
24338
|
return unchanged ? "unchanged" : undefined;
|
|
@@ -24249,7 +24349,7 @@ function createNativeHookWriter(options) {
|
|
|
24249
24349
|
const expectedFingerprint = fingerprintTree(stage);
|
|
24250
24350
|
let activated = false, moved = false, committed = false;
|
|
24251
24351
|
try {
|
|
24252
|
-
if (
|
|
24352
|
+
if (existsSync26(target)) {
|
|
24253
24353
|
renameSync8(target, backup);
|
|
24254
24354
|
moved = true;
|
|
24255
24355
|
}
|
|
@@ -24268,7 +24368,7 @@ function createNativeHookWriter(options) {
|
|
|
24268
24368
|
renameSync8(backup, target);
|
|
24269
24369
|
throw error;
|
|
24270
24370
|
} finally {
|
|
24271
|
-
if (committed || !
|
|
24371
|
+
if (committed || !existsSync26(backup))
|
|
24272
24372
|
rmSync11(transaction, { recursive: true, force: true });
|
|
24273
24373
|
}
|
|
24274
24374
|
} finally {
|
|
@@ -24278,7 +24378,7 @@ function createNativeHookWriter(options) {
|
|
|
24278
24378
|
async remove(id, removeOptions) {
|
|
24279
24379
|
const target = hookPackagePath(store, id);
|
|
24280
24380
|
assertHookPath(store, target);
|
|
24281
|
-
if (!
|
|
24381
|
+
if (!existsSync26(target))
|
|
24282
24382
|
return options.legacyRemove(id, removeOptions);
|
|
24283
24383
|
const owner = readHookOwner(target);
|
|
24284
24384
|
if (owner === null || owner.pluginId !== id || removeOptions?.source !== undefined && owner.source !== removeOptions.source) {
|
|
@@ -24301,12 +24401,12 @@ function createNativeHookWriter(options) {
|
|
|
24301
24401
|
committed = true;
|
|
24302
24402
|
} catch (error) {
|
|
24303
24403
|
restoreRegistration(registration, before, after);
|
|
24304
|
-
if (!
|
|
24404
|
+
if (!existsSync26(target))
|
|
24305
24405
|
renameSync8(backup, target);
|
|
24306
24406
|
throw error;
|
|
24307
24407
|
}
|
|
24308
24408
|
} finally {
|
|
24309
|
-
if (committed || !
|
|
24409
|
+
if (committed || !existsSync26(backup))
|
|
24310
24410
|
rmSync11(transaction, { recursive: true, force: true });
|
|
24311
24411
|
}
|
|
24312
24412
|
},
|
|
@@ -24320,11 +24420,10 @@ function nextRegistration(registration, raw, enabled) {
|
|
|
24320
24420
|
return enabled ? registration.content : undefined;
|
|
24321
24421
|
const value = registrationDocument(registration, raw);
|
|
24322
24422
|
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)
|
|
24423
|
+
const present = previous.includes(registration.entry);
|
|
24424
|
+
if (enabled === present)
|
|
24327
24425
|
return raw;
|
|
24426
|
+
const entries = enabled ? [...previous, registration.entry] : previous.filter((entry) => entry !== registration.entry);
|
|
24328
24427
|
value[registration.field] = entries;
|
|
24329
24428
|
return JSON.stringify(value, null, 2) + `
|
|
24330
24429
|
`;
|
|
@@ -24349,7 +24448,7 @@ function writeExactFile(path, text) {
|
|
|
24349
24448
|
rmSync11(path, { force: true });
|
|
24350
24449
|
return;
|
|
24351
24450
|
}
|
|
24352
|
-
const mode =
|
|
24451
|
+
const mode = existsSync26(path) ? lstatSync20(path).mode & 511 : 420;
|
|
24353
24452
|
mkdirSync11(dirname13(path), { recursive: true });
|
|
24354
24453
|
const temporary = mkdtempSync10(join34(dirname13(path), ".plugnz-hook-write-"));
|
|
24355
24454
|
try {
|
|
@@ -24363,7 +24462,7 @@ function writeExactFile(path, text) {
|
|
|
24363
24462
|
}
|
|
24364
24463
|
|
|
24365
24464
|
// src/hosts/pi-writer.ts
|
|
24366
|
-
import { existsSync as
|
|
24465
|
+
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
24466
|
import { basename as basename4, dirname as dirname14, join as join35, resolve as resolve21 } from "node:path";
|
|
24368
24467
|
import { tmpdir as tmpdir8 } from "node:os";
|
|
24369
24468
|
var MARKER7 = ".plgnz-install.json";
|
|
@@ -24397,7 +24496,7 @@ var piWriter = {
|
|
|
24397
24496
|
const backups = [];
|
|
24398
24497
|
try {
|
|
24399
24498
|
for (const candidate of [...new Set([target, ...prior])]) {
|
|
24400
|
-
if (!
|
|
24499
|
+
if (!existsSync27(candidate)) {
|
|
24401
24500
|
backups.push({ target: candidate });
|
|
24402
24501
|
continue;
|
|
24403
24502
|
}
|
|
@@ -24454,7 +24553,7 @@ var piWriter = {
|
|
|
24454
24553
|
function stagePlugin4(source, stage, plugin, market) {
|
|
24455
24554
|
assertTree(source);
|
|
24456
24555
|
const root = join35(source, "skills");
|
|
24457
|
-
if (!
|
|
24556
|
+
if (!existsSync27(root) || !lstatSync21(root).isDirectory())
|
|
24458
24557
|
throw new Error("Pi standalone delivery requires plugin skills/ directories");
|
|
24459
24558
|
const destination = join35(stage, packageName(plugin, market));
|
|
24460
24559
|
projectPluginForPi(source, destination, plugin);
|
|
@@ -24462,7 +24561,7 @@ function stagePlugin4(source, stage, plugin, market) {
|
|
|
24462
24561
|
const walk = (dir) => {
|
|
24463
24562
|
for (const entry of readdirSync19(dir)) {
|
|
24464
24563
|
const path = join35(dir, entry);
|
|
24465
|
-
const stat =
|
|
24564
|
+
const stat = lstatSync21(path);
|
|
24466
24565
|
if (stat.isDirectory())
|
|
24467
24566
|
walk(path);
|
|
24468
24567
|
else if (entry === "SKILL.md")
|
|
@@ -24506,7 +24605,7 @@ function packageName(plugin, market) {
|
|
|
24506
24605
|
}
|
|
24507
24606
|
function owner2(dir) {
|
|
24508
24607
|
const file = join35(dir, MARKER7);
|
|
24509
|
-
if (!
|
|
24608
|
+
if (!existsSync27(file))
|
|
24510
24609
|
return null;
|
|
24511
24610
|
try {
|
|
24512
24611
|
const x = JSON.parse(readFileSync29(file, "utf8"));
|
|
@@ -24522,12 +24621,12 @@ function owner2(dir) {
|
|
|
24522
24621
|
}
|
|
24523
24622
|
function ownedFor(id, source) {
|
|
24524
24623
|
assertPiStore();
|
|
24525
|
-
if (!
|
|
24624
|
+
if (!existsSync27(skillsDir()))
|
|
24526
24625
|
return [];
|
|
24527
24626
|
const out = [];
|
|
24528
24627
|
for (const name of readdirSync19(skillsDir())) {
|
|
24529
24628
|
const path = join35(skillsDir(), name);
|
|
24530
|
-
if (!
|
|
24629
|
+
if (!lstatSync21(path).isDirectory())
|
|
24531
24630
|
continue;
|
|
24532
24631
|
const mark = owner2(path);
|
|
24533
24632
|
if (mark?.pluginId === id && (source === undefined || mark.source === source))
|
|
@@ -24537,7 +24636,7 @@ function ownedFor(id, source) {
|
|
|
24537
24636
|
}
|
|
24538
24637
|
function checkTarget(target, id, source) {
|
|
24539
24638
|
assertUnder(skillsDir(), target);
|
|
24540
|
-
if (!
|
|
24639
|
+
if (!existsSync27(target))
|
|
24541
24640
|
return;
|
|
24542
24641
|
const mark = owner2(target);
|
|
24543
24642
|
if (mark === null)
|
|
@@ -24546,7 +24645,7 @@ function checkTarget(target, id, source) {
|
|
|
24546
24645
|
throw new Error(`Pi standalone skill belongs to another source; refusing to replace it: ${target}`);
|
|
24547
24646
|
}
|
|
24548
24647
|
function sameTree6(stage, target) {
|
|
24549
|
-
if (!
|
|
24648
|
+
if (!existsSync27(target))
|
|
24550
24649
|
return false;
|
|
24551
24650
|
const bytes = readFileSync29;
|
|
24552
24651
|
const list = (root) => {
|
|
@@ -24555,7 +24654,7 @@ function sameTree6(stage, target) {
|
|
|
24555
24654
|
for (const name of readdirSync19(dir).sort()) {
|
|
24556
24655
|
if (name === MARKER7)
|
|
24557
24656
|
continue;
|
|
24558
|
-
const path = join35(dir, name), relative = prefix ? `${prefix}/${name}` : name, stat =
|
|
24657
|
+
const path = join35(dir, name), relative = prefix ? `${prefix}/${name}` : name, stat = lstatSync21(path);
|
|
24559
24658
|
if (stat.isDirectory())
|
|
24560
24659
|
walk(path, relative);
|
|
24561
24660
|
else if (stat.isFile())
|
|
@@ -24570,11 +24669,11 @@ function sameTree6(stage, target) {
|
|
|
24570
24669
|
return JSON.stringify(list(stage)) === JSON.stringify(list(target));
|
|
24571
24670
|
}
|
|
24572
24671
|
function assertTree(root) {
|
|
24573
|
-
const stat =
|
|
24672
|
+
const stat = lstatSync21(root);
|
|
24574
24673
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
24575
24674
|
throw new Error(`Pi plugin root is not a real directory: ${root}`);
|
|
24576
24675
|
for (const name of readdirSync19(root)) {
|
|
24577
|
-
const path = join35(root, name), child =
|
|
24676
|
+
const path = join35(root, name), child = lstatSync21(path);
|
|
24578
24677
|
if (child.isSymbolicLink())
|
|
24579
24678
|
throw new Error(`Pi plugin contains symlink: ${path}`);
|
|
24580
24679
|
if (child.isDirectory())
|
|
@@ -24604,18 +24703,18 @@ function assertPiStore() {
|
|
|
24604
24703
|
let current = home;
|
|
24605
24704
|
for (const part of [basename4(dirname14(root)), basename4(root)]) {
|
|
24606
24705
|
current = join35(current, part);
|
|
24607
|
-
if (
|
|
24706
|
+
if (existsSync27(current) && lstatSync21(current).isSymbolicLink())
|
|
24608
24707
|
throw new Error(`Pi managed path component is a symlink: ${current}`);
|
|
24609
24708
|
}
|
|
24610
|
-
if (
|
|
24709
|
+
if (existsSync27(root))
|
|
24611
24710
|
assertRealDirectory(root);
|
|
24612
|
-
if (
|
|
24711
|
+
if (existsSync27(skillsDir())) {
|
|
24613
24712
|
assertUnder(root, skillsDir());
|
|
24614
24713
|
assertRealDirectory(skillsDir());
|
|
24615
24714
|
}
|
|
24616
24715
|
}
|
|
24617
24716
|
function assertRealDirectory(path) {
|
|
24618
|
-
const stat =
|
|
24717
|
+
const stat = lstatSync21(path);
|
|
24619
24718
|
if (stat.isSymbolicLink())
|
|
24620
24719
|
throw new Error(`Pi managed path component is a symlink: ${path}`);
|
|
24621
24720
|
if (!stat.isDirectory())
|
|
@@ -24628,7 +24727,7 @@ function assertUnder(root, path) {
|
|
|
24628
24727
|
let current = base;
|
|
24629
24728
|
for (const part of candidate.slice(base.length).split("/").filter(Boolean)) {
|
|
24630
24729
|
current = join35(current, part);
|
|
24631
|
-
if (
|
|
24730
|
+
if (existsSync27(current) && lstatSync21(current).isSymbolicLink())
|
|
24632
24731
|
throw new Error(`Pi managed path component is a symlink: ${current}`);
|
|
24633
24732
|
}
|
|
24634
24733
|
}
|
|
@@ -24644,7 +24743,7 @@ var piHookWriter = createNativeHookWriter({
|
|
|
24644
24743
|
});
|
|
24645
24744
|
|
|
24646
24745
|
// src/hosts/dcode-writer.ts
|
|
24647
|
-
import { cpSync as cpSync11, existsSync as
|
|
24746
|
+
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
24747
|
import { basename as basename5, dirname as dirname15, join as join36, resolve as resolve22 } from "node:path";
|
|
24649
24748
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
24650
24749
|
import { spawn as spawnChild } from "node:child_process";
|
|
@@ -24673,7 +24772,7 @@ function nativePython() {
|
|
|
24673
24772
|
throw new Error("dcode native lock runtime is unavailable");
|
|
24674
24773
|
const shebang = readFileSync30(binary, "utf8").split(/\r?\n/, 1)[0] ?? "";
|
|
24675
24774
|
const match = /^#!(\/[^\s]+python(?:\d+(?:\.\d+)?)?)$/u.exec(shebang);
|
|
24676
|
-
if (match?.[1] === undefined || !
|
|
24775
|
+
if (match?.[1] === undefined || !existsSync28(match[1]))
|
|
24677
24776
|
throw new Error("dcode native Python interpreter is unverified; set OPEN_PLUGIN_DCODE_PYTHON_BIN to its verified interpreter");
|
|
24678
24777
|
return match[1];
|
|
24679
24778
|
}
|
|
@@ -24774,7 +24873,7 @@ function observeDcodeTarget(target) {
|
|
|
24774
24873
|
throw new Error(`dcode install record ${nativeId} has duplicate rows`);
|
|
24775
24874
|
const path = rowInstall(rows[0], nativeId);
|
|
24776
24875
|
assertCachePath(path);
|
|
24777
|
-
const present =
|
|
24876
|
+
const present = existsSync28(path);
|
|
24778
24877
|
const marker = present ? ownership3(path) : null;
|
|
24779
24878
|
const body = present ? readDoc2(join36(path, MARKER8), {}, "ownership marker") : {};
|
|
24780
24879
|
const owned = marker?.pluginId === nativeId;
|
|
@@ -24795,7 +24894,7 @@ function observeDcodeTarget(target) {
|
|
|
24795
24894
|
});
|
|
24796
24895
|
}
|
|
24797
24896
|
function dcodeLifecycleReadback(binding) {
|
|
24798
|
-
if (
|
|
24897
|
+
if (existsSync28(join36(dcodeStateDir(), READBACK_FAULT)))
|
|
24799
24898
|
throw new Error(`dcode readback failed for ${binding.nativeId}`);
|
|
24800
24899
|
const installations = observeDcodeTarget(binding.target);
|
|
24801
24900
|
const row = installations.find((item) => item.nativeId === binding.nativeId);
|
|
@@ -24816,7 +24915,7 @@ function dcodeLifecycleReadback(binding) {
|
|
|
24816
24915
|
transition: { requirement: present ? "restart" : "none", status: "effective" },
|
|
24817
24916
|
installedFingerprint: present ? row.installedFingerprint : null,
|
|
24818
24917
|
contentRoots: present ? row.contentRoots : [],
|
|
24819
|
-
retention: { pluginData:
|
|
24918
|
+
retention: { pluginData: existsSync28(dataRoot) ? { state: "present", fingerprint: fingerprintTree(dataRoot) } : { state: "absent", fingerprint: null }, inactiveMetadata: { state: "absent", fingerprint: null } }
|
|
24820
24919
|
};
|
|
24821
24920
|
}
|
|
24822
24921
|
function captureDcodeRollback(binding, attemptId, operationId) {
|
|
@@ -24825,13 +24924,13 @@ function captureDcodeRollback(binding, attemptId, operationId) {
|
|
|
24825
24924
|
const registry = readRegistry3(dcodeRegistryFile());
|
|
24826
24925
|
const enabled = boolObject(readEnablement(dcodeEnablementFile()).enabledPlugins, "enabledPlugins");
|
|
24827
24926
|
const row = object9(registry.plugins, "registry plugins")[binding.nativeId];
|
|
24828
|
-
const state = { row: row ?? null, enabled: enabled[binding.nativeId] ?? null, registryExisted:
|
|
24927
|
+
const state = { row: row ?? null, enabled: enabled[binding.nativeId] ?? null, registryExisted: existsSync28(dcodeRegistryFile()), enablementExisted: existsSync28(dcodeEnablementFile()) };
|
|
24829
24928
|
writeFileSync13(join36(dir, "state.json"), JSON.stringify(state));
|
|
24830
24929
|
for (const [index, item] of rowsFor(row).entries()) {
|
|
24831
24930
|
const path = rowInstall(item, binding.nativeId);
|
|
24832
24931
|
assertCachePath(path);
|
|
24833
24932
|
assertNoSymlinks6(path);
|
|
24834
|
-
if (
|
|
24933
|
+
if (existsSync28(path))
|
|
24835
24934
|
cpSync11(path, join36(dir, `content-${index}`), { recursive: true });
|
|
24836
24935
|
}
|
|
24837
24936
|
return dir;
|
|
@@ -24917,7 +25016,7 @@ var dcodeDefinition = {
|
|
|
24917
25016
|
stageActivation: async (request) => {
|
|
24918
25017
|
const dir = lifecycleDirectory(request.snapshot.attemptId, request.snapshot.operationId);
|
|
24919
25018
|
const stagingRoot = join36(dir, "stage");
|
|
24920
|
-
if (
|
|
25019
|
+
if (existsSync28(stagingRoot))
|
|
24921
25020
|
throw new Error("dcode preparation stage already exists");
|
|
24922
25021
|
mkdirSync13(stagingRoot, { recursive: true });
|
|
24923
25022
|
const manifest = declaredManifest(request.snapshot.packageRoot, request.snapshot.packageName);
|
|
@@ -24939,7 +25038,7 @@ var dcodeDefinition = {
|
|
|
24939
25038
|
const found = new Set;
|
|
24940
25039
|
for (const candidate of dcodeMcpCandidates()) {
|
|
24941
25040
|
const file = join36(projection.stagingRoot, candidate.kind === "spec" ? candidate.file : candidate.manifest);
|
|
24942
|
-
if (!
|
|
25041
|
+
if (!existsSync28(file))
|
|
24943
25042
|
continue;
|
|
24944
25043
|
const body = readDoc2(file, {}, "MCP document");
|
|
24945
25044
|
if (typeof body.mcpServers !== "object" || body.mcpServers === null || Array.isArray(body.mcpServers))
|
|
@@ -24979,7 +25078,7 @@ var dcodeDefinition = {
|
|
|
24979
25078
|
if (manifest.version !== projection.packageVersion)
|
|
24980
25079
|
throw new Error("dcode legacy version differs; refusing adoption");
|
|
24981
25080
|
}
|
|
24982
|
-
if (
|
|
25081
|
+
if (existsSync28(target) && ownership3(target)?.pluginId !== projection.nativeId)
|
|
24983
25082
|
throw new Error("dcode lifecycle target is not owned");
|
|
24984
25083
|
const rollbackReference = captureDcodeRollback(projection, projection.attemptId, projection.operationId);
|
|
24985
25084
|
writeFileSync13(join36(rollbackReference, "next-path.json"), JSON.stringify({ target }));
|
|
@@ -24998,7 +25097,7 @@ var dcodeDefinition = {
|
|
|
24998
25097
|
const target = lifecycleSlot(prepared.handle.nativeId, prepared.handle.projectedFingerprint);
|
|
24999
25098
|
assertCachePath(target);
|
|
25000
25099
|
mkdirSync13(dirname15(target), { recursive: true });
|
|
25001
|
-
if (
|
|
25100
|
+
if (existsSync28(target)) {
|
|
25002
25101
|
const marker = ownership3(target);
|
|
25003
25102
|
if (marker?.pluginId !== prepared.handle.nativeId)
|
|
25004
25103
|
throw new Error("dcode lifecycle activation would overwrite foreign content");
|
|
@@ -25038,22 +25137,22 @@ var dcodeDefinition = {
|
|
|
25038
25137
|
},
|
|
25039
25138
|
rollback: async (handle) => {
|
|
25040
25139
|
await acquireNativeLock(handle.attemptId, handle.operationId);
|
|
25041
|
-
if (!
|
|
25140
|
+
if (!existsSync28(join36(handle.rollbackReference, "state.json")))
|
|
25042
25141
|
throw new Error("dcode rollback snapshot is missing; recovery refused");
|
|
25043
25142
|
const state = readDoc2(join36(handle.rollbackReference, "state.json"), {}, "rollback state");
|
|
25044
25143
|
if (recoveringNativeLocks.has(`${handle.attemptId}:${handle.operationId}`))
|
|
25045
25144
|
assertRecoveryRollbackMetadata(handle, state);
|
|
25046
25145
|
for (const [index, root] of handle.prior.contentRoots.entries()) {
|
|
25047
25146
|
const backup = join36(handle.rollbackReference, `content-${index}`);
|
|
25048
|
-
if (!
|
|
25147
|
+
if (!existsSync28(backup) || fingerprintTree(backup) !== root.fingerprint)
|
|
25049
25148
|
throw new Error("dcode rollback snapshot bytes do not match the sealed prior");
|
|
25050
|
-
if (recoveringNativeLocks.has(`${handle.attemptId}:${handle.operationId}`) &&
|
|
25149
|
+
if (recoveringNativeLocks.has(`${handle.attemptId}:${handle.operationId}`) && existsSync28(root.path) && fingerprintTree(root.path) !== root.fingerprint)
|
|
25051
25150
|
throw new Error("dcode prior root changed outside the sealed operation; refusing stale overwrite");
|
|
25052
25151
|
}
|
|
25053
25152
|
const target = handle.projectedFingerprint === null ? undefined : lifecycleSlot(handle.nativeId, handle.projectedFingerprint);
|
|
25054
25153
|
if (target !== undefined)
|
|
25055
25154
|
assertCachePath(target);
|
|
25056
|
-
if (target !== undefined &&
|
|
25155
|
+
if (target !== undefined && existsSync28(target) && !handle.prior.contentRoots.some((root) => resolve22(root.path) === resolve22(target))) {
|
|
25057
25156
|
if (ownership3(target)?.pluginId !== handle.nativeId || recoveringNativeLocks.has(`${handle.attemptId}:${handle.operationId}`) && fingerprintTree(target) !== handle.projectedFingerprint)
|
|
25058
25157
|
throw new Error("dcode rollback candidate differs from the sealed operation; refusing stale overwrite");
|
|
25059
25158
|
rmSync13(target, { recursive: true });
|
|
@@ -25062,7 +25161,7 @@ var dcodeDefinition = {
|
|
|
25062
25161
|
const path = rowInstall(row, handle.nativeId);
|
|
25063
25162
|
assertCachePath(path);
|
|
25064
25163
|
const backup = join36(handle.rollbackReference, `content-${index}`);
|
|
25065
|
-
if (
|
|
25164
|
+
if (existsSync28(backup)) {
|
|
25066
25165
|
mkdirSync13(dirname15(path), { recursive: true });
|
|
25067
25166
|
cpSync11(backup, path, { recursive: true });
|
|
25068
25167
|
}
|
|
@@ -25096,14 +25195,14 @@ var dcodeDefinition = {
|
|
|
25096
25195
|
const next = readDoc2(nextFile, {}, "cleanup target");
|
|
25097
25196
|
if (disposition === "verified-commit" && recovering !== undefined) {
|
|
25098
25197
|
const retiredRoots = recovering.prior.contentRoots.filter((root) => !recovering.expected.contentRoots.some((next) => resolve22(next.path) === resolve22(root.path)));
|
|
25099
|
-
if (
|
|
25198
|
+
if (existsSync28(priorFile))
|
|
25100
25199
|
assertRecoveryRollbackMetadata(recovering, readDoc2(priorFile, {}, "rollback state"));
|
|
25101
|
-
else if (retiredRoots.some((root) =>
|
|
25200
|
+
else if (retiredRoots.some((root) => existsSync28(root.path)))
|
|
25102
25201
|
throw new Error("dcode cleanup prior metadata is missing; recovery refused");
|
|
25103
|
-
if (
|
|
25202
|
+
if (existsSync28(nextFile) && (typeof next.target !== "string" || !recovering.expected.contentRoots.some((root) => resolve22(root.path) === resolve22(next.target))))
|
|
25104
25203
|
throw new Error("dcode cleanup target differs from the sealed expected root; recovery refused");
|
|
25105
25204
|
for (const root of retiredRoots) {
|
|
25106
|
-
if (
|
|
25205
|
+
if (existsSync28(root.path) && fingerprintTree(root.path) !== root.fingerprint)
|
|
25107
25206
|
throw new Error("dcode cleanup prior root changed; refusing stale deletion");
|
|
25108
25207
|
}
|
|
25109
25208
|
for (const root of retiredRoots)
|
|
@@ -25185,7 +25284,7 @@ var dcodeWriter = {
|
|
|
25185
25284
|
const slot = ownership3(target);
|
|
25186
25285
|
if (slot !== null && (slot.source !== resolved.sourceUri || slot.pluginId !== id))
|
|
25187
25286
|
throw new Error(`dcode plugin ${id} belongs to another source; refusing to replace it`);
|
|
25188
|
-
if (
|
|
25287
|
+
if (existsSync28(target) && slot === null)
|
|
25189
25288
|
throw new Error(`dcode cache target is unowned; refusing to replace it: ${target}`);
|
|
25190
25289
|
const former = prior.kind === "none" ? undefined : prior.path;
|
|
25191
25290
|
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 +25328,13 @@ var dcodeWriter = {
|
|
|
25229
25328
|
}
|
|
25230
25329
|
} finally {
|
|
25231
25330
|
rmSync13(stage, { recursive: true, force: true });
|
|
25232
|
-
if (opts?.dryRun !== true &&
|
|
25331
|
+
if (opts?.dryRun !== true && existsSync28(managedRoot) && readdirSync20(managedRoot).every((name) => name.startsWith(".plgnz-dcode-"))) {
|
|
25233
25332
|
rmSync13(managedRoot, { recursive: true, force: true });
|
|
25234
25333
|
}
|
|
25235
25334
|
}
|
|
25236
25335
|
},
|
|
25237
25336
|
async pin(plugin, opts) {
|
|
25238
|
-
if (plugin.path === undefined || !
|
|
25337
|
+
if (plugin.path === undefined || !existsSync28(plugin.path))
|
|
25239
25338
|
return { changes: [], refusals: [] };
|
|
25240
25339
|
assertCachePath(plugin.path);
|
|
25241
25340
|
if (ownership3(plugin.path)?.pluginId !== plugin.id)
|
|
@@ -25319,7 +25418,7 @@ function assessPrior(value, id, source, adopt, name, version, sourceDir) {
|
|
|
25319
25418
|
throw new Error(`dcode plugin ${id} has a conflicting ownership marker`);
|
|
25320
25419
|
if (!adopt)
|
|
25321
25420
|
throw new Error(`dcode install record ${id} is not plgnz-owned; refusing to replace it`);
|
|
25322
|
-
if (!
|
|
25421
|
+
if (!existsSync28(install) || lstatSync22(install).isSymbolicLink() || !lstatSync22(install).isDirectory()) {
|
|
25323
25422
|
throw new Error(`dcode install record ${id} is not plgnz-owned; refusing to replace it`);
|
|
25324
25423
|
}
|
|
25325
25424
|
assertNoSymlinks6(install);
|
|
@@ -25342,7 +25441,7 @@ function assessPrior(value, id, source, adopt, name, version, sourceDir) {
|
|
|
25342
25441
|
return { kind: "adoptable", path: install };
|
|
25343
25442
|
}
|
|
25344
25443
|
function declaredManifest(dir, expectedName) {
|
|
25345
|
-
const manifest = MANIFESTS.map((relative) => join36(dir, relative)).find((file) =>
|
|
25444
|
+
const manifest = MANIFESTS.map((relative) => join36(dir, relative)).find((file) => existsSync28(file));
|
|
25346
25445
|
if (manifest === undefined)
|
|
25347
25446
|
throw new Error("dcode stage has no supported plugin manifest");
|
|
25348
25447
|
let parsed;
|
|
@@ -25367,7 +25466,7 @@ function stagePlugin5(source, stage, name, version) {
|
|
|
25367
25466
|
throw new Error(`dcode manifest identity does not match ${name}`);
|
|
25368
25467
|
}
|
|
25369
25468
|
function forceAutoUpdateOff(dir) {
|
|
25370
|
-
const manifest = MANIFESTS.map((relative) => join36(dir, relative)).find((file) =>
|
|
25469
|
+
const manifest = MANIFESTS.map((relative) => join36(dir, relative)).find((file) => existsSync28(file));
|
|
25371
25470
|
if (manifest === undefined)
|
|
25372
25471
|
throw new Error("dcode stage has no supported plugin manifest");
|
|
25373
25472
|
const parsed = object9(JSON.parse(readFileSync30(manifest, "utf8")), "manifest");
|
|
@@ -25381,7 +25480,7 @@ function forceAutoUpdateOff(dir) {
|
|
|
25381
25480
|
`);
|
|
25382
25481
|
}
|
|
25383
25482
|
function assertReadback(id, registryFile, enablementFile, target, version, projected, sourceRevision) {
|
|
25384
|
-
if (
|
|
25483
|
+
if (existsSync28(join36(dcodeStateDir(), READBACK_FAULT)))
|
|
25385
25484
|
throw new Error(`dcode readback failed for ${id}`);
|
|
25386
25485
|
const registry = readRegistry3(registryFile);
|
|
25387
25486
|
const enablement = readEnablement(enablementFile);
|
|
@@ -25407,18 +25506,18 @@ function assertReadback(id, registryFile, enablementFile, target, version, proje
|
|
|
25407
25506
|
function retireFormer(path) {
|
|
25408
25507
|
try {
|
|
25409
25508
|
assertCachePath(path);
|
|
25410
|
-
const stat =
|
|
25509
|
+
const stat = lstatSync22(path);
|
|
25411
25510
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
25412
25511
|
throw new Error("former cache is not a directory");
|
|
25413
25512
|
const backup = join36(dirname15(path), `.plgnz-dcode-retire-${basename5(path)}`);
|
|
25414
|
-
if (
|
|
25415
|
-
if (!
|
|
25513
|
+
if (existsSync28(backup)) {
|
|
25514
|
+
if (!lstatSync22(backup).isDirectory())
|
|
25416
25515
|
throw new Error("retire destination is not a directory");
|
|
25417
25516
|
rmSync13(backup, { recursive: true, force: true });
|
|
25418
25517
|
}
|
|
25419
25518
|
renameSync10(path, backup);
|
|
25420
25519
|
rmSync13(backup, { recursive: true, force: true });
|
|
25421
|
-
if (
|
|
25520
|
+
if (existsSync28(path))
|
|
25422
25521
|
throw new Error("former cache remains");
|
|
25423
25522
|
return;
|
|
25424
25523
|
} catch {
|
|
@@ -25440,7 +25539,7 @@ function listTree(root) {
|
|
|
25440
25539
|
continue;
|
|
25441
25540
|
const file = join36(dir, entry);
|
|
25442
25541
|
const relative = prefix ? `${prefix}/${entry}` : entry;
|
|
25443
|
-
const stat =
|
|
25542
|
+
const stat = lstatSync22(file);
|
|
25444
25543
|
if (stat.isSymbolicLink())
|
|
25445
25544
|
throw new Error(`dcode plugin contains symlink: ${file}`);
|
|
25446
25545
|
if (stat.isDirectory())
|
|
@@ -25455,12 +25554,12 @@ function listTree(root) {
|
|
|
25455
25554
|
return out;
|
|
25456
25555
|
}
|
|
25457
25556
|
function sameTree7(left, right) {
|
|
25458
|
-
if (!
|
|
25557
|
+
if (!existsSync28(right))
|
|
25459
25558
|
return false;
|
|
25460
25559
|
return JSON.stringify(listTree(left)) === JSON.stringify(listTree(right));
|
|
25461
25560
|
}
|
|
25462
25561
|
function readDoc2(file, fallback, label) {
|
|
25463
|
-
if (!
|
|
25562
|
+
if (!existsSync28(file))
|
|
25464
25563
|
return fallback;
|
|
25465
25564
|
try {
|
|
25466
25565
|
const value = JSON.parse(readFileSync30(file, "utf8"));
|
|
@@ -25520,7 +25619,7 @@ function ownership3(dir) {
|
|
|
25520
25619
|
assertManagedPath4(dir);
|
|
25521
25620
|
const file = join36(dir, MARKER8);
|
|
25522
25621
|
assertManagedPath4(file);
|
|
25523
|
-
if (!
|
|
25622
|
+
if (!existsSync28(file))
|
|
25524
25623
|
return null;
|
|
25525
25624
|
try {
|
|
25526
25625
|
const value = object9(JSON.parse(readFileSync30(file, "utf8")), "ownership marker");
|
|
@@ -25550,7 +25649,7 @@ function writeDoc2(file, value) {
|
|
|
25550
25649
|
}
|
|
25551
25650
|
function snapshot2(file) {
|
|
25552
25651
|
const read = readFileSync30;
|
|
25553
|
-
return
|
|
25652
|
+
return existsSync28(file) ? read(file) : undefined;
|
|
25554
25653
|
}
|
|
25555
25654
|
function restore3(file, before) {
|
|
25556
25655
|
try {
|
|
@@ -25563,7 +25662,7 @@ function restore3(file, before) {
|
|
|
25563
25662
|
} catch {}
|
|
25564
25663
|
}
|
|
25565
25664
|
function activate5(stage, target, parent) {
|
|
25566
|
-
if (!
|
|
25665
|
+
if (!existsSync28(target)) {
|
|
25567
25666
|
renameSync10(stage, target);
|
|
25568
25667
|
return { commit: () => {}, rollback: () => rmSync13(target, { recursive: true, force: true }) };
|
|
25569
25668
|
}
|
|
@@ -25589,7 +25688,7 @@ function moveAside3(path, parent = dirname15(path)) {
|
|
|
25589
25688
|
return {
|
|
25590
25689
|
commit: () => rmSync13(backupRoot, { recursive: true, force: true }),
|
|
25591
25690
|
rollback: () => {
|
|
25592
|
-
if (
|
|
25691
|
+
if (existsSync28(backup))
|
|
25593
25692
|
renameSync10(backup, path);
|
|
25594
25693
|
rmSync13(backupRoot, { recursive: true, force: true });
|
|
25595
25694
|
}
|
|
@@ -25598,7 +25697,7 @@ function moveAside3(path, parent = dirname15(path)) {
|
|
|
25598
25697
|
function assertNoSymlinks6(dir) {
|
|
25599
25698
|
for (const entry of readdirSync20(dir)) {
|
|
25600
25699
|
const file = join36(dir, entry);
|
|
25601
|
-
const stat =
|
|
25700
|
+
const stat = lstatSync22(file);
|
|
25602
25701
|
if (stat.isSymbolicLink())
|
|
25603
25702
|
throw new Error(`dcode plugin contains symlink: ${file}`);
|
|
25604
25703
|
if (stat.isDirectory())
|
|
@@ -25615,19 +25714,19 @@ function assertCachePath(path) {
|
|
|
25615
25714
|
if (target === root || !target.startsWith(`${root}/`))
|
|
25616
25715
|
throw new Error(`dcode path escapes managed cache: ${path}`);
|
|
25617
25716
|
let current = root;
|
|
25618
|
-
if (
|
|
25717
|
+
if (existsSync28(current) && lstatSync22(current).isSymbolicLink())
|
|
25619
25718
|
throw new Error(`dcode native path contains symlink: ${current}`);
|
|
25620
25719
|
const relative = target.slice(root.length).replace(/^\//, "");
|
|
25621
25720
|
for (const part of relative.length === 0 ? [] : relative.split("/")) {
|
|
25622
25721
|
if (part === "" || part === "." || part === "..")
|
|
25623
25722
|
throw new Error(`dcode path escapes managed cache: ${path}`);
|
|
25624
25723
|
current = join36(current, part);
|
|
25625
|
-
if (!
|
|
25724
|
+
if (!existsSync28(current))
|
|
25626
25725
|
return;
|
|
25627
|
-
if (
|
|
25726
|
+
if (lstatSync22(current).isSymbolicLink())
|
|
25628
25727
|
throw new Error(`dcode native path contains symlink: ${current}`);
|
|
25629
25728
|
}
|
|
25630
|
-
if (!
|
|
25729
|
+
if (!existsSync28(target) || !existsSync28(root))
|
|
25631
25730
|
return;
|
|
25632
25731
|
const realRoot = realpathSync5(root);
|
|
25633
25732
|
const realTarget = realpathSync5(target);
|
|
@@ -25640,18 +25739,18 @@ function assertManagedPath4(path) {
|
|
|
25640
25739
|
if (target !== root && !target.startsWith(`${root}/`))
|
|
25641
25740
|
throw new Error(`dcode path escapes native root: ${path}`);
|
|
25642
25741
|
let current = root;
|
|
25643
|
-
if (
|
|
25742
|
+
if (existsSync28(current) && lstatSync22(current).isSymbolicLink())
|
|
25644
25743
|
throw new Error(`dcode native path contains symlink: ${current}`);
|
|
25645
25744
|
const relative = target.slice(root.length).replace(/^\//, "");
|
|
25646
25745
|
for (const part of relative ? relative.split("/") : []) {
|
|
25647
25746
|
current = join36(current, part);
|
|
25648
|
-
if (
|
|
25747
|
+
if (existsSync28(current) && lstatSync22(current).isSymbolicLink())
|
|
25649
25748
|
throw new Error(`dcode native path contains symlink: ${current}`);
|
|
25650
25749
|
}
|
|
25651
25750
|
}
|
|
25652
25751
|
|
|
25653
25752
|
// src/hosts/opencode-writer.ts
|
|
25654
|
-
import { cpSync as cpSync12, existsSync as
|
|
25753
|
+
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
25754
|
import { dirname as dirname16, join as join37 } from "node:path";
|
|
25656
25755
|
import { tmpdir as tmpdir10 } from "node:os";
|
|
25657
25756
|
var MARKER9 = ".plgnz-install.json";
|
|
@@ -25683,7 +25782,7 @@ var opencodeWriter = {
|
|
|
25683
25782
|
try {
|
|
25684
25783
|
for (const key of keys2()) {
|
|
25685
25784
|
const target = targets[key];
|
|
25686
|
-
if (!
|
|
25785
|
+
if (!existsSync29(target)) {
|
|
25687
25786
|
moves.push({ target });
|
|
25688
25787
|
continue;
|
|
25689
25788
|
}
|
|
@@ -25722,7 +25821,7 @@ var opencodeWriter = {
|
|
|
25722
25821
|
const targets = targetsFor(name, plugin);
|
|
25723
25822
|
assertStore();
|
|
25724
25823
|
for (const key of keys2())
|
|
25725
|
-
if (
|
|
25824
|
+
if (existsSync29(targets[key])) {
|
|
25726
25825
|
assertManagedTree(targets[key]);
|
|
25727
25826
|
if (!owned(targets[key], id))
|
|
25728
25827
|
throw new Error(`OpenCode target is not owned by ${id}: ${targets[key]}`);
|
|
@@ -25731,7 +25830,7 @@ var opencodeWriter = {
|
|
|
25731
25830
|
try {
|
|
25732
25831
|
for (const key of keys2()) {
|
|
25733
25832
|
const target = targets[key];
|
|
25734
|
-
if (!
|
|
25833
|
+
if (!existsSync29(target))
|
|
25735
25834
|
continue;
|
|
25736
25835
|
const root = mkdtempSync13(join37(dirname16(target), ".plgnz-opencode-remove-"));
|
|
25737
25836
|
const backup = join37(root, "previous");
|
|
@@ -25777,13 +25876,13 @@ function stagePackage(source, stage, name, activePrivateRoot, ownerValue) {
|
|
|
25777
25876
|
return { private: privateRoot, skills, commands };
|
|
25778
25877
|
}
|
|
25779
25878
|
function sourceCommands(source) {
|
|
25780
|
-
const root =
|
|
25781
|
-
if (!
|
|
25879
|
+
const root = existsSync29(join37(source, ".claude", "commands")) ? join37(source, ".claude", "commands") : join37(source, "commands");
|
|
25880
|
+
if (!existsSync29(root))
|
|
25782
25881
|
return [];
|
|
25783
25882
|
const out = [];
|
|
25784
25883
|
const walk = (dir) => {
|
|
25785
25884
|
for (const entry of readdirSync21(dir).sort()) {
|
|
25786
|
-
const path = join37(dir, entry), stat =
|
|
25885
|
+
const path = join37(dir, entry), stat = lstatSync23(path);
|
|
25787
25886
|
if (stat.isDirectory()) {
|
|
25788
25887
|
walk(path);
|
|
25789
25888
|
continue;
|
|
@@ -25804,12 +25903,12 @@ function sourceCommands(source) {
|
|
|
25804
25903
|
}
|
|
25805
25904
|
function manualSkills(source) {
|
|
25806
25905
|
const root = join37(source, "skills");
|
|
25807
|
-
if (!
|
|
25906
|
+
if (!existsSync29(root))
|
|
25808
25907
|
return [];
|
|
25809
25908
|
const out = [];
|
|
25810
25909
|
const walk = (dir) => {
|
|
25811
25910
|
for (const entry of readdirSync21(dir).sort()) {
|
|
25812
|
-
const path = join37(dir, entry), stat =
|
|
25911
|
+
const path = join37(dir, entry), stat = lstatSync23(path);
|
|
25813
25912
|
if (stat.isDirectory())
|
|
25814
25913
|
walk(path);
|
|
25815
25914
|
else if (stat.isFile() && entry === "SKILL.md") {
|
|
@@ -25915,7 +26014,7 @@ function targetsFor(name, commandNamespace) {
|
|
|
25915
26014
|
}
|
|
25916
26015
|
function owner3(path) {
|
|
25917
26016
|
const file = join37(path, MARKER9);
|
|
25918
|
-
if (!
|
|
26017
|
+
if (!existsSync29(file))
|
|
25919
26018
|
return null;
|
|
25920
26019
|
try {
|
|
25921
26020
|
const value = JSON.parse(readFileSync31(file, "utf8"));
|
|
@@ -25935,7 +26034,7 @@ function owned(privateTarget, id, source) {
|
|
|
25935
26034
|
}
|
|
25936
26035
|
function checkTargets(targets, id, source) {
|
|
25937
26036
|
for (const key of keys2())
|
|
25938
|
-
if (
|
|
26037
|
+
if (existsSync29(targets[key])) {
|
|
25939
26038
|
assertManagedTree(targets[key]);
|
|
25940
26039
|
if (!owned(targets[key], id, source))
|
|
25941
26040
|
throw new Error(`OpenCode target is unowned or belongs to another source: ${targets[key]}`);
|
|
@@ -25945,7 +26044,7 @@ function allSame(staged, targets) {
|
|
|
25945
26044
|
return keys2().every((key) => sameTree8(staged[key], targets[key]));
|
|
25946
26045
|
}
|
|
25947
26046
|
function sameTree8(a, b) {
|
|
25948
|
-
if (!
|
|
26047
|
+
if (!existsSync29(a) || !existsSync29(b))
|
|
25949
26048
|
return false;
|
|
25950
26049
|
const bytes = readFileSync31;
|
|
25951
26050
|
const list = (root) => {
|
|
@@ -25954,7 +26053,7 @@ function sameTree8(a, b) {
|
|
|
25954
26053
|
for (const name of readdirSync21(dir).sort()) {
|
|
25955
26054
|
if (name === MARKER9)
|
|
25956
26055
|
continue;
|
|
25957
|
-
const path = join37(dir, name), rel = prefix ? `${prefix}/${name}` : name, stat =
|
|
26056
|
+
const path = join37(dir, name), rel = prefix ? `${prefix}/${name}` : name, stat = lstatSync23(path);
|
|
25958
26057
|
if (stat.isDirectory())
|
|
25959
26058
|
walk(path, rel);
|
|
25960
26059
|
else if (stat.isFile())
|
|
@@ -25969,11 +26068,11 @@ function sameTree8(a, b) {
|
|
|
25969
26068
|
return JSON.stringify(list(a)) === JSON.stringify(list(b));
|
|
25970
26069
|
}
|
|
25971
26070
|
function assertTree2(root) {
|
|
25972
|
-
const stat =
|
|
26071
|
+
const stat = lstatSync23(root);
|
|
25973
26072
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
25974
26073
|
throw new Error(`OpenCode plugin root is not a real directory: ${root}`);
|
|
25975
26074
|
for (const name of readdirSync21(root)) {
|
|
25976
|
-
const path = join37(root, name), child =
|
|
26075
|
+
const path = join37(root, name), child = lstatSync23(path);
|
|
25977
26076
|
if (name === MARKER9)
|
|
25978
26077
|
throw new Error(`OpenCode plugin reserves ${MARKER9}: ${path}`);
|
|
25979
26078
|
if (child.isSymbolicLink())
|
|
@@ -25985,11 +26084,11 @@ function assertTree2(root) {
|
|
|
25985
26084
|
}
|
|
25986
26085
|
}
|
|
25987
26086
|
function assertManagedTree(root) {
|
|
25988
|
-
const stat =
|
|
26087
|
+
const stat = lstatSync23(root);
|
|
25989
26088
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
25990
26089
|
throw new Error(`OpenCode managed tree is unsafe: ${root}`);
|
|
25991
26090
|
for (const name of readdirSync21(root)) {
|
|
25992
|
-
const path = join37(root, name), child =
|
|
26091
|
+
const path = join37(root, name), child = lstatSync23(path);
|
|
25993
26092
|
if (child.isSymbolicLink())
|
|
25994
26093
|
throw new Error(`OpenCode managed tree contains symlink: ${path}`);
|
|
25995
26094
|
if (child.isDirectory())
|
|
@@ -26000,11 +26099,11 @@ function assertManagedTree(root) {
|
|
|
26000
26099
|
}
|
|
26001
26100
|
function assertSupportedRoot(source) {
|
|
26002
26101
|
for (const entry of ["agents", "hooks", ".claude/agents", ".claude/hooks", "mcp.json", ".mcp.json"])
|
|
26003
|
-
if (
|
|
26102
|
+
if (existsSync29(join37(source, entry)))
|
|
26004
26103
|
throw new Error(`OpenCode cannot preserve root ${entry} semantics: ${join37(source, entry)}`);
|
|
26005
26104
|
for (const file of ["plugin.json", ".plugin/plugin.json", ".claude-plugin/plugin.json"]) {
|
|
26006
26105
|
const path = join37(source, file);
|
|
26007
|
-
if (!
|
|
26106
|
+
if (!existsSync29(path))
|
|
26008
26107
|
continue;
|
|
26009
26108
|
let manifest;
|
|
26010
26109
|
try {
|
|
@@ -26021,7 +26120,7 @@ function assertSupportedRoot(source) {
|
|
|
26021
26120
|
}
|
|
26022
26121
|
function assertStore() {
|
|
26023
26122
|
for (const path of [opencodeRoot(), join37(opencodeRoot(), ".plgnz"), opencodePackagesDir(), opencodeSkillsDir(), opencodeCommandsDir()])
|
|
26024
|
-
if (
|
|
26123
|
+
if (existsSync29(path) && (!lstatSync23(path).isDirectory() || lstatSync23(path).isSymbolicLink()))
|
|
26025
26124
|
throw new Error(`OpenCode managed path is unsafe: ${path}`);
|
|
26026
26125
|
}
|
|
26027
26126
|
function ensureStore2() {
|
|
@@ -26043,7 +26142,7 @@ var opencodeHookWriter = createNativeHookWriter({
|
|
|
26043
26142
|
|
|
26044
26143
|
// src/hosts/grok-writer.ts
|
|
26045
26144
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
26046
|
-
import { cpSync as cpSync13, existsSync as
|
|
26145
|
+
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
26146
|
import { dirname as dirname17, join as join38, resolve as resolve24 } from "node:path";
|
|
26048
26147
|
import { tmpdir as tmpdir11 } from "node:os";
|
|
26049
26148
|
var stableId = (plugin) => plugin.marketplace === undefined ? plugin.name : `${plugin.name}@${plugin.marketplace}`;
|
|
@@ -26082,7 +26181,7 @@ var grokWriter = {
|
|
|
26082
26181
|
const activation = join38(grokRoot(), "plugins", plugin.name);
|
|
26083
26182
|
const existingNative = grok.listInstalled().find((candidate) => candidate.name === plugin.name)?.path;
|
|
26084
26183
|
assertActivationLink(activation, existingNative);
|
|
26085
|
-
const unchanged = lstatExists2(activation) && prior !== undefined && priorMarker?.fingerprint === plugin.contentFingerprint && priorMarker?.nativeFingerprint === nativeFingerprint &&
|
|
26184
|
+
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
26185
|
if (opts?.dryRun)
|
|
26087
26186
|
return unchanged ? "unchanged" : undefined;
|
|
26088
26187
|
if (unchanged)
|
|
@@ -26228,7 +26327,7 @@ function basename6(path) {
|
|
|
26228
26327
|
function assertActivationLink(link, nativePath) {
|
|
26229
26328
|
if (!lstatExists2(link))
|
|
26230
26329
|
return;
|
|
26231
|
-
if (nativePath === undefined || !
|
|
26330
|
+
if (nativePath === undefined || !lstatSync24(link).isSymbolicLink() || canonical(nativePath) === undefined || canonical(link) !== canonical(nativePath)) {
|
|
26232
26331
|
throw new Error(`Grok activation path is not the registered native plugin: ${link}`);
|
|
26233
26332
|
}
|
|
26234
26333
|
}
|
|
@@ -26294,7 +26393,7 @@ function validateGrokSource(dir) {
|
|
|
26294
26393
|
}
|
|
26295
26394
|
function projectGrokSource(dir) {
|
|
26296
26395
|
const manifest = join38(dir, "plugin.json");
|
|
26297
|
-
if (
|
|
26396
|
+
if (existsSync30(manifest)) {
|
|
26298
26397
|
const doc = JSON.parse(readFileSync32(manifest, "utf8"));
|
|
26299
26398
|
if (doc["permissions"] !== undefined)
|
|
26300
26399
|
throw new Error(`Grok permission semantics are unverified: ${manifest}`);
|
|
@@ -26302,13 +26401,13 @@ function projectGrokSource(dir) {
|
|
|
26302
26401
|
throw new Error(`Grok custom command path is unverified: ${manifest}`);
|
|
26303
26402
|
}
|
|
26304
26403
|
const skills = join38(dir, "skills");
|
|
26305
|
-
if (
|
|
26404
|
+
if (existsSync30(skills))
|
|
26306
26405
|
for (const name of readdirSync22(skills)) {
|
|
26307
26406
|
const skill = join38(skills, name);
|
|
26308
|
-
if (!
|
|
26407
|
+
if (!lstatSync24(skill).isDirectory())
|
|
26309
26408
|
continue;
|
|
26310
26409
|
const file = join38(skill, "SKILL.md");
|
|
26311
|
-
if (!
|
|
26410
|
+
if (!existsSync30(file))
|
|
26312
26411
|
continue;
|
|
26313
26412
|
const raw = readFileSync32(file, "utf8");
|
|
26314
26413
|
const fm = openingFrontmatter3(raw, file);
|
|
@@ -26318,7 +26417,7 @@ function projectGrokSource(dir) {
|
|
|
26318
26417
|
normalizeBooleanPolicy(fm, "user-invocable", "user_invocable", file);
|
|
26319
26418
|
const sidecar = join38(skill, "agents", "openai.yaml");
|
|
26320
26419
|
let sidecarManual;
|
|
26321
|
-
if (
|
|
26420
|
+
if (existsSync30(sidecar)) {
|
|
26322
26421
|
const parsed = yamlParse(readFileSync32(sidecar, "utf8"));
|
|
26323
26422
|
const policy = parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed["policy"] : undefined;
|
|
26324
26423
|
if (policy !== undefined) {
|
|
@@ -26340,19 +26439,19 @@ function projectGrokSource(dir) {
|
|
|
26340
26439
|
const commands = join38(dir, "commands");
|
|
26341
26440
|
const claudeCommands = join38(dir, ".claude", "commands");
|
|
26342
26441
|
const seen = new Set;
|
|
26343
|
-
for (const source of [
|
|
26344
|
-
if (!
|
|
26442
|
+
for (const source of [existsSync30(commands) ? commands : claudeCommands]) {
|
|
26443
|
+
if (!existsSync30(source))
|
|
26345
26444
|
continue;
|
|
26346
26445
|
for (const entry of readdirSync22(source)) {
|
|
26347
26446
|
const path = join38(source, entry);
|
|
26348
|
-
const stat =
|
|
26447
|
+
const stat = lstatSync24(path);
|
|
26349
26448
|
if (!stat.isFile() || !/\.(md|toml)$/u.test(entry))
|
|
26350
26449
|
continue;
|
|
26351
26450
|
const name = entry.replace(/\.(md|toml)$/u, "");
|
|
26352
26451
|
if (seen.has(name))
|
|
26353
26452
|
throw new Error(`duplicate Grok command ${name}`);
|
|
26354
26453
|
seen.add(name);
|
|
26355
|
-
if (
|
|
26454
|
+
if (existsSync30(join38(skills, name, "SKILL.md")))
|
|
26356
26455
|
throw new Error(`Grok command ${name} collides with a native skill`);
|
|
26357
26456
|
const output = join38(commands, `${name}.md`);
|
|
26358
26457
|
if (entry.endsWith(".md")) {
|
|
@@ -26403,11 +26502,11 @@ ${doc.prompt}`);
|
|
|
26403
26502
|
}
|
|
26404
26503
|
const legacyMcp = join38(dir, "mcp.json");
|
|
26405
26504
|
const nativeMcp = join38(dir, ".mcp.json");
|
|
26406
|
-
if (
|
|
26505
|
+
if (existsSync30(legacyMcp) && existsSync30(nativeMcp) && canonicalJson2(JSON.parse(readFileSync32(legacyMcp, "utf8")).mcpServers) !== canonicalJson2(JSON.parse(readFileSync32(nativeMcp, "utf8")).mcpServers))
|
|
26407
26506
|
throw new Error(`conflicting Grok MCP declarations: ${legacyMcp} and ${nativeMcp}`);
|
|
26408
|
-
if (
|
|
26507
|
+
if (existsSync30(legacyMcp) && !existsSync30(nativeMcp))
|
|
26409
26508
|
cpSync13(legacyMcp, nativeMcp);
|
|
26410
|
-
if (
|
|
26509
|
+
if (existsSync30(nativeMcp)) {
|
|
26411
26510
|
const value = JSON.parse(readFileSync32(nativeMcp, "utf8"));
|
|
26412
26511
|
const servers = value?.["mcpServers"];
|
|
26413
26512
|
if (!value || typeof value !== "object" || !servers || typeof servers !== "object" || Array.isArray(servers))
|
|
@@ -26457,28 +26556,28 @@ function legacyCandidate(plugin, adopt, prior) {
|
|
|
26457
26556
|
throw new Error(`Grok ${plugin.name}: an existing native install is not plgnz-owned; refusing to replace it`);
|
|
26458
26557
|
const installed = canonical(matches[0].path);
|
|
26459
26558
|
const base = canonical(join38(grokRoot(), "installed-plugins"));
|
|
26460
|
-
if (installed === undefined || base === undefined || !installed.startsWith(`${base}/`) ||
|
|
26559
|
+
if (installed === undefined || base === undefined || !installed.startsWith(`${base}/`) || lstatSync24(matches[0].path).isSymbolicLink())
|
|
26461
26560
|
throw new Error(`Grok ${plugin.name}: legacy native path is unsafe`);
|
|
26462
26561
|
const rows = repos().filter(([, repo]) => canonical(typeof repo.path === "string" ? repo.path : "") === installed);
|
|
26463
26562
|
if (rows.length !== 1 || provenanceOf(rows[0][1]) !== null || namesOf(rows[0][1]).length !== 1 || namesOf(rows[0][1])[0] !== plugin.name)
|
|
26464
26563
|
throw new Error(`Grok ${plugin.name}: legacy native identity is ambiguous`);
|
|
26465
26564
|
const source = localSourceOf(rows[0][1]);
|
|
26466
|
-
if (source === undefined || !
|
|
26565
|
+
if (source === undefined || !existsSync30(source) || lstatSync24(source).isSymbolicLink())
|
|
26467
26566
|
throw new Error(`Grok ${plugin.name}: legacy source is missing or unsafe`);
|
|
26468
26567
|
const oldManifest = JSON.parse(readFileSync32(join38(installed, "plugin.json"), "utf8"));
|
|
26469
26568
|
const newManifest = JSON.parse(readFileSync32(join38(plugin.dir, "plugin.json"), "utf8"));
|
|
26470
26569
|
if (oldManifest.name !== plugin.name || newManifest.name !== plugin.name || oldManifest.version !== newManifest.version || fingerprintTree(source) !== fingerprintTree(installed))
|
|
26471
26570
|
throw new Error(`Grok ${plugin.name}: legacy source, version, and native bytes must match before adoption`);
|
|
26472
26571
|
const link = join38(grokRoot(), "plugins", plugin.name);
|
|
26473
|
-
if (
|
|
26474
|
-
if (!
|
|
26572
|
+
if (existsSync30(link) || lstatExists2(link)) {
|
|
26573
|
+
if (!lstatSync24(link).isSymbolicLink() || canonical(resolve24(dirname17(link), readlinkSync3(link))) !== installed)
|
|
26475
26574
|
throw new Error(`Grok ${plugin.name}: unmanaged same-name plugin link blocks adoption`);
|
|
26476
26575
|
}
|
|
26477
26576
|
return { source, fingerprint: fingerprintTree(installed), ...lstatExists2(link) ? { link } : {} };
|
|
26478
26577
|
}
|
|
26479
26578
|
function lstatExists2(path) {
|
|
26480
26579
|
try {
|
|
26481
|
-
|
|
26580
|
+
lstatSync24(path);
|
|
26482
26581
|
return true;
|
|
26483
26582
|
} catch {
|
|
26484
26583
|
return false;
|
|
@@ -26505,7 +26604,7 @@ function assertOwnedRoot(root) {
|
|
|
26505
26604
|
let current = base;
|
|
26506
26605
|
for (const part of relative) {
|
|
26507
26606
|
current = join38(current, part);
|
|
26508
|
-
const stat =
|
|
26607
|
+
const stat = lstatSync24(current);
|
|
26509
26608
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
26510
26609
|
throw new Error(`Grok marketplace root is not a safe owned directory: ${current}`);
|
|
26511
26610
|
}
|
|
@@ -26697,7 +26796,7 @@ function configPriorRecord(attemptId, operationId) {
|
|
|
26697
26796
|
}
|
|
26698
26797
|
function discardStage(attemptId, operationId) {
|
|
26699
26798
|
const record = stageRecord(attemptId, operationId);
|
|
26700
|
-
if (
|
|
26799
|
+
if (existsSync30(record)) {
|
|
26701
26800
|
const stage = readFileSync32(record, "utf8").trim();
|
|
26702
26801
|
if (stage !== "")
|
|
26703
26802
|
rmSync15(stage, { recursive: true, force: true });
|
|
@@ -26763,7 +26862,7 @@ function marketplacePathOf(repo) {
|
|
|
26763
26862
|
}
|
|
26764
26863
|
function savedRegistryRepo(directory) {
|
|
26765
26864
|
const file = join38(directory, "registry-repo.json");
|
|
26766
|
-
if (!
|
|
26865
|
+
if (!existsSync30(file))
|
|
26767
26866
|
return { key: null, repo: null };
|
|
26768
26867
|
const value = JSON.parse(readFileSync32(file, "utf8"));
|
|
26769
26868
|
const key = typeof value.key === "string" ? value.key : null;
|
|
@@ -26833,7 +26932,7 @@ function captureHostSnapshot(directory, nativeId, packageName, attemptId, operat
|
|
|
26833
26932
|
rmSync15(directory, { recursive: true, force: true });
|
|
26834
26933
|
mkdirSync15(directory, { recursive: true });
|
|
26835
26934
|
const priorConfig = configPriorRecord(attemptId, operationId);
|
|
26836
|
-
if (
|
|
26935
|
+
if (existsSync30(priorConfig))
|
|
26837
26936
|
cpSync13(priorConfig, join38(directory, "config-prior.json"));
|
|
26838
26937
|
const plugin = grok.listInstalled().find((candidate) => candidate.id === nativeId);
|
|
26839
26938
|
if (plugin?.path !== undefined) {
|
|
@@ -26851,7 +26950,7 @@ function captureHostSnapshot(directory, nativeId, packageName, attemptId, operat
|
|
|
26851
26950
|
const matched = matchingRegistryRepo(nativeId, packageName);
|
|
26852
26951
|
writeFileSync15(join38(directory, "registry-repo.json"), JSON.stringify(matched === undefined ? { key: null } : { key: matched[0], repo: matched[1] }));
|
|
26853
26952
|
const link = join38(grokRoot(), "plugins", packageName);
|
|
26854
|
-
if (lstatExists2(link) &&
|
|
26953
|
+
if (lstatExists2(link) && lstatSync24(link).isSymbolicLink())
|
|
26855
26954
|
writeFileSync15(join38(directory, "link.txt"), readlinkSync3(link));
|
|
26856
26955
|
}
|
|
26857
26956
|
function freshNativePaths(directory, marketplacePath) {
|
|
@@ -26870,17 +26969,17 @@ function freshNativePaths(directory, marketplacePath) {
|
|
|
26870
26969
|
}
|
|
26871
26970
|
function restoreActivationLink(directory, packageName) {
|
|
26872
26971
|
const link = join38(grokRoot(), "plugins", packageName);
|
|
26873
|
-
if (
|
|
26972
|
+
if (existsSync30(join38(directory, "link.txt"))) {
|
|
26874
26973
|
if (lstatExists2(link))
|
|
26875
26974
|
rmSync15(link);
|
|
26876
26975
|
symlinkSync2(readFileSync32(join38(directory, "link.txt"), "utf8"), link);
|
|
26877
26976
|
return;
|
|
26878
26977
|
}
|
|
26879
|
-
if (lstatExists2(link) &&
|
|
26978
|
+
if (lstatExists2(link) && lstatSync24(link).isSymbolicLink())
|
|
26880
26979
|
rmSync15(link);
|
|
26881
26980
|
}
|
|
26882
26981
|
function restoreConfigFile(record) {
|
|
26883
|
-
if (!
|
|
26982
|
+
if (!existsSync30(record))
|
|
26884
26983
|
return;
|
|
26885
26984
|
const value = JSON.parse(readFileSync32(record, "utf8"));
|
|
26886
26985
|
const file = configFile3();
|
|
@@ -26898,8 +26997,8 @@ function restoreHostSnapshot(directory, scopeId, nativeId, packageName) {
|
|
|
26898
26997
|
const finalPath = lifecycleMarketplace(scopeId, nativeId);
|
|
26899
26998
|
const backupPath = join38(directory, "backup-path.txt");
|
|
26900
26999
|
const nativePathFile = join38(directory, "native-path.txt");
|
|
26901
|
-
const hadNative =
|
|
26902
|
-
const hadMarketplace =
|
|
27000
|
+
const hadNative = existsSync30(nativePathFile);
|
|
27001
|
+
const hadMarketplace = existsSync30(join38(directory, "marketplace"));
|
|
26903
27002
|
if (!hadNative)
|
|
26904
27003
|
for (const native of freshNativePaths(directory, finalPath))
|
|
26905
27004
|
rmSync15(native, { recursive: true, force: true });
|
|
@@ -26919,7 +27018,7 @@ function restoreHostSnapshot(directory, scopeId, nativeId, packageName) {
|
|
|
26919
27018
|
restoreRegistryKey(directory, finalPath, packageName);
|
|
26920
27019
|
restoreActivationLink(directory, packageName);
|
|
26921
27020
|
restoreRecordedConfig(directory);
|
|
26922
|
-
if (
|
|
27021
|
+
if (existsSync30(backupPath))
|
|
26923
27022
|
rmSync15(readFileSync32(backupPath, "utf8"), { recursive: true, force: true });
|
|
26924
27023
|
if (hadNative) {
|
|
26925
27024
|
run(["plugin", "update", packageName]);
|
|
@@ -26946,7 +27045,7 @@ ${tail}`;
|
|
|
26946
27045
|
}
|
|
26947
27046
|
function pinPluginAutoUpdate(attemptId, operationId) {
|
|
26948
27047
|
const file = configFile3();
|
|
26949
|
-
const present =
|
|
27048
|
+
const present = existsSync30(file);
|
|
26950
27049
|
const current = present ? readFileSync32(file, "utf8") : "";
|
|
26951
27050
|
const record = configPriorRecord(attemptId, operationId);
|
|
26952
27051
|
mkdirSync15(dirname17(record), { recursive: true });
|
|
@@ -27048,7 +27147,7 @@ var grokLifecycleDefinition = {
|
|
|
27048
27147
|
refreshStagedFingerprint(prepared.stagingRoot, nativeFingerprint);
|
|
27049
27148
|
const finalPath = lifecycleMarketplace(prepared.handle.scopeId, prepared.handle.nativeId);
|
|
27050
27149
|
const stagedRoot = dirname17(dirname17(prepared.stagingRoot));
|
|
27051
|
-
const backup =
|
|
27150
|
+
const backup = existsSync30(finalPath) ? `${finalPath}.plgnz-backup-${prepared.handle.attemptId}` : undefined;
|
|
27052
27151
|
if (backup !== undefined)
|
|
27053
27152
|
renameSync12(finalPath, backup);
|
|
27054
27153
|
renameSync12(stagedRoot, finalPath);
|
|
@@ -27136,25 +27235,25 @@ function createGrokLifecycleAdapter() {
|
|
|
27136
27235
|
|
|
27137
27236
|
// src/hosts/zcode-cli-writer.ts
|
|
27138
27237
|
init_zcode_cli_hooks();
|
|
27139
|
-
import { chmodSync as chmodSync3, cpSync as cpSync14, existsSync as
|
|
27238
|
+
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
27239
|
import { basename as basename7, dirname as dirname19, join as join40, resolve as resolve26 } from "node:path";
|
|
27141
27240
|
import { tmpdir as tmpdir12 } from "node:os";
|
|
27142
27241
|
|
|
27143
27242
|
// src/hosts/zcode-cli-projection.ts
|
|
27144
|
-
import { lstatSync as
|
|
27243
|
+
import { lstatSync as lstatSync25, readFileSync as readFileSync33, readdirSync as readdirSync23 } from "node:fs";
|
|
27145
27244
|
import { dirname as dirname18, join as join39, relative as relative8, resolve as resolve25 } from "node:path";
|
|
27146
27245
|
var encode2 = (value) => new TextEncoder().encode(value);
|
|
27147
27246
|
var decode = (value) => new TextDecoder().decode(value);
|
|
27148
27247
|
function readZcodeProjectionTree(root) {
|
|
27149
27248
|
const tree = new Map;
|
|
27150
27249
|
const walk = (path, prefix) => {
|
|
27151
|
-
const stat =
|
|
27250
|
+
const stat = lstatSync25(path);
|
|
27152
27251
|
if (stat.isSymbolicLink())
|
|
27153
27252
|
throw new Error(`ZCode projection contains symlink: ${path}`);
|
|
27154
27253
|
if (!stat.isDirectory())
|
|
27155
27254
|
throw new Error(`ZCode projection root is not a directory: ${path}`);
|
|
27156
27255
|
for (const name of readdirSync23(path).sort()) {
|
|
27157
|
-
const file = join39(path, name), key = prefix === "" ? name : `${prefix}/${name}`, child =
|
|
27256
|
+
const file = join39(path, name), key = prefix === "" ? name : `${prefix}/${name}`, child = lstatSync25(file);
|
|
27158
27257
|
if (child.isSymbolicLink())
|
|
27159
27258
|
throw new Error(`ZCode projection contains symlink: ${file}`);
|
|
27160
27259
|
if (child.isDirectory()) {
|
|
@@ -27426,7 +27525,7 @@ function projectZcodePlugin(source, destination, resourceCopy, resourceLinkRoot,
|
|
|
27426
27525
|
const target = resolve26(destination);
|
|
27427
27526
|
const ownedResources = resolve26(resourceCopy);
|
|
27428
27527
|
const links = resolve26(resourceLinkRoot);
|
|
27429
|
-
if (!
|
|
27528
|
+
if (!existsSync31(input) || !statSync13(input).isDirectory())
|
|
27430
27529
|
throw new Error(`ZCode plugin source is not a directory: ${input}`);
|
|
27431
27530
|
if (target === input || ownedResources === input || target.startsWith(`${input}/`) || ownedResources.startsWith(`${input}/`))
|
|
27432
27531
|
throw new Error("ZCode projected outputs must not be inside the source");
|
|
@@ -27438,7 +27537,7 @@ function projectZcodePlugin(source, destination, resourceCopy, resourceLinkRoot,
|
|
|
27438
27537
|
}
|
|
27439
27538
|
for (const output of [target, ownedResources]) {
|
|
27440
27539
|
try {
|
|
27441
|
-
|
|
27540
|
+
lstatSync26(output);
|
|
27442
27541
|
assertNoSymlinks7(output);
|
|
27443
27542
|
} catch (error) {
|
|
27444
27543
|
if (error.code !== "ENOENT")
|
|
@@ -27487,7 +27586,7 @@ function readJson3(file) {
|
|
|
27487
27586
|
}
|
|
27488
27587
|
}
|
|
27489
27588
|
function commandNames(dir, prefix = "") {
|
|
27490
|
-
if (!
|
|
27589
|
+
if (!existsSync31(dir))
|
|
27491
27590
|
return [];
|
|
27492
27591
|
const out = [];
|
|
27493
27592
|
for (const name of readdirSync24(dir)) {
|
|
@@ -27532,7 +27631,7 @@ function nativeForLogical(logicalId) {
|
|
|
27532
27631
|
}
|
|
27533
27632
|
function sameCandidate(prior, market, resources, resourceRoot, logical, native, source, fingerprint) {
|
|
27534
27633
|
const marker = readZcodeOwnership(prior.installPath);
|
|
27535
|
-
if (marker?.logicalId !== logical || marker.nativeId !== native || marker.source !== source || marker.fingerprint !== fingerprint || marker.resourcePath !== resourceRoot || !
|
|
27634
|
+
if (marker?.logicalId !== logical || marker.nativeId !== native || marker.source !== source || marker.fingerprint !== fingerprint || marker.resourcePath !== resourceRoot || !existsSync31(resourceRoot))
|
|
27536
27635
|
return false;
|
|
27537
27636
|
try {
|
|
27538
27637
|
return fingerprintTree(join40(market, "plugins", prior.name)) === fingerprintTree(prior.installPath) && fingerprintTree(resources) === fingerprintTree(resourceRoot);
|
|
@@ -27541,21 +27640,21 @@ function sameCandidate(prior, market, resources, resourceRoot, logical, native,
|
|
|
27541
27640
|
}
|
|
27542
27641
|
}
|
|
27543
27642
|
function assertReplaceableOwnedRoots(market, resources, name, prior, logical, native, source) {
|
|
27544
|
-
if (!
|
|
27643
|
+
if (!existsSync31(market) && !existsSync31(resources))
|
|
27545
27644
|
return;
|
|
27546
27645
|
if (prior === undefined)
|
|
27547
|
-
throw new Error(`Official ZCode owned path already exists without a proven native install: ${
|
|
27646
|
+
throw new Error(`Official ZCode owned path already exists without a proven native install: ${existsSync31(market) ? market : resources}`);
|
|
27548
27647
|
const priorRoot = zcodeSafeInstallRoot(prior.installPath);
|
|
27549
27648
|
const marker = priorRoot === undefined ? null : readZcodeOwnership(priorRoot);
|
|
27550
27649
|
if (marker?.logicalId !== logical || marker.nativeId !== native || marker.source !== source)
|
|
27551
27650
|
throw new Error(`Official ZCode existing paths are not proven owned: ${native}`);
|
|
27552
|
-
if (
|
|
27651
|
+
if (existsSync31(market)) {
|
|
27553
27652
|
assertNoSymlinks7(market);
|
|
27554
27653
|
const staged = readZcodeOwnership(join40(market, "plugins", name));
|
|
27555
27654
|
if (staged?.logicalId !== logical || staged.nativeId !== native || staged.source !== source)
|
|
27556
27655
|
throw new Error(`Official ZCode marketplace root is not proven owned: ${market}`);
|
|
27557
27656
|
}
|
|
27558
|
-
if (
|
|
27657
|
+
if (existsSync31(resources) && marker.resourcePath !== resources)
|
|
27559
27658
|
throw new Error(`Official ZCode resource root is not proven owned: ${resources}`);
|
|
27560
27659
|
}
|
|
27561
27660
|
function provePrior(prior, logical, native, source) {
|
|
@@ -27613,12 +27712,12 @@ function requireFingerprint(plugin) {
|
|
|
27613
27712
|
return fp.toLowerCase();
|
|
27614
27713
|
}
|
|
27615
27714
|
function moveAside4(path) {
|
|
27616
|
-
if (!
|
|
27715
|
+
if (!existsSync31(path))
|
|
27617
27716
|
return { rollback: () => {}, commit: () => {} };
|
|
27618
27717
|
const backup = `${path}.plgnz-backup-${Date.now()}`;
|
|
27619
27718
|
renameSync13(path, backup);
|
|
27620
27719
|
return { rollback: () => {
|
|
27621
|
-
if (!
|
|
27720
|
+
if (!existsSync31(path))
|
|
27622
27721
|
renameSync13(backup, path);
|
|
27623
27722
|
}, commit: () => rmSync16(backup, { recursive: true, force: true }) };
|
|
27624
27723
|
}
|
|
@@ -27628,7 +27727,7 @@ function assertName(value, label) {
|
|
|
27628
27727
|
}
|
|
27629
27728
|
function assertNoSymlinks7(root) {
|
|
27630
27729
|
const visit = (path) => {
|
|
27631
|
-
const stat =
|
|
27730
|
+
const stat = lstatSync26(path);
|
|
27632
27731
|
if (stat.isSymbolicLink())
|
|
27633
27732
|
throw new Error(`ZCode source contains symlink: ${path}`);
|
|
27634
27733
|
if (stat.isDirectory())
|
|
@@ -27745,7 +27844,7 @@ function capturedNativeRoot(reference, attemptId, operationId) {
|
|
|
27745
27844
|
const root = dirname19(dirname19(dirname19(reference)));
|
|
27746
27845
|
for (const ancestor of [join40(root, "plgnz-lifecycle"), join40(root, "plgnz-lifecycle", attemptId), reference]) {
|
|
27747
27846
|
try {
|
|
27748
|
-
if (
|
|
27847
|
+
if (lstatSync26(ancestor).isSymbolicLink())
|
|
27749
27848
|
throw new Error("ZCode captured snapshot ancestor was redirected");
|
|
27750
27849
|
} catch (error) {
|
|
27751
27850
|
if (!isObject4(error) || error["code"] !== "ENOENT")
|
|
@@ -27757,7 +27856,7 @@ function capturedNativeRoot(reference, attemptId, operationId) {
|
|
|
27757
27856
|
return root;
|
|
27758
27857
|
}
|
|
27759
27858
|
function assertStageCleanupAuthority(stage, reference) {
|
|
27760
|
-
if (
|
|
27859
|
+
if (lstatSync26(dirname19(stage)).isSymbolicLink() || lstatSync26(stage).isSymbolicLink())
|
|
27761
27860
|
throw new Error("ZCode cleanup stage is redirected");
|
|
27762
27861
|
assertNoSymlinks7(stage);
|
|
27763
27862
|
const artifact = reference.artifactId;
|
|
@@ -27796,7 +27895,7 @@ function assertStageCleanupAuthority(stage, reference) {
|
|
|
27796
27895
|
}
|
|
27797
27896
|
function readConfigObject() {
|
|
27798
27897
|
const file = join40(zcodeCliConfigRoot(), "config.json");
|
|
27799
|
-
if (!
|
|
27898
|
+
if (!existsSync31(file))
|
|
27800
27899
|
return null;
|
|
27801
27900
|
const value = JSON.parse(readFileSync34(file, "utf8"));
|
|
27802
27901
|
if (!isObject4(value))
|
|
@@ -27814,7 +27913,7 @@ function optionValue(nativeId) {
|
|
|
27814
27913
|
}
|
|
27815
27914
|
function retainedState(nativeId) {
|
|
27816
27915
|
const dataDir = zcodePluginDataDir(nativeId);
|
|
27817
|
-
const pluginData =
|
|
27916
|
+
const pluginData = existsSync31(dataDir) && statSync13(dataDir).isDirectory() ? { state: "present", fingerprint: fingerprintTree(dataDir) } : { state: "absent", fingerprint: null };
|
|
27818
27917
|
const options = optionValue(nativeId);
|
|
27819
27918
|
const inactiveMetadata = options === undefined ? { state: "absent", fingerprint: null } : { state: "present", fingerprint: sha2562(canonicalJson3(options)) };
|
|
27820
27919
|
return { pluginData, inactiveMetadata };
|
|
@@ -27906,9 +28005,9 @@ function resourceObservation2(root, digest) {
|
|
|
27906
28005
|
const expected = join40(zcodeResourceRoot(), marketplaceName2(marker.nativeId), marker.fingerprint);
|
|
27907
28006
|
if (canonicalExistingPath(resourcePath) !== canonicalExistingPath(expected))
|
|
27908
28007
|
throw new Error("ZCode resource receipt names a foreign root");
|
|
27909
|
-
if (!
|
|
28008
|
+
if (!existsSync31(resourcePath))
|
|
27910
28009
|
return { roots, conforming: false };
|
|
27911
|
-
if (
|
|
28010
|
+
if (lstatSync26(resourcePath).isSymbolicLink())
|
|
27912
28011
|
throw new Error("ZCode resource receipt root is redirected");
|
|
27913
28012
|
const resource = realpathSync6(resourcePath);
|
|
27914
28013
|
const owned = realpathSync6(zcodeResourceRoot());
|
|
@@ -27922,7 +28021,7 @@ function retirementSnapshot(attemptId, operationId, nativeId) {
|
|
|
27922
28021
|
const dir = join40(realpathSync6(zcodeCliRoot()), "plgnz-lifecycle", attemptId, operationId);
|
|
27923
28022
|
if (canonicalExistingPath(dir) !== dir)
|
|
27924
28023
|
throw new Error("ZCode rollback snapshot path is redirected");
|
|
27925
|
-
if (
|
|
28024
|
+
if (existsSync31(dir)) {
|
|
27926
28025
|
if (!statSync13(dir).isDirectory())
|
|
27927
28026
|
throw new Error(`ZCode rollback snapshot already exists and is not a directory: ${dir}`);
|
|
27928
28027
|
return dir;
|
|
@@ -27934,17 +28033,17 @@ function retirementSnapshot(attemptId, operationId, nativeId) {
|
|
|
27934
28033
|
cpSync14(root, join40(dir, "cache"), { recursive: true });
|
|
27935
28034
|
writeFileSync16(join40(dir, "install-path.txt"), root ?? "");
|
|
27936
28035
|
const registry = zcodeRegistryFile();
|
|
27937
|
-
if (
|
|
28036
|
+
if (existsSync31(registry))
|
|
27938
28037
|
cpSync14(registry, join40(dir, "installed_plugins.json"));
|
|
27939
28038
|
const config = join40(zcodeCliConfigRoot(), "config.json");
|
|
27940
|
-
if (
|
|
28039
|
+
if (existsSync31(config))
|
|
27941
28040
|
cpSync14(config, join40(dir, "config.json"));
|
|
27942
28041
|
return dir;
|
|
27943
28042
|
}
|
|
27944
28043
|
function canonicalExistingPath(path) {
|
|
27945
28044
|
const missing = [];
|
|
27946
28045
|
let current = path;
|
|
27947
|
-
while (!
|
|
28046
|
+
while (!existsSync31(current)) {
|
|
27948
28047
|
const parent = dirname19(current);
|
|
27949
28048
|
if (parent === current)
|
|
27950
28049
|
throw new Error(`ZCode path does not exist: ${path}`);
|
|
@@ -27960,7 +28059,7 @@ function isCacheInstallPath(path) {
|
|
|
27960
28059
|
}
|
|
27961
28060
|
function removeRegistryPlugin(nativeId) {
|
|
27962
28061
|
const file = zcodeRegistryFile();
|
|
27963
|
-
if (!
|
|
28062
|
+
if (!existsSync31(file))
|
|
27964
28063
|
return false;
|
|
27965
28064
|
const value = JSON.parse(readFileSync34(file, "utf8"));
|
|
27966
28065
|
if (!isObject4(value) || !Array.isArray(value["plugins"]))
|
|
@@ -27976,7 +28075,7 @@ function removeRegistryPlugin(nativeId) {
|
|
|
27976
28075
|
}
|
|
27977
28076
|
function removeEnabledFlag(nativeId) {
|
|
27978
28077
|
const file = join40(zcodeCliConfigRoot(), "config.json");
|
|
27979
|
-
if (!
|
|
28078
|
+
if (!existsSync31(file))
|
|
27980
28079
|
return;
|
|
27981
28080
|
const value = readConfigObject();
|
|
27982
28081
|
if (value === null || !isObject4(value["plugins"]) || !isObject4(value["plugins"]["enabledPlugins"]))
|
|
@@ -27988,7 +28087,7 @@ function removeEnabledFlag(nativeId) {
|
|
|
27988
28087
|
`);
|
|
27989
28088
|
}
|
|
27990
28089
|
function snapshotRegistryRow(file, nativeId) {
|
|
27991
|
-
if (!
|
|
28090
|
+
if (!existsSync31(file))
|
|
27992
28091
|
return;
|
|
27993
28092
|
const value = JSON.parse(readFileSync34(file, "utf8"));
|
|
27994
28093
|
if (!isObject4(value) || !Array.isArray(value["plugins"]))
|
|
@@ -28001,9 +28100,9 @@ function snapshotRegistryRow(file, nativeId) {
|
|
|
28001
28100
|
function restoreRegistryPlugin(nativeId, snapshotFile) {
|
|
28002
28101
|
const saved = snapshotRegistryRow(snapshotFile, nativeId);
|
|
28003
28102
|
const file = zcodeRegistryFile();
|
|
28004
|
-
if (!
|
|
28103
|
+
if (!existsSync31(file) && saved === undefined)
|
|
28005
28104
|
return;
|
|
28006
|
-
const live =
|
|
28105
|
+
const live = existsSync31(file) ? JSON.parse(readFileSync34(file, "utf8")) : { version: 1, plugins: [] };
|
|
28007
28106
|
if (!isObject4(live) || !Array.isArray(live["plugins"]))
|
|
28008
28107
|
throw new Error(`Official ZCode registry is unsupported: ${file}`);
|
|
28009
28108
|
const plugins = live["plugins"].filter((row) => !isObject4(row) || row["id"] !== nativeId);
|
|
@@ -28023,8 +28122,8 @@ function configSection(config, key) {
|
|
|
28023
28122
|
}
|
|
28024
28123
|
function restorePluginConfig(nativeId, snapshotFile) {
|
|
28025
28124
|
const file = join40(zcodeCliConfigRoot(), "config.json");
|
|
28026
|
-
const snapshot =
|
|
28027
|
-
const live =
|
|
28125
|
+
const snapshot = existsSync31(snapshotFile) ? readConfigObjectFrom(snapshotFile) : null;
|
|
28126
|
+
const live = existsSync31(file) ? readConfigObject() : {};
|
|
28028
28127
|
if (live === null)
|
|
28029
28128
|
throw new Error(`Official ZCode config is unsupported: ${file}`);
|
|
28030
28129
|
const savedPlugins = snapshot !== null && isObject4(snapshot["plugins"]) ? snapshot["plugins"] : undefined;
|
|
@@ -28067,7 +28166,7 @@ function stageLayout(stagingRoot) {
|
|
|
28067
28166
|
return { marketStage, resourcesStage: join40(dirname19(marketStage), "resources") };
|
|
28068
28167
|
}
|
|
28069
28168
|
function recordTree(dir, name, path) {
|
|
28070
|
-
const existed =
|
|
28169
|
+
const existed = existsSync31(path);
|
|
28071
28170
|
writeFileSync16(join40(dir, `${name}-path.txt`), path);
|
|
28072
28171
|
writeFileSync16(join40(dir, `${name}-existed.txt`), existed ? "1" : "0");
|
|
28073
28172
|
if (existed)
|
|
@@ -28078,7 +28177,7 @@ function knownMarketplacesFile() {
|
|
|
28078
28177
|
}
|
|
28079
28178
|
function readKnownMarketplaces() {
|
|
28080
28179
|
const file = knownMarketplacesFile();
|
|
28081
|
-
if (!
|
|
28180
|
+
if (!existsSync31(file))
|
|
28082
28181
|
return {};
|
|
28083
28182
|
const value = JSON.parse(readFileSync34(file, "utf8"));
|
|
28084
28183
|
if (!isObject4(value))
|
|
@@ -28097,7 +28196,7 @@ function writeKnownMarketplaces(markets) {
|
|
|
28097
28196
|
}
|
|
28098
28197
|
function recordMarketplaceEntry(dir, market) {
|
|
28099
28198
|
const flag = join40(dir, "marketplace-entry.txt");
|
|
28100
|
-
if (
|
|
28199
|
+
if (existsSync31(flag))
|
|
28101
28200
|
return;
|
|
28102
28201
|
const markets = readKnownMarketplaces();
|
|
28103
28202
|
const present = Object.hasOwn(markets, market);
|
|
@@ -28107,7 +28206,7 @@ function recordMarketplaceEntry(dir, market) {
|
|
|
28107
28206
|
}
|
|
28108
28207
|
function restoreMarketplaceEntry(dir, market) {
|
|
28109
28208
|
const flag = join40(dir, "marketplace-entry.txt");
|
|
28110
|
-
if (!
|
|
28209
|
+
if (!existsSync31(flag))
|
|
28111
28210
|
return;
|
|
28112
28211
|
const markets = readKnownMarketplaces();
|
|
28113
28212
|
if (readFileSync34(flag, "utf8") !== "1") {
|
|
@@ -28118,7 +28217,7 @@ function restoreMarketplaceEntry(dir, market) {
|
|
|
28118
28217
|
return;
|
|
28119
28218
|
}
|
|
28120
28219
|
const savedFile = join40(dir, "marketplace-entry.json");
|
|
28121
|
-
if (!
|
|
28220
|
+
if (!existsSync31(savedFile))
|
|
28122
28221
|
throw new Error("ZCode rollback marketplace entry is missing");
|
|
28123
28222
|
const saved = JSON.parse(readFileSync34(savedFile, "utf8"));
|
|
28124
28223
|
markets[market] = saved;
|
|
@@ -28126,9 +28225,9 @@ function restoreMarketplaceEntry(dir, market) {
|
|
|
28126
28225
|
}
|
|
28127
28226
|
function activationSnapshot(attemptId, operationId, nativeId, marketplace, resources) {
|
|
28128
28227
|
const dir = retirementSnapshot(attemptId, operationId, nativeId);
|
|
28129
|
-
if (!
|
|
28228
|
+
if (!existsSync31(join40(dir, "marketplace-path.txt")))
|
|
28130
28229
|
recordTree(dir, "marketplace", marketplace);
|
|
28131
|
-
if (!
|
|
28230
|
+
if (!existsSync31(join40(dir, "resources-path.txt")))
|
|
28132
28231
|
recordTree(dir, "resources", resources);
|
|
28133
28232
|
recordMarketplaceEntry(dir, marketplaceName2(nativeId));
|
|
28134
28233
|
return dir;
|
|
@@ -28136,7 +28235,7 @@ function activationSnapshot(attemptId, operationId, nativeId, marketplace, resou
|
|
|
28136
28235
|
function restoreRecordedTree(dir, name, ownedRoot) {
|
|
28137
28236
|
const pathFile = join40(dir, `${name}-path.txt`);
|
|
28138
28237
|
const existedFile = join40(dir, `${name}-existed.txt`);
|
|
28139
|
-
if (!
|
|
28238
|
+
if (!existsSync31(pathFile) || !existsSync31(existedFile))
|
|
28140
28239
|
return;
|
|
28141
28240
|
const path = readFileSync34(pathFile, "utf8");
|
|
28142
28241
|
const existed = readFileSync34(existedFile, "utf8") === "1";
|
|
@@ -28147,9 +28246,9 @@ function restoreRecordedTree(dir, name, ownedRoot) {
|
|
|
28147
28246
|
if (!target.startsWith(`${owned}/`))
|
|
28148
28247
|
throw new Error(`ZCode rollback ${name} path is outside its root`);
|
|
28149
28248
|
const copy = join40(dir, name);
|
|
28150
|
-
if (existed && !
|
|
28249
|
+
if (existed && !existsSync31(copy))
|
|
28151
28250
|
throw new Error(`ZCode rollback ${name} copy is missing`);
|
|
28152
|
-
if (!existed &&
|
|
28251
|
+
if (!existed && existsSync31(copy))
|
|
28153
28252
|
throw new Error(`ZCode rollback ${name} copy has no path`);
|
|
28154
28253
|
rmSync16(target, { recursive: true, force: true });
|
|
28155
28254
|
if (!existed)
|
|
@@ -28219,7 +28318,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28219
28318
|
const resourceRoot = join40(realpathSync6(zcodeCliRoot()), "plgnz-resources", market, snapshot.packageFingerprint);
|
|
28220
28319
|
const stageParent = join40(zcodeCliRoot(), ".plgnz-zcode-stage");
|
|
28221
28320
|
mkdirSync16(stageParent, { recursive: true });
|
|
28222
|
-
if (
|
|
28321
|
+
if (lstatSync26(stageParent).isSymbolicLink())
|
|
28223
28322
|
throw new Error("ZCode staging parent is redirected");
|
|
28224
28323
|
const stage = activationStage(request.selection.attemptId, request.selection.operationId);
|
|
28225
28324
|
mkdirSync16(stage);
|
|
@@ -28311,7 +28410,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28311
28410
|
const resourceRoot = marker.resourcePath;
|
|
28312
28411
|
const prior = nativeById(nativeId);
|
|
28313
28412
|
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) &&
|
|
28413
|
+
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
28414
|
if (unchanged)
|
|
28316
28415
|
return { receiptId: `apply:${prepared.handle.attemptId}:${prepared.handle.operationId}`, changed: false };
|
|
28317
28416
|
const marketBackup = moveAside4(marketRoot);
|
|
@@ -28364,11 +28463,11 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28364
28463
|
rollback: async (handle) => {
|
|
28365
28464
|
capturedNativeRoot(handle.rollbackReference, handle.attemptId, handle.operationId);
|
|
28366
28465
|
const dir = handle.rollbackReference;
|
|
28367
|
-
if (!
|
|
28466
|
+
if (!existsSync31(dir) || !statSync13(dir).isDirectory())
|
|
28368
28467
|
throw new Error("ZCode rollback snapshot is missing");
|
|
28369
|
-
const installPath =
|
|
28468
|
+
const installPath = existsSync31(join40(dir, "install-path.txt")) ? readFileSync34(join40(dir, "install-path.txt"), "utf8") : "";
|
|
28370
28469
|
const cache = join40(dir, "cache");
|
|
28371
|
-
const cachePresent =
|
|
28470
|
+
const cachePresent = existsSync31(cache);
|
|
28372
28471
|
if (installPath.length > 0 && !cachePresent)
|
|
28373
28472
|
throw new Error("ZCode rollback cache copy is missing");
|
|
28374
28473
|
if (installPath.length === 0 && cachePresent)
|
|
@@ -28406,7 +28505,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28406
28505
|
const parent = join40(realpathSync6(zcodeCliRoot()), "plgnz-lifecycle");
|
|
28407
28506
|
for (const candidate of [parent, join40(parent, reference.attemptId), join40(parent, reference.attemptId, reference.operationId)]) {
|
|
28408
28507
|
try {
|
|
28409
|
-
const stat =
|
|
28508
|
+
const stat = lstatSync26(candidate);
|
|
28410
28509
|
if (stat.isSymbolicLink() || candidate === join40(parent, reference.attemptId, reference.operationId))
|
|
28411
28510
|
throw new Error("ZCode pre-seal cleanup has no captured snapshot authority");
|
|
28412
28511
|
} catch (error) {
|
|
@@ -28416,7 +28515,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28416
28515
|
}
|
|
28417
28516
|
}
|
|
28418
28517
|
try {
|
|
28419
|
-
if (
|
|
28518
|
+
if (lstatSync26(dirname19(stage)).isSymbolicLink())
|
|
28420
28519
|
throw new Error("ZCode cleanup staging parent is redirected");
|
|
28421
28520
|
} catch (error) {
|
|
28422
28521
|
if (!isObject4(error) || error["code"] !== "ENOENT")
|
|
@@ -28424,7 +28523,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28424
28523
|
}
|
|
28425
28524
|
let stagePresent = true;
|
|
28426
28525
|
try {
|
|
28427
|
-
|
|
28526
|
+
lstatSync26(stage);
|
|
28428
28527
|
} catch (error) {
|
|
28429
28528
|
if (!isObject4(error) || error["code"] !== "ENOENT")
|
|
28430
28529
|
throw error;
|
|
@@ -28442,7 +28541,7 @@ var zcodeCliLifecycleDefinition = {
|
|
|
28442
28541
|
var zcodeCliLifecycle = createLifecycleHostAdapter(zcodeCliLifecycleDefinition);
|
|
28443
28542
|
|
|
28444
28543
|
// src/hosts/hermes-writer.ts
|
|
28445
|
-
import { chmodSync as chmodSync4, cpSync as cpSync15, existsSync as
|
|
28544
|
+
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
28545
|
import { basename as basename8, dirname as dirname20, isAbsolute as isAbsolute12, join as join41, resolve as resolve27 } from "node:path";
|
|
28447
28546
|
import { tmpdir as tmpdir13 } from "node:os";
|
|
28448
28547
|
|
|
@@ -28714,12 +28813,12 @@ var hermesWriter = {
|
|
|
28714
28813
|
assertReplaceable(target, packageStage, id, ownershipId, resolved.sourceUri, opts?.adoptExisting === true, validatePackage);
|
|
28715
28814
|
if (hasCompanion)
|
|
28716
28815
|
assertReplaceable(companion, companionStage, companionId, ownershipId, resolved.sourceUri, opts?.adoptExisting === true, validateCompanion);
|
|
28717
|
-
else if (
|
|
28816
|
+
else if (existsSync32(companion))
|
|
28718
28817
|
assertReplaceable(companion, undefined, companionId, ownershipId, resolved.sourceUri, opts?.adoptExisting === true, validateCompanion);
|
|
28719
28818
|
const primaryMarker = readOwnership5(target);
|
|
28720
28819
|
const companionMarker = readOwnership5(companion);
|
|
28721
28820
|
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) : !
|
|
28821
|
+
const unchangedCompanion = hasCompanion ? companionMarker?.pluginId === ownershipId && companionMarker.fingerprint === ownership.fingerprint && sameTree9(companionStage, companion) : !existsSync32(companion);
|
|
28723
28822
|
if (opts?.dryRun)
|
|
28724
28823
|
return unchangedPrimary && unchangedCompanion ? "unchanged" : undefined;
|
|
28725
28824
|
if (unchangedPrimary && unchangedCompanion) {
|
|
@@ -28731,7 +28830,7 @@ var hermesWriter = {
|
|
|
28731
28830
|
changes.push(replaceTarget(packageStage, target, root));
|
|
28732
28831
|
if (hasCompanion)
|
|
28733
28832
|
changes.push(replaceTarget(companionStage, companion, root));
|
|
28734
|
-
else if (
|
|
28833
|
+
else if (existsSync32(companion))
|
|
28735
28834
|
changes.push(removeTarget(companion, root));
|
|
28736
28835
|
updatePluginConfig(effectiveConfigPath(), [id, ...hasCompanion ? [companionId] : []], hasCompanion ? [] : [companionId]);
|
|
28737
28836
|
for (const change of changes)
|
|
@@ -28763,14 +28862,14 @@ var hermesWriter = {
|
|
|
28763
28862
|
return;
|
|
28764
28863
|
const changes = [];
|
|
28765
28864
|
try {
|
|
28766
|
-
if (
|
|
28865
|
+
if (existsSync32(target))
|
|
28767
28866
|
changes.push(removeTarget(target, root));
|
|
28768
28867
|
const companionMarker = readOwnership5(companion);
|
|
28769
28868
|
const disable = [nativeId];
|
|
28770
28869
|
if (companionMarker !== null && companionMarker.pluginId === marker.pluginId && companionMarker.source === marker.source && companionMarker.fingerprint === marker.fingerprint) {
|
|
28771
28870
|
changes.push(removeTarget(companion, root));
|
|
28772
28871
|
disable.push(companionId);
|
|
28773
|
-
} else if (!
|
|
28872
|
+
} else if (!existsSync32(companion))
|
|
28774
28873
|
disable.push(companionId);
|
|
28775
28874
|
updatePluginConfig(effectiveConfigPath(), [], disable);
|
|
28776
28875
|
for (const change of changes)
|
|
@@ -28783,7 +28882,7 @@ var hermesWriter = {
|
|
|
28783
28882
|
}
|
|
28784
28883
|
};
|
|
28785
28884
|
function assertReplaceable(target, stage, expected, ownershipId, source, adopt, validate) {
|
|
28786
|
-
if (!
|
|
28885
|
+
if (!existsSync32(target))
|
|
28787
28886
|
return;
|
|
28788
28887
|
const marker = readOwnership5(target);
|
|
28789
28888
|
if (marker !== null) {
|
|
@@ -28801,7 +28900,7 @@ function assertReplaceable(target, stage, expected, ownershipId, source, adopt,
|
|
|
28801
28900
|
function validatePackage(root, expected) {
|
|
28802
28901
|
assertTree3(root);
|
|
28803
28902
|
const manifest = join41(root, "plugin.json");
|
|
28804
|
-
if (!
|
|
28903
|
+
if (!existsSync32(manifest))
|
|
28805
28904
|
throw new Error("Hermes stage has no Agent Plugins manifest");
|
|
28806
28905
|
let value;
|
|
28807
28906
|
try {
|
|
@@ -28817,7 +28916,7 @@ function validatePackage(root, expected) {
|
|
|
28817
28916
|
function validateCompanion(root, expected) {
|
|
28818
28917
|
assertTree3(root);
|
|
28819
28918
|
const manifest = join41(root, "plugin.yaml");
|
|
28820
|
-
if (!
|
|
28919
|
+
if (!existsSync32(manifest) || !existsSync32(join41(root, "__init__.py")))
|
|
28821
28920
|
throw new Error(`Hermes native companion is incomplete: ${root}`);
|
|
28822
28921
|
const value = yamlParse(readFileSync35(manifest, "utf8"));
|
|
28823
28922
|
if (!value || typeof value !== "object" || Array.isArray(value) || value.name !== expected)
|
|
@@ -28825,7 +28924,7 @@ function validateCompanion(root, expected) {
|
|
|
28825
28924
|
}
|
|
28826
28925
|
function readOwnership5(target) {
|
|
28827
28926
|
const file = join41(target, MARKER11);
|
|
28828
|
-
if (!
|
|
28927
|
+
if (!existsSync32(file))
|
|
28829
28928
|
return null;
|
|
28830
28929
|
try {
|
|
28831
28930
|
const value = JSON.parse(readFileSync35(file, "utf8"));
|
|
@@ -28840,7 +28939,7 @@ function readOwnership5(target) {
|
|
|
28840
28939
|
}
|
|
28841
28940
|
}
|
|
28842
28941
|
function replaceTarget(stage, target, root) {
|
|
28843
|
-
if (!
|
|
28942
|
+
if (!existsSync32(target)) {
|
|
28844
28943
|
renameSync14(stage, target);
|
|
28845
28944
|
return { commit: () => {}, rollback: () => rmSync17(target, { recursive: true, force: true }) };
|
|
28846
28945
|
}
|
|
@@ -28865,14 +28964,14 @@ function removeTarget(target, root) {
|
|
|
28865
28964
|
const backup = join41(backupRoot, "previous");
|
|
28866
28965
|
renameSync14(target, backup);
|
|
28867
28966
|
return { commit: () => rmSync17(backupRoot, { recursive: true, force: true }), rollback: () => {
|
|
28868
|
-
if (!
|
|
28967
|
+
if (!existsSync32(target))
|
|
28869
28968
|
renameSync14(backup, target);
|
|
28870
28969
|
rmSync17(backupRoot, { recursive: true, force: true });
|
|
28871
28970
|
} };
|
|
28872
28971
|
}
|
|
28873
28972
|
function updatePluginConfig(configured, enable, disable) {
|
|
28874
|
-
const actual =
|
|
28875
|
-
const exists =
|
|
28973
|
+
const actual = existsSync32(configured) && lstatSync27(configured).isSymbolicLink() ? realpathSync7(configured) : configured;
|
|
28974
|
+
const exists = existsSync32(actual);
|
|
28876
28975
|
const original = exists ? readFileSync35(actual, "utf8") : "";
|
|
28877
28976
|
let parsed = {};
|
|
28878
28977
|
if (original.trim() !== "") {
|
|
@@ -28930,7 +29029,7 @@ function effectiveConfigPath() {
|
|
|
28930
29029
|
const configured = resolve27(hermesConfigPath());
|
|
28931
29030
|
if (native === configured)
|
|
28932
29031
|
return configured;
|
|
28933
|
-
if (!
|
|
29032
|
+
if (!existsSync32(native) || !existsSync32(configured))
|
|
28934
29033
|
throw new Error(`Hermes only reads ${native}; configured path ${configured} must already resolve to the same file`);
|
|
28935
29034
|
const nativeReal = realpathSync7(native);
|
|
28936
29035
|
const configuredReal = realpathSync7(configured);
|
|
@@ -28939,7 +29038,7 @@ function effectiveConfigPath() {
|
|
|
28939
29038
|
throw new Error(`Hermes only reads ${native}; configured path ${configured} is a different file`);
|
|
28940
29039
|
}
|
|
28941
29040
|
function sameTree9(left, right) {
|
|
28942
|
-
if (!
|
|
29041
|
+
if (!existsSync32(right))
|
|
28943
29042
|
return false;
|
|
28944
29043
|
const list = (root) => {
|
|
28945
29044
|
const out = [];
|
|
@@ -28947,7 +29046,7 @@ function sameTree9(left, right) {
|
|
|
28947
29046
|
for (const name of readdirSync25(dir).sort()) {
|
|
28948
29047
|
if (name === MARKER11)
|
|
28949
29048
|
continue;
|
|
28950
|
-
const path = join41(dir, name), relative = prefix ? `${prefix}/${name}` : name, stat =
|
|
29049
|
+
const path = join41(dir, name), relative = prefix ? `${prefix}/${name}` : name, stat = lstatSync27(path);
|
|
28951
29050
|
if (stat.isSymbolicLink())
|
|
28952
29051
|
throw new Error(`Hermes plugin contains symlink: ${path}`);
|
|
28953
29052
|
if (stat.isDirectory())
|
|
@@ -28967,13 +29066,13 @@ function readBytes2(path) {
|
|
|
28967
29066
|
return readFileSync35(path);
|
|
28968
29067
|
}
|
|
28969
29068
|
function assertTree3(root) {
|
|
28970
|
-
const stat =
|
|
29069
|
+
const stat = lstatSync27(root);
|
|
28971
29070
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
28972
29071
|
throw new Error(`Hermes plugin source is not a real directory: ${root}`);
|
|
28973
29072
|
for (const name of readdirSync25(root)) {
|
|
28974
29073
|
if (name === MARKER11)
|
|
28975
29074
|
continue;
|
|
28976
|
-
const path = join41(root, name), entry =
|
|
29075
|
+
const path = join41(root, name), entry = lstatSync27(path);
|
|
28977
29076
|
if (entry.isSymbolicLink())
|
|
28978
29077
|
throw new Error(`Hermes plugin contains symlink: ${path}`);
|
|
28979
29078
|
if (entry.isDirectory())
|
|
@@ -28988,15 +29087,15 @@ function assertManagedPath5(root, target) {
|
|
|
28988
29087
|
throw new Error(`Hermes managed path escapes its store: ${target}`);
|
|
28989
29088
|
let current = base;
|
|
28990
29089
|
for (const part of selected.slice(base.length).split("/").filter(Boolean)) {
|
|
28991
|
-
if (
|
|
28992
|
-
const stat =
|
|
29090
|
+
if (existsSync32(current)) {
|
|
29091
|
+
const stat = lstatSync27(current);
|
|
28993
29092
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
28994
29093
|
throw new Error(`Hermes managed path component is unsafe: ${current}`);
|
|
28995
29094
|
}
|
|
28996
29095
|
current = join41(current, part);
|
|
28997
29096
|
}
|
|
28998
|
-
if (
|
|
28999
|
-
const stat =
|
|
29097
|
+
if (existsSync32(current)) {
|
|
29098
|
+
const stat = lstatSync27(current);
|
|
29000
29099
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
29001
29100
|
throw new Error(`Hermes managed path component is unsafe: ${current}`);
|
|
29002
29101
|
}
|
|
@@ -29144,7 +29243,7 @@ function verifiedSourceImportClosure(root) {
|
|
|
29144
29243
|
if (entry.startsWith(".") || entry === "__pycache__" || entry === "node_modules")
|
|
29145
29244
|
continue;
|
|
29146
29245
|
const path = join41(directory, entry);
|
|
29147
|
-
const stat =
|
|
29246
|
+
const stat = lstatSync27(path);
|
|
29148
29247
|
if (stat.isSymbolicLink()) {
|
|
29149
29248
|
if (entry.endsWith(".py") || statSync14(path).isDirectory())
|
|
29150
29249
|
return false;
|
|
@@ -29156,7 +29255,7 @@ function verifiedSourceImportClosure(root) {
|
|
|
29156
29255
|
return visit(root, true);
|
|
29157
29256
|
}
|
|
29158
29257
|
function hermesExecutableSource(binary, depth = 0) {
|
|
29159
|
-
if (depth > 4 || !isAbsolute12(binary) || !
|
|
29258
|
+
if (depth > 4 || !isAbsolute12(binary) || !existsSync32(binary))
|
|
29160
29259
|
return;
|
|
29161
29260
|
const executable = realpathSync7(binary);
|
|
29162
29261
|
if (!statSync14(executable).isFile())
|
|
@@ -29168,7 +29267,7 @@ exec `)) {
|
|
|
29168
29267
|
exec `.length));
|
|
29169
29268
|
if (args?.length === 2 && args[1] === "$@")
|
|
29170
29269
|
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])) || !
|
|
29270
|
+
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
29271
|
return;
|
|
29173
29272
|
const code = args[3];
|
|
29174
29273
|
if (!code.startsWith(`import os, re, sys
|
|
@@ -29180,26 +29279,26 @@ exec `.length));
|
|
|
29180
29279
|
const root = literalPythonPath(bindings[0][1]);
|
|
29181
29280
|
if (root === undefined || code.replaceAll(bindings[0][1], "'/__PLUGNZ_HERMES_ROOT__'") !== hermesNativeBootstrap)
|
|
29182
29281
|
return;
|
|
29183
|
-
return root !== undefined && isAbsolute12(root) &&
|
|
29282
|
+
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
29283
|
}
|
|
29185
29284
|
const interpreter = /^#!([^\n]+)\n/u.exec(text)?.[1];
|
|
29186
|
-
if (interpreter === undefined || !isAbsolute12(interpreter) || !
|
|
29285
|
+
if (interpreter === undefined || !isAbsolute12(interpreter) || !existsSync32(interpreter) || !/^python(?:\d+(?:\.\d+)*)?$/u.test(basename8(interpreter)) || text.slice(text.indexOf(`
|
|
29187
29286
|
`) + 1) !== hermesUvConsoleBody)
|
|
29188
29287
|
return;
|
|
29189
29288
|
const venv = dirname20(dirname20(executable));
|
|
29190
|
-
if (dirname20(interpreter) !== join41(venv, "bin") || !
|
|
29289
|
+
if (dirname20(interpreter) !== join41(venv, "bin") || !existsSync32(join41(venv, "pyvenv.cfg")))
|
|
29191
29290
|
return;
|
|
29192
|
-
if (
|
|
29291
|
+
if (existsSync32(join41(venv, "bin", "pyvenv.cfg")) || !isolatedVenvConfig(readFileSync35(join41(venv, "pyvenv.cfg"), "utf8")) || process.env["PYTHONHOME"] || process.env["PYTHONPATH"])
|
|
29193
29292
|
return;
|
|
29194
29293
|
if (hasImportShadow(join41(venv, "bin"), ["hermes_cli", "sitecustomize", "usercustomize", "_virtualenv"]))
|
|
29195
29294
|
return;
|
|
29196
29295
|
const lib = join41(venv, "lib");
|
|
29197
|
-
if (!
|
|
29296
|
+
if (!existsSync32(lib))
|
|
29198
29297
|
return;
|
|
29199
29298
|
const roots = [];
|
|
29200
29299
|
for (const python of readdirSync25(lib).filter((name) => /^python\d+\.\d+$/u.test(name))) {
|
|
29201
29300
|
const packages = join41(lib, python, "site-packages");
|
|
29202
|
-
if (!
|
|
29301
|
+
if (!existsSync32(packages))
|
|
29203
29302
|
continue;
|
|
29204
29303
|
if (hasImportShadow(packages, ["hermes_cli", "sitecustomize", "usercustomize", "_virtualenv"], ["_virtualenv.py"]))
|
|
29205
29304
|
return;
|
|
@@ -29207,13 +29306,13 @@ exec `.length));
|
|
|
29207
29306
|
const distribution = join41(packages, name);
|
|
29208
29307
|
const metadata = join41(distribution, "direct_url.json");
|
|
29209
29308
|
const entry = join41(distribution, "entry_points.txt");
|
|
29210
|
-
if (!
|
|
29309
|
+
if (!existsSync32(metadata) || !existsSync32(entry) || !/^hermes\s*=\s*hermes_cli\.main:main$/mu.test(readFileSync35(entry, "utf8")))
|
|
29211
29310
|
continue;
|
|
29212
29311
|
const direct = JSON.parse(readFileSync35(metadata, "utf8"));
|
|
29213
29312
|
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
29313
|
continue;
|
|
29215
29314
|
const root = decodeURIComponent(direct.url.slice("file://".length));
|
|
29216
|
-
if (!isAbsolute12(root) || !
|
|
29315
|
+
if (!isAbsolute12(root) || !existsSync32(join41(root, "hermes_cli", "main.py")))
|
|
29217
29316
|
continue;
|
|
29218
29317
|
const sourceModules = [
|
|
29219
29318
|
"hermes_cli",
|
|
@@ -29221,7 +29320,7 @@ exec `.length));
|
|
|
29221
29320
|
"hermes_constants",
|
|
29222
29321
|
"pm",
|
|
29223
29322
|
...readdirSync25(root).filter((name) => name.endsWith(".py")).map((name) => name.slice(0, -3)),
|
|
29224
|
-
...readdirSync25(root).filter((name) =>
|
|
29323
|
+
...readdirSync25(root).filter((name) => existsSync32(join41(root, name, "__init__.py")))
|
|
29225
29324
|
];
|
|
29226
29325
|
if (hasImportShadow(packages, sourceModules) || hasImportShadow(join41(venv, "bin"), sourceModules))
|
|
29227
29326
|
return;
|
|
@@ -29236,11 +29335,11 @@ exec `.length));
|
|
|
29236
29335
|
const pth = readFileSync35(join41(packages, pthName), "utf8").trim();
|
|
29237
29336
|
if (pthName === `_virtualenv.pth` && pth === "import _virtualenv") {
|
|
29238
29337
|
const helper = join41(packages, "_virtualenv.py");
|
|
29239
|
-
if (!
|
|
29338
|
+
if (!existsSync32(helper) || new CryptoHasher("sha256").update(readFileSync35(helper, "utf8")).digest("hex") !== "cfb3db86aaa53bb62b5ff764970bec2d71c9228590a0ebec57f6ec926cc0bf1a")
|
|
29240
29339
|
return;
|
|
29241
29340
|
} else if (pthName === `__editable__.hermes_agent-${version}.pth` && pth === root)
|
|
29242
29341
|
binding = true;
|
|
29243
|
-
else if (pthName === `__editable__.hermes_agent-${version}.pth` && pth === `import ${finder}; ${finder}.install()` &&
|
|
29342
|
+
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
29343
|
binding = true;
|
|
29245
29344
|
else
|
|
29246
29345
|
return;
|
|
@@ -29253,7 +29352,7 @@ exec `.length));
|
|
|
29253
29352
|
}
|
|
29254
29353
|
function observeHermesRevision() {
|
|
29255
29354
|
const binary = process.env["OPEN_PLUGIN_HERMES_BIN"] ?? which("hermes");
|
|
29256
|
-
if (!binary || !
|
|
29355
|
+
if (!binary || !existsSync32(binary))
|
|
29257
29356
|
return { kind: "unknown", diagnostic: "Select an existing Hermes launcher with OPEN_PLUGIN_HERMES_BIN; a profile config does not identify its runtime" };
|
|
29258
29357
|
try {
|
|
29259
29358
|
const root = hermesExecutableSource(binary);
|
|
@@ -29327,14 +29426,14 @@ function resolveInstanceConfig(root, configPath) {
|
|
|
29327
29426
|
const configured = resolve27(configPath);
|
|
29328
29427
|
if (native === configured)
|
|
29329
29428
|
return configured;
|
|
29330
|
-
if (!
|
|
29429
|
+
if (!existsSync32(native) || !existsSync32(configured))
|
|
29331
29430
|
throw new Error(`Hermes only reads ${native}; configured path ${configured} must already resolve to the same file`);
|
|
29332
29431
|
if (realpathSync7(native) === realpathSync7(configured))
|
|
29333
29432
|
return configured;
|
|
29334
29433
|
throw new Error(`Hermes only reads ${native}; configured path ${configured} is a different file`);
|
|
29335
29434
|
}
|
|
29336
29435
|
function actualConfig(configPath) {
|
|
29337
|
-
return
|
|
29436
|
+
return existsSync32(configPath) && lstatSync27(configPath).isSymbolicLink() ? realpathSync7(configPath) : configPath;
|
|
29338
29437
|
}
|
|
29339
29438
|
function workDir(store, attemptId, operationId) {
|
|
29340
29439
|
return join41(store.root, ".plgnz-lifecycle", encodeURIComponent(attemptId), encodeURIComponent(operationId));
|
|
@@ -29403,7 +29502,7 @@ function sameLifecycleOwner(marker, claim) {
|
|
|
29403
29502
|
return installed !== null && installed.pluginId === claim.pluginId && installed.scopeId === claim.scopeId && installed.sourceType === claim.sourceType && installed.locator === claim.locator;
|
|
29404
29503
|
}
|
|
29405
29504
|
function assertLifecycleOwned(target, claim, handle) {
|
|
29406
|
-
if (!
|
|
29505
|
+
if (!existsSync32(target))
|
|
29407
29506
|
return;
|
|
29408
29507
|
const marker = readMarker(target);
|
|
29409
29508
|
if (marker === null)
|
|
@@ -29433,7 +29532,7 @@ function copyReplace(stage, target, root) {
|
|
|
29433
29532
|
}
|
|
29434
29533
|
function flagSet(configPath, key) {
|
|
29435
29534
|
const actual = actualConfig(configPath);
|
|
29436
|
-
if (!
|
|
29535
|
+
if (!existsSync32(actual))
|
|
29437
29536
|
return new Set;
|
|
29438
29537
|
const parsed = yamlParse(readFileSync35(actual, "utf8"));
|
|
29439
29538
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
@@ -29459,7 +29558,7 @@ function activationMatches(configPath, packageName, companionId, hasCompanion) {
|
|
|
29459
29558
|
}
|
|
29460
29559
|
function entryValue(configPath, packageName) {
|
|
29461
29560
|
const actual = actualConfig(configPath);
|
|
29462
|
-
if (!
|
|
29561
|
+
if (!existsSync32(actual))
|
|
29463
29562
|
return;
|
|
29464
29563
|
const parsed = yamlParse(readFileSync35(actual, "utf8"));
|
|
29465
29564
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
@@ -29492,7 +29591,7 @@ function sha2563(value) {
|
|
|
29492
29591
|
}
|
|
29493
29592
|
function retentionFor(store, packageName) {
|
|
29494
29593
|
const dataDir = join41(store.root, "plugin-data", hermesPluginDataNamespace(packageName));
|
|
29495
|
-
const pluginData =
|
|
29594
|
+
const pluginData = existsSync32(dataDir) && lstatSync27(dataDir).isDirectory() ? { state: "present", fingerprint: fingerprintTree(dataDir) } : { state: "absent", fingerprint: null };
|
|
29496
29595
|
const entry = entryValue(store.configPath, packageName);
|
|
29497
29596
|
const inactiveMetadata = entry === undefined ? { state: "absent", fingerprint: null } : { state: "present", fingerprint: sha2563(JSON.stringify(canonicalValue(entry))) };
|
|
29498
29597
|
return { pluginData, inactiveMetadata };
|
|
@@ -29501,7 +29600,7 @@ function atomicFingerprint(packageDir, companionDir) {
|
|
|
29501
29600
|
const temp = mkdtempSync16(join41(tmpdir13(), "plgnz-hermes-atomic-"));
|
|
29502
29601
|
try {
|
|
29503
29602
|
cpSync15(packageDir, join41(temp, "package"), { recursive: true });
|
|
29504
|
-
if (companionDir !== undefined &&
|
|
29603
|
+
if (companionDir !== undefined && existsSync32(companionDir))
|
|
29505
29604
|
cpSync15(companionDir, join41(temp, "commands"), { recursive: true });
|
|
29506
29605
|
return fingerprintTree(temp);
|
|
29507
29606
|
} finally {
|
|
@@ -29510,7 +29609,7 @@ function atomicFingerprint(packageDir, companionDir) {
|
|
|
29510
29609
|
}
|
|
29511
29610
|
function readConfigDocument2(configPath) {
|
|
29512
29611
|
const actual = actualConfig(configPath);
|
|
29513
|
-
if (!
|
|
29612
|
+
if (!existsSync32(actual))
|
|
29514
29613
|
return null;
|
|
29515
29614
|
const text = readFileSync35(actual, "utf8");
|
|
29516
29615
|
if (text.trim() === "")
|
|
@@ -29568,7 +29667,7 @@ function membership(list, id, present) {
|
|
|
29568
29667
|
}
|
|
29569
29668
|
function writeConfigDocument(configPath, doc) {
|
|
29570
29669
|
const actual = actualConfig(configPath);
|
|
29571
|
-
const exists =
|
|
29670
|
+
const exists = existsSync32(actual);
|
|
29572
29671
|
const mode = exists ? statSync14(actual).mode & 511 : null;
|
|
29573
29672
|
mkdirSync17(dirname20(actual), { recursive: true });
|
|
29574
29673
|
const temp = join41(dirname20(actual), `.plgnz-hermes-rollback-${Date.now()}-${Math.random().toString(16).slice(2)}.yaml`);
|
|
@@ -29616,18 +29715,18 @@ function saveRollback(store, reference, packageName, packageDir, companionDir) {
|
|
|
29616
29715
|
mkdirSync17(reference, { recursive: true });
|
|
29617
29716
|
const companionId = hermesCommandCompanionId(packageName);
|
|
29618
29717
|
writeFileSync17(join41(reference, "config-slice.json"), JSON.stringify(captureConfigSlice(store.configPath, packageName, companionId)));
|
|
29619
|
-
if (
|
|
29718
|
+
if (existsSync32(packageDir))
|
|
29620
29719
|
cpSync15(packageDir, join41(reference, "package"), { recursive: true });
|
|
29621
|
-
if (
|
|
29720
|
+
if (existsSync32(companionDir))
|
|
29622
29721
|
cpSync15(companionDir, join41(reference, "commands"), { recursive: true });
|
|
29623
29722
|
}
|
|
29624
29723
|
function restoreRollback3(store, reference, packageDir, companionDir) {
|
|
29625
29724
|
const slice = JSON.parse(readFileSync35(join41(reference, "config-slice.json"), "utf8"));
|
|
29626
29725
|
rmSync17(packageDir, { recursive: true, force: true });
|
|
29627
29726
|
rmSync17(companionDir, { recursive: true, force: true });
|
|
29628
|
-
if (
|
|
29727
|
+
if (existsSync32(join41(reference, "package")))
|
|
29629
29728
|
cpSync15(join41(reference, "package"), packageDir, { recursive: true });
|
|
29630
|
-
if (
|
|
29729
|
+
if (existsSync32(join41(reference, "commands")))
|
|
29631
29730
|
cpSync15(join41(reference, "commands"), companionDir, { recursive: true });
|
|
29632
29731
|
restoreConfigSlice(store.configPath, slice);
|
|
29633
29732
|
}
|
|
@@ -29676,7 +29775,7 @@ var hermesLifecycleDefinition = {
|
|
|
29676
29775
|
try {
|
|
29677
29776
|
const store = storeFor(target);
|
|
29678
29777
|
const actual = actualConfig(store.configPath);
|
|
29679
|
-
if (!
|
|
29778
|
+
if (!existsSync32(actual) || !statSync14(actual).isFile())
|
|
29680
29779
|
return { kind: "unknown" };
|
|
29681
29780
|
const text = readFileSync35(actual, "utf8");
|
|
29682
29781
|
if (text.trim() !== "") {
|
|
@@ -29759,9 +29858,9 @@ var hermesLifecycleDefinition = {
|
|
|
29759
29858
|
const companionStage = join41(stagingRoot, "commands");
|
|
29760
29859
|
mkdirSync17(packageStage, { recursive: true });
|
|
29761
29860
|
projectPluginForHermes(request.snapshot.packageRoot, packageStage, companionStage);
|
|
29762
|
-
if (
|
|
29861
|
+
if (existsSync32(companionStage) && readdirSync25(companionStage).length === 0)
|
|
29763
29862
|
rmSync17(companionStage, { recursive: true });
|
|
29764
|
-
const hasCompanion =
|
|
29863
|
+
const hasCompanion = existsSync32(companionStage);
|
|
29765
29864
|
validatePackage(packageStage, request.snapshot.packageName);
|
|
29766
29865
|
if (hasCompanion)
|
|
29767
29866
|
validateCompanion(companionStage, hermesCommandCompanionId(request.snapshot.packageName));
|
|
@@ -29785,7 +29884,7 @@ var hermesLifecycleDefinition = {
|
|
|
29785
29884
|
if (projection.pins.length === 0)
|
|
29786
29885
|
return [];
|
|
29787
29886
|
const mcp = join41(projection.stagingRoot, "package", "mcp.json");
|
|
29788
|
-
if (!
|
|
29887
|
+
if (!existsSync32(mcp))
|
|
29789
29888
|
throw new Error(`Hermes pin set has no mcp.json: ${mcp}`);
|
|
29790
29889
|
const value = JSON.parse(readFileSync35(mcp, "utf8"));
|
|
29791
29890
|
const servers = value.mcpServers ?? {};
|
|
@@ -29804,7 +29903,7 @@ var hermesLifecycleDefinition = {
|
|
|
29804
29903
|
const paths = packagePaths(store, projection.packageName);
|
|
29805
29904
|
const prior = withIdentity(inspect(store, projection.nativeId, projection.packageName, "none"), projection.target, projection.scopeId, projection.packageName, projection.nativeId);
|
|
29806
29905
|
capturePriorSourceRepair(projection, prior.installedFingerprint);
|
|
29807
|
-
const hasCompanion =
|
|
29906
|
+
const hasCompanion = existsSync32(join41(projection.stagingRoot, "commands"));
|
|
29808
29907
|
const contentRoots = [{ label: "package", path: paths.packageDir, fingerprint: fingerprintTree(join41(projection.stagingRoot, "package")) }];
|
|
29809
29908
|
if (hasCompanion)
|
|
29810
29909
|
contentRoots.push({ label: "commands", path: paths.companionDir, fingerprint: fingerprintTree(join41(projection.stagingRoot, "commands")) });
|
|
@@ -29841,15 +29940,15 @@ var hermesLifecycleDefinition = {
|
|
|
29841
29940
|
assertManagedPath5(store.pluginsDir, paths.companionDir);
|
|
29842
29941
|
const stagedPackage = join41(prepared.stagingRoot, "package");
|
|
29843
29942
|
const stagedCompanion = join41(prepared.stagingRoot, "commands");
|
|
29844
|
-
const hasCompanion =
|
|
29943
|
+
const hasCompanion = existsSync32(stagedCompanion);
|
|
29845
29944
|
const owner = ownerFromHandle(prepared.handle);
|
|
29846
29945
|
assertLifecycleOwned(paths.packageDir, owner, prepared.handle);
|
|
29847
29946
|
if (hasCompanion)
|
|
29848
29947
|
assertLifecycleOwned(paths.companionDir, owner, prepared.handle);
|
|
29849
|
-
else if (
|
|
29948
|
+
else if (existsSync32(paths.companionDir))
|
|
29850
29949
|
assertLifecycleOwned(paths.companionDir, owner, prepared.handle);
|
|
29851
29950
|
mkdirSync17(store.pluginsDir, { recursive: true });
|
|
29852
|
-
const unchanged =
|
|
29951
|
+
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
29952
|
if (unchanged)
|
|
29854
29953
|
return { receiptId: `apply:${prepared.handle.attemptId}:${prepared.handle.operationId}`, changed: false };
|
|
29855
29954
|
const changes = [];
|
|
@@ -29857,7 +29956,7 @@ var hermesLifecycleDefinition = {
|
|
|
29857
29956
|
changes.push(copyReplace(stagedPackage, paths.packageDir, store.pluginsDir));
|
|
29858
29957
|
if (hasCompanion)
|
|
29859
29958
|
changes.push(copyReplace(stagedCompanion, paths.companionDir, store.pluginsDir));
|
|
29860
|
-
else if (
|
|
29959
|
+
else if (existsSync32(paths.companionDir))
|
|
29861
29960
|
changes.push(removeTarget(paths.companionDir, store.pluginsDir));
|
|
29862
29961
|
updatePluginConfig(store.configPath, [prepared.handle.packageName, ...hasCompanion ? [paths.companionId] : []], hasCompanion ? [] : [paths.companionId]);
|
|
29863
29962
|
for (const change of changes)
|
|
@@ -29883,11 +29982,11 @@ var hermesLifecycleDefinition = {
|
|
|
29883
29982
|
const source = prepared.handle.sourceLocator ?? prepared.handle.sourceRevision;
|
|
29884
29983
|
const changes = [];
|
|
29885
29984
|
try {
|
|
29886
|
-
if (
|
|
29985
|
+
if (existsSync32(paths.packageDir)) {
|
|
29887
29986
|
assertLifecycleOwned(paths.packageDir, ownerFromHandle(prepared.handle));
|
|
29888
29987
|
changes.push(removeTarget(paths.packageDir, store.pluginsDir));
|
|
29889
29988
|
}
|
|
29890
|
-
if (
|
|
29989
|
+
if (existsSync32(paths.companionDir)) {
|
|
29891
29990
|
const marker = readMarker(paths.companionDir);
|
|
29892
29991
|
if (marker !== null && marker.pluginId === prepared.handle.nativeId && marker.source === source)
|
|
29893
29992
|
changes.push(removeTarget(paths.companionDir, store.pluginsDir));
|
|
@@ -30234,7 +30333,7 @@ function invalidSelection2(diagnostic) {
|
|
|
30234
30333
|
}
|
|
30235
30334
|
|
|
30236
30335
|
// src/recorded-pins.ts
|
|
30237
|
-
import { existsSync as
|
|
30336
|
+
import { existsSync as existsSync33, readFileSync as readFileSync36 } from "node:fs";
|
|
30238
30337
|
import { isAbsolute as isAbsolute13, join as join42, resolve as resolve28 } from "node:path";
|
|
30239
30338
|
function resolveRecordedPinExecutables(packageRoot, servers) {
|
|
30240
30339
|
const pins = [];
|
|
@@ -30257,7 +30356,7 @@ function resolveRecordedPinExecutables(packageRoot, servers) {
|
|
|
30257
30356
|
function recordedPinCommand(packageRoot, server) {
|
|
30258
30357
|
for (const name of [".mcp.json", "mcp.json"]) {
|
|
30259
30358
|
const file = join42(packageRoot, name);
|
|
30260
|
-
if (!
|
|
30359
|
+
if (!existsSync33(file))
|
|
30261
30360
|
continue;
|
|
30262
30361
|
let parsed;
|
|
30263
30362
|
try {
|
|
@@ -31434,6 +31533,14 @@ function writeState(records, file = stateFile()) {
|
|
|
31434
31533
|
validateLegacyInstallRecords(records);
|
|
31435
31534
|
atomicWrite(file, JSON.stringify({ version: 1, installs: records }, null, 2));
|
|
31436
31535
|
}
|
|
31536
|
+
function writeInstallLedger(records, changed, binding) {
|
|
31537
|
+
const loaded = readLifecycleState();
|
|
31538
|
+
if (loaded.sourceVersion !== 2) {
|
|
31539
|
+
writeState(records);
|
|
31540
|
+
return;
|
|
31541
|
+
}
|
|
31542
|
+
writeLifecycleState(withLegacyWriterRecord(loaded.state, changed, binding), { globalPreflight: "succeeded" });
|
|
31543
|
+
}
|
|
31437
31544
|
function withLegacyWriterRecord(state, record, binding) {
|
|
31438
31545
|
const source = persistedSource(binding);
|
|
31439
31546
|
const scope = createDeploymentScopeIdentity(source, { kind: record.host, instance: "default" });
|
|
@@ -33446,6 +33553,9 @@ function selectTargets(all, options) {
|
|
|
33446
33553
|
return defaultPinTargets(all);
|
|
33447
33554
|
}
|
|
33448
33555
|
|
|
33556
|
+
// src/update.ts
|
|
33557
|
+
init_compatibility();
|
|
33558
|
+
|
|
33449
33559
|
// src/native-identity.ts
|
|
33450
33560
|
function captureNativeIdentity(writer, plugin) {
|
|
33451
33561
|
let nativeId = null;
|
|
@@ -33497,7 +33607,12 @@ function shortSha2(sha) {
|
|
|
33497
33607
|
async function runUpdate(name, options = {}) {
|
|
33498
33608
|
const hosts = options.writers ?? writers;
|
|
33499
33609
|
let state = options.state ?? readState();
|
|
33500
|
-
const save =
|
|
33610
|
+
const save = (records, changed, binding) => {
|
|
33611
|
+
if (options.writeState !== undefined)
|
|
33612
|
+
options.writeState(records);
|
|
33613
|
+
else
|
|
33614
|
+
writeInstallLedger(records, changed, binding);
|
|
33615
|
+
};
|
|
33501
33616
|
const prefix = options.dryRun === true ? "[dry-run] " : "";
|
|
33502
33617
|
const findings = [];
|
|
33503
33618
|
let mutationStarted = false;
|
|
@@ -33626,7 +33741,7 @@ async function runUpdate(name, options = {}) {
|
|
|
33626
33741
|
const pending = { ...record, pending: "install" };
|
|
33627
33742
|
record = pending;
|
|
33628
33743
|
const next = state.map((candidate) => candidate === persistedRecord ? pending : candidate);
|
|
33629
|
-
save(next);
|
|
33744
|
+
save(next, pending, resolved.snapshot.binding);
|
|
33630
33745
|
state = next;
|
|
33631
33746
|
recordMutationStarted = true;
|
|
33632
33747
|
mutationStarted = true;
|
|
@@ -33713,7 +33828,7 @@ async function runUpdate(name, options = {}) {
|
|
|
33713
33828
|
delete finalized.pending;
|
|
33714
33829
|
const next = state.map((candidate) => candidate === record ? finalized : candidate);
|
|
33715
33830
|
try {
|
|
33716
|
-
save(next);
|
|
33831
|
+
save(next, finalized, resolved.snapshot.binding);
|
|
33717
33832
|
} catch (error) {
|
|
33718
33833
|
findings.push(findingFor(record, {
|
|
33719
33834
|
mark: "✗",
|
|
@@ -33847,6 +33962,9 @@ function findConsumerProfile(id) {
|
|
|
33847
33962
|
return byId.get(id);
|
|
33848
33963
|
}
|
|
33849
33964
|
|
|
33965
|
+
// src/cli.ts
|
|
33966
|
+
init_compatibility();
|
|
33967
|
+
|
|
33850
33968
|
// src/legacy-install-outcome.ts
|
|
33851
33969
|
function serializeLegacyInstallOutcomes(report) {
|
|
33852
33970
|
const rows = report.outcomes.map((outcome) => ({
|
|
@@ -33903,7 +34021,7 @@ function legacyCommandAction(command) {
|
|
|
33903
34021
|
// package.json
|
|
33904
34022
|
var package_default = {
|
|
33905
34023
|
name: "plugnz",
|
|
33906
|
-
version: "0.0.
|
|
34024
|
+
version: "0.0.24",
|
|
33907
34025
|
description: "Install, diagnose and update agent plugins (Agent Plugins spec) and MCP configs across Claude Code, Codex, Cursor, Kimi and more",
|
|
33908
34026
|
license: "MIT",
|
|
33909
34027
|
type: "module",
|
|
@@ -34361,6 +34479,10 @@ function printReport(report, mode) {
|
|
|
34361
34479
|
const legacy = serializeLegacyInstallOutcomes(report);
|
|
34362
34480
|
for (const item of legacy)
|
|
34363
34481
|
console.log(`${item.target} ${item.status} ${item.plugin}${item.diagnostic ? ` ${item.diagnostic}` : ""}`);
|
|
34482
|
+
for (const facts of report.verification?.operations ?? []) {
|
|
34483
|
+
const outcome = report.outcomes.find((row) => row.operationId === facts.operationId);
|
|
34484
|
+
console.log(`${outcome.scope.target.kind} ${outcome.package} compatibility=${facts.compatibility} registration=${facts.registration} executionApproval=${facts.executionApproval} delivery=${facts.delivery}`);
|
|
34485
|
+
}
|
|
34364
34486
|
}
|
|
34365
34487
|
}
|
|
34366
34488
|
function select(available, targets) {
|
|
@@ -34663,14 +34785,6 @@ async function runPlannerAdd(source, binding, targets, flags) {
|
|
|
34663
34785
|
command: { ...executed.report.command, name: "add" }
|
|
34664
34786
|
});
|
|
34665
34787
|
}
|
|
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
34788
|
async function runWriterAdd(source, selectedWriters, flags, mode) {
|
|
34675
34789
|
let resolved;
|
|
34676
34790
|
try {
|
|
@@ -35002,7 +35116,8 @@ async function runRecordedLifecycleUpdate(flags, state) {
|
|
|
35002
35116
|
const scope = scopes.get(activation.scopeId);
|
|
35003
35117
|
if (scope === undefined || scope.target.instance !== "default" || !kinds.has(scope.target.kind))
|
|
35004
35118
|
return [];
|
|
35005
|
-
|
|
35119
|
+
const writer = present.selected.find((candidate) => candidate.id === scope.target.kind);
|
|
35120
|
+
if (!requestedPersistedIdentityMatches(writer, activation.packageId, activation.nativeId, requested))
|
|
35006
35121
|
return [];
|
|
35007
35122
|
return [{ scope, packageId: activation.packageId }];
|
|
35008
35123
|
});
|
|
@@ -35080,6 +35195,7 @@ async function runRecordedLifecycleUpdate(flags, state) {
|
|
|
35080
35195
|
});
|
|
35081
35196
|
}
|
|
35082
35197
|
function emitAddReport(report, mode) {
|
|
35198
|
+
report = parseLifecycleReport({ ...report, verification: installationVerification(report) });
|
|
35083
35199
|
if (mode === "json")
|
|
35084
35200
|
return emitValidatedReport(report, true);
|
|
35085
35201
|
printReport(report, mode);
|