agentwheel 0.20.10 → 0.20.12
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 +73 -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) {
|
|
@@ -8536,6 +8541,14 @@ async function resolvePriorTargetState(options) {
|
|
|
8536
8541
|
};
|
|
8537
8542
|
}
|
|
8538
8543
|
if (options.stableLock) return { graphLock: options.stableLock };
|
|
8544
|
+
if (candidates.length > 0 && options.recoverLegacyState) {
|
|
8545
|
+
for (const candidate of candidates) {
|
|
8546
|
+
options.warn?.(
|
|
8547
|
+
`Legacy graph-only target state for ${options.adapter} at ${candidate.graphLockPath} has no correlated install manifest; runtime identity and ownership cannot be proven. Preserving it outside the recovered stable state.`
|
|
8548
|
+
);
|
|
8549
|
+
}
|
|
8550
|
+
return {};
|
|
8551
|
+
}
|
|
8539
8552
|
if (candidates.length > 1) {
|
|
8540
8553
|
throw new Error(`Ambiguous legacy target state for ${options.adapter}: multiple graph-only candidates were found.`);
|
|
8541
8554
|
}
|
|
@@ -8563,34 +8576,28 @@ async function discoverLegacyStateCandidates(options) {
|
|
|
8563
8576
|
const fingerprint = name.slice(0, -suffix.length);
|
|
8564
8577
|
if (!/^[a-f0-9]{64}$/u.test(fingerprint)) continue;
|
|
8565
8578
|
const graphLockPath = join33(directory, name);
|
|
8566
|
-
let graphLock;
|
|
8567
8579
|
try {
|
|
8580
|
+
let graphLock;
|
|
8568
8581
|
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 {
|
|
8582
|
+
if (graphLock.canonical.targetFingerprint !== fingerprint) {
|
|
8583
|
+
throw new Error(
|
|
8584
|
+
`Legacy graph lock fingerprint does not match its filename at ${graphLockPath}.`
|
|
8585
|
+
);
|
|
8586
|
+
}
|
|
8587
|
+
if (options.transport.kind === "ssh") {
|
|
8588
|
+
throw new Error(
|
|
8589
|
+
`Legacy SSH target state at ${graphLockPath} does not record its original endpoint; Agentwheel cannot prove endpoint identity, so the graph lock was preserved.`
|
|
8590
|
+
);
|
|
8591
|
+
}
|
|
8592
|
+
const graphLockDigest = digestGraphLock(graphLock);
|
|
8593
|
+
const candidateStateKey = stateKeyFor(options.adapter, {
|
|
8594
|
+
installationType: options.installationType,
|
|
8595
|
+
stateKey: options.explicitStateKey,
|
|
8596
|
+
targetFingerprint: fingerprint,
|
|
8597
|
+
fleetId: options.fleetId
|
|
8598
|
+
});
|
|
8599
|
+
let manifest;
|
|
8600
|
+
let sourceLock;
|
|
8594
8601
|
manifest = await readInstallManifest(options.installRoot, options.adapter, options.transport, {
|
|
8595
8602
|
installationType: options.installationType,
|
|
8596
8603
|
stateKey: candidateStateKey
|
|
@@ -8599,32 +8606,32 @@ async function discoverLegacyStateCandidates(options) {
|
|
|
8599
8606
|
installationType: options.installationType,
|
|
8600
8607
|
stateKey: candidateStateKey
|
|
8601
8608
|
});
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
if (sourceLock) {
|
|
8609
|
-
throw new Error(`Legacy source lock for ${graphLockPath} has no correlated install manifest.`);
|
|
8609
|
+
if (!manifest) {
|
|
8610
|
+
if (sourceLock) {
|
|
8611
|
+
throw new Error(`Legacy source lock for ${graphLockPath} has no correlated install manifest.`);
|
|
8612
|
+
}
|
|
8613
|
+
candidates.push({ stateKey: candidateStateKey, graphLockPath, graphLockDigest, graphLock });
|
|
8614
|
+
continue;
|
|
8610
8615
|
}
|
|
8611
|
-
|
|
8612
|
-
|
|
8616
|
+
const validated = validateLegacyManifestCandidate(manifest, {
|
|
8617
|
+
...options,
|
|
8618
|
+
candidateStateKey,
|
|
8619
|
+
graphLockDigest,
|
|
8620
|
+
graphLockPath
|
|
8621
|
+
});
|
|
8622
|
+
candidates.push({
|
|
8623
|
+
stateKey: candidateStateKey,
|
|
8624
|
+
graphLockPath,
|
|
8625
|
+
graphLockDigest,
|
|
8626
|
+
graphLock,
|
|
8627
|
+
manifest: validated,
|
|
8628
|
+
sourceLock
|
|
8629
|
+
});
|
|
8630
|
+
} catch (error) {
|
|
8631
|
+
const message = `Legacy target state for ${graphLockPath} is invalid: ` + (error instanceof Error ? error.message : String(error));
|
|
8632
|
+
if (!options.recoverLegacyState) throw new Error(message);
|
|
8633
|
+
options.warn?.(`${message} Preserving it outside the recovered stable state.`);
|
|
8613
8634
|
}
|
|
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
8635
|
}
|
|
8629
8636
|
return candidates;
|
|
8630
8637
|
}
|
|
@@ -13703,10 +13710,10 @@ program.command("scan").description("scan a package source for validation findin
|
|
|
13703
13710
|
await releaseGitSnapshotLease(resolved.cacheLeasePath);
|
|
13704
13711
|
}
|
|
13705
13712
|
});
|
|
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) => {
|
|
13713
|
+
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
13714
|
await runInstallCommand(source, { ...options, dryRun: true }, { apply: false });
|
|
13708
13715
|
});
|
|
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) => {
|
|
13716
|
+
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
13717
|
await runInstallCommand(source, options, { apply: !options.dryRun });
|
|
13711
13718
|
});
|
|
13712
13719
|
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 +14914,8 @@ async function buildGraphPlansForTarget(target, source, options, behavior) {
|
|
|
14907
14914
|
}
|
|
14908
14915
|
const priorGroupState = await resolveCliTargetState(group.target, {
|
|
14909
14916
|
...targetOptions,
|
|
14910
|
-
installationType: group.installationType
|
|
14917
|
+
installationType: group.installationType,
|
|
14918
|
+
recoverLegacyState: targetOptions.recoverLegacyState
|
|
14911
14919
|
});
|
|
14912
14920
|
const previousGroupLock = priorGroupState.graphLock;
|
|
14913
14921
|
const dependencyUpdateRootNames = /* @__PURE__ */ new Set();
|
|
@@ -15016,7 +15024,8 @@ async function buildGraphPlansForTarget(target, source, options, behavior) {
|
|
|
15016
15024
|
deferForeignStateCheck: targetOptions.deferForeignStateCheck === true || targetOptions.focusedArtifact !== void 0,
|
|
15017
15025
|
replaceConflict: targetOptions.replaceConflict,
|
|
15018
15026
|
retireExactMcp: targetOptions.retireExactMcp,
|
|
15019
|
-
expectedFromWorkspaceOwner: targetOptions.expectedFromWorkspaceOwner
|
|
15027
|
+
expectedFromWorkspaceOwner: targetOptions.expectedFromWorkspaceOwner,
|
|
15028
|
+
recoverLegacyState: targetOptions.recoverLegacyState
|
|
15020
15029
|
});
|
|
15021
15030
|
if ((behavior.mode === "install" || behavior.mode === "update") && scopedRootId) {
|
|
15022
15031
|
const manifest = result.previousManifest;
|
|
@@ -15842,7 +15851,9 @@ async function resolveCliTargetState(target, options) {
|
|
|
15842
15851
|
graphLockPath: stableGraphLockPath,
|
|
15843
15852
|
stableManifest,
|
|
15844
15853
|
stableLock,
|
|
15845
|
-
transport
|
|
15854
|
+
transport,
|
|
15855
|
+
recoverLegacyState: options.recoverLegacyState,
|
|
15856
|
+
warn: options.warn
|
|
15846
15857
|
});
|
|
15847
15858
|
return {
|
|
15848
15859
|
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.12"
|
|
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.
|