agentwheel 0.14.6 → 0.14.8
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 +3 -2
- package/dist/index.js +513 -281
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10,9 +10,9 @@ import {
|
|
|
10
10
|
|
|
11
11
|
// src/cli/index.ts
|
|
12
12
|
import { existsSync } from "fs";
|
|
13
|
-
import { mkdir as
|
|
13
|
+
import { mkdir as mkdir21, rm as rm11, writeFile as writeFile20 } from "fs/promises";
|
|
14
14
|
import { homedir as homedir9 } from "os";
|
|
15
|
-
import { dirname as
|
|
15
|
+
import { dirname as dirname30, join as join41, resolve as resolve20 } from "path";
|
|
16
16
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
17
17
|
import { Command } from "commander";
|
|
18
18
|
|
|
@@ -111,6 +111,7 @@ var targetMappingSchema = z2.object({
|
|
|
111
111
|
"codex-plugin",
|
|
112
112
|
"hermes-plugin",
|
|
113
113
|
"copilot-plugin",
|
|
114
|
+
"openclaw-subagent",
|
|
114
115
|
"codex-subagent",
|
|
115
116
|
"copilot-instruction",
|
|
116
117
|
"copilot-prompt",
|
|
@@ -142,6 +143,20 @@ function supportedInstallationTypes(adapter, artifactType) {
|
|
|
142
143
|
}
|
|
143
144
|
return [...types].sort((a, b) => a.localeCompare(b));
|
|
144
145
|
}
|
|
146
|
+
function adapterTargetSupport(adapter, artifactType, installationType) {
|
|
147
|
+
if (artifactType === "fragments") return { ok: true };
|
|
148
|
+
const registry = adapter.targets[artifactType];
|
|
149
|
+
const supported = supportedInstallationTypes(adapter, artifactType);
|
|
150
|
+
if (!registry) {
|
|
151
|
+
return { ok: false, reason: "adapter-target-unsupported", supportedInstallationTypes: supported };
|
|
152
|
+
}
|
|
153
|
+
const target = registry[installationType];
|
|
154
|
+
if (target?.enabled) return { ok: true };
|
|
155
|
+
if (target && !target.enabled) {
|
|
156
|
+
return { ok: false, reason: "adapter-target-disabled", supportedInstallationTypes: supported };
|
|
157
|
+
}
|
|
158
|
+
return { ok: false, reason: "adapter-target-unsupported", supportedInstallationTypes: supported };
|
|
159
|
+
}
|
|
145
160
|
function resolveInstallationTypeForArtifacts(adapter, artifactTypes, requested) {
|
|
146
161
|
const installableTypes = [...new Set(artifactTypes.filter((type) => type !== "fragments"))];
|
|
147
162
|
if (installableTypes.length === 0) {
|
|
@@ -376,6 +391,9 @@ var openClawAdapter = {
|
|
|
376
391
|
local: { enabled: true, dest: "skills" },
|
|
377
392
|
user: { enabled: true, root: "home", dest: ".openclaw/skills" }
|
|
378
393
|
},
|
|
394
|
+
subagents: {
|
|
395
|
+
user: { enabled: true, root: "home", dest: ".openclaw/workspace-subagents", semantic: "openclaw-subagent" }
|
|
396
|
+
},
|
|
379
397
|
mcp: {
|
|
380
398
|
user: { enabled: true, root: "home", dest: ".openclaw/openclaw.json", merge: "openclaw-json-deep" }
|
|
381
399
|
},
|
|
@@ -469,7 +487,7 @@ async function resolveAdapter(options) {
|
|
|
469
487
|
import { execFile as execFile3 } from "child_process";
|
|
470
488
|
import { mkdtemp as mkdtemp2, rm as rm4, writeFile as writeFile9 } from "fs/promises";
|
|
471
489
|
import { tmpdir as tmpdir3 } from "os";
|
|
472
|
-
import { basename as basename3, join as join5 } from "path";
|
|
490
|
+
import { basename as basename3, dirname as dirname10, join as join5 } from "path";
|
|
473
491
|
import { promisify as promisify3 } from "util";
|
|
474
492
|
|
|
475
493
|
// src/model/graph-lock.ts
|
|
@@ -892,11 +910,33 @@ async function mergeOpenClawJsonFile(sourcePath, destPath) {
|
|
|
892
910
|
sourcePath
|
|
893
911
|
);
|
|
894
912
|
const current = await pathExists(destPath) ? JSON.parse(await readFile6(destPath, "utf8")) : {};
|
|
895
|
-
const merged =
|
|
913
|
+
const merged = mergeOpenClawJson(current, source);
|
|
896
914
|
await mkdir4(dirname5(destPath), { recursive: true });
|
|
897
915
|
await writeFile5(destPath, `${JSON.stringify(merged, null, 2)}
|
|
898
916
|
`, "utf8");
|
|
899
917
|
}
|
|
918
|
+
function mergeOpenClawJson(base, incoming, path = []) {
|
|
919
|
+
if (isMcpServerCodexAgentsPath(path) && Array.isArray(incoming)) {
|
|
920
|
+
return incoming;
|
|
921
|
+
}
|
|
922
|
+
if (path.join(".") === "agents.list" && Array.isArray(base) && Array.isArray(incoming)) {
|
|
923
|
+
return mergeOpenClawAgentsById(base, incoming);
|
|
924
|
+
}
|
|
925
|
+
if (Array.isArray(base) && Array.isArray(incoming)) {
|
|
926
|
+
return deepMerge(base, incoming);
|
|
927
|
+
}
|
|
928
|
+
if (isRecord(base) && isRecord(incoming)) {
|
|
929
|
+
const out = { ...base };
|
|
930
|
+
for (const [key, value] of Object.entries(incoming)) {
|
|
931
|
+
out[key] = key in out ? mergeOpenClawJson(out[key], value, [...path, key]) : value;
|
|
932
|
+
}
|
|
933
|
+
return out;
|
|
934
|
+
}
|
|
935
|
+
return incoming;
|
|
936
|
+
}
|
|
937
|
+
function isMcpServerCodexAgentsPath(path) {
|
|
938
|
+
return path.length === 5 && path[0] === "mcp" && path[1] === "servers" && path[3] === "codex" && path[4] === "agents";
|
|
939
|
+
}
|
|
900
940
|
function expandEnvPlaceholders(value, sourcePath) {
|
|
901
941
|
if (typeof value === "string") {
|
|
902
942
|
return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g, (_match, name) => {
|
|
@@ -934,6 +974,24 @@ function normalizeOpenClawMcpServer(server) {
|
|
|
934
974
|
delete out.type;
|
|
935
975
|
return out;
|
|
936
976
|
}
|
|
977
|
+
function mergeOpenClawAgentsById(base, incoming) {
|
|
978
|
+
const out = [...base];
|
|
979
|
+
const indexById = /* @__PURE__ */ new Map();
|
|
980
|
+
for (const [index, value] of out.entries()) {
|
|
981
|
+
const id = isRecord(value) && typeof value.id === "string" ? value.id : void 0;
|
|
982
|
+
if (id) indexById.set(id, index);
|
|
983
|
+
}
|
|
984
|
+
for (const value of incoming) {
|
|
985
|
+
const id = isRecord(value) && typeof value.id === "string" ? value.id : void 0;
|
|
986
|
+
if (!id || !indexById.has(id)) {
|
|
987
|
+
out.push(value);
|
|
988
|
+
if (id) indexById.set(id, out.length - 1);
|
|
989
|
+
continue;
|
|
990
|
+
}
|
|
991
|
+
out[indexById.get(id)] = value;
|
|
992
|
+
}
|
|
993
|
+
return out;
|
|
994
|
+
}
|
|
937
995
|
|
|
938
996
|
// src/install/manifest.ts
|
|
939
997
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -1908,7 +1966,7 @@ async function applyOperation(operation, context) {
|
|
|
1908
1966
|
if (operation.mergeStrategy === "json-deep") {
|
|
1909
1967
|
await mergeWithTransport(operation.sourcePath, operation.destPath, transport, mergeJsonFile);
|
|
1910
1968
|
} else if (operation.mergeStrategy === "openclaw-json-deep") {
|
|
1911
|
-
await
|
|
1969
|
+
await mergeOpenClawJsonWithTransport(operation.sourcePath, operation.destPath, transport);
|
|
1912
1970
|
} else if (operation.mergeStrategy === "yaml-deep") {
|
|
1913
1971
|
await mergeWithTransport(operation.sourcePath, operation.destPath, transport, mergeYamlFile);
|
|
1914
1972
|
} else if (operation.mergeStrategy === "codex-toml-mcp") {
|
|
@@ -2258,13 +2316,58 @@ async function mergeWithTransport(sourcePath, destPath, transport, merge) {
|
|
|
2258
2316
|
await rm4(tempRoot, { recursive: true, force: true });
|
|
2259
2317
|
}
|
|
2260
2318
|
}
|
|
2319
|
+
async function mergeOpenClawJsonWithTransport(sourcePath, destPath, transport) {
|
|
2320
|
+
const tempRoot = await mkdtemp2(join5(tmpdir3(), "agentwheel-openclaw-merge-"));
|
|
2321
|
+
const localDest = join5(tempRoot, basename3(destPath) || "openclaw.json");
|
|
2322
|
+
const validationPath = transport.kind === "local" ? localDest : `${destPath}.validate-agentwheel-${process.pid}-${Date.now()}`;
|
|
2323
|
+
try {
|
|
2324
|
+
if (await transport.pathExists(destPath)) {
|
|
2325
|
+
await writeFile9(localDest, await transport.readFile(destPath), "utf8");
|
|
2326
|
+
}
|
|
2327
|
+
await mergeOpenClawJsonFile(sourcePath, localDest);
|
|
2328
|
+
if (transport.kind !== "local") {
|
|
2329
|
+
await transport.atomicCopy(localDest, validationPath, "file");
|
|
2330
|
+
}
|
|
2331
|
+
await validateOpenClawConfig(validationPath, destPath, transport);
|
|
2332
|
+
await transport.atomicCopy(localDest, destPath, "file");
|
|
2333
|
+
} finally {
|
|
2334
|
+
if (transport.kind !== "local") await transport.rm(validationPath);
|
|
2335
|
+
await rm4(tempRoot, { recursive: true, force: true });
|
|
2336
|
+
}
|
|
2337
|
+
}
|
|
2338
|
+
async function validateOpenClawConfig(configPath, destPath, transport) {
|
|
2339
|
+
if (!transport.execFile) {
|
|
2340
|
+
throw new Error(`Cannot validate OpenClaw config over ${transport.description}: transport does not support command execution.`);
|
|
2341
|
+
}
|
|
2342
|
+
const openClawHome = dirname10(destPath);
|
|
2343
|
+
const bundledBin = join5(openClawHome, "npm", "node_modules", ".bin", "openclaw");
|
|
2344
|
+
const script = String.raw`
|
|
2345
|
+
set -euo pipefail
|
|
2346
|
+
cfg=$1
|
|
2347
|
+
bundled_bin=$2
|
|
2348
|
+
if [ -x "$bundled_bin" ]; then
|
|
2349
|
+
bin="$bundled_bin"
|
|
2350
|
+
elif command -v openclaw >/dev/null 2>&1; then
|
|
2351
|
+
bin="openclaw"
|
|
2352
|
+
else
|
|
2353
|
+
echo "OpenClaw binary not found; cannot validate $cfg" >&2
|
|
2354
|
+
exit 127
|
|
2355
|
+
fi
|
|
2356
|
+
out=$(OPENCLAW_CONFIG_PATH="$cfg" "$bin" config validate --json 2>&1) || {
|
|
2357
|
+
printf '%s\n' "$out" >&2
|
|
2358
|
+
exit 1
|
|
2359
|
+
}
|
|
2360
|
+
printf '%s' "$out" | node -e 'let s=""; process.stdin.on("data", c => s += c); process.stdin.on("end", () => { const data = JSON.parse(s); if (!data.valid) { console.error(JSON.stringify(data, null, 2)); process.exit(1); } });'
|
|
2361
|
+
`;
|
|
2362
|
+
await transport.execFile("bash", ["-lc", script, "agentwheel-openclaw-validate", configPath, bundledBin]);
|
|
2363
|
+
}
|
|
2261
2364
|
|
|
2262
2365
|
// src/install/plan.ts
|
|
2263
|
-
import { basename as
|
|
2366
|
+
import { basename as basename8, join as join16, relative as relative3 } from "path";
|
|
2264
2367
|
|
|
2265
2368
|
// src/staging/codex-subagents.ts
|
|
2266
2369
|
import { mkdir as mkdir8, readFile as readFile10, writeFile as writeFile10 } from "fs/promises";
|
|
2267
|
-
import { basename as basename4, dirname as
|
|
2370
|
+
import { basename as basename4, dirname as dirname11, join as join6 } from "path";
|
|
2268
2371
|
var requiredCodexAgentFields = ["name", "description", "developer_instructions"];
|
|
2269
2372
|
async function renderCodexSubagents(artifacts, stageRoot, adapter) {
|
|
2270
2373
|
if (adapter?.name !== "codex") return artifacts;
|
|
@@ -2309,7 +2412,7 @@ async function renderCodexSubagent(artifact, stageRoot) {
|
|
|
2309
2412
|
}
|
|
2310
2413
|
const markdown = await readFile10(markdownPath, "utf8");
|
|
2311
2414
|
const toml = markdownToCodexAgentToml(agentName, markdown);
|
|
2312
|
-
await mkdir8(
|
|
2415
|
+
await mkdir8(dirname11(renderedPath), { recursive: true });
|
|
2313
2416
|
await writeFile10(renderedPath, toml, "utf8");
|
|
2314
2417
|
return {
|
|
2315
2418
|
...artifact,
|
|
@@ -2379,7 +2482,7 @@ function escapeRegExp(value) {
|
|
|
2379
2482
|
|
|
2380
2483
|
// src/staging/copilot-artifacts.ts
|
|
2381
2484
|
import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile11 } from "fs/promises";
|
|
2382
|
-
import { basename as basename5, dirname as
|
|
2485
|
+
import { basename as basename5, dirname as dirname12, join as join7 } from "path";
|
|
2383
2486
|
async function renderCopilotArtifacts(artifacts, stageRoot, adapter) {
|
|
2384
2487
|
if (adapter?.name !== "copilot") return artifacts;
|
|
2385
2488
|
const names = /* @__PURE__ */ new Set();
|
|
@@ -2410,7 +2513,7 @@ async function renderCopilotSubagent(artifact, stageRoot) {
|
|
|
2410
2513
|
throw new Error(`Copilot subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
|
|
2411
2514
|
}
|
|
2412
2515
|
const markdown = await readFile11(markdownPath, "utf8");
|
|
2413
|
-
await mkdir9(
|
|
2516
|
+
await mkdir9(dirname12(renderedPath), { recursive: true });
|
|
2414
2517
|
await writeFile11(renderedPath, ensureCopilotAgentDescription(agentName, markdown), "utf8");
|
|
2415
2518
|
return {
|
|
2416
2519
|
...artifact,
|
|
@@ -2463,15 +2566,84 @@ function yamlString(value) {
|
|
|
2463
2566
|
return JSON.stringify(value);
|
|
2464
2567
|
}
|
|
2465
2568
|
|
|
2569
|
+
// src/staging/openclaw-subagents.ts
|
|
2570
|
+
import { mkdir as mkdir10, readFile as readFile12, writeFile as writeFile12 } from "fs/promises";
|
|
2571
|
+
import { basename as basename6, dirname as dirname13, join as join8 } from "path";
|
|
2572
|
+
async function renderOpenClawSubagents(artifacts, stageRoot, adapter) {
|
|
2573
|
+
if (adapter?.name !== "openclaw") return artifacts;
|
|
2574
|
+
const names = /* @__PURE__ */ new Set();
|
|
2575
|
+
const rendered = [];
|
|
2576
|
+
for (const artifact of artifacts) {
|
|
2577
|
+
if (artifact.type !== "subagents") {
|
|
2578
|
+
rendered.push(artifact);
|
|
2579
|
+
continue;
|
|
2580
|
+
}
|
|
2581
|
+
const next = await renderOpenClawSubagent(artifact, stageRoot);
|
|
2582
|
+
if (names.has(next.name)) {
|
|
2583
|
+
throw new Error(`OpenClaw subagents produce duplicate agent id '${next.name}'.`);
|
|
2584
|
+
}
|
|
2585
|
+
names.add(next.name);
|
|
2586
|
+
rendered.push(next);
|
|
2587
|
+
}
|
|
2588
|
+
return rendered;
|
|
2589
|
+
}
|
|
2590
|
+
async function renderOpenClawSubagent(artifact, stageRoot) {
|
|
2591
|
+
const sourcePath = artifact.stagedPath ?? artifact.sourcePath;
|
|
2592
|
+
const agentId = openClawAgentId(artifact);
|
|
2593
|
+
const markdownPath = artifact.kind === "dir" ? join8(sourcePath, "AGENTS.md") : sourcePath;
|
|
2594
|
+
if (artifact.kind === "dir" && !await pathExists(markdownPath)) {
|
|
2595
|
+
throw new Error(`OpenClaw subagent directory ${artifact.relativePath} must contain AGENTS.md.`);
|
|
2596
|
+
}
|
|
2597
|
+
if (artifact.kind === "file" && !artifact.name.toLowerCase().endsWith(".md") && !sourcePath.toLowerCase().endsWith(".md")) {
|
|
2598
|
+
throw new Error(`OpenClaw subagent ${artifact.relativePath} must be a .md file or directory containing AGENTS.md.`);
|
|
2599
|
+
}
|
|
2600
|
+
const parsed = splitFrontmatter3(await readFile12(markdownPath, "utf8"));
|
|
2601
|
+
const body = parsed.body.trim().length > 0 ? parsed.body.trim() : `# ${titleFromAgentId(agentId)}
|
|
2602
|
+
|
|
2603
|
+
${parsed.description ?? `OpenClaw subagent ${agentId}.`}`;
|
|
2604
|
+
const renderedPath = join8(stageRoot, ".agentwheel-rendered", "openclaw-subagents", agentId, "AGENTS.md");
|
|
2605
|
+
await mkdir10(dirname13(renderedPath), { recursive: true });
|
|
2606
|
+
await writeFile12(renderedPath, `${body}
|
|
2607
|
+
`, "utf8");
|
|
2608
|
+
const renderedDir = dirname13(renderedPath);
|
|
2609
|
+
return {
|
|
2610
|
+
...artifact,
|
|
2611
|
+
name: agentId,
|
|
2612
|
+
sourcePath: renderedDir,
|
|
2613
|
+
stagedPath: renderedDir,
|
|
2614
|
+
relativePath: join8("subagents", agentId),
|
|
2615
|
+
kind: "dir",
|
|
2616
|
+
hash: await hashPath(renderedDir)
|
|
2617
|
+
};
|
|
2618
|
+
}
|
|
2619
|
+
function openClawAgentId(artifact) {
|
|
2620
|
+
const raw = artifact.kind === "dir" ? artifact.name : basename6(artifact.name);
|
|
2621
|
+
return raw.replace(/\.agent\.md$/i, "").replace(/\.md$/i, "");
|
|
2622
|
+
}
|
|
2623
|
+
function splitFrontmatter3(markdown) {
|
|
2624
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/.exec(markdown);
|
|
2625
|
+
if (!match) return { body: markdown };
|
|
2626
|
+
const frontmatter = match[1] ?? "";
|
|
2627
|
+
const body = markdown.slice(match[0].length);
|
|
2628
|
+
const description = frontmatter.split(/\r?\n/).map((line) => /^description:\s*(?:"([^"]*)"|'([^']*)'|(.+))\s*$/.exec(line.trim())).find((item) => item !== null);
|
|
2629
|
+
return {
|
|
2630
|
+
body,
|
|
2631
|
+
description: description ? (description[1] ?? description[2] ?? description[3] ?? "").trim() : void 0
|
|
2632
|
+
};
|
|
2633
|
+
}
|
|
2634
|
+
function titleFromAgentId(agentId) {
|
|
2635
|
+
return agentId.split(/[-_]/g).filter(Boolean).map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
|
|
2636
|
+
}
|
|
2637
|
+
|
|
2466
2638
|
// src/targets/plugins/claude.ts
|
|
2467
|
-
import { join as
|
|
2639
|
+
import { join as join10 } from "path";
|
|
2468
2640
|
|
|
2469
2641
|
// src/targets/plugins/common.ts
|
|
2470
|
-
import { readFile as
|
|
2471
|
-
import { join as
|
|
2642
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
2643
|
+
import { join as join9 } from "path";
|
|
2472
2644
|
import { parseDocument } from "yaml";
|
|
2473
2645
|
function pluginStateRoot(request) {
|
|
2474
|
-
return
|
|
2646
|
+
return join9(
|
|
2475
2647
|
request.targetRoot,
|
|
2476
2648
|
".agentwheel",
|
|
2477
2649
|
"plugins",
|
|
@@ -2489,16 +2661,16 @@ function safeNameSegment(value) {
|
|
|
2489
2661
|
return normalized.length > 0 ? normalized : "unnamed";
|
|
2490
2662
|
}
|
|
2491
2663
|
async function jsonPluginName(root, relativeManifestPath, fallback) {
|
|
2492
|
-
const manifestPath =
|
|
2664
|
+
const manifestPath = join9(root, relativeManifestPath);
|
|
2493
2665
|
if (!await pathExists(manifestPath)) return fallback;
|
|
2494
|
-
const parsed = JSON.parse(await
|
|
2666
|
+
const parsed = JSON.parse(await readFile13(manifestPath, "utf8"));
|
|
2495
2667
|
return typeof parsed.name === "string" && parsed.name.trim().length > 0 ? parsed.name.trim() : fallback;
|
|
2496
2668
|
}
|
|
2497
2669
|
async function yamlPluginName(root, relativeManifestPaths, fallback) {
|
|
2498
2670
|
for (const relativeManifestPath of relativeManifestPaths) {
|
|
2499
|
-
const manifestPath =
|
|
2671
|
+
const manifestPath = join9(root, relativeManifestPath);
|
|
2500
2672
|
if (!await pathExists(manifestPath)) continue;
|
|
2501
|
-
const document = parseDocument(await
|
|
2673
|
+
const document = parseDocument(await readFile13(manifestPath, "utf8"));
|
|
2502
2674
|
const parsed = document.toJSON();
|
|
2503
2675
|
if (!isRecord4(parsed)) continue;
|
|
2504
2676
|
for (const key of ["name", "module", "package"]) {
|
|
@@ -2527,7 +2699,7 @@ async function claudePluginSpec(request) {
|
|
|
2527
2699
|
packageName: request.artifact.packageName,
|
|
2528
2700
|
installName: request.installName
|
|
2529
2701
|
});
|
|
2530
|
-
const marketplaceRoot =
|
|
2702
|
+
const marketplaceRoot = join10(stateRoot, "marketplace");
|
|
2531
2703
|
const scope = claudeScope(request.installationType);
|
|
2532
2704
|
const selector = `${pluginName}@${marketplaceName}`;
|
|
2533
2705
|
return {
|
|
@@ -2552,7 +2724,7 @@ function claudeScope(installationType) {
|
|
|
2552
2724
|
}
|
|
2553
2725
|
|
|
2554
2726
|
// src/targets/plugins/codex.ts
|
|
2555
|
-
import { join as
|
|
2727
|
+
import { join as join11 } from "path";
|
|
2556
2728
|
async function codexPluginSpec(request) {
|
|
2557
2729
|
const pluginName = await jsonPluginName(request.sourcePath, ".codex-plugin/plugin.json", request.installName);
|
|
2558
2730
|
const marketplaceName = agentwheelMarketplaceName(request.artifact.packageName, pluginName);
|
|
@@ -2563,7 +2735,7 @@ async function codexPluginSpec(request) {
|
|
|
2563
2735
|
packageName: request.artifact.packageName,
|
|
2564
2736
|
installName: request.installName
|
|
2565
2737
|
});
|
|
2566
|
-
const marketplaceRoot =
|
|
2738
|
+
const marketplaceRoot = join11(stateRoot, "marketplace");
|
|
2567
2739
|
const selector = `${pluginName}@${marketplaceName}`;
|
|
2568
2740
|
return {
|
|
2569
2741
|
runtime: "codex",
|
|
@@ -2582,7 +2754,7 @@ async function codexPluginSpec(request) {
|
|
|
2582
2754
|
}
|
|
2583
2755
|
|
|
2584
2756
|
// src/targets/plugins/copilot.ts
|
|
2585
|
-
import { join as
|
|
2757
|
+
import { join as join12 } from "path";
|
|
2586
2758
|
async function copilotPluginSpec(request) {
|
|
2587
2759
|
if (request.installationType !== "user") {
|
|
2588
2760
|
throw new Error("Copilot plugins are persistent user-level installs only; pass --installation-type user.");
|
|
@@ -2595,7 +2767,7 @@ async function copilotPluginSpec(request) {
|
|
|
2595
2767
|
packageName: request.artifact.packageName,
|
|
2596
2768
|
installName: request.installName
|
|
2597
2769
|
});
|
|
2598
|
-
const pluginRoot =
|
|
2770
|
+
const pluginRoot = join12(stateRoot, "plugin");
|
|
2599
2771
|
return {
|
|
2600
2772
|
runtime: "copilot",
|
|
2601
2773
|
pluginName,
|
|
@@ -2606,7 +2778,7 @@ async function copilotPluginSpec(request) {
|
|
|
2606
2778
|
}
|
|
2607
2779
|
|
|
2608
2780
|
// src/targets/plugins/hermes.ts
|
|
2609
|
-
import { join as
|
|
2781
|
+
import { join as join13 } from "path";
|
|
2610
2782
|
async function hermesPluginSpec(request) {
|
|
2611
2783
|
if (request.installationType !== "user") {
|
|
2612
2784
|
throw new Error("Hermes plugins are user-level installs only; pass --installation-type user.");
|
|
@@ -2619,7 +2791,7 @@ async function hermesPluginSpec(request) {
|
|
|
2619
2791
|
packageName: request.artifact.packageName,
|
|
2620
2792
|
installName: request.installName
|
|
2621
2793
|
});
|
|
2622
|
-
const repoRoot =
|
|
2794
|
+
const repoRoot = join13(stateRoot, "repo");
|
|
2623
2795
|
return {
|
|
2624
2796
|
runtime: "hermes",
|
|
2625
2797
|
pluginName,
|
|
@@ -2630,8 +2802,8 @@ async function hermesPluginSpec(request) {
|
|
|
2630
2802
|
}
|
|
2631
2803
|
|
|
2632
2804
|
// src/targets/plugins/openclaw.ts
|
|
2633
|
-
import { readFile as
|
|
2634
|
-
import { join as
|
|
2805
|
+
import { readFile as readFile14 } from "fs/promises";
|
|
2806
|
+
import { join as join14 } from "path";
|
|
2635
2807
|
function openClawPluginInstallCommand(request) {
|
|
2636
2808
|
return ["openclaw", "plugins", "install", "--force", request.path];
|
|
2637
2809
|
}
|
|
@@ -2658,19 +2830,19 @@ async function openClawPluginSpec(request) {
|
|
|
2658
2830
|
}
|
|
2659
2831
|
async function openClawPluginName(root, fallback) {
|
|
2660
2832
|
for (const manifestName of ["plugin.json", "openclaw.plugin.json"]) {
|
|
2661
|
-
const manifestPath =
|
|
2833
|
+
const manifestPath = join14(root, manifestName);
|
|
2662
2834
|
if (!await pathExists(manifestPath)) continue;
|
|
2663
|
-
const parsed = JSON.parse(await
|
|
2835
|
+
const parsed = JSON.parse(await readFile14(manifestPath, "utf8"));
|
|
2664
2836
|
if (typeof parsed.name === "string" && parsed.name.trim().length > 0) return parsed.name.trim();
|
|
2665
2837
|
}
|
|
2666
2838
|
return fallback;
|
|
2667
2839
|
}
|
|
2668
2840
|
async function openClawClawHubPluginMetadata(root, fallback) {
|
|
2669
|
-
const metadataPath =
|
|
2841
|
+
const metadataPath = join14(root, "clawhub.json");
|
|
2670
2842
|
if (!await pathExists(metadataPath)) {
|
|
2671
2843
|
throw new Error("OpenClaw ClawHub plugins must contain clawhub.json");
|
|
2672
2844
|
}
|
|
2673
|
-
const parsed = JSON.parse(await
|
|
2845
|
+
const parsed = JSON.parse(await readFile14(metadataPath, "utf8"));
|
|
2674
2846
|
const installSpec = stringField(parsed.installSpec);
|
|
2675
2847
|
if (!installSpec?.startsWith("clawhub:")) {
|
|
2676
2848
|
throw new Error("OpenClaw ClawHub plugin metadata must declare installSpec starting with clawhub:");
|
|
@@ -2709,11 +2881,6 @@ async function semanticPluginSpecForArtifact(request) {
|
|
|
2709
2881
|
return void 0;
|
|
2710
2882
|
}
|
|
2711
2883
|
|
|
2712
|
-
// src/validation/artifacts.ts
|
|
2713
|
-
import { readFile as readFile14 } from "fs/promises";
|
|
2714
|
-
import { basename as basename6, join as join14 } from "path";
|
|
2715
|
-
import { parseDocument as parseDocument2 } from "yaml";
|
|
2716
|
-
|
|
2717
2884
|
// src/model/selection.ts
|
|
2718
2885
|
function artifactSelectorKey(artifact) {
|
|
2719
2886
|
return `${artifact.type}/${artifact.name}`;
|
|
@@ -2764,7 +2931,51 @@ function subagentBaseName(name) {
|
|
|
2764
2931
|
return name.replace(/\.agent\.md$/i, "").replace(/\.toml$/i, "").replace(/\.md$/i, "");
|
|
2765
2932
|
}
|
|
2766
2933
|
|
|
2934
|
+
// src/validation/adapter-targets.ts
|
|
2935
|
+
function filterArtifactsByAdapterTargets(artifacts, adapter, installationType, options = {}) {
|
|
2936
|
+
const skipped = [];
|
|
2937
|
+
const installable = artifacts.filter((artifact) => {
|
|
2938
|
+
if (artifact.type === "fragments") return true;
|
|
2939
|
+
const support = adapterTargetSupport(adapter, artifact.type, installationType);
|
|
2940
|
+
if (support.ok) return true;
|
|
2941
|
+
const selector = artifactSelectorKey(artifact);
|
|
2942
|
+
skipped.push({ selector, artifactType: artifact.type, support });
|
|
2943
|
+
options.warn?.(skipWarning(selector, adapter, installationType, artifact.type, support));
|
|
2944
|
+
return false;
|
|
2945
|
+
});
|
|
2946
|
+
const before = artifacts.filter((artifact) => artifact.type !== "fragments");
|
|
2947
|
+
const after = installable.filter((artifact) => artifact.type !== "fragments");
|
|
2948
|
+
if (before.length > 0 && after.length === 0) {
|
|
2949
|
+
throw new Error(
|
|
2950
|
+
`${unsupportedSummary(adapter, installationType, skipped)} No installable artifacts remain for adapter ${adapter.name}/${installationType} after skipping unsupported targets: ${skipped.map((item) => item.selector).join(", ")}`
|
|
2951
|
+
);
|
|
2952
|
+
}
|
|
2953
|
+
return installable;
|
|
2954
|
+
}
|
|
2955
|
+
function unsupportedSummary(adapter, installationType, skipped) {
|
|
2956
|
+
const types = [...new Set(skipped.map((item) => item.artifactType))].sort((a, b) => a.localeCompare(b));
|
|
2957
|
+
if (types.length !== 1) {
|
|
2958
|
+
return `Adapter ${adapter.name} does not support selected artifact targets for installation type '${installationType}'.`;
|
|
2959
|
+
}
|
|
2960
|
+
const type = types[0];
|
|
2961
|
+
const supported = [...new Set(skipped.flatMap((item) => item.support.supportedInstallationTypes))].sort((a, b) => a.localeCompare(b));
|
|
2962
|
+
if (supported.length > 0) {
|
|
2963
|
+
return `Adapter ${adapter.name} does not support ${type} artifacts for installation type '${installationType}'. Supported: ${supported.join(", ")}.`;
|
|
2964
|
+
}
|
|
2965
|
+
return `Adapter ${adapter.name} does not support ${type} artifacts for any installation type.`;
|
|
2966
|
+
}
|
|
2967
|
+
function skipWarning(selector, adapter, installationType, artifactType, support) {
|
|
2968
|
+
if (support.reason === "adapter-target-disabled") {
|
|
2969
|
+
return `skip ${selector} (selected but adapter-target-disabled: ${adapter.name}/${installationType} disables ${artifactType})`;
|
|
2970
|
+
}
|
|
2971
|
+
const suffix = support.supportedInstallationTypes.length > 0 ? `; supported installation types: ${support.supportedInstallationTypes.join(", ")}` : "";
|
|
2972
|
+
return `skip ${selector} (selected but adapter-target-unsupported: ${adapter.name}/${installationType} has no enabled target for ${artifactType}${suffix})`;
|
|
2973
|
+
}
|
|
2974
|
+
|
|
2767
2975
|
// src/validation/artifacts.ts
|
|
2976
|
+
import { readFile as readFile15 } from "fs/promises";
|
|
2977
|
+
import { basename as basename7, join as join15 } from "path";
|
|
2978
|
+
import { parseDocument as parseDocument2 } from "yaml";
|
|
2768
2979
|
var behavioralRuleFormats = ["markdown-rule", "claude-markdown-rule", "copilot-instruction-rule"];
|
|
2769
2980
|
var pluginFormats = ["claude-plugin", "codex-plugin", "hermes-plugin", "copilot-plugin", "openclaw-plugin", "openclaw-clawhub-plugin"];
|
|
2770
2981
|
async function filterArtifactsByInstallFormat(artifacts, adapter, installationType, options = {}) {
|
|
@@ -2875,7 +3086,7 @@ async function inferArtifactFormat(artifact, target) {
|
|
|
2875
3086
|
return void 0;
|
|
2876
3087
|
}
|
|
2877
3088
|
if (artifact.type === "plugins" && target.semantic === "openclaw-plugin") {
|
|
2878
|
-
if (artifact.kind === "dir" && await pathExists(
|
|
3089
|
+
if (artifact.kind === "dir" && await pathExists(join15(artifactPath(artifact), "clawhub.json"))) return "openclaw-clawhub-plugin";
|
|
2879
3090
|
if (artifact.kind === "dir" && (await openClawPluginManifestPaths(artifact)).length > 0) return "openclaw-plugin";
|
|
2880
3091
|
}
|
|
2881
3092
|
return void 0;
|
|
@@ -2927,7 +3138,7 @@ async function validateGenericStructure(artifact, target) {
|
|
|
2927
3138
|
const issues = [];
|
|
2928
3139
|
if (artifact.type === "skills") {
|
|
2929
3140
|
if (artifact.kind === "dir") {
|
|
2930
|
-
const skillMd =
|
|
3141
|
+
const skillMd = join15(artifactPath(artifact), "SKILL.md");
|
|
2931
3142
|
if (!await pathExists(skillMd)) {
|
|
2932
3143
|
issues.push({ artifact, message: "skill directory must contain SKILL.md" });
|
|
2933
3144
|
} else {
|
|
@@ -2939,10 +3150,17 @@ async function validateGenericStructure(artifact, target) {
|
|
|
2939
3150
|
issues.push(...await validateSkillFrontmatter(artifact, artifactPath(artifact)));
|
|
2940
3151
|
}
|
|
2941
3152
|
}
|
|
2942
|
-
if (target.merge === "json-deep") {
|
|
3153
|
+
if (target.merge === "json-deep" || target.merge === "openclaw-json-deep") {
|
|
2943
3154
|
const parsed = await parseJsonObjectArtifact(artifact);
|
|
2944
3155
|
if (!parsed.ok) issues.push({ artifact, message: parsed.message });
|
|
2945
3156
|
}
|
|
3157
|
+
if (artifact.type === "subagents" && target.semantic === "openclaw-subagent") {
|
|
3158
|
+
if (artifact.kind !== "dir") {
|
|
3159
|
+
issues.push({ artifact, message: "OpenClaw subagent artifacts must render to a workspace directory containing AGENTS.md" });
|
|
3160
|
+
} else if (!await pathExists(join15(artifactPath(artifact), "AGENTS.md"))) {
|
|
3161
|
+
issues.push({ artifact, message: "OpenClaw subagent workspace directory must contain AGENTS.md" });
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
2946
3164
|
if (target.merge === "yaml-deep") {
|
|
2947
3165
|
const parsed = await parseYamlObjectArtifact(artifact);
|
|
2948
3166
|
if (!parsed.ok) issues.push({ artifact, message: parsed.message });
|
|
@@ -2960,7 +3178,7 @@ async function validateGenericStructure(artifact, target) {
|
|
|
2960
3178
|
async function validateSkillFrontmatter(artifact, skillMdPath) {
|
|
2961
3179
|
let content;
|
|
2962
3180
|
try {
|
|
2963
|
-
content = await
|
|
3181
|
+
content = await readFile15(skillMdPath, "utf8");
|
|
2964
3182
|
} catch (error) {
|
|
2965
3183
|
return [{ artifact, message: `could not read SKILL.md: ${errorMessage(error)}` }];
|
|
2966
3184
|
}
|
|
@@ -3013,7 +3231,7 @@ function validatePluginArtifact(artifact, format) {
|
|
|
3013
3231
|
async function validateJsonPluginDescriptor(artifact, relativeManifestPath, label) {
|
|
3014
3232
|
const generic = validatePluginArtifact(artifact, `${label.toLowerCase()}-plugin`);
|
|
3015
3233
|
if (generic.length > 0) return generic;
|
|
3016
|
-
const manifestPath =
|
|
3234
|
+
const manifestPath = join15(artifactPath(artifact), relativeManifestPath);
|
|
3017
3235
|
if (!await pathExists(manifestPath)) {
|
|
3018
3236
|
return [{ artifact, message: `${label} plugins must contain ${relativeManifestPath}` }];
|
|
3019
3237
|
}
|
|
@@ -3024,26 +3242,26 @@ async function validateHermesPlugin(artifact) {
|
|
|
3024
3242
|
const generic = validatePluginArtifact(artifact, "hermes-plugin");
|
|
3025
3243
|
if (generic.length > 0) return generic;
|
|
3026
3244
|
const root = artifactPath(artifact);
|
|
3027
|
-
const manifestPaths = [
|
|
3245
|
+
const manifestPaths = [join15(root, "plugin.yaml"), join15(root, "plugin.yml")];
|
|
3028
3246
|
const manifestPath = await firstExistingPath(manifestPaths);
|
|
3029
3247
|
if (!manifestPath) {
|
|
3030
3248
|
return [{ artifact, message: "Hermes plugins must contain plugin.yaml or plugin.yml" }];
|
|
3031
3249
|
}
|
|
3032
3250
|
try {
|
|
3033
|
-
const document = parseDocument2(await
|
|
3251
|
+
const document = parseDocument2(await readFile15(manifestPath, "utf8"));
|
|
3034
3252
|
if (document.errors.length > 0) {
|
|
3035
|
-
return [{ artifact, message: `Hermes ${
|
|
3253
|
+
return [{ artifact, message: `Hermes ${basename7(manifestPath)} must be valid YAML: ${document.errors[0]?.message ?? "parse error"}` }];
|
|
3036
3254
|
}
|
|
3037
3255
|
const parsed = document.toJSON();
|
|
3038
3256
|
if (!isUnknownRecord(parsed)) {
|
|
3039
|
-
return [{ artifact, message: `Hermes ${
|
|
3257
|
+
return [{ artifact, message: `Hermes ${basename7(manifestPath)} must contain a YAML object` }];
|
|
3040
3258
|
}
|
|
3041
3259
|
if (!hasStringField(parsed, "name") && !hasStringField(parsed, "module") && !hasStringField(parsed, "package") && !hasNestedPackageName(parsed)) {
|
|
3042
|
-
return [{ artifact, message: `Hermes ${
|
|
3260
|
+
return [{ artifact, message: `Hermes ${basename7(manifestPath)} must declare a non-empty name, module, or package name` }];
|
|
3043
3261
|
}
|
|
3044
3262
|
return [];
|
|
3045
3263
|
} catch (error) {
|
|
3046
|
-
return [{ artifact, message: `Hermes ${
|
|
3264
|
+
return [{ artifact, message: `Hermes ${basename7(manifestPath)} must be valid YAML: ${errorMessage(error)}` }];
|
|
3047
3265
|
}
|
|
3048
3266
|
}
|
|
3049
3267
|
async function firstExistingPath(paths) {
|
|
@@ -3054,16 +3272,16 @@ async function firstExistingPath(paths) {
|
|
|
3054
3272
|
}
|
|
3055
3273
|
async function parseJsonPluginManifest(manifestPath, label) {
|
|
3056
3274
|
try {
|
|
3057
|
-
const parsed = JSON.parse(await
|
|
3275
|
+
const parsed = JSON.parse(await readFile15(manifestPath, "utf8"));
|
|
3058
3276
|
if (!isRecord5(parsed)) {
|
|
3059
|
-
return { ok: false, message: `${label} ${
|
|
3277
|
+
return { ok: false, message: `${label} ${basename7(manifestPath)} must be a JSON object` };
|
|
3060
3278
|
}
|
|
3061
3279
|
if (typeof parsed.name !== "string" || parsed.name.trim().length === 0) {
|
|
3062
|
-
return { ok: false, message: `${label} ${
|
|
3280
|
+
return { ok: false, message: `${label} ${basename7(manifestPath)} must declare a non-empty name` };
|
|
3063
3281
|
}
|
|
3064
3282
|
return { ok: true, name: parsed.name.trim() };
|
|
3065
3283
|
} catch (error) {
|
|
3066
|
-
return { ok: false, message: `${label} ${
|
|
3284
|
+
return { ok: false, message: `${label} ${basename7(manifestPath)} must be valid JSON: ${errorMessage(error)}` };
|
|
3067
3285
|
}
|
|
3068
3286
|
}
|
|
3069
3287
|
async function validateOpenClawPlugin(artifact) {
|
|
@@ -3096,12 +3314,12 @@ async function validateOpenClawClawHubPlugin(artifact) {
|
|
|
3096
3314
|
if (artifact.kind !== "dir") {
|
|
3097
3315
|
return [{ artifact, message: "OpenClaw ClawHub plugins must be directory artifacts" }];
|
|
3098
3316
|
}
|
|
3099
|
-
const metadataPath =
|
|
3317
|
+
const metadataPath = join15(artifactPath(artifact), "clawhub.json");
|
|
3100
3318
|
if (!await pathExists(metadataPath)) {
|
|
3101
3319
|
return [{ artifact, message: "OpenClaw ClawHub plugins must contain clawhub.json" }];
|
|
3102
3320
|
}
|
|
3103
3321
|
try {
|
|
3104
|
-
const parsed = JSON.parse(await
|
|
3322
|
+
const parsed = JSON.parse(await readFile15(metadataPath, "utf8"));
|
|
3105
3323
|
if (!isRecord5(parsed)) {
|
|
3106
3324
|
return [{ artifact, message: "OpenClaw ClawHub clawhub.json must be a JSON object" }];
|
|
3107
3325
|
}
|
|
@@ -3118,14 +3336,14 @@ async function validateOpenClawClawHubPlugin(artifact) {
|
|
|
3118
3336
|
}
|
|
3119
3337
|
async function openClawPluginManifestPaths(artifact) {
|
|
3120
3338
|
const root = artifactPath(artifact);
|
|
3121
|
-
const candidates = [
|
|
3339
|
+
const candidates = [join15(root, "plugin.json"), join15(root, "openclaw.plugin.json")];
|
|
3122
3340
|
const existing = await Promise.all(candidates.map(async (candidate) => await pathExists(candidate) ? candidate : void 0));
|
|
3123
3341
|
return existing.filter((candidate) => candidate !== void 0);
|
|
3124
3342
|
}
|
|
3125
3343
|
async function parseOpenClawPluginManifest(manifestPath) {
|
|
3126
|
-
const manifestName =
|
|
3344
|
+
const manifestName = basename7(manifestPath);
|
|
3127
3345
|
try {
|
|
3128
|
-
const parsed = JSON.parse(await
|
|
3346
|
+
const parsed = JSON.parse(await readFile15(manifestPath, "utf8"));
|
|
3129
3347
|
if (!isRecord5(parsed)) {
|
|
3130
3348
|
return { ok: false, path: manifestPath, message: `OpenClaw ${manifestName} must be a JSON object` };
|
|
3131
3349
|
}
|
|
@@ -3142,7 +3360,7 @@ async function parseJsonObjectArtifact(artifact) {
|
|
|
3142
3360
|
return { ok: false, message: "merge artifacts must be JSON files" };
|
|
3143
3361
|
}
|
|
3144
3362
|
try {
|
|
3145
|
-
const parsed = JSON.parse(await
|
|
3363
|
+
const parsed = JSON.parse(await readFile15(artifactPath(artifact), "utf8"));
|
|
3146
3364
|
if (!isRecord5(parsed)) return { ok: false, message: "merge artifacts must contain a JSON object" };
|
|
3147
3365
|
return { ok: true, value: parsed };
|
|
3148
3366
|
} catch (error) {
|
|
@@ -3154,7 +3372,7 @@ async function parseYamlObjectArtifact(artifact) {
|
|
|
3154
3372
|
return { ok: false, message: "merge artifacts must be YAML files" };
|
|
3155
3373
|
}
|
|
3156
3374
|
try {
|
|
3157
|
-
const document = parseDocument2(await
|
|
3375
|
+
const document = parseDocument2(await readFile15(artifactPath(artifact), "utf8"));
|
|
3158
3376
|
if (document.errors.length > 0) {
|
|
3159
3377
|
return { ok: false, message: `merge artifact must be valid YAML: ${document.errors[0]?.message ?? "parse error"}` };
|
|
3160
3378
|
}
|
|
@@ -3181,7 +3399,7 @@ function artifactLabel(artifact) {
|
|
|
3181
3399
|
return `${owner}${artifact.type}/${artifact.name}`;
|
|
3182
3400
|
}
|
|
3183
3401
|
function hasExtension(artifact, extension) {
|
|
3184
|
-
return
|
|
3402
|
+
return basename7(artifact.name).toLowerCase().endsWith(extension) || basename7(artifactPath(artifact)).toLowerCase().endsWith(extension);
|
|
3185
3403
|
}
|
|
3186
3404
|
function isPluginFormat(value) {
|
|
3187
3405
|
return value !== void 0 && pluginFormats.includes(value);
|
|
@@ -3215,7 +3433,10 @@ function errorMessage(error) {
|
|
|
3215
3433
|
// src/install/plan.ts
|
|
3216
3434
|
async function createCombinedInstallPlan(desiredArtifacts, adapter, targetRoot, manifest, transport = localTransport, options = {}) {
|
|
3217
3435
|
const requestedInstallationType = options.installationType ?? defaultInstallationType;
|
|
3218
|
-
const
|
|
3436
|
+
const formatCompatibleArtifacts = await filterArtifactsByInstallFormat(desiredArtifacts, adapter, requestedInstallationType, { warn: options.warn });
|
|
3437
|
+
const installableArtifacts = filterArtifactsByAdapterTargets(formatCompatibleArtifacts, adapter, requestedInstallationType, {
|
|
3438
|
+
warn: options.suppressAdapterTargetWarnings ? void 0 : options.warn
|
|
3439
|
+
});
|
|
3219
3440
|
const installationType = resolveInstallationTypeForArtifacts(adapter, installableArtifacts.map((artifact) => artifact.type), requestedInstallationType);
|
|
3220
3441
|
const installRoot = installRootForArtifacts(adapter, targetRoot, installationType, installableArtifacts.map((artifact) => artifact.type), transport.kind === "ssh");
|
|
3221
3442
|
await validateArtifactsForInstall(installableArtifacts, adapter, installationType);
|
|
@@ -3359,7 +3580,7 @@ async function createPlanFromOperations(desiredOps, adapter, targetRoot, manifes
|
|
|
3359
3580
|
for (const entry of effectiveEntries) {
|
|
3360
3581
|
if (desired.has(entry.path)) continue;
|
|
3361
3582
|
const semanticPlugin = entry.semanticPlugin;
|
|
3362
|
-
const destPath = semanticPlugin ? targetRoot :
|
|
3583
|
+
const destPath = semanticPlugin ? targetRoot : join16(targetRoot, entry.path);
|
|
3363
3584
|
if (!semanticPlugin && !await transport.pathExists(destPath)) continue;
|
|
3364
3585
|
const currentHash = semanticPlugin ? entry.hash : await currentEntryHash(entry, destPath, transport);
|
|
3365
3586
|
if (workspaceOwner && !entryOwnedByWorkspace(entry, workspaceOwner)) {
|
|
@@ -3508,15 +3729,15 @@ async function prepareManagedBlockOperations(desiredOps, adapter, targetRoot, tr
|
|
|
3508
3729
|
return prepared;
|
|
3509
3730
|
}
|
|
3510
3731
|
async function shouldSkipClaudeBridge(adapter, op, targetRoot, transport) {
|
|
3511
|
-
if (adapter.name !== "claude" || op.artifactType !== "instructions" ||
|
|
3732
|
+
if (adapter.name !== "claude" || op.artifactType !== "instructions" || basename8(op.destPath).toLowerCase() !== "claude.md") {
|
|
3512
3733
|
return false;
|
|
3513
3734
|
}
|
|
3514
|
-
const agentsPath =
|
|
3735
|
+
const agentsPath = join16(targetRoot, "AGENTS.md");
|
|
3515
3736
|
return claudeInstructionBridgesAgents(op.destPath, agentsPath, transport);
|
|
3516
3737
|
}
|
|
3517
3738
|
async function warnOnCopilotDoubleRead(adapter, op, targetRoot, transport, options) {
|
|
3518
|
-
if (adapter.name !== "claude" || op.artifactType !== "instructions" ||
|
|
3519
|
-
const agentsPath =
|
|
3739
|
+
if (adapter.name !== "claude" || op.artifactType !== "instructions" || basename8(op.destPath).toLowerCase() !== "claude.md") return;
|
|
3740
|
+
const agentsPath = join16(targetRoot, "AGENTS.md");
|
|
3520
3741
|
if (!await transport.pathExists(agentsPath)) return;
|
|
3521
3742
|
if (await claudeInstructionBridgesAgents(op.destPath, agentsPath, transport)) return;
|
|
3522
3743
|
options.warn?.("CLAUDE.md and AGENTS.md are separate instruction files; if Copilot is active it may read the managed instructions twice.");
|
|
@@ -3600,7 +3821,7 @@ async function canStrictlyAdoptLegacyEntry(entry, op, targetRoot, transport) {
|
|
|
3600
3821
|
if (entry.artifactType !== op.artifactType || entry.artifactName !== op.artifactName) return false;
|
|
3601
3822
|
if (!op.desiredHash || entry.sourceHash !== op.desiredHash) return false;
|
|
3602
3823
|
if (!packageIdentityMatches(entry, op)) return false;
|
|
3603
|
-
const destPath =
|
|
3824
|
+
const destPath = join16(targetRoot, entry.path);
|
|
3604
3825
|
if (!await transport.pathExists(destPath)) return false;
|
|
3605
3826
|
return await transport.hashPath(destPath) === entry.hash;
|
|
3606
3827
|
}
|
|
@@ -3731,7 +3952,7 @@ function keepForeignManifestEntryOperation(entry, targetRoot, workspaceOwner, op
|
|
|
3731
3952
|
artifactType: entry.artifactType,
|
|
3732
3953
|
artifactName: entry.artifactName,
|
|
3733
3954
|
kind: entry.kind,
|
|
3734
|
-
destPath: operation?.destPath ??
|
|
3955
|
+
destPath: operation?.destPath ?? join16(targetRoot, entry.path),
|
|
3735
3956
|
relativeDestPath: entry.path,
|
|
3736
3957
|
desiredHash: entry.sourceHash,
|
|
3737
3958
|
currentHash: currentHash ?? operation?.currentHash ?? entry.hash,
|
|
@@ -3799,7 +4020,7 @@ async function operationForArtifact(artifact, adapter, targetRoot, installationT
|
|
|
3799
4020
|
}
|
|
3800
4021
|
}
|
|
3801
4022
|
if (artifact.type === "subagents" && target.semantic === "codex-subagent") {
|
|
3802
|
-
const destPath2 =
|
|
4023
|
+
const destPath2 = join16(targetRoot, target.dest, `${installName.replace(/\.toml$/i, "")}.toml`);
|
|
3803
4024
|
return {
|
|
3804
4025
|
action: "create",
|
|
3805
4026
|
artifactType: artifact.type,
|
|
@@ -3817,7 +4038,7 @@ async function operationForArtifact(artifact, adapter, targetRoot, installationT
|
|
|
3817
4038
|
installName: installName.replace(/\.toml$/i, "")
|
|
3818
4039
|
};
|
|
3819
4040
|
}
|
|
3820
|
-
const destPath = artifact.type === "instructions" || artifact.type === "settings" || isFileTarget(target.dest) ?
|
|
4041
|
+
const destPath = artifact.type === "instructions" || artifact.type === "settings" || isFileTarget(target.dest) ? join16(targetRoot, target.dest) : join16(targetRoot, target.dest, installName);
|
|
3821
4042
|
return {
|
|
3822
4043
|
action: "create",
|
|
3823
4044
|
artifactType: artifact.type,
|
|
@@ -3896,12 +4117,12 @@ function isPendingInstallOperation(operation) {
|
|
|
3896
4117
|
}
|
|
3897
4118
|
|
|
3898
4119
|
// src/install/uninstall.ts
|
|
3899
|
-
import { join as
|
|
4120
|
+
import { join as join17 } from "path";
|
|
3900
4121
|
async function createUninstallPlan(manifest, transport = localTransport) {
|
|
3901
4122
|
const operations = [];
|
|
3902
4123
|
for (const entry of manifest.entries) {
|
|
3903
4124
|
const semanticPlugin = "semanticPlugin" in entry ? entry.semanticPlugin : void 0;
|
|
3904
|
-
const destPath = semanticPlugin ? manifest.targetRoot :
|
|
4125
|
+
const destPath = semanticPlugin ? manifest.targetRoot : join17(manifest.targetRoot, entry.path);
|
|
3905
4126
|
if (!semanticPlugin && !await transport.pathExists(destPath)) continue;
|
|
3906
4127
|
const currentHash = semanticPlugin ? entry.hash : await currentEntryHash2(entry, destPath, transport);
|
|
3907
4128
|
if (currentHash !== entry.hash) {
|
|
@@ -3972,7 +4193,7 @@ async function createOwnershipUninstallPlan(manifest, remainingDesired, adapter,
|
|
|
3972
4193
|
const operations = [];
|
|
3973
4194
|
for (const entry of manifest.entries) {
|
|
3974
4195
|
const semanticPlugin = "semanticPlugin" in entry ? entry.semanticPlugin : void 0;
|
|
3975
|
-
const destPath = semanticPlugin ? manifest.targetRoot :
|
|
4196
|
+
const destPath = semanticPlugin ? manifest.targetRoot : join17(manifest.targetRoot, entry.path);
|
|
3976
4197
|
if (!semanticPlugin && !await transport.pathExists(destPath)) continue;
|
|
3977
4198
|
const currentHash = semanticPlugin ? entry.hash : await currentEntryHash2(entry, destPath, transport);
|
|
3978
4199
|
const remainingOwners = ownersByPath.get(entry.path) ?? [];
|
|
@@ -4291,17 +4512,17 @@ function ownerChains(lock, nodeId) {
|
|
|
4291
4512
|
}
|
|
4292
4513
|
|
|
4293
4514
|
// src/source/clawhub.ts
|
|
4294
|
-
import { mkdir as
|
|
4295
|
-
import { basename as
|
|
4515
|
+
import { mkdir as mkdir11, rm as rm5, writeFile as writeFile13 } from "fs/promises";
|
|
4516
|
+
import { basename as basename10, dirname as dirname14, join as join20, resolve as resolve6 } from "path";
|
|
4296
4517
|
|
|
4297
4518
|
// src/source/local.ts
|
|
4298
4519
|
import { createHash as createHash4 } from "crypto";
|
|
4299
4520
|
import { readdir, stat as stat3 } from "fs/promises";
|
|
4300
|
-
import { basename as
|
|
4521
|
+
import { basename as basename9, join as join19, relative as relative4, resolve as resolve5 } from "path";
|
|
4301
4522
|
|
|
4302
4523
|
// src/model/package.ts
|
|
4303
|
-
import { readFile as
|
|
4304
|
-
import { join as
|
|
4524
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
4525
|
+
import { join as join18 } from "path";
|
|
4305
4526
|
import { parse as parse3, printParseErrorCode as printParseErrorCode2 } from "jsonc-parser";
|
|
4306
4527
|
import { z as z5 } from "zod";
|
|
4307
4528
|
var legacyArtifactTypeSchema = z5.enum([
|
|
@@ -4384,7 +4605,7 @@ var packageManifestNames = [...openPackManifestNames, ...legacyPackageManifestNa
|
|
|
4384
4605
|
var warnedLegacyManifestPaths = /* @__PURE__ */ new Set();
|
|
4385
4606
|
async function findPackageManifestPath(root, options = {}) {
|
|
4386
4607
|
for (const name of packageManifestNames) {
|
|
4387
|
-
const candidate =
|
|
4608
|
+
const candidate = join18(root, name);
|
|
4388
4609
|
if (!await pathExists(candidate)) continue;
|
|
4389
4610
|
if (isLegacyPackageManifestName(name) && options.warnLegacy !== false && !warnedLegacyManifestPaths.has(candidate)) {
|
|
4390
4611
|
warnedLegacyManifestPaths.add(candidate);
|
|
@@ -4397,7 +4618,7 @@ async function findPackageManifestPath(root, options = {}) {
|
|
|
4397
4618
|
async function readPackageManifest(root) {
|
|
4398
4619
|
const path = await findPackageManifestPath(root);
|
|
4399
4620
|
if (!path) return void 0;
|
|
4400
|
-
const content = await
|
|
4621
|
+
const content = await readFile16(path, "utf8");
|
|
4401
4622
|
const errors = [];
|
|
4402
4623
|
const parsed = parse3(content, errors, { allowTrailingComma: true, disallowComments: false });
|
|
4403
4624
|
if (errors.length > 0) {
|
|
@@ -4480,29 +4701,29 @@ var LocalSourceDriver = class {
|
|
|
4480
4701
|
}
|
|
4481
4702
|
const artifacts = [];
|
|
4482
4703
|
const root = resolved.resolvedPath;
|
|
4483
|
-
const instructions = await firstExisting([
|
|
4704
|
+
const instructions = await firstExisting([join19(root, "instructions.md"), join19(root, "AGENTS.md")]);
|
|
4484
4705
|
if (instructions) {
|
|
4485
4706
|
artifacts.push({
|
|
4486
4707
|
type: "instructions",
|
|
4487
|
-
name:
|
|
4708
|
+
name: basename9(instructions),
|
|
4488
4709
|
sourcePath: instructions,
|
|
4489
|
-
relativePath:
|
|
4710
|
+
relativePath: basename9(instructions),
|
|
4490
4711
|
kind: "file",
|
|
4491
4712
|
hash: await hashPath(instructions),
|
|
4492
4713
|
packageName: resolved.packageName,
|
|
4493
4714
|
channel: "managed"
|
|
4494
4715
|
});
|
|
4495
4716
|
}
|
|
4496
|
-
const rulesDir =
|
|
4717
|
+
const rulesDir = join19(root, "rules");
|
|
4497
4718
|
if (await pathExists(rulesDir)) {
|
|
4498
4719
|
for (const entry of await sortedDirEntries(rulesDir)) {
|
|
4499
|
-
const full =
|
|
4720
|
+
const full = join19(rulesDir, entry.name);
|
|
4500
4721
|
if (entry.isFile()) {
|
|
4501
4722
|
artifacts.push({
|
|
4502
4723
|
type: "rules",
|
|
4503
4724
|
name: entry.name,
|
|
4504
4725
|
sourcePath: full,
|
|
4505
|
-
relativePath:
|
|
4726
|
+
relativePath: join19("rules", entry.name),
|
|
4506
4727
|
kind: "file",
|
|
4507
4728
|
hash: await hashPath(full),
|
|
4508
4729
|
packageName: resolved.packageName,
|
|
@@ -4511,16 +4732,16 @@ var LocalSourceDriver = class {
|
|
|
4511
4732
|
}
|
|
4512
4733
|
}
|
|
4513
4734
|
}
|
|
4514
|
-
const fragmentsDir =
|
|
4735
|
+
const fragmentsDir = join19(root, "fragments");
|
|
4515
4736
|
if (await pathExists(fragmentsDir)) {
|
|
4516
4737
|
for (const entry of await sortedDirEntries(fragmentsDir)) {
|
|
4517
|
-
const full =
|
|
4738
|
+
const full = join19(fragmentsDir, entry.name);
|
|
4518
4739
|
if (entry.isFile()) {
|
|
4519
4740
|
artifacts.push({
|
|
4520
4741
|
type: "fragments",
|
|
4521
4742
|
name: entry.name,
|
|
4522
4743
|
sourcePath: full,
|
|
4523
|
-
relativePath:
|
|
4744
|
+
relativePath: join19("fragments", entry.name),
|
|
4524
4745
|
kind: "file",
|
|
4525
4746
|
hash: await hashPath(full),
|
|
4526
4747
|
packageName: resolved.packageName,
|
|
@@ -4529,16 +4750,16 @@ var LocalSourceDriver = class {
|
|
|
4529
4750
|
}
|
|
4530
4751
|
}
|
|
4531
4752
|
}
|
|
4532
|
-
const skillsDir =
|
|
4753
|
+
const skillsDir = join19(root, "skills");
|
|
4533
4754
|
if (await pathExists(skillsDir)) {
|
|
4534
4755
|
for (const entry of await sortedDirEntries(skillsDir)) {
|
|
4535
|
-
const full =
|
|
4756
|
+
const full = join19(skillsDir, entry.name);
|
|
4536
4757
|
if (entry.isDirectory()) {
|
|
4537
4758
|
artifacts.push({
|
|
4538
4759
|
type: "skills",
|
|
4539
4760
|
name: entry.name,
|
|
4540
4761
|
sourcePath: full,
|
|
4541
|
-
relativePath:
|
|
4762
|
+
relativePath: join19("skills", entry.name),
|
|
4542
4763
|
kind: "dir",
|
|
4543
4764
|
hash: await hashPath(full),
|
|
4544
4765
|
packageName: resolved.packageName,
|
|
@@ -4549,7 +4770,7 @@ var LocalSourceDriver = class {
|
|
|
4549
4770
|
type: "skills",
|
|
4550
4771
|
name: entry.name.replace(/\.md$/, ""),
|
|
4551
4772
|
sourcePath: full,
|
|
4552
|
-
relativePath:
|
|
4773
|
+
relativePath: join19("skills", entry.name),
|
|
4553
4774
|
kind: "file",
|
|
4554
4775
|
hash: await hashPath(full),
|
|
4555
4776
|
packageName: resolved.packageName,
|
|
@@ -4559,7 +4780,7 @@ var LocalSourceDriver = class {
|
|
|
4559
4780
|
}
|
|
4560
4781
|
}
|
|
4561
4782
|
for (const type of ["commands", "subagents", "mcp", "hooks", "settings", "plugins"]) {
|
|
4562
|
-
const dir =
|
|
4783
|
+
const dir = join19(root, type);
|
|
4563
4784
|
if (!await pathExists(dir)) continue;
|
|
4564
4785
|
artifacts.push(...await listGenericArtifacts(type, dir, type, resolved.packageName));
|
|
4565
4786
|
}
|
|
@@ -4575,7 +4796,7 @@ var LocalSourceDriver = class {
|
|
|
4575
4796
|
findings.push({ level: "warning", message: "No instructions.md or AGENTS.md found", path: resolved.resolvedPath });
|
|
4576
4797
|
}
|
|
4577
4798
|
for (const artifact of artifacts.filter((item) => item.type === "skills" && item.kind === "dir")) {
|
|
4578
|
-
if (!await pathExists(
|
|
4799
|
+
if (!await pathExists(join19(artifact.sourcePath, "SKILL.md"))) {
|
|
4579
4800
|
findings.push({ level: "warning", message: `Skill directory has no SKILL.md: ${artifact.name}`, path: artifact.sourcePath });
|
|
4580
4801
|
}
|
|
4581
4802
|
}
|
|
@@ -4599,7 +4820,7 @@ async function hashLocalSource(root, manifest) {
|
|
|
4599
4820
|
}
|
|
4600
4821
|
const provides = [...manifest.provides].sort((a, b) => `${a.type}\0${a.path}`.localeCompare(`${b.type}\0${b.path}`));
|
|
4601
4822
|
for (const provide of provides) {
|
|
4602
|
-
const full =
|
|
4823
|
+
const full = join19(root, provide.path);
|
|
4603
4824
|
if (!await pathExists(full)) continue;
|
|
4604
4825
|
hash.update("provide\0");
|
|
4605
4826
|
hash.update(provide.type).update("\0");
|
|
@@ -4622,27 +4843,27 @@ async function listFromManifest(root, packageName) {
|
|
|
4622
4843
|
if (!manifest) return [];
|
|
4623
4844
|
const artifacts = [];
|
|
4624
4845
|
for (const provide of manifest.provides) {
|
|
4625
|
-
const full =
|
|
4846
|
+
const full = join19(root, provide.path);
|
|
4626
4847
|
if (!await pathExists(full)) continue;
|
|
4627
4848
|
const stats = await stat3(full);
|
|
4628
4849
|
if (provide.type === "instructions") {
|
|
4629
4850
|
if (stats.isFile()) {
|
|
4630
|
-
artifacts.push(await artifactForFile(provide.type,
|
|
4851
|
+
artifacts.push(await artifactForFile(provide.type, basename9(full), full, provide.path, packageName, provide, manifest, basename9(full)));
|
|
4631
4852
|
}
|
|
4632
4853
|
continue;
|
|
4633
4854
|
}
|
|
4634
4855
|
if (stats.isDirectory()) {
|
|
4635
4856
|
for (const entry of await sortedDirEntries(full)) {
|
|
4636
|
-
const child =
|
|
4857
|
+
const child = join19(full, entry.name);
|
|
4637
4858
|
if ((provide.type === "skills" || provide.type === "plugins" || provide.type === "subagents") && entry.isDirectory()) {
|
|
4638
|
-
artifacts.push(await artifactForDir(provide.type, entry.name, child,
|
|
4859
|
+
artifacts.push(await artifactForDir(provide.type, entry.name, child, join19(provide.path, entry.name), packageName, provide, manifest, entry.name));
|
|
4639
4860
|
} else if (entry.isFile()) {
|
|
4640
4861
|
const name = provide.type === "rules" && entry.name.endsWith(".md") ? entry.name : entry.name;
|
|
4641
|
-
artifacts.push(await artifactForFile(provide.type, name, child,
|
|
4862
|
+
artifacts.push(await artifactForFile(provide.type, name, child, join19(provide.path, entry.name), packageName, provide, manifest, name));
|
|
4642
4863
|
}
|
|
4643
4864
|
}
|
|
4644
4865
|
} else if (stats.isFile()) {
|
|
4645
|
-
artifacts.push(await artifactForFile(provide.type,
|
|
4866
|
+
artifacts.push(await artifactForFile(provide.type, basename9(full), full, provide.path, packageName, provide, manifest, basename9(full)));
|
|
4646
4867
|
}
|
|
4647
4868
|
}
|
|
4648
4869
|
return artifacts;
|
|
@@ -4650,11 +4871,11 @@ async function listFromManifest(root, packageName) {
|
|
|
4650
4871
|
async function listGenericArtifacts(type, dir, relativeRoot, packageName) {
|
|
4651
4872
|
const artifacts = [];
|
|
4652
4873
|
for (const entry of await sortedDirEntries(dir)) {
|
|
4653
|
-
const full =
|
|
4874
|
+
const full = join19(dir, entry.name);
|
|
4654
4875
|
if (entry.isDirectory()) {
|
|
4655
|
-
artifacts.push(await artifactForDir(type, entry.name, full,
|
|
4876
|
+
artifacts.push(await artifactForDir(type, entry.name, full, join19(relativeRoot, entry.name), packageName));
|
|
4656
4877
|
} else if (entry.isFile()) {
|
|
4657
|
-
artifacts.push(await artifactForFile(type, entry.name, full,
|
|
4878
|
+
artifacts.push(await artifactForFile(type, entry.name, full, join19(relativeRoot, entry.name), packageName));
|
|
4658
4879
|
}
|
|
4659
4880
|
}
|
|
4660
4881
|
return artifacts;
|
|
@@ -4771,7 +4992,7 @@ var ClawHubSourceDriver = class {
|
|
|
4771
4992
|
return this.local.list({ ...resolved, driver: "local" });
|
|
4772
4993
|
}
|
|
4773
4994
|
async scan(resolved) {
|
|
4774
|
-
if (!await pathExists(
|
|
4995
|
+
if (!await pathExists(join20(resolved.resolvedPath, "plugins"))) {
|
|
4775
4996
|
return { ok: false, findings: [{ level: "error", message: "ClawHub source has no generated plugin artifact" }] };
|
|
4776
4997
|
}
|
|
4777
4998
|
return { ok: true, findings: [] };
|
|
@@ -4823,10 +5044,10 @@ async function writeGeneratedPackage(root, packageInfo) {
|
|
|
4823
5044
|
artifact: packageInfo.artifact,
|
|
4824
5045
|
verification: packageInfo.verification
|
|
4825
5046
|
};
|
|
4826
|
-
const pluginPath =
|
|
5047
|
+
const pluginPath = join20(root, "plugins", pluginId, "clawhub.json");
|
|
4827
5048
|
await rm5(root, { recursive: true, force: true });
|
|
4828
|
-
await
|
|
4829
|
-
await
|
|
5049
|
+
await mkdir11(dirname14(pluginPath), { recursive: true });
|
|
5050
|
+
await writeFile13(join20(root, "openpack.json"), `${JSON.stringify({
|
|
4830
5051
|
schemaVersion: 2,
|
|
4831
5052
|
name: `clawhub/${name}`,
|
|
4832
5053
|
version: packageInfo.latestVersion ?? "latest",
|
|
@@ -4842,23 +5063,23 @@ async function writeGeneratedPackage(root, packageInfo) {
|
|
|
4842
5063
|
]
|
|
4843
5064
|
}, null, 2)}
|
|
4844
5065
|
`, "utf8");
|
|
4845
|
-
await
|
|
5066
|
+
await writeFile13(pluginPath, `${JSON.stringify(plugin, null, 2)}
|
|
4846
5067
|
`, "utf8");
|
|
4847
5068
|
}
|
|
4848
5069
|
function installNameFor2(value) {
|
|
4849
|
-
return
|
|
5070
|
+
return basename10(value).replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "clawhub-plugin";
|
|
4850
5071
|
}
|
|
4851
5072
|
function cachePathFor(packageName, cacheRoot) {
|
|
4852
|
-
const root = cacheRoot ? resolve6(cacheRoot) :
|
|
5073
|
+
const root = cacheRoot ? resolve6(cacheRoot) : join20(process.env.HOME ?? ".", ".agentwheel", "cache");
|
|
4853
5074
|
const slug2 = `clawhub-${packageName}`.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
4854
|
-
return
|
|
5075
|
+
return join20(root, slug2 || "clawhub-package");
|
|
4855
5076
|
}
|
|
4856
5077
|
|
|
4857
5078
|
// src/source/git.ts
|
|
4858
5079
|
import { execFile as execFile4 } from "child_process";
|
|
4859
|
-
import { cp as cp2, mkdir as
|
|
5080
|
+
import { cp as cp2, mkdir as mkdir12, rename as rename3, rm as rm6, writeFile as writeFile14 } from "fs/promises";
|
|
4860
5081
|
import { homedir as homedir2 } from "os";
|
|
4861
|
-
import { basename as
|
|
5082
|
+
import { basename as basename11, dirname as dirname15, join as join21, resolve as resolve7 } from "path";
|
|
4862
5083
|
import { promisify as promisify4 } from "util";
|
|
4863
5084
|
var execFileAsync4 = promisify4(execFile4);
|
|
4864
5085
|
var GitSourceDriver = class {
|
|
@@ -4881,8 +5102,8 @@ var GitSourceDriver = class {
|
|
|
4881
5102
|
async fetch(resolved) {
|
|
4882
5103
|
return withFilesystemLock(`${resolved.resolvedPath}.lock`, resolved.cacheLockTimeoutMs ?? 3e4, async () => {
|
|
4883
5104
|
const parsed = parseGitSource(resolved.source);
|
|
4884
|
-
await
|
|
4885
|
-
if (!await pathExists(
|
|
5105
|
+
await mkdir12(resolve7(resolved.resolvedPath, ".."), { recursive: true });
|
|
5106
|
+
if (!await pathExists(join21(resolved.resolvedPath, ".git"))) {
|
|
4886
5107
|
if (resolved.frozenLock) {
|
|
4887
5108
|
throw new Error(`Frozen lock requires cached git checkout at ${resolved.resolvedPath}`);
|
|
4888
5109
|
}
|
|
@@ -4949,20 +5170,20 @@ function parseGitSource(source) {
|
|
|
4949
5170
|
throw new Error(`Invalid git source: ${source}`);
|
|
4950
5171
|
}
|
|
4951
5172
|
function cachePathFor2(url, cacheRoot) {
|
|
4952
|
-
const root = cacheRoot ? resolve7(cacheRoot) :
|
|
5173
|
+
const root = cacheRoot ? resolve7(cacheRoot) : join21(homedir2(), ".agentwheel", "cache");
|
|
4953
5174
|
const slug2 = url.replace(/^[a-z]+:\/\//i, "").replace(/\.git$/i, "").replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
4954
|
-
return
|
|
5175
|
+
return join21(root, slug2 || basename11(url));
|
|
4955
5176
|
}
|
|
4956
5177
|
async function git(args) {
|
|
4957
5178
|
return execFileAsync4("git", args, { maxBuffer: 1024 * 1024 * 10 });
|
|
4958
5179
|
}
|
|
4959
5180
|
async function snapshotCheckout(checkoutPath, commit) {
|
|
4960
|
-
const snapshotPath =
|
|
5181
|
+
const snapshotPath = join21(dirname15(checkoutPath), `${basename11(checkoutPath)}-${commit.slice(0, 12)}`);
|
|
4961
5182
|
if (await pathExists(snapshotPath)) return snapshotPath;
|
|
4962
|
-
const tempPath =
|
|
5183
|
+
const tempPath = join21(dirname15(checkoutPath), `${basename11(snapshotPath)}.tmp-${process.pid}-${Date.now()}`);
|
|
4963
5184
|
await rm6(tempPath, { recursive: true, force: true });
|
|
4964
5185
|
await cp2(checkoutPath, tempPath, { recursive: true, dereference: true });
|
|
4965
|
-
await rm6(
|
|
5186
|
+
await rm6(join21(tempPath, ".git"), { recursive: true, force: true });
|
|
4966
5187
|
try {
|
|
4967
5188
|
await rename3(tempPath, snapshotPath);
|
|
4968
5189
|
} catch (error) {
|
|
@@ -4973,12 +5194,12 @@ async function snapshotCheckout(checkoutPath, commit) {
|
|
|
4973
5194
|
return snapshotPath;
|
|
4974
5195
|
}
|
|
4975
5196
|
async function withFilesystemLock(lockPath, timeoutMs, fn) {
|
|
4976
|
-
await
|
|
5197
|
+
await mkdir12(dirname15(lockPath), { recursive: true });
|
|
4977
5198
|
const started = Date.now();
|
|
4978
5199
|
while (true) {
|
|
4979
5200
|
try {
|
|
4980
|
-
await
|
|
4981
|
-
await
|
|
5201
|
+
await mkdir12(lockPath);
|
|
5202
|
+
await writeFile14(join21(lockPath, "owner.json"), JSON.stringify({ pid: process.pid, createdAt: (/* @__PURE__ */ new Date()).toISOString() }), "utf8");
|
|
4982
5203
|
break;
|
|
4983
5204
|
} catch (error) {
|
|
4984
5205
|
if (!isAlreadyExists2(error)) throw error;
|
|
@@ -4999,8 +5220,8 @@ function isAlreadyExists2(error) {
|
|
|
4999
5220
|
}
|
|
5000
5221
|
|
|
5001
5222
|
// src/source/mcp-registry.ts
|
|
5002
|
-
import { mkdir as
|
|
5003
|
-
import { basename as
|
|
5223
|
+
import { mkdir as mkdir13, writeFile as writeFile15 } from "fs/promises";
|
|
5224
|
+
import { basename as basename12, dirname as dirname16, join as join22, resolve as resolve8 } from "path";
|
|
5004
5225
|
var registryBaseUrl = "https://registry.modelcontextprotocol.io/v0.1";
|
|
5005
5226
|
var sourcePrefix2 = "mcp-registry:";
|
|
5006
5227
|
var McpRegistrySourceDriver = class {
|
|
@@ -5066,7 +5287,7 @@ var McpRegistrySourceDriver = class {
|
|
|
5066
5287
|
return this.local.list({ ...resolved, driver: "local" });
|
|
5067
5288
|
}
|
|
5068
5289
|
async scan(resolved) {
|
|
5069
|
-
if (!await pathExists(
|
|
5290
|
+
if (!await pathExists(join22(resolved.resolvedPath, "mcp"))) {
|
|
5070
5291
|
return { ok: false, findings: [{ level: "error", message: "MCP registry source has no generated mcp artifact" }] };
|
|
5071
5292
|
}
|
|
5072
5293
|
return { ok: true, findings: [] };
|
|
@@ -5106,16 +5327,16 @@ function isSafeHttpUrl(value) {
|
|
|
5106
5327
|
}
|
|
5107
5328
|
async function writeGeneratedPackage2(root, server) {
|
|
5108
5329
|
const serverId = installNameFor3(server.serverName);
|
|
5109
|
-
const mcpPath =
|
|
5110
|
-
await
|
|
5111
|
-
await
|
|
5330
|
+
const mcpPath = join22(root, "mcp", `${serverId}.json`);
|
|
5331
|
+
await mkdir13(dirname16(mcpPath), { recursive: true });
|
|
5332
|
+
await writeFile15(join22(root, "openpack.json"), `${JSON.stringify({
|
|
5112
5333
|
schemaVersion: 2,
|
|
5113
5334
|
name: `mcp-registry/${server.serverName}`,
|
|
5114
5335
|
version: server.version ?? "latest",
|
|
5115
5336
|
provides: [{ type: "mcp", path: "mcp" }]
|
|
5116
5337
|
}, null, 2)}
|
|
5117
5338
|
`, "utf8");
|
|
5118
|
-
await
|
|
5339
|
+
await writeFile15(mcpPath, `${JSON.stringify({
|
|
5119
5340
|
mcpServers: {
|
|
5120
5341
|
[serverId]: {
|
|
5121
5342
|
type: "streamable-http",
|
|
@@ -5126,23 +5347,23 @@ async function writeGeneratedPackage2(root, server) {
|
|
|
5126
5347
|
`, "utf8");
|
|
5127
5348
|
}
|
|
5128
5349
|
function installNameFor3(serverName) {
|
|
5129
|
-
return
|
|
5350
|
+
return basename12(serverName).replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "mcp-server";
|
|
5130
5351
|
}
|
|
5131
5352
|
function cachePathFor3(serverName, cacheRoot) {
|
|
5132
|
-
const root = cacheRoot ? resolve8(cacheRoot) :
|
|
5353
|
+
const root = cacheRoot ? resolve8(cacheRoot) : join22(process.env.HOME ?? ".", ".agentwheel", "cache");
|
|
5133
5354
|
const slug2 = `mcp-registry-${serverName}`.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "");
|
|
5134
|
-
return
|
|
5355
|
+
return join22(root, slug2 || "mcp-registry-server");
|
|
5135
5356
|
}
|
|
5136
5357
|
|
|
5137
5358
|
// src/source/skillkit.ts
|
|
5138
|
-
import { cp as cp3, mkdir as
|
|
5359
|
+
import { cp as cp3, mkdir as mkdir14, readFile as readFile17, rm as rm7 } from "fs/promises";
|
|
5139
5360
|
import { homedir as homedir3 } from "os";
|
|
5140
|
-
import { basename as
|
|
5361
|
+
import { basename as basename14, dirname as dirname18, join as join24, resolve as resolve9 } from "path";
|
|
5141
5362
|
import * as defaultSkillKit from "@skillkit/core";
|
|
5142
5363
|
|
|
5143
5364
|
// src/source/skill-artifacts.ts
|
|
5144
5365
|
import { readdir as readdir2, stat as stat4 } from "fs/promises";
|
|
5145
|
-
import { basename as
|
|
5366
|
+
import { basename as basename13, dirname as dirname17, extname as extname2, join as join23 } from "path";
|
|
5146
5367
|
async function artifactsFromSkillPaths(paths, packageName) {
|
|
5147
5368
|
const artifacts = [];
|
|
5148
5369
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -5164,28 +5385,28 @@ async function discoverSkillPaths(root) {
|
|
|
5164
5385
|
async function artifactFromSkillPath(item, packageName) {
|
|
5165
5386
|
const stats = await stat4(item.path);
|
|
5166
5387
|
if (stats.isDirectory()) {
|
|
5167
|
-
const skillMd =
|
|
5388
|
+
const skillMd = join23(item.path, "SKILL.md");
|
|
5168
5389
|
if (!await pathExists(skillMd)) return void 0;
|
|
5169
|
-
const name = sanitizeSkillName(item.name ??
|
|
5390
|
+
const name = sanitizeSkillName(item.name ?? basename13(item.path));
|
|
5170
5391
|
return {
|
|
5171
5392
|
type: "skills",
|
|
5172
5393
|
name,
|
|
5173
5394
|
sourcePath: item.path,
|
|
5174
|
-
relativePath:
|
|
5395
|
+
relativePath: join23("skills", name),
|
|
5175
5396
|
kind: "dir",
|
|
5176
5397
|
hash: await hashPath(item.path),
|
|
5177
5398
|
packageName,
|
|
5178
5399
|
channel: "managed"
|
|
5179
5400
|
};
|
|
5180
5401
|
}
|
|
5181
|
-
if (stats.isFile() &&
|
|
5182
|
-
const dir =
|
|
5183
|
-
const name = sanitizeSkillName(item.name ??
|
|
5402
|
+
if (stats.isFile() && basename13(item.path).toLowerCase() === "skill.md") {
|
|
5403
|
+
const dir = dirname17(item.path);
|
|
5404
|
+
const name = sanitizeSkillName(item.name ?? basename13(dir));
|
|
5184
5405
|
return {
|
|
5185
5406
|
type: "skills",
|
|
5186
5407
|
name,
|
|
5187
5408
|
sourcePath: dir,
|
|
5188
|
-
relativePath:
|
|
5409
|
+
relativePath: join23("skills", name),
|
|
5189
5410
|
kind: "dir",
|
|
5190
5411
|
hash: await hashPath(dir),
|
|
5191
5412
|
packageName,
|
|
@@ -5193,12 +5414,12 @@ async function artifactFromSkillPath(item, packageName) {
|
|
|
5193
5414
|
};
|
|
5194
5415
|
}
|
|
5195
5416
|
if (stats.isFile() && extname2(item.path).toLowerCase() === ".md") {
|
|
5196
|
-
const name = sanitizeSkillName(item.name ??
|
|
5417
|
+
const name = sanitizeSkillName(item.name ?? basename13(item.path, ".md"));
|
|
5197
5418
|
return {
|
|
5198
5419
|
type: "skills",
|
|
5199
5420
|
name,
|
|
5200
5421
|
sourcePath: item.path,
|
|
5201
|
-
relativePath:
|
|
5422
|
+
relativePath: join23("skills", `${name}.md`),
|
|
5202
5423
|
kind: "file",
|
|
5203
5424
|
hash: await hashPath(item.path),
|
|
5204
5425
|
packageName,
|
|
@@ -5216,7 +5437,7 @@ async function walk(dir, paths) {
|
|
|
5216
5437
|
}
|
|
5217
5438
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
5218
5439
|
if (!entry.isDirectory() || entry.name === ".git" || entry.name === "node_modules") continue;
|
|
5219
|
-
await walk(
|
|
5440
|
+
await walk(join23(dir, entry.name), paths);
|
|
5220
5441
|
}
|
|
5221
5442
|
}
|
|
5222
5443
|
function sanitizeSkillName(name) {
|
|
@@ -5238,7 +5459,7 @@ var SkillKitSourceDriver = class {
|
|
|
5238
5459
|
driver: this.name,
|
|
5239
5460
|
source,
|
|
5240
5461
|
resolvedPath,
|
|
5241
|
-
packageName: `skillkit/${
|
|
5462
|
+
packageName: `skillkit/${basename14(resolvedPath)}`,
|
|
5242
5463
|
mode: options.mode ?? "pinned",
|
|
5243
5464
|
sourceHash: await hashPath(resolvedPath)
|
|
5244
5465
|
};
|
|
@@ -5272,7 +5493,7 @@ var SkillKitSourceDriver = class {
|
|
|
5272
5493
|
if (!provider?.clone) {
|
|
5273
5494
|
throw new Error("SkillKit provider API unavailable or cannot resolve source. Expected @skillkit/core detectProvider().clone().");
|
|
5274
5495
|
}
|
|
5275
|
-
await
|
|
5496
|
+
await mkdir14(dirname18(resolved.resolvedPath), { recursive: true });
|
|
5276
5497
|
const result = await provider.clone(providerSpec, resolved.resolvedPath, {});
|
|
5277
5498
|
if (!result.success || !result.path) {
|
|
5278
5499
|
throw new Error(`SkillKit provider failed to fetch ${spec}: ${result.error ?? "unknown error"}`);
|
|
@@ -5316,9 +5537,9 @@ var SkillKitSourceDriver = class {
|
|
|
5316
5537
|
throw new Error("SkillKit translateSkill API unavailable");
|
|
5317
5538
|
}
|
|
5318
5539
|
for (const skill of this.discover(resolved.resolvedPath)) {
|
|
5319
|
-
const skillMd =
|
|
5540
|
+
const skillMd = join24(skill.path, "SKILL.md");
|
|
5320
5541
|
if (await pathExists(skillMd)) {
|
|
5321
|
-
this.core.translateSkill(await
|
|
5542
|
+
this.core.translateSkill(await readFile17(skillMd, "utf8"), "openclaw", { sourceFilename: "SKILL.md" });
|
|
5322
5543
|
}
|
|
5323
5544
|
}
|
|
5324
5545
|
return resolved;
|
|
@@ -5347,8 +5568,8 @@ function normalizeProviderSource(spec) {
|
|
|
5347
5568
|
return spec;
|
|
5348
5569
|
}
|
|
5349
5570
|
function cachePathFor4(spec, cacheRoot) {
|
|
5350
|
-
const root = cacheRoot ? resolve9(cacheRoot) :
|
|
5351
|
-
return
|
|
5571
|
+
const root = cacheRoot ? resolve9(cacheRoot) : join24(homedir3(), ".agentwheel", "cache");
|
|
5572
|
+
return join24(root, "skillkit", packageSlug(spec));
|
|
5352
5573
|
}
|
|
5353
5574
|
function packageSlug(spec) {
|
|
5354
5575
|
return spec.replace(/^[a-z]+:\/\//i, "").replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "source";
|
|
@@ -5361,7 +5582,7 @@ function mapSeverity(severity) {
|
|
|
5361
5582
|
|
|
5362
5583
|
// src/source/vercel-skills.ts
|
|
5363
5584
|
import { stat as stat5 } from "fs/promises";
|
|
5364
|
-
import { basename as
|
|
5585
|
+
import { basename as basename15, join as join25, relative as relative5, resolve as resolve10 } from "path";
|
|
5365
5586
|
var VercelSkillsSourceDriver = class {
|
|
5366
5587
|
name = "vercel-skills";
|
|
5367
5588
|
git = new GitSourceDriver();
|
|
@@ -5376,7 +5597,7 @@ var VercelSkillsSourceDriver = class {
|
|
|
5376
5597
|
driver: this.name,
|
|
5377
5598
|
source,
|
|
5378
5599
|
resolvedPath,
|
|
5379
|
-
packageName: `vercel/${
|
|
5600
|
+
packageName: `vercel/${basename15(resolvedPath)}`,
|
|
5380
5601
|
mode: options.mode ?? "pinned",
|
|
5381
5602
|
sourceHash: await hashPath(resolvedPath)
|
|
5382
5603
|
};
|
|
@@ -5424,7 +5645,7 @@ var VercelSkillsSourceDriver = class {
|
|
|
5424
5645
|
};
|
|
5425
5646
|
async function resolveVercelSkillSubpath(root, subpath) {
|
|
5426
5647
|
if (!subpath) return root;
|
|
5427
|
-
const candidates = [
|
|
5648
|
+
const candidates = [join25(root, subpath), join25(root, "skills", subpath)];
|
|
5428
5649
|
for (const candidate of candidates) {
|
|
5429
5650
|
if (await pathExists(candidate)) return candidate;
|
|
5430
5651
|
}
|
|
@@ -5494,14 +5715,14 @@ function getSourceDriver(name = "local") {
|
|
|
5494
5715
|
}
|
|
5495
5716
|
|
|
5496
5717
|
// src/staging/staging.ts
|
|
5497
|
-
import { chmod, cp as cp5, mkdir as
|
|
5498
|
-
import { basename as
|
|
5718
|
+
import { chmod, cp as cp5, mkdir as mkdir16, mkdtemp as mkdtemp3, readdir as readdir5, stat as stat8 } from "fs/promises";
|
|
5719
|
+
import { basename as basename18, dirname as dirname21, join as join28, relative as relative7, resolve as resolve12, sep as sep2 } from "path";
|
|
5499
5720
|
import { tmpdir as tmpdir4 } from "os";
|
|
5500
5721
|
|
|
5501
5722
|
// src/compose/markdown.ts
|
|
5502
5723
|
import { createHash as createHash5 } from "crypto";
|
|
5503
|
-
import { readdir as readdir3, readFile as
|
|
5504
|
-
import { basename as
|
|
5724
|
+
import { readdir as readdir3, readFile as readFile18, stat as stat6, writeFile as writeFile16 } from "fs/promises";
|
|
5725
|
+
import { basename as basename16, dirname as dirname19, extname as extname3, join as join26, relative as relative6, resolve as resolve11, sep } from "path";
|
|
5505
5726
|
var includePattern = /<!--\s*openpack:include(\?)?\s+([^>]+?)\s*-->/g;
|
|
5506
5727
|
var escapedIncludePattern = /<!--\s*openpack\\:include(\?)?\s+([^>]+?)\s*-->/g;
|
|
5507
5728
|
var generatedPattern = /<!--\s*(?:BEGIN|END)\s+openpack:include\b/;
|
|
@@ -5516,7 +5737,7 @@ async function expandMarkdownIncludes(artifacts, packageRoot, options = {}) {
|
|
|
5516
5737
|
const composedFrom = [];
|
|
5517
5738
|
for (const file of files) {
|
|
5518
5739
|
const result = await expandFile(file, packageRoot, composeEntriesForFile(artifact, file), artifactPaths, options);
|
|
5519
|
-
if (result.changed) await
|
|
5740
|
+
if (result.changed) await writeFile16(file, result.content, "utf8");
|
|
5520
5741
|
composedFrom.push(...result.composedFrom);
|
|
5521
5742
|
}
|
|
5522
5743
|
const stagedPath = artifact.stagedPath ?? artifact.sourcePath;
|
|
@@ -5538,7 +5759,7 @@ async function validateMarkdownIncludes(artifacts, packageRoot, options = {}) {
|
|
|
5538
5759
|
}
|
|
5539
5760
|
}
|
|
5540
5761
|
async function expandFile(file, packageRoot, appendEntries, artifactPaths, options) {
|
|
5541
|
-
const raw = await
|
|
5762
|
+
const raw = await readFile18(file, "utf8");
|
|
5542
5763
|
const owner = ownerSelector(packageRoot, file, options.nodeId);
|
|
5543
5764
|
const expanded = await expandContent(raw, packageRoot, [owner], artifactPaths, options);
|
|
5544
5765
|
let content = expanded.content;
|
|
@@ -5631,7 +5852,7 @@ async function expandInclude(selector, packageRoot, artifactPaths, options) {
|
|
|
5631
5852
|
if (!stats.isFile()) {
|
|
5632
5853
|
throw new Error(`OpenPack include is not a file: ${displaySelector}`);
|
|
5633
5854
|
}
|
|
5634
|
-
const raw = sourceContent ?? await
|
|
5855
|
+
const raw = sourceContent ?? await readFile18(sourcePath, "utf8");
|
|
5635
5856
|
const { optional: _optional, markers: _markers, chain: _chain, ...childOptions } = options;
|
|
5636
5857
|
const expanded = await expandContent(raw, includePackageRoot, [...options.chain, displaySelector], includeArtifactPaths, {
|
|
5637
5858
|
...childOptions,
|
|
@@ -5707,7 +5928,7 @@ async function listMarkdownFiles(root) {
|
|
|
5707
5928
|
const out = [];
|
|
5708
5929
|
async function walk2(dir) {
|
|
5709
5930
|
for (const entry of (await readdir3(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
5710
|
-
const full =
|
|
5931
|
+
const full = join26(dir, entry.name);
|
|
5711
5932
|
if (entry.isDirectory()) {
|
|
5712
5933
|
await walk2(full);
|
|
5713
5934
|
} else if (entry.isFile() && extname3(entry.name).toLowerCase() === ".md") {
|
|
@@ -5721,7 +5942,7 @@ async function listMarkdownFiles(root) {
|
|
|
5721
5942
|
function composeEntriesForFile(artifact, file) {
|
|
5722
5943
|
if (!artifact.compose?.length) return [];
|
|
5723
5944
|
if (artifact.kind === "file") return [resolve11(artifact.stagedPath ?? artifact.sourcePath), resolve11(file)].every(Boolean) && resolve11(artifact.stagedPath ?? artifact.sourcePath) === resolve11(file) ? artifact.compose : [];
|
|
5724
|
-
return
|
|
5945
|
+
return basename16(file) === "SKILL.md" && dirname19(file) === resolve11(artifact.stagedPath ?? artifact.sourcePath) ? artifact.compose : [];
|
|
5725
5946
|
}
|
|
5726
5947
|
function orderedForExpansion(artifacts) {
|
|
5727
5948
|
return [...artifacts].sort((a, b) => Number(a.type === "fragments") - Number(b.type === "fragments"));
|
|
@@ -5767,8 +5988,8 @@ function artifactPathMap(artifacts) {
|
|
|
5767
5988
|
}
|
|
5768
5989
|
|
|
5769
5990
|
// src/staging/customize.ts
|
|
5770
|
-
import { cp as cp4, mkdir as
|
|
5771
|
-
import { dirname as
|
|
5991
|
+
import { cp as cp4, mkdir as mkdir15, readdir as readdir4, readFile as readFile19, writeFile as writeFile17 } from "fs/promises";
|
|
5992
|
+
import { dirname as dirname20, join as join27 } from "path";
|
|
5772
5993
|
async function applyCustomizations(artifacts, options) {
|
|
5773
5994
|
let next = [...artifacts];
|
|
5774
5995
|
next = await applyReplacements2(next, options, "override", installableArtifactTypes());
|
|
@@ -5784,16 +6005,16 @@ async function applyFragmentCustomizations(artifacts, options) {
|
|
|
5784
6005
|
return next.sort((a, b) => `${a.type}:${a.name}:${a.channel}`.localeCompare(`${b.type}:${b.name}:${b.channel}`));
|
|
5785
6006
|
}
|
|
5786
6007
|
async function applyInstructionOverlay(artifacts, options) {
|
|
5787
|
-
const overlayPath =
|
|
6008
|
+
const overlayPath = join27(options.workspaceRoot, ".agentwheel", "overlays", options.adapter.name, "instructions.local.md");
|
|
5788
6009
|
if (!await pathExists(overlayPath)) return artifacts;
|
|
5789
6010
|
const index = artifacts.findIndex((artifact2) => artifact2.type === "instructions");
|
|
5790
6011
|
if (index < 0) return artifacts;
|
|
5791
6012
|
const artifact = artifacts[index];
|
|
5792
|
-
const managed = await
|
|
5793
|
-
const local = await
|
|
5794
|
-
const composedPath =
|
|
5795
|
-
await
|
|
5796
|
-
await
|
|
6013
|
+
const managed = await readFile19(artifact.stagedPath ?? artifact.sourcePath, "utf8");
|
|
6014
|
+
const local = await readFile19(overlayPath, "utf8");
|
|
6015
|
+
const composedPath = join27(options.stageRoot, ".agentwheel-composed", "instructions", "AGENTS.md");
|
|
6016
|
+
await mkdir15(dirname20(composedPath), { recursive: true });
|
|
6017
|
+
await writeFile17(
|
|
5797
6018
|
composedPath,
|
|
5798
6019
|
[
|
|
5799
6020
|
"<!-- BEGIN agentwheel managed: upstream -->",
|
|
@@ -5819,19 +6040,19 @@ async function applyInstructionOverlay(artifacts, options) {
|
|
|
5819
6040
|
return [...artifacts.slice(0, index), updated, ...artifacts.slice(index + 1)];
|
|
5820
6041
|
}
|
|
5821
6042
|
async function applyAdditions(artifacts, options) {
|
|
5822
|
-
const additionsRoot =
|
|
5823
|
-
const rulesRoot =
|
|
6043
|
+
const additionsRoot = join27(options.workspaceRoot, ".agentwheel", "additions");
|
|
6044
|
+
const rulesRoot = join27(additionsRoot, "rules");
|
|
5824
6045
|
if (!await pathExists(rulesRoot)) return artifacts;
|
|
5825
6046
|
const additions = [];
|
|
5826
6047
|
for (const entry of await sortedDirEntries2(rulesRoot)) {
|
|
5827
|
-
const full =
|
|
6048
|
+
const full = join27(rulesRoot, entry.name);
|
|
5828
6049
|
if (!entry.isFile()) continue;
|
|
5829
6050
|
additions.push({
|
|
5830
6051
|
type: "rules",
|
|
5831
6052
|
name: entry.name,
|
|
5832
6053
|
sourcePath: full,
|
|
5833
6054
|
stagedPath: full,
|
|
5834
|
-
relativePath:
|
|
6055
|
+
relativePath: join27("additions", "rules", entry.name),
|
|
5835
6056
|
kind: "file",
|
|
5836
6057
|
hash: await hashPath(full),
|
|
5837
6058
|
packageName: options.packageName,
|
|
@@ -5855,17 +6076,17 @@ async function applyReplacements2(artifacts, options, channel, artifactTypes) {
|
|
|
5855
6076
|
);
|
|
5856
6077
|
}
|
|
5857
6078
|
for (const type of artifactTypes) {
|
|
5858
|
-
const typeRoot =
|
|
6079
|
+
const typeRoot = join27(root, type);
|
|
5859
6080
|
if (!await pathExists(typeRoot)) continue;
|
|
5860
6081
|
for (const entry of await sortedDirEntries2(typeRoot)) {
|
|
5861
6082
|
const artifactMapKey = `${type}:${entry.name}`;
|
|
5862
6083
|
if (seen.has(artifactMapKey)) continue;
|
|
5863
6084
|
seen.add(artifactMapKey);
|
|
5864
|
-
const full =
|
|
6085
|
+
const full = join27(typeRoot, entry.name);
|
|
5865
6086
|
const artifactKind = entry.isDirectory() ? "dir" : "file";
|
|
5866
6087
|
const existing = byKey.get(artifactMapKey);
|
|
5867
|
-
const stagedPath =
|
|
5868
|
-
await
|
|
6088
|
+
const stagedPath = join27(options.stageRoot, ".agentwheel-composed", channel, type, entry.name);
|
|
6089
|
+
await mkdir15(dirname20(stagedPath), { recursive: true });
|
|
5869
6090
|
await cp4(full, stagedPath, { recursive: artifactKind === "dir", dereference: true });
|
|
5870
6091
|
byKey.set(artifactMapKey, {
|
|
5871
6092
|
...existing,
|
|
@@ -5873,7 +6094,7 @@ async function applyReplacements2(artifacts, options, channel, artifactTypes) {
|
|
|
5873
6094
|
name: entry.name,
|
|
5874
6095
|
sourcePath: full,
|
|
5875
6096
|
stagedPath,
|
|
5876
|
-
relativePath: existing?.relativePath ??
|
|
6097
|
+
relativePath: existing?.relativePath ?? join27(type, entry.name),
|
|
5877
6098
|
kind: artifactKind,
|
|
5878
6099
|
hash: await hashPath(stagedPath),
|
|
5879
6100
|
packageName,
|
|
@@ -5888,13 +6109,13 @@ function replacementRoots(options, channel) {
|
|
|
5888
6109
|
const stateDir = channel === "override" ? "overrides" : "ejected";
|
|
5889
6110
|
const roots = [];
|
|
5890
6111
|
if (options.graphNodeId) {
|
|
5891
|
-
roots.push({ root:
|
|
6112
|
+
roots.push({ root: join27(options.workspaceRoot, ".agentwheel", stateDir, ...options.graphNodeId.split("/")), kind: "node" });
|
|
5892
6113
|
}
|
|
5893
6114
|
if (options.packageName && options.packageVersion) {
|
|
5894
|
-
roots.push({ root:
|
|
6115
|
+
roots.push({ root: join27(options.workspaceRoot, ".agentwheel", stateDir, ...`${options.packageName}@${options.packageVersion}`.split("/")), kind: "version" });
|
|
5895
6116
|
}
|
|
5896
6117
|
if (options.packageName) {
|
|
5897
|
-
roots.push({ root:
|
|
6118
|
+
roots.push({ root: join27(options.workspaceRoot, ".agentwheel", stateDir, ...options.packageName.split("/")), kind: "package" });
|
|
5898
6119
|
}
|
|
5899
6120
|
return roots;
|
|
5900
6121
|
}
|
|
@@ -5921,15 +6142,15 @@ async function stageResolvedSourceRaw(driver, resolved) {
|
|
|
5921
6142
|
return stageResolvedArtifactsRaw(resolved, artifacts);
|
|
5922
6143
|
}
|
|
5923
6144
|
async function stageResolvedArtifactsRaw(resolved, artifacts) {
|
|
5924
|
-
const root = await mkdtemp3(
|
|
6145
|
+
const root = await mkdtemp3(join28(tmpdir4(), "agentwheel-stage-"));
|
|
5925
6146
|
const stagedArtifacts = [];
|
|
5926
6147
|
for (const artifact of artifacts) {
|
|
5927
|
-
const stagedPath =
|
|
5928
|
-
await
|
|
6148
|
+
const stagedPath = join28(root, artifact.relativePath);
|
|
6149
|
+
await mkdir16(dirname21(stagedPath), { recursive: true });
|
|
5929
6150
|
await cp5(artifact.sourcePath, stagedPath, {
|
|
5930
6151
|
recursive: artifact.kind === "dir",
|
|
5931
6152
|
dereference: true,
|
|
5932
|
-
filter: (path) => !isIgnoredGeneratedEntry(
|
|
6153
|
+
filter: (path) => !isIgnoredGeneratedEntry(basename18(path))
|
|
5933
6154
|
});
|
|
5934
6155
|
await composeAssets(artifact, resolved.resolvedPath, stagedPath);
|
|
5935
6156
|
stagedArtifacts.push({
|
|
@@ -5958,7 +6179,8 @@ async function renderStagedBundle(bundle, options = {}) {
|
|
|
5958
6179
|
const runtimeSelectedSet = new Set(normalizeArtifactSelectors(options.select, options.skills) ?? []);
|
|
5959
6180
|
const runtimeArtifacts = options.adapter ? filterArtifactsByRuntime(selectedArtifacts, options.adapter.name, runtimeSelectedSet) : selectedArtifacts;
|
|
5960
6181
|
const codexRenderedArtifacts = await renderCodexSubagents(runtimeArtifacts, root, options.adapter);
|
|
5961
|
-
const
|
|
6182
|
+
const openClawRenderedArtifacts = await renderOpenClawSubagents(codexRenderedArtifacts, root, options.adapter);
|
|
6183
|
+
const renderedArtifacts = await renderCopilotArtifacts(openClawRenderedArtifacts, root, options.adapter);
|
|
5962
6184
|
const finalArtifacts = options.workspaceRoot && options.adapter ? await applyCustomizations(renderedArtifacts, {
|
|
5963
6185
|
workspaceRoot: options.workspaceRoot,
|
|
5964
6186
|
adapter: options.adapter,
|
|
@@ -6010,16 +6232,16 @@ async function composeAssets(artifact, packageRoot, stagedPath) {
|
|
|
6010
6232
|
}
|
|
6011
6233
|
for (const asset of artifact.assets) {
|
|
6012
6234
|
const source = resolvePackagePath(packageRoot, asset.from);
|
|
6013
|
-
const dest =
|
|
6235
|
+
const dest = join28(stagedPath, asset.into);
|
|
6014
6236
|
await copyAsset(asset, source, dest);
|
|
6015
6237
|
}
|
|
6016
6238
|
}
|
|
6017
6239
|
async function copyAsset(asset, source, dest) {
|
|
6018
6240
|
const sourceStats = await stat8(source);
|
|
6019
6241
|
if (sourceStats.isFile()) {
|
|
6020
|
-
if (matchesAny(
|
|
6021
|
-
await
|
|
6022
|
-
await copyAssetFile(source,
|
|
6242
|
+
if (matchesAny(basename18(source), asset.include)) {
|
|
6243
|
+
await mkdir16(dest, { recursive: true });
|
|
6244
|
+
await copyAssetFile(source, join28(dest, basename18(source)), asset);
|
|
6023
6245
|
}
|
|
6024
6246
|
return;
|
|
6025
6247
|
}
|
|
@@ -6027,19 +6249,19 @@ async function copyAsset(asset, source, dest) {
|
|
|
6027
6249
|
throw new Error(`Asset include source is not a file or directory: ${source}`);
|
|
6028
6250
|
}
|
|
6029
6251
|
if (!asset.include?.length) {
|
|
6030
|
-
await
|
|
6252
|
+
await mkdir16(dirname21(dest), { recursive: true });
|
|
6031
6253
|
await cp5(source, dest, { recursive: true, dereference: true });
|
|
6032
6254
|
if (asset.mode === "copy") await normalizeCopiedModes(dest);
|
|
6033
6255
|
return;
|
|
6034
6256
|
}
|
|
6035
6257
|
for (const file of await listFiles(source)) {
|
|
6036
6258
|
const rel = relative7(source, file).replaceAll("\\", "/");
|
|
6037
|
-
if (!matchesAny(rel, asset.include) && !matchesAny(
|
|
6038
|
-
await copyAssetFile(file,
|
|
6259
|
+
if (!matchesAny(rel, asset.include) && !matchesAny(basename18(file), asset.include)) continue;
|
|
6260
|
+
await copyAssetFile(file, join28(dest, rel), asset);
|
|
6039
6261
|
}
|
|
6040
6262
|
}
|
|
6041
6263
|
async function copyAssetFile(source, dest, asset) {
|
|
6042
|
-
await
|
|
6264
|
+
await mkdir16(dirname21(dest), { recursive: true });
|
|
6043
6265
|
await cp5(source, dest, { dereference: true });
|
|
6044
6266
|
if (asset.mode === "copy") await chmod(dest, 420);
|
|
6045
6267
|
}
|
|
@@ -6055,7 +6277,7 @@ async function listFiles(root) {
|
|
|
6055
6277
|
const out = [];
|
|
6056
6278
|
async function walk2(dir) {
|
|
6057
6279
|
for (const entry of (await readdir5(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
6058
|
-
const full =
|
|
6280
|
+
const full = join28(dir, entry.name);
|
|
6059
6281
|
if (entry.isDirectory()) {
|
|
6060
6282
|
await walk2(full);
|
|
6061
6283
|
} else if (entry.isFile()) {
|
|
@@ -6074,7 +6296,7 @@ async function normalizeCopiedModes(path) {
|
|
|
6074
6296
|
}
|
|
6075
6297
|
if (!stats.isDirectory()) return;
|
|
6076
6298
|
for (const entry of await readdir5(path, { withFileTypes: true })) {
|
|
6077
|
-
await normalizeCopiedModes(
|
|
6299
|
+
await normalizeCopiedModes(join28(path, entry.name));
|
|
6078
6300
|
}
|
|
6079
6301
|
}
|
|
6080
6302
|
function matchesAny(path, patterns) {
|
|
@@ -6087,9 +6309,9 @@ function matchesGlob(path, pattern) {
|
|
|
6087
6309
|
}
|
|
6088
6310
|
|
|
6089
6311
|
// src/model/workspace.ts
|
|
6090
|
-
import { readFile as
|
|
6312
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
6091
6313
|
import { homedir as homedir4 } from "os";
|
|
6092
|
-
import { dirname as
|
|
6314
|
+
import { dirname as dirname22, join as join29, resolve as resolve13 } from "path";
|
|
6093
6315
|
import { z as z6 } from "zod";
|
|
6094
6316
|
var workspacePackageSchema = z6.object({
|
|
6095
6317
|
name: z6.string().min(1),
|
|
@@ -6133,6 +6355,8 @@ var workspaceTrustSchema = z6.object({
|
|
|
6133
6355
|
}).default({});
|
|
6134
6356
|
var workspaceAgentSchema = z6.object({
|
|
6135
6357
|
adapter: z6.string().min(1),
|
|
6358
|
+
adapterConfig: z6.string().min(1).optional(),
|
|
6359
|
+
adapterModule: z6.string().min(1).optional(),
|
|
6136
6360
|
root: z6.string().min(1),
|
|
6137
6361
|
installationType: installationTypeSchema.optional(),
|
|
6138
6362
|
transport: z6.enum(["local", "ssh"]).default("local"),
|
|
@@ -6160,12 +6384,12 @@ var workspaceConfigSchema = z6.object({
|
|
|
6160
6384
|
agents: z6.record(z6.string(), workspaceAgentSchema).default({})
|
|
6161
6385
|
});
|
|
6162
6386
|
function workspaceConfigPath(workspaceRoot) {
|
|
6163
|
-
return
|
|
6387
|
+
return join29(workspaceRoot, ".agentwheel", "config.json");
|
|
6164
6388
|
}
|
|
6165
6389
|
async function readWorkspaceConfig(workspaceRoot) {
|
|
6166
6390
|
const path = workspaceConfigPath(workspaceRoot);
|
|
6167
6391
|
if (!await pathExists(path)) return emptyWorkspaceConfig();
|
|
6168
|
-
return workspaceConfigSchema.parse(JSON.parse(await
|
|
6392
|
+
return workspaceConfigSchema.parse(JSON.parse(await readFile20(path, "utf8")));
|
|
6169
6393
|
}
|
|
6170
6394
|
async function writeWorkspaceConfig(workspaceRoot, config) {
|
|
6171
6395
|
await writeJsonAtomic(workspaceConfigPath(workspaceRoot), workspaceConfigSchema.parse(config));
|
|
@@ -6178,13 +6402,13 @@ function upsertPackage(config, entry) {
|
|
|
6178
6402
|
return { schemaVersion: 1, packages, bootstrapSkills: parsed.bootstrapSkills, registry: parsed.registry ?? {}, trust: parsed.trust ?? {}, profiles: parsed.profiles ?? {}, agents: parsed.agents ?? {} };
|
|
6179
6403
|
}
|
|
6180
6404
|
function globalWorkspaceConfigPath(globalRoot = homedir4()) {
|
|
6181
|
-
return
|
|
6405
|
+
return join29(globalRoot, ".agentwheel", "config.json");
|
|
6182
6406
|
}
|
|
6183
6407
|
async function findWorkspaceRoot(start = process.cwd()) {
|
|
6184
6408
|
let current = resolve13(start);
|
|
6185
6409
|
while (true) {
|
|
6186
6410
|
if (await pathExists(workspaceConfigPath(current))) return current;
|
|
6187
|
-
const parent =
|
|
6411
|
+
const parent = dirname22(current);
|
|
6188
6412
|
if (parent === current) return resolve13(start);
|
|
6189
6413
|
current = parent;
|
|
6190
6414
|
}
|
|
@@ -6220,7 +6444,7 @@ function emptyWorkspaceConfig() {
|
|
|
6220
6444
|
}
|
|
6221
6445
|
async function readConfigPath(path) {
|
|
6222
6446
|
if (!await pathExists(path)) return emptyWorkspaceConfig();
|
|
6223
|
-
return workspaceConfigSchema.parse(JSON.parse(await
|
|
6447
|
+
return workspaceConfigSchema.parse(JSON.parse(await readFile20(path, "utf8")));
|
|
6224
6448
|
}
|
|
6225
6449
|
function mergeWorkspaceTrust(global, project) {
|
|
6226
6450
|
return {
|
|
@@ -6235,23 +6459,23 @@ function sortedUnique2(values) {
|
|
|
6235
6459
|
}
|
|
6236
6460
|
|
|
6237
6461
|
// src/lifecycle/customization.ts
|
|
6238
|
-
import { appendFile, cp as cp6, mkdir as
|
|
6239
|
-
import { dirname as
|
|
6462
|
+
import { appendFile, cp as cp6, mkdir as mkdir17, rm as rm9 } from "fs/promises";
|
|
6463
|
+
import { dirname as dirname24, join as join32 } from "path";
|
|
6240
6464
|
|
|
6241
6465
|
// src/resolve/graph.ts
|
|
6242
6466
|
import { createHash as createHash6 } from "crypto";
|
|
6243
|
-
import { mkdtemp as mkdtemp4, readdir as readdir6, readFile as
|
|
6467
|
+
import { mkdtemp as mkdtemp4, readdir as readdir6, readFile as readFile22, stat as stat10 } from "fs/promises";
|
|
6244
6468
|
import { tmpdir as tmpdir5 } from "os";
|
|
6245
|
-
import { basename as
|
|
6469
|
+
import { basename as basename19, extname as extname4, join as join31 } from "path";
|
|
6246
6470
|
|
|
6247
6471
|
// src/resolve/identity.ts
|
|
6248
6472
|
import { homedir as homedir6 } from "os";
|
|
6249
6473
|
import { resolve as resolve15 } from "path";
|
|
6250
6474
|
|
|
6251
6475
|
// src/registry/client.ts
|
|
6252
|
-
import { readFile as
|
|
6476
|
+
import { readFile as readFile21, rm as rm8, stat as stat9 } from "fs/promises";
|
|
6253
6477
|
import { homedir as homedir5 } from "os";
|
|
6254
|
-
import { dirname as
|
|
6478
|
+
import { dirname as dirname23, join as join30, resolve as resolve14 } from "path";
|
|
6255
6479
|
import { fileURLToPath } from "url";
|
|
6256
6480
|
|
|
6257
6481
|
// src/model/registry.ts
|
|
@@ -6355,7 +6579,7 @@ var RegistryClient = class {
|
|
|
6355
6579
|
}
|
|
6356
6580
|
async readCache() {
|
|
6357
6581
|
if (!await pathExists(this.cachePath)) return void 0;
|
|
6358
|
-
return registryCacheSchema.parse(JSON.parse(await
|
|
6582
|
+
return registryCacheSchema.parse(JSON.parse(await readFile21(this.cachePath, "utf8")));
|
|
6359
6583
|
}
|
|
6360
6584
|
isExpired(cache, ttlMs) {
|
|
6361
6585
|
return this.now().getTime() - new Date(cache.fetchedAt).getTime() > ttlMs;
|
|
@@ -6374,10 +6598,10 @@ var RegistryClient = class {
|
|
|
6374
6598
|
if (await pathExists(filePath)) {
|
|
6375
6599
|
const fullPath = resolve14(filePath);
|
|
6376
6600
|
const stats = await stat9(fullPath);
|
|
6377
|
-
return
|
|
6601
|
+
return readFile21(stats.isDirectory() ? join30(fullPath, "index.json") : fullPath, "utf8");
|
|
6378
6602
|
}
|
|
6379
|
-
const resolved = await this.git.fetch(await this.git.resolve(source, { cacheRoot:
|
|
6380
|
-
return
|
|
6603
|
+
const resolved = await this.git.fetch(await this.git.resolve(source, { cacheRoot: join30(dirname23(this.cachePath), "registry-repos") }));
|
|
6604
|
+
return readFile21(join30(resolved.resolvedPath, "index.json"), "utf8");
|
|
6381
6605
|
}
|
|
6382
6606
|
warnCompatibility(entries) {
|
|
6383
6607
|
for (const entry of entries) {
|
|
@@ -6415,7 +6639,7 @@ function mergeIndexes(indexes) {
|
|
|
6415
6639
|
return [...merged.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
6416
6640
|
}
|
|
6417
6641
|
function defaultRegistryCachePath() {
|
|
6418
|
-
return
|
|
6642
|
+
return join30(homedir5(), ".agentwheel", "registry-cache.json");
|
|
6419
6643
|
}
|
|
6420
6644
|
function sameSources(a, b) {
|
|
6421
6645
|
return a.length === b.length && a.every((source, index) => source === b[index]);
|
|
@@ -6665,7 +6889,7 @@ function compareSemver(a, b) {
|
|
|
6665
6889
|
var cacheLocks = /* @__PURE__ */ new Map();
|
|
6666
6890
|
async function resolveDependencyGraph(roots, options) {
|
|
6667
6891
|
if (roots.length === 0) throw new Error("At least one graph root is required.");
|
|
6668
|
-
const graphRoot = await mkdtemp4(
|
|
6892
|
+
const graphRoot = await mkdtemp4(join31(tmpdir5(), "agentwheel-graph-"));
|
|
6669
6893
|
const fetchCache = /* @__PURE__ */ new Map();
|
|
6670
6894
|
const nodesByKey = /* @__PURE__ */ new Map();
|
|
6671
6895
|
const rootResults = [];
|
|
@@ -7128,7 +7352,7 @@ async function collectIncludeNeeds(artifact, artifactsByRelativePath) {
|
|
|
7128
7352
|
const file = stack.shift();
|
|
7129
7353
|
if (scanned.has(file)) continue;
|
|
7130
7354
|
scanned.add(file);
|
|
7131
|
-
const content = await
|
|
7355
|
+
const content = await readFile22(file, "utf8");
|
|
7132
7356
|
for (const include of extractOpenPackIncludeSelectors(content)) {
|
|
7133
7357
|
await collectIncludeSelector(include.raw, include.optional, artifactsByRelativePath, scanned, stack, needs);
|
|
7134
7358
|
}
|
|
@@ -7171,7 +7395,7 @@ async function listMarkdownFiles2(root) {
|
|
|
7171
7395
|
const out = [];
|
|
7172
7396
|
async function walk2(dir) {
|
|
7173
7397
|
for (const entry of (await readdir6(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
7174
|
-
const full =
|
|
7398
|
+
const full = join31(dir, entry.name);
|
|
7175
7399
|
if (entry.isDirectory()) {
|
|
7176
7400
|
await walk2(full);
|
|
7177
7401
|
} else if (entry.isFile() && extname4(entry.name).toLowerCase() === ".md") {
|
|
@@ -7206,7 +7430,7 @@ async function fetchPackage(normalized, mode, options, fetchCache, refOverride)
|
|
|
7206
7430
|
const promise = (async () => {
|
|
7207
7431
|
const driver = getSourceDriver(normalized.driver);
|
|
7208
7432
|
const resolved = await driver.resolve(normalized.source, {
|
|
7209
|
-
cacheRoot: options.cacheRoot ??
|
|
7433
|
+
cacheRoot: options.cacheRoot ?? join31(options.workspaceRoot, ".agentwheel", "cache"),
|
|
7210
7434
|
mode,
|
|
7211
7435
|
ref: refOverride ?? normalized.requestedRef,
|
|
7212
7436
|
frozenLock: hardLockedCheckout
|
|
@@ -7216,7 +7440,7 @@ async function fetchPackage(normalized, mode, options, fetchCache, refOverride)
|
|
|
7216
7440
|
const exported = await driver.export(translated);
|
|
7217
7441
|
const manifest = await readPackageManifest(exported.resolvedPath);
|
|
7218
7442
|
const artifacts = await driver.list(exported);
|
|
7219
|
-
const name = manifest?.name ?? exported.packageName ??
|
|
7443
|
+
const name = manifest?.name ?? exported.packageName ?? basename19(exported.resolvedPath);
|
|
7220
7444
|
const version = manifest?.version ?? exported.packageVersion ?? "0.0.0";
|
|
7221
7445
|
const sourceHash = exported.sourceHash ?? await hashPath(exported.resolvedPath);
|
|
7222
7446
|
return {
|
|
@@ -7413,8 +7637,8 @@ async function mapLimit(items, limit, fn) {
|
|
|
7413
7637
|
|
|
7414
7638
|
// src/lifecycle/customization.ts
|
|
7415
7639
|
async function remember(workspaceRoot, runtime, text) {
|
|
7416
|
-
const overlayPath =
|
|
7417
|
-
await
|
|
7640
|
+
const overlayPath = join32(workspaceRoot, ".agentwheel", "overlays", runtime, "instructions.local.md");
|
|
7641
|
+
await mkdir17(dirname24(overlayPath), { recursive: true });
|
|
7418
7642
|
await appendFile(overlayPath, `${text.trim()}
|
|
7419
7643
|
`, "utf8");
|
|
7420
7644
|
return { overlayPath };
|
|
@@ -7437,8 +7661,8 @@ async function ejectArtifact(workspaceRoot, item) {
|
|
|
7437
7661
|
throw new Error(`Artifact not found: ${item}`);
|
|
7438
7662
|
}
|
|
7439
7663
|
const ejectedIdentity = parsed.packageIdentity === parsed.packageName ? parsed.packageIdentity : candidate.nodeId === parsed.packageIdentity ? candidate.nodeId : `${candidate.packageName}@${candidate.packageVersion}`;
|
|
7440
|
-
const ejectedPath =
|
|
7441
|
-
await
|
|
7664
|
+
const ejectedPath = join32(workspaceRoot, ".agentwheel", "ejected", ...ejectedIdentity.split("/"), parsed.type, parsed.name);
|
|
7665
|
+
await mkdir17(dirname24(ejectedPath), { recursive: true });
|
|
7442
7666
|
await rm9(ejectedPath, { recursive: true, force: true });
|
|
7443
7667
|
await cp6(artifact.stagedPath ?? artifact.sourcePath, ejectedPath, { recursive: artifact.kind === "dir", dereference: true });
|
|
7444
7668
|
return {
|
|
@@ -7480,7 +7704,7 @@ async function stageEjectCandidate(workspaceRoot, pkg) {
|
|
|
7480
7704
|
const adapter = pkg.adapterConfig ? await loadAdapterConfig(pkg.adapterConfig) : getAdapter(pkg.adapter);
|
|
7481
7705
|
const bundle = await stageSource(driver, normalized.source, {
|
|
7482
7706
|
adapter,
|
|
7483
|
-
cacheRoot:
|
|
7707
|
+
cacheRoot: join32(workspaceRoot, ".agentwheel", "cache"),
|
|
7484
7708
|
mode: pkg.mode,
|
|
7485
7709
|
ref: normalized.requestedRef ?? pkg.requestedRef
|
|
7486
7710
|
});
|
|
@@ -7531,8 +7755,8 @@ import { rm as rm10 } from "fs/promises";
|
|
|
7531
7755
|
|
|
7532
7756
|
// src/lifecycle/source-plan.ts
|
|
7533
7757
|
import { createHash as createHash8 } from "crypto";
|
|
7534
|
-
import { mkdir as
|
|
7535
|
-
import { dirname as
|
|
7758
|
+
import { mkdir as mkdir19 } from "fs/promises";
|
|
7759
|
+
import { dirname as dirname26, join as join35, resolve as resolve16 } from "path";
|
|
7536
7760
|
|
|
7537
7761
|
// src/resolve/graph-diff.ts
|
|
7538
7762
|
function diffGraphLocks(previous, next) {
|
|
@@ -7654,11 +7878,11 @@ function short(hash) {
|
|
|
7654
7878
|
|
|
7655
7879
|
// src/resolve/render.ts
|
|
7656
7880
|
import { createHash as createHash7 } from "crypto";
|
|
7657
|
-
import { readFile as
|
|
7881
|
+
import { readFile as readFile23, mkdtemp as mkdtemp5 } from "fs/promises";
|
|
7658
7882
|
import { tmpdir as tmpdir6 } from "os";
|
|
7659
|
-
import { join as
|
|
7883
|
+
import { join as join33 } from "path";
|
|
7660
7884
|
async function renderGraphForTarget(graph, targetContext = {}) {
|
|
7661
|
-
const root = await mkdtemp5(
|
|
7885
|
+
const root = await mkdtemp5(join33(tmpdir6(), "agentwheel-render-"));
|
|
7662
7886
|
const artifacts = [];
|
|
7663
7887
|
const stagedNodes = /* @__PURE__ */ new Map();
|
|
7664
7888
|
const includeEdges = /* @__PURE__ */ new Map();
|
|
@@ -7731,7 +7955,8 @@ async function renderGraphForTarget(graph, targetContext = {}) {
|
|
|
7731
7955
|
const runtimeSelectedSet = new Set(normalizeArtifactSelectors(rawNode.node.selected) ?? []);
|
|
7732
7956
|
const runtimeArtifacts = targetContext.adapter ? filterArtifactsByRuntime2(selectedArtifacts, targetContext.adapter.name, runtimeSelectedSet) : selectedArtifacts;
|
|
7733
7957
|
const codexRenderedArtifacts = await renderCodexSubagents(runtimeArtifacts, staged.root, targetContext.adapter);
|
|
7734
|
-
const
|
|
7958
|
+
const openClawRenderedArtifacts = await renderOpenClawSubagents(codexRenderedArtifacts, staged.root, targetContext.adapter);
|
|
7959
|
+
const runtimeRenderedArtifacts = await renderCopilotArtifacts(openClawRenderedArtifacts, staged.root, targetContext.adapter);
|
|
7735
7960
|
const renderedArtifacts = targetContext.workspaceRoot && targetContext.adapter ? await applyCustomizations(runtimeRenderedArtifacts, {
|
|
7736
7961
|
workspaceRoot: targetContext.workspaceRoot,
|
|
7737
7962
|
adapter: targetContext.adapter,
|
|
@@ -7778,7 +8003,7 @@ async function artifactContentMap(artifacts) {
|
|
|
7778
8003
|
const out = /* @__PURE__ */ new Map();
|
|
7779
8004
|
for (const artifact of artifacts) {
|
|
7780
8005
|
if (artifact.kind !== "file") continue;
|
|
7781
|
-
out.set(artifact.relativePath.replaceAll("\\", "/"), await
|
|
8006
|
+
out.set(artifact.relativePath.replaceAll("\\", "/"), await readFile23(artifact.stagedPath ?? artifact.sourcePath, "utf8"));
|
|
7782
8007
|
}
|
|
7783
8008
|
return out;
|
|
7784
8009
|
}
|
|
@@ -8041,9 +8266,9 @@ function lockArtifactFor(artifact) {
|
|
|
8041
8266
|
}
|
|
8042
8267
|
|
|
8043
8268
|
// src/lifecycle/trust.ts
|
|
8044
|
-
import { mkdir as
|
|
8269
|
+
import { mkdir as mkdir18, readFile as readFile24 } from "fs/promises";
|
|
8045
8270
|
import { homedir as homedir7 } from "os";
|
|
8046
|
-
import { dirname as
|
|
8271
|
+
import { dirname as dirname25, join as join34 } from "path";
|
|
8047
8272
|
import { z as z8 } from "zod";
|
|
8048
8273
|
var trustStoreSchema = z8.object({
|
|
8049
8274
|
version: z8.literal(1),
|
|
@@ -8117,14 +8342,14 @@ function sortedUnique4(values) {
|
|
|
8117
8342
|
}
|
|
8118
8343
|
async function readTrustStore(path) {
|
|
8119
8344
|
if (!await pathExists(path)) return { version: 1, acceptedSources: [] };
|
|
8120
|
-
return trustStoreSchema.parse(JSON.parse(await
|
|
8345
|
+
return trustStoreSchema.parse(JSON.parse(await readFile24(path, "utf8")));
|
|
8121
8346
|
}
|
|
8122
8347
|
async function writeTrustStore(path, store) {
|
|
8123
|
-
await
|
|
8348
|
+
await mkdir18(dirname25(path), { recursive: true });
|
|
8124
8349
|
await writeJsonAtomic(path, trustStoreSchema.parse(store));
|
|
8125
8350
|
}
|
|
8126
8351
|
function defaultTrustStorePath() {
|
|
8127
|
-
return process.env.AGENTWHEEL_TRUST_STORE ??
|
|
8352
|
+
return process.env.AGENTWHEEL_TRUST_STORE ?? join34(homedir7(), ".agentwheel", "trust.json");
|
|
8128
8353
|
}
|
|
8129
8354
|
|
|
8130
8355
|
// src/lifecycle/source-plan.ts
|
|
@@ -8162,7 +8387,7 @@ async function createGraphSourcePlan(options) {
|
|
|
8162
8387
|
const registryClient = new RegistryClient({ workspaceRoot, offline: lockMode, offlineLabel: lockLabel, warn });
|
|
8163
8388
|
const graph = await resolveDependencyGraph(options.roots, {
|
|
8164
8389
|
workspaceRoot,
|
|
8165
|
-
cacheRoot:
|
|
8390
|
+
cacheRoot: join35(workspaceRoot, ".agentwheel", "cache"),
|
|
8166
8391
|
registryClient,
|
|
8167
8392
|
noDeps: options.noDeps,
|
|
8168
8393
|
includeSuggestions: options.includeSuggestions,
|
|
@@ -8187,7 +8412,12 @@ async function createGraphSourcePlan(options) {
|
|
|
8187
8412
|
targetFingerprint,
|
|
8188
8413
|
warn
|
|
8189
8414
|
});
|
|
8190
|
-
const desiredArtifacts =
|
|
8415
|
+
const desiredArtifacts = filterArtifactsByAdapterTargets(
|
|
8416
|
+
desiredArtifactsFromGraphBundle(bundle),
|
|
8417
|
+
options.adapter,
|
|
8418
|
+
installationType,
|
|
8419
|
+
{ warn }
|
|
8420
|
+
);
|
|
8191
8421
|
const resolvedInstallationType = resolveInstallationTypeForArtifacts(options.adapter, desiredArtifacts.map((artifact) => artifact.type), installationType);
|
|
8192
8422
|
const resolvedInstallRoot = installRootForArtifacts(options.adapter, options.targetRoot, resolvedInstallationType, desiredArtifacts.map((artifact) => artifact.type), transport.kind === "ssh");
|
|
8193
8423
|
const graphLockDigest = digestGraphLock(bundle.graphLock);
|
|
@@ -8262,7 +8492,7 @@ async function readExistingGraphLock(path) {
|
|
|
8262
8492
|
return readGraphLock(path);
|
|
8263
8493
|
}
|
|
8264
8494
|
function pathForGraphLock(workspaceRoot, targetKey, adapter, targetFingerprint) {
|
|
8265
|
-
return
|
|
8495
|
+
return join35(workspaceRoot, ".agentwheel", "locks", sanitizePathSegment(targetKey), sanitizePathSegment(adapter), `${targetFingerprint}.graph-lock.json`);
|
|
8266
8496
|
}
|
|
8267
8497
|
function sanitizePathSegment(value) {
|
|
8268
8498
|
return value.replace(/[^a-z0-9._-]+/gi, "-").replace(/^-+|-+$/g, "") || "default";
|
|
@@ -8326,7 +8556,7 @@ ${sources.map((source) => `- ${source}`).join("\n")}`);
|
|
|
8326
8556
|
}
|
|
8327
8557
|
|
|
8328
8558
|
// src/runtime/target.ts
|
|
8329
|
-
import { basename as
|
|
8559
|
+
import { basename as basename20, dirname as dirname27, join as join36, resolve as resolve17 } from "path";
|
|
8330
8560
|
var runtimeMarkers = [
|
|
8331
8561
|
{ adapter: "openclaw", dirs: [".openclaw", ".clawdbot", ".moltbot"] },
|
|
8332
8562
|
{ adapter: "claude", dirs: [".claude"] },
|
|
@@ -8437,9 +8667,9 @@ async function detectRuntimeTargets(cwd = process.cwd(), adapterFilter) {
|
|
|
8437
8667
|
for (const marker of runtimeMarkers) {
|
|
8438
8668
|
if (adapterFilter && marker.adapter !== adapterFilter) continue;
|
|
8439
8669
|
for (const dir of marker.dirs) {
|
|
8440
|
-
if (
|
|
8441
|
-
matches.push({ adapter: marker.adapter, targetRoot:
|
|
8442
|
-
} else if (await pathExists(
|
|
8670
|
+
if (basename20(root) === dir) {
|
|
8671
|
+
matches.push({ adapter: marker.adapter, targetRoot: dirname27(root) });
|
|
8672
|
+
} else if (await pathExists(join36(root, dir))) {
|
|
8443
8673
|
matches.push({ adapter: marker.adapter, targetRoot: root });
|
|
8444
8674
|
}
|
|
8445
8675
|
}
|
|
@@ -8455,6 +8685,8 @@ function targetFromAgent(name, config, workspaceRoot, installationType) {
|
|
|
8455
8685
|
agentName: name,
|
|
8456
8686
|
targetKey: name,
|
|
8457
8687
|
adapter: agent.adapter,
|
|
8688
|
+
adapterConfig: agent.adapterConfig,
|
|
8689
|
+
adapterModule: agent.adapterModule,
|
|
8458
8690
|
installationType: installationType ?? agent.installationType,
|
|
8459
8691
|
targetRoot: agent.transport === "ssh" ? agent.root : resolveConfigPath(agent.root, workspaceRoot),
|
|
8460
8692
|
workspaceRoot,
|
|
@@ -8478,7 +8710,7 @@ function dedupeTargets(matches) {
|
|
|
8478
8710
|
function runtimeScanRoot(request) {
|
|
8479
8711
|
const root = resolve17(request.targetRoot ?? request.cwd ?? process.cwd());
|
|
8480
8712
|
if (request.targetRoot) return root;
|
|
8481
|
-
return runtimeMarkers.some((marker) => marker.dirs.includes(
|
|
8713
|
+
return runtimeMarkers.some((marker) => marker.dirs.includes(basename20(root))) ? dirname27(root) : root;
|
|
8482
8714
|
}
|
|
8483
8715
|
|
|
8484
8716
|
// src/lifecycle/profile.ts
|
|
@@ -8762,9 +8994,9 @@ function shellQuoteArg(value) {
|
|
|
8762
8994
|
}
|
|
8763
8995
|
|
|
8764
8996
|
// src/cli/update-check.ts
|
|
8765
|
-
import { mkdir as
|
|
8997
|
+
import { mkdir as mkdir20, readFile as readFile25, writeFile as writeFile18 } from "fs/promises";
|
|
8766
8998
|
import { homedir as homedir8 } from "os";
|
|
8767
|
-
import { dirname as
|
|
8999
|
+
import { dirname as dirname28, join as join37 } from "path";
|
|
8768
9000
|
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8769
9001
|
var DEFAULT_TIMEOUT_MS = 300;
|
|
8770
9002
|
var REGISTRY_URL = "https://registry.npmjs.org/agentwheel";
|
|
@@ -8772,7 +9004,7 @@ async function maybeCheckForUpdate(options) {
|
|
|
8772
9004
|
if (isDisabled(options)) return;
|
|
8773
9005
|
const now = options.now?.() ?? /* @__PURE__ */ new Date();
|
|
8774
9006
|
const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
|
|
8775
|
-
const cachePath = options.cachePath ??
|
|
9007
|
+
const cachePath = options.cachePath ?? join37(homedir8(), ".agentwheel", "update-check.json");
|
|
8776
9008
|
try {
|
|
8777
9009
|
const cached = await readCache(cachePath);
|
|
8778
9010
|
if (cached && now.getTime() - Date.parse(cached.checkedAt) < ttlMs) {
|
|
@@ -8809,7 +9041,7 @@ async function fetchLatestVersion(fetchImpl, timeoutMs) {
|
|
|
8809
9041
|
}
|
|
8810
9042
|
async function readCache(path) {
|
|
8811
9043
|
try {
|
|
8812
|
-
const parsed = JSON.parse(await
|
|
9044
|
+
const parsed = JSON.parse(await readFile25(path, "utf8"));
|
|
8813
9045
|
if (typeof parsed.checkedAt !== "string" || typeof parsed.latest !== "string") return void 0;
|
|
8814
9046
|
return { checkedAt: parsed.checkedAt, latest: parsed.latest };
|
|
8815
9047
|
} catch {
|
|
@@ -8817,8 +9049,8 @@ async function readCache(path) {
|
|
|
8817
9049
|
}
|
|
8818
9050
|
}
|
|
8819
9051
|
async function writeCache(path, cache) {
|
|
8820
|
-
await
|
|
8821
|
-
await
|
|
9052
|
+
await mkdir20(dirname28(path), { recursive: true });
|
|
9053
|
+
await writeFile18(path, `${JSON.stringify(cache, null, 2)}
|
|
8822
9054
|
`, "utf8");
|
|
8823
9055
|
}
|
|
8824
9056
|
function warnIfNewer(latest, current, stderr = process.stderr) {
|
|
@@ -8981,13 +9213,13 @@ function isCrossPackageSelector(value) {
|
|
|
8981
9213
|
}
|
|
8982
9214
|
|
|
8983
9215
|
// src/model/package-migrate.ts
|
|
8984
|
-
import { readFile as
|
|
8985
|
-
import { join as
|
|
9216
|
+
import { readFile as readFile26, rename as rename4, writeFile as writeFile19 } from "fs/promises";
|
|
9217
|
+
import { join as join39, resolve as resolve19 } from "path";
|
|
8986
9218
|
import { applyEdits, modify, parse as parse4 } from "jsonc-parser";
|
|
8987
9219
|
async function migratePackageManifest(root) {
|
|
8988
9220
|
const packageRoot = resolve19(root);
|
|
8989
9221
|
for (const name of openPackManifestNames) {
|
|
8990
|
-
const path =
|
|
9222
|
+
const path = join39(packageRoot, name);
|
|
8991
9223
|
if (await pathExists(path)) {
|
|
8992
9224
|
return { changed: false, to: path, message: `Package already uses ${name}.` };
|
|
8993
9225
|
}
|
|
@@ -8996,18 +9228,18 @@ async function migratePackageManifest(root) {
|
|
|
8996
9228
|
if (!legacyName) {
|
|
8997
9229
|
throw new Error(`No legacy package manifest found at ${packageRoot}`);
|
|
8998
9230
|
}
|
|
8999
|
-
const from =
|
|
9231
|
+
const from = join39(packageRoot, legacyName);
|
|
9000
9232
|
const toName = legacyName.endsWith(".jsonc") ? "openpack.jsonc" : "openpack.json";
|
|
9001
|
-
const to =
|
|
9002
|
-
const content = await
|
|
9233
|
+
const to = join39(packageRoot, toName);
|
|
9234
|
+
const content = await readFile26(from, "utf8");
|
|
9003
9235
|
const updated = updateSchemaVersion(content);
|
|
9004
9236
|
await rename4(from, to);
|
|
9005
|
-
await
|
|
9237
|
+
await writeFile19(to, updated, "utf8");
|
|
9006
9238
|
return { changed: true, from, to, message: `Migrated ${legacyName} to ${toName}.` };
|
|
9007
9239
|
}
|
|
9008
9240
|
async function firstExistingLegacyManifest(root) {
|
|
9009
9241
|
for (const name of legacyPackageManifestNames) {
|
|
9010
|
-
if (await pathExists(
|
|
9242
|
+
if (await pathExists(join39(root, name))) return name;
|
|
9011
9243
|
}
|
|
9012
9244
|
return void 0;
|
|
9013
9245
|
}
|
|
@@ -9025,20 +9257,20 @@ function updateSchemaVersion(content) {
|
|
|
9025
9257
|
|
|
9026
9258
|
// src/cli/version.ts
|
|
9027
9259
|
import { readFileSync } from "fs";
|
|
9028
|
-
import { dirname as
|
|
9260
|
+
import { dirname as dirname29, join as join40 } from "path";
|
|
9029
9261
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9030
9262
|
var FALLBACK_VERSION = "0.0.0";
|
|
9031
9263
|
function resolveCliVersion() {
|
|
9032
|
-
let dir =
|
|
9264
|
+
let dir = dirname29(fileURLToPath2(import.meta.url));
|
|
9033
9265
|
while (true) {
|
|
9034
9266
|
try {
|
|
9035
|
-
const pkg = JSON.parse(readFileSync(
|
|
9267
|
+
const pkg = JSON.parse(readFileSync(join40(dir, "package.json"), "utf8"));
|
|
9036
9268
|
if (pkg.name === "agentwheel" && typeof pkg.version === "string") {
|
|
9037
9269
|
return pkg.version;
|
|
9038
9270
|
}
|
|
9039
9271
|
} catch {
|
|
9040
9272
|
}
|
|
9041
|
-
const parent =
|
|
9273
|
+
const parent = dirname29(dir);
|
|
9042
9274
|
if (parent === dir) return FALLBACK_VERSION;
|
|
9043
9275
|
dir = parent;
|
|
9044
9276
|
}
|
|
@@ -9086,7 +9318,7 @@ program.command("list").description("list artifacts exposed by a package source"
|
|
|
9086
9318
|
const resolvedInput = await resolvePackageSource(source, targetRoot);
|
|
9087
9319
|
const selectedArtifacts = selectedArtifactsFromOptionsOrRegistry(options, resolvedInput.registryEntry);
|
|
9088
9320
|
const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
|
|
9089
|
-
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot:
|
|
9321
|
+
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join41(targetRoot, ".agentwheel", "cache") }))));
|
|
9090
9322
|
const artifacts = filterArtifactsBySelection(await driver.list(resolved), selectedArtifacts);
|
|
9091
9323
|
for (const artifact of artifacts) {
|
|
9092
9324
|
console.log(`${artifact.type} ${artifact.name} ${artifact.relativePath}`);
|
|
@@ -9096,7 +9328,7 @@ program.command("scan").description("scan a package source for validation findin
|
|
|
9096
9328
|
const targetRoot = normalizeTargetRoot(options.targetRoot);
|
|
9097
9329
|
const resolvedInput = await resolvePackageSource(source, targetRoot);
|
|
9098
9330
|
const driver = getSourceDriver(options.driver ?? inferSourceDriverName(resolvedInput.source));
|
|
9099
|
-
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot:
|
|
9331
|
+
const resolved = await driver.export(await driver.translate(await driver.fetch(await driver.resolve(resolvedInput.source, { cacheRoot: join41(targetRoot, ".agentwheel", "cache") }))));
|
|
9100
9332
|
const result = await driver.scan(resolved);
|
|
9101
9333
|
if (result.findings.length === 0) {
|
|
9102
9334
|
console.log("Scan ok: no findings");
|
|
@@ -9393,7 +9625,7 @@ async function packageEntryFromSource(source, targetRoot, options) {
|
|
|
9393
9625
|
const bundle = await stageSource(driver, resolvedSource, {
|
|
9394
9626
|
workspaceRoot: targetRoot,
|
|
9395
9627
|
adapter,
|
|
9396
|
-
cacheRoot:
|
|
9628
|
+
cacheRoot: join41(targetRoot, ".agentwheel", "cache"),
|
|
9397
9629
|
mode: options.mode,
|
|
9398
9630
|
frozenLock: lockMode,
|
|
9399
9631
|
select: selectedArtifacts
|
|
@@ -9751,7 +9983,7 @@ function keepManifestEntryOperation(entry, targetRoot, rootId, operation, option
|
|
|
9751
9983
|
artifactType: entry.artifactType,
|
|
9752
9984
|
artifactName: entry.artifactName,
|
|
9753
9985
|
kind: entry.kind,
|
|
9754
|
-
destPath: operation?.destPath ??
|
|
9986
|
+
destPath: operation?.destPath ?? join41(targetRoot, entry.path),
|
|
9755
9987
|
relativeDestPath: entry.path,
|
|
9756
9988
|
desiredHash: entry.sourceHash,
|
|
9757
9989
|
currentHash: operation?.currentHash ?? entry.hash,
|
|
@@ -10011,12 +10243,12 @@ async function printDoctor(target, options) {
|
|
|
10011
10243
|
const requestedSkills = doctorSkillRequests(target, options);
|
|
10012
10244
|
const skills = [];
|
|
10013
10245
|
for (const request of requestedSkills) {
|
|
10014
|
-
const skillPath =
|
|
10246
|
+
const skillPath = join41(state.installRoot, targetMapping.dest, request.name);
|
|
10015
10247
|
const exists = await pathExists(skillPath);
|
|
10016
10248
|
const manifestEntry = manifest?.entries.find((entry) => {
|
|
10017
10249
|
if (entry.artifactType !== "skills") return false;
|
|
10018
10250
|
const legacyInstallName = "installName" in entry && typeof entry.installName === "string" ? entry.installName : void 0;
|
|
10019
|
-
return entry.artifactName === request.name || legacyInstallName === request.name || entry.path ===
|
|
10251
|
+
return entry.artifactName === request.name || legacyInstallName === request.name || entry.path === join41(targetMapping.dest, request.name);
|
|
10020
10252
|
});
|
|
10021
10253
|
const status = manifestEntry ? "managed" : exists ? "present-unmanaged" : "missing";
|
|
10022
10254
|
skills.push({
|
|
@@ -10096,7 +10328,7 @@ function doctorSkillLabel(name) {
|
|
|
10096
10328
|
return `${name} skill`;
|
|
10097
10329
|
}
|
|
10098
10330
|
function isSyncwheelWorkspace(targetRoot) {
|
|
10099
|
-
return existsSync(
|
|
10331
|
+
return existsSync(join41(targetRoot, ".syncwheel", "manifest.json"));
|
|
10100
10332
|
}
|
|
10101
10333
|
function skillInstallCommand(adapter, installationType, options, skill, behavior = {}) {
|
|
10102
10334
|
const args = [
|
|
@@ -10238,10 +10470,10 @@ function filterUninstallPlanBySelection(plan, selected) {
|
|
|
10238
10470
|
};
|
|
10239
10471
|
}
|
|
10240
10472
|
async function initPackage(root) {
|
|
10241
|
-
await
|
|
10242
|
-
await
|
|
10243
|
-
await
|
|
10244
|
-
const manifestPath =
|
|
10473
|
+
await mkdir21(join41(root, "instructions"), { recursive: true });
|
|
10474
|
+
await mkdir21(join41(root, "rules"), { recursive: true });
|
|
10475
|
+
await mkdir21(join41(root, "skills"), { recursive: true });
|
|
10476
|
+
const manifestPath = join41(root, "openpack.json");
|
|
10245
10477
|
const manifest = {
|
|
10246
10478
|
schemaVersion: 2,
|
|
10247
10479
|
name: "example/agentwheel-package",
|
|
@@ -10252,12 +10484,12 @@ async function initPackage(root) {
|
|
|
10252
10484
|
{ type: "skills", path: "skills" }
|
|
10253
10485
|
]
|
|
10254
10486
|
};
|
|
10255
|
-
await
|
|
10487
|
+
await writeFile20(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
10256
10488
|
`, "utf8");
|
|
10257
|
-
await
|
|
10489
|
+
await writeFile20(join41(root, "instructions", "AGENTS.md"), "# Agent Instructions\n", "utf8");
|
|
10258
10490
|
}
|
|
10259
10491
|
async function defaultBootstrapPackage(_root) {
|
|
10260
|
-
const packageRoot = await findAgentwheelPackageRoot(
|
|
10492
|
+
const packageRoot = await findAgentwheelPackageRoot(dirname30(fileURLToPath3(import.meta.url)));
|
|
10261
10493
|
if (!packageRoot) return void 0;
|
|
10262
10494
|
return {
|
|
10263
10495
|
name: "agentwheel",
|
|
@@ -10304,7 +10536,7 @@ async function findAgentwheelPackageRoot(start) {
|
|
|
10304
10536
|
let current = resolve20(start);
|
|
10305
10537
|
while (true) {
|
|
10306
10538
|
if (await findPackageManifestPath(current, { warnLegacy: false })) return current;
|
|
10307
|
-
const parent =
|
|
10539
|
+
const parent = dirname30(current);
|
|
10308
10540
|
if (parent === current) return void 0;
|
|
10309
10541
|
current = parent;
|
|
10310
10542
|
}
|