@agntn/harnesses 0.1.0 → 0.1.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 +19 -17
- package/dist/_chunks/agents-sync.d.mts +19 -5
- package/dist/_chunks/agents-sync.d.mts.map +1 -1
- package/dist/_chunks/agents-sync.mjs +264 -29
- package/dist/_chunks/agents-sync.mjs.map +1 -1
- package/dist/_chunks/tool-operations.mjs +34 -9
- package/dist/_chunks/tool-operations.mjs.map +1 -1
- package/dist/_chunks/types.mjs +1 -1
- package/dist/_chunks/types.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/dist/tool-operations.d.mts +3 -2
- package/dist/tool-operations.d.mts.map +1 -1
- package/package.json +13 -15
package/README.md
CHANGED
|
@@ -55,20 +55,21 @@ import type { ClaudeSessionEntry, CodexThread, GeminiConversationRecord } from "
|
|
|
55
55
|
|
|
56
56
|
## Supported agents
|
|
57
57
|
|
|
58
|
-
| Agent | ID | Detection | Skills
|
|
59
|
-
| --------------- | ---------------- | ------------- |
|
|
60
|
-
| Antigravity CLI | `antigravity` | project | `.agents/skills/`
|
|
61
|
-
| Claude Code | `claude` | env + project | `.claude/skills/`
|
|
62
|
-
| Codex CLI | `codex` | project | `.agents/skills/`
|
|
63
|
-
| Gemini CLI | `gemini` | env + project | `.gemini/skills/`
|
|
64
|
-
| Grok CLI | `grok` | env + project | `.grok/skills/`
|
|
65
|
-
| OpenCode | `opencode` | project | `.opencode/skills/`
|
|
66
|
-
| Cursor | `cursor` | env + project | `.cursor/skills/`
|
|
67
|
-
| GitHub Copilot | `github-copilot` | env + project | `.github/skills/`
|
|
68
|
-
| Mastra Code | `mastracode` | project | `.mastracode/skills/`
|
|
69
|
-
| OMP (oh-my-pi) | `omp` | env + project | `.omp/skills/`
|
|
70
|
-
| Pi Coding Agent | `pi` | env + project | `.pi/skills/`
|
|
71
|
-
|
|
|
58
|
+
| Agent | ID | Detection | Skills | Hooks | Sessions |
|
|
59
|
+
| --------------- | ---------------- | ------------- | ---------------------- | ------------------------ | -------------- |
|
|
60
|
+
| Antigravity CLI | `antigravity` | project | `.agents/skills/` | - | JSONL + SQLite |
|
|
61
|
+
| Claude Code | `claude` | env + project | `.claude/skills/` | `.claude/hooks/` | JSONL |
|
|
62
|
+
| Codex CLI | `codex` | project | `.agents/skills/` | - | SQLite + JSONL |
|
|
63
|
+
| Gemini CLI | `gemini` | env + project | `.gemini/skills/` | - | JSON |
|
|
64
|
+
| Grok CLI | `grok` | env + project | `.grok/skills/` | `.grok/hooks/` | TOML + JSONL |
|
|
65
|
+
| OpenCode | `opencode` | project | `.opencode/skills/` | - | SQLite |
|
|
66
|
+
| Cursor | `cursor` | env + project | `.cursor/skills/` | - | - |
|
|
67
|
+
| GitHub Copilot | `github-copilot` | env + project | `.github/skills/` | - | - |
|
|
68
|
+
| Mastra Code | `mastracode` | project | `.mastracode/skills/` | `.mastracode/hooks.json` | SQLite |
|
|
69
|
+
| OMP (oh-my-pi) | `omp` | env + project | `.omp/skills/` | - | JSONL + SQLite |
|
|
70
|
+
| Pi Coding Agent | `pi` | env + project | `.pi/skills/` | - | JSON + JSONL |
|
|
71
|
+
| Prime Agent | `prime-agent` | env + project | `.prime/agent/skills/` | - | JSONL + JSON |
|
|
72
|
+
| Freebuff | `freebuff` | project | `.agents/skills/` | - | JSON + JSONL |
|
|
72
73
|
|
|
73
74
|
### Native audio and video input
|
|
74
75
|
|
|
@@ -87,6 +88,7 @@ import type { ClaudeSessionEntry, CodexThread, GeminiConversationRecord } from "
|
|
|
87
88
|
| Mastra Code | No | No | No verified native route |
|
|
88
89
|
| OMP (oh-my-pi) | No | No | No verified native route |
|
|
89
90
|
| Pi Coding Agent | No | No | No verified native route |
|
|
91
|
+
| Prime Agent | No | No | No verified native route |
|
|
90
92
|
| Freebuff | No | No | No verified native route |
|
|
91
93
|
|
|
92
94
|
Primary references: [Antigravity prompting](https://antigravity.google/docs/cli/prompting/), [Antigravity changelog](https://github.com/google-antigravity/antigravity-cli/blob/main/CHANGELOG.md), [Gemini CLI tools](https://github.com/google-gemini/gemini-cli/blob/main/docs/reference/tools.md), [Gemini CLI video request](https://github.com/google-gemini/gemini-cli/issues/27194), [OpenCode attachments](https://opencode.ai/v2/docs/attachments/), [Cursor prompting](https://cursor.com/docs/agent/prompting), and [Copilot CLI voice input](https://docs.github.com/en/copilot/how-tos/copilot-cli/use-copilot-cli/voice-input).
|
|
@@ -109,7 +111,7 @@ console.log(result.aborted);
|
|
|
109
111
|
|
|
110
112
|
This is command cleanup, not a sandbox. Descendants that leave the POSIX process group, or outlive an already exited root on Windows, cannot be reliably reached by these mechanisms. Inherited output pipes do not extend the wait after cleanup. Scheduling and OS delays can exceed the stated budgets.
|
|
111
113
|
|
|
112
|
-
Each agent is a concrete subclass of the abstract `Harness` class. Custom subclasses can be added with `registerHarness`. Every harness exposes config paths, session locations, instruction files, skills dirs, hooks, commands, persistence formats, capabilities (MCP, vision, audio, video, tools, streaming), detection rules, a normalized non-interactive invocation (`harness.invoke(prompt, { model })`) where the CLI has a headless mode, native model listing (`harness.listModels()`) where the CLI supports it, and its MCP server config files (`listMcpServers`/`addMcpServer`/`removeMcpServer` normalize the dialects; writes rewrite JSON and surgically edit TOML with comments preserved). `syncMcpServers` treats `~/.config/agntn/mcp.jsonc` (JSONC, XDG-aware) as the single source of truth and resets every harness's user-scope MCP config to exactly that list; a top-level `"excludes": ["codex"]` array opts individual harnesses out of the sync (their own servers stay, master-listed names are withdrawn), and `~`/`${HOME}` in commands, args, and env values expand to absolute paths at sync time (harnesses spawn MCP servers without a shell). `syncAgentsFiles` links every harness's global instructions file (CLAUDE.md/AGENTS.md/GEMINI.md) to one master file as symlinks, so an edit made through any harness lands in the single physical copy; `~/.config/agntn/agents.jsonc` sets the `source`, `companions`, and `excludes`, diverged regular files are backed up and relinked, and check mode reports without writing. Companion paths are relative to the source directory and are linked at the same relative path beside each harness target.
|
|
114
|
+
Each agent is a concrete subclass of the abstract `Harness` class. Custom subclasses can be added with `registerHarness`. Every harness exposes config paths, session locations, instruction files, skills dirs, hooks, commands, persistence formats, capabilities (MCP, vision, audio, video, tools, streaming), detection rules, a normalized non-interactive invocation (`harness.invoke(prompt, { model })`) where the CLI has a headless mode, native model listing (`harness.listModels()`) where the CLI supports it, and its MCP server config files (`listMcpServers`/`addMcpServer`/`removeMcpServer` normalize the dialects; writes rewrite JSON and surgically edit TOML with comments preserved). `syncMcpServers` treats `~/.config/agntn/mcp.jsonc` (JSONC, XDG-aware) as the single source of truth and resets every harness's user-scope MCP config to exactly that list; a top-level `"excludes": ["codex"]` array opts individual harnesses out of the sync (their own servers stay, master-listed names are withdrawn), and `~`/`${HOME}` in commands, args, and env values expand to absolute paths at sync time (harnesses spawn MCP servers without a shell). An env value that is exactly `${NAME}` references that variable of the harness environment: Prime Agent stores it natively as `{"env": "NAME"}`, the other harnesses receive the value from the syncing process, and a server one dialect cannot hold is reported as `skipped` with a reason while the rest of the list syncs. `syncAgentsFiles` links every harness's global instructions file (CLAUDE.md/AGENTS.md/GEMINI.md) to one master file as symlinks, so an edit made through any harness lands in the single physical copy; `~/.config/agntn/agents.jsonc` sets the `source`, `companions`, and `excludes`, diverged regular files are backed up and relinked, and check mode reports without writing. Companion paths are relative to the source directory and are linked at the same relative path beside each harness target.
|
|
113
115
|
|
|
114
116
|
```jsonc
|
|
115
117
|
{
|
|
@@ -121,7 +123,7 @@ Each agent is a concrete subclass of the abstract `Harness` class. Custom subcla
|
|
|
121
123
|
|
|
122
124
|
All paths carry `scope` (user/project/system/data), `level` (official/community/inferred), and optional `platforms` tags.
|
|
123
125
|
|
|
124
|
-
The `harnesses_info` agent tool accepts one harness id or a batch of up to 20 ids. Batch results keep the input order and include errors for unknown ids beside successful metadata.
|
|
126
|
+
The `harnesses_info` agent tool accepts one harness id or a batch of up to 20 ids. Batch results keep the input order and include errors for unknown ids beside successful metadata. Paths come once, resolved for the current platform. The templates stay with `harnesses info`.
|
|
125
127
|
|
|
126
128
|
## CLI
|
|
127
129
|
|
|
@@ -151,7 +153,7 @@ harnesses mcp # run the MCP server over stdio
|
|
|
151
153
|
|
|
152
154
|
[unagent](https://github.com/onmax/unagent) covers similar ground but makes different tradeoffs.
|
|
153
155
|
|
|
154
|
-
**harnesses is deep and narrow.** Each harness gets verified, platform-specific paths with scope, evidence level, and platform tags. Session formats are typed per harness.
|
|
156
|
+
**harnesses is deep and narrow.** Each harness gets verified, platform-specific paths with scope, evidence level, and platform tags. Session formats are typed per harness. Thirteen harnesses, each fully mapped.
|
|
155
157
|
|
|
156
158
|
**unagent is wide and shallow.** 40+ agents detected by env vars, but each definition is just `configDir` + `rulesFile` + `skillsDir`. No platform-specific paths, no session schemas. In exchange, it ships runtime primitives harnesses doesn't touch yet: skill install/uninstall, vector stores, browser automation, sandboxes, queues, workflows.
|
|
157
159
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
declare const version: string;
|
|
2
|
-
type HarnessId = "antigravity" | "codex" | "gemini" | "grok" | "claude" | "opencode" | "cursor" | "freebuff" | "github-copilot" | "mastracode" | "omp" | "pi";
|
|
2
|
+
type HarnessId = "antigravity" | "codex" | "gemini" | "grok" | "claude" | "opencode" | "cursor" | "freebuff" | "github-copilot" | "mastracode" | "omp" | "pi" | "prime-agent";
|
|
3
3
|
type EvidenceLevel = "official" | "community" | "inferred";
|
|
4
4
|
type Platform = "linux" | "darwin" | "win32";
|
|
5
5
|
interface PathCandidate {
|
|
@@ -122,6 +122,11 @@ interface McpServerConfig {
|
|
|
122
122
|
transport: "stdio" | "http" | "sse";
|
|
123
123
|
command?: string;
|
|
124
124
|
args?: string[];
|
|
125
|
+
/**
|
|
126
|
+
* Environment for stdio servers. A value that is exactly "${NAME}" refers to
|
|
127
|
+
* the variable NAME of the harness environment: dialects with native
|
|
128
|
+
* references keep it, the others resolve it when the entry is written.
|
|
129
|
+
*/
|
|
125
130
|
env?: Record<string, string>;
|
|
126
131
|
url?: string;
|
|
127
132
|
headers?: Record<string, string>;
|
|
@@ -133,8 +138,11 @@ interface McpConfigFile extends PathCandidate {
|
|
|
133
138
|
format: "json" | "toml";
|
|
134
139
|
/** Object path to the server map inside the file, e.g. ["mcpServers"]. */
|
|
135
140
|
key: string[];
|
|
136
|
-
/**
|
|
137
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Shape of individual entries; "standard" is the {command, args, env, url}
|
|
143
|
+
* family and "prime" is that family with env values as {"env": "NAME"} references.
|
|
144
|
+
*/
|
|
145
|
+
dialect: "standard" | "antigravity" | "opencode" | "prime" | "vscode";
|
|
138
146
|
}
|
|
139
147
|
interface HarnessDetection {
|
|
140
148
|
/** Environment variables that indicate running inside this agent. */
|
|
@@ -284,6 +292,10 @@ interface McpConfigListing {
|
|
|
284
292
|
/** Set when the file exists but could not be parsed. */
|
|
285
293
|
error?: string;
|
|
286
294
|
}
|
|
295
|
+
/** Thrown when a server's env cannot be written the way the target dialect requires. */
|
|
296
|
+
declare class McpEnvError extends Error {
|
|
297
|
+
readonly name = "McpEnvError";
|
|
298
|
+
}
|
|
287
299
|
/**
|
|
288
300
|
* Lists the MCP servers a harness has configured, per declared config file.
|
|
289
301
|
* Missing files come back with `exists: false`; unparsable ones carry `error`.
|
|
@@ -346,7 +358,9 @@ interface SyncTargetResult {
|
|
|
346
358
|
excluded?: true;
|
|
347
359
|
results: Array<{
|
|
348
360
|
name: string;
|
|
349
|
-
action: "added" | "replaced" | "removed" | "unchanged";
|
|
361
|
+
action: "added" | "replaced" | "removed" | "unchanged" | "skipped";
|
|
362
|
+
/** Why a master server could not be written to this harness. */
|
|
363
|
+
reason?: string;
|
|
350
364
|
}>;
|
|
351
365
|
}
|
|
352
366
|
/** Outcome of resetting the harness configs to the master list. */
|
|
@@ -430,5 +444,5 @@ declare function readAgentsConfig(options?: ResolveOptions): AgentsConfig;
|
|
|
430
444
|
* @returns {AgentsSyncReport} Per-harness synchronization outcomes.
|
|
431
445
|
*/
|
|
432
446
|
declare function syncAgentsFiles(harnesses: readonly Harness[], check?: boolean, options?: ResolveOptions): AgentsSyncReport;
|
|
433
|
-
export { AgentsCompanionTargetResult, AgentsConfig, AgentsSyncAction, AgentsSyncReport, AgentsTargetResult, AvailableModel, EvidenceLevel, Harness, HarnessCapabilities, HarnessConstructor, HarnessDetection, HarnessId, HarnessInvocation, HarnessInvocationModes, HarnessModelListing, InvokeOptions, InvokeResult, ListModelsOptions, ListModelsResult, McpConfigFile, McpConfigListing, McpServerConfig, PathCandidate, Platform, ResolveOptions, ResolvedPaths, StorageDescriptor, SyncReport, SyncTargetResult, addMcpServer, listMcpServers, masterMcpPath, parseJsonc, readAgentsConfig, readMasterMcpServers, removeMcpServer, syncAgentsFiles, syncMcpServers, version };
|
|
447
|
+
export { AgentsCompanionTargetResult, AgentsConfig, AgentsSyncAction, AgentsSyncReport, AgentsTargetResult, AvailableModel, EvidenceLevel, Harness, HarnessCapabilities, HarnessConstructor, HarnessDetection, HarnessId, HarnessInvocation, HarnessInvocationModes, HarnessModelListing, InvokeOptions, InvokeResult, ListModelsOptions, ListModelsResult, McpConfigFile, McpConfigListing, McpEnvError, McpServerConfig, PathCandidate, Platform, ResolveOptions, ResolvedPaths, StorageDescriptor, SyncReport, SyncTargetResult, addMcpServer, listMcpServers, masterMcpPath, parseJsonc, readAgentsConfig, readMasterMcpServers, removeMcpServer, syncAgentsFiles, syncMcpServers, version };
|
|
434
448
|
//# sourceMappingURL=agents-sync.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents-sync.d.mts","names":[],"sources":["../../src/types.ts","../../src/harness.ts","../../src/mcp-servers.ts","../../src/agents-sync.ts"],"mappings":"AAEA,cAAa;KAED;
|
|
1
|
+
{"version":3,"file":"agents-sync.d.mts","names":[],"sources":["../../src/types.ts","../../src/harness.ts","../../src/mcp-servers.ts","../../src/agents-sync.ts"],"mappings":"AAEA,cAAa;KAED;KAcA;KACA;UAEK;EACf;EACA;EACA,OAAO;EACP,YAAY;EACZ;;UAGe;EACf;EACA,OAAO;EACP;;UAGe;EACf;EACA;;EAEA;;EAEA;EACA;EACA;;;UAIe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;EACA,OAAO;EACP;;;UAIe;EACf;EACA;EACA;EACA;EACA;EACA;;;UAIe;;EAEf;;EAEA;EACA,OAAO;EACP;;;UAIe;EACf;EACA;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;EACA,MAAM;;EAEN;;EAEA,SAAS;;UAGM;EACf;EACA,MAAM;;EAEN;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;EAET;;UAGe;EACf;EACA;EACA;EACA;;EAEA;EACA;;EAEA;;;UAIe,yBAAyB;;EAExC,QAAQ;;;UAIO;EACf;EACA;EACA;EACA;;;;;;EAMA,MAAM;EACN;EACA,UAAU;;EAEV;;;UAIe,sBAAsB;EACrC;;EAEA;;;;;EAKA;;UAGe;;EAEf;;EAEA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf,QAAQ;EACR,UAAU;EACV,cAAc;EACd,QAAQ;EACR,UAAU;EACV,OAAO;;KC5JJ,oBAAoB;EACvB;EACA;EACA;EACA;;uBA2OoB;oBACF,IAAI;oBACJ;oBACA;oBACA,QAAQ;oBACR,UAAU;oBACV,aAAa;oBACb,cAAc;oBACd,QAAQ;oBACR,UAAU;oBACV,OAAO;oBACP,cAAc;oBACd,WAAW;;oBAEX,YAAY;;WAErB,cAAc;;WAEd,YAAY;;;;;;WAMZ;EAET;EAYA;EAIA,cAAc;MAKV;;;;;;MAsBA,mBAAmB;;;;;;;;;;EAoBvB,gBACE,gBACA,UAAS;IACN;IAAiB;;;;;;;;EAmBtB,gBAAgB,UAAS;;;;;;;;;;EAqBzB,OAAO,gBAAgB,UAAS,gBAAqB,QAAQ;;;;;;;;;UA2BrD;;;;;;;EAgBR,yBAAyB;IAAoB;IAAiB;;;;;;;;;EAmBxD,WAAW,UAAS,oBAAyB,QAAQ;;;;;;YAyBjD,wBAAwB,kBAAkB;;;;;;;;;;EAapD,kBAAkB,UAAU,eAC1B,kBAAkB,KAClB,UAAS,iBACR;EAcH,QAAQ,UAAS,iBAAsB;;KAY7B,+BAA+B;;UCxgB1B;EACf;EACA,OAAO;EACP,QAAQ;EACR,OAAO;EACP;EACA;EACA,SAAS;;EAET;;;cA2JW,oBAAoB;WACb;;;;;;;;;;iBAkOJ,eAAe,SAAS,SAAS,UAAS,iBAAsB;;;;;;;;;;;;iBAiLhE,aACd,SAAS,SACT,QAAQ,iBACR,4BACA,UAAS;EACN;EAAc;;;;;;;;;;;iBA2BH,gBACd,SAAS,SACT,cACA,4BACA,UAAS;EACN;EAAc;;;;;;;;;iBA8FH,WAAW;;;;;;;iBAwBX,cAAc,UAAS;;UAKtB;EACf;EACA;;EAEA;;EAEA;EACA,SAAS;IACP;IACA;;IAEA;;;;UAKa;EACf;EACA;EACA,SAAS;;;;;;;;iBAuEK,qBAAqB,UAAS;EAC5C;EACA,SAAS;;EAET;;;;;;;;;;;iBAmIc,eACd,oBAAoB,WACpB,UAAS,iBACR;;UCn7Bc;;EAEf;;EAEA;;EAEA;;EAEA;;KAGU;;UAGK;WACN;WACA;WACA,QAAQ,QAAQ;;WAEhB;;;UAIM;EACf;EACA;EACA,QAAQ;;EAER;;EAEA,sBAAsB;;;UAIP;EACf;EACA;EACA,SAAS;;;;;;;;iBA2FK,iBAAiB,UAAS,iBAAsB;;;;;;;;;;iBAiMhD,gBACd,oBAAoB,WACpB,iBACA,UAAS,iBACR"}
|
|
@@ -1896,16 +1896,37 @@ const MODEL_HEADERS = [
|
|
|
1896
1896
|
"thinking",
|
|
1897
1897
|
"images"
|
|
1898
1898
|
];
|
|
1899
|
-
function parseTokenCount(value) {
|
|
1899
|
+
function parseTokenCount(value, harness) {
|
|
1900
1900
|
const match = /^(\d+(?:\.\d+)?)([KM])?$/.exec(value);
|
|
1901
|
-
if (!match?.[1]) throw new Error(`Invalid
|
|
1901
|
+
if (!match?.[1]) throw new Error(`Invalid ${harness} token count: ${JSON.stringify(value)}`);
|
|
1902
1902
|
const multiplier = match[2] === "M" ? 1e6 : match[2] === "K" ? 1e3 : 1;
|
|
1903
1903
|
return Number(match[1]) * multiplier;
|
|
1904
1904
|
}
|
|
1905
|
-
function parseBoolean(value, column) {
|
|
1905
|
+
function parseBoolean(value, column, harness) {
|
|
1906
1906
|
if (value === "yes") return true;
|
|
1907
1907
|
if (value === "no") return false;
|
|
1908
|
-
throw new Error(`Invalid
|
|
1908
|
+
throw new Error(`Invalid ${harness} ${column} value: ${JSON.stringify(value)}`);
|
|
1909
|
+
}
|
|
1910
|
+
function parsePiModelTable(stdout, harness) {
|
|
1911
|
+
const lines = stripVTControlCharacters(stdout).split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
1912
|
+
const first = lines[0];
|
|
1913
|
+
if (!first) throw new Error(`Unexpected empty ${harness} model-list output`);
|
|
1914
|
+
if (first.startsWith("No models available.") || first.startsWith("No models matching ")) return [];
|
|
1915
|
+
const headers = first.split(/\s{2,}/);
|
|
1916
|
+
if (headers.length !== MODEL_HEADERS.length || headers.some((value, i) => value !== MODEL_HEADERS[i])) throw new Error(`Unexpected ${harness} model-list header: ${JSON.stringify(first)}`);
|
|
1917
|
+
return lines.slice(1).map((line) => {
|
|
1918
|
+
const columns = line.split(/\s{2,}/);
|
|
1919
|
+
const [provider, id, context, maxOutput, thinking, images] = columns;
|
|
1920
|
+
if (columns.length !== MODEL_HEADERS.length || !provider || !id || !context || !maxOutput || !thinking || !images) throw new Error(`Unexpected ${harness} model-list row: ${JSON.stringify(line)}`);
|
|
1921
|
+
return {
|
|
1922
|
+
provider,
|
|
1923
|
+
id,
|
|
1924
|
+
contextWindow: parseTokenCount(context, harness),
|
|
1925
|
+
maxOutputTokens: parseTokenCount(maxOutput, harness),
|
|
1926
|
+
thinking: parseBoolean(thinking, "thinking", harness),
|
|
1927
|
+
images: parseBoolean(images, "images", harness)
|
|
1928
|
+
};
|
|
1929
|
+
});
|
|
1909
1930
|
}
|
|
1910
1931
|
var Pi = class extends Harness {
|
|
1911
1932
|
id = "pi";
|
|
@@ -2046,25 +2067,172 @@ var Pi = class extends Harness {
|
|
|
2046
2067
|
projectMarkers: [".pi"]
|
|
2047
2068
|
};
|
|
2048
2069
|
parseModelListingOutput(stdout) {
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2070
|
+
return parsePiModelTable(stdout, "Pi");
|
|
2071
|
+
}
|
|
2072
|
+
};
|
|
2073
|
+
var PrimeAgent = class extends Harness {
|
|
2074
|
+
id = "prime-agent";
|
|
2075
|
+
name = "Prime Agent";
|
|
2076
|
+
binaries = ["prime-agent"];
|
|
2077
|
+
capabilities = {
|
|
2078
|
+
mcp: true,
|
|
2079
|
+
vision: true,
|
|
2080
|
+
audio: false,
|
|
2081
|
+
video: false,
|
|
2082
|
+
tools: true,
|
|
2083
|
+
streaming: true
|
|
2084
|
+
};
|
|
2085
|
+
config = [{
|
|
2086
|
+
path: "~/.prime/agent/settings.json",
|
|
2087
|
+
scope: "user",
|
|
2088
|
+
level: "official",
|
|
2089
|
+
note: "Config dir overridable with PRIME_AGENT_CODING_AGENT_DIR."
|
|
2090
|
+
}, {
|
|
2091
|
+
path: ".prime/agent/settings.json",
|
|
2092
|
+
scope: "project",
|
|
2093
|
+
level: "official"
|
|
2094
|
+
}];
|
|
2095
|
+
sessions = [{
|
|
2096
|
+
path: "~/.prime/agent/sessions/<session-id>.jsonl",
|
|
2097
|
+
scope: "data",
|
|
2098
|
+
level: "official",
|
|
2099
|
+
note: "Flat directory of JSONL transcripts whose header records the working directory; session ids are UUIDv7. Overridable with PRIME_AGENT_SESSION_DIR or --session-dir."
|
|
2100
|
+
}, {
|
|
2101
|
+
path: "~/.prime/agent/session-artifacts/<session-id>/",
|
|
2102
|
+
scope: "data",
|
|
2103
|
+
level: "official",
|
|
2104
|
+
note: "Per-session Python kernel state, scheduled jobs, harness state and child session transcripts under sub-<id>/."
|
|
2105
|
+
}];
|
|
2106
|
+
persistence = [
|
|
2107
|
+
{
|
|
2108
|
+
format: "JSON",
|
|
2109
|
+
level: "official",
|
|
2110
|
+
note: "Settings, auth, telemetry, model cache and session artifact state files."
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
format: "JSONL",
|
|
2114
|
+
level: "official",
|
|
2115
|
+
note: "Session transcripts, the RLM spawn ledger and structured logs."
|
|
2116
|
+
},
|
|
2117
|
+
{
|
|
2118
|
+
format: "dill",
|
|
2119
|
+
level: "official",
|
|
2120
|
+
note: "Pickled Python REPL state (kernel-state.dill) in session artifacts."
|
|
2121
|
+
}
|
|
2122
|
+
];
|
|
2123
|
+
instructions = [
|
|
2124
|
+
{
|
|
2125
|
+
path: "AGENTS.md",
|
|
2126
|
+
scope: "project",
|
|
2127
|
+
level: "official",
|
|
2128
|
+
note: "Loaded from parent directories and cwd; CLAUDE.md accepted as an alternative."
|
|
2129
|
+
},
|
|
2130
|
+
{
|
|
2131
|
+
path: ".prime/agent/SYSTEM.md",
|
|
2132
|
+
scope: "project",
|
|
2133
|
+
level: "official",
|
|
2134
|
+
note: "Replaces the default system prompt; APPEND_SYSTEM.md appends instead."
|
|
2135
|
+
},
|
|
2136
|
+
{
|
|
2137
|
+
path: "~/.prime/agent/AGENTS.md",
|
|
2138
|
+
scope: "user",
|
|
2139
|
+
level: "official",
|
|
2140
|
+
note: "Global user-level instructions; CLAUDE.md accepted as an alternative."
|
|
2141
|
+
},
|
|
2142
|
+
{
|
|
2143
|
+
path: "~/.prime/agent/SYSTEM.md",
|
|
2144
|
+
scope: "user",
|
|
2145
|
+
level: "official",
|
|
2146
|
+
note: "Global system prompt replacement; APPEND_SYSTEM.md appends instead."
|
|
2147
|
+
}
|
|
2148
|
+
];
|
|
2149
|
+
skills = [
|
|
2150
|
+
{
|
|
2151
|
+
path: ".prime/agent/skills/",
|
|
2152
|
+
scope: "project",
|
|
2153
|
+
level: "official"
|
|
2154
|
+
},
|
|
2155
|
+
{
|
|
2156
|
+
path: ".agents/skills/",
|
|
2157
|
+
scope: "project",
|
|
2158
|
+
level: "official",
|
|
2159
|
+
note: "Also scanned in ancestor directories up to the Git repository root; root .md files are ignored there."
|
|
2160
|
+
},
|
|
2161
|
+
{
|
|
2162
|
+
path: "~/.prime/agent/skills/",
|
|
2163
|
+
scope: "user",
|
|
2164
|
+
level: "official",
|
|
2165
|
+
note: "Global user-level skills."
|
|
2166
|
+
},
|
|
2167
|
+
{
|
|
2168
|
+
path: "~/.agents/skills/",
|
|
2169
|
+
scope: "user",
|
|
2170
|
+
level: "official",
|
|
2171
|
+
note: "Shared skills directory; root .md files are ignored there."
|
|
2172
|
+
}
|
|
2173
|
+
];
|
|
2174
|
+
commands = [{
|
|
2175
|
+
path: ".prime/agent/prompts/",
|
|
2176
|
+
scope: "project",
|
|
2177
|
+
level: "official",
|
|
2178
|
+
note: "Prompt templates invoked as slash commands."
|
|
2179
|
+
}, {
|
|
2180
|
+
path: "~/.prime/agent/prompts/",
|
|
2181
|
+
scope: "user",
|
|
2182
|
+
level: "official",
|
|
2183
|
+
note: "Global user-level prompt templates."
|
|
2184
|
+
}];
|
|
2185
|
+
hooks = [];
|
|
2186
|
+
invocation = {
|
|
2187
|
+
args: ["-p", "{prompt}"],
|
|
2188
|
+
jsonArgs: [
|
|
2189
|
+
"-p",
|
|
2190
|
+
"--mode",
|
|
2191
|
+
"json",
|
|
2192
|
+
"{prompt}"
|
|
2193
|
+
],
|
|
2194
|
+
noToolsArgs: [
|
|
2195
|
+
"-p",
|
|
2196
|
+
"--no-tools",
|
|
2197
|
+
"{prompt}"
|
|
2198
|
+
],
|
|
2199
|
+
noToolsJsonArgs: [
|
|
2200
|
+
"-p",
|
|
2201
|
+
"--no-tools",
|
|
2202
|
+
"--mode",
|
|
2203
|
+
"json",
|
|
2204
|
+
"{prompt}"
|
|
2205
|
+
],
|
|
2206
|
+
modelArgs: ["--model", "{model}"],
|
|
2207
|
+
level: "official",
|
|
2208
|
+
note: "Add --mode json for structured event output. No read-only mode: the only built-in tool is a Python REPL and the worker and kernel processes are not a security sandbox."
|
|
2209
|
+
};
|
|
2210
|
+
modelListing = {
|
|
2211
|
+
args: ["model", "list"],
|
|
2212
|
+
searchArgs: [
|
|
2213
|
+
"model",
|
|
2214
|
+
"list",
|
|
2215
|
+
"{search}"
|
|
2216
|
+
],
|
|
2217
|
+
level: "official",
|
|
2218
|
+
note: "Lists models with configured provider authentication; accepts an optional fuzzy search. --list-models was removed."
|
|
2219
|
+
};
|
|
2220
|
+
mcpConfigs = [{
|
|
2221
|
+
path: "~/.prime/agent/settings.json",
|
|
2222
|
+
scope: "user",
|
|
2223
|
+
level: "official",
|
|
2224
|
+
format: "json",
|
|
2225
|
+
key: ["mcpServers"],
|
|
2226
|
+
dialect: "prime",
|
|
2227
|
+
note: "prime-agent mcp add/remove manage this map; project settings entries are ignored for execution. Stdio env values are {\"env\": \"NAME\"} references, written from \"${NAME}\" values; literals are refused because the kernel rejects them at connect time."
|
|
2228
|
+
}];
|
|
2229
|
+
agentsFile = "~/.prime/agent/AGENTS.md";
|
|
2230
|
+
detection = {
|
|
2231
|
+
envVars: ["PRIME_AGENT_KERNEL_OWNER_PID"],
|
|
2232
|
+
projectMarkers: [".prime/agent"]
|
|
2233
|
+
};
|
|
2234
|
+
parseModelListingOutput(stdout) {
|
|
2235
|
+
return parsePiModelTable(stdout, "Prime Agent");
|
|
2068
2236
|
}
|
|
2069
2237
|
};
|
|
2070
2238
|
const harnesses = [
|
|
@@ -2079,6 +2247,7 @@ const harnesses = [
|
|
|
2079
2247
|
MastraCode,
|
|
2080
2248
|
Omp,
|
|
2081
2249
|
OpenCode,
|
|
2250
|
+
PrimeAgent,
|
|
2082
2251
|
Pi
|
|
2083
2252
|
];
|
|
2084
2253
|
let registry;
|
|
@@ -2222,9 +2391,30 @@ function normalizeStandard(name, raw) {
|
|
|
2222
2391
|
enabled: booleanField(raw, "enabled")
|
|
2223
2392
|
});
|
|
2224
2393
|
}
|
|
2394
|
+
const ENV_REFERENCE = /^\$\{([A-Za-z_][A-Za-z0-9_]*)\}$/;
|
|
2395
|
+
var McpEnvError = class extends Error {
|
|
2396
|
+
name = "McpEnvError";
|
|
2397
|
+
};
|
|
2398
|
+
function envReference(value) {
|
|
2399
|
+
return ENV_REFERENCE.exec(value)?.[1];
|
|
2400
|
+
}
|
|
2401
|
+
function primeEnv(value) {
|
|
2402
|
+
if (!isObjectRecord(value) || Array.isArray(value)) return void 0;
|
|
2403
|
+
const out = {};
|
|
2404
|
+
for (const [key, raw] of Object.entries(value)) if (typeof raw === "string") out[key] = raw;
|
|
2405
|
+
else if (isObjectRecord(raw) && typeof raw.env === "string") out[key] = `\${${raw.env}}`;
|
|
2406
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2407
|
+
}
|
|
2408
|
+
function normalizePrime(name, raw) {
|
|
2409
|
+
return compact({
|
|
2410
|
+
...normalizeStandard(name, raw),
|
|
2411
|
+
env: primeEnv(raw.env)
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2225
2414
|
function normalizeEntry(name, raw, dialect) {
|
|
2226
2415
|
if (dialect === "antigravity") return normalizeAntigravity(name, raw);
|
|
2227
2416
|
if (dialect === "opencode") return normalizeOpenCode(name, raw);
|
|
2417
|
+
if (dialect === "prime") return normalizePrime(name, raw);
|
|
2228
2418
|
return normalizeStandard(name, raw);
|
|
2229
2419
|
}
|
|
2230
2420
|
function denormalizeAntigravity(server) {
|
|
@@ -2260,9 +2450,44 @@ function denormalizeStandard(server) {
|
|
|
2260
2450
|
enabled: server.enabled
|
|
2261
2451
|
});
|
|
2262
2452
|
}
|
|
2453
|
+
function denormalizePrime(server) {
|
|
2454
|
+
const env = server.env ? Object.fromEntries(Object.entries(server.env).map(([key, value]) => [key, { env: requirePrimeReference(server, key, value) }])) : void 0;
|
|
2455
|
+
return compact({
|
|
2456
|
+
...denormalizeStandard(server),
|
|
2457
|
+
env
|
|
2458
|
+
});
|
|
2459
|
+
}
|
|
2460
|
+
function requirePrimeReference(server, key, value) {
|
|
2461
|
+
const reference = envReference(value);
|
|
2462
|
+
if (reference === void 0) throw new McpEnvError(`${server.name}: Prime Agent takes only environment references in env; write ${key} as "\${NAME}" and export NAME where prime-agent runs`);
|
|
2463
|
+
return reference;
|
|
2464
|
+
}
|
|
2465
|
+
function resolveEnvReferences(server, dialect) {
|
|
2466
|
+
if (!server.env) return server;
|
|
2467
|
+
if (dialect === "prime") {
|
|
2468
|
+
for (const [key, value] of Object.entries(server.env)) requirePrimeReference(server, key, value);
|
|
2469
|
+
return server;
|
|
2470
|
+
}
|
|
2471
|
+
const env = {};
|
|
2472
|
+
for (const [key, value] of Object.entries(server.env)) {
|
|
2473
|
+
const reference = envReference(value);
|
|
2474
|
+
if (reference === void 0) {
|
|
2475
|
+
env[key] = value;
|
|
2476
|
+
continue;
|
|
2477
|
+
}
|
|
2478
|
+
const resolved = Object.hasOwn(process.env, reference) ? process.env[reference] : void 0;
|
|
2479
|
+
if (typeof resolved !== "string") throw new McpEnvError(`${server.name}: env ${key} references ${reference}, which is not set in this environment`);
|
|
2480
|
+
env[key] = resolved;
|
|
2481
|
+
}
|
|
2482
|
+
return {
|
|
2483
|
+
...server,
|
|
2484
|
+
env
|
|
2485
|
+
};
|
|
2486
|
+
}
|
|
2263
2487
|
function denormalizeEntry(server, dialect) {
|
|
2264
2488
|
if (dialect === "antigravity") return denormalizeAntigravity(server);
|
|
2265
2489
|
if (dialect === "opencode") return denormalizeOpenCode(server);
|
|
2490
|
+
if (dialect === "prime") return denormalizePrime(server);
|
|
2266
2491
|
return denormalizeStandard(server);
|
|
2267
2492
|
}
|
|
2268
2493
|
function listingBase(entry, path) {
|
|
@@ -2399,15 +2624,16 @@ function removeTomlServer(path, key, name) {
|
|
|
2399
2624
|
}
|
|
2400
2625
|
function addMcpServer(harness, server, scope = "user", options = {}) {
|
|
2401
2626
|
const { entry, path } = writableConfig(harness, scope, options);
|
|
2627
|
+
const resolved = resolveEnvReferences(server, entry.dialect);
|
|
2402
2628
|
if (entry.format === "toml") return {
|
|
2403
2629
|
path,
|
|
2404
|
-
replaced: addTomlServer(path, entry.key,
|
|
2630
|
+
replaced: addTomlServer(path, entry.key, resolved)
|
|
2405
2631
|
};
|
|
2406
2632
|
const root = JSON.parse(readIfExists$1(path) ?? "{}");
|
|
2407
2633
|
const map = drill(root, entry.key, "create");
|
|
2408
2634
|
if (!map) throw new Error(`Config at ${path} has a non-object at ${entry.key.join(".")}`);
|
|
2409
2635
|
const replaced = Object.hasOwn(map, server.name);
|
|
2410
|
-
map[server.name] = denormalizeEntry(
|
|
2636
|
+
map[server.name] = denormalizeEntry(resolved, entry.dialect);
|
|
2411
2637
|
writeAtomically(path, `${JSON.stringify(root, null, 2)}\n`);
|
|
2412
2638
|
return {
|
|
2413
2639
|
path,
|
|
@@ -2616,20 +2842,29 @@ function withdrawMasterServersFromExcludedHarness(harness, existing, masterNames
|
|
|
2616
2842
|
function syncIncludedHarness(harness, master, existing, masterNames, initialPath, options) {
|
|
2617
2843
|
const results = [];
|
|
2618
2844
|
let path = initialPath;
|
|
2619
|
-
|
|
2620
|
-
|
|
2845
|
+
const { dialect } = writableConfig(harness, "user", options).entry;
|
|
2846
|
+
for (const server of master.servers) try {
|
|
2847
|
+
const resolved = resolveEnvReferences(server, dialect);
|
|
2848
|
+
if (existing.get(server.name) === canonical(resolved)) {
|
|
2621
2849
|
results.push({
|
|
2622
2850
|
name: server.name,
|
|
2623
2851
|
action: "unchanged"
|
|
2624
2852
|
});
|
|
2625
2853
|
continue;
|
|
2626
2854
|
}
|
|
2627
|
-
const written = addMcpServer(harness,
|
|
2855
|
+
const written = addMcpServer(harness, resolved, "user", options);
|
|
2628
2856
|
path = written.path;
|
|
2629
2857
|
results.push({
|
|
2630
2858
|
name: server.name,
|
|
2631
2859
|
action: written.replaced ? "replaced" : "added"
|
|
2632
2860
|
});
|
|
2861
|
+
} catch (error) {
|
|
2862
|
+
if (!(error instanceof McpEnvError)) throw error;
|
|
2863
|
+
results.push({
|
|
2864
|
+
name: server.name,
|
|
2865
|
+
action: "skipped",
|
|
2866
|
+
reason: error.message
|
|
2867
|
+
});
|
|
2633
2868
|
}
|
|
2634
2869
|
for (const name of existing.keys()) {
|
|
2635
2870
|
if (masterNames.has(name)) continue;
|
|
@@ -2858,6 +3093,6 @@ function syncAgentsFiles(harnesses, check = false, options = {}) {
|
|
|
2858
3093
|
targets: harnesses.map((harness) => syncTarget(harness, config, check, options))
|
|
2859
3094
|
};
|
|
2860
3095
|
}
|
|
2861
|
-
export { Harness, addMcpServer, detectHarness, detectHarnessFromEnv, detectProjectHarnesses, getAllHarnesses, getHarness, isHarnessId, listHarnesses, listMcpServers, masterMcpPath, parseJsonc, readAgentsConfig, readMasterMcpServers, registerHarness, removeMcpServer, resolvePathTemplate, syncAgentsFiles, syncMcpServers };
|
|
3096
|
+
export { Harness, McpEnvError, addMcpServer, detectHarness, detectHarnessFromEnv, detectProjectHarnesses, getAllHarnesses, getHarness, isHarnessId, listHarnesses, listMcpServers, masterMcpPath, parseJsonc, readAgentsConfig, readMasterMcpServers, registerHarness, removeMcpServer, resolvePathTemplate, syncAgentsFiles, syncMcpServers };
|
|
2862
3097
|
|
|
2863
3098
|
//# sourceMappingURL=agents-sync.mjs.map
|