agentwheel 0.20.1 → 0.20.3
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 +431 -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,259 @@ 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, normalized.abandonIncompleteMergeOwner === true);
|
|
9376
|
+
const destinationEntry = candidates[0];
|
|
9377
|
+
const coverage = await assertContributionCoverage(
|
|
9378
|
+
sourceEntry,
|
|
9379
|
+
destinationEntry,
|
|
9380
|
+
normalized.targetRoot,
|
|
9381
|
+
transport,
|
|
9382
|
+
normalized.abandonIncompleteMergeOwner === true
|
|
9383
|
+
);
|
|
9384
|
+
const runtimeHash = coverage === "abandoned-incomplete-merge" ? await transport.hashPath(containedArtifactPath(normalized.targetRoot, destinationEntry.path)) : await verifyManifestEntryRuntime(normalized.targetRoot, destinationEntry, transport);
|
|
9385
|
+
selected.push({
|
|
9386
|
+
path: sourceEntry.path,
|
|
9387
|
+
sourceEntryDigest: entryDigest(sourceEntry),
|
|
9388
|
+
destinationEntryDigest: entryDigest(destinationEntry),
|
|
9389
|
+
runtimeHash,
|
|
9390
|
+
coverage
|
|
9391
|
+
});
|
|
9392
|
+
}
|
|
9393
|
+
selected.sort((a, b) => a.path.localeCompare(b.path) || a.sourceEntryDigest.localeCompare(b.sourceEntryDigest) || a.destinationEntryDigest.localeCompare(b.destinationEntryDigest));
|
|
9394
|
+
if (selected.length === 0) {
|
|
9395
|
+
throw new Error("No stale source ownership entries match an exact path in the destination Fleet manifest.");
|
|
9396
|
+
}
|
|
9397
|
+
const withoutDigest = {
|
|
9398
|
+
adapter: normalized.adapter,
|
|
9399
|
+
installationType: normalized.installationType,
|
|
9400
|
+
targetRoot: normalized.targetRoot,
|
|
9401
|
+
source: {
|
|
9402
|
+
stateKey: normalized.sourceStateKey,
|
|
9403
|
+
manifestPath: installManifestPath(normalized.targetRoot, normalized.adapter, {
|
|
9404
|
+
installationType: normalized.installationType,
|
|
9405
|
+
stateKey: normalized.sourceStateKey
|
|
9406
|
+
}),
|
|
9407
|
+
revision: source.revision,
|
|
9408
|
+
owner: sourceOwner
|
|
9409
|
+
},
|
|
9410
|
+
destination: {
|
|
9411
|
+
stateKey: normalized.destinationStateKey,
|
|
9412
|
+
manifestPath: installManifestPath(normalized.targetRoot, normalized.adapter, {
|
|
9413
|
+
installationType: normalized.installationType,
|
|
9414
|
+
stateKey: normalized.destinationStateKey
|
|
9415
|
+
}),
|
|
9416
|
+
revision: destination.revision,
|
|
9417
|
+
owner: destinationOwner,
|
|
9418
|
+
fleetId: normalized.toFleetId
|
|
9419
|
+
},
|
|
9420
|
+
manifestInventoryRevision: await computeInstallManifestInventoryRevision(
|
|
9421
|
+
normalized.targetRoot,
|
|
9422
|
+
normalized.adapter,
|
|
9423
|
+
transport
|
|
9424
|
+
),
|
|
9425
|
+
selected
|
|
9426
|
+
};
|
|
9427
|
+
return { ...withoutDigest, planDigest: digest(withoutDigest) };
|
|
9428
|
+
}
|
|
9429
|
+
function normalizeRequest(request) {
|
|
9430
|
+
const targetRoot = resolve20(request.targetRoot);
|
|
9431
|
+
const sourceStateKey = exactStateKey(request.adapter, request.sourceStateKey, request.installationType, "source");
|
|
9432
|
+
const destinationStateKey = exactStateKey(request.adapter, request.destinationStateKey, request.installationType, "destination");
|
|
9433
|
+
if (sourceStateKey === destinationStateKey) throw new Error("Source and destination state keys must differ.");
|
|
9434
|
+
if (!request.toFleetId.trim()) throw new Error("Destination Fleet id is required.");
|
|
9435
|
+
return {
|
|
9436
|
+
...request,
|
|
9437
|
+
targetRoot,
|
|
9438
|
+
installationType: request.installationType.trim(),
|
|
9439
|
+
sourceStateKey,
|
|
9440
|
+
destinationStateKey,
|
|
9441
|
+
fromWorkspaceRoot: resolve20(request.fromWorkspaceRoot),
|
|
9442
|
+
toWorkspaceRoot: resolve20(request.toWorkspaceRoot),
|
|
9443
|
+
toFleetId: request.toFleetId.trim()
|
|
9444
|
+
};
|
|
9445
|
+
}
|
|
9446
|
+
function exactStateKey(adapter, value, installationType, label) {
|
|
9447
|
+
if (!value || stateKeyFor(adapter, { installationType, stateKey: value }) !== value) {
|
|
9448
|
+
throw new Error(`The ${label} state key must be an exact canonical state key.`);
|
|
9449
|
+
}
|
|
9450
|
+
return value;
|
|
9451
|
+
}
|
|
9452
|
+
async function requireManifest(request, stateKey, transport, label) {
|
|
9453
|
+
const manifest = await readInstallManifest(request.targetRoot, request.adapter, transport, {
|
|
9454
|
+
installationType: request.installationType,
|
|
9455
|
+
stateKey
|
|
9456
|
+
});
|
|
9457
|
+
if (!manifest) throw new Error(`No ${label} install manifest for state key ${stateKey}.`);
|
|
9458
|
+
if (manifest.version !== 2) throw new Error(`${label} ownership retirement requires an Agentwheel v2 install manifest.`);
|
|
9459
|
+
const actualStateKey = stateKeyFor(manifest.adapter, {
|
|
9460
|
+
installationType: manifest.installationType,
|
|
9461
|
+
stateKey: manifest.stateKey
|
|
9462
|
+
});
|
|
9463
|
+
if (manifest.adapter !== request.adapter || manifest.installationType !== request.installationType || resolve20(manifest.targetRoot) !== request.targetRoot || actualStateKey !== stateKey) {
|
|
9464
|
+
throw new Error(`${label} install manifest identity does not match the requested adapter, target, installation type, and state key.`);
|
|
9465
|
+
}
|
|
9466
|
+
return manifest;
|
|
9467
|
+
}
|
|
9468
|
+
function assertRetirableSourceEntry(entry, abandonIncompleteMergeOwner) {
|
|
9469
|
+
if (entry.semanticPlugin || entry.semanticCommand || entry.executed) {
|
|
9470
|
+
throw new Error(`Cannot retire semantic source ownership at ${entry.path}.`);
|
|
9471
|
+
}
|
|
9472
|
+
if (entry.mergeStrategy && !hasMergeRemovalContent(entry.mergeRemoval)) {
|
|
9473
|
+
if (abandonIncompleteMergeOwner) return;
|
|
9474
|
+
throw new Error(`Cannot retire incomplete merge ownership at ${entry.path}.`);
|
|
9475
|
+
}
|
|
9476
|
+
}
|
|
9477
|
+
async function assertContributionCoverage(source, destination, targetRoot, transport, abandonIncompleteMergeOwner) {
|
|
9478
|
+
const sourceManagedBlock = source.mode === "managed-block";
|
|
9479
|
+
const destinationManagedBlock = destination.mode === "managed-block";
|
|
9480
|
+
const sourceMerge = source.mergeStrategy !== void 0;
|
|
9481
|
+
const destinationMerge = destination.mergeStrategy !== void 0;
|
|
9482
|
+
const sourceCategory = sourceManagedBlock ? "managed-block" : sourceMerge ? "merge" : "plain";
|
|
9483
|
+
const destinationCategory = destinationManagedBlock ? "managed-block" : destinationMerge ? "merge" : "plain";
|
|
9484
|
+
if (sourceCategory !== destinationCategory) {
|
|
9485
|
+
throw new Error(
|
|
9486
|
+
`Destination Fleet ownership category ${destinationCategory} cannot replace stale source category ${sourceCategory} at ${source.path}.`
|
|
9487
|
+
);
|
|
9488
|
+
}
|
|
9489
|
+
if (sourceCategory === "plain") return "exact";
|
|
9490
|
+
if (sourceManagedBlock) {
|
|
9491
|
+
const sourceSelector = managedInstructionSelector(source.logicalSelector, source.artifactType, source.artifactName);
|
|
9492
|
+
const destinationSelector = managedInstructionSelector(destination.logicalSelector, destination.artifactType, destination.artifactName);
|
|
9493
|
+
if (!sourceManagedBlock || !destinationManagedBlock || sourceSelector !== destinationSelector) {
|
|
9494
|
+
throw new Error(`Destination Fleet does not exactly cover stale source managed block contribution at ${source.path}.`);
|
|
9495
|
+
}
|
|
9496
|
+
return "exact";
|
|
9497
|
+
}
|
|
9498
|
+
if (source.mergeStrategy && destination.mergeStrategy) {
|
|
9499
|
+
if (!hasMergeRemovalContent(source.mergeRemoval)) {
|
|
9500
|
+
if (abandonIncompleteMergeOwner) return "abandoned-incomplete-merge";
|
|
9501
|
+
throw new Error(`Cannot retire incomplete merge ownership at ${source.path}.`);
|
|
9502
|
+
}
|
|
9503
|
+
const exactlyCovered = destination.mergeStrategy === source.mergeStrategy && hasMergeRemovalContent(destination.mergeRemoval) && contributionSelector(source) === contributionSelector(destination) && canonicalJson(source.mergeRemoval) === canonicalJson(destination.mergeRemoval);
|
|
9504
|
+
if (exactlyCovered) return "exact";
|
|
9505
|
+
const current = await transport.readFile(containedArtifactPath(targetRoot, source.path));
|
|
9506
|
+
if (!mergeContributionAbsent(source.mergeRemoval, source.mergeStrategy, current)) {
|
|
9507
|
+
throw new Error(`Destination Fleet does not exactly cover or replace stale source merge contribution at ${source.path}.`);
|
|
9508
|
+
}
|
|
9509
|
+
return "exact";
|
|
9510
|
+
}
|
|
9511
|
+
throw new Error(`Unsupported ownership coverage at ${source.path}.`);
|
|
9512
|
+
}
|
|
9513
|
+
function contributionSelector(entry) {
|
|
9514
|
+
return entry.logicalSelector ?? `${entry.artifactType}/${entry.artifactName}`;
|
|
9515
|
+
}
|
|
9516
|
+
function assertApplyPreconditions(request) {
|
|
9517
|
+
for (const [label, value] of [
|
|
9518
|
+
["plan digest", request.planDigest],
|
|
9519
|
+
["source manifest revision", request.expectedSourceRevision],
|
|
9520
|
+
["destination manifest revision", request.expectedDestinationRevision],
|
|
9521
|
+
["manifest inventory revision", request.expectedInventoryRevision]
|
|
9522
|
+
]) {
|
|
9523
|
+
if (!value || !/^[a-f0-9]{64}$/.test(value)) {
|
|
9524
|
+
throw new Error(`Applying stale ownership retirement requires a reviewed lowercase SHA-256 ${label}.`);
|
|
9525
|
+
}
|
|
9526
|
+
}
|
|
9527
|
+
}
|
|
9528
|
+
function assertExpected(expected, current, label) {
|
|
9529
|
+
if (expected !== current) throw new Error(`Stale ${label}: expected ${expected}, found ${current}; replan required.`);
|
|
9530
|
+
}
|
|
9531
|
+
function entryDigest(entry) {
|
|
9532
|
+
return digest(entry);
|
|
9533
|
+
}
|
|
9534
|
+
function digest(value) {
|
|
9535
|
+
return createHash9("sha256").update(canonicalJson(value)).digest("hex");
|
|
9536
|
+
}
|
|
9537
|
+
function canonicalJson(value) {
|
|
9538
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
|
|
9539
|
+
if (!value || typeof value !== "object") return JSON.stringify(value);
|
|
9540
|
+
const record = value;
|
|
9541
|
+
return `{${Object.keys(record).filter((key) => record[key] !== void 0).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
|
|
9542
|
+
}
|
|
9543
|
+
|
|
9285
9544
|
// src/version/policy.ts
|
|
9286
9545
|
import { execFile as execFile3 } from "child_process";
|
|
9287
9546
|
import { readFile as readFile23 } from "fs/promises";
|
|
9288
|
-
import { join as join39, resolve as
|
|
9547
|
+
import { join as join39, resolve as resolve21 } from "path";
|
|
9289
9548
|
import { promisify as promisify3 } from "util";
|
|
9290
9549
|
import { parse as parseJsonc } from "jsonc-parser";
|
|
9291
9550
|
import { z as z5 } from "zod";
|
|
@@ -9379,7 +9638,7 @@ async function discoverVersionsFromSource(pkg, workspaceRoot) {
|
|
|
9379
9638
|
if (tagged.length > 0) return tagged;
|
|
9380
9639
|
}
|
|
9381
9640
|
if (driverName === "local") {
|
|
9382
|
-
const root =
|
|
9641
|
+
const root = resolve21(workspaceRoot, pkg.source);
|
|
9383
9642
|
const manifest2 = await readPackageManifest(root);
|
|
9384
9643
|
const current = manifest2 ? [{ version: manifest2.version, ref: pkg.requestedRef ?? root }] : [];
|
|
9385
9644
|
try {
|
|
@@ -9502,7 +9761,7 @@ async function readVersionCache(path) {
|
|
|
9502
9761
|
// src/profile/members.ts
|
|
9503
9762
|
import { execFile as execFile4 } from "child_process";
|
|
9504
9763
|
import { readFile as readFile24 } from "fs/promises";
|
|
9505
|
-
import { join as join40, resolve as
|
|
9764
|
+
import { join as join40, resolve as resolve22 } from "path";
|
|
9506
9765
|
import { promisify as promisify4 } from "util";
|
|
9507
9766
|
import { z as z7 } from "zod";
|
|
9508
9767
|
|
|
@@ -9677,7 +9936,7 @@ async function invokeMemberStatus(member, parentWorkspace, chain, options, cliEn
|
|
|
9677
9936
|
let stderr = "";
|
|
9678
9937
|
try {
|
|
9679
9938
|
if (member.transport === "local") {
|
|
9680
|
-
const workspace =
|
|
9939
|
+
const workspace = resolve22(parentWorkspace, member.workspace);
|
|
9681
9940
|
const result = await execFileAsync4(process.execPath, [cliEntry, ...args], {
|
|
9682
9941
|
cwd: workspace,
|
|
9683
9942
|
env: env2,
|
|
@@ -9723,7 +9982,7 @@ async function runMemberAgentwheel(member, parentWorkspace, args, chain) {
|
|
|
9723
9982
|
process.execPath,
|
|
9724
9983
|
[process.argv[1], "--no-update-check", ...args],
|
|
9725
9984
|
{
|
|
9726
|
-
cwd:
|
|
9985
|
+
cwd: resolve22(parentWorkspace, member.workspace),
|
|
9727
9986
|
env: env2,
|
|
9728
9987
|
maxBuffer: 20 * 1024 * 1024
|
|
9729
9988
|
}
|
|
@@ -9824,7 +10083,7 @@ function assertNoCompositeCycle(workspaceRoot, profileName, chain) {
|
|
|
9824
10083
|
}
|
|
9825
10084
|
}
|
|
9826
10085
|
function compositeKey(workspaceRoot, profileName) {
|
|
9827
|
-
return `${
|
|
10086
|
+
return `${resolve22(workspaceRoot)}#${profileName}`;
|
|
9828
10087
|
}
|
|
9829
10088
|
|
|
9830
10089
|
// src/status/repository.ts
|
|
@@ -9871,7 +10130,7 @@ function valueAfter(lines, prefix) {
|
|
|
9871
10130
|
}
|
|
9872
10131
|
|
|
9873
10132
|
// src/catalogue/client.ts
|
|
9874
|
-
import { createHash as
|
|
10133
|
+
import { createHash as createHash10 } from "crypto";
|
|
9875
10134
|
import { readFile as readFile25, rm as rm8 } from "fs/promises";
|
|
9876
10135
|
import { homedir as homedir9 } from "os";
|
|
9877
10136
|
import { join as join41 } from "path";
|
|
@@ -10146,7 +10405,7 @@ var CatalogueClient = class {
|
|
|
10146
10405
|
}
|
|
10147
10406
|
return {
|
|
10148
10407
|
value: schema.parse(value),
|
|
10149
|
-
digest:
|
|
10408
|
+
digest: createHash10("sha256").update(bytes).digest("hex")
|
|
10150
10409
|
};
|
|
10151
10410
|
}
|
|
10152
10411
|
};
|
|
@@ -10157,7 +10416,7 @@ function sameSources2(a, b) {
|
|
|
10157
10416
|
return a.length === b.length && a.every((source, index) => source === b[index]);
|
|
10158
10417
|
}
|
|
10159
10418
|
function catalogueContentHash(enriched, vercel) {
|
|
10160
|
-
return
|
|
10419
|
+
return createHash10("sha256").update(JSON.stringify({ enriched, vercel })).digest("hex");
|
|
10161
10420
|
}
|
|
10162
10421
|
|
|
10163
10422
|
// src/search/index.ts
|
|
@@ -10519,7 +10778,7 @@ function includesToken(normalizedText, token) {
|
|
|
10519
10778
|
}
|
|
10520
10779
|
|
|
10521
10780
|
// src/semantic/index.ts
|
|
10522
|
-
import { createHash as
|
|
10781
|
+
import { createHash as createHash11 } from "crypto";
|
|
10523
10782
|
import { homedir as homedir10 } from "os";
|
|
10524
10783
|
import { join as join42 } from "path";
|
|
10525
10784
|
import { env, pipeline } from "@huggingface/transformers";
|
|
@@ -10609,8 +10868,8 @@ var SemanticSearchClient = class {
|
|
|
10609
10868
|
if (!response.ok) throw new Error(`Semantic index file failed (${response.status}): ${descriptor.path}`);
|
|
10610
10869
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
10611
10870
|
if (bytes.byteLength !== descriptor.bytes) throw new Error(`Semantic index file size does not match: ${descriptor.path}`);
|
|
10612
|
-
const
|
|
10613
|
-
if (
|
|
10871
|
+
const digest2 = createHash11("sha256").update(bytes).digest("hex");
|
|
10872
|
+
if (digest2 !== descriptor.sha256) throw new Error(`Semantic index checksum does not match: ${descriptor.path}`);
|
|
10614
10873
|
return bytes;
|
|
10615
10874
|
}
|
|
10616
10875
|
};
|
|
@@ -10699,7 +10958,7 @@ function ensureTrailingSlash(value) {
|
|
|
10699
10958
|
}
|
|
10700
10959
|
|
|
10701
10960
|
// src/trial/skill.ts
|
|
10702
|
-
import { createHash as
|
|
10961
|
+
import { createHash as createHash12 } from "crypto";
|
|
10703
10962
|
import { readFile as readFile26, stat as stat13 } from "fs/promises";
|
|
10704
10963
|
import { join as join43 } from "path";
|
|
10705
10964
|
import { parse as parseYaml2 } from "yaml";
|
|
@@ -10729,7 +10988,7 @@ async function createSkillTrial(driver, resolved, selectors) {
|
|
|
10729
10988
|
skill: {
|
|
10730
10989
|
name: artifact.name,
|
|
10731
10990
|
relativePath: artifact.relativePath,
|
|
10732
|
-
sha256:
|
|
10991
|
+
sha256: createHash12("sha256").update(content).digest("hex"),
|
|
10733
10992
|
frontmatter,
|
|
10734
10993
|
content
|
|
10735
10994
|
}
|
|
@@ -10748,12 +11007,12 @@ function readSkillFrontmatter(content, artifact) {
|
|
|
10748
11007
|
}
|
|
10749
11008
|
|
|
10750
11009
|
// src/lifecycle/fleet-normalize.ts
|
|
10751
|
-
import { createHash as
|
|
11010
|
+
import { createHash as createHash13 } from "crypto";
|
|
10752
11011
|
import { readFile as readFile27, readdir as readdir9, rm as rm9 } from "fs/promises";
|
|
10753
11012
|
import { homedir as homedir11 } from "os";
|
|
10754
|
-
import { basename as basename19, isAbsolute as isAbsolute3, join as join44, relative as relative8, resolve as
|
|
11013
|
+
import { basename as basename19, isAbsolute as isAbsolute3, join as join44, relative as relative8, resolve as resolve23 } from "path";
|
|
10755
11014
|
async function planFleetNormalization(request) {
|
|
10756
|
-
const normalizedRequest =
|
|
11015
|
+
const normalizedRequest = normalizeRequest2(request);
|
|
10757
11016
|
const destinationScope = await resolveWorkspaceScope({
|
|
10758
11017
|
fleet: normalizedRequest.destinationFleet,
|
|
10759
11018
|
globalRoot: normalizedRequest.globalRoot
|
|
@@ -10774,8 +11033,8 @@ async function planFleetNormalization(request) {
|
|
|
10774
11033
|
if (!sourcePackage || !destinationPackage) {
|
|
10775
11034
|
throw new Error(`Package '${name}' must be an existing duplicate in both source and destination fleets.`);
|
|
10776
11035
|
}
|
|
10777
|
-
const sourceDeclaration =
|
|
10778
|
-
const destinationDeclaration =
|
|
11036
|
+
const sourceDeclaration = canonicalJson2(sourcePackage);
|
|
11037
|
+
const destinationDeclaration = canonicalJson2(destinationPackage);
|
|
10779
11038
|
if (sourceDeclaration !== destinationDeclaration) {
|
|
10780
11039
|
throw new Error(
|
|
10781
11040
|
`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 +11071,13 @@ async function planFleetNormalization(request) {
|
|
|
10812
11071
|
packages,
|
|
10813
11072
|
installedState
|
|
10814
11073
|
};
|
|
10815
|
-
return { ...planWithoutDigest, planDigest: sha2564(
|
|
11074
|
+
return { ...planWithoutDigest, planDigest: sha2564(canonicalJson2(planWithoutDigest)) };
|
|
10816
11075
|
}
|
|
10817
11076
|
async function applyFleetNormalization(request, hooks = {}) {
|
|
10818
11077
|
if (!request.apply) throw new Error("Fleet normalization is dry-run by default; pass --apply with --plan-digest <digest>.");
|
|
10819
11078
|
if (!request.planDigest) throw new Error("Applying fleet normalization requires --plan-digest <digest> from a reviewed dry-run.");
|
|
10820
11079
|
assertDigest(request.planDigest);
|
|
10821
|
-
const normalizedRequest =
|
|
11080
|
+
const normalizedRequest = normalizeRequest2(request);
|
|
10822
11081
|
const roots = await normalizationRoots(normalizedRequest);
|
|
10823
11082
|
const ordered = [.../* @__PURE__ */ new Set([roots.source, roots.destination])].sort((a, b) => a.localeCompare(b));
|
|
10824
11083
|
return withOrderedLocks(ordered, async () => {
|
|
@@ -10950,14 +11209,14 @@ async function assertNormalizationPostconditions(journal) {
|
|
|
10950
11209
|
}
|
|
10951
11210
|
for (const graphLock of journal.graphLocks) {
|
|
10952
11211
|
const raw = await readOptionalRecord(graphLock.path);
|
|
10953
|
-
const
|
|
10954
|
-
if (
|
|
11212
|
+
const digest2 = raw ? sha2564(canonicalJson2(await readGraphLock(graphLock.path))) : null;
|
|
11213
|
+
if (digest2 !== graphLock.afterDigest) {
|
|
10955
11214
|
throw new Error(`Fleet normalization graph-lock postcheck failed: ${graphLock.path}`);
|
|
10956
11215
|
}
|
|
10957
11216
|
}
|
|
10958
11217
|
}
|
|
10959
11218
|
async function recoverFleetNormalization(request) {
|
|
10960
|
-
const normalizedRequest =
|
|
11219
|
+
const normalizedRequest = normalizeRequest2(request);
|
|
10961
11220
|
const roots = await normalizationRoots(normalizedRequest);
|
|
10962
11221
|
const ordered = [.../* @__PURE__ */ new Set([roots.source, roots.destination])].sort((a, b) => a.localeCompare(b));
|
|
10963
11222
|
return withOrderedLocks(ordered, async () => {
|
|
@@ -11000,7 +11259,7 @@ async function assertSourceFleetPostcondition(request, source, selectedPackages)
|
|
|
11000
11259
|
);
|
|
11001
11260
|
}
|
|
11002
11261
|
}
|
|
11003
|
-
function
|
|
11262
|
+
function normalizeRequest2(request) {
|
|
11004
11263
|
const packages = request.packages === void 0 ? void 0 : sortedUnique6(request.packages);
|
|
11005
11264
|
if (request.packages !== void 0 && packages?.length === 0) throw new Error("--package requires at least one package name.");
|
|
11006
11265
|
const artifacts = request.artifacts === void 0 ? void 0 : sortedUnique6(request.artifacts.map((artifact) => normalizeArtifactSelector(artifact)));
|
|
@@ -11022,17 +11281,17 @@ function normalizeRequest(request) {
|
|
|
11022
11281
|
...profile ? { profile } : {},
|
|
11023
11282
|
...agent ? { agent } : {},
|
|
11024
11283
|
...orphanedOwnerRoots ? { orphanedOwnerRoots } : {},
|
|
11025
|
-
...request.globalRoot ? { globalRoot:
|
|
11284
|
+
...request.globalRoot ? { globalRoot: resolve23(request.globalRoot) } : {}
|
|
11026
11285
|
};
|
|
11027
11286
|
}
|
|
11028
11287
|
function normalizeOrphanedOwnerRoot(value) {
|
|
11029
11288
|
const root = value.trim();
|
|
11030
11289
|
if (!root || !isAbsolute3(root)) throw new Error(`Invalid orphaned owner root '${value}'; expected an absolute workspace path.`);
|
|
11031
|
-
return
|
|
11290
|
+
return resolve23(root);
|
|
11032
11291
|
}
|
|
11033
11292
|
async function normalizationRoots(request) {
|
|
11034
11293
|
const destination = await showRegisteredFleet(request.destinationFleet, { globalRoot: request.globalRoot });
|
|
11035
|
-
const source = request.from === "user" ?
|
|
11294
|
+
const source = request.from === "user" ? resolve23(request.globalRoot ?? homedir11()) : (await showRegisteredFleet(request.from.slice("fleet:".length), { globalRoot: request.globalRoot })).root;
|
|
11036
11295
|
return { source, destination: destination.root };
|
|
11037
11296
|
}
|
|
11038
11297
|
async function withOrderedLocks(roots, fn) {
|
|
@@ -11123,10 +11382,10 @@ async function inspectInstalledState(source, destination, packageNames) {
|
|
|
11123
11382
|
const destinationGraphAfter = destinationGraph?.lock ?? destinationGraphFromSource(sourceGraph.lock, destinationState.targetFingerprint);
|
|
11124
11383
|
graphTransfers.push({
|
|
11125
11384
|
sourceGraphLockPath: sourceGraph.path,
|
|
11126
|
-
sourceGraphLockDigest: sha2564(
|
|
11385
|
+
sourceGraphLockDigest: sha2564(canonicalJson2(sourceGraph.lock)),
|
|
11127
11386
|
destinationGraphLockPath: destinationState.graphLockPath,
|
|
11128
|
-
destinationGraphLockDigest: destinationGraph ? sha2564(
|
|
11129
|
-
destinationGraphLockAfterDigest: sha2564(
|
|
11387
|
+
destinationGraphLockDigest: destinationGraph ? sha2564(canonicalJson2(destinationGraph.lock)) : null,
|
|
11388
|
+
destinationGraphLockAfterDigest: sha2564(canonicalJson2(destinationGraphAfter)),
|
|
11130
11389
|
targetKey: sourceGraph.targetKey,
|
|
11131
11390
|
adapter: destinationState.adapter,
|
|
11132
11391
|
targetFingerprint: destinationState.targetFingerprint
|
|
@@ -11339,7 +11598,7 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
|
|
|
11339
11598
|
)
|
|
11340
11599
|
});
|
|
11341
11600
|
if (!selectedArtifacts) {
|
|
11342
|
-
const fullDigest = sha2564(
|
|
11601
|
+
const fullDigest = sha2564(canonicalJson2(graph.lock));
|
|
11343
11602
|
const existingDestinationGraph = graphCandidates.find((candidate) => candidate.path === destinationState.graphLockPath);
|
|
11344
11603
|
if (existingDestinationGraph) assertGraphIsSubset(graph, existingDestinationGraph);
|
|
11345
11604
|
const destinationGraph = destinationGraphFromSource(graph.lock, destinationState.targetFingerprint);
|
|
@@ -11347,8 +11606,8 @@ async function inspectLegacySelfInstalledState(fleet, packageNames, profileName,
|
|
|
11347
11606
|
sourceGraphLockPath: graph.path,
|
|
11348
11607
|
sourceGraphLockDigest: fullDigest,
|
|
11349
11608
|
destinationGraphLockPath: destinationState.graphLockPath,
|
|
11350
|
-
destinationGraphLockDigest: existingDestinationGraph ? sha2564(
|
|
11351
|
-
destinationGraphLockAfterDigest: sha2564(
|
|
11609
|
+
destinationGraphLockDigest: existingDestinationGraph ? sha2564(canonicalJson2(existingDestinationGraph.lock)) : null,
|
|
11610
|
+
destinationGraphLockAfterDigest: sha2564(canonicalJson2(destinationGraph)),
|
|
11352
11611
|
targetKey: graph.targetKey,
|
|
11353
11612
|
adapter: graph.adapter,
|
|
11354
11613
|
targetFingerprint: destinationState.targetFingerprint
|
|
@@ -11406,7 +11665,7 @@ function targetKeysForAgent(scope, name) {
|
|
|
11406
11665
|
async function runtimeRoots(scope) {
|
|
11407
11666
|
const roots = /* @__PURE__ */ new Set([scope.root]);
|
|
11408
11667
|
if (scope.config.packages.some((pkg) => pkg.installationType === "user") || Object.values(scope.config.agents).some((agent) => agent.installationType === "user")) {
|
|
11409
|
-
roots.add(
|
|
11668
|
+
roots.add(resolve23(process.env.AGENTWHEEL_TEST_HOME || process.env.HOME || homedir11()));
|
|
11410
11669
|
}
|
|
11411
11670
|
for (const [name, agent] of Object.entries(scope.config.agents)) {
|
|
11412
11671
|
if (agent.transport === "ssh") throw new Error(`Installed-state normalization cannot inspect SSH agent '${name}' locally.`);
|
|
@@ -11443,14 +11702,14 @@ async function collectManifests(roots) {
|
|
|
11443
11702
|
}
|
|
11444
11703
|
continue;
|
|
11445
11704
|
}
|
|
11446
|
-
if (
|
|
11705
|
+
if (resolve23(parsed.targetRoot) !== resolve23(root)) {
|
|
11447
11706
|
throw new Error(`Install manifest target root does not match its enumerated runtime root: ${path}`);
|
|
11448
11707
|
}
|
|
11449
11708
|
const expectedPath = installManifestPath(parsed.targetRoot, parsed.adapter, {
|
|
11450
11709
|
installationType: parsed.installationType,
|
|
11451
11710
|
stateKey: parsed.stateKey
|
|
11452
11711
|
});
|
|
11453
|
-
if (
|
|
11712
|
+
if (resolve23(expectedPath) !== resolve23(path)) {
|
|
11454
11713
|
throw new Error(`Install manifest state identity does not match its canonical path: ${path}`);
|
|
11455
11714
|
}
|
|
11456
11715
|
found.set(path, { path, raw, manifest: { ...parsed, revision: computeManifestRevision(raw), legacy: false } });
|
|
@@ -11471,7 +11730,7 @@ async function collectManifestPaths(paths) {
|
|
|
11471
11730
|
installationType: parsed.installationType,
|
|
11472
11731
|
stateKey: parsed.stateKey
|
|
11473
11732
|
});
|
|
11474
|
-
if (
|
|
11733
|
+
if (resolve23(expectedPath) !== resolve23(path)) {
|
|
11475
11734
|
throw new Error(`Install manifest state identity does not match its canonical path: ${path}`);
|
|
11476
11735
|
}
|
|
11477
11736
|
found.push({ path, raw, manifest: { ...parsed, revision: computeManifestRevision(raw), legacy: false } });
|
|
@@ -11518,7 +11777,7 @@ async function relevantGraphLocks(workspaceRoot, selected, targetKeys, include)
|
|
|
11518
11777
|
const projection = relevantGraphProjection(lock, selected);
|
|
11519
11778
|
results.push({
|
|
11520
11779
|
...candidate,
|
|
11521
|
-
digest: sha2564(
|
|
11780
|
+
digest: sha2564(canonicalJson2(projection)),
|
|
11522
11781
|
artifactIdentities: lock.canonical.artifacts.filter((artifact) => artifact.owners.some((owner) => ownerMatchesGraphPackage(lock, owner, selected))).map(graphArtifactIdentity).sort()
|
|
11523
11782
|
});
|
|
11524
11783
|
}
|
|
@@ -11554,7 +11813,7 @@ async function legacyManifestPathForConfiguredTarget(scope, graph) {
|
|
|
11554
11813
|
baseDir: scope.root
|
|
11555
11814
|
});
|
|
11556
11815
|
const targetRoot = resolveConfigPath(agent.root, scope.root);
|
|
11557
|
-
const installRoot =
|
|
11816
|
+
const installRoot = resolve23(installRootForAdapterInstallationType(adapter, targetRoot, agent.installationType, false));
|
|
11558
11817
|
const stateKey = stateKeyFor(adapter.name, {
|
|
11559
11818
|
installationType: agent.installationType,
|
|
11560
11819
|
targetFingerprint: graph.lock.canonical.targetFingerprint
|
|
@@ -11628,7 +11887,7 @@ async function targetStateForGraph(scope, graph, identityFleetId = scope.fleetId
|
|
|
11628
11887
|
targetFingerprint,
|
|
11629
11888
|
...identityFleetId ? { fleetId: identityFleetId } : {}
|
|
11630
11889
|
});
|
|
11631
|
-
const installRoot =
|
|
11890
|
+
const installRoot = resolve23(installRootForAdapterInstallationType(adapter, targetRoot, installationType, false));
|
|
11632
11891
|
return {
|
|
11633
11892
|
adapter: adapter.name,
|
|
11634
11893
|
installationType,
|
|
@@ -11659,9 +11918,9 @@ async function legacyTargetStateForGraph(scope, graph) {
|
|
|
11659
11918
|
};
|
|
11660
11919
|
}
|
|
11661
11920
|
function assertGraphIsSubset(source, destination) {
|
|
11662
|
-
const sourceRoots = new Map(source.lock.canonical.roots.map((root) => [root.rootId,
|
|
11921
|
+
const sourceRoots = new Map(source.lock.canonical.roots.map((root) => [root.rootId, canonicalJson2(root)]));
|
|
11663
11922
|
for (const root of destination.lock.canonical.roots) {
|
|
11664
|
-
if (sourceRoots.get(root.rootId) !==
|
|
11923
|
+
if (sourceRoots.get(root.rootId) !== canonicalJson2(root)) {
|
|
11665
11924
|
throw new Error(
|
|
11666
11925
|
`Partially normalized destination graph diverges at root '${root.rootId}': ${destination.path}`
|
|
11667
11926
|
);
|
|
@@ -11691,7 +11950,7 @@ function destinationGraphFromSource(source, targetFingerprint) {
|
|
|
11691
11950
|
function mergeDestinationManifest(existing, state, generatedAt, desiredEntries, replaceOwners = /* @__PURE__ */ new Set()) {
|
|
11692
11951
|
if (existing) {
|
|
11693
11952
|
const manifest2 = existing.manifest;
|
|
11694
|
-
if (manifest2.adapter !== state.adapter || manifest2.installationType !== state.installationType || manifest2.stateKey !== state.stateKey ||
|
|
11953
|
+
if (manifest2.adapter !== state.adapter || manifest2.installationType !== state.installationType || manifest2.stateKey !== state.stateKey || resolve23(manifest2.targetRoot) !== state.installRoot) {
|
|
11695
11954
|
throw new Error(`Destination manifest identity diverges from the derived target: ${existing.path}`);
|
|
11696
11955
|
}
|
|
11697
11956
|
}
|
|
@@ -11751,7 +12010,7 @@ async function assertEquivalentRuntimeState(entry, sourcePath, destinationPath)
|
|
|
11751
12010
|
const content = await readFile27(path, "utf8");
|
|
11752
12011
|
if (hasMergeRemovalContent(entry.mergeRemoval)) {
|
|
11753
12012
|
assertExactMergeContribution(entry.mergeRemoval, entry.mergeStrategy, content);
|
|
11754
|
-
} else if (
|
|
12013
|
+
} else if (resolve23(sourcePath) === resolve23(destinationPath) && entry.mergeStrategy !== "codex-toml-mcp") {
|
|
11755
12014
|
assertExactMergeContribution({}, entry.mergeStrategy, content);
|
|
11756
12015
|
} else {
|
|
11757
12016
|
throw new Error(`Installed-state normalization cannot prove incomplete merge ownership at ${path}.`);
|
|
@@ -11762,8 +12021,8 @@ async function assertEquivalentRuntimeState(entry, sourcePath, destinationPath)
|
|
|
11762
12021
|
await assertEquivalentRuntimeBytes(sourcePath, destinationPath, entry.hash);
|
|
11763
12022
|
}
|
|
11764
12023
|
function renderedEntryPathForRoot(root, entryPath) {
|
|
11765
|
-
const normalizedRoot =
|
|
11766
|
-
const candidate =
|
|
12024
|
+
const normalizedRoot = resolve23(root);
|
|
12025
|
+
const candidate = resolve23(normalizedRoot, entryPath);
|
|
11767
12026
|
if (candidate !== normalizedRoot && !candidate.startsWith(`${normalizedRoot}/`)) {
|
|
11768
12027
|
throw new Error(`Install manifest entry escapes its target root: ${entryPath}`);
|
|
11769
12028
|
}
|
|
@@ -11854,8 +12113,8 @@ function ownerMatchesGraphPackage(lock, owner, selected) {
|
|
|
11854
12113
|
return ownerMatchesPackage(owner, selected) || lock.canonical.roots.some((root) => selected.has(root.rootId) && root.graphNodeId === owner);
|
|
11855
12114
|
}
|
|
11856
12115
|
function renderedEntryPath(manifest, entry) {
|
|
11857
|
-
const root =
|
|
11858
|
-
const candidate =
|
|
12116
|
+
const root = resolve23(manifest.targetRoot);
|
|
12117
|
+
const candidate = resolve23(root, entry.path);
|
|
11859
12118
|
if (candidate !== root && !candidate.startsWith(`${root}/`)) {
|
|
11860
12119
|
throw new Error(`Install manifest entry escapes its target root: ${entry.path}`);
|
|
11861
12120
|
}
|
|
@@ -11874,7 +12133,7 @@ function assertSimpleVerifiableEntry(entry, path) {
|
|
|
11874
12133
|
if (entry.kind !== "file" && entry.kind !== "dir") throw new Error(`Unsupported installed entry kind at ${path}.`);
|
|
11875
12134
|
}
|
|
11876
12135
|
function entryIdentity(entry) {
|
|
11877
|
-
return
|
|
12136
|
+
return canonicalJson2({
|
|
11878
12137
|
path: entry.path,
|
|
11879
12138
|
artifactType: entry.artifactType,
|
|
11880
12139
|
artifactName: entry.artifactName,
|
|
@@ -11892,7 +12151,7 @@ function entryIdentity(entry) {
|
|
|
11892
12151
|
});
|
|
11893
12152
|
}
|
|
11894
12153
|
function graphArtifactIdentity(artifact) {
|
|
11895
|
-
return
|
|
12154
|
+
return canonicalJson2({
|
|
11896
12155
|
graphNodeId: artifact.graphNodeId,
|
|
11897
12156
|
type: artifact.type,
|
|
11898
12157
|
name: artifact.name,
|
|
@@ -11906,7 +12165,7 @@ function graphArtifactIdentity(artifact) {
|
|
|
11906
12165
|
});
|
|
11907
12166
|
}
|
|
11908
12167
|
function graphEntryIdentity(entry) {
|
|
11909
|
-
return
|
|
12168
|
+
return canonicalJson2({
|
|
11910
12169
|
graphNodeId: entry.graphNodeId,
|
|
11911
12170
|
type: entry.artifactType,
|
|
11912
12171
|
name: entry.artifactName,
|
|
@@ -12010,7 +12269,7 @@ async function buildJournalGraphLockStates(plan) {
|
|
|
12010
12269
|
for (const transfer of plan.installedState.graphTransfers) {
|
|
12011
12270
|
const sourceBefore = JSON.parse(await readFile27(transfer.sourceGraphLockPath, "utf8"));
|
|
12012
12271
|
const sourceLock = await readGraphLock(transfer.sourceGraphLockPath);
|
|
12013
|
-
const sourceDigest = sha2564(
|
|
12272
|
+
const sourceDigest = sha2564(canonicalJson2(sourceLock));
|
|
12014
12273
|
if (sourceDigest !== transfer.sourceGraphLockDigest) {
|
|
12015
12274
|
throw new Error(`Source graph lock changed after planning: ${transfer.sourceGraphLockPath}`);
|
|
12016
12275
|
}
|
|
@@ -12028,9 +12287,9 @@ async function buildJournalGraphLockStates(plan) {
|
|
|
12028
12287
|
continue;
|
|
12029
12288
|
}
|
|
12030
12289
|
const destinationBefore = await readOptionalRecord(transfer.destinationGraphLockPath);
|
|
12031
|
-
const destinationBeforeDigest = destinationBefore ? sha2564(
|
|
12290
|
+
const destinationBeforeDigest = destinationBefore ? sha2564(canonicalJson2(await readGraphLock(transfer.destinationGraphLockPath))) : null;
|
|
12032
12291
|
const destinationAfter = destinationBefore ? await readGraphLock(transfer.destinationGraphLockPath) : destinationGraphFromSource(sourceLock, transfer.targetFingerprint);
|
|
12033
|
-
const destinationAfterDigest = sha2564(
|
|
12292
|
+
const destinationAfterDigest = sha2564(canonicalJson2(destinationAfter));
|
|
12034
12293
|
if (destinationBeforeDigest !== transfer.destinationGraphLockDigest || destinationAfterDigest !== transfer.destinationGraphLockAfterDigest) {
|
|
12035
12294
|
throw new Error(`Destination graph lock changed after planning: ${transfer.destinationGraphLockPath}`);
|
|
12036
12295
|
}
|
|
@@ -12140,8 +12399,8 @@ async function assertJournalRecoverable(journal) {
|
|
|
12140
12399
|
}
|
|
12141
12400
|
for (const graphLock of journal.graphLocks) {
|
|
12142
12401
|
const raw = await readOptionalRecord(graphLock.path);
|
|
12143
|
-
const
|
|
12144
|
-
if (
|
|
12402
|
+
const digest2 = raw ? sha2564(canonicalJson2(await readGraphLock(graphLock.path))) : null;
|
|
12403
|
+
if (digest2 !== graphLock.beforeDigest && digest2 !== graphLock.afterDigest) {
|
|
12145
12404
|
throw new Error(`Cannot recover fleet normalization because graph lock changed outside the transaction: ${graphLock.path}`);
|
|
12146
12405
|
}
|
|
12147
12406
|
}
|
|
@@ -12193,12 +12452,12 @@ function packageMap(config) {
|
|
|
12193
12452
|
return result;
|
|
12194
12453
|
}
|
|
12195
12454
|
function configRevision(config) {
|
|
12196
|
-
return sha2564(
|
|
12455
|
+
return sha2564(canonicalJson2(config));
|
|
12197
12456
|
}
|
|
12198
12457
|
function normalizationJournalPath(sourceRoot, destinationFleet) {
|
|
12199
12458
|
return join44(sourceRoot, ".agentwheel", `fleet-normalize-${destinationFleet}.journal.json`);
|
|
12200
12459
|
}
|
|
12201
|
-
function
|
|
12460
|
+
function canonicalJson2(value) {
|
|
12202
12461
|
return JSON.stringify(sortValue(value));
|
|
12203
12462
|
}
|
|
12204
12463
|
function sortValue(value) {
|
|
@@ -12209,7 +12468,7 @@ function sortValue(value) {
|
|
|
12209
12468
|
return value;
|
|
12210
12469
|
}
|
|
12211
12470
|
function sha2564(value) {
|
|
12212
|
-
return
|
|
12471
|
+
return createHash13("sha256").update(value).digest("hex");
|
|
12213
12472
|
}
|
|
12214
12473
|
function assertDigest(value) {
|
|
12215
12474
|
if (!/^[a-f0-9]{64}$/.test(value)) throw new Error(`Invalid plan digest: ${value}`);
|
|
@@ -12247,6 +12506,7 @@ var commandGovernance = {
|
|
|
12247
12506
|
"package migrate": "governed-always",
|
|
12248
12507
|
remember: "governed-always",
|
|
12249
12508
|
"ownership handoff": "governed-unless-dry-run",
|
|
12509
|
+
"ownership retire-stale": "governed-apply",
|
|
12250
12510
|
"mcp retire": "governed-apply",
|
|
12251
12511
|
eject: "governed-always",
|
|
12252
12512
|
uninstall: "governed-unless-dry-run",
|
|
@@ -12663,7 +12923,7 @@ ownershipCommand.command("handoff").description("transfer one managed artifact b
|
|
|
12663
12923
|
const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
|
|
12664
12924
|
if (options.toFleet) {
|
|
12665
12925
|
const fleet = await showRegisteredFleet(options.toFleet);
|
|
12666
|
-
if (
|
|
12926
|
+
if (resolve24(fleet.root) !== resolve24(toWorkspaceRoot)) {
|
|
12667
12927
|
throw new Error(`Destination fleet '${options.toFleet}' is registered at ${fleet.root}, not ${toWorkspaceRoot}.`);
|
|
12668
12928
|
}
|
|
12669
12929
|
}
|
|
@@ -12688,6 +12948,86 @@ ownershipCommand.command("handoff").description("transfer one managed artifact b
|
|
|
12688
12948
|
console.log(`Manifest revision: ${result.manifestRevision}`);
|
|
12689
12949
|
console.log(`Owner: ${result.fromOwner} -> ${result.toOwner}`);
|
|
12690
12950
|
});
|
|
12951
|
+
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("--abandon-incomplete-merge-owner", "explicitly retire incomplete legacy merge metadata without changing runtime bytes", false).option("--apply", "apply the exact reviewed metadata-only retirement", false).option("--json", "print the complete deterministic plan as JSON", false).action(async (options) => {
|
|
12952
|
+
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
12953
|
+
const fleet = await showRegisteredFleet(options.fleet);
|
|
12954
|
+
const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
|
|
12955
|
+
if (resolve24(fleet.root) !== resolve24(toWorkspaceRoot)) {
|
|
12956
|
+
throw new Error(`Destination Fleet '${options.fleet}' is registered at ${fleet.root}, not ${toWorkspaceRoot}.`);
|
|
12957
|
+
}
|
|
12958
|
+
const targets = await resolveCliTargets(normalizedOptions);
|
|
12959
|
+
if (targets.length !== 1) {
|
|
12960
|
+
throw new Error(`Stale ownership retirement requires exactly one destination Fleet target, found ${targets.length}.`);
|
|
12961
|
+
}
|
|
12962
|
+
const target = targets[0];
|
|
12963
|
+
if (target.fleetId !== options.fleet || resolve24(target.workspaceRoot) !== resolve24(fleet.root)) {
|
|
12964
|
+
throw new Error(`Resolved target does not belong to destination Fleet '${options.fleet}'.`);
|
|
12965
|
+
}
|
|
12966
|
+
const adapterOptions = adapterOptionsForTarget(target, normalizedOptions);
|
|
12967
|
+
const adapter = await resolveAdapterForTarget(target, adapterOptions);
|
|
12968
|
+
const installationType = normalizedOptions.installationType ?? target.installationType ?? resolveInstallationTypeForAdapter(adapter);
|
|
12969
|
+
const state = installStateForTarget(target, adapter, adapterOptions, installationType);
|
|
12970
|
+
const request = {
|
|
12971
|
+
targetRoot: state.installRoot,
|
|
12972
|
+
adapter: adapter.name,
|
|
12973
|
+
installationType,
|
|
12974
|
+
sourceStateKey: options.sourceStateKey,
|
|
12975
|
+
destinationStateKey: state.stateKey,
|
|
12976
|
+
fromWorkspaceRoot: normalizeCliPath(options.fromWorkspaceRoot),
|
|
12977
|
+
toWorkspaceRoot,
|
|
12978
|
+
toFleetId: fleet.id,
|
|
12979
|
+
planDigest: options.planDigest,
|
|
12980
|
+
expectedSourceRevision: options.expectedSourceRevision,
|
|
12981
|
+
expectedDestinationRevision: options.expectedDestinationRevision,
|
|
12982
|
+
expectedInventoryRevision: options.expectedInventoryRevision,
|
|
12983
|
+
abandonIncompleteMergeOwner: options.abandonIncompleteMergeOwner,
|
|
12984
|
+
transport: transportForTarget(target)
|
|
12985
|
+
};
|
|
12986
|
+
const result = options.apply ? await applyRetireStaleOwnership(request) : await planRetireStaleOwnership(request);
|
|
12987
|
+
const targetArgs = options.profile ? ["--profile", options.profile] : target.agentName ? ["--agent", target.agentName] : ["--adapter", adapter.name, "--target-root", target.targetRoot];
|
|
12988
|
+
const applyArgs = [
|
|
12989
|
+
"agentwheel",
|
|
12990
|
+
"ownership",
|
|
12991
|
+
"retire-stale",
|
|
12992
|
+
"--from-workspace-root",
|
|
12993
|
+
request.fromWorkspaceRoot,
|
|
12994
|
+
"--to-workspace-root",
|
|
12995
|
+
request.toWorkspaceRoot,
|
|
12996
|
+
"--source-state-key",
|
|
12997
|
+
request.sourceStateKey,
|
|
12998
|
+
"--fleet",
|
|
12999
|
+
request.toFleetId,
|
|
13000
|
+
...targetArgs,
|
|
13001
|
+
"--installation-type",
|
|
13002
|
+
installationType,
|
|
13003
|
+
...options.adapterConfig ? ["--adapter-config", options.adapterConfig] : [],
|
|
13004
|
+
...options.adapterModule ? ["--adapter-module", options.adapterModule] : [],
|
|
13005
|
+
...options.allowAdapterCode ? ["--allow-adapter-code"] : [],
|
|
13006
|
+
...options.abandonIncompleteMergeOwner ? ["--abandon-incomplete-merge-owner"] : [],
|
|
13007
|
+
"--plan-digest",
|
|
13008
|
+
result.planDigest,
|
|
13009
|
+
"--expected-source-revision",
|
|
13010
|
+
result.source.revision,
|
|
13011
|
+
"--expected-destination-revision",
|
|
13012
|
+
result.destination.revision,
|
|
13013
|
+
"--expected-inventory-revision",
|
|
13014
|
+
result.manifestInventoryRevision,
|
|
13015
|
+
"--apply"
|
|
13016
|
+
];
|
|
13017
|
+
const applyCommand = applyArgs.map(shellQuoteArgument).join(" ");
|
|
13018
|
+
if (options.json) {
|
|
13019
|
+
console.log(JSON.stringify({ ...result, applyCommand }, null, 2));
|
|
13020
|
+
return;
|
|
13021
|
+
}
|
|
13022
|
+
console.log(`${options.apply ? "Retired stale ownership" : "Stale ownership retirement plan"}: ${result.selected.length} entr${result.selected.length === 1 ? "y" : "ies"}`);
|
|
13023
|
+
console.log(`Target: ${result.adapter}/${result.installationType} at ${result.targetRoot}`);
|
|
13024
|
+
console.log(`Source: ${result.source.stateKey} revision ${result.source.revision}`);
|
|
13025
|
+
console.log(`Destination: ${result.destination.stateKey} revision ${result.destination.revision}`);
|
|
13026
|
+
console.log(`Manifest inventory revision: ${result.manifestInventoryRevision}`);
|
|
13027
|
+
for (const entry of result.selected) console.log(`- ${entry.path}: ${entry.sourceEntryDigest} -> ${entry.destinationEntryDigest}`);
|
|
13028
|
+
console.log(`Plan digest: ${result.planDigest}`);
|
|
13029
|
+
if (!options.apply) console.log(`Apply: ${applyCommand}`);
|
|
13030
|
+
});
|
|
12691
13031
|
var mcpCommand = program.command("mcp").description("operate on MCP runtime configuration");
|
|
12692
13032
|
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
13033
|
if (options.apply && options.dryRun) throw new Error("--apply cannot be combined with --dry-run.");
|
|
@@ -13678,7 +14018,7 @@ function scopeUpdatePlanToDependencies(result, selectors, previousLock, manifest
|
|
|
13678
14018
|
selectedPreviousNodeIds,
|
|
13679
14019
|
selectedRootIds
|
|
13680
14020
|
);
|
|
13681
|
-
const graphLockDigest =
|
|
14021
|
+
const graphLockDigest = createHash14("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
13682
14022
|
return {
|
|
13683
14023
|
...result,
|
|
13684
14024
|
bundle: { ...result.bundle, graphLock },
|
|
@@ -13804,7 +14144,7 @@ function operationBelongsToDependencyUpdate(operation, allowedNodeIds, allowedNa
|
|
|
13804
14144
|
function scopeInstallPlanToArtifact(result, rootId, focused, manifest) {
|
|
13805
14145
|
const scoped = scopePlanOperationsToArtifact(result, rootId, focused, manifest);
|
|
13806
14146
|
const graphLock = focusedGraphLockForInstall(scoped.bundle.graphLock, rootId, focused);
|
|
13807
|
-
const graphLockDigest =
|
|
14147
|
+
const graphLockDigest = createHash14("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
13808
14148
|
return {
|
|
13809
14149
|
...scoped,
|
|
13810
14150
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -13815,7 +14155,7 @@ function scopeInstallPlanToArtifact(result, rootId, focused, manifest) {
|
|
|
13815
14155
|
function scopeUpdatePlanToArtifact(result, rootId, focused, previousLock, manifest) {
|
|
13816
14156
|
const scoped = scopePlanOperationsToArtifact(result, rootId, focused, manifest, previousLock);
|
|
13817
14157
|
const graphLock = mergeFocusedArtifactGraphLock(scoped.bundle.graphLock, previousLock, rootId, focused);
|
|
13818
|
-
const graphLockDigest =
|
|
14158
|
+
const graphLockDigest = createHash14("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
13819
14159
|
return {
|
|
13820
14160
|
...scoped,
|
|
13821
14161
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -14110,7 +14450,7 @@ function scopeUpdatePlanToRoot(result, rootId, previousLock, manifest) {
|
|
|
14110
14450
|
selectedPreviousNodeIds,
|
|
14111
14451
|
/* @__PURE__ */ new Set([rootId])
|
|
14112
14452
|
);
|
|
14113
|
-
const graphLockDigest =
|
|
14453
|
+
const graphLockDigest = createHash14("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
14114
14454
|
return {
|
|
14115
14455
|
...scoped,
|
|
14116
14456
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -14666,7 +15006,7 @@ async function assertCompositeMutationSupported(workspaceRoot, profile, readOnly
|
|
|
14666
15006
|
`Composite-profile mutation is refused before member execution because ${member.id} uses ${member.transport}; durable remote policy and recovery preflight is not implemented.`
|
|
14667
15007
|
);
|
|
14668
15008
|
}
|
|
14669
|
-
const memberRoot =
|
|
15009
|
+
const memberRoot = resolve24(workspaceRoot, member.workspace);
|
|
14670
15010
|
const memberPolicy = await mutationPolicyForWorkspace(memberRoot);
|
|
14671
15011
|
if (memberPolicy?.revisioning.mode === "commit-after-verify") {
|
|
14672
15012
|
throw new Error(
|
|
@@ -15117,11 +15457,14 @@ function looksLikeSourceSpecifier(value) {
|
|
|
15117
15457
|
}
|
|
15118
15458
|
function normalizeCliPath(value) {
|
|
15119
15459
|
if (value === "~") return homedir12();
|
|
15120
|
-
if (value.startsWith("~/")) return
|
|
15121
|
-
return
|
|
15460
|
+
if (value.startsWith("~/")) return resolve24(homedir12(), value.slice(2));
|
|
15461
|
+
return resolve24(value);
|
|
15462
|
+
}
|
|
15463
|
+
function shellQuoteArgument(value) {
|
|
15464
|
+
return /^[a-z0-9_./:@%+=,-]+$/i.test(value) ? value : `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
15122
15465
|
}
|
|
15123
15466
|
function isHomePath(path) {
|
|
15124
|
-
return
|
|
15467
|
+
return resolve24(path) === resolve24(homedir12());
|
|
15125
15468
|
}
|
|
15126
15469
|
function adapterListFromOption(adapter) {
|
|
15127
15470
|
if (!adapter) return [];
|
|
@@ -15242,7 +15585,7 @@ function withFleetExample(config) {
|
|
|
15242
15585
|
};
|
|
15243
15586
|
}
|
|
15244
15587
|
async function findAgentwheelPackageRoot(start) {
|
|
15245
|
-
let current =
|
|
15588
|
+
let current = resolve24(start);
|
|
15246
15589
|
while (true) {
|
|
15247
15590
|
if (await findPackageManifestPath(current, { warnLegacy: false })) return current;
|
|
15248
15591
|
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