@agntn/harnesses 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -5
- package/dist/_chunks/agents.mjs +5 -3
- package/dist/_chunks/agents.mjs.map +1 -1
- package/dist/_chunks/mcp-servers.mjs +5 -3
- package/dist/_chunks/mcp-servers.mjs.map +1 -1
- package/dist/_chunks/mcp.mjs +10 -1
- package/dist/_chunks/mcp.mjs.map +1 -1
- package/dist/_chunks/output.mjs +7 -1
- package/dist/_chunks/output.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +4 -2
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/{prompt-sync.d.mts → skills-sync.d.mts} +111 -53
- package/dist/_chunks/skills-sync.d.mts.map +1 -0
- package/dist/_chunks/{prompt-sync.mjs → skills-sync.mjs} +392 -100
- package/dist/_chunks/skills-sync.mjs.map +1 -0
- package/dist/_chunks/skills.mjs +30 -0
- package/dist/_chunks/skills.mjs.map +1 -0
- package/dist/_chunks/tool-operations.mjs +36 -8
- package/dist/_chunks/tool-operations.mjs.map +1 -1
- package/dist/_chunks/tool-schemas.d.mts +21 -13
- package/dist/_chunks/tool-schemas.d.mts.map +1 -1
- package/dist/_chunks/tool-schemas.mjs +7 -1
- package/dist/_chunks/tool-schemas.mjs.map +1 -1
- package/dist/_chunks/types.mjs +5 -2
- package/dist/_chunks/types.mjs.map +1 -1
- package/dist/cli.mjs +9 -3
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +16 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5 -3
- package/dist/index.mjs.map +1 -1
- package/dist/mcp.d.mts +2 -0
- package/dist/mcp.d.mts.map +1 -1
- package/dist/mcp.mjs +6256 -3
- package/dist/mcp.mjs.map +1 -1
- package/dist/tool-operations.d.mts +14 -3
- package/dist/tool-operations.d.mts.map +1 -1
- package/dist/tool-operations.mjs +3 -3
- package/dist/tool-schemas.d.mts +2 -2
- package/dist/tool-schemas.mjs +1 -1
- package/dist/typebox.LICENSE +23 -0
- package/package.json +19 -19
- package/packages/omp/extensions/harnesses.ts +27 -40
- package/packages/pi/extensions/harnesses.ts +26 -45
- package/packages/shared/tui.ts +13 -0
- package/dist/THIRD-PARTY-LICENSES.md +0 -36
- package/dist/_chunks/libs/typebox.mjs +0 -5439
- package/dist/_chunks/libs/typebox.mjs.map +0 -1
- package/dist/_chunks/prompt-sync.d.mts.map +0 -1
- package/dist/_chunks/prompt-sync.mjs.map +0 -1
|
@@ -8,6 +8,7 @@ import os, { homedir } from "node:os";
|
|
|
8
8
|
import { stripVTControlCharacters } from "node:util";
|
|
9
9
|
import { parse } from "smol-toml";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
|
+
//#region src/resolve.ts
|
|
11
12
|
const PATH_MARKERS = /^~(?=\/|$)|\$\{HOME\}|\$\{PROJECT_ROOT\}|\$\{TMPDIR\}|%([^%]+)%/g;
|
|
12
13
|
function resolvePathTemplate(template, options = {}) {
|
|
13
14
|
const homeDir = options.homeDir ?? os.homedir();
|
|
@@ -27,6 +28,8 @@ function agntnDataDir(options = {}) {
|
|
|
27
28
|
const base = process.env.XDG_DATA_HOME && process.env.XDG_DATA_HOME !== "" ? process.env.XDG_DATA_HOME : join(options.homeDir ?? os.homedir(), ".local", "share");
|
|
28
29
|
return join(base, "agntn");
|
|
29
30
|
}
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/harness.ts
|
|
30
33
|
function moveRoot(path, root, value) {
|
|
31
34
|
if (path === root) return value;
|
|
32
35
|
const rest = path.slice(root.length);
|
|
@@ -37,6 +40,7 @@ const SUPPORTED_PLATFORMS = {
|
|
|
37
40
|
darwin: true,
|
|
38
41
|
win32: true
|
|
39
42
|
};
|
|
43
|
+
const PARENT_ENV = "AGNTN_HARNESSES_PARENT";
|
|
40
44
|
const ALTERNATE_INVOCATION_MODE = {
|
|
41
45
|
advisor: "agent",
|
|
42
46
|
advisorStructured: "agentStructured",
|
|
@@ -249,6 +253,7 @@ function executeCommand(command, args, options) {
|
|
|
249
253
|
});
|
|
250
254
|
}
|
|
251
255
|
var Harness = class {
|
|
256
|
+
skillsSyncTarget = null;
|
|
252
257
|
promptTemplates = [];
|
|
253
258
|
promptTemplateSyncTarget = null;
|
|
254
259
|
temp = [];
|
|
@@ -324,6 +329,8 @@ var Harness = class {
|
|
|
324
329
|
return `${`Harness ${this.id} has no ${INVOCATION_MODE_DESCRIPTION[mode]} invocation`}${invocationRetryHint(this.invocation, mode, options)}`;
|
|
325
330
|
}
|
|
326
331
|
invoke(prompt, options = {}) {
|
|
332
|
+
const parent = process.env[PARENT_ENV];
|
|
333
|
+
if (parent) return Promise.reject(/* @__PURE__ */ new Error(`Nested run refused: this process already runs inside ${parent}, started by harnesses. ${this.id} under it would stack agents, and in a read-only sandbox it gets no network and hangs until the deadline. Answer without it`));
|
|
327
334
|
const invocationOptions = {
|
|
328
335
|
model: options.model,
|
|
329
336
|
structured: options.structured,
|
|
@@ -334,9 +341,16 @@ var Harness = class {
|
|
|
334
341
|
if (!built) return Promise.reject(new Error(this.invocationError(invocationOptions) ?? "Invalid invocation"));
|
|
335
342
|
const versionError = this.readOnlyVersionError(invocationOptions);
|
|
336
343
|
if (versionError) return Promise.reject(new Error(versionError));
|
|
344
|
+
const command = {
|
|
345
|
+
...options,
|
|
346
|
+
env: {
|
|
347
|
+
...options.env,
|
|
348
|
+
[PARENT_ENV]: this.id
|
|
349
|
+
}
|
|
350
|
+
};
|
|
337
351
|
const streamArgs = options.structured ? void 0 : this.invocation?.streamArgs;
|
|
338
|
-
if (!streamArgs) return executeCommand(built.command, built.args,
|
|
339
|
-
return executeCommand(built.command, [...built.args, ...streamArgs],
|
|
352
|
+
if (!streamArgs) return executeCommand(built.command, built.args, command);
|
|
353
|
+
return executeCommand(built.command, [...built.args, ...streamArgs], command).then((result) => ({
|
|
340
354
|
...result,
|
|
341
355
|
stdout: this.foldStreamOutput(result.stdout, !result.timedOut && !result.aborted)
|
|
342
356
|
}));
|
|
@@ -402,6 +416,7 @@ var Harness = class {
|
|
|
402
416
|
sessions: this.resolveCandidates(this.sessions, options),
|
|
403
417
|
instructions: this.resolveCandidates(this.instructions, options),
|
|
404
418
|
skills: this.resolveCandidates(this.skills, options),
|
|
419
|
+
skillsSyncTarget: this.skillsSyncTarget === null ? null : this.resolveCandidates([this.skillsSyncTarget], options)[0] ?? null,
|
|
405
420
|
commands: this.resolveCandidates(this.commands, options),
|
|
406
421
|
promptTemplates: this.resolveCandidates(this.promptTemplates, options),
|
|
407
422
|
promptTemplateSyncTarget: this.promptTemplateSyncTarget === null ? null : this.resolveCandidates([this.promptTemplateSyncTarget], options)[0] ?? null,
|
|
@@ -420,6 +435,8 @@ var Harness = class {
|
|
|
420
435
|
}));
|
|
421
436
|
}
|
|
422
437
|
};
|
|
438
|
+
//#endregion
|
|
439
|
+
//#region src/harnesses/antigravity.ts
|
|
423
440
|
function parseAntigravityModels(stdout) {
|
|
424
441
|
const lines = stripVTControlCharacters(stdout).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
425
442
|
if (lines.length === 0) throw new Error("Unexpected empty Antigravity model-list output");
|
|
@@ -553,6 +570,11 @@ var Antigravity = class extends Harness {
|
|
|
553
570
|
scope: "user",
|
|
554
571
|
level: "official"
|
|
555
572
|
}];
|
|
573
|
+
skillsSyncTarget = {
|
|
574
|
+
path: "~/.gemini/config/skills/",
|
|
575
|
+
scope: "user",
|
|
576
|
+
level: "official"
|
|
577
|
+
};
|
|
556
578
|
commands = [];
|
|
557
579
|
hooks = [{
|
|
558
580
|
path: ".agents/hooks.json",
|
|
@@ -600,6 +622,8 @@ var Antigravity = class extends Harness {
|
|
|
600
622
|
return model.id;
|
|
601
623
|
}
|
|
602
624
|
};
|
|
625
|
+
//#endregion
|
|
626
|
+
//#region src/harnesses/claude.ts
|
|
603
627
|
function parseStreamLine(line) {
|
|
604
628
|
try {
|
|
605
629
|
const parsed = JSON.parse(line);
|
|
@@ -752,6 +776,11 @@ var Claude = class extends Harness {
|
|
|
752
776
|
level: "official",
|
|
753
777
|
note: "Global user-level skills."
|
|
754
778
|
}];
|
|
779
|
+
skillsSyncTarget = {
|
|
780
|
+
path: "~/.claude/skills/",
|
|
781
|
+
scope: "user",
|
|
782
|
+
level: "official"
|
|
783
|
+
};
|
|
755
784
|
commands = [{
|
|
756
785
|
path: ".claude/commands/",
|
|
757
786
|
scope: "project",
|
|
@@ -922,6 +951,8 @@ var Claude = class extends Harness {
|
|
|
922
951
|
return foldClaudeStream(stdout, complete);
|
|
923
952
|
}
|
|
924
953
|
};
|
|
954
|
+
//#endregion
|
|
955
|
+
//#region src/harnesses/codex.ts
|
|
925
956
|
var Codex = class extends Harness {
|
|
926
957
|
id = "codex";
|
|
927
958
|
name = "OpenAI Codex CLI";
|
|
@@ -1044,6 +1075,11 @@ var Codex = class extends Harness {
|
|
|
1044
1075
|
platforms: ["linux", "darwin"]
|
|
1045
1076
|
}
|
|
1046
1077
|
];
|
|
1078
|
+
skillsSyncTarget = {
|
|
1079
|
+
path: "~/.agents/skills/",
|
|
1080
|
+
scope: "user",
|
|
1081
|
+
level: "official"
|
|
1082
|
+
};
|
|
1047
1083
|
commands = [{
|
|
1048
1084
|
path: "~/.codex/prompts/",
|
|
1049
1085
|
scope: "user",
|
|
@@ -1129,6 +1165,8 @@ var Codex = class extends Harness {
|
|
|
1129
1165
|
]
|
|
1130
1166
|
};
|
|
1131
1167
|
};
|
|
1168
|
+
//#endregion
|
|
1169
|
+
//#region src/harnesses/cursor.ts
|
|
1132
1170
|
var Cursor = class extends Harness {
|
|
1133
1171
|
id = "cursor";
|
|
1134
1172
|
name = "Cursor";
|
|
@@ -1188,6 +1226,11 @@ var Cursor = class extends Harness {
|
|
|
1188
1226
|
note: "Cursor natively scans Codex skills directory."
|
|
1189
1227
|
}
|
|
1190
1228
|
];
|
|
1229
|
+
skillsSyncTarget = {
|
|
1230
|
+
path: "~/.cursor/skills/",
|
|
1231
|
+
scope: "user",
|
|
1232
|
+
level: "official"
|
|
1233
|
+
};
|
|
1191
1234
|
commands = [];
|
|
1192
1235
|
hooks = [];
|
|
1193
1236
|
invocation = {
|
|
@@ -1222,6 +1265,8 @@ var Cursor = class extends Harness {
|
|
|
1222
1265
|
projectMarkers: [".cursor", ".cursorrules"]
|
|
1223
1266
|
};
|
|
1224
1267
|
};
|
|
1268
|
+
//#endregion
|
|
1269
|
+
//#region src/harnesses/freebuff.ts
|
|
1225
1270
|
var Freebuff = class extends Harness {
|
|
1226
1271
|
id = "freebuff";
|
|
1227
1272
|
name = "Freebuff";
|
|
@@ -1328,6 +1373,8 @@ var Freebuff = class extends Harness {
|
|
|
1328
1373
|
projectMarkers: [".agents", "knowledge.md"]
|
|
1329
1374
|
};
|
|
1330
1375
|
};
|
|
1376
|
+
//#endregion
|
|
1377
|
+
//#region src/harnesses/gemini.ts
|
|
1331
1378
|
var Gemini = class extends Harness {
|
|
1332
1379
|
id = "gemini";
|
|
1333
1380
|
name = "Google Gemini CLI";
|
|
@@ -1422,6 +1469,11 @@ var Gemini = class extends Harness {
|
|
|
1422
1469
|
level: "official"
|
|
1423
1470
|
}
|
|
1424
1471
|
];
|
|
1472
|
+
skillsSyncTarget = {
|
|
1473
|
+
path: "~/.gemini/skills/",
|
|
1474
|
+
scope: "user",
|
|
1475
|
+
level: "official"
|
|
1476
|
+
};
|
|
1425
1477
|
commands = [{
|
|
1426
1478
|
path: ".gemini/commands/",
|
|
1427
1479
|
scope: "project",
|
|
@@ -1474,6 +1526,8 @@ var Gemini = class extends Harness {
|
|
|
1474
1526
|
projectMarkers: [".gemini", "GEMINI.md"]
|
|
1475
1527
|
};
|
|
1476
1528
|
};
|
|
1529
|
+
//#endregion
|
|
1530
|
+
//#region src/harnesses/github-copilot.ts
|
|
1477
1531
|
var GitHubCopilot = class extends Harness {
|
|
1478
1532
|
id = "github-copilot";
|
|
1479
1533
|
name = "GitHub Copilot";
|
|
@@ -1542,6 +1596,8 @@ var GitHubCopilot = class extends Harness {
|
|
|
1542
1596
|
]
|
|
1543
1597
|
};
|
|
1544
1598
|
};
|
|
1599
|
+
//#endregion
|
|
1600
|
+
//#region src/harnesses/grok.ts
|
|
1545
1601
|
function parseGrokModels(stdout) {
|
|
1546
1602
|
const lines = stripVTControlCharacters(stdout).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1547
1603
|
const start = lines.indexOf("Available models:");
|
|
@@ -1641,6 +1697,11 @@ var Grok = class extends Harness {
|
|
|
1641
1697
|
level: "official",
|
|
1642
1698
|
note: "Global user-level skills."
|
|
1643
1699
|
}];
|
|
1700
|
+
skillsSyncTarget = {
|
|
1701
|
+
path: "~/.grok/skills/",
|
|
1702
|
+
scope: "user",
|
|
1703
|
+
level: "official"
|
|
1704
|
+
};
|
|
1644
1705
|
commands = [{
|
|
1645
1706
|
path: ".grok/commands/",
|
|
1646
1707
|
scope: "project",
|
|
@@ -1721,6 +1782,8 @@ var Grok = class extends Harness {
|
|
|
1721
1782
|
return parseGrokModels(stdout);
|
|
1722
1783
|
}
|
|
1723
1784
|
};
|
|
1785
|
+
//#endregion
|
|
1786
|
+
//#region src/harnesses/mastracode.ts
|
|
1724
1787
|
function packageVersion(commandPath) {
|
|
1725
1788
|
try {
|
|
1726
1789
|
const require = createRequire(realpathSync(commandPath));
|
|
@@ -1876,6 +1939,11 @@ var MastraCode = class extends Harness {
|
|
|
1876
1939
|
note: "Claude Code compatible."
|
|
1877
1940
|
}
|
|
1878
1941
|
];
|
|
1942
|
+
skillsSyncTarget = {
|
|
1943
|
+
path: "~/.mastracode/skills/",
|
|
1944
|
+
scope: "user",
|
|
1945
|
+
level: "official"
|
|
1946
|
+
};
|
|
1879
1947
|
commands = [
|
|
1880
1948
|
{
|
|
1881
1949
|
path: ".mastracode/commands/",
|
|
@@ -1966,6 +2034,32 @@ var MastraCode = class extends Harness {
|
|
|
1966
2034
|
projectMarkers: [".mastracode"]
|
|
1967
2035
|
};
|
|
1968
2036
|
};
|
|
2037
|
+
//#endregion
|
|
2038
|
+
//#region src/harnesses/omp.ts
|
|
2039
|
+
function isRecord(value) {
|
|
2040
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2041
|
+
}
|
|
2042
|
+
function parseOmpModels(stdout) {
|
|
2043
|
+
let parsed;
|
|
2044
|
+
try {
|
|
2045
|
+
parsed = JSON.parse(stdout);
|
|
2046
|
+
} catch {
|
|
2047
|
+
throw new Error(`Unexpected OMP model-list output: ${JSON.stringify(stdout.slice(0, 200))}`);
|
|
2048
|
+
}
|
|
2049
|
+
if (!isRecord(parsed) || !Array.isArray(parsed["models"])) throw new Error(`Unexpected OMP model-list output: ${JSON.stringify(stdout.slice(0, 200))}`);
|
|
2050
|
+
return parsed["models"].map((entry) => {
|
|
2051
|
+
if (!isRecord(entry) || typeof entry["provider"] !== "string" || typeof entry["id"] !== "string") throw new Error(`Unexpected OMP model-list entry: ${JSON.stringify(entry)}`);
|
|
2052
|
+
const { contextWindow, maxTokens, reasoning, input } = entry;
|
|
2053
|
+
return {
|
|
2054
|
+
provider: entry["provider"],
|
|
2055
|
+
id: entry["id"],
|
|
2056
|
+
...typeof contextWindow === "number" ? { contextWindow } : {},
|
|
2057
|
+
...typeof maxTokens === "number" ? { maxOutputTokens: maxTokens } : {},
|
|
2058
|
+
...typeof reasoning === "boolean" ? { thinking: reasoning } : {},
|
|
2059
|
+
...Array.isArray(input) ? { images: input.includes("image") } : {}
|
|
2060
|
+
};
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
1969
2063
|
var Omp = class extends Harness {
|
|
1970
2064
|
id = "omp";
|
|
1971
2065
|
name = "OMP (oh-my-pi)";
|
|
@@ -2105,6 +2199,11 @@ var Omp = class extends Harness {
|
|
|
2105
2199
|
note: "Auto-generated managed skills."
|
|
2106
2200
|
}
|
|
2107
2201
|
];
|
|
2202
|
+
skillsSyncTarget = {
|
|
2203
|
+
path: "~/.omp/agent/skills/",
|
|
2204
|
+
scope: "user",
|
|
2205
|
+
level: "official"
|
|
2206
|
+
};
|
|
2108
2207
|
commands = [{
|
|
2109
2208
|
path: ".omp/commands/",
|
|
2110
2209
|
scope: "project",
|
|
@@ -2150,6 +2249,27 @@ var Omp = class extends Harness {
|
|
|
2150
2249
|
level: "official",
|
|
2151
2250
|
note: "Add --mode json for structured event output. --no-tools disables only OMP's bundled tools, so it cannot provide an advisor mode without tools."
|
|
2152
2251
|
};
|
|
2252
|
+
modelListing = {
|
|
2253
|
+
args: [
|
|
2254
|
+
"models",
|
|
2255
|
+
"--json",
|
|
2256
|
+
"--kind",
|
|
2257
|
+
"chat",
|
|
2258
|
+
"--no-extensions"
|
|
2259
|
+
],
|
|
2260
|
+
searchArgs: [
|
|
2261
|
+
"models",
|
|
2262
|
+
"find",
|
|
2263
|
+
"--json",
|
|
2264
|
+
"--kind",
|
|
2265
|
+
"chat",
|
|
2266
|
+
"--no-extensions",
|
|
2267
|
+
"--",
|
|
2268
|
+
"{search}"
|
|
2269
|
+
],
|
|
2270
|
+
level: "official",
|
|
2271
|
+
note: "Lists chat models with configured provider authentication as JSON; find matches a substring of the provider, id or name, ignoring case. --no-extensions keeps extension load errors out of the run; verified with 18.4.10."
|
|
2272
|
+
};
|
|
2153
2273
|
mcpConfigs = [{
|
|
2154
2274
|
path: "~/.omp/agent/mcp.json",
|
|
2155
2275
|
scope: "user",
|
|
@@ -2185,7 +2305,12 @@ var Omp = class extends Harness {
|
|
|
2185
2305
|
envVars: ["OMP_PROFILE", "PI_CODING_AGENT_DIR"],
|
|
2186
2306
|
projectMarkers: [".omp"]
|
|
2187
2307
|
};
|
|
2308
|
+
parseModelListingOutput(stdout) {
|
|
2309
|
+
return parseOmpModels(stdout);
|
|
2310
|
+
}
|
|
2188
2311
|
};
|
|
2312
|
+
//#endregion
|
|
2313
|
+
//#region src/harnesses/opencode.ts
|
|
2189
2314
|
var OpenCode = class extends Harness {
|
|
2190
2315
|
id = "opencode";
|
|
2191
2316
|
name = "OpenCode CLI";
|
|
@@ -2282,6 +2407,11 @@ var OpenCode = class extends Harness {
|
|
|
2282
2407
|
scope: "project",
|
|
2283
2408
|
level: "official"
|
|
2284
2409
|
},
|
|
2410
|
+
{
|
|
2411
|
+
path: "~/.config/opencode/skills/",
|
|
2412
|
+
scope: "user",
|
|
2413
|
+
level: "official"
|
|
2414
|
+
},
|
|
2285
2415
|
{
|
|
2286
2416
|
path: "~/.claude/skills/",
|
|
2287
2417
|
scope: "user",
|
|
@@ -2294,6 +2424,12 @@ var OpenCode = class extends Harness {
|
|
|
2294
2424
|
level: "official"
|
|
2295
2425
|
}
|
|
2296
2426
|
];
|
|
2427
|
+
skillsSyncTarget = {
|
|
2428
|
+
path: "~/.config/opencode/skills/",
|
|
2429
|
+
scope: "user",
|
|
2430
|
+
level: "official",
|
|
2431
|
+
note: "OpenCode also scans ~/.claude/skills/ and ~/.agents/skills/; skill names must be unique across them."
|
|
2432
|
+
};
|
|
2297
2433
|
commands = [{
|
|
2298
2434
|
path: ".opencode/commands/",
|
|
2299
2435
|
scope: "project",
|
|
@@ -2349,6 +2485,8 @@ var OpenCode = class extends Harness {
|
|
|
2349
2485
|
]
|
|
2350
2486
|
};
|
|
2351
2487
|
};
|
|
2488
|
+
//#endregion
|
|
2489
|
+
//#region src/harnesses/pi.ts
|
|
2352
2490
|
const MODEL_HEADERS = [
|
|
2353
2491
|
"provider",
|
|
2354
2492
|
"model",
|
|
@@ -2461,6 +2599,11 @@ var Pi = class extends Harness {
|
|
|
2461
2599
|
level: "official",
|
|
2462
2600
|
note: "Global user-level skills."
|
|
2463
2601
|
}];
|
|
2602
|
+
skillsSyncTarget = {
|
|
2603
|
+
path: "~/.pi/agent/skills/",
|
|
2604
|
+
scope: "user",
|
|
2605
|
+
level: "official"
|
|
2606
|
+
};
|
|
2464
2607
|
commands = [{
|
|
2465
2608
|
path: ".pi/prompts/",
|
|
2466
2609
|
scope: "project",
|
|
@@ -2524,6 +2667,23 @@ var Pi = class extends Harness {
|
|
|
2524
2667
|
level: "official",
|
|
2525
2668
|
note: "Lists models with configured provider authentication; accepts an optional fuzzy search."
|
|
2526
2669
|
};
|
|
2670
|
+
mcpConfigs = [{
|
|
2671
|
+
path: "~/.pi/agent/mcp.json",
|
|
2672
|
+
scope: "user",
|
|
2673
|
+
level: "official",
|
|
2674
|
+
format: "json",
|
|
2675
|
+
key: ["mcpServers"],
|
|
2676
|
+
dialect: "pi",
|
|
2677
|
+
note: "Read by the built-in MCP extension, which -builtin:mcp in the extensions setting turns off."
|
|
2678
|
+
}, {
|
|
2679
|
+
path: ".pi/mcp.json",
|
|
2680
|
+
scope: "project",
|
|
2681
|
+
level: "official",
|
|
2682
|
+
format: "json",
|
|
2683
|
+
key: ["mcpServers"],
|
|
2684
|
+
dialect: "pi",
|
|
2685
|
+
note: "Read only after the project is trusted."
|
|
2686
|
+
}];
|
|
2527
2687
|
envOverrides = [{
|
|
2528
2688
|
variable: "PI_CODING_AGENT_DIR",
|
|
2529
2689
|
path: "~/.pi/agent",
|
|
@@ -2559,6 +2719,8 @@ var Pi = class extends Harness {
|
|
|
2559
2719
|
return parsePiModelTable(stdout, "Pi");
|
|
2560
2720
|
}
|
|
2561
2721
|
};
|
|
2722
|
+
//#endregion
|
|
2723
|
+
//#region src/harnesses/prime-agent.ts
|
|
2562
2724
|
var PrimeAgent = class extends Harness {
|
|
2563
2725
|
id = "prime-agent";
|
|
2564
2726
|
name = "Prime Agent";
|
|
@@ -2660,6 +2822,11 @@ var PrimeAgent = class extends Harness {
|
|
|
2660
2822
|
note: "Shared skills directory; root .md files are ignored there."
|
|
2661
2823
|
}
|
|
2662
2824
|
];
|
|
2825
|
+
skillsSyncTarget = {
|
|
2826
|
+
path: "~/.prime/agent/skills/",
|
|
2827
|
+
scope: "user",
|
|
2828
|
+
level: "official"
|
|
2829
|
+
};
|
|
2663
2830
|
commands = [{
|
|
2664
2831
|
path: ".prime/agent/prompts/",
|
|
2665
2832
|
scope: "project",
|
|
@@ -2731,6 +2898,8 @@ var PrimeAgent = class extends Harness {
|
|
|
2731
2898
|
return parsePiModelTable(stdout, "Prime Agent");
|
|
2732
2899
|
}
|
|
2733
2900
|
};
|
|
2901
|
+
//#endregion
|
|
2902
|
+
//#region src/harnesses/index.ts
|
|
2734
2903
|
const harnesses = [
|
|
2735
2904
|
Antigravity,
|
|
2736
2905
|
Claude,
|
|
@@ -2746,6 +2915,8 @@ const harnesses = [
|
|
|
2746
2915
|
PrimeAgent,
|
|
2747
2916
|
Pi
|
|
2748
2917
|
];
|
|
2918
|
+
//#endregion
|
|
2919
|
+
//#region src/registry.ts
|
|
2749
2920
|
let registry;
|
|
2750
2921
|
function getRegistry() {
|
|
2751
2922
|
if (!registry) {
|
|
@@ -2793,6 +2964,8 @@ function detectHarness(cwd) {
|
|
|
2793
2964
|
}
|
|
2794
2965
|
return match;
|
|
2795
2966
|
}
|
|
2967
|
+
//#endregion
|
|
2968
|
+
//#region src/mcp-servers.ts
|
|
2796
2969
|
function resolveConfigs(harness, options) {
|
|
2797
2970
|
return harness.resolveCandidates(harness.mcpConfigs, options).map((entry) => ({
|
|
2798
2971
|
entry,
|
|
@@ -2891,6 +3064,9 @@ const ENV_REFERENCE = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/;
|
|
|
2891
3064
|
var McpEnvError = class extends Error {
|
|
2892
3065
|
name = "McpEnvError";
|
|
2893
3066
|
};
|
|
3067
|
+
var McpTransportError = class extends Error {
|
|
3068
|
+
name = "McpTransportError";
|
|
3069
|
+
};
|
|
2894
3070
|
function envReference(value) {
|
|
2895
3071
|
return ENV_REFERENCE.exec(value)?.[1];
|
|
2896
3072
|
}
|
|
@@ -3006,6 +3182,7 @@ function resolveEnvReferences(server, dialect) {
|
|
|
3006
3182
|
}
|
|
3007
3183
|
function shapeForDialect(server, dialect) {
|
|
3008
3184
|
const shaped = resolveEnvReferences(server, dialect);
|
|
3185
|
+
if (dialect === "pi" && shaped.transport === "sse") throw new McpTransportError(`${server.name}: Pi takes stdio and streamable HTTP servers, not sse; point url at the server's streamable HTTP endpoint`);
|
|
3009
3186
|
if (dialect !== "mastracode") return shaped;
|
|
3010
3187
|
return compact({
|
|
3011
3188
|
...shaped,
|
|
@@ -3020,6 +3197,26 @@ function denormalizeEntry(server, dialect) {
|
|
|
3020
3197
|
if (dialect === "prime") return denormalizePrime(server);
|
|
3021
3198
|
return denormalizeStandard(server);
|
|
3022
3199
|
}
|
|
3200
|
+
const STANDARD_FIELDS = /* @__PURE__ */ new Set([
|
|
3201
|
+
"type",
|
|
3202
|
+
"command",
|
|
3203
|
+
"args",
|
|
3204
|
+
"env",
|
|
3205
|
+
"url",
|
|
3206
|
+
"httpUrl",
|
|
3207
|
+
"headers",
|
|
3208
|
+
"enabled"
|
|
3209
|
+
]);
|
|
3210
|
+
function replacementEntry(previous, server, dialect) {
|
|
3211
|
+
const entry = denormalizeEntry(server, dialect);
|
|
3212
|
+
if (dialect !== "pi" || !isObjectRecord(previous)) return entry;
|
|
3213
|
+
if (normalizeStandard(server.name, previous).transport !== server.transport) return entry;
|
|
3214
|
+
const kept = Object.entries(previous).filter(([key]) => !STANDARD_FIELDS.has(key));
|
|
3215
|
+
return {
|
|
3216
|
+
...entry,
|
|
3217
|
+
...Object.fromEntries(kept)
|
|
3218
|
+
};
|
|
3219
|
+
}
|
|
3023
3220
|
function listingBase(entry, path) {
|
|
3024
3221
|
return compact({
|
|
3025
3222
|
path,
|
|
@@ -3160,7 +3357,7 @@ function addMcpServer(harness, server, scope = "user", options = {}) {
|
|
|
3160
3357
|
const map = drill(root, entry.key, "create");
|
|
3161
3358
|
if (!map) throw new Error(`Config at ${path} has a non-object at ${entry.key.join(".")}`);
|
|
3162
3359
|
const replaced = Object.hasOwn(map, server.name);
|
|
3163
|
-
map[server.name] =
|
|
3360
|
+
map[server.name] = replacementEntry(map[server.name], resolved, entry.dialect);
|
|
3164
3361
|
writeAtomically(path, `${JSON.stringify(root, null, 2)}\n`);
|
|
3165
3362
|
return {
|
|
3166
3363
|
path,
|
|
@@ -3366,6 +3563,9 @@ function withdrawMasterServersFromExcludedHarness(harness, existing, masterNames
|
|
|
3366
3563
|
results
|
|
3367
3564
|
};
|
|
3368
3565
|
}
|
|
3566
|
+
function cannotHold(error) {
|
|
3567
|
+
return error instanceof McpEnvError || error instanceof McpTransportError;
|
|
3568
|
+
}
|
|
3369
3569
|
function syncIncludedHarness(harness, master, existing, masterNames, initialPath, options) {
|
|
3370
3570
|
const results = [];
|
|
3371
3571
|
let path = initialPath;
|
|
@@ -3386,7 +3586,7 @@ function syncIncludedHarness(harness, master, existing, masterNames, initialPath
|
|
|
3386
3586
|
action: written.replaced ? "replaced" : "added"
|
|
3387
3587
|
});
|
|
3388
3588
|
} catch (error) {
|
|
3389
|
-
if (!(error
|
|
3589
|
+
if (!cannotHold(error)) throw error;
|
|
3390
3590
|
results.push({
|
|
3391
3591
|
name: server.name,
|
|
3392
3592
|
action: "skipped",
|
|
@@ -3436,6 +3636,8 @@ function syncMcpServers(harnesses, options = {}) {
|
|
|
3436
3636
|
targets: harnesses.map((harness) => syncMcpTarget(harness, master, masterNames, options))
|
|
3437
3637
|
};
|
|
3438
3638
|
}
|
|
3639
|
+
//#endregion
|
|
3640
|
+
//#region src/agents-sync.ts
|
|
3439
3641
|
function readIfExists(path) {
|
|
3440
3642
|
try {
|
|
3441
3643
|
return readFileSync(path, "utf8");
|
|
@@ -3583,7 +3785,7 @@ function syncFileTarget(id, path, source, check, options) {
|
|
|
3583
3785
|
};
|
|
3584
3786
|
return applyFileTarget(id, path, source, state, options);
|
|
3585
3787
|
}
|
|
3586
|
-
function syncTarget$
|
|
3788
|
+
function syncTarget$2(harness, config, check, options) {
|
|
3587
3789
|
if (config.excludes.includes(harness.id)) return {
|
|
3588
3790
|
id: harness.id,
|
|
3589
3791
|
action: "skipped",
|
|
@@ -3634,9 +3836,134 @@ function syncAgentsFiles(harnesses, check = false, options = {}) {
|
|
|
3634
3836
|
return {
|
|
3635
3837
|
source: config.source,
|
|
3636
3838
|
check,
|
|
3637
|
-
targets: harnesses.map((harness) => syncTarget$
|
|
3839
|
+
targets: harnesses.map((harness) => syncTarget$2(harness, config, check, options))
|
|
3638
3840
|
};
|
|
3639
3841
|
}
|
|
3842
|
+
//#endregion
|
|
3843
|
+
//#region src/directory-link.ts
|
|
3844
|
+
const CHECK_DETAIL = "check mode: not applied";
|
|
3845
|
+
function linkTarget(path) {
|
|
3846
|
+
const target = readlinkSync(path);
|
|
3847
|
+
return isAbsolute(target) ? target : resolve(dirname(path), target);
|
|
3848
|
+
}
|
|
3849
|
+
function isInsideDirectory(path, directory) {
|
|
3850
|
+
const remainder = relative(directory, path);
|
|
3851
|
+
return remainder !== "" && !remainder.startsWith("..") && !isAbsolute(remainder);
|
|
3852
|
+
}
|
|
3853
|
+
function tempPath(path, kind) {
|
|
3854
|
+
return join(dirname(path), `.${basename(path)}-${randomUUID()}.${kind}.tmp`);
|
|
3855
|
+
}
|
|
3856
|
+
function realDirectory(path) {
|
|
3857
|
+
try {
|
|
3858
|
+
return realpathSync(path);
|
|
3859
|
+
} catch {
|
|
3860
|
+
return resolve(path);
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
function backupDestination(kind, id, path, options) {
|
|
3864
|
+
const backupDir = join(agntnDataDir(options), "diverged", kind, id);
|
|
3865
|
+
mkdirSync(backupDir, { recursive: true });
|
|
3866
|
+
const backup = join(backupDir, `${basename(path)}-${Date.now()}-${randomUUID()}`);
|
|
3867
|
+
if (lstatSync(path).isSymbolicLink()) {
|
|
3868
|
+
symlinkSync(linkTarget(path), backup);
|
|
3869
|
+
unlinkSync(path);
|
|
3870
|
+
return backup;
|
|
3871
|
+
}
|
|
3872
|
+
moveFile(path, backup);
|
|
3873
|
+
return backup;
|
|
3874
|
+
}
|
|
3875
|
+
function linkDirectory(path, source, kind) {
|
|
3876
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
3877
|
+
const temp = tempPath(path, `${kind}-link`);
|
|
3878
|
+
symlinkSync(source, temp, "junction");
|
|
3879
|
+
renameSync(temp, path);
|
|
3880
|
+
}
|
|
3881
|
+
const DIRECTORY_ACTION = {
|
|
3882
|
+
missing: "linked",
|
|
3883
|
+
"correct-link": "unchanged",
|
|
3884
|
+
"wrong-link": "relinked",
|
|
3885
|
+
"legacy-links": "relinked",
|
|
3886
|
+
"local-files": "adopted",
|
|
3887
|
+
"not-directory": "skipped",
|
|
3888
|
+
source: "skipped"
|
|
3889
|
+
};
|
|
3890
|
+
const SKIP_DETAIL = {
|
|
3891
|
+
"not-directory": "destination exists and is not a directory or symlink",
|
|
3892
|
+
source: "destination holds the source directory"
|
|
3893
|
+
};
|
|
3894
|
+
function isEntryLink(path, sourceDirs) {
|
|
3895
|
+
if (!lstatSync(path).isSymbolicLink()) return false;
|
|
3896
|
+
const target = linkTarget(path);
|
|
3897
|
+
return sourceDirs.some((directory) => isInsideDirectory(target, directory));
|
|
3898
|
+
}
|
|
3899
|
+
function linksThrough(sourceDir, targetDir) {
|
|
3900
|
+
let path = sourceDir;
|
|
3901
|
+
for (let hop = 0; hop < 32; hop++) {
|
|
3902
|
+
if (path === targetDir || isInsideDirectory(path, targetDir)) return true;
|
|
3903
|
+
try {
|
|
3904
|
+
if (!lstatSync(path).isSymbolicLink()) return false;
|
|
3905
|
+
} catch {
|
|
3906
|
+
return false;
|
|
3907
|
+
}
|
|
3908
|
+
path = linkTarget(path);
|
|
3909
|
+
}
|
|
3910
|
+
return false;
|
|
3911
|
+
}
|
|
3912
|
+
function inspectDirectory(targetDir, sourceDir) {
|
|
3913
|
+
let stats;
|
|
3914
|
+
try {
|
|
3915
|
+
stats = lstatSync(targetDir);
|
|
3916
|
+
} catch (error) {
|
|
3917
|
+
if (error.code === "ENOENT") return { kind: "missing" };
|
|
3918
|
+
throw error;
|
|
3919
|
+
}
|
|
3920
|
+
if (stats.isSymbolicLink()) {
|
|
3921
|
+
if (linkTarget(targetDir) === sourceDir) return { kind: "correct-link" };
|
|
3922
|
+
return { kind: linksThrough(sourceDir, targetDir) ? "source" : "wrong-link" };
|
|
3923
|
+
}
|
|
3924
|
+
if (!stats.isDirectory()) return { kind: "not-directory" };
|
|
3925
|
+
return inspectLocalDirectory(targetDir, sourceDir);
|
|
3926
|
+
}
|
|
3927
|
+
function inspectLocalDirectory(targetDir, sourceDir) {
|
|
3928
|
+
const realSource = realDirectory(sourceDir);
|
|
3929
|
+
const realTarget = realpathSync(targetDir);
|
|
3930
|
+
if (realSource === realTarget || isInsideDirectory(realSource, realTarget)) return { kind: "source" };
|
|
3931
|
+
const sourceDirs = realSource === sourceDir ? [sourceDir] : [sourceDir, realSource];
|
|
3932
|
+
const entries = readdirSync(targetDir).map((entry) => join(targetDir, entry));
|
|
3933
|
+
return entries.every((entry) => isEntryLink(entry, sourceDirs)) ? {
|
|
3934
|
+
kind: "legacy-links",
|
|
3935
|
+
entries
|
|
3936
|
+
} : { kind: "local-files" };
|
|
3937
|
+
}
|
|
3938
|
+
function clearDirectory(kind, id, targetDir, state, options) {
|
|
3939
|
+
if (state.kind === "wrong-link" || state.kind === "local-files") return backupDestination(kind, id, targetDir, options);
|
|
3940
|
+
if (state.kind === "legacy-links") {
|
|
3941
|
+
for (const entry of state.entries) unlinkSync(entry);
|
|
3942
|
+
rmdirSync(targetDir);
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
function syncDirectoryLink(kind, id, targetDir, sourceDir, check, options) {
|
|
3946
|
+
const state = inspectDirectory(targetDir, sourceDir);
|
|
3947
|
+
const action = DIRECTORY_ACTION[state.kind];
|
|
3948
|
+
if (state.kind === "correct-link") return { action };
|
|
3949
|
+
const skip = SKIP_DETAIL[state.kind];
|
|
3950
|
+
if (skip !== void 0) return {
|
|
3951
|
+
action,
|
|
3952
|
+
detail: skip
|
|
3953
|
+
};
|
|
3954
|
+
if (check) return {
|
|
3955
|
+
action,
|
|
3956
|
+
detail: CHECK_DETAIL
|
|
3957
|
+
};
|
|
3958
|
+
const detail = clearDirectory(kind, id, targetDir, state, options);
|
|
3959
|
+
linkDirectory(targetDir, sourceDir, kind);
|
|
3960
|
+
return {
|
|
3961
|
+
action,
|
|
3962
|
+
detail
|
|
3963
|
+
};
|
|
3964
|
+
}
|
|
3965
|
+
//#endregion
|
|
3966
|
+
//#region src/prompt-sync.ts
|
|
3640
3967
|
const GENERATED_MARKER = "# Generated by @agntn/harnesses from ";
|
|
3641
3968
|
const PORTABLE_PROMPT_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]*$/u;
|
|
3642
3969
|
const GEMINI_ACTION = {
|
|
@@ -3684,10 +4011,6 @@ function generatedSource(content) {
|
|
|
3684
4011
|
return null;
|
|
3685
4012
|
}
|
|
3686
4013
|
}
|
|
3687
|
-
function linkTarget(path) {
|
|
3688
|
-
const target = readlinkSync(path);
|
|
3689
|
-
return isAbsolute(target) ? target : resolve(dirname(path), target);
|
|
3690
|
-
}
|
|
3691
4014
|
function inspectDestination(path) {
|
|
3692
4015
|
let stats;
|
|
3693
4016
|
try {
|
|
@@ -3705,93 +4028,12 @@ function inspectDestination(path) {
|
|
|
3705
4028
|
};
|
|
3706
4029
|
return { kind: "unmanaged-file" };
|
|
3707
4030
|
}
|
|
3708
|
-
function tempPath(path, kind) {
|
|
3709
|
-
return join(dirname(path), `.${basename(path)}-${randomUUID()}.${kind}.tmp`);
|
|
3710
|
-
}
|
|
3711
|
-
function linkDirectory(path, source) {
|
|
3712
|
-
mkdirSync(dirname(path), { recursive: true });
|
|
3713
|
-
const temp = tempPath(path, "prompt-link");
|
|
3714
|
-
symlinkSync(source, temp, "junction");
|
|
3715
|
-
renameSync(temp, path);
|
|
3716
|
-
}
|
|
3717
4031
|
function writeTemplate(path, content) {
|
|
3718
4032
|
mkdirSync(dirname(path), { recursive: true });
|
|
3719
4033
|
const temp = tempPath(path, "prompt-write");
|
|
3720
4034
|
writeFileSync(temp, content);
|
|
3721
4035
|
renameSync(temp, path);
|
|
3722
4036
|
}
|
|
3723
|
-
function backupDestination(id, path, options) {
|
|
3724
|
-
const backupDir = join(agntnDataDir(options), "diverged", "prompts", id);
|
|
3725
|
-
mkdirSync(backupDir, { recursive: true });
|
|
3726
|
-
const backup = join(backupDir, `${basename(path)}-${Date.now()}-${randomUUID()}`);
|
|
3727
|
-
if (lstatSync(path).isSymbolicLink()) {
|
|
3728
|
-
symlinkSync(linkTarget(path), backup);
|
|
3729
|
-
unlinkSync(path);
|
|
3730
|
-
return backup;
|
|
3731
|
-
}
|
|
3732
|
-
moveFile(path, backup);
|
|
3733
|
-
return backup;
|
|
3734
|
-
}
|
|
3735
|
-
function checkDetail() {
|
|
3736
|
-
return "check mode: not applied";
|
|
3737
|
-
}
|
|
3738
|
-
function isInsideDirectory(path, directory) {
|
|
3739
|
-
const remainder = relative(directory, path);
|
|
3740
|
-
return remainder !== "" && !remainder.startsWith("..") && !isAbsolute(remainder);
|
|
3741
|
-
}
|
|
3742
|
-
function isLegacyTemplateLink(path, sourceDir) {
|
|
3743
|
-
return lstatSync(path).isSymbolicLink() && isInsideDirectory(linkTarget(path), sourceDir);
|
|
3744
|
-
}
|
|
3745
|
-
const DIRECTORY_ACTION = {
|
|
3746
|
-
missing: "linked",
|
|
3747
|
-
"correct-link": "unchanged",
|
|
3748
|
-
"wrong-link": "relinked",
|
|
3749
|
-
"legacy-links": "relinked",
|
|
3750
|
-
"local-files": "adopted",
|
|
3751
|
-
"not-directory": "skipped"
|
|
3752
|
-
};
|
|
3753
|
-
function inspectDirectory(targetDir, sourceDir) {
|
|
3754
|
-
let stats;
|
|
3755
|
-
try {
|
|
3756
|
-
stats = lstatSync(targetDir);
|
|
3757
|
-
} catch (error) {
|
|
3758
|
-
if (error.code === "ENOENT") return { kind: "missing" };
|
|
3759
|
-
throw error;
|
|
3760
|
-
}
|
|
3761
|
-
if (stats.isSymbolicLink()) return { kind: linkTarget(targetDir) === sourceDir ? "correct-link" : "wrong-link" };
|
|
3762
|
-
if (!stats.isDirectory()) return { kind: "not-directory" };
|
|
3763
|
-
const entries = readdirSync(targetDir).map((entry) => join(targetDir, entry));
|
|
3764
|
-
return entries.every((entry) => isLegacyTemplateLink(entry, sourceDir)) ? {
|
|
3765
|
-
kind: "legacy-links",
|
|
3766
|
-
entries
|
|
3767
|
-
} : { kind: "local-files" };
|
|
3768
|
-
}
|
|
3769
|
-
function clearDirectory(id, targetDir, state, options) {
|
|
3770
|
-
if (state.kind === "wrong-link" || state.kind === "local-files") return backupDestination(id, targetDir, options);
|
|
3771
|
-
if (state.kind === "legacy-links") {
|
|
3772
|
-
for (const entry of state.entries) unlinkSync(entry);
|
|
3773
|
-
rmdirSync(targetDir);
|
|
3774
|
-
}
|
|
3775
|
-
}
|
|
3776
|
-
function syncMarkdownDirectory(id, targetDir, sourceDir, check, options) {
|
|
3777
|
-
const state = inspectDirectory(targetDir, sourceDir);
|
|
3778
|
-
const action = DIRECTORY_ACTION[state.kind];
|
|
3779
|
-
if (state.kind === "correct-link") return { action };
|
|
3780
|
-
if (state.kind === "not-directory") return {
|
|
3781
|
-
action,
|
|
3782
|
-
detail: "destination exists and is not a directory or symlink"
|
|
3783
|
-
};
|
|
3784
|
-
if (check) return {
|
|
3785
|
-
action,
|
|
3786
|
-
detail: checkDetail()
|
|
3787
|
-
};
|
|
3788
|
-
const detail = clearDirectory(id, targetDir, state, options);
|
|
3789
|
-
linkDirectory(targetDir, sourceDir);
|
|
3790
|
-
return {
|
|
3791
|
-
action,
|
|
3792
|
-
detail
|
|
3793
|
-
};
|
|
3794
|
-
}
|
|
3795
4037
|
function parseYaml(raw) {
|
|
3796
4038
|
return createRequire(import.meta.url)("yaml").parse(raw);
|
|
3797
4039
|
}
|
|
@@ -3844,10 +4086,10 @@ function syncGeminiTemplate(id, targetDir, template, check, options) {
|
|
|
3844
4086
|
source: template.path,
|
|
3845
4087
|
path,
|
|
3846
4088
|
action,
|
|
3847
|
-
detail:
|
|
4089
|
+
detail: CHECK_DETAIL
|
|
3848
4090
|
};
|
|
3849
4091
|
let detail;
|
|
3850
|
-
if (GEMINI_BACKUP[state.kind]) detail = backupDestination(id, path, options);
|
|
4092
|
+
if (GEMINI_BACKUP[state.kind]) detail = backupDestination("prompts", id, path, options);
|
|
3851
4093
|
writeTemplate(path, content);
|
|
3852
4094
|
return {
|
|
3853
4095
|
name: template.name,
|
|
@@ -3885,7 +4127,7 @@ function pruneGeminiTarget(id, targetDir, sourceDir, activeNames, check, options
|
|
|
3885
4127
|
...source === null ? {} : { source },
|
|
3886
4128
|
path,
|
|
3887
4129
|
action: "removed",
|
|
3888
|
-
detail:
|
|
4130
|
+
detail: CHECK_DETAIL
|
|
3889
4131
|
};
|
|
3890
4132
|
if (source !== null) {
|
|
3891
4133
|
unlinkSync(path);
|
|
@@ -3900,11 +4142,11 @@ function pruneGeminiTarget(id, targetDir, sourceDir, activeNames, check, options
|
|
|
3900
4142
|
name,
|
|
3901
4143
|
path,
|
|
3902
4144
|
action: "removed",
|
|
3903
|
-
detail: backupDestination(id, path, options)
|
|
4145
|
+
detail: backupDestination("prompts", id, path, options)
|
|
3904
4146
|
};
|
|
3905
4147
|
});
|
|
3906
4148
|
}
|
|
3907
|
-
function syncTarget(harness, templates, sourceDir, check, options) {
|
|
4149
|
+
function syncTarget$1(harness, templates, sourceDir, check, options) {
|
|
3908
4150
|
const target = harness.promptTemplateSyncTarget;
|
|
3909
4151
|
if (target === null) return {
|
|
3910
4152
|
id: harness.id,
|
|
@@ -3922,7 +4164,7 @@ function syncTarget(harness, templates, sourceDir, check, options) {
|
|
|
3922
4164
|
id: harness.id,
|
|
3923
4165
|
path: targetDir,
|
|
3924
4166
|
format: resolved.format,
|
|
3925
|
-
...
|
|
4167
|
+
...syncDirectoryLink("prompts", harness.id, targetDir, sourceDir, check, options),
|
|
3926
4168
|
templates: []
|
|
3927
4169
|
};
|
|
3928
4170
|
const results = templates.map((template) => syncGeminiTemplate(harness.id, targetDir, template, check, options));
|
|
@@ -3946,9 +4188,59 @@ function syncPromptTemplates(harnesses, check = false, options = {}) {
|
|
|
3946
4188
|
source,
|
|
3947
4189
|
check,
|
|
3948
4190
|
templates: prepared.map((template) => template.name),
|
|
3949
|
-
targets: harnesses.map((harness) => syncTarget(harness, prepared, source, check, options))
|
|
4191
|
+
targets: harnesses.map((harness) => syncTarget$1(harness, prepared, source, check, options))
|
|
4192
|
+
};
|
|
4193
|
+
}
|
|
4194
|
+
//#endregion
|
|
4195
|
+
//#region src/skills-sync.ts
|
|
4196
|
+
function readSkills(sourceDir, check) {
|
|
4197
|
+
let entries;
|
|
4198
|
+
try {
|
|
4199
|
+
entries = readdirSync(sourceDir);
|
|
4200
|
+
} catch (error) {
|
|
4201
|
+
if (error.code !== "ENOENT") throw error;
|
|
4202
|
+
if (!check) mkdirSync(sourceDir, { recursive: true });
|
|
4203
|
+
return [];
|
|
4204
|
+
}
|
|
4205
|
+
return entries.filter((entry) => {
|
|
4206
|
+
const path = join(sourceDir, entry);
|
|
4207
|
+
try {
|
|
4208
|
+
return statSync(path).isDirectory() && existsSync(join(path, "SKILL.md"));
|
|
4209
|
+
} catch {
|
|
4210
|
+
return false;
|
|
4211
|
+
}
|
|
4212
|
+
}).sort((left, right) => left.localeCompare(right));
|
|
4213
|
+
}
|
|
4214
|
+
function syncTarget(harness, sourceDir, check, options) {
|
|
4215
|
+
const target = harness.skillsSyncTarget;
|
|
4216
|
+
if (target === null) return {
|
|
4217
|
+
id: harness.id,
|
|
4218
|
+
action: "skipped",
|
|
4219
|
+
detail: "no stable user-scope skills directory"
|
|
4220
|
+
};
|
|
4221
|
+
const resolved = harness.resolveCandidates([target], options)[0];
|
|
4222
|
+
if (resolved === void 0) return {
|
|
4223
|
+
id: harness.id,
|
|
4224
|
+
action: "skipped",
|
|
4225
|
+
detail: "skills directory is unavailable on this platform"
|
|
4226
|
+
};
|
|
4227
|
+
const targetDir = resolve(resolved.path);
|
|
4228
|
+
return {
|
|
4229
|
+
id: harness.id,
|
|
4230
|
+
path: targetDir,
|
|
4231
|
+
...syncDirectoryLink("skills", harness.id, targetDir, sourceDir, check, options)
|
|
4232
|
+
};
|
|
4233
|
+
}
|
|
4234
|
+
function syncSkills(harnesses, check = false, options = {}) {
|
|
4235
|
+
const source = join(agntnDataDir(options), "skills");
|
|
4236
|
+
return {
|
|
4237
|
+
source,
|
|
4238
|
+
check,
|
|
4239
|
+
skills: readSkills(source, check),
|
|
4240
|
+
targets: harnesses.map((harness) => syncTarget(harness, source, check, options))
|
|
3950
4241
|
};
|
|
3951
4242
|
}
|
|
3952
|
-
|
|
4243
|
+
//#endregion
|
|
4244
|
+
export { agntnConfigDir as C, Harness as S, resolvePathTemplate as T, getAllHarnesses as _, McpEnvError as a, listHarnesses as b, listMcpServers as c, readMasterMcpServers as d, removeMcpServer as f, detectProjectHarnesses as g, detectHarnessFromEnv as h, syncAgentsFiles as i, masterMcpPath as l, detectHarness as m, syncPromptTemplates as n, McpTransportError as o, syncMcpServers as p, readAgentsConfig as r, addMcpServer as s, syncSkills as t, parseJsonc as u, getHarness as v, agntnDataDir as w, registerHarness as x, isHarnessId as y };
|
|
3953
4245
|
|
|
3954
|
-
//# sourceMappingURL=
|
|
4246
|
+
//# sourceMappingURL=skills-sync.mjs.map
|