agentwheel 0.20.15 → 0.20.17
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 +11 -0
- package/dist/index.js +34 -4
- 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
package/README.md
CHANGED
|
@@ -148,6 +148,8 @@ revalidates the exact contribution under the apply lock. It removes only the sel
|
|
|
148
148
|
server; sibling servers and user configuration remain. The command previews by default. A later
|
|
149
149
|
runtime approval must use the same command with `--apply` instead of `--dry-run`.
|
|
150
150
|
|
|
151
|
+
When stable and legacy manifests disagree, `update --recover-legacy-state` explicitly uses recovered stable state while preserving legacy evidence. Preview the same command with `--dry-run` first.
|
|
152
|
+
|
|
151
153
|
For a surgical dependency update, start with a dry-run:
|
|
152
154
|
|
|
153
155
|
```bash
|
|
@@ -459,6 +461,15 @@ agentwheel ownership retire-stale \
|
|
|
459
461
|
|
|
460
462
|
The dry-run still proves exact destination coverage and runtime bytes. Apply only its emitted command,
|
|
461
463
|
which includes the plan, source, destination, and manifest-inventory revisions.
|
|
464
|
+
For duplicate state owned by the same registered Fleet, set both workspace roots to the Fleet root
|
|
465
|
+
and add `--from-fleet-id <fleet-id>`. The planner selects only legacy paths covered by the stable
|
|
466
|
+
Fleet manifest. For JSON deep merges it also accepts a source contribution that is an exact
|
|
467
|
+
recursive subset of the destination contribution. Across package revisions, merge entries must
|
|
468
|
+
identify the same package and artifact with equal source hashes; other merge contributions must
|
|
469
|
+
match exactly. A source-only path stays in the legacy manifest;
|
|
470
|
+
when every source entry is covered, apply removes the old manifest and source lock without changing
|
|
471
|
+
runtime files or the stable manifest. Preserve copies of those old state files before applying a
|
|
472
|
+
retirement when they are needed as historical evidence.
|
|
462
473
|
|
|
463
474
|
## Core Ideas
|
|
464
475
|
|
package/dist/index.js
CHANGED
|
@@ -10001,7 +10001,7 @@ async function observe(request, transport) {
|
|
|
10001
10001
|
const normalized = normalizeRequest(request);
|
|
10002
10002
|
const source = await requireManifest(normalized, normalized.sourceStateKey, transport, "source");
|
|
10003
10003
|
const destination = await requireManifest(normalized, normalized.destinationStateKey, transport, "destination");
|
|
10004
|
-
const sourceOwner = workspaceOwnerForRoot(normalized.fromWorkspaceRoot);
|
|
10004
|
+
const sourceOwner = workspaceOwnerForRoot(normalized.fromWorkspaceRoot, normalized.fromFleetId);
|
|
10005
10005
|
const destinationOwner = workspaceOwnerForRoot(normalized.toWorkspaceRoot, normalized.toFleetId);
|
|
10006
10006
|
const destinationByPath = /* @__PURE__ */ new Map();
|
|
10007
10007
|
for (const entry of destination.entries) {
|
|
@@ -10078,6 +10078,11 @@ function normalizeRequest(request) {
|
|
|
10078
10078
|
const destinationStateKey = exactStateKey(request.adapter, request.destinationStateKey, request.installationType, "destination");
|
|
10079
10079
|
if (sourceStateKey === destinationStateKey) throw new Error("Source and destination state keys must differ.");
|
|
10080
10080
|
if (!request.toFleetId.trim()) throw new Error("Destination Fleet id is required.");
|
|
10081
|
+
const fromFleetId = request.fromFleetId?.trim();
|
|
10082
|
+
if (request.fromFleetId !== void 0 && !fromFleetId) throw new Error("Source Fleet id cannot be empty.");
|
|
10083
|
+
if (fromFleetId && (fromFleetId !== request.toFleetId.trim() || resolve21(request.fromWorkspaceRoot) !== resolve21(request.toWorkspaceRoot))) {
|
|
10084
|
+
throw new Error("Fleet-qualified stale ownership retirement requires the same source and destination Fleet and workspace root.");
|
|
10085
|
+
}
|
|
10081
10086
|
return {
|
|
10082
10087
|
...request,
|
|
10083
10088
|
targetRoot,
|
|
@@ -10085,6 +10090,7 @@ function normalizeRequest(request) {
|
|
|
10085
10090
|
sourceStateKey,
|
|
10086
10091
|
destinationStateKey,
|
|
10087
10092
|
fromWorkspaceRoot: resolve21(request.fromWorkspaceRoot),
|
|
10093
|
+
...fromFleetId ? { fromFleetId } : {},
|
|
10088
10094
|
toWorkspaceRoot: resolve21(request.toWorkspaceRoot),
|
|
10089
10095
|
toFleetId: request.toFleetId.trim()
|
|
10090
10096
|
};
|
|
@@ -10121,6 +10127,7 @@ function assertRetirableSourceEntry(entry, abandonIncompleteMergeOwner) {
|
|
|
10121
10127
|
}
|
|
10122
10128
|
}
|
|
10123
10129
|
async function assertContributionCoverage(source, destination, targetRoot, transport, abandonIncompleteMergeOwner) {
|
|
10130
|
+
containedArtifactPath(targetRoot, source.path);
|
|
10124
10131
|
const sourceManagedBlock = source.mode === "managed-block";
|
|
10125
10132
|
const destinationManagedBlock = destination.mode === "managed-block";
|
|
10126
10133
|
const sourceMerge = source.mergeStrategy !== void 0;
|
|
@@ -10146,8 +10153,19 @@ async function assertContributionCoverage(source, destination, targetRoot, trans
|
|
|
10146
10153
|
if (abandonIncompleteMergeOwner) return "abandoned-incomplete-merge";
|
|
10147
10154
|
throw new Error(`Cannot retire incomplete merge ownership at ${source.path}.`);
|
|
10148
10155
|
}
|
|
10149
|
-
const
|
|
10156
|
+
const selectorsDiffer = contributionSelector(source) !== contributionSelector(destination);
|
|
10157
|
+
if (selectorsDiffer && !sameContributionSelector(source, destination)) {
|
|
10158
|
+
throw new Error(`Destination Fleet does not identify the same source merge artifact at ${source.path}.`);
|
|
10159
|
+
}
|
|
10160
|
+
if (source.mergeStrategy === "json-deep" && destination.mergeStrategy === "json-deep" && hasMergeRemovalContent(destination.mergeRemoval) && sameContributionSelector(source, destination)) {
|
|
10161
|
+
if (canonicalJson(combineMergeRemovals(destination.mergeRemoval, source.mergeRemoval)) === canonicalJson(destination.mergeRemoval)) return "exact";
|
|
10162
|
+
throw new Error(`Destination Fleet does not exactly cover stale source merge contribution at ${source.path}.`);
|
|
10163
|
+
}
|
|
10164
|
+
const exactlyCovered = destination.mergeStrategy === source.mergeStrategy && hasMergeRemovalContent(destination.mergeRemoval) && sameContributionSelector(source, destination) && canonicalJson(source.mergeRemoval) === canonicalJson(destination.mergeRemoval);
|
|
10150
10165
|
if (exactlyCovered) return "exact";
|
|
10166
|
+
if (selectorsDiffer) {
|
|
10167
|
+
throw new Error(`Destination Fleet does not exactly cover stale source merge contribution at ${source.path}.`);
|
|
10168
|
+
}
|
|
10151
10169
|
const current = await transport.readFile(containedArtifactPath(targetRoot, source.path));
|
|
10152
10170
|
if (!mergeContributionAbsent(source.mergeRemoval, source.mergeStrategy, current)) {
|
|
10153
10171
|
throw new Error(`Destination Fleet does not exactly cover or replace stale source merge contribution at ${source.path}.`);
|
|
@@ -10159,6 +10177,15 @@ async function assertContributionCoverage(source, destination, targetRoot, trans
|
|
|
10159
10177
|
function contributionSelector(entry) {
|
|
10160
10178
|
return entry.logicalSelector ?? `${entry.artifactType}/${entry.artifactName}`;
|
|
10161
10179
|
}
|
|
10180
|
+
function sameContributionSelector(source, destination) {
|
|
10181
|
+
if (contributionSelector(source) === contributionSelector(destination)) return true;
|
|
10182
|
+
if (!source.packageName || source.packageName !== destination.packageName || source.artifactType !== destination.artifactType || source.artifactName !== destination.artifactName || source.installName !== destination.installName || source.sourceHash !== destination.sourceHash || !source.graphNodeId || !destination.graphNodeId) return false;
|
|
10183
|
+
const selector = artifactSelectorKey({ type: source.artifactType, name: source.artifactName });
|
|
10184
|
+
if (source.logicalSelector !== `${source.graphNodeId}:${selector}` || destination.logicalSelector !== `${destination.graphNodeId}:${selector}`) return false;
|
|
10185
|
+
const sourceAt = source.graphNodeId.lastIndexOf("@");
|
|
10186
|
+
const destinationAt = destination.graphNodeId.lastIndexOf("@");
|
|
10187
|
+
return sourceAt > 0 && destinationAt > 0 && source.graphNodeId.slice(0, sourceAt) === source.packageName && destination.graphNodeId.slice(0, destinationAt) === destination.packageName && source.graphNodeId.indexOf("+", sourceAt) > sourceAt && destination.graphNodeId.indexOf("+", destinationAt) > destinationAt;
|
|
10188
|
+
}
|
|
10162
10189
|
function assertApplyPreconditions(request) {
|
|
10163
10190
|
for (const [label, value] of [
|
|
10164
10191
|
["plan digest", request.planDigest],
|
|
@@ -13764,7 +13791,7 @@ program.command("sync", { hidden: true }).argument("[name-or-source]", "configur
|
|
|
13764
13791
|
console.error("warning: 'agentwheel sync' is deprecated and will be removed in 0.10. Use 'agentwheel install'.");
|
|
13765
13792
|
await runInstallCommand(source, options, { apply: !options.dryRun });
|
|
13766
13793
|
});
|
|
13767
|
-
program.command("update").description("re-resolve tracking packages, then apply the result").argument("[name]", "configured package name or source to update").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").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>", "workspace root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plans without writing", false).option("--force-drift", "replace drifted managed artifacts", false).option("--force-foreign-state", "plan even when another workspace owns install state at the same paths", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--execute-plugins", "execute semantic plugin installs", false).option("--reload-runtimes", "run configured runtime reload commands after executed semantic plugin changes", false).option("--restart-runtimes", "alias for --reload-runtimes", false).option("--allow-adapter-code", "allow loading local adapter code from configured packages", false).option("--select <type/name>", "temporarily select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--artifact <type/name>", "update only one configured artifact while preserving sibling state").option("--skill <name>", "temporarily select a skill by name (repeatable or comma-separated)", collectSkillOption, []).option("--dependency <name-or-source>", "update one tracking dependency while keeping unrelated graph nodes locked (repeatable)", collectDependencyOption, []).option("--with-suggestions", "include suggested companion artifacts for selected roots", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "exclude unrelated configured workspace packages", false).option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (name, options) => {
|
|
13794
|
+
program.command("update").description("re-resolve tracking packages, then apply the result").argument("[name]", "configured package name or source to update").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").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>", "workspace root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plans without writing", false).option("--force-drift", "replace drifted managed artifacts", false).option("--force-foreign-state", "plan even when another workspace owns install state at the same paths", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--recover-legacy-state", "build a stable state while preserving invalid legacy candidates", false).option("--execute-plugins", "execute semantic plugin installs", false).option("--reload-runtimes", "run configured runtime reload commands after executed semantic plugin changes", false).option("--restart-runtimes", "alias for --reload-runtimes", false).option("--allow-adapter-code", "allow loading local adapter code from configured packages", false).option("--select <type/name>", "temporarily select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--artifact <type/name>", "update only one configured artifact while preserving sibling state").option("--skill <name>", "temporarily select a skill by name (repeatable or comma-separated)", collectSkillOption, []).option("--dependency <name-or-source>", "update one tracking dependency while keeping unrelated graph nodes locked (repeatable)", collectDependencyOption, []).option("--with-suggestions", "include suggested companion artifacts for selected roots", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "exclude unrelated configured workspace packages", false).option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (name, options) => {
|
|
13768
13795
|
if (options.onlySource && options.dependency.length > 0) throw new Error("--only-source cannot be combined with --dependency.");
|
|
13769
13796
|
if (options.onlySource && !name) throw new Error("--only-source requires a configured package argument.");
|
|
13770
13797
|
if (name && options.dependency.length > 0) throw new Error("A package argument cannot be combined with --dependency.");
|
|
@@ -14035,7 +14062,7 @@ ownershipCommand.command("recovery-plan").description("write a read-only per-pat
|
|
|
14035
14062
|
await rm10(stage, { recursive: true, force: true });
|
|
14036
14063
|
}
|
|
14037
14064
|
});
|
|
14038
|
-
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").option("--destination-state-key <key>", "exact Fleet-owned destination install-manifest state key (defaults to the stable target state)").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) => {
|
|
14065
|
+
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").option("--from-fleet-id <id>", "exact stale Fleet owner id for same-Fleet duplicate state").requiredOption("--to-workspace-root <path>", "registered destination Fleet root").requiredOption("--source-state-key <key>", "exact source install-manifest state key").option("--destination-state-key <key>", "exact Fleet-owned destination install-manifest state key (defaults to the stable target state)").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) => {
|
|
14039
14066
|
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
14040
14067
|
const fleet = await showRegisteredFleet(options.fleet);
|
|
14041
14068
|
const toWorkspaceRoot = normalizeCliPath(options.toWorkspaceRoot);
|
|
@@ -14061,6 +14088,7 @@ ownershipCommand.command("retire-stale").description("retire stale source-manife
|
|
|
14061
14088
|
sourceStateKey: options.sourceStateKey,
|
|
14062
14089
|
destinationStateKey: options.destinationStateKey ?? stableState.stateKey,
|
|
14063
14090
|
fromWorkspaceRoot: normalizeCliPath(options.fromWorkspaceRoot),
|
|
14091
|
+
fromFleetId: options.fromFleetId,
|
|
14064
14092
|
toWorkspaceRoot,
|
|
14065
14093
|
toFleetId: fleet.id,
|
|
14066
14094
|
planDigest: options.planDigest,
|
|
@@ -14078,6 +14106,7 @@ ownershipCommand.command("retire-stale").description("retire stale source-manife
|
|
|
14078
14106
|
"retire-stale",
|
|
14079
14107
|
"--from-workspace-root",
|
|
14080
14108
|
request.fromWorkspaceRoot,
|
|
14109
|
+
...request.fromFleetId ? ["--from-fleet-id", request.fromFleetId] : [],
|
|
14081
14110
|
"--to-workspace-root",
|
|
14082
14111
|
request.toWorkspaceRoot,
|
|
14083
14112
|
"--source-state-key",
|
|
@@ -16209,6 +16238,7 @@ function compositeUpdateArguments(profile, packageName, options) {
|
|
|
16209
16238
|
args.push("--profile", profile);
|
|
16210
16239
|
if (options.dryRun) args.push("--dry-run");
|
|
16211
16240
|
if (options.refresh) args.push("--refresh");
|
|
16241
|
+
if (options.recoverLegacyState) args.push("--recover-legacy-state");
|
|
16212
16242
|
if (options.forceDrift) args.push("--force-drift");
|
|
16213
16243
|
if (options.forceForeignState) args.push("--force-foreign-state");
|
|
16214
16244
|
if (options.forceConflict) args.push("--force-conflict");
|
package/openpack.json
CHANGED
package/package.json
CHANGED