agentwheel 0.10.0 → 0.11.0
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 +58 -4
- package/dist/index.js +177 -22
- package/openpack.json +1 -1
- package/package.json +1 -1
- package/skills/agentwheel/SKILL.md +31 -1
package/README.md
CHANGED
|
@@ -34,9 +34,9 @@ agentwheel install
|
|
|
34
34
|
No lock-in. No central gatekeeper. Packages live in plain git repos or local folders, customizations
|
|
35
35
|
live in your workspace, and runtimes stay generated output.
|
|
36
36
|
|
|
37
|
-
> **Status: early (v0.
|
|
38
|
-
> `add`, `install`, `update`, and `uninstall`. A hidden `sync` shim remains for
|
|
39
|
-
>
|
|
37
|
+
> **Status: early (v0.11).** The public CLI vocabulary is package-manager style:
|
|
38
|
+
> `add`, `install`, `update`, and `uninstall`. A hidden `sync` shim remains for old bootstrapped
|
|
39
|
+
> skills; use `install` in all new docs and scripts.
|
|
40
40
|
|
|
41
41
|
## Supported runtimes & resources
|
|
42
42
|
|
|
@@ -272,6 +272,58 @@ still owned by another configured package.
|
|
|
272
272
|
}
|
|
273
273
|
```
|
|
274
274
|
|
|
275
|
+
### Source Overrides
|
|
276
|
+
|
|
277
|
+
Use package-level `overrides` when a workspace intentionally wants one selected source to replace
|
|
278
|
+
an artifact that arrives from another package, such as a forked skill replacing the same skill
|
|
279
|
+
pulled in by a meta-package. Overrides are explicit; package array order never decides precedence.
|
|
280
|
+
|
|
281
|
+
```jsonc
|
|
282
|
+
{
|
|
283
|
+
"schemaVersion": 1,
|
|
284
|
+
"packages": [
|
|
285
|
+
{
|
|
286
|
+
"name": "nestdev-must-have-core",
|
|
287
|
+
"source": "github:NestDevLab/agent-must-have#core",
|
|
288
|
+
"driver": "git",
|
|
289
|
+
"adapter": "codex",
|
|
290
|
+
"mode": "tracking"
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
"name": "agent-toolkit-nestdev",
|
|
294
|
+
"source": "github:Yehonal/agent-toolkit#main",
|
|
295
|
+
"driver": "git",
|
|
296
|
+
"adapter": "codex",
|
|
297
|
+
"mode": "tracking",
|
|
298
|
+
"select": [
|
|
299
|
+
"rules/self-improve-on-correction.md",
|
|
300
|
+
"skills/self-improve"
|
|
301
|
+
],
|
|
302
|
+
"overrides": [
|
|
303
|
+
"github:FrancescoBorzi/agent-toolkit::rules/self-improve-on-correction.md",
|
|
304
|
+
"github:FrancescoBorzi/agent-toolkit::skills/self-improve"
|
|
305
|
+
]
|
|
306
|
+
}
|
|
307
|
+
]
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
The `source::type/name` selector identifies the artifact to replace. `github:owner/repo` matches
|
|
312
|
+
that repository at any ref; add `#main` or another ref to narrow it. The replacing package must
|
|
313
|
+
select exactly one artifact with the same `type/name`, and the override must match exactly one
|
|
314
|
+
losing artifact. Otherwise planning fails instead of hiding a collision.
|
|
315
|
+
|
|
316
|
+
The same declaration can be created from the CLI:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
agentwheel add github:Yehonal/agent-toolkit#main \
|
|
320
|
+
--skill self-improve \
|
|
321
|
+
--override 'github:FrancescoBorzi/agent-toolkit::skills/self-improve'
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
`agentwheel plan`, `agentwheel deps tree`, and `agentwheel deps why` print `OVERRIDE` lines for
|
|
325
|
+
these decisions, and graph locks store them for review.
|
|
326
|
+
|
|
275
327
|
Migrating an existing legacy package takes one command:
|
|
276
328
|
|
|
277
329
|
```bash
|
|
@@ -285,7 +337,9 @@ Drift detection blocks accidental edits to generated runtime files. Intentional
|
|
|
285
337
|
|
|
286
338
|
- **Layer** local instructions with `agentwheel remember`.
|
|
287
339
|
- **Add** separate local artifacts under `.agentwheel/additions`.
|
|
288
|
-
- **Override** an upstream item under `.agentwheel/overrides`.
|
|
340
|
+
- **Override content** for an upstream item under `.agentwheel/overrides`.
|
|
341
|
+
- **Override source precedence** with package `overrides` when a forked source should replace a
|
|
342
|
+
colliding artifact from another package.
|
|
289
343
|
- **Eject** an item into `.agentwheel/ejected` when you want local ownership.
|
|
290
344
|
|
|
291
345
|
## Custom And Private Runtimes
|
package/dist/index.js
CHANGED
|
@@ -297,7 +297,8 @@ var graphLockRootSchema = z3.object({
|
|
|
297
297
|
graphNodeId: z3.string().min(1),
|
|
298
298
|
mode: z3.enum(["pinned", "tracking"]),
|
|
299
299
|
selected: z3.array(z3.string().min(1)),
|
|
300
|
-
aliases: z3.record(z3.string(), z3.string().min(1)).optional()
|
|
300
|
+
aliases: z3.record(z3.string(), z3.string().min(1)).optional(),
|
|
301
|
+
overrides: z3.array(z3.string().min(1)).optional()
|
|
301
302
|
});
|
|
302
303
|
var graphLockEdgeSchema = z3.object({
|
|
303
304
|
from: z3.string().min(1),
|
|
@@ -346,6 +347,15 @@ var graphLockNamespacingSchema = z3.object({
|
|
|
346
347
|
installName: z3.string().min(1),
|
|
347
348
|
reason: z3.enum(["alias", "transitive-collision"])
|
|
348
349
|
});
|
|
350
|
+
var graphLockOverrideSchema = z3.object({
|
|
351
|
+
rootId: z3.string().min(1),
|
|
352
|
+
selector: z3.string().min(1),
|
|
353
|
+
graphNodeId: z3.string().min(1),
|
|
354
|
+
overriddenGraphNodeId: z3.string().min(1),
|
|
355
|
+
type: artifactTypeSchema,
|
|
356
|
+
name: z3.string().min(1),
|
|
357
|
+
installName: z3.string().min(1)
|
|
358
|
+
});
|
|
349
359
|
var graphLockCanonicalSchema = z3.object({
|
|
350
360
|
targetFingerprint: z3.string().min(1).optional(),
|
|
351
361
|
roots: z3.array(graphLockRootSchema),
|
|
@@ -354,6 +364,7 @@ var graphLockCanonicalSchema = z3.object({
|
|
|
354
364
|
includeEdges: z3.array(graphLockIncludeEdgeSchema).default([]),
|
|
355
365
|
artifacts: z3.array(graphLockArtifactSchema).default([]),
|
|
356
366
|
namespacing: z3.array(graphLockNamespacingSchema).default([]),
|
|
367
|
+
overrides: z3.array(graphLockOverrideSchema).default([]),
|
|
357
368
|
plainNameIncumbents: z3.array(graphLockPlainNameIncumbentSchema).default([])
|
|
358
369
|
});
|
|
359
370
|
var graphLockSchema = z3.object({
|
|
@@ -384,7 +395,11 @@ function canonicalizeGraphLock(lock) {
|
|
|
384
395
|
version: 1,
|
|
385
396
|
canonical: {
|
|
386
397
|
targetFingerprint: parsed.canonical.targetFingerprint,
|
|
387
|
-
roots: [...parsed.canonical.roots].map((root) => ({
|
|
398
|
+
roots: [...parsed.canonical.roots].map((root) => ({
|
|
399
|
+
...root,
|
|
400
|
+
selected: sortedUnique(root.selected),
|
|
401
|
+
overrides: root.overrides ? sortedUnique(root.overrides) : void 0
|
|
402
|
+
})).sort((a, b) => `${a.rootId}:${a.graphNodeId}`.localeCompare(`${b.rootId}:${b.graphNodeId}`)),
|
|
388
403
|
nodes: [...parsed.canonical.nodes].map((node) => ({
|
|
389
404
|
...node,
|
|
390
405
|
requiredBy: sortedUnique(node.requiredBy),
|
|
@@ -395,6 +410,7 @@ function canonicalizeGraphLock(lock) {
|
|
|
395
410
|
includeEdges: [...parsed.canonical.includeEdges].sort((a, b) => `${a.fromNodeId}:${a.alias}:${a.toNodeId}:${a.selector}`.localeCompare(`${b.fromNodeId}:${b.alias}:${b.toNodeId}:${b.selector}`)),
|
|
396
411
|
artifacts: [...parsed.canonical.artifacts].map((artifact) => ({ ...artifact, owners: sortedUnique(artifact.owners) })).sort((a, b) => a.logicalSelector.localeCompare(b.logicalSelector)),
|
|
397
412
|
namespacing: [...parsed.canonical.namespacing].sort((a, b) => `${a.type}:${a.installName}:${a.graphNodeId}:${a.name}`.localeCompare(`${b.type}:${b.installName}:${b.graphNodeId}:${b.name}`)),
|
|
413
|
+
overrides: [...parsed.canonical.overrides].sort((a, b) => `${a.type}:${a.installName}:${a.graphNodeId}:${a.overriddenGraphNodeId}`.localeCompare(`${b.type}:${b.installName}:${b.graphNodeId}:${b.overriddenGraphNodeId}`)),
|
|
398
414
|
plainNameIncumbents: [...parsed.canonical.plainNameIncumbents].sort((a, b) => `${a.adapter}:${a.targetFingerprint}:${a.type}:${a.name}`.localeCompare(`${b.adapter}:${b.targetFingerprint}:${b.type}:${b.name}`))
|
|
399
415
|
}
|
|
400
416
|
};
|
|
@@ -2138,6 +2154,9 @@ function formatGraphPlan(result) {
|
|
|
2138
2154
|
for (const decision of result.bundle.graphLock.canonical.namespacing) {
|
|
2139
2155
|
lines.push(`NAMESPACE ${decision.graphNodeId}:${decision.type}/${decision.name} -> ${decision.type}/${decision.installName} (${decision.reason})`);
|
|
2140
2156
|
}
|
|
2157
|
+
for (const decision of result.bundle.graphLock.canonical.overrides) {
|
|
2158
|
+
lines.push(`OVERRIDE ${decision.graphNodeId}:${decision.type}/${decision.name} replaces ${decision.overriddenGraphNodeId}:${decision.type}/${decision.name} via ${decision.rootId} (${decision.selector})`);
|
|
2159
|
+
}
|
|
2141
2160
|
if (result.graphDiff.length > 0) {
|
|
2142
2161
|
lines.push("Graph diff:");
|
|
2143
2162
|
lines.push(...result.graphDiff);
|
|
@@ -2175,6 +2194,9 @@ function formatLockDependencyTree(lock) {
|
|
|
2175
2194
|
for (const decision of lock.canonical.namespacing) {
|
|
2176
2195
|
lines.push(`NAMESPACE ${decision.graphNodeId}:${decision.type}/${decision.name} -> ${decision.type}/${decision.installName} (${decision.reason})`);
|
|
2177
2196
|
}
|
|
2197
|
+
for (const decision of lock.canonical.overrides) {
|
|
2198
|
+
lines.push(`OVERRIDE ${decision.graphNodeId}:${decision.type}/${decision.name} replaces ${decision.overriddenGraphNodeId}:${decision.type}/${decision.name} via ${decision.rootId} (${decision.selector})`);
|
|
2199
|
+
}
|
|
2178
2200
|
return lines.join("\n");
|
|
2179
2201
|
}
|
|
2180
2202
|
function formatDepsWhy(lock, manifest, query) {
|
|
@@ -2197,6 +2219,9 @@ function formatDepsWhy(lock, manifest, query) {
|
|
|
2197
2219
|
}
|
|
2198
2220
|
const namespace = lock.canonical.namespacing.find((decision) => decision.graphNodeId === match.graphNodeId && decision.type === match.type && decision.name === match.name);
|
|
2199
2221
|
lines.push(namespace ? `NAME ${namespace.reason}: ${namespace.type}/${namespace.name} -> ${namespace.type}/${namespace.installName}` : `NAME plain: ${match.type}/${match.name}`);
|
|
2222
|
+
for (const override of lock.canonical.overrides.filter((decision) => decision.graphNodeId === match.graphNodeId && decision.type === match.type && decision.name === match.name)) {
|
|
2223
|
+
lines.push(`OVERRIDE replaces ${override.overriddenGraphNodeId}:${override.type}/${override.name} via ${override.rootId}`);
|
|
2224
|
+
}
|
|
2200
2225
|
return lines.join("\n");
|
|
2201
2226
|
}
|
|
2202
2227
|
function formatSelected(selected, reasons) {
|
|
@@ -3776,7 +3801,8 @@ var workspacePackageSchema = z6.object({
|
|
|
3776
3801
|
requestedRef: z6.string().min(1).optional(),
|
|
3777
3802
|
select: z6.array(z6.string().min(1)).optional(),
|
|
3778
3803
|
skills: z6.array(z6.string().min(1)).optional(),
|
|
3779
|
-
aliases: z6.record(z6.string(), z6.string().min(1)).optional()
|
|
3804
|
+
aliases: z6.record(z6.string(), z6.string().min(1)).optional(),
|
|
3805
|
+
overrides: z6.array(z6.string().min(1)).optional()
|
|
3780
3806
|
});
|
|
3781
3807
|
var workspaceProfileRuntimeSchema = z6.object({
|
|
3782
3808
|
agent: z6.string().min(1).optional(),
|
|
@@ -4315,6 +4341,7 @@ async function resolveDependencyGraph(roots, options) {
|
|
|
4315
4341
|
requiredBy: `workspace:${rootId}`,
|
|
4316
4342
|
rootId,
|
|
4317
4343
|
aliases: root.aliases,
|
|
4344
|
+
overrides: root.overrides,
|
|
4318
4345
|
useLock: root.useLock ?? options.lockedResolution,
|
|
4319
4346
|
depth: 0,
|
|
4320
4347
|
optional: false,
|
|
@@ -4346,7 +4373,7 @@ async function resolveDependencyGraph(roots, options) {
|
|
|
4346
4373
|
generatedAt: (options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
|
|
4347
4374
|
};
|
|
4348
4375
|
}
|
|
4349
|
-
function createGraphLock(graph, artifacts = [], targetFingerprint, includeEdges = [], namespacing = []) {
|
|
4376
|
+
function createGraphLock(graph, artifacts = [], targetFingerprint, includeEdges = [], namespacing = [], overrides = []) {
|
|
4350
4377
|
const roots = graph.roots.map((root) => ({
|
|
4351
4378
|
rootId: root.rootId,
|
|
4352
4379
|
source: root.source,
|
|
@@ -4354,7 +4381,8 @@ function createGraphLock(graph, artifacts = [], targetFingerprint, includeEdges
|
|
|
4354
4381
|
graphNodeId: root.graphNodeId,
|
|
4355
4382
|
mode: root.mode,
|
|
4356
4383
|
selected: root.selected,
|
|
4357
|
-
aliases: root.aliases
|
|
4384
|
+
aliases: root.aliases,
|
|
4385
|
+
overrides: root.overrides
|
|
4358
4386
|
}));
|
|
4359
4387
|
return {
|
|
4360
4388
|
version: 1,
|
|
@@ -4366,6 +4394,7 @@ function createGraphLock(graph, artifacts = [], targetFingerprint, includeEdges
|
|
|
4366
4394
|
includeEdges,
|
|
4367
4395
|
artifacts,
|
|
4368
4396
|
namespacing,
|
|
4397
|
+
overrides,
|
|
4369
4398
|
plainNameIncumbents: []
|
|
4370
4399
|
}
|
|
4371
4400
|
};
|
|
@@ -4462,7 +4491,8 @@ Run without ${lockLabel === "Offline" ? "--offline" : "--frozen-lock"} first.`
|
|
|
4462
4491
|
graphNodeId: state.node.id,
|
|
4463
4492
|
mode: state.node.mode,
|
|
4464
4493
|
selected: state.node.selected,
|
|
4465
|
-
aliases: requirement.aliases
|
|
4494
|
+
aliases: requirement.aliases,
|
|
4495
|
+
overrides: requirement.overrides
|
|
4466
4496
|
});
|
|
4467
4497
|
}
|
|
4468
4498
|
if (requirement.parentId && requirement.alias) {
|
|
@@ -5069,7 +5099,8 @@ function diffGraphLocks(previous, next) {
|
|
|
5069
5099
|
return [
|
|
5070
5100
|
...diffNodes(previous.canonical.nodes, next.canonical.nodes),
|
|
5071
5101
|
...diffIncludeEdges(previous.canonical.includeEdges, next.canonical.includeEdges),
|
|
5072
|
-
...diffNamespacing(previous.canonical.namespacing, next.canonical.namespacing)
|
|
5102
|
+
...diffNamespacing(previous.canonical.namespacing, next.canonical.namespacing),
|
|
5103
|
+
...diffOverrides(previous.canonical.overrides, next.canonical.overrides)
|
|
5073
5104
|
];
|
|
5074
5105
|
}
|
|
5075
5106
|
function diffNodes(previous, next) {
|
|
@@ -5131,6 +5162,23 @@ function diffNamespacing(previous, next) {
|
|
|
5131
5162
|
}
|
|
5132
5163
|
return lines.sort((a, b) => a.localeCompare(b));
|
|
5133
5164
|
}
|
|
5165
|
+
function diffOverrides(previous, next) {
|
|
5166
|
+
const previousByKey = new Map(previous.map((decision) => [overrideKey(decision), decision]));
|
|
5167
|
+
const nextByKey = new Map(next.map((decision) => [overrideKey(decision), decision]));
|
|
5168
|
+
const lines = [];
|
|
5169
|
+
for (const [key, decision] of nextByKey) {
|
|
5170
|
+
const old = previousByKey.get(key);
|
|
5171
|
+
if (!old) {
|
|
5172
|
+
lines.push(`ADDED override ${formatOverride(decision)}`);
|
|
5173
|
+
} else if (old.graphNodeId !== decision.graphNodeId || old.installName !== decision.installName) {
|
|
5174
|
+
lines.push(`CHANGED override ${decision.selector} ${old.graphNodeId}:${old.type}/${old.name} -> ${decision.graphNodeId}:${decision.type}/${decision.name}`);
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
for (const [key, decision] of previousByKey) {
|
|
5178
|
+
if (!nextByKey.has(key)) lines.push(`REMOVED override ${formatOverride(decision)}`);
|
|
5179
|
+
}
|
|
5180
|
+
return lines.sort((a, b) => a.localeCompare(b));
|
|
5181
|
+
}
|
|
5134
5182
|
function stableNodeKey(node) {
|
|
5135
5183
|
return `${node.normalizedSource}\0${node.name}`;
|
|
5136
5184
|
}
|
|
@@ -5150,9 +5198,15 @@ function formatIncludeEdge(edge) {
|
|
|
5150
5198
|
function namespaceKey(decision) {
|
|
5151
5199
|
return `${decision.graphNodeId}\0${decision.type}\0${decision.name}`;
|
|
5152
5200
|
}
|
|
5201
|
+
function overrideKey(decision) {
|
|
5202
|
+
return `${decision.rootId}\0${decision.selector}\0${decision.overriddenGraphNodeId}\0${decision.type}\0${decision.name}`;
|
|
5203
|
+
}
|
|
5153
5204
|
function formatNamespace(decision) {
|
|
5154
5205
|
return `${decision.graphNodeId}:${decision.type}/${decision.name} -> ${decision.type}/${decision.installName} (${decision.reason})`;
|
|
5155
5206
|
}
|
|
5207
|
+
function formatOverride(decision) {
|
|
5208
|
+
return `${decision.graphNodeId}:${decision.type}/${decision.name} replaces ${decision.overriddenGraphNodeId}:${decision.type}/${decision.name} via ${decision.rootId} (${decision.selector})`;
|
|
5209
|
+
}
|
|
5156
5210
|
function short(hash) {
|
|
5157
5211
|
return hash.slice(0, 12);
|
|
5158
5212
|
}
|
|
@@ -5254,13 +5308,13 @@ async function renderGraphForTarget(graph, targetContext = {}) {
|
|
|
5254
5308
|
owners: [...rawNode.node.requiredBy].sort((a, b) => a.localeCompare(b))
|
|
5255
5309
|
})));
|
|
5256
5310
|
}
|
|
5257
|
-
const { artifacts: namedArtifacts, namespacing } = assignInstallNames(graph, artifacts);
|
|
5311
|
+
const { artifacts: namedArtifacts, namespacing, overrides } = assignInstallNames(graph, artifacts);
|
|
5258
5312
|
const sortedArtifacts = namedArtifacts.sort((a, b) => a.logicalSelector.localeCompare(b.logicalSelector));
|
|
5259
5313
|
return {
|
|
5260
5314
|
root,
|
|
5261
5315
|
nodes: graph.nodes,
|
|
5262
5316
|
artifacts: sortedArtifacts,
|
|
5263
|
-
graphLock: createGraphLock(graph, sortedArtifacts.map(lockArtifactFor), targetContext.targetFingerprint, [...includeEdges.values()], namespacing)
|
|
5317
|
+
graphLock: createGraphLock(graph, sortedArtifacts.map(lockArtifactFor), targetContext.targetFingerprint, [...includeEdges.values()], namespacing, overrides)
|
|
5264
5318
|
};
|
|
5265
5319
|
}
|
|
5266
5320
|
function aliasEdgeMap(graph) {
|
|
@@ -5304,7 +5358,8 @@ function assignInstallNames(graph, artifacts) {
|
|
|
5304
5358
|
decisions.set(decisionKey(updated), namespaceDecision(updated, "alias"));
|
|
5305
5359
|
return updated;
|
|
5306
5360
|
});
|
|
5307
|
-
const
|
|
5361
|
+
const { artifacts: withOverrides, overrides } = applyWorkspaceOverrides(graph, withAliases);
|
|
5362
|
+
const collisionGroups = [...groupBy(withOverrides, (artifact) => `${artifact.type}\0${artifact.installName}`).values()].filter((group) => group.length > 1);
|
|
5308
5363
|
const toRename = /* @__PURE__ */ new Set();
|
|
5309
5364
|
for (const group of collisionGroups) {
|
|
5310
5365
|
if (group.some((artifact) => decisions.has(decisionKey(artifact)))) throw installNameCollisionError(group);
|
|
@@ -5315,11 +5370,11 @@ function assignInstallNames(graph, artifacts) {
|
|
|
5315
5370
|
}
|
|
5316
5371
|
}
|
|
5317
5372
|
const used = /* @__PURE__ */ new Map();
|
|
5318
|
-
for (const artifact of
|
|
5373
|
+
for (const artifact of withOverrides) {
|
|
5319
5374
|
if (toRename.has(artifact)) continue;
|
|
5320
5375
|
used.set(`${artifact.type}\0${artifact.installName}`, artifact);
|
|
5321
5376
|
}
|
|
5322
|
-
const out =
|
|
5377
|
+
const out = withOverrides.filter((artifact) => !toRename.has(artifact));
|
|
5323
5378
|
for (const group of groupBy([...toRename], (artifact) => `${artifact.type}\0${artifact.name}`).values()) {
|
|
5324
5379
|
const renamed = namespaceTransitiveGroup(group, used);
|
|
5325
5380
|
for (const artifact of renamed) {
|
|
@@ -5328,7 +5383,52 @@ function assignInstallNames(graph, artifacts) {
|
|
|
5328
5383
|
out.push(artifact);
|
|
5329
5384
|
}
|
|
5330
5385
|
}
|
|
5331
|
-
|
|
5386
|
+
const finalInstallNames = new Map(out.map((artifact) => [decisionKey(artifact), artifact.installName]));
|
|
5387
|
+
const finalOverrides = overrides.map((override) => ({
|
|
5388
|
+
...override,
|
|
5389
|
+
installName: finalInstallNames.get(`${override.graphNodeId}\0${override.type}\0${override.name}`) ?? override.installName
|
|
5390
|
+
}));
|
|
5391
|
+
return { artifacts: out, namespacing: [...decisions.values()], overrides: finalOverrides };
|
|
5392
|
+
}
|
|
5393
|
+
function applyWorkspaceOverrides(graph, artifacts) {
|
|
5394
|
+
const directives = workspaceOverrides(graph);
|
|
5395
|
+
if (directives.length === 0) return { artifacts, overrides: [] };
|
|
5396
|
+
const nodeById = new Map(graph.nodes.map((node) => [node.id, node]));
|
|
5397
|
+
let remaining = [...artifacts];
|
|
5398
|
+
const decisions = [];
|
|
5399
|
+
for (const directive of directives) {
|
|
5400
|
+
const matched = remaining.filter((artifact) => overrideMatchesArtifact(directive.selector, artifact, nodeById.get(artifact.graphNodeId)));
|
|
5401
|
+
const losers = matched.filter((artifact) => !directive.reachable.has(artifact.graphNodeId));
|
|
5402
|
+
if (matched.length === 0) {
|
|
5403
|
+
throw new Error(`Workspace override ${directive.selector} from ${directive.rootId} did not match any rendered artifact.`);
|
|
5404
|
+
}
|
|
5405
|
+
if (losers.length === 0) {
|
|
5406
|
+
throw new Error(`Workspace override ${directive.selector} from ${directive.rootId} matched only artifacts inside the replacing root.`);
|
|
5407
|
+
}
|
|
5408
|
+
if (losers.length > 1) {
|
|
5409
|
+
throw new Error(`Workspace override ${directive.selector} from ${directive.rootId} matched multiple artifacts: ${losers.map((artifact) => artifact.logicalSelector).sort().join(", ")}`);
|
|
5410
|
+
}
|
|
5411
|
+
const loser = losers[0];
|
|
5412
|
+
const winners = remaining.filter((artifact) => artifact !== loser && directive.reachable.has(artifact.graphNodeId) && artifact.type === loser.type && artifact.name === loser.name);
|
|
5413
|
+
if (winners.length === 0) {
|
|
5414
|
+
throw new Error(`Workspace override ${directive.selector} from ${directive.rootId} has no selected replacement for ${loser.type}/${loser.name}.`);
|
|
5415
|
+
}
|
|
5416
|
+
if (winners.length > 1) {
|
|
5417
|
+
throw new Error(`Workspace override ${directive.selector} from ${directive.rootId} has multiple selected replacements for ${loser.type}/${loser.name}: ${winners.map((artifact) => artifact.logicalSelector).sort().join(", ")}`);
|
|
5418
|
+
}
|
|
5419
|
+
const winner = winners[0];
|
|
5420
|
+
remaining = remaining.filter((artifact) => artifact !== loser);
|
|
5421
|
+
decisions.push({
|
|
5422
|
+
rootId: directive.rootId,
|
|
5423
|
+
selector: directive.selector,
|
|
5424
|
+
graphNodeId: winner.graphNodeId,
|
|
5425
|
+
overriddenGraphNodeId: loser.graphNodeId,
|
|
5426
|
+
type: winner.type,
|
|
5427
|
+
name: winner.name,
|
|
5428
|
+
installName: winner.installName
|
|
5429
|
+
});
|
|
5430
|
+
}
|
|
5431
|
+
return { artifacts: remaining, overrides: decisions };
|
|
5332
5432
|
}
|
|
5333
5433
|
function namespaceTransitiveGroup(group, used) {
|
|
5334
5434
|
const sorted = [...group].sort((a, b) => a.logicalSelector.localeCompare(b.logicalSelector));
|
|
@@ -5366,6 +5466,16 @@ function workspaceAliases(graph) {
|
|
|
5366
5466
|
}
|
|
5367
5467
|
return aliases;
|
|
5368
5468
|
}
|
|
5469
|
+
function workspaceOverrides(graph) {
|
|
5470
|
+
const overrides = [];
|
|
5471
|
+
for (const root of graph.roots) {
|
|
5472
|
+
const reachable = reachableNodeIds(graph, root.graphNodeId);
|
|
5473
|
+
for (const selector of root.overrides ?? []) {
|
|
5474
|
+
overrides.push({ rootId: root.rootId, selector, reachable });
|
|
5475
|
+
}
|
|
5476
|
+
}
|
|
5477
|
+
return overrides;
|
|
5478
|
+
}
|
|
5369
5479
|
function validateAliasScopes(graph, artifacts, aliases) {
|
|
5370
5480
|
for (const alias of aliases) {
|
|
5371
5481
|
const matching = artifacts.filter((artifact) => {
|
|
@@ -5382,6 +5492,35 @@ function aliasMatchesArtifact(selector, artifact, node) {
|
|
|
5382
5492
|
const artifactSelector = `${artifact.type}/${artifact.name}`;
|
|
5383
5493
|
return selector === `${artifact.graphNodeId}:${artifactSelector}` || node !== void 0 && selector === `${node.name}@${node.version}:${artifactSelector}` || node !== void 0 && selector === `${node.name}:${artifactSelector}`;
|
|
5384
5494
|
}
|
|
5495
|
+
function overrideMatchesArtifact(selector, artifact, node) {
|
|
5496
|
+
const sourceSeparator = selector.lastIndexOf("::");
|
|
5497
|
+
if (sourceSeparator >= 0) {
|
|
5498
|
+
const sourceSelector = selector.slice(0, sourceSeparator).trim();
|
|
5499
|
+
const artifactSelector = selector.slice(sourceSeparator + 2).trim();
|
|
5500
|
+
return artifactSelector === `${artifact.type}/${artifact.name}` && sourceMatchesArtifact(sourceSelector, node);
|
|
5501
|
+
}
|
|
5502
|
+
return aliasMatchesArtifact(selector, artifact, node);
|
|
5503
|
+
}
|
|
5504
|
+
function sourceMatchesArtifact(selector, node) {
|
|
5505
|
+
if (!node || selector.length === 0) return false;
|
|
5506
|
+
if (selector === node.source || selector === node.normalizedSource || selector === node.name || selector === node.id) return true;
|
|
5507
|
+
const normalized = node.normalizedSource.toLowerCase();
|
|
5508
|
+
const source = node.source.toLowerCase();
|
|
5509
|
+
const value = selector.toLowerCase();
|
|
5510
|
+
if (value === source || value === normalized || value === node.name.toLowerCase() || value === node.id.toLowerCase()) return true;
|
|
5511
|
+
const github = /^github:([^#]+?)(?:#(.+))?$/.exec(value);
|
|
5512
|
+
if (github) {
|
|
5513
|
+
const repo = github[1].replace(/\.git$/i, "");
|
|
5514
|
+
const ref = github[2];
|
|
5515
|
+
const prefix = `git:https://github.com/${repo}.git#`;
|
|
5516
|
+
return ref ? normalized.includes(`${prefix}${ref}`) : normalized.includes(prefix);
|
|
5517
|
+
}
|
|
5518
|
+
if (!value.includes(":") && value.includes("/")) {
|
|
5519
|
+
const repo = value.replace(/\.git$/i, "");
|
|
5520
|
+
return normalized.includes(`github.com/${repo}.git#`) || source.includes(`github.com/${repo}.git`);
|
|
5521
|
+
}
|
|
5522
|
+
return false;
|
|
5523
|
+
}
|
|
5385
5524
|
function reachableNodeIds(graph, rootNodeId) {
|
|
5386
5525
|
const reachable = /* @__PURE__ */ new Set();
|
|
5387
5526
|
const queue = [rootNodeId];
|
|
@@ -5743,7 +5882,8 @@ async function syncProfile(options) {
|
|
|
5743
5882
|
mode: options.mode ?? pkg.mode,
|
|
5744
5883
|
ref: pkg.requestedRef,
|
|
5745
5884
|
select: selected ?? normalizeArtifactSelectors(pkg.select, pkg.skills),
|
|
5746
|
-
aliases: pkg.aliases
|
|
5885
|
+
aliases: pkg.aliases,
|
|
5886
|
+
overrides: pkg.overrides
|
|
5747
5887
|
})),
|
|
5748
5888
|
targetRoot: target.targetRoot,
|
|
5749
5889
|
workspaceRoot: options.workspaceRoot,
|
|
@@ -6246,7 +6386,7 @@ program.command("init").description("initialize an agentwheel workspace or packa
|
|
|
6246
6386
|
if (bootstrapPackage) console.log("Auto-added the agentwheel bootstrap skill for openclaw.");
|
|
6247
6387
|
console.log(nextInstallNudge());
|
|
6248
6388
|
});
|
|
6249
|
-
program.command("add").description("add a package to .agentwheel/config.json without touching runtimes").argument("<source>", "package source").option("--driver <driver>", "source driver (local, git, skillkit, or vercel-skills)").option("--adapter <adapter>", "built-in adapter", "openclaw").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("--target-root <path>", "workspace root", process.cwd()).option("--mode <mode>", "pinned or tracking", "pinned").option("--name <name>", "package alias").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, []).action(async (source, options) => {
|
|
6389
|
+
program.command("add").description("add a package to .agentwheel/config.json without touching runtimes").argument("<source>", "package source").option("--driver <driver>", "source driver (local, git, skillkit, or vercel-skills)").option("--adapter <adapter>", "built-in adapter", "openclaw").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("--target-root <path>", "workspace root", process.cwd()).option("--mode <mode>", "pinned or tracking", "pinned").option("--name <name>", "package alias").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("--override <source-or-package::type/name>", "allow this package to replace a colliding artifact (repeatable)", collectOverrideOption, []).action(async (source, options) => {
|
|
6250
6390
|
const targetRoot = normalizeTargetRoot(options.targetRoot);
|
|
6251
6391
|
const entry = await packageEntryFromSource(source, targetRoot, options);
|
|
6252
6392
|
await writeWorkspaceConfig(targetRoot, upsertPackage(await readWorkspaceConfig(targetRoot), entry));
|
|
@@ -6278,13 +6418,13 @@ program.command("scan").description("scan a package source for validation findin
|
|
|
6278
6418
|
}
|
|
6279
6419
|
if (!result.ok) process.exitCode = 1;
|
|
6280
6420
|
});
|
|
6281
|
-
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").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("--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("--dry-run", "accepted for symmetry; plan never writes", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "with a source argument, exclude 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("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (source, options) => {
|
|
6421
|
+
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").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("--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("--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("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "with a source argument, exclude 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("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (source, options) => {
|
|
6282
6422
|
await runInstallCommand(source, { ...options, dryRun: true }, { apply: false });
|
|
6283
6423
|
});
|
|
6284
|
-
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").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("--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("--profile <name>", "workspace runtime profile").option("--dry-run", "show plan without writing", false).option("--execute-plugins", "execute semantic plugin installs", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "with a source argument, exclude 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("--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) => {
|
|
6424
|
+
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").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("--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("--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("--execute-plugins", "execute semantic plugin installs", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "with a source argument, exclude 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("--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) => {
|
|
6285
6425
|
await runInstallCommand(source, options, { apply: !options.dryRun });
|
|
6286
6426
|
});
|
|
6287
|
-
program.command("sync", { hidden: true }).argument("[name-or-source]", "configured package name/source or package source").option("--driver <driver>", "source driver").option("--adapter <adapter>", "built-in adapter").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("--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("--profile <name>", "workspace runtime profile").option("--dry-run", "show plan without writing", false).option("--execute-plugins", "execute semantic plugin installs", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "with a source argument, exclude 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("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (source, options) => {
|
|
6427
|
+
program.command("sync", { hidden: true }).argument("[name-or-source]", "configured package name/source or package source").option("--driver <driver>", "source driver").option("--adapter <adapter>", "built-in adapter").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("--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("--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("--execute-plugins", "execute semantic plugin installs", false).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "with a source argument, exclude 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("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (source, options) => {
|
|
6288
6428
|
console.error("warning: 'agentwheel sync' is deprecated and will be removed in 0.10. Use 'agentwheel install'.");
|
|
6289
6429
|
await runInstallCommand(source, options, { apply: !options.dryRun });
|
|
6290
6430
|
});
|
|
@@ -6304,6 +6444,9 @@ program.command("deps").description("inspect the OpenPack dependency graph").add
|
|
|
6304
6444
|
for (const decision of result.bundle.graphLock.canonical.namespacing) {
|
|
6305
6445
|
console.log(`NAMESPACE ${decision.graphNodeId}:${decision.type}/${decision.name} -> ${decision.type}/${decision.installName} (${decision.reason})`);
|
|
6306
6446
|
}
|
|
6447
|
+
for (const decision of result.bundle.graphLock.canonical.overrides) {
|
|
6448
|
+
console.log(`OVERRIDE ${decision.graphNodeId}:${decision.type}/${decision.name} replaces ${decision.overriddenGraphNodeId}:${decision.type}/${decision.name} via ${decision.rootId} (${decision.selector})`);
|
|
6449
|
+
}
|
|
6307
6450
|
await rm9(result.bundle.root, { recursive: true, force: true });
|
|
6308
6451
|
}
|
|
6309
6452
|
continue;
|
|
@@ -6520,7 +6663,8 @@ async function packageEntryFromSource(source, targetRoot, options) {
|
|
|
6520
6663
|
adapterCodeHash: adapter.programmatic?.hash,
|
|
6521
6664
|
mode: options.mode ?? "pinned",
|
|
6522
6665
|
requestedRef: bundle.source.requestedRef,
|
|
6523
|
-
select: selectedArtifacts
|
|
6666
|
+
select: selectedArtifacts,
|
|
6667
|
+
overrides: overrideArtifactsFromOptions(options)
|
|
6524
6668
|
};
|
|
6525
6669
|
} finally {
|
|
6526
6670
|
await rm9(bundle.root, { recursive: true, force: true });
|
|
@@ -6642,6 +6786,7 @@ async function buildGraphPlansForTarget(target, source, options, behavior) {
|
|
|
6642
6786
|
ref: pkg.requestedRef,
|
|
6643
6787
|
select: selectedArtifacts ?? normalizeArtifactSelectors(pkg.select, pkg.skills),
|
|
6644
6788
|
aliases: pkg.aliases,
|
|
6789
|
+
overrides: pkg.overrides,
|
|
6645
6790
|
useLock: behavior.mode === "install" ? true : !updateThisPackage
|
|
6646
6791
|
};
|
|
6647
6792
|
}),
|
|
@@ -6822,7 +6967,8 @@ async function uninstallConfiguredPackage(target, packageName, options) {
|
|
|
6822
6967
|
mode: pkg2.mode,
|
|
6823
6968
|
ref: pkg2.requestedRef,
|
|
6824
6969
|
select: normalizeArtifactSelectors(pkg2.select, pkg2.skills),
|
|
6825
|
-
aliases: pkg2.aliases
|
|
6970
|
+
aliases: pkg2.aliases,
|
|
6971
|
+
overrides: pkg2.overrides
|
|
6826
6972
|
})),
|
|
6827
6973
|
targetRoot: remainingGroup.target.targetRoot,
|
|
6828
6974
|
workspaceRoot: remainingGroup.target.workspaceRoot,
|
|
@@ -6985,9 +7131,16 @@ function collectSkillOption(value, previous) {
|
|
|
6985
7131
|
function collectTrustOption(value, previous) {
|
|
6986
7132
|
return [...previous, value];
|
|
6987
7133
|
}
|
|
7134
|
+
function collectOverrideOption(value, previous) {
|
|
7135
|
+
return [...previous, ...splitSelectorList(value)];
|
|
7136
|
+
}
|
|
6988
7137
|
function selectedArtifactsFromOptions(options) {
|
|
6989
7138
|
return normalizeArtifactSelectors(options.select, options.skills ?? options.skill);
|
|
6990
7139
|
}
|
|
7140
|
+
function overrideArtifactsFromOptions(options) {
|
|
7141
|
+
const values = options.overrides ?? options.override;
|
|
7142
|
+
return values && values.length > 0 ? values : void 0;
|
|
7143
|
+
}
|
|
6991
7144
|
function filterUninstallPlanBySelection(plan, selected) {
|
|
6992
7145
|
if (!selected?.length) return plan;
|
|
6993
7146
|
const requested = normalizeArtifactSelectors(selected) ?? [];
|
|
@@ -7108,7 +7261,9 @@ async function main() {
|
|
|
7108
7261
|
});
|
|
7109
7262
|
await program.parseAsync();
|
|
7110
7263
|
}
|
|
7111
|
-
|
|
7264
|
+
try {
|
|
7265
|
+
await main();
|
|
7266
|
+
} catch (error) {
|
|
7112
7267
|
console.error(error instanceof Error ? error.message : String(error));
|
|
7113
7268
|
process.exitCode = 1;
|
|
7114
|
-
}
|
|
7269
|
+
}
|
package/openpack.json
CHANGED
package/package.json
CHANGED
|
@@ -141,6 +141,34 @@ agentwheel add github:owner/repo --select skills/code-review --select rules/core
|
|
|
141
141
|
agentwheel add github:owner/repo --select skills/code-review,rules/core.md
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
+
Use a source override when a selected package should replace the same artifact coming from another
|
|
145
|
+
source, such as a forked skill overriding a meta-pack dependency. The declaration is explicit and
|
|
146
|
+
planning fails if it does not match exactly one losing artifact and one selected replacement:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
agentwheel add github:Yehonal/agent-toolkit#main \
|
|
150
|
+
--skill self-improve \
|
|
151
|
+
--override 'github:FrancescoBorzi/agent-toolkit::skills/self-improve'
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Equivalent config:
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"name": "agent-toolkit-nestdev",
|
|
159
|
+
"source": "github:Yehonal/agent-toolkit#main",
|
|
160
|
+
"driver": "git",
|
|
161
|
+
"adapter": "codex",
|
|
162
|
+
"mode": "tracking",
|
|
163
|
+
"select": ["skills/self-improve"],
|
|
164
|
+
"overrides": ["github:FrancescoBorzi/agent-toolkit::skills/self-improve"]
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
`source::type/name` identifies the artifact being replaced. `github:owner/repo` matches any ref
|
|
169
|
+
for that repo; include `#main` or another ref to narrow it. Review `OVERRIDE` lines in
|
|
170
|
+
`agentwheel plan`, `agentwheel deps tree`, or `agentwheel deps why` before applying fleet-wide.
|
|
171
|
+
|
|
144
172
|
Use `--name` for a stable local alias:
|
|
145
173
|
|
|
146
174
|
```bash
|
|
@@ -289,7 +317,9 @@ Drift means a managed runtime output changed outside agentwheel. Fix drift by ch
|
|
|
289
317
|
|
|
290
318
|
- Layer local instructions with `agentwheel remember`.
|
|
291
319
|
- Add separate local artifacts under `.agentwheel/additions`.
|
|
292
|
-
- Override
|
|
320
|
+
- Override upstream content under `.agentwheel/overrides`.
|
|
321
|
+
- Override source precedence with package `overrides` when a forked source should replace a
|
|
322
|
+
colliding upstream artifact.
|
|
293
323
|
- Eject an item into `.agentwheel/ejected` when the user wants local ownership.
|
|
294
324
|
|
|
295
325
|
Append durable local instruction text:
|