@agntn/harnesses 0.0.1 → 0.1.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.
@@ -46,10 +46,11 @@ const tools = [
46
46
  description: "List the models currently available to one AI coding harness through its native CLI, normalized across providers. An optional search filter is passed to harnesses that support it. The command may load project configuration and extensions.",
47
47
  inputSchema: schemas.models,
48
48
  annotations: EXEC_READ,
49
- execute: (args) => listHarnessModels(args.id, {
49
+ execute: (args, signal) => listHarnessModels(args.id, {
50
50
  search: args.search,
51
51
  cwd: args.cwd,
52
- timeoutSeconds: args.timeoutSeconds
52
+ timeoutSeconds: args.timeoutSeconds,
53
+ signal
53
54
  })
54
55
  },
55
56
  {
@@ -63,10 +64,11 @@ const tools = [
63
64
  idempotentHint: false,
64
65
  openWorldHint: true
65
66
  },
66
- execute: (args) => runHarness(args.id, args.prompt, {
67
+ execute: (args, signal) => runHarness(args.id, args.prompt, {
67
68
  cwd: args.cwd,
68
69
  model: args.model,
69
70
  timeoutSeconds: args.timeoutSeconds,
71
+ signal,
70
72
  structured: args.structured,
71
73
  tools: args.tools,
72
74
  readOnly: args.readOnly
@@ -146,13 +148,13 @@ function createMcpServer() {
146
148
  inputSchema: tool.inputSchema,
147
149
  annotations: tool.annotations
148
150
  })) }));
149
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
151
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
150
152
  const tool = toolsByName.get(request.params.name);
151
153
  if (!tool) return errorResult(`Unknown harnesses tool: ${JSON.stringify(request.params.name)}`);
152
154
  const args = request.params.arguments ?? {};
153
155
  if (!Check(tool.inputSchema, args)) return errorResult(validationError(tool.inputSchema, args));
154
156
  try {
155
- return toCallToolResult(await tool.execute(args));
157
+ return toCallToolResult(await tool.execute(args, extra.signal));
156
158
  } catch (error) {
157
159
  return errorResult(`${tool.name} failed: ${error instanceof Error ? error.message : String(error)}`);
158
160
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.mjs","names":["Type","Value.Errors","Value.Check"],"sources":["../../src/mcp.ts"],"sourcesContent":["import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n type CallToolResult,\n type Tool,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { Type, type TSchema } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport {\n detectHarnesses,\n harnessInfo,\n listHarnessModels,\n mcpAdd,\n mcpList,\n mcpRemove,\n mcpSync,\n agentsSync,\n runHarness,\n type McpServerParams,\n type ToolResult,\n} from \"./tool-operations.ts\";\nimport { harnessToolSchemas } from \"./tool-schemas.ts\";\nimport { version } from \"./types.ts\";\n\ninterface ToolDefinition {\n name: string;\n title: string;\n description: string;\n inputSchema: TSchema;\n annotations: Tool[\"annotations\"];\n execute(\n args: Readonly<Record<string, unknown>>,\n ): ToolResult<unknown> | Promise<ToolResult<unknown>>;\n}\n\nconst READ_ONLY: Tool[\"annotations\"] = {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n};\n\nconst EXEC_READ: Tool[\"annotations\"] = {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n};\n\nconst CONFIG_WRITE: Tool[\"annotations\"] = {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: false,\n};\n\nconst schemas = harnessToolSchemas<TSchema, TSchema>(Type);\n\nconst tools: ToolDefinition[] = [\n {\n name: \"harnesses_detect\",\n title: \"Harnesses Detect\",\n description:\n \"List every known AI coding harness with its install state and version, scanned from the binaries on PATH.\",\n inputSchema: schemas.detect,\n annotations: READ_ONLY,\n execute: () => detectHarnesses(),\n },\n {\n name: \"harnesses_info\",\n title: \"Harnesses Info\",\n description:\n \"Full metadata for one or more AI coding harnesses, including supported invocation and model operations, configuration, sessions, instructions, skills, commands, hooks, and resolved paths.\",\n inputSchema: schemas.info,\n annotations: READ_ONLY,\n execute: (args) => harnessInfo(args.id as string | string[]),\n },\n {\n name: \"harnesses_models\",\n title: \"Harnesses Models\",\n description:\n \"List the models currently available to one AI coding harness through its native CLI, normalized across providers. An optional search filter is passed to harnesses that support it. The command may load project configuration and extensions.\",\n inputSchema: schemas.models,\n annotations: EXEC_READ,\n execute: (args) =>\n listHarnessModels(args.id as string, {\n search: args.search as string | undefined,\n cwd: args.cwd as string | undefined,\n timeoutSeconds: args.timeoutSeconds as number | undefined,\n }),\n },\n {\n name: \"harnesses_run\",\n title: \"Harnesses Run\",\n description:\n \"Run one prompt through an AI coding harness's normalized non-interactive invocation and return its output. Pass tools=true whenever the task needs harness tools, including Grok native X search. Add readOnly=true to require native read-only tool enforcement. Pass tools=false only for an advisor without tools. Unsupported modes never widen access.\",\n inputSchema: schemas.run,\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: true,\n },\n execute: (args) =>\n runHarness(args.id as string, args.prompt as string, {\n cwd: args.cwd as string | undefined,\n model: args.model as string | undefined,\n timeoutSeconds: args.timeoutSeconds as number | undefined,\n structured: args.structured as boolean | undefined,\n tools: args.tools as boolean | undefined,\n readOnly: args.readOnly as boolean | undefined,\n }),\n },\n {\n name: \"harnesses_mcp_list\",\n title: \"Harnesses MCP List\",\n description:\n \"List the MCP servers configured in each harness's config files, normalized across dialects. Omit id to scan every harness.\",\n inputSchema: schemas.mcpList,\n annotations: READ_ONLY,\n execute: (args) => mcpList(args.id as string | undefined),\n },\n {\n name: \"harnesses_mcp_add\",\n title: \"Harnesses MCP Add\",\n description:\n \"Add or replace one MCP server in a harness config. JSON configs are rewritten; TOML configs get a surgical, comment-preserving edit.\",\n inputSchema: schemas.mcpAdd,\n annotations: CONFIG_WRITE,\n execute: (args) =>\n mcpAdd(\n args.id as string,\n args as unknown as McpServerParams,\n (args.scope as \"user\" | \"project\") ?? \"user\",\n ),\n },\n {\n name: \"harnesses_mcp_sync\",\n title: \"Harnesses MCP Sync\",\n description:\n \"Reset every harness's user-scope MCP config to exactly the master list from ~/.config/agntn/mcp.jsonc: servers are added, replaced, and extras removed. Excluded harnesses keep their own servers, but master-listed names are withdrawn from them.\",\n inputSchema: schemas.mcpSync,\n annotations: CONFIG_WRITE,\n execute: (args) => mcpSync(args.id as string | undefined),\n },\n {\n name: \"harnesses_agents_sync\",\n title: \"Harnesses Agents Sync\",\n description:\n \"Link every harness's global instructions file and declared companions to the master bundle, so edits made through any harness land in one place. Diverged copies are backed up and relinked. Pass check to only report.\",\n inputSchema: schemas.agentsSync,\n annotations: CONFIG_WRITE,\n execute: (args) => agentsSync(args.id as string | undefined, args.check === true),\n },\n {\n name: \"harnesses_mcp_remove\",\n title: \"Harnesses MCP Remove\",\n description:\n \"Remove one MCP server from a harness config. JSON configs are rewritten; TOML configs get a surgical, comment-preserving edit.\",\n inputSchema: schemas.mcpRemove,\n annotations: CONFIG_WRITE,\n execute: (args) =>\n mcpRemove(\n args.id as string,\n args.name as string,\n (args.scope as \"user\" | \"project\") ?? \"user\",\n ),\n },\n];\n\n/**\n * Formats the first TypeBox validation failure for an MCP client.\n *\n * @param schema - Schema that rejected the value.\n * @param value - Rejected input value.\n * @returns {string} A client-facing validation message.\n */\nfunction validationError(schema: TSchema, value: unknown): string {\n const first = Value.Errors(schema, value)[0];\n if (!first) return \"Invalid arguments\";\n return `Invalid arguments at ${first.instancePath || \"/\"}: ${first.message}`;\n}\n\n/**\n * Wraps error text for the MCP client, replacing control bytes with spaces.\n *\n * Every error branch goes through here because parts of these messages echo\n * client-controlled values (a tool name, an argument) or downstream error\n * messages: one raw newline or escape byte would forge extra lines that read\n * as the server's own answer.\n *\n * @param text - Untrusted error text.\n * @returns {CallToolResult} A sanitized MCP error result.\n */\nfunction errorResult(text: string): CallToolResult {\n return {\n content: [{ type: \"text\", text: text.replaceAll(/\\p{Cc}/gu, \" \") }],\n isError: true,\n };\n}\n\n/**\n * Converts a shared tool result to the MCP text-result contract.\n *\n * `details` is dropped and `structuredContent` is never set: clients that see\n * structured output prefer it over `content` and would hide the readable answer.\n *\n * @param result - Shared tool result to adapt.\n * @returns {CallToolResult} The MCP text-result envelope.\n */\nfunction toCallToolResult(result: ToolResult<unknown>): CallToolResult {\n return {\n content: result.content,\n ...(result.isError === undefined ? {} : { isError: result.isError }),\n };\n}\n\n/**\n * Creates an unconnected MCP server exposing the harness registry tools.\n *\n * Built on the low-level `Server` even though the SDK marks it `@deprecated`,\n * because `McpServer.registerTool` accepts Standard Schema (Zod) only. TypeBox 1.x\n * does not implement Standard Schema, and this package's tool schemas are TypeBox,\n * shared with the Pi and OMP extensions. The high-level API would force a second\n * definition of every parameter.\n *\n * @returns {Server} An unconnected MCP server.\n */\nexport function createMcpServer(): Server {\n const toolsByName = new Map(tools.map((tool) => [tool.name, tool]));\n const server = new Server({ name: \"harnesses\", version }, { capabilities: { tools: {} } });\n\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: tools.map((tool): Tool => ({\n name: tool.name,\n title: tool.title,\n description: tool.description,\n inputSchema: tool.inputSchema as Tool[\"inputSchema\"],\n annotations: tool.annotations,\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = toolsByName.get(request.params.name);\n if (!tool) {\n return errorResult(`Unknown harnesses tool: ${JSON.stringify(request.params.name)}`);\n }\n\n const args = request.params.arguments ?? {};\n if (!Value.Check(tool.inputSchema, args)) {\n return errorResult(validationError(tool.inputSchema, args));\n }\n\n try {\n return toCallToolResult(await tool.execute(args));\n } catch (error) {\n return errorResult(\n `${tool.name} failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n });\n\n return server;\n}\n"],"mappings":";;;;;;AAoCA,MAAM,YAAiC;CACrC,cAAc;CACd,iBAAiB;CACjB,gBAAgB;CAChB,eAAe;AACjB;AAEA,MAAM,YAAiC;CACrC,cAAc;CACd,iBAAiB;CACjB,gBAAgB;CAChB,eAAe;AACjB;AAEA,MAAM,eAAoC;CACxC,cAAc;CACd,iBAAiB;CACjB,gBAAgB;CAChB,eAAe;AACjB;AAEA,MAAM,UAAU,mBAAqCA,eAAI;AAEzD,MAAM,QAA0B;CAC9B;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;EACb,eAAe,gBAAgB;CACjC;CACA;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;EACb,UAAU,SAAS,YAAY,KAAK,EAAuB;CAC7D;CACA;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;EACb,UAAU,SACR,kBAAkB,KAAK,IAAc;GACnC,QAAQ,KAAK;GACb,KAAK,KAAK;GACV,gBAAgB,KAAK;EACvB,CAAC;CACL;CACA;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;GACX,cAAc;GACd,iBAAiB;GACjB,gBAAgB;GAChB,eAAe;EACjB;EACA,UAAU,SACR,WAAW,KAAK,IAAc,KAAK,QAAkB;GACnD,KAAK,KAAK;GACV,OAAO,KAAK;GACZ,gBAAgB,KAAK;GACrB,YAAY,KAAK;GACjB,OAAO,KAAK;GACZ,UAAU,KAAK;EACjB,CAAC;CACL;CACA;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;EACb,UAAU,SAAS,QAAQ,KAAK,EAAwB;CAC1D;CACA;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;EACb,UAAU,SACR,OACE,KAAK,IACL,MACC,KAAK,SAAgC,MACxC;CACJ;CACA;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;EACb,UAAU,SAAS,QAAQ,KAAK,EAAwB;CAC1D;CACA;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;EACb,UAAU,SAAS,WAAW,KAAK,IAA0B,KAAK,UAAU,IAAI;CAClF;CACA;EACE,MAAM;EACN,OAAO;EACP,aACE;EACF,aAAa,QAAQ;EACrB,aAAa;EACb,UAAU,SACR,UACE,KAAK,IACL,KAAK,MACJ,KAAK,SAAgC,MACxC;CACJ;AACF;;;;;;AASA,SAAS,YAAA,MAAgB;CACvB,OAAM;EACN,SAAK,CAAA;GACL,MAAO;GACT,MAAA,KAAA,WAAA,YAAA,GAAA;;;;;;;;;;;AAcE,SAAO,kBAAA;CACL,MAAA,cAAU,IAAA,IAAA,MAAA,KAAA,SAAA,CAAA,KAAA,MAAA,IAAA,CAAA,CAAA;CAAE,MAAA,SAAM,IAAA,OAAA;EAAQ,MAAA;EAAuC;CACjE,GAAA,EAAA,cAAS,EAAA,OAAA,CAAA,EAAA,EAAA,CAAA;CACX,OAAA,kBAAA,+BAAA,EAAA,OAAA,MAAA,KAAA,UAAA;EACF,MAAA,KAAA;;;;;;;;;;EAWA,IAAA,CAAA,MAAS,KAAA,aAAiB,IAA6C,GAAA,OAAA,YAAA,gBAAA,KAAA,aAAA,IAAA,CAAA;EACrE,IAAA;GACE,OAAA,iBAAgB,MAAA,KAAA,QAAA,IAAA,CAAA;EAChB,SAAI,OAAO;GACb,OAAA,YAAA,GAAA,KAAA,KAAA,WAAA,iBAAA,QAAA,MAAA,UAAA,OAAA,KAAA,GAAA;EACF"}
1
+ {"version":3,"file":"mcp.mjs","names":["Type","Value.Errors","Value.Check"],"sources":["../../src/mcp.ts"],"sourcesContent":["import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n type CallToolResult,\n type Tool,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { Type, type TSchema } from \"typebox\";\nimport { Value } from \"typebox/value\";\nimport {\n detectHarnesses,\n harnessInfo,\n listHarnessModels,\n mcpAdd,\n mcpList,\n mcpRemove,\n mcpSync,\n agentsSync,\n runHarness,\n type McpServerParams,\n type ToolResult,\n} from \"./tool-operations.ts\";\nimport { harnessToolSchemas } from \"./tool-schemas.ts\";\nimport { version } from \"./types.ts\";\n\ninterface ToolDefinition {\n name: string;\n title: string;\n description: string;\n inputSchema: TSchema;\n annotations: Tool[\"annotations\"];\n execute(\n args: Readonly<Record<string, unknown>>,\n signal: AbortSignal,\n ): ToolResult<unknown> | Promise<ToolResult<unknown>>;\n}\n\nconst READ_ONLY: Tool[\"annotations\"] = {\n readOnlyHint: true,\n destructiveHint: false,\n idempotentHint: true,\n openWorldHint: false,\n};\n\nconst EXEC_READ: Tool[\"annotations\"] = {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: true,\n};\n\nconst CONFIG_WRITE: Tool[\"annotations\"] = {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: false,\n};\n\nconst schemas = harnessToolSchemas<TSchema, TSchema>(Type);\n\nconst tools: ToolDefinition[] = [\n {\n name: \"harnesses_detect\",\n title: \"Harnesses Detect\",\n description:\n \"List every known AI coding harness with its install state and version, scanned from the binaries on PATH.\",\n inputSchema: schemas.detect,\n annotations: READ_ONLY,\n execute: () => detectHarnesses(),\n },\n {\n name: \"harnesses_info\",\n title: \"Harnesses Info\",\n description:\n \"Full metadata for one or more AI coding harnesses, including supported invocation and model operations, configuration, sessions, instructions, skills, commands, hooks, and resolved paths.\",\n inputSchema: schemas.info,\n annotations: READ_ONLY,\n execute: (args) => harnessInfo(args.id as string | string[]),\n },\n {\n name: \"harnesses_models\",\n title: \"Harnesses Models\",\n description:\n \"List the models currently available to one AI coding harness through its native CLI, normalized across providers. An optional search filter is passed to harnesses that support it. The command may load project configuration and extensions.\",\n inputSchema: schemas.models,\n annotations: EXEC_READ,\n execute: (args, signal) =>\n listHarnessModels(args.id as string, {\n search: args.search as string | undefined,\n cwd: args.cwd as string | undefined,\n timeoutSeconds: args.timeoutSeconds as number | undefined,\n signal,\n }),\n },\n {\n name: \"harnesses_run\",\n title: \"Harnesses Run\",\n description:\n \"Run one prompt through an AI coding harness's normalized non-interactive invocation and return its output. Pass tools=true whenever the task needs harness tools, including Grok native X search. Add readOnly=true to require native read-only tool enforcement. Pass tools=false only for an advisor without tools. Unsupported modes never widen access.\",\n inputSchema: schemas.run,\n annotations: {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: true,\n },\n execute: (args, signal) =>\n runHarness(args.id as string, args.prompt as string, {\n cwd: args.cwd as string | undefined,\n model: args.model as string | undefined,\n timeoutSeconds: args.timeoutSeconds as number | undefined,\n signal,\n structured: args.structured as boolean | undefined,\n tools: args.tools as boolean | undefined,\n readOnly: args.readOnly as boolean | undefined,\n }),\n },\n {\n name: \"harnesses_mcp_list\",\n title: \"Harnesses MCP List\",\n description:\n \"List the MCP servers configured in each harness's config files, normalized across dialects. Omit id to scan every harness.\",\n inputSchema: schemas.mcpList,\n annotations: READ_ONLY,\n execute: (args) => mcpList(args.id as string | undefined),\n },\n {\n name: \"harnesses_mcp_add\",\n title: \"Harnesses MCP Add\",\n description:\n \"Add or replace one MCP server in a harness config. JSON configs are rewritten; TOML configs get a surgical, comment-preserving edit.\",\n inputSchema: schemas.mcpAdd,\n annotations: CONFIG_WRITE,\n execute: (args) =>\n mcpAdd(\n args.id as string,\n args as unknown as McpServerParams,\n (args.scope as \"user\" | \"project\") ?? \"user\",\n ),\n },\n {\n name: \"harnesses_mcp_sync\",\n title: \"Harnesses MCP Sync\",\n description:\n \"Reset every harness's user-scope MCP config to exactly the master list from ~/.config/agntn/mcp.jsonc: servers are added, replaced, and extras removed. Excluded harnesses keep their own servers, but master-listed names are withdrawn from them.\",\n inputSchema: schemas.mcpSync,\n annotations: CONFIG_WRITE,\n execute: (args) => mcpSync(args.id as string | undefined),\n },\n {\n name: \"harnesses_agents_sync\",\n title: \"Harnesses Agents Sync\",\n description:\n \"Link every harness's global instructions file and declared companions to the master bundle, so edits made through any harness land in one place. Diverged copies are backed up and relinked. Pass check to only report.\",\n inputSchema: schemas.agentsSync,\n annotations: CONFIG_WRITE,\n execute: (args) => agentsSync(args.id as string | undefined, args.check === true),\n },\n {\n name: \"harnesses_mcp_remove\",\n title: \"Harnesses MCP Remove\",\n description:\n \"Remove one MCP server from a harness config. JSON configs are rewritten; TOML configs get a surgical, comment-preserving edit.\",\n inputSchema: schemas.mcpRemove,\n annotations: CONFIG_WRITE,\n execute: (args) =>\n mcpRemove(\n args.id as string,\n args.name as string,\n (args.scope as \"user\" | \"project\") ?? \"user\",\n ),\n },\n];\n\n/**\n * Formats the first TypeBox validation failure for an MCP client.\n *\n * @param schema - Schema that rejected the value.\n * @param value - Rejected input value.\n * @returns {string} A client-facing validation message.\n */\nfunction validationError(schema: TSchema, value: unknown): string {\n const first = Value.Errors(schema, value)[0];\n if (!first) return \"Invalid arguments\";\n return `Invalid arguments at ${first.instancePath || \"/\"}: ${first.message}`;\n}\n\n/**\n * Wraps error text for the MCP client, replacing control bytes with spaces.\n *\n * Every error branch goes through here because parts of these messages echo\n * client-controlled values (a tool name, an argument) or downstream error\n * messages: one raw newline or escape byte would forge extra lines that read\n * as the server's own answer.\n *\n * @param text - Untrusted error text.\n * @returns {CallToolResult} A sanitized MCP error result.\n */\nfunction errorResult(text: string): CallToolResult {\n return {\n content: [{ type: \"text\", text: text.replaceAll(/\\p{Cc}/gu, \" \") }],\n isError: true,\n };\n}\n\n/**\n * Converts a shared tool result to the MCP text-result contract.\n *\n * `details` is dropped and `structuredContent` is never set: clients that see\n * structured output prefer it over `content` and would hide the readable answer.\n *\n * @param result - Shared tool result to adapt.\n * @returns {CallToolResult} The MCP text-result envelope.\n */\nfunction toCallToolResult(result: ToolResult<unknown>): CallToolResult {\n return {\n content: result.content,\n ...(result.isError === undefined ? {} : { isError: result.isError }),\n };\n}\n\n/**\n * Creates an unconnected MCP server exposing the harness registry tools.\n *\n * Built on the low-level `Server` even though the SDK marks it `@deprecated`,\n * because `McpServer.registerTool` accepts Standard Schema (Zod) only. TypeBox 1.x\n * does not implement Standard Schema, and this package's tool schemas are TypeBox,\n * shared with the Pi and OMP extensions. The high-level API would force a second\n * definition of every parameter.\n *\n * @returns {Server} An unconnected MCP server.\n */\nexport function createMcpServer(): Server {\n const toolsByName = new Map(tools.map((tool) => [tool.name, tool]));\n const server = new Server({ name: \"harnesses\", version }, { capabilities: { tools: {} } });\n\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: tools.map((tool): Tool => ({\n name: tool.name,\n title: tool.title,\n description: tool.description,\n inputSchema: tool.inputSchema as Tool[\"inputSchema\"],\n annotations: tool.annotations,\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {\n const tool = toolsByName.get(request.params.name);\n if (!tool) {\n return errorResult(`Unknown harnesses tool: ${JSON.stringify(request.params.name)}`);\n }\n\n const args = request.params.arguments ?? {};\n if (!Value.Check(tool.inputSchema, args)) {\n return errorResult(validationError(tool.inputSchema, args));\n }\n\n try {\n return toCallToolResult(await tool.execute(args, extra.signal));\n } catch (error) {\n return errorResult(\n `${tool.name} failed: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n });\n\n return server;\n}\n"],"mappings":"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"}
@@ -41,8 +41,21 @@ function selectedInvocationMode(structured, tools, readOnly) {
41
41
  if (tools) return structured ? "agentStructured" : "agent";
42
42
  return structured ? "advisorStructured" : "advisor";
43
43
  }
44
+ function invocationRetry(invocationModes, mode, options) {
45
+ const withoutStructured = selectedInvocationMode(false, options.tools, options.readOnly);
46
+ if (options.structured) {
47
+ if (invocationModes[withoutStructured]) return { structured: false };
48
+ const alternateWithoutStructured = ALTERNATE_INVOCATION_MODE[withoutStructured];
49
+ if (alternateWithoutStructured && invocationModes[alternateWithoutStructured]) return {
50
+ structured: false,
51
+ tools: !options.tools
52
+ };
53
+ }
54
+ const alternateMode = ALTERNATE_INVOCATION_MODE[mode];
55
+ return alternateMode !== void 0 && invocationModes[alternateMode] ? { tools: !options.tools } : void 0;
56
+ }
44
57
  function completedRun(harness, result, options) {
45
- const details = {
58
+ const contentOutcome = {
46
59
  id: harness.id,
47
60
  command: result.command,
48
61
  args: result.args,
@@ -52,7 +65,11 @@ function completedRun(harness, result, options) {
52
65
  readOnly: options.readOnly,
53
66
  exitCode: result.exitCode,
54
67
  timedOut: result.timedOut,
55
- stdout: truncate(result.stdout),
68
+ aborted: result.aborted,
69
+ stdout: truncate(result.stdout)
70
+ };
71
+ const details = {
72
+ ...contentOutcome,
56
73
  stderr: truncate(result.stderr)
57
74
  };
58
75
  if (result.timedOut || result.exitCode !== 0) return {
@@ -61,7 +78,7 @@ function completedRun(harness, result, options) {
61
78
  isError: true
62
79
  };
63
80
  return {
64
- content: text(details),
81
+ content: text(result.stdout.length > 0 ? contentOutcome : details),
65
82
  details
66
83
  };
67
84
  }
@@ -78,11 +95,11 @@ function unsupportedInvocation(harness, id, options) {
78
95
  isError: true
79
96
  };
80
97
  }
81
- const alternateMode = ALTERNATE_INVOCATION_MODE[mode];
98
+ const retry = invocationRetry(invocationModes, mode, options);
82
99
  const details = {
83
100
  error,
84
101
  invocationModes,
85
- ...(alternateMode === void 0 ? false : invocationModes[alternateMode]) ? { retry: { tools: !options.tools } } : {}
102
+ ...retry === void 0 ? {} : { retry }
86
103
  };
87
104
  return {
88
105
  content: text(details),
@@ -168,7 +185,8 @@ async function listHarnessModels(id, options = {}) {
168
185
  result = await harness.listModels({
169
186
  search: options.search,
170
187
  cwd: options.cwd,
171
- timeoutMs: timeoutSeconds * 1e3
188
+ timeoutMs: timeoutSeconds * 1e3,
189
+ signal: options.signal
172
190
  });
173
191
  } catch (error) {
174
192
  const details = { error: `Failed to list ${id} models: ${errorMessage(error)}` };
@@ -186,6 +204,7 @@ async function listHarnessModels(id, options = {}) {
186
204
  models: result.models,
187
205
  exitCode: result.exitCode,
188
206
  timedOut: result.timedOut,
207
+ aborted: result.aborted,
189
208
  stderr: truncate(result.stderr)
190
209
  };
191
210
  return {
@@ -220,6 +239,7 @@ async function runHarness(id, prompt, options = {}) {
220
239
  cwd: options.cwd,
221
240
  model: options.model,
222
241
  timeoutMs: timeoutSeconds * 1e3,
242
+ signal: options.signal,
223
243
  structured,
224
244
  tools,
225
245
  readOnly
@@ -234,6 +254,11 @@ async function runHarness(id, prompt, options = {}) {
234
254
  }
235
255
  return completedRun(harness, result, invocationOptions);
236
256
  }
257
+ const MCP_REDACTED_VALUE = "<redacted>";
258
+ const MCP_CONFIG_ERROR = "Unable to read or parse MCP config";
259
+ function redactMcpValues(values) {
260
+ return Object.fromEntries(Object.keys(values).map((key) => [key, MCP_REDACTED_VALUE]));
261
+ }
237
262
  function toMcpServerConfig(params) {
238
263
  const server = {
239
264
  name: params.name,
@@ -250,7 +275,15 @@ function mcpList(id) {
250
275
  if (id !== void 0 && !isHarnessId(id)) return unknownHarness(id);
251
276
  const details = { harnesses: (id !== void 0 && isHarnessId(id) ? [getHarness(id)] : getAllHarnesses()).map((harness) => ({
252
277
  id: harness.id,
253
- configs: listMcpServers(harness)
278
+ configs: listMcpServers(harness).map((listing) => ({
279
+ ...listing,
280
+ ...listing.error === void 0 ? {} : { error: MCP_CONFIG_ERROR },
281
+ servers: listing.servers.map((server) => ({
282
+ ...server,
283
+ ...server.env === void 0 ? {} : { env: redactMcpValues(server.env) },
284
+ ...server.headers === void 0 ? {} : { headers: redactMcpValues(server.headers) }
285
+ }))
286
+ }))
254
287
  })).filter((entry) => entry.configs.length > 0) };
255
288
  return {
256
289
  content: text(details),
@@ -1 +1 @@
1
- {"version":3,"file":"tool-operations.mjs","names":["toToon"],"sources":["../../src/tool-operations.ts"],"sourcesContent":["/**\n * Tool executors behind the agent extensions.\n *\n * Each executor returns the text a caller reads plus the structured details a\n * harness can attach to the call. The text is TOON-encoded so the model sees\n * the same compact shape the CLI's --toon flag prints.\n */\nimport { encode as toToon } from \"@toon-format/toon\";\nimport { getAllHarnesses, getHarness, isHarnessId, listHarnesses } from \"./registry.ts\";\nimport {\n addMcpServer,\n listMcpServers,\n readMasterMcpServers,\n removeMcpServer,\n syncMcpServers,\n} from \"./mcp-servers.ts\";\nimport type { McpConfigListing, SyncReport } from \"./mcp-servers.ts\";\nimport { readAgentsConfig, syncAgentsFiles } from \"./agents-sync.ts\";\nimport type { AgentsSyncReport } from \"./agents-sync.ts\";\nexport type { AgentsSyncReport } from \"./agents-sync.ts\";\nexport type { SyncReport } from \"./mcp-servers.ts\";\nexport type { HarnessInvocationModes } from \"./types.ts\";\nimport type { Harness } from \"./harness.ts\";\nimport type {\n AvailableModel,\n HarnessCapabilities,\n HarnessDetection,\n HarnessId,\n HarnessInvocationModes,\n InvokeResult,\n ListModelsResult,\n McpServerConfig,\n PathCandidate,\n ResolvedPaths,\n StorageDescriptor,\n} from \"./types.ts\";\n\n/** Text for the model plus details for the harness, shared by every tool surface. */\nexport interface ToolResult<Details> {\n content: Array<{ type: \"text\"; text: string }>;\n details: Details;\n /** Set when the tool could not answer. */\n isError?: boolean;\n}\n\n/** Install state of one harness on this machine. */\nexport interface HarnessStatus {\n id: HarnessId;\n name: string;\n installed: boolean;\n version: string | null;\n}\n\n/** Every registered harness with its install state, as scanned by {@link detectHarnesses}. */\nexport interface HarnessListing {\n harnesses: HarnessStatus[];\n}\n\n/** Full metadata for one harness, including paths resolved for this platform. */\nexport interface HarnessMetadata {\n id: HarnessId;\n name: string;\n binaries: string[];\n capabilities: HarnessCapabilities;\n invocationModes: HarnessInvocationModes;\n modelListing: boolean;\n modelSelection: boolean;\n config: PathCandidate[];\n sessions: PathCandidate[];\n instructions: PathCandidate[];\n skills: PathCandidate[];\n commands: PathCandidate[];\n hooks: PathCandidate[];\n persistence: StorageDescriptor[];\n detection: HarnessDetection;\n resolved: ResolvedPaths;\n}\n\n/** Returned when the requested harness id is not registered. */\nexport interface UnknownHarness {\n error: string;\n known: HarnessId[];\n}\n\n/** Returned when a direct batch call bypasses the tool schema limits. */\nexport interface HarnessInfoInputError {\n error: string;\n}\n\n/** One harness lookup result. */\nexport type HarnessInfoResult = HarnessMetadata | UnknownHarness;\n\n/** Scalar, batch, or rejected batch details from {@link harnessInfo}. */\nexport type HarnessInfoDetails = HarnessInfoResult | HarnessInfoResult[] | HarnessInfoInputError;\n\nimport { HARNESS_INFO_MAX_ITEMS, RUN_TIMEOUT_DEFAULT_SECONDS } from \"./tool-schemas.ts\";\nexport { HARNESS_INFO_MAX_ITEMS } from \"./tool-schemas.ts\";\n\n/** Default wall-clock budget for one harness run, in seconds. */\nexport const RUN_DEFAULT_TIMEOUT_SECONDS = RUN_TIMEOUT_DEFAULT_SECONDS;\n\n/** The run tool's per-stream cap: harness output is unbounded, model context is not. */\nexport const RUN_MAX_OUTPUT_CHARS = 8000;\n\nfunction text(data: unknown): Array<{ type: \"text\"; text: string }> {\n return [{ type: \"text\", text: toToon(data) }];\n}\n\nfunction unknownHarness(id: string): ToolResult<UnknownHarness> {\n const details: UnknownHarness = { error: `Unknown harness: ${id}`, known: listHarnesses() };\n return { content: text(details), details, isError: true };\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction truncate(output: string): string {\n if (output.length <= RUN_MAX_OUTPUT_CHARS) return output;\n return `${output.slice(0, RUN_MAX_OUTPUT_CHARS)}\\n[truncated ${output.length - RUN_MAX_OUTPUT_CHARS} of ${output.length} characters]`;\n}\n\nfunction modelListingUnavailable(harness: Harness, id: string): RunFailure {\n return {\n error: harness.modelListing\n ? `Harness ${id} does not support filtering its model listing`\n : `Harness ${id} does not support model listing`,\n };\n}\n\ntype RunInvocationOptions = Readonly<{\n model?: string;\n structured: boolean;\n tools: boolean;\n readOnly: boolean;\n}>;\n\ntype InvocationMode = keyof HarnessInvocationModes;\n\nconst ALTERNATE_INVOCATION_MODE: Partial<Record<InvocationMode, InvocationMode>> = {\n advisor: \"agent\",\n advisorStructured: \"agentStructured\",\n agent: \"advisor\",\n agentStructured: \"advisorStructured\",\n};\n\nfunction selectedInvocationMode(\n structured: boolean,\n tools: boolean,\n readOnly: boolean,\n): InvocationMode {\n if (readOnly) return structured ? \"readOnlyStructured\" : \"readOnly\";\n if (tools) return structured ? \"agentStructured\" : \"agent\";\n return structured ? \"advisorStructured\" : \"advisor\";\n}\n\nfunction completedRun(\n harness: Harness,\n result: InvokeResult,\n options: RunInvocationOptions,\n): ToolResult<RunOutcome> {\n const details: RunOutcome = {\n id: harness.id,\n command: result.command,\n args: result.args,\n ...(options.model === undefined ? {} : { model: options.model }),\n structured: options.structured,\n tools: options.tools,\n readOnly: options.readOnly,\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n stdout: truncate(result.stdout),\n stderr: truncate(result.stderr),\n };\n if (result.timedOut || result.exitCode !== 0) {\n return { content: text(details), details, isError: true };\n }\n return { content: text(details), details };\n}\n\nfunction unsupportedInvocation(\n harness: Harness,\n id: string,\n options: RunInvocationOptions,\n): ToolResult<RunFailure> {\n const error = harness.invocationError(options) ?? `Invalid ${id} invocation`;\n const invocationModes = harness.invocationModes;\n const mode = selectedInvocationMode(options.structured, options.tools, options.readOnly);\n const modelUnsupported =\n options.model !== undefined && harness.invocation?.modelArgs === undefined;\n if (invocationModes[mode] || harness.invocation === null || modelUnsupported) {\n const details: RunFailure = { error };\n return { content: text(details), details, isError: true };\n }\n\n const alternateMode = ALTERNATE_INVOCATION_MODE[mode];\n const alternateAvailable = alternateMode === undefined ? false : invocationModes[alternateMode];\n const details: RunFailure = {\n error,\n invocationModes,\n ...(alternateAvailable ? { retry: { tools: !options.tools } } : {}),\n };\n return { content: text(details), details, isError: true };\n}\n\n/**\n * Scans every registered harness for its binaries and version.\n *\n * @returns {ToolResult<HarnessListing>} The complete installation listing.\n */\nexport function detectHarnesses(): ToolResult<HarnessListing> {\n const details: HarnessListing = {\n harnesses: getAllHarnesses().map((harness) => {\n const installed = harness.isInstalled();\n return {\n id: harness.id,\n name: harness.name,\n installed,\n version: installed ? harness.version : null,\n };\n }),\n };\n\n return { content: text(details), details };\n}\n\nfunction harnessInfoResult(id: string): HarnessInfoResult {\n if (!isHarnessId(id)) return unknownHarness(id).details;\n\n const harness = getHarness(id);\n return {\n id: harness.id,\n name: harness.name,\n binaries: harness.binaries,\n capabilities: harness.capabilities,\n invocationModes: harness.invocationModes,\n modelListing: harness.modelListing !== null,\n modelSelection: harness.invocation?.modelArgs !== undefined,\n config: harness.config,\n sessions: harness.sessions,\n instructions: harness.instructions,\n skills: harness.skills,\n commands: harness.commands,\n hooks: harness.hooks,\n persistence: harness.persistence,\n detection: harness.detection,\n resolved: harness.resolve(),\n };\n}\n\n/** Full metadata for one harness, with paths resolved for the current platform. */\nexport function harnessInfo(id: string): ToolResult<HarnessInfoResult>;\n/** Full metadata for several harnesses, preserving input order and errors for each item. */\nexport function harnessInfo(\n ids: readonly string[],\n): ToolResult<HarnessInfoResult[] | HarnessInfoInputError>;\nexport function harnessInfo(input: string | readonly string[]): ToolResult<HarnessInfoDetails>;\nexport function harnessInfo(input: string | readonly string[]): ToolResult<HarnessInfoDetails> {\n if (typeof input === \"string\") {\n const details = harnessInfoResult(input);\n return { content: text(details), details, ...(\"error\" in details ? { isError: true } : {}) };\n }\n\n if (input.length < 1 || input.length > HARNESS_INFO_MAX_ITEMS) {\n const details: HarnessInfoInputError = {\n error: `harnesses_info accepts between 1 and ${HARNESS_INFO_MAX_ITEMS} ids`,\n };\n return { content: text(details), details, isError: true };\n }\n\n const details = input.map(harnessInfoResult);\n return {\n content: text(details),\n details,\n ...(details.some((result) => \"error\" in result) ? { isError: true } : {}),\n };\n}\n\n/** Options accepted by {@link listHarnessModels}. */\nexport interface ModelsOptions {\n search?: string;\n cwd?: string;\n /** Wall-clock budget in seconds; defaults to {@link RUN_DEFAULT_TIMEOUT_SECONDS}. */\n timeoutSeconds?: number;\n}\n\n/** One completed native model-listing query. */\nexport interface ModelsOutcome {\n id: HarnessId;\n command: string;\n args: string[];\n search?: string;\n models: AvailableModel[];\n exitCode: number | null;\n timedOut: boolean;\n stderr: string;\n}\n\n/**\n * Lists the models currently available to one harness through its native CLI.\n *\n * @param id - Harness id to query.\n * @param options - Search, working-directory, and timeout options.\n * @returns {Promise<ToolResult<ModelsOutcome | RunFailure>>} The model listing or failure.\n */\nexport async function listHarnessModels(\n id: string,\n options: ModelsOptions = {},\n): Promise<ToolResult<ModelsOutcome | RunFailure>> {\n if (!isHarnessId(id)) return unknownHarness(id);\n\n const harness = getHarness(id);\n const built = harness.buildModelListInvocation(options.search);\n if (!built) {\n const details = modelListingUnavailable(harness, id);\n return { content: text(details), details, isError: true };\n }\n\n const timeoutSeconds = options.timeoutSeconds ?? RUN_DEFAULT_TIMEOUT_SECONDS;\n let result: ListModelsResult;\n try {\n result = await harness.listModels({\n search: options.search,\n cwd: options.cwd,\n timeoutMs: timeoutSeconds * 1000,\n });\n } catch (error) {\n const details: RunFailure = { error: `Failed to list ${id} models: ${errorMessage(error)}` };\n return { content: text(details), details, isError: true };\n }\n\n const details: ModelsOutcome = {\n id: harness.id,\n command: result.command,\n args: result.args,\n ...(options.search === undefined ? {} : { search: options.search }),\n models: result.models,\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n stderr: truncate(result.stderr),\n };\n\n return {\n content: text(details),\n details,\n ...(result.timedOut || result.exitCode !== 0 ? { isError: true } : {}),\n };\n}\n\n/** Options accepted by {@link runHarness}. */\nexport interface RunOptions {\n cwd?: string;\n /** Harness-native model id or selector. */\n model?: string;\n /** Wall-clock budget in seconds; defaults to {@link RUN_DEFAULT_TIMEOUT_SECONDS}. */\n timeoutSeconds?: number;\n /** Use the harness's structured (JSON) output mode instead of plain text. */\n structured?: boolean;\n /** Enable tools; defaults to a native advisor without tools invocation. */\n tools?: boolean;\n /** Require native enforcement of read-only tool access. Implies tools. */\n readOnly?: boolean;\n}\n\n/** One completed (or failed) harness run, with output capped for the model. */\nexport interface RunOutcome {\n id: HarnessId;\n command: string;\n args: string[];\n model?: string;\n structured: boolean;\n tools: boolean;\n readOnly: boolean;\n exitCode: number | null;\n timedOut: boolean;\n stdout: string;\n stderr: string;\n}\n\n/** Returned when the harness cannot be run at all. */\nexport interface RunFailure {\n error: string;\n known?: HarnessId[];\n /** Modes accepted by the selected harness when invocation mode caused the failure. */\n invocationModes?: HarnessInvocationModes;\n /** Explicit mode change that makes the same invocation shape executable. */\n retry?: { tools: boolean };\n}\n\nfunction normalizedRunAccess(options: Readonly<RunOptions>): {\n tools: boolean;\n readOnly: boolean;\n} {\n const readOnly = options.readOnly ?? false;\n return { readOnly, tools: readOnly ? true : (options.tools ?? false) };\n}\n\n/**\n * Runs one prompt through a harness's normalized non-interactive invocation.\n *\n * Tool use defaults to a native advisor without tools invocation. Harnesses that\n * cannot disable tools reject that mode; setting `tools` selects their full\n * agent invocation. `model` is translated through the harness-specific recipe.\n * This layer also closes stdin, enforces the timeout, and\n * caps the echoed output.\n *\n * @param id - Harness id to run.\n * @param prompt - Prompt sent to the selected harness.\n * @param options - Model, mode, working-directory, and timeout options.\n * @returns {Promise<ToolResult<RunOutcome | RunFailure>>} The capped run outcome or failure.\n */\nexport async function runHarness(\n id: string,\n prompt: string,\n options: RunOptions = {},\n): Promise<ToolResult<RunOutcome | RunFailure>> {\n if (!isHarnessId(id)) return unknownHarness(id);\n\n const harness = getHarness(id);\n const structured = options.structured ?? false;\n const { tools, readOnly } = normalizedRunAccess(options);\n const invocationOptions = { model: options.model, structured, tools, readOnly };\n if (!harness.buildInvocation(prompt, invocationOptions)) {\n return unsupportedInvocation(harness, id, invocationOptions);\n }\n\n const timeoutSeconds = options.timeoutSeconds ?? RUN_DEFAULT_TIMEOUT_SECONDS;\n\n let result: InvokeResult;\n try {\n result = await harness.invoke(prompt, {\n cwd: options.cwd,\n model: options.model,\n timeoutMs: timeoutSeconds * 1000,\n structured,\n tools,\n readOnly,\n });\n } catch (error) {\n const details: RunFailure = { error: `Failed to run ${id}: ${errorMessage(error)}` };\n return { content: text(details), details, isError: true };\n }\n\n return completedRun(harness, result, invocationOptions);\n}\n\n/** MCP server listings for one harness or all of them. */\nexport interface McpListing {\n harnesses: Array<{ id: HarnessId; configs: McpConfigListing[] }>;\n}\n\n/** Result of one MCP config mutation. */\nexport interface McpMutation {\n id: HarnessId;\n path: string;\n action: \"added\" | \"replaced\" | \"removed\" | \"noop\";\n}\n\n/** Flat tool parameters describing one MCP server, shared by every surface. */\nexport interface McpServerParams {\n name: string;\n transport?: McpServerConfig[\"transport\"];\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n url?: string;\n headers?: Record<string, string>;\n}\n\n/**\n * Builds the normalized server shape from flat tool parameters.\n *\n * @param params - Flat MCP server parameters.\n * @returns {McpServerConfig} The normalized server configuration.\n */\nexport function toMcpServerConfig(params: McpServerParams): McpServerConfig {\n const server: McpServerConfig = {\n name: params.name,\n transport: params.transport ?? (params.url ? \"http\" : \"stdio\"),\n };\n if (params.command !== undefined) server.command = params.command;\n if (params.args !== undefined) server.args = params.args;\n if (params.env !== undefined) server.env = params.env;\n if (params.url !== undefined) server.url = params.url;\n if (params.headers !== undefined) server.headers = params.headers;\n return server;\n}\n\n/**\n * Lists configured MCP servers, normalized across harness config dialects.\n *\n * @param id - Optional harness id; omission lists every harness.\n * @returns {ToolResult<McpListing | UnknownHarness>} The normalized listing or id error.\n */\nexport function mcpList(id?: string): ToolResult<McpListing | UnknownHarness> {\n if (id !== undefined && !isHarnessId(id)) return unknownHarness(id);\n\n const targets = id !== undefined && isHarnessId(id) ? [getHarness(id)] : getAllHarnesses();\n const details: McpListing = {\n harnesses: targets\n .map((harness) => ({ id: harness.id, configs: listMcpServers(harness) }))\n .filter((entry) => entry.configs.length > 0),\n };\n\n return { content: text(details), details };\n}\n\nfunction mcpMutate(\n id: string,\n mutate: (harness: Harness) => { path: string; action: McpMutation[\"action\"] },\n): ToolResult<McpMutation | RunFailure> {\n if (!isHarnessId(id)) return unknownHarness(id);\n\n try {\n const { path, action } = mutate(getHarness(id));\n const details: McpMutation = { id, path, action };\n return { content: text(details), details, ...(action === \"noop\" ? { isError: true } : {}) };\n } catch (error) {\n const details: RunFailure = { error: errorMessage(error) };\n return { content: text(details), details, isError: true };\n }\n}\n\n/**\n * Adds or replaces one MCP server in a harness's config.\n *\n * @param id - Target harness id.\n * @param params - Server parameters to normalize and write.\n * @param scope - User or project config scope.\n * @returns {ToolResult<McpMutation | RunFailure>} The mutation outcome or failure.\n */\nexport function mcpAdd(\n id: string,\n params: McpServerParams,\n scope: \"user\" | \"project\" = \"user\",\n): ToolResult<McpMutation | RunFailure> {\n return mcpMutate(id, (harness) => {\n const { path, replaced } = addMcpServer(harness, toMcpServerConfig(params), scope);\n return { path, action: replaced ? \"replaced\" : \"added\" };\n });\n}\n\n/**\n * Removes one MCP server from a harness's config.\n *\n * @param id - Target harness id.\n * @param name - Server name to remove.\n * @param scope - User or project config scope.\n * @returns {ToolResult<McpMutation | RunFailure>} The mutation outcome or failure.\n */\nexport function mcpRemove(\n id: string,\n name: string,\n scope: \"user\" | \"project\" = \"user\",\n): ToolResult<McpMutation | RunFailure> {\n return mcpMutate(id, (harness) => {\n const { path, removed } = removeMcpServer(harness, name, scope);\n return { path, action: removed ? \"removed\" : \"noop\" };\n });\n}\n\n/**\n * Pushes the master MCP list from ~/.config/agntn/mcp.jsonc into harness configs.\n *\n * @param id - Optional harness id; omission targets every harness.\n * @returns {ToolResult<SyncReport | RunFailure>} The sync report or failure.\n */\nexport function mcpSync(id?: string): ToolResult<SyncReport | RunFailure> {\n if (id !== undefined && !isHarnessId(id)) return unknownHarness(id);\n\n try {\n // Preflight before any write: a typo in excludes must fail the whole run,\n // not silently leave the misspelled harness unprotected.\n const unknown = readMasterMcpServers().excludes.filter((entry) => !isHarnessId(entry));\n if (unknown.length > 0) {\n const details: RunFailure = {\n error: `Master MCP list excludes unknown harnesses: ${unknown.join(\", \")}`,\n known: listHarnesses(),\n };\n return { content: text(details), details, isError: true };\n }\n const details = syncMcpServers(\n id !== undefined && isHarnessId(id) ? [getHarness(id)] : getAllHarnesses(),\n );\n return { content: text(details), details };\n } catch (error) {\n const details: RunFailure = { error: errorMessage(error) };\n return { content: text(details), details, isError: true };\n }\n}\n\n/**\n * Links every harness's global instructions file to the master AGENTS.md.\n *\n * @param id - Optional harness id; omission targets every harness.\n * @param check - Report intended changes without writing them.\n * @returns {ToolResult<AgentsSyncReport | RunFailure>} The sync report or failure.\n */\nexport function agentsSync(id?: string, check = false): ToolResult<AgentsSyncReport | RunFailure> {\n if (id !== undefined && !isHarnessId(id)) return unknownHarness(id);\n\n try {\n // Preflight before any write: a typo in excludes must fail the whole run,\n // not silently adopt the harness it was meant to protect.\n const unknown = readAgentsConfig().excludes.filter((entry) => !isHarnessId(entry));\n if (unknown.length > 0) {\n const details: RunFailure = {\n error: `Agents config excludes unknown harnesses: ${unknown.join(\", \")}`,\n known: listHarnesses(),\n };\n return { content: text(details), details, isError: true };\n }\n const details = syncAgentsFiles(\n id !== undefined && isHarnessId(id) ? [getHarness(id)] : getAllHarnesses(),\n check,\n );\n return { content: text(details), details };\n } catch (error) {\n const details: RunFailure = { error: errorMessage(error) };\n return { content: text(details), details, isError: true };\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tool-operations.mjs","names":["toToon"],"sources":["../../src/tool-operations.ts"],"sourcesContent":["/**\n * Tool executors behind the agent extensions.\n *\n * Each executor returns the text a caller reads plus the structured details a\n * harness can attach to the call. The text is TOON-encoded so the model sees\n * the same compact shape the CLI's --toon flag prints.\n */\nimport { encode as toToon } from \"@toon-format/toon\";\nimport { getAllHarnesses, getHarness, isHarnessId, listHarnesses } from \"./registry.ts\";\nimport {\n addMcpServer,\n listMcpServers,\n readMasterMcpServers,\n removeMcpServer,\n syncMcpServers,\n} from \"./mcp-servers.ts\";\nimport type { McpConfigListing, SyncReport } from \"./mcp-servers.ts\";\nimport { readAgentsConfig, syncAgentsFiles } from \"./agents-sync.ts\";\nimport type { AgentsSyncReport } from \"./agents-sync.ts\";\nexport type { AgentsSyncReport } from \"./agents-sync.ts\";\nexport type { SyncReport } from \"./mcp-servers.ts\";\nexport type { HarnessInvocationModes } from \"./types.ts\";\nimport type { Harness } from \"./harness.ts\";\nimport type {\n AvailableModel,\n HarnessCapabilities,\n HarnessDetection,\n HarnessId,\n HarnessInvocationModes,\n InvokeResult,\n ListModelsResult,\n McpServerConfig,\n PathCandidate,\n ResolvedPaths,\n StorageDescriptor,\n} from \"./types.ts\";\n\n/** Text for the model plus details for the harness, shared by every tool surface. */\nexport interface ToolResult<Details> {\n content: Array<{ type: \"text\"; text: string }>;\n details: Details;\n /** Set when the tool could not answer. */\n isError?: boolean;\n}\n\n/** Install state of one harness on this machine. */\nexport interface HarnessStatus {\n id: HarnessId;\n name: string;\n installed: boolean;\n version: string | null;\n}\n\n/** Every registered harness with its install state, as scanned by {@link detectHarnesses}. */\nexport interface HarnessListing {\n harnesses: HarnessStatus[];\n}\n\n/** Full metadata for one harness, including paths resolved for this platform. */\nexport interface HarnessMetadata {\n id: HarnessId;\n name: string;\n binaries: string[];\n capabilities: HarnessCapabilities;\n invocationModes: HarnessInvocationModes;\n modelListing: boolean;\n modelSelection: boolean;\n config: PathCandidate[];\n sessions: PathCandidate[];\n instructions: PathCandidate[];\n skills: PathCandidate[];\n commands: PathCandidate[];\n hooks: PathCandidate[];\n persistence: StorageDescriptor[];\n detection: HarnessDetection;\n resolved: ResolvedPaths;\n}\n\n/** Returned when the requested harness id is not registered. */\nexport interface UnknownHarness {\n error: string;\n known: HarnessId[];\n}\n\n/** Returned when a direct batch call bypasses the tool schema limits. */\nexport interface HarnessInfoInputError {\n error: string;\n}\n\n/** One harness lookup result. */\nexport type HarnessInfoResult = HarnessMetadata | UnknownHarness;\n\n/** Scalar, batch, or rejected batch details from {@link harnessInfo}. */\nexport type HarnessInfoDetails = HarnessInfoResult | HarnessInfoResult[] | HarnessInfoInputError;\n\nimport { HARNESS_INFO_MAX_ITEMS, RUN_TIMEOUT_DEFAULT_SECONDS } from \"./tool-schemas.ts\";\nexport { HARNESS_INFO_MAX_ITEMS } from \"./tool-schemas.ts\";\n\n/** Default wall-clock budget for one harness run, in seconds. */\nexport const RUN_DEFAULT_TIMEOUT_SECONDS = RUN_TIMEOUT_DEFAULT_SECONDS;\n\n/** The run tool's per-stream cap: harness output is unbounded, model context is not. */\nexport const RUN_MAX_OUTPUT_CHARS = 8000;\n\nfunction text(data: unknown): Array<{ type: \"text\"; text: string }> {\n return [{ type: \"text\", text: toToon(data) }];\n}\n\nfunction unknownHarness(id: string): ToolResult<UnknownHarness> {\n const details: UnknownHarness = { error: `Unknown harness: ${id}`, known: listHarnesses() };\n return { content: text(details), details, isError: true };\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction truncate(output: string): string {\n if (output.length <= RUN_MAX_OUTPUT_CHARS) return output;\n return `${output.slice(0, RUN_MAX_OUTPUT_CHARS)}\\n[truncated ${output.length - RUN_MAX_OUTPUT_CHARS} of ${output.length} characters]`;\n}\n\nfunction modelListingUnavailable(harness: Harness, id: string): RunFailure {\n return {\n error: harness.modelListing\n ? `Harness ${id} does not support filtering its model listing`\n : `Harness ${id} does not support model listing`,\n };\n}\n\ntype RunInvocationOptions = Readonly<{\n model?: string;\n structured: boolean;\n tools: boolean;\n readOnly: boolean;\n}>;\n\ntype InvocationMode = keyof HarnessInvocationModes;\n\nconst ALTERNATE_INVOCATION_MODE: Partial<Record<InvocationMode, InvocationMode>> = {\n advisor: \"agent\",\n advisorStructured: \"agentStructured\",\n agent: \"advisor\",\n agentStructured: \"advisorStructured\",\n};\n\nfunction selectedInvocationMode(\n structured: boolean,\n tools: boolean,\n readOnly: boolean,\n): InvocationMode {\n if (readOnly) return structured ? \"readOnlyStructured\" : \"readOnly\";\n if (tools) return structured ? \"agentStructured\" : \"agent\";\n return structured ? \"advisorStructured\" : \"advisor\";\n}\n\nfunction invocationRetry(\n invocationModes: Readonly<HarnessInvocationModes>,\n mode: InvocationMode,\n options: RunInvocationOptions,\n): RunFailure[\"retry\"] {\n const withoutStructured = selectedInvocationMode(false, options.tools, options.readOnly);\n if (options.structured) {\n if (invocationModes[withoutStructured]) return { structured: false };\n const alternateWithoutStructured = ALTERNATE_INVOCATION_MODE[withoutStructured];\n if (alternateWithoutStructured && invocationModes[alternateWithoutStructured]) {\n return { structured: false, tools: !options.tools };\n }\n }\n\n const alternateMode = ALTERNATE_INVOCATION_MODE[mode];\n return alternateMode !== undefined && invocationModes[alternateMode]\n ? { tools: !options.tools }\n : undefined;\n}\n\nfunction completedRun(\n harness: Harness,\n result: InvokeResult,\n options: RunInvocationOptions,\n): ToolResult<RunOutcome> {\n const contentOutcome: Omit<RunOutcome, \"stderr\"> = {\n id: harness.id,\n command: result.command,\n args: result.args,\n ...(options.model === undefined ? {} : { model: options.model }),\n structured: options.structured,\n tools: options.tools,\n readOnly: options.readOnly,\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n aborted: result.aborted,\n stdout: truncate(result.stdout),\n };\n const details: RunOutcome = { ...contentOutcome, stderr: truncate(result.stderr) };\n if (result.timedOut || result.exitCode !== 0) {\n return { content: text(details), details, isError: true };\n }\n return { content: text(result.stdout.length > 0 ? contentOutcome : details), details };\n}\n\nfunction unsupportedInvocation(\n harness: Harness,\n id: string,\n options: RunInvocationOptions,\n): ToolResult<RunFailure> {\n const error = harness.invocationError(options) ?? `Invalid ${id} invocation`;\n const invocationModes = harness.invocationModes;\n const mode = selectedInvocationMode(options.structured, options.tools, options.readOnly);\n const modelUnsupported =\n options.model !== undefined && harness.invocation?.modelArgs === undefined;\n if (invocationModes[mode] || harness.invocation === null || modelUnsupported) {\n const details: RunFailure = { error };\n return { content: text(details), details, isError: true };\n }\n\n const retry = invocationRetry(invocationModes, mode, options);\n const details: RunFailure = {\n error,\n invocationModes,\n ...(retry === undefined ? {} : { retry }),\n };\n return { content: text(details), details, isError: true };\n}\n\n/**\n * Scans every registered harness for its binaries and version.\n *\n * @returns {ToolResult<HarnessListing>} The complete installation listing.\n */\nexport function detectHarnesses(): ToolResult<HarnessListing> {\n const details: HarnessListing = {\n harnesses: getAllHarnesses().map((harness) => {\n const installed = harness.isInstalled();\n return {\n id: harness.id,\n name: harness.name,\n installed,\n version: installed ? harness.version : null,\n };\n }),\n };\n\n return { content: text(details), details };\n}\n\nfunction harnessInfoResult(id: string): HarnessInfoResult {\n if (!isHarnessId(id)) return unknownHarness(id).details;\n\n const harness = getHarness(id);\n return {\n id: harness.id,\n name: harness.name,\n binaries: harness.binaries,\n capabilities: harness.capabilities,\n invocationModes: harness.invocationModes,\n modelListing: harness.modelListing !== null,\n modelSelection: harness.invocation?.modelArgs !== undefined,\n config: harness.config,\n sessions: harness.sessions,\n instructions: harness.instructions,\n skills: harness.skills,\n commands: harness.commands,\n hooks: harness.hooks,\n persistence: harness.persistence,\n detection: harness.detection,\n resolved: harness.resolve(),\n };\n}\n\n/** Full metadata for one harness, with paths resolved for the current platform. */\nexport function harnessInfo(id: string): ToolResult<HarnessInfoResult>;\n/** Full metadata for several harnesses, preserving input order and errors for each item. */\nexport function harnessInfo(\n ids: readonly string[],\n): ToolResult<HarnessInfoResult[] | HarnessInfoInputError>;\nexport function harnessInfo(input: string | readonly string[]): ToolResult<HarnessInfoDetails>;\nexport function harnessInfo(input: string | readonly string[]): ToolResult<HarnessInfoDetails> {\n if (typeof input === \"string\") {\n const details = harnessInfoResult(input);\n return { content: text(details), details, ...(\"error\" in details ? { isError: true } : {}) };\n }\n\n if (input.length < 1 || input.length > HARNESS_INFO_MAX_ITEMS) {\n const details: HarnessInfoInputError = {\n error: `harnesses_info accepts between 1 and ${HARNESS_INFO_MAX_ITEMS} ids`,\n };\n return { content: text(details), details, isError: true };\n }\n\n const details = input.map(harnessInfoResult);\n return {\n content: text(details),\n details,\n ...(details.some((result) => \"error\" in result) ? { isError: true } : {}),\n };\n}\n\n/** Options accepted by {@link listHarnessModels}. */\nexport interface ModelsOptions {\n search?: string;\n cwd?: string;\n /** Wall-clock budget in seconds; defaults to {@link RUN_DEFAULT_TIMEOUT_SECONDS}. */\n timeoutSeconds?: number;\n /** Cancel the owned command through the host request signal. */\n signal?: AbortSignal;\n}\n\n/** One completed native model-listing query. */\nexport interface ModelsOutcome {\n id: HarnessId;\n command: string;\n args: string[];\n search?: string;\n models: AvailableModel[];\n exitCode: number | null;\n timedOut: boolean;\n aborted: boolean;\n stderr: string;\n}\n\n/**\n * Lists the models currently available to one harness through its native CLI.\n *\n * @param id - Harness id to query.\n * @param options - Search, working-directory, and timeout options.\n * @returns {Promise<ToolResult<ModelsOutcome | RunFailure>>} The model listing or failure.\n */\nexport async function listHarnessModels(\n id: string,\n options: ModelsOptions = {},\n): Promise<ToolResult<ModelsOutcome | RunFailure>> {\n if (!isHarnessId(id)) return unknownHarness(id);\n\n const harness = getHarness(id);\n const built = harness.buildModelListInvocation(options.search);\n if (!built) {\n const details = modelListingUnavailable(harness, id);\n return { content: text(details), details, isError: true };\n }\n\n const timeoutSeconds = options.timeoutSeconds ?? RUN_DEFAULT_TIMEOUT_SECONDS;\n let result: ListModelsResult;\n try {\n result = await harness.listModels({\n search: options.search,\n cwd: options.cwd,\n timeoutMs: timeoutSeconds * 1000,\n signal: options.signal,\n });\n } catch (error) {\n const details: RunFailure = { error: `Failed to list ${id} models: ${errorMessage(error)}` };\n return { content: text(details), details, isError: true };\n }\n\n const details: ModelsOutcome = {\n id: harness.id,\n command: result.command,\n args: result.args,\n ...(options.search === undefined ? {} : { search: options.search }),\n models: result.models,\n exitCode: result.exitCode,\n timedOut: result.timedOut,\n aborted: result.aborted,\n stderr: truncate(result.stderr),\n };\n\n return {\n content: text(details),\n details,\n ...(result.timedOut || result.exitCode !== 0 ? { isError: true } : {}),\n };\n}\n\n/** Options accepted by {@link runHarness}. */\nexport interface RunOptions {\n cwd?: string;\n /** Harness-native model id or selector. */\n model?: string;\n /** Wall-clock budget in seconds; defaults to {@link RUN_DEFAULT_TIMEOUT_SECONDS}. */\n timeoutSeconds?: number;\n /** Cancel the owned command through the host request signal. */\n signal?: AbortSignal;\n /** Use the harness's structured (JSON) output mode instead of plain text. */\n structured?: boolean;\n /** Enable tools; defaults to a native advisor without tools invocation. */\n tools?: boolean;\n /** Require native enforcement of read-only tool access. Implies tools. */\n readOnly?: boolean;\n}\n\n/** One completed (or failed) harness run, with output capped for the model. */\nexport interface RunOutcome {\n id: HarnessId;\n command: string;\n args: string[];\n model?: string;\n structured: boolean;\n tools: boolean;\n readOnly: boolean;\n exitCode: number | null;\n timedOut: boolean;\n aborted: boolean;\n stdout: string;\n stderr: string;\n}\n\n/** Returned when the harness cannot be run at all. */\nexport interface RunFailure {\n error: string;\n known?: HarnessId[];\n /** Modes accepted by the selected harness when invocation mode caused the failure. */\n invocationModes?: HarnessInvocationModes;\n /** Explicit mode change that makes the same invocation shape executable. */\n retry?: { structured: false; tools?: boolean } | { tools: boolean };\n}\n\nfunction normalizedRunAccess(options: Readonly<RunOptions>): {\n tools: boolean;\n readOnly: boolean;\n} {\n const readOnly = options.readOnly ?? false;\n return { readOnly, tools: readOnly ? true : (options.tools ?? false) };\n}\n\n/**\n * Runs one prompt through a harness's normalized non-interactive invocation.\n *\n * Tool use defaults to a native advisor without tools invocation. Harnesses that\n * cannot disable tools reject that mode; setting `tools` selects their full\n * agent invocation. `model` is translated through the harness-specific recipe.\n * This layer also closes stdin, enforces the timeout, and\n * caps the echoed output.\n *\n * @param id - Harness id to run.\n * @param prompt - Prompt sent to the selected harness.\n * @param options - Model, mode, working-directory, and timeout options.\n * @returns {Promise<ToolResult<RunOutcome | RunFailure>>} The capped run outcome or failure.\n */\nexport async function runHarness(\n id: string,\n prompt: string,\n options: RunOptions = {},\n): Promise<ToolResult<RunOutcome | RunFailure>> {\n if (!isHarnessId(id)) return unknownHarness(id);\n\n const harness = getHarness(id);\n const structured = options.structured ?? false;\n const { tools, readOnly } = normalizedRunAccess(options);\n const invocationOptions = { model: options.model, structured, tools, readOnly };\n if (!harness.buildInvocation(prompt, invocationOptions)) {\n return unsupportedInvocation(harness, id, invocationOptions);\n }\n\n const timeoutSeconds = options.timeoutSeconds ?? RUN_DEFAULT_TIMEOUT_SECONDS;\n\n let result: InvokeResult;\n try {\n result = await harness.invoke(prompt, {\n cwd: options.cwd,\n model: options.model,\n timeoutMs: timeoutSeconds * 1000,\n signal: options.signal,\n structured,\n tools,\n readOnly,\n });\n } catch (error) {\n const details: RunFailure = { error: `Failed to run ${id}: ${errorMessage(error)}` };\n return { content: text(details), details, isError: true };\n }\n\n return completedRun(harness, result, invocationOptions);\n}\n\n/** MCP server listings for one harness or all of them. */\nexport interface McpListing {\n harnesses: Array<{ id: HarnessId; configs: McpConfigListing[] }>;\n}\n\n/** Marker used only at the tool and CLI boundary, leaving config reads lossless for edits. */\nconst MCP_REDACTED_VALUE = \"<redacted>\";\nconst MCP_CONFIG_ERROR = \"Unable to read or parse MCP config\";\n\nfunction redactMcpValues(values: Readonly<Record<string, string>>): Record<string, string> {\n return Object.fromEntries(Object.keys(values).map((key) => [key, MCP_REDACTED_VALUE]));\n}\n\n/** Result of one MCP config mutation. */\nexport interface McpMutation {\n id: HarnessId;\n path: string;\n action: \"added\" | \"replaced\" | \"removed\" | \"noop\";\n}\n\n/** Flat tool parameters describing one MCP server, shared by every surface. */\nexport interface McpServerParams {\n name: string;\n transport?: McpServerConfig[\"transport\"];\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n url?: string;\n headers?: Record<string, string>;\n}\n\n/**\n * Builds the normalized server shape from flat tool parameters.\n *\n * @param params - Flat MCP server parameters.\n * @returns {McpServerConfig} The normalized server configuration.\n */\nexport function toMcpServerConfig(params: McpServerParams): McpServerConfig {\n const server: McpServerConfig = {\n name: params.name,\n transport: params.transport ?? (params.url ? \"http\" : \"stdio\"),\n };\n if (params.command !== undefined) server.command = params.command;\n if (params.args !== undefined) server.args = params.args;\n if (params.env !== undefined) server.env = params.env;\n if (params.url !== undefined) server.url = params.url;\n if (params.headers !== undefined) server.headers = params.headers;\n return server;\n}\n\n/**\n * Lists configured MCP servers, normalized across harness config dialects.\n *\n * @param id - Optional harness id; omission lists every harness.\n * @returns {ToolResult<McpListing | UnknownHarness>} The normalized listing or id error.\n */\nexport function mcpList(id?: string): ToolResult<McpListing | UnknownHarness> {\n if (id !== undefined && !isHarnessId(id)) return unknownHarness(id);\n\n const targets = id !== undefined && isHarnessId(id) ? [getHarness(id)] : getAllHarnesses();\n const details: McpListing = {\n harnesses: targets\n .map((harness) => ({\n id: harness.id,\n configs: listMcpServers(harness).map((listing) => ({\n ...listing,\n ...(listing.error === undefined ? {} : { error: MCP_CONFIG_ERROR }),\n servers: listing.servers.map((server) => ({\n ...server,\n ...(server.env === undefined ? {} : { env: redactMcpValues(server.env) }),\n ...(server.headers === undefined ? {} : { headers: redactMcpValues(server.headers) }),\n })),\n })),\n }))\n .filter((entry) => entry.configs.length > 0),\n };\n\n return { content: text(details), details };\n}\n\nfunction mcpMutate(\n id: string,\n mutate: (harness: Harness) => { path: string; action: McpMutation[\"action\"] },\n): ToolResult<McpMutation | RunFailure> {\n if (!isHarnessId(id)) return unknownHarness(id);\n\n try {\n const { path, action } = mutate(getHarness(id));\n const details: McpMutation = { id, path, action };\n return { content: text(details), details, ...(action === \"noop\" ? { isError: true } : {}) };\n } catch (error) {\n const details: RunFailure = { error: errorMessage(error) };\n return { content: text(details), details, isError: true };\n }\n}\n\n/**\n * Adds or replaces one MCP server in a harness's config.\n *\n * @param id - Target harness id.\n * @param params - Server parameters to normalize and write.\n * @param scope - User or project config scope.\n * @returns {ToolResult<McpMutation | RunFailure>} The mutation outcome or failure.\n */\nexport function mcpAdd(\n id: string,\n params: McpServerParams,\n scope: \"user\" | \"project\" = \"user\",\n): ToolResult<McpMutation | RunFailure> {\n return mcpMutate(id, (harness) => {\n const { path, replaced } = addMcpServer(harness, toMcpServerConfig(params), scope);\n return { path, action: replaced ? \"replaced\" : \"added\" };\n });\n}\n\n/**\n * Removes one MCP server from a harness's config.\n *\n * @param id - Target harness id.\n * @param name - Server name to remove.\n * @param scope - User or project config scope.\n * @returns {ToolResult<McpMutation | RunFailure>} The mutation outcome or failure.\n */\nexport function mcpRemove(\n id: string,\n name: string,\n scope: \"user\" | \"project\" = \"user\",\n): ToolResult<McpMutation | RunFailure> {\n return mcpMutate(id, (harness) => {\n const { path, removed } = removeMcpServer(harness, name, scope);\n return { path, action: removed ? \"removed\" : \"noop\" };\n });\n}\n\n/**\n * Pushes the master MCP list from ~/.config/agntn/mcp.jsonc into harness configs.\n *\n * @param id - Optional harness id; omission targets every harness.\n * @returns {ToolResult<SyncReport | RunFailure>} The sync report or failure.\n */\nexport function mcpSync(id?: string): ToolResult<SyncReport | RunFailure> {\n if (id !== undefined && !isHarnessId(id)) return unknownHarness(id);\n\n try {\n // Preflight before any write: a typo in excludes must fail the whole run,\n // not silently leave the misspelled harness unprotected.\n const unknown = readMasterMcpServers().excludes.filter((entry) => !isHarnessId(entry));\n if (unknown.length > 0) {\n const details: RunFailure = {\n error: `Master MCP list excludes unknown harnesses: ${unknown.join(\", \")}`,\n known: listHarnesses(),\n };\n return { content: text(details), details, isError: true };\n }\n const details = syncMcpServers(\n id !== undefined && isHarnessId(id) ? [getHarness(id)] : getAllHarnesses(),\n );\n return { content: text(details), details };\n } catch (error) {\n const details: RunFailure = { error: errorMessage(error) };\n return { content: text(details), details, isError: true };\n }\n}\n\n/**\n * Links every harness's global instructions file to the master AGENTS.md.\n *\n * @param id - Optional harness id; omission targets every harness.\n * @param check - Report intended changes without writing them.\n * @returns {ToolResult<AgentsSyncReport | RunFailure>} The sync report or failure.\n */\nexport function agentsSync(id?: string, check = false): ToolResult<AgentsSyncReport | RunFailure> {\n if (id !== undefined && !isHarnessId(id)) return unknownHarness(id);\n\n try {\n // Preflight before any write: a typo in excludes must fail the whole run,\n // not silently adopt the harness it was meant to protect.\n const unknown = readAgentsConfig().excludes.filter((entry) => !isHarnessId(entry));\n if (unknown.length > 0) {\n const details: RunFailure = {\n error: `Agents config excludes unknown harnesses: ${unknown.join(\", \")}`,\n known: listHarnesses(),\n };\n return { content: text(details), details, isError: true };\n }\n const details = syncAgentsFiles(\n id !== undefined && isHarnessId(id) ? [getHarness(id)] : getAllHarnesses(),\n check,\n );\n return { content: text(details), details };\n } catch (error) {\n const details: RunFailure = { error: errorMessage(error) };\n return { content: text(details), details, isError: true };\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- const version = "0.0.1";
1
+ const version = "0.1.0";
2
2
  export { version };
3
3
 
4
4
  //# sourceMappingURL=types.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","names":["pkg.version"],"sources":["../../package.json","../../src/types.ts"],"sourcesContent":["","import pkg from \"../package.json\" with { type: \"json\" };\n\nexport const version: string = pkg.version;\n\nexport type HarnessId =\n | \"antigravity\"\n | \"codex\"\n | \"gemini\"\n | \"grok\"\n | \"claude\"\n | \"opencode\"\n | \"cursor\"\n | \"freebuff\"\n | \"github-copilot\"\n | \"mastracode\"\n | \"omp\"\n | \"pi\";\nexport type EvidenceLevel = \"official\" | \"community\" | \"inferred\";\nexport type Platform = \"linux\" | \"darwin\" | \"win32\";\n\nexport interface PathCandidate {\n path: string;\n scope: \"user\" | \"project\" | \"system\" | \"data\";\n level: EvidenceLevel;\n platforms?: Platform[];\n note?: string;\n}\n\nexport interface StorageDescriptor {\n format: string;\n level: EvidenceLevel;\n note?: string;\n}\n\nexport interface HarnessCapabilities {\n mcp: boolean;\n vision: boolean;\n /** Audio reaches the model without conversion or MCP. */\n audio: boolean;\n /** Video reaches the model without conversion or MCP. */\n video: boolean;\n tools: boolean;\n streaming: boolean;\n}\n\n/** How to run one prompt through the harness non-interactively. */\nexport interface HarnessInvocation {\n /** Binary to spawn; defaults to the harness's first `binaries` entry. */\n binary?: string;\n /** Full agent argument template; every \"{prompt}\" is replaced with the prompt text. */\n args: string[];\n /** Structured full agent argument template. */\n jsonArgs?: string[];\n /** Advisor argument template without tools; absent when the CLI cannot disable tools. */\n noToolsArgs?: string[];\n /** Structured advisor argument template without tools. */\n noToolsJsonArgs?: string[];\n /** Agent argument template whose native sandbox enforces read-only tool access. */\n readOnlyArgs?: string[];\n /** Structured agent argument template with read-only tool access. */\n readOnlyJsonArgs?: string[];\n /** Arguments appended when a model is selected; every \"{model}\" is replaced. */\n modelArgs?: string[];\n level: EvidenceLevel;\n note?: string;\n}\n\n/** Invocation modes a harness supports without fallback or prompt-only restrictions. */\nexport interface HarnessInvocationModes {\n advisor: boolean;\n advisorStructured: boolean;\n readOnly: boolean;\n readOnlyStructured: boolean;\n agent: boolean;\n agentStructured: boolean;\n}\n\n/** How to ask one harness CLI for the models currently available to it. */\nexport interface HarnessModelListing {\n /** Arguments used when no search filter is supplied. */\n args: string[];\n /** Optional argument template for a search filter; every \"{search}\" is replaced. */\n searchArgs?: string[];\n level: EvidenceLevel;\n note?: string;\n}\n\n/** One model normalized from a harness's native model-listing output. */\nexport interface AvailableModel {\n provider: string;\n id: string;\n contextWindow: number;\n maxOutputTokens: number;\n thinking: boolean;\n images: boolean;\n}\n\n/** Options for querying the models available to one harness. */\nexport interface ListModelsOptions {\n search?: string;\n cwd?: string;\n env?: Record<string, string>;\n /** Kill the model-listing command after this many milliseconds; unset means no timeout. */\n timeoutMs?: number;\n}\n\nexport interface InvokeOptions {\n cwd?: string;\n env?: Record<string, string>;\n /** Harness-native model id or selector. */\n model?: string;\n /** Enable the spawned harness's tools; defaults to advisor without tools mode. */\n tools?: boolean;\n /** Require native enforcement of read-only tool access. Implies `tools: true`. */\n readOnly?: boolean;\n /** Kill the harness after this many milliseconds; unset means no timeout. */\n timeoutMs?: number;\n /** Use the harness's structured (JSON) output mode instead of plain text. */\n structured?: boolean;\n}\n\nexport interface InvokeResult {\n command: string;\n args: string[];\n stdout: string;\n stderr: string;\n /** Process exit code; null when the run hit `timeoutMs` and was killed. */\n exitCode: number | null;\n timedOut: boolean;\n}\n\n/** Result of one native model-listing command. */\nexport interface ListModelsResult extends InvokeResult {\n /** Empty on a successful no-match response or when the command itself failed. */\n models: AvailableModel[];\n}\n\n/** Normalized MCP server entry, shared across every harness dialect. */\nexport interface McpServerConfig {\n name: string;\n transport: \"stdio\" | \"http\" | \"sse\";\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n url?: string;\n headers?: Record<string, string>;\n /** Present only when the harness tracks an on/off state per server. */\n enabled?: boolean;\n}\n\n/** How one harness config file stores its MCP servers. */\nexport interface McpConfigFile extends PathCandidate {\n format: \"json\" | \"toml\";\n /** Object path to the server map inside the file, e.g. [\"mcpServers\"]. */\n key: string[];\n /** Shape of individual entries; \"standard\" is the {command, args, env, url} family. */\n dialect: \"standard\" | \"antigravity\" | \"opencode\" | \"vscode\";\n}\n\nexport interface HarnessDetection {\n /** Environment variables that indicate running inside this agent. */\n envVars: string[];\n /** Project-level files or directories whose presence indicates this agent. */\n projectMarkers: string[];\n}\n\nexport interface ResolveOptions {\n homeDir?: string;\n projectRoot?: string;\n platform?: Platform;\n}\n\nexport interface ResolvedPaths {\n config: PathCandidate[];\n sessions: PathCandidate[];\n instructions: PathCandidate[];\n skills: PathCandidate[];\n commands: PathCandidate[];\n hooks: PathCandidate[];\n}\n"],"mappings":"ACEA,MAAa,UAAkBA"}
1
+ {"version":3,"file":"types.mjs","names":["pkg.version"],"sources":["../../package.json","../../src/types.ts"],"sourcesContent":["","import pkg from \"../package.json\" with { type: \"json\" };\n\nexport const version: string = pkg.version;\n\nexport type HarnessId =\n | \"antigravity\"\n | \"codex\"\n | \"gemini\"\n | \"grok\"\n | \"claude\"\n | \"opencode\"\n | \"cursor\"\n | \"freebuff\"\n | \"github-copilot\"\n | \"mastracode\"\n | \"omp\"\n | \"pi\";\nexport type EvidenceLevel = \"official\" | \"community\" | \"inferred\";\nexport type Platform = \"linux\" | \"darwin\" | \"win32\";\n\nexport interface PathCandidate {\n path: string;\n scope: \"user\" | \"project\" | \"system\" | \"data\";\n level: EvidenceLevel;\n platforms?: Platform[];\n note?: string;\n}\n\nexport interface StorageDescriptor {\n format: string;\n level: EvidenceLevel;\n note?: string;\n}\n\nexport interface HarnessCapabilities {\n mcp: boolean;\n vision: boolean;\n /** Audio reaches the model without conversion or MCP. */\n audio: boolean;\n /** Video reaches the model without conversion or MCP. */\n video: boolean;\n tools: boolean;\n streaming: boolean;\n}\n\n/** How to run one prompt through the harness non-interactively. */\nexport interface HarnessInvocation {\n /** Binary to spawn; defaults to the harness's first `binaries` entry. */\n binary?: string;\n /** Full agent argument template; every \"{prompt}\" is replaced with the prompt text. */\n args: string[];\n /** Structured full agent argument template. */\n jsonArgs?: string[];\n /** Advisor argument template without tools; absent when the CLI cannot disable tools. */\n noToolsArgs?: string[];\n /** Structured advisor argument template without tools. */\n noToolsJsonArgs?: string[];\n /** Agent argument template whose native sandbox enforces read-only tool access. */\n readOnlyArgs?: string[];\n /** Structured agent argument template with read-only tool access. */\n readOnlyJsonArgs?: string[];\n /** Lowest CLI version whose read-only enforcement was verified; older or unknown versions reject read-only runs. */\n readOnlyMinVersion?: string;\n /** Arguments appended when a model is selected; every \"{model}\" is replaced. */\n modelArgs?: string[];\n level: EvidenceLevel;\n note?: string;\n}\n\n/** Invocation modes a harness supports without fallback or prompt-only restrictions. */\nexport interface HarnessInvocationModes {\n advisor: boolean;\n advisorStructured: boolean;\n readOnly: boolean;\n readOnlyStructured: boolean;\n agent: boolean;\n agentStructured: boolean;\n}\n\n/** How to ask one harness CLI for the models currently available to it. */\nexport interface HarnessModelListing {\n /** Arguments used when no search filter is supplied. */\n args: string[];\n /** Optional argument template for a search filter; every \"{search}\" is replaced. */\n searchArgs?: string[];\n level: EvidenceLevel;\n note?: string;\n}\n\n/** One model normalized from a harness's native model-listing output. */\nexport interface AvailableModel {\n provider: string;\n id: string;\n contextWindow: number;\n maxOutputTokens: number;\n thinking: boolean;\n images: boolean;\n}\n\n/** Options for querying the models available to one harness. */\nexport interface ListModelsOptions {\n search?: string;\n cwd?: string;\n env?: Record<string, string>;\n /** Milliseconds before cleanup starts. Unset or 0 disables the deadline. */\n timeoutMs?: number;\n /** Cancel with the same process cleanup as a timeout. */\n signal?: AbortSignal;\n}\n\nexport interface InvokeOptions {\n cwd?: string;\n env?: Record<string, string>;\n /** Harness-native model id or selector. */\n model?: string;\n /** Enable the spawned harness's tools; defaults to advisor without tools mode. */\n tools?: boolean;\n /** Require native enforcement of read-only tool access. Implies `tools: true`. */\n readOnly?: boolean;\n /** Milliseconds before cleanup starts. Unset or 0 disables the deadline. */\n timeoutMs?: number;\n /** Cancel with the same process cleanup as a timeout. */\n signal?: AbortSignal;\n /** Use the harness's structured (JSON) output mode instead of plain text. */\n structured?: boolean;\n}\n\nexport interface InvokeResult {\n command: string;\n args: string[];\n stdout: string;\n stderr: string;\n /** Process exit code; null when terminated by a signal, timeout, or cancellation. */\n exitCode: number | null;\n timedOut: boolean;\n /** True when caller cancellation wins over the deadline or completion. */\n aborted: boolean;\n}\n\n/** Result of one native model-listing command. */\nexport interface ListModelsResult extends InvokeResult {\n /** Empty on a successful no-match response or when the command itself failed. */\n models: AvailableModel[];\n}\n\n/** Normalized MCP server entry, shared across every harness dialect. */\nexport interface McpServerConfig {\n name: string;\n transport: \"stdio\" | \"http\" | \"sse\";\n command?: string;\n args?: string[];\n env?: Record<string, string>;\n url?: string;\n headers?: Record<string, string>;\n /** Present only when the harness tracks an on/off state per server. */\n enabled?: boolean;\n}\n\n/** How one harness config file stores its MCP servers. */\nexport interface McpConfigFile extends PathCandidate {\n format: \"json\" | \"toml\";\n /** Object path to the server map inside the file, e.g. [\"mcpServers\"]. */\n key: string[];\n /** Shape of individual entries; \"standard\" is the {command, args, env, url} family. */\n dialect: \"standard\" | \"antigravity\" | \"opencode\" | \"vscode\";\n}\n\nexport interface HarnessDetection {\n /** Environment variables that indicate running inside this agent. */\n envVars: string[];\n /** Project-level files or directories whose presence indicates this agent. */\n projectMarkers: string[];\n}\n\nexport interface ResolveOptions {\n homeDir?: string;\n projectRoot?: string;\n platform?: Platform;\n}\n\nexport interface ResolvedPaths {\n config: PathCandidate[];\n sessions: PathCandidate[];\n instructions: PathCandidate[];\n skills: PathCandidate[];\n commands: PathCandidate[];\n hooks: PathCandidate[];\n}\n"],"mappings":"ACEA,MAAa,UAAkBA"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/registry.ts","../src/resolve.ts","../src/schemas/claude.ts","../src/schemas/gemini.ts","../src/schemas/codex.ts","../src/schemas/opencode.ts","../src/index.ts"],"mappings":";iBAiBgB,gBAAgB,cAAc,qBAAqB;iBAMnD,WAAW,IAAI,YAAY;iBAM3B,iBAAiB;iBAIjB,YAAY,aAAa,MAAM;iBAI/B,mBAAmB;;;;;;;iBAUnB,wBAAwB;;;;;;;;iBAcxB,uBAAuB,eAAe;;;;;;;;;;iBAatC,cAAc,eAAe;iBCtE7B,oBAAoB,kBAAkB,UAAS;UCJ9C;EACf;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;KAGU,qBACR,kBACA,sBACA,qBACA;UAEa;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe,wBAAwB;EACvC;EACA;IACE;IACA,kBAAkB;;EAEpB;EACA;IACE;IACA;IACA;IACA;;;UAIa,6BAA6B;EAC5C;EACA;EACA;IACE;IACA;IACA;IACA;IACA,SAAS;IACT;IACA;IACA,OAAO;;;UAIM;EACf;EACA;EACA;;KAGU,qBAAqB,kBAAkB,uBAAuB;UAEzD;EACf;EACA;EACA;EACA;EACA,gBAAgB;IAGZ;IACA;IACA;;;UClGW;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACT,WAAW;EACX,YAAY;;UAGG;EACf;EACA;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;;UC9Ce;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UC7Be;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;KAGU,eACR,mBACA,wBACA,mBACA,mBACA,sBACA,wBACA,yBACA,uBACA,oBACA,oBACA,oBACA;UAEa;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;cCpCW,qBAAqB"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/registry.ts","../src/resolve.ts","../src/schemas/claude.ts","../src/schemas/gemini.ts","../src/schemas/codex.ts","../src/schemas/opencode.ts","../src/index.ts"],"mappings":";iBAiBgB,gBAAgB,cAAc,qBAAqB;iBAMnD,WAAW,IAAI,YAAY;iBAM3B,iBAAiB;iBAIjB,YAAY,aAAa,MAAM;iBAI/B,mBAAmB;;;;;;;iBAUnB,wBAAwB;;;;;;;;iBAcxB,uBAAuB,eAAe;;;;;;;;;;iBAatC,cAAc,eAAe;iBChE7B,oBAAoB,kBAAkB,UAAS;UCV9C;EACf;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;KAGU,qBACR,kBACA,sBACA,qBACA;UAEa;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe,wBAAwB;EACvC;EACA;IACE;IACA,kBAAkB;;EAEpB;EACA;IACE;IACA;IACA;IACA;;;UAIa,6BAA6B;EAC5C;EACA;EACA;IACE;IACA;IACA;IACA;IACA,SAAS;IACT;IACA;IACA,OAAO;;;UAIM;EACf;EACA;EACA;;KAGU,qBAAqB,kBAAkB,uBAAuB;UAEzD;EACf;EACA;EACA;EACA;EACA,gBAAgB;IAGZ;IACA;IACA;;;UClGW;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA,MAAM;EACN;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;EACT,WAAW;EACX,YAAY;;UAGG;EACf;EACA;EACA;EACA;EACA,UAAU;EACV;EACA;EACA;;UC9Ce;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UC7Be;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;KAGU,eACR,mBACA,wBACA,mBACA,mBACA,sBACA,wBACA,yBACA,uBACA,oBACA,oBACA,oBACA;UAEa;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;cCpCW,qBAAqB"}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.mts","names":[],"sources":["../src/mcp.ts"],"mappings":";;;;;;;;;;;;iBAqOgB,mBAAmB"}
1
+ {"version":3,"file":"mcp.d.mts","names":[],"sources":["../src/mcp.ts"],"mappings":";;;;;;;;;;;;iBAwOgB,mBAAmB"}
@@ -74,6 +74,8 @@ interface ModelsOptions {
74
74
  cwd?: string;
75
75
  /** Wall-clock budget in seconds; defaults to {@link RUN_DEFAULT_TIMEOUT_SECONDS}. */
76
76
  timeoutSeconds?: number;
77
+ /** Cancel the owned command through the host request signal. */
78
+ signal?: AbortSignal;
77
79
  }
78
80
  /** One completed native model-listing query. */
79
81
  interface ModelsOutcome {
@@ -84,6 +86,7 @@ interface ModelsOutcome {
84
86
  models: AvailableModel[];
85
87
  exitCode: number | null;
86
88
  timedOut: boolean;
89
+ aborted: boolean;
87
90
  stderr: string;
88
91
  }
89
92
  /**
@@ -101,6 +104,8 @@ interface RunOptions {
101
104
  model?: string;
102
105
  /** Wall-clock budget in seconds; defaults to {@link RUN_DEFAULT_TIMEOUT_SECONDS}. */
103
106
  timeoutSeconds?: number;
107
+ /** Cancel the owned command through the host request signal. */
108
+ signal?: AbortSignal;
104
109
  /** Use the harness's structured (JSON) output mode instead of plain text. */
105
110
  structured?: boolean;
106
111
  /** Enable tools; defaults to a native advisor without tools invocation. */
@@ -119,6 +124,7 @@ interface RunOutcome {
119
124
  readOnly: boolean;
120
125
  exitCode: number | null;
121
126
  timedOut: boolean;
127
+ aborted: boolean;
122
128
  stdout: string;
123
129
  stderr: string;
124
130
  }
@@ -130,6 +136,9 @@ interface RunFailure {
130
136
  invocationModes?: HarnessInvocationModes;
131
137
  /** Explicit mode change that makes the same invocation shape executable. */
132
138
  retry?: {
139
+ structured: false;
140
+ tools?: boolean;
141
+ } | {
133
142
  tools: boolean;
134
143
  };
135
144
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tool-operations.d.mts","names":[],"sources":["../src/tool-operations.ts"],"mappings":";;;UAsCiB,WAAW;EAC1B,SAAS;IAAQ;IAAc;;EAC/B,SAAS;;EAET;;;UAIe;EACf,IAAI;EACJ;EACA;EACA;;;UAIe;EACf,WAAW;;;UAII;EACf,IAAI;EACJ;EACA;EACA,cAAc;EACd,iBAAiB;EACjB;EACA;EACA,QAAQ;EACR,UAAU;EACV,cAAc;EACd,QAAQ;EACR,UAAU;EACV,OAAO;EACP,aAAa;EACb,WAAW;EACX,UAAU;;;UAIK;EACf;EACA,OAAO;;;UAIQ;EACf;;;KAIU,oBAAoB,kBAAkB;;KAGtC,qBAAqB,oBAAoB,sBAAsB;;cAM9D;;cAGA;;;;;;iBA4GG,mBAAmB,WAAW;;iBAyC9B,YAAY,aAAa,WAAW;;iBAEpC,YACd,yBACC,WAAW,sBAAsB;iBACpB,YAAY,oCAAoC,WAAW;;UAuB1D;EACf;EACA;;EAEA;;;UAIe;EACf,IAAI;EACJ;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;;;;;;;;;iBAUoB,kBACpB,YACA,UAAS,gBACR,QAAQ,WAAW,gBAAgB;;UA0CrB;EACf;;EAEA;;EAEA;;EAEA;;EAEA;;EAEA;;;UAIe;EACf,IAAI;EACJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA,QAAQ;;EAER,kBAAkB;;EAElB;IAAU;;;;;;;;;;;;;;;;;iBAyBU,WACpB,YACA,gBACA,UAAS,aACR,QAAQ,WAAW,aAAa;;UAgClB;EACf,WAAW;IAAQ,IAAI;IAAW,SAAS;;;;UAI5B;EACf,IAAI;EACJ;EACA;;;UAIe;EACf;EACA,YAAY;EACZ;EACA;EACA,MAAM;EACN;EACA,UAAU;;;;;;;;iBASI,kBAAkB,QAAQ,kBAAkB;;;;;;;iBAmB5C,QAAQ,cAAc,WAAW,aAAa;;;;;;;;;iBAqC9C,OACd,YACA,QAAQ,iBACR,6BACC,WAAW,cAAc;;;;;;;;;iBAeZ,UACd,YACA,cACA,6BACC,WAAW,cAAc;;;;;;;iBAaZ,QAAQ,cAAc,WAAW,aAAa;;;;;;;;iBA+B9C,WAAW,aAAa,kBAAgB,WAAW,mBAAmB"}
1
+ {"version":3,"file":"tool-operations.d.mts","names":[],"sources":["../src/tool-operations.ts"],"mappings":";;;UAsCiB,WAAW;EAC1B,SAAS;IAAQ;IAAc;;EAC/B,SAAS;;EAET;;;UAIe;EACf,IAAI;EACJ;EACA;EACA;;;UAIe;EACf,WAAW;;;UAII;EACf,IAAI;EACJ;EACA;EACA,cAAc;EACd,iBAAiB;EACjB;EACA;EACA,QAAQ;EACR,UAAU;EACV,cAAc;EACd,QAAQ;EACR,UAAU;EACV,OAAO;EACP,aAAa;EACb,WAAW;EACX,UAAU;;;UAIK;EACf;EACA,OAAO;;;UAIQ;EACf;;;KAIU,oBAAoB,kBAAkB;;KAGtC,qBAAqB,oBAAoB,sBAAsB;;cAM9D;;cAGA;;;;;;iBAgIG,mBAAmB,WAAW;;iBAyC9B,YAAY,aAAa,WAAW;;iBAEpC,YACd,yBACC,WAAW,sBAAsB;iBACpB,YAAY,oCAAoC,WAAW;;UAuB1D;EACf;EACA;;EAEA;;EAEA,SAAS;;;UAIM;EACf,IAAI;EACJ;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA;EACA;;;;;;;;;iBAUoB,kBACpB,YACA,UAAS,gBACR,QAAQ,WAAW,gBAAgB;;UA4CrB;EACf;;EAEA;;EAEA;;EAEA,SAAS;;EAET;;EAEA;;EAEA;;;UAIe;EACf,IAAI;EACJ;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA,QAAQ;;EAER,kBAAkB;;EAElB;IAAU;IAAmB;;IAAsB;;;;;;;;;;;;;;;;;iBAyB/B,WACpB,YACA,gBACA,UAAS,aACR,QAAQ,WAAW,aAAa;;UAiClB;EACf,WAAW;IAAQ,IAAI;IAAW,SAAS;;;;UAY5B;EACf,IAAI;EACJ;EACA;;;UAIe;EACf;EACA,YAAY;EACZ;EACA;EACA,MAAM;EACN;EACA,UAAU;;;;;;;;iBASI,kBAAkB,QAAQ,kBAAkB;;;;;;;iBAmB5C,QAAQ,cAAc,WAAW,aAAa;;;;;;;;;iBAgD9C,OACd,YACA,QAAQ,iBACR,6BACC,WAAW,cAAc;;;;;;;;;iBAeZ,UACd,YACA,cACA,6BACC,WAAW,cAAc;;;;;;;iBAaZ,QAAQ,cAAc,WAAW,aAAa;;;;;;;;iBA+B9C,WAAW,aAAa,kBAAgB,WAAW,mBAAmB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agntn/harnesses",
3
- "version": "0.0.1",
3
+ "version": "0.1.0",
4
4
  "description": "Metadata registry for AI coding harnesses: binaries, configs, sessions, and capabilities.",
5
5
  "homepage": "https://github.com/agntn/harnesses#readme",
6
6
  "bugs": "https://github.com/agntn/harnesses/issues",
@@ -36,6 +36,18 @@
36
36
  "publishConfig": {
37
37
  "access": "public"
38
38
  },
39
+ "scripts": {
40
+ "build": "obuild",
41
+ "dev": "obuild --stub",
42
+ "docs": "pnpm --dir docs dev",
43
+ "lint": "pnpm build && oxlint . && oxfmt --check .",
44
+ "lint:fix": "pnpm build && oxlint . --fix && oxfmt . && pnpm build",
45
+ "typecheck": "tsgo --noEmit --skipLibCheck && pnpm build && tsgo --noEmit --skipLibCheck -p tsconfig.extensions.json",
46
+ "test": "vitest",
47
+ "test:run": "vitest --run",
48
+ "prepack": "pnpm run build",
49
+ "release": "pnpm test:run && pnpm build && changelogen --release --push"
50
+ },
39
51
  "dependencies": {
40
52
  "@modelcontextprotocol/sdk": "1.30.0",
41
53
  "@toon-format/toon": "^4.1.1",
@@ -79,6 +91,7 @@
79
91
  "engines": {
80
92
  "node": ">=22"
81
93
  },
94
+ "packageManager": "pnpm@11.24.0",
82
95
  "omp": {
83
96
  "extensions": [
84
97
  "./packages/omp/extensions/harnesses.ts"
@@ -88,15 +101,5 @@
88
101
  "extensions": [
89
102
  "./packages/pi/extensions/harnesses.ts"
90
103
  ]
91
- },
92
- "scripts": {
93
- "build": "obuild",
94
- "dev": "obuild --stub",
95
- "lint": "pnpm build && oxlint . && oxfmt --check .",
96
- "lint:fix": "pnpm build && oxlint . --fix && oxfmt . && pnpm build",
97
- "typecheck": "tsgo --noEmit --skipLibCheck && pnpm build && tsgo --noEmit --skipLibCheck -p tsconfig.extensions.json",
98
- "test": "vitest",
99
- "test:run": "vitest --run",
100
- "release": "pnpm test:run && pnpm build && changelogen --release --push"
101
104
  }
102
- }
105
+ }
@@ -106,20 +106,24 @@ export default function harnessesExtension(pi: ExtensionAPI): void {
106
106
  async execute(
107
107
  _toolCallId,
108
108
  params: HarnessSchemas.ModelsParams,
109
+ signal,
109
110
  ): Promise<AgentToolResult<HarnessTools.ModelsOutcome | HarnessTools.RunFailure>> {
110
111
  const { listHarnessModels } = await loadToolOperations();
111
112
  const { content, details, isError } = await listHarnessModels(params.id, {
112
113
  search: params.search,
113
114
  cwd: params.cwd,
114
115
  timeoutSeconds: params.timeoutSeconds,
116
+ signal,
115
117
  });
116
118
  if (isError) {
117
119
  const message =
118
120
  "error" in details
119
121
  ? details.error
120
- : details.timedOut
121
- ? `Harness ${details.id} model listing timed out`
122
- : details.stderr || `Harness ${details.id} exited with code ${details.exitCode}`;
122
+ : details.aborted
123
+ ? `Harness ${details.id} model listing aborted`
124
+ : details.timedOut
125
+ ? `Harness ${details.id} model listing timed out`
126
+ : details.stderr || `Harness ${details.id} exited with code ${details.exitCode}`;
123
127
  throw new Error(message);
124
128
  }
125
129
  return { content, details };
@@ -137,23 +141,25 @@ export default function harnessesExtension(pi: ExtensionAPI): void {
137
141
  async execute(
138
142
  _toolCallId,
139
143
  params: HarnessSchemas.RunParams,
144
+ signal,
140
145
  ): Promise<AgentToolResult<HarnessTools.RunOutcome | HarnessTools.RunFailure>> {
141
146
  const { runHarness } = await loadToolOperations();
142
147
  const { content, details, isError } = await runHarness(params.id, params.prompt, {
143
148
  cwd: params.cwd,
144
149
  model: params.model,
145
150
  timeoutSeconds: params.timeoutSeconds,
151
+ signal,
146
152
  structured: params.structured,
147
153
  tools: params.tools,
148
154
  readOnly: params.readOnly,
149
155
  });
150
156
  if (isError) {
157
+ if ("error" in details) throw new Error(details.error);
151
158
  const message =
152
- "error" in details
153
- ? details.error
154
- : details.timedOut
155
- ? `Harness ${details.id} timed out`
156
- : details.stderr || `Harness ${details.id} exited with code ${details.exitCode}`;
159
+ content[0]?.text ??
160
+ (details.timedOut
161
+ ? `Harness ${details.id} timed out`
162
+ : details.stderr || `Harness ${details.id} exited with code ${details.exitCode}`);
157
163
  throw new Error(message);
158
164
  }
159
165
  return { content, details };