@posthog/agent 2.3.46 → 2.3.62

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.d.ts CHANGED
@@ -1,3 +1,9 @@
1
+ interface McpToolMetadata {
2
+ readOnly: boolean;
3
+ name: string;
4
+ description?: string;
5
+ }
6
+ declare function getMcpToolMetadata(toolName: string): McpToolMetadata | undefined;
1
7
  declare function isMcpToolReadOnly(toolName: string): boolean;
2
8
 
3
- export { isMcpToolReadOnly };
9
+ export { type McpToolMetadata, getMcpToolMetadata, isMcpToolReadOnly };
package/dist/index.js CHANGED
@@ -1,10 +1,14 @@
1
1
  // src/adapters/claude/mcp/tool-metadata.ts
2
2
  var mcpToolMetadataCache = /* @__PURE__ */ new Map();
3
+ function getMcpToolMetadata(toolName) {
4
+ return mcpToolMetadataCache.get(toolName);
5
+ }
3
6
  function isMcpToolReadOnly(toolName) {
4
7
  const metadata = mcpToolMetadataCache.get(toolName);
5
8
  return metadata?.readOnly === true;
6
9
  }
7
10
  export {
11
+ getMcpToolMetadata,
8
12
  isMcpToolReadOnly
9
13
  };
10
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/adapters/claude/mcp/tool-metadata.ts"],"sourcesContent":["import type { McpServerStatus, Query } from \"@anthropic-ai/claude-agent-sdk\";\nimport { Logger } from \"../../../utils/logger\";\n\nexport interface McpToolMetadata {\n readOnly: boolean;\n name: string;\n description?: string;\n}\n\nconst mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();\n\nconst PENDING_RETRY_INTERVAL_MS = 1_000;\nconst PENDING_MAX_RETRIES = 10;\n\nfunction buildToolKey(serverName: string, toolName: string): string {\n return `mcp__${serverName}__${toolName}`;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function fetchMcpToolMetadata(\n q: Query,\n logger: Logger = new Logger({ debug: false, prefix: \"[McpToolMetadata]\" }),\n): Promise<void> {\n let retries = 0;\n\n while (retries <= PENDING_MAX_RETRIES) {\n let statuses: McpServerStatus[];\n try {\n statuses = await q.mcpServerStatus();\n } catch (error) {\n logger.error(\"Failed to fetch MCP server status\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n\n const pendingServers = statuses.filter((s) => s.status === \"pending\");\n\n for (const server of statuses) {\n if (server.status !== \"connected\" || !server.tools) {\n continue;\n }\n\n let readOnlyCount = 0;\n for (const tool of server.tools) {\n const toolKey = buildToolKey(server.name, tool.name);\n const readOnly = tool.annotations?.readOnly === true;\n mcpToolMetadataCache.set(toolKey, {\n readOnly,\n name: tool.name,\n description: tool.description,\n });\n if (readOnly) readOnlyCount++;\n }\n\n logger.info(\"Fetched MCP tool metadata\", {\n serverName: server.name,\n toolCount: server.tools.length,\n readOnlyCount,\n });\n }\n\n if (pendingServers.length === 0) {\n return;\n }\n\n retries++;\n if (retries > PENDING_MAX_RETRIES) {\n logger.warn(\"Gave up waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n });\n return;\n }\n\n logger.info(\"Waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n retry: retries,\n });\n await delay(PENDING_RETRY_INTERVAL_MS);\n }\n}\n\nexport function getMcpToolMetadata(\n toolName: string,\n): McpToolMetadata | undefined {\n return mcpToolMetadataCache.get(toolName);\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":";AASA,IAAM,uBAAqD,oBAAI,IAAI;AAkF5D,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 { McpServerStatus, Query } from \"@anthropic-ai/claude-agent-sdk\";\nimport { Logger } from \"../../../utils/logger\";\n\nexport interface McpToolMetadata {\n readOnly: boolean;\n name: string;\n description?: string;\n}\n\nconst mcpToolMetadataCache: Map<string, McpToolMetadata> = new Map();\n\nconst PENDING_RETRY_INTERVAL_MS = 1_000;\nconst PENDING_MAX_RETRIES = 10;\n\nfunction buildToolKey(serverName: string, toolName: string): string {\n return `mcp__${serverName}__${toolName}`;\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function fetchMcpToolMetadata(\n q: Query,\n logger: Logger = new Logger({ debug: false, prefix: \"[McpToolMetadata]\" }),\n): Promise<void> {\n let retries = 0;\n\n while (retries <= PENDING_MAX_RETRIES) {\n let statuses: McpServerStatus[];\n try {\n statuses = await q.mcpServerStatus();\n } catch (error) {\n logger.error(\"Failed to fetch MCP server status\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return;\n }\n\n const pendingServers = statuses.filter((s) => s.status === \"pending\");\n\n for (const server of statuses) {\n if (server.status !== \"connected\" || !server.tools) {\n continue;\n }\n\n let readOnlyCount = 0;\n for (const tool of server.tools) {\n const toolKey = buildToolKey(server.name, tool.name);\n const readOnly = tool.annotations?.readOnly === true;\n\n mcpToolMetadataCache.set(toolKey, {\n readOnly,\n name: tool.name,\n description: tool.description,\n });\n if (readOnly) readOnlyCount++;\n }\n\n logger.info(\"Fetched MCP tool metadata\", {\n serverName: server.name,\n toolCount: server.tools.length,\n readOnlyCount,\n });\n }\n\n if (pendingServers.length === 0) {\n return;\n }\n\n retries++;\n if (retries > PENDING_MAX_RETRIES) {\n logger.warn(\"Gave up waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n });\n return;\n }\n\n logger.info(\"Waiting for pending MCP servers\", {\n pendingServers: pendingServers.map((s) => s.name),\n retry: retries,\n });\n await delay(PENDING_RETRY_INTERVAL_MS);\n }\n}\n\nexport function getMcpToolMetadata(\n toolName: string,\n): McpToolMetadata | undefined {\n return mcpToolMetadataCache.get(toolName);\n}\n\nexport function isMcpToolReadOnly(toolName: string): boolean {\n const metadata = mcpToolMetadataCache.get(toolName);\n return metadata?.readOnly === true;\n}\n\nexport function getConnectedMcpServerNames(): string[] {\n const names = new Set<string>();\n for (const key of mcpToolMetadataCache.keys()) {\n const parts = key.split(\"__\");\n if (parts.length >= 3) names.add(parts[1]);\n }\n return [...names];\n}\n\nexport function clearMcpToolMetadataCache(): void {\n mcpToolMetadataCache.clear();\n}\n"],"mappings":";AASA,IAAM,uBAAqD,oBAAI,IAAI;AA6E5D,SAAS,mBACd,UAC6B;AAC7B,SAAO,qBAAqB,IAAI,QAAQ;AAC1C;AAEO,SAAS,kBAAkB,UAA2B;AAC3D,QAAM,WAAW,qBAAqB,IAAI,QAAQ;AAClD,SAAO,UAAU,aAAa;AAChC;","names":[]}
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "@posthog/agent",
4
- version: "2.3.46",
4
+ version: "2.3.62",
5
5
  repository: "https://github.com/PostHog/code",
6
6
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
7
7
  exports: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../package.json","../src/utils/gateway.ts","../src/posthog-api.ts"],"sourcesContent":["{\n \"name\": \"@posthog/agent\",\n \"version\": \"2.3.46\",\n \"repository\": \"https://github.com/PostHog/code\",\n \"description\": \"TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./agent\": {\n \"types\": \"./dist/agent.d.ts\",\n \"import\": \"./dist/agent.js\"\n },\n \"./gateway-models\": {\n \"types\": \"./dist/gateway-models.d.ts\",\n \"import\": \"./dist/gateway-models.js\"\n },\n \"./posthog-api\": {\n \"types\": \"./dist/posthog-api.d.ts\",\n \"import\": \"./dist/posthog-api.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"import\": \"./dist/types.js\"\n },\n \"./adapters/claude/questions/utils\": {\n \"types\": \"./dist/adapters/claude/questions/utils.d.ts\",\n \"import\": \"./dist/adapters/claude/questions/utils.js\"\n },\n \"./adapters/claude/permissions/permission-options\": {\n \"types\": \"./dist/adapters/claude/permissions/permission-options.d.ts\",\n \"import\": \"./dist/adapters/claude/permissions/permission-options.js\"\n },\n \"./adapters/claude/tools\": {\n \"types\": \"./dist/adapters/claude/tools.d.ts\",\n \"import\": \"./dist/adapters/claude/tools.js\"\n },\n \"./adapters/claude/conversion/tool-use-to-acp\": {\n \"types\": \"./dist/adapters/claude/conversion/tool-use-to-acp.d.ts\",\n \"import\": \"./dist/adapters/claude/conversion/tool-use-to-acp.js\"\n },\n \"./adapters/claude/session/jsonl-hydration\": {\n \"types\": \"./dist/adapters/claude/session/jsonl-hydration.d.ts\",\n \"import\": \"./dist/adapters/claude/session/jsonl-hydration.js\"\n },\n \"./server\": {\n \"types\": \"./dist/server/agent-server.d.ts\",\n \"import\": \"./dist/server/agent-server.js\"\n }\n },\n \"bin\": {\n \"agent-server\": \"./dist/server/bin.cjs\"\n },\n \"type\": \"module\",\n \"keywords\": [\n \"posthog\",\n \"claude\",\n \"agent\",\n \"ai\",\n \"git\",\n \"typescript\"\n ],\n \"author\": \"PostHog\",\n \"license\": \"SEE LICENSE IN LICENSE\",\n \"scripts\": {\n \"build\": \"rm -rf dist && tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"pnpm exec tsc --noEmit\",\n \"prepublishOnly\": \"pnpm run build\",\n \"clean\": \"rm -rf dist .turbo\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"devDependencies\": {\n \"@posthog/shared\": \"workspace:*\",\n \"@posthog/git\": \"workspace:*\",\n \"@types/bun\": \"latest\",\n \"@types/tar\": \"^6.1.13\",\n \"msw\": \"^2.12.7\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.20.6\",\n \"typescript\": \"^5.5.0\",\n \"vitest\": \"^2.1.8\"\n },\n \"dependencies\": {\n \"@agentclientprotocol/sdk\": \"0.15.0\",\n \"@anthropic-ai/claude-agent-sdk\": \"0.2.71\",\n \"@anthropic-ai/sdk\": \"^0.78.0\",\n \"@hono/node-server\": \"^1.19.9\",\n \"@opentelemetry/api-logs\": \"^0.208.0\",\n \"@opentelemetry/exporter-logs-otlp-http\": \"^0.208.0\",\n \"@opentelemetry/resources\": \"^2.0.0\",\n \"@opentelemetry/sdk-logs\": \"^0.208.0\",\n \"@opentelemetry/semantic-conventions\": \"^1.28.0\",\n \"@types/jsonwebtoken\": \"^9.0.10\",\n \"commander\": \"^14.0.2\",\n \"hono\": \"^4.11.7\",\n \"jsonwebtoken\": \"^9.0.2\",\n \"minimatch\": \"^10.0.3\",\n \"tar\": \"^7.5.0\",\n \"uuid\": \"13.0.0\",\n \"yoga-wasm-web\": \"^0.3.3\",\n \"zod\": \"^3.24.1\"\n },\n \"files\": [\n \"dist/**/*\",\n \"src/**/*\",\n \"README.md\",\n \"CLAUDE.md\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","export type GatewayProduct = \"posthog_code\" | \"background_agents\";\n\nexport function getLlmGatewayUrl(\n posthogHost: string,\n product: GatewayProduct = \"posthog_code\",\n): string {\n const url = new URL(posthogHost);\n const hostname = url.hostname;\n\n // Local development (normalize 127.0.0.1 to localhost)\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\") {\n return `${url.protocol}//localhost:3308/${product}`;\n }\n\n // Docker containers accessing host\n if (hostname === \"host.docker.internal\") {\n return `${url.protocol}//host.docker.internal:3308/${product}`;\n }\n\n // Production - extract region from hostname, default to US\n const region = hostname.match(/^(us|eu)\\.posthog\\.com$/)?.[1] ?? \"us\";\n return `https://gateway.${region}.posthog.com/${product}`;\n}\n","import packageJson from \"../package.json\" with { type: \"json\" };\nimport type {\n ArtifactType,\n PostHogAPIConfig,\n StoredEntry,\n Task,\n TaskRun,\n TaskRunArtifact,\n} from \"./types\";\nimport { getLlmGatewayUrl } from \"./utils/gateway\";\n\nexport { getLlmGatewayUrl };\n\nconst DEFAULT_USER_AGENT = `posthog/agent.hog.dev; version: ${packageJson.version}`;\n\nexport interface TaskArtifactUploadPayload {\n name: string;\n type: ArtifactType;\n content: string;\n content_type?: string;\n}\n\nexport type TaskRunUpdate = Partial<\n Pick<\n TaskRun,\n | \"status\"\n | \"branch\"\n | \"stage\"\n | \"error_message\"\n | \"output\"\n | \"state\"\n | \"environment\"\n >\n>;\n\nexport class PostHogAPIClient {\n private config: PostHogAPIConfig;\n\n constructor(config: PostHogAPIConfig) {\n this.config = config;\n }\n\n private get baseUrl(): string {\n const host = this.config.apiUrl.endsWith(\"/\")\n ? this.config.apiUrl.slice(0, -1)\n : this.config.apiUrl;\n return host;\n }\n\n private get headers(): Record<string, string> {\n return {\n Authorization: `Bearer ${this.config.getApiKey()}`,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.config.userAgent ?? DEFAULT_USER_AGENT,\n };\n }\n\n private async apiRequest<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const response = await fetch(url, {\n ...options,\n headers: {\n ...this.headers,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n let errorMessage: string;\n try {\n const errorResponse = await response.json();\n errorMessage = `Failed request: [${response.status}] ${JSON.stringify(errorResponse)}`;\n } catch {\n errorMessage = `Failed request: [${response.status}] ${response.statusText}`;\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n private getTeamId(): number {\n return this.config.projectId;\n }\n\n getApiKey(): string {\n return this.config.getApiKey();\n }\n\n getLlmGatewayUrl(): string {\n return getLlmGatewayUrl(this.baseUrl);\n }\n\n async getTask(taskId: string): Promise<Task> {\n const teamId = this.getTeamId();\n return this.apiRequest<Task>(`/api/projects/${teamId}/tasks/${taskId}/`);\n }\n\n async getTaskRun(taskId: string, runId: string): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/`,\n );\n }\n\n async updateTaskRun(\n taskId: string,\n runId: string,\n payload: TaskRunUpdate,\n ): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/`,\n {\n method: \"PATCH\",\n body: JSON.stringify(payload),\n },\n );\n }\n\n async appendTaskRunLog(\n taskId: string,\n runId: string,\n entries: StoredEntry[],\n ): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/append_log/`,\n {\n method: \"POST\",\n body: JSON.stringify({ entries }),\n },\n );\n }\n\n async relayMessage(\n taskId: string,\n runId: string,\n text: string,\n ): Promise<void> {\n const teamId = this.getTeamId();\n await this.apiRequest<{ status: string }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/relay_message/`,\n {\n method: \"POST\",\n body: JSON.stringify({ text }),\n },\n );\n }\n\n async uploadTaskArtifacts(\n taskId: string,\n runId: string,\n artifacts: TaskArtifactUploadPayload[],\n ): Promise<TaskRunArtifact[]> {\n if (!artifacts.length) {\n return [];\n }\n\n const teamId = this.getTeamId();\n const response = await this.apiRequest<{ artifacts: TaskRunArtifact[] }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/artifacts/`,\n {\n method: \"POST\",\n body: JSON.stringify({ artifacts }),\n },\n );\n\n return response.artifacts ?? [];\n }\n\n async getArtifactPresignedUrl(\n taskId: string,\n runId: string,\n storagePath: string,\n ): Promise<string | null> {\n const teamId = this.getTeamId();\n try {\n const response = await this.apiRequest<{\n url: string;\n expires_in: number;\n }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/artifacts/presign/`,\n {\n method: \"POST\",\n body: JSON.stringify({ storage_path: storagePath }),\n },\n );\n return response.url;\n } catch {\n return null;\n }\n }\n\n /**\n * Download artifact content by storage path\n * Gets a presigned URL and fetches the content\n */\n async downloadArtifact(\n taskId: string,\n runId: string,\n storagePath: string,\n ): Promise<ArrayBuffer | null> {\n const url = await this.getArtifactPresignedUrl(taskId, runId, storagePath);\n if (!url) {\n return null;\n }\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download artifact: ${response.status}`);\n }\n return response.arrayBuffer();\n } catch {\n return null;\n }\n }\n\n /**\n * Fetch logs for a task run via the logs API endpoint\n * @param taskRun - The task run to fetch logs for\n * @returns Array of stored entries, or empty array if no logs available\n */\n async fetchTaskRunLogs(taskRun: TaskRun): Promise<StoredEntry[]> {\n const teamId = this.getTeamId();\n\n try {\n const response = await fetch(\n `${this.baseUrl}/api/projects/${teamId}/tasks/${taskRun.task}/runs/${taskRun.id}/logs`,\n { headers: this.headers },\n );\n\n if (!response.ok) {\n if (response.status === 404) {\n return [];\n }\n throw new Error(\n `Failed to fetch logs: ${response.status} ${response.statusText}`,\n );\n }\n\n const content = await response.text();\n\n if (!content.trim()) {\n return [];\n }\n\n // Parse newline-delimited JSON\n return content\n .trim()\n .split(\"\\n\")\n .map((line) => JSON.parse(line) as StoredEntry);\n } catch (error) {\n throw new Error(\n `Failed to fetch task run logs: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../package.json","../src/utils/gateway.ts","../src/posthog-api.ts"],"sourcesContent":["{\n \"name\": \"@posthog/agent\",\n \"version\": \"2.3.62\",\n \"repository\": \"https://github.com/PostHog/code\",\n \"description\": \"TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n },\n \"./agent\": {\n \"types\": \"./dist/agent.d.ts\",\n \"import\": \"./dist/agent.js\"\n },\n \"./gateway-models\": {\n \"types\": \"./dist/gateway-models.d.ts\",\n \"import\": \"./dist/gateway-models.js\"\n },\n \"./posthog-api\": {\n \"types\": \"./dist/posthog-api.d.ts\",\n \"import\": \"./dist/posthog-api.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"import\": \"./dist/types.js\"\n },\n \"./adapters/claude/questions/utils\": {\n \"types\": \"./dist/adapters/claude/questions/utils.d.ts\",\n \"import\": \"./dist/adapters/claude/questions/utils.js\"\n },\n \"./adapters/claude/permissions/permission-options\": {\n \"types\": \"./dist/adapters/claude/permissions/permission-options.d.ts\",\n \"import\": \"./dist/adapters/claude/permissions/permission-options.js\"\n },\n \"./adapters/claude/tools\": {\n \"types\": \"./dist/adapters/claude/tools.d.ts\",\n \"import\": \"./dist/adapters/claude/tools.js\"\n },\n \"./adapters/claude/conversion/tool-use-to-acp\": {\n \"types\": \"./dist/adapters/claude/conversion/tool-use-to-acp.d.ts\",\n \"import\": \"./dist/adapters/claude/conversion/tool-use-to-acp.js\"\n },\n \"./adapters/claude/session/jsonl-hydration\": {\n \"types\": \"./dist/adapters/claude/session/jsonl-hydration.d.ts\",\n \"import\": \"./dist/adapters/claude/session/jsonl-hydration.js\"\n },\n \"./server\": {\n \"types\": \"./dist/server/agent-server.d.ts\",\n \"import\": \"./dist/server/agent-server.js\"\n }\n },\n \"bin\": {\n \"agent-server\": \"./dist/server/bin.cjs\"\n },\n \"type\": \"module\",\n \"keywords\": [\n \"posthog\",\n \"claude\",\n \"agent\",\n \"ai\",\n \"git\",\n \"typescript\"\n ],\n \"author\": \"PostHog\",\n \"license\": \"SEE LICENSE IN LICENSE\",\n \"scripts\": {\n \"build\": \"rm -rf dist && tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"pnpm exec tsc --noEmit\",\n \"prepublishOnly\": \"pnpm run build\",\n \"clean\": \"rm -rf dist .turbo\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"devDependencies\": {\n \"@posthog/shared\": \"workspace:*\",\n \"@posthog/git\": \"workspace:*\",\n \"@types/bun\": \"latest\",\n \"@types/tar\": \"^6.1.13\",\n \"msw\": \"^2.12.7\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.20.6\",\n \"typescript\": \"^5.5.0\",\n \"vitest\": \"^2.1.8\"\n },\n \"dependencies\": {\n \"@agentclientprotocol/sdk\": \"0.15.0\",\n \"@anthropic-ai/claude-agent-sdk\": \"0.2.71\",\n \"@anthropic-ai/sdk\": \"^0.78.0\",\n \"@hono/node-server\": \"^1.19.9\",\n \"@opentelemetry/api-logs\": \"^0.208.0\",\n \"@opentelemetry/exporter-logs-otlp-http\": \"^0.208.0\",\n \"@opentelemetry/resources\": \"^2.0.0\",\n \"@opentelemetry/sdk-logs\": \"^0.208.0\",\n \"@opentelemetry/semantic-conventions\": \"^1.28.0\",\n \"@types/jsonwebtoken\": \"^9.0.10\",\n \"commander\": \"^14.0.2\",\n \"hono\": \"^4.11.7\",\n \"jsonwebtoken\": \"^9.0.2\",\n \"minimatch\": \"^10.0.3\",\n \"tar\": \"^7.5.0\",\n \"uuid\": \"13.0.0\",\n \"yoga-wasm-web\": \"^0.3.3\",\n \"zod\": \"^3.24.1\"\n },\n \"files\": [\n \"dist/**/*\",\n \"src/**/*\",\n \"README.md\",\n \"CLAUDE.md\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","export type GatewayProduct = \"posthog_code\" | \"background_agents\";\n\nexport function getLlmGatewayUrl(\n posthogHost: string,\n product: GatewayProduct = \"posthog_code\",\n): string {\n const url = new URL(posthogHost);\n const hostname = url.hostname;\n\n // Local development (normalize 127.0.0.1 to localhost)\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\") {\n return `${url.protocol}//localhost:3308/${product}`;\n }\n\n // Docker containers accessing host\n if (hostname === \"host.docker.internal\") {\n return `${url.protocol}//host.docker.internal:3308/${product}`;\n }\n\n // Production - extract region from hostname, default to US\n const region = hostname.match(/^(us|eu)\\.posthog\\.com$/)?.[1] ?? \"us\";\n return `https://gateway.${region}.posthog.com/${product}`;\n}\n","import packageJson from \"../package.json\" with { type: \"json\" };\nimport type {\n ArtifactType,\n PostHogAPIConfig,\n StoredEntry,\n Task,\n TaskRun,\n TaskRunArtifact,\n} from \"./types\";\nimport { getLlmGatewayUrl } from \"./utils/gateway\";\n\nexport { getLlmGatewayUrl };\n\nconst DEFAULT_USER_AGENT = `posthog/agent.hog.dev; version: ${packageJson.version}`;\n\nexport interface TaskArtifactUploadPayload {\n name: string;\n type: ArtifactType;\n content: string;\n content_type?: string;\n}\n\nexport type TaskRunUpdate = Partial<\n Pick<\n TaskRun,\n | \"status\"\n | \"branch\"\n | \"stage\"\n | \"error_message\"\n | \"output\"\n | \"state\"\n | \"environment\"\n >\n>;\n\nexport class PostHogAPIClient {\n private config: PostHogAPIConfig;\n\n constructor(config: PostHogAPIConfig) {\n this.config = config;\n }\n\n private get baseUrl(): string {\n const host = this.config.apiUrl.endsWith(\"/\")\n ? this.config.apiUrl.slice(0, -1)\n : this.config.apiUrl;\n return host;\n }\n\n private get headers(): Record<string, string> {\n return {\n Authorization: `Bearer ${this.config.getApiKey()}`,\n \"Content-Type\": \"application/json\",\n \"User-Agent\": this.config.userAgent ?? DEFAULT_USER_AGENT,\n };\n }\n\n private async apiRequest<T>(\n endpoint: string,\n options: RequestInit = {},\n ): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const response = await fetch(url, {\n ...options,\n headers: {\n ...this.headers,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n let errorMessage: string;\n try {\n const errorResponse = await response.json();\n errorMessage = `Failed request: [${response.status}] ${JSON.stringify(errorResponse)}`;\n } catch {\n errorMessage = `Failed request: [${response.status}] ${response.statusText}`;\n }\n throw new Error(errorMessage);\n }\n\n return response.json();\n }\n\n private getTeamId(): number {\n return this.config.projectId;\n }\n\n getApiKey(): string {\n return this.config.getApiKey();\n }\n\n getLlmGatewayUrl(): string {\n return getLlmGatewayUrl(this.baseUrl);\n }\n\n async getTask(taskId: string): Promise<Task> {\n const teamId = this.getTeamId();\n return this.apiRequest<Task>(`/api/projects/${teamId}/tasks/${taskId}/`);\n }\n\n async getTaskRun(taskId: string, runId: string): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/`,\n );\n }\n\n async updateTaskRun(\n taskId: string,\n runId: string,\n payload: TaskRunUpdate,\n ): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/`,\n {\n method: \"PATCH\",\n body: JSON.stringify(payload),\n },\n );\n }\n\n async appendTaskRunLog(\n taskId: string,\n runId: string,\n entries: StoredEntry[],\n ): Promise<TaskRun> {\n const teamId = this.getTeamId();\n return this.apiRequest<TaskRun>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/append_log/`,\n {\n method: \"POST\",\n body: JSON.stringify({ entries }),\n },\n );\n }\n\n async relayMessage(\n taskId: string,\n runId: string,\n text: string,\n ): Promise<void> {\n const teamId = this.getTeamId();\n await this.apiRequest<{ status: string }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/relay_message/`,\n {\n method: \"POST\",\n body: JSON.stringify({ text }),\n },\n );\n }\n\n async uploadTaskArtifacts(\n taskId: string,\n runId: string,\n artifacts: TaskArtifactUploadPayload[],\n ): Promise<TaskRunArtifact[]> {\n if (!artifacts.length) {\n return [];\n }\n\n const teamId = this.getTeamId();\n const response = await this.apiRequest<{ artifacts: TaskRunArtifact[] }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/artifacts/`,\n {\n method: \"POST\",\n body: JSON.stringify({ artifacts }),\n },\n );\n\n return response.artifacts ?? [];\n }\n\n async getArtifactPresignedUrl(\n taskId: string,\n runId: string,\n storagePath: string,\n ): Promise<string | null> {\n const teamId = this.getTeamId();\n try {\n const response = await this.apiRequest<{\n url: string;\n expires_in: number;\n }>(\n `/api/projects/${teamId}/tasks/${taskId}/runs/${runId}/artifacts/presign/`,\n {\n method: \"POST\",\n body: JSON.stringify({ storage_path: storagePath }),\n },\n );\n return response.url;\n } catch {\n return null;\n }\n }\n\n /**\n * Download artifact content by storage path\n * Gets a presigned URL and fetches the content\n */\n async downloadArtifact(\n taskId: string,\n runId: string,\n storagePath: string,\n ): Promise<ArrayBuffer | null> {\n const url = await this.getArtifactPresignedUrl(taskId, runId, storagePath);\n if (!url) {\n return null;\n }\n\n try {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to download artifact: ${response.status}`);\n }\n return response.arrayBuffer();\n } catch {\n return null;\n }\n }\n\n /**\n * Fetch logs for a task run via the logs API endpoint\n * @param taskRun - The task run to fetch logs for\n * @returns Array of stored entries, or empty array if no logs available\n */\n async fetchTaskRunLogs(taskRun: TaskRun): Promise<StoredEntry[]> {\n const teamId = this.getTeamId();\n\n try {\n const response = await fetch(\n `${this.baseUrl}/api/projects/${teamId}/tasks/${taskRun.task}/runs/${taskRun.id}/logs`,\n { headers: this.headers },\n );\n\n if (!response.ok) {\n if (response.status === 404) {\n return [];\n }\n throw new Error(\n `Failed to fetch logs: ${response.status} ${response.statusText}`,\n );\n }\n\n const content = await response.text();\n\n if (!content.trim()) {\n return [];\n }\n\n // Parse newline-delimited JSON\n return content\n .trim()\n .split(\"\\n\")\n .map((line) => JSON.parse(line) as StoredEntry);\n } catch (error) {\n throw new Error(\n `Failed to fetch task run logs: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -71,6 +71,8 @@ declare class AgentServer {
71
71
  private questionRelayedToSlack;
72
72
  private detectedPrUrl;
73
73
  private resumeState;
74
+ private initializationPromise;
75
+ private pendingEvents;
74
76
  private emitConsoleLog;
75
77
  constructor(config: AgentServerConfig);
76
78
  private getEffectiveMode;
@@ -81,6 +83,7 @@ declare class AgentServer {
81
83
  private authenticateRequest;
82
84
  private executeCommand;
83
85
  private initializeSession;
86
+ private _doInitializeSession;
84
87
  private sendInitialTaskMessage;
85
88
  private sendResumeMessage;
86
89
  private static RESUME_HISTORY_TOKEN_BUDGET;
@@ -103,6 +106,7 @@ declare class AgentServer {
103
106
  private captureTreeState;
104
107
  private broadcastTurnComplete;
105
108
  private broadcastEvent;
109
+ private replayPendingEvents;
106
110
  private sendSseEvent;
107
111
  }
108
112
 
@@ -908,7 +908,7 @@ import { Hono } from "hono";
908
908
  // package.json
909
909
  var package_default = {
910
910
  name: "@posthog/agent",
911
- version: "2.3.46",
911
+ version: "2.3.62",
912
912
  repository: "https://github.com/PostHog/code",
913
913
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
914
914
  exports: {
@@ -1739,6 +1739,14 @@ function isMcpToolReadOnly(toolName) {
1739
1739
  const metadata = mcpToolMetadataCache.get(toolName);
1740
1740
  return metadata?.readOnly === true;
1741
1741
  }
1742
+ function getConnectedMcpServerNames() {
1743
+ const names = /* @__PURE__ */ new Set();
1744
+ for (const key of mcpToolMetadataCache.keys()) {
1745
+ const parts = key.split("__");
1746
+ if (parts.length >= 3) names.add(parts[1]);
1747
+ }
1748
+ return [...names];
1749
+ }
1742
1750
 
1743
1751
  // src/adapters/claude/conversion/tool-use-to-acp.ts
1744
1752
  var SYSTEM_REMINDER_REGEX = /\s*<system-reminder>[\s\S]*?<\/system-reminder>/g;
@@ -2495,7 +2503,10 @@ function handleToolResultChunk(chunk, ctx) {
2495
2503
  toolCallId: chunk.tool_use_id,
2496
2504
  sessionUpdate: "tool_call_update",
2497
2505
  status: chunk.is_error ? "failed" : "completed",
2498
- rawOutput: chunk.content,
2506
+ rawOutput: ctx.mcpToolUseResult ? { ...ctx.mcpToolUseResult, isError: chunk.is_error ?? false } : {
2507
+ content: Array.isArray(chunk.content) ? chunk.content : typeof chunk.content === "string" ? [{ type: "text", text: chunk.content }] : [],
2508
+ isError: chunk.is_error ?? false
2509
+ },
2499
2510
  ...toolUpdate
2500
2511
  });
2501
2512
  return updates;
@@ -2549,7 +2560,7 @@ function processContentChunk(chunk, role, ctx) {
2549
2560
  return [];
2550
2561
  }
2551
2562
  }
2552
- function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput, cwd) {
2563
+ function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentCache, client, logger, parentToolCallId, registerHooks, supportsTerminalOutput, cwd, mcpToolUseResult) {
2553
2564
  if (typeof content === "string") {
2554
2565
  const update = {
2555
2566
  sessionUpdate: messageUpdateType(role),
@@ -2573,7 +2584,8 @@ function toAcpNotifications(content, role, sessionId, toolUseCache, fileContentC
2573
2584
  parentToolCallId,
2574
2585
  registerHooks,
2575
2586
  supportsTerminalOutput,
2576
- cwd
2587
+ cwd,
2588
+ mcpToolUseResult
2577
2589
  };
2578
2590
  const output = [];
2579
2591
  for (const chunk of content) {
@@ -2832,6 +2844,7 @@ async function handleUserAssistantMessage(message, context) {
2832
2844
  const content = message.message.content;
2833
2845
  const contentToProcess = message.type === "assistant" ? filterMessageContent(content) : content;
2834
2846
  const parentToolCallId = "parent_tool_use_id" in message ? message.parent_tool_use_id ?? void 0 : void 0;
2847
+ const mcpToolUseResult = message.type === "user" && message.tool_use_result != null ? message.tool_use_result : void 0;
2835
2848
  for (const notification of toAcpNotifications(
2836
2849
  contentToProcess,
2837
2850
  message.message.role,
@@ -2843,7 +2856,8 @@ async function handleUserAssistantMessage(message, context) {
2843
2856
  parentToolCallId,
2844
2857
  context.registerHooks,
2845
2858
  context.supportsTerminalOutput,
2846
- session.cwd
2859
+ session.cwd,
2860
+ mcpToolUseResult
2847
2861
  )) {
2848
2862
  await client.sessionUpdate(notification);
2849
2863
  session.notificationHistory.push(notification);
@@ -4683,11 +4697,17 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
4683
4697
  * Both populate caches used later — neither is needed to return configOptions.
4684
4698
  */
4685
4699
  deferBackgroundFetches(q) {
4700
+ this.logger.info("Starting background fetches (commands + MCP metadata)");
4686
4701
  Promise.all([
4687
4702
  new Promise((resolve4) => setTimeout(resolve4, 10)).then(
4688
4703
  () => this.sendAvailableCommandsUpdate()
4689
4704
  ),
4690
- fetchMcpToolMetadata(q, this.logger)
4705
+ fetchMcpToolMetadata(q, this.logger).then(() => {
4706
+ const serverNames = getConnectedMcpServerNames();
4707
+ if (serverNames.length > 0) {
4708
+ this.options?.onMcpServersReady?.(serverNames);
4709
+ }
4710
+ })
4691
4711
  ]).catch(
4692
4712
  (err) => this.logger.error("Background fetch failed", { error: err })
4693
4713
  );
@@ -11118,7 +11138,7 @@ var SessionLogWriter = class _SessionLogWriter {
11118
11138
  taskId: context.taskId,
11119
11139
  runId: context.runId
11120
11140
  });
11121
- this.sessions.set(sessionId, { context });
11141
+ this.sessions.set(sessionId, { context, currentTurnMessages: [] });
11122
11142
  this.lastFlushAttemptTime.set(sessionId, Date.now());
11123
11143
  if (this.localCachePath) {
11124
11144
  const sessionDir = path10.join(
@@ -11165,6 +11185,7 @@ var SessionLogWriter = class _SessionLogWriter {
11165
11185
  const nonChunkAgentText = this.extractAgentMessageText(message);
11166
11186
  if (nonChunkAgentText) {
11167
11187
  session.lastAgentMessage = nonChunkAgentText;
11188
+ session.currentTurnMessages.push(nonChunkAgentText);
11168
11189
  }
11169
11190
  const entry = {
11170
11191
  type: "notification",
@@ -11261,6 +11282,7 @@ var SessionLogWriter = class _SessionLogWriter {
11261
11282
  const { text: text2, firstTimestamp } = session.chunkBuffer;
11262
11283
  session.chunkBuffer = void 0;
11263
11284
  session.lastAgentMessage = text2;
11285
+ session.currentTurnMessages.push(text2);
11264
11286
  const entry = {
11265
11287
  type: "notification",
11266
11288
  timestamp: firstTimestamp,
@@ -11286,6 +11308,17 @@ var SessionLogWriter = class _SessionLogWriter {
11286
11308
  getLastAgentMessage(sessionId) {
11287
11309
  return this.sessions.get(sessionId)?.lastAgentMessage;
11288
11310
  }
11311
+ getFullAgentResponse(sessionId) {
11312
+ const session = this.sessions.get(sessionId);
11313
+ if (!session || session.currentTurnMessages.length === 0) return void 0;
11314
+ return session.currentTurnMessages.join("\n\n");
11315
+ }
11316
+ resetTurnMessages(sessionId) {
11317
+ const session = this.sessions.get(sessionId);
11318
+ if (session) {
11319
+ session.currentTurnMessages = [];
11320
+ }
11321
+ }
11289
11322
  extractAgentMessageText(message) {
11290
11323
  if (message.method !== "session/update") {
11291
11324
  return null;
@@ -11601,6 +11634,12 @@ var AgentServer = class _AgentServer {
11601
11634
  questionRelayedToSlack = false;
11602
11635
  detectedPrUrl = null;
11603
11636
  resumeState = null;
11637
+ // Guards against concurrent session initialization. autoInitializeSession() and
11638
+ // the GET /events SSE handler can both call initializeSession() — the SSE connection
11639
+ // often arrives while newSession() is still awaited (this.session is still null),
11640
+ // causing a second session to be created and duplicate Slack messages to be sent.
11641
+ initializationPromise = null;
11642
+ pendingEvents = [];
11604
11643
  emitConsoleLog = (level, _scope, message, data) => {
11605
11644
  if (!this.session) return;
11606
11645
  const formatted = data !== void 0 ? `${message} ${JSON.stringify(data)}` : message;
@@ -11680,6 +11719,7 @@ var AgentServer = class _AgentServer {
11680
11719
  await this.initializeSession(payload, sseController);
11681
11720
  } else {
11682
11721
  this.session.sseController = sseController;
11722
+ this.replayPendingEvents();
11683
11723
  }
11684
11724
  this.sendSseEvent(sseController, {
11685
11725
  type: "connected",
@@ -11859,6 +11899,7 @@ var AgentServer = class _AgentServer {
11859
11899
  this.logger.info(
11860
11900
  `Processing user message (detectedPrUrl=${this.detectedPrUrl ?? "none"}): ${content.substring(0, 100)}...`
11861
11901
  );
11902
+ this.session.logWriter.resetTurnMessages(this.session.payload.run_id);
11862
11903
  const result = await this.session.clientConnection.prompt({
11863
11904
  sessionId: this.session.acpSessionId,
11864
11905
  prompt: [{ type: "text", text: content }],
@@ -11874,7 +11915,24 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
11874
11915
  }
11875
11916
  });
11876
11917
  this.broadcastTurnComplete(result.stopReason);
11877
- return { stopReason: result.stopReason };
11918
+ if (result.stopReason === "end_turn") {
11919
+ this.relayAgentResponse(this.session.payload).catch(
11920
+ (err) => this.logger.warn("Failed to relay follow-up response", err)
11921
+ );
11922
+ }
11923
+ let assistantMessage;
11924
+ try {
11925
+ await this.session.logWriter.flush(this.session.payload.run_id);
11926
+ assistantMessage = this.session.logWriter.getFullAgentResponse(
11927
+ this.session.payload.run_id
11928
+ );
11929
+ } catch {
11930
+ this.logger.warn("Failed to extract assistant message from logs");
11931
+ }
11932
+ return {
11933
+ stopReason: result.stopReason,
11934
+ ...assistantMessage && { assistant_message: assistantMessage }
11935
+ };
11878
11936
  }
11879
11937
  case POSTHOG_NOTIFICATIONS.CANCEL:
11880
11938
  case "cancel": {
@@ -11897,6 +11955,28 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
11897
11955
  }
11898
11956
  }
11899
11957
  async initializeSession(payload, sseController) {
11958
+ if (this.initializationPromise) {
11959
+ this.logger.info("Waiting for in-progress initialization", {
11960
+ runId: payload.run_id
11961
+ });
11962
+ await this.initializationPromise;
11963
+ if (this.session && sseController) {
11964
+ this.session.sseController = sseController;
11965
+ this.replayPendingEvents();
11966
+ }
11967
+ return;
11968
+ }
11969
+ this.initializationPromise = this._doInitializeSession(
11970
+ payload,
11971
+ sseController
11972
+ );
11973
+ try {
11974
+ await this.initializationPromise;
11975
+ } finally {
11976
+ this.initializationPromise = null;
11977
+ }
11978
+ }
11979
+ async _doInitializeSession(payload, sseController) {
11900
11980
  if (this.session) {
11901
11981
  await this.cleanupSession();
11902
11982
  }
@@ -12083,6 +12163,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
12083
12163
  descriptionLength: initialPrompt.length,
12084
12164
  usedInitialPromptOverride: !!initialPromptOverride
12085
12165
  });
12166
+ this.session.logWriter.resetTurnMessages(payload.run_id);
12086
12167
  const result = await this.session.clientConnection.prompt({
12087
12168
  sessionId: this.session.acpSessionId,
12088
12169
  prompt: [{ type: "text", text: initialPrompt }]
@@ -12109,7 +12190,7 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`
12109
12190
  this.resumeState.conversation
12110
12191
  );
12111
12192
  const pendingUserMessage = this.getPendingUserMessage(taskRun);
12112
- const sandboxContext = this.resumeState.snapshotApplied ? `The sandbox environment (all files, packages, and code changes) has been fully restored from a snapshot.` : `The sandbox could not be restored from a snapshot (it may have expired). You are starting with a fresh environment but have the full conversation history below.`;
12193
+ const sandboxContext = this.resumeState.snapshotApplied ? `The workspace environment (all files, packages, and code changes) has been fully restored from where you left off.` : `The workspace files from the previous session were not restored (the file snapshot may have expired), so you are starting with a fresh environment. Your conversation history is fully preserved below.`;
12113
12194
  let resumePrompt;
12114
12195
  if (pendingUserMessage) {
12115
12196
  resumePrompt = `You are resuming a previous conversation. ${sandboxContext}
@@ -12140,6 +12221,7 @@ Continue from where you left off. The user is waiting for your response.`;
12140
12221
  snapshotApplied: this.resumeState.snapshotApplied
12141
12222
  });
12142
12223
  this.resumeState = null;
12224
+ this.session.logWriter.resetTurnMessages(payload.run_id);
12143
12225
  const result = await this.session.clientConnection.prompt({
12144
12226
  sessionId: this.session.acpSessionId,
12145
12227
  prompt: [{ type: "text", text: resumePrompt }]
@@ -12148,6 +12230,9 @@ Continue from where you left off. The user is waiting for your response.`;
12148
12230
  stopReason: result.stopReason
12149
12231
  });
12150
12232
  this.broadcastTurnComplete(result.stopReason);
12233
+ if (result.stopReason === "end_turn") {
12234
+ await this.relayAgentResponse(payload);
12235
+ }
12151
12236
  } catch (error) {
12152
12237
  this.logger.error("Failed to send resume message", error);
12153
12238
  if (this.session) {
@@ -12246,6 +12331,26 @@ Important:
12246
12331
  - Do NOT create a new branch or a new pull request.
12247
12332
  - Do NOT add "Co-Authored-By" trailers to commit messages.
12248
12333
  - Do NOT add "Generated with [Claude Code]" or similar attribution lines to PR descriptions.
12334
+ `;
12335
+ }
12336
+ if (!this.config.repositoryPath) {
12337
+ return `
12338
+ # Cloud Task Execution \u2014 No Repository Mode
12339
+
12340
+ You are a helpful assistant with access to PostHog via MCP tools. You can help with both code tasks and data/analytics questions.
12341
+
12342
+ When the user asks about analytics, data, metrics, events, funnels, dashboards, feature flags, experiments, or anything PostHog-related:
12343
+ - Use your PostHog MCP tools to query data, search insights, and provide real answers
12344
+ - Do NOT tell the user to check an external analytics platform \u2014 you ARE the analytics platform
12345
+ - Use tools like insight-query, query-run, event-definitions-list, and others to answer questions directly
12346
+
12347
+ When the user asks for code changes or software engineering tasks:
12348
+ - Let them know you can help but don't have a repository connected for this session
12349
+ - Offer to write code snippets, scripts, or provide guidance
12350
+
12351
+ Important:
12352
+ - Do NOT create branches, commits, or pull requests in this mode.
12353
+ - Prefer using MCP tools to answer questions with real data over giving generic advice.
12249
12354
  `;
12250
12355
  }
12251
12356
  return `
@@ -12348,6 +12453,9 @@ Important:
12348
12453
  }
12349
12454
  };
12350
12455
  },
12456
+ extNotification: async (method, params) => {
12457
+ this.logger.debug("Extension notification", { method, params });
12458
+ },
12351
12459
  sessionUpdate: async (params) => {
12352
12460
  if (params.update?.sessionUpdate === "tool_call_update") {
12353
12461
  const meta = params.update?._meta?.claudeCode;
@@ -12380,7 +12488,7 @@ Important:
12380
12488
  error
12381
12489
  });
12382
12490
  }
12383
- const message = this.session.logWriter.getLastAgentMessage(payload.run_id);
12491
+ const message = this.session.logWriter.getFullAgentResponse(payload.run_id);
12384
12492
  if (!message) {
12385
12493
  this.logger.warn("No agent message found for Slack relay", {
12386
12494
  taskId: payload.task_id,
@@ -12533,6 +12641,7 @@ Important:
12533
12641
  if (this.session.sseController) {
12534
12642
  this.session.sseController.close();
12535
12643
  }
12644
+ this.pendingEvents = [];
12536
12645
  this.session = null;
12537
12646
  }
12538
12647
  async captureTreeState() {
@@ -12581,6 +12690,16 @@ Important:
12581
12690
  broadcastEvent(event) {
12582
12691
  if (this.session?.sseController) {
12583
12692
  this.sendSseEvent(this.session.sseController, event);
12693
+ } else if (this.session) {
12694
+ this.pendingEvents.push(event);
12695
+ }
12696
+ }
12697
+ replayPendingEvents() {
12698
+ if (!this.session?.sseController || this.pendingEvents.length === 0) return;
12699
+ const events = this.pendingEvents;
12700
+ this.pendingEvents = [];
12701
+ for (const event of events) {
12702
+ this.sendSseEvent(this.session.sseController, event);
12584
12703
  }
12585
12704
  }
12586
12705
  sendSseEvent(controller, data) {