plugnz 0.0.8 → 0.0.9
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/plugnz.mjs +820 -55
- package/package.json +1 -1
package/dist/plugnz.mjs
CHANGED
|
@@ -9339,10 +9339,23 @@ var dcode = {
|
|
|
9339
9339
|
continue;
|
|
9340
9340
|
const row = entry;
|
|
9341
9341
|
const path = typeof row.installPath === "string" ? row.installPath : typeof row.install_path === "string" ? row.install_path : undefined;
|
|
9342
|
+
let declaredVersion;
|
|
9343
|
+
if (path && existsSync8(path)) {
|
|
9344
|
+
for (const relative of ["plugin.json", ".claude-plugin/plugin.json", ".codex-plugin/plugin.json"]) {
|
|
9345
|
+
try {
|
|
9346
|
+
const manifest = JSON.parse(readFileSync6(join11(path, relative), "utf8"));
|
|
9347
|
+
if (typeof manifest.version === "string") {
|
|
9348
|
+
declaredVersion = manifest.version;
|
|
9349
|
+
break;
|
|
9350
|
+
}
|
|
9351
|
+
} catch {}
|
|
9352
|
+
}
|
|
9353
|
+
}
|
|
9342
9354
|
const at = id.indexOf("@");
|
|
9343
9355
|
const name = at < 0 ? id : id.slice(0, at);
|
|
9344
9356
|
const marketplace = at < 0 ? undefined : id.slice(at + 1);
|
|
9345
|
-
const
|
|
9357
|
+
const version = typeof row.version === "string" ? row.version : declaredVersion;
|
|
9358
|
+
const plugin = { id, name, ...marketplace ? { marketplace } : {}, ...path && existsSync8(path) ? { path } : {}, ...version === undefined ? {} : { version }, ...enabled.enabledPlugins[id] === true ? { enabled: true } : { enabled: false } };
|
|
9346
9359
|
result.push(plugin);
|
|
9347
9360
|
}
|
|
9348
9361
|
return result;
|
|
@@ -12627,7 +12640,13 @@ function assertOutcome(outcome, snapshots, dryRun, command) {
|
|
|
12627
12640
|
}
|
|
12628
12641
|
const containment = outcome["action"] === "retain-prior" || outcome["action"] === "disable-nonconforming";
|
|
12629
12642
|
const appliedDisablement = outcome["action"] === "disable-nonconforming" && outcome["changed"] === true;
|
|
12630
|
-
if (
|
|
12643
|
+
if (outcome["action"] === "disable-nonconforming" && outcome["result"] === "succeeded") {
|
|
12644
|
+
throw contradiction(`disablement '${outcome["operationId"]}' cannot claim Desired convergence`);
|
|
12645
|
+
}
|
|
12646
|
+
if (!dryRun && outcome["action"] === "disable-nonconforming" && outcome["resourceState"] === "retained" && outcome["activationState"] === "inactive" && outcome["changed"] !== true) {
|
|
12647
|
+
throw contradiction(`disablement '${outcome["operationId"]}' cannot claim inactive containment without a verified mutation`);
|
|
12648
|
+
}
|
|
12649
|
+
if (containment && !dryRun && (outcome["action"] === "retain-prior" || isObject2(reason) && reason["category"] === "capability")) {
|
|
12631
12650
|
const expectedResourceState = "retained";
|
|
12632
12651
|
const expectedActivationState = outcome["action"] === "retain-prior" ? "retained-prior" : appliedDisablement ? "inactive" : "active-nonconforming";
|
|
12633
12652
|
if (outcome["result"] !== "failed" || outcome["resourceState"] !== expectedResourceState || outcome["activationState"] !== expectedActivationState) {
|
|
@@ -13546,7 +13565,8 @@ var dcode0183Managed = createCapabilityEvidenceProfile({
|
|
|
13546
13565
|
},
|
|
13547
13566
|
evidence: [
|
|
13548
13567
|
"docs/evidence/dcode-native-update-0.1.83-20261009.json",
|
|
13549
|
-
"docs/research/dcode-session-findings-2026-10-09.md"
|
|
13568
|
+
"docs/research/dcode-session-findings-2026-10-09.md",
|
|
13569
|
+
"docs/evidence/dcode-managed-lifecycle-20261011.md"
|
|
13550
13570
|
]
|
|
13551
13571
|
});
|
|
13552
13572
|
var capabilityEvidenceProfiles = Object.freeze([
|
|
@@ -14228,6 +14248,12 @@ function createLifecycleHostAdapter(definition) {
|
|
|
14228
14248
|
assertReadbackMatch(handle.prior, observation, "rollback");
|
|
14229
14249
|
return deepFreeze({ phase: "rollback-verified", handle, observation });
|
|
14230
14250
|
},
|
|
14251
|
+
async releaseRecovery(handle) {
|
|
14252
|
+
assertHandle(definition.id, handle);
|
|
14253
|
+
await invokePhase("cleanup", async () => {
|
|
14254
|
+
await definition.releaseRecovery?.(handle);
|
|
14255
|
+
});
|
|
14256
|
+
},
|
|
14231
14257
|
async cleanup(target, disposition) {
|
|
14232
14258
|
const reference = cleanupReference(definition.id, target);
|
|
14233
14259
|
if (isPreparationProjection(target) && disposition !== "aborted-preparation") {
|
|
@@ -20598,10 +20624,431 @@ function assertUnder(root, path) {
|
|
|
20598
20624
|
import { cpSync as cpSync8, existsSync as existsSync23, lstatSync as lstatSync16, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync9, readFileSync as readFileSync22, readdirSync as readdirSync17, realpathSync as realpathSync3, renameSync as renameSync8, rmSync as rmSync9, writeFileSync as writeFileSync9 } from "node:fs";
|
|
20599
20625
|
import { basename as basename5, dirname as dirname11, join as join28, resolve as resolve17 } from "node:path";
|
|
20600
20626
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
20627
|
+
import { spawn as spawnChild } from "node:child_process";
|
|
20601
20628
|
var MARKER7 = ".plgnz-install.json";
|
|
20602
20629
|
var MANIFESTS = ["plugin.json", ".claude-plugin/plugin.json", ".codex-plugin/plugin.json"];
|
|
20603
20630
|
var READBACK_FAULT = ".plgnz-dcode-readback-fault";
|
|
20631
|
+
var NATIVE_LOCK_SCRIPT = `import sys
|
|
20632
|
+
from importlib.metadata import version
|
|
20633
|
+
from filelock import FileLock
|
|
20634
|
+
if version('deepagents-code') != '0.1.83':
|
|
20635
|
+
raise RuntimeError('unverified dcode lock runtime')
|
|
20636
|
+
with FileLock(sys.argv[1]).acquire(timeout=10):
|
|
20637
|
+
print('DCODE_LOCK_0.1.83', flush=True)
|
|
20638
|
+
sys.stdin.read()
|
|
20639
|
+
`;
|
|
20640
|
+
var nativeLocks = new Map;
|
|
20641
|
+
function nativePython() {
|
|
20642
|
+
const override = process.env["OPEN_PLUGIN_DCODE_PYTHON_BIN"];
|
|
20643
|
+
if (override) {
|
|
20644
|
+
assertIdentity2(basename5(override), "Python binary");
|
|
20645
|
+
return override;
|
|
20646
|
+
}
|
|
20647
|
+
const binary = dcodeBinary();
|
|
20648
|
+
if (binary === undefined)
|
|
20649
|
+
throw new Error("dcode native lock runtime is unavailable");
|
|
20650
|
+
const shebang = readFileSync22(binary, "utf8").split(/\r?\n/, 1)[0] ?? "";
|
|
20651
|
+
const match = /^#!(\/[^\s]+python(?:\d+(?:\.\d+)?)?)$/u.exec(shebang);
|
|
20652
|
+
if (match?.[1] === undefined || !existsSync23(match[1]))
|
|
20653
|
+
throw new Error("dcode native Python interpreter is unverified; set OPEN_PLUGIN_DCODE_PYTHON_BIN to its verified interpreter");
|
|
20654
|
+
return match[1];
|
|
20655
|
+
}
|
|
20656
|
+
function probeLifecycleVersion() {
|
|
20657
|
+
const observation = probeDcodeVersion();
|
|
20658
|
+
if (observation.kind !== "detected" || observation.version !== "0.1.83")
|
|
20659
|
+
return observation;
|
|
20660
|
+
const result = spawnSync([nativePython(), "-c", "from importlib.metadata import version; import filelock; assert version('deepagents-code') == '0.1.83'; print('DCODE_LOCK_0.1.83')"], { stdout: "pipe", stderr: "pipe", timeout: 1e4 });
|
|
20661
|
+
if (result.exitCode !== 0 || new TextDecoder().decode(result.stdout).trim() !== "DCODE_LOCK_0.1.83")
|
|
20662
|
+
throw new Error(`dcode native lock runtime is unverified: ${new TextDecoder().decode(result.stderr).trim()}`);
|
|
20663
|
+
return observation;
|
|
20664
|
+
}
|
|
20665
|
+
async function acquireNativeLock(attemptId, operationId) {
|
|
20666
|
+
const key = `${attemptId}:${operationId}`;
|
|
20667
|
+
const existing = nativeLocks.get(key);
|
|
20668
|
+
if (existing !== undefined) {
|
|
20669
|
+
if (!existing.isAlive())
|
|
20670
|
+
throw new Error("dcode native lock was lost before verification");
|
|
20671
|
+
return;
|
|
20672
|
+
}
|
|
20673
|
+
const file = join28(dcodeRoot(), "plugins", ".mutation.lock");
|
|
20674
|
+
assertManagedPath4(file);
|
|
20675
|
+
mkdirSync9(dirname11(file), { recursive: true });
|
|
20676
|
+
const child = spawnChild(nativePython(), ["-c", NATIVE_LOCK_SCRIPT, file], { env: { ...process.env, HOME: process.env["OPEN_PLUGIN_HOME"] || process.env["HOME"], DEEPAGENTS_HOME: dcodeRoot() }, stdio: ["pipe", "pipe", "pipe"] });
|
|
20677
|
+
let alive = true;
|
|
20678
|
+
const exited = new Promise((resolveExit) => child.on("exit", (code) => {
|
|
20679
|
+
alive = false;
|
|
20680
|
+
resolveExit(code);
|
|
20681
|
+
}));
|
|
20682
|
+
await new Promise((resolveLock, rejectLock) => {
|
|
20683
|
+
let output = "", diagnostic = "", settled = false;
|
|
20684
|
+
const finish = (error) => {
|
|
20685
|
+
if (settled)
|
|
20686
|
+
return;
|
|
20687
|
+
settled = true;
|
|
20688
|
+
clearTimeout(timer);
|
|
20689
|
+
if (error) {
|
|
20690
|
+
child.kill("SIGKILL");
|
|
20691
|
+
rejectLock(error);
|
|
20692
|
+
} else
|
|
20693
|
+
resolveLock();
|
|
20694
|
+
};
|
|
20695
|
+
const timer = setTimeout(() => finish(new Error("dcode native lock acquisition timed out")), 12000);
|
|
20696
|
+
child.stdout.on("data", (data) => {
|
|
20697
|
+
output += new TextDecoder().decode(data);
|
|
20698
|
+
if (output.includes(`DCODE_LOCK_0.1.83
|
|
20699
|
+
`))
|
|
20700
|
+
finish();
|
|
20701
|
+
});
|
|
20702
|
+
child.stderr.on("data", (data) => {
|
|
20703
|
+
diagnostic += new TextDecoder().decode(data);
|
|
20704
|
+
});
|
|
20705
|
+
child.on("error", (error) => finish(new Error(`dcode native lock failed: ${error.message}`)));
|
|
20706
|
+
child.on("exit", (code) => finish(new Error(`dcode native lock failed (${code}): ${diagnostic.trim()}`)));
|
|
20707
|
+
});
|
|
20708
|
+
nativeLocks.set(key, { child, exited, isAlive: () => alive });
|
|
20709
|
+
}
|
|
20710
|
+
async function releaseNativeLock(attemptId, operationId) {
|
|
20711
|
+
const key = `${attemptId}:${operationId}`, held = nativeLocks.get(key);
|
|
20712
|
+
if (held === undefined)
|
|
20713
|
+
return;
|
|
20714
|
+
nativeLocks.delete(key);
|
|
20715
|
+
held.child.stdin.end();
|
|
20716
|
+
let timer;
|
|
20717
|
+
try {
|
|
20718
|
+
const code = await Promise.race([held.exited, new Promise((_, reject) => {
|
|
20719
|
+
timer = setTimeout(() => {
|
|
20720
|
+
held.child.kill("SIGKILL");
|
|
20721
|
+
reject(new Error("dcode native lock release timed out"));
|
|
20722
|
+
}, 2000);
|
|
20723
|
+
})]);
|
|
20724
|
+
if (code !== 0)
|
|
20725
|
+
throw new Error(`dcode native lock process failed during mutation (${code})`);
|
|
20726
|
+
} finally {
|
|
20727
|
+
if (timer !== undefined)
|
|
20728
|
+
clearTimeout(timer);
|
|
20729
|
+
}
|
|
20730
|
+
}
|
|
20731
|
+
function lifecycleDirectory(attemptId, operationId) {
|
|
20732
|
+
const hash = new CryptoHasher("sha256");
|
|
20733
|
+
hash.update(`${attemptId}\x00${operationId}`);
|
|
20734
|
+
const dir = join28(dcodeCacheRoot(), "plgnz-operations", hash.digest("hex"));
|
|
20735
|
+
assertCachePath(dir);
|
|
20736
|
+
return dir;
|
|
20737
|
+
}
|
|
20738
|
+
function lifecycleSlot(nativeId, fingerprint) {
|
|
20739
|
+
return managedSlot(nativeId, fingerprint);
|
|
20740
|
+
}
|
|
20741
|
+
function observeDcodeTarget(target) {
|
|
20742
|
+
if (target.kind !== "dcode" || target.instance !== "default")
|
|
20743
|
+
throw new Error("unsupported dcode target identity");
|
|
20744
|
+
const registry = readRegistry3(dcodeRegistryFile());
|
|
20745
|
+
const enabled = boolObject(readEnablement(dcodeEnablementFile()).enabledPlugins, "enabledPlugins");
|
|
20746
|
+
return Object.entries(object3(registry.plugins, "registry plugins")).map(([nativeId, raw]) => {
|
|
20747
|
+
const rows = rowsFor(raw);
|
|
20748
|
+
if (rows.length !== 1)
|
|
20749
|
+
throw new Error(`dcode install record ${nativeId} has duplicate rows`);
|
|
20750
|
+
const path = rowInstall(rows[0], nativeId);
|
|
20751
|
+
assertCachePath(path);
|
|
20752
|
+
const present = existsSync23(path);
|
|
20753
|
+
const marker = present ? ownership3(path) : null;
|
|
20754
|
+
const body = present ? readDoc2(join28(path, MARKER7), {}, "ownership marker") : {};
|
|
20755
|
+
const owned = marker?.pluginId === nativeId;
|
|
20756
|
+
const fingerprint = present ? fingerprintTree(path) : null;
|
|
20757
|
+
return {
|
|
20758
|
+
nativeId,
|
|
20759
|
+
packageName: nativeId.split("@")[0],
|
|
20760
|
+
ownership: owned ? { kind: "owned", proof: body.proof === "adopted" ? "adopted" : "created", scopeId: typeof body.scopeId === "string" ? body.scopeId : "dcode:default", proofId: `dcode-marker:${nativeId}` } : { kind: "unmanaged" },
|
|
20761
|
+
presence: present ? "present" : "absent",
|
|
20762
|
+
enablement: enabled[nativeId] === true ? "enabled" : "disabled",
|
|
20763
|
+
activation: enabled[nativeId] === true && present ? "active" : "inactive",
|
|
20764
|
+
installedFingerprint: fingerprint,
|
|
20765
|
+
installedVersion: present ? declaredManifest(path, nativeId.split("@")[0]).version : null,
|
|
20766
|
+
source: owned ? { type: body.sourceType === "git" ? "git" : "local", immutableRevision: marker.kind === "current" ? marker.sourceRevision : marker.fingerprint, locator: body.sourceType === "git" ? marker.source : null } : null,
|
|
20767
|
+
contentRoots: fingerprint === null ? [] : [{ label: "managed", path, fingerprint }]
|
|
20768
|
+
};
|
|
20769
|
+
});
|
|
20770
|
+
}
|
|
20771
|
+
function dcodeLifecycleReadback(binding) {
|
|
20772
|
+
if (existsSync23(join28(dcodeStateDir(), READBACK_FAULT)))
|
|
20773
|
+
throw new Error(`dcode readback failed for ${binding.nativeId}`);
|
|
20774
|
+
const installations = observeDcodeTarget(binding.target);
|
|
20775
|
+
const row = installations.find((item) => item.nativeId === binding.nativeId);
|
|
20776
|
+
const present = row?.presence === "present";
|
|
20777
|
+
const enabled = row?.enablement === "enabled" && present;
|
|
20778
|
+
const dataRoot = join28(dcodeRoot(), "plugins", "data");
|
|
20779
|
+
assertManagedPath4(dataRoot);
|
|
20780
|
+
return {
|
|
20781
|
+
adapterId: binding.adapterId,
|
|
20782
|
+
target: binding.target,
|
|
20783
|
+
scopeId: binding.scopeId,
|
|
20784
|
+
packageName: binding.packageName,
|
|
20785
|
+
nativeId: binding.nativeId,
|
|
20786
|
+
route: binding.route ?? (present ? "managed" : "none"),
|
|
20787
|
+
presence: present ? "present" : "absent",
|
|
20788
|
+
enablement: enabled ? "enabled" : "disabled",
|
|
20789
|
+
activation: enabled ? "active" : "inactive",
|
|
20790
|
+
transition: { requirement: present ? "restart" : "none", status: "effective" },
|
|
20791
|
+
installedFingerprint: present ? row.installedFingerprint : null,
|
|
20792
|
+
contentRoots: present ? row.contentRoots : [],
|
|
20793
|
+
retention: { pluginData: existsSync23(dataRoot) ? { state: "present", fingerprint: fingerprintTree(dataRoot) } : { state: "absent", fingerprint: null }, inactiveMetadata: { state: "absent", fingerprint: null } }
|
|
20794
|
+
};
|
|
20795
|
+
}
|
|
20796
|
+
function captureDcodeRollback(binding, attemptId, operationId) {
|
|
20797
|
+
const dir = join28(lifecycleDirectory(attemptId, operationId), "rollback");
|
|
20798
|
+
mkdirSync9(dir, { recursive: true });
|
|
20799
|
+
const registry = readRegistry3(dcodeRegistryFile());
|
|
20800
|
+
const enabled = boolObject(readEnablement(dcodeEnablementFile()).enabledPlugins, "enabledPlugins");
|
|
20801
|
+
const row = object3(registry.plugins, "registry plugins")[binding.nativeId];
|
|
20802
|
+
const state = { row: row ?? null, enabled: enabled[binding.nativeId] ?? null, registryExisted: existsSync23(dcodeRegistryFile()), enablementExisted: existsSync23(dcodeEnablementFile()) };
|
|
20803
|
+
writeFileSync9(join28(dir, "state.json"), JSON.stringify(state));
|
|
20804
|
+
for (const [index, item] of rowsFor(row).entries()) {
|
|
20805
|
+
const path = rowInstall(item, binding.nativeId);
|
|
20806
|
+
assertCachePath(path);
|
|
20807
|
+
assertNoSymlinks6(path);
|
|
20808
|
+
if (existsSync23(path))
|
|
20809
|
+
cpSync8(path, join28(dir, `content-${index}`), { recursive: true });
|
|
20810
|
+
}
|
|
20811
|
+
return dir;
|
|
20812
|
+
}
|
|
20813
|
+
async function lockPreparation(binding, attemptId, operationId, expectedObservationId) {
|
|
20814
|
+
await acquireNativeLock(attemptId, operationId);
|
|
20815
|
+
const observed = createTargetInventoryObservation("dcode", { target: binding.target, installations: observeDcodeTarget(binding.target) });
|
|
20816
|
+
if (observed.observationId !== expectedObservationId)
|
|
20817
|
+
throw new Error("dcode native inventory changed before locked preparation; refusing stale rollback authority");
|
|
20818
|
+
}
|
|
20819
|
+
async function captureOwnedPreparation(binding, attemptId, operationId, expectedObservationId, capture) {
|
|
20820
|
+
try {
|
|
20821
|
+
await lockPreparation(binding, attemptId, operationId, expectedObservationId);
|
|
20822
|
+
return capture();
|
|
20823
|
+
} catch (error) {
|
|
20824
|
+
try {
|
|
20825
|
+
await releaseNativeLock(attemptId, operationId);
|
|
20826
|
+
} catch (releaseError) {
|
|
20827
|
+
throw new Error(`${error instanceof Error ? error.message : String(error)}; dcode preparation lock release failed: ${releaseError instanceof Error ? releaseError.message : String(releaseError)}`);
|
|
20828
|
+
}
|
|
20829
|
+
throw error;
|
|
20830
|
+
}
|
|
20831
|
+
}
|
|
20832
|
+
function preflightAdoption(request) {
|
|
20833
|
+
if (request.operation !== "install" && request.operation !== "update")
|
|
20834
|
+
return;
|
|
20835
|
+
const snapshot = request.snapshot;
|
|
20836
|
+
const installed = request.targetObservation.installations.find((item) => item.nativeId === snapshot.nativeId);
|
|
20837
|
+
if (installed?.ownership.kind !== "unmanaged" || installed.presence !== "present")
|
|
20838
|
+
return;
|
|
20839
|
+
const path = installed.contentRoots[0]?.path;
|
|
20840
|
+
if (path === undefined)
|
|
20841
|
+
throw new Error("dcode unmanaged adoption has no native root");
|
|
20842
|
+
const manifest = declaredManifest(snapshot.packageRoot, snapshot.packageName);
|
|
20843
|
+
assessPrior(object3(readRegistry3(dcodeRegistryFile()).plugins, "registry plugins")[snapshot.nativeId], snapshot.nativeId, snapshot.nativeGit?.locator ?? `local:${snapshot.scopeId}`, true, snapshot.packageName, manifest.version, snapshot.packageRoot);
|
|
20844
|
+
if (fingerprintTree(path) !== installed.installedFingerprint)
|
|
20845
|
+
throw new Error("dcode unmanaged adoption changed during preflight");
|
|
20846
|
+
}
|
|
20847
|
+
function setDcodeRow(nativeId, row, enabled) {
|
|
20848
|
+
assertManagedPath4(dcodeRegistryFile());
|
|
20849
|
+
assertManagedPath4(dcodeEnablementFile());
|
|
20850
|
+
const registry = readRegistry3(dcodeRegistryFile()), enablement = readEnablement(dcodeEnablementFile());
|
|
20851
|
+
const plugins = { ...object3(registry.plugins, "registry plugins") }, flags = { ...boolObject(enablement.enabledPlugins, "enabledPlugins") };
|
|
20852
|
+
if (row === null)
|
|
20853
|
+
delete plugins[nativeId];
|
|
20854
|
+
else
|
|
20855
|
+
plugins[nativeId] = row;
|
|
20856
|
+
if (enabled === null)
|
|
20857
|
+
delete flags[nativeId];
|
|
20858
|
+
else
|
|
20859
|
+
flags[nativeId] = enabled;
|
|
20860
|
+
writeDoc2(dcodeRegistryFile(), { ...registry, plugins });
|
|
20861
|
+
writeDoc2(dcodeEnablementFile(), { ...enablement, enabledPlugins: flags });
|
|
20862
|
+
}
|
|
20863
|
+
var dcodeDefinition = {
|
|
20864
|
+
id: "dcode",
|
|
20865
|
+
evidenceProfiles: capabilityEvidenceProfiles.filter((profile) => profile.host === "dcode").flatMap((profile) => [profile, createCapabilityEvidenceProfile({ ...profile, operations: ["disable"], semantics: { ...profile.semantics, "reversible-disable": "supported" }, evidence: [...profile.evidence, "docs/evidence/dcode-managed-lifecycle-20261011.md"] })]),
|
|
20866
|
+
probeVersion: async () => probeLifecycleVersion(),
|
|
20867
|
+
observeTarget: async (target) => ({ target, installations: observeDcodeTarget(target) }),
|
|
20868
|
+
observeNativeMutationScope: async () => ({ kind: "unavailable" }),
|
|
20869
|
+
observeNativeProjection: async (request) => {
|
|
20870
|
+
preflightAdoption(request);
|
|
20871
|
+
return { kind: "requires-managed", reasonId: "dcode-frozen-projection-and-updater-isolation" };
|
|
20872
|
+
},
|
|
20873
|
+
revalidateTargetPrecondition: async (handle) => {
|
|
20874
|
+
await acquireNativeLock(handle.attemptId, handle.operationId);
|
|
20875
|
+
return { version: probeDcodeVersion(), targetObservationId: createTargetInventoryObservation("dcode", { target: handle.target, installations: observeDcodeTarget(handle.target) }).observationId };
|
|
20876
|
+
},
|
|
20877
|
+
stageActivation: async (request) => {
|
|
20878
|
+
const dir = lifecycleDirectory(request.snapshot.attemptId, request.snapshot.operationId);
|
|
20879
|
+
const stagingRoot = join28(dir, "stage");
|
|
20880
|
+
if (existsSync23(stagingRoot))
|
|
20881
|
+
throw new Error("dcode preparation stage already exists");
|
|
20882
|
+
mkdirSync9(stagingRoot, { recursive: true });
|
|
20883
|
+
const manifest = declaredManifest(request.snapshot.packageRoot, request.snapshot.packageName);
|
|
20884
|
+
try {
|
|
20885
|
+
stagePlugin5(request.snapshot.packageRoot, stagingRoot, request.snapshot.packageName, manifest.version);
|
|
20886
|
+
} catch (error) {
|
|
20887
|
+
rmSync9(dir, { recursive: true, force: true });
|
|
20888
|
+
throw error;
|
|
20889
|
+
}
|
|
20890
|
+
return { stagingRoot, stagingId: `${request.snapshot.attemptId}:${request.snapshot.operationId}` };
|
|
20891
|
+
},
|
|
20892
|
+
applyLifecycleDirectives: async (projection) => {
|
|
20893
|
+
forceAutoUpdateOff(projection.stagingRoot);
|
|
20894
|
+
const prior = observeDcodeTarget(projection.target).find((item) => item.nativeId === projection.nativeId);
|
|
20895
|
+
writeFileSync9(join28(projection.stagingRoot, MARKER7), JSON.stringify({ source: projection.sourceLocator ?? `local:${projection.scopeId}`, pluginId: projection.nativeId, fingerprint: projection.sourceRevision, sourceRevision: projection.sourceRevision, projectedFingerprint: projectionDigest(projection.stagingRoot), scopeId: projection.scopeId, sourceType: projection.sourceType, proof: prior?.ownership.kind === "unmanaged" ? "adopted" : "created" }));
|
|
20896
|
+
return ["dcode.managed-unversioned-registry"];
|
|
20897
|
+
},
|
|
20898
|
+
applyPins: async (projection) => {
|
|
20899
|
+
const found = new Set;
|
|
20900
|
+
for (const candidate of dcodeMcpCandidates()) {
|
|
20901
|
+
const file = join28(projection.stagingRoot, candidate.kind === "spec" ? candidate.file : candidate.manifest);
|
|
20902
|
+
if (!existsSync23(file))
|
|
20903
|
+
continue;
|
|
20904
|
+
const body = readDoc2(file, {}, "MCP document");
|
|
20905
|
+
if (typeof body.mcpServers !== "object" || body.mcpServers === null || Array.isArray(body.mcpServers))
|
|
20906
|
+
continue;
|
|
20907
|
+
let changed = false;
|
|
20908
|
+
for (const pin of projection.pins) {
|
|
20909
|
+
const server = body.mcpServers[pin.server];
|
|
20910
|
+
if (typeof server !== "object" || server === null || Array.isArray(server))
|
|
20911
|
+
continue;
|
|
20912
|
+
server.command = pin.executable;
|
|
20913
|
+
found.add(pin.server);
|
|
20914
|
+
changed = true;
|
|
20915
|
+
}
|
|
20916
|
+
if (changed)
|
|
20917
|
+
writeFileSync9(file, JSON.stringify(body, null, 2));
|
|
20918
|
+
}
|
|
20919
|
+
if (projection.pins.some((pin) => !found.has(pin.server)))
|
|
20920
|
+
throw new Error("dcode resolved pin is absent from staged MCP configuration");
|
|
20921
|
+
const marker = readDoc2(join28(projection.stagingRoot, MARKER7), {}, "ownership marker");
|
|
20922
|
+
marker.projectedFingerprint = projectionDigest(projection.stagingRoot);
|
|
20923
|
+
writeFileSync9(join28(projection.stagingRoot, MARKER7), JSON.stringify(marker));
|
|
20924
|
+
return [...found];
|
|
20925
|
+
},
|
|
20926
|
+
captureActivationPreparation: async (projection, fingerprint) => {
|
|
20927
|
+
await lockPreparation(projection, projection.attemptId, projection.operationId, projection.targetObservationId);
|
|
20928
|
+
const prior = dcodeLifecycleReadback(projection);
|
|
20929
|
+
const target = lifecycleSlot(projection.nativeId, fingerprint);
|
|
20930
|
+
assertCachePath(target);
|
|
20931
|
+
const installed = observeDcodeTarget(projection.target).find((item) => item.nativeId === projection.nativeId);
|
|
20932
|
+
if (installed?.ownership.kind === "owned" && installed.ownership.scopeId !== projection.scopeId)
|
|
20933
|
+
throw new Error("dcode scope ownership conflict");
|
|
20934
|
+
if (installed?.ownership.kind === "unmanaged") {
|
|
20935
|
+
const path = installed.contentRoots[0]?.path;
|
|
20936
|
+
if (path === undefined || !sameTree7(projection.snapshot.packageRoot, path))
|
|
20937
|
+
throw new Error("dcode legacy content differs; refusing adoption");
|
|
20938
|
+
const manifest = declaredManifest(path, projection.packageName);
|
|
20939
|
+
if (manifest.version !== projection.packageVersion)
|
|
20940
|
+
throw new Error("dcode legacy version differs; refusing adoption");
|
|
20941
|
+
}
|
|
20942
|
+
if (existsSync23(target) && ownership3(target)?.pluginId !== projection.nativeId)
|
|
20943
|
+
throw new Error("dcode lifecycle target is not owned");
|
|
20944
|
+
const rollbackReference = captureDcodeRollback(projection, projection.attemptId, projection.operationId);
|
|
20945
|
+
writeFileSync9(join28(rollbackReference, "next-path.json"), JSON.stringify({ target }));
|
|
20946
|
+
return { prior, expected: { ...prior, route: "managed", presence: "present", enablement: "enabled", activation: "active", transition: { requirement: "restart", status: "effective" }, installedFingerprint: fingerprint, contentRoots: [{ label: "managed", path: target, fingerprint }] }, rollbackReference, rollbackCoverageOperationIds: projection.affectedOperationIds };
|
|
20947
|
+
},
|
|
20948
|
+
captureDisablePreparation: async (request) => {
|
|
20949
|
+
const binding = { adapterId: "dcode", ...request.activation };
|
|
20950
|
+
return captureOwnedPreparation(binding, request.attemptId, request.operationId, request.selection.targetObservationId, () => ({ prior: dcodeLifecycleReadback(binding), rollbackReference: captureDcodeRollback(binding, request.attemptId, request.operationId), rollbackCoverageOperationIds: request.selection.affectedOperationIds, transition: { requirement: "restart", status: "effective" } }));
|
|
20951
|
+
},
|
|
20952
|
+
captureRetirementPreparation: async (request) => {
|
|
20953
|
+
const binding = { adapterId: "dcode", ...request.activation };
|
|
20954
|
+
return captureOwnedPreparation(binding, request.attemptId, request.operationId, request.selection.targetObservationId, () => ({ prior: dcodeLifecycleReadback(binding), rollbackReference: captureDcodeRollback(binding, request.attemptId, request.operationId), rollbackCoverageOperationIds: request.selection.affectedOperationIds, transition: { requirement: "none", status: "effective" } }));
|
|
20955
|
+
},
|
|
20956
|
+
apply: async (prepared) => {
|
|
20957
|
+
await acquireNativeLock(prepared.handle.attemptId, prepared.handle.operationId);
|
|
20958
|
+
const target = lifecycleSlot(prepared.handle.nativeId, prepared.handle.projectedFingerprint);
|
|
20959
|
+
assertCachePath(target);
|
|
20960
|
+
mkdirSync9(dirname11(target), { recursive: true });
|
|
20961
|
+
if (existsSync23(target)) {
|
|
20962
|
+
const marker = ownership3(target);
|
|
20963
|
+
if (marker?.pluginId !== prepared.handle.nativeId)
|
|
20964
|
+
throw new Error("dcode lifecycle activation would overwrite foreign content");
|
|
20965
|
+
if (fingerprintTree(target) !== prepared.handle.projectedFingerprint)
|
|
20966
|
+
throw new Error("dcode immutable projection slot has diverged");
|
|
20967
|
+
} else {
|
|
20968
|
+
renameSync8(prepared.stagingRoot, target);
|
|
20969
|
+
}
|
|
20970
|
+
setDcodeRow(prepared.handle.nativeId, [{ installPath: target }], true);
|
|
20971
|
+
return { receiptId: `dcode-apply:${prepared.handle.operationId}`, changed: true };
|
|
20972
|
+
},
|
|
20973
|
+
disable: async (prepared) => {
|
|
20974
|
+
await acquireNativeLock(prepared.handle.attemptId, prepared.handle.operationId);
|
|
20975
|
+
const row = object3(readRegistry3(dcodeRegistryFile()).plugins, "registry plugins")[prepared.handle.nativeId];
|
|
20976
|
+
setDcodeRow(prepared.handle.nativeId, row ?? null, false);
|
|
20977
|
+
return { receiptId: `dcode-disable:${prepared.handle.operationId}`, changed: true };
|
|
20978
|
+
},
|
|
20979
|
+
retire: async (prepared) => {
|
|
20980
|
+
await acquireNativeLock(prepared.handle.attemptId, prepared.handle.operationId);
|
|
20981
|
+
const rows = rowsFor(object3(readRegistry3(dcodeRegistryFile()).plugins, "registry plugins")[prepared.handle.nativeId]);
|
|
20982
|
+
for (const row of rows) {
|
|
20983
|
+
const path = rowInstall(row, prepared.handle.nativeId);
|
|
20984
|
+
assertCachePath(path);
|
|
20985
|
+
if (ownership3(path)?.pluginId !== prepared.handle.nativeId)
|
|
20986
|
+
throw new Error("dcode retirement has no ownership proof");
|
|
20987
|
+
}
|
|
20988
|
+
setDcodeRow(prepared.handle.nativeId, null, null);
|
|
20989
|
+
for (const row of rows)
|
|
20990
|
+
rmSync9(rowInstall(row, prepared.handle.nativeId), { recursive: true, force: true });
|
|
20991
|
+
return { receiptId: `dcode-retire:${prepared.handle.operationId}`, changed: true };
|
|
20992
|
+
},
|
|
20993
|
+
readback: async (handle) => {
|
|
20994
|
+
const held = nativeLocks.get(`${handle.attemptId}:${handle.operationId}`);
|
|
20995
|
+
if (held !== undefined && !held.isAlive())
|
|
20996
|
+
throw new Error("dcode native lock was lost before readback");
|
|
20997
|
+
return dcodeLifecycleReadback(handle);
|
|
20998
|
+
},
|
|
20999
|
+
rollback: async (handle) => {
|
|
21000
|
+
await acquireNativeLock(handle.attemptId, handle.operationId);
|
|
21001
|
+
const target = handle.projectedFingerprint === null ? undefined : lifecycleSlot(handle.nativeId, handle.projectedFingerprint);
|
|
21002
|
+
if (target !== undefined)
|
|
21003
|
+
assertCachePath(target);
|
|
21004
|
+
if (target !== undefined && existsSync23(target) && !handle.prior.contentRoots.some((root) => resolve17(root.path) === resolve17(target))) {
|
|
21005
|
+
if (ownership3(target)?.pluginId !== handle.nativeId)
|
|
21006
|
+
throw new Error("dcode rollback target is not owned");
|
|
21007
|
+
rmSync9(target, { recursive: true });
|
|
21008
|
+
}
|
|
21009
|
+
const state = readDoc2(join28(handle.rollbackReference, "state.json"), {}, "rollback state");
|
|
21010
|
+
for (const [index, row] of rowsFor(state.row).entries()) {
|
|
21011
|
+
const path = rowInstall(row, handle.nativeId);
|
|
21012
|
+
assertCachePath(path);
|
|
21013
|
+
const backup = join28(handle.rollbackReference, `content-${index}`);
|
|
21014
|
+
if (existsSync23(backup)) {
|
|
21015
|
+
mkdirSync9(dirname11(path), { recursive: true });
|
|
21016
|
+
cpSync8(backup, path, { recursive: true });
|
|
21017
|
+
}
|
|
21018
|
+
}
|
|
21019
|
+
setDcodeRow(handle.nativeId, state.row ?? null, typeof state.enabled === "boolean" ? state.enabled : null);
|
|
21020
|
+
if (state.registryExisted === false && Object.keys(object3(readRegistry3(dcodeRegistryFile()).plugins, "registry plugins")).length === 0)
|
|
21021
|
+
rmSync9(dcodeRegistryFile());
|
|
21022
|
+
if (state.enablementExisted === false && Object.keys(boolObject(readEnablement(dcodeEnablementFile()).enabledPlugins, "enabledPlugins")).length === 0)
|
|
21023
|
+
rmSync9(dcodeEnablementFile());
|
|
21024
|
+
return { receiptId: `dcode-rollback:${handle.operationId}`, changed: true };
|
|
21025
|
+
},
|
|
21026
|
+
releaseRecovery: async (handle) => {
|
|
21027
|
+
await releaseNativeLock(handle.attemptId, handle.operationId);
|
|
21028
|
+
},
|
|
21029
|
+
cleanup: async (reference, disposition) => {
|
|
21030
|
+
try {
|
|
21031
|
+
const dir = lifecycleDirectory(reference.attemptId, reference.operationId);
|
|
21032
|
+
const next = readDoc2(join28(dir, "rollback", "next-path.json"), {}, "cleanup target");
|
|
21033
|
+
if (disposition === "verified-commit" && typeof next.target === "string") {
|
|
21034
|
+
const prior = readDoc2(join28(dir, "rollback", "state.json"), {}, "rollback state");
|
|
21035
|
+
for (const row of rowsFor(prior.row)) {
|
|
21036
|
+
const path = rowInstall(row, reference.operationId);
|
|
21037
|
+
assertCachePath(path);
|
|
21038
|
+
if (resolve17(path) !== resolve17(next.target))
|
|
21039
|
+
rmSync9(path, { recursive: true, force: true });
|
|
21040
|
+
}
|
|
21041
|
+
}
|
|
21042
|
+
rmSync9(dir, { recursive: true, force: true });
|
|
21043
|
+
} finally {
|
|
21044
|
+
await releaseNativeLock(reference.attemptId, reference.operationId);
|
|
21045
|
+
}
|
|
21046
|
+
return { cleanupId: `dcode-cleanup:${reference.operationId}`, completed: true };
|
|
21047
|
+
}
|
|
21048
|
+
};
|
|
21049
|
+
var dcodeLifecycle = createLifecycleHostAdapter(dcodeDefinition);
|
|
20604
21050
|
var dcodeWriter = {
|
|
21051
|
+
lifecyclePinAdapter: dcodeLifecycle,
|
|
20605
21052
|
...dcode,
|
|
20606
21053
|
supportsAdoption: true,
|
|
20607
21054
|
plannedNativeId: (plugin) => `${plugin.name}@${plugin.marketplace || "local"}`,
|
|
@@ -20664,7 +21111,7 @@ var dcodeWriter = {
|
|
|
20664
21111
|
throw new Error(`dcode cache target is unowned; refusing to replace it: ${target}`);
|
|
20665
21112
|
const former = prior.kind === "none" ? undefined : prior.path;
|
|
20666
21113
|
const unchanged = (former === undefined || resolve17(former) === resolve17(target)) && slot?.kind === "current" && slot.fingerprint === sourceFingerprint && slot.projectedFingerprint === projected && slot.sourceRevision === resolved.sha && sameTree7(stage, target);
|
|
20667
|
-
const nextRegistry = { ...registry, plugins: { ...plugins, [id]: [{ installPath: target
|
|
21114
|
+
const nextRegistry = { ...registry, plugins: { ...plugins, [id]: [{ installPath: target }] } };
|
|
20668
21115
|
const nextEnablement = { ...enablement, enabledPlugins: { ...enabled, [id]: true } };
|
|
20669
21116
|
if (opts?.dryRun) {
|
|
20670
21117
|
console.log(`[dcode] would activate directory: ${target}`);
|
|
@@ -20715,6 +21162,8 @@ var dcodeWriter = {
|
|
|
20715
21162
|
assertCachePath(plugin.path);
|
|
20716
21163
|
if (ownership3(plugin.path)?.pluginId !== plugin.id)
|
|
20717
21164
|
return { changes: [], refusals: [] };
|
|
21165
|
+
if (opts?.dryRun !== true)
|
|
21166
|
+
throw new Error("dcode pin requires the durable lifecycle pin workflow; direct in-place pinning is refused");
|
|
20718
21167
|
return pinPluginMcpFiles(plugin.path, dcodeMcpCandidates(), opts);
|
|
20719
21168
|
},
|
|
20720
21169
|
async remove(id) {
|
|
@@ -20864,7 +21313,9 @@ function assertReadback(id, registryFile, enablementFile, target, version, proje
|
|
|
20864
21313
|
const install = rowInstall(rows[0], id);
|
|
20865
21314
|
if (resolve17(install) !== resolve17(target))
|
|
20866
21315
|
throw new Error(`dcode readback path mismatch for ${id}`);
|
|
20867
|
-
if (rows[0].version !== version)
|
|
21316
|
+
if (rows[0].version !== undefined && rows[0].version !== null)
|
|
21317
|
+
throw new Error(`dcode managed install is eligible for native auto-update: ${id}`);
|
|
21318
|
+
if (declaredManifest(target, id.split("@")[0]).version !== version)
|
|
20868
21319
|
throw new Error(`dcode readback version mismatch for ${id}`);
|
|
20869
21320
|
if (boolObject(object3(enablement.enabledPlugins, "enabledPlugins"), "enabledPlugins")[id] !== true)
|
|
20870
21321
|
throw new Error(`dcode readback enablement mismatch for ${id}`);
|
|
@@ -25034,7 +25485,22 @@ async function planLifecycle(input) {
|
|
|
25034
25485
|
const result = await prepareEntry(entry, input.hosts, loaded.state, command, input.transportSource, transportCache);
|
|
25035
25486
|
if (result.kind === "defect")
|
|
25036
25487
|
return zeroWrite(command, input.dryRun, result.reason, result.terminalPhase);
|
|
25037
|
-
|
|
25488
|
+
if (input.removalSelection !== undefined) {
|
|
25489
|
+
if (command !== "remove" || result.kind !== "retire-source") {
|
|
25490
|
+
return zeroWrite(command, input.dryRun, createLifecycleReason("internal", "internal.invariant", "package retirement selection is valid only for manual removal"));
|
|
25491
|
+
}
|
|
25492
|
+
const selected = input.removalSelection.filter((row) => row.scopeId === result.scope.id);
|
|
25493
|
+
if (selected.length === 0 || selected.some((row) => !loaded.state.activations.some((activation) => activation.scopeId === row.scopeId && activation.packageId === row.packageId && activation.nativeId === row.nativeId))) {
|
|
25494
|
+
return zeroWrite(command, input.dryRun, createLifecycleReason("internal", "internal.invariant", "manual removal selection no longer matches recorded ownership"));
|
|
25495
|
+
}
|
|
25496
|
+
const retirementPackages = selected.map(({ packageId, nativeId }) => ({ packageId, nativeId })).sort((left, right) => left.packageId.localeCompare(right.packageId) || left.nativeId.localeCompare(right.nativeId));
|
|
25497
|
+
prepared.push({
|
|
25498
|
+
...result,
|
|
25499
|
+
retirementPackages,
|
|
25500
|
+
identity: ["remove-packages", result.scope.id, ...retirementPackages.flatMap((row) => [row.packageId, row.nativeId])]
|
|
25501
|
+
});
|
|
25502
|
+
} else
|
|
25503
|
+
prepared.push(result);
|
|
25038
25504
|
}
|
|
25039
25505
|
const attemptId = lifecycleAttemptId(loaded.state.stateGeneration, prepared.map((item) => item.identity));
|
|
25040
25506
|
const scopes = [];
|
|
@@ -25080,6 +25546,10 @@ async function prepareSync(entry, hosts, state, command, transportSource, transp
|
|
|
25080
25546
|
throw error;
|
|
25081
25547
|
}
|
|
25082
25548
|
const scope = deploymentScopeForSyncManifestEntry(entry);
|
|
25549
|
+
const recordedScope = state.scopes.find((row) => row.id === scope.id);
|
|
25550
|
+
if (recordedScope?.target.context !== undefined && JSON.stringify(canonicalTargetContext(recordedScope.target.context)) !== JSON.stringify(entry.target.context === undefined ? undefined : canonicalTargetContext(entry.target.context))) {
|
|
25551
|
+
return defect(createLifecycleReason("internal", "internal.invariant", `target context changed for recorded scope '${scope.id}'; use a distinct target instance or retire the recorded scope explicitly`));
|
|
25552
|
+
}
|
|
25083
25553
|
const pending = pendingDefect(state, scope.id, new Set(selected.map((item) => item.plugin.name)), command);
|
|
25084
25554
|
if (pending !== null)
|
|
25085
25555
|
return defect(pending);
|
|
@@ -25229,6 +25699,7 @@ async function planSync(item, attemptId, validatedAt, state, command) {
|
|
|
25229
25699
|
kind: "planned",
|
|
25230
25700
|
scope: {
|
|
25231
25701
|
scope: item.scope,
|
|
25702
|
+
target: item.observation?.target ?? item.entry.target,
|
|
25232
25703
|
selectorMode: item.entry.selectors === undefined ? "all" : "explicit",
|
|
25233
25704
|
desired: desiredGeneration(existing, item.frozen.snapshot.revision, item.frozen.snapshot.fingerprint, packages, validatedAt),
|
|
25234
25705
|
prune: blocks || retirements.operations.some((row) => row.operation.action !== "retire-orphan") ? "blocked" : "planned"
|
|
@@ -25308,7 +25779,7 @@ async function planOmissions(item, attemptId, state, desired) {
|
|
|
25308
25779
|
return { kind: "omissions", operations };
|
|
25309
25780
|
}
|
|
25310
25781
|
async function planRetire(item, attemptId, state) {
|
|
25311
|
-
const activations = state.activations.filter((activation) => activation.scopeId === item.recorded.id).sort((left, right) => left.packageId < right.packageId ? -1 : left.packageId > right.packageId ? 1 : 0);
|
|
25782
|
+
const activations = state.activations.filter((activation) => activation.scopeId === item.recorded.id && (item.retirementPackages === undefined || item.retirementPackages.some((row) => row.packageId === activation.packageId && row.nativeId === activation.nativeId))).sort((left, right) => left.packageId < right.packageId ? -1 : left.packageId > right.packageId ? 1 : 0);
|
|
25312
25783
|
const operations = [];
|
|
25313
25784
|
for (const activation of activations) {
|
|
25314
25785
|
const installation = item.observation?.installations.find((row) => row.nativeId === activation.nativeId);
|
|
@@ -25328,8 +25799,10 @@ async function planRetire(item, attemptId, state) {
|
|
|
25328
25799
|
kind: "planned",
|
|
25329
25800
|
scope: {
|
|
25330
25801
|
scope: item.scope,
|
|
25802
|
+
target: item.observation?.target ?? item.recorded.target,
|
|
25331
25803
|
selectorMode: "retired",
|
|
25332
25804
|
desired: null,
|
|
25805
|
+
...item.retirementPackages === undefined ? {} : { retirementPackages: item.retirementPackages },
|
|
25333
25806
|
prune: operations.length > 0 && operations.every((row) => row.operation.action === "retire-orphan") ? "planned" : "blocked"
|
|
25334
25807
|
},
|
|
25335
25808
|
operations
|
|
@@ -25830,7 +26303,7 @@ function lifecycleAttemptId(stateGeneration, identities) {
|
|
|
25830
26303
|
return `attempt-v1-${digest3([String(stateGeneration), ...identities.flat()])}`;
|
|
25831
26304
|
}
|
|
25832
26305
|
function lifecycleAttemptIdForPlannedScopes(stateGeneration, scopes) {
|
|
25833
|
-
return lifecycleAttemptId(stateGeneration, scopes.map((planned) => plannedAttemptIdentity(planned.scope.id, planned.desired?.sourceFingerprint, planned.desired?.packages.map((pkg) => pkg.packageId), planned.selectorMode === "retired" || planned.desired === null)));
|
|
26306
|
+
return lifecycleAttemptId(stateGeneration, scopes.map((planned) => planned.retirementPackages !== undefined ? ["remove-packages", planned.scope.id, ...planned.retirementPackages.flatMap((row) => [row.packageId, row.nativeId])] : plannedAttemptIdentity(planned.scope.id, planned.desired?.sourceFingerprint, planned.desired?.packages.map((pkg) => pkg.packageId), planned.selectorMode === "retired" || planned.desired === null)));
|
|
25834
26307
|
}
|
|
25835
26308
|
function plannedAttemptIdentity(scopeId, sourceFingerprint, packageIds, retired = false) {
|
|
25836
26309
|
if (retired || sourceFingerprint === undefined || packageIds === undefined)
|
|
@@ -26093,8 +26566,9 @@ async function runOperation(plan, operation, hosts, ledger) {
|
|
|
26093
26566
|
return succeeded(operation, false);
|
|
26094
26567
|
case "retire-orphan":
|
|
26095
26568
|
return runRetire(plan, operation, hosts, ledger);
|
|
26096
|
-
case "route-migrate":
|
|
26097
26569
|
case "disable-nonconforming":
|
|
26570
|
+
return runDisable(plan, operation, hosts, ledger);
|
|
26571
|
+
case "route-migrate":
|
|
26098
26572
|
case "retain-prior":
|
|
26099
26573
|
case "not-attempted":
|
|
26100
26574
|
return stop(operation, createLifecycleReason("internal", "internal.invariant", `operation '${operation.operationId}' is not applied by this execution slice`));
|
|
@@ -26157,6 +26631,12 @@ async function runActivation(plan, operation, hosts, ledger, action) {
|
|
|
26157
26631
|
verified = host.adapter.verify(receipt.handle, observation);
|
|
26158
26632
|
} catch (error) {
|
|
26159
26633
|
const reason = thrownReason(error);
|
|
26634
|
+
if (receipt === undefined && ledger.journalState(plan.attemptId, operation.operationId) === "applying" && error instanceof LifecycleHostPhaseError && !error.mutationStarted) {
|
|
26635
|
+
ledger.markNotApplied(plan, operation);
|
|
26636
|
+
if (preparation !== undefined)
|
|
26637
|
+
await abortPreparation(host, preparation);
|
|
26638
|
+
return stop(operation, reason);
|
|
26639
|
+
}
|
|
26160
26640
|
if (handle !== undefined && ledger.journalState(plan.attemptId, operation.operationId) === "applying") {
|
|
26161
26641
|
return recoverApplied(plan, operation, host, ledger, handle, reason);
|
|
26162
26642
|
}
|
|
@@ -26230,7 +26710,7 @@ async function prepareActivation(plan, operation, host, nativeId, action, record
|
|
|
26230
26710
|
if (plugin === undefined || packageFingerprint === undefined) {
|
|
26231
26711
|
return refused(createLifecycleReason("internal", "internal.invariant", `${action} '${operation.package}' is missing from the frozen source`));
|
|
26232
26712
|
}
|
|
26233
|
-
const target = lifecycleTarget2(operation);
|
|
26713
|
+
const target = lifecycleTarget2(plan, operation);
|
|
26234
26714
|
const observation = await host.adapter.observeTarget(target);
|
|
26235
26715
|
const version = await host.adapter.probeVersion(observation.target);
|
|
26236
26716
|
if (version.kind !== "detected") {
|
|
@@ -26314,6 +26794,50 @@ function sealActivationSnapshot(operation, attemptId, nativeId, frozen, plugin,
|
|
|
26314
26794
|
throw new Error(`frozen snapshot action '${snapshot.action}' is not ${action}`);
|
|
26315
26795
|
return snapshot;
|
|
26316
26796
|
}
|
|
26797
|
+
async function runDisable(plan, operation, hosts, ledger) {
|
|
26798
|
+
const host = hosts.find((candidate) => candidate.kinds.includes(operation.scope.target.kind));
|
|
26799
|
+
const reason = plan.report.outcomes.find((row) => row.operationId === operation.operationId)?.reason;
|
|
26800
|
+
if (host === undefined || operation.nativeId === null || reason === undefined || reason === null) {
|
|
26801
|
+
return stop(operation, createLifecycleReason("internal", "internal.invariant", "disable containment lost its adapter, identity or desired failure reason"));
|
|
26802
|
+
}
|
|
26803
|
+
let preparation;
|
|
26804
|
+
let receipt;
|
|
26805
|
+
try {
|
|
26806
|
+
const prepared = await prepareOwnedMutation(plan, operation, host, operation.nativeId, ledger, "disable");
|
|
26807
|
+
if (prepared.kind === "refused")
|
|
26808
|
+
return stop(operation, prepared.reason);
|
|
26809
|
+
if (prepared.selection.operation !== "disable")
|
|
26810
|
+
throw new Error("disable containment selected the wrong operation");
|
|
26811
|
+
ledger.acceptJournal(plan, operation, "disable-nonconforming");
|
|
26812
|
+
preparation = await host.adapter.prepareDisable({ operationId: operation.operationId, attemptId: plan.attemptId, selection: { ...prepared.selection, operation: "disable" }, activation: prepared.activation });
|
|
26813
|
+
ledger.markApplying(plan, operation);
|
|
26814
|
+
receipt = await host.adapter.disable(preparation);
|
|
26815
|
+
const observation = await host.adapter.readback(receipt.handle);
|
|
26816
|
+
const verified = host.adapter.verify(receipt.handle, observation);
|
|
26817
|
+
ledger.confirmDisable(plan, operation);
|
|
26818
|
+
try {
|
|
26819
|
+
await host.adapter.cleanup(verified.handle, "verified-commit");
|
|
26820
|
+
} catch {
|
|
26821
|
+
ledger.markCleanupPending(plan, operation, "disable-nonconforming");
|
|
26822
|
+
return pendingCleanup(operation);
|
|
26823
|
+
}
|
|
26824
|
+
ledger.completeContainment(plan, operation);
|
|
26825
|
+
return { stop: true, reason, outcome: { ...operation, result: "failed", resourceState: "retained", activationState: "inactive", changed: receipt.changed, reason } };
|
|
26826
|
+
} catch (error) {
|
|
26827
|
+
const failure = thrownReason(error);
|
|
26828
|
+
if (receipt === undefined && error instanceof LifecycleHostPhaseError && !error.mutationStarted) {
|
|
26829
|
+
if (ledger.journalState(plan.attemptId, operation.operationId) !== undefined)
|
|
26830
|
+
ledger.markNotApplied(plan, operation);
|
|
26831
|
+
if (preparation !== undefined)
|
|
26832
|
+
await abortPreparation(host, preparation);
|
|
26833
|
+
return stop(operation, failure);
|
|
26834
|
+
}
|
|
26835
|
+
if (preparation !== undefined && (receipt !== undefined || ledger.journalState(plan.attemptId, operation.operationId) === "applying")) {
|
|
26836
|
+
return recoverApplied(plan, operation, host, ledger, preparation.handle, failure);
|
|
26837
|
+
}
|
|
26838
|
+
return stop(operation, failure);
|
|
26839
|
+
}
|
|
26840
|
+
}
|
|
26317
26841
|
async function runRetire(plan, operation, hosts, ledger) {
|
|
26318
26842
|
if (ledger.journalState(plan.attemptId, operation.operationId) === "completed")
|
|
26319
26843
|
return retired(operation, false);
|
|
@@ -26331,17 +26855,20 @@ async function runRetire(plan, operation, hosts, ledger) {
|
|
|
26331
26855
|
}
|
|
26332
26856
|
let prepared;
|
|
26333
26857
|
try {
|
|
26334
|
-
prepared = await
|
|
26858
|
+
prepared = await prepareOwnedMutation(plan, operation, host, nativeId, ledger);
|
|
26335
26859
|
} catch (error) {
|
|
26336
26860
|
return stop(operation, thrownReason(error));
|
|
26337
26861
|
}
|
|
26338
26862
|
if (prepared.kind === "refused")
|
|
26339
26863
|
return stop(operation, prepared.reason);
|
|
26864
|
+
if (prepared.selection.operation !== "retire")
|
|
26865
|
+
return stop(operation, createLifecycleReason("internal", "internal.invariant", "retirement selected the wrong operation"));
|
|
26340
26866
|
try {
|
|
26341
26867
|
ledger.acceptJournal(plan, operation, "retire-orphan");
|
|
26342
26868
|
} catch (error) {
|
|
26343
26869
|
return stop(operation, thrownReason(error));
|
|
26344
26870
|
}
|
|
26871
|
+
let preparation;
|
|
26345
26872
|
let receipt;
|
|
26346
26873
|
let verified;
|
|
26347
26874
|
try {
|
|
@@ -26349,17 +26876,27 @@ async function runRetire(plan, operation, hosts, ledger) {
|
|
|
26349
26876
|
operationId: operation.operationId,
|
|
26350
26877
|
attemptId: plan.attemptId,
|
|
26351
26878
|
action: "retire-orphan",
|
|
26352
|
-
selection: prepared.selection,
|
|
26879
|
+
selection: { ...prepared.selection, operation: "retire" },
|
|
26353
26880
|
activation: prepared.activation
|
|
26354
26881
|
});
|
|
26882
|
+
preparation = sealed;
|
|
26355
26883
|
ledger.markPruning(plan, operation);
|
|
26356
26884
|
receipt = await host.adapter.retire(sealed);
|
|
26357
26885
|
const observation = await host.adapter.readback(receipt.handle);
|
|
26358
26886
|
verified = host.adapter.verify(receipt.handle, observation);
|
|
26359
26887
|
} catch (error) {
|
|
26360
26888
|
const reason = thrownReason(error);
|
|
26889
|
+
if (receipt === undefined && ledger.journalState(plan.attemptId, operation.operationId) === "applying" && error instanceof LifecycleHostPhaseError && !error.mutationStarted) {
|
|
26890
|
+
ledger.markNotApplied(plan, operation);
|
|
26891
|
+
if (preparation !== undefined)
|
|
26892
|
+
await abortPreparation(host, preparation);
|
|
26893
|
+
return stop(operation, reason);
|
|
26894
|
+
}
|
|
26361
26895
|
if (receipt !== undefined)
|
|
26362
26896
|
return recoverApplied(plan, operation, host, ledger, receipt.handle, reason);
|
|
26897
|
+
if (preparation !== undefined && ledger.journalState(plan.attemptId, operation.operationId) === "applying") {
|
|
26898
|
+
return recoverApplied(plan, operation, host, ledger, preparation.handle, reason);
|
|
26899
|
+
}
|
|
26363
26900
|
return stop(operation, reason);
|
|
26364
26901
|
}
|
|
26365
26902
|
if (receipt === undefined || verified === undefined) {
|
|
@@ -26379,12 +26916,13 @@ async function runRetire(plan, operation, hosts, ledger) {
|
|
|
26379
26916
|
ledger.markCompleted(plan, operation);
|
|
26380
26917
|
return retired(operation, receipt.changed);
|
|
26381
26918
|
}
|
|
26382
|
-
async function
|
|
26919
|
+
async function prepareOwnedMutation(plan, operation, host, nativeId, ledger, capabilityOperation = "retire") {
|
|
26920
|
+
const operationLabel = capabilityOperation === "disable" ? "disablement" : "retirement";
|
|
26383
26921
|
const recorded = ledger.activation(operation.scope.id, operation.package, nativeId);
|
|
26384
26922
|
if (recorded === undefined || recorded.route.kind === "legacy-unverified" || recorded.ownership.kind === "legacy-claim" || recorded.sourceRevision === undefined) {
|
|
26385
26923
|
return refused(createLifecycleReason("internal", "internal.invariant", `ownership of '${operation.package}' was not revalidated`));
|
|
26386
26924
|
}
|
|
26387
|
-
const target = lifecycleTarget2(operation);
|
|
26925
|
+
const target = lifecycleTarget2(plan, operation);
|
|
26388
26926
|
const observation = await host.adapter.observeTarget(target);
|
|
26389
26927
|
const installation = observation.installations.find((row) => row.nativeId === nativeId);
|
|
26390
26928
|
if (installation === undefined || installation.presence !== "present" || installation.ownership.kind !== "owned" || installation.ownership.scopeId !== operation.scope.id) {
|
|
@@ -26392,10 +26930,10 @@ async function prepareRetirement(plan, operation, host, nativeId, ledger) {
|
|
|
26392
26930
|
}
|
|
26393
26931
|
const version = await host.adapter.probeVersion(observation.target);
|
|
26394
26932
|
if (version.kind !== "detected") {
|
|
26395
|
-
return refused(createLifecycleReason("runtime", "runtime.operation-failed",
|
|
26933
|
+
return refused(createLifecycleReason("runtime", "runtime.operation-failed", `${operationLabel} '${operation.package}' lost its detected target version`));
|
|
26396
26934
|
}
|
|
26397
26935
|
if (recorded.fingerprints.installed !== installation.installedFingerprint) {
|
|
26398
|
-
return refused(createLifecycleReason("internal", "internal.invariant",
|
|
26936
|
+
return refused(createLifecycleReason("internal", "internal.invariant", `${operationLabel} '${operation.package}' fingerprint does not match the owned install`));
|
|
26399
26937
|
}
|
|
26400
26938
|
const owned = ownedActivation(operation.scope, operation.scope.source, recorded, installation, observation.target);
|
|
26401
26939
|
if (owned === null) {
|
|
@@ -26404,27 +26942,27 @@ async function prepareRetirement(plan, operation, host, nativeId, ledger) {
|
|
|
26404
26942
|
const planCoverage = createLifecyclePlanCoverage(observation, [{
|
|
26405
26943
|
nativeId,
|
|
26406
26944
|
operationId: operation.operationId,
|
|
26407
|
-
operation:
|
|
26945
|
+
operation: capabilityOperation,
|
|
26408
26946
|
mutationGroupId: operation.operationId,
|
|
26409
26947
|
authorization: "observed-owned"
|
|
26410
26948
|
}]);
|
|
26411
26949
|
const nativeScope = await host.adapter.observeNativeMutationScope({
|
|
26412
26950
|
targetObservation: observation,
|
|
26413
|
-
operation:
|
|
26951
|
+
operation: capabilityOperation,
|
|
26414
26952
|
packageName: owned.packageName,
|
|
26415
26953
|
nativeId,
|
|
26416
26954
|
sourceType: owned.sourceType
|
|
26417
26955
|
});
|
|
26418
26956
|
const nativeProjection = await host.adapter.observeNativeProjection({
|
|
26419
26957
|
targetObservation: observation,
|
|
26420
|
-
operation:
|
|
26958
|
+
operation: capabilityOperation,
|
|
26421
26959
|
operationId: operation.operationId,
|
|
26422
26960
|
attemptId: plan.attemptId,
|
|
26423
26961
|
activation: owned
|
|
26424
26962
|
});
|
|
26425
26963
|
const decision = host.adapter.decideRoute({
|
|
26426
26964
|
target: observation.target,
|
|
26427
|
-
operation:
|
|
26965
|
+
operation: capabilityOperation,
|
|
26428
26966
|
operationId: operation.operationId,
|
|
26429
26967
|
attemptId: plan.attemptId,
|
|
26430
26968
|
scopeId: operation.scope.id,
|
|
@@ -26438,13 +26976,13 @@ async function prepareRetirement(plan, operation, host, nativeId, ledger) {
|
|
|
26438
26976
|
planCoverage,
|
|
26439
26977
|
activation: owned
|
|
26440
26978
|
});
|
|
26441
|
-
if (decision.kind !== "selected" || decision.operation !==
|
|
26442
|
-
return refused(createLifecycleReason("runtime", "runtime.operation-failed",
|
|
26979
|
+
if (decision.kind !== "selected" || decision.operation !== capabilityOperation || decision.route !== operation.route) {
|
|
26980
|
+
return refused(createLifecycleReason("runtime", "runtime.operation-failed", `${operationLabel} '${operation.package}' kept frozen route '${operation.route}'`));
|
|
26443
26981
|
}
|
|
26444
26982
|
return { kind: "ready", selection: decision, activation: owned, recorded };
|
|
26445
26983
|
}
|
|
26446
|
-
function lifecycleTarget2(operation) {
|
|
26447
|
-
return { kind: operation.scope.target.kind, instance: operation.scope.target.instance };
|
|
26984
|
+
function lifecycleTarget2(plan, operation) {
|
|
26985
|
+
return plan.scopes.find((row) => row.scope.id === operation.scope.id)?.target ?? { kind: operation.scope.target.kind, instance: operation.scope.target.instance };
|
|
26448
26986
|
}
|
|
26449
26987
|
|
|
26450
26988
|
class Ledger {
|
|
@@ -26505,8 +27043,18 @@ class Ledger {
|
|
|
26505
27043
|
return this.state.activations.find((row) => row.scopeId === scopeId && row.packageId === packageId && row.nativeId === nativeId);
|
|
26506
27044
|
}
|
|
26507
27045
|
markApplying(plan, operation) {
|
|
27046
|
+
if (operation.action === "disable-nonconforming")
|
|
27047
|
+
this.disablePending(plan, operation, "applying");
|
|
26508
27048
|
this.replaceAttempt(plan, (attempt) => this.journaled(attempt, operation.operationId, "applying", "applying", true));
|
|
26509
27049
|
}
|
|
27050
|
+
markNotApplied(plan, operation) {
|
|
27051
|
+
if (operation.action === "disable-nonconforming")
|
|
27052
|
+
this.clearDisablePending(operation);
|
|
27053
|
+
this.replaceAttempt(plan, (attempt) => {
|
|
27054
|
+
const next = this.journaled(attempt, operation.operationId, "not-attempted", "failed", false);
|
|
27055
|
+
return { ...next, mutationStarted: next.journal.some((row) => mutationBegan(row.state)) };
|
|
27056
|
+
});
|
|
27057
|
+
}
|
|
26510
27058
|
markPruning(plan, operation) {
|
|
26511
27059
|
this.replaceAttempt(plan, (attempt) => this.journaled(attempt, operation.operationId, "applying", "pruning", true));
|
|
26512
27060
|
}
|
|
@@ -26570,13 +27118,36 @@ class Ledger {
|
|
|
26570
27118
|
}
|
|
26571
27119
|
markRolledBack(plan, operation) {
|
|
26572
27120
|
this.adoptMovedGeneration();
|
|
27121
|
+
if (operation.action === "disable-nonconforming")
|
|
27122
|
+
this.clearDisablePending(operation, true);
|
|
26573
27123
|
this.replaceAttempt(plan, (attempt) => this.journaled(attempt, operation.operationId, "rolled-back", "failed", true));
|
|
26574
27124
|
}
|
|
27125
|
+
confirmDisable(plan, operation) {
|
|
27126
|
+
this.clearDisablePending(operation);
|
|
27127
|
+
this.state = { ...this.state, activations: this.state.activations.map((row) => row.scopeId === operation.scope.id && row.packageId === operation.package ? { ...row, activationState: "inactive", readbackState: "verified", readbackAt: this.now, updatedAt: this.now } : row) };
|
|
27128
|
+
this.replaceAttempt(plan, (attempt) => this.journaled(attempt, operation.operationId, "readback-verified", "readback", true));
|
|
27129
|
+
}
|
|
27130
|
+
completeContainment(plan, operation) {
|
|
27131
|
+
this.replaceAttempt(plan, (attempt) => this.journaled(attempt, operation.operationId, "completed", "failed", true));
|
|
27132
|
+
}
|
|
26575
27133
|
markRollbackRequired(plan, operation) {
|
|
26576
27134
|
this.adoptMovedGeneration();
|
|
26577
27135
|
this.retargetBareAlias(plan, operation);
|
|
27136
|
+
if (operation.action === "disable-nonconforming")
|
|
27137
|
+
this.disablePending(plan, operation, "rollback");
|
|
26578
27138
|
this.replaceAttempt(plan, (attempt) => this.journaled(attempt, operation.operationId, "rollback", "recovery-required", true));
|
|
26579
27139
|
}
|
|
27140
|
+
disablePending(plan, operation, phase) {
|
|
27141
|
+
this.state = { ...this.state, activations: this.state.activations.map((row) => row.scopeId === operation.scope.id && row.packageId === operation.package ? { ...row, pending: { operation: "disable-nonconforming", phase, attemptId: plan.attemptId, startedAt: this.now } } : row) };
|
|
27142
|
+
}
|
|
27143
|
+
clearDisablePending(operation, rolledBack = false) {
|
|
27144
|
+
this.state = { ...this.state, activations: this.state.activations.map((row) => {
|
|
27145
|
+
if (row.scopeId !== operation.scope.id || row.packageId !== operation.package)
|
|
27146
|
+
return row;
|
|
27147
|
+
const { pending: _pending, ...prior } = row;
|
|
27148
|
+
return rolledBack ? { ...prior, activationState: "nonconforming", readbackState: "unverified" } : prior;
|
|
27149
|
+
}) };
|
|
27150
|
+
}
|
|
26580
27151
|
markCompleted(plan, operation) {
|
|
26581
27152
|
const desiredPairs = plan.operations.filter((row) => row.operation.scope.id === operation.scope.id && row.operation.coverage === "desired-pair");
|
|
26582
27153
|
const converged = desiredPairs.every((row) => row.operation.operationId === operation.operationId || row.operation.action === "unchanged" || this.journalState(plan.attemptId, row.operation.operationId) === "completed");
|
|
@@ -26595,7 +27166,13 @@ class Ledger {
|
|
|
26595
27166
|
if (scope.authority !== "authoritative")
|
|
26596
27167
|
return scope;
|
|
26597
27168
|
const planned = plan.scopes.find((row) => row.scope.id === scope.id);
|
|
27169
|
+
if (planned?.retirementPackages !== undefined)
|
|
27170
|
+
return scope;
|
|
26598
27171
|
if (planned?.selectorMode === "retired") {
|
|
27172
|
+
if (this.state.activations.some((row) => row.scopeId === scope.id))
|
|
27173
|
+
return scope;
|
|
27174
|
+
if (plan.operations.some((row) => row.operation.scope.id === scope.id && row.operation.operationId !== operation.operationId && this.journalState(plan.attemptId, row.operation.operationId) !== "completed"))
|
|
27175
|
+
return scope;
|
|
26599
27176
|
const { desired: _desired, lastConverged: _converged, ...kept } = scope;
|
|
26600
27177
|
return {
|
|
26601
27178
|
...kept,
|
|
@@ -26663,7 +27240,7 @@ class Ledger {
|
|
|
26663
27240
|
if (existing !== undefined && existing.authority !== "authoritative")
|
|
26664
27241
|
return existing;
|
|
26665
27242
|
const selectorMode = planned.selectorMode;
|
|
26666
|
-
const target = { kind: planned.scope.target.kind, instance: planned.scope.target.instance };
|
|
27243
|
+
const target = planned.target ?? { kind: planned.scope.target.kind, instance: planned.scope.target.instance };
|
|
26667
27244
|
if (existing === undefined) {
|
|
26668
27245
|
return {
|
|
26669
27246
|
id: planned.scope.id,
|
|
@@ -26829,19 +27406,40 @@ function succeeded(operation, changed, notices = []) {
|
|
|
26829
27406
|
};
|
|
26830
27407
|
}
|
|
26831
27408
|
async function recoverApplied(plan, operation, host, ledger, handle, reason) {
|
|
27409
|
+
let verified = false;
|
|
27410
|
+
let diagnostic = "";
|
|
26832
27411
|
try {
|
|
26833
|
-
|
|
26834
|
-
|
|
26835
|
-
|
|
26836
|
-
|
|
26837
|
-
|
|
26838
|
-
|
|
27412
|
+
try {
|
|
27413
|
+
await host.adapter.rollback(handle);
|
|
27414
|
+
const observation = await host.adapter.readback(handle);
|
|
27415
|
+
host.adapter.verifyRollback(handle, observation);
|
|
27416
|
+
verified = true;
|
|
27417
|
+
} catch (error) {
|
|
27418
|
+
diagnostic = `; rollback verification failed: ${unknownErrorDiagnostic(error)}`;
|
|
27419
|
+
}
|
|
27420
|
+
try {
|
|
27421
|
+
if (verified)
|
|
27422
|
+
ledger.markRolledBack(plan, operation);
|
|
27423
|
+
else
|
|
27424
|
+
ledger.markRollbackRequired(plan, operation);
|
|
27425
|
+
} catch (error) {
|
|
27426
|
+
verified = false;
|
|
27427
|
+
diagnostic += `; recovery ledger could not be persisted: ${unknownErrorDiagnostic(error)}`;
|
|
27428
|
+
}
|
|
27429
|
+
if (verified) {
|
|
27430
|
+
try {
|
|
27431
|
+
await host.adapter.cleanup(handle, "verified-rollback");
|
|
27432
|
+
} catch {}
|
|
27433
|
+
}
|
|
27434
|
+
} finally {
|
|
27435
|
+
try {
|
|
27436
|
+
await host.adapter.releaseRecovery(handle);
|
|
27437
|
+
} catch (error) {
|
|
27438
|
+
verified = false;
|
|
27439
|
+
diagnostic += `; recovery resources could not be released: ${unknownErrorDiagnostic(error)}`;
|
|
27440
|
+
}
|
|
26839
27441
|
}
|
|
26840
|
-
|
|
26841
|
-
try {
|
|
26842
|
-
await host.adapter.cleanup(handle, "verified-rollback");
|
|
26843
|
-
} catch {}
|
|
26844
|
-
return reportedRollback(operation, reason);
|
|
27442
|
+
return verified ? reportedRollback(operation, reason) : pendingRecovery(operation, `; original failure: ${reason.diagnostic}${diagnostic}`);
|
|
26845
27443
|
}
|
|
26846
27444
|
async function abortPreparation(host, preparation) {
|
|
26847
27445
|
try {
|
|
@@ -26869,8 +27467,8 @@ function pendingReadback(operation, reason) {
|
|
|
26869
27467
|
}
|
|
26870
27468
|
};
|
|
26871
27469
|
}
|
|
26872
|
-
function pendingRecovery(operation) {
|
|
26873
|
-
const reason = createLifecycleReason("recovery", "recovery.required", `rollback for '${operation.operationId}' did not verify`);
|
|
27470
|
+
function pendingRecovery(operation, diagnostic = "") {
|
|
27471
|
+
const reason = createLifecycleReason("recovery", "recovery.required", `rollback for '${operation.operationId}' did not verify${diagnostic}`);
|
|
26874
27472
|
return {
|
|
26875
27473
|
stop: true,
|
|
26876
27474
|
reason,
|
|
@@ -26906,8 +27504,8 @@ function pendingCleanup(operation) {
|
|
|
26906
27504
|
outcome: {
|
|
26907
27505
|
...operation,
|
|
26908
27506
|
result: "pending",
|
|
26909
|
-
resourceState: "present",
|
|
26910
|
-
activationState: "active-conforming",
|
|
27507
|
+
resourceState: operation.action === "disable-nonconforming" ? "retained" : "present",
|
|
27508
|
+
activationState: operation.action === "disable-nonconforming" ? "inactive" : "active-conforming",
|
|
26911
27509
|
changed: true,
|
|
26912
27510
|
reason
|
|
26913
27511
|
}
|
|
@@ -26986,7 +27584,7 @@ function summaryFor(outcomes) {
|
|
|
26986
27584
|
const failed = outcomes.find((outcome) => outcome.result !== "succeeded");
|
|
26987
27585
|
const changed = outcomes.some((outcome) => outcome.changed);
|
|
26988
27586
|
const pending = outcomes.find((outcome) => outcome.result === "pending");
|
|
26989
|
-
const readback = outcomes.find((outcome) => outcome.reason?.category === "readback");
|
|
27587
|
+
const readback = outcomes.find((outcome) => outcome.reason?.category === "readback" || outcome.action === "disable-nonconforming" && outcome.changed);
|
|
26990
27588
|
const reapplied = outcomes.some((outcome) => outcome.result === "succeeded" && outcome.action === "update");
|
|
26991
27589
|
const mutationStarted = changed || pending !== undefined || reapplied;
|
|
26992
27590
|
if (failed === undefined) {
|
|
@@ -27080,7 +27678,8 @@ async function runFrozenLifecycle(command) {
|
|
|
27080
27678
|
validatedAt: command.now,
|
|
27081
27679
|
hosts: command.hosts,
|
|
27082
27680
|
...command.command === undefined ? {} : { command: command.command },
|
|
27083
|
-
...command.transportSource === undefined ? {} : { transportSource: command.transportSource }
|
|
27681
|
+
...command.transportSource === undefined ? {} : { transportSource: command.transportSource },
|
|
27682
|
+
...command.removalSelection === undefined ? {} : { removalSelection: command.removalSelection }
|
|
27084
27683
|
});
|
|
27085
27684
|
const executed = await executeLifecycle({
|
|
27086
27685
|
plan,
|
|
@@ -27103,6 +27702,7 @@ function plannerHost(kind, adapter, plannedNativeId, announceDryRun) {
|
|
|
27103
27702
|
var lifecyclePlannerHostKinds = [
|
|
27104
27703
|
"claude-code",
|
|
27105
27704
|
"codex",
|
|
27705
|
+
"dcode",
|
|
27106
27706
|
"kimi",
|
|
27107
27707
|
"cursor",
|
|
27108
27708
|
"omp",
|
|
@@ -27114,6 +27714,7 @@ function createLifecyclePlannerHosts() {
|
|
|
27114
27714
|
return [
|
|
27115
27715
|
plannerHost("claude-code", createClaudeCodeLifecycleHost(), claudeCodeWriter.plannedNativeId),
|
|
27116
27716
|
plannerHost("codex", codexLifecycle, codexWriter.plannedNativeId),
|
|
27717
|
+
plannerHost("dcode", dcodeLifecycle, dcodeWriter.plannedNativeId),
|
|
27117
27718
|
plannerHost("kimi", createLifecycleHostAdapter(kimiLifecycle), kimiWriter.plannedNativeId),
|
|
27118
27719
|
plannerHost("cursor", cursorManagedLifecycle, cursorWriter.plannedNativeId, announceCursorDryRun),
|
|
27119
27720
|
plannerHost("omp", ompLifecycle, ompWriter.plannedNativeId),
|
|
@@ -27123,6 +27724,161 @@ function createLifecyclePlannerHosts() {
|
|
|
27123
27724
|
];
|
|
27124
27725
|
}
|
|
27125
27726
|
|
|
27727
|
+
// src/pin-lifecycle.ts
|
|
27728
|
+
import { cpSync as cpSync13, mkdtempSync as mkdtempSync14, rmSync as rmSync15 } from "node:fs";
|
|
27729
|
+
import { tmpdir as tmpdir12 } from "node:os";
|
|
27730
|
+
import { basename as basename9, join as join35, relative as relative8 } from "node:path";
|
|
27731
|
+
async function runOfflineLifecyclePin(host, plugin, dryRun) {
|
|
27732
|
+
const adapter = host.lifecyclePinAdapter;
|
|
27733
|
+
if (adapter === undefined || plugin.path === undefined)
|
|
27734
|
+
throw new Error("offline lifecycle pin has no adapter or active root");
|
|
27735
|
+
let state = readLifecycleState().state;
|
|
27736
|
+
const matches = state.activations.filter((row) => row.nativeId === plugin.id && state.scopes.some((scope) => scope.id === row.scopeId && scope.target.kind === host.id));
|
|
27737
|
+
if (matches.length !== 1)
|
|
27738
|
+
throw new Error("offline lifecycle pin requires one recorded owned activation");
|
|
27739
|
+
const activation = matches[0];
|
|
27740
|
+
const scope = state.scopes.find((row) => row.id === activation.scopeId);
|
|
27741
|
+
if (activation.ownership.kind === "legacy-claim" || activation.route.kind === "legacy-unverified" || activation.sourceRevision === undefined || activation.pending !== undefined)
|
|
27742
|
+
throw new Error("offline lifecycle pin requires verified ownership with no pending recovery");
|
|
27743
|
+
if (activation.activationState !== "active" || activation.readbackState !== "verified")
|
|
27744
|
+
throw new Error("offline lifecycle pin requires a verified active installation");
|
|
27745
|
+
const preview = await host.pin(plugin, { dryRun: true });
|
|
27746
|
+
if (preview.refusals.length !== 0)
|
|
27747
|
+
return { changes: [], refusals: preview.refusals };
|
|
27748
|
+
if (preview.changes.length === 0)
|
|
27749
|
+
return preview;
|
|
27750
|
+
const now = new Date().toISOString();
|
|
27751
|
+
const frozenRoot = mkdtempSync14(join35(tmpdir12(), "plgnz-offline-pin-"));
|
|
27752
|
+
const attemptId = `pin-${basename9(frozenRoot)}`;
|
|
27753
|
+
const operationId = `${attemptId}:${plugin.id}`;
|
|
27754
|
+
let handle;
|
|
27755
|
+
let preparation;
|
|
27756
|
+
let accepted = false, applying = false, committed = false;
|
|
27757
|
+
const attempt = { id: attemptId, command: "update", phase: "accepted", mutationStarted: false, scopeIds: [scope.id], journal: [{ operationId, scopeId: scope.id, packageId: activation.packageId, nativeId: activation.nativeId, action: "update", state: "pending", route: activation.route, startedAt: now, updatedAt: now }], startedAt: now, updatedAt: now };
|
|
27758
|
+
const persist = (nextActivation) => {
|
|
27759
|
+
if (readLifecycleState().state.stateGeneration !== state.stateGeneration)
|
|
27760
|
+
throw new Error("pin ledger changed concurrently; refusing stale commit");
|
|
27761
|
+
const next = { ...state, stateGeneration: state.stateGeneration + 1, activations: state.activations.map((row) => row.scopeId === activation.scopeId && row.nativeId === activation.nativeId ? nextActivation : row), attempts: [...state.attempts.filter((row) => row.id !== attemptId), { ...attempt, journal: attempt.journal.map((row) => ({ ...row })) }] };
|
|
27762
|
+
writeLifecycleState(next, { globalPreflight: "succeeded" });
|
|
27763
|
+
state = next;
|
|
27764
|
+
};
|
|
27765
|
+
const pending = (phase) => persist({ ...activation, pending: { operation: "update", phase, attemptId, startedAt: now }, readbackState: "pending" });
|
|
27766
|
+
try {
|
|
27767
|
+
cpSync13(plugin.path, frozenRoot, { recursive: true });
|
|
27768
|
+
const packageFingerprint = fingerprintTree(frozenRoot);
|
|
27769
|
+
if (packageFingerprint !== activation.fingerprints.installed)
|
|
27770
|
+
throw new Error("pin active bytes differ from recorded readback");
|
|
27771
|
+
const target = { kind: scope.target.kind, instance: scope.target.instance };
|
|
27772
|
+
const observed = await adapter.observeTarget(target);
|
|
27773
|
+
const installed = observed.installations.find((row) => row.nativeId === plugin.id);
|
|
27774
|
+
if (installed?.ownership.kind !== "owned" || installed.ownership.scopeId !== scope.id || installed.installedFingerprint !== packageFingerprint || installed.enablement !== "enabled")
|
|
27775
|
+
throw new Error("pin native identity or bytes differ from the recorded owned activation");
|
|
27776
|
+
const version = await adapter.probeVersion(target);
|
|
27777
|
+
const sourceType = scope.source.kind;
|
|
27778
|
+
const inventory = inventoryPackageSemantics({ dir: frozenRoot, name: activation.packageId, ...plugin.version === undefined ? {} : { version: plugin.version }, contentFingerprint: packageFingerprint });
|
|
27779
|
+
const snapshot = createFrozenPackageSnapshot({ operationId, attemptId, scopeId: scope.id, target, action: "update", packageName: activation.packageId, nativeId: plugin.id, sourceType, immutableRevision: activation.sourceRevision, snapshotRoot: frozenRoot, packageRoot: frozenRoot, relativePackagePath: ".", snapshotFingerprint: packageFingerprint, packageFingerprint, ...sourceType === "git" ? { nativeGit: { locator: scope.source.locator, resolvedRevision: activation.sourceRevision } } : {}, inventory });
|
|
27780
|
+
const pins = createResolvedLifecyclePins(preview.changes.map((change) => ({ server: change.server, executable: change.to })).sort((left, right) => left.server < right.server ? -1 : left.server > right.server ? 1 : 0));
|
|
27781
|
+
const nativeScope = await adapter.observeNativeMutationScope({ targetObservation: observed, operation: "update", packageName: activation.packageId, nativeId: plugin.id, sourceType });
|
|
27782
|
+
const nativeProjection = await adapter.observeNativeProjection({ targetObservation: observed, operation: "update", snapshot, pins });
|
|
27783
|
+
const selection = adapter.decideRoute({ target, operationId, attemptId, scopeId: scope.id, packageName: activation.packageId, nativeId: plugin.id, version, sourceType, targetObservation: observed, nativeScope, nativeProjection, planCoverage: createLifecyclePlanCoverage(observed, [{ nativeId: plugin.id, operationId, operation: "update", mutationGroupId: operationId, authorization: "observed-owned" }]), operation: "update", snapshot, pins });
|
|
27784
|
+
if (selection.kind !== "selected")
|
|
27785
|
+
throw new Error(`pin capability ${selection.status}: ${selection.gaps.map((gap) => gap.capabilityId).join(", ")}`);
|
|
27786
|
+
if (selection.route !== "managed")
|
|
27787
|
+
throw new Error("offline lifecycle pin requires a frozen Managed projection");
|
|
27788
|
+
if (dryRun)
|
|
27789
|
+
return preview;
|
|
27790
|
+
pending("accepted");
|
|
27791
|
+
accepted = true;
|
|
27792
|
+
preparation = await adapter.stageActivation({ selection, snapshot, pins });
|
|
27793
|
+
preparation = await adapter.applyLifecycleDirectives(preparation);
|
|
27794
|
+
preparation = await adapter.applyPins(preparation);
|
|
27795
|
+
const sealed = await adapter.sealActivation(preparation);
|
|
27796
|
+
preparation = sealed;
|
|
27797
|
+
handle = sealed.handle;
|
|
27798
|
+
attempt.phase = "applying";
|
|
27799
|
+
attempt.mutationStarted = true;
|
|
27800
|
+
attempt.journal[0].state = "applying";
|
|
27801
|
+
pending("applying");
|
|
27802
|
+
applying = true;
|
|
27803
|
+
await adapter.apply(sealed);
|
|
27804
|
+
const observation = await adapter.readback(handle);
|
|
27805
|
+
adapter.verify(handle, observation);
|
|
27806
|
+
if (observation.installedFingerprint === null || handle.projectedFingerprint === null)
|
|
27807
|
+
throw new Error("pin readback lacks exact installed/projected fingerprint");
|
|
27808
|
+
attempt.phase = "finalizing";
|
|
27809
|
+
attempt.journal[0].state = "readback-verified";
|
|
27810
|
+
const pinnedActivation = { ...activation, route: { kind: handle.route, evidenceKey: { kind: "capability-profile", key: handle.evidenceId } }, fingerprints: { ...activation.fingerprints, projected: handle.projectedFingerprint, installed: observation.installedFingerprint }, pins: [...new Set([...activation.pins, ...pins.map((pin) => pin.server)])].sort(), readbackState: "verified", readbackAt: now, updatedAt: now };
|
|
27811
|
+
persist(pinnedActivation);
|
|
27812
|
+
committed = true;
|
|
27813
|
+
try {
|
|
27814
|
+
await adapter.cleanup(handle, "verified-commit");
|
|
27815
|
+
} catch (error) {
|
|
27816
|
+
attempt.journal[0].state = "cleanup-pending";
|
|
27817
|
+
persist({ ...pinnedActivation, pending: { operation: "update", phase: "cleanup", attemptId, startedAt: now } });
|
|
27818
|
+
await adapter.releaseRecovery(handle);
|
|
27819
|
+
throw error;
|
|
27820
|
+
}
|
|
27821
|
+
attempt.phase = "completed";
|
|
27822
|
+
attempt.journal[0].state = "completed";
|
|
27823
|
+
attempt.completedAt = now;
|
|
27824
|
+
persist(pinnedActivation);
|
|
27825
|
+
const activatedRoot = observation.contentRoots[0]?.path;
|
|
27826
|
+
return { ...preview, changes: preview.changes.map((change) => ({ ...change, file: activatedRoot === undefined ? change.file : join35(activatedRoot, relative8(plugin.path, change.file)) })) };
|
|
27827
|
+
} catch (error) {
|
|
27828
|
+
if (!committed && handle !== undefined && applying) {
|
|
27829
|
+
if (!(error instanceof LifecycleHostPhaseError && error.mutationStarted === false)) {
|
|
27830
|
+
attempt.phase = "recovery-required";
|
|
27831
|
+
attempt.journal[0].state = "rollback";
|
|
27832
|
+
try {
|
|
27833
|
+
let journalError;
|
|
27834
|
+
try {
|
|
27835
|
+
pending("rollback");
|
|
27836
|
+
} catch (writeError) {
|
|
27837
|
+
journalError = writeError;
|
|
27838
|
+
}
|
|
27839
|
+
await adapter.rollback(handle);
|
|
27840
|
+
adapter.verifyRollback(handle, await adapter.readback(handle));
|
|
27841
|
+
if (journalError !== undefined)
|
|
27842
|
+
throw new Error(`rollback verified but its durable receipt is blocked: ${journalError.message}`);
|
|
27843
|
+
attempt.phase = "finalizing";
|
|
27844
|
+
attempt.journal[0].state = "cleanup-pending";
|
|
27845
|
+
persist({ ...activation, pending: { operation: "update", phase: "cleanup", attemptId, startedAt: now } });
|
|
27846
|
+
await adapter.cleanup(handle, "verified-rollback");
|
|
27847
|
+
attempt.phase = "failed";
|
|
27848
|
+
attempt.journal[0].state = "rolled-back";
|
|
27849
|
+
persist(activation);
|
|
27850
|
+
} catch (recoveryError) {
|
|
27851
|
+
await adapter.releaseRecovery(handle);
|
|
27852
|
+
throw new Error(`pin failed: ${error.message}; recovery remains pending: ${recoveryError.message}`);
|
|
27853
|
+
}
|
|
27854
|
+
} else {
|
|
27855
|
+
attempt.phase = "failed";
|
|
27856
|
+
attempt.journal[0].state = "not-attempted";
|
|
27857
|
+
attempt.mutationStarted = false;
|
|
27858
|
+
persist(activation);
|
|
27859
|
+
await adapter.cleanup(handle, "aborted-preparation");
|
|
27860
|
+
}
|
|
27861
|
+
} else if (!committed && accepted) {
|
|
27862
|
+
try {
|
|
27863
|
+
if (preparation !== undefined)
|
|
27864
|
+
await adapter.cleanup(preparation, "aborted-preparation");
|
|
27865
|
+
} finally {
|
|
27866
|
+
attempt.phase = "failed";
|
|
27867
|
+
attempt.journal[0].state = "not-attempted";
|
|
27868
|
+
persist(activation);
|
|
27869
|
+
}
|
|
27870
|
+
}
|
|
27871
|
+
throw error;
|
|
27872
|
+
} finally {
|
|
27873
|
+
try {
|
|
27874
|
+
if (handle !== undefined)
|
|
27875
|
+
await adapter.releaseRecovery(handle);
|
|
27876
|
+
} finally {
|
|
27877
|
+
rmSync15(frozenRoot, { recursive: true, force: true });
|
|
27878
|
+
}
|
|
27879
|
+
}
|
|
27880
|
+
}
|
|
27881
|
+
|
|
27126
27882
|
// src/pin.ts
|
|
27127
27883
|
function defaultPinTargets(all = writers) {
|
|
27128
27884
|
return all.filter((w) => w.gui);
|
|
@@ -27133,13 +27889,20 @@ async function runPin(options = {}) {
|
|
|
27133
27889
|
const selected = selectTargets(candidates, options);
|
|
27134
27890
|
const findings = [];
|
|
27135
27891
|
let ledgerChanged = false;
|
|
27892
|
+
const changedRecords = new Set;
|
|
27136
27893
|
for (const host of selected) {
|
|
27137
27894
|
if (!host.detect())
|
|
27138
27895
|
continue;
|
|
27139
27896
|
for (const plugin of host.listInstalled()) {
|
|
27140
27897
|
if (plugin.path === undefined)
|
|
27141
27898
|
continue;
|
|
27142
|
-
|
|
27899
|
+
let outcome;
|
|
27900
|
+
try {
|
|
27901
|
+
outcome = host.lifecyclePinAdapter === undefined ? await host.pin(plugin, { dryRun: options.dryRun }) : await runOfflineLifecyclePin(host, plugin, options.dryRun === true);
|
|
27902
|
+
} catch (error) {
|
|
27903
|
+
findings.push({ host: host.id, mark: "✗", message: `plugin '${plugin.id}' pin failed — ${error.message}` });
|
|
27904
|
+
continue;
|
|
27905
|
+
}
|
|
27143
27906
|
const prefix = options.dryRun === true ? "[dry-run] " : "";
|
|
27144
27907
|
for (const change of outcome.changes) {
|
|
27145
27908
|
findings.push({
|
|
@@ -27157,6 +27920,8 @@ async function runPin(options = {}) {
|
|
|
27157
27920
|
}
|
|
27158
27921
|
if (outcome.changes.length === 0)
|
|
27159
27922
|
continue;
|
|
27923
|
+
if (host.lifecyclePinAdapter !== undefined)
|
|
27924
|
+
continue;
|
|
27160
27925
|
const record = findRecord(state, host.id, plugin.id);
|
|
27161
27926
|
if (record === undefined) {
|
|
27162
27927
|
findings.push({
|
|
@@ -27168,6 +27933,7 @@ async function runPin(options = {}) {
|
|
|
27168
27933
|
}
|
|
27169
27934
|
if (options.dryRun === true)
|
|
27170
27935
|
continue;
|
|
27936
|
+
changedRecords.add(record);
|
|
27171
27937
|
const pins = new Set(record.pins ?? []);
|
|
27172
27938
|
for (const change of outcome.changes)
|
|
27173
27939
|
pins.add(change.server);
|
|
@@ -27185,10 +27951,10 @@ async function runPin(options = {}) {
|
|
|
27185
27951
|
}
|
|
27186
27952
|
}
|
|
27187
27953
|
if (ledgerChanged)
|
|
27188
|
-
persistRecordedPins(state, options.state !== undefined);
|
|
27954
|
+
persistRecordedPins(state, options.state !== undefined, changedRecords);
|
|
27189
27955
|
return { findings, exitCode: findings.some((f) => f.mark === "✗") ? 1 : 0 };
|
|
27190
27956
|
}
|
|
27191
|
-
function persistRecordedPins(records, legacyLedger) {
|
|
27957
|
+
function persistRecordedPins(records, legacyLedger, changedRecords) {
|
|
27192
27958
|
const loaded = legacyLedger ? null : readLifecycleState();
|
|
27193
27959
|
if (loaded === null || loaded.sourceVersion !== 2) {
|
|
27194
27960
|
writeState(records);
|
|
@@ -27200,7 +27966,7 @@ function persistRecordedPins(records, legacyLedger) {
|
|
|
27200
27966
|
stateGeneration: loaded.state.stateGeneration + 1,
|
|
27201
27967
|
activations: loaded.state.activations.map((activation) => {
|
|
27202
27968
|
const scope = scopes.get(activation.scopeId);
|
|
27203
|
-
const record = records.find((candidate) => candidate.host === scope?.target.kind && candidate.id === activation.nativeId);
|
|
27969
|
+
const record = records.find((candidate) => changedRecords.has(candidate) && candidate.host === scope?.target.kind && candidate.id === activation.nativeId);
|
|
27204
27970
|
if (record === undefined)
|
|
27205
27971
|
return activation;
|
|
27206
27972
|
return {
|
|
@@ -27672,7 +28438,7 @@ function legacyCommandAction(command) {
|
|
|
27672
28438
|
// package.json
|
|
27673
28439
|
var package_default = {
|
|
27674
28440
|
name: "plugnz",
|
|
27675
|
-
version: "0.0.
|
|
28441
|
+
version: "0.0.9",
|
|
27676
28442
|
description: "Install, diagnose and update agent plugins (Agent Plugins spec) and MCP configs across Claude Code, Codex, Cursor, Kimi and more",
|
|
27677
28443
|
license: "MIT",
|
|
27678
28444
|
type: "module",
|
|
@@ -28681,19 +29447,13 @@ async function runRecordedLifecycleRemove(flags, target, state, selected) {
|
|
|
28681
29447
|
const alias = writer?.persistedNativeIdMayAlias?.(activation.nativeId, target) === true;
|
|
28682
29448
|
if (target !== activation.packageId && target !== activation.nativeId && !alias)
|
|
28683
29449
|
return [];
|
|
28684
|
-
return [{ scope }];
|
|
29450
|
+
return [{ scope, activation }];
|
|
28685
29451
|
});
|
|
28686
29452
|
if (matches.length === 0 || matches.some((match) => !plannerKinds.has(match.scope.target.kind)))
|
|
28687
29453
|
return null;
|
|
28688
29454
|
const byScope = new Map;
|
|
28689
29455
|
for (const match of matches)
|
|
28690
29456
|
byScope.set(match.scope.id, match.scope);
|
|
28691
|
-
for (const scopeId of byScope.keys()) {
|
|
28692
|
-
const inScope = state.activations.filter((activation) => activation.scopeId === scopeId).length;
|
|
28693
|
-
const selectedInScope = matches.filter((match) => match.scope.id === scopeId).length;
|
|
28694
|
-
if (inScope !== selectedInScope)
|
|
28695
|
-
return null;
|
|
28696
|
-
}
|
|
28697
29457
|
const perHost = new Map;
|
|
28698
29458
|
for (const match of matches) {
|
|
28699
29459
|
const count = (perHost.get(match.scope.target.kind) ?? 0) + 1;
|
|
@@ -28726,7 +29486,12 @@ async function runRecordedLifecycleRemove(flags, target, state, selected) {
|
|
|
28726
29486
|
dryRun: flags.dryRun,
|
|
28727
29487
|
hosts: createLifecyclePlannerHosts(),
|
|
28728
29488
|
now: new Date().toISOString(),
|
|
28729
|
-
command: "remove"
|
|
29489
|
+
command: "remove",
|
|
29490
|
+
removalSelection: matches.map(({ activation }) => ({
|
|
29491
|
+
scopeId: activation.scopeId,
|
|
29492
|
+
packageId: activation.packageId,
|
|
29493
|
+
nativeId: activation.nativeId
|
|
29494
|
+
}))
|
|
28730
29495
|
});
|
|
28731
29496
|
return executed.report;
|
|
28732
29497
|
}
|
package/package.json
CHANGED