@posthog/agent 2.3.709 → 2.3.735

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/types.d.ts CHANGED
@@ -26,7 +26,7 @@ interface Task {
26
26
  slug?: string;
27
27
  title: string;
28
28
  description: string;
29
- origin_product: "error_tracking" | "eval_clusters" | "user_created" | "support_queue" | "session_summaries" | "signal_report";
29
+ origin_product: "error_tracking" | "eval_clusters" | "user_created" | "support_queue" | "session_summaries" | "signal_report" | "slack";
30
30
  signal_report?: string | null;
31
31
  github_integration?: number | null;
32
32
  repository: string;
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n GitHandoffCheckpoint,\n HandoffLocalGitState as GitHandoffLocalGitState,\n} from \"@posthog/git/handoff\";\n\n/**\n * Stored custom notification following ACP extensibility model.\n * Custom notifications use underscore-prefixed methods (e.g., `_posthog/phase_start`).\n * See: https://agentclientprotocol.com/docs/extensibility\n */\nexport interface StoredNotification {\n type: \"notification\";\n /** When this notification was stored */\n timestamp: string;\n /** JSON-RPC 2.0 notification (no id field = notification, not request) */\n notification: {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n };\n}\n\n/**\n * Type alias for stored log entries.\n */\nexport type StoredEntry = StoredNotification;\n\n// PostHog Task model (matches PostHog Code's OpenAPI schema)\nexport interface Task {\n id: string;\n task_number?: number;\n slug?: string;\n title: string;\n description: string;\n origin_product:\n | \"error_tracking\"\n | \"eval_clusters\"\n | \"user_created\"\n | \"support_queue\"\n | \"session_summaries\"\n | \"signal_report\";\n signal_report?: string | null; // Inbox report UUID when origin_product is \"signal_report\"\n github_integration?: number | null;\n repository: string; // Format: \"organization/repository\" (e.g., \"posthog/posthog-js\")\n json_schema?: Record<string, unknown> | null; // JSON schema for task output validation\n internal?: boolean;\n created_at: string;\n updated_at: string;\n created_by?: {\n id: number;\n uuid: string;\n distinct_id: string;\n first_name: string;\n email: string;\n };\n latest_run?: TaskRun;\n}\n\n// Log entry structure for TaskRun.log\n\nexport type ArtifactType =\n | \"plan\"\n | \"context\"\n | \"reference\"\n | \"output\"\n | \"artifact\"\n | \"user_attachment\";\n\nexport interface TaskRunArtifact {\n id?: string;\n name: string;\n type: ArtifactType;\n source?: string;\n size?: number;\n content_type?: string;\n storage_path?: string;\n uploaded_at?: string;\n}\n\nexport type TaskRunStatus =\n | \"not_started\"\n | \"queued\"\n | \"in_progress\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\nexport type TaskRunEnvironment = \"local\" | \"cloud\";\n\n// TaskRun model - represents individual execution runs of tasks\nexport interface TaskRun {\n id: string;\n task: string; // Task ID\n team: number;\n branch: string | null;\n stage: string | null; // Current stage (e.g., 'research', 'plan', 'build')\n environment: TaskRunEnvironment;\n status: TaskRunStatus;\n log_url: string;\n error_message: string | null;\n output: Record<string, unknown> | null; // Structured output (PR URL, commit SHA, etc.)\n state: Record<string, unknown>; // Intermediate run state (defaults to {}, never null)\n artifacts?: TaskRunArtifact[];\n created_at: string;\n updated_at: string;\n completed_at: string | null;\n}\n\nexport interface ProcessSpawnedCallback {\n onProcessSpawned?: (info: {\n pid: number;\n command: string;\n sessionId?: string;\n }) => void;\n onProcessExited?: (pid: number) => void;\n onMcpServersReady?: (serverNames: string[]) => void;\n}\n\nexport interface TaskExecutionOptions {\n repositoryPath?: string;\n adapter?: \"claude\" | \"codex\";\n model?: string;\n gatewayUrl?: string;\n codexBinaryPath?: string;\n instructions?: string;\n processCallbacks?: ProcessSpawnedCallback;\n /** Callback invoked when the agent calls the create_output tool for structured output */\n onStructuredOutput?: (output: Record<string, unknown>) => Promise<void>;\n /** Additional directories the agent process can access beyond cwd. */\n additionalDirectories?: string[];\n}\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport type OnLogCallback = (\n level: LogLevel,\n scope: string,\n message: string,\n data?: unknown,\n) => void;\n\nexport interface PostHogAPIConfig {\n apiUrl: string;\n getApiKey: () => string | Promise<string>;\n refreshApiKey?: () => string | Promise<string>;\n projectId: number;\n userAgent?: string;\n}\n\nexport interface OtelTransportConfig {\n /** PostHog ingest host, e.g., \"https://us.i.posthog.com\" */\n host: string;\n /** Project API key */\n apiKey: string;\n /** Override the logs endpoint path (default: /i/v1/logs) */\n logsPath?: string;\n}\n\nexport interface AgentConfig {\n posthog?: PostHogAPIConfig;\n /** OTEL transport config for shipping logs to PostHog Logs */\n otelTransport?: OtelTransportConfig;\n /** Skip session log persistence (e.g. for preview sessions with no real task) */\n skipLogPersistence?: boolean;\n /** Local cache path for instant log loading (e.g., ~/.posthog-code) */\n localCachePath?: string;\n /**\n * Annotate files the agent reads with PostHog enrichment (event volume,\n * flag rollout/staleness, experiment links). Defaults to enabled when\n * `posthog` config is present; set `{ enabled: false }` to opt out.\n */\n enricher?: { enabled?: boolean };\n debug?: boolean;\n onLog?: OnLogCallback;\n}\n\n// Device info for tracking where work happens\nexport interface DeviceInfo {\n type: \"local\" | \"cloud\";\n name?: string;\n}\n\n// Agent execution mode - for tracking interactive vs background runs, when backgrounded an agent will continue working without asking questions\nexport type AgentMode = \"interactive\" | \"background\";\n\n// Git file status codes\nexport type FileStatus = \"A\" | \"M\" | \"D\";\n\nexport interface FileChange {\n path: string;\n status: FileStatus;\n}\n\nexport type HandoffLocalGitState = GitHandoffLocalGitState;\n\nexport interface GitCheckpoint extends GitHandoffCheckpoint {\n artifactPath?: string;\n indexArtifactPath?: string;\n}\n\nexport interface GitCheckpointEvent extends GitCheckpoint {\n device?: DeviceInfo;\n}\n\n/**\n * Keeps the emitted `@posthog/agent/types` entrypoint as a runtime ESM module.\n *\n * `export {}` is stripped by tsup in this package, which leaves `dist/types.js`\n * empty and breaks downstream type resolution for the exported subpath.\n */\nexport const AGENT_TYPES_MODULE = true;\n"],"mappings":";AAkNO,IAAM,qBAAqB;","names":[]}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n GitHandoffCheckpoint,\n HandoffLocalGitState as GitHandoffLocalGitState,\n} from \"@posthog/git/handoff\";\n\n/**\n * Stored custom notification following ACP extensibility model.\n * Custom notifications use underscore-prefixed methods (e.g., `_posthog/phase_start`).\n * See: https://agentclientprotocol.com/docs/extensibility\n */\nexport interface StoredNotification {\n type: \"notification\";\n /** When this notification was stored */\n timestamp: string;\n /** JSON-RPC 2.0 notification (no id field = notification, not request) */\n notification: {\n jsonrpc: \"2.0\";\n method: string;\n params?: Record<string, unknown>;\n };\n}\n\n/**\n * Type alias for stored log entries.\n */\nexport type StoredEntry = StoredNotification;\n\n// PostHog Task model (matches PostHog Code's OpenAPI schema)\nexport interface Task {\n id: string;\n task_number?: number;\n slug?: string;\n title: string;\n description: string;\n origin_product:\n | \"error_tracking\"\n | \"eval_clusters\"\n | \"user_created\"\n | \"support_queue\"\n | \"session_summaries\"\n | \"signal_report\"\n | \"slack\";\n signal_report?: string | null; // Inbox report UUID when origin_product is \"signal_report\"\n github_integration?: number | null;\n repository: string; // Format: \"organization/repository\" (e.g., \"posthog/posthog-js\")\n json_schema?: Record<string, unknown> | null; // JSON schema for task output validation\n internal?: boolean;\n created_at: string;\n updated_at: string;\n created_by?: {\n id: number;\n uuid: string;\n distinct_id: string;\n first_name: string;\n email: string;\n };\n latest_run?: TaskRun;\n}\n\n// Log entry structure for TaskRun.log\n\nexport type ArtifactType =\n | \"plan\"\n | \"context\"\n | \"reference\"\n | \"output\"\n | \"artifact\"\n | \"user_attachment\";\n\nexport interface TaskRunArtifact {\n id?: string;\n name: string;\n type: ArtifactType;\n source?: string;\n size?: number;\n content_type?: string;\n storage_path?: string;\n uploaded_at?: string;\n}\n\nexport type TaskRunStatus =\n | \"not_started\"\n | \"queued\"\n | \"in_progress\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\nexport type TaskRunEnvironment = \"local\" | \"cloud\";\n\n// TaskRun model - represents individual execution runs of tasks\nexport interface TaskRun {\n id: string;\n task: string; // Task ID\n team: number;\n branch: string | null;\n stage: string | null; // Current stage (e.g., 'research', 'plan', 'build')\n environment: TaskRunEnvironment;\n status: TaskRunStatus;\n log_url: string;\n error_message: string | null;\n output: Record<string, unknown> | null; // Structured output (PR URL, commit SHA, etc.)\n state: Record<string, unknown>; // Intermediate run state (defaults to {}, never null)\n artifacts?: TaskRunArtifact[];\n created_at: string;\n updated_at: string;\n completed_at: string | null;\n}\n\nexport interface ProcessSpawnedCallback {\n onProcessSpawned?: (info: {\n pid: number;\n command: string;\n sessionId?: string;\n }) => void;\n onProcessExited?: (pid: number) => void;\n onMcpServersReady?: (serverNames: string[]) => void;\n}\n\nexport interface TaskExecutionOptions {\n repositoryPath?: string;\n adapter?: \"claude\" | \"codex\";\n model?: string;\n gatewayUrl?: string;\n codexBinaryPath?: string;\n instructions?: string;\n processCallbacks?: ProcessSpawnedCallback;\n /** Callback invoked when the agent calls the create_output tool for structured output */\n onStructuredOutput?: (output: Record<string, unknown>) => Promise<void>;\n /** Additional directories the agent process can access beyond cwd. */\n additionalDirectories?: string[];\n}\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport type OnLogCallback = (\n level: LogLevel,\n scope: string,\n message: string,\n data?: unknown,\n) => void;\n\nexport interface PostHogAPIConfig {\n apiUrl: string;\n getApiKey: () => string | Promise<string>;\n refreshApiKey?: () => string | Promise<string>;\n projectId: number;\n userAgent?: string;\n}\n\nexport interface OtelTransportConfig {\n /** PostHog ingest host, e.g., \"https://us.i.posthog.com\" */\n host: string;\n /** Project API key */\n apiKey: string;\n /** Override the logs endpoint path (default: /i/v1/logs) */\n logsPath?: string;\n}\n\nexport interface AgentConfig {\n posthog?: PostHogAPIConfig;\n /** OTEL transport config for shipping logs to PostHog Logs */\n otelTransport?: OtelTransportConfig;\n /** Skip session log persistence (e.g. for preview sessions with no real task) */\n skipLogPersistence?: boolean;\n /** Local cache path for instant log loading (e.g., ~/.posthog-code) */\n localCachePath?: string;\n /**\n * Annotate files the agent reads with PostHog enrichment (event volume,\n * flag rollout/staleness, experiment links). Defaults to enabled when\n * `posthog` config is present; set `{ enabled: false }` to opt out.\n */\n enricher?: { enabled?: boolean };\n debug?: boolean;\n onLog?: OnLogCallback;\n}\n\n// Device info for tracking where work happens\nexport interface DeviceInfo {\n type: \"local\" | \"cloud\";\n name?: string;\n}\n\n// Agent execution mode - for tracking interactive vs background runs, when backgrounded an agent will continue working without asking questions\nexport type AgentMode = \"interactive\" | \"background\";\n\n// Git file status codes\nexport type FileStatus = \"A\" | \"M\" | \"D\";\n\nexport interface FileChange {\n path: string;\n status: FileStatus;\n}\n\nexport type HandoffLocalGitState = GitHandoffLocalGitState;\n\nexport interface GitCheckpoint extends GitHandoffCheckpoint {\n artifactPath?: string;\n indexArtifactPath?: string;\n}\n\nexport interface GitCheckpointEvent extends GitCheckpoint {\n device?: DeviceInfo;\n}\n\n/**\n * Keeps the emitted `@posthog/agent/types` entrypoint as a runtime ESM module.\n *\n * `export {}` is stripped by tsup in this package, which leaves `dist/types.js`\n * empty and breaks downstream type resolution for the exported subpath.\n */\nexport const AGENT_TYPES_MODULE = true;\n"],"mappings":";AAmNO,IAAM,qBAAqB;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/agent",
3
- "version": "2.3.709",
3
+ "version": "2.3.735",
4
4
  "repository": "https://github.com/PostHog/code",
5
5
  "description": "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
6
6
  "exports": {
@@ -107,8 +107,8 @@
107
107
  "typescript": "^5.5.0",
108
108
  "vitest": "^2.1.8",
109
109
  "@posthog/shared": "1.0.0",
110
- "@posthog/git": "1.0.0",
111
- "@posthog/enricher": "1.0.0"
110
+ "@posthog/enricher": "1.0.0",
111
+ "@posthog/git": "1.0.0"
112
112
  },
113
113
  "dependencies": {
114
114
  "@agentclientprotocol/sdk": "0.19.0",
@@ -53,6 +53,7 @@ Fork of `@anthropic-ai/claude-agent-acp`. Upstream repo: https://github.com/anth
53
53
  | Auth methods | `claude-ai-login` + `console-login` | Returns empty `authMethods` | Auth handled externally |
54
54
  | Session fingerprinting | Implicit teardown on cwd/mcp change | Explicit `refreshSession()` | Caller-initiated is more predictable |
55
55
  | Shutdown on ACP close | Process exits | No standalone process | Agent is embedded in server |
56
+ | Unsupported slash commands | Loops silently on early idle | Emits "Unsupported slash command" chunk, gated on `initializationResult().commands` so plugin/skill commands (e.g. `/skills-store`) whose echoes use a fresh uuid are not false-flagged | The SDK consumes some slash commands without producing output (e.g. `/plugin` in non-interactive mode); without this we hang. The known-commands gate avoids racing plugin/skill loads where idle can arrive before the transformed user-message echo. |
56
57
 
57
58
  ## Changes Ported in v0.30.0 Sync
58
59
 
@@ -34,7 +34,11 @@ function makeAgent(): { agent: Agent; client: ClientMocks } {
34
34
  return { agent, client };
35
35
  }
36
36
 
37
- function installFakeSession(agent: Agent, sessionId: string): MockQuery {
37
+ function installFakeSession(
38
+ agent: Agent,
39
+ sessionId: string,
40
+ knownSlashCommands?: Set<string>,
41
+ ): MockQuery {
38
42
  const query = createMockQuery();
39
43
  const input = new Pushable();
40
44
  const abortController = new AbortController();
@@ -63,6 +67,7 @@ function installFakeSession(agent: Agent, sessionId: string): MockQuery {
63
67
  taskRunId: "run-1",
64
68
  lastContextWindowSize: 200_000,
65
69
  modelId: "claude-sonnet-4-6",
70
+ knownSlashCommands,
66
71
  };
67
72
 
68
73
  (agent as unknown as { session: typeof session }).session = session;
@@ -99,6 +104,7 @@ describe("ClaudeAcpAgent.prompt — early idle handling", () => {
99
104
  label: "unsupported slash command surfaces error and ends turn",
100
105
  sessionId: "s-slash",
101
106
  prompt: "/plugin install slack",
107
+ knownCommands: undefined,
102
108
  expectsUnsupportedChunk: true,
103
109
  commandInMessage: "/plugin",
104
110
  },
@@ -106,6 +112,16 @@ describe("ClaudeAcpAgent.prompt — early idle handling", () => {
106
112
  label: "non-slash prompt with early idle is silently skipped",
107
113
  sessionId: "s-regular",
108
114
  prompt: "hello",
115
+ knownCommands: undefined,
116
+ expectsUnsupportedChunk: false,
117
+ commandInMessage: null,
118
+ },
119
+ {
120
+ label:
121
+ "known plugin/skill command with early idle is not flagged as unsupported",
122
+ sessionId: "s-skill",
123
+ prompt: "/skills-store use my address pr review skill",
124
+ knownCommands: new Set(["skills-store"]),
109
125
  expectsUnsupportedChunk: false,
110
126
  commandInMessage: null,
111
127
  },
@@ -113,7 +129,11 @@ describe("ClaudeAcpAgent.prompt — early idle handling", () => {
113
129
 
114
130
  it.each(cases)("$label", async (tc) => {
115
131
  const { agent, client } = makeAgent();
116
- const query = installFakeSession(agent, tc.sessionId);
132
+ const query = installFakeSession(
133
+ agent,
134
+ tc.sessionId,
135
+ tc.knownCommands as Set<string> | undefined,
136
+ );
117
137
 
118
138
  const promptPromise = agent.prompt({
119
139
  sessionId: tc.sessionId,
@@ -43,6 +43,7 @@ import {
43
43
  type Query,
44
44
  query,
45
45
  type SDKUserMessage,
46
+ type SlashCommand,
46
47
  } from "@anthropic-ai/claude-agent-sdk";
47
48
  import { v7 as uuidv7 } from "uuid";
48
49
  import packageJson from "../../../package.json" with { type: "json" };
@@ -143,6 +144,17 @@ function readClaudeMdQuietly(cwd: string, logger: Logger): string | undefined {
143
144
  }
144
145
  }
145
146
 
147
+ function collectKnownSlashCommands(
148
+ commands: SlashCommand[] | undefined,
149
+ ): Set<string> {
150
+ const names = new Set<string>();
151
+ if (!commands) return names;
152
+ for (const cmd of commands) {
153
+ if (cmd.name) names.add(cmd.name);
154
+ }
155
+ return names;
156
+ }
157
+
146
158
  function sanitizeTitle(text: string): string {
147
159
  const sanitized = text
148
160
  .replace(/[\r\n]+/g, " ")
@@ -500,7 +512,17 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
500
512
  // and produced no output (e.g. /plugin in a non-interactive
501
513
  // context). Without this branch we would loop forever waiting
502
514
  // for an echo that never comes; surface a clear error instead.
503
- if (commandMatch) {
515
+ //
516
+ // Only fire for commands the SDK does NOT recognize. Plugin
517
+ // and skill commands (e.g. /skills-store) produce a fresh
518
+ // user-message echo with a new uuid that our replay check
519
+ // can't match, so an early idle here is a race, not a real
520
+ // "unsupported" — fall through and let the loop continue.
521
+ const cmdName = commandMatch?.[1].slice(1);
522
+ const known =
523
+ cmdName !== undefined &&
524
+ this.session.knownSlashCommands?.has(cmdName) === true;
525
+ if (commandMatch && !known) {
504
526
  const cmd = commandMatch[1];
505
527
  this.logger.warn(
506
528
  "Slash command produced no output; treating as unsupported",
@@ -520,6 +542,8 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
520
542
  }
521
543
  this.logger.debug("Skipping idle state before prompt replay", {
522
544
  sessionId: params.sessionId,
545
+ command: commandMatch?.[1],
546
+ known,
523
547
  });
524
548
  break;
525
549
  }
@@ -1305,6 +1329,9 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
1305
1329
  `Session ${forkSession ? "fork" : "resumption"} timed out for sessionId=${sessionId}`,
1306
1330
  );
1307
1331
  }
1332
+ session.knownSlashCommands = collectKnownSlashCommands(
1333
+ result.value.commands,
1334
+ );
1308
1335
  } catch (err) {
1309
1336
  settingsManager.dispose();
1310
1337
  if (
@@ -1356,6 +1383,9 @@ export class ClaudeAcpAgent extends BaseAcpAgent {
1356
1383
  `Session initialization timed out for sessionId=${sessionId}`,
1357
1384
  );
1358
1385
  }
1386
+ session.knownSlashCommands = collectKnownSlashCommands(
1387
+ initResult.value.commands,
1388
+ );
1359
1389
  } catch (err) {
1360
1390
  settingsManager.dispose();
1361
1391
  this.logger.error("Session initialization failed", {
@@ -68,6 +68,13 @@ export type Session = BaseSession & {
68
68
  emitRawSDKMessages: boolean | SDKMessageFilter[];
69
69
  /** Refreshed at session init and on MCP/skill changes. */
70
70
  contextBreakdownBaseline?: ContextBreakdownBaseline;
71
+ /**
72
+ * Slash command names (without leading slash) the SDK recognizes for this
73
+ * session — built-ins plus plugin/skill commands. Captured from the SDK's
74
+ * init response. Used to distinguish "command produced no output" from
75
+ * "command is genuinely unknown" when the session goes idle without an echo.
76
+ */
77
+ knownSlashCommands?: Set<string>;
71
78
  };
72
79
 
73
80
  export type ToolUseCache = {
@@ -1,10 +1,11 @@
1
1
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import type { Task } from "../types";
2
3
  import { AgentServer } from "./agent-server";
3
4
 
4
5
  interface TestableServer {
5
6
  configureEnvironment(args?: {
6
7
  isInternal?: boolean;
7
- originProduct?: string | null;
8
+ originProduct?: Task["origin_product"] | null;
8
9
  signalReportId?: string | null;
9
10
  taskId?: string | null;
10
11
  taskRunId?: string | null;
@@ -162,6 +163,43 @@ describe("AgentServer.configureEnvironment", () => {
162
163
  );
163
164
  });
164
165
 
166
+ it("tags as slack_app when the task was initiated from Slack", () => {
167
+ buildServer("interactive").configureEnvironment({
168
+ originProduct: "slack",
169
+ });
170
+
171
+ expect(process.env.LLM_GATEWAY_URL).toBe(
172
+ "https://gateway.us.posthog.com/slack_app",
173
+ );
174
+ expect(process.env.ANTHROPIC_BASE_URL).toBe(
175
+ "https://gateway.us.posthog.com/slack_app",
176
+ );
177
+ expect(process.env.OPENAI_BASE_URL).toBe(
178
+ "https://gateway.us.posthog.com/slack_app/v1",
179
+ );
180
+ });
181
+
182
+ it("prefers slack_app over background_agents when both signals are present", () => {
183
+ buildServer("interactive").configureEnvironment({
184
+ isInternal: true,
185
+ originProduct: "slack",
186
+ });
187
+
188
+ expect(process.env.LLM_GATEWAY_URL).toBe(
189
+ "https://gateway.us.posthog.com/slack_app",
190
+ );
191
+ });
192
+
193
+ it("falls back to posthog_code for non-slack origin products", () => {
194
+ buildServer("background").configureEnvironment({
195
+ originProduct: "user_created",
196
+ });
197
+
198
+ expect(process.env.LLM_GATEWAY_URL).toBe(
199
+ "https://gateway.us.posthog.com/posthog_code",
200
+ );
201
+ });
202
+
165
203
  it("respects the LLM_GATEWAY_URL override regardless of internal flag", () => {
166
204
  process.env.LLM_GATEWAY_URL = "http://ngrok.test/proxy";
167
205
 
@@ -43,6 +43,7 @@ import type {
43
43
  GitCheckpointEvent,
44
44
  HandoffLocalGitState,
45
45
  LogLevel,
46
+ Task,
46
47
  TaskRun,
47
48
  TaskRunArtifact,
48
49
  } from "../types";
@@ -1860,7 +1861,7 @@ ${signedCommitInstructions}
1860
1861
  taskUserId,
1861
1862
  }: {
1862
1863
  isInternal?: boolean;
1863
- originProduct?: string | null;
1864
+ originProduct?: Task["origin_product"] | null;
1864
1865
  signalReportId?: string | null;
1865
1866
  taskId?: string | null;
1866
1867
  taskRunId?: string | null;
package/src/types.ts CHANGED
@@ -38,7 +38,8 @@ export interface Task {
38
38
  | "user_created"
39
39
  | "support_queue"
40
40
  | "session_summaries"
41
- | "signal_report";
41
+ | "signal_report"
42
+ | "slack";
42
43
  signal_report?: string | null; // Inbox report UUID when origin_product is "signal_report"
43
44
  github_integration?: number | null;
44
45
  repository: string; // Format: "organization/repository" (e.g., "posthog/posthog-js")
@@ -1,4 +1,8 @@
1
- export type GatewayProduct = "posthog_code" | "background_agents" | "signals";
1
+ export type GatewayProduct =
2
+ | "posthog_code"
3
+ | "background_agents"
4
+ | "signals"
5
+ | "slack_app";
2
6
 
3
7
  export function resolveGatewayProduct({
4
8
  isInternal,
@@ -7,6 +11,9 @@ export function resolveGatewayProduct({
7
11
  isInternal?: boolean;
8
12
  originProduct?: string | null;
9
13
  } = {}): GatewayProduct {
14
+ if (originProduct === "slack") {
15
+ return "slack_app";
16
+ }
10
17
  if (isInternal) {
11
18
  return originProduct === "signal_report" ? "signals" : "background_agents";
12
19
  }