agentwheel 0.4.0 → 0.4.1
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/README.md +3 -0
- package/dist/index.js +67 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -72,6 +72,9 @@ pnpm link --global
|
|
|
72
72
|
|
|
73
73
|
`plan`, `sync --dry-run`, and `update --dry-run` show exactly what would change before anything is written. They're the commands to trust.
|
|
74
74
|
|
|
75
|
+
`uninstall` removes clean managed files by default and keeps drifted files in place with a warning.
|
|
76
|
+
Use `agentwheel uninstall --force` only when you also want to remove drifted managed files.
|
|
77
|
+
|
|
75
78
|
## Runtime targeting
|
|
76
79
|
|
|
77
80
|
Normal use no longer needs `--target-root`. Run agentwheel inside a runtime folder and it detects
|
package/dist/index.js
CHANGED
|
@@ -461,16 +461,52 @@ async function applyInstallPlan(plan, sourceLock, options = {}) {
|
|
|
461
461
|
await writeSourceLock(plan.targetRoot, plan.adapter, sourceLock);
|
|
462
462
|
return manifest;
|
|
463
463
|
}
|
|
464
|
-
async function uninstall(plan,
|
|
464
|
+
async function uninstall(plan, options = {}) {
|
|
465
|
+
const resolvedOptions = typeof options === "boolean" ? { dryRun: options } : options;
|
|
465
466
|
if (plan.hasBlockingChanges) {
|
|
466
|
-
const blockers = plan.operations.filter((operation) => operation.action === "
|
|
467
|
-
throw new Error(`Refusing to uninstall with
|
|
467
|
+
const blockers = plan.operations.filter((operation) => operation.action === "conflict");
|
|
468
|
+
throw new Error(`Refusing to uninstall with blocking changes: ${blockers.map((item) => item.relativeDestPath).join(", ")}`);
|
|
468
469
|
}
|
|
469
|
-
|
|
470
|
+
const removable = plan.operations.filter((operation) => operation.action === "remove" || resolvedOptions.force && operation.action === "keep");
|
|
471
|
+
const kept = resolvedOptions.force ? [] : plan.operations.filter((operation) => operation.action === "keep");
|
|
472
|
+
const removedDrifted = resolvedOptions.force ? plan.operations.filter((operation) => operation.action === "keep").length : 0;
|
|
473
|
+
if (resolvedOptions.dryRun) return { removed: removable.length, kept: kept.length, removedDrifted };
|
|
470
474
|
for (const operation of plan.operations) {
|
|
471
|
-
|
|
475
|
+
if (operation.action === "remove" || resolvedOptions.force && operation.action === "keep") {
|
|
476
|
+
await rm2(operation.destPath, { recursive: true, force: true });
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
if (kept.length > 0) {
|
|
480
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
481
|
+
await writeInstallManifest({
|
|
482
|
+
version: 1,
|
|
483
|
+
adapter: plan.adapter,
|
|
484
|
+
targetRoot: plan.targetRoot,
|
|
485
|
+
generatedAt: now,
|
|
486
|
+
adapterCode: plan.adapterCode,
|
|
487
|
+
entries: kept.map((operation) => {
|
|
488
|
+
if (!operation.manifestHash || !operation.desiredHash) {
|
|
489
|
+
throw new Error(`Invalid kept operation missing manifest/source hash: ${operation.relativeDestPath}`);
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
path: operation.relativeDestPath,
|
|
493
|
+
artifactType: operation.artifactType,
|
|
494
|
+
artifactName: operation.artifactName,
|
|
495
|
+
kind: operation.kind,
|
|
496
|
+
hash: operation.manifestHash,
|
|
497
|
+
sourceHash: operation.desiredHash,
|
|
498
|
+
updatedAt: now,
|
|
499
|
+
channel: operation.channel,
|
|
500
|
+
packageName: operation.packageName,
|
|
501
|
+
semanticCommand: operation.semanticCommand,
|
|
502
|
+
mergeStrategy: operation.mergeStrategy
|
|
503
|
+
};
|
|
504
|
+
}).sort((a, b) => a.path.localeCompare(b.path))
|
|
505
|
+
});
|
|
506
|
+
} else {
|
|
507
|
+
await removeStateFiles(plan.targetRoot, plan.adapter);
|
|
472
508
|
}
|
|
473
|
-
|
|
509
|
+
return { removed: removable.length, kept: kept.length, removedDrifted };
|
|
474
510
|
}
|
|
475
511
|
|
|
476
512
|
// src/install/plan.ts
|
|
@@ -658,6 +694,7 @@ function summarizePlan(plan) {
|
|
|
658
694
|
update: 0,
|
|
659
695
|
skip: 0,
|
|
660
696
|
remove: 0,
|
|
697
|
+
keep: 0,
|
|
661
698
|
drift: 0,
|
|
662
699
|
conflict: 0,
|
|
663
700
|
plugin: 0,
|
|
@@ -679,17 +716,20 @@ async function createUninstallPlan(manifest) {
|
|
|
679
716
|
const currentHash = await hashPath(destPath);
|
|
680
717
|
if (currentHash !== entry.hash) {
|
|
681
718
|
operations.push({
|
|
682
|
-
action: "
|
|
719
|
+
action: "keep",
|
|
683
720
|
artifactType: entry.artifactType,
|
|
684
721
|
artifactName: entry.artifactName,
|
|
685
722
|
kind: entry.kind,
|
|
686
723
|
destPath,
|
|
687
724
|
relativeDestPath: entry.path,
|
|
725
|
+
desiredHash: entry.sourceHash,
|
|
688
726
|
currentHash,
|
|
689
727
|
manifestHash: entry.hash,
|
|
690
|
-
reason: "managed destination changed outside agentwheel",
|
|
728
|
+
reason: "managed destination changed outside agentwheel; keeping by default",
|
|
691
729
|
channel: entry.channel,
|
|
692
|
-
packageName: entry.packageName
|
|
730
|
+
packageName: entry.packageName,
|
|
731
|
+
semanticCommand: entry.semanticCommand,
|
|
732
|
+
mergeStrategy: entry.mergeStrategy
|
|
693
733
|
});
|
|
694
734
|
} else {
|
|
695
735
|
operations.push({
|
|
@@ -712,7 +752,8 @@ async function createUninstallPlan(manifest) {
|
|
|
712
752
|
adapter: manifest.adapter,
|
|
713
753
|
targetRoot: manifest.targetRoot,
|
|
714
754
|
operations,
|
|
715
|
-
hasBlockingChanges: operations.some((operation) => operation.action === "
|
|
755
|
+
hasBlockingChanges: operations.some((operation) => operation.action === "conflict"),
|
|
756
|
+
adapterCode: manifest.adapterCode
|
|
716
757
|
};
|
|
717
758
|
}
|
|
718
759
|
|
|
@@ -722,6 +763,7 @@ var labels = {
|
|
|
722
763
|
update: "UPDATE",
|
|
723
764
|
skip: "SKIP",
|
|
724
765
|
remove: "REMOVE",
|
|
766
|
+
keep: "KEEP",
|
|
725
767
|
drift: "DRIFT",
|
|
726
768
|
conflict: "CONFLICT",
|
|
727
769
|
plugin: "PLUGIN",
|
|
@@ -743,7 +785,7 @@ function formatPlan(plan) {
|
|
|
743
785
|
}
|
|
744
786
|
const summary = summarizePlan(plan);
|
|
745
787
|
lines.push(
|
|
746
|
-
`Summary: create ${summary.create}, update ${summary.update}, skip ${summary.skip}, remove ${summary.remove}, drift ${summary.drift}, conflict ${summary.conflict}, plugin ${summary.plugin}`
|
|
788
|
+
`Summary: create ${summary.create}, update ${summary.update}, skip ${summary.skip}, remove ${summary.remove}, keep ${summary.keep}, drift ${summary.drift}, conflict ${summary.conflict}, plugin ${summary.plugin}`
|
|
747
789
|
);
|
|
748
790
|
return lines.join("\n");
|
|
749
791
|
}
|
|
@@ -2068,7 +2110,7 @@ function dedupeTargets(matches) {
|
|
|
2068
2110
|
|
|
2069
2111
|
// src/cli/index.ts
|
|
2070
2112
|
var program = new Command();
|
|
2071
|
-
program.name("agentwheel").description("Multi-runtime agent artifact orchestrator").version("0.4.
|
|
2113
|
+
program.name("agentwheel").description("Multi-runtime agent artifact orchestrator").version("0.4.1");
|
|
2072
2114
|
program.command("init").argument("[kind]", "workspace or package", "workspace").option("--target-root <path>", "workspace root", process.cwd()).action(async (kind, options) => {
|
|
2073
2115
|
const root = normalizeTargetRoot(options.targetRoot);
|
|
2074
2116
|
if (kind === "package") {
|
|
@@ -2225,7 +2267,7 @@ program.command("eject").argument("<item>", "package/type/name").option("--targe
|
|
|
2225
2267
|
const result = await ejectArtifact(targetRoot, item);
|
|
2226
2268
|
console.log(`Ejected ${item} to ${result.ejectedPath}.`);
|
|
2227
2269
|
});
|
|
2228
|
-
program.command("uninstall").option("--adapter <adapter>", "adapter", "openclaw").option("--adapter-module <path>", "local programmatic adapter module").option("--allow-adapter-code", "allow loading local adapter code", false).option("--target-root <path>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--dry-run", "show removals without writing", false).action(async (options) => {
|
|
2270
|
+
program.command("uninstall").option("--adapter <adapter>", "adapter", "openclaw").option("--adapter-module <path>", "local programmatic adapter module").option("--allow-adapter-code", "allow loading local adapter code", false).option("--target-root <path>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--dry-run", "show removals without writing", false).option("--force", "remove drifted managed files too", false).action(async (options) => {
|
|
2229
2271
|
const targets = await resolveCliTargets(options);
|
|
2230
2272
|
for (const target of targets) {
|
|
2231
2273
|
const adapter = await resolveAdapterForTarget(target, options);
|
|
@@ -2236,10 +2278,10 @@ program.command("uninstall").option("--adapter <adapter>", "adapter", "openclaw"
|
|
|
2236
2278
|
}
|
|
2237
2279
|
const plan = await createUninstallPlan(manifest);
|
|
2238
2280
|
console.log(formatPlan(plan));
|
|
2239
|
-
await uninstall(plan, options.dryRun);
|
|
2281
|
+
const result = await uninstall(plan, { dryRun: options.dryRun, force: options.force });
|
|
2240
2282
|
if (!options.dryRun) {
|
|
2241
2283
|
await adapter.programmatic?.uninstall?.({ targetRoot: target.targetRoot, adapterName: adapter.name });
|
|
2242
|
-
console.log(
|
|
2284
|
+
console.log(formatUninstallResult(result));
|
|
2243
2285
|
}
|
|
2244
2286
|
if (plan.hasBlockingChanges) process.exitCode = 1;
|
|
2245
2287
|
}
|
|
@@ -2329,6 +2371,16 @@ async function initPackage(root) {
|
|
|
2329
2371
|
`, "utf8");
|
|
2330
2372
|
await writeFile4(join19(root, "instructions", "AGENTS.md"), "# Agent Instructions\n", "utf8");
|
|
2331
2373
|
}
|
|
2374
|
+
function formatUninstallResult(result) {
|
|
2375
|
+
const removedLabel = result.removed === 1 ? "managed file" : "managed files";
|
|
2376
|
+
if (result.removedDrifted > 0) {
|
|
2377
|
+
const driftedLabel = result.removedDrifted === 1 ? "drifted file" : "drifted files";
|
|
2378
|
+
return `Removed ${result.removed} ${removedLabel}, including ${result.removedDrifted} ${driftedLabel}.`;
|
|
2379
|
+
}
|
|
2380
|
+
if (result.kept === 0) return `Removed ${result.removed} ${removedLabel}.`;
|
|
2381
|
+
const keptLabel = result.kept === 1 ? "drifted file" : "drifted files";
|
|
2382
|
+
return `Removed ${result.removed} ${removedLabel}; kept ${result.kept} ${keptLabel} (use --force to remove).`;
|
|
2383
|
+
}
|
|
2332
2384
|
function printRegistryEntries(entries) {
|
|
2333
2385
|
for (const entry of entries) {
|
|
2334
2386
|
const tags = entry.tags?.length ? ` [${entry.tags.join(",")}]` : "";
|