agentwheel 0.16.6 → 0.17.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 +19 -0
- package/dist/{chunk-PKAPR55N.js → chunk-24IUHC3D.js} +27 -0
- package/dist/{identify-VV7SXUIQ.js → identify-G3TXOHNS.js} +1 -1
- package/dist/index.js +1668 -816
- package/openpack.json +1 -1
- package/package.json +1 -1
- package/skills/agentwheel/SKILL.md +23 -1
- package/skills/agentwheel-artifact-evolution/SKILL.md +42 -0
- package/skills/agentwheel-artifact-evolution/agents/openai.yaml +4 -0
- package/skills/agentwheel-discovery/SKILL.md +1 -1
package/dist/index.js
CHANGED
|
@@ -3,17 +3,19 @@ import {
|
|
|
3
3
|
atomicCopy,
|
|
4
4
|
hashPath,
|
|
5
5
|
inferSourceDriverName,
|
|
6
|
+
isAlreadyExists,
|
|
6
7
|
isIgnoredGeneratedEntry,
|
|
7
8
|
pathExists,
|
|
9
|
+
withFilesystemLock,
|
|
8
10
|
writeJsonAtomic
|
|
9
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-24IUHC3D.js";
|
|
10
12
|
|
|
11
13
|
// src/cli/index.ts
|
|
12
|
-
import { createHash as
|
|
14
|
+
import { createHash as createHash15 } from "crypto";
|
|
13
15
|
import { existsSync } from "fs";
|
|
14
|
-
import { mkdir as
|
|
16
|
+
import { mkdir as mkdir24, rm as rm13, writeFile as writeFile22 } from "fs/promises";
|
|
15
17
|
import { homedir as homedir12 } from "os";
|
|
16
|
-
import { dirname as
|
|
18
|
+
import { dirname as dirname33, join as join49, resolve as resolve22 } from "path";
|
|
17
19
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
18
20
|
import { Command } from "commander";
|
|
19
21
|
|
|
@@ -495,113 +497,126 @@ import { promisify as promisify3 } from "util";
|
|
|
495
497
|
import { createHash } from "crypto";
|
|
496
498
|
import { mkdir, readFile as readFile3, rename, writeFile as writeFile2 } from "fs/promises";
|
|
497
499
|
import { dirname } from "path";
|
|
500
|
+
import { z as z4 } from "zod";
|
|
501
|
+
|
|
502
|
+
// src/model/cache-identity.ts
|
|
498
503
|
import { z as z3 } from "zod";
|
|
499
|
-
var
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
504
|
+
var immutableCacheIdentitySchema = z3.string().regex(
|
|
505
|
+
/^(?:[0-9a-f]{40}|content-[0-9a-f]{64})$/i,
|
|
506
|
+
"Expected a Git commit or content-addressed SHA-256 cache identity"
|
|
507
|
+
);
|
|
508
|
+
function normalizeImmutableCacheIdentity(value) {
|
|
509
|
+
return value === void 0 ? void 0 : immutableCacheIdentitySchema.parse(value).toLowerCase();
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/model/graph-lock.ts
|
|
513
|
+
var graphLockNodeSchema = z4.object({
|
|
514
|
+
id: z4.string().min(1),
|
|
515
|
+
name: z4.string().min(1),
|
|
516
|
+
version: z4.string().min(1),
|
|
517
|
+
source: z4.string().min(1),
|
|
518
|
+
normalizedSource: z4.string().min(1),
|
|
519
|
+
driver: z4.string().min(1),
|
|
520
|
+
requestedRef: z4.string().min(1).optional(),
|
|
521
|
+
resolvedCommit: z4.string().min(1).optional(),
|
|
522
|
+
cacheIdentity: immutableCacheIdentitySchema.optional(),
|
|
523
|
+
sourceHash: z4.string().min(16),
|
|
524
|
+
mode: z4.enum(["pinned", "tracking"]),
|
|
525
|
+
requiredBy: z4.array(z4.string().min(1)),
|
|
526
|
+
selected: z4.array(z4.string().min(1)),
|
|
527
|
+
selectionReasons: z4.record(z4.string(), z4.array(z4.string().min(1))).optional()
|
|
513
528
|
});
|
|
514
|
-
var graphLockRootSchema =
|
|
515
|
-
rootId:
|
|
516
|
-
source:
|
|
517
|
-
normalizedSource:
|
|
518
|
-
graphNodeId:
|
|
519
|
-
mode:
|
|
520
|
-
selected:
|
|
521
|
-
aliases:
|
|
522
|
-
overrides:
|
|
523
|
-
selectionImport:
|
|
524
|
-
configPath:
|
|
525
|
-
configHash:
|
|
526
|
-
exportHash:
|
|
527
|
-
exportName:
|
|
528
|
-
extends:
|
|
529
|
-
inherited:
|
|
530
|
-
additions:
|
|
531
|
-
exclusions:
|
|
532
|
-
effective:
|
|
529
|
+
var graphLockRootSchema = z4.object({
|
|
530
|
+
rootId: z4.string().min(1),
|
|
531
|
+
source: z4.string().min(1),
|
|
532
|
+
normalizedSource: z4.string().min(1),
|
|
533
|
+
graphNodeId: z4.string().min(1),
|
|
534
|
+
mode: z4.enum(["pinned", "tracking"]),
|
|
535
|
+
selected: z4.array(z4.string().min(1)),
|
|
536
|
+
aliases: z4.record(z4.string(), z4.string().min(1)).optional(),
|
|
537
|
+
overrides: z4.array(z4.string().min(1)).optional(),
|
|
538
|
+
selectionImport: z4.object({
|
|
539
|
+
configPath: z4.string().min(1),
|
|
540
|
+
configHash: z4.string().min(16),
|
|
541
|
+
exportHash: z4.string().min(16),
|
|
542
|
+
exportName: z4.string().min(1),
|
|
543
|
+
extends: z4.array(z4.string().min(1)),
|
|
544
|
+
inherited: z4.array(z4.string().min(1)),
|
|
545
|
+
additions: z4.array(z4.string().min(1)),
|
|
546
|
+
exclusions: z4.array(z4.string().min(1)),
|
|
547
|
+
effective: z4.array(z4.string().min(1))
|
|
533
548
|
}).optional()
|
|
534
549
|
});
|
|
535
|
-
var graphLockEdgeSchema =
|
|
536
|
-
from:
|
|
537
|
-
to:
|
|
538
|
-
alias:
|
|
539
|
-
source:
|
|
540
|
-
normalizedSource:
|
|
541
|
-
requestedRef:
|
|
542
|
-
version:
|
|
543
|
-
mode:
|
|
544
|
-
optional:
|
|
545
|
-
selected:
|
|
550
|
+
var graphLockEdgeSchema = z4.object({
|
|
551
|
+
from: z4.string().min(1),
|
|
552
|
+
to: z4.string().min(1),
|
|
553
|
+
alias: z4.string().min(1),
|
|
554
|
+
source: z4.string().min(1),
|
|
555
|
+
normalizedSource: z4.string().min(1),
|
|
556
|
+
requestedRef: z4.string().min(1).optional(),
|
|
557
|
+
version: z4.string().min(1).optional(),
|
|
558
|
+
mode: z4.enum(["pinned", "tracking"]),
|
|
559
|
+
optional: z4.boolean().default(false),
|
|
560
|
+
selected: z4.array(z4.string().min(1))
|
|
546
561
|
});
|
|
547
|
-
var graphLockIncludeEdgeSchema =
|
|
548
|
-
fromNodeId:
|
|
549
|
-
alias:
|
|
550
|
-
toNodeId:
|
|
551
|
-
selector:
|
|
552
|
-
sourceHash:
|
|
562
|
+
var graphLockIncludeEdgeSchema = z4.object({
|
|
563
|
+
fromNodeId: z4.string().min(1),
|
|
564
|
+
alias: z4.string().min(1),
|
|
565
|
+
toNodeId: z4.string().min(1),
|
|
566
|
+
selector: z4.string().min(1),
|
|
567
|
+
sourceHash: z4.string().min(16)
|
|
553
568
|
});
|
|
554
|
-
var graphLockArtifactSchema =
|
|
555
|
-
graphNodeId:
|
|
556
|
-
dependencyRole:
|
|
569
|
+
var graphLockArtifactSchema = z4.object({
|
|
570
|
+
graphNodeId: z4.string().min(1),
|
|
571
|
+
dependencyRole: z4.enum(["root", "direct", "transitive", "fragment"]),
|
|
557
572
|
type: artifactTypeSchema,
|
|
558
|
-
name:
|
|
559
|
-
installName:
|
|
560
|
-
logicalSelector:
|
|
561
|
-
owners:
|
|
562
|
-
relativePath:
|
|
573
|
+
name: z4.string().min(1),
|
|
574
|
+
installName: z4.string().min(1),
|
|
575
|
+
logicalSelector: z4.string().min(1),
|
|
576
|
+
owners: z4.array(z4.string().min(1)),
|
|
577
|
+
relativePath: z4.string().min(1),
|
|
563
578
|
kind: fileKindSchema,
|
|
564
|
-
hash:
|
|
565
|
-
channel:
|
|
566
|
-
composedFrom:
|
|
579
|
+
hash: z4.string().min(16),
|
|
580
|
+
channel: z4.enum(["managed", "overlay", "addition", "override", "ejected"]).default("managed"),
|
|
581
|
+
composedFrom: z4.array(composedFromEntrySchema).optional()
|
|
567
582
|
});
|
|
568
|
-
var graphLockPlainNameIncumbentSchema =
|
|
569
|
-
adapter:
|
|
570
|
-
targetFingerprint:
|
|
583
|
+
var graphLockPlainNameIncumbentSchema = z4.object({
|
|
584
|
+
adapter: z4.string().min(1),
|
|
585
|
+
targetFingerprint: z4.string().min(1),
|
|
571
586
|
type: artifactTypeSchema,
|
|
572
|
-
name:
|
|
573
|
-
graphNodeId:
|
|
587
|
+
name: z4.string().min(1),
|
|
588
|
+
graphNodeId: z4.string().min(1)
|
|
574
589
|
});
|
|
575
|
-
var graphLockNamespacingSchema =
|
|
576
|
-
graphNodeId:
|
|
590
|
+
var graphLockNamespacingSchema = z4.object({
|
|
591
|
+
graphNodeId: z4.string().min(1),
|
|
577
592
|
type: artifactTypeSchema,
|
|
578
|
-
name:
|
|
579
|
-
installName:
|
|
580
|
-
reason:
|
|
593
|
+
name: z4.string().min(1),
|
|
594
|
+
installName: z4.string().min(1),
|
|
595
|
+
reason: z4.enum(["alias", "transitive-collision"])
|
|
581
596
|
});
|
|
582
|
-
var graphLockOverrideSchema =
|
|
583
|
-
rootId:
|
|
584
|
-
selector:
|
|
585
|
-
graphNodeId:
|
|
586
|
-
overriddenGraphNodeId:
|
|
597
|
+
var graphLockOverrideSchema = z4.object({
|
|
598
|
+
rootId: z4.string().min(1),
|
|
599
|
+
selector: z4.string().min(1),
|
|
600
|
+
graphNodeId: z4.string().min(1),
|
|
601
|
+
overriddenGraphNodeId: z4.string().min(1),
|
|
587
602
|
type: artifactTypeSchema,
|
|
588
|
-
name:
|
|
589
|
-
installName:
|
|
603
|
+
name: z4.string().min(1),
|
|
604
|
+
installName: z4.string().min(1)
|
|
590
605
|
});
|
|
591
|
-
var graphLockCanonicalSchema =
|
|
592
|
-
targetFingerprint:
|
|
593
|
-
roots:
|
|
594
|
-
nodes:
|
|
595
|
-
edges:
|
|
596
|
-
includeEdges:
|
|
597
|
-
artifacts:
|
|
598
|
-
namespacing:
|
|
599
|
-
overrides:
|
|
600
|
-
plainNameIncumbents:
|
|
606
|
+
var graphLockCanonicalSchema = z4.object({
|
|
607
|
+
targetFingerprint: z4.string().min(1).optional(),
|
|
608
|
+
roots: z4.array(graphLockRootSchema),
|
|
609
|
+
nodes: z4.array(graphLockNodeSchema),
|
|
610
|
+
edges: z4.array(graphLockEdgeSchema),
|
|
611
|
+
includeEdges: z4.array(graphLockIncludeEdgeSchema).default([]),
|
|
612
|
+
artifacts: z4.array(graphLockArtifactSchema).default([]),
|
|
613
|
+
namespacing: z4.array(graphLockNamespacingSchema).default([]),
|
|
614
|
+
overrides: z4.array(graphLockOverrideSchema).default([]),
|
|
615
|
+
plainNameIncumbents: z4.array(graphLockPlainNameIncumbentSchema).default([])
|
|
601
616
|
});
|
|
602
|
-
var graphLockSchema =
|
|
603
|
-
version:
|
|
604
|
-
generatedAt:
|
|
617
|
+
var graphLockSchema = z4.object({
|
|
618
|
+
version: z4.literal(1),
|
|
619
|
+
generatedAt: z4.string().datetime().optional(),
|
|
605
620
|
canonical: graphLockCanonicalSchema
|
|
606
621
|
});
|
|
607
622
|
async function readGraphLock(path) {
|
|
@@ -1052,56 +1067,56 @@ import { createHash as createHash2 } from "crypto";
|
|
|
1052
1067
|
import { resolve as resolve3 } from "path";
|
|
1053
1068
|
|
|
1054
1069
|
// src/model/manifest.ts
|
|
1055
|
-
import { z as
|
|
1056
|
-
var mergeValueSchema =
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1070
|
+
import { z as z5 } from "zod";
|
|
1071
|
+
var mergeValueSchema = z5.lazy(() => z5.union([
|
|
1072
|
+
z5.null(),
|
|
1073
|
+
z5.boolean(),
|
|
1074
|
+
z5.number(),
|
|
1075
|
+
z5.string(),
|
|
1076
|
+
z5.array(mergeValueSchema),
|
|
1077
|
+
z5.record(z5.string(), mergeValueSchema)
|
|
1063
1078
|
]));
|
|
1064
|
-
var mergeRemovalSchema =
|
|
1065
|
-
var dependencyRoleSchema =
|
|
1079
|
+
var mergeRemovalSchema = z5.record(z5.string(), mergeValueSchema);
|
|
1080
|
+
var dependencyRoleSchema = z5.enum(["root", "direct", "transitive", "fragment"]);
|
|
1066
1081
|
var legacyUnownedWorkspaceOwner = "legacy:unowned";
|
|
1067
|
-
var semanticPluginSpecSchema =
|
|
1068
|
-
runtime:
|
|
1069
|
-
pluginName:
|
|
1070
|
-
marketplaceName:
|
|
1071
|
-
stateRoot:
|
|
1072
|
-
installCommands:
|
|
1073
|
-
uninstallCommands:
|
|
1074
|
-
enableCommands:
|
|
1075
|
-
disableCommands:
|
|
1082
|
+
var semanticPluginSpecSchema = z5.object({
|
|
1083
|
+
runtime: z5.enum(["openclaw", "claude", "codex", "copilot", "hermes"]),
|
|
1084
|
+
pluginName: z5.string().min(1),
|
|
1085
|
+
marketplaceName: z5.string().min(1).optional(),
|
|
1086
|
+
stateRoot: z5.string().min(1).optional(),
|
|
1087
|
+
installCommands: z5.array(z5.array(z5.string()).min(1)).min(1),
|
|
1088
|
+
uninstallCommands: z5.array(z5.array(z5.string()).min(1)).min(1),
|
|
1089
|
+
enableCommands: z5.array(z5.array(z5.string()).min(1)).optional(),
|
|
1090
|
+
disableCommands: z5.array(z5.array(z5.string()).min(1)).optional()
|
|
1076
1091
|
});
|
|
1077
|
-
var manifestEntryV1Schema =
|
|
1078
|
-
path:
|
|
1092
|
+
var manifestEntryV1Schema = z5.object({
|
|
1093
|
+
path: z5.string().min(1),
|
|
1079
1094
|
artifactType: artifactTypeSchema,
|
|
1080
|
-
artifactName:
|
|
1095
|
+
artifactName: z5.string().min(1),
|
|
1081
1096
|
kind: fileKindSchema,
|
|
1082
|
-
hash:
|
|
1083
|
-
sourceHash:
|
|
1084
|
-
updatedAt:
|
|
1085
|
-
channel:
|
|
1086
|
-
packageName:
|
|
1087
|
-
semanticCommand:
|
|
1097
|
+
hash: z5.string().min(16),
|
|
1098
|
+
sourceHash: z5.string().min(16),
|
|
1099
|
+
updatedAt: z5.string().datetime(),
|
|
1100
|
+
channel: z5.enum(["managed", "overlay", "addition", "override", "ejected"]).default("managed"),
|
|
1101
|
+
packageName: z5.string().min(1).optional(),
|
|
1102
|
+
semanticCommand: z5.array(z5.string()).optional(),
|
|
1088
1103
|
semanticPlugin: semanticPluginSpecSchema.optional(),
|
|
1089
|
-
executed:
|
|
1090
|
-
mergeStrategy:
|
|
1104
|
+
executed: z5.boolean().optional(),
|
|
1105
|
+
mergeStrategy: z5.enum(["json-deep", "openclaw-json-deep", "yaml-deep", "codex-toml-mcp"]).optional(),
|
|
1091
1106
|
mergeRemoval: mergeRemovalSchema.optional(),
|
|
1092
|
-
mergeCreatedDestination:
|
|
1093
|
-
mode:
|
|
1094
|
-
composedFrom:
|
|
1107
|
+
mergeCreatedDestination: z5.boolean().optional(),
|
|
1108
|
+
mode: z5.enum(["managed-block"]).optional(),
|
|
1109
|
+
composedFrom: z5.array(composedFromEntrySchema).optional()
|
|
1095
1110
|
});
|
|
1096
1111
|
var manifestEntrySchema = manifestEntryV1Schema.extend({
|
|
1097
|
-
installName:
|
|
1098
|
-
logicalSelector:
|
|
1099
|
-
graphNodeId:
|
|
1112
|
+
installName: z5.string().min(1),
|
|
1113
|
+
logicalSelector: z5.string().min(1).optional(),
|
|
1114
|
+
graphNodeId: z5.string().min(1).optional(),
|
|
1100
1115
|
dependencyRole: dependencyRoleSchema.default("root"),
|
|
1101
|
-
owners:
|
|
1102
|
-
refCount:
|
|
1103
|
-
workspaceOwner:
|
|
1104
|
-
graphLockDigest:
|
|
1116
|
+
owners: z5.array(z5.string().min(1)).min(1),
|
|
1117
|
+
refCount: z5.number().int().positive(),
|
|
1118
|
+
workspaceOwner: z5.string().min(1).default(legacyUnownedWorkspaceOwner),
|
|
1119
|
+
graphLockDigest: z5.string().min(1).optional()
|
|
1105
1120
|
}).transform((entry) => {
|
|
1106
1121
|
const owners = [...new Set(entry.owners)].sort();
|
|
1107
1122
|
return {
|
|
@@ -1110,59 +1125,60 @@ var manifestEntrySchema = manifestEntryV1Schema.extend({
|
|
|
1110
1125
|
refCount: owners.length
|
|
1111
1126
|
};
|
|
1112
1127
|
});
|
|
1113
|
-
var installManifestV1Schema =
|
|
1114
|
-
version:
|
|
1115
|
-
adapter:
|
|
1116
|
-
targetRoot:
|
|
1117
|
-
generatedAt:
|
|
1118
|
-
adapterCode:
|
|
1119
|
-
modulePath:
|
|
1120
|
-
hash:
|
|
1128
|
+
var installManifestV1Schema = z5.object({
|
|
1129
|
+
version: z5.literal(1),
|
|
1130
|
+
adapter: z5.string().min(1),
|
|
1131
|
+
targetRoot: z5.string().min(1),
|
|
1132
|
+
generatedAt: z5.string().datetime(),
|
|
1133
|
+
adapterCode: z5.object({
|
|
1134
|
+
modulePath: z5.string().min(1),
|
|
1135
|
+
hash: z5.string().min(16)
|
|
1121
1136
|
}).optional(),
|
|
1122
|
-
entries:
|
|
1137
|
+
entries: z5.array(manifestEntryV1Schema)
|
|
1123
1138
|
}).transform((manifest) => ({
|
|
1124
1139
|
...manifest,
|
|
1125
1140
|
legacy: true
|
|
1126
1141
|
}));
|
|
1127
|
-
var installManifestV2Schema =
|
|
1128
|
-
version:
|
|
1129
|
-
adapter:
|
|
1142
|
+
var installManifestV2Schema = z5.object({
|
|
1143
|
+
version: z5.literal(2),
|
|
1144
|
+
adapter: z5.string().min(1),
|
|
1130
1145
|
installationType: installationTypeSchema.default(defaultInstallationType),
|
|
1131
|
-
stateKey:
|
|
1132
|
-
targetRoot:
|
|
1133
|
-
generatedAt:
|
|
1134
|
-
revision:
|
|
1135
|
-
adapterCode:
|
|
1136
|
-
modulePath:
|
|
1137
|
-
hash:
|
|
1146
|
+
stateKey: z5.string().min(1).optional(),
|
|
1147
|
+
targetRoot: z5.string().min(1),
|
|
1148
|
+
generatedAt: z5.string().datetime(),
|
|
1149
|
+
revision: z5.string().min(16),
|
|
1150
|
+
adapterCode: z5.object({
|
|
1151
|
+
modulePath: z5.string().min(1),
|
|
1152
|
+
hash: z5.string().min(16)
|
|
1138
1153
|
}).optional(),
|
|
1139
|
-
entries:
|
|
1154
|
+
entries: z5.array(manifestEntrySchema)
|
|
1140
1155
|
}).transform((manifest) => ({
|
|
1141
1156
|
...manifest,
|
|
1142
1157
|
legacy: false
|
|
1143
1158
|
}));
|
|
1144
|
-
var installManifestSchema =
|
|
1145
|
-
var sourceLockSchema =
|
|
1146
|
-
version:
|
|
1147
|
-
driver:
|
|
1148
|
-
source:
|
|
1149
|
-
resolvedPath:
|
|
1150
|
-
packageName:
|
|
1151
|
-
packageVersion:
|
|
1152
|
-
mode:
|
|
1153
|
-
requestedRef:
|
|
1154
|
-
resolvedCommit:
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
+
var installManifestSchema = z5.union([installManifestV2Schema, installManifestV1Schema]);
|
|
1160
|
+
var sourceLockSchema = z5.object({
|
|
1161
|
+
version: z5.literal(1),
|
|
1162
|
+
driver: z5.string().min(1),
|
|
1163
|
+
source: z5.string().min(1),
|
|
1164
|
+
resolvedPath: z5.string().min(1),
|
|
1165
|
+
packageName: z5.string().min(1).optional(),
|
|
1166
|
+
packageVersion: z5.string().min(1).optional(),
|
|
1167
|
+
mode: z5.enum(["pinned", "tracking"]).default("pinned"),
|
|
1168
|
+
requestedRef: z5.string().min(1).optional(),
|
|
1169
|
+
resolvedCommit: z5.string().min(1).optional(),
|
|
1170
|
+
cacheIdentity: immutableCacheIdentitySchema.optional(),
|
|
1171
|
+
sourceHash: z5.string().min(16).optional(),
|
|
1172
|
+
generatedAt: z5.string().datetime(),
|
|
1173
|
+
artifacts: z5.array(
|
|
1174
|
+
z5.object({
|
|
1159
1175
|
type: artifactTypeSchema,
|
|
1160
|
-
name:
|
|
1161
|
-
relativePath:
|
|
1176
|
+
name: z5.string().min(1),
|
|
1177
|
+
relativePath: z5.string().min(1),
|
|
1162
1178
|
kind: fileKindSchema,
|
|
1163
|
-
hash:
|
|
1179
|
+
hash: z5.string().min(16),
|
|
1164
1180
|
format: artifactFormatSchema.optional(),
|
|
1165
|
-
composedFrom:
|
|
1181
|
+
composedFrom: z5.array(composedFromEntrySchema).optional()
|
|
1166
1182
|
})
|
|
1167
1183
|
)
|
|
1168
1184
|
});
|
|
@@ -1307,7 +1323,7 @@ async function acquireApplyLock(targetRoot, adapter, transport = localTransport,
|
|
|
1307
1323
|
try {
|
|
1308
1324
|
await transport.mkdirExclusive(lockPath);
|
|
1309
1325
|
} catch (error) {
|
|
1310
|
-
if (!
|
|
1326
|
+
if (!isAlreadyExists2(error)) throw error;
|
|
1311
1327
|
await handleExistingLock(lockPath, ownerPath, transport, options);
|
|
1312
1328
|
await transport.mkdirExclusive(lockPath);
|
|
1313
1329
|
}
|
|
@@ -1405,7 +1421,7 @@ async function readLockOwner(ownerPath, transport) {
|
|
|
1405
1421
|
return void 0;
|
|
1406
1422
|
}
|
|
1407
1423
|
}
|
|
1408
|
-
function
|
|
1424
|
+
function isAlreadyExists2(error) {
|
|
1409
1425
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
1410
1426
|
}
|
|
1411
1427
|
function journalTimestamp(date) {
|
|
@@ -1432,6 +1448,10 @@ async function mergeCodexTomlMcp(sourcePath, destPath) {
|
|
|
1432
1448
|
await mkdir6(dirname7(destPath), { recursive: true });
|
|
1433
1449
|
await writeFile6(destPath, merged, "utf8");
|
|
1434
1450
|
}
|
|
1451
|
+
function mismatchedCodexTomlMcpServers(source, currentContent) {
|
|
1452
|
+
const servers = extractMcpServers(source);
|
|
1453
|
+
return Object.entries(servers).filter(([name, server]) => extractMcpServerBlock(currentContent, name) !== formatMcpServer(name, server)).map(([name]) => name);
|
|
1454
|
+
}
|
|
1435
1455
|
function extractMcpServers(source) {
|
|
1436
1456
|
const raw = isRecord2(source.mcpServers) ? source.mcpServers : source;
|
|
1437
1457
|
const servers = {};
|
|
@@ -1483,6 +1503,32 @@ function formatMcpServer(name, server) {
|
|
|
1483
1503
|
}
|
|
1484
1504
|
return lines.join("\n");
|
|
1485
1505
|
}
|
|
1506
|
+
function extractMcpServerBlock(content, serverName) {
|
|
1507
|
+
const lines = content.split(/\r?\n/);
|
|
1508
|
+
const blocks = [];
|
|
1509
|
+
let block;
|
|
1510
|
+
let collecting = false;
|
|
1511
|
+
for (const line of lines) {
|
|
1512
|
+
const section = line.match(/^\s*\[([^\]]+)]\s*$/)?.[1];
|
|
1513
|
+
if (section) {
|
|
1514
|
+
const match = section.match(/^mcp_servers\.([^\.\]]+)(?:\.|$)/);
|
|
1515
|
+
const name = match?.[1] ? unquoteTomlKey(match[1]) : void 0;
|
|
1516
|
+
if (collecting && block) {
|
|
1517
|
+
while (block.at(-1)?.trim() === "") block.pop();
|
|
1518
|
+
blocks.push(block);
|
|
1519
|
+
}
|
|
1520
|
+
collecting = name === serverName;
|
|
1521
|
+
block = collecting ? [] : void 0;
|
|
1522
|
+
}
|
|
1523
|
+
if (collecting) block?.push(line);
|
|
1524
|
+
}
|
|
1525
|
+
if (collecting && block) {
|
|
1526
|
+
while (block.at(-1)?.trim() === "") block.pop();
|
|
1527
|
+
blocks.push(block);
|
|
1528
|
+
}
|
|
1529
|
+
if (blocks.length === 0) return void 0;
|
|
1530
|
+
return blocks.map((lines2) => lines2.join("\n")).join("\n\n");
|
|
1531
|
+
}
|
|
1486
1532
|
function formatTomlValue(value) {
|
|
1487
1533
|
if (typeof value === "string") return JSON.stringify(value);
|
|
1488
1534
|
if (typeof value === "number" || typeof value === "boolean") return String(value);
|
|
@@ -1571,9 +1617,53 @@ function dedupeArray2(values) {
|
|
|
1571
1617
|
import { mkdir as mkdir8, readFile as readFile9, writeFile as writeFile8 } from "fs/promises";
|
|
1572
1618
|
import { dirname as dirname9 } from "path";
|
|
1573
1619
|
import { parse as parse3, stringify as stringify2 } from "yaml";
|
|
1574
|
-
|
|
1620
|
+
var MergeAdoptionMismatchError = class extends Error {
|
|
1621
|
+
};
|
|
1622
|
+
function assertExactMcpMergeContribution(removal, strategy, currentContent) {
|
|
1623
|
+
if (strategy === "codex-toml-mcp") {
|
|
1624
|
+
const mismatched = mismatchedCodexTomlMcpServers(removal, currentContent);
|
|
1625
|
+
if (mismatched.length > 0) {
|
|
1626
|
+
throw new MergeAdoptionMismatchError(`exact MCP retirement precondition failed: Codex MCP server content differs or is missing for ${mismatched.join(", ")}`);
|
|
1627
|
+
}
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
if (strategy !== "json-deep") {
|
|
1631
|
+
throw new MergeAdoptionMismatchError(`exact MCP retirement precondition failed: strategy ${strategy} is not supported`);
|
|
1632
|
+
}
|
|
1633
|
+
const mismatch = firstMcpContributionMismatch(parseMergeDestination(currentContent, strategy), removal);
|
|
1634
|
+
if (mismatch) {
|
|
1635
|
+
throw new MergeAdoptionMismatchError(`exact MCP retirement precondition failed: destination differs or is missing at ${mismatch}`);
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
function combineMergeRemovals(existing, incoming) {
|
|
1639
|
+
return combineMergeValues(existing, incoming);
|
|
1640
|
+
}
|
|
1641
|
+
function hasMergeRemovalContent(removal) {
|
|
1642
|
+
if (!removal) return false;
|
|
1643
|
+
return Object.entries(removal).some(([key, value]) => {
|
|
1644
|
+
return !(key === "mcpServers" && isRecord4(value) && Object.keys(value).length === 0);
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
async function mergeRemovalForInstall(sourcePath, strategy, currentContent, options = {}) {
|
|
1575
1648
|
const source = await readMergeSource(sourcePath, strategy);
|
|
1576
1649
|
if (currentContent === void 0) return source;
|
|
1650
|
+
if (options.adoptExistingMcp) {
|
|
1651
|
+
if (strategy === "codex-toml-mcp") {
|
|
1652
|
+
const mismatched = mismatchedCodexTomlMcpServers(source, currentContent);
|
|
1653
|
+
if (mismatched.length > 0) {
|
|
1654
|
+
throw new MergeAdoptionMismatchError(`cannot adopt merged contribution: Codex MCP server content differs or is missing for ${mismatched.join(", ")}`);
|
|
1655
|
+
}
|
|
1656
|
+
return source;
|
|
1657
|
+
}
|
|
1658
|
+
if (strategy !== "json-deep") {
|
|
1659
|
+
throw new MergeAdoptionMismatchError(`cannot adopt merged contribution: strategy ${strategy} is not supported for MCP adoption`);
|
|
1660
|
+
}
|
|
1661
|
+
const mismatch = firstMcpContributionMismatch(parseMergeDestination(currentContent, strategy), source);
|
|
1662
|
+
if (mismatch) {
|
|
1663
|
+
throw new MergeAdoptionMismatchError(`cannot adopt merged contribution: destination differs or is missing at ${mismatch}`);
|
|
1664
|
+
}
|
|
1665
|
+
return source;
|
|
1666
|
+
}
|
|
1577
1667
|
if (strategy === "codex-toml-mcp") {
|
|
1578
1668
|
const existingServers = codexTomlMcpServerNames(currentContent);
|
|
1579
1669
|
const servers = isRecord4(source.mcpServers) ? source.mcpServers : source;
|
|
@@ -1621,6 +1711,33 @@ function introducedMergeContent(base, incoming) {
|
|
|
1621
1711
|
}
|
|
1622
1712
|
return introduced;
|
|
1623
1713
|
}
|
|
1714
|
+
function firstMcpContributionMismatch(current, incoming) {
|
|
1715
|
+
if (!isRecord4(current) || !isRecord4(incoming)) return "$";
|
|
1716
|
+
if (!isRecord4(current.mcpServers) || !isRecord4(incoming.mcpServers)) return "$.mcpServers";
|
|
1717
|
+
for (const [name, incomingServer] of Object.entries(incoming.mcpServers)) {
|
|
1718
|
+
if (!(name in current.mcpServers) || !sameMcpValue(current.mcpServers[name], incomingServer)) {
|
|
1719
|
+
return `$.mcpServers.${name}`;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
for (const [key, incomingValue] of Object.entries(incoming)) {
|
|
1723
|
+
if (key === "mcpServers") continue;
|
|
1724
|
+
if (!(key in current) || !sameMcpValue(current[key], incomingValue)) return `$.${key}`;
|
|
1725
|
+
}
|
|
1726
|
+
return void 0;
|
|
1727
|
+
}
|
|
1728
|
+
function combineMergeValues(existing, incoming) {
|
|
1729
|
+
if (isRecord4(existing) && isRecord4(incoming)) {
|
|
1730
|
+
const combined = { ...existing };
|
|
1731
|
+
for (const [key, incomingValue] of Object.entries(incoming)) {
|
|
1732
|
+
combined[key] = key in combined ? combineMergeValues(combined[key], incomingValue) : incomingValue;
|
|
1733
|
+
}
|
|
1734
|
+
return combined;
|
|
1735
|
+
}
|
|
1736
|
+
if (Array.isArray(existing) && Array.isArray(incoming)) {
|
|
1737
|
+
return [...existing, ...incoming.filter((value) => !existing.some((current) => sameValue(current, value)))];
|
|
1738
|
+
}
|
|
1739
|
+
return incoming;
|
|
1740
|
+
}
|
|
1624
1741
|
function removeIntroducedContent(current, removal) {
|
|
1625
1742
|
for (const [key, removalValue] of Object.entries(removal)) {
|
|
1626
1743
|
if (!(key in current)) continue;
|
|
@@ -1675,6 +1792,18 @@ function isRecord4(value) {
|
|
|
1675
1792
|
function sameValue(left, right) {
|
|
1676
1793
|
return JSON.stringify(left) === JSON.stringify(right);
|
|
1677
1794
|
}
|
|
1795
|
+
function sameMcpValue(left, right) {
|
|
1796
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
1797
|
+
return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => sameMcpValue(value, right[index]));
|
|
1798
|
+
}
|
|
1799
|
+
if (isRecord4(left) || isRecord4(right)) {
|
|
1800
|
+
if (!isRecord4(left) || !isRecord4(right)) return false;
|
|
1801
|
+
const leftKeys = Object.keys(left).sort();
|
|
1802
|
+
const rightKeys = Object.keys(right).sort();
|
|
1803
|
+
return leftKeys.length === rightKeys.length && leftKeys.every((key, index) => key === rightKeys[index] && sameMcpValue(left[key], right[key]));
|
|
1804
|
+
}
|
|
1805
|
+
return left === right;
|
|
1806
|
+
}
|
|
1678
1807
|
function unquoteTomlKey2(key) {
|
|
1679
1808
|
if (!key.startsWith('"')) return key;
|
|
1680
1809
|
try {
|
|
@@ -2043,6 +2172,7 @@ async function uninstall(plan, options = {}) {
|
|
|
2043
2172
|
const lock = await acquireApplyLock(plan.targetRoot, plan.adapter, transport, resolvedOptions.lock, scope);
|
|
2044
2173
|
try {
|
|
2045
2174
|
await assertBaseRevision(plan, transport);
|
|
2175
|
+
await assertExactMergeRemovalPreconditions(removable, transport);
|
|
2046
2176
|
const journal = {
|
|
2047
2177
|
version: 1,
|
|
2048
2178
|
mode: "uninstall",
|
|
@@ -2223,6 +2353,16 @@ async function applyOperation(operation, context) {
|
|
|
2223
2353
|
if (operation.mergeCreatedDestination) {
|
|
2224
2354
|
await transport.rm(operation.destPath);
|
|
2225
2355
|
} else if (operation.mergeRemoval) {
|
|
2356
|
+
if (operation.exactMergeRemoval) {
|
|
2357
|
+
if (!await transport.pathExists(operation.destPath)) {
|
|
2358
|
+
throw new Error(`Exact MCP retirement destination is missing: ${operation.relativeDestPath}`);
|
|
2359
|
+
}
|
|
2360
|
+
assertExactMcpMergeContribution(
|
|
2361
|
+
operation.mergeRemoval,
|
|
2362
|
+
operation.mergeStrategy,
|
|
2363
|
+
await transport.readFile(operation.destPath)
|
|
2364
|
+
);
|
|
2365
|
+
}
|
|
2226
2366
|
await removeMergeWithTransport(operation.destPath, operation.mergeStrategy, operation.mergeRemoval, transport);
|
|
2227
2367
|
}
|
|
2228
2368
|
} else {
|
|
@@ -2507,6 +2647,22 @@ async function assertBaseRevision(plan, transport) {
|
|
|
2507
2647
|
throw new Error(`Install manifest changed since planning for ${plan.adapter}; replan needed`);
|
|
2508
2648
|
}
|
|
2509
2649
|
}
|
|
2650
|
+
async function assertExactMergeRemovalPreconditions(operations, transport) {
|
|
2651
|
+
for (const operation of operations) {
|
|
2652
|
+
if (!operation.exactMergeRemoval) continue;
|
|
2653
|
+
if (!operation.mergeStrategy || !operation.mergeRemoval) {
|
|
2654
|
+
throw new Error(`Invalid exact MCP retirement operation: ${operation.relativeDestPath}`);
|
|
2655
|
+
}
|
|
2656
|
+
if (!await transport.pathExists(operation.destPath)) {
|
|
2657
|
+
throw new Error(`Exact MCP retirement destination is missing: ${operation.relativeDestPath}`);
|
|
2658
|
+
}
|
|
2659
|
+
assertExactMcpMergeContribution(
|
|
2660
|
+
operation.mergeRemoval,
|
|
2661
|
+
operation.mergeStrategy,
|
|
2662
|
+
await transport.readFile(operation.destPath)
|
|
2663
|
+
);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2510
2666
|
function isJournaledMutation(operation) {
|
|
2511
2667
|
if (operation.semanticPlugin && (operation.action === "plugin" || operation.action === "remove")) return false;
|
|
2512
2668
|
return operation.action === "create" || operation.action === "update" || operation.action === "remove";
|
|
@@ -3766,12 +3922,49 @@ async function createPlanFromOperations(desiredOps, adapter, targetRoot, manifes
|
|
|
3766
3922
|
if (op.mergeStrategy) {
|
|
3767
3923
|
const existing2 = manifestByPath.get(op.relativeDestPath);
|
|
3768
3924
|
const exists2 = await transport.pathExists(op.destPath);
|
|
3769
|
-
const
|
|
3925
|
+
const currentContent = exists2 ? await transport.readFile(op.destPath) : void 0;
|
|
3926
|
+
const currentHash2 = exists2 ? await transport.hashPath(op.destPath) : void 0;
|
|
3927
|
+
if (existing2 && workspaceOwner && !entryOwnedByWorkspace(existing2, workspaceOwner)) {
|
|
3928
|
+
if (!await canAdoptLegacyUnownedEntry(existing2, op, transport)) {
|
|
3929
|
+
operations.push(keepForeignManifestEntryOperation(existing2, targetRoot, workspaceOwner, op, currentHash2));
|
|
3930
|
+
continue;
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
const incompleteMergeOwnership = existing2 && existing2.mergeStrategy && !("mergeCreatedDestination" in existing2 && existing2.mergeCreatedDestination === true) && !("mergeRemoval" in existing2 && hasMergeRemovalContent(existing2.mergeRemoval));
|
|
3934
|
+
const adoptExisting = exists2 && (!existing2 || incompleteMergeOwnership) && options.forceConflict === true && op.artifactType === "mcp" && (op.mergeStrategy === "json-deep" || op.mergeStrategy === "codex-toml-mcp");
|
|
3935
|
+
let mergeRemoval;
|
|
3936
|
+
try {
|
|
3937
|
+
mergeRemoval = await mergeRemovalForInstall(op.sourcePath, op.mergeStrategy, currentContent, { adoptExistingMcp: adoptExisting });
|
|
3938
|
+
} catch (error) {
|
|
3939
|
+
if (!(error instanceof MergeAdoptionMismatchError)) throw error;
|
|
3940
|
+
operations.push({
|
|
3941
|
+
...op,
|
|
3942
|
+
action: "conflict",
|
|
3943
|
+
currentHash: currentHash2,
|
|
3944
|
+
reason: error.message,
|
|
3945
|
+
blockedReason: error.message
|
|
3946
|
+
});
|
|
3947
|
+
continue;
|
|
3948
|
+
}
|
|
3949
|
+
if (existing2 && "mergeRemoval" in existing2 && existing2.mergeRemoval) {
|
|
3950
|
+
mergeRemoval = combineMergeRemovals(existing2.mergeRemoval, mergeRemoval);
|
|
3951
|
+
}
|
|
3770
3952
|
if (!exists2) {
|
|
3771
3953
|
operations.push({ ...op, action: "create", mergeRemoval, mergeCreatedDestination: true, reason: "merge destination missing" });
|
|
3772
3954
|
continue;
|
|
3773
3955
|
}
|
|
3774
|
-
|
|
3956
|
+
if (adoptExisting) {
|
|
3957
|
+
operations.push({
|
|
3958
|
+
...op,
|
|
3959
|
+
action: "skip",
|
|
3960
|
+
mergeRemoval,
|
|
3961
|
+
mergeCreatedDestination: existing2?.mergeCreatedDestination,
|
|
3962
|
+
currentHash: currentHash2,
|
|
3963
|
+
manifestHash: existing2?.hash,
|
|
3964
|
+
reason: existing2 ? "force repairing exact incomplete merge ownership" : "force adopting exact unmanaged merge contribution"
|
|
3965
|
+
});
|
|
3966
|
+
continue;
|
|
3967
|
+
}
|
|
3775
3968
|
if (existing2 && existing2.sourceHash === op.desiredHash) {
|
|
3776
3969
|
operations.push(options.forceDrift ? { ...op, action: "update", mergeRemoval, mergeCreatedDestination: existing2.mergeCreatedDestination, currentHash: currentHash2, manifestHash: existing2.hash, reason: "force refreshing managed merge destination" } : { ...op, action: "skip", mergeRemoval: existing2.mergeRemoval, mergeCreatedDestination: existing2.mergeCreatedDestination, currentHash: currentHash2, manifestHash: existing2.hash, reason: "merged source already up to date" });
|
|
3777
3970
|
} else {
|
|
@@ -4426,7 +4619,7 @@ async function createUninstallPlan(manifest, transport = localTransport) {
|
|
|
4426
4619
|
composedFrom: entry.composedFrom,
|
|
4427
4620
|
...operationMetadataFromEntry2(entry)
|
|
4428
4621
|
});
|
|
4429
|
-
} else if (entry.mergeStrategy && !("mergeRemoval" in entry && entry.mergeRemoval
|
|
4622
|
+
} else if (entry.mergeStrategy && !("mergeRemoval" in entry && hasMergeRemovalContent(entry.mergeRemoval)) && !("mergeCreatedDestination" in entry && entry.mergeCreatedDestination === true)) {
|
|
4430
4623
|
operations.push(legacyMergeKeepOperation(entry, destPath));
|
|
4431
4624
|
} else {
|
|
4432
4625
|
operations.push({
|
|
@@ -4527,7 +4720,7 @@ async function createOwnershipUninstallPlan(manifest, remainingDesired, adapter,
|
|
|
4527
4720
|
...operationMetadataFromEntry2(entry),
|
|
4528
4721
|
graphLockDigest: options.graphLockDigest
|
|
4529
4722
|
});
|
|
4530
|
-
} else if (entry.mergeStrategy && !("mergeRemoval" in entry && entry.mergeRemoval
|
|
4723
|
+
} else if (entry.mergeStrategy && !("mergeRemoval" in entry && hasMergeRemovalContent(entry.mergeRemoval)) && !("mergeCreatedDestination" in entry && entry.mergeCreatedDestination === true)) {
|
|
4531
4724
|
operations.push(legacyMergeKeepOperation(entry, destPath));
|
|
4532
4725
|
} else {
|
|
4533
4726
|
operations.push({
|
|
@@ -5396,8 +5589,8 @@ import { basename as basename9, join as join19, relative as relative4, resolve a
|
|
|
5396
5589
|
import { readFile as readFile17 } from "fs/promises";
|
|
5397
5590
|
import { join as join18 } from "path";
|
|
5398
5591
|
import { parse as parse4, printParseErrorCode as printParseErrorCode2 } from "jsonc-parser";
|
|
5399
|
-
import { z as
|
|
5400
|
-
var legacyArtifactTypeSchema =
|
|
5592
|
+
import { z as z6 } from "zod";
|
|
5593
|
+
var legacyArtifactTypeSchema = z6.enum([
|
|
5401
5594
|
"instructions",
|
|
5402
5595
|
"rules",
|
|
5403
5596
|
"skills",
|
|
@@ -5408,33 +5601,33 @@ var legacyArtifactTypeSchema = z5.enum([
|
|
|
5408
5601
|
"settings",
|
|
5409
5602
|
"plugins"
|
|
5410
5603
|
]);
|
|
5411
|
-
var runtimeListSchema =
|
|
5412
|
-
var packageProvideBaseSchema =
|
|
5413
|
-
path:
|
|
5604
|
+
var runtimeListSchema = z6.array(z6.string().min(1));
|
|
5605
|
+
var packageProvideBaseSchema = z6.object({
|
|
5606
|
+
path: z6.string().min(1),
|
|
5414
5607
|
format: artifactFormatSchema.optional(),
|
|
5415
|
-
assets:
|
|
5416
|
-
required:
|
|
5608
|
+
assets: z6.array(packageAssetSchema).optional(),
|
|
5609
|
+
required: z6.boolean().optional()
|
|
5417
5610
|
});
|
|
5418
|
-
var packageItemSchema =
|
|
5611
|
+
var packageItemSchema = z6.object({
|
|
5419
5612
|
format: artifactFormatSchema.optional(),
|
|
5420
|
-
requires:
|
|
5421
|
-
suggests:
|
|
5422
|
-
compose:
|
|
5613
|
+
requires: z6.array(packageItemRequireSchema).optional(),
|
|
5614
|
+
suggests: z6.array(packageItemSuggestSchema).optional(),
|
|
5615
|
+
compose: z6.array(packageComposeEntrySchema).optional(),
|
|
5423
5616
|
runtimes: runtimeListSchema.optional()
|
|
5424
5617
|
});
|
|
5425
|
-
var packageDependencySchema =
|
|
5426
|
-
source:
|
|
5427
|
-
ref:
|
|
5428
|
-
version:
|
|
5429
|
-
select:
|
|
5430
|
-
mode:
|
|
5431
|
-
optional:
|
|
5432
|
-
integrity:
|
|
5618
|
+
var packageDependencySchema = z6.object({
|
|
5619
|
+
source: z6.string().min(1),
|
|
5620
|
+
ref: z6.string().min(1).optional(),
|
|
5621
|
+
version: z6.string().min(1).optional(),
|
|
5622
|
+
select: z6.array(z6.string().min(1)).optional(),
|
|
5623
|
+
mode: z6.enum(["pinned", "tracking"]).optional(),
|
|
5624
|
+
optional: z6.boolean().optional(),
|
|
5625
|
+
integrity: z6.string().min(1).optional(),
|
|
5433
5626
|
runtimes: runtimeListSchema.optional()
|
|
5434
5627
|
});
|
|
5435
5628
|
var packageSuggestionSchema = packageDependencySchema.extend({
|
|
5436
|
-
reason:
|
|
5437
|
-
when:
|
|
5629
|
+
reason: z6.string().min(1).optional(),
|
|
5630
|
+
when: z6.string().min(1).optional()
|
|
5438
5631
|
});
|
|
5439
5632
|
var packageProvideV1Schema = packageProvideBaseSchema.extend({
|
|
5440
5633
|
type: legacyArtifactTypeSchema
|
|
@@ -5442,35 +5635,35 @@ var packageProvideV1Schema = packageProvideBaseSchema.extend({
|
|
|
5442
5635
|
var packageProvideSchema = packageProvideBaseSchema.extend({
|
|
5443
5636
|
type: artifactTypeSchema,
|
|
5444
5637
|
runtimes: runtimeListSchema.optional(),
|
|
5445
|
-
items:
|
|
5638
|
+
items: z6.record(z6.string().min(1), packageItemSchema).optional()
|
|
5446
5639
|
});
|
|
5447
|
-
var packageManifestV1Schema =
|
|
5448
|
-
schemaVersion:
|
|
5449
|
-
name:
|
|
5450
|
-
version:
|
|
5451
|
-
provides:
|
|
5640
|
+
var packageManifestV1Schema = z6.object({
|
|
5641
|
+
schemaVersion: z6.literal(1),
|
|
5642
|
+
name: z6.string().min(1),
|
|
5643
|
+
version: z6.string().min(1),
|
|
5644
|
+
provides: z6.array(packageProvideV1Schema).min(1)
|
|
5452
5645
|
});
|
|
5453
|
-
var packageManifestV2Schema =
|
|
5454
|
-
schemaVersion:
|
|
5455
|
-
name:
|
|
5456
|
-
version:
|
|
5646
|
+
var packageManifestV2Schema = z6.object({
|
|
5647
|
+
schemaVersion: z6.literal(2),
|
|
5648
|
+
name: z6.string().min(1),
|
|
5649
|
+
version: z6.string().min(1),
|
|
5457
5650
|
runtimes: runtimeListSchema.optional(),
|
|
5458
|
-
requires:
|
|
5459
|
-
suggests:
|
|
5460
|
-
compose:
|
|
5461
|
-
provides:
|
|
5651
|
+
requires: z6.record(z6.string().min(1), packageDependencySchema).optional(),
|
|
5652
|
+
suggests: z6.record(z6.string().min(1), packageSuggestionSchema).optional(),
|
|
5653
|
+
compose: z6.array(packageComposeEntrySchema).optional(),
|
|
5654
|
+
provides: z6.array(packageProvideSchema).default([])
|
|
5462
5655
|
}).superRefine((manifest, ctx) => {
|
|
5463
5656
|
const hasProvides = manifest.provides.length > 0;
|
|
5464
5657
|
const hasRequires = Object.keys(manifest.requires ?? {}).length > 0;
|
|
5465
5658
|
if (!hasProvides && !hasRequires) {
|
|
5466
5659
|
ctx.addIssue({
|
|
5467
|
-
code:
|
|
5660
|
+
code: z6.ZodIssueCode.custom,
|
|
5468
5661
|
path: ["provides"],
|
|
5469
5662
|
message: "OpenPack v2 manifest must declare at least one provides entry or one requires dependency"
|
|
5470
5663
|
});
|
|
5471
5664
|
}
|
|
5472
5665
|
});
|
|
5473
|
-
var packageManifestSchema =
|
|
5666
|
+
var packageManifestSchema = z6.union([packageManifestV1Schema, packageManifestV2Schema]);
|
|
5474
5667
|
var openPackManifestNames = ["openpack.json", "openpack.jsonc"];
|
|
5475
5668
|
var legacyPackageManifestNames = ["agentwheel.json", "agentwheel.jsonc"];
|
|
5476
5669
|
var packageManifestNames = [...openPackManifestNames, ...legacyPackageManifestNames];
|
|
@@ -5664,7 +5857,7 @@ var LocalSourceDriver = class {
|
|
|
5664
5857
|
async scan(resolved) {
|
|
5665
5858
|
const artifacts = await this.list(resolved);
|
|
5666
5859
|
const findings = [];
|
|
5667
|
-
if (!artifacts.some((artifact) => artifact.type === "instructions")) {
|
|
5860
|
+
if (!resolved.packageName && !artifacts.some((artifact) => artifact.type === "instructions")) {
|
|
5668
5861
|
findings.push({ level: "warning", message: "No instructions.md or AGENTS.md found", path: resolved.resolvedPath });
|
|
5669
5862
|
}
|
|
5670
5863
|
for (const artifact of artifacts.filter((item) => item.type === "skills" && item.kind === "dir")) {
|
|
@@ -5730,6 +5923,7 @@ async function listFromManifest(root, packageName) {
|
|
|
5730
5923
|
if ((provide.type === "skills" || provide.type === "plugins" || provide.type === "subagents") && entry.isDirectory()) {
|
|
5731
5924
|
artifacts.push(await artifactForDir(provide.type, entry.name, child, join19(provide.path, entry.name), packageName, provide, manifest, entry.name));
|
|
5732
5925
|
} else if (entry.isFile()) {
|
|
5926
|
+
if (provide.type === "skills" && entry.name.toLowerCase() === "readme.md") continue;
|
|
5733
5927
|
const name = provide.type === "rules" && entry.name.endsWith(".md") ? entry.name : entry.name;
|
|
5734
5928
|
artifacts.push(await artifactForFile(provide.type, name, child, join19(provide.path, entry.name), packageName, provide, manifest, name));
|
|
5735
5929
|
}
|
|
@@ -5949,9 +6143,9 @@ function cachePathFor(packageName, cacheRoot) {
|
|
|
5949
6143
|
|
|
5950
6144
|
// src/source/git.ts
|
|
5951
6145
|
import { execFile as execFile4 } from "child_process";
|
|
5952
|
-
import { cp as cp2, mkdir as
|
|
6146
|
+
import { cp as cp2, mkdir as mkdir14, rename as rename3, rm as rm7 } from "fs/promises";
|
|
5953
6147
|
import { homedir as homedir3 } from "os";
|
|
5954
|
-
import { basename as basename11, dirname as
|
|
6148
|
+
import { basename as basename11, dirname as dirname17, join as join23, resolve as resolve7 } from "path";
|
|
5955
6149
|
import { promisify as promisify4 } from "util";
|
|
5956
6150
|
|
|
5957
6151
|
// src/source/auth.ts
|
|
@@ -6023,6 +6217,209 @@ function isMissingFile(error) {
|
|
|
6023
6217
|
return isRecord8(error) && error.code === "ENOENT";
|
|
6024
6218
|
}
|
|
6025
6219
|
|
|
6220
|
+
// src/source/cache.ts
|
|
6221
|
+
import { randomUUID } from "crypto";
|
|
6222
|
+
import { mkdir as mkdir13, readdir as readdir2, readFile as readFile19, rm as rm6, stat as stat4, writeFile as writeFile15 } from "fs/promises";
|
|
6223
|
+
import { dirname as dirname16, join as join22 } from "path";
|
|
6224
|
+
var snapshotNamePattern = /^(.*)-([0-9a-f]{12})$/i;
|
|
6225
|
+
var leaseMarker = ".agentwheel-lease-";
|
|
6226
|
+
async function pruneGitCache(cacheRoot, options = {}) {
|
|
6227
|
+
if (!await pathExists(cacheRoot)) return { removedPaths: [], retainedPaths: [] };
|
|
6228
|
+
if (options.maintenanceLockHeld) return pruneGitCacheUnlocked(cacheRoot, options);
|
|
6229
|
+
return withGitCacheMaintenanceLock(
|
|
6230
|
+
cacheRoot,
|
|
6231
|
+
options.cacheLockTimeoutMs ?? 3e4,
|
|
6232
|
+
() => pruneGitCacheUnlocked(cacheRoot, options)
|
|
6233
|
+
);
|
|
6234
|
+
}
|
|
6235
|
+
async function withGitCacheMaintenanceLock(cacheRoot, timeoutMs, fn) {
|
|
6236
|
+
const lockPath = join22(cacheRoot, ".maintenance.lock");
|
|
6237
|
+
await mkdir13(cacheRoot, { recursive: true });
|
|
6238
|
+
const started = Date.now();
|
|
6239
|
+
while (true) {
|
|
6240
|
+
try {
|
|
6241
|
+
await mkdir13(lockPath);
|
|
6242
|
+
await writeFile15(
|
|
6243
|
+
join22(lockPath, "owner.json"),
|
|
6244
|
+
JSON.stringify({ pid: process.pid, createdAt: (/* @__PURE__ */ new Date()).toISOString() }),
|
|
6245
|
+
"utf8"
|
|
6246
|
+
);
|
|
6247
|
+
break;
|
|
6248
|
+
} catch (error) {
|
|
6249
|
+
if (!isAlreadyExists3(error)) throw error;
|
|
6250
|
+
if (await removeStaleMaintenanceLock(lockPath)) continue;
|
|
6251
|
+
if (Date.now() - started > timeoutMs) {
|
|
6252
|
+
throw new Error(`Timed out waiting for git cache maintenance lock at ${lockPath}`);
|
|
6253
|
+
}
|
|
6254
|
+
await new Promise((resolve23) => setTimeout(resolve23, 50));
|
|
6255
|
+
}
|
|
6256
|
+
}
|
|
6257
|
+
try {
|
|
6258
|
+
return await fn();
|
|
6259
|
+
} finally {
|
|
6260
|
+
await rm6(lockPath, { recursive: true, force: true });
|
|
6261
|
+
}
|
|
6262
|
+
}
|
|
6263
|
+
async function createGitSnapshotLease(snapshotPath) {
|
|
6264
|
+
const leasePath = `${snapshotPath}${leaseMarker}${process.pid}-${randomUUID()}`;
|
|
6265
|
+
await writeFile15(leasePath, JSON.stringify({ pid: process.pid, createdAt: (/* @__PURE__ */ new Date()).toISOString() }), {
|
|
6266
|
+
encoding: "utf8",
|
|
6267
|
+
flag: "wx"
|
|
6268
|
+
});
|
|
6269
|
+
return leasePath;
|
|
6270
|
+
}
|
|
6271
|
+
async function releaseGitSnapshotLease(leasePath) {
|
|
6272
|
+
if (leasePath) await rm6(leasePath, { force: true });
|
|
6273
|
+
}
|
|
6274
|
+
async function removeGeneratedEntries(root, preserveGit) {
|
|
6275
|
+
let entries;
|
|
6276
|
+
try {
|
|
6277
|
+
entries = await readdir2(root, { withFileTypes: true });
|
|
6278
|
+
} catch {
|
|
6279
|
+
return;
|
|
6280
|
+
}
|
|
6281
|
+
for (const entry of entries) {
|
|
6282
|
+
const path = join22(root, entry.name);
|
|
6283
|
+
if (isIgnoredGeneratedEntry(entry.name) && !(preserveGit && entry.name === ".git")) {
|
|
6284
|
+
await rm6(path, { recursive: true, force: true });
|
|
6285
|
+
} else if (entry.isDirectory()) {
|
|
6286
|
+
await removeGeneratedEntries(path, preserveGit);
|
|
6287
|
+
}
|
|
6288
|
+
}
|
|
6289
|
+
}
|
|
6290
|
+
async function pruneGitCacheUnlocked(cacheRoot, options) {
|
|
6291
|
+
const referencedCommits = await referencedGraphLockCommits(join22(dirname16(cacheRoot), "locks"));
|
|
6292
|
+
const entries = await readdir2(cacheRoot, { withFileTypes: true });
|
|
6293
|
+
const groups = /* @__PURE__ */ new Map();
|
|
6294
|
+
for (const entry of entries) {
|
|
6295
|
+
if (!entry.isDirectory()) continue;
|
|
6296
|
+
const match = snapshotNamePattern.exec(entry.name);
|
|
6297
|
+
if (!match) continue;
|
|
6298
|
+
const checkoutPath = join22(cacheRoot, match[1]);
|
|
6299
|
+
if (!await pathExists(join22(checkoutPath, ".git"))) continue;
|
|
6300
|
+
const snapshotPath = join22(cacheRoot, entry.name);
|
|
6301
|
+
const snapshotStats = await stat4(snapshotPath);
|
|
6302
|
+
const snapshots = groups.get(checkoutPath) ?? [];
|
|
6303
|
+
snapshots.push({ path: snapshotPath, commitPrefix: match[2].toLowerCase(), modifiedAt: snapshotStats.mtimeMs });
|
|
6304
|
+
groups.set(checkoutPath, snapshots);
|
|
6305
|
+
}
|
|
6306
|
+
const keepCount = Math.max(1, Math.floor(options.keepSnapshots ?? 3));
|
|
6307
|
+
const removedPaths = [];
|
|
6308
|
+
const retainedPaths = [];
|
|
6309
|
+
for (const [checkoutPath, snapshots] of groups) {
|
|
6310
|
+
if (!options.dryRun) await removeGeneratedEntries(checkoutPath, true);
|
|
6311
|
+
snapshots.sort((a, b) => b.modifiedAt - a.modifiedAt || a.path.localeCompare(b.path));
|
|
6312
|
+
const keep = /* @__PURE__ */ new Set();
|
|
6313
|
+
for (const snapshot of snapshots.slice(0, keepCount)) keep.add(snapshot.path);
|
|
6314
|
+
if (options.currentSnapshot) keep.add(options.currentSnapshot);
|
|
6315
|
+
for (const snapshot of snapshots) {
|
|
6316
|
+
if ([...referencedCommits].some((commit) => commit.startsWith(snapshot.commitPrefix))) keep.add(snapshot.path);
|
|
6317
|
+
if (await hasLiveSnapshotLease(snapshot.path, options.dryRun === true)) keep.add(snapshot.path);
|
|
6318
|
+
}
|
|
6319
|
+
for (const snapshot of snapshots) {
|
|
6320
|
+
if (keep.has(snapshot.path)) {
|
|
6321
|
+
retainedPaths.push(snapshot.path);
|
|
6322
|
+
if (!options.dryRun) await removeGeneratedEntries(snapshot.path, false);
|
|
6323
|
+
} else {
|
|
6324
|
+
removedPaths.push(snapshot.path);
|
|
6325
|
+
if (!options.dryRun) await rm6(snapshot.path, { recursive: true, force: true });
|
|
6326
|
+
}
|
|
6327
|
+
}
|
|
6328
|
+
}
|
|
6329
|
+
return { removedPaths, retainedPaths };
|
|
6330
|
+
}
|
|
6331
|
+
async function referencedGraphLockCommits(lockRoot) {
|
|
6332
|
+
const commits = /* @__PURE__ */ new Set();
|
|
6333
|
+
await walkGraphLocks(lockRoot, (value) => collectResolvedCommits(value, commits));
|
|
6334
|
+
return commits;
|
|
6335
|
+
}
|
|
6336
|
+
async function walkGraphLocks(root, visit) {
|
|
6337
|
+
let entries;
|
|
6338
|
+
try {
|
|
6339
|
+
entries = await readdir2(root, { withFileTypes: true });
|
|
6340
|
+
} catch (error) {
|
|
6341
|
+
if (isNotFound(error)) return;
|
|
6342
|
+
throw new Error(`Cannot inspect graph-lock directory ${root}; cache prune aborted: ${errorMessage3(error)}`);
|
|
6343
|
+
}
|
|
6344
|
+
for (const entry of entries) {
|
|
6345
|
+
const path = join22(root, entry.name);
|
|
6346
|
+
if (entry.isDirectory()) {
|
|
6347
|
+
await walkGraphLocks(path, visit);
|
|
6348
|
+
} else if (entry.isFile() && entry.name.endsWith(".graph-lock.json")) {
|
|
6349
|
+
try {
|
|
6350
|
+
visit(JSON.parse(await readFile19(path, "utf8")));
|
|
6351
|
+
} catch (error) {
|
|
6352
|
+
throw new Error(`Cannot read graph lock ${path}; cache prune aborted: ${errorMessage3(error)}`);
|
|
6353
|
+
}
|
|
6354
|
+
}
|
|
6355
|
+
}
|
|
6356
|
+
}
|
|
6357
|
+
async function hasLiveSnapshotLease(snapshotPath, dryRun) {
|
|
6358
|
+
const directory = dirname16(snapshotPath);
|
|
6359
|
+
const prefix = `${snapshotPath.slice(directory.length + 1)}${leaseMarker}`;
|
|
6360
|
+
const entries = await readdir2(directory, { withFileTypes: true });
|
|
6361
|
+
let live = false;
|
|
6362
|
+
for (const entry of entries) {
|
|
6363
|
+
if (!entry.isFile() || !entry.name.startsWith(prefix)) continue;
|
|
6364
|
+
const leasePath = join22(directory, entry.name);
|
|
6365
|
+
try {
|
|
6366
|
+
const value = JSON.parse(await readFile19(leasePath, "utf8"));
|
|
6367
|
+
if (typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0) {
|
|
6368
|
+
live = true;
|
|
6369
|
+
} else if (isProcessAlive(value.pid)) {
|
|
6370
|
+
live = true;
|
|
6371
|
+
} else if (!dryRun) {
|
|
6372
|
+
await rm6(leasePath, { force: true });
|
|
6373
|
+
}
|
|
6374
|
+
} catch {
|
|
6375
|
+
live = true;
|
|
6376
|
+
}
|
|
6377
|
+
}
|
|
6378
|
+
return live;
|
|
6379
|
+
}
|
|
6380
|
+
async function removeStaleMaintenanceLock(lockPath) {
|
|
6381
|
+
try {
|
|
6382
|
+
const value = JSON.parse(await readFile19(join22(lockPath, "owner.json"), "utf8"));
|
|
6383
|
+
if (typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0 || isProcessAlive(value.pid)) {
|
|
6384
|
+
return false;
|
|
6385
|
+
}
|
|
6386
|
+
await rm6(lockPath, { recursive: true, force: true });
|
|
6387
|
+
return true;
|
|
6388
|
+
} catch {
|
|
6389
|
+
return false;
|
|
6390
|
+
}
|
|
6391
|
+
}
|
|
6392
|
+
function isProcessAlive(pid) {
|
|
6393
|
+
try {
|
|
6394
|
+
process.kill(pid, 0);
|
|
6395
|
+
return true;
|
|
6396
|
+
} catch (error) {
|
|
6397
|
+
return typeof error === "object" && error !== null && "code" in error && error.code !== "ESRCH";
|
|
6398
|
+
}
|
|
6399
|
+
}
|
|
6400
|
+
function collectResolvedCommits(value, commits) {
|
|
6401
|
+
if (Array.isArray(value)) {
|
|
6402
|
+
for (const item of value) collectResolvedCommits(item, commits);
|
|
6403
|
+
return;
|
|
6404
|
+
}
|
|
6405
|
+
if (!value || typeof value !== "object") return;
|
|
6406
|
+
for (const [key, item] of Object.entries(value)) {
|
|
6407
|
+
if (key === "resolvedCommit" && typeof item === "string" && /^[0-9a-f]{12,40}$/i.test(item)) {
|
|
6408
|
+
commits.add(item.toLowerCase());
|
|
6409
|
+
}
|
|
6410
|
+
collectResolvedCommits(item, commits);
|
|
6411
|
+
}
|
|
6412
|
+
}
|
|
6413
|
+
function isAlreadyExists3(error) {
|
|
6414
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
6415
|
+
}
|
|
6416
|
+
function isNotFound(error) {
|
|
6417
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
6418
|
+
}
|
|
6419
|
+
function errorMessage3(error) {
|
|
6420
|
+
return error instanceof Error ? error.message : String(error);
|
|
6421
|
+
}
|
|
6422
|
+
|
|
6026
6423
|
// src/source/git.ts
|
|
6027
6424
|
var execFileAsync4 = promisify4(execFile4);
|
|
6028
6425
|
var GitSourceDriver = class {
|
|
@@ -6045,12 +6442,12 @@ var GitSourceDriver = class {
|
|
|
6045
6442
|
async fetch(resolved) {
|
|
6046
6443
|
return withFilesystemLock(`${resolved.resolvedPath}.lock`, resolved.cacheLockTimeoutMs ?? 3e4, async () => {
|
|
6047
6444
|
const parsed = parseGitSource(resolved.source);
|
|
6048
|
-
await
|
|
6049
|
-
if (!await pathExists(
|
|
6445
|
+
await mkdir14(resolve7(resolved.resolvedPath, ".."), { recursive: true });
|
|
6446
|
+
if (!await pathExists(join23(resolved.resolvedPath, ".git"))) {
|
|
6050
6447
|
if (resolved.frozenLock) {
|
|
6051
6448
|
throw new Error(`Frozen lock requires cached git checkout at ${resolved.resolvedPath}`);
|
|
6052
6449
|
}
|
|
6053
|
-
await
|
|
6450
|
+
await rm7(resolved.resolvedPath, { recursive: true, force: true });
|
|
6054
6451
|
await git([...await gitAuthArguments(parsed.url), "clone", parsed.url, resolved.resolvedPath]);
|
|
6055
6452
|
} else if (!resolved.frozenLock) {
|
|
6056
6453
|
await git([
|
|
@@ -6076,9 +6473,24 @@ var GitSourceDriver = class {
|
|
|
6076
6473
|
await git(["-C", resolved.resolvedPath, "checkout", "--detach", ref]);
|
|
6077
6474
|
}
|
|
6078
6475
|
}
|
|
6476
|
+
await removeGeneratedEntries(resolved.resolvedPath, true);
|
|
6079
6477
|
const { stdout } = await git(["-C", resolved.resolvedPath, "rev-parse", "HEAD"]);
|
|
6080
6478
|
const resolvedCommit = stdout.trim();
|
|
6081
|
-
const
|
|
6479
|
+
const cacheRoot = dirname17(resolved.resolvedPath);
|
|
6480
|
+
const snapshot = await withGitCacheMaintenanceLock(
|
|
6481
|
+
cacheRoot,
|
|
6482
|
+
resolved.cacheLockTimeoutMs ?? 3e4,
|
|
6483
|
+
async () => {
|
|
6484
|
+
const path = await snapshotCheckout(resolved.resolvedPath, resolvedCommit);
|
|
6485
|
+
const leasePath = await createGitSnapshotLease(path);
|
|
6486
|
+
await pruneGitCache(cacheRoot, {
|
|
6487
|
+
currentSnapshot: path,
|
|
6488
|
+
maintenanceLockHeld: true
|
|
6489
|
+
});
|
|
6490
|
+
return { path, leasePath };
|
|
6491
|
+
}
|
|
6492
|
+
);
|
|
6493
|
+
const snapshotPath = snapshot.path;
|
|
6082
6494
|
const manifest = await readPackageManifest(snapshotPath);
|
|
6083
6495
|
return {
|
|
6084
6496
|
...resolved,
|
|
@@ -6086,9 +6498,10 @@ var GitSourceDriver = class {
|
|
|
6086
6498
|
packageName: manifest?.name,
|
|
6087
6499
|
packageVersion: manifest?.version,
|
|
6088
6500
|
resolvedCommit,
|
|
6089
|
-
sourceHash: await hashPath(snapshotPath)
|
|
6501
|
+
sourceHash: await hashPath(snapshotPath),
|
|
6502
|
+
cacheLeasePath: snapshot.leasePath
|
|
6090
6503
|
};
|
|
6091
|
-
});
|
|
6504
|
+
}, "git cache");
|
|
6092
6505
|
}
|
|
6093
6506
|
async list(resolved) {
|
|
6094
6507
|
return this.local.list({ ...resolved, driver: "local" });
|
|
@@ -6121,58 +6534,37 @@ function parseGitSource(source) {
|
|
|
6121
6534
|
throw new Error(`Invalid git source: ${source}`);
|
|
6122
6535
|
}
|
|
6123
6536
|
function cachePathFor2(url, cacheRoot) {
|
|
6124
|
-
const root = cacheRoot ? resolve7(cacheRoot) :
|
|
6537
|
+
const root = cacheRoot ? resolve7(cacheRoot) : join23(homedir3(), ".agentwheel", "cache");
|
|
6125
6538
|
const slug2 = url.replace(/^[a-z]+:\/\//i, "").replace(/\.git$/i, "").replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
6126
|
-
return
|
|
6539
|
+
return join23(root, slug2 || basename11(url));
|
|
6127
6540
|
}
|
|
6128
6541
|
async function git(args) {
|
|
6129
6542
|
return execFileAsync4("git", args, { maxBuffer: 1024 * 1024 * 10 });
|
|
6130
6543
|
}
|
|
6131
6544
|
async function snapshotCheckout(checkoutPath, commit) {
|
|
6132
|
-
const snapshotPath =
|
|
6545
|
+
const snapshotPath = join23(dirname17(checkoutPath), `${basename11(checkoutPath)}-${commit.slice(0, 12)}`);
|
|
6133
6546
|
if (await pathExists(snapshotPath)) return snapshotPath;
|
|
6134
|
-
const tempPath =
|
|
6135
|
-
await
|
|
6136
|
-
await cp2(checkoutPath, tempPath, {
|
|
6137
|
-
|
|
6547
|
+
const tempPath = join23(dirname17(checkoutPath), `${basename11(snapshotPath)}.tmp-${process.pid}-${Date.now()}`);
|
|
6548
|
+
await rm7(tempPath, { recursive: true, force: true });
|
|
6549
|
+
await cp2(checkoutPath, tempPath, {
|
|
6550
|
+
recursive: true,
|
|
6551
|
+
dereference: true,
|
|
6552
|
+
filter: (path) => !isIgnoredGeneratedEntry(basename11(path))
|
|
6553
|
+
});
|
|
6554
|
+
await rm7(join23(tempPath, ".git"), { recursive: true, force: true });
|
|
6138
6555
|
try {
|
|
6139
6556
|
await rename3(tempPath, snapshotPath);
|
|
6140
6557
|
} catch (error) {
|
|
6141
|
-
if (!
|
|
6142
|
-
await
|
|
6558
|
+
if (!isAlreadyExists(error)) throw error;
|
|
6559
|
+
await rm7(tempPath, { recursive: true, force: true });
|
|
6143
6560
|
return snapshotPath;
|
|
6144
6561
|
}
|
|
6145
6562
|
return snapshotPath;
|
|
6146
6563
|
}
|
|
6147
|
-
async function withFilesystemLock(lockPath, timeoutMs, fn) {
|
|
6148
|
-
await mkdir13(dirname16(lockPath), { recursive: true });
|
|
6149
|
-
const started = Date.now();
|
|
6150
|
-
while (true) {
|
|
6151
|
-
try {
|
|
6152
|
-
await mkdir13(lockPath);
|
|
6153
|
-
await writeFile15(join22(lockPath, "owner.json"), JSON.stringify({ pid: process.pid, createdAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf8");
|
|
6154
|
-
break;
|
|
6155
|
-
} catch (error) {
|
|
6156
|
-
if (!isAlreadyExists2(error)) throw error;
|
|
6157
|
-
if (Date.now() - started > timeoutMs) {
|
|
6158
|
-
throw new Error(`Timed out waiting for git cache lock at ${lockPath}`);
|
|
6159
|
-
}
|
|
6160
|
-
await new Promise((resolve23) => setTimeout(resolve23, 50));
|
|
6161
|
-
}
|
|
6162
|
-
}
|
|
6163
|
-
try {
|
|
6164
|
-
return await fn();
|
|
6165
|
-
} finally {
|
|
6166
|
-
await rm6(lockPath, { recursive: true, force: true });
|
|
6167
|
-
}
|
|
6168
|
-
}
|
|
6169
|
-
function isAlreadyExists2(error) {
|
|
6170
|
-
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
6171
|
-
}
|
|
6172
6564
|
|
|
6173
6565
|
// src/source/mcp-registry.ts
|
|
6174
|
-
import { mkdir as
|
|
6175
|
-
import { basename as basename12, dirname as
|
|
6566
|
+
import { mkdir as mkdir15, writeFile as writeFile16 } from "fs/promises";
|
|
6567
|
+
import { basename as basename12, dirname as dirname18, join as join24, resolve as resolve8 } from "path";
|
|
6176
6568
|
var registryBaseUrl = "https://registry.modelcontextprotocol.io/v0.1";
|
|
6177
6569
|
var sourcePrefix2 = "mcp-registry:";
|
|
6178
6570
|
var McpRegistrySourceDriver = class {
|
|
@@ -6238,7 +6630,7 @@ var McpRegistrySourceDriver = class {
|
|
|
6238
6630
|
return this.local.list({ ...resolved, driver: "local" });
|
|
6239
6631
|
}
|
|
6240
6632
|
async scan(resolved) {
|
|
6241
|
-
if (!await pathExists(
|
|
6633
|
+
if (!await pathExists(join24(resolved.resolvedPath, "mcp"))) {
|
|
6242
6634
|
return { ok: false, findings: [{ level: "error", message: "MCP registry source has no generated mcp artifact" }] };
|
|
6243
6635
|
}
|
|
6244
6636
|
return { ok: true, findings: [] };
|
|
@@ -6278,9 +6670,9 @@ function isSafeHttpUrl(value) {
|
|
|
6278
6670
|
}
|
|
6279
6671
|
async function writeGeneratedPackage2(root, server) {
|
|
6280
6672
|
const serverId = installNameFor3(server.serverName);
|
|
6281
|
-
const mcpPath =
|
|
6282
|
-
await
|
|
6283
|
-
await writeFile16(
|
|
6673
|
+
const mcpPath = join24(root, "mcp", `${serverId}.json`);
|
|
6674
|
+
await mkdir15(dirname18(mcpPath), { recursive: true });
|
|
6675
|
+
await writeFile16(join24(root, "openpack.json"), `${JSON.stringify({
|
|
6284
6676
|
schemaVersion: 2,
|
|
6285
6677
|
name: `mcp-registry/${server.serverName}`,
|
|
6286
6678
|
version: server.version ?? "latest",
|
|
@@ -6301,20 +6693,23 @@ function installNameFor3(serverName) {
|
|
|
6301
6693
|
return basename12(serverName).replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "mcp-server";
|
|
6302
6694
|
}
|
|
6303
6695
|
function cachePathFor3(serverName, cacheRoot) {
|
|
6304
|
-
const root = cacheRoot ? resolve8(cacheRoot) :
|
|
6696
|
+
const root = cacheRoot ? resolve8(cacheRoot) : join24(process.env.HOME ?? ".", ".agentwheel", "cache");
|
|
6305
6697
|
const slug2 = `mcp-registry-${serverName}`.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
6306
|
-
return
|
|
6698
|
+
return join24(root, slug2 || "mcp-registry-server");
|
|
6307
6699
|
}
|
|
6308
6700
|
|
|
6309
6701
|
// src/source/skillkit.ts
|
|
6310
|
-
import {
|
|
6702
|
+
import { createHash as createHash6, randomUUID as randomUUID2 } from "crypto";
|
|
6703
|
+
import { execFile as execFile5 } from "child_process";
|
|
6704
|
+
import { cp as cp3, mkdir as mkdir16, readFile as readFile20, rename as rename4, rm as rm8 } from "fs/promises";
|
|
6311
6705
|
import { homedir as homedir4 } from "os";
|
|
6312
|
-
import { basename as basename14, dirname as
|
|
6706
|
+
import { basename as basename14, dirname as dirname20, join as join26, resolve as resolve9 } from "path";
|
|
6707
|
+
import { promisify as promisify5 } from "util";
|
|
6313
6708
|
import * as defaultSkillKit from "@skillkit/core";
|
|
6314
6709
|
|
|
6315
6710
|
// src/source/skill-artifacts.ts
|
|
6316
|
-
import { readdir as
|
|
6317
|
-
import { basename as basename13, dirname as
|
|
6711
|
+
import { readdir as readdir3, stat as stat5 } from "fs/promises";
|
|
6712
|
+
import { basename as basename13, dirname as dirname19, extname as extname2, join as join25 } from "path";
|
|
6318
6713
|
async function artifactsFromSkillPaths(paths, packageName) {
|
|
6319
6714
|
const artifacts = [];
|
|
6320
6715
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -6334,16 +6729,16 @@ async function discoverSkillPaths(root) {
|
|
|
6334
6729
|
return paths;
|
|
6335
6730
|
}
|
|
6336
6731
|
async function artifactFromSkillPath(item, packageName) {
|
|
6337
|
-
const stats = await
|
|
6732
|
+
const stats = await stat5(item.path);
|
|
6338
6733
|
if (stats.isDirectory()) {
|
|
6339
|
-
const skillMd =
|
|
6734
|
+
const skillMd = join25(item.path, "SKILL.md");
|
|
6340
6735
|
if (!await pathExists(skillMd)) return void 0;
|
|
6341
6736
|
const name = sanitizeSkillName(item.name ?? basename13(item.path));
|
|
6342
6737
|
return {
|
|
6343
6738
|
type: "skills",
|
|
6344
6739
|
name,
|
|
6345
6740
|
sourcePath: item.path,
|
|
6346
|
-
relativePath:
|
|
6741
|
+
relativePath: join25("skills", name),
|
|
6347
6742
|
kind: "dir",
|
|
6348
6743
|
hash: await hashPath(item.path),
|
|
6349
6744
|
packageName,
|
|
@@ -6351,13 +6746,13 @@ async function artifactFromSkillPath(item, packageName) {
|
|
|
6351
6746
|
};
|
|
6352
6747
|
}
|
|
6353
6748
|
if (stats.isFile() && basename13(item.path).toLowerCase() === "skill.md") {
|
|
6354
|
-
const dir =
|
|
6749
|
+
const dir = dirname19(item.path);
|
|
6355
6750
|
const name = sanitizeSkillName(item.name ?? basename13(dir));
|
|
6356
6751
|
return {
|
|
6357
6752
|
type: "skills",
|
|
6358
6753
|
name,
|
|
6359
6754
|
sourcePath: dir,
|
|
6360
|
-
relativePath:
|
|
6755
|
+
relativePath: join25("skills", name),
|
|
6361
6756
|
kind: "dir",
|
|
6362
6757
|
hash: await hashPath(dir),
|
|
6363
6758
|
packageName,
|
|
@@ -6370,7 +6765,7 @@ async function artifactFromSkillPath(item, packageName) {
|
|
|
6370
6765
|
type: "skills",
|
|
6371
6766
|
name,
|
|
6372
6767
|
sourcePath: item.path,
|
|
6373
|
-
relativePath:
|
|
6768
|
+
relativePath: join25("skills", `${name}.md`),
|
|
6374
6769
|
kind: "file",
|
|
6375
6770
|
hash: await hashPath(item.path),
|
|
6376
6771
|
packageName,
|
|
@@ -6381,14 +6776,14 @@ async function artifactFromSkillPath(item, packageName) {
|
|
|
6381
6776
|
}
|
|
6382
6777
|
async function walk(dir, paths) {
|
|
6383
6778
|
if (!await pathExists(dir)) return;
|
|
6384
|
-
const entries = await
|
|
6779
|
+
const entries = await readdir3(dir, { withFileTypes: true });
|
|
6385
6780
|
if (entries.some((entry) => entry.isFile() && entry.name === "SKILL.md")) {
|
|
6386
6781
|
paths.push({ path: dir });
|
|
6387
6782
|
return;
|
|
6388
6783
|
}
|
|
6389
6784
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
6390
6785
|
if (!entry.isDirectory() || entry.name === ".git" || entry.name === "node_modules") continue;
|
|
6391
|
-
await walk(
|
|
6786
|
+
await walk(join25(dir, entry.name), paths);
|
|
6392
6787
|
}
|
|
6393
6788
|
}
|
|
6394
6789
|
function sanitizeSkillName(name) {
|
|
@@ -6396,12 +6791,14 @@ function sanitizeSkillName(name) {
|
|
|
6396
6791
|
}
|
|
6397
6792
|
|
|
6398
6793
|
// src/source/skillkit.ts
|
|
6794
|
+
var execFileAsync5 = promisify5(execFile5);
|
|
6399
6795
|
var SkillKitSourceDriver = class {
|
|
6400
6796
|
constructor(core = defaultSkillKit) {
|
|
6401
6797
|
this.core = core;
|
|
6402
6798
|
}
|
|
6403
6799
|
core;
|
|
6404
6800
|
name = "skillkit";
|
|
6801
|
+
inflightFetches = /* @__PURE__ */ new Map();
|
|
6405
6802
|
async resolve(source, options = {}) {
|
|
6406
6803
|
const spec = parseSkillKitSource(source);
|
|
6407
6804
|
if (await pathExists(spec)) {
|
|
@@ -6415,14 +6812,17 @@ var SkillKitSourceDriver = class {
|
|
|
6415
6812
|
sourceHash: await hashPath(resolvedPath)
|
|
6416
6813
|
};
|
|
6417
6814
|
}
|
|
6815
|
+
const cacheIdentity = normalizeImmutableCacheIdentity(options.cacheIdentity) ?? immutableCommit(options.ref);
|
|
6418
6816
|
return {
|
|
6419
6817
|
driver: this.name,
|
|
6420
6818
|
source,
|
|
6421
|
-
resolvedPath: cachePathFor4(spec, options.cacheRoot),
|
|
6819
|
+
resolvedPath: cachePathFor4(spec, options.cacheRoot, cacheIdentity),
|
|
6422
6820
|
packageName: `skillkit/${packageSlug(spec)}`,
|
|
6423
6821
|
mode: options.mode ?? "tracking",
|
|
6424
6822
|
requestedRef: options.ref,
|
|
6425
|
-
|
|
6823
|
+
cacheIdentity,
|
|
6824
|
+
frozenLock: options.frozenLock,
|
|
6825
|
+
cacheLockTimeoutMs: options.cacheLockTimeoutMs
|
|
6426
6826
|
};
|
|
6427
6827
|
}
|
|
6428
6828
|
async fetch(resolved) {
|
|
@@ -6430,35 +6830,104 @@ var SkillKitSourceDriver = class {
|
|
|
6430
6830
|
if (await pathExists(spec)) {
|
|
6431
6831
|
return resolved;
|
|
6432
6832
|
}
|
|
6833
|
+
const requestedCommit = immutableCommit(resolved.requestedRef);
|
|
6834
|
+
const immutableCacheIdentity = resolved.cacheIdentity ?? requestedCommit;
|
|
6433
6835
|
if (resolved.frozenLock) {
|
|
6836
|
+
if (!immutableCacheIdentity) {
|
|
6837
|
+
throw new Error("Frozen lock requires cached SkillKit source identified by an immutable cache identity.");
|
|
6838
|
+
}
|
|
6434
6839
|
if (!await pathExists(resolved.resolvedPath)) {
|
|
6435
6840
|
throw new Error(`Frozen lock requires cached SkillKit source at ${resolved.resolvedPath}`);
|
|
6436
6841
|
}
|
|
6437
6842
|
return {
|
|
6438
6843
|
...resolved,
|
|
6844
|
+
resolvedCommit: requestedCommit,
|
|
6845
|
+
cacheIdentity: immutableCacheIdentity,
|
|
6439
6846
|
sourceHash: await hashPath(resolved.resolvedPath)
|
|
6440
6847
|
};
|
|
6441
6848
|
}
|
|
6849
|
+
if (immutableCacheIdentity && await pathExists(resolved.resolvedPath)) {
|
|
6850
|
+
return {
|
|
6851
|
+
...resolved,
|
|
6852
|
+
resolvedCommit: requestedCommit,
|
|
6853
|
+
cacheIdentity: immutableCacheIdentity,
|
|
6854
|
+
sourceHash: await hashPath(resolved.resolvedPath)
|
|
6855
|
+
};
|
|
6856
|
+
}
|
|
6857
|
+
const specCachePath = cachePathFor4(spec, dirname20(dirname20(resolved.resolvedPath)));
|
|
6858
|
+
const refIdentity = resolved.requestedRef ?? "default";
|
|
6859
|
+
const lockPath = `${specCachePath}.ref-${createHash6("sha256").update(refIdentity).digest("hex")}.lock`;
|
|
6860
|
+
const inflightKey = `${lockPath}\0${requestedCommit ?? "movable"}`;
|
|
6861
|
+
const inflight = this.inflightFetches.get(inflightKey);
|
|
6862
|
+
if (inflight) return inflight;
|
|
6863
|
+
const fetchPromise = this.materializeRemote(resolved, spec, specCachePath, lockPath, requestedCommit);
|
|
6864
|
+
this.inflightFetches.set(inflightKey, fetchPromise);
|
|
6865
|
+
try {
|
|
6866
|
+
return await fetchPromise;
|
|
6867
|
+
} finally {
|
|
6868
|
+
if (this.inflightFetches.get(inflightKey) === fetchPromise) this.inflightFetches.delete(inflightKey);
|
|
6869
|
+
}
|
|
6870
|
+
}
|
|
6871
|
+
async materializeRemote(resolved, spec, specCachePath, lockPath, requestedCommit) {
|
|
6442
6872
|
const providerSpec = normalizeProviderSource(spec);
|
|
6443
6873
|
const provider = this.core.detectProvider?.(providerSpec);
|
|
6444
6874
|
if (!provider?.clone) {
|
|
6445
6875
|
throw new Error("SkillKit provider API unavailable or cannot resolve source. Expected @skillkit/core detectProvider().clone().");
|
|
6446
6876
|
}
|
|
6447
|
-
await
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6877
|
+
const materialized = await withFilesystemLock(lockPath, resolved.cacheLockTimeoutMs ?? 3e4, async () => {
|
|
6878
|
+
const immutablePath = requestedCommit ? cachePathFor4(spec, dirname20(dirname20(specCachePath)), requestedCommit) : void 0;
|
|
6879
|
+
if (immutablePath && await pathExists(immutablePath)) {
|
|
6880
|
+
return { path: immutablePath, commit: requestedCommit, cacheIdentity: requestedCommit };
|
|
6881
|
+
}
|
|
6882
|
+
await mkdir16(dirname20(specCachePath), { recursive: true });
|
|
6883
|
+
const candidatePath = `${specCachePath}.agentwheel-tmp-${process.pid}-${randomUUID2()}`;
|
|
6884
|
+
const publishPath = `${candidatePath}.publish`;
|
|
6885
|
+
let result;
|
|
6886
|
+
try {
|
|
6887
|
+
const requestedRef = resolved.requestedRef;
|
|
6888
|
+
result = await provider.clone(providerSpec, candidatePath, requestedCommit || !requestedRef ? {} : { branch: requestedRef });
|
|
6889
|
+
if (!result.success || !result.path) {
|
|
6890
|
+
throw new Error(`SkillKit provider failed to fetch ${spec}: ${result.error ?? "unknown error"}`);
|
|
6891
|
+
}
|
|
6892
|
+
if (requestedCommit && requestedRef) {
|
|
6893
|
+
if (!result.tempRoot) {
|
|
6894
|
+
throw new Error(`SkillKit provider cannot materialize commit ${requestedRef}: clone result has no git checkout root`);
|
|
6895
|
+
}
|
|
6896
|
+
await checkoutCommit(result.tempRoot, requestedRef);
|
|
6897
|
+
}
|
|
6898
|
+
const resolvedIdentity = await resolveCloneIdentity(result);
|
|
6899
|
+
if (requestedCommit && !resolvedIdentity.commit?.startsWith(requestedCommit)) {
|
|
6900
|
+
throw new Error(
|
|
6901
|
+
`SkillKit provider resolved ${resolvedIdentity.commit ?? "non-Git content"} instead of requested commit ${requestedCommit}`
|
|
6902
|
+
);
|
|
6903
|
+
}
|
|
6904
|
+
const cachePath = cachePathFor4(spec, dirname20(dirname20(specCachePath)), resolvedIdentity.cacheKey);
|
|
6905
|
+
if (await pathExists(cachePath)) {
|
|
6906
|
+
return { path: cachePath, commit: resolvedIdentity.commit, cacheIdentity: resolvedIdentity.cacheKey };
|
|
6907
|
+
}
|
|
6908
|
+
const publishCandidate = resolve9(result.path) === resolve9(candidatePath) ? candidatePath : publishPath;
|
|
6909
|
+
if (publishCandidate === publishPath) await cp3(result.path, publishPath, { recursive: true, dereference: true });
|
|
6910
|
+
try {
|
|
6911
|
+
await rename4(publishCandidate, cachePath);
|
|
6912
|
+
} catch (error) {
|
|
6913
|
+
if (!isAlreadyExists(error) && !isDirectoryNotEmpty(error)) throw error;
|
|
6914
|
+
await rm8(publishCandidate, { recursive: true, force: true });
|
|
6915
|
+
}
|
|
6916
|
+
return { path: cachePath, commit: resolvedIdentity.commit, cacheIdentity: resolvedIdentity.cacheKey };
|
|
6917
|
+
} finally {
|
|
6918
|
+
await rm8(candidatePath, { recursive: true, force: true });
|
|
6919
|
+
await rm8(publishPath, { recursive: true, force: true });
|
|
6920
|
+
if (result?.tempRoot) {
|
|
6921
|
+
await rm8(result.tempRoot, { recursive: true, force: true });
|
|
6922
|
+
}
|
|
6923
|
+
}
|
|
6924
|
+
});
|
|
6459
6925
|
return {
|
|
6460
6926
|
...resolved,
|
|
6461
|
-
|
|
6927
|
+
resolvedPath: materialized.path,
|
|
6928
|
+
resolvedCommit: materialized.commit,
|
|
6929
|
+
cacheIdentity: materialized.cacheIdentity,
|
|
6930
|
+
sourceHash: await hashPath(materialized.path)
|
|
6462
6931
|
};
|
|
6463
6932
|
}
|
|
6464
6933
|
async list(resolved) {
|
|
@@ -6488,9 +6957,9 @@ var SkillKitSourceDriver = class {
|
|
|
6488
6957
|
throw new Error("SkillKit translateSkill API unavailable");
|
|
6489
6958
|
}
|
|
6490
6959
|
for (const skill of this.discover(resolved.resolvedPath)) {
|
|
6491
|
-
const skillMd =
|
|
6960
|
+
const skillMd = join26(skill.path, "SKILL.md");
|
|
6492
6961
|
if (await pathExists(skillMd)) {
|
|
6493
|
-
this.core.translateSkill(await
|
|
6962
|
+
this.core.translateSkill(await readFile20(skillMd, "utf8"), "openclaw", { sourceFilename: "SKILL.md" });
|
|
6494
6963
|
}
|
|
6495
6964
|
}
|
|
6496
6965
|
return resolved;
|
|
@@ -6518,9 +6987,11 @@ function normalizeProviderSource(spec) {
|
|
|
6518
6987
|
if (spec.startsWith("git:https://github.com/")) return spec.slice("git:".length);
|
|
6519
6988
|
return spec;
|
|
6520
6989
|
}
|
|
6521
|
-
function cachePathFor4(spec, cacheRoot) {
|
|
6522
|
-
const root = cacheRoot ? resolve9(cacheRoot) :
|
|
6523
|
-
|
|
6990
|
+
function cachePathFor4(spec, cacheRoot, immutableIdentity) {
|
|
6991
|
+
const root = cacheRoot ? resolve9(cacheRoot) : join26(homedir4(), ".agentwheel", "cache");
|
|
6992
|
+
const sourceIdentity = createHash6("sha256").update(spec).digest("hex");
|
|
6993
|
+
const snapshotIdentity = immutableIdentity ? `-${immutableIdentity.toLowerCase()}` : "";
|
|
6994
|
+
return join26(root, "skillkit", `${packageSlug(spec)}-${sourceIdentity}${snapshotIdentity}`);
|
|
6524
6995
|
}
|
|
6525
6996
|
function packageSlug(spec) {
|
|
6526
6997
|
return spec.replace(/^[a-z]+:\/\//i, "").replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "source";
|
|
@@ -6530,10 +7001,40 @@ function mapSeverity(severity) {
|
|
|
6530
7001
|
if (severity === "medium" || severity === "low") return "warning";
|
|
6531
7002
|
return "info";
|
|
6532
7003
|
}
|
|
7004
|
+
function isDirectoryNotEmpty(error) {
|
|
7005
|
+
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOTEMPTY";
|
|
7006
|
+
}
|
|
7007
|
+
function immutableCommit(ref) {
|
|
7008
|
+
return ref && /^[0-9a-f]{7,40}$/i.test(ref) ? ref.toLowerCase() : void 0;
|
|
7009
|
+
}
|
|
7010
|
+
async function resolveCloneIdentity(result) {
|
|
7011
|
+
if (result.resolvedCommit && /^[0-9a-f]{40}$/i.test(result.resolvedCommit)) {
|
|
7012
|
+
const commit = result.resolvedCommit.toLowerCase();
|
|
7013
|
+
return { cacheKey: commit, commit };
|
|
7014
|
+
}
|
|
7015
|
+
const checkoutRoot = result.tempRoot ?? result.path;
|
|
7016
|
+
if (!checkoutRoot) throw new Error("SkillKit provider clone has no checkout path");
|
|
7017
|
+
try {
|
|
7018
|
+
const { stdout } = await execFileAsync5("git", ["-C", checkoutRoot, "rev-parse", "HEAD"]);
|
|
7019
|
+
const commit = stdout.trim().toLowerCase();
|
|
7020
|
+
if (!/^[0-9a-f]{40}$/.test(commit)) throw new Error(`invalid commit '${commit}'`);
|
|
7021
|
+
return { cacheKey: commit, commit };
|
|
7022
|
+
} catch {
|
|
7023
|
+
return { cacheKey: `content-${await hashPath(result.path)}` };
|
|
7024
|
+
}
|
|
7025
|
+
}
|
|
7026
|
+
async function checkoutCommit(root, commit) {
|
|
7027
|
+
try {
|
|
7028
|
+
await execFileAsync5("git", ["-C", root, "checkout", "--detach", commit]);
|
|
7029
|
+
} catch {
|
|
7030
|
+
await execFileAsync5("git", ["-C", root, "fetch", "origin", commit]);
|
|
7031
|
+
await execFileAsync5("git", ["-C", root, "checkout", "--detach", commit]);
|
|
7032
|
+
}
|
|
7033
|
+
}
|
|
6533
7034
|
|
|
6534
7035
|
// src/source/vercel-skills.ts
|
|
6535
|
-
import { stat as
|
|
6536
|
-
import { basename as basename15, join as
|
|
7036
|
+
import { stat as stat6 } from "fs/promises";
|
|
7037
|
+
import { basename as basename15, join as join27, relative as relative5, resolve as resolve10 } from "path";
|
|
6537
7038
|
var VercelSkillsSourceDriver = class {
|
|
6538
7039
|
name = "vercel-skills";
|
|
6539
7040
|
git = new GitSourceDriver();
|
|
@@ -6541,7 +7042,7 @@ var VercelSkillsSourceDriver = class {
|
|
|
6541
7042
|
const parsed = parseVercelSource(source);
|
|
6542
7043
|
if (parsed.kind === "local") {
|
|
6543
7044
|
const resolvedPath = resolve10(parsed.path);
|
|
6544
|
-
if (!await pathExists(resolvedPath) || !(await
|
|
7045
|
+
if (!await pathExists(resolvedPath) || !(await stat6(resolvedPath)).isDirectory()) {
|
|
6545
7046
|
throw new Error(`Vercel skills local source not found: ${resolvedPath}`);
|
|
6546
7047
|
}
|
|
6547
7048
|
return {
|
|
@@ -6596,7 +7097,7 @@ var VercelSkillsSourceDriver = class {
|
|
|
6596
7097
|
};
|
|
6597
7098
|
async function resolveVercelSkillSubpath(root, subpath) {
|
|
6598
7099
|
if (!subpath) return root;
|
|
6599
|
-
const candidates = [
|
|
7100
|
+
const candidates = [join27(root, subpath), join27(root, "skills", subpath)];
|
|
6600
7101
|
for (const candidate of candidates) {
|
|
6601
7102
|
if (await pathExists(candidate)) return candidate;
|
|
6602
7103
|
}
|
|
@@ -6666,14 +7167,14 @@ function getSourceDriver(name = "local") {
|
|
|
6666
7167
|
}
|
|
6667
7168
|
|
|
6668
7169
|
// src/staging/staging.ts
|
|
6669
|
-
import { chmod, cp as cp5, mkdir as
|
|
6670
|
-
import { basename as basename19, dirname as
|
|
7170
|
+
import { chmod, cp as cp5, mkdir as mkdir19, mkdtemp as mkdtemp3, readdir as readdir6, stat as stat9 } from "fs/promises";
|
|
7171
|
+
import { basename as basename19, dirname as dirname24, join as join31, relative as relative7, resolve as resolve12, sep as sep2 } from "path";
|
|
6671
7172
|
import { tmpdir as tmpdir4 } from "os";
|
|
6672
7173
|
|
|
6673
7174
|
// src/compose/markdown.ts
|
|
6674
|
-
import { createHash as
|
|
6675
|
-
import { readdir as
|
|
6676
|
-
import { basename as basename16, dirname as
|
|
7175
|
+
import { createHash as createHash7 } from "crypto";
|
|
7176
|
+
import { readdir as readdir4, readFile as readFile21, stat as stat7, writeFile as writeFile17 } from "fs/promises";
|
|
7177
|
+
import { basename as basename16, dirname as dirname21, extname as extname3, join as join28, relative as relative6, resolve as resolve11, sep } from "path";
|
|
6677
7178
|
var includePattern = /<!--\s*openpack:include(\?)?\s+([^>]+?)\s*-->/g;
|
|
6678
7179
|
var escapedIncludePattern = /<!--\s*openpack\\:include(\?)?\s+([^>]+?)\s*-->/g;
|
|
6679
7180
|
var generatedPattern = /<!--\s*(?:BEGIN|END)\s+openpack:include\b/;
|
|
@@ -6711,7 +7212,7 @@ async function validateMarkdownIncludes(artifacts, packageRoot, options = {}) {
|
|
|
6711
7212
|
}
|
|
6712
7213
|
}
|
|
6713
7214
|
async function expandFile(file, packageRoot, appendEntries, artifactPaths, options) {
|
|
6714
|
-
const raw = await
|
|
7215
|
+
const raw = await readFile21(file, "utf8");
|
|
6715
7216
|
const owner = ownerSelector(packageRoot, file, options.nodeId);
|
|
6716
7217
|
const expanded = await expandContent(raw, packageRoot, [owner], artifactPaths, options);
|
|
6717
7218
|
let content = expanded.content;
|
|
@@ -6800,11 +7301,11 @@ async function expandInclude(selector, packageRoot, artifactPaths, options) {
|
|
|
6800
7301
|
if (options.optional) return void 0;
|
|
6801
7302
|
throw new Error(`OpenPack include not found: ${displaySelector}`);
|
|
6802
7303
|
}
|
|
6803
|
-
const stats = await
|
|
7304
|
+
const stats = await stat7(sourcePath);
|
|
6804
7305
|
if (!stats.isFile()) {
|
|
6805
7306
|
throw new Error(`OpenPack include is not a file: ${displaySelector}`);
|
|
6806
7307
|
}
|
|
6807
|
-
const raw = sourceContent ?? await
|
|
7308
|
+
const raw = sourceContent ?? await readFile21(sourcePath, "utf8");
|
|
6808
7309
|
const { optional: _optional, markers: _markers, chain: _chain, ...childOptions } = options;
|
|
6809
7310
|
const expanded = await expandContent(raw, includePackageRoot, [...options.chain, displaySelector], includeArtifactPaths, {
|
|
6810
7311
|
...childOptions,
|
|
@@ -6871,7 +7372,7 @@ function resolvePackageSelector(packageRoot, selector) {
|
|
|
6871
7372
|
}
|
|
6872
7373
|
async function markdownFilesForArtifact(artifact) {
|
|
6873
7374
|
const root = artifact.stagedPath ?? artifact.sourcePath;
|
|
6874
|
-
const stats = await
|
|
7375
|
+
const stats = await stat7(root);
|
|
6875
7376
|
if (stats.isFile()) return extname3(root).toLowerCase() === ".md" ? [root] : [];
|
|
6876
7377
|
if (!stats.isDirectory()) return [];
|
|
6877
7378
|
return listMarkdownFiles(root);
|
|
@@ -6879,8 +7380,8 @@ async function markdownFilesForArtifact(artifact) {
|
|
|
6879
7380
|
async function listMarkdownFiles(root) {
|
|
6880
7381
|
const out = [];
|
|
6881
7382
|
async function walk2(dir) {
|
|
6882
|
-
for (const entry of (await
|
|
6883
|
-
const full =
|
|
7383
|
+
for (const entry of (await readdir4(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7384
|
+
const full = join28(dir, entry.name);
|
|
6884
7385
|
if (entry.isDirectory()) {
|
|
6885
7386
|
await walk2(full);
|
|
6886
7387
|
} else if (entry.isFile() && extname3(entry.name).toLowerCase() === ".md") {
|
|
@@ -6894,7 +7395,7 @@ async function listMarkdownFiles(root) {
|
|
|
6894
7395
|
function composeEntriesForFile(artifact, file) {
|
|
6895
7396
|
if (!artifact.compose?.length) return [];
|
|
6896
7397
|
if (artifact.kind === "file") return [resolve11(artifact.stagedPath ?? artifact.sourcePath), resolve11(file)].every(Boolean) && resolve11(artifact.stagedPath ?? artifact.sourcePath) === resolve11(file) ? artifact.compose : [];
|
|
6897
|
-
return basename16(file) === "SKILL.md" &&
|
|
7398
|
+
return basename16(file) === "SKILL.md" && dirname21(file) === resolve11(artifact.stagedPath ?? artifact.sourcePath) ? artifact.compose : [];
|
|
6898
7399
|
}
|
|
6899
7400
|
function orderedForExpansion(artifacts) {
|
|
6900
7401
|
return [...artifacts].sort((a, b) => Number(a.type === "fragments") - Number(b.type === "fragments"));
|
|
@@ -6925,7 +7426,7 @@ function cleanSelector(value) {
|
|
|
6925
7426
|
return value.trim().replace(/\s+/g, " ");
|
|
6926
7427
|
}
|
|
6927
7428
|
function sha256(content) {
|
|
6928
|
-
return
|
|
7429
|
+
return createHash7("sha256").update(content).digest("hex");
|
|
6929
7430
|
}
|
|
6930
7431
|
function uniqueComposedFrom(entries) {
|
|
6931
7432
|
if (entries.length === 0) return [];
|
|
@@ -6940,8 +7441,8 @@ function artifactPathMap(artifacts) {
|
|
|
6940
7441
|
}
|
|
6941
7442
|
|
|
6942
7443
|
// src/staging/customize.ts
|
|
6943
|
-
import { cp as cp4, mkdir as
|
|
6944
|
-
import { dirname as
|
|
7444
|
+
import { cp as cp4, mkdir as mkdir17, readdir as readdir5, readFile as readFile22, writeFile as writeFile18 } from "fs/promises";
|
|
7445
|
+
import { dirname as dirname22, join as join29 } from "path";
|
|
6945
7446
|
async function applyCustomizations(artifacts, options) {
|
|
6946
7447
|
let next = [...artifacts];
|
|
6947
7448
|
next = await applyReplacements2(next, options, "override", installableArtifactTypes());
|
|
@@ -6957,15 +7458,15 @@ async function applyFragmentCustomizations(artifacts, options) {
|
|
|
6957
7458
|
return next.sort((a, b) => `${a.type}:${a.name}:${a.channel}`.localeCompare(`${b.type}:${b.name}:${b.channel}`));
|
|
6958
7459
|
}
|
|
6959
7460
|
async function applyInstructionOverlay(artifacts, options) {
|
|
6960
|
-
const overlayPath =
|
|
7461
|
+
const overlayPath = join29(options.workspaceRoot, ".agentwheel", "overlays", options.adapter.name, "instructions.local.md");
|
|
6961
7462
|
if (!await pathExists(overlayPath)) return artifacts;
|
|
6962
7463
|
const index = artifacts.findIndex((artifact2) => artifact2.type === "instructions");
|
|
6963
7464
|
if (index < 0) return artifacts;
|
|
6964
7465
|
const artifact = artifacts[index];
|
|
6965
|
-
const managed = await
|
|
6966
|
-
const local = await
|
|
6967
|
-
const composedPath =
|
|
6968
|
-
await
|
|
7466
|
+
const managed = await readFile22(artifact.stagedPath ?? artifact.sourcePath, "utf8");
|
|
7467
|
+
const local = await readFile22(overlayPath, "utf8");
|
|
7468
|
+
const composedPath = join29(options.stageRoot, ".agentwheel-composed", "instructions", "AGENTS.md");
|
|
7469
|
+
await mkdir17(dirname22(composedPath), { recursive: true });
|
|
6969
7470
|
await writeFile18(
|
|
6970
7471
|
composedPath,
|
|
6971
7472
|
[
|
|
@@ -6992,19 +7493,19 @@ async function applyInstructionOverlay(artifacts, options) {
|
|
|
6992
7493
|
return [...artifacts.slice(0, index), updated, ...artifacts.slice(index + 1)];
|
|
6993
7494
|
}
|
|
6994
7495
|
async function applyAdditions(artifacts, options) {
|
|
6995
|
-
const additionsRoot =
|
|
6996
|
-
const rulesRoot =
|
|
7496
|
+
const additionsRoot = join29(options.workspaceRoot, ".agentwheel", "additions");
|
|
7497
|
+
const rulesRoot = join29(additionsRoot, "rules");
|
|
6997
7498
|
if (!await pathExists(rulesRoot)) return artifacts;
|
|
6998
7499
|
const additions = [];
|
|
6999
7500
|
for (const entry of await sortedDirEntries2(rulesRoot)) {
|
|
7000
|
-
const full =
|
|
7501
|
+
const full = join29(rulesRoot, entry.name);
|
|
7001
7502
|
if (!entry.isFile()) continue;
|
|
7002
7503
|
additions.push({
|
|
7003
7504
|
type: "rules",
|
|
7004
7505
|
name: entry.name,
|
|
7005
7506
|
sourcePath: full,
|
|
7006
7507
|
stagedPath: full,
|
|
7007
|
-
relativePath:
|
|
7508
|
+
relativePath: join29("additions", "rules", entry.name),
|
|
7008
7509
|
kind: "file",
|
|
7009
7510
|
hash: await hashPath(full),
|
|
7010
7511
|
packageName: options.packageName,
|
|
@@ -7028,17 +7529,17 @@ async function applyReplacements2(artifacts, options, channel, artifactTypes) {
|
|
|
7028
7529
|
);
|
|
7029
7530
|
}
|
|
7030
7531
|
for (const type of artifactTypes) {
|
|
7031
|
-
const typeRoot =
|
|
7532
|
+
const typeRoot = join29(root, type);
|
|
7032
7533
|
if (!await pathExists(typeRoot)) continue;
|
|
7033
7534
|
for (const entry of await sortedDirEntries2(typeRoot)) {
|
|
7034
7535
|
const artifactMapKey = `${type}:${entry.name}`;
|
|
7035
7536
|
if (seen.has(artifactMapKey)) continue;
|
|
7036
7537
|
seen.add(artifactMapKey);
|
|
7037
|
-
const full =
|
|
7538
|
+
const full = join29(typeRoot, entry.name);
|
|
7038
7539
|
const artifactKind = entry.isDirectory() ? "dir" : "file";
|
|
7039
7540
|
const existing = byKey.get(artifactMapKey);
|
|
7040
|
-
const stagedPath =
|
|
7041
|
-
await
|
|
7541
|
+
const stagedPath = join29(options.stageRoot, ".agentwheel-composed", channel, type, entry.name);
|
|
7542
|
+
await mkdir17(dirname22(stagedPath), { recursive: true });
|
|
7042
7543
|
await cp4(full, stagedPath, { recursive: artifactKind === "dir", dereference: true });
|
|
7043
7544
|
byKey.set(artifactMapKey, {
|
|
7044
7545
|
...existing,
|
|
@@ -7046,7 +7547,7 @@ async function applyReplacements2(artifacts, options, channel, artifactTypes) {
|
|
|
7046
7547
|
name: entry.name,
|
|
7047
7548
|
sourcePath: full,
|
|
7048
7549
|
stagedPath,
|
|
7049
|
-
relativePath: existing?.relativePath ??
|
|
7550
|
+
relativePath: existing?.relativePath ?? join29(type, entry.name),
|
|
7050
7551
|
kind: artifactKind,
|
|
7051
7552
|
hash: await hashPath(stagedPath),
|
|
7052
7553
|
packageName,
|
|
@@ -7061,13 +7562,13 @@ function replacementRoots(options, channel) {
|
|
|
7061
7562
|
const stateDir = channel === "override" ? "overrides" : "ejected";
|
|
7062
7563
|
const roots = [];
|
|
7063
7564
|
if (options.graphNodeId) {
|
|
7064
|
-
roots.push({ root:
|
|
7565
|
+
roots.push({ root: join29(options.workspaceRoot, ".agentwheel", stateDir, ...options.graphNodeId.split("/")), kind: "node" });
|
|
7065
7566
|
}
|
|
7066
7567
|
if (options.packageName && options.packageVersion) {
|
|
7067
|
-
roots.push({ root:
|
|
7568
|
+
roots.push({ root: join29(options.workspaceRoot, ".agentwheel", stateDir, ...`${options.packageName}@${options.packageVersion}`.split("/")), kind: "version" });
|
|
7068
7569
|
}
|
|
7069
7570
|
if (options.packageName) {
|
|
7070
|
-
roots.push({ root:
|
|
7571
|
+
roots.push({ root: join29(options.workspaceRoot, ".agentwheel", stateDir, ...options.packageName.split("/")), kind: "package" });
|
|
7071
7572
|
}
|
|
7072
7573
|
return roots;
|
|
7073
7574
|
}
|
|
@@ -7078,12 +7579,12 @@ function installableArtifactTypes() {
|
|
|
7078
7579
|
return ["instructions", "rules", "skills", "commands", "subagents", "mcp", "hooks", "settings", "plugins"];
|
|
7079
7580
|
}
|
|
7080
7581
|
async function sortedDirEntries2(path) {
|
|
7081
|
-
return (await
|
|
7582
|
+
return (await readdir5(path, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
7082
7583
|
}
|
|
7083
7584
|
|
|
7084
7585
|
// src/staging/claude-subagents.ts
|
|
7085
|
-
import { mkdir as
|
|
7086
|
-
import { basename as basename18, dirname as
|
|
7586
|
+
import { mkdir as mkdir18, readFile as readFile23, writeFile as writeFile19 } from "fs/promises";
|
|
7587
|
+
import { basename as basename18, dirname as dirname23, join as join30 } from "path";
|
|
7087
7588
|
async function renderClaudeSubagents(artifacts, stageRoot, adapter) {
|
|
7088
7589
|
if (adapter?.name !== "claude") return artifacts;
|
|
7089
7590
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -7105,16 +7606,16 @@ async function renderClaudeSubagents(artifacts, stageRoot, adapter) {
|
|
|
7105
7606
|
async function renderClaudeSubagent(artifact, stageRoot) {
|
|
7106
7607
|
const sourcePath = artifact.stagedPath ?? artifact.sourcePath;
|
|
7107
7608
|
const agentName = claudeAgentName(artifact);
|
|
7108
|
-
const markdownPath = artifact.kind === "dir" ?
|
|
7609
|
+
const markdownPath = artifact.kind === "dir" ? join30(sourcePath, "AGENTS.md") : sourcePath;
|
|
7109
7610
|
if (artifact.kind === "dir" && !await pathExists(markdownPath)) {
|
|
7110
7611
|
throw new Error(`Claude subagent directory ${artifact.relativePath} must contain AGENTS.md.`);
|
|
7111
7612
|
}
|
|
7112
7613
|
if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md") && !sourcePath.toLowerCase().endsWith(".md")) {
|
|
7113
7614
|
throw new Error(`Claude subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
|
|
7114
7615
|
}
|
|
7115
|
-
const content = await
|
|
7116
|
-
const renderedPath =
|
|
7117
|
-
await
|
|
7616
|
+
const content = await readFile23(markdownPath, "utf8");
|
|
7617
|
+
const renderedPath = join30(stageRoot, ".agentwheel-rendered", "claude-subagents", `${agentName}.md`);
|
|
7618
|
+
await mkdir18(dirname23(renderedPath), { recursive: true });
|
|
7118
7619
|
await writeFile19(renderedPath, content.endsWith("\n") ? content : `${content}
|
|
7119
7620
|
`, "utf8");
|
|
7120
7621
|
return {
|
|
@@ -7122,7 +7623,7 @@ async function renderClaudeSubagent(artifact, stageRoot) {
|
|
|
7122
7623
|
name: `${agentName}.md`,
|
|
7123
7624
|
sourcePath: renderedPath,
|
|
7124
7625
|
stagedPath: renderedPath,
|
|
7125
|
-
relativePath:
|
|
7626
|
+
relativePath: join30("subagents", `${agentName}.md`),
|
|
7126
7627
|
kind: "file",
|
|
7127
7628
|
hash: await hashPath(renderedPath)
|
|
7128
7629
|
};
|
|
@@ -7138,18 +7639,23 @@ async function stageSource(driver, source, options = {}) {
|
|
|
7138
7639
|
}
|
|
7139
7640
|
async function stageSourceRaw(driver, source, options = {}) {
|
|
7140
7641
|
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(source, options))));
|
|
7141
|
-
|
|
7642
|
+
try {
|
|
7643
|
+
const staged = await stageResolvedSourceRaw(driver, resolved);
|
|
7644
|
+
return { ...staged, source: { ...staged.source, cacheLeasePath: void 0 } };
|
|
7645
|
+
} finally {
|
|
7646
|
+
await releaseGitSnapshotLease(resolved.cacheLeasePath);
|
|
7647
|
+
}
|
|
7142
7648
|
}
|
|
7143
7649
|
async function stageResolvedSourceRaw(driver, resolved) {
|
|
7144
7650
|
const artifacts = await driver.list(resolved);
|
|
7145
7651
|
return stageResolvedArtifactsRaw(resolved, artifacts);
|
|
7146
7652
|
}
|
|
7147
7653
|
async function stageResolvedArtifactsRaw(resolved, artifacts) {
|
|
7148
|
-
const root = await mkdtemp3(
|
|
7654
|
+
const root = await mkdtemp3(join31(tmpdir4(), "agentwheel-stage-"));
|
|
7149
7655
|
const stagedArtifacts = [];
|
|
7150
7656
|
for (const artifact of artifacts) {
|
|
7151
|
-
const stagedPath =
|
|
7152
|
-
await
|
|
7657
|
+
const stagedPath = join31(root, artifact.relativePath);
|
|
7658
|
+
await mkdir19(dirname24(stagedPath), { recursive: true });
|
|
7153
7659
|
await cp5(artifact.sourcePath, stagedPath, {
|
|
7154
7660
|
recursive: artifact.kind === "dir",
|
|
7155
7661
|
dereference: true,
|
|
@@ -7206,6 +7712,7 @@ async function renderStagedBundle(bundle, options = {}) {
|
|
|
7206
7712
|
mode: resolved.mode ?? "pinned",
|
|
7207
7713
|
requestedRef: resolved.requestedRef,
|
|
7208
7714
|
resolvedCommit: resolved.resolvedCommit,
|
|
7715
|
+
cacheIdentity: resolved.cacheIdentity,
|
|
7209
7716
|
sourceHash: resolved.sourceHash,
|
|
7210
7717
|
generatedAt,
|
|
7211
7718
|
artifacts: finalArtifacts.map((artifact) => ({
|
|
@@ -7236,16 +7743,16 @@ async function composeAssets(artifact, packageRoot, stagedPath) {
|
|
|
7236
7743
|
}
|
|
7237
7744
|
for (const asset of artifact.assets) {
|
|
7238
7745
|
const source = resolvePackagePath(packageRoot, asset.from);
|
|
7239
|
-
const dest =
|
|
7746
|
+
const dest = join31(stagedPath, asset.into);
|
|
7240
7747
|
await copyAsset(asset, source, dest);
|
|
7241
7748
|
}
|
|
7242
7749
|
}
|
|
7243
7750
|
async function copyAsset(asset, source, dest) {
|
|
7244
|
-
const sourceStats = await
|
|
7751
|
+
const sourceStats = await stat9(source);
|
|
7245
7752
|
if (sourceStats.isFile()) {
|
|
7246
7753
|
if (matchesAny(basename19(source), asset.include)) {
|
|
7247
|
-
await
|
|
7248
|
-
await copyAssetFile(source,
|
|
7754
|
+
await mkdir19(dest, { recursive: true });
|
|
7755
|
+
await copyAssetFile(source, join31(dest, basename19(source)), asset);
|
|
7249
7756
|
}
|
|
7250
7757
|
return;
|
|
7251
7758
|
}
|
|
@@ -7253,7 +7760,7 @@ async function copyAsset(asset, source, dest) {
|
|
|
7253
7760
|
throw new Error(`Asset include source is not a file or directory: ${source}`);
|
|
7254
7761
|
}
|
|
7255
7762
|
if (!asset.include?.length) {
|
|
7256
|
-
await
|
|
7763
|
+
await mkdir19(dirname24(dest), { recursive: true });
|
|
7257
7764
|
await cp5(source, dest, { recursive: true, dereference: true });
|
|
7258
7765
|
if (asset.mode === "copy") await normalizeCopiedModes(dest);
|
|
7259
7766
|
return;
|
|
@@ -7261,11 +7768,11 @@ async function copyAsset(asset, source, dest) {
|
|
|
7261
7768
|
for (const file of await listFiles(source)) {
|
|
7262
7769
|
const rel = relative7(source, file).replaceAll("\\", "/");
|
|
7263
7770
|
if (!matchesAny(rel, asset.include) && !matchesAny(basename19(file), asset.include)) continue;
|
|
7264
|
-
await copyAssetFile(file,
|
|
7771
|
+
await copyAssetFile(file, join31(dest, rel), asset);
|
|
7265
7772
|
}
|
|
7266
7773
|
}
|
|
7267
7774
|
async function copyAssetFile(source, dest, asset) {
|
|
7268
|
-
await
|
|
7775
|
+
await mkdir19(dirname24(dest), { recursive: true });
|
|
7269
7776
|
await cp5(source, dest, { dereference: true });
|
|
7270
7777
|
if (asset.mode === "copy") await chmod(dest, 420);
|
|
7271
7778
|
}
|
|
@@ -7280,8 +7787,8 @@ function resolvePackagePath(packageRoot, path) {
|
|
|
7280
7787
|
async function listFiles(root) {
|
|
7281
7788
|
const out = [];
|
|
7282
7789
|
async function walk2(dir) {
|
|
7283
|
-
for (const entry of (await
|
|
7284
|
-
const full =
|
|
7790
|
+
for (const entry of (await readdir6(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7791
|
+
const full = join31(dir, entry.name);
|
|
7285
7792
|
if (entry.isDirectory()) {
|
|
7286
7793
|
await walk2(full);
|
|
7287
7794
|
} else if (entry.isFile()) {
|
|
@@ -7293,14 +7800,14 @@ async function listFiles(root) {
|
|
|
7293
7800
|
return out;
|
|
7294
7801
|
}
|
|
7295
7802
|
async function normalizeCopiedModes(path) {
|
|
7296
|
-
const stats = await
|
|
7803
|
+
const stats = await stat9(path);
|
|
7297
7804
|
if (stats.isFile()) {
|
|
7298
7805
|
await chmod(path, 420);
|
|
7299
7806
|
return;
|
|
7300
7807
|
}
|
|
7301
7808
|
if (!stats.isDirectory()) return;
|
|
7302
|
-
for (const entry of await
|
|
7303
|
-
await normalizeCopiedModes(
|
|
7809
|
+
for (const entry of await readdir6(path, { withFileTypes: true })) {
|
|
7810
|
+
await normalizeCopiedModes(join31(path, entry.name));
|
|
7304
7811
|
}
|
|
7305
7812
|
}
|
|
7306
7813
|
function matchesAny(path, patterns) {
|
|
@@ -7313,10 +7820,10 @@ function matchesGlob(path, pattern) {
|
|
|
7313
7820
|
}
|
|
7314
7821
|
|
|
7315
7822
|
// src/model/workspace.ts
|
|
7316
|
-
import { readFile as
|
|
7823
|
+
import { readFile as readFile24 } from "fs/promises";
|
|
7317
7824
|
import { homedir as homedir5 } from "os";
|
|
7318
|
-
import { dirname as
|
|
7319
|
-
import { z as
|
|
7825
|
+
import { dirname as dirname25, join as join32, resolve as resolve13 } from "path";
|
|
7826
|
+
import { z as z7 } from "zod";
|
|
7320
7827
|
|
|
7321
7828
|
// src/resolve/semver.ts
|
|
7322
7829
|
var semverPattern = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
@@ -7415,14 +7922,14 @@ function compareSemver(a, b) {
|
|
|
7415
7922
|
}
|
|
7416
7923
|
|
|
7417
7924
|
// src/model/workspace.ts
|
|
7418
|
-
var artifactSelectorListSchema =
|
|
7419
|
-
var workspaceSelectionImportSchema =
|
|
7420
|
-
export:
|
|
7925
|
+
var artifactSelectorListSchema = z7.array(z7.string().min(1));
|
|
7926
|
+
var workspaceSelectionImportSchema = z7.object({
|
|
7927
|
+
export: z7.string().min(1),
|
|
7421
7928
|
add: artifactSelectorListSchema.optional(),
|
|
7422
7929
|
exclude: artifactSelectorListSchema.optional()
|
|
7423
7930
|
}).strict();
|
|
7424
|
-
var workspaceSelectionExportSchema =
|
|
7425
|
-
extends:
|
|
7931
|
+
var workspaceSelectionExportSchema = z7.object({
|
|
7932
|
+
extends: z7.string().min(1).optional(),
|
|
7426
7933
|
select: artifactSelectorListSchema.optional(),
|
|
7427
7934
|
add: artifactSelectorListSchema.optional(),
|
|
7428
7935
|
exclude: artifactSelectorListSchema.optional()
|
|
@@ -7442,29 +7949,29 @@ var workspaceSelectionExportSchema = z6.object({
|
|
|
7442
7949
|
});
|
|
7443
7950
|
}
|
|
7444
7951
|
});
|
|
7445
|
-
var workspaceExportsSchema =
|
|
7446
|
-
selections:
|
|
7952
|
+
var workspaceExportsSchema = z7.object({
|
|
7953
|
+
selections: z7.record(z7.string().min(1), workspaceSelectionExportSchema).default({})
|
|
7447
7954
|
}).strict();
|
|
7448
|
-
var workspacePackageBaseSchema =
|
|
7449
|
-
name:
|
|
7450
|
-
source:
|
|
7451
|
-
driver:
|
|
7452
|
-
adapter:
|
|
7453
|
-
adapterConfig:
|
|
7454
|
-
adapterModule:
|
|
7455
|
-
adapterCodeHash:
|
|
7955
|
+
var workspacePackageBaseSchema = z7.object({
|
|
7956
|
+
name: z7.string().min(1),
|
|
7957
|
+
source: z7.string().min(1),
|
|
7958
|
+
driver: z7.enum(["local", "git", "skillkit", "vercel-skills", "mcp-registry", "clawhub"]).default("local"),
|
|
7959
|
+
adapter: z7.string().min(1).default("openclaw"),
|
|
7960
|
+
adapterConfig: z7.string().min(1).optional(),
|
|
7961
|
+
adapterModule: z7.string().min(1).optional(),
|
|
7962
|
+
adapterCodeHash: z7.string().min(16).optional(),
|
|
7456
7963
|
installationType: installationTypeSchema.optional(),
|
|
7457
|
-
mode:
|
|
7458
|
-
version:
|
|
7964
|
+
mode: z7.enum(["pinned", "tracking"]).default("pinned"),
|
|
7965
|
+
version: z7.string().min(1).refine(isSupportedVersionRange, {
|
|
7459
7966
|
message: "Version policy must be an exact semver, ~range, ^range, comparator range, or *"
|
|
7460
7967
|
}).optional(),
|
|
7461
|
-
requestedRef:
|
|
7462
|
-
select:
|
|
7463
|
-
skills:
|
|
7464
|
-
withSuggestions:
|
|
7465
|
-
suggestions:
|
|
7466
|
-
aliases:
|
|
7467
|
-
overrides:
|
|
7968
|
+
requestedRef: z7.string().min(1).optional(),
|
|
7969
|
+
select: z7.array(z7.string().min(1)).optional(),
|
|
7970
|
+
skills: z7.array(z7.string().min(1)).optional(),
|
|
7971
|
+
withSuggestions: z7.boolean().optional(),
|
|
7972
|
+
suggestions: z7.array(z7.string().min(1)).optional(),
|
|
7973
|
+
aliases: z7.record(z7.string(), z7.string().min(1)).optional(),
|
|
7974
|
+
overrides: z7.array(z7.string().min(1)).optional()
|
|
7468
7975
|
});
|
|
7469
7976
|
var workspacePackageSchema = workspacePackageBaseSchema.extend({
|
|
7470
7977
|
selection: workspaceSelectionImportSchema.optional()
|
|
@@ -7478,31 +7985,33 @@ var workspacePackageSchema = workspacePackageBaseSchema.extend({
|
|
|
7478
7985
|
}
|
|
7479
7986
|
});
|
|
7480
7987
|
var workspacePackageV1Schema = workspacePackageBaseSchema.extend({
|
|
7481
|
-
selection:
|
|
7988
|
+
selection: z7.never().optional()
|
|
7482
7989
|
});
|
|
7483
|
-
var commandSchema =
|
|
7484
|
-
var commandListSchema =
|
|
7485
|
-
var
|
|
7486
|
-
|
|
7487
|
-
|
|
7488
|
-
|
|
7489
|
-
|
|
7990
|
+
var commandSchema = z7.array(z7.string().min(1)).min(1);
|
|
7991
|
+
var commandListSchema = z7.array(commandSchema).min(1).optional();
|
|
7992
|
+
var installStateKeySchema = z7.string().min(1).regex(/^[a-z0-9][a-z0-9._-]*$/i);
|
|
7993
|
+
var workspaceProfileRuntimeSchema = z7.object({
|
|
7994
|
+
agent: z7.string().min(1).optional(),
|
|
7995
|
+
adapter: z7.string().min(1).default("openclaw"),
|
|
7996
|
+
adapterConfig: z7.string().min(1).optional(),
|
|
7997
|
+
adapterModule: z7.string().min(1).optional(),
|
|
7490
7998
|
installationType: installationTypeSchema.optional(),
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7999
|
+
stateKey: installStateKeySchema.optional(),
|
|
8000
|
+
targetRoot: z7.string().min(1).optional(),
|
|
8001
|
+
executePlugins: z7.boolean().optional(),
|
|
8002
|
+
reloadRuntimes: z7.boolean().optional(),
|
|
7494
8003
|
reloadCommands: commandListSchema
|
|
7495
8004
|
});
|
|
7496
|
-
var workspaceProfileMemberSchema =
|
|
7497
|
-
id:
|
|
7498
|
-
workspace:
|
|
7499
|
-
profile:
|
|
7500
|
-
transport:
|
|
7501
|
-
host:
|
|
7502
|
-
user:
|
|
7503
|
-
port:
|
|
7504
|
-
identityFile:
|
|
7505
|
-
refreshTtlSeconds:
|
|
8005
|
+
var workspaceProfileMemberSchema = z7.object({
|
|
8006
|
+
id: z7.string().min(1).regex(/^[a-z0-9][a-z0-9._-]*$/i),
|
|
8007
|
+
workspace: z7.string().min(1),
|
|
8008
|
+
profile: z7.string().min(1),
|
|
8009
|
+
transport: z7.enum(["local", "ssh"]).default("local"),
|
|
8010
|
+
host: z7.string().min(1).optional(),
|
|
8011
|
+
user: z7.string().min(1).optional(),
|
|
8012
|
+
port: z7.number().int().positive().optional(),
|
|
8013
|
+
identityFile: z7.string().min(1).optional(),
|
|
8014
|
+
refreshTtlSeconds: z7.number().int().positive().optional()
|
|
7506
8015
|
}).strict().superRefine((member, ctx) => {
|
|
7507
8016
|
if (member.transport === "ssh" && !member.host) {
|
|
7508
8017
|
ctx.addIssue({ code: "custom", path: ["host"], message: "SSH profile members require host" });
|
|
@@ -7511,14 +8020,14 @@ var workspaceProfileMemberSchema = z6.object({
|
|
|
7511
8020
|
ctx.addIssue({ code: "custom", path: ["workspace"], message: "SSH profile member workspaces must be absolute" });
|
|
7512
8021
|
}
|
|
7513
8022
|
});
|
|
7514
|
-
var workspaceLeafProfileSchema =
|
|
7515
|
-
runtimes:
|
|
7516
|
-
members:
|
|
8023
|
+
var workspaceLeafProfileSchema = z7.object({
|
|
8024
|
+
runtimes: z7.array(workspaceProfileRuntimeSchema).min(1),
|
|
8025
|
+
members: z7.never().optional()
|
|
7517
8026
|
}).strict();
|
|
7518
|
-
var workspaceCompositeProfileSchema =
|
|
7519
|
-
members:
|
|
7520
|
-
runtimes:
|
|
7521
|
-
refreshTtlSeconds:
|
|
8027
|
+
var workspaceCompositeProfileSchema = z7.object({
|
|
8028
|
+
members: z7.array(workspaceProfileMemberSchema).min(1),
|
|
8029
|
+
runtimes: z7.never().optional(),
|
|
8030
|
+
refreshTtlSeconds: z7.number().int().positive().default(86400)
|
|
7522
8031
|
}).strict().superRefine((profile, ctx) => {
|
|
7523
8032
|
const seen = /* @__PURE__ */ new Set();
|
|
7524
8033
|
for (const [index, member] of profile.members.entries()) {
|
|
@@ -7528,31 +8037,32 @@ var workspaceCompositeProfileSchema = z6.object({
|
|
|
7528
8037
|
seen.add(member.id);
|
|
7529
8038
|
}
|
|
7530
8039
|
});
|
|
7531
|
-
var workspaceProfileSchema =
|
|
8040
|
+
var workspaceProfileSchema = z7.union([
|
|
7532
8041
|
workspaceLeafProfileSchema,
|
|
7533
8042
|
workspaceCompositeProfileSchema
|
|
7534
8043
|
]);
|
|
7535
|
-
var workspaceRegistrySchema =
|
|
7536
|
-
sources:
|
|
7537
|
-
ttlSeconds:
|
|
8044
|
+
var workspaceRegistrySchema = z7.object({
|
|
8045
|
+
sources: z7.array(z7.string().min(1)).optional(),
|
|
8046
|
+
ttlSeconds: z7.number().int().positive().optional()
|
|
7538
8047
|
}).default({});
|
|
7539
|
-
var workspaceTrustSchema =
|
|
7540
|
-
allow:
|
|
7541
|
-
acceptedSources:
|
|
7542
|
-
denyArtifactTypes:
|
|
7543
|
-
requireReviewForTransitive:
|
|
8048
|
+
var workspaceTrustSchema = z7.object({
|
|
8049
|
+
allow: z7.array(z7.string().min(1)).optional(),
|
|
8050
|
+
acceptedSources: z7.array(z7.string().min(1)).optional(),
|
|
8051
|
+
denyArtifactTypes: z7.array(artifactTypeSchema).optional(),
|
|
8052
|
+
requireReviewForTransitive: z7.boolean().optional()
|
|
7544
8053
|
}).default({});
|
|
7545
|
-
var workspaceAgentSchema =
|
|
7546
|
-
adapter:
|
|
7547
|
-
adapterConfig:
|
|
7548
|
-
adapterModule:
|
|
7549
|
-
root:
|
|
8054
|
+
var workspaceAgentSchema = z7.object({
|
|
8055
|
+
adapter: z7.string().min(1),
|
|
8056
|
+
adapterConfig: z7.string().min(1).optional(),
|
|
8057
|
+
adapterModule: z7.string().min(1).optional(),
|
|
8058
|
+
root: z7.string().min(1),
|
|
7550
8059
|
installationType: installationTypeSchema.optional(),
|
|
7551
|
-
|
|
7552
|
-
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
8060
|
+
stateKey: installStateKeySchema.optional(),
|
|
8061
|
+
transport: z7.enum(["local", "ssh"]).default("local"),
|
|
8062
|
+
host: z7.string().min(1).optional(),
|
|
8063
|
+
user: z7.string().min(1).optional(),
|
|
8064
|
+
port: z7.number().int().positive().optional(),
|
|
8065
|
+
identityFile: z7.string().min(1).optional(),
|
|
7556
8066
|
reloadCommands: commandListSchema
|
|
7557
8067
|
}).superRefine((agent, ctx) => {
|
|
7558
8068
|
if (agent.transport !== "ssh") return;
|
|
@@ -7564,34 +8074,34 @@ var workspaceAgentSchema = z6.object({
|
|
|
7564
8074
|
});
|
|
7565
8075
|
}
|
|
7566
8076
|
});
|
|
7567
|
-
var workspaceConfigBaseSchema =
|
|
7568
|
-
bootstrapSkills:
|
|
8077
|
+
var workspaceConfigBaseSchema = z7.object({
|
|
8078
|
+
bootstrapSkills: z7.boolean().optional(),
|
|
7569
8079
|
registry: workspaceRegistrySchema,
|
|
7570
8080
|
trust: workspaceTrustSchema,
|
|
7571
|
-
profiles:
|
|
7572
|
-
agents:
|
|
8081
|
+
profiles: z7.record(z7.string(), workspaceProfileSchema).default({}),
|
|
8082
|
+
agents: z7.record(z7.string(), workspaceAgentSchema).default({})
|
|
7573
8083
|
});
|
|
7574
8084
|
var workspaceConfigV1Schema = workspaceConfigBaseSchema.extend({
|
|
7575
|
-
schemaVersion:
|
|
7576
|
-
packages:
|
|
7577
|
-
exports:
|
|
8085
|
+
schemaVersion: z7.literal(1),
|
|
8086
|
+
packages: z7.array(workspacePackageV1Schema).default([]),
|
|
8087
|
+
exports: z7.never().optional()
|
|
7578
8088
|
});
|
|
7579
8089
|
var workspaceConfigV2Schema = workspaceConfigBaseSchema.extend({
|
|
7580
|
-
schemaVersion:
|
|
7581
|
-
packages:
|
|
8090
|
+
schemaVersion: z7.literal(2),
|
|
8091
|
+
packages: z7.array(workspacePackageSchema).default([]),
|
|
7582
8092
|
exports: workspaceExportsSchema.default({ selections: {} })
|
|
7583
8093
|
});
|
|
7584
|
-
var workspaceConfigSchema =
|
|
8094
|
+
var workspaceConfigSchema = z7.discriminatedUnion("schemaVersion", [
|
|
7585
8095
|
workspaceConfigV1Schema,
|
|
7586
8096
|
workspaceConfigV2Schema
|
|
7587
8097
|
]);
|
|
7588
8098
|
function workspaceConfigPath(workspaceRoot) {
|
|
7589
|
-
return
|
|
8099
|
+
return join32(workspaceRoot, ".agentwheel", "config.json");
|
|
7590
8100
|
}
|
|
7591
8101
|
async function readWorkspaceConfig(workspaceRoot) {
|
|
7592
8102
|
const path = workspaceConfigPath(workspaceRoot);
|
|
7593
8103
|
if (!await pathExists(path)) return emptyWorkspaceConfig();
|
|
7594
|
-
return workspaceConfigSchema.parse(JSON.parse(await
|
|
8104
|
+
return workspaceConfigSchema.parse(JSON.parse(await readFile24(path, "utf8")));
|
|
7595
8105
|
}
|
|
7596
8106
|
async function writeWorkspaceConfig(workspaceRoot, config) {
|
|
7597
8107
|
await writeJsonAtomic(workspaceConfigPath(workspaceRoot), workspaceConfigSchema.parse(config));
|
|
@@ -7604,13 +8114,13 @@ function upsertPackage(config, entry) {
|
|
|
7604
8114
|
return workspaceConfigSchema.parse({ ...parsed, packages });
|
|
7605
8115
|
}
|
|
7606
8116
|
function globalWorkspaceConfigPath(globalRoot = homedir5()) {
|
|
7607
|
-
return
|
|
8117
|
+
return join32(globalRoot, ".agentwheel", "config.json");
|
|
7608
8118
|
}
|
|
7609
8119
|
async function findWorkspaceRoot(start = process.cwd()) {
|
|
7610
8120
|
let current = resolve13(start);
|
|
7611
8121
|
while (true) {
|
|
7612
8122
|
if (await pathExists(workspaceConfigPath(current))) return current;
|
|
7613
|
-
const parent =
|
|
8123
|
+
const parent = dirname25(current);
|
|
7614
8124
|
if (parent === current) return resolve13(start);
|
|
7615
8125
|
current = parent;
|
|
7616
8126
|
}
|
|
@@ -7652,7 +8162,7 @@ function isCompositeWorkspaceProfile(profile) {
|
|
|
7652
8162
|
}
|
|
7653
8163
|
async function readConfigPath(path) {
|
|
7654
8164
|
if (!await pathExists(path)) return emptyWorkspaceConfig();
|
|
7655
|
-
return workspaceConfigSchema.parse(JSON.parse(await
|
|
8165
|
+
return workspaceConfigSchema.parse(JSON.parse(await readFile24(path, "utf8")));
|
|
7656
8166
|
}
|
|
7657
8167
|
function mergeWorkspaceTrust(global, project) {
|
|
7658
8168
|
return {
|
|
@@ -7667,21 +8177,21 @@ function sortedUnique2(values) {
|
|
|
7667
8177
|
}
|
|
7668
8178
|
|
|
7669
8179
|
// src/lifecycle/customization.ts
|
|
7670
|
-
import { appendFile, cp as cp6, mkdir as
|
|
7671
|
-
import { dirname as
|
|
8180
|
+
import { appendFile, cp as cp6, mkdir as mkdir20, rm as rm10 } from "fs/promises";
|
|
8181
|
+
import { dirname as dirname27, join as join35 } from "path";
|
|
7672
8182
|
|
|
7673
8183
|
// src/resolve/graph.ts
|
|
7674
|
-
import { createHash as
|
|
7675
|
-
import { mkdtemp as mkdtemp4, readdir as
|
|
8184
|
+
import { createHash as createHash9 } from "crypto";
|
|
8185
|
+
import { mkdtemp as mkdtemp4, readdir as readdir7, readFile as readFile27, stat as stat11 } from "fs/promises";
|
|
7676
8186
|
import { tmpdir as tmpdir5 } from "os";
|
|
7677
|
-
import { basename as basename20, extname as extname4, join as
|
|
8187
|
+
import { basename as basename20, extname as extname4, join as join34 } from "path";
|
|
7678
8188
|
|
|
7679
8189
|
// src/model/workspace-composition.ts
|
|
7680
|
-
import { createHash as
|
|
7681
|
-
import { readFile as
|
|
7682
|
-
import { z as
|
|
7683
|
-
var selectionSourceConfigSchema =
|
|
7684
|
-
schemaVersion:
|
|
8190
|
+
import { createHash as createHash8 } from "crypto";
|
|
8191
|
+
import { readFile as readFile25 } from "fs/promises";
|
|
8192
|
+
import { z as z8 } from "zod";
|
|
8193
|
+
var selectionSourceConfigSchema = z8.object({
|
|
8194
|
+
schemaVersion: z8.literal(2),
|
|
7685
8195
|
exports: workspaceExportsSchema
|
|
7686
8196
|
}).passthrough();
|
|
7687
8197
|
async function resolveSelectionImport(sourceRoot, sourceDriver, selection) {
|
|
@@ -7697,7 +8207,7 @@ async function resolveSelectionImport(sourceRoot, sourceDriver, selection) {
|
|
|
7697
8207
|
}
|
|
7698
8208
|
let raw;
|
|
7699
8209
|
try {
|
|
7700
|
-
raw = JSON.parse(await
|
|
8210
|
+
raw = JSON.parse(await readFile25(path, "utf8"));
|
|
7701
8211
|
} catch (error) {
|
|
7702
8212
|
const message = error instanceof Error ? error.message : String(error);
|
|
7703
8213
|
throw new Error(`Selection import '${parsedSelection.export}' cannot parse ${path}: ${message}`);
|
|
@@ -7775,7 +8285,7 @@ function sortedUnique3(values) {
|
|
|
7775
8285
|
return [...new Set(values)].sort((a, b) => a.localeCompare(b));
|
|
7776
8286
|
}
|
|
7777
8287
|
function sha2562(value) {
|
|
7778
|
-
return
|
|
8288
|
+
return createHash8("sha256").update(value).digest("hex");
|
|
7779
8289
|
}
|
|
7780
8290
|
function stableJson(value) {
|
|
7781
8291
|
return JSON.stringify(stableValue2(value));
|
|
@@ -7799,42 +8309,42 @@ import { homedir as homedir7 } from "os";
|
|
|
7799
8309
|
import { resolve as resolve15 } from "path";
|
|
7800
8310
|
|
|
7801
8311
|
// src/registry/client.ts
|
|
7802
|
-
import { readFile as
|
|
8312
|
+
import { readFile as readFile26, rm as rm9, stat as stat10 } from "fs/promises";
|
|
7803
8313
|
import { homedir as homedir6 } from "os";
|
|
7804
|
-
import { dirname as
|
|
8314
|
+
import { dirname as dirname26, join as join33, resolve as resolve14 } from "path";
|
|
7805
8315
|
import { fileURLToPath } from "url";
|
|
7806
8316
|
|
|
7807
8317
|
// src/model/registry.ts
|
|
7808
|
-
import { z as
|
|
7809
|
-
var registryEntrySchema =
|
|
7810
|
-
name:
|
|
7811
|
-
source:
|
|
7812
|
-
type:
|
|
7813
|
-
description:
|
|
7814
|
-
tags:
|
|
7815
|
-
select:
|
|
7816
|
-
skills:
|
|
7817
|
-
homepageUrl:
|
|
7818
|
-
homepageLinkLabel:
|
|
7819
|
-
sourceUrl:
|
|
7820
|
-
sourceLinkLabel:
|
|
7821
|
-
openpack:
|
|
7822
|
-
schemaVersion:
|
|
7823
|
-
specVersion:
|
|
8318
|
+
import { z as z9 } from "zod";
|
|
8319
|
+
var registryEntrySchema = z9.object({
|
|
8320
|
+
name: z9.string().min(1),
|
|
8321
|
+
source: z9.string().min(1),
|
|
8322
|
+
type: z9.enum(["package", "skill", "plugin", "mcp", "adapter"]).default("package"),
|
|
8323
|
+
description: z9.string().default(""),
|
|
8324
|
+
tags: z9.array(z9.string().min(1)).default([]),
|
|
8325
|
+
select: z9.array(z9.string().min(1)).optional(),
|
|
8326
|
+
skills: z9.array(z9.string().min(1)).optional(),
|
|
8327
|
+
homepageUrl: z9.string().min(1).optional(),
|
|
8328
|
+
homepageLinkLabel: z9.string().min(1).optional(),
|
|
8329
|
+
sourceUrl: z9.string().min(1).optional(),
|
|
8330
|
+
sourceLinkLabel: z9.string().min(1).optional(),
|
|
8331
|
+
openpack: z9.object({
|
|
8332
|
+
schemaVersion: z9.number().int().positive().optional(),
|
|
8333
|
+
specVersion: z9.string().min(1).optional()
|
|
7824
8334
|
}).passthrough().optional()
|
|
7825
8335
|
});
|
|
7826
|
-
var registryIndexSchema =
|
|
7827
|
-
|
|
7828
|
-
|
|
7829
|
-
schemaVersion:
|
|
7830
|
-
entries:
|
|
8336
|
+
var registryIndexSchema = z9.union([
|
|
8337
|
+
z9.array(registryEntrySchema),
|
|
8338
|
+
z9.object({
|
|
8339
|
+
schemaVersion: z9.literal(1).optional(),
|
|
8340
|
+
entries: z9.array(registryEntrySchema)
|
|
7831
8341
|
})
|
|
7832
8342
|
]).transform((value) => Array.isArray(value) ? value : value.entries);
|
|
7833
|
-
var registryCacheSchema =
|
|
7834
|
-
version:
|
|
7835
|
-
fetchedAt:
|
|
7836
|
-
sources:
|
|
7837
|
-
entries:
|
|
8343
|
+
var registryCacheSchema = z9.object({
|
|
8344
|
+
version: z9.literal(1),
|
|
8345
|
+
fetchedAt: z9.string().datetime(),
|
|
8346
|
+
sources: z9.array(z9.string().min(1)),
|
|
8347
|
+
entries: z9.array(registryEntrySchema)
|
|
7838
8348
|
});
|
|
7839
8349
|
|
|
7840
8350
|
// src/registry/client.ts
|
|
@@ -7875,7 +8385,7 @@ var RegistryClient = class {
|
|
|
7875
8385
|
return index.entries.find((entry) => entry.name === name);
|
|
7876
8386
|
}
|
|
7877
8387
|
async clearCache() {
|
|
7878
|
-
await
|
|
8388
|
+
await rm9(this.cachePath, { force: true });
|
|
7879
8389
|
}
|
|
7880
8390
|
async getSources() {
|
|
7881
8391
|
if (this.options.sources?.length) return this.options.sources;
|
|
@@ -7898,7 +8408,7 @@ var RegistryClient = class {
|
|
|
7898
8408
|
}
|
|
7899
8409
|
async readCache() {
|
|
7900
8410
|
if (!await pathExists(this.cachePath)) return void 0;
|
|
7901
|
-
return registryCacheSchema.parse(JSON.parse(await
|
|
8411
|
+
return registryCacheSchema.parse(JSON.parse(await readFile26(this.cachePath, "utf8")));
|
|
7902
8412
|
}
|
|
7903
8413
|
isExpired(cache, ttlMs) {
|
|
7904
8414
|
return this.now().getTime() - new Date(cache.fetchedAt).getTime() > ttlMs;
|
|
@@ -7916,11 +8426,11 @@ var RegistryClient = class {
|
|
|
7916
8426
|
const filePath = source.startsWith("file:") ? fileURLToPath(source) : source;
|
|
7917
8427
|
if (await pathExists(filePath)) {
|
|
7918
8428
|
const fullPath = resolve14(filePath);
|
|
7919
|
-
const stats = await
|
|
7920
|
-
return
|
|
8429
|
+
const stats = await stat10(fullPath);
|
|
8430
|
+
return readFile26(stats.isDirectory() ? join33(fullPath, "index.json") : fullPath, "utf8");
|
|
7921
8431
|
}
|
|
7922
|
-
const resolved = await this.git.fetch(await this.git.resolve(source, { cacheRoot:
|
|
7923
|
-
return
|
|
8432
|
+
const resolved = await this.git.fetch(await this.git.resolve(source, { cacheRoot: join33(dirname26(this.cachePath), "registry-repos") }));
|
|
8433
|
+
return readFile26(join33(resolved.resolvedPath, "index.json"), "utf8");
|
|
7924
8434
|
}
|
|
7925
8435
|
warnCompatibility(entries) {
|
|
7926
8436
|
for (const entry of entries) {
|
|
@@ -7934,7 +8444,7 @@ var RegistryClient = class {
|
|
|
7934
8444
|
}
|
|
7935
8445
|
};
|
|
7936
8446
|
async function resolvePackageSource(source, workspaceRoot, options = {}) {
|
|
7937
|
-
const { isExplicitSource } = await import("./identify-
|
|
8447
|
+
const { isExplicitSource } = await import("./identify-G3TXOHNS.js");
|
|
7938
8448
|
if (await isExplicitSource(source)) return { source };
|
|
7939
8449
|
const entry = await new RegistryClient({ workspaceRoot, offline: options.offline, warn: options.warn }).resolve(source);
|
|
7940
8450
|
if (!entry) {
|
|
@@ -7958,7 +8468,7 @@ function mergeIndexes(indexes) {
|
|
|
7958
8468
|
return [...merged.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
7959
8469
|
}
|
|
7960
8470
|
function defaultRegistryCachePath() {
|
|
7961
|
-
return
|
|
8471
|
+
return join33(homedir6(), ".agentwheel", "registry-cache.json");
|
|
7962
8472
|
}
|
|
7963
8473
|
function sameSources(a, b) {
|
|
7964
8474
|
return a.length === b.length && a.every((source, index) => source === b[index]);
|
|
@@ -8122,7 +8632,7 @@ function normalizeLiteralProviderSpec(source, prefix) {
|
|
|
8122
8632
|
var cacheLocks = /* @__PURE__ */ new Map();
|
|
8123
8633
|
async function resolveDependencyGraph(roots, options) {
|
|
8124
8634
|
if (roots.length === 0) throw new Error("At least one graph root is required.");
|
|
8125
|
-
const graphRoot = await mkdtemp4(
|
|
8635
|
+
const graphRoot = await mkdtemp4(join34(tmpdir5(), "agentwheel-graph-"));
|
|
8126
8636
|
const fetchCache = /* @__PURE__ */ new Map();
|
|
8127
8637
|
const nodesByKey = /* @__PURE__ */ new Map();
|
|
8128
8638
|
const rootResults = [];
|
|
@@ -8231,12 +8741,13 @@ Run without ${lockLabel === "Offline" ? "--offline" : "--frozen-lock"} first.`
|
|
|
8231
8741
|
}
|
|
8232
8742
|
lockedByReference = void 0;
|
|
8233
8743
|
normalized = declared;
|
|
8744
|
+
requirement.updateClosure = true;
|
|
8234
8745
|
}
|
|
8235
8746
|
}
|
|
8236
8747
|
const frozen = lockedByReference ?? lockedNodeForRequirement(normalized.normalizedSource, requirement, options, lockLabel);
|
|
8237
8748
|
let fetched;
|
|
8238
8749
|
try {
|
|
8239
|
-
fetched = await fetchPackage(normalized, requirement.mode, options, fetchCache, frozen
|
|
8750
|
+
fetched = await fetchPackage(normalized, requirement.mode, options, fetchCache, frozen);
|
|
8240
8751
|
} catch (error) {
|
|
8241
8752
|
const usingLockedNode = frozen?.node !== void 0;
|
|
8242
8753
|
if (!options.frozenLock && !options.offline && !usingLockedNode) throw error;
|
|
@@ -8271,6 +8782,7 @@ Run without ${lockLabel === "Offline" ? "--offline" : "--frozen-lock"} first.`
|
|
|
8271
8782
|
driver: fetched.resolved.driver,
|
|
8272
8783
|
requestedRef: fetched.resolved.requestedRef,
|
|
8273
8784
|
resolvedCommit: fetched.resolved.resolvedCommit,
|
|
8785
|
+
cacheIdentity: fetched.resolved.cacheIdentity,
|
|
8274
8786
|
sourceHash: fetched.sourceHash,
|
|
8275
8787
|
mode: fetched.resolved.mode ?? requirement.mode,
|
|
8276
8788
|
requiredBy: [],
|
|
@@ -8642,7 +9154,7 @@ async function collectIncludeNeeds(artifact, artifactsByRelativePath) {
|
|
|
8642
9154
|
const file = stack.shift();
|
|
8643
9155
|
if (scanned.has(file)) continue;
|
|
8644
9156
|
scanned.add(file);
|
|
8645
|
-
const content = await
|
|
9157
|
+
const content = await readFile27(file, "utf8");
|
|
8646
9158
|
for (const include of extractOpenPackIncludeSelectors(content)) {
|
|
8647
9159
|
await collectIncludeSelector(include.raw, include.optional, artifactsByRelativePath, scanned, stack, needs);
|
|
8648
9160
|
}
|
|
@@ -8676,7 +9188,7 @@ function requirementTargetsRuntime(runtimes, runtime, label, warn) {
|
|
|
8676
9188
|
}
|
|
8677
9189
|
async function markdownFilesForArtifact2(artifact) {
|
|
8678
9190
|
const root = artifact.sourcePath;
|
|
8679
|
-
const stats = await
|
|
9191
|
+
const stats = await stat11(root);
|
|
8680
9192
|
if (stats.isFile()) return extname4(root).toLowerCase() === ".md" ? [root] : [];
|
|
8681
9193
|
if (!stats.isDirectory()) return [];
|
|
8682
9194
|
return listMarkdownFiles2(root);
|
|
@@ -8684,8 +9196,8 @@ async function markdownFilesForArtifact2(artifact) {
|
|
|
8684
9196
|
async function listMarkdownFiles2(root) {
|
|
8685
9197
|
const out = [];
|
|
8686
9198
|
async function walk2(dir) {
|
|
8687
|
-
for (const entry of (await
|
|
8688
|
-
const full =
|
|
9199
|
+
for (const entry of (await readdir7(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
9200
|
+
const full = join34(dir, entry.name);
|
|
8689
9201
|
if (entry.isDirectory()) {
|
|
8690
9202
|
await walk2(full);
|
|
8691
9203
|
} else if (entry.isFile() && extname4(entry.name).toLowerCase() === ".md") {
|
|
@@ -8712,17 +9224,19 @@ function dependencyTargetsRuntime(runtimes, runtime, nodeId, alias, warn) {
|
|
|
8712
9224
|
warn?.(`skip dependency ${nodeId}:${alias} (not targeted: runtimes=[${runtimes.join(",")}])`);
|
|
8713
9225
|
return false;
|
|
8714
9226
|
}
|
|
8715
|
-
async function fetchPackage(normalized, mode, options, fetchCache,
|
|
9227
|
+
async function fetchPackage(normalized, mode, options, fetchCache, frozen) {
|
|
8716
9228
|
const hardLockedCheckout = options.frozenLock === true || options.offline === true;
|
|
8717
|
-
const
|
|
9229
|
+
const refOverride = frozen?.requestedRef;
|
|
9230
|
+
const key = `${normalized.driver}\0${normalized.normalizedSource}\0${mode}\0${refOverride ?? ""}\0${frozen?.cacheIdentity ?? ""}\0${hardLockedCheckout ? "hard-locked" : "mutable"}`;
|
|
8718
9231
|
const existing = fetchCache.get(key);
|
|
8719
9232
|
if (existing) return existing;
|
|
8720
9233
|
const promise = (async () => {
|
|
8721
9234
|
const driver = getSourceDriver(normalized.driver);
|
|
8722
9235
|
const resolved = await driver.resolve(normalized.source, {
|
|
8723
|
-
cacheRoot: options.cacheRoot ??
|
|
9236
|
+
cacheRoot: options.cacheRoot ?? join34(options.workspaceRoot, ".agentwheel", "cache"),
|
|
8724
9237
|
mode,
|
|
8725
9238
|
ref: refOverride ?? normalized.requestedRef,
|
|
9239
|
+
cacheIdentity: frozen?.cacheIdentity,
|
|
8726
9240
|
frozenLock: hardLockedCheckout
|
|
8727
9241
|
});
|
|
8728
9242
|
const fetched = await withCachePathLock(resolved.resolvedPath, () => driver.fetch(resolved));
|
|
@@ -8771,7 +9285,8 @@ function lockedNodeForRequirement(normalizedSource, requirement, options, label)
|
|
|
8771
9285
|
const node = matches[0];
|
|
8772
9286
|
return {
|
|
8773
9287
|
node,
|
|
8774
|
-
requestedRef: node
|
|
9288
|
+
requestedRef: lockedSourceRef(node),
|
|
9289
|
+
cacheIdentity: node.cacheIdentity
|
|
8775
9290
|
};
|
|
8776
9291
|
}
|
|
8777
9292
|
function lockedNodeForRequirementReference(requirement, options, label) {
|
|
@@ -8804,7 +9319,8 @@ function lockedNodeForRequirementReference(requirement, options, label) {
|
|
|
8804
9319
|
}
|
|
8805
9320
|
return {
|
|
8806
9321
|
node,
|
|
8807
|
-
requestedRef: node
|
|
9322
|
+
requestedRef: lockedSourceRef(node),
|
|
9323
|
+
cacheIdentity: node.cacheIdentity
|
|
8808
9324
|
};
|
|
8809
9325
|
}
|
|
8810
9326
|
function shouldCheckLockedRootSource(requirement) {
|
|
@@ -8827,6 +9343,9 @@ function normalizedSourceFromLockedNode(node) {
|
|
|
8827
9343
|
requestedRef: node.requestedRef
|
|
8828
9344
|
};
|
|
8829
9345
|
}
|
|
9346
|
+
function lockedSourceRef(node) {
|
|
9347
|
+
return node.driver === "git" || node.driver === "skillkit" ? node.resolvedCommit ?? node.requestedRef : node.requestedRef;
|
|
9348
|
+
}
|
|
8830
9349
|
function verifyIntegrity(integrity, sourceHash, label) {
|
|
8831
9350
|
if (!integrity) return;
|
|
8832
9351
|
const expected = integrity.replace(/^sha256[-:]/i, "");
|
|
@@ -8906,7 +9425,7 @@ function detectDirectCollisions(nodes) {
|
|
|
8906
9425
|
}
|
|
8907
9426
|
}
|
|
8908
9427
|
function graphNodeId(name, version, normalizedSource, resolvedCommit, sourceHash) {
|
|
8909
|
-
const digest =
|
|
9428
|
+
const digest = createHash9("sha256").update(normalizedSource).update("\0").update(resolvedCommit ?? sourceHash).digest("hex").slice(0, 12);
|
|
8910
9429
|
return `${name}@${version}+${digest}`;
|
|
8911
9430
|
}
|
|
8912
9431
|
function sortedUnique4(values) {
|
|
@@ -8927,8 +9446,8 @@ async function mapLimit(items, limit, fn) {
|
|
|
8927
9446
|
|
|
8928
9447
|
// src/lifecycle/customization.ts
|
|
8929
9448
|
async function remember(workspaceRoot, runtime, text) {
|
|
8930
|
-
const overlayPath =
|
|
8931
|
-
await
|
|
9449
|
+
const overlayPath = join35(workspaceRoot, ".agentwheel", "overlays", runtime, "instructions.local.md");
|
|
9450
|
+
await mkdir20(dirname27(overlayPath), { recursive: true });
|
|
8932
9451
|
await appendFile(overlayPath, `${text.trim()}
|
|
8933
9452
|
`, "utf8");
|
|
8934
9453
|
return { overlayPath };
|
|
@@ -8951,9 +9470,9 @@ async function ejectArtifact(workspaceRoot, item) {
|
|
|
8951
9470
|
throw new Error(`Artifact not found: ${item}`);
|
|
8952
9471
|
}
|
|
8953
9472
|
const ejectedIdentity = parsed.packageIdentity === parsed.packageName ? parsed.packageIdentity : candidate.nodeId === parsed.packageIdentity ? candidate.nodeId : `${candidate.packageName}@${candidate.packageVersion}`;
|
|
8954
|
-
const ejectedPath =
|
|
8955
|
-
await
|
|
8956
|
-
await
|
|
9473
|
+
const ejectedPath = join35(workspaceRoot, ".agentwheel", "ejected", ...ejectedIdentity.split("/"), parsed.type, parsed.name);
|
|
9474
|
+
await mkdir20(dirname27(ejectedPath), { recursive: true });
|
|
9475
|
+
await rm10(ejectedPath, { recursive: true, force: true });
|
|
8957
9476
|
await cp6(artifact.stagedPath ?? artifact.sourcePath, ejectedPath, { recursive: artifact.kind === "dir", dereference: true });
|
|
8958
9477
|
return {
|
|
8959
9478
|
...parsed,
|
|
@@ -8964,7 +9483,7 @@ async function ejectArtifact(workspaceRoot, item) {
|
|
|
8964
9483
|
ejectedPath
|
|
8965
9484
|
};
|
|
8966
9485
|
} finally {
|
|
8967
|
-
await Promise.all(candidates.map((candidate) =>
|
|
9486
|
+
await Promise.all(candidates.map((candidate) => rm10(candidate.bundle.root, { recursive: true, force: true })));
|
|
8968
9487
|
}
|
|
8969
9488
|
}
|
|
8970
9489
|
function parseEjectItem(item) {
|
|
@@ -8994,7 +9513,7 @@ async function stageEjectCandidate(workspaceRoot, pkg) {
|
|
|
8994
9513
|
const adapter = pkg.adapterConfig ? await loadAdapterConfig(pkg.adapterConfig) : getAdapter(pkg.adapter);
|
|
8995
9514
|
const bundle = await stageSource(driver, normalized.source, {
|
|
8996
9515
|
adapter,
|
|
8997
|
-
cacheRoot:
|
|
9516
|
+
cacheRoot: join35(workspaceRoot, ".agentwheel", "cache"),
|
|
8998
9517
|
mode: pkg.mode,
|
|
8999
9518
|
ref: normalized.requestedRef ?? pkg.requestedRef
|
|
9000
9519
|
});
|
|
@@ -9041,12 +9560,12 @@ function ejectCommands(candidates, parsed) {
|
|
|
9041
9560
|
}
|
|
9042
9561
|
|
|
9043
9562
|
// src/lifecycle/profile.ts
|
|
9044
|
-
import { rm as
|
|
9563
|
+
import { rm as rm11 } from "fs/promises";
|
|
9045
9564
|
|
|
9046
9565
|
// src/lifecycle/source-plan.ts
|
|
9047
|
-
import { createHash as
|
|
9048
|
-
import { mkdir as
|
|
9049
|
-
import { dirname as
|
|
9566
|
+
import { createHash as createHash11 } from "crypto";
|
|
9567
|
+
import { mkdir as mkdir22 } from "fs/promises";
|
|
9568
|
+
import { dirname as dirname29, join as join38 } from "path";
|
|
9050
9569
|
|
|
9051
9570
|
// src/resolve/graph-diff.ts
|
|
9052
9571
|
function diffGraphLocks(previous, next) {
|
|
@@ -9089,7 +9608,7 @@ function diffNodes(previous, next) {
|
|
|
9089
9608
|
for (const [key, oldNode] of previousByStable) {
|
|
9090
9609
|
const newNode = nextByStable.get(key);
|
|
9091
9610
|
if (!newNode) continue;
|
|
9092
|
-
if (oldNode.id === newNode.id && oldNode.version === newNode.version && oldNode.resolvedCommit === newNode.resolvedCommit && oldNode.sourceHash === newNode.sourceHash) {
|
|
9611
|
+
if (oldNode.id === newNode.id && oldNode.version === newNode.version && oldNode.resolvedCommit === newNode.resolvedCommit && oldNode.cacheIdentity === newNode.cacheIdentity && oldNode.sourceHash === newNode.sourceHash) {
|
|
9093
9612
|
continue;
|
|
9094
9613
|
}
|
|
9095
9614
|
movedOldIds.add(oldNode.id);
|
|
@@ -9161,6 +9680,7 @@ function nodeChangeDetails(oldNode, newNode) {
|
|
|
9161
9680
|
const details = [];
|
|
9162
9681
|
if (oldNode.version !== newNode.version) details.push(`version ${oldNode.version} -> ${newNode.version}`);
|
|
9163
9682
|
if (oldNode.resolvedCommit !== newNode.resolvedCommit) details.push(`commit ${oldNode.resolvedCommit ?? "<none>"} -> ${newNode.resolvedCommit ?? "<none>"}`);
|
|
9683
|
+
if (oldNode.cacheIdentity !== newNode.cacheIdentity) details.push(`cache ${short(oldNode.cacheIdentity ?? "none")} -> ${short(newNode.cacheIdentity ?? "none")}`);
|
|
9164
9684
|
if (oldNode.sourceHash !== newNode.sourceHash) details.push(`sourceHash ${short(oldNode.sourceHash)} -> ${short(newNode.sourceHash)}`);
|
|
9165
9685
|
return details.length > 0 ? ` (${details.join(", ")})` : "";
|
|
9166
9686
|
}
|
|
@@ -9207,12 +9727,12 @@ function formatSelectionImport(root) {
|
|
|
9207
9727
|
}
|
|
9208
9728
|
|
|
9209
9729
|
// src/resolve/render.ts
|
|
9210
|
-
import { createHash as
|
|
9211
|
-
import { readFile as
|
|
9730
|
+
import { createHash as createHash10 } from "crypto";
|
|
9731
|
+
import { readFile as readFile28, mkdtemp as mkdtemp5 } from "fs/promises";
|
|
9212
9732
|
import { tmpdir as tmpdir6 } from "os";
|
|
9213
|
-
import { join as
|
|
9733
|
+
import { join as join36 } from "path";
|
|
9214
9734
|
async function renderGraphForTarget(graph, targetContext = {}) {
|
|
9215
|
-
const root = await mkdtemp5(
|
|
9735
|
+
const root = await mkdtemp5(join36(tmpdir6(), "agentwheel-render-"));
|
|
9216
9736
|
const artifacts = [];
|
|
9217
9737
|
const stagedNodes = /* @__PURE__ */ new Map();
|
|
9218
9738
|
const includeEdges = /* @__PURE__ */ new Map();
|
|
@@ -9334,7 +9854,7 @@ async function artifactContentMap(artifacts) {
|
|
|
9334
9854
|
const out = /* @__PURE__ */ new Map();
|
|
9335
9855
|
for (const artifact of artifacts) {
|
|
9336
9856
|
if (artifact.kind !== "file") continue;
|
|
9337
|
-
out.set(artifact.relativePath.replaceAll("\\", "/"), await
|
|
9857
|
+
out.set(artifact.relativePath.replaceAll("\\", "/"), await readFile28(artifact.stagedPath ?? artifact.sourcePath, "utf8"));
|
|
9338
9858
|
}
|
|
9339
9859
|
return out;
|
|
9340
9860
|
}
|
|
@@ -9348,7 +9868,7 @@ function filterArtifactsByRuntime2(artifacts, adapterName, selectedSet) {
|
|
|
9348
9868
|
});
|
|
9349
9869
|
}
|
|
9350
9870
|
function sha2563(content) {
|
|
9351
|
-
return
|
|
9871
|
+
return createHash10("sha256").update(content).digest("hex");
|
|
9352
9872
|
}
|
|
9353
9873
|
function assignInstallNames(graph, artifacts) {
|
|
9354
9874
|
const aliases = workspaceAliases(graph);
|
|
@@ -9597,13 +10117,13 @@ function lockArtifactFor(artifact) {
|
|
|
9597
10117
|
}
|
|
9598
10118
|
|
|
9599
10119
|
// src/lifecycle/trust.ts
|
|
9600
|
-
import { mkdir as
|
|
10120
|
+
import { mkdir as mkdir21, readFile as readFile29 } from "fs/promises";
|
|
9601
10121
|
import { homedir as homedir8 } from "os";
|
|
9602
|
-
import { dirname as
|
|
9603
|
-
import { z as
|
|
9604
|
-
var trustStoreSchema =
|
|
9605
|
-
version:
|
|
9606
|
-
acceptedSources:
|
|
10122
|
+
import { dirname as dirname28, join as join37 } from "path";
|
|
10123
|
+
import { z as z10 } from "zod";
|
|
10124
|
+
var trustStoreSchema = z10.object({
|
|
10125
|
+
version: z10.literal(1),
|
|
10126
|
+
acceptedSources: z10.array(z10.string().min(1)).default([])
|
|
9607
10127
|
});
|
|
9608
10128
|
function normalizeTrustPolicy(policy) {
|
|
9609
10129
|
return {
|
|
@@ -9673,14 +10193,14 @@ function sortedUnique5(values) {
|
|
|
9673
10193
|
}
|
|
9674
10194
|
async function readTrustStore(path) {
|
|
9675
10195
|
if (!await pathExists(path)) return { version: 1, acceptedSources: [] };
|
|
9676
|
-
return trustStoreSchema.parse(JSON.parse(await
|
|
10196
|
+
return trustStoreSchema.parse(JSON.parse(await readFile29(path, "utf8")));
|
|
9677
10197
|
}
|
|
9678
10198
|
async function writeTrustStore(path, store) {
|
|
9679
|
-
await
|
|
10199
|
+
await mkdir21(dirname28(path), { recursive: true });
|
|
9680
10200
|
await writeJsonAtomic(path, trustStoreSchema.parse(store));
|
|
9681
10201
|
}
|
|
9682
10202
|
function defaultTrustStorePath() {
|
|
9683
|
-
return process.env.AGENTWHEEL_TRUST_STORE ??
|
|
10203
|
+
return process.env.AGENTWHEEL_TRUST_STORE ?? join37(homedir8(), ".agentwheel", "trust.json");
|
|
9684
10204
|
}
|
|
9685
10205
|
|
|
9686
10206
|
// src/lifecycle/ownership.ts
|
|
@@ -9817,6 +10337,82 @@ function assertManifestIdentity(manifest, request) {
|
|
|
9817
10337
|
}
|
|
9818
10338
|
}
|
|
9819
10339
|
|
|
10340
|
+
// src/lifecycle/mcp-retirement.ts
|
|
10341
|
+
async function createExactMcpRetirementPlan(desiredArtifacts, adapter, targetRoot, manifest, transport = localTransport, options) {
|
|
10342
|
+
if (desiredArtifacts.length !== 1 || desiredArtifacts[0]?.type !== "mcp") {
|
|
10343
|
+
throw new Error(`Exact MCP retirement requires exactly one MCP artifact; found ${desiredArtifacts.length}.`);
|
|
10344
|
+
}
|
|
10345
|
+
if (manifest && manifest.version !== 2) {
|
|
10346
|
+
throw new Error("Exact MCP retirement requires an Agentwheel v2 install manifest when managed state exists.");
|
|
10347
|
+
}
|
|
10348
|
+
if (manifest && manifest.entries.length !== 1) {
|
|
10349
|
+
throw new Error(`Exact MCP retirement requires exactly one manifest entry; found ${manifest.entries.length}.`);
|
|
10350
|
+
}
|
|
10351
|
+
if (options.expectedFromWorkspaceOwner && !manifest) {
|
|
10352
|
+
throw new Error(`Expected managed MCP ownership from ${options.expectedFromWorkspaceOwner}, but no manifest exists.`);
|
|
10353
|
+
}
|
|
10354
|
+
if (options.expectedFromWorkspaceOwner === options.workspaceOwner) {
|
|
10355
|
+
throw new Error("Exact MCP retirement ownership handoff requires different old and new workspace owners.");
|
|
10356
|
+
}
|
|
10357
|
+
const adoption = await createCombinedInstallPlan(
|
|
10358
|
+
desiredArtifacts,
|
|
10359
|
+
adapter,
|
|
10360
|
+
targetRoot,
|
|
10361
|
+
void 0,
|
|
10362
|
+
transport,
|
|
10363
|
+
{
|
|
10364
|
+
baseRevision: manifest?.revision ?? null,
|
|
10365
|
+
graphLockDigest: options.graphLockDigest,
|
|
10366
|
+
workspaceOwner: options.workspaceOwner,
|
|
10367
|
+
installationType: options.installationType,
|
|
10368
|
+
stateKey: options.stateKey,
|
|
10369
|
+
forceConflict: true
|
|
10370
|
+
}
|
|
10371
|
+
);
|
|
10372
|
+
if (adoption.operations.length !== 1) {
|
|
10373
|
+
throw new Error(`Exact MCP retirement expected one rendered operation; found ${adoption.operations.length}.`);
|
|
10374
|
+
}
|
|
10375
|
+
const operation = adoption.operations[0];
|
|
10376
|
+
if (adoption.hasBlockingChanges || operation.action !== "skip" || !operation.mergeStrategy || !operation.mergeRemoval) {
|
|
10377
|
+
return adoption;
|
|
10378
|
+
}
|
|
10379
|
+
if (operation.mergeStrategy !== "json-deep" && operation.mergeStrategy !== "codex-toml-mcp") {
|
|
10380
|
+
throw new Error(`Exact MCP retirement does not support merge strategy ${operation.mergeStrategy}.`);
|
|
10381
|
+
}
|
|
10382
|
+
const removalKeys = Object.keys(operation.mergeRemoval);
|
|
10383
|
+
const servers = operation.mergeRemoval.mcpServers;
|
|
10384
|
+
if (removalKeys.length !== 1 || removalKeys[0] !== "mcpServers" || !servers || typeof servers !== "object" || Array.isArray(servers) || Object.keys(servers).length !== 1) {
|
|
10385
|
+
throw new Error("Exact MCP retirement requires exactly one MCP server and no non-MCP configuration.");
|
|
10386
|
+
}
|
|
10387
|
+
const entry = manifest?.entries[0];
|
|
10388
|
+
if (entry) {
|
|
10389
|
+
const mismatches = [];
|
|
10390
|
+
if (entry.artifactType !== operation.artifactType) mismatches.push(`artifact type ${entry.artifactType}`);
|
|
10391
|
+
if (entry.artifactName !== operation.artifactName) mismatches.push(`artifact name ${entry.artifactName}`);
|
|
10392
|
+
if (entry.path !== operation.relativeDestPath) mismatches.push(`path ${entry.path}`);
|
|
10393
|
+
if (entry.sourceHash !== operation.desiredHash) mismatches.push("source hash");
|
|
10394
|
+
if (entry.mergeStrategy !== operation.mergeStrategy) mismatches.push(`merge strategy ${entry.mergeStrategy ?? "missing"}`);
|
|
10395
|
+
if (entry.mergeCreatedDestination === true) mismatches.push("manifest claims ownership of the whole destination");
|
|
10396
|
+
const expectedOwner = options.expectedFromWorkspaceOwner ?? options.workspaceOwner;
|
|
10397
|
+
if (entry.workspaceOwner !== expectedOwner) mismatches.push(`owner ${entry.workspaceOwner}`);
|
|
10398
|
+
if (mismatches.length > 0) {
|
|
10399
|
+
throw new Error(`Exact MCP retirement manifest precondition failed: ${mismatches.join(", ")}.`);
|
|
10400
|
+
}
|
|
10401
|
+
}
|
|
10402
|
+
return {
|
|
10403
|
+
...adoption,
|
|
10404
|
+
baseRevision: manifest?.revision ?? null,
|
|
10405
|
+
operations: [{
|
|
10406
|
+
...operation,
|
|
10407
|
+
action: "remove",
|
|
10408
|
+
exactMergeRemoval: true,
|
|
10409
|
+
manifestHash: entry?.hash,
|
|
10410
|
+
workspaceOwner: options.workspaceOwner,
|
|
10411
|
+
reason: entry ? `retire exact MCP contribution after explicit ownership handoff from ${entry.workspaceOwner}` : `retire exact unmanaged MCP contribution under ${options.workspaceOwner}`
|
|
10412
|
+
}]
|
|
10413
|
+
};
|
|
10414
|
+
}
|
|
10415
|
+
|
|
9820
10416
|
// src/lifecycle/source-plan.ts
|
|
9821
10417
|
async function createGraphSourcePlan(options) {
|
|
9822
10418
|
if (options.roots.length === 0) {
|
|
@@ -9852,7 +10448,7 @@ async function createGraphSourcePlan(options) {
|
|
|
9852
10448
|
const registryClient = new RegistryClient({ workspaceRoot, offline: lockMode, offlineLabel: lockLabel, warn });
|
|
9853
10449
|
const graph = await resolveDependencyGraph(options.roots, {
|
|
9854
10450
|
workspaceRoot,
|
|
9855
|
-
cacheRoot:
|
|
10451
|
+
cacheRoot: join38(workspaceRoot, ".agentwheel", "cache"),
|
|
9856
10452
|
registryClient,
|
|
9857
10453
|
noDeps: options.noDeps,
|
|
9858
10454
|
includeSuggestions: options.includeSuggestions,
|
|
@@ -9889,10 +10485,24 @@ async function createGraphSourcePlan(options) {
|
|
|
9889
10485
|
const graphLockDigest = digestGraphLock(bundle.graphLock);
|
|
9890
10486
|
const graphDiff = diffGraphLocks(previousLock, bundle.graphLock);
|
|
9891
10487
|
const manifest = await readInstallManifest(resolvedInstallRoot, options.adapter.name, transport, { installationType: resolvedInstallationType, stateKey });
|
|
9892
|
-
const
|
|
10488
|
+
const workspaceOwner = workspaceOwnerForRoot(workspaceRoot);
|
|
10489
|
+
const plan = options.retireExactMcp ? await createExactMcpRetirementPlan(
|
|
10490
|
+
desiredArtifacts,
|
|
10491
|
+
options.adapter,
|
|
10492
|
+
options.targetRoot,
|
|
10493
|
+
manifest,
|
|
10494
|
+
transport,
|
|
10495
|
+
{
|
|
10496
|
+
installationType: resolvedInstallationType,
|
|
10497
|
+
stateKey,
|
|
10498
|
+
workspaceOwner,
|
|
10499
|
+
expectedFromWorkspaceOwner: options.expectedFromWorkspaceOwner,
|
|
10500
|
+
graphLockDigest
|
|
10501
|
+
}
|
|
10502
|
+
) : await createCombinedInstallPlan(desiredArtifacts, options.adapter, options.targetRoot, manifest, transport, {
|
|
9893
10503
|
baseRevision: manifest?.revision ?? null,
|
|
9894
10504
|
graphLockDigest,
|
|
9895
|
-
workspaceOwner
|
|
10505
|
+
workspaceOwner,
|
|
9896
10506
|
installationType: resolvedInstallationType,
|
|
9897
10507
|
stateKey,
|
|
9898
10508
|
forceDrift: options.forceDrift,
|
|
@@ -9958,13 +10568,13 @@ async function readExistingGraphLock(path) {
|
|
|
9958
10568
|
return readGraphLock(path);
|
|
9959
10569
|
}
|
|
9960
10570
|
function pathForGraphLock(workspaceRoot, targetKey2, adapter, targetFingerprint) {
|
|
9961
|
-
return
|
|
10571
|
+
return join38(workspaceRoot, ".agentwheel", "locks", sanitizePathSegment(targetKey2), sanitizePathSegment(adapter), `${targetFingerprint}.graph-lock.json`);
|
|
9962
10572
|
}
|
|
9963
10573
|
function sanitizePathSegment(value) {
|
|
9964
10574
|
return value.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "default";
|
|
9965
10575
|
}
|
|
9966
10576
|
function digestGraphLock(lock) {
|
|
9967
|
-
return
|
|
10577
|
+
return createHash11("sha256").update(canonicalGraphLockJson(lock)).digest("hex");
|
|
9968
10578
|
}
|
|
9969
10579
|
function assertFrozenGraph(previousLock, graph, frozen, label) {
|
|
9970
10580
|
if (!frozen) return;
|
|
@@ -10090,7 +10700,7 @@ function targetLabel(target) {
|
|
|
10090
10700
|
}
|
|
10091
10701
|
|
|
10092
10702
|
// src/runtime/target.ts
|
|
10093
|
-
import { basename as basename21, dirname as
|
|
10703
|
+
import { basename as basename21, dirname as dirname30, join as join39, resolve as resolve17 } from "path";
|
|
10094
10704
|
var runtimeMarkers = [
|
|
10095
10705
|
{ adapter: "openclaw", dirs: [".openclaw", ".clawdbot", ".moltbot"] },
|
|
10096
10706
|
{ adapter: "claude", dirs: [".claude"] },
|
|
@@ -10161,6 +10771,7 @@ function resolveProfileRuntimeTarget(runtime, config, workspaceRoot, installatio
|
|
|
10161
10771
|
...target,
|
|
10162
10772
|
adapterConfig: runtime.adapterConfig,
|
|
10163
10773
|
adapterModule: runtime.adapterModule,
|
|
10774
|
+
stateKey: runtime.stateKey ?? target.stateKey,
|
|
10164
10775
|
executePlugins: runtime.executePlugins,
|
|
10165
10776
|
reloadRuntimes: runtime.reloadRuntimes,
|
|
10166
10777
|
reloadCommands: runtime.reloadCommands ?? target.reloadCommands,
|
|
@@ -10173,6 +10784,7 @@ function resolveProfileRuntimeTarget(runtime, config, workspaceRoot, installatio
|
|
|
10173
10784
|
adapterConfig: runtime.adapterConfig,
|
|
10174
10785
|
adapterModule: runtime.adapterModule,
|
|
10175
10786
|
installationType: installationType ?? runtime.installationType,
|
|
10787
|
+
stateKey: runtime.stateKey,
|
|
10176
10788
|
targetRoot: runtime.targetRoot ? resolveConfigPath(runtime.targetRoot, workspaceRoot) : workspaceRoot,
|
|
10177
10789
|
workspaceRoot,
|
|
10178
10790
|
executePlugins: runtime.executePlugins,
|
|
@@ -10211,8 +10823,8 @@ async function detectRuntimeTargets(cwd = process.cwd(), adapterFilter) {
|
|
|
10211
10823
|
if (adapterFilter && marker.adapter !== adapterFilter) continue;
|
|
10212
10824
|
for (const dir of marker.dirs) {
|
|
10213
10825
|
if (basename21(root) === dir) {
|
|
10214
|
-
matches.push({ adapter: marker.adapter, targetRoot:
|
|
10215
|
-
} else if (await pathExists(
|
|
10826
|
+
matches.push({ adapter: marker.adapter, targetRoot: dirname30(root) });
|
|
10827
|
+
} else if (await pathExists(join39(root, dir))) {
|
|
10216
10828
|
matches.push({ adapter: marker.adapter, targetRoot: root });
|
|
10217
10829
|
}
|
|
10218
10830
|
}
|
|
@@ -10231,6 +10843,7 @@ function targetFromAgent(name, config, workspaceRoot, installationType) {
|
|
|
10231
10843
|
adapterConfig: agent.adapterConfig,
|
|
10232
10844
|
adapterModule: agent.adapterModule,
|
|
10233
10845
|
installationType: installationType ?? agent.installationType,
|
|
10846
|
+
stateKey: agent.stateKey,
|
|
10234
10847
|
targetRoot: agent.transport === "ssh" ? agent.root : resolveConfigPath(agent.root, workspaceRoot),
|
|
10235
10848
|
workspaceRoot,
|
|
10236
10849
|
reloadCommands: agent.reloadCommands,
|
|
@@ -10254,7 +10867,7 @@ function dedupeTargets(matches) {
|
|
|
10254
10867
|
function runtimeScanRoot(request) {
|
|
10255
10868
|
const root = resolve17(request.targetRoot ?? request.cwd ?? process.cwd());
|
|
10256
10869
|
if (request.targetRoot) return root;
|
|
10257
|
-
return runtimeMarkers.some((marker) => marker.dirs.includes(basename21(root))) ?
|
|
10870
|
+
return runtimeMarkers.some((marker) => marker.dirs.includes(basename21(root))) ? dirname30(root) : root;
|
|
10258
10871
|
}
|
|
10259
10872
|
|
|
10260
10873
|
// src/lifecycle/profile.ts
|
|
@@ -10317,9 +10930,11 @@ async function syncProfile(options) {
|
|
|
10317
10930
|
agentName: target.agentName,
|
|
10318
10931
|
targetRoot: target.targetRoot,
|
|
10319
10932
|
transport: transport.kind,
|
|
10320
|
-
ssh: target.ssh
|
|
10933
|
+
ssh: target.ssh,
|
|
10934
|
+
stateKey: target.stateKey
|
|
10321
10935
|
},
|
|
10322
10936
|
installationType,
|
|
10937
|
+
stateKey: target.stateKey,
|
|
10323
10938
|
noDeps: options.noDeps,
|
|
10324
10939
|
includeSuggestions: options.includeSuggestions,
|
|
10325
10940
|
suggestionAliases: options.suggestionAliases,
|
|
@@ -10362,7 +10977,7 @@ async function syncProfile(options) {
|
|
|
10362
10977
|
}
|
|
10363
10978
|
results.push(result);
|
|
10364
10979
|
} finally {
|
|
10365
|
-
await
|
|
10980
|
+
await rm11(graphPlan.bundle.root, { recursive: true, force: true });
|
|
10366
10981
|
}
|
|
10367
10982
|
}
|
|
10368
10983
|
return results;
|
|
@@ -10556,9 +11171,9 @@ function shellQuoteArg(value) {
|
|
|
10556
11171
|
}
|
|
10557
11172
|
|
|
10558
11173
|
// src/cli/update-check.ts
|
|
10559
|
-
import { mkdir as
|
|
11174
|
+
import { mkdir as mkdir23, readFile as readFile30, writeFile as writeFile20 } from "fs/promises";
|
|
10560
11175
|
import { homedir as homedir9 } from "os";
|
|
10561
|
-
import { dirname as
|
|
11176
|
+
import { dirname as dirname31, join as join40 } from "path";
|
|
10562
11177
|
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
10563
11178
|
var DEFAULT_TIMEOUT_MS = 300;
|
|
10564
11179
|
var REGISTRY_URL = "https://registry.npmjs.org/agentwheel";
|
|
@@ -10566,7 +11181,7 @@ async function maybeCheckForUpdate(options) {
|
|
|
10566
11181
|
if (isDisabled(options)) return;
|
|
10567
11182
|
const now = options.now?.() ?? /* @__PURE__ */ new Date();
|
|
10568
11183
|
const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
|
|
10569
|
-
const cachePath = options.cachePath ??
|
|
11184
|
+
const cachePath = options.cachePath ?? join40(homedir9(), ".agentwheel", "update-check.json");
|
|
10570
11185
|
try {
|
|
10571
11186
|
const cached = await readCache(cachePath);
|
|
10572
11187
|
if (cached && now.getTime() - Date.parse(cached.checkedAt) < ttlMs) {
|
|
@@ -10603,7 +11218,7 @@ async function fetchLatestVersion(fetchImpl, timeoutMs) {
|
|
|
10603
11218
|
}
|
|
10604
11219
|
async function readCache(path) {
|
|
10605
11220
|
try {
|
|
10606
|
-
const parsed = JSON.parse(await
|
|
11221
|
+
const parsed = JSON.parse(await readFile30(path, "utf8"));
|
|
10607
11222
|
if (typeof parsed.checkedAt !== "string" || typeof parsed.latest !== "string") return void 0;
|
|
10608
11223
|
return { checkedAt: parsed.checkedAt, latest: parsed.latest };
|
|
10609
11224
|
} catch {
|
|
@@ -10611,7 +11226,7 @@ async function readCache(path) {
|
|
|
10611
11226
|
}
|
|
10612
11227
|
}
|
|
10613
11228
|
async function writeCache(path, cache) {
|
|
10614
|
-
await
|
|
11229
|
+
await mkdir23(dirname31(path), { recursive: true });
|
|
10615
11230
|
await writeFile20(path, `${JSON.stringify(cache, null, 2)}
|
|
10616
11231
|
`, "utf8");
|
|
10617
11232
|
}
|
|
@@ -10634,7 +11249,7 @@ function normalizeVersion(version) {
|
|
|
10634
11249
|
}
|
|
10635
11250
|
|
|
10636
11251
|
// src/model/package-validate.ts
|
|
10637
|
-
import { stat as
|
|
11252
|
+
import { stat as stat12 } from "fs/promises";
|
|
10638
11253
|
import { resolve as resolve18 } from "path";
|
|
10639
11254
|
async function validatePackage(root) {
|
|
10640
11255
|
const packageRoot = resolve18(root);
|
|
@@ -10727,7 +11342,7 @@ async function validateManifestComposeInclude(packageRoot, selector, optional, f
|
|
|
10727
11342
|
findings.push({ level: "error", message: `Compose include escapes package root: ${selector}`, path: manifestPath });
|
|
10728
11343
|
return;
|
|
10729
11344
|
}
|
|
10730
|
-
if (!optional) await
|
|
11345
|
+
if (!optional) await stat12(full);
|
|
10731
11346
|
} catch (error) {
|
|
10732
11347
|
if (!optional) {
|
|
10733
11348
|
findings.push({ level: "error", message: error instanceof Error ? error.message : String(error), path: manifestPath });
|
|
@@ -10775,13 +11390,13 @@ function isCrossPackageSelector(value) {
|
|
|
10775
11390
|
}
|
|
10776
11391
|
|
|
10777
11392
|
// src/model/package-migrate.ts
|
|
10778
|
-
import { readFile as
|
|
10779
|
-
import { join as
|
|
11393
|
+
import { readFile as readFile31, rename as rename5, writeFile as writeFile21 } from "fs/promises";
|
|
11394
|
+
import { join as join42, resolve as resolve19 } from "path";
|
|
10780
11395
|
import { applyEdits, modify, parse as parse5 } from "jsonc-parser";
|
|
10781
11396
|
async function migratePackageManifest(root) {
|
|
10782
11397
|
const packageRoot = resolve19(root);
|
|
10783
11398
|
for (const name of openPackManifestNames) {
|
|
10784
|
-
const path =
|
|
11399
|
+
const path = join42(packageRoot, name);
|
|
10785
11400
|
if (await pathExists(path)) {
|
|
10786
11401
|
return { changed: false, to: path, message: `Package already uses ${name}.` };
|
|
10787
11402
|
}
|
|
@@ -10790,18 +11405,18 @@ async function migratePackageManifest(root) {
|
|
|
10790
11405
|
if (!legacyName) {
|
|
10791
11406
|
throw new Error(`No legacy package manifest found at ${packageRoot}`);
|
|
10792
11407
|
}
|
|
10793
|
-
const from =
|
|
11408
|
+
const from = join42(packageRoot, legacyName);
|
|
10794
11409
|
const toName = legacyName.endsWith(".jsonc") ? "openpack.jsonc" : "openpack.json";
|
|
10795
|
-
const to =
|
|
10796
|
-
const content = await
|
|
11410
|
+
const to = join42(packageRoot, toName);
|
|
11411
|
+
const content = await readFile31(from, "utf8");
|
|
10797
11412
|
const updated = updateSchemaVersion(content);
|
|
10798
|
-
await
|
|
11413
|
+
await rename5(from, to);
|
|
10799
11414
|
await writeFile21(to, updated, "utf8");
|
|
10800
11415
|
return { changed: true, from, to, message: `Migrated ${legacyName} to ${toName}.` };
|
|
10801
11416
|
}
|
|
10802
11417
|
async function firstExistingLegacyManifest(root) {
|
|
10803
11418
|
for (const name of legacyPackageManifestNames) {
|
|
10804
|
-
if (await pathExists(
|
|
11419
|
+
if (await pathExists(join42(root, name))) return name;
|
|
10805
11420
|
}
|
|
10806
11421
|
return void 0;
|
|
10807
11422
|
}
|
|
@@ -10819,45 +11434,45 @@ function updateSchemaVersion(content) {
|
|
|
10819
11434
|
|
|
10820
11435
|
// src/cli/version.ts
|
|
10821
11436
|
import { readFileSync } from "fs";
|
|
10822
|
-
import { dirname as
|
|
11437
|
+
import { dirname as dirname32, join as join43 } from "path";
|
|
10823
11438
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10824
11439
|
var FALLBACK_VERSION = "0.0.0";
|
|
10825
11440
|
function resolveCliVersion() {
|
|
10826
|
-
let dir =
|
|
11441
|
+
let dir = dirname32(fileURLToPath2(import.meta.url));
|
|
10827
11442
|
while (true) {
|
|
10828
11443
|
try {
|
|
10829
|
-
const pkg = JSON.parse(readFileSync(
|
|
11444
|
+
const pkg = JSON.parse(readFileSync(join43(dir, "package.json"), "utf8"));
|
|
10830
11445
|
if (pkg.name === "agentwheel" && typeof pkg.version === "string") {
|
|
10831
11446
|
return pkg.version;
|
|
10832
11447
|
}
|
|
10833
11448
|
} catch {
|
|
10834
11449
|
}
|
|
10835
|
-
const parent =
|
|
11450
|
+
const parent = dirname32(dir);
|
|
10836
11451
|
if (parent === dir) return FALLBACK_VERSION;
|
|
10837
11452
|
dir = parent;
|
|
10838
11453
|
}
|
|
10839
11454
|
}
|
|
10840
11455
|
|
|
10841
11456
|
// src/version/policy.ts
|
|
10842
|
-
import { execFile as
|
|
10843
|
-
import { readFile as
|
|
10844
|
-
import { join as
|
|
10845
|
-
import { promisify as
|
|
11457
|
+
import { execFile as execFile6 } from "child_process";
|
|
11458
|
+
import { readFile as readFile32 } from "fs/promises";
|
|
11459
|
+
import { join as join44, resolve as resolve20 } from "path";
|
|
11460
|
+
import { promisify as promisify6 } from "util";
|
|
10846
11461
|
import { parse as parseJsonc } from "jsonc-parser";
|
|
10847
|
-
import { z as
|
|
10848
|
-
var
|
|
11462
|
+
import { z as z11 } from "zod";
|
|
11463
|
+
var execFileAsync6 = promisify6(execFile6);
|
|
10849
11464
|
var DEFAULT_VERSION_REFRESH_TTL_SECONDS = 86400;
|
|
10850
|
-
var cachedVersionSchema =
|
|
10851
|
-
version:
|
|
10852
|
-
ref:
|
|
11465
|
+
var cachedVersionSchema = z11.object({
|
|
11466
|
+
version: z11.string().min(1),
|
|
11467
|
+
ref: z11.string().min(1)
|
|
10853
11468
|
});
|
|
10854
|
-
var versionCacheEntrySchema =
|
|
10855
|
-
checkedAt:
|
|
10856
|
-
versions:
|
|
11469
|
+
var versionCacheEntrySchema = z11.object({
|
|
11470
|
+
checkedAt: z11.string().datetime(),
|
|
11471
|
+
versions: z11.array(cachedVersionSchema)
|
|
10857
11472
|
});
|
|
10858
|
-
var versionCacheSchema =
|
|
10859
|
-
schemaVersion:
|
|
10860
|
-
sources:
|
|
11473
|
+
var versionCacheSchema = z11.object({
|
|
11474
|
+
schemaVersion: z11.literal(1),
|
|
11475
|
+
sources: z11.record(z11.string(), versionCacheEntrySchema)
|
|
10861
11476
|
});
|
|
10862
11477
|
async function discoverPackageVersions(pkg, workspaceRoot, options = {}) {
|
|
10863
11478
|
const now = (options.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
@@ -10939,7 +11554,7 @@ async function discoverVersionsFromSource(pkg, workspaceRoot) {
|
|
|
10939
11554
|
const manifest2 = await readPackageManifest(root);
|
|
10940
11555
|
const current = manifest2 ? [{ version: manifest2.version, ref: pkg.requestedRef ?? root }] : [];
|
|
10941
11556
|
try {
|
|
10942
|
-
const { stdout } = await
|
|
11557
|
+
const { stdout } = await execFileAsync6("git", ["-C", root, "remote", "get-url", "origin"]);
|
|
10943
11558
|
return uniqueVersions([
|
|
10944
11559
|
...await discoverGitTagsFromUrl(stdout.trim(), pkg.version, root),
|
|
10945
11560
|
...current
|
|
@@ -10950,7 +11565,7 @@ async function discoverVersionsFromSource(pkg, workspaceRoot) {
|
|
|
10950
11565
|
}
|
|
10951
11566
|
const driver = getSourceDriver(driverName);
|
|
10952
11567
|
const resolved = await driver.resolve(pkg.source, {
|
|
10953
|
-
cacheRoot:
|
|
11568
|
+
cacheRoot: join44(workspaceRoot, ".agentwheel", "cache"),
|
|
10954
11569
|
mode: "tracking",
|
|
10955
11570
|
ref: pkg.requestedRef
|
|
10956
11571
|
});
|
|
@@ -10965,7 +11580,7 @@ async function discoverGitTags(source, policy) {
|
|
|
10965
11580
|
return discoverGitTagsFromUrl(url, policy, localRoot);
|
|
10966
11581
|
}
|
|
10967
11582
|
async function discoverGitTagsFromUrl(url, policy, localRoot) {
|
|
10968
|
-
const { stdout } = await
|
|
11583
|
+
const { stdout } = await execFileAsync6("git", ["ls-remote", "--tags", "--refs", url], {
|
|
10969
11584
|
maxBuffer: 10 * 1024 * 1024
|
|
10970
11585
|
});
|
|
10971
11586
|
const byVersion = /* @__PURE__ */ new Map();
|
|
@@ -11003,7 +11618,7 @@ async function manifestVersionAtRef(url, ref, localRoot) {
|
|
|
11003
11618
|
if (localRoot) {
|
|
11004
11619
|
for (const name of ["openpack.json", "openpack.jsonc"]) {
|
|
11005
11620
|
try {
|
|
11006
|
-
const { stdout } = await
|
|
11621
|
+
const { stdout } = await execFileAsync6("git", ["-C", localRoot, "show", `${ref}:${name}`], {
|
|
11007
11622
|
maxBuffer: 1024 * 1024
|
|
11008
11623
|
});
|
|
11009
11624
|
const parsed = parseJsonc(stdout);
|
|
@@ -11044,27 +11659,27 @@ function gitUrlFromSource(source) {
|
|
|
11044
11659
|
throw new Error(`Version discovery does not support Git source: ${source}`);
|
|
11045
11660
|
}
|
|
11046
11661
|
function versionCachePath(workspaceRoot) {
|
|
11047
|
-
return
|
|
11662
|
+
return join44(workspaceRoot, ".agentwheel", "cache", "version-index.json");
|
|
11048
11663
|
}
|
|
11049
11664
|
async function readVersionCache(path) {
|
|
11050
11665
|
if (!await pathExists(path)) return { schemaVersion: 1, sources: {} };
|
|
11051
11666
|
try {
|
|
11052
|
-
return versionCacheSchema.parse(JSON.parse(await
|
|
11667
|
+
return versionCacheSchema.parse(JSON.parse(await readFile32(path, "utf8")));
|
|
11053
11668
|
} catch {
|
|
11054
11669
|
return { schemaVersion: 1, sources: {} };
|
|
11055
11670
|
}
|
|
11056
11671
|
}
|
|
11057
11672
|
|
|
11058
11673
|
// src/profile/members.ts
|
|
11059
|
-
import { execFile as
|
|
11060
|
-
import { readFile as
|
|
11061
|
-
import { join as
|
|
11062
|
-
import { promisify as
|
|
11063
|
-
import { z as
|
|
11674
|
+
import { execFile as execFile7 } from "child_process";
|
|
11675
|
+
import { readFile as readFile33 } from "fs/promises";
|
|
11676
|
+
import { join as join45, resolve as resolve21 } from "path";
|
|
11677
|
+
import { promisify as promisify7 } from "util";
|
|
11678
|
+
import { z as z13 } from "zod";
|
|
11064
11679
|
|
|
11065
11680
|
// src/status/report.ts
|
|
11066
|
-
import { z as
|
|
11067
|
-
var statusHealthSchema =
|
|
11681
|
+
import { z as z12 } from "zod";
|
|
11682
|
+
var statusHealthSchema = z12.enum([
|
|
11068
11683
|
"PASS",
|
|
11069
11684
|
"WARN",
|
|
11070
11685
|
"FAIL",
|
|
@@ -11073,77 +11688,77 @@ var statusHealthSchema = z11.enum([
|
|
|
11073
11688
|
"INCOMPATIBLE",
|
|
11074
11689
|
"BUSY"
|
|
11075
11690
|
]);
|
|
11076
|
-
var statusPackageSchema =
|
|
11077
|
-
name:
|
|
11078
|
-
source:
|
|
11079
|
-
mode:
|
|
11080
|
-
policy:
|
|
11081
|
-
installed:
|
|
11082
|
-
locked:
|
|
11083
|
-
latestAllowed:
|
|
11084
|
-
latestOverall:
|
|
11085
|
-
availability:
|
|
11086
|
-
checkedAt:
|
|
11087
|
-
error:
|
|
11088
|
-
updateAvailableAllowed:
|
|
11089
|
-
updateAvailableOverall:
|
|
11691
|
+
var statusPackageSchema = z12.object({
|
|
11692
|
+
name: z12.string().min(1),
|
|
11693
|
+
source: z12.string().min(1),
|
|
11694
|
+
mode: z12.enum(["pinned", "tracking"]),
|
|
11695
|
+
policy: z12.string().min(1),
|
|
11696
|
+
installed: z12.string().nullable(),
|
|
11697
|
+
locked: z12.string().nullable(),
|
|
11698
|
+
latestAllowed: z12.string().nullable(),
|
|
11699
|
+
latestOverall: z12.string().nullable(),
|
|
11700
|
+
availability: z12.enum(["FRESH", "STALE", "UNKNOWN"]),
|
|
11701
|
+
checkedAt: z12.string().nullable(),
|
|
11702
|
+
error: z12.string().optional(),
|
|
11703
|
+
updateAvailableAllowed: z12.boolean(),
|
|
11704
|
+
updateAvailableOverall: z12.boolean()
|
|
11090
11705
|
});
|
|
11091
|
-
var statusArtifactSchema =
|
|
11092
|
-
selector:
|
|
11093
|
-
type:
|
|
11094
|
-
name:
|
|
11095
|
-
installName:
|
|
11096
|
-
packageName:
|
|
11097
|
-
packageVersion:
|
|
11098
|
-
hash:
|
|
11099
|
-
installed:
|
|
11706
|
+
var statusArtifactSchema = z12.object({
|
|
11707
|
+
selector: z12.string().min(1),
|
|
11708
|
+
type: z12.string().min(1),
|
|
11709
|
+
name: z12.string().min(1),
|
|
11710
|
+
installName: z12.string().min(1),
|
|
11711
|
+
packageName: z12.string().nullable(),
|
|
11712
|
+
packageVersion: z12.string().nullable(),
|
|
11713
|
+
hash: z12.string().min(16),
|
|
11714
|
+
installed: z12.boolean()
|
|
11100
11715
|
});
|
|
11101
|
-
var statusTargetSchema =
|
|
11102
|
-
adapter:
|
|
11103
|
-
installationType:
|
|
11104
|
-
targetRoot:
|
|
11716
|
+
var statusTargetSchema = z12.object({
|
|
11717
|
+
adapter: z12.string().min(1),
|
|
11718
|
+
installationType: z12.string().min(1),
|
|
11719
|
+
targetRoot: z12.string().min(1),
|
|
11105
11720
|
health: statusHealthSchema,
|
|
11106
|
-
manifestRevision:
|
|
11107
|
-
manifestEntryCount:
|
|
11108
|
-
graphLockPath:
|
|
11109
|
-
packageCount:
|
|
11110
|
-
artifactCount:
|
|
11111
|
-
pendingCount:
|
|
11112
|
-
driftCount:
|
|
11113
|
-
conflictCount:
|
|
11114
|
-
error:
|
|
11115
|
-
packages:
|
|
11116
|
-
artifacts:
|
|
11721
|
+
manifestRevision: z12.string().nullable(),
|
|
11722
|
+
manifestEntryCount: z12.number().int().nonnegative(),
|
|
11723
|
+
graphLockPath: z12.string().nullable(),
|
|
11724
|
+
packageCount: z12.number().int().nonnegative(),
|
|
11725
|
+
artifactCount: z12.number().int().nonnegative(),
|
|
11726
|
+
pendingCount: z12.number().int().nonnegative(),
|
|
11727
|
+
driftCount: z12.number().int().nonnegative(),
|
|
11728
|
+
conflictCount: z12.number().int().nonnegative(),
|
|
11729
|
+
error: z12.string().optional(),
|
|
11730
|
+
packages: z12.array(statusPackageSchema),
|
|
11731
|
+
artifacts: z12.array(statusArtifactSchema)
|
|
11117
11732
|
});
|
|
11118
|
-
var statusReportSchema =
|
|
11119
|
-
schemaVersion:
|
|
11120
|
-
command:
|
|
11121
|
-
agentwheelVersion:
|
|
11122
|
-
generatedAt:
|
|
11123
|
-
workspace:
|
|
11124
|
-
profile:
|
|
11733
|
+
var statusReportSchema = z12.lazy(() => z12.object({
|
|
11734
|
+
schemaVersion: z12.literal(1),
|
|
11735
|
+
command: z12.literal("status"),
|
|
11736
|
+
agentwheelVersion: z12.string().min(1),
|
|
11737
|
+
generatedAt: z12.string().datetime(),
|
|
11738
|
+
workspace: z12.string().min(1),
|
|
11739
|
+
profile: z12.string().nullable(),
|
|
11125
11740
|
health: statusHealthSchema,
|
|
11126
|
-
repository:
|
|
11127
|
-
available:
|
|
11128
|
-
branch:
|
|
11129
|
-
head:
|
|
11130
|
-
upstream:
|
|
11131
|
-
ahead:
|
|
11132
|
-
behind:
|
|
11133
|
-
dirtyCount:
|
|
11134
|
-
error:
|
|
11741
|
+
repository: z12.object({
|
|
11742
|
+
available: z12.boolean(),
|
|
11743
|
+
branch: z12.string().nullable(),
|
|
11744
|
+
head: z12.string().nullable(),
|
|
11745
|
+
upstream: z12.string().nullable(),
|
|
11746
|
+
ahead: z12.number().int().nonnegative(),
|
|
11747
|
+
behind: z12.number().int().nonnegative(),
|
|
11748
|
+
dirtyCount: z12.number().int().nonnegative(),
|
|
11749
|
+
error: z12.string().optional()
|
|
11135
11750
|
}),
|
|
11136
|
-
targets:
|
|
11137
|
-
members:
|
|
11138
|
-
id:
|
|
11139
|
-
transport:
|
|
11140
|
-
workspace:
|
|
11141
|
-
profile:
|
|
11751
|
+
targets: z12.array(statusTargetSchema),
|
|
11752
|
+
members: z12.array(z12.object({
|
|
11753
|
+
id: z12.string().min(1),
|
|
11754
|
+
transport: z12.enum(["local", "ssh"]),
|
|
11755
|
+
workspace: z12.string().min(1),
|
|
11756
|
+
profile: z12.string().min(1),
|
|
11142
11757
|
health: statusHealthSchema,
|
|
11143
|
-
agentwheelVersion:
|
|
11144
|
-
checkedAt:
|
|
11145
|
-
stale:
|
|
11146
|
-
error:
|
|
11758
|
+
agentwheelVersion: z12.string().nullable(),
|
|
11759
|
+
checkedAt: z12.string().nullable(),
|
|
11760
|
+
stale: z12.boolean(),
|
|
11761
|
+
error: z12.string().optional(),
|
|
11147
11762
|
report: statusReportSchema.optional()
|
|
11148
11763
|
}))
|
|
11149
11764
|
}));
|
|
@@ -11167,10 +11782,10 @@ function blocksCompositeApply(health) {
|
|
|
11167
11782
|
}
|
|
11168
11783
|
|
|
11169
11784
|
// src/profile/members.ts
|
|
11170
|
-
var
|
|
11171
|
-
var memberCacheSchema =
|
|
11172
|
-
schemaVersion:
|
|
11173
|
-
checkedAt:
|
|
11785
|
+
var execFileAsync7 = promisify7(execFile7);
|
|
11786
|
+
var memberCacheSchema = z13.object({
|
|
11787
|
+
schemaVersion: z13.literal(1),
|
|
11788
|
+
checkedAt: z13.string().datetime(),
|
|
11174
11789
|
report: statusReportSchema
|
|
11175
11790
|
});
|
|
11176
11791
|
async function collectCompositeMembers(options) {
|
|
@@ -11234,7 +11849,7 @@ async function invokeMemberStatus(member, parentWorkspace, chain, options, cliEn
|
|
|
11234
11849
|
try {
|
|
11235
11850
|
if (member.transport === "local") {
|
|
11236
11851
|
const workspace = resolve21(parentWorkspace, member.workspace);
|
|
11237
|
-
const result = await
|
|
11852
|
+
const result = await execFileAsync7(process.execPath, [cliEntry, ...args], {
|
|
11238
11853
|
cwd: workspace,
|
|
11239
11854
|
env: env2,
|
|
11240
11855
|
maxBuffer: 20 * 1024 * 1024
|
|
@@ -11250,7 +11865,7 @@ async function invokeMemberStatus(member, parentWorkspace, chain, options, cliEn
|
|
|
11250
11865
|
"agentwheel",
|
|
11251
11866
|
...args.map(shellQuote2)
|
|
11252
11867
|
];
|
|
11253
|
-
const result = await
|
|
11868
|
+
const result = await execFileAsync7("ssh", [...sshArgs, remoteArgs.join(" ")], {
|
|
11254
11869
|
env: env2,
|
|
11255
11870
|
maxBuffer: 20 * 1024 * 1024
|
|
11256
11871
|
});
|
|
@@ -11275,7 +11890,7 @@ async function runMemberAgentwheel(member, parentWorkspace, args, chain) {
|
|
|
11275
11890
|
const env2 = { ...process.env, AGENTWHEEL_COMPOSITE_CHAIN: JSON.stringify(chain) };
|
|
11276
11891
|
try {
|
|
11277
11892
|
if (member.transport === "local") {
|
|
11278
|
-
const result2 = await
|
|
11893
|
+
const result2 = await execFileAsync7(
|
|
11279
11894
|
process.execPath,
|
|
11280
11895
|
[process.argv[1], "--no-update-check", ...args],
|
|
11281
11896
|
{
|
|
@@ -11294,7 +11909,7 @@ async function runMemberAgentwheel(member, parentWorkspace, args, chain) {
|
|
|
11294
11909
|
"--no-update-check",
|
|
11295
11910
|
...args.map(shellQuote2)
|
|
11296
11911
|
];
|
|
11297
|
-
const result = await
|
|
11912
|
+
const result = await execFileAsync7("ssh", [...sshArguments(member), remoteArgs.join(" ")], {
|
|
11298
11913
|
env: env2,
|
|
11299
11914
|
maxBuffer: 20 * 1024 * 1024
|
|
11300
11915
|
});
|
|
@@ -11354,12 +11969,12 @@ function memberFailure(member, health, error) {
|
|
|
11354
11969
|
};
|
|
11355
11970
|
}
|
|
11356
11971
|
function memberCachePath(workspaceRoot, profileName, memberId) {
|
|
11357
|
-
return
|
|
11972
|
+
return join45(workspaceRoot, ".agentwheel", "cache", "member-status", profileName, `${memberId}.json`);
|
|
11358
11973
|
}
|
|
11359
11974
|
async function readMemberCache(path) {
|
|
11360
11975
|
if (!await pathExists(path)) return void 0;
|
|
11361
11976
|
try {
|
|
11362
|
-
return memberCacheSchema.parse(JSON.parse(await
|
|
11977
|
+
return memberCacheSchema.parse(JSON.parse(await readFile33(path, "utf8")));
|
|
11363
11978
|
} catch {
|
|
11364
11979
|
return void 0;
|
|
11365
11980
|
}
|
|
@@ -11368,7 +11983,7 @@ function parseCompositeChain() {
|
|
|
11368
11983
|
const value = process.env.AGENTWHEEL_COMPOSITE_CHAIN;
|
|
11369
11984
|
if (!value) return [];
|
|
11370
11985
|
try {
|
|
11371
|
-
return
|
|
11986
|
+
return z13.array(z13.string()).parse(JSON.parse(value));
|
|
11372
11987
|
} catch {
|
|
11373
11988
|
throw new Error("Invalid AGENTWHEEL_COMPOSITE_CHAIN protocol value.");
|
|
11374
11989
|
}
|
|
@@ -11384,12 +11999,12 @@ function compositeKey(workspaceRoot, profileName) {
|
|
|
11384
11999
|
}
|
|
11385
12000
|
|
|
11386
12001
|
// src/status/repository.ts
|
|
11387
|
-
import { execFile as
|
|
11388
|
-
import { promisify as
|
|
11389
|
-
var
|
|
12002
|
+
import { execFile as execFile8 } from "child_process";
|
|
12003
|
+
import { promisify as promisify8 } from "util";
|
|
12004
|
+
var execFileAsync8 = promisify8(execFile8);
|
|
11390
12005
|
async function collectRepositoryStatus(workspaceRoot) {
|
|
11391
12006
|
try {
|
|
11392
|
-
const { stdout } = await
|
|
12007
|
+
const { stdout } = await execFileAsync8(
|
|
11393
12008
|
"git",
|
|
11394
12009
|
["-C", workspaceRoot, "status", "--porcelain=v2", "--branch"],
|
|
11395
12010
|
{ maxBuffer: 10 * 1024 * 1024 }
|
|
@@ -11427,16 +12042,16 @@ function valueAfter(lines, prefix) {
|
|
|
11427
12042
|
}
|
|
11428
12043
|
|
|
11429
12044
|
// src/catalogue/client.ts
|
|
11430
|
-
import { createHash as
|
|
11431
|
-
import { readFile as
|
|
12045
|
+
import { createHash as createHash12 } from "crypto";
|
|
12046
|
+
import { readFile as readFile34, rm as rm12 } from "fs/promises";
|
|
11432
12047
|
import { homedir as homedir10 } from "os";
|
|
11433
|
-
import { join as
|
|
12048
|
+
import { join as join46 } from "path";
|
|
11434
12049
|
|
|
11435
12050
|
// src/model/catalogue.ts
|
|
11436
|
-
import { z as
|
|
11437
|
-
var searchScopeSchema =
|
|
11438
|
-
var searchTypeSchema =
|
|
11439
|
-
var searchEcosystemSchema =
|
|
12051
|
+
import { z as z14 } from "zod";
|
|
12052
|
+
var searchScopeSchema = z14.enum(["all", "registry", "enriched", "vercel"]);
|
|
12053
|
+
var searchTypeSchema = z14.enum(["package", "skill", "plugin", "mcp", "adapter"]);
|
|
12054
|
+
var searchEcosystemSchema = z14.enum([
|
|
11440
12055
|
"official",
|
|
11441
12056
|
"openpack",
|
|
11442
12057
|
"mcp-registry",
|
|
@@ -11444,13 +12059,13 @@ var searchEcosystemSchema = z13.enum([
|
|
|
11444
12059
|
"skillkit",
|
|
11445
12060
|
"vercel"
|
|
11446
12061
|
]);
|
|
11447
|
-
var catalogueProvenanceSchema =
|
|
11448
|
-
var installabilitySchema =
|
|
11449
|
-
var nullableString =
|
|
11450
|
-
var nullableStringArray =
|
|
11451
|
-
var enrichedCatalogueEntrySchema =
|
|
11452
|
-
id:
|
|
11453
|
-
name:
|
|
12062
|
+
var catalogueProvenanceSchema = z14.enum(["registry", "enriched", "vercel"]);
|
|
12063
|
+
var installabilitySchema = z14.enum(["registry", "source", "informational"]);
|
|
12064
|
+
var nullableString = z14.string().nullable();
|
|
12065
|
+
var nullableStringArray = z14.array(z14.string()).nullable();
|
|
12066
|
+
var enrichedCatalogueEntrySchema = z14.object({
|
|
12067
|
+
id: z14.string().min(1),
|
|
12068
|
+
name: z14.string().min(1),
|
|
11454
12069
|
ecosystem: searchEcosystemSchema.nullable(),
|
|
11455
12070
|
type: searchTypeSchema.nullable(),
|
|
11456
12071
|
description: nullableString,
|
|
@@ -11460,17 +12075,17 @@ var enrichedCatalogueEntrySchema = z13.object({
|
|
|
11460
12075
|
repoUrl: nullableString,
|
|
11461
12076
|
homepageUrl: nullableString.optional(),
|
|
11462
12077
|
homepageLinkLabel: nullableString.optional(),
|
|
11463
|
-
stars:
|
|
12078
|
+
stars: z14.number().finite().nullable().optional(),
|
|
11464
12079
|
lastPush: nullableString.optional(),
|
|
11465
|
-
archived:
|
|
12080
|
+
archived: z14.boolean().nullable(),
|
|
11466
12081
|
provides: nullableStringArray,
|
|
11467
12082
|
version: nullableString,
|
|
11468
|
-
featured:
|
|
12083
|
+
featured: z14.boolean().nullable().optional()
|
|
11469
12084
|
});
|
|
11470
|
-
var enrichedCatalogueSchema =
|
|
11471
|
-
schemaVersion:
|
|
11472
|
-
generatedAt:
|
|
11473
|
-
entries:
|
|
12085
|
+
var enrichedCatalogueSchema = z14.object({
|
|
12086
|
+
schemaVersion: z14.literal(1),
|
|
12087
|
+
generatedAt: z14.string().datetime(),
|
|
12088
|
+
entries: z14.array(enrichedCatalogueEntrySchema)
|
|
11474
12089
|
}).superRefine((value, context) => {
|
|
11475
12090
|
const seen = /* @__PURE__ */ new Set();
|
|
11476
12091
|
value.entries.forEach((entry, index) => {
|
|
@@ -11484,17 +12099,17 @@ var enrichedCatalogueSchema = z13.object({
|
|
|
11484
12099
|
seen.add(entry.id);
|
|
11485
12100
|
});
|
|
11486
12101
|
});
|
|
11487
|
-
var vercelCatalogueEntrySchema =
|
|
11488
|
-
o:
|
|
11489
|
-
r:
|
|
11490
|
-
s:
|
|
11491
|
-
d:
|
|
12102
|
+
var vercelCatalogueEntrySchema = z14.object({
|
|
12103
|
+
o: z14.string().min(1),
|
|
12104
|
+
r: z14.string().min(1),
|
|
12105
|
+
s: z14.string().min(1),
|
|
12106
|
+
d: z14.string().nullable().optional()
|
|
11492
12107
|
});
|
|
11493
|
-
var vercelCatalogueSchema =
|
|
11494
|
-
schemaVersion:
|
|
11495
|
-
generatedAt:
|
|
11496
|
-
count:
|
|
11497
|
-
entries:
|
|
12108
|
+
var vercelCatalogueSchema = z14.object({
|
|
12109
|
+
schemaVersion: z14.literal(1),
|
|
12110
|
+
generatedAt: z14.string().datetime(),
|
|
12111
|
+
count: z14.number().int().nonnegative(),
|
|
12112
|
+
entries: z14.array(vercelCatalogueEntrySchema)
|
|
11498
12113
|
}).superRefine((value, context) => {
|
|
11499
12114
|
if (value.count !== value.entries.length) {
|
|
11500
12115
|
context.addIssue({
|
|
@@ -11516,53 +12131,53 @@ var vercelCatalogueSchema = z13.object({
|
|
|
11516
12131
|
seen.add(id);
|
|
11517
12132
|
});
|
|
11518
12133
|
});
|
|
11519
|
-
var catalogueCacheSchema =
|
|
11520
|
-
version:
|
|
11521
|
-
fetchedAt:
|
|
11522
|
-
sources:
|
|
12134
|
+
var catalogueCacheSchema = z14.object({
|
|
12135
|
+
version: z14.literal(1),
|
|
12136
|
+
fetchedAt: z14.string().datetime(),
|
|
12137
|
+
sources: z14.tuple([z14.string().url(), z14.string().url()]),
|
|
11523
12138
|
enriched: enrichedCatalogueSchema,
|
|
11524
12139
|
vercel: vercelCatalogueSchema,
|
|
11525
|
-
sourceDigests:
|
|
11526
|
-
enriched:
|
|
11527
|
-
vercel:
|
|
12140
|
+
sourceDigests: z14.object({
|
|
12141
|
+
enriched: z14.string().regex(/^[a-f0-9]{64}$/),
|
|
12142
|
+
vercel: z14.string().regex(/^[a-f0-9]{64}$/)
|
|
11528
12143
|
}).optional()
|
|
11529
12144
|
});
|
|
11530
|
-
var catalogueCacheEnvelopeSchema =
|
|
11531
|
-
version:
|
|
11532
|
-
fetchedAt:
|
|
11533
|
-
sources:
|
|
11534
|
-
contentHash:
|
|
11535
|
-
sourceDigests:
|
|
11536
|
-
enriched:
|
|
11537
|
-
vercel:
|
|
12145
|
+
var catalogueCacheEnvelopeSchema = z14.object({
|
|
12146
|
+
version: z14.literal(1),
|
|
12147
|
+
fetchedAt: z14.string().datetime(),
|
|
12148
|
+
sources: z14.tuple([z14.string().url(), z14.string().url()]),
|
|
12149
|
+
contentHash: z14.string().regex(/^[a-f0-9]{64}$/).optional(),
|
|
12150
|
+
sourceDigests: z14.object({
|
|
12151
|
+
enriched: z14.string().regex(/^[a-f0-9]{64}$/),
|
|
12152
|
+
vercel: z14.string().regex(/^[a-f0-9]{64}$/)
|
|
11538
12153
|
}).optional(),
|
|
11539
|
-
enriched:
|
|
11540
|
-
vercel:
|
|
12154
|
+
enriched: z14.unknown(),
|
|
12155
|
+
vercel: z14.unknown()
|
|
11541
12156
|
});
|
|
11542
|
-
var searchResultSchema =
|
|
11543
|
-
id:
|
|
11544
|
-
name:
|
|
11545
|
-
description:
|
|
12157
|
+
var searchResultSchema = z14.object({
|
|
12158
|
+
id: z14.string().min(1),
|
|
12159
|
+
name: z14.string().min(1),
|
|
12160
|
+
description: z14.string(),
|
|
11546
12161
|
type: searchTypeSchema,
|
|
11547
12162
|
ecosystem: searchEcosystemSchema.optional(),
|
|
11548
|
-
tags:
|
|
11549
|
-
provides:
|
|
11550
|
-
source:
|
|
11551
|
-
repoUrl:
|
|
11552
|
-
installCommand:
|
|
12163
|
+
tags: z14.array(z14.string()),
|
|
12164
|
+
provides: z14.array(z14.string()),
|
|
12165
|
+
source: z14.string().min(1).optional(),
|
|
12166
|
+
repoUrl: z14.string().min(1).optional(),
|
|
12167
|
+
installCommand: z14.string().min(1).optional(),
|
|
11553
12168
|
installability: installabilitySchema,
|
|
11554
|
-
provenances:
|
|
11555
|
-
score:
|
|
11556
|
-
matchedFields:
|
|
11557
|
-
semanticScore:
|
|
12169
|
+
provenances: z14.array(catalogueProvenanceSchema).min(1),
|
|
12170
|
+
score: z14.number().int().nonnegative(),
|
|
12171
|
+
matchedFields: z14.array(z14.string()),
|
|
12172
|
+
semanticScore: z14.number().finite().optional()
|
|
11558
12173
|
});
|
|
11559
|
-
var searchResponseSchema =
|
|
11560
|
-
schemaVersion:
|
|
11561
|
-
query:
|
|
12174
|
+
var searchResponseSchema = z14.object({
|
|
12175
|
+
schemaVersion: z14.literal(1),
|
|
12176
|
+
query: z14.string(),
|
|
11562
12177
|
scope: searchScopeSchema,
|
|
11563
|
-
fromCache:
|
|
11564
|
-
searchMode:
|
|
11565
|
-
results:
|
|
12178
|
+
fromCache: z14.boolean(),
|
|
12179
|
+
searchMode: z14.enum(["lexical", "semantic"]).optional(),
|
|
12180
|
+
results: z14.array(searchResultSchema)
|
|
11566
12181
|
});
|
|
11567
12182
|
|
|
11568
12183
|
// src/catalogue/client.ts
|
|
@@ -11641,12 +12256,12 @@ var CatalogueClient = class {
|
|
|
11641
12256
|
}
|
|
11642
12257
|
}
|
|
11643
12258
|
async clearCache() {
|
|
11644
|
-
await
|
|
12259
|
+
await rm12(this.cachePath, { force: true });
|
|
11645
12260
|
}
|
|
11646
12261
|
async readCache() {
|
|
11647
12262
|
if (!await pathExists(this.cachePath)) return void 0;
|
|
11648
12263
|
try {
|
|
11649
|
-
const value = JSON.parse(await
|
|
12264
|
+
const value = JSON.parse(await readFile34(this.cachePath, "utf8"));
|
|
11650
12265
|
const envelope = catalogueCacheEnvelopeSchema.parse(value);
|
|
11651
12266
|
if (envelope.contentHash) {
|
|
11652
12267
|
const contentHash = catalogueContentHash(envelope.enriched, envelope.vercel);
|
|
@@ -11702,18 +12317,18 @@ var CatalogueClient = class {
|
|
|
11702
12317
|
}
|
|
11703
12318
|
return {
|
|
11704
12319
|
value: schema.parse(value),
|
|
11705
|
-
digest:
|
|
12320
|
+
digest: createHash12("sha256").update(bytes).digest("hex")
|
|
11706
12321
|
};
|
|
11707
12322
|
}
|
|
11708
12323
|
};
|
|
11709
12324
|
function defaultCatalogueCachePath() {
|
|
11710
|
-
return
|
|
12325
|
+
return join46(homedir10(), ".agentwheel", "catalogue-cache.json");
|
|
11711
12326
|
}
|
|
11712
12327
|
function sameSources2(a, b) {
|
|
11713
12328
|
return a.length === b.length && a.every((source, index) => source === b[index]);
|
|
11714
12329
|
}
|
|
11715
12330
|
function catalogueContentHash(enriched, vercel) {
|
|
11716
|
-
return
|
|
12331
|
+
return createHash12("sha256").update(JSON.stringify({ enriched, vercel })).digest("hex");
|
|
11717
12332
|
}
|
|
11718
12333
|
|
|
11719
12334
|
// src/search/index.ts
|
|
@@ -12075,9 +12690,9 @@ function includesToken(normalizedText, token) {
|
|
|
12075
12690
|
}
|
|
12076
12691
|
|
|
12077
12692
|
// src/semantic/index.ts
|
|
12078
|
-
import { createHash as
|
|
12693
|
+
import { createHash as createHash13 } from "crypto";
|
|
12079
12694
|
import { homedir as homedir11 } from "os";
|
|
12080
|
-
import { join as
|
|
12695
|
+
import { join as join47 } from "path";
|
|
12081
12696
|
import { env, pipeline } from "@huggingface/transformers";
|
|
12082
12697
|
var DEFAULT_SEMANTIC_INDEX_URL = "https://raw.githubusercontent.com/NestDevLab/agentwheel-registry/main/catalogue-semantic-index/gte-v1/";
|
|
12083
12698
|
var CONTRACT = {
|
|
@@ -12165,13 +12780,13 @@ var SemanticSearchClient = class {
|
|
|
12165
12780
|
if (!response.ok) throw new Error(`Semantic index file failed (${response.status}): ${descriptor.path}`);
|
|
12166
12781
|
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
12167
12782
|
if (bytes.byteLength !== descriptor.bytes) throw new Error(`Semantic index file size does not match: ${descriptor.path}`);
|
|
12168
|
-
const digest =
|
|
12783
|
+
const digest = createHash13("sha256").update(bytes).digest("hex");
|
|
12169
12784
|
if (digest !== descriptor.sha256) throw new Error(`Semantic index checksum does not match: ${descriptor.path}`);
|
|
12170
12785
|
return bytes;
|
|
12171
12786
|
}
|
|
12172
12787
|
};
|
|
12173
12788
|
async function embedQuery(query) {
|
|
12174
|
-
env.cacheDir =
|
|
12789
|
+
env.cacheDir = join47(homedir11(), ".agentwheel", "semantic-models");
|
|
12175
12790
|
const extractor = await pipeline("feature-extraction", CONTRACT.model.id, {
|
|
12176
12791
|
revision: CONTRACT.model.revision,
|
|
12177
12792
|
dtype: CONTRACT.model.dtype,
|
|
@@ -12255,9 +12870,9 @@ function ensureTrailingSlash(value) {
|
|
|
12255
12870
|
}
|
|
12256
12871
|
|
|
12257
12872
|
// src/trial/skill.ts
|
|
12258
|
-
import { createHash as
|
|
12259
|
-
import { readFile as
|
|
12260
|
-
import { join as
|
|
12873
|
+
import { createHash as createHash14 } from "crypto";
|
|
12874
|
+
import { readFile as readFile35, stat as stat13 } from "fs/promises";
|
|
12875
|
+
import { join as join48 } from "path";
|
|
12261
12876
|
import { parse as parseYaml2 } from "yaml";
|
|
12262
12877
|
var MAX_TRIAL_SKILL_BYTES = 512 * 1024;
|
|
12263
12878
|
async function createSkillTrial(driver, resolved, selectors) {
|
|
@@ -12269,12 +12884,12 @@ async function createSkillTrial(driver, resolved, selectors) {
|
|
|
12269
12884
|
throw new Error("Skill trial requires exactly one selected skill. Use --skill <name> or --select skills/<name>.");
|
|
12270
12885
|
}
|
|
12271
12886
|
const artifact = skills[0];
|
|
12272
|
-
const path = artifact.kind === "dir" ?
|
|
12273
|
-
const info = await
|
|
12887
|
+
const path = artifact.kind === "dir" ? join48(artifact.sourcePath, "SKILL.md") : artifact.sourcePath;
|
|
12888
|
+
const info = await stat13(path);
|
|
12274
12889
|
if (info.size > MAX_TRIAL_SKILL_BYTES) {
|
|
12275
12890
|
throw new Error(`Skill trial exceeds the ${MAX_TRIAL_SKILL_BYTES / 1024} KiB content limit.`);
|
|
12276
12891
|
}
|
|
12277
|
-
const content = await
|
|
12892
|
+
const content = await readFile35(path, "utf8");
|
|
12278
12893
|
const frontmatter = readSkillFrontmatter(content, artifact);
|
|
12279
12894
|
return {
|
|
12280
12895
|
schemaVersion: 1,
|
|
@@ -12285,7 +12900,7 @@ async function createSkillTrial(driver, resolved, selectors) {
|
|
|
12285
12900
|
skill: {
|
|
12286
12901
|
name: artifact.name,
|
|
12287
12902
|
relativePath: artifact.relativePath,
|
|
12288
|
-
sha256:
|
|
12903
|
+
sha256: createHash14("sha256").update(content).digest("hex"),
|
|
12289
12904
|
frontmatter,
|
|
12290
12905
|
content
|
|
12291
12906
|
}
|
|
@@ -12334,6 +12949,15 @@ program.command("init").description("initialize an agentwheel workspace or packa
|
|
|
12334
12949
|
if (bootstrapPackage) console.log("Auto-added the agentwheel bootstrap skill for openclaw.");
|
|
12335
12950
|
console.log(nextInstallNudge());
|
|
12336
12951
|
});
|
|
12952
|
+
var cacheCommand = program.command("cache").description("inspect and maintain local source caches");
|
|
12953
|
+
cacheCommand.command("prune").description("remove old Git source snapshots while preserving locked commits").option("-t, --target-root <path>", "workspace root", process.cwd()).option("--keep <count>", "newest snapshots to retain per source", parsePositiveInteger, 3).option("--apply", "delete the selected snapshots; without this flag only preview", false).action(async (options) => {
|
|
12954
|
+
const targetRoot = normalizeTargetRoot(options.targetRoot);
|
|
12955
|
+
const cacheRoot = join49(targetRoot, ".agentwheel", "cache");
|
|
12956
|
+
const result = await pruneGitCache(cacheRoot, { keepSnapshots: options.keep, dryRun: !options.apply });
|
|
12957
|
+
const verb = options.apply ? "Removed" : "Would remove";
|
|
12958
|
+
for (const path of result.removedPaths) console.log(`${verb} ${path}`);
|
|
12959
|
+
console.log(`${options.apply ? "Pruned" : "Preview"}: ${result.removedPaths.length} snapshots; retained ${result.retainedPaths.length}.`);
|
|
12960
|
+
});
|
|
12337
12961
|
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, vercel-skills, mcp-registry, or clawhub)").option("--adapter <adapter>", "built-in adapter", "openclaw").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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>", "workspace root").option("--mode <mode>", "pinned or tracking", "pinned").option("--version <range>", "root package version policy (exact, ~, ^, or *)").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("--with-suggestions", "include suggested companion artifacts for selected roots on future installs", false).option("--suggestion <alias>", "include one suggested companion alias on future installs (repeatable or comma-separated)", collectSuggestionOption, []).option("--override <source-or-package::type/name>", "allow this package to replace a colliding artifact (repeatable)", collectOverrideOption, []).action(async (source, options) => {
|
|
12338
12962
|
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
12339
12963
|
const targetRoot = normalizeTargetRoot(normalizedOptions.targetRoot ?? process.cwd());
|
|
@@ -12346,10 +12970,14 @@ program.command("list").description("list artifacts exposed by a package source"
|
|
|
12346
12970
|
const resolvedInput = await resolvePackageSource(source, targetRoot);
|
|
12347
12971
|
const selectedArtifacts = selectedArtifactsFromOptionsOrRegistry(options, resolvedInput.registryEntry);
|
|
12348
12972
|
const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
|
|
12349
|
-
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot:
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12973
|
+
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join49(targetRoot, ".agentwheel", "cache") }))));
|
|
12974
|
+
try {
|
|
12975
|
+
const artifacts = filterArtifactsBySelection(await driver.list(resolved), selectedArtifacts);
|
|
12976
|
+
for (const artifact of artifacts) {
|
|
12977
|
+
console.log(`${artifact.type} ${artifact.name} ${artifact.relativePath}`);
|
|
12978
|
+
}
|
|
12979
|
+
} finally {
|
|
12980
|
+
await releaseGitSnapshotLease(resolved.cacheLeasePath);
|
|
12353
12981
|
}
|
|
12354
12982
|
});
|
|
12355
12983
|
program.command("search").description("search registry and public catalogue artifacts").argument("<query>", "search query").option("--json", "print the versioned search response as JSON", false).option("--scope <scope>", "search scope: all, registry, enriched, or vercel", "all").option("--type <type>", "artifact type: package, skill, plugin, mcp, or adapter").option("--ecosystem <ecosystem>", "ecosystem: official, openpack, mcp-registry, clawhub, skillkit, or vercel").option("--limit <n>", "maximum number of results (1-100)", "20").option("--include-archived", "include archived catalogue entries", false).option("--refresh", "refresh registry and catalogue caches", false).option("--offline", "use compatible local caches without network access", false).option("--semantic", "rank published catalogue entries with the verified semantic index", false).option("-t, --target-root <path>", "workspace root", process.cwd()).action(async (query, options) => {
|
|
@@ -12411,42 +13039,50 @@ program.command("try").description("read and validate one skill for the current
|
|
|
12411
13039
|
const resolvedInput = await resolvePackageSource(source, targetRoot);
|
|
12412
13040
|
const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
|
|
12413
13041
|
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, {
|
|
12414
|
-
cacheRoot:
|
|
13042
|
+
cacheRoot: join49(targetRoot, ".agentwheel", "cache")
|
|
12415
13043
|
}))));
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
13044
|
+
try {
|
|
13045
|
+
const trial = await createSkillTrial(driver, resolved, selectedArtifactsFromOptionsOrRegistry(options, resolvedInput.registryEntry));
|
|
13046
|
+
if (options.json) {
|
|
13047
|
+
console.log(JSON.stringify(trial, null, 2));
|
|
13048
|
+
return;
|
|
13049
|
+
}
|
|
13050
|
+
console.log(`Read-only skill trial: ${trial.skill.name}`);
|
|
13051
|
+
console.log(`Source: ${trial.source}`);
|
|
13052
|
+
console.log(`Description: ${trial.skill.frontmatter.description}`);
|
|
13053
|
+
console.log("No configuration or runtime files were changed.");
|
|
13054
|
+
console.log("\n--- SKILL.md ---\n");
|
|
13055
|
+
console.log(trial.skill.content);
|
|
13056
|
+
} finally {
|
|
13057
|
+
await releaseGitSnapshotLease(resolved.cacheLeasePath);
|
|
12420
13058
|
}
|
|
12421
|
-
console.log(`Read-only skill trial: ${trial.skill.name}`);
|
|
12422
|
-
console.log(`Source: ${trial.source}`);
|
|
12423
|
-
console.log(`Description: ${trial.skill.frontmatter.description}`);
|
|
12424
|
-
console.log("No configuration or runtime files were changed.");
|
|
12425
|
-
console.log("\n--- SKILL.md ---\n");
|
|
12426
|
-
console.log(trial.skill.content);
|
|
12427
13059
|
});
|
|
12428
13060
|
program.command("scan").description("scan a package source for validation findings").argument("<source>", "package source").option("--driver <driver>", "source driver").option("-t, --target-root <path>", "workspace root", process.cwd()).action(async (source, options) => {
|
|
12429
13061
|
const targetRoot = normalizeTargetRoot(options.targetRoot);
|
|
12430
13062
|
const resolvedInput = await resolvePackageSource(source, targetRoot);
|
|
12431
13063
|
const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
|
|
12432
|
-
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot:
|
|
12433
|
-
|
|
12434
|
-
|
|
12435
|
-
|
|
12436
|
-
|
|
12437
|
-
|
|
12438
|
-
|
|
13064
|
+
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join49(targetRoot, ".agentwheel", "cache") }))));
|
|
13065
|
+
try {
|
|
13066
|
+
const result = await driver.scan(resolved);
|
|
13067
|
+
if (result.findings.length === 0) {
|
|
13068
|
+
console.log("Scan ok: no findings");
|
|
13069
|
+
} else {
|
|
13070
|
+
for (const finding of result.findings) {
|
|
13071
|
+
console.log(`${finding.level.toUpperCase()}: ${finding.message}${finding.path ? ` (${finding.path})` : ""}`);
|
|
13072
|
+
}
|
|
12439
13073
|
}
|
|
13074
|
+
if (!result.ok) process.exitCode = 1;
|
|
13075
|
+
} finally {
|
|
13076
|
+
await releaseGitSnapshotLease(resolved.cacheLeasePath);
|
|
12440
13077
|
}
|
|
12441
|
-
if (!result.ok) process.exitCode = 1;
|
|
12442
13078
|
});
|
|
12443
|
-
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", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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-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", "
|
|
13079
|
+
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", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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-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) => {
|
|
12444
13080
|
await runInstallCommand(source, { ...options, dryRun: true }, { apply: false });
|
|
12445
13081
|
});
|
|
12446
|
-
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", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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-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", "
|
|
13082
|
+
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", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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-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) => {
|
|
12447
13083
|
await runInstallCommand(source, options, { apply: !options.dryRun });
|
|
12448
13084
|
});
|
|
12449
|
-
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", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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-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", "
|
|
13085
|
+
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", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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-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) => {
|
|
12450
13086
|
await servePlanDashboard({
|
|
12451
13087
|
bind: options.bind,
|
|
12452
13088
|
port: parseServePort(options.port),
|
|
@@ -12455,11 +13091,13 @@ program.command("serve").description("serve a read-only live dashboard for the r
|
|
|
12455
13091
|
buildReport: () => buildPlanReport(source, options)
|
|
12456
13092
|
});
|
|
12457
13093
|
});
|
|
12458
|
-
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 or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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("--force-drift", "replace drifted managed artifacts", 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", "
|
|
13094
|
+
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 or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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("--force-drift", "replace drifted managed artifacts", 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, []).action(async (source, options) => {
|
|
12459
13095
|
console.error("warning: 'agentwheel sync' is deprecated and will be removed in 0.10. Use 'agentwheel install'.");
|
|
12460
13096
|
await runInstallCommand(source, options, { apply: !options.dryRun });
|
|
12461
13097
|
});
|
|
12462
|
-
program.command("update").description("re-resolve tracking packages, then apply the result").argument("[name]", "configured package name or source to update").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).option("-t, --target-root <path>", "workspace root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plans without writing", false).option("--force-drift", "replace drifted managed artifacts", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--execute-plugins", "execute semantic plugin installs", false).option("--reload-runtimes", "run configured runtime reload commands after executed semantic plugin changes", false).option("--restart-runtimes", "alias for --reload-runtimes", false).option("--allow-adapter-code", "allow loading local adapter code from configured packages", false).option("--select <type/name>", "temporarily select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "temporarily select a skill by name (repeatable or comma-separated)", collectSkillOption, []).option("--dependency <name-or-source>", "update one tracking dependency while keeping unrelated graph nodes locked (repeatable)", collectDependencyOption, []).option("--with-suggestions", "include suggested companion artifacts for selected roots", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (name, options) => {
|
|
13098
|
+
program.command("update").description("re-resolve tracking packages, then apply the result").argument("[name]", "configured package name or source to update").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).option("-t, --target-root <path>", "workspace root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plans without writing", false).option("--force-drift", "replace drifted managed artifacts", false).option("--force-conflict", "adopt unmanaged destinations when their content already matches the desired artifact", false).option("--replace-conflict", "replace unmanaged destinations even when their content differs", false).option("--execute-plugins", "execute semantic plugin installs", false).option("--reload-runtimes", "run configured runtime reload commands after executed semantic plugin changes", false).option("--restart-runtimes", "alias for --reload-runtimes", false).option("--allow-adapter-code", "allow loading local adapter code from configured packages", false).option("--select <type/name>", "temporarily select an artifact by type/name (repeatable or comma-separated)", collectSelectOption, []).option("--skill <name>", "temporarily select a skill by name (repeatable or comma-separated)", collectSkillOption, []).option("--dependency <name-or-source>", "update one tracking dependency while keeping unrelated graph nodes locked (repeatable)", collectDependencyOption, []).option("--with-suggestions", "include suggested companion artifacts for selected roots", false).option("--suggestion <alias>", "include one suggested companion alias (repeatable or comma-separated)", collectSuggestionOption, []).option("--no-deps", "resolve only root sources and ignore requires with a warning").option("--only-source", "exclude unrelated configured workspace packages", false).option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (name, options) => {
|
|
13099
|
+
if (options.onlySource && options.dependency.length > 0) throw new Error("--only-source cannot be combined with --dependency.");
|
|
13100
|
+
if (options.onlySource && !name) throw new Error("--only-source requires a configured package argument.");
|
|
12463
13101
|
if (name && options.dependency.length > 0) throw new Error("A package argument cannot be combined with --dependency.");
|
|
12464
13102
|
if (options.dependency.length > 0 && (options.select.length > 0 || options.skill.length > 0)) {
|
|
12465
13103
|
throw new Error("--dependency cannot be combined with --select or --skill; package selections remain unchanged.");
|
|
@@ -12478,6 +13116,11 @@ program.command("update").description("re-resolve tracking packages, then apply
|
|
|
12478
13116
|
await runConfiguredGraphPackages(target, { ...normalizedOptions, scope: name }, { mode: "update" });
|
|
12479
13117
|
}
|
|
12480
13118
|
});
|
|
13119
|
+
program.command("skill").description("operate on configured skills").addCommand(
|
|
13120
|
+
new Command("update").description("reconcile one skill through its configured owning package").argument("<name>", "configured skill name").option("--package <name>", "owning configured package when automatic ownership is ambiguous").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).option("-t, --target-root <path>", "workspace root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--profile <name>", "workspace runtime profile").option("--dry-run", "show plans without writing", false).option("--adopt", "replace unmanaged destinations in the owning package closure", false).option("--force-drift", "replace drifted managed artifacts", false).option("--allow-adapter-code", "allow loading local adapter code from the owning package", false).option("--no-deps", "resolve only the owning package and ignore its requires with a warning").option("--frozen-lock", "resolve strictly from the existing graph lock and cached sources", false).option("--offline", "resolve strictly from graph locks and local caches", false).option("--refresh", "refresh available package versions even when the version-index TTL is fresh", false).option("--yes", "trust all new transitive sources", false).option("--trust <pattern>", "pre-approve a transitive source glob (repeatable)", collectTrustOption, []).action(async (name, options) => {
|
|
13121
|
+
await runSkillUpdateCommand(name, options);
|
|
13122
|
+
})
|
|
13123
|
+
);
|
|
12481
13124
|
program.command("deps").description("inspect the OpenPack dependency graph").addCommand(
|
|
12482
13125
|
new Command("tree").description("print the OpenPack dependency graph").argument("[source]", "optional package source to resolve").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).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("--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("--no-deps", "resolve only root sources and ignore requires with a warning").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) => {
|
|
12483
13126
|
const normalizedOptions = normalizeRuntimeScopeOptions(options, { defaultUser: shouldDefaultUserInstall(source, options) });
|
|
@@ -12492,7 +13135,7 @@ program.command("deps").description("inspect the OpenPack dependency graph").add
|
|
|
12492
13135
|
for (const decision of result.bundle.graphLock.canonical.overrides) {
|
|
12493
13136
|
console.log(`OVERRIDE ${decision.graphNodeId}:${decision.type}/${decision.name} replaces ${decision.overriddenGraphNodeId}:${decision.type}/${decision.name} via ${decision.rootId} (${decision.selector})`);
|
|
12494
13137
|
}
|
|
12495
|
-
await
|
|
13138
|
+
await rm13(result.bundle.root, { recursive: true, force: true });
|
|
12496
13139
|
}
|
|
12497
13140
|
continue;
|
|
12498
13141
|
}
|
|
@@ -12621,6 +13264,11 @@ ownershipCommand.command("handoff").description("transfer one managed artifact b
|
|
|
12621
13264
|
console.log(`Manifest revision: ${result.manifestRevision}`);
|
|
12622
13265
|
console.log(`Owner: ${result.fromOwner} -> ${result.toOwner}`);
|
|
12623
13266
|
});
|
|
13267
|
+
var mcpCommand = program.command("mcp").description("operate on MCP runtime configuration");
|
|
13268
|
+
mcpCommand.command("retire").description("remove one exact legacy MCP contribution with explicit state ownership").argument("<package>", "configured package containing exactly one legacy MCP artifact").option("--agent <name>", "one named agent from merged config").option("--profile <name>", "workspace runtime profile resolving to one target").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--from-workspace-root <path>", "required previous owner when managed legacy state exists").option("--dry-run", "show the retirement plan without writing (default)", false).option("--apply", "apply the exact reviewed retirement plan", false).option("--json", "print the install plan as JSON", false).action(async (packageName, options) => {
|
|
13269
|
+
if (options.apply && options.dryRun) throw new Error("--apply cannot be combined with --dry-run.");
|
|
13270
|
+
await runExactMcpRetirement(packageName, { ...options, dryRun: !options.apply });
|
|
13271
|
+
});
|
|
12624
13272
|
program.command("eject").description("copy a managed artifact into local ownership").argument("<item>", "package/type/name").option("-t, --target-root <path>", "workspace root", process.cwd()).action(async (item, options) => {
|
|
12625
13273
|
const targetRoot = normalizeTargetRoot(options.targetRoot);
|
|
12626
13274
|
const result = await ejectArtifact(targetRoot, item);
|
|
@@ -12697,7 +13345,7 @@ journalCommand.command("list").description("show pending apply journals for reso
|
|
|
12697
13345
|
if (!journal) continue;
|
|
12698
13346
|
pending += 1;
|
|
12699
13347
|
console.log(`PENDING ${state.adapter.name}/${state.installationType} at ${state.installRoot}`);
|
|
12700
|
-
console.log(` journal: ${
|
|
13348
|
+
console.log(` journal: ${join49(state.installRoot, ".agentwheel", `${state.state.stateKey}.apply-journal.json`)}`);
|
|
12701
13349
|
console.log(` stateKey: ${state.state.stateKey}`);
|
|
12702
13350
|
console.log(` createdAt: ${journal.createdAt}`);
|
|
12703
13351
|
console.log(` updatedAt: ${journal.updatedAt}`);
|
|
@@ -12818,7 +13466,11 @@ async function runInstallCommand(nameOrSource, options, behavior) {
|
|
|
12818
13466
|
let extraPackage;
|
|
12819
13467
|
if (nameOrSource && !configured) {
|
|
12820
13468
|
try {
|
|
12821
|
-
let entry = await packageEntryFromSource(nameOrSource, target.workspaceRoot, {
|
|
13469
|
+
let entry = await packageEntryFromSource(nameOrSource, target.workspaceRoot, {
|
|
13470
|
+
...targetOptions,
|
|
13471
|
+
adapter: targetOptions.adapter ?? target.adapter,
|
|
13472
|
+
deferGraphRendering: true
|
|
13473
|
+
});
|
|
12822
13474
|
if (targetOptions.multiAdapterSource) {
|
|
12823
13475
|
entry = packageEntryWithAdapterSuffix(entry);
|
|
12824
13476
|
}
|
|
@@ -12849,7 +13501,7 @@ async function runInstallCommand(nameOrSource, options, behavior) {
|
|
|
12849
13501
|
if (reloaded) console.log(`Reloaded runtime via ${formatReloadCommands(target.reloadCommands)}.`);
|
|
12850
13502
|
}
|
|
12851
13503
|
}
|
|
12852
|
-
await
|
|
13504
|
+
await rm13(result.bundle.root, { recursive: true, force: true });
|
|
12853
13505
|
if (result.plan.hasBlockingChanges) process.exitCode = 1;
|
|
12854
13506
|
}
|
|
12855
13507
|
if (behavior.apply && extraPackage && !targetOptions.onlySource) {
|
|
@@ -12915,6 +13567,7 @@ async function buildPlanReport(nameOrSource, options) {
|
|
|
12915
13567
|
let entry = await packageEntryFromSource(nameOrSource, target.workspaceRoot, {
|
|
12916
13568
|
...targetOptions,
|
|
12917
13569
|
adapter: targetOptions.adapter ?? target.adapter,
|
|
13570
|
+
deferGraphRendering: true,
|
|
12918
13571
|
warn: collectWarning
|
|
12919
13572
|
});
|
|
12920
13573
|
if (targetOptions.multiAdapterSource) {
|
|
@@ -12944,7 +13597,7 @@ async function buildPlanReport(nameOrSource, options) {
|
|
|
12944
13597
|
for (const result of results) {
|
|
12945
13598
|
reportTargets.push(installPlanReportTarget(result.plan, result.graphLockDigest));
|
|
12946
13599
|
reportWarnings.push(...result.warnings);
|
|
12947
|
-
await
|
|
13600
|
+
await rm13(result.bundle.root, { recursive: true, force: true });
|
|
12948
13601
|
}
|
|
12949
13602
|
}
|
|
12950
13603
|
return planReport(reportTargets, reportWarnings);
|
|
@@ -12997,16 +13650,26 @@ async function packageEntryFromSource(source, targetRoot, options) {
|
|
|
12997
13650
|
`No available version of ${provisionalName} satisfies ${options.version}; latest overall is ${initialVersion.availability.latestOverall ?? "unknown"}.`
|
|
12998
13651
|
);
|
|
12999
13652
|
}
|
|
13000
|
-
const bundle = await
|
|
13653
|
+
const bundle = options.deferGraphRendering ? await stageSourceRaw(driver, resolvedSource, {
|
|
13654
|
+
cacheRoot: join49(targetRoot, ".agentwheel", "cache"),
|
|
13655
|
+
mode: options.mode,
|
|
13656
|
+
ref: initialVersion?.ref,
|
|
13657
|
+
frozenLock: lockMode
|
|
13658
|
+
}) : await stageSource(driver, resolvedSource, {
|
|
13001
13659
|
workspaceRoot: targetRoot,
|
|
13002
13660
|
adapter,
|
|
13003
|
-
cacheRoot:
|
|
13661
|
+
cacheRoot: join49(targetRoot, ".agentwheel", "cache"),
|
|
13004
13662
|
mode: options.mode,
|
|
13005
13663
|
ref: initialVersion?.ref,
|
|
13006
13664
|
frozenLock: lockMode,
|
|
13007
13665
|
select: selectedArtifacts
|
|
13008
13666
|
});
|
|
13009
|
-
const
|
|
13667
|
+
const installationArtifacts = options.deferGraphRendering ? filterArtifactsBySelection(bundle.artifacts, selectedArtifacts).filter((artifact) => !artifact.runtimes?.length || artifact.runtimes.includes(adapter.name)) : bundle.artifacts;
|
|
13668
|
+
const installationType = resolveInstallationTypeForArtifacts(
|
|
13669
|
+
adapter,
|
|
13670
|
+
installationArtifacts.map((artifact) => artifact.type),
|
|
13671
|
+
options.installationType
|
|
13672
|
+
);
|
|
13010
13673
|
try {
|
|
13011
13674
|
return {
|
|
13012
13675
|
name: options.name ?? resolvedInput.registryEntry?.name ?? bundle.source.packageName ?? source,
|
|
@@ -13026,7 +13689,7 @@ async function packageEntryFromSource(source, targetRoot, options) {
|
|
|
13026
13689
|
overrides: overrideArtifactsFromOptions(options)
|
|
13027
13690
|
};
|
|
13028
13691
|
} finally {
|
|
13029
|
-
await
|
|
13692
|
+
await rm13(bundle.root, { recursive: true, force: true });
|
|
13030
13693
|
}
|
|
13031
13694
|
}
|
|
13032
13695
|
function findConfiguredPackage(packages, value) {
|
|
@@ -13036,6 +13699,64 @@ function findConfiguredPackageForTarget(packages, value, options, target) {
|
|
|
13036
13699
|
const matches = packages.filter((pkg) => pkg.name === value || pkg.source === value);
|
|
13037
13700
|
return options.multiAdapterSource ? matches.find((pkg) => pkg.adapter === target.adapter) : matches[0];
|
|
13038
13701
|
}
|
|
13702
|
+
async function configuredPackageForSkill(target, packages, skillName, options, explicitPackageName) {
|
|
13703
|
+
const selector = `skills/${skillName}`;
|
|
13704
|
+
if (explicitPackageName) {
|
|
13705
|
+
const pkg = findConfiguredPackage(packages, explicitPackageName);
|
|
13706
|
+
if (!pkg) throw new Error(`Configured package not found: ${explicitPackageName}`);
|
|
13707
|
+
if (!await packageSelectsSkillForTarget(target, pkg, selector, options)) {
|
|
13708
|
+
throw new Error(`Configured package '${pkg.name}' does not select ${selector}.`);
|
|
13709
|
+
}
|
|
13710
|
+
return pkg;
|
|
13711
|
+
}
|
|
13712
|
+
const adapterPackages = packages.filter((pkg) => pkg.adapter === target.adapter);
|
|
13713
|
+
const candidates = adapterPackages.length > 0 ? adapterPackages : packages;
|
|
13714
|
+
const matches = [];
|
|
13715
|
+
for (const pkg of candidates) {
|
|
13716
|
+
if (await packageSelectsSkillForTarget(target, pkg, selector, options)) matches.push(pkg);
|
|
13717
|
+
}
|
|
13718
|
+
if (matches.length === 1) return matches[0];
|
|
13719
|
+
if (matches.length > 1) {
|
|
13720
|
+
throw new Error(
|
|
13721
|
+
`Skill '${skillName}' has multiple configured owners: ${matches.map((pkg) => pkg.name).sort().join(", ")}. Pass --package <name>.`
|
|
13722
|
+
);
|
|
13723
|
+
}
|
|
13724
|
+
throw new Error(
|
|
13725
|
+
`No configured owner found for skill '${skillName}'. Add ${selector} to one package selection or pass --package <name>.`
|
|
13726
|
+
);
|
|
13727
|
+
}
|
|
13728
|
+
async function packageSelectsSkillForTarget(target, pkg, selector, options) {
|
|
13729
|
+
const explicitSelection = normalizeArtifactSelectors(pkg.select, pkg.skills);
|
|
13730
|
+
if (explicitSelection && !explicitSelection.some((candidate) => candidate === selector)) return false;
|
|
13731
|
+
const groups = /* @__PURE__ */ new Map();
|
|
13732
|
+
const group = graphGroupForPackage(groups, target, pkg, options);
|
|
13733
|
+
const adapter = await resolveAdapterForTarget(group.target, group.adapterOptions);
|
|
13734
|
+
const graphLockPath = graphLockPathForTarget(
|
|
13735
|
+
group.target.workspaceRoot,
|
|
13736
|
+
targetKeyForTarget(group.target, adapter.name),
|
|
13737
|
+
adapter.name,
|
|
13738
|
+
targetFingerprintParts(group.target, adapter, group.adapterOptions, group.installationType)
|
|
13739
|
+
);
|
|
13740
|
+
if (await pathExists(graphLockPath)) {
|
|
13741
|
+
const lock = await readGraphLock(graphLockPath);
|
|
13742
|
+
const root = lock.canonical.roots.find((candidate) => candidate.rootId === pkg.name);
|
|
13743
|
+
if (root?.selected.includes(selector)) return true;
|
|
13744
|
+
}
|
|
13745
|
+
const results = await buildGraphPlansForTarget(target, void 0, {
|
|
13746
|
+
...options,
|
|
13747
|
+
scope: pkg.name,
|
|
13748
|
+
onlySource: true,
|
|
13749
|
+
dryRun: true,
|
|
13750
|
+
suppressEmptyMessage: true
|
|
13751
|
+
}, { mode: "install" });
|
|
13752
|
+
try {
|
|
13753
|
+
return results.some((result) => result.bundle.graphLock.canonical.roots.some(
|
|
13754
|
+
(root) => root.rootId === pkg.name && root.selected.includes(selector)
|
|
13755
|
+
));
|
|
13756
|
+
} finally {
|
|
13757
|
+
await Promise.all(results.map((result) => rm13(result.bundle.root, { recursive: true, force: true })));
|
|
13758
|
+
}
|
|
13759
|
+
}
|
|
13039
13760
|
function noDepsFromOptions(options) {
|
|
13040
13761
|
return options.noDeps === true || options.deps === false;
|
|
13041
13762
|
}
|
|
@@ -13156,6 +13877,69 @@ function adapterOptionsForTarget(target, options) {
|
|
|
13156
13877
|
function targetKeyForTarget(target, adapterName) {
|
|
13157
13878
|
return target.targetKey ?? target.agentName ?? adapterName ?? target.source;
|
|
13158
13879
|
}
|
|
13880
|
+
async function runExactMcpRetirement(packageName, options) {
|
|
13881
|
+
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
13882
|
+
const targets = await resolveCliTargets(normalizedOptions);
|
|
13883
|
+
if (targets.length !== 1) {
|
|
13884
|
+
throw new Error(`Exact MCP retirement requires exactly one runtime target, found ${targets.length}.`);
|
|
13885
|
+
}
|
|
13886
|
+
const target = targets[0];
|
|
13887
|
+
const expectedFromWorkspaceOwner = options.fromWorkspaceRoot ? workspaceOwnerForRoot(normalizeCliPath(options.fromWorkspaceRoot)) : void 0;
|
|
13888
|
+
const results = await buildGraphPlansForTarget(target, void 0, {
|
|
13889
|
+
...normalizedOptions,
|
|
13890
|
+
scope: packageName,
|
|
13891
|
+
onlySource: true,
|
|
13892
|
+
retireExactMcp: true,
|
|
13893
|
+
expectedFromWorkspaceOwner,
|
|
13894
|
+
dryRun: true
|
|
13895
|
+
}, { mode: "install" });
|
|
13896
|
+
if (results.length !== 1) {
|
|
13897
|
+
await Promise.all(results.map((result2) => rm13(result2.bundle.root, { recursive: true, force: true })));
|
|
13898
|
+
throw new Error(`Exact MCP retirement requires one package plan, found ${results.length}.`);
|
|
13899
|
+
}
|
|
13900
|
+
const result = results[0];
|
|
13901
|
+
try {
|
|
13902
|
+
console.log(options.json ? JSON.stringify(result.plan, null, 2) : formatGraphPlan(result));
|
|
13903
|
+
if (result.plan.hasBlockingChanges) {
|
|
13904
|
+
process.exitCode = 1;
|
|
13905
|
+
return;
|
|
13906
|
+
}
|
|
13907
|
+
if (!options.dryRun) {
|
|
13908
|
+
await uninstall(result.plan, { transport: transportForTarget(target) });
|
|
13909
|
+
console.log(`Retired exact MCP contribution for ${result.plan.adapter} at ${result.plan.targetRoot}.`);
|
|
13910
|
+
}
|
|
13911
|
+
} finally {
|
|
13912
|
+
await rm13(result.bundle.root, { recursive: true, force: true });
|
|
13913
|
+
}
|
|
13914
|
+
}
|
|
13915
|
+
async function runSkillUpdateCommand(skillName, options) {
|
|
13916
|
+
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
13917
|
+
const composite = await resolveSelectedCompositeProfile(normalizedOptions);
|
|
13918
|
+
if (composite) {
|
|
13919
|
+
await runCompositeSkillUpdate(
|
|
13920
|
+
composite.workspaceRoot,
|
|
13921
|
+
composite.name,
|
|
13922
|
+
composite.profile,
|
|
13923
|
+
skillName,
|
|
13924
|
+
options.package,
|
|
13925
|
+
normalizedOptions
|
|
13926
|
+
);
|
|
13927
|
+
return;
|
|
13928
|
+
}
|
|
13929
|
+
const targets = await resolveCliTargets(normalizedOptions, { preferAllProfile: true });
|
|
13930
|
+
for (const target of targets) {
|
|
13931
|
+
const config = await readMergedWorkspaceConfig(target.workspaceRoot);
|
|
13932
|
+
const owner = await configuredPackageForSkill(target, config.packages, skillName, normalizedOptions, options.package);
|
|
13933
|
+
const mode = owner.mode === "tracking" ? "update" : "install";
|
|
13934
|
+
console.log(`Skill ${skillName}: ${owner.name} (${mode}).`);
|
|
13935
|
+
await runConfiguredGraphPackages(target, {
|
|
13936
|
+
...normalizedOptions,
|
|
13937
|
+
scope: owner.name,
|
|
13938
|
+
onlySource: true,
|
|
13939
|
+
replaceConflict: options.adopt === true
|
|
13940
|
+
}, { mode });
|
|
13941
|
+
}
|
|
13942
|
+
}
|
|
13159
13943
|
async function runConfiguredGraphPackages(target, options, behavior) {
|
|
13160
13944
|
const results = await buildGraphPlansForTarget(target, void 0, options, behavior);
|
|
13161
13945
|
for (const result of results) {
|
|
@@ -13177,7 +13961,7 @@ async function runConfiguredGraphPackages(target, options, behavior) {
|
|
|
13177
13961
|
console.log(`Applied ${result.plan.adapter} at ${result.plan.targetRoot}.`);
|
|
13178
13962
|
if (reloaded) console.log(`Reloaded runtime via ${formatReloadCommands(target.reloadCommands)}.`);
|
|
13179
13963
|
}
|
|
13180
|
-
await
|
|
13964
|
+
await rm13(result.bundle.root, { recursive: true, force: true });
|
|
13181
13965
|
if (result.plan.hasBlockingChanges) process.exitCode = 1;
|
|
13182
13966
|
}
|
|
13183
13967
|
}
|
|
@@ -13191,14 +13975,20 @@ async function buildGraphPlansForTarget(target, source, options, behavior) {
|
|
|
13191
13975
|
const scopedPackage = targetOptions.scope ? findConfiguredPackage(config.packages, targetOptions.scope) : void 0;
|
|
13192
13976
|
const scopedRootId = scopedPackage?.name ?? (source ? targetOptions.scope : void 0);
|
|
13193
13977
|
if (targetOptions.scope && !scopedPackage && !source) throw new Error(`Configured package not found: ${targetOptions.scope}`);
|
|
13194
|
-
if (
|
|
13978
|
+
if (scopedPackage && targetOptions.onlySource) {
|
|
13979
|
+
const group = graphGroupForPackage(groups, target, scopedPackage, targetOptions);
|
|
13980
|
+
group.packages.push(scopedPackage);
|
|
13981
|
+
} else if (!source || !targetOptions.onlySource) {
|
|
13195
13982
|
for (const pkg of config.packages) {
|
|
13196
13983
|
const group = graphGroupForPackage(groups, target, pkg, targetOptions);
|
|
13197
13984
|
group.packages.push(pkg);
|
|
13198
13985
|
}
|
|
13199
13986
|
}
|
|
13200
13987
|
if (source) {
|
|
13201
|
-
let entry = targetOptions.extraPackage ?? await packageEntryFromSource(source, target.workspaceRoot,
|
|
13988
|
+
let entry = targetOptions.extraPackage ?? await packageEntryFromSource(source, target.workspaceRoot, {
|
|
13989
|
+
...targetOptions,
|
|
13990
|
+
deferGraphRendering: true
|
|
13991
|
+
});
|
|
13202
13992
|
if (targetOptions.multiAdapterSource) {
|
|
13203
13993
|
entry = packageEntryWithAdapterSuffix(entry);
|
|
13204
13994
|
}
|
|
@@ -13329,6 +14119,7 @@ async function buildGraphPlansForTarget(target, source, options, behavior) {
|
|
|
13329
14119
|
targetKey: targetKeyForTarget(group.target, adapter.name),
|
|
13330
14120
|
targetFingerprintParts: targetFingerprintParts(group.target, adapter, group.adapterOptions, group.installationType),
|
|
13331
14121
|
installationType: group.installationType,
|
|
14122
|
+
stateKey: group.target.stateKey,
|
|
13332
14123
|
noDeps: noDepsFromOptions(targetOptions),
|
|
13333
14124
|
includeSuggestions: targetOptions.withSuggestions,
|
|
13334
14125
|
suggestionAliases: suggestionAliasesFromOptions(targetOptions),
|
|
@@ -13342,12 +14133,14 @@ async function buildGraphPlansForTarget(target, source, options, behavior) {
|
|
|
13342
14133
|
isTTY: process.stdin.isTTY === true,
|
|
13343
14134
|
forceDrift: targetOptions.forceDrift,
|
|
13344
14135
|
forceConflict: targetOptions.forceConflict,
|
|
13345
|
-
replaceConflict: targetOptions.replaceConflict
|
|
14136
|
+
replaceConflict: targetOptions.replaceConflict,
|
|
14137
|
+
retireExactMcp: targetOptions.retireExactMcp,
|
|
14138
|
+
expectedFromWorkspaceOwner: targetOptions.expectedFromWorkspaceOwner
|
|
13346
14139
|
});
|
|
13347
14140
|
if ((behavior.mode === "install" || behavior.mode === "update") && scopedRootId) {
|
|
13348
14141
|
const state = installStateForTarget(group.target, adapter, group.adapterOptions, group.installationType);
|
|
13349
14142
|
const manifest = await readInstallManifest(state.installRoot, adapter.name, transport, state);
|
|
13350
|
-
results.push(
|
|
14143
|
+
results.push(previousGroupLock ? scopeUpdatePlanToRoot(result, scopedRootId, previousGroupLock, manifest) : scopeInstallPlanToRoot(result, scopedRootId, manifest));
|
|
13351
14144
|
} else if (scopedDependencyUpdate) {
|
|
13352
14145
|
const state = installStateForTarget(group.target, adapter, group.adapterOptions, group.installationType);
|
|
13353
14146
|
const manifest = await readInstallManifest(state.installRoot, adapter.name, transport, state);
|
|
@@ -13394,7 +14187,7 @@ function scopeUpdatePlanToDependencies(result, selectors, previousLock, manifest
|
|
|
13394
14187
|
selectedPreviousNodeIds,
|
|
13395
14188
|
selectedRootIds
|
|
13396
14189
|
);
|
|
13397
|
-
const graphLockDigest =
|
|
14190
|
+
const graphLockDigest = createHash15("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
13398
14191
|
return {
|
|
13399
14192
|
...result,
|
|
13400
14193
|
bundle: { ...result.bundle, graphLock },
|
|
@@ -13562,7 +14355,7 @@ function scopeUpdatePlanToRoot(result, rootId, previousLock, manifest) {
|
|
|
13562
14355
|
selectedPreviousNodeIds,
|
|
13563
14356
|
/* @__PURE__ */ new Set([rootId])
|
|
13564
14357
|
);
|
|
13565
|
-
const graphLockDigest =
|
|
14358
|
+
const graphLockDigest = createHash15("sha256").update(canonicalGraphLockJson(graphLock)).digest("hex");
|
|
13566
14359
|
return {
|
|
13567
14360
|
...scoped,
|
|
13568
14361
|
bundle: { ...scoped.bundle, graphLock },
|
|
@@ -13634,7 +14427,7 @@ function keepManifestEntryOperation(entry, targetRoot, scopeDescription, operati
|
|
|
13634
14427
|
artifactType: entry.artifactType,
|
|
13635
14428
|
artifactName: entry.artifactName,
|
|
13636
14429
|
kind: entry.kind,
|
|
13637
|
-
destPath: operation?.destPath ??
|
|
14430
|
+
destPath: operation?.destPath ?? join49(targetRoot, entry.path),
|
|
13638
14431
|
relativeDestPath: entry.path,
|
|
13639
14432
|
desiredHash: entry.sourceHash,
|
|
13640
14433
|
currentHash: operation?.currentHash ?? entry.hash,
|
|
@@ -13751,7 +14544,7 @@ async function uninstallConfiguredPackage(target, packageName, options) {
|
|
|
13751
14544
|
if (!options.dryRun) {
|
|
13752
14545
|
console.log(formatUninstallResult(result));
|
|
13753
14546
|
}
|
|
13754
|
-
if (renderedRoot) await
|
|
14547
|
+
if (renderedRoot) await rm13(renderedRoot, { recursive: true, force: true });
|
|
13755
14548
|
if (plan.hasBlockingChanges) process.exitCode = 1;
|
|
13756
14549
|
}
|
|
13757
14550
|
}
|
|
@@ -13802,14 +14595,15 @@ function targetFingerprintParts(target, adapter, options, installationType) {
|
|
|
13802
14595
|
agentName: target.agentName,
|
|
13803
14596
|
targetRoot: target.targetRoot,
|
|
13804
14597
|
transport: target.transport,
|
|
13805
|
-
ssh: target.ssh
|
|
14598
|
+
ssh: target.ssh,
|
|
14599
|
+
stateKey: target.stateKey
|
|
13806
14600
|
};
|
|
13807
14601
|
}
|
|
13808
14602
|
function installStateForTarget(target, adapter, options, installationType) {
|
|
13809
14603
|
const targetFingerprint = targetFingerprintDigest(target, adapter, options, installationType);
|
|
13810
14604
|
return {
|
|
13811
14605
|
installationType,
|
|
13812
|
-
stateKey: stateKeyFor(adapter.name, { installationType, targetFingerprint }),
|
|
14606
|
+
stateKey: target.stateKey ?? stateKeyFor(adapter.name, { installationType, targetFingerprint }),
|
|
13813
14607
|
installRoot: installRootForAdapterInstallationType(adapter, target.targetRoot, installationType, target.transport === "ssh")
|
|
13814
14608
|
};
|
|
13815
14609
|
}
|
|
@@ -14005,6 +14799,44 @@ async function runCompositeUpdate(workspaceRoot, profileName, profile, packageNa
|
|
|
14005
14799
|
if (result.stderr.trim()) console.error(result.stderr.trimEnd());
|
|
14006
14800
|
}
|
|
14007
14801
|
}
|
|
14802
|
+
async function runCompositeSkillUpdate(workspaceRoot, profileName, profile, skillName, packageName, options) {
|
|
14803
|
+
const preflight = await collectCompositeStatus(workspaceRoot, profileName, profile, options);
|
|
14804
|
+
printStatusReport(preflight);
|
|
14805
|
+
const blockers = preflight.members.filter((member) => blocksCompositeApply(member.health));
|
|
14806
|
+
if (blockers.length > 0) {
|
|
14807
|
+
throw new Error(
|
|
14808
|
+
"Composite skill update blocked before member execution: " + blockers.map((member) => `${member.id}=${member.health}`).join(", ")
|
|
14809
|
+
);
|
|
14810
|
+
}
|
|
14811
|
+
const incomingChain = parseCompositeChain();
|
|
14812
|
+
const memberChain = [...incomingChain, compositeKey(workspaceRoot, profileName)];
|
|
14813
|
+
for (const member of profile.members) {
|
|
14814
|
+
if (!options.dryRun) {
|
|
14815
|
+
const before = preflight.members.find((candidate) => candidate.id === member.id);
|
|
14816
|
+
const revalidated = await collectCompositeMembers({
|
|
14817
|
+
cliVersion: CLI_VERSION,
|
|
14818
|
+
workspaceRoot,
|
|
14819
|
+
profileName,
|
|
14820
|
+
profileTtlSeconds: profile.refreshTtlSeconds,
|
|
14821
|
+
members: [member],
|
|
14822
|
+
refresh: true,
|
|
14823
|
+
chain: incomingChain
|
|
14824
|
+
});
|
|
14825
|
+
const current = revalidated[0];
|
|
14826
|
+
if (blocksCompositeApply(current.health)) {
|
|
14827
|
+
throw new Error(`Composite skill update stopped before ${member.id}: revalidation is ${current.health}.`);
|
|
14828
|
+
}
|
|
14829
|
+
if (statusRevisionSignature(before?.report) !== statusRevisionSignature(current.report)) {
|
|
14830
|
+
throw new Error(`Composite skill update stopped before ${member.id}: member revision changed after preflight.`);
|
|
14831
|
+
}
|
|
14832
|
+
}
|
|
14833
|
+
const args = compositeSkillUpdateArguments(member.profile, skillName, packageName, options);
|
|
14834
|
+
console.log(`${options.dryRun ? "Plan" : "Update"} member ${member.id}:`);
|
|
14835
|
+
const result = await runMemberAgentwheel(member, workspaceRoot, args, memberChain);
|
|
14836
|
+
if (result.stdout.trim()) console.log(result.stdout.trimEnd());
|
|
14837
|
+
if (result.stderr.trim()) console.error(result.stderr.trimEnd());
|
|
14838
|
+
}
|
|
14839
|
+
}
|
|
14008
14840
|
async function runCompositeInstall(workspaceRoot, profileName, profile, nameOrSource, options, behavior) {
|
|
14009
14841
|
const preflight = await collectCompositeStatus(workspaceRoot, profileName, profile, options);
|
|
14010
14842
|
printStatusReport(preflight);
|
|
@@ -14080,6 +14912,21 @@ function compositeUpdateArguments(profile, packageName, options) {
|
|
|
14080
14912
|
if (options.yes) args.push("--yes");
|
|
14081
14913
|
return args;
|
|
14082
14914
|
}
|
|
14915
|
+
function compositeSkillUpdateArguments(profile, skillName, packageName, options) {
|
|
14916
|
+
const args = ["skill", "update", skillName, "--profile", profile];
|
|
14917
|
+
if (packageName) args.push("--package", packageName);
|
|
14918
|
+
if (options.dryRun) args.push("--dry-run");
|
|
14919
|
+
if (options.adopt) args.push("--adopt");
|
|
14920
|
+
if (options.refresh) args.push("--refresh");
|
|
14921
|
+
if (options.forceDrift) args.push("--force-drift");
|
|
14922
|
+
if (options.allowAdapterCode) args.push("--allow-adapter-code");
|
|
14923
|
+
if (options.noDeps) args.push("--no-deps");
|
|
14924
|
+
if (options.frozenLock) args.push("--frozen-lock");
|
|
14925
|
+
if (options.offline) args.push("--offline");
|
|
14926
|
+
for (const trust of options.trust ?? []) args.push("--trust", trust);
|
|
14927
|
+
if (options.yes) args.push("--yes");
|
|
14928
|
+
return args;
|
|
14929
|
+
}
|
|
14083
14930
|
function statusRevisionSignature(report) {
|
|
14084
14931
|
if (!report) return "missing";
|
|
14085
14932
|
return JSON.stringify({
|
|
@@ -14202,7 +15049,7 @@ async function collectPendingInstallWork(target, options) {
|
|
|
14202
15049
|
const message = error instanceof Error ? error.message : String(error);
|
|
14203
15050
|
return { pendingCount: 0, driftCount: 0, conflictCount: 0, counts: {}, error: message };
|
|
14204
15051
|
} finally {
|
|
14205
|
-
await Promise.all(results.map((result) =>
|
|
15052
|
+
await Promise.all(results.map((result) => rm13(result.bundle.root, { recursive: true, force: true })));
|
|
14206
15053
|
}
|
|
14207
15054
|
}
|
|
14208
15055
|
async function printDoctor(target, options) {
|
|
@@ -14219,12 +15066,12 @@ async function printDoctor(target, options) {
|
|
|
14219
15066
|
const requestedSkills = doctorSkillRequests(target, options);
|
|
14220
15067
|
const skills = [];
|
|
14221
15068
|
for (const request of requestedSkills) {
|
|
14222
|
-
const skillPath =
|
|
15069
|
+
const skillPath = join49(state.installRoot, targetMapping.dest, request.name);
|
|
14223
15070
|
const exists = await pathExists(skillPath);
|
|
14224
15071
|
const manifestEntry = manifest?.entries.find((entry) => {
|
|
14225
15072
|
if (entry.artifactType !== "skills") return false;
|
|
14226
15073
|
const legacyInstallName = "installName" in entry && typeof entry.installName === "string" ? entry.installName : void 0;
|
|
14227
|
-
return entry.artifactName === request.name || legacyInstallName === request.name || entry.path ===
|
|
15074
|
+
return entry.artifactName === request.name || legacyInstallName === request.name || entry.path === join49(targetMapping.dest, request.name);
|
|
14228
15075
|
});
|
|
14229
15076
|
const status = manifestEntry ? "managed" : exists ? "present-unmanaged" : "missing";
|
|
14230
15077
|
skills.push({
|
|
@@ -14304,7 +15151,7 @@ function doctorSkillLabel(name) {
|
|
|
14304
15151
|
return `${name} skill`;
|
|
14305
15152
|
}
|
|
14306
15153
|
function isSyncwheelWorkspace(targetRoot) {
|
|
14307
|
-
return existsSync(
|
|
15154
|
+
return existsSync(join49(targetRoot, ".syncwheel", "manifest.json"));
|
|
14308
15155
|
}
|
|
14309
15156
|
function skillInstallCommand(adapter, installationType, options, skill, behavior = {}) {
|
|
14310
15157
|
const args = [
|
|
@@ -14336,6 +15183,11 @@ function shellQuoteArg2(value) {
|
|
|
14336
15183
|
function collectSelectOption(value, previous) {
|
|
14337
15184
|
return [...previous, ...splitSelectorList(value)];
|
|
14338
15185
|
}
|
|
15186
|
+
function parsePositiveInteger(value) {
|
|
15187
|
+
const parsed = Number(value);
|
|
15188
|
+
if (!Number.isInteger(parsed) || parsed < 1) throw new Error(`Expected a positive integer, got: ${value}`);
|
|
15189
|
+
return parsed;
|
|
15190
|
+
}
|
|
14339
15191
|
function collectSkillOption(value, previous) {
|
|
14340
15192
|
return [...previous, ...splitSelectorList(value)];
|
|
14341
15193
|
}
|
|
@@ -14452,10 +15304,10 @@ function filterUninstallPlanBySelection(plan, selected) {
|
|
|
14452
15304
|
};
|
|
14453
15305
|
}
|
|
14454
15306
|
async function initPackage(root) {
|
|
14455
|
-
await
|
|
14456
|
-
await
|
|
14457
|
-
await
|
|
14458
|
-
const manifestPath =
|
|
15307
|
+
await mkdir24(join49(root, "instructions"), { recursive: true });
|
|
15308
|
+
await mkdir24(join49(root, "rules"), { recursive: true });
|
|
15309
|
+
await mkdir24(join49(root, "skills"), { recursive: true });
|
|
15310
|
+
const manifestPath = join49(root, "openpack.json");
|
|
14459
15311
|
const manifest = {
|
|
14460
15312
|
schemaVersion: 2,
|
|
14461
15313
|
name: "example/agentwheel-package",
|
|
@@ -14468,10 +15320,10 @@ async function initPackage(root) {
|
|
|
14468
15320
|
};
|
|
14469
15321
|
await writeFile22(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
14470
15322
|
`, "utf8");
|
|
14471
|
-
await writeFile22(
|
|
15323
|
+
await writeFile22(join49(root, "instructions", "AGENTS.md"), "# Agent Instructions\n", "utf8");
|
|
14472
15324
|
}
|
|
14473
15325
|
async function defaultBootstrapPackage(_root) {
|
|
14474
|
-
const packageRoot = await findAgentwheelPackageRoot(
|
|
15326
|
+
const packageRoot = await findAgentwheelPackageRoot(dirname33(fileURLToPath3(import.meta.url)));
|
|
14475
15327
|
if (!packageRoot) return void 0;
|
|
14476
15328
|
return {
|
|
14477
15329
|
name: "agentwheel",
|
|
@@ -14518,7 +15370,7 @@ async function findAgentwheelPackageRoot(start) {
|
|
|
14518
15370
|
let current = resolve22(start);
|
|
14519
15371
|
while (true) {
|
|
14520
15372
|
if (await findPackageManifestPath(current, { warnLegacy: false })) return current;
|
|
14521
|
-
const parent =
|
|
15373
|
+
const parent = dirname33(current);
|
|
14522
15374
|
if (parent === current) return void 0;
|
|
14523
15375
|
current = parent;
|
|
14524
15376
|
}
|