agentwheel 0.20.10 → 0.20.11
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 +16 -0
- package/dist/{apply-ZNEUBJU3.js → apply-ZGCJLZMZ.js} +3 -3
- package/dist/{chunk-P2JK34W7.js → chunk-A44XYLUT.js} +2 -2
- package/dist/{chunk-J7DKPDS7.js → chunk-FP26KSBM.js} +3 -3
- package/dist/{chunk-7VPI5J5Y.js → chunk-GE7F76AC.js} +21 -0
- package/dist/{chunk-EMDIG24I.js → chunk-U2GRG4UI.js} +1 -1
- package/dist/{identify-D64HZTUT.js → identify-O54QXPQR.js} +2 -2
- package/dist/index.js +65 -62
- package/dist/{transaction-4ERCJXG7.js → transaction-4KBNHDQX.js} +2 -2
- package/openpack.json +1 -1
- package/package.json +1 -1
- package/skills/agentwheel/SKILL.md +15 -1
- package/skills/agentwheel-discovery/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -427,6 +427,22 @@ apply journal that embeds and exactly correlates the missing manifest and graph
|
|
|
427
427
|
discoverable for recovery. Legacy SSH state is also preserved and refused because the old records do
|
|
428
428
|
not prove which endpoint owned it.
|
|
429
429
|
|
|
430
|
+
After reviewing `agentwheel ownership recovery-plan`, use `--recover-legacy-state` only for an
|
|
431
|
+
invalid local candidate whose historical files must remain preserved. The recovery plan ignores
|
|
432
|
+
that candidate when constructing the new stable state; it does not authorize runtime replacement.
|
|
433
|
+
Adopting matching unmanaged files still requires `--force-conflict`, while replacing differing files
|
|
434
|
+
still requires `--replace-conflict`. Review the resulting plan before applying the same flags:
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
agentwheel plan --fleet example-fleet --agent lab-claude \
|
|
438
|
+
--recover-legacy-state --force-conflict --replace-conflict
|
|
439
|
+
agentwheel install --fleet example-fleet --agent lab-claude \
|
|
440
|
+
--recover-legacy-state --force-conflict --replace-conflict
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
Once the stable manifest exists, normal status and planning use it while retaining the invalid
|
|
444
|
+
historical candidate for explicit later cleanup.
|
|
445
|
+
|
|
430
446
|
## Core Ideas
|
|
431
447
|
|
|
432
448
|
**Three places, one direction:**
|
|
@@ -5,9 +5,9 @@ import {
|
|
|
5
5
|
commitManifestMetadataJournal,
|
|
6
6
|
recoverPendingApply,
|
|
7
7
|
uninstall
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-A44XYLUT.js";
|
|
9
|
+
import "./chunk-FP26KSBM.js";
|
|
10
|
+
import "./chunk-GE7F76AC.js";
|
|
11
11
|
export {
|
|
12
12
|
applyCombinedInstallPlan,
|
|
13
13
|
applyInstallPlan,
|
|
@@ -24,11 +24,11 @@ import {
|
|
|
24
24
|
rollbackCompletedOperations,
|
|
25
25
|
sourceLockPath,
|
|
26
26
|
writeApplyJournal
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-FP26KSBM.js";
|
|
28
28
|
import {
|
|
29
29
|
pathExists,
|
|
30
30
|
writeJsonAtomic
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-GE7F76AC.js";
|
|
32
32
|
|
|
33
33
|
// src/install/apply.ts
|
|
34
34
|
import { execFile } from "child_process";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
hashPath,
|
|
5
5
|
pathExists,
|
|
6
6
|
writeJsonAtomic
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-GE7F76AC.js";
|
|
8
8
|
|
|
9
9
|
// src/install/transaction.ts
|
|
10
10
|
import { createHash as createHash6 } from "crypto";
|
|
@@ -2865,8 +2865,8 @@ async function recoverMutationRuntime(operationId, options = {}) {
|
|
|
2865
2865
|
}
|
|
2866
2866
|
mutation = GovernedMutation.activateExisting(receipt, baseline, lock);
|
|
2867
2867
|
const [{ recoverPendingApply }, { readLinkedLocalApplyJournal: readLinkedLocalApplyJournal2, removeApplyJournal: removeApplyJournal2, localPathExists: localPathExists2 }] = await Promise.all([
|
|
2868
|
-
import("./apply-
|
|
2869
|
-
import("./transaction-
|
|
2868
|
+
import("./apply-ZGCJLZMZ.js"),
|
|
2869
|
+
import("./transaction-4KBNHDQX.js")
|
|
2870
2870
|
]);
|
|
2871
2871
|
let missingReservation = false;
|
|
2872
2872
|
for (const entry of pending) {
|
|
@@ -90,6 +90,7 @@ async function withFilesystemLock(lockPath, timeoutMs, fn, description = "cache"
|
|
|
90
90
|
break;
|
|
91
91
|
} catch (error) {
|
|
92
92
|
if (!isAlreadyExists(error)) throw error;
|
|
93
|
+
if (await removeStaleFilesystemLock(lockPath)) continue;
|
|
93
94
|
if (Date.now() - started > timeoutMs) {
|
|
94
95
|
throw new Error(`Timed out waiting for ${description} lock at ${lockPath}`);
|
|
95
96
|
}
|
|
@@ -102,6 +103,26 @@ async function withFilesystemLock(lockPath, timeoutMs, fn, description = "cache"
|
|
|
102
103
|
await rm(lockPath, { recursive: true, force: true });
|
|
103
104
|
}
|
|
104
105
|
}
|
|
106
|
+
async function removeStaleFilesystemLock(lockPath) {
|
|
107
|
+
try {
|
|
108
|
+
const owner = JSON.parse(await readFile(join(lockPath, "owner.json"), "utf8"));
|
|
109
|
+
if (typeof owner.pid !== "number" || !Number.isSafeInteger(owner.pid) || owner.pid <= 0 || isProcessAlive(owner.pid)) return false;
|
|
110
|
+
const stalePath = `${lockPath}.stale-${process.pid}-${Date.now()}`;
|
|
111
|
+
await rename(lockPath, stalePath);
|
|
112
|
+
await rm(stalePath, { recursive: true, force: true });
|
|
113
|
+
return true;
|
|
114
|
+
} catch {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function isProcessAlive(pid) {
|
|
119
|
+
try {
|
|
120
|
+
process.kill(pid, 0);
|
|
121
|
+
return true;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return typeof error === "object" && error !== null && "code" in error && error.code !== "ESRCH";
|
|
124
|
+
}
|
|
125
|
+
}
|
|
105
126
|
function isAlreadyExists(error) {
|
|
106
127
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
107
128
|
}
|
package/dist/index.js
CHANGED
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
uninstall,
|
|
38
38
|
withManifestRevision,
|
|
39
39
|
writeInstallManifest
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-A44XYLUT.js";
|
|
41
41
|
import {
|
|
42
42
|
CURRENT_WORKSPACE_SCHEMA_VERSION,
|
|
43
43
|
GovernedMutation,
|
|
@@ -98,10 +98,10 @@ import {
|
|
|
98
98
|
workspaceSelectionImportSchema,
|
|
99
99
|
writeApplyJournal,
|
|
100
100
|
writeWorkspaceConfig
|
|
101
|
-
} from "./chunk-
|
|
101
|
+
} from "./chunk-FP26KSBM.js";
|
|
102
102
|
import {
|
|
103
103
|
inferSourceDriverName
|
|
104
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-U2GRG4UI.js";
|
|
105
105
|
import {
|
|
106
106
|
hashPath,
|
|
107
107
|
isAlreadyExists,
|
|
@@ -110,7 +110,7 @@ import {
|
|
|
110
110
|
pathExists,
|
|
111
111
|
withFilesystemLock,
|
|
112
112
|
writeJsonAtomic
|
|
113
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-GE7F76AC.js";
|
|
114
114
|
|
|
115
115
|
// src/cli/index.ts
|
|
116
116
|
import { createHash as createHash15 } from "crypto";
|
|
@@ -5789,7 +5789,7 @@ var RegistryClient = class {
|
|
|
5789
5789
|
}
|
|
5790
5790
|
};
|
|
5791
5791
|
async function resolvePackageSource(source, workspaceRoot, options = {}) {
|
|
5792
|
-
const { isExplicitSource } = await import("./identify-
|
|
5792
|
+
const { isExplicitSource } = await import("./identify-O54QXPQR.js");
|
|
5793
5793
|
if (await isExplicitSource(source)) return { source };
|
|
5794
5794
|
const entry = await new RegistryClient({ workspaceRoot, offline: options.offline, warn: options.warn }).resolve(source);
|
|
5795
5795
|
if (!entry) {
|
|
@@ -8233,7 +8233,9 @@ async function createGraphSourcePlan(options) {
|
|
|
8233
8233
|
graphLockPath,
|
|
8234
8234
|
stableManifest,
|
|
8235
8235
|
stableLock: stableLock2,
|
|
8236
|
-
transport
|
|
8236
|
+
transport,
|
|
8237
|
+
recoverLegacyState: options.recoverLegacyState,
|
|
8238
|
+
warn
|
|
8237
8239
|
});
|
|
8238
8240
|
return { priorState: priorState2, stableLock: stableLock2, stableSourceLock: stableSourceLock2 };
|
|
8239
8241
|
};
|
|
@@ -8495,7 +8497,10 @@ function validateJournalManifestEnvelope(value, options, stateKey, journalPath)
|
|
|
8495
8497
|
return manifest;
|
|
8496
8498
|
}
|
|
8497
8499
|
async function resolvePriorTargetState(options) {
|
|
8498
|
-
const candidates = await discoverLegacyStateCandidates(
|
|
8500
|
+
const candidates = await discoverLegacyStateCandidates({
|
|
8501
|
+
...options,
|
|
8502
|
+
recoverLegacyState: options.recoverLegacyState === true || options.stableManifest !== void 0
|
|
8503
|
+
});
|
|
8499
8504
|
const correlated = candidates.filter((candidate) => candidate.manifest);
|
|
8500
8505
|
if (options.stableManifest) {
|
|
8501
8506
|
for (const candidate of correlated) {
|
|
@@ -8563,34 +8568,28 @@ async function discoverLegacyStateCandidates(options) {
|
|
|
8563
8568
|
const fingerprint = name.slice(0, -suffix.length);
|
|
8564
8569
|
if (!/^[a-f0-9]{64}$/u.test(fingerprint)) continue;
|
|
8565
8570
|
const graphLockPath = join33(directory, name);
|
|
8566
|
-
let graphLock;
|
|
8567
8571
|
try {
|
|
8572
|
+
let graphLock;
|
|
8568
8573
|
graphLock = await readGraphLock(graphLockPath);
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
targetFingerprint: fingerprint,
|
|
8589
|
-
fleetId: options.fleetId
|
|
8590
|
-
});
|
|
8591
|
-
let manifest;
|
|
8592
|
-
let sourceLock;
|
|
8593
|
-
try {
|
|
8574
|
+
if (graphLock.canonical.targetFingerprint !== fingerprint) {
|
|
8575
|
+
throw new Error(
|
|
8576
|
+
`Legacy graph lock fingerprint does not match its filename at ${graphLockPath}.`
|
|
8577
|
+
);
|
|
8578
|
+
}
|
|
8579
|
+
if (options.transport.kind === "ssh") {
|
|
8580
|
+
throw new Error(
|
|
8581
|
+
`Legacy SSH target state at ${graphLockPath} does not record its original endpoint; Agentwheel cannot prove endpoint identity, so the graph lock was preserved.`
|
|
8582
|
+
);
|
|
8583
|
+
}
|
|
8584
|
+
const graphLockDigest = digestGraphLock(graphLock);
|
|
8585
|
+
const candidateStateKey = stateKeyFor(options.adapter, {
|
|
8586
|
+
installationType: options.installationType,
|
|
8587
|
+
stateKey: options.explicitStateKey,
|
|
8588
|
+
targetFingerprint: fingerprint,
|
|
8589
|
+
fleetId: options.fleetId
|
|
8590
|
+
});
|
|
8591
|
+
let manifest;
|
|
8592
|
+
let sourceLock;
|
|
8594
8593
|
manifest = await readInstallManifest(options.installRoot, options.adapter, options.transport, {
|
|
8595
8594
|
installationType: options.installationType,
|
|
8596
8595
|
stateKey: candidateStateKey
|
|
@@ -8599,32 +8598,32 @@ async function discoverLegacyStateCandidates(options) {
|
|
|
8599
8598
|
installationType: options.installationType,
|
|
8600
8599
|
stateKey: candidateStateKey
|
|
8601
8600
|
});
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
if (sourceLock) {
|
|
8609
|
-
throw new Error(`Legacy source lock for ${graphLockPath} has no correlated install manifest.`);
|
|
8601
|
+
if (!manifest) {
|
|
8602
|
+
if (sourceLock) {
|
|
8603
|
+
throw new Error(`Legacy source lock for ${graphLockPath} has no correlated install manifest.`);
|
|
8604
|
+
}
|
|
8605
|
+
candidates.push({ stateKey: candidateStateKey, graphLockPath, graphLockDigest, graphLock });
|
|
8606
|
+
continue;
|
|
8610
8607
|
}
|
|
8611
|
-
|
|
8612
|
-
|
|
8608
|
+
const validated = validateLegacyManifestCandidate(manifest, {
|
|
8609
|
+
...options,
|
|
8610
|
+
candidateStateKey,
|
|
8611
|
+
graphLockDigest,
|
|
8612
|
+
graphLockPath
|
|
8613
|
+
});
|
|
8614
|
+
candidates.push({
|
|
8615
|
+
stateKey: candidateStateKey,
|
|
8616
|
+
graphLockPath,
|
|
8617
|
+
graphLockDigest,
|
|
8618
|
+
graphLock,
|
|
8619
|
+
manifest: validated,
|
|
8620
|
+
sourceLock
|
|
8621
|
+
});
|
|
8622
|
+
} catch (error) {
|
|
8623
|
+
const message = `Legacy target state for ${graphLockPath} is invalid: ` + (error instanceof Error ? error.message : String(error));
|
|
8624
|
+
if (!options.recoverLegacyState) throw new Error(message);
|
|
8625
|
+
options.warn?.(`${message} Preserving it outside the recovered stable state.`);
|
|
8613
8626
|
}
|
|
8614
|
-
const validated = validateLegacyManifestCandidate(manifest, {
|
|
8615
|
-
...options,
|
|
8616
|
-
candidateStateKey,
|
|
8617
|
-
graphLockDigest,
|
|
8618
|
-
graphLockPath
|
|
8619
|
-
});
|
|
8620
|
-
candidates.push({
|
|
8621
|
-
stateKey: candidateStateKey,
|
|
8622
|
-
graphLockPath,
|
|
8623
|
-
graphLockDigest,
|
|
8624
|
-
graphLock,
|
|
8625
|
-
manifest: validated,
|
|
8626
|
-
sourceLock
|
|
8627
|
-
});
|
|
8628
8627
|
}
|
|
8629
8628
|
return candidates;
|
|
8630
8629
|
}
|
|
@@ -13703,10 +13702,10 @@ program.command("scan").description("scan a package source for validation findin
|
|
|
13703
13702
|
await releaseGitSnapshotLease(resolved.cacheLeasePath);
|
|
13704
13703
|
}
|
|
13705
13704
|
});
|
|
13706
|
-
program.command("plan").description("preview what install would reconcile without writing").argument("[name-or-source]", "configured package name/source or package source to preview").option("--driver <driver>", "source driver").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("--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 agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--profile <name>", "workspace runtime profile").option("--mode <mode>", "pinned or tracking").option("--select <type/name>", "select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "select a skill by name (repeatable or comma-separated)", collectSkillOption, []).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("--override <source-or-package::type/name>", "for source previews, allow the source to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--dry-run", "accepted for symmetry; plan never writes", false).option("--format <fmt>", "output format: human|json|mermaid|html", "human").option("--json", "print the resolved plan as JSON", false).option("--force-drift", "replace drifted managed artifacts during install planning", 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("--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 (source, options) => {
|
|
13705
|
+
program.command("plan").description("preview what install would reconcile without writing").argument("[name-or-source]", "configured package name/source or package source to preview").option("--driver <driver>", "source driver").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("--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 agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--profile <name>", "workspace runtime profile").option("--mode <mode>", "pinned or tracking").option("--select <type/name>", "select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "select a skill by name (repeatable or comma-separated)", collectSkillOption, []).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("--override <source-or-package::type/name>", "for source previews, allow the source to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--dry-run", "accepted for symmetry; plan never writes", false).option("--format <fmt>", "output format: human|json|mermaid|html", "human").option("--json", "print the resolved plan as JSON", false).option("--force-drift", "replace drifted managed artifacts during install planning", 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("--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 (source, options) => {
|
|
13707
13706
|
await runInstallCommand(source, { ...options, dryRun: true }, { apply: false });
|
|
13708
13707
|
});
|
|
13709
|
-
program.command("install").description("install configured packages into runtime targets").argument("[name-or-source]", "configured package name/source or package source to add and install").option("--driver <driver>", "source driver").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("--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 agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--mode <mode>", "pinned or tracking").option("--select <type/name>", "select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "select a skill by name (repeatable or comma-separated)", collectSkillOption, []).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("--override <source-or-package::type/name>", "when adding a source, allow it to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plan without writing", false).option("--format <fmt>", "output format: human|json|mermaid|html", "human").option("--json", "print the resolved plan as JSON", 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("--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, []).addHelpText("after", "\nScoped install never removes files owned only by other configured packages; run a full install to reconcile those removals.\n").action(async (source, options) => {
|
|
13708
|
+
program.command("install").description("install configured packages into runtime targets").argument("[name-or-source]", "configured package name/source or package source to add and install").option("--driver <driver>", "source driver").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("--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 agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--mode <mode>", "pinned or tracking").option("--select <type/name>", "select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "select a skill by name (repeatable or comma-separated)", collectSkillOption, []).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("--override <source-or-package::type/name>", "when adding a source, allow it to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plan without writing", false).option("--format <fmt>", "output format: human|json|mermaid|html", "human").option("--json", "print the resolved plan as JSON", 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("--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, []).addHelpText("after", "\nScoped install never removes files owned only by other configured packages; run a full install to reconcile those removals.\n").action(async (source, options) => {
|
|
13710
13709
|
await runInstallCommand(source, options, { apply: !options.dryRun });
|
|
13711
13710
|
});
|
|
13712
13711
|
program.command("serve").description("serve a read-only live dashboard for the resolved install plan").argument("[name-or-source]", "configured package name/source or package source to preview").option("--driver <driver>", "source driver").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("--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 agent from merged config").option("--all", "run for every configured agent", false).option("--all-detected", "run for every runtime directory detected in the target root", false).option("--profile <name>", "workspace runtime profile").option("--mode <mode>", "pinned or tracking").option("--select <type/name>", "select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "select a skill by name (repeatable or comma-separated)", collectSkillOption, []).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("--override <source-or-package::type/name>", "for source previews, allow the source to replace a colliding artifact (repeatable)", collectOverrideOption, []).option("--force-drift", "replace drifted managed artifacts during install planning", 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("--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, []).option("--bind <addr>", "interface to bind", "127.0.0.1").option("--port <n>", "TCP port (0 selects an ephemeral port)", "8765").option("--interval <seconds>", "background re-render cadence in seconds", "60").option("--once", "render once and skip the background re-render loop", false).action(async (source, options) => {
|
|
@@ -14907,7 +14906,8 @@ async function buildGraphPlansForTarget(target, source, options, behavior) {
|
|
|
14907
14906
|
}
|
|
14908
14907
|
const priorGroupState = await resolveCliTargetState(group.target, {
|
|
14909
14908
|
...targetOptions,
|
|
14910
|
-
installationType: group.installationType
|
|
14909
|
+
installationType: group.installationType,
|
|
14910
|
+
recoverLegacyState: targetOptions.recoverLegacyState
|
|
14911
14911
|
});
|
|
14912
14912
|
const previousGroupLock = priorGroupState.graphLock;
|
|
14913
14913
|
const dependencyUpdateRootNames = /* @__PURE__ */ new Set();
|
|
@@ -15016,7 +15016,8 @@ async function buildGraphPlansForTarget(target, source, options, behavior) {
|
|
|
15016
15016
|
deferForeignStateCheck: targetOptions.deferForeignStateCheck === true || targetOptions.focusedArtifact !== void 0,
|
|
15017
15017
|
replaceConflict: targetOptions.replaceConflict,
|
|
15018
15018
|
retireExactMcp: targetOptions.retireExactMcp,
|
|
15019
|
-
expectedFromWorkspaceOwner: targetOptions.expectedFromWorkspaceOwner
|
|
15019
|
+
expectedFromWorkspaceOwner: targetOptions.expectedFromWorkspaceOwner,
|
|
15020
|
+
recoverLegacyState: targetOptions.recoverLegacyState
|
|
15020
15021
|
});
|
|
15021
15022
|
if ((behavior.mode === "install" || behavior.mode === "update") && scopedRootId) {
|
|
15022
15023
|
const manifest = result.previousManifest;
|
|
@@ -15842,7 +15843,9 @@ async function resolveCliTargetState(target, options) {
|
|
|
15842
15843
|
graphLockPath: stableGraphLockPath,
|
|
15843
15844
|
stableManifest,
|
|
15844
15845
|
stableLock,
|
|
15845
|
-
transport
|
|
15846
|
+
transport,
|
|
15847
|
+
recoverLegacyState: options.recoverLegacyState,
|
|
15848
|
+
warn: options.warn
|
|
15846
15849
|
});
|
|
15847
15850
|
return {
|
|
15848
15851
|
adapter,
|
|
@@ -18,8 +18,8 @@ import {
|
|
|
18
18
|
removeApplyJournal,
|
|
19
19
|
rollbackCompletedOperations,
|
|
20
20
|
writeApplyJournal
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import "./chunk-
|
|
21
|
+
} from "./chunk-FP26KSBM.js";
|
|
22
|
+
import "./chunk-GE7F76AC.js";
|
|
23
23
|
export {
|
|
24
24
|
abortApplyJournal,
|
|
25
25
|
acquireApplyLock,
|
package/openpack.json
CHANGED
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@ allowed-tools: [Bash]
|
|
|
5
5
|
license: MIT
|
|
6
6
|
metadata:
|
|
7
7
|
author: NestDevLab
|
|
8
|
-
version: "0.20.
|
|
8
|
+
version: "0.20.11"
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# agentwheel
|
|
@@ -618,3 +618,17 @@ nothing else is stale. If it differs, regenerate only the affected graph locks (
|
|
|
618
618
|
leave them uncommitted: lock commits belong to the approved install. `update --dependency` cannot
|
|
619
619
|
recompute an edge whose root node id changed (e.g. after renaming the root package's artifacts);
|
|
620
620
|
regenerate the locks instead.
|
|
621
|
+
|
|
622
|
+
If target-state discovery rejects an invalid historical graph-lock/manifest pair, first write and
|
|
623
|
+
review `agentwheel ownership recovery-plan`. For a complete local report, preview a stable-state
|
|
624
|
+
recovery with the exact Fleet target:
|
|
625
|
+
|
|
626
|
+
```bash
|
|
627
|
+
agentwheel plan --fleet <fleet-id> --agent <agent> \
|
|
628
|
+
--recover-legacy-state --force-conflict --replace-conflict
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
`--recover-legacy-state` preserves the invalid historical files and only bypasses their use as the
|
|
632
|
+
planning base. `--force-conflict` adopts exact existing content; `--replace-conflict` permits the
|
|
633
|
+
reviewed plan to update differing unmanaged content. Apply only the same reviewed target and flags.
|
|
634
|
+
After the first stable install, rerun the ordinary plan without recovery flags and require a no-op.
|