@posthog/agent 2.3.443 → 2.3.454

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.
@@ -10,6 +10,6 @@ interface PermissionOption {
10
10
  };
11
11
  }
12
12
  declare function buildPermissionOptions(toolName: string, toolInput: Record<string, unknown>, repoRoot?: string, suggestions?: PermissionUpdate[]): PermissionOption[];
13
- declare function buildExitPlanModePermissionOptions(): PermissionOption[];
13
+ declare function buildExitPlanModePermissionOptions(previousMode?: string): PermissionOption[];
14
14
 
15
15
  export { type PermissionOption, buildExitPlanModePermissionOptions, buildPermissionOptions };
@@ -149,7 +149,13 @@ function buildPermissionOptions(toolName, toolInput, repoRoot, suggestions) {
149
149
  }
150
150
  return permissionOptions("Yes, always allow");
151
151
  }
152
- function buildExitPlanModePermissionOptions() {
152
+ var CONTINUE_LABELS = {
153
+ auto: 'Yes, continue in "auto" mode',
154
+ acceptEdits: "Yes, continue auto-accepting edits",
155
+ default: "Yes, continue manually approving edits",
156
+ bypassPermissions: "Yes, continue bypassing all permissions"
157
+ };
158
+ function buildExitPlanModePermissionOptions(previousMode) {
153
159
  const options = [];
154
160
  if (ALLOW_BYPASS) {
155
161
  options.push({
@@ -173,14 +179,27 @@ function buildExitPlanModePermissionOptions() {
173
179
  kind: "allow_once",
174
180
  name: "Yes, and manually approve edits",
175
181
  optionId: "default"
176
- },
177
- {
178
- kind: "reject_once",
179
- name: "No, and tell the agent what to do differently",
180
- optionId: "reject_with_feedback",
181
- _meta: { customInput: true }
182
182
  }
183
183
  );
184
+ const previousIndex = previousMode ? options.findIndex((opt) => opt.optionId === previousMode) : -1;
185
+ if (previousIndex > 0) {
186
+ const [previous] = options.splice(previousIndex, 1);
187
+ const continueLabel = CONTINUE_LABELS[previous.optionId];
188
+ options.unshift(
189
+ continueLabel ? { ...previous, name: continueLabel } : previous
190
+ );
191
+ } else if (previousIndex === 0) {
192
+ const continueLabel = CONTINUE_LABELS[options[0].optionId];
193
+ if (continueLabel) {
194
+ options[0] = { ...options[0], name: continueLabel };
195
+ }
196
+ }
197
+ options.push({
198
+ kind: "reject_once",
199
+ name: "No, and tell the agent what to do differently",
200
+ optionId: "reject_with_feedback",
201
+ _meta: { customInput: true }
202
+ });
184
203
  return options;
185
204
  }
186
205
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/utils/common.ts","../../../../src/execution-mode.ts","../../../../src/adapters/claude/tools.ts","../../../../src/adapters/claude/permissions/permission-options.ts"],"sourcesContent":["import type { Logger } from \"./logger\";\n\n/**\n * Races an operation against a timeout.\n * Returns success with the value if the operation completes in time,\n * or timeout if the operation takes longer than the specified duration.\n */\nexport async function withTimeout<T>(\n operation: Promise<T>,\n timeoutMs: number,\n): Promise<{ result: \"success\"; value: T } | { result: \"timeout\" }> {\n const timeoutPromise = new Promise<{ result: \"timeout\" }>((resolve) =>\n setTimeout(() => resolve({ result: \"timeout\" }), timeoutMs),\n );\n const operationPromise = operation.then((value) => ({\n result: \"success\" as const,\n value,\n }));\n return Promise.race([operationPromise, timeoutPromise]);\n}\n\nexport const IS_ROOT =\n typeof process !== \"undefined\" &&\n (process.geteuid?.() ?? process.getuid?.()) === 0;\n\nexport const ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;\n\nexport function unreachable(value: never, logger: Logger): void {\n let valueAsString: string;\n try {\n valueAsString = JSON.stringify(value);\n } catch {\n valueAsString = String(value);\n }\n logger.error(`Unexpected case: ${valueAsString}`);\n}\n","import { ALLOW_BYPASS } from \"./utils/common\";\n\nexport interface ModeInfo {\n id: string;\n name: string;\n description: string;\n}\n\nconst availableModes: ModeInfo[] = [\n {\n id: \"default\",\n name: \"Default\",\n description: \"Standard behavior, prompts for dangerous operations\",\n },\n {\n id: \"acceptEdits\",\n name: \"Accept Edits\",\n description: \"Auto-accept file edit operations\",\n },\n {\n id: \"plan\",\n name: \"Plan Mode\",\n description: \"Planning mode, no actual tool execution\",\n },\n];\n\nif (ALLOW_BYPASS) {\n availableModes.push(\n {\n id: \"bypassPermissions\",\n name: \"Bypass Permissions\",\n description: \"Auto-accept all permission requests\",\n },\n {\n id: \"auto\",\n name: \"Auto Mode\",\n description: \"Use a model classifier to approve/deny permission prompts\",\n },\n );\n}\n\n// Expose execution mode IDs in type-safe order for type checks\nexport const CODE_EXECUTION_MODES = [\n \"default\",\n \"acceptEdits\",\n \"plan\",\n \"bypassPermissions\",\n \"auto\",\n] as const;\n\nexport type CodeExecutionMode = (typeof CODE_EXECUTION_MODES)[number];\n\nexport function isCodeExecutionMode(mode: string): mode is CodeExecutionMode {\n return (CODE_EXECUTION_MODES as readonly string[]).includes(mode);\n}\n\nexport function getAvailableModes(): ModeInfo[] {\n return ALLOW_BYPASS\n ? availableModes\n : availableModes.filter((m) => m.id !== \"bypassPermissions\");\n}\n\n// --- Codex-native modes ---\n\nexport const CODEX_NATIVE_MODES = [\"auto\", \"read-only\", \"full-access\"] as const;\n\nexport type CodexNativeMode = (typeof CODEX_NATIVE_MODES)[number];\n\n/** Union of all permission mode IDs across adapters */\nexport type PermissionMode = CodeExecutionMode | CodexNativeMode;\n\nexport function isCodexNativeMode(mode: string): mode is CodexNativeMode {\n return (CODEX_NATIVE_MODES as readonly string[]).includes(mode);\n}\n\nconst codexModes: ModeInfo[] = [\n {\n id: \"read-only\",\n name: \"Read Only\",\n description: \"Read-only access, no file modifications\",\n },\n {\n id: \"auto\",\n name: \"Auto\",\n description: \"Standard behavior, prompts for dangerous operations\",\n },\n];\n\nif (ALLOW_BYPASS) {\n codexModes.push({\n id: \"full-access\",\n name: \"Full Access\",\n description: \"Auto-accept all permission requests\",\n });\n}\n\nexport function getAvailableCodexModes(): ModeInfo[] {\n return ALLOW_BYPASS\n ? codexModes\n : codexModes.filter((m) => m.id !== \"full-access\");\n}\n","export {\n CODE_EXECUTION_MODES,\n type CodeExecutionMode,\n getAvailableModes,\n type ModeInfo,\n} from \"../../execution-mode\";\n\nimport type { CodeExecutionMode } from \"../../execution-mode\";\nimport { isMcpToolReadOnly } from \"./mcp/tool-metadata\";\n\nexport const READ_TOOLS: Set<string> = new Set([\"Read\", \"NotebookRead\"]);\n\nexport const WRITE_TOOLS: Set<string> = new Set([\n \"Edit\",\n \"Write\",\n \"NotebookEdit\",\n]);\n\nexport const BASH_TOOLS: Set<string> = new Set([\n \"Bash\",\n \"BashOutput\",\n \"KillShell\",\n]);\n\nexport const SEARCH_TOOLS: Set<string> = new Set([\"Glob\", \"Grep\", \"LS\"]);\n\nexport const WEB_TOOLS: Set<string> = new Set([\"WebSearch\", \"WebFetch\"]);\n\nexport const AGENT_TOOLS: Set<string> = new Set([\n \"Task\",\n \"Agent\",\n \"TodoWrite\",\n \"Skill\",\n]);\n\nconst BASE_ALLOWED_TOOLS = [\n ...READ_TOOLS,\n ...SEARCH_TOOLS,\n ...WEB_TOOLS,\n ...AGENT_TOOLS,\n];\n\nconst AUTO_ALLOWED_TOOLS: Record<string, Set<string>> = {\n auto: new Set(BASE_ALLOWED_TOOLS),\n default: new Set(BASE_ALLOWED_TOOLS),\n acceptEdits: new Set([...BASE_ALLOWED_TOOLS, ...WRITE_TOOLS]),\n plan: new Set(BASE_ALLOWED_TOOLS),\n};\n\nexport function isToolAllowedForMode(\n toolName: string,\n mode: CodeExecutionMode,\n): boolean {\n if (mode === \"bypassPermissions\") {\n return true;\n }\n if (AUTO_ALLOWED_TOOLS[mode]?.has(toolName) === true) {\n return true;\n }\n if (isMcpToolReadOnly(toolName)) {\n return true;\n }\n return false;\n}\n","import type { PermissionUpdate } from \"@anthropic-ai/claude-agent-sdk\";\nimport { ALLOW_BYPASS } from \"../../../utils/common\";\nimport { BASH_TOOLS, READ_TOOLS, SEARCH_TOOLS, WRITE_TOOLS } from \"../tools\";\n\nexport interface PermissionOption {\n kind: \"allow_once\" | \"allow_always\" | \"reject_once\" | \"reject_always\";\n name: string;\n optionId: string;\n _meta?: { description?: string; customInput?: boolean };\n}\n\nfunction permissionOptions(allowAlwaysLabel: string): PermissionOption[] {\n return [\n { kind: \"allow_once\", name: \"Yes\", optionId: \"allow\" },\n { kind: \"allow_always\", name: allowAlwaysLabel, optionId: \"allow_always\" },\n {\n kind: \"reject_once\",\n name: \"No, and tell the agent what to do differently\",\n optionId: \"reject\",\n _meta: { customInput: true },\n },\n ];\n}\n\nexport function buildPermissionOptions(\n toolName: string,\n toolInput: Record<string, unknown>,\n repoRoot?: string,\n suggestions?: PermissionUpdate[],\n): PermissionOption[] {\n if (BASH_TOOLS.has(toolName)) {\n const rawRuleContent = suggestions\n ?.flatMap((s) => (\"rules\" in s ? s.rules : []))\n .find((r) => r.toolName === \"Bash\" && r.ruleContent)?.ruleContent;\n const ruleContent = rawRuleContent?.replace(/:?\\*$/, \"\");\n\n const command = toolInput?.command as string | undefined;\n const cmdName = command?.split(/\\s+/)[0] ?? \"this command\";\n const scopeLabel = repoRoot ? ` in ${repoRoot}` : \"\";\n const label = ruleContent ?? `\\`${cmdName}\\` commands`;\n\n return permissionOptions(\n `Yes, and don't ask again for ${label}${scopeLabel}`,\n );\n }\n\n if (toolName === \"BashOutput\") {\n return permissionOptions(\"Yes, allow all background process reads\");\n }\n\n if (toolName === \"KillShell\") {\n return permissionOptions(\"Yes, allow killing processes\");\n }\n\n if (WRITE_TOOLS.has(toolName)) {\n return permissionOptions(\"Yes, allow all edits during this session\");\n }\n\n if (READ_TOOLS.has(toolName)) {\n return permissionOptions(\"Yes, allow all reads during this session\");\n }\n\n if (SEARCH_TOOLS.has(toolName)) {\n return permissionOptions(\"Yes, allow all searches during this session\");\n }\n\n if (toolName === \"WebFetch\") {\n const url = toolInput?.url as string | undefined;\n let domain = \"\";\n try {\n domain = url ? new URL(url).hostname : \"\";\n } catch {}\n return permissionOptions(\n domain\n ? `Yes, allow all fetches from ${domain}`\n : \"Yes, allow all fetches\",\n );\n }\n\n if (toolName === \"WebSearch\") {\n return permissionOptions(\"Yes, allow all web searches\");\n }\n\n if (toolName === \"Task\") {\n return permissionOptions(\"Yes, allow all sub-tasks\");\n }\n\n if (toolName === \"TodoWrite\") {\n return permissionOptions(\"Yes, allow all todo updates\");\n }\n\n return permissionOptions(\"Yes, always allow\");\n}\n\nexport function buildExitPlanModePermissionOptions(): PermissionOption[] {\n const options: PermissionOption[] = [];\n\n if (ALLOW_BYPASS) {\n options.push({\n kind: \"allow_always\",\n name: \"Yes, bypass all permissions\",\n optionId: \"bypassPermissions\",\n });\n }\n\n options.push(\n {\n kind: \"allow_always\",\n name: 'Yes, and use \"auto\" mode',\n optionId: \"auto\",\n },\n {\n kind: \"allow_always\",\n name: \"Yes, and auto-accept edits\",\n optionId: \"acceptEdits\",\n },\n {\n kind: \"allow_once\",\n name: \"Yes, and manually approve edits\",\n optionId: \"default\",\n },\n {\n kind: \"reject_once\",\n name: \"No, and tell the agent what to do differently\",\n optionId: \"reject_with_feedback\",\n _meta: { customInput: true },\n },\n );\n\n return options;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/utils/common.ts","../../../../src/execution-mode.ts","../../../../src/adapters/claude/tools.ts","../../../../src/adapters/claude/permissions/permission-options.ts"],"sourcesContent":["import type { Logger } from \"./logger\";\n\n/**\n * Races an operation against a timeout.\n * Returns success with the value if the operation completes in time,\n * or timeout if the operation takes longer than the specified duration.\n */\nexport async function withTimeout<T>(\n operation: Promise<T>,\n timeoutMs: number,\n): Promise<{ result: \"success\"; value: T } | { result: \"timeout\" }> {\n const timeoutPromise = new Promise<{ result: \"timeout\" }>((resolve) =>\n setTimeout(() => resolve({ result: \"timeout\" }), timeoutMs),\n );\n const operationPromise = operation.then((value) => ({\n result: \"success\" as const,\n value,\n }));\n return Promise.race([operationPromise, timeoutPromise]);\n}\n\nexport const IS_ROOT =\n typeof process !== \"undefined\" &&\n (process.geteuid?.() ?? process.getuid?.()) === 0;\n\nexport const ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;\n\nexport function unreachable(value: never, logger: Logger): void {\n let valueAsString: string;\n try {\n valueAsString = JSON.stringify(value);\n } catch {\n valueAsString = String(value);\n }\n logger.error(`Unexpected case: ${valueAsString}`);\n}\n","import { ALLOW_BYPASS } from \"./utils/common\";\n\nexport interface ModeInfo {\n id: string;\n name: string;\n description: string;\n}\n\nconst availableModes: ModeInfo[] = [\n {\n id: \"default\",\n name: \"Default\",\n description: \"Standard behavior, prompts for dangerous operations\",\n },\n {\n id: \"acceptEdits\",\n name: \"Accept Edits\",\n description: \"Auto-accept file edit operations\",\n },\n {\n id: \"plan\",\n name: \"Plan Mode\",\n description: \"Planning mode, no actual tool execution\",\n },\n];\n\nif (ALLOW_BYPASS) {\n availableModes.push(\n {\n id: \"bypassPermissions\",\n name: \"Bypass Permissions\",\n description: \"Auto-accept all permission requests\",\n },\n {\n id: \"auto\",\n name: \"Auto Mode\",\n description: \"Use a model classifier to approve/deny permission prompts\",\n },\n );\n}\n\n// Expose execution mode IDs in type-safe order for type checks\nexport const CODE_EXECUTION_MODES = [\n \"default\",\n \"acceptEdits\",\n \"plan\",\n \"bypassPermissions\",\n \"auto\",\n] as const;\n\nexport type CodeExecutionMode = (typeof CODE_EXECUTION_MODES)[number];\n\nexport function isCodeExecutionMode(mode: string): mode is CodeExecutionMode {\n return (CODE_EXECUTION_MODES as readonly string[]).includes(mode);\n}\n\nexport function getAvailableModes(): ModeInfo[] {\n return ALLOW_BYPASS\n ? availableModes\n : availableModes.filter((m) => m.id !== \"bypassPermissions\");\n}\n\n// --- Codex-native modes ---\n\nexport const CODEX_NATIVE_MODES = [\"auto\", \"read-only\", \"full-access\"] as const;\n\nexport type CodexNativeMode = (typeof CODEX_NATIVE_MODES)[number];\n\n/** Union of all permission mode IDs across adapters */\nexport type PermissionMode = CodeExecutionMode | CodexNativeMode;\n\nexport function isCodexNativeMode(mode: string): mode is CodexNativeMode {\n return (CODEX_NATIVE_MODES as readonly string[]).includes(mode);\n}\n\nconst codexModes: ModeInfo[] = [\n {\n id: \"read-only\",\n name: \"Read Only\",\n description: \"Read-only access, no file modifications\",\n },\n {\n id: \"auto\",\n name: \"Auto\",\n description: \"Standard behavior, prompts for dangerous operations\",\n },\n];\n\nif (ALLOW_BYPASS) {\n codexModes.push({\n id: \"full-access\",\n name: \"Full Access\",\n description: \"Auto-accept all permission requests\",\n });\n}\n\nexport function getAvailableCodexModes(): ModeInfo[] {\n return ALLOW_BYPASS\n ? codexModes\n : codexModes.filter((m) => m.id !== \"full-access\");\n}\n","export {\n CODE_EXECUTION_MODES,\n type CodeExecutionMode,\n getAvailableModes,\n type ModeInfo,\n} from \"../../execution-mode\";\n\nimport type { CodeExecutionMode } from \"../../execution-mode\";\nimport { isMcpToolReadOnly } from \"./mcp/tool-metadata\";\n\nexport const READ_TOOLS: Set<string> = new Set([\"Read\", \"NotebookRead\"]);\n\nexport const WRITE_TOOLS: Set<string> = new Set([\n \"Edit\",\n \"Write\",\n \"NotebookEdit\",\n]);\n\nexport const BASH_TOOLS: Set<string> = new Set([\n \"Bash\",\n \"BashOutput\",\n \"KillShell\",\n]);\n\nexport const SEARCH_TOOLS: Set<string> = new Set([\"Glob\", \"Grep\", \"LS\"]);\n\nexport const WEB_TOOLS: Set<string> = new Set([\"WebSearch\", \"WebFetch\"]);\n\nexport const AGENT_TOOLS: Set<string> = new Set([\n \"Task\",\n \"Agent\",\n \"TodoWrite\",\n \"Skill\",\n]);\n\nconst BASE_ALLOWED_TOOLS = [\n ...READ_TOOLS,\n ...SEARCH_TOOLS,\n ...WEB_TOOLS,\n ...AGENT_TOOLS,\n];\n\nconst AUTO_ALLOWED_TOOLS: Record<string, Set<string>> = {\n auto: new Set(BASE_ALLOWED_TOOLS),\n default: new Set(BASE_ALLOWED_TOOLS),\n acceptEdits: new Set([...BASE_ALLOWED_TOOLS, ...WRITE_TOOLS]),\n plan: new Set(BASE_ALLOWED_TOOLS),\n};\n\nexport function isToolAllowedForMode(\n toolName: string,\n mode: CodeExecutionMode,\n): boolean {\n if (mode === \"bypassPermissions\") {\n return true;\n }\n if (AUTO_ALLOWED_TOOLS[mode]?.has(toolName) === true) {\n return true;\n }\n if (isMcpToolReadOnly(toolName)) {\n return true;\n }\n return false;\n}\n","import type { PermissionUpdate } from \"@anthropic-ai/claude-agent-sdk\";\nimport { ALLOW_BYPASS } from \"../../../utils/common\";\nimport { BASH_TOOLS, READ_TOOLS, SEARCH_TOOLS, WRITE_TOOLS } from \"../tools\";\n\nexport interface PermissionOption {\n kind: \"allow_once\" | \"allow_always\" | \"reject_once\" | \"reject_always\";\n name: string;\n optionId: string;\n _meta?: { description?: string; customInput?: boolean };\n}\n\nfunction permissionOptions(allowAlwaysLabel: string): PermissionOption[] {\n return [\n { kind: \"allow_once\", name: \"Yes\", optionId: \"allow\" },\n { kind: \"allow_always\", name: allowAlwaysLabel, optionId: \"allow_always\" },\n {\n kind: \"reject_once\",\n name: \"No, and tell the agent what to do differently\",\n optionId: \"reject\",\n _meta: { customInput: true },\n },\n ];\n}\n\nexport function buildPermissionOptions(\n toolName: string,\n toolInput: Record<string, unknown>,\n repoRoot?: string,\n suggestions?: PermissionUpdate[],\n): PermissionOption[] {\n if (BASH_TOOLS.has(toolName)) {\n const rawRuleContent = suggestions\n ?.flatMap((s) => (\"rules\" in s ? s.rules : []))\n .find((r) => r.toolName === \"Bash\" && r.ruleContent)?.ruleContent;\n const ruleContent = rawRuleContent?.replace(/:?\\*$/, \"\");\n\n const command = toolInput?.command as string | undefined;\n const cmdName = command?.split(/\\s+/)[0] ?? \"this command\";\n const scopeLabel = repoRoot ? ` in ${repoRoot}` : \"\";\n const label = ruleContent ?? `\\`${cmdName}\\` commands`;\n\n return permissionOptions(\n `Yes, and don't ask again for ${label}${scopeLabel}`,\n );\n }\n\n if (toolName === \"BashOutput\") {\n return permissionOptions(\"Yes, allow all background process reads\");\n }\n\n if (toolName === \"KillShell\") {\n return permissionOptions(\"Yes, allow killing processes\");\n }\n\n if (WRITE_TOOLS.has(toolName)) {\n return permissionOptions(\"Yes, allow all edits during this session\");\n }\n\n if (READ_TOOLS.has(toolName)) {\n return permissionOptions(\"Yes, allow all reads during this session\");\n }\n\n if (SEARCH_TOOLS.has(toolName)) {\n return permissionOptions(\"Yes, allow all searches during this session\");\n }\n\n if (toolName === \"WebFetch\") {\n const url = toolInput?.url as string | undefined;\n let domain = \"\";\n try {\n domain = url ? new URL(url).hostname : \"\";\n } catch {}\n return permissionOptions(\n domain\n ? `Yes, allow all fetches from ${domain}`\n : \"Yes, allow all fetches\",\n );\n }\n\n if (toolName === \"WebSearch\") {\n return permissionOptions(\"Yes, allow all web searches\");\n }\n\n if (toolName === \"Task\") {\n return permissionOptions(\"Yes, allow all sub-tasks\");\n }\n\n if (toolName === \"TodoWrite\") {\n return permissionOptions(\"Yes, allow all todo updates\");\n }\n\n return permissionOptions(\"Yes, always allow\");\n}\n\nconst CONTINUE_LABELS: Record<string, string> = {\n auto: 'Yes, continue in \"auto\" mode',\n acceptEdits: \"Yes, continue auto-accepting edits\",\n default: \"Yes, continue manually approving edits\",\n bypassPermissions: \"Yes, continue bypassing all permissions\",\n};\n\nexport function buildExitPlanModePermissionOptions(\n previousMode?: string,\n): PermissionOption[] {\n const options: PermissionOption[] = [];\n\n if (ALLOW_BYPASS) {\n options.push({\n kind: \"allow_always\",\n name: \"Yes, bypass all permissions\",\n optionId: \"bypassPermissions\",\n });\n }\n\n options.push(\n {\n kind: \"allow_always\",\n name: 'Yes, and use \"auto\" mode',\n optionId: \"auto\",\n },\n {\n kind: \"allow_always\",\n name: \"Yes, and auto-accept edits\",\n optionId: \"acceptEdits\",\n },\n {\n kind: \"allow_once\",\n name: \"Yes, and manually approve edits\",\n optionId: \"default\",\n },\n );\n\n const previousIndex = previousMode\n ? options.findIndex((opt) => opt.optionId === previousMode)\n : -1;\n if (previousIndex > 0) {\n const [previous] = options.splice(previousIndex, 1);\n const continueLabel = CONTINUE_LABELS[previous.optionId];\n options.unshift(\n continueLabel ? { ...previous, name: continueLabel } : previous,\n );\n } else if (previousIndex === 0) {\n const continueLabel = CONTINUE_LABELS[options[0].optionId];\n if (continueLabel) {\n options[0] = { ...options[0], name: continueLabel };\n }\n }\n\n options.push({\n kind: \"reject_once\",\n name: \"No, and tell the agent what to do differently\",\n optionId: \"reject_with_feedback\",\n _meta: { customInput: true },\n });\n\n return options;\n}\n"],"mappings":"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","names":[]}
package/dist/agent.js CHANGED
@@ -4030,7 +4030,7 @@ import { v7 as uuidv7 } from "uuid";
4030
4030
  // package.json
4031
4031
  var package_default = {
4032
4032
  name: "@posthog/agent",
4033
- version: "2.3.443",
4033
+ version: "2.3.454",
4034
4034
  repository: "https://github.com/PostHog/code",
4035
4035
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
4036
4036
  exports: {
@@ -10346,7 +10346,13 @@ function buildPermissionOptions(toolName, toolInput, repoRoot, suggestions) {
10346
10346
  }
10347
10347
  return permissionOptions("Yes, always allow");
10348
10348
  }
10349
- function buildExitPlanModePermissionOptions() {
10349
+ var CONTINUE_LABELS = {
10350
+ auto: 'Yes, continue in "auto" mode',
10351
+ acceptEdits: "Yes, continue auto-accepting edits",
10352
+ default: "Yes, continue manually approving edits",
10353
+ bypassPermissions: "Yes, continue bypassing all permissions"
10354
+ };
10355
+ function buildExitPlanModePermissionOptions(previousMode) {
10350
10356
  const options = [];
10351
10357
  if (ALLOW_BYPASS) {
10352
10358
  options.push({
@@ -10370,14 +10376,27 @@ function buildExitPlanModePermissionOptions() {
10370
10376
  kind: "allow_once",
10371
10377
  name: "Yes, and manually approve edits",
10372
10378
  optionId: "default"
10373
- },
10374
- {
10375
- kind: "reject_once",
10376
- name: "No, and tell the agent what to do differently",
10377
- optionId: "reject_with_feedback",
10378
- _meta: { customInput: true }
10379
10379
  }
10380
10380
  );
10381
+ const previousIndex = previousMode ? options.findIndex((opt) => opt.optionId === previousMode) : -1;
10382
+ if (previousIndex > 0) {
10383
+ const [previous] = options.splice(previousIndex, 1);
10384
+ const continueLabel = CONTINUE_LABELS[previous.optionId];
10385
+ options.unshift(
10386
+ continueLabel ? { ...previous, name: continueLabel } : previous
10387
+ );
10388
+ } else if (previousIndex === 0) {
10389
+ const continueLabel = CONTINUE_LABELS[options[0].optionId];
10390
+ if (continueLabel) {
10391
+ options[0] = { ...options[0], name: continueLabel };
10392
+ }
10393
+ }
10394
+ options.push({
10395
+ kind: "reject_once",
10396
+ name: "No, and tell the agent what to do differently",
10397
+ optionId: "reject_with_feedback",
10398
+ _meta: { customInput: true }
10399
+ });
10381
10400
  return options;
10382
10401
  }
10383
10402
 
@@ -10432,13 +10451,13 @@ async function validatePlanContent(planText, context) {
10432
10451
  return { valid: true };
10433
10452
  }
10434
10453
  async function requestPlanApproval(context, updatedInput) {
10435
- const { client, sessionId, toolUseID } = context;
10454
+ const { client, sessionId, toolUseID, session } = context;
10436
10455
  const toolInfo = toolInfoFromToolUse({
10437
10456
  name: context.toolName,
10438
10457
  input: updatedInput
10439
10458
  });
10440
10459
  return await client.requestPermission({
10441
- options: buildExitPlanModePermissionOptions(),
10460
+ options: buildExitPlanModePermissionOptions(session.modeBeforePlan),
10442
10461
  sessionId,
10443
10462
  toolCall: {
10444
10463
  toolCallId: toolUseID,
@@ -17088,6 +17107,9 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17088
17107
  }
17089
17108
  const previousMode = this.session.permissionMode;
17090
17109
  this.session.permissionMode = modeId;
17110
+ if (modeId === "plan" && previousMode !== "plan") {
17111
+ this.session.modeBeforePlan = previousMode;
17112
+ }
17091
17113
  try {
17092
17114
  await this.session.query.setPermissionMode(modeId);
17093
17115
  } catch (error) {
@@ -17310,7 +17332,11 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17310
17332
  createOnModeChange() {
17311
17333
  return async (newMode) => {
17312
17334
  if (this.session) {
17335
+ const previousMode = this.session.permissionMode;
17313
17336
  this.session.permissionMode = newMode;
17337
+ if (newMode === "plan" && previousMode !== "plan") {
17338
+ this.session.modeBeforePlan = previousMode;
17339
+ }
17314
17340
  }
17315
17341
  await this.updateConfigOption("mode", newMode);
17316
17342
  };