agentwheel 0.20.1 → 0.20.2
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/{apply-R5VHCIUN.js → apply-OGC6E2Y4.js} +4 -2
- package/dist/{chunk-AFVGRRZW.js → chunk-BAJEWUI6.js} +10 -2
- package/dist/{chunk-BJEZXIXX.js → chunk-Z4N7TB6Q.js} +14 -2
- package/dist/index.js +416 -88
- package/dist/{transaction-ITXC7FFV.js → transaction-7CNV5MAQ.js} +3 -1
- package/openpack.json +1 -1
- package/package.json +1 -1
- package/skills/agentwheel/SKILL.md +1 -1
- package/skills/agentwheel-discovery/SKILL.md +1 -1
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
import {
|
|
3
3
|
applyCombinedInstallPlan,
|
|
4
4
|
applyInstallPlan,
|
|
5
|
+
commitManifestMetadataJournal,
|
|
5
6
|
recoverPendingApply,
|
|
6
7
|
uninstall
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-BAJEWUI6.js";
|
|
9
|
+
import "./chunk-Z4N7TB6Q.js";
|
|
9
10
|
import "./chunk-7VPI5J5Y.js";
|
|
10
11
|
export {
|
|
11
12
|
applyCombinedInstallPlan,
|
|
12
13
|
applyInstallPlan,
|
|
14
|
+
commitManifestMetadataJournal,
|
|
13
15
|
recoverPendingApply,
|
|
14
16
|
uninstall
|
|
15
17
|
};
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
rollbackCompletedOperations,
|
|
25
25
|
sourceLockPath,
|
|
26
26
|
writeApplyJournal
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-Z4N7TB6Q.js";
|
|
28
28
|
import {
|
|
29
29
|
pathExists,
|
|
30
30
|
writeJsonAtomic
|
|
@@ -1607,6 +1607,12 @@ function shouldPreserveKeptOperationWhenKeepingFiles(operation) {
|
|
|
1607
1607
|
function isForceRemovableKeep(operation) {
|
|
1608
1608
|
return operation.action === "keep" && operation.preserveInManifest !== true;
|
|
1609
1609
|
}
|
|
1610
|
+
async function commitManifestMetadataJournal(journal, transport = localTransport) {
|
|
1611
|
+
if (journal.mode !== "uninstall" || journal.operations.length !== 0) {
|
|
1612
|
+
throw new Error("Manifest metadata journal must contain no runtime operations.");
|
|
1613
|
+
}
|
|
1614
|
+
return commitJournalState(journal, transport, void 0, journal.createdAt);
|
|
1615
|
+
}
|
|
1610
1616
|
async function commitJournalState(journal, transport, entries, now) {
|
|
1611
1617
|
const manifest = withManifestRevision({
|
|
1612
1618
|
...journal.manifest,
|
|
@@ -2291,6 +2297,7 @@ export {
|
|
|
2291
2297
|
combineMergeRemovals,
|
|
2292
2298
|
hasMergeRemovalContent,
|
|
2293
2299
|
mergeRemovalForInstall,
|
|
2300
|
+
mergeContributionAbsent,
|
|
2294
2301
|
normalizeOwners,
|
|
2295
2302
|
managedInstructionBlockMode,
|
|
2296
2303
|
desiredManagedInstructionBlockHash,
|
|
@@ -2301,5 +2308,6 @@ export {
|
|
|
2301
2308
|
applyInstallPlan,
|
|
2302
2309
|
applyCombinedInstallPlan,
|
|
2303
2310
|
recoverPendingApply,
|
|
2304
|
-
uninstall
|
|
2311
|
+
uninstall,
|
|
2312
|
+
commitManifestMetadataJournal
|
|
2305
2313
|
};
|
|
@@ -2624,8 +2624,8 @@ async function recoverMutationRuntime(operationId, options = {}) {
|
|
|
2624
2624
|
}
|
|
2625
2625
|
mutation = GovernedMutation.activateExisting(receipt, baseline, lock);
|
|
2626
2626
|
const [{ recoverPendingApply }, { readLinkedLocalApplyJournal: readLinkedLocalApplyJournal2, removeApplyJournal: removeApplyJournal2, localPathExists: localPathExists2 }] = await Promise.all([
|
|
2627
|
-
import("./apply-
|
|
2628
|
-
import("./transaction-
|
|
2627
|
+
import("./apply-OGC6E2Y4.js"),
|
|
2628
|
+
import("./transaction-7CNV5MAQ.js")
|
|
2629
2629
|
]);
|
|
2630
2630
|
let missingReservation = false;
|
|
2631
2631
|
for (const entry of pending) {
|
|
@@ -2870,6 +2870,17 @@ async function listApplyJournals(targetRoot, adapter, transport = localTransport
|
|
|
2870
2870
|
}
|
|
2871
2871
|
return found.sort((a, b) => a.path.localeCompare(b.path));
|
|
2872
2872
|
}
|
|
2873
|
+
async function listAllApplyJournals(targetRoot, adapter, transport = localTransport) {
|
|
2874
|
+
const suffix = ".apply-journal.json";
|
|
2875
|
+
const found = [];
|
|
2876
|
+
for (const fileName of await transport.listDir(metadataDir(targetRoot))) {
|
|
2877
|
+
if (!fileName.endsWith(suffix)) continue;
|
|
2878
|
+
const path = join6(metadataDir(targetRoot), fileName);
|
|
2879
|
+
const journal = parseApplyJournal(JSON.parse(await transport.readFile(path)));
|
|
2880
|
+
if (journal.adapter === adapter) found.push({ path, journal });
|
|
2881
|
+
}
|
|
2882
|
+
return found.sort((a, b) => a.path.localeCompare(b.path));
|
|
2883
|
+
}
|
|
2873
2884
|
async function readLinkedLocalApplyJournal(path, operationId, expectedDigest, expectedTransportDescription) {
|
|
2874
2885
|
const absolutePath = resolve9(path);
|
|
2875
2886
|
const journal = parseApplyJournal(JSON.parse(await readFile7(absolutePath, "utf8")));
|
|
@@ -3150,6 +3161,7 @@ export {
|
|
|
3150
3161
|
writeApplyJournal,
|
|
3151
3162
|
readApplyJournal,
|
|
3152
3163
|
listApplyJournals,
|
|
3164
|
+
listAllApplyJournals,
|
|
3153
3165
|
readLinkedLocalApplyJournal,
|
|
3154
3166
|
removeApplyJournal,
|
|
3155
3167
|
abortApplyJournal,
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
canonicalizeGraphLock,
|
|
10
10
|
claudeInstructionBridgesAgents,
|
|
11
11
|
combineMergeRemovals,
|
|
12
|
+
commitManifestMetadataJournal,
|
|
12
13
|
computeInstallManifestInventoryRevision,
|
|
13
14
|
computeManifestRevision,
|
|
14
15
|
computeTargetFingerprint,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
managedInstructionBlockMode,
|
|
21
22
|
managedInstructionPhysicalKey,
|
|
22
23
|
managedInstructionSelector,
|
|
24
|
+
mergeContributionAbsent,
|
|
23
25
|
mergeRemovalForInstall,
|
|
24
26
|
normalizeImmutableCacheIdentity,
|
|
25
27
|
normalizeOwners,
|
|
@@ -31,7 +33,7 @@ import {
|
|
|
31
33
|
uninstall,
|
|
32
34
|
withManifestRevision,
|
|
33
35
|
writeInstallManifest
|
|
34
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-BAJEWUI6.js";
|
|
35
37
|
import {
|
|
36
38
|
CURRENT_WORKSPACE_SCHEMA_VERSION,
|
|
37
39
|
GovernedMutation,
|
|
@@ -55,10 +57,12 @@ import {
|
|
|
55
57
|
installRootForAdapterInstallationType,
|
|
56
58
|
installRootForArtifacts,
|
|
57
59
|
isCompositeWorkspaceProfile,
|
|
60
|
+
listAllApplyJournals,
|
|
58
61
|
listApplyJournals,
|
|
59
62
|
listMutationReceipts,
|
|
60
63
|
loadAdapterConfig,
|
|
61
64
|
localTransport,
|
|
65
|
+
mutationMetadataForApplyJournal,
|
|
62
66
|
mutationPolicyForWorkspace,
|
|
63
67
|
packageAssetSchema,
|
|
64
68
|
packageComposeEntrySchema,
|
|
@@ -88,8 +92,9 @@ import {
|
|
|
88
92
|
workspaceConfigSchema,
|
|
89
93
|
workspaceExportsSchema,
|
|
90
94
|
workspaceSelectionImportSchema,
|
|
95
|
+
writeApplyJournal,
|
|
91
96
|
writeWorkspaceConfig
|
|
92
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-Z4N7TB6Q.js";
|
|
93
98
|
import {
|
|
94
99
|
inferSourceDriverName
|
|
95
100
|
} from "./chunk-EMDIG24I.js";
|
|
@@ -104,11 +109,11 @@ import {
|
|
|
104
109
|
} from "./chunk-7VPI5J5Y.js";
|
|
105
110
|
|
|
106
111
|
// src/cli/index.ts
|
|
107
|
-
import { createHash as
|
|
112
|
+
import { createHash as createHash14 } from "crypto";
|
|
108
113
|
import { existsSync } from "fs";
|
|
109
114
|
import { mkdir as mkdir16, rm as rm10, writeFile as writeFile13 } from "fs/promises";
|
|
110
115
|
import { homedir as homedir12 } from "os";
|
|
111
|
-
import { dirname as dirname22, join as join45, resolve as
|
|
116
|
+
import { dirname as dirname22, join as join45, resolve as resolve24 } from "path";
|
|
112
117
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
113
118
|
import { Command } from "commander";
|
|
114
119
|
|
|
@@ -3102,14 +3107,14 @@ async function writeMermaidAsset(response) {
|
|
|
3102
3107
|
"content-type": "application/javascript; charset=utf-8",
|
|
3103
3108
|
"cache-control": "public, max-age=3600"
|
|
3104
3109
|
});
|
|
3105
|
-
await new Promise((
|
|
3110
|
+
await new Promise((resolve25) => {
|
|
3106
3111
|
const stream = createReadStream(assetPath);
|
|
3107
3112
|
stream.on("error", () => {
|
|
3108
3113
|
if (!response.headersSent) writeText(response, 404, "Mermaid asset unavailable.\n");
|
|
3109
3114
|
else response.destroy();
|
|
3110
|
-
|
|
3115
|
+
resolve25();
|
|
3111
3116
|
});
|
|
3112
|
-
stream.on("end",
|
|
3117
|
+
stream.on("end", resolve25);
|
|
3113
3118
|
stream.pipe(response);
|
|
3114
3119
|
});
|
|
3115
3120
|
}
|
|
@@ -3136,14 +3141,14 @@ function escapeHtml2(value) {
|
|
|
3136
3141
|
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
3137
3142
|
}
|
|
3138
3143
|
function listen(server, port, bind) {
|
|
3139
|
-
return new Promise((
|
|
3144
|
+
return new Promise((resolve25, reject) => {
|
|
3140
3145
|
const onError = (error) => {
|
|
3141
3146
|
server.off("listening", onListening);
|
|
3142
3147
|
reject(error);
|
|
3143
3148
|
};
|
|
3144
3149
|
const onListening = () => {
|
|
3145
3150
|
server.off("error", onError);
|
|
3146
|
-
|
|
3151
|
+
resolve25();
|
|
3147
3152
|
};
|
|
3148
3153
|
server.once("error", onError);
|
|
3149
3154
|
server.once("listening", onListening);
|
|
@@ -3151,7 +3156,7 @@ function listen(server, port, bind) {
|
|
|
3151
3156
|
});
|
|
3152
3157
|
}
|
|
3153
3158
|
function waitForShutdown(server, beforeClose) {
|
|
3154
|
-
return new Promise((
|
|
3159
|
+
return new Promise((resolve25) => {
|
|
3155
3160
|
let closing = false;
|
|
3156
3161
|
const shutdown = () => {
|
|
3157
3162
|
if (closing) return;
|
|
@@ -3159,7 +3164,7 @@ function waitForShutdown(server, beforeClose) {
|
|
|
3159
3164
|
process.off("SIGINT", shutdown);
|
|
3160
3165
|
process.off("SIGTERM", shutdown);
|
|
3161
3166
|
beforeClose();
|
|
3162
|
-
server.close(() =>
|
|
3167
|
+
server.close(() => resolve25());
|
|
3163
3168
|
};
|
|
3164
3169
|
process.once("SIGINT", shutdown);
|
|
3165
3170
|
process.once("SIGTERM", shutdown);
|
|
@@ -3169,7 +3174,7 @@ function waitForShutdown(server, beforeClose) {
|
|
|
3169
3174
|
process.off("SIGINT", shutdown);
|
|
3170
3175
|
process.off("SIGTERM", shutdown);
|
|
3171
3176
|
beforeClose();
|
|
3172
|
-
|
|
3177
|
+
resolve25();
|
|
3173
3178
|
});
|
|
3174
3179
|
});
|
|
3175
3180
|
}
|
|
@@ -3722,7 +3727,7 @@ async function fetchClawHubPackage(fetchImpl, packageName) {
|
|
|
3722
3727
|
throw new Error(`ClawHub lookup failed for ${packageName}`);
|
|
3723
3728
|
}
|
|
3724
3729
|
async function delay(ms) {
|
|
3725
|
-
await new Promise((
|
|
3730
|
+
await new Promise((resolve25) => setTimeout(resolve25, ms));
|
|
3726
3731
|
}
|
|
3727
3732
|
function parseClawHubSource(source) {
|
|
3728
3733
|
if (!source.startsWith(sourcePrefix)) {
|
|
@@ -3893,7 +3898,7 @@ async function withGitCacheMaintenanceLock(cacheRoot, timeoutMs, fn) {
|
|
|
3893
3898
|
if (Date.now() - started > timeoutMs) {
|
|
3894
3899
|
throw new Error(`Timed out waiting for git cache maintenance lock at ${lockPath}`);
|
|
3895
3900
|
}
|
|
3896
|
-
await new Promise((
|
|
3901
|
+
await new Promise((resolve25) => setTimeout(resolve25, 50));
|
|
3897
3902
|
}
|
|
3898
3903
|
}
|
|
3899
3904
|
try {
|
|
@@ -6684,8 +6689,8 @@ function verifyIntegrity(integrity, sourceHash, label) {
|
|
|
6684
6689
|
async function withCachePathLock(path, fn) {
|
|
6685
6690
|
const previous = cacheLocks.get(path) ?? Promise.resolve();
|
|
6686
6691
|
let release = () => void 0;
|
|
6687
|
-
const current = previous.then(() => new Promise((
|
|
6688
|
-
release =
|
|
6692
|
+
const current = previous.then(() => new Promise((resolve25) => {
|
|
6693
|
+
release = resolve25;
|
|
6689
6694
|
}));
|
|
6690
6695
|
cacheLocks.set(path, current);
|
|
6691
6696
|
await previous;
|
|
@@ -6761,8 +6766,8 @@ function detectDirectCollisions(nodes) {
|
|
|
6761
6766
|
}
|
|
6762
6767
|
}
|
|
6763
6768
|
function graphNodeId(name, version, normalizedSource, resolvedCommit, sourceHash) {
|
|
6764
|
-
const
|
|
6765
|
-
return `${name}@${version}+${
|
|
6769
|
+
const digest2 = createHash6("sha256").update(normalizedSource).update("\0").update(resolvedCommit ?? sourceHash).digest("hex").slice(0, 12);
|
|
6770
|
+
return `${name}@${version}+${digest2}`;
|
|
6766
6771
|
}
|
|
6767
6772
|
function sortedUnique2(values) {
|
|
6768
6773
|
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
@@ -9246,6 +9251,11 @@ async function verifiedEntryHash(entry, destPath, transport) {
|
|
|
9246
9251
|
}
|
|
9247
9252
|
return currentHash;
|
|
9248
9253
|
}
|
|
9254
|
+
async function verifyManifestEntryRuntime(targetRoot, entry, transport = localTransport) {
|
|
9255
|
+
const path = containedArtifactPath(targetRoot, entry.path);
|
|
9256
|
+
if (!await transport.pathExists(path)) throw new Error(`Managed artifact is missing: ${entry.path}`);
|
|
9257
|
+
return verifiedEntryHash(entry, path, transport);
|
|
9258
|
+
}
|
|
9249
9259
|
function containedArtifactPath(targetRoot, relativePath) {
|
|
9250
9260
|
if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\0")) {
|
|
9251
9261
|
throw new Error(`Unsafe managed artifact path: ${relativePath}`);
|
|
@@ -9282,10 +9292,246 @@ function assertManifestIdentity(manifest, request) {
|
|
|
9282
9292
|
}
|
|
9283
9293
|
}
|
|
9284
9294
|
|
|
9295
|
+
// src/lifecycle/ownership-retire-stale.ts
|
|
9296
|
+
import { createHash as createHash9 } from "crypto";
|
|
9297
|
+
import { resolve as resolve20 } from "path";
|
|
9298
|
+
async function planRetireStaleOwnership(request) {
|
|
9299
|
+
return observe(request, request.transport ?? localTransport);
|
|
9300
|
+
}
|
|
9301
|
+
async function applyRetireStaleOwnership(request) {
|
|
9302
|
+
assertApplyPreconditions(request);
|
|
9303
|
+
const transport = request.transport ?? localTransport;
|
|
9304
|
+
const lock = await acquireApplyLock(request.targetRoot, request.adapter, transport, {}, {
|
|
9305
|
+
installationType: request.installationType,
|
|
9306
|
+
stateKey: request.destinationStateKey
|
|
9307
|
+
});
|
|
9308
|
+
try {
|
|
9309
|
+
const pending = await listAllApplyJournals(request.targetRoot, request.adapter, transport);
|
|
9310
|
+
if (pending.length > 0) {
|
|
9311
|
+
throw new Error(`Cannot retire stale ownership while runtime apply journal(s) are pending: ${pending.map((item) => item.path).join(", ")}`);
|
|
9312
|
+
}
|
|
9313
|
+
const current = await observe(request, transport);
|
|
9314
|
+
assertExpected(request.planDigest, current.planDigest, "plan digest");
|
|
9315
|
+
assertExpected(request.expectedSourceRevision, current.source.revision, "source manifest revision");
|
|
9316
|
+
assertExpected(request.expectedDestinationRevision, current.destination.revision, "destination manifest revision");
|
|
9317
|
+
assertExpected(request.expectedInventoryRevision, current.manifestInventoryRevision, "manifest inventory revision");
|
|
9318
|
+
const source = await requireManifest(request, request.sourceStateKey, transport, "source");
|
|
9319
|
+
const selectedDigests = new Set(current.selected.map((entry) => entry.sourceEntryDigest));
|
|
9320
|
+
const retained = source.entries.filter((entry) => !selectedDigests.has(entryDigest(entry)));
|
|
9321
|
+
if (source.entries.length - retained.length !== current.selected.length) {
|
|
9322
|
+
throw new Error("Source manifest selection changed while locked; replan required.");
|
|
9323
|
+
}
|
|
9324
|
+
declareMutationPath(current.source.manifestPath);
|
|
9325
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9326
|
+
const mutation = mutationMetadataForApplyJournal();
|
|
9327
|
+
const journal = {
|
|
9328
|
+
version: mutation ? 2 : 1,
|
|
9329
|
+
...mutation ? { mutation } : {},
|
|
9330
|
+
mode: "uninstall",
|
|
9331
|
+
adapter: request.adapter,
|
|
9332
|
+
installationType: request.installationType,
|
|
9333
|
+
stateKey: request.sourceStateKey,
|
|
9334
|
+
targetRoot: request.targetRoot,
|
|
9335
|
+
baseRevision: source.revision,
|
|
9336
|
+
createdAt: now,
|
|
9337
|
+
updatedAt: now,
|
|
9338
|
+
operations: [],
|
|
9339
|
+
completed: [],
|
|
9340
|
+
manifest: { ...source, entries: retained }
|
|
9341
|
+
};
|
|
9342
|
+
await writeApplyJournal(journal, transport);
|
|
9343
|
+
await commitManifestMetadataJournal(journal, transport);
|
|
9344
|
+
return {
|
|
9345
|
+
...current,
|
|
9346
|
+
applied: true,
|
|
9347
|
+
sourceManifestRemoved: retained.length === 0,
|
|
9348
|
+
retainedSourceEntries: retained.length
|
|
9349
|
+
};
|
|
9350
|
+
} finally {
|
|
9351
|
+
await lock.release();
|
|
9352
|
+
}
|
|
9353
|
+
}
|
|
9354
|
+
async function observe(request, transport) {
|
|
9355
|
+
const normalized = normalizeRequest(request);
|
|
9356
|
+
const source = await requireManifest(normalized, normalized.sourceStateKey, transport, "source");
|
|
9357
|
+
const destination = await requireManifest(normalized, normalized.destinationStateKey, transport, "destination");
|
|
9358
|
+
const sourceOwner = workspaceOwnerForRoot(normalized.fromWorkspaceRoot);
|
|
9359
|
+
const destinationOwner = workspaceOwnerForRoot(normalized.toWorkspaceRoot, normalized.toFleetId);
|
|
9360
|
+
const destinationByPath = /* @__PURE__ */ new Map();
|
|
9361
|
+
for (const entry of destination.entries) {
|
|
9362
|
+
if (entry.workspaceOwner !== destinationOwner) continue;
|
|
9363
|
+
const entries = destinationByPath.get(entry.path) ?? [];
|
|
9364
|
+
entries.push(entry);
|
|
9365
|
+
destinationByPath.set(entry.path, entries);
|
|
9366
|
+
}
|
|
9367
|
+
const selected = [];
|
|
9368
|
+
for (const sourceEntry of source.entries) {
|
|
9369
|
+
if (sourceEntry.workspaceOwner !== sourceOwner) continue;
|
|
9370
|
+
const candidates = destinationByPath.get(sourceEntry.path) ?? [];
|
|
9371
|
+
if (candidates.length === 0) continue;
|
|
9372
|
+
if (candidates.length !== 1) {
|
|
9373
|
+
throw new Error(`Destination Fleet manifest has ambiguous ownership for ${sourceEntry.path}.`);
|
|
9374
|
+
}
|
|
9375
|
+
assertRetirableSourceEntry(sourceEntry);
|
|
9376
|
+
const destinationEntry = candidates[0];
|
|
9377
|
+
await assertContributionCoverage(sourceEntry, destinationEntry, normalized.targetRoot, transport);
|
|
9378
|
+
const runtimeHash = await verifyManifestEntryRuntime(normalized.targetRoot, destinationEntry, transport);
|
|
9379
|
+
selected.push({
|
|
9380
|
+
path: sourceEntry.path,
|
|
9381
|
+
sourceEntryDigest: entryDigest(sourceEntry),
|
|
9382
|
+
destinationEntryDigest: entryDigest(destinationEntry),
|
|
9383
|
+
runtimeHash
|
|
9384
|
+
});
|
|
9385
|
+
}
|
|
9386
|
+
selected.sort((a, b) => a.path.localeCompare(b.path) || a.sourceEntryDigest.localeCompare(b.sourceEntryDigest) || a.destinationEntryDigest.localeCompare(b.destinationEntryDigest));
|
|
9387
|
+
if (selected.length === 0) {
|
|
9388
|
+
throw new Error("No stale source ownership entries match an exact path in the destination Fleet manifest.");
|
|
9389
|
+
}
|
|
9390
|
+
const withoutDigest = {
|
|
9391
|
+
adapter: normalized.adapter,
|
|
9392
|
+
installationType: normalized.installationType,
|
|
9393
|
+
targetRoot: normalized.targetRoot,
|
|
9394
|
+
source: {
|
|
9395
|
+
stateKey: normalized.sourceStateKey,
|
|
9396
|
+
manifestPath: installManifestPath(normalized.targetRoot, normalized.adapter, {
|
|
9397
|
+
installationType: normalized.installationType,
|
|
9398
|
+
stateKey: normalized.sourceStateKey
|
|
9399
|
+
}),
|
|
9400
|
+
revision: source.revision,
|
|
9401
|
+
owner: sourceOwner
|
|
9402
|
+
},
|
|
9403
|
+
destination: {
|
|
9404
|
+
stateKey: normalized.destinationStateKey,
|
|
9405
|
+
manifestPath: installManifestPath(normalized.targetRoot, normalized.adapter, {
|
|
9406
|
+
installationType: normalized.installationType,
|
|
9407
|
+
stateKey: normalized.destinationStateKey
|
|
9408
|
+
}),
|
|
9409
|
+
revision: destination.revision,
|
|
9410
|
+
owner: destinationOwner,
|
|
9411
|
+
fleetId: normalized.toFleetId
|
|
9412
|
+
},
|
|
9413
|
+
manifestInventoryRevision: await computeInstallManifestInventoryRevision(
|
|
9414
|
+
normalized.targetRoot,
|
|
9415
|
+
normalized.adapter,
|
|
9416
|
+
transport
|
|
9417
|
+
),
|
|
9418
|
+
selected
|
|
9419
|
+
};
|
|
9420
|
+
return { ...withoutDigest, planDigest: digest(withoutDigest) };
|
|
9421
|
+
}
|
|
9422
|
+
function normalizeRequest(request) {
|
|
9423
|
+
const targetRoot = resolve20(request.targetRoot);
|
|
9424
|
+
const sourceStateKey = exactStateKey(request.adapter, request.sourceStateKey, request.installationType, "source");
|
|
9425
|
+
const destinationStateKey = exactStateKey(request.adapter, request.destinationStateKey, request.installationType, "destination");
|
|
9426
|
+
if (sourceStateKey === destinationStateKey) throw new Error("Source and destination state keys must differ.");
|
|
9427
|
+
if (!request.toFleetId.trim()) throw new Error("Destination Fleet id is required.");
|
|
9428
|
+
return {
|
|
9429
|
+
...request,
|
|
9430
|
+
targetRoot,
|
|
9431
|
+
installationType: request.installationType.trim(),
|
|
9432
|
+
sourceStateKey,
|
|
9433
|
+
destinationStateKey,
|
|
9434
|
+
fromWorkspaceRoot: resolve20(request.fromWorkspaceRoot),
|
|
9435
|
+
toWorkspaceRoot: resolve20(request.toWorkspaceRoot),
|
|
9436
|
+
toFleetId: request.toFleetId.trim()
|
|
9437
|
+
};
|
|
9438
|
+
}
|
|
9439
|
+
function exactStateKey(adapter, value, installationType, label) {
|
|
9440
|
+
if (!value || stateKeyFor(adapter, { installationType, stateKey: value }) !== value) {
|
|
9441
|
+
throw new Error(`The ${label} state key must be an exact canonical state key.`);
|
|
9442
|
+
}
|
|
9443
|
+
return value;
|
|
9444
|
+
}
|
|
9445
|
+
async function requireManifest(request, stateKey, transport, label) {
|
|
9446
|
+
const manifest = await readInstallManifest(request.targetRoot, request.adapter, transport, {
|
|
9447
|
+
installationType: request.installationType,
|
|
9448
|
+
stateKey
|
|
9449
|
+
});
|
|
9450
|
+
if (!manifest) throw new Error(`No ${label} install manifest for state key ${stateKey}.`);
|
|
9451
|
+
if (manifest.version !== 2) throw new Error(`${label} ownership retirement requires an Agentwheel v2 install manifest.`);
|
|
9452
|
+
const actualStateKey = stateKeyFor(manifest.adapter, {
|
|
9453
|
+
installationType: manifest.installationType,
|
|
9454
|
+
stateKey: manifest.stateKey
|
|
9455
|
+
});
|
|
9456
|
+
if (manifest.adapter !== request.adapter || manifest.installationType !== request.installationType || resolve20(manifest.targetRoot) !== request.targetRoot || actualStateKey !== stateKey) {
|
|
9457
|
+
throw new Error(`${label} install manifest identity does not match the requested adapter, target, installation type, and state key.`);
|
|
9458
|
+
}
|
|
9459
|
+
return manifest;
|
|
9460
|
+
}
|
|
9461
|
+
function assertRetirableSourceEntry(entry) {
|
|
9462
|
+
if (entry.semanticPlugin || entry.semanticCommand || entry.executed) {
|
|
9463
|
+
throw new Error(`Cannot retire semantic source ownership at ${entry.path}.`);
|
|
9464
|
+
}
|
|
9465
|
+
if (entry.mergeStrategy && !entry.mergeRemoval) {
|
|
9466
|
+
throw new Error(`Cannot retire incomplete merge ownership at ${entry.path}.`);
|
|
9467
|
+
}
|
|
9468
|
+
}
|
|
9469
|
+
async function assertContributionCoverage(source, destination, targetRoot, transport) {
|
|
9470
|
+
const sourceManagedBlock = source.mode === "managed-block";
|
|
9471
|
+
const destinationManagedBlock = destination.mode === "managed-block";
|
|
9472
|
+
const sourceMerge = source.mergeStrategy !== void 0;
|
|
9473
|
+
const destinationMerge = destination.mergeStrategy !== void 0;
|
|
9474
|
+
const sourceCategory = sourceManagedBlock ? "managed-block" : sourceMerge ? "merge" : "plain";
|
|
9475
|
+
const destinationCategory = destinationManagedBlock ? "managed-block" : destinationMerge ? "merge" : "plain";
|
|
9476
|
+
if (sourceCategory !== destinationCategory) {
|
|
9477
|
+
throw new Error(
|
|
9478
|
+
`Destination Fleet ownership category ${destinationCategory} cannot replace stale source category ${sourceCategory} at ${source.path}.`
|
|
9479
|
+
);
|
|
9480
|
+
}
|
|
9481
|
+
if (sourceCategory === "plain") return;
|
|
9482
|
+
if (sourceManagedBlock) {
|
|
9483
|
+
const sourceSelector = managedInstructionSelector(source.logicalSelector, source.artifactType, source.artifactName);
|
|
9484
|
+
const destinationSelector = managedInstructionSelector(destination.logicalSelector, destination.artifactType, destination.artifactName);
|
|
9485
|
+
if (!sourceManagedBlock || !destinationManagedBlock || sourceSelector !== destinationSelector) {
|
|
9486
|
+
throw new Error(`Destination Fleet does not exactly cover stale source managed block contribution at ${source.path}.`);
|
|
9487
|
+
}
|
|
9488
|
+
return;
|
|
9489
|
+
}
|
|
9490
|
+
if (source.mergeStrategy && destination.mergeStrategy) {
|
|
9491
|
+
if (!source.mergeRemoval) throw new Error(`Cannot retire incomplete merge ownership at ${source.path}.`);
|
|
9492
|
+
const exactlyCovered = destination.mergeStrategy === source.mergeStrategy && destination.mergeRemoval && contributionSelector(source) === contributionSelector(destination) && canonicalJson(source.mergeRemoval) === canonicalJson(destination.mergeRemoval);
|
|
9493
|
+
if (exactlyCovered) return;
|
|
9494
|
+
const current = await transport.readFile(containedArtifactPath(targetRoot, source.path));
|
|
9495
|
+
if (!mergeContributionAbsent(source.mergeRemoval, source.mergeStrategy, current)) {
|
|
9496
|
+
throw new Error(`Destination Fleet does not exactly cover or replace stale source merge contribution at ${source.path}.`);
|
|
9497
|
+
}
|
|
9498
|
+
}
|
|
9499
|
+
}
|
|
9500
|
+
function contributionSelector(entry) {
|
|
9501
|
+
return entry.logicalSelector ?? `${entry.artifactType}/${entry.artifactName}`;
|
|
9502
|
+
}
|
|
9503
|
+
function assertApplyPreconditions(request) {
|
|
9504
|
+
for (const [label, value] of [
|
|
9505
|
+
["plan digest", request.planDigest],
|
|
9506
|
+
["source manifest revision", request.expectedSourceRevision],
|
|
9507
|
+
["destination manifest revision", request.expectedDestinationRevision],
|
|
9508
|
+
["manifest inventory revision", request.expectedInventoryRevision]
|
|
9509
|
+
]) {
|
|
9510
|
+
if (!value || !/^[a-f0-9]{64}$/.test(value)) {
|
|
9511
|
+
throw new Error(`Applying stale ownership retirement requires a reviewed lowercase SHA-256 ${label}.`);
|
|
9512
|
+
}
|
|
9513
|
+
}
|
|
9514
|
+
}
|
|
9515
|
+
function assertExpected(expected, current, label) {
|
|
9516
|
+
if (expected !== current) throw new Error(`Stale ${label}: expected ${expected}, found ${current}; replan required.`);
|
|
9517
|
+
}
|
|
9518
|
+
function entryDigest(entry) {
|
|
9519
|
+
return digest(entry);
|
|
9520
|
+
}
|
|
9521
|
+
function digest(value) {
|
|
9522
|
+
return createHash9("sha256").update(canonicalJson(value)).digest("hex");
|
|
9523
|
+
}
|
|
9524
|
+
function canonicalJson(value) {
|
|
9525
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
9526
|
+
if (!value || typeof value !== "object") return JSON.stringify(value);
|
|
9527
|
+
const record = value;
|
|
9528
|
+
return `{${Object.keys(record).filter((key) => record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
|
|
9529
|
+
}
|
|
9530
|
+
|
|
9285
9531
|
// src/version/policy.ts
|
|
9286
9532
|
import { execFile as execFile3 } from "child_process";
|
|
9287
9533
|
import { readFile as readFile23 } from "fs/promises";
|
|
9288
|
-
import { join as join39, resolve as
|
|
9534
|
+
import { join as join39, resolve as resolve21 } from "path";
|
|
9289
9535
|
import { promisify as promisify3 } from "util";
|
|
9290
9536
|
import { parse as parseJsonc } from "jsonc-parser";
|
|
9291
9537
|
import { z as z5 } from "zod";
|
|
@@ -9379,7 +9625,7 @@ async function discoverVersionsFromSource(pkg, workspaceRoot) {
|
|
|
9379
9625
|
if (tagged.length > 0) return tagged;
|
|
9380
9626
|
}
|
|
9381
9627
|
if (driverName === "local") {
|
|
9382
|
-
const root =
|
|
9628
|
+
const root = resolve21(workspaceRoot, pkg.source);
|
|
9383
9629
|
const manifest2 = await readPackageManifest(root);
|
|
9384
9630
|
const current = manifest2 ? [{ version: manifest2.version, ref: pkg.requestedRef ?? root }] : [];
|
|
9385
9631
|
try {
|
|
@@ -9502,7 +9748,7 @@ async function readVersionCache(path) {
|
|
|
9502
9748
|
// src/profile/members.ts
|
|
9503
9749
|
import { execFile as execFile4 } from "child_process";
|
|
9504
9750
|
import { readFile as readFile24 } from "fs/promises";
|
|
9505
|
-
import { join as join40, resolve as
|
|
9751
|
+
import { join as join40, resolve as resolve22 } from "path";
|
|
9506
9752
|
import { promisify as promisify4 } from "util";
|
|
9507
9753
|
import { z as z7 } from "zod";
|
|
9508
9754
|
|
|
@@ -9677,7 +9923,7 @@ async function invokeMemberStatus(member, parentWorkspace, chain, options, cliEn
|
|
|
9677
9923
|
let stderr = "";
|
|
9678
9924
|
try {
|
|
9679
9925
|
if (member.transport === "local") {
|
|
9680
|
-
const workspace =
|
|
9926
|
+
const workspace = resolve22(parentWorkspace, member.workspace);
|
|
9681
9927
|
const result = await execFileAsync4(process.execPath, [cliEntry, ...args], {
|
|
9682
9928
|
cwd: workspace,
|
|
9683
9929
|
env: env2,
|
|
@@ -9723,7 +9969,7 @@ async function runMemberAgentwheel(member, parentWorkspace, args, chain) {
|
|
|
9723
9969
|
process.execPath,
|
|
9724
9970
|
[process.argv[1], "--no-update-check", ...args],
|
|
9725
9971
|
{
|
|
9726
|
-
cwd:
|
|
9972
|
+
cwd: resolve22(parentWorkspace, member.workspace),
|
|
9727
9973
|
env: env2,
|
|
9728
9974
|
maxBuffer: 20 * 1024 * 1024
|
|
9729
9975
|
}
|
|
@@ -9824,7 +10070,7 @@ function assertNoCompositeCycle(workspaceRoot, profileName, chain) {
|
|
|
9824
10070
|
}
|
|
9825
10071
|
}
|
|
9826
10072
|
function compositeKey(workspaceRoot, profileName) {
|
|
9827
|
-
return `${
|
|
10073
|
+
return `${resolve22(workspaceRoot)}#${profileName}`;
|
|
9828
10074
|
}
|
|
9829
10075
|
|
|
9830
10076
|
// src/status/repository.ts
|
|
@@ -9871,7 +10117,7 @@ function valueAfter(lines, prefix) {
|
|
|
9871
10117
|
}
|
|
9872
10118
|
|
|
9873
10119
|
// src/catalogue/client.ts
|
|
9874
|
-
import { createHash as
|
|
10120
|
+
import { createHash as createHash10 } from "crypto";
|
|
9875
10121
|
import { readFile as readFile25, rm as rm8 } from "fs/promises";
|
|
9876
10122
|
import { homedir as homedir9 } from "os";
|
|
9877
10123
|
import { join as join41 } from "path";
|
|
@@ -10146,7 +10392,7 @@ var CatalogueClient = class {
|
|
|
10146
10392
|
}
|
|
10147
10393
|
return {
|
|
10148
10394
|
value: schema.parse(value),
|
|
10149
|
-
digest:
|
|
10395
|
+
digest: createHash10("sha256").update(bytes).digest("hex")
|
|
10150
10396
|
};
|
|
10151
10397
|
}
|
|
10152
10398
|
};
|
|
@@ -10157,7 +10403,7 @@ function sameSources2(a, b) {
|
|
|
10157
10403
|
return a.length === b.length && a.every((source, index) => source === b[index]);
|
|
10158
10404
|
}
|
|
10159
10405
|
function catalogueContentHash(enriched, vercel) {
|
|
10160
|
-
return
|
|
10406
|
+
return createHash10("sha256").update(JSON.stringify({ enriched, vercel })).digest("hex");
|
|
10161
10407
|
}
|
|
10162
10408
|
|
|
10163
10409
|
// src/search/index.ts
|
|
@@ -10519,7 +10765,7 @@ function includesToken(normalizedText, token) {
|
|
|
10519
10765
|
}
|
|
10520
10766
|
|
|
10521
10767
|
// src/semantic/index.ts
|
|
10522
|
-
import { createHash as
|
|
10768
|
+
import { createHash as createHash11 } from "crypto";
|
|
10523
10769
|
import { homedir as homedir10 } from "os";
|
|
10524
10770
|
import { join as join42 } from "path";
|
|
10525
10771
|
import { env, pipeline } from "@huggingface/transformers";
|
|
@@ -10609,8 +10855,8 @@ var SemanticSearchClient = class {
|
|
|
10609
10855
|
if (!response.ok) throw new Error(`Semantic index file failed (${response.status}): ${descriptor.path}`);
|
|
10610
10856
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
10611
10857
|
if (bytes.byteLength !== descriptor.bytes) throw new Error(`Semantic index file size does not match: ${descriptor.path}`);
|
|
10612
|
-
const
|
|
10613
|
-
if (
|
|
10858
|
+
const digest2 = createHash11("sha256").update(bytes).digest("hex");
|
|
10859
|
+
if (digest2 !== descriptor.sha256) throw new Error(`Semantic index checksum does not match: ${descriptor.path}`);
|
|
10614
10860
|
return bytes;
|
|
10615
10861
|
}
|
|
10616
10862
|
};
|
|
@@ -10699,7 +10945,7 @@ function ensureTrailingSlash(value) {
|
|
|
10699
10945
|
}
|
|
10700
10946
|
|
|
10701
10947
|
// src/trial/skill.ts
|
|
10702
|
-
import { createHash as
|
|
10948
|
+
import { createHash as createHash12 } from "crypto";
|
|
10703
10949
|
import { readFile as readFile26, stat as stat13 } from "fs/promises";
|
|
10704
10950
|
import { join as join43 } from "path";
|
|
10705
10951
|
import { parse as parseYaml2 } from "yaml";
|
|
@@ -10729,7 +10975,7 @@ async function createSkillTrial(driver, resolved, selectors) {
|
|
|
10729
10975
|
skill: {
|
|
10730
10976
|
name: artifact.name,
|
|
10731
10977
|
relativePath: artifact.relativePath,
|
|
10732
|
-
sha256:
|
|
10978
|
+
sha256: createHash12("sha256").update(content).digest("hex"),
|
|
10733
10979
|
frontmatter,
|
|
10734
10980
|
content
|
|
10735
10981
|
}
|
|
@@ -10748,12 +10994,12 @@ function readSkillFrontmatter(content, artifact) {
|
|
|
10748
10994
|
}
|
|
10749
10995
|
|
|
10750
10996
|
// src/lifecycle/fleet-normalize.ts
|
|
10751
|
-
import { createHash as
|
|
10997
|
+
import { createHash as createHash13 } from "crypto";
|
|
10752
10998
|
import { readFile as readFile27, readdir as readdir9, rm as rm9 } from "fs/promises";
|
|
10753
10999
|
import { homedir as homedir11 } from "os";
|
|
10754
|
-
import { basename as basename19, isAbsolute as isAbsolute3, join as join44, relative as relative8, resolve as
|
|
11000
|
+
import { basename as basename19, isAbsolute as isAbsolute3, join as join44, relative as relative8, resolve as resolve23 } from "path";
|
|
10755
11001
|
async function planFleetNormalization(request) {
|
|
10756
|
-
const normalizedRequest =
|
|
11002
|
+
const normalizedRequest = normalizeRequest2(request);
|
|
10757
11003
|
const destinationScope = await resolveWorkspaceScope({
|
|
10758
11004
|
fleet: normalizedRequest.destinationFleet,
|
|
10759
11005
|
globalRoot: normalizedRequest.globalRoot
|
|
@@ -10774,8 +11020,8 @@ async function planFleetNormalization(request) {
|
|
|
10774
11020
|
if (!sourcePackage || !destinationPackage) {
|
|
10775
11021
|
throw new Error(`Package '${name}' must be an existing duplicate in both source and destination fleets.`);
|
|
10776
11022
|
}
|
|
10777
|
-
const sourceDeclaration =
|
|
10778
|
-
const destinationDeclaration =
|
|
11023
|
+
const sourceDeclaration = canonicalJson2(sourcePackage);
|
|
11024
|
+
const destinationDeclaration = canonicalJson2(destinationPackage);
|
|
10779
11025
|
if (sourceDeclaration !== destinationDeclaration) {
|
|
10780
11026
|
throw new Error(
|
|
10781
11027
|
`Package '${name}' has divergent declarations. Source, driver, adapter, adapter configuration, installation type, version policy, selections, aliases, overrides, and suggestions must match before normalization.`
|
|
@@ -10812,13 +11058,13 @@ async function planFleetNormalization(request) {
|
|
|
10812
11058
|
packages,
|
|
10813
11059
|
installedState
|
|
10814
11060
|
};
|
|
10815
|
-
return { ...planWithoutDigest, planDigest: sha2564(
|
|
11061
|
+
return { ...planWithoutDigest, planDigest: sha2564(canonicalJson2(planWithoutDigest)) };
|
|
10816
11062
|
}
|
|
10817
11063
|
async function applyFleetNormalization(request, hooks = {}) {
|
|
10818
11064
|
if (!request.apply) throw new Error("Fleet normalization is dry-run by default; pass --apply with --plan-digest <digest>.");
|
|
10819
11065
|
if (!request.planDigest) throw new Error("Applying fleet normalization requires --plan-digest <digest> from a reviewed dry-run.");
|
|
10820
11066
|
assertDigest(request.planDigest);
|
|
10821
|
-
const normalizedRequest =
|
|
11067
|
+
const normalizedRequest = normalizeRequest2(request);
|
|
10822
11068
|
const roots = await normalizationRoots(normalizedRequest);
|
|
10823
11069
|
const ordered = [.../* @__PURE__ */ new Set([roots.source, roots.destination])].sort((a, b) => a.localeCompare(b));
|
|
10824
11070
|
return withOrderedLocks(ordered, async () => {
|
|
@@ -10950,14 +11196,14 @@ async function assertNormalizationPostconditions(journal) {
|
|
|
10950
11196
|
}
|
|
10951
11197
|
for (const graphLock of journal.graphLocks) {
|
|
10952
11198
|
const raw = await readOptionalRecord(graphLock.path);
|
|
10953
|
-
const
|
|
10954
|
-
if (
|
|
11199
|
+
const digest2 = raw ? sha2564(canonicalJson2(await readGraphLock(graphLock.path))) : null;
|
|
11200
|
+
if (digest2 !== graphLock.afterDigest) {
|
|
10955
11201
|
throw new Error(`Fleet normalization graph-lock postcheck failed: ${graphLock.path}`);
|
|
10956
11202
|
}
|
|
10957
11203
|
}
|
|
10958
11204
|
}
|
|
10959
11205
|
async function recoverFleetNormalization(request) {
|
|
10960
|
-
const normalizedRequest =
|
|
11206
|
+
const normalizedRequest = normalizeRequest2(request);
|
|
10961
11207
|
const roots = await normalizationRoots(normalizedRequest);
|
|
10962
11208
|
const ordered = [.../* @__PURE__ */ new Set([roots.source, roots.destination])].sort((a, b) => a.localeCompare(b));
|
|
10963
11209
|
return withOrderedLocks(ordered, async () => {
|
|
@@ -11000,7 +11246,7 @@ async function assertSourceFleetPostcondition(request, source, selectedPackages)
|
|
|
11000
11246
|
);
|
|
11001
11247
|
}
|
|
11002
11248
|
}
|
|
11003
|
-
function
|
|
11249
|
+
function normalizeRequest2(request) {
|
|
11004
11250
|
const packages = request.packages === void 0 ? void 0 : sortedUnique6(request.packages);
|
|
11005
11251
|
if (request.packages !== void 0 && packages?.length === 0) throw new Error("--package requires at least one package name.");
|
|
11006
11252
|
const artifacts = request.artifacts === void 0 ? void 0 : sortedUnique6(request.artifacts.map((artifact) => normalizeArtifactSelector(artifact)));
|
|
@@ -11022,17 +11268,17 @@ function normalizeRequest(request) {
|
|
|
11022
11268
|
...profile ? { profile } : {},
|
|
11023
11269
|
...agent ? { agent } : {},
|
|
11024
11270
|
...orphanedOwnerRoots ? { orphanedOwnerRoots } : {},
|
|
11025
|
-
...request.globalRoot ? { globalRoot:
|
|
11271
|
+
...request.globalRoot ? { globalRoot: resolve23(request.globalRoot) } : {}
|
|
11026
11272
|
};
|
|
11027
11273
|
}
|
|
11028
11274
|
function normalizeOrphanedOwnerRoot(value) {
|
|
11029
11275
|
const root = value.trim();
|
|
11030
11276
|
if (!root || !isAbsolute3(root)) throw new Error(`Invalid orphaned owner root '${value}'; expected an absolute workspace path.`);
|
|
11031
|
-
return
|
|
11277
|
+
return resolve23(root);
|
|
11032
11278
|
}
|
|
11033
11279
|
async function normalizationRoots(request) {
|
|
11034
11280
|
const destination = await showRegisteredFleet(request.destinationFleet, { globalRoot: request.globalRoot });
|
|
11035
|
-
const source = request.from === "user" ?
|
|
11281
|
+
const source = request.from === "user" ? resolve23(request.globalRoot ?? homedir11()) : (await showRegisteredFleet(request.from.slice("fleet:".length), { globalRoot: request.globalRoot })).root;
|
|
11036
11282
|
return { source, destination: destination.root };
|
|
11037
11283
|
}
|
|
11038
11284
|
async function withOrderedLocks(roots, fn) {
|
|
@@ -11123,10 +11369,10 @@ async function inspectInstalledState(source, destination, packageNames) {
|
|
|
11123
11369
|
const destinationGraphAfter = destinationGraph?.lock ?? destinationGraphFromSource(sourceGraph.lock, destinationState.targetFingerprint);
|
|
11124
11370
|
graphTransfers.push({
|
|
11125
11371
|
sourceGraphLockPath: sourceGraph.path,
|
|
11126
|
-
sourceGraphLockDigest: sha2564(
|
|
11372
|
+
sourceGraphLockDigest: sha2564(canonicalJson2(sourceGraph.lock)),
|
|
11127
11373
|
destinationGraphLockPath: destinationState.graphLockPath,
|
|
11128
|
-
destinationGraphLockDigest: destinationGraph ? sha2564(
|
|
11129
|
-
destinationGraphLockAfterDigest: sha2564(
|
|
11374
|
+
destinationGraphLockDigest: destinationGraph ? sha2564(canonicalJson2(destinationGraph.lock)) : null,
|
|
11375
|
+
destinationGraphLockAfterDigest: sha2564(canonicalJson2(destinationGraphAfter)),
|
|
11130
11376
|
targetKey: sourceGraph.targetKey,
|
|
11131
11377
|
adapter: destinationState.adapter,
|
|
11132
11378
|
targetFingerprint: destinationState.targetFingerprint
|
|
@@ -11339,7 +11585,7 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
|
|
|
11339
11585
|
)
|
|
11340
11586
|
});
|
|
11341
11587
|
if (!selectedArtifacts) {
|
|
11342
|
-
const fullDigest = sha2564(
|
|
11588
|
+
const fullDigest = sha2564(canonicalJson2(graph.lock));
|
|
11343
11589
|
const existingDestinationGraph = graphCandidates.find((candidate) => candidate.path === destinationState.graphLockPath);
|
|
11344
11590
|
if (existingDestinationGraph) assertGraphIsSubset(graph, existingDestinationGraph);
|
|
11345
11591
|
const destinationGraph = destinationGraphFromSource(graph.lock, destinationState.targetFingerprint);
|
|
@@ -11347,8 +11593,8 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
|
|
|
11347
11593
|
sourceGraphLockPath: graph.path,
|
|
11348
11594
|
sourceGraphLockDigest: fullDigest,
|
|
11349
11595
|
destinationGraphLockPath: destinationState.graphLockPath,
|
|
11350
|
-
destinationGraphLockDigest: existingDestinationGraph ? sha2564(
|
|
11351
|
-
destinationGraphLockAfterDigest: sha2564(
|
|
11596
|
+
destinationGraphLockDigest: existingDestinationGraph ? sha2564(canonicalJson2(existingDestinationGraph.lock)) : null,
|
|
11597
|
+
destinationGraphLockAfterDigest: sha2564(canonicalJson2(destinationGraph)),
|
|
11352
11598
|
targetKey: graph.targetKey,
|
|
11353
11599
|
adapter: graph.adapter,
|
|
11354
11600
|
targetFingerprint: destinationState.targetFingerprint
|
|
@@ -11406,7 +11652,7 @@ function targetKeysForAgent(scope, name) {
|
|
|
11406
11652
|
async function runtimeRoots(scope) {
|
|
11407
11653
|
const roots = /* @__PURE__ */ new Set([scope.root]);
|
|
11408
11654
|
if (scope.config.packages.some((pkg) => pkg.installationType === "user") || Object.values(scope.config.agents).some((agent) => agent.installationType === "user")) {
|
|
11409
|
-
roots.add(
|
|
11655
|
+
roots.add(resolve23(process.env.AGENTWHEEL_TEST_HOME || process.env.HOME || homedir11()));
|
|
11410
11656
|
}
|
|
11411
11657
|
for (const [name, agent] of Object.entries(scope.config.agents)) {
|
|
11412
11658
|
if (agent.transport === "ssh") throw new Error(`Installed-state normalization cannot inspect SSH agent '${name}' locally.`);
|
|
@@ -11443,14 +11689,14 @@ async function collectManifests(roots) {
|
|
|
11443
11689
|
}
|
|
11444
11690
|
continue;
|
|
11445
11691
|
}
|
|
11446
|
-
if (
|
|
11692
|
+
if (resolve23(parsed.targetRoot) !== resolve23(root)) {
|
|
11447
11693
|
throw new Error(`Install manifest target root does not match its enumerated runtime root: ${path}`);
|
|
11448
11694
|
}
|
|
11449
11695
|
const expectedPath = installManifestPath(parsed.targetRoot, parsed.adapter, {
|
|
11450
11696
|
installationType: parsed.installationType,
|
|
11451
11697
|
stateKey: parsed.stateKey
|
|
11452
11698
|
});
|
|
11453
|
-
if (
|
|
11699
|
+
if (resolve23(expectedPath) !== resolve23(path)) {
|
|
11454
11700
|
throw new Error(`Install manifest state identity does not match its canonical path: ${path}`);
|
|
11455
11701
|
}
|
|
11456
11702
|
found.set(path, { path, raw, manifest: { ...parsed, revision: computeManifestRevision(raw), legacy: false } });
|
|
@@ -11471,7 +11717,7 @@ async function collectManifestPaths(paths) {
|
|
|
11471
11717
|
installationType: parsed.installationType,
|
|
11472
11718
|
stateKey: parsed.stateKey
|
|
11473
11719
|
});
|
|
11474
|
-
if (
|
|
11720
|
+
if (resolve23(expectedPath) !== resolve23(path)) {
|
|
11475
11721
|
throw new Error(`Install manifest state identity does not match its canonical path: ${path}`);
|
|
11476
11722
|
}
|
|
11477
11723
|
found.push({ path, raw, manifest: { ...parsed, revision: computeManifestRevision(raw), legacy: false } });
|
|
@@ -11518,7 +11764,7 @@ async function relevantGraphLocks(workspaceRoot, selected, targetKeys, include)
|
|
|
11518
11764
|
const projection = relevantGraphProjection(lock, selected);
|
|
11519
11765
|
results.push({
|
|
11520
11766
|
...candidate,
|
|
11521
|
-
digest: sha2564(
|
|
11767
|
+
digest: sha2564(canonicalJson2(projection)),
|
|
11522
11768
|
artifactIdentities: lock.canonical.artifacts.filter((artifact) => artifact.owners.some((owner) => ownerMatchesGraphPackage(lock, owner, selected))).map(graphArtifactIdentity).sort()
|
|
11523
11769
|
});
|
|
11524
11770
|
}
|
|
@@ -11554,7 +11800,7 @@ async function legacyManifestPathForConfiguredTarget(scope, graph) {
|
|
|
11554
11800
|
baseDir: scope.root
|
|
11555
11801
|
});
|
|
11556
11802
|
const targetRoot = resolveConfigPath(agent.root, scope.root);
|
|
11557
|
-
const installRoot =
|
|
11803
|
+
const installRoot = resolve23(installRootForAdapterInstallationType(adapter, targetRoot, agent.installationType, false));
|
|
11558
11804
|
const stateKey = stateKeyFor(adapter.name, {
|
|
11559
11805
|
installationType: agent.installationType,
|
|
11560
11806
|
targetFingerprint: graph.lock.canonical.targetFingerprint
|
|
@@ -11628,7 +11874,7 @@ async function targetStateForGraph(scope, graph, identityFleetId = scope.fleetId
|
|
|
11628
11874
|
targetFingerprint,
|
|
11629
11875
|
...identityFleetId ? { fleetId: identityFleetId } : {}
|
|
11630
11876
|
});
|
|
11631
|
-
const installRoot =
|
|
11877
|
+
const installRoot = resolve23(installRootForAdapterInstallationType(adapter, targetRoot, installationType, false));
|
|
11632
11878
|
return {
|
|
11633
11879
|
adapter: adapter.name,
|
|
11634
11880
|
installationType,
|
|
@@ -11659,9 +11905,9 @@ async function legacyTargetStateForGraph(scope, graph) {
|
|
|
11659
11905
|
};
|
|
11660
11906
|
}
|
|
11661
11907
|
function assertGraphIsSubset(source, destination) {
|
|
11662
|
-
const sourceRoots = new Map(source.lock.canonical.roots.map((root) => [root.rootId,
|
|
11908
|
+
const sourceRoots = new Map(source.lock.canonical.roots.map((root) => [root.rootId, canonicalJson2(root)]));
|
|
11663
11909
|
for (const root of destination.lock.canonical.roots) {
|
|
11664
|
-
if (sourceRoots.get(root.rootId) !==
|
|
11910
|
+
if (sourceRoots.get(root.rootId) !== canonicalJson2(root)) {
|
|
11665
11911
|
throw new Error(
|
|
11666
11912
|
`Partially normalized destination graph diverges at root '${root.rootId}': ${destination.path}`
|
|
11667
11913
|
);
|
|
@@ -11691,7 +11937,7 @@ function destinationGraphFromSource(source, targetFingerprint) {
|
|
|
11691
11937
|
function mergeDestinationManifest(existing, state, generatedAt, desiredEntries, replaceOwners = /* @__PURE__ */ new Set()) {
|
|
11692
11938
|
if (existing) {
|
|
11693
11939
|
const manifest2 = existing.manifest;
|
|
11694
|
-
if (manifest2.adapter !== state.adapter || manifest2.installationType !== state.installationType || manifest2.stateKey !== state.stateKey ||
|
|
11940
|
+
if (manifest2.adapter !== state.adapter || manifest2.installationType !== state.installationType || manifest2.stateKey !== state.stateKey || resolve23(manifest2.targetRoot) !== state.installRoot) {
|
|
11695
11941
|
throw new Error(`Destination manifest identity diverges from the derived target: ${existing.path}`);
|
|
11696
11942
|
}
|
|
11697
11943
|
}
|
|
@@ -11751,7 +11997,7 @@ async function assertEquivalentRuntimeState(entry, sourcePath, destinationPath)
|
|
|
11751
11997
|
const content = await readFile27(path, "utf8");
|
|
11752
11998
|
if (hasMergeRemovalContent(entry.mergeRemoval)) {
|
|
11753
11999
|
assertExactMergeContribution(entry.mergeRemoval, entry.mergeStrategy, content);
|
|
11754
|
-
} else if (
|
|
12000
|
+
} else if (resolve23(sourcePath) === resolve23(destinationPath) && entry.mergeStrategy !== "codex-toml-mcp") {
|
|
11755
12001
|
assertExactMergeContribution({}, entry.mergeStrategy, content);
|
|
11756
12002
|
} else {
|
|
11757
12003
|
throw new Error(`Installed-state normalization cannot prove incomplete merge ownership at ${path}.`);
|
|
@@ -11762,8 +12008,8 @@ async function assertEquivalentRuntimeState(entry, sourcePath, destinationPath)
|
|
|
11762
12008
|
await assertEquivalentRuntimeBytes(sourcePath, destinationPath, entry.hash);
|
|
11763
12009
|
}
|
|
11764
12010
|
function renderedEntryPathForRoot(root, entryPath) {
|
|
11765
|
-
const normalizedRoot =
|
|
11766
|
-
const candidate =
|
|
12011
|
+
const normalizedRoot = resolve23(root);
|
|
12012
|
+
const candidate = resolve23(normalizedRoot, entryPath);
|
|
11767
12013
|
if (candidate !== normalizedRoot && !candidate.startsWith(`${normalizedRoot}/`)) {
|
|
11768
12014
|
throw new Error(`Install manifest entry escapes its target root: ${entryPath}`);
|
|
11769
12015
|
}
|
|
@@ -11854,8 +12100,8 @@ function ownerMatchesGraphPackage(lock, owner, selected) {
|
|
|
11854
12100
|
return ownerMatchesPackage(owner, selected) || lock.canonical.roots.some((root) => selected.has(root.rootId) && root.graphNodeId === owner);
|
|
11855
12101
|
}
|
|
11856
12102
|
function renderedEntryPath(manifest, entry) {
|
|
11857
|
-
const root =
|
|
11858
|
-
const candidate =
|
|
12103
|
+
const root = resolve23(manifest.targetRoot);
|
|
12104
|
+
const candidate = resolve23(root, entry.path);
|
|
11859
12105
|
if (candidate !== root && !candidate.startsWith(`${root}/`)) {
|
|
11860
12106
|
throw new Error(`Install manifest entry escapes its target root: ${entry.path}`);
|
|
11861
12107
|
}
|
|
@@ -11874,7 +12120,7 @@ function assertSimpleVerifiableEntry(entry, path) {
|
|
|
11874
12120
|
if (entry.kind !== "file" && entry.kind !== "dir") throw new Error(`Unsupported installed entry kind at ${path}.`);
|
|
11875
12121
|
}
|
|
11876
12122
|
function entryIdentity(entry) {
|
|
11877
|
-
return
|
|
12123
|
+
return canonicalJson2({
|
|
11878
12124
|
path: entry.path,
|
|
11879
12125
|
artifactType: entry.artifactType,
|
|
11880
12126
|
artifactName: entry.artifactName,
|
|
@@ -11892,7 +12138,7 @@ function entryIdentity(entry) {
|
|
|
11892
12138
|
});
|
|
11893
12139
|
}
|
|
11894
12140
|
function graphArtifactIdentity(artifact) {
|
|
11895
|
-
return
|
|
12141
|
+
return canonicalJson2({
|
|
11896
12142
|
graphNodeId: artifact.graphNodeId,
|
|
11897
12143
|
type: artifact.type,
|
|
11898
12144
|
name: artifact.name,
|
|
@@ -11906,7 +12152,7 @@ function graphArtifactIdentity(artifact) {
|
|
|
11906
12152
|
});
|
|
11907
12153
|
}
|
|
11908
12154
|
function graphEntryIdentity(entry) {
|
|
11909
|
-
return
|
|
12155
|
+
return canonicalJson2({
|
|
11910
12156
|
graphNodeId: entry.graphNodeId,
|
|
11911
12157
|
type: entry.artifactType,
|
|
11912
12158
|
name: entry.artifactName,
|
|
@@ -12010,7 +12256,7 @@ async function buildJournalGraphLockStates(plan) {
|
|
|
12010
12256
|
for (const transfer of plan.installedState.graphTransfers) {
|
|
12011
12257
|
const sourceBefore = JSON.parse(await readFile27(transfer.sourceGraphLockPath, "utf8"));
|
|
12012
12258
|
const sourceLock = await readGraphLock(transfer.sourceGraphLockPath);
|
|
12013
|
-
const sourceDigest = sha2564(
|
|
12259
|
+
const sourceDigest = sha2564(canonicalJson2(sourceLock));
|
|
12014
12260
|
if (sourceDigest !== transfer.sourceGraphLockDigest) {
|
|
12015
12261
|
throw new Error(`Source graph lock changed after planning: ${transfer.sourceGraphLockPath}`);
|
|
12016
12262
|
}
|
|
@@ -12028,9 +12274,9 @@ async function buildJournalGraphLockStates(plan) {
|
|
|
12028
12274
|
continue;
|
|
12029
12275
|
}
|
|
12030
12276
|
const destinationBefore = await readOptionalRecord(transfer.destinationGraphLockPath);
|
|
12031
|
-
const destinationBeforeDigest = destinationBefore ? sha2564(
|
|
12277
|
+
const destinationBeforeDigest = destinationBefore ? sha2564(canonicalJson2(await readGraphLock(transfer.destinationGraphLockPath))) : null;
|
|
12032
12278
|
const destinationAfter = destinationBefore ? await readGraphLock(transfer.destinationGraphLockPath) : destinationGraphFromSource(sourceLock, transfer.targetFingerprint);
|
|
12033
|
-
const destinationAfterDigest = sha2564(
|
|
12279
|
+
const destinationAfterDigest = sha2564(canonicalJson2(destinationAfter));
|
|
12034
12280
|
if (destinationBeforeDigest !== transfer.destinationGraphLockDigest || destinationAfterDigest !== transfer.destinationGraphLockAfterDigest) {
|
|
12035
12281
|
throw new Error(`Destination graph lock changed after planning: ${transfer.destinationGraphLockPath}`);
|
|
12036
12282
|
}
|
|
@@ -12140,8 +12386,8 @@ async function assertJournalRecoverable(journal) {
|
|
|
12140
12386
|
}
|
|
12141
12387
|
for (const graphLock of journal.graphLocks) {
|
|
12142
12388
|
const raw = await readOptionalRecord(graphLock.path);
|
|
12143
|
-
const
|
|
12144
|
-
if (
|
|
12389
|
+
const digest2 = raw ? sha2564(canonicalJson2(await readGraphLock(graphLock.path))) : null;
|
|
12390
|
+
if (digest2 !== graphLock.beforeDigest && digest2 !== graphLock.afterDigest) {
|
|
12145
12391
|
throw new Error(`Cannot recover fleet normalization because graph lock changed outside the transaction: ${graphLock.path}`);
|
|
12146
12392
|
}
|
|
12147
12393
|
}
|
|
@@ -12193,12 +12439,12 @@ function packageMap(config) {
|
|
|
12193
12439
|
return result;
|
|
12194
12440
|
}
|
|
12195
12441
|
function configRevision(config) {
|
|
12196
|
-
return sha2564(
|
|
12442
|
+
return sha2564(canonicalJson2(config));
|
|
12197
12443
|
}
|
|
12198
12444
|
function normalizationJournalPath(sourceRoot, destinationFleet) {
|
|
12199
12445
|
return join44(sourceRoot, ".agentwheel", `fleet-normalize-${destinationFleet}.journal.json`);
|
|
12200
12446
|
}
|
|
12201
|
-
function
|
|
12447
|
+
function canonicalJson2(value) {
|
|
12202
12448
|
return JSON.stringify(sortValue(value));
|
|
12203
12449
|
}
|
|
12204
12450
|
function sortValue(value) {
|
|
@@ -12209,7 +12455,7 @@ function sortValue(value) {
|
|
|
12209
12455
|
return value;
|
|
12210
12456
|
}
|
|
12211
12457
|
function sha2564(value) {
|
|
12212
|
-
return
|
|
12458
|
+
return createHash13("sha256").update(value).digest("hex");
|
|
12213
12459
|
}
|
|
12214
12460
|
function assertDigest(value) {
|
|
12215
12461
|
if (!/^[a-f0-9]{64}$/.test(value)) throw new Error(`Invalid plan digest: ${value}`);
|
|
@@ -12247,6 +12493,7 @@ var commandGovernance = {
|
|
|
12247
12493
|
"package migrate": "governed-always",
|
|
12248
12494
|
remember: "governed-always",
|
|
12249
12495
|
"ownership handoff": "governed-unless-dry-run",
|
|
12496
|
+
"ownership retire-stale": "governed-apply",
|
|
12250
12497
|
"mcp retire": "governed-apply",
|
|
12251
12498
|
eject: "governed-always",
|
|
12252
12499
|
uninstall: "governed-unless-dry-run",
|
|
@@ -12663,7 +12910,7 @@ ownershipCommand.command("handoff").description("transfer one managed artifact b
|
|
|
12663
12910
|
const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
|
|
12664
12911
|
if (options.toFleet) {
|
|
12665
12912
|
const fleet = await showRegisteredFleet(options.toFleet);
|
|
12666
|
-
if (
|
|
12913
|
+
if (resolve24(fleet.root) !== resolve24(toWorkspaceRoot)) {
|
|
12667
12914
|
throw new Error(`Destination fleet '${options.toFleet}' is registered at ${fleet.root}, not ${toWorkspaceRoot}.`);
|
|
12668
12915
|
}
|
|
12669
12916
|
}
|
|
@@ -12688,6 +12935,84 @@ ownershipCommand.command("handoff").description("transfer one managed artifact b
|
|
|
12688
12935
|
console.log(`Manifest revision: ${result.manifestRevision}`);
|
|
12689
12936
|
console.log(`Owner: ${result.fromOwner} -> ${result.toOwner}`);
|
|
12690
12937
|
});
|
|
12938
|
+
ownershipCommand.command("retire-stale").description("retire stale source-manifest ownership already covered by one Fleet manifest").requiredOption("--from-workspace-root <path>", "exact stale workspace owner root").requiredOption("--to-workspace-root <path>", "registered destination Fleet root").requiredOption("--source-state-key <key>", "exact source install-manifest state key").requiredOption("--fleet <id>", "registered destination Fleet").option("--adapter <adapter>", "built-in adapter").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--adapter-config <path>", "adapter JSON/JSONC file").option("--adapter-module <path>", "local programmatic adapter module").option("--allow-adapter-code", "allow loading local adapter code", false).option("-t, --target-root <path>", "runtime/project root").option("--agent <name>", "named destination Fleet agent").option("--profile <name>", "destination Fleet profile resolving to one target").option("--plan-digest <sha256>", "reviewed plan digest; required with --apply").option("--expected-source-revision <sha256>", "reviewed source manifest revision; required with --apply").option("--expected-destination-revision <sha256>", "reviewed destination manifest revision; required with --apply").option("--expected-inventory-revision <sha256>", "reviewed runtime manifest inventory revision; required with --apply").option("--apply", "apply the exact reviewed metadata-only retirement", false).option("--json", "print the complete deterministic plan as JSON", false).action(async (options) => {
|
|
12939
|
+
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
12940
|
+
const fleet = await showRegisteredFleet(options.fleet);
|
|
12941
|
+
const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
|
|
12942
|
+
if (resolve24(fleet.root) !== resolve24(toWorkspaceRoot)) {
|
|
12943
|
+
throw new Error(`Destination Fleet '${options.fleet}' is registered at ${fleet.root}, not ${toWorkspaceRoot}.`);
|
|
12944
|
+
}
|
|
12945
|
+
const targets = await resolveCliTargets(normalizedOptions);
|
|
12946
|
+
if (targets.length !== 1) {
|
|
12947
|
+
throw new Error(`Stale ownership retirement requires exactly one destination Fleet target, found ${targets.length}.`);
|
|
12948
|
+
}
|
|
12949
|
+
const target = targets[0];
|
|
12950
|
+
if (target.fleetId !== options.fleet || resolve24(target.workspaceRoot) !== resolve24(fleet.root)) {
|
|
12951
|
+
throw new Error(`Resolved target does not belong to destination Fleet '${options.fleet}'.`);
|
|
12952
|
+
}
|
|
12953
|
+
const adapterOptions = adapterOptionsForTarget(target, normalizedOptions);
|
|
12954
|
+
const adapter = await resolveAdapterForTarget(target, adapterOptions);
|
|
12955
|
+
const installationType = normalizedOptions.installationType ?? target.installationType ?? resolveInstallationTypeForAdapter(adapter);
|
|
12956
|
+
const state = installStateForTarget(target, adapter, adapterOptions, installationType);
|
|
12957
|
+
const request = {
|
|
12958
|
+
targetRoot: state.installRoot,
|
|
12959
|
+
adapter: adapter.name,
|
|
12960
|
+
installationType,
|
|
12961
|
+
sourceStateKey: options.sourceStateKey,
|
|
12962
|
+
destinationStateKey: state.stateKey,
|
|
12963
|
+
fromWorkspaceRoot: normalizeCliPath(options.fromWorkspaceRoot),
|
|
12964
|
+
toWorkspaceRoot,
|
|
12965
|
+
toFleetId: fleet.id,
|
|
12966
|
+
planDigest: options.planDigest,
|
|
12967
|
+
expectedSourceRevision: options.expectedSourceRevision,
|
|
12968
|
+
expectedDestinationRevision: options.expectedDestinationRevision,
|
|
12969
|
+
expectedInventoryRevision: options.expectedInventoryRevision,
|
|
12970
|
+
transport: transportForTarget(target)
|
|
12971
|
+
};
|
|
12972
|
+
const result = options.apply ? await applyRetireStaleOwnership(request) : await planRetireStaleOwnership(request);
|
|
12973
|
+
const targetArgs = options.profile ? ["--profile", options.profile] : target.agentName ? ["--agent", target.agentName] : ["--adapter", adapter.name, "--target-root", target.targetRoot];
|
|
12974
|
+
const applyArgs = [
|
|
12975
|
+
"agentwheel",
|
|
12976
|
+
"ownership",
|
|
12977
|
+
"retire-stale",
|
|
12978
|
+
"--from-workspace-root",
|
|
12979
|
+
request.fromWorkspaceRoot,
|
|
12980
|
+
"--to-workspace-root",
|
|
12981
|
+
request.toWorkspaceRoot,
|
|
12982
|
+
"--source-state-key",
|
|
12983
|
+
request.sourceStateKey,
|
|
12984
|
+
"--fleet",
|
|
12985
|
+
request.toFleetId,
|
|
12986
|
+
...targetArgs,
|
|
12987
|
+
"--installation-type",
|
|
12988
|
+
installationType,
|
|
12989
|
+
...options.adapterConfig ? ["--adapter-config", options.adapterConfig] : [],
|
|
12990
|
+
...options.adapterModule ? ["--adapter-module", options.adapterModule] : [],
|
|
12991
|
+
...options.allowAdapterCode ? ["--allow-adapter-code"] : [],
|
|
12992
|
+
"--plan-digest",
|
|
12993
|
+
result.planDigest,
|
|
12994
|
+
"--expected-source-revision",
|
|
12995
|
+
result.source.revision,
|
|
12996
|
+
"--expected-destination-revision",
|
|
12997
|
+
result.destination.revision,
|
|
12998
|
+
"--expected-inventory-revision",
|
|
12999
|
+
result.manifestInventoryRevision,
|
|
13000
|
+
"--apply"
|
|
13001
|
+
];
|
|
13002
|
+
const applyCommand = applyArgs.map(shellQuoteArgument).join(" ");
|
|
13003
|
+
if (options.json) {
|
|
13004
|
+
console.log(JSON.stringify({ ...result, applyCommand }, null, 2));
|
|
13005
|
+
return;
|
|
13006
|
+
}
|
|
13007
|
+
console.log(`${options.apply ? "Retired stale ownership" : "Stale ownership retirement plan"}: ${result.selected.length} entr${result.selected.length === 1 ? "y" : "ies"}`);
|
|
13008
|
+
console.log(`Target: ${result.adapter}/${result.installationType} at ${result.targetRoot}`);
|
|
13009
|
+
console.log(`Source: ${result.source.stateKey} revision ${result.source.revision}`);
|
|
13010
|
+
console.log(`Destination: ${result.destination.stateKey} revision ${result.destination.revision}`);
|
|
13011
|
+
console.log(`Manifest inventory revision: ${result.manifestInventoryRevision}`);
|
|
13012
|
+
for (const entry of result.selected) console.log(`- ${entry.path}: ${entry.sourceEntryDigest} -> ${entry.destinationEntryDigest}`);
|
|
13013
|
+
console.log(`Plan digest: ${result.planDigest}`);
|
|
13014
|
+
if (!options.apply) console.log(`Apply: ${applyCommand}`);
|
|
13015
|
+
});
|
|
12691
13016
|
var mcpCommand = program.command("mcp").description("operate on MCP runtime configuration");
|
|
12692
13017
|
mcpCommand.command("retire").description("remove one exact legacy MCP contribution with explicit state ownership").argument("<package>", "configured package containing exactly one legacy MCP artifact").option("--user", "use the user workspace", false).option("--local", "use the nearest local workspace", false).option("--fleet <id>", "use one registered named fleet").option("-t, --target-root <path>", "explicit runtime/project root").option("--agent <name>", "one named agent from merged config").option("--profile <name>", "workspace runtime profile resolving to one target").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--from-workspace-root <path>", "required previous owner when managed legacy state exists").option("--dry-run", "show the retirement plan without writing (default)", false).option("--apply", "apply the exact reviewed retirement plan", false).option("--json", "print the install plan as JSON", false).action(async (packageName, options) => {
|
|
12693
13018
|
if (options.apply && options.dryRun) throw new Error("--apply cannot be combined with --dry-run.");
|
|
@@ -13678,7 +14003,7 @@ function scopeUpdatePlanToDependencies(result, selectors, previousLock, manifest
|
|
|
13678
14003
|
selectedPreviousNodeIds,
|
|
13679
14004
|
selectedRootIds
|
|
13680
14005
|
);
|
|
13681
|
-
const graphLockDigest =
|
|
14006
|
+
const graphLockDigest = createHash14("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
13682
14007
|
return {
|
|
13683
14008
|
...result,
|
|
13684
14009
|
bundle: { ...result.bundle, graphLock },
|
|
@@ -13804,7 +14129,7 @@ function operationBelongsToDependencyUpdate(operation, allowedNodeIds, allowedNa
|
|
|
13804
14129
|
function scopeInstallPlanToArtifact(result, rootId, focused, manifest) {
|
|
13805
14130
|
const scoped = scopePlanOperationsToArtifact(result, rootId, focused, manifest);
|
|
13806
14131
|
const graphLock = focusedGraphLockForInstall(scoped.bundle.graphLock, rootId, focused);
|
|
13807
|
-
const graphLockDigest =
|
|
14132
|
+
const graphLockDigest = createHash14("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
13808
14133
|
return {
|
|
13809
14134
|
...scoped,
|
|
13810
14135
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -13815,7 +14140,7 @@ function scopeInstallPlanToArtifact(result, rootId, focused, manifest) {
|
|
|
13815
14140
|
function scopeUpdatePlanToArtifact(result, rootId, focused, previousLock, manifest) {
|
|
13816
14141
|
const scoped = scopePlanOperationsToArtifact(result, rootId, focused, manifest, previousLock);
|
|
13817
14142
|
const graphLock = mergeFocusedArtifactGraphLock(scoped.bundle.graphLock, previousLock, rootId, focused);
|
|
13818
|
-
const graphLockDigest =
|
|
14143
|
+
const graphLockDigest = createHash14("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
13819
14144
|
return {
|
|
13820
14145
|
...scoped,
|
|
13821
14146
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -14110,7 +14435,7 @@ function scopeUpdatePlanToRoot(result, rootId, previousLock, manifest) {
|
|
|
14110
14435
|
selectedPreviousNodeIds,
|
|
14111
14436
|
/* @__PURE__ */ new Set([rootId])
|
|
14112
14437
|
);
|
|
14113
|
-
const graphLockDigest =
|
|
14438
|
+
const graphLockDigest = createHash14("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
14114
14439
|
return {
|
|
14115
14440
|
...scoped,
|
|
14116
14441
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -14666,7 +14991,7 @@ async function assertCompositeMutationSupported(workspaceRoot, profile, readOnly
|
|
|
14666
14991
|
`Composite-profile mutation is refused before member execution because ${member.id} uses ${member.transport}; durable remote policy and recovery preflight is not implemented.`
|
|
14667
14992
|
);
|
|
14668
14993
|
}
|
|
14669
|
-
const memberRoot =
|
|
14994
|
+
const memberRoot = resolve24(workspaceRoot, member.workspace);
|
|
14670
14995
|
const memberPolicy = await mutationPolicyForWorkspace(memberRoot);
|
|
14671
14996
|
if (memberPolicy?.revisioning.mode === "commit-after-verify") {
|
|
14672
14997
|
throw new Error(
|
|
@@ -15117,11 +15442,14 @@ function looksLikeSourceSpecifier(value) {
|
|
|
15117
15442
|
}
|
|
15118
15443
|
function normalizeCliPath(value) {
|
|
15119
15444
|
if (value === "~") return homedir12();
|
|
15120
|
-
if (value.startsWith("~/")) return
|
|
15121
|
-
return
|
|
15445
|
+
if (value.startsWith("~/")) return resolve24(homedir12(), value.slice(2));
|
|
15446
|
+
return resolve24(value);
|
|
15447
|
+
}
|
|
15448
|
+
function shellQuoteArgument(value) {
|
|
15449
|
+
return /^[a-z0-9_./:@%+=,-]+$/i.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
15122
15450
|
}
|
|
15123
15451
|
function isHomePath(path) {
|
|
15124
|
-
return
|
|
15452
|
+
return resolve24(path) === resolve24(homedir12());
|
|
15125
15453
|
}
|
|
15126
15454
|
function adapterListFromOption(adapter) {
|
|
15127
15455
|
if (!adapter) return [];
|
|
@@ -15242,7 +15570,7 @@ function withFleetExample(config) {
|
|
|
15242
15570
|
};
|
|
15243
15571
|
}
|
|
15244
15572
|
async function findAgentwheelPackageRoot(start) {
|
|
15245
|
-
let current =
|
|
15573
|
+
let current = resolve24(start);
|
|
15246
15574
|
while (true) {
|
|
15247
15575
|
if (await findPackageManifestPath(current, { warnLegacy: false })) return current;
|
|
15248
15576
|
const parent = dirname22(current);
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
applyLockPath,
|
|
9
9
|
assertApplyJournalRecoveryAllowed,
|
|
10
10
|
assertGovernedRuntimeTransportSupported,
|
|
11
|
+
listAllApplyJournals,
|
|
11
12
|
listApplyJournals,
|
|
12
13
|
localPathExists,
|
|
13
14
|
mutationMetadataForApplyJournal,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
removeApplyJournal,
|
|
18
19
|
rollbackCompletedOperations,
|
|
19
20
|
writeApplyJournal
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-Z4N7TB6Q.js";
|
|
21
22
|
import "./chunk-7VPI5J5Y.js";
|
|
22
23
|
export {
|
|
23
24
|
abortApplyJournal,
|
|
@@ -28,6 +29,7 @@ export {
|
|
|
28
29
|
applyLockPath,
|
|
29
30
|
assertApplyJournalRecoveryAllowed,
|
|
30
31
|
assertGovernedRuntimeTransportSupported,
|
|
32
|
+
listAllApplyJournals,
|
|
31
33
|
listApplyJournals,
|
|
32
34
|
localPathExists,
|
|
33
35
|
mutationMetadataForApplyJournal,
|
package/openpack.json
CHANGED
package/package.json
CHANGED