agentwheel 0.20.0 → 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-7HJQQOCI.js → apply-OGC6E2Y4.js} +4 -2
- package/dist/{chunk-USHT7FGV.js → chunk-BAJEWUI6.js} +84 -6
- package/dist/{chunk-HOYIIUL5.js → chunk-Z4N7TB6Q.js} +37 -4
- package/dist/index.js +730 -298
- package/dist/{transaction-IM5MZS4B.js → transaction-7CNV5MAQ.js} +5 -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
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
acquireApplyLock,
|
|
4
|
+
applyJournalPath,
|
|
4
5
|
artifactFormatSchema,
|
|
5
6
|
artifactTypeSchema,
|
|
6
7
|
assertApplyJournalRecoveryAllowed,
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
fileKindSchema,
|
|
12
13
|
installManifestPath,
|
|
13
14
|
installationTypeSchema,
|
|
15
|
+
listApplyJournals,
|
|
14
16
|
localPathExists,
|
|
15
17
|
localTransport,
|
|
16
18
|
metadataDir,
|
|
@@ -22,7 +24,7 @@ import {
|
|
|
22
24
|
rollbackCompletedOperations,
|
|
23
25
|
sourceLockPath,
|
|
24
26
|
writeApplyJournal
|
|
25
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-Z4N7TB6Q.js";
|
|
26
28
|
import {
|
|
27
29
|
pathExists,
|
|
28
30
|
writeJsonAtomic
|
|
@@ -549,16 +551,15 @@ async function readInstallManifest(targetRoot, adapter, transport = localTranspo
|
|
|
549
551
|
async function listInstallManifests(targetRoot, adapter, transport = localTransport) {
|
|
550
552
|
const dir = metadataDir(targetRoot);
|
|
551
553
|
const suffix = ".install-manifest.json";
|
|
552
|
-
const prefix = `${adapter}.`;
|
|
553
554
|
const found = [];
|
|
554
555
|
for (const fileName of await transport.listDir(dir)) {
|
|
555
556
|
if (!fileName.endsWith(suffix)) continue;
|
|
556
557
|
const stateKey = fileName.slice(0, -suffix.length);
|
|
557
|
-
if (stateKey !== adapter && !stateKey.startsWith(prefix)) continue;
|
|
558
558
|
const path = join(dir, fileName);
|
|
559
559
|
try {
|
|
560
560
|
const raw = JSON.parse(await transport.readFile(path));
|
|
561
561
|
const parsed = installManifestSchema.parse(raw);
|
|
562
|
+
if (parsed.adapter !== adapter) continue;
|
|
562
563
|
found.push({ path, fileName, stateKey, manifest: { ...parsed, revision: computeManifestRevision(raw) } });
|
|
563
564
|
} catch (error) {
|
|
564
565
|
throw new Error(`Unreadable install manifest at ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -566,6 +567,10 @@ async function listInstallManifests(targetRoot, adapter, transport = localTransp
|
|
|
566
567
|
}
|
|
567
568
|
return found.sort((a, b) => a.fileName.localeCompare(b.fileName));
|
|
568
569
|
}
|
|
570
|
+
async function computeInstallManifestInventoryRevision(targetRoot, adapter, transport = localTransport) {
|
|
571
|
+
const inventory = (await listInstallManifests(targetRoot, adapter, transport)).map((item) => [item.fileName, item.manifest.revision]);
|
|
572
|
+
return createHash2("sha256").update(JSON.stringify(inventory)).digest("hex");
|
|
573
|
+
}
|
|
569
574
|
async function writeInstallManifest(manifest, transport = localTransport) {
|
|
570
575
|
const next = withManifestRevision(manifest);
|
|
571
576
|
await transport.writeJsonAtomic(installManifestPath(next.targetRoot, next.adapter, {
|
|
@@ -1360,6 +1365,7 @@ async function recoverPendingApply(targetRoot, adapter, transport = localTranspo
|
|
|
1360
1365
|
assertGovernedRuntimeTransportSupported(transport);
|
|
1361
1366
|
const lock = await acquireApplyLock(targetRoot, adapter, transport, {}, scope);
|
|
1362
1367
|
try {
|
|
1368
|
+
await assertRuntimeJournalGate(targetRoot, adapter, transport, scope, true);
|
|
1363
1369
|
const journal = await readApplyJournal(targetRoot, adapter, transport, scope);
|
|
1364
1370
|
if (!journal) return void 0;
|
|
1365
1371
|
assertApplyJournalRecoveryAllowed(journal);
|
|
@@ -1402,6 +1408,26 @@ async function recoverPendingApply(targetRoot, adapter, transport = localTranspo
|
|
|
1402
1408
|
await lock.release();
|
|
1403
1409
|
}
|
|
1404
1410
|
}
|
|
1411
|
+
async function assertRuntimeJournalGate(targetRoot, adapter, transport, scope, allowRequestedJournal = false) {
|
|
1412
|
+
const pending = await listApplyJournals(targetRoot, adapter, transport, {
|
|
1413
|
+
installationType: scope.installationType
|
|
1414
|
+
});
|
|
1415
|
+
if (pending.length === 0) return;
|
|
1416
|
+
const requestedPath = applyJournalPath(targetRoot, adapter, scope);
|
|
1417
|
+
if (allowRequestedJournal && pending.length === 1 && pending[0].path === requestedPath) return;
|
|
1418
|
+
throw new Error(
|
|
1419
|
+
`Cannot mutate ${adapter}/${scope.installationType ?? "local"} at ${targetRoot} while runtime apply journal(s) are pending: ` + pending.map((item) => item.path).join(", ")
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
async function assertRuntimeStateRevision(plan, transport) {
|
|
1423
|
+
if (!plan.runtimeStateRevision) return;
|
|
1424
|
+
const current = await computeInstallManifestInventoryRevision(plan.targetRoot, plan.adapter, transport);
|
|
1425
|
+
if (current !== plan.runtimeStateRevision) {
|
|
1426
|
+
throw new Error(
|
|
1427
|
+
`Runtime manifest inventory changed after planning: expected ${plan.runtimeStateRevision}, found ${current}; replan needed.`
|
|
1428
|
+
);
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1405
1431
|
async function applyPlanTransactionally(plan, options = {}) {
|
|
1406
1432
|
const transport = options.transport ?? localTransport;
|
|
1407
1433
|
const scope = { installationType: plan.installationType, stateKey: plan.stateKey };
|
|
@@ -1412,6 +1438,8 @@ async function applyPlanTransactionally(plan, options = {}) {
|
|
|
1412
1438
|
assertGovernedRuntimeTransportSupported(transport);
|
|
1413
1439
|
const lock = await acquireApplyLock(plan.targetRoot, plan.adapter, transport, options.lock, scope);
|
|
1414
1440
|
try {
|
|
1441
|
+
await assertRuntimeJournalGate(plan.targetRoot, plan.adapter, transport, scope);
|
|
1442
|
+
await assertRuntimeStateRevision(plan, transport);
|
|
1415
1443
|
await assertBaseRevision(plan, transport);
|
|
1416
1444
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1417
1445
|
const graphLockDigest = options.graphLockDigest ?? plan.graphLockDigest;
|
|
@@ -1493,7 +1521,7 @@ async function uninstall(plan, options = {}) {
|
|
|
1493
1521
|
const preserved = [...preservedKept, ...skipped].filter((operation) => operation.preserveInManifest !== false);
|
|
1494
1522
|
for (const operation of [...removable, ...preserved]) assertOperationContained(operation, plan.targetRoot);
|
|
1495
1523
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1496
|
-
|
|
1524
|
+
let finalManifest = withManifestRevision({
|
|
1497
1525
|
version: 2,
|
|
1498
1526
|
adapter: plan.adapter,
|
|
1499
1527
|
installationType: plan.installationType,
|
|
@@ -1517,8 +1545,25 @@ async function uninstall(plan, options = {}) {
|
|
|
1517
1545
|
});
|
|
1518
1546
|
const lock = await acquireApplyLock(plan.targetRoot, plan.adapter, transport, resolvedOptions.lock, scope);
|
|
1519
1547
|
try {
|
|
1548
|
+
await assertRuntimeJournalGate(plan.targetRoot, plan.adapter, transport, scope);
|
|
1549
|
+
await assertRuntimeStateRevision(plan, transport);
|
|
1520
1550
|
await assertBaseRevision(plan, transport);
|
|
1521
1551
|
await assertExactMergeRemovalPreconditions(removable, transport);
|
|
1552
|
+
const revalidatedSkips = /* @__PURE__ */ new Map();
|
|
1553
|
+
for (const operation of skipped) {
|
|
1554
|
+
const entry = await applyOperation(operation, {
|
|
1555
|
+
transport,
|
|
1556
|
+
now,
|
|
1557
|
+
graphLockDigest: operation.graphLockDigest ?? plan.graphLockDigest
|
|
1558
|
+
});
|
|
1559
|
+
if (entry) revalidatedSkips.set(operation.relativeDestPath, entry);
|
|
1560
|
+
}
|
|
1561
|
+
if (revalidatedSkips.size > 0) {
|
|
1562
|
+
finalManifest = withManifestRevision({
|
|
1563
|
+
...finalManifest,
|
|
1564
|
+
entries: finalManifest.entries.map((entry) => revalidatedSkips.get(entry.path) ?? entry)
|
|
1565
|
+
});
|
|
1566
|
+
}
|
|
1522
1567
|
const mutation = mutationMetadataForApplyJournal();
|
|
1523
1568
|
const journal = {
|
|
1524
1569
|
version: mutation ? 2 : 1,
|
|
@@ -1562,6 +1607,12 @@ function shouldPreserveKeptOperationWhenKeepingFiles(operation) {
|
|
|
1562
1607
|
function isForceRemovableKeep(operation) {
|
|
1563
1608
|
return operation.action === "keep" && operation.preserveInManifest !== true;
|
|
1564
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
|
+
}
|
|
1565
1616
|
async function commitJournalState(journal, transport, entries, now) {
|
|
1566
1617
|
const manifest = withManifestRevision({
|
|
1567
1618
|
...journal.manifest,
|
|
@@ -1724,9 +1775,33 @@ async function applyOperation(operation, context) {
|
|
|
1724
1775
|
if (!operation.desiredHash) {
|
|
1725
1776
|
throw new Error(`Invalid skip operation missing hash: ${operation.relativeDestPath}`);
|
|
1726
1777
|
}
|
|
1778
|
+
let verifiedCurrentHash = operation.currentHash;
|
|
1779
|
+
if (operation.mode === managedInstructionBlockMode) {
|
|
1780
|
+
const selector = managedInstructionSelector(operation.logicalSelector, operation.artifactType, operation.artifactName);
|
|
1781
|
+
if (!await managedInstructionBlockLanded(operation.destPath, selector, operation.desiredHash, transport)) {
|
|
1782
|
+
throw new Error(`Managed block changed after planning: ${operation.relativeDestPath}`);
|
|
1783
|
+
}
|
|
1784
|
+
verifiedCurrentHash = operation.desiredHash;
|
|
1785
|
+
} else if (operation.mergeStrategy && hasMergeRemovalContent(operation.mergeRemoval)) {
|
|
1786
|
+
if (!await transport.pathExists(operation.destPath)) {
|
|
1787
|
+
throw new Error(`Merge skip destination disappeared after planning: ${operation.relativeDestPath}`);
|
|
1788
|
+
}
|
|
1789
|
+
assertExactMergeContribution(operation.mergeRemoval, operation.mergeStrategy, await transport.readFile(operation.destPath));
|
|
1790
|
+
verifiedCurrentHash = await transport.hashPath(operation.destPath);
|
|
1791
|
+
} else if (!operation.semanticPlugin && !operation.programmaticOperation) {
|
|
1792
|
+
if (!await transport.pathExists(operation.destPath)) {
|
|
1793
|
+
throw new Error(`Skip destination disappeared after planning: ${operation.relativeDestPath}`);
|
|
1794
|
+
}
|
|
1795
|
+
const currentHash = await transport.hashPath(operation.destPath);
|
|
1796
|
+
const expectedHash = operation.currentHash ?? operation.desiredHash;
|
|
1797
|
+
if (currentHash !== expectedHash) {
|
|
1798
|
+
throw new Error(`Skip destination changed after planning: ${operation.relativeDestPath}`);
|
|
1799
|
+
}
|
|
1800
|
+
verifiedCurrentHash = currentHash;
|
|
1801
|
+
}
|
|
1727
1802
|
return manifestEntryForOperation(operation, {
|
|
1728
1803
|
now,
|
|
1729
|
-
hash: (operation.mergeStrategy || operation.mode === managedInstructionBlockMode) &&
|
|
1804
|
+
hash: (operation.mergeStrategy || operation.mode === managedInstructionBlockMode) && verifiedCurrentHash ? verifiedCurrentHash : operation.desiredHash,
|
|
1730
1805
|
sourceHash: operation.desiredHash,
|
|
1731
1806
|
graphLockDigest: context.graphLockDigest
|
|
1732
1807
|
});
|
|
@@ -2210,6 +2285,7 @@ export {
|
|
|
2210
2285
|
installManifestSchema,
|
|
2211
2286
|
readInstallManifest,
|
|
2212
2287
|
listInstallManifests,
|
|
2288
|
+
computeInstallManifestInventoryRevision,
|
|
2213
2289
|
writeInstallManifest,
|
|
2214
2290
|
normalizeTargetRoot,
|
|
2215
2291
|
withManifestRevision,
|
|
@@ -2221,6 +2297,7 @@ export {
|
|
|
2221
2297
|
combineMergeRemovals,
|
|
2222
2298
|
hasMergeRemovalContent,
|
|
2223
2299
|
mergeRemovalForInstall,
|
|
2300
|
+
mergeContributionAbsent,
|
|
2224
2301
|
normalizeOwners,
|
|
2225
2302
|
managedInstructionBlockMode,
|
|
2226
2303
|
desiredManagedInstructionBlockHash,
|
|
@@ -2231,5 +2308,6 @@ export {
|
|
|
2231
2308
|
applyInstallPlan,
|
|
2232
2309
|
applyCombinedInstallPlan,
|
|
2233
2310
|
recoverPendingApply,
|
|
2234
|
-
uninstall
|
|
2311
|
+
uninstall,
|
|
2312
|
+
commitManifestMetadataJournal
|
|
2235
2313
|
};
|
|
@@ -344,7 +344,7 @@ var targetRegistryInputSchema = z2.union([
|
|
|
344
344
|
targetRegistrySchema
|
|
345
345
|
]);
|
|
346
346
|
var adapterSchema = z2.object({
|
|
347
|
-
name: z2.string().
|
|
347
|
+
name: z2.string().regex(/^[a-z0-9][a-z0-9._-]*$/i, "adapter name must be a canonical path-safe identifier"),
|
|
348
348
|
displayName: z2.string().min(1).optional(),
|
|
349
349
|
targets: z2.partialRecord(
|
|
350
350
|
artifactTypeSchema,
|
|
@@ -460,6 +460,7 @@ function metadataDir(targetRoot) {
|
|
|
460
460
|
return join(targetRoot, ".agentwheel");
|
|
461
461
|
}
|
|
462
462
|
function stateKeyFor(adapter, scope = {}) {
|
|
463
|
+
assertPathSafeAdapterName(adapter);
|
|
463
464
|
if (scope.stateKey) {
|
|
464
465
|
const explicit = sanitizeStateKey(scope.stateKey);
|
|
465
466
|
const adapterScoped = scope.fleetId && explicit !== adapter && !explicit.startsWith(`${adapter}.`) ? `${adapter}.${explicit}` : explicit;
|
|
@@ -470,6 +471,11 @@ function stateKeyFor(adapter, scope = {}) {
|
|
|
470
471
|
const fingerprint = scope.targetFingerprint ? `.${scope.targetFingerprint}` : "";
|
|
471
472
|
return sanitizeStateKey(`${adapter}.${installationType}${fingerprint}`);
|
|
472
473
|
}
|
|
474
|
+
function assertPathSafeAdapterName(adapter) {
|
|
475
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/i.test(adapter)) {
|
|
476
|
+
throw new Error(`Adapter name '${adapter}' is not a canonical path-safe identifier.`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
473
479
|
function installManifestPath(targetRoot, adapter, scope = {}) {
|
|
474
480
|
return join(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.install-manifest.json`);
|
|
475
481
|
}
|
|
@@ -2618,8 +2624,8 @@ async function recoverMutationRuntime(operationId, options = {}) {
|
|
|
2618
2624
|
}
|
|
2619
2625
|
mutation = GovernedMutation.activateExisting(receipt, baseline, lock);
|
|
2620
2626
|
const [{ recoverPendingApply }, { readLinkedLocalApplyJournal: readLinkedLocalApplyJournal2, removeApplyJournal: removeApplyJournal2, localPathExists: localPathExists2 }] = await Promise.all([
|
|
2621
|
-
import("./apply-
|
|
2622
|
-
import("./transaction-
|
|
2627
|
+
import("./apply-OGC6E2Y4.js"),
|
|
2628
|
+
import("./transaction-7CNV5MAQ.js")
|
|
2623
2629
|
]);
|
|
2624
2630
|
let missingReservation = false;
|
|
2625
2631
|
for (const entry of pending) {
|
|
@@ -2782,7 +2788,8 @@ function upsertRuntimeJournal(entries, link2, status) {
|
|
|
2782
2788
|
|
|
2783
2789
|
// src/install/transaction.ts
|
|
2784
2790
|
function applyLockPath(targetRoot, adapter, scope = {}) {
|
|
2785
|
-
|
|
2791
|
+
const installationType = scope.installationType ?? "local";
|
|
2792
|
+
return join6(metadataDir(targetRoot), `${stateKeyFor(adapter, { installationType })}.runtime-apply-lock`);
|
|
2786
2793
|
}
|
|
2787
2794
|
function applyJournalPath(targetRoot, adapter, scope = {}) {
|
|
2788
2795
|
return join6(metadataDir(targetRoot), `${stateKeyFor(adapter, scope)}.apply-journal.json`);
|
|
@@ -2850,6 +2857,30 @@ async function readApplyJournal(targetRoot, adapter, transport = localTransport,
|
|
|
2850
2857
|
if (!await transport.pathExists(path)) return void 0;
|
|
2851
2858
|
return parseApplyJournal(JSON.parse(await transport.readFile(path)));
|
|
2852
2859
|
}
|
|
2860
|
+
async function listApplyJournals(targetRoot, adapter, transport = localTransport, scope = {}) {
|
|
2861
|
+
const installationType = scope.installationType ?? "local";
|
|
2862
|
+
const suffix = ".apply-journal.json";
|
|
2863
|
+
const found = [];
|
|
2864
|
+
for (const fileName of await transport.listDir(metadataDir(targetRoot))) {
|
|
2865
|
+
if (!fileName.endsWith(suffix)) continue;
|
|
2866
|
+
const path = join6(metadataDir(targetRoot), fileName);
|
|
2867
|
+
const journal = parseApplyJournal(JSON.parse(await transport.readFile(path)));
|
|
2868
|
+
if (journal.adapter !== adapter || (journal.installationType ?? "local") !== installationType) continue;
|
|
2869
|
+
found.push({ path, journal });
|
|
2870
|
+
}
|
|
2871
|
+
return found.sort((a, b) => a.path.localeCompare(b.path));
|
|
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
|
+
}
|
|
2853
2884
|
async function readLinkedLocalApplyJournal(path, operationId, expectedDigest, expectedTransportDescription) {
|
|
2854
2885
|
const absolutePath = resolve9(path);
|
|
2855
2886
|
const journal = parseApplyJournal(JSON.parse(await readFile7(absolutePath, "utf8")));
|
|
@@ -3129,6 +3160,8 @@ export {
|
|
|
3129
3160
|
acquireApplyLock,
|
|
3130
3161
|
writeApplyJournal,
|
|
3131
3162
|
readApplyJournal,
|
|
3163
|
+
listApplyJournals,
|
|
3164
|
+
listAllApplyJournals,
|
|
3132
3165
|
readLinkedLocalApplyJournal,
|
|
3133
3166
|
removeApplyJournal,
|
|
3134
3167
|
abortApplyJournal,
|