@agntn/harnesses 0.3.0 → 0.3.1
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 +34 -4
- 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} +103 -50
- package/dist/_chunks/skills-sync.d.mts.map +1 -0
- package/dist/_chunks/{prompt-sync.mjs → skills-sync.mjs} +298 -98
- 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 +22 -2
- 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 +18 -18
- package/packages/omp/extensions/harnesses.ts +18 -0
- 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,8 @@ var MastraCode = class extends Harness {
|
|
|
1966
2034
|
projectMarkers: [".mastracode"]
|
|
1967
2035
|
};
|
|
1968
2036
|
};
|
|
2037
|
+
//#endregion
|
|
2038
|
+
//#region src/harnesses/omp.ts
|
|
1969
2039
|
var Omp = class extends Harness {
|
|
1970
2040
|
id = "omp";
|
|
1971
2041
|
name = "OMP (oh-my-pi)";
|
|
@@ -2105,6 +2175,11 @@ var Omp = class extends Harness {
|
|
|
2105
2175
|
note: "Auto-generated managed skills."
|
|
2106
2176
|
}
|
|
2107
2177
|
];
|
|
2178
|
+
skillsSyncTarget = {
|
|
2179
|
+
path: "~/.omp/agent/skills/",
|
|
2180
|
+
scope: "user",
|
|
2181
|
+
level: "official"
|
|
2182
|
+
};
|
|
2108
2183
|
commands = [{
|
|
2109
2184
|
path: ".omp/commands/",
|
|
2110
2185
|
scope: "project",
|
|
@@ -2186,6 +2261,8 @@ var Omp = class extends Harness {
|
|
|
2186
2261
|
projectMarkers: [".omp"]
|
|
2187
2262
|
};
|
|
2188
2263
|
};
|
|
2264
|
+
//#endregion
|
|
2265
|
+
//#region src/harnesses/opencode.ts
|
|
2189
2266
|
var OpenCode = class extends Harness {
|
|
2190
2267
|
id = "opencode";
|
|
2191
2268
|
name = "OpenCode CLI";
|
|
@@ -2282,6 +2359,11 @@ var OpenCode = class extends Harness {
|
|
|
2282
2359
|
scope: "project",
|
|
2283
2360
|
level: "official"
|
|
2284
2361
|
},
|
|
2362
|
+
{
|
|
2363
|
+
path: "~/.config/opencode/skills/",
|
|
2364
|
+
scope: "user",
|
|
2365
|
+
level: "official"
|
|
2366
|
+
},
|
|
2285
2367
|
{
|
|
2286
2368
|
path: "~/.claude/skills/",
|
|
2287
2369
|
scope: "user",
|
|
@@ -2294,6 +2376,12 @@ var OpenCode = class extends Harness {
|
|
|
2294
2376
|
level: "official"
|
|
2295
2377
|
}
|
|
2296
2378
|
];
|
|
2379
|
+
skillsSyncTarget = {
|
|
2380
|
+
path: "~/.config/opencode/skills/",
|
|
2381
|
+
scope: "user",
|
|
2382
|
+
level: "official",
|
|
2383
|
+
note: "OpenCode also scans ~/.claude/skills/ and ~/.agents/skills/; skill names must be unique across them."
|
|
2384
|
+
};
|
|
2297
2385
|
commands = [{
|
|
2298
2386
|
path: ".opencode/commands/",
|
|
2299
2387
|
scope: "project",
|
|
@@ -2349,6 +2437,8 @@ var OpenCode = class extends Harness {
|
|
|
2349
2437
|
]
|
|
2350
2438
|
};
|
|
2351
2439
|
};
|
|
2440
|
+
//#endregion
|
|
2441
|
+
//#region src/harnesses/pi.ts
|
|
2352
2442
|
const MODEL_HEADERS = [
|
|
2353
2443
|
"provider",
|
|
2354
2444
|
"model",
|
|
@@ -2461,6 +2551,11 @@ var Pi = class extends Harness {
|
|
|
2461
2551
|
level: "official",
|
|
2462
2552
|
note: "Global user-level skills."
|
|
2463
2553
|
}];
|
|
2554
|
+
skillsSyncTarget = {
|
|
2555
|
+
path: "~/.pi/agent/skills/",
|
|
2556
|
+
scope: "user",
|
|
2557
|
+
level: "official"
|
|
2558
|
+
};
|
|
2464
2559
|
commands = [{
|
|
2465
2560
|
path: ".pi/prompts/",
|
|
2466
2561
|
scope: "project",
|
|
@@ -2559,6 +2654,8 @@ var Pi = class extends Harness {
|
|
|
2559
2654
|
return parsePiModelTable(stdout, "Pi");
|
|
2560
2655
|
}
|
|
2561
2656
|
};
|
|
2657
|
+
//#endregion
|
|
2658
|
+
//#region src/harnesses/prime-agent.ts
|
|
2562
2659
|
var PrimeAgent = class extends Harness {
|
|
2563
2660
|
id = "prime-agent";
|
|
2564
2661
|
name = "Prime Agent";
|
|
@@ -2660,6 +2757,11 @@ var PrimeAgent = class extends Harness {
|
|
|
2660
2757
|
note: "Shared skills directory; root .md files are ignored there."
|
|
2661
2758
|
}
|
|
2662
2759
|
];
|
|
2760
|
+
skillsSyncTarget = {
|
|
2761
|
+
path: "~/.prime/agent/skills/",
|
|
2762
|
+
scope: "user",
|
|
2763
|
+
level: "official"
|
|
2764
|
+
};
|
|
2663
2765
|
commands = [{
|
|
2664
2766
|
path: ".prime/agent/prompts/",
|
|
2665
2767
|
scope: "project",
|
|
@@ -2731,6 +2833,8 @@ var PrimeAgent = class extends Harness {
|
|
|
2731
2833
|
return parsePiModelTable(stdout, "Prime Agent");
|
|
2732
2834
|
}
|
|
2733
2835
|
};
|
|
2836
|
+
//#endregion
|
|
2837
|
+
//#region src/harnesses/index.ts
|
|
2734
2838
|
const harnesses = [
|
|
2735
2839
|
Antigravity,
|
|
2736
2840
|
Claude,
|
|
@@ -2746,6 +2850,8 @@ const harnesses = [
|
|
|
2746
2850
|
PrimeAgent,
|
|
2747
2851
|
Pi
|
|
2748
2852
|
];
|
|
2853
|
+
//#endregion
|
|
2854
|
+
//#region src/registry.ts
|
|
2749
2855
|
let registry;
|
|
2750
2856
|
function getRegistry() {
|
|
2751
2857
|
if (!registry) {
|
|
@@ -2793,6 +2899,8 @@ function detectHarness(cwd) {
|
|
|
2793
2899
|
}
|
|
2794
2900
|
return match;
|
|
2795
2901
|
}
|
|
2902
|
+
//#endregion
|
|
2903
|
+
//#region src/mcp-servers.ts
|
|
2796
2904
|
function resolveConfigs(harness, options) {
|
|
2797
2905
|
return harness.resolveCandidates(harness.mcpConfigs, options).map((entry) => ({
|
|
2798
2906
|
entry,
|
|
@@ -3436,6 +3544,8 @@ function syncMcpServers(harnesses, options = {}) {
|
|
|
3436
3544
|
targets: harnesses.map((harness) => syncMcpTarget(harness, master, masterNames, options))
|
|
3437
3545
|
};
|
|
3438
3546
|
}
|
|
3547
|
+
//#endregion
|
|
3548
|
+
//#region src/agents-sync.ts
|
|
3439
3549
|
function readIfExists(path) {
|
|
3440
3550
|
try {
|
|
3441
3551
|
return readFileSync(path, "utf8");
|
|
@@ -3583,7 +3693,7 @@ function syncFileTarget(id, path, source, check, options) {
|
|
|
3583
3693
|
};
|
|
3584
3694
|
return applyFileTarget(id, path, source, state, options);
|
|
3585
3695
|
}
|
|
3586
|
-
function syncTarget$
|
|
3696
|
+
function syncTarget$2(harness, config, check, options) {
|
|
3587
3697
|
if (config.excludes.includes(harness.id)) return {
|
|
3588
3698
|
id: harness.id,
|
|
3589
3699
|
action: "skipped",
|
|
@@ -3634,9 +3744,134 @@ function syncAgentsFiles(harnesses, check = false, options = {}) {
|
|
|
3634
3744
|
return {
|
|
3635
3745
|
source: config.source,
|
|
3636
3746
|
check,
|
|
3637
|
-
targets: harnesses.map((harness) => syncTarget$
|
|
3747
|
+
targets: harnesses.map((harness) => syncTarget$2(harness, config, check, options))
|
|
3638
3748
|
};
|
|
3639
3749
|
}
|
|
3750
|
+
//#endregion
|
|
3751
|
+
//#region src/directory-link.ts
|
|
3752
|
+
const CHECK_DETAIL = "check mode: not applied";
|
|
3753
|
+
function linkTarget(path) {
|
|
3754
|
+
const target = readlinkSync(path);
|
|
3755
|
+
return isAbsolute(target) ? target : resolve(dirname(path), target);
|
|
3756
|
+
}
|
|
3757
|
+
function isInsideDirectory(path, directory) {
|
|
3758
|
+
const remainder = relative(directory, path);
|
|
3759
|
+
return remainder !== "" && !remainder.startsWith("..") && !isAbsolute(remainder);
|
|
3760
|
+
}
|
|
3761
|
+
function tempPath(path, kind) {
|
|
3762
|
+
return join(dirname(path), `.${basename(path)}-${randomUUID()}.${kind}.tmp`);
|
|
3763
|
+
}
|
|
3764
|
+
function realDirectory(path) {
|
|
3765
|
+
try {
|
|
3766
|
+
return realpathSync(path);
|
|
3767
|
+
} catch {
|
|
3768
|
+
return resolve(path);
|
|
3769
|
+
}
|
|
3770
|
+
}
|
|
3771
|
+
function backupDestination(kind, id, path, options) {
|
|
3772
|
+
const backupDir = join(agntnDataDir(options), "diverged", kind, id);
|
|
3773
|
+
mkdirSync(backupDir, { recursive: true });
|
|
3774
|
+
const backup = join(backupDir, `${basename(path)}-${Date.now()}-${randomUUID()}`);
|
|
3775
|
+
if (lstatSync(path).isSymbolicLink()) {
|
|
3776
|
+
symlinkSync(linkTarget(path), backup);
|
|
3777
|
+
unlinkSync(path);
|
|
3778
|
+
return backup;
|
|
3779
|
+
}
|
|
3780
|
+
moveFile(path, backup);
|
|
3781
|
+
return backup;
|
|
3782
|
+
}
|
|
3783
|
+
function linkDirectory(path, source, kind) {
|
|
3784
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
3785
|
+
const temp = tempPath(path, `${kind}-link`);
|
|
3786
|
+
symlinkSync(source, temp, "junction");
|
|
3787
|
+
renameSync(temp, path);
|
|
3788
|
+
}
|
|
3789
|
+
const DIRECTORY_ACTION = {
|
|
3790
|
+
missing: "linked",
|
|
3791
|
+
"correct-link": "unchanged",
|
|
3792
|
+
"wrong-link": "relinked",
|
|
3793
|
+
"legacy-links": "relinked",
|
|
3794
|
+
"local-files": "adopted",
|
|
3795
|
+
"not-directory": "skipped",
|
|
3796
|
+
source: "skipped"
|
|
3797
|
+
};
|
|
3798
|
+
const SKIP_DETAIL = {
|
|
3799
|
+
"not-directory": "destination exists and is not a directory or symlink",
|
|
3800
|
+
source: "destination holds the source directory"
|
|
3801
|
+
};
|
|
3802
|
+
function isEntryLink(path, sourceDirs) {
|
|
3803
|
+
if (!lstatSync(path).isSymbolicLink()) return false;
|
|
3804
|
+
const target = linkTarget(path);
|
|
3805
|
+
return sourceDirs.some((directory) => isInsideDirectory(target, directory));
|
|
3806
|
+
}
|
|
3807
|
+
function linksThrough(sourceDir, targetDir) {
|
|
3808
|
+
let path = sourceDir;
|
|
3809
|
+
for (let hop = 0; hop < 32; hop++) {
|
|
3810
|
+
if (path === targetDir || isInsideDirectory(path, targetDir)) return true;
|
|
3811
|
+
try {
|
|
3812
|
+
if (!lstatSync(path).isSymbolicLink()) return false;
|
|
3813
|
+
} catch {
|
|
3814
|
+
return false;
|
|
3815
|
+
}
|
|
3816
|
+
path = linkTarget(path);
|
|
3817
|
+
}
|
|
3818
|
+
return false;
|
|
3819
|
+
}
|
|
3820
|
+
function inspectDirectory(targetDir, sourceDir) {
|
|
3821
|
+
let stats;
|
|
3822
|
+
try {
|
|
3823
|
+
stats = lstatSync(targetDir);
|
|
3824
|
+
} catch (error) {
|
|
3825
|
+
if (error.code === "ENOENT") return { kind: "missing" };
|
|
3826
|
+
throw error;
|
|
3827
|
+
}
|
|
3828
|
+
if (stats.isSymbolicLink()) {
|
|
3829
|
+
if (linkTarget(targetDir) === sourceDir) return { kind: "correct-link" };
|
|
3830
|
+
return { kind: linksThrough(sourceDir, targetDir) ? "source" : "wrong-link" };
|
|
3831
|
+
}
|
|
3832
|
+
if (!stats.isDirectory()) return { kind: "not-directory" };
|
|
3833
|
+
return inspectLocalDirectory(targetDir, sourceDir);
|
|
3834
|
+
}
|
|
3835
|
+
function inspectLocalDirectory(targetDir, sourceDir) {
|
|
3836
|
+
const realSource = realDirectory(sourceDir);
|
|
3837
|
+
const realTarget = realpathSync(targetDir);
|
|
3838
|
+
if (realSource === realTarget || isInsideDirectory(realSource, realTarget)) return { kind: "source" };
|
|
3839
|
+
const sourceDirs = realSource === sourceDir ? [sourceDir] : [sourceDir, realSource];
|
|
3840
|
+
const entries = readdirSync(targetDir).map((entry) => join(targetDir, entry));
|
|
3841
|
+
return entries.every((entry) => isEntryLink(entry, sourceDirs)) ? {
|
|
3842
|
+
kind: "legacy-links",
|
|
3843
|
+
entries
|
|
3844
|
+
} : { kind: "local-files" };
|
|
3845
|
+
}
|
|
3846
|
+
function clearDirectory(kind, id, targetDir, state, options) {
|
|
3847
|
+
if (state.kind === "wrong-link" || state.kind === "local-files") return backupDestination(kind, id, targetDir, options);
|
|
3848
|
+
if (state.kind === "legacy-links") {
|
|
3849
|
+
for (const entry of state.entries) unlinkSync(entry);
|
|
3850
|
+
rmdirSync(targetDir);
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
function syncDirectoryLink(kind, id, targetDir, sourceDir, check, options) {
|
|
3854
|
+
const state = inspectDirectory(targetDir, sourceDir);
|
|
3855
|
+
const action = DIRECTORY_ACTION[state.kind];
|
|
3856
|
+
if (state.kind === "correct-link") return { action };
|
|
3857
|
+
const skip = SKIP_DETAIL[state.kind];
|
|
3858
|
+
if (skip !== void 0) return {
|
|
3859
|
+
action,
|
|
3860
|
+
detail: skip
|
|
3861
|
+
};
|
|
3862
|
+
if (check) return {
|
|
3863
|
+
action,
|
|
3864
|
+
detail: CHECK_DETAIL
|
|
3865
|
+
};
|
|
3866
|
+
const detail = clearDirectory(kind, id, targetDir, state, options);
|
|
3867
|
+
linkDirectory(targetDir, sourceDir, kind);
|
|
3868
|
+
return {
|
|
3869
|
+
action,
|
|
3870
|
+
detail
|
|
3871
|
+
};
|
|
3872
|
+
}
|
|
3873
|
+
//#endregion
|
|
3874
|
+
//#region src/prompt-sync.ts
|
|
3640
3875
|
const GENERATED_MARKER = "# Generated by @agntn/harnesses from ";
|
|
3641
3876
|
const PORTABLE_PROMPT_NAME = /^[A-Za-z0-9][A-Za-z0-9_-]*$/u;
|
|
3642
3877
|
const GEMINI_ACTION = {
|
|
@@ -3684,10 +3919,6 @@ function generatedSource(content) {
|
|
|
3684
3919
|
return null;
|
|
3685
3920
|
}
|
|
3686
3921
|
}
|
|
3687
|
-
function linkTarget(path) {
|
|
3688
|
-
const target = readlinkSync(path);
|
|
3689
|
-
return isAbsolute(target) ? target : resolve(dirname(path), target);
|
|
3690
|
-
}
|
|
3691
3922
|
function inspectDestination(path) {
|
|
3692
3923
|
let stats;
|
|
3693
3924
|
try {
|
|
@@ -3705,93 +3936,12 @@ function inspectDestination(path) {
|
|
|
3705
3936
|
};
|
|
3706
3937
|
return { kind: "unmanaged-file" };
|
|
3707
3938
|
}
|
|
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
3939
|
function writeTemplate(path, content) {
|
|
3718
3940
|
mkdirSync(dirname(path), { recursive: true });
|
|
3719
3941
|
const temp = tempPath(path, "prompt-write");
|
|
3720
3942
|
writeFileSync(temp, content);
|
|
3721
3943
|
renameSync(temp, path);
|
|
3722
3944
|
}
|
|
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
3945
|
function parseYaml(raw) {
|
|
3796
3946
|
return createRequire(import.meta.url)("yaml").parse(raw);
|
|
3797
3947
|
}
|
|
@@ -3844,10 +3994,10 @@ function syncGeminiTemplate(id, targetDir, template, check, options) {
|
|
|
3844
3994
|
source: template.path,
|
|
3845
3995
|
path,
|
|
3846
3996
|
action,
|
|
3847
|
-
detail:
|
|
3997
|
+
detail: CHECK_DETAIL
|
|
3848
3998
|
};
|
|
3849
3999
|
let detail;
|
|
3850
|
-
if (GEMINI_BACKUP[state.kind]) detail = backupDestination(id, path, options);
|
|
4000
|
+
if (GEMINI_BACKUP[state.kind]) detail = backupDestination("prompts", id, path, options);
|
|
3851
4001
|
writeTemplate(path, content);
|
|
3852
4002
|
return {
|
|
3853
4003
|
name: template.name,
|
|
@@ -3885,7 +4035,7 @@ function pruneGeminiTarget(id, targetDir, sourceDir, activeNames, check, options
|
|
|
3885
4035
|
...source === null ? {} : { source },
|
|
3886
4036
|
path,
|
|
3887
4037
|
action: "removed",
|
|
3888
|
-
detail:
|
|
4038
|
+
detail: CHECK_DETAIL
|
|
3889
4039
|
};
|
|
3890
4040
|
if (source !== null) {
|
|
3891
4041
|
unlinkSync(path);
|
|
@@ -3900,11 +4050,11 @@ function pruneGeminiTarget(id, targetDir, sourceDir, activeNames, check, options
|
|
|
3900
4050
|
name,
|
|
3901
4051
|
path,
|
|
3902
4052
|
action: "removed",
|
|
3903
|
-
detail: backupDestination(id, path, options)
|
|
4053
|
+
detail: backupDestination("prompts", id, path, options)
|
|
3904
4054
|
};
|
|
3905
4055
|
});
|
|
3906
4056
|
}
|
|
3907
|
-
function syncTarget(harness, templates, sourceDir, check, options) {
|
|
4057
|
+
function syncTarget$1(harness, templates, sourceDir, check, options) {
|
|
3908
4058
|
const target = harness.promptTemplateSyncTarget;
|
|
3909
4059
|
if (target === null) return {
|
|
3910
4060
|
id: harness.id,
|
|
@@ -3922,7 +4072,7 @@ function syncTarget(harness, templates, sourceDir, check, options) {
|
|
|
3922
4072
|
id: harness.id,
|
|
3923
4073
|
path: targetDir,
|
|
3924
4074
|
format: resolved.format,
|
|
3925
|
-
...
|
|
4075
|
+
...syncDirectoryLink("prompts", harness.id, targetDir, sourceDir, check, options),
|
|
3926
4076
|
templates: []
|
|
3927
4077
|
};
|
|
3928
4078
|
const results = templates.map((template) => syncGeminiTemplate(harness.id, targetDir, template, check, options));
|
|
@@ -3946,9 +4096,59 @@ function syncPromptTemplates(harnesses, check = false, options = {}) {
|
|
|
3946
4096
|
source,
|
|
3947
4097
|
check,
|
|
3948
4098
|
templates: prepared.map((template) => template.name),
|
|
3949
|
-
targets: harnesses.map((harness) => syncTarget(harness, prepared, source, check, options))
|
|
4099
|
+
targets: harnesses.map((harness) => syncTarget$1(harness, prepared, source, check, options))
|
|
4100
|
+
};
|
|
4101
|
+
}
|
|
4102
|
+
//#endregion
|
|
4103
|
+
//#region src/skills-sync.ts
|
|
4104
|
+
function readSkills(sourceDir, check) {
|
|
4105
|
+
let entries;
|
|
4106
|
+
try {
|
|
4107
|
+
entries = readdirSync(sourceDir);
|
|
4108
|
+
} catch (error) {
|
|
4109
|
+
if (error.code !== "ENOENT") throw error;
|
|
4110
|
+
if (!check) mkdirSync(sourceDir, { recursive: true });
|
|
4111
|
+
return [];
|
|
4112
|
+
}
|
|
4113
|
+
return entries.filter((entry) => {
|
|
4114
|
+
const path = join(sourceDir, entry);
|
|
4115
|
+
try {
|
|
4116
|
+
return statSync(path).isDirectory() && existsSync(join(path, "SKILL.md"));
|
|
4117
|
+
} catch {
|
|
4118
|
+
return false;
|
|
4119
|
+
}
|
|
4120
|
+
}).sort((left, right) => left.localeCompare(right));
|
|
4121
|
+
}
|
|
4122
|
+
function syncTarget(harness, sourceDir, check, options) {
|
|
4123
|
+
const target = harness.skillsSyncTarget;
|
|
4124
|
+
if (target === null) return {
|
|
4125
|
+
id: harness.id,
|
|
4126
|
+
action: "skipped",
|
|
4127
|
+
detail: "no stable user-scope skills directory"
|
|
4128
|
+
};
|
|
4129
|
+
const resolved = harness.resolveCandidates([target], options)[0];
|
|
4130
|
+
if (resolved === void 0) return {
|
|
4131
|
+
id: harness.id,
|
|
4132
|
+
action: "skipped",
|
|
4133
|
+
detail: "skills directory is unavailable on this platform"
|
|
4134
|
+
};
|
|
4135
|
+
const targetDir = resolve(resolved.path);
|
|
4136
|
+
return {
|
|
4137
|
+
id: harness.id,
|
|
4138
|
+
path: targetDir,
|
|
4139
|
+
...syncDirectoryLink("skills", harness.id, targetDir, sourceDir, check, options)
|
|
4140
|
+
};
|
|
4141
|
+
}
|
|
4142
|
+
function syncSkills(harnesses, check = false, options = {}) {
|
|
4143
|
+
const source = join(agntnDataDir(options), "skills");
|
|
4144
|
+
return {
|
|
4145
|
+
source,
|
|
4146
|
+
check,
|
|
4147
|
+
skills: readSkills(source, check),
|
|
4148
|
+
targets: harnesses.map((harness) => syncTarget(harness, source, check, options))
|
|
3950
4149
|
};
|
|
3951
4150
|
}
|
|
3952
|
-
|
|
4151
|
+
//#endregion
|
|
4152
|
+
export { agntnDataDir as C, agntnConfigDir as S, getHarness as _, McpEnvError as a, registerHarness as b, masterMcpPath as c, removeMcpServer as d, syncMcpServers as f, getAllHarnesses as g, detectProjectHarnesses as h, syncAgentsFiles as i, parseJsonc as l, detectHarnessFromEnv as m, syncPromptTemplates as n, addMcpServer as o, detectHarness as p, readAgentsConfig as r, listMcpServers as s, syncSkills as t, readMasterMcpServers as u, isHarnessId as v, resolvePathTemplate as w, Harness as x, listHarnesses as y };
|
|
3953
4153
|
|
|
3954
|
-
//# sourceMappingURL=
|
|
4154
|
+
//# sourceMappingURL=skills-sync.mjs.map
|