@posthog/agent 2.1.82 → 2.1.85

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapters/claude/mcp/tool-metadata.ts"],"sourcesContent":["import type { McpServerConfig } from \"@anthropic-ai/claude-agent-sdk\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { Logger } from \"../../../utils/logger.js\";\n\nexport interface McpToolMetadata {\n readOnly: boolean;\n}\n\nconst mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();\n\nfunction buildToolKey(serverName: string, toolName: string): string {\n return `mcp__${serverName}__${toolName}`;\n}\n\nfunction isHttpMcpServer(\n config: McpServerConfig,\n): config is McpServerConfig & { type: \"http\"; url: string } {\n return config.type === \"http\" && typeof (config as any).url === \"string\";\n}\n\nasync function fetchToolsFromHttpServer(\n _serverName: string,\n config: McpServerConfig & { type: \"http\"; url: string },\n): Promise<Tool[]> {\n const transport = new StreamableHTTPClientTransport(new URL(config.url), {\n requestInit: {\n headers: (config as any).headers || {},\n },\n });\n\n const client = new Client({\n name: \"twig-metadata-fetcher\",\n version: \"1.0.0\",\n });\n\n try {\n await client.connect(transport);\n const result = await client.listTools();\n return result.tools;\n } finally {\n await client.close().catch(() => {});\n }\n}\n\nfunction extractToolMetadata(tool: Tool): McpToolMetadata {\n return {\n readOnly: tool.annotations?.readOnlyHint === true,\n };\n}\n\nexport async function fetchMcpToolMetadata(\n mcpServers: Record<string, McpServerConfig>,\n logger: Logger = new Logger({ debug: false, prefix: \"[McpToolMetadata]\" }),\n): Promise<void> {\n const fetchPromises: Promise<void>[] = [];\n\n for (const [serverName, config] of Object.entries(mcpServers)) {\n if (!isHttpMcpServer(config)) {\n continue;\n }\n\n const fetchPromise = fetchToolsFromHttpServer(serverName, config)\n .then((tools) => {\n const toolCount = tools.length;\n const readOnlyCount = tools.filter(\n (t) => t.annotations?.readOnlyHint === true,\n ).length;\n\n for (const tool of tools) {\n const toolKey = buildToolKey(serverName, tool.name);\n mcpToolMetadataCache.set(toolKey, extractToolMetadata(tool));\n }\n\n logger.info(\"Fetched MCP tool metadata\", {\n serverName,\n toolCount,\n readOnlyCount,\n });\n })\n .catch((error) => {\n logger.error(\"Failed to fetch MCP tool metadata\", {\n serverName,\n error: error instanceof Error ? error.message : String(error),\n });\n });\n\n fetchPromises.push(fetchPromise);\n }\n\n await Promise.all(fetchPromises);\n}\n\nexport function isMcpToolReadOnly(toolName: string): boolean {\n const metadata = mcpToolMetadataCache.get(toolName);\n return metadata?.readOnly === true;\n}\n\nexport function clearMcpToolMetadataCache(): void {\n mcpToolMetadataCache.clear();\n}\n"],"mappings":";AACA,SAAS,cAAc;AACvB,SAAS,qCAAqC;AAQ9C,IAAM,uBAAqD,oBAAI,IAAI;AAoF5D,SAAS,kBAAkB,UAA2B;AAC3D,QAAM,WAAW,qBAAqB,IAAI,QAAQ;AAClD,SAAO,UAAU,aAAa;AAChC;","names":[]}
1
+ {"version":3,"sources":["../src/adapters/claude/mcp/tool-metadata.ts"],"sourcesContent":["import type {\n McpHttpServerConfig,\n McpServerConfig,\n} from \"@anthropic-ai/claude-agent-sdk\";\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\nimport { Logger } from \"../../../utils/logger.js\";\n\nexport interface McpToolMetadata {\n readOnly: boolean;\n}\n\nconst mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();\n\nfunction buildToolKey(serverName: string, toolName: string): string {\n return `mcp__${serverName}__${toolName}`;\n}\n\nfunction isHttpMcpServer(\n config: McpServerConfig,\n): config is McpHttpServerConfig {\n return config.type === \"http\" && typeof config.url === \"string\";\n}\n\nasync function fetchToolsFromHttpServer(\n _serverName: string,\n config: McpHttpServerConfig,\n): Promise<Tool[]> {\n const transport = new StreamableHTTPClientTransport(new URL(config.url), {\n requestInit: {\n headers: config.headers ?? {},\n },\n });\n\n const client = new Client({\n name: \"twig-metadata-fetcher\",\n version: \"1.0.0\",\n });\n\n try {\n await client.connect(transport);\n const result = await client.listTools();\n return result.tools;\n } finally {\n await client.close().catch(() => {});\n }\n}\n\nfunction extractToolMetadata(tool: Tool): McpToolMetadata {\n return {\n readOnly: tool.annotations?.readOnlyHint === true,\n };\n}\n\nexport async function fetchMcpToolMetadata(\n mcpServers: Record<string, McpServerConfig>,\n logger: Logger = new Logger({ debug: false, prefix: \"[McpToolMetadata]\" }),\n): Promise<void> {\n const fetchPromises: Promise<void>[] = [];\n\n for (const [serverName, config] of Object.entries(mcpServers)) {\n if (!isHttpMcpServer(config)) {\n continue;\n }\n\n const fetchPromise = fetchToolsFromHttpServer(serverName, config)\n .then((tools) => {\n const toolCount = tools.length;\n const readOnlyCount = tools.filter(\n (t) => t.annotations?.readOnlyHint === true,\n ).length;\n\n for (const tool of tools) {\n const toolKey = buildToolKey(serverName, tool.name);\n mcpToolMetadataCache.set(toolKey, extractToolMetadata(tool));\n }\n\n logger.info(\"Fetched MCP tool metadata\", {\n serverName,\n toolCount,\n readOnlyCount,\n });\n })\n .catch((error) => {\n logger.error(\"Failed to fetch MCP tool metadata\", {\n serverName,\n error: error instanceof Error ? error.message : String(error),\n });\n });\n\n fetchPromises.push(fetchPromise);\n }\n\n await Promise.all(fetchPromises);\n}\n\nexport function isMcpToolReadOnly(toolName: string): boolean {\n const metadata = mcpToolMetadataCache.get(toolName);\n return metadata?.readOnly === true;\n}\n\nexport function clearMcpToolMetadataCache(): void {\n mcpToolMetadataCache.clear();\n}\n"],"mappings":";AAIA,SAAS,cAAc;AACvB,SAAS,qCAAqC;AAQ9C,IAAM,uBAAqD,oBAAI,IAAI;AAoF5D,SAAS,kBAAkB,UAA2B;AAC3D,QAAM,WAAW,qBAAqB,IAAI,QAAQ;AAClD,SAAO,UAAU,aAAa;AAChC;","names":[]}
@@ -1183,7 +1183,7 @@ import { v7 as uuidv7 } from "uuid";
1183
1183
  // package.json
1184
1184
  var package_default = {
1185
1185
  name: "@posthog/agent",
1186
- version: "2.1.82",
1186
+ version: "2.1.85",
1187
1187
  repository: "https://github.com/PostHog/twig",
1188
1188
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
1189
1189
  exports: {
@@ -2009,6 +2009,28 @@ function toolUpdateFromToolResult(toolResult, toolUse) {
2009
2009
  }
2010
2010
  return { title: "Question answered" };
2011
2011
  }
2012
+ case "WebFetch": {
2013
+ const input = toolUse?.input;
2014
+ const url = input?.url ? String(input.url) : "";
2015
+ const prompt = input?.prompt ? String(input.prompt) : void 0;
2016
+ const resultContent = toAcpContentUpdate(
2017
+ toolResult.content,
2018
+ "is_error" in toolResult ? toolResult.is_error : false
2019
+ );
2020
+ const content = [];
2021
+ if (url) {
2022
+ content.push({
2023
+ type: "content",
2024
+ content: resourceLink(url, url, {
2025
+ description: prompt
2026
+ })
2027
+ });
2028
+ }
2029
+ if (resultContent.content) {
2030
+ content.push(...resultContent.content);
2031
+ }
2032
+ return { content };
2033
+ }
2012
2034
  default: {
2013
2035
  return toAcpContentUpdate(
2014
2036
  toolResult.content,
@@ -2475,7 +2497,7 @@ function isHttpMcpServer(config) {
2475
2497
  async function fetchToolsFromHttpServer(_serverName, config) {
2476
2498
  const transport = new StreamableHTTPClientTransport(new URL(config.url), {
2477
2499
  requestInit: {
2478
- headers: config.headers || {}
2500
+ headers: config.headers ?? {}
2479
2501
  }
2480
2502
  });
2481
2503
  const client = new Client({
@@ -2855,7 +2877,7 @@ async function applyPlanApproval(response, context, updatedInput) {
2855
2877
  return { behavior: "deny", message, interrupt: false };
2856
2878
  }
2857
2879
  async function handleEnterPlanModeTool(context) {
2858
- const { session, toolInput, logger } = context;
2880
+ const { session, toolInput } = context;
2859
2881
  session.permissionMode = "plan";
2860
2882
  await session.query.setPermissionMode("plan");
2861
2883
  await context.emitConfigOptionsUpdate();
@@ -3203,6 +3225,11 @@ function buildSpawnWrapper(sessionId, onProcessSpawned, onProcessExited) {
3203
3225
  child.kill("SIGTERM");
3204
3226
  });
3205
3227
  }
3228
+ if (!child.stdin || !child.stdout) {
3229
+ throw new Error(
3230
+ `Failed to get stdio streams for spawned process (pid=${child.pid})`
3231
+ );
3232
+ }
3206
3233
  return {
3207
3234
  stdin: child.stdin,
3208
3235
  stdout: child.stdout,
@@ -3215,12 +3242,15 @@ function buildSpawnWrapper(sessionId, onProcessSpawned, onProcessExited) {
3215
3242
  kill(signal) {
3216
3243
  return child.kill(signal);
3217
3244
  },
3245
+ // biome-ignore lint/suspicious/noExplicitAny: ChildProcess event listener types require any[]
3218
3246
  on(event, listener) {
3219
3247
  child.on(event, listener);
3220
3248
  },
3249
+ // biome-ignore lint/suspicious/noExplicitAny: ChildProcess event listener types require any[]
3221
3250
  once(event, listener) {
3222
3251
  child.once(event, listener);
3223
3252
  },
3253
+ // biome-ignore lint/suspicious/noExplicitAny: ChildProcess event listener types require any[]
3224
3254
  off(event, listener) {
3225
3255
  child.off(event, listener);
3226
3256
  }
@@ -3901,15 +3931,16 @@ function createClaudeConnection(config) {
3901
3931
  deviceType: config.deviceType
3902
3932
  });
3903
3933
  }
3934
+ const taskRunId = config.taskRunId;
3904
3935
  agentWritable = createTappedWritableStream(streams.agent.writable, {
3905
3936
  onMessage: (line) => {
3906
- logWriter.appendRawLine(config.taskRunId, line);
3937
+ logWriter.appendRawLine(taskRunId, line);
3907
3938
  },
3908
3939
  logger
3909
3940
  });
3910
3941
  clientWritable = createTappedWritableStream(streams.client.writable, {
3911
3942
  onMessage: (line) => {
3912
- logWriter.appendRawLine(config.taskRunId, line);
3943
+ logWriter.appendRawLine(taskRunId, line);
3913
3944
  },
3914
3945
  logger
3915
3946
  });
@@ -4105,7 +4136,7 @@ function createCodexConnection(config) {
4105
4136
  }
4106
4137
  });
4107
4138
  const shouldTapLogs = config.taskRunId && logWriter;
4108
- if (shouldTapLogs) {
4139
+ if (shouldTapLogs && config.taskRunId) {
4109
4140
  const taskRunId2 = config.taskRunId;
4110
4141
  if (!logWriter.isRegistered(taskRunId2)) {
4111
4142
  logWriter.register(taskRunId2, {
@@ -9237,11 +9268,13 @@ var AsyncReaderWriterLock = class {
9237
9268
  return;
9238
9269
  if (this.writeQueue.length > 0) {
9239
9270
  const next = this.writeQueue.shift();
9240
- next();
9271
+ if (next)
9272
+ next();
9241
9273
  } else {
9242
9274
  while (this.readQueue.length > 0 && !this.writerWaiting) {
9243
9275
  const next = this.readQueue.shift();
9244
- next();
9276
+ if (next)
9277
+ next();
9245
9278
  }
9246
9279
  }
9247
9280
  }
@@ -9757,27 +9790,29 @@ var ApplySnapshotSaga = class extends Saga {
9757
9790
  if (!snapshot.archiveUrl) {
9758
9791
  throw new Error("Cannot apply snapshot: no archive URL");
9759
9792
  }
9793
+ const archiveUrl = snapshot.archiveUrl;
9760
9794
  await this.step({
9761
9795
  name: "create_tmp_dir",
9762
9796
  execute: () => mkdir3(tmpDir, { recursive: true }),
9763
9797
  rollback: async () => {
9764
9798
  }
9765
9799
  });
9766
- this.archivePath = join5(tmpDir, `${snapshot.treeHash}.tar.gz`);
9800
+ const archivePath = join5(tmpDir, `${snapshot.treeHash}.tar.gz`);
9801
+ this.archivePath = archivePath;
9767
9802
  await this.step({
9768
9803
  name: "download_archive",
9769
9804
  execute: async () => {
9770
9805
  const arrayBuffer = await apiClient.downloadArtifact(
9771
9806
  taskId,
9772
9807
  runId,
9773
- snapshot.archiveUrl
9808
+ archiveUrl
9774
9809
  );
9775
9810
  if (!arrayBuffer) {
9776
9811
  throw new Error("Failed to download archive");
9777
9812
  }
9778
9813
  const base64Content = Buffer.from(arrayBuffer).toString("utf-8");
9779
9814
  const binaryContent = Buffer.from(base64Content, "base64");
9780
- await writeFile3(this.archivePath, binaryContent);
9815
+ await writeFile3(archivePath, binaryContent);
9781
9816
  },
9782
9817
  rollback: async () => {
9783
9818
  if (this.archivePath) {