@posthog/agent 2.3.171 → 2.3.173
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/adapters/claude/permissions/permission-options.js +19 -0
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
- package/dist/adapters/claude/tools.js +19 -0
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/agent.js +160 -106
- package/dist/agent.js.map +1 -1
- package/dist/execution-mode.d.ts +7 -2
- package/dist/execution-mode.js +25 -0
- package/dist/execution-mode.js.map +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +125 -71
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +125 -71
- package/dist/server/bin.cjs.map +1 -1
- package/package.json +1 -1
- package/src/acp-extensions.ts +3 -0
- package/src/adapters/claude/claude-agent.ts +13 -9
- package/src/adapters/codex/codex-agent.ts +61 -63
- package/src/adapters/codex/codex-client.ts +48 -4
- package/src/adapters/codex/session-state.ts +4 -3
- package/src/adapters/codex/spawn.ts +2 -0
- package/src/execution-mode.ts +37 -1
|
@@ -32,6 +32,25 @@ if (ALLOW_BYPASS) {
|
|
|
32
32
|
description: "Auto-accept all permission requests"
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
+
var codexModes = [
|
|
36
|
+
{
|
|
37
|
+
id: "read-only",
|
|
38
|
+
name: "Read Only",
|
|
39
|
+
description: "Read-only access, no file modifications"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "auto",
|
|
43
|
+
name: "Auto",
|
|
44
|
+
description: "Standard behavior, prompts for dangerous operations"
|
|
45
|
+
}
|
|
46
|
+
];
|
|
47
|
+
if (ALLOW_BYPASS) {
|
|
48
|
+
codexModes.push({
|
|
49
|
+
id: "full-access",
|
|
50
|
+
name: "Full Access",
|
|
51
|
+
description: "Auto-accept all permission requests"
|
|
52
|
+
});
|
|
53
|
+
}
|
|
35
54
|
|
|
36
55
|
// src/adapters/claude/tools.ts
|
|
37
56
|
var READ_TOOLS = /* @__PURE__ */ new Set(["Read", "NotebookRead"]);
|
|
@@ -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 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 { IS_ROOT } from \"./utils/common\";\n\nexport interface ModeInfo {\n id: CodeExecutionMode;\n name: string;\n description: string;\n}\n\n// Helper constant that can easily be toggled for env/feature flag/etc\nconst ALLOW_BYPASS = !IS_ROOT;\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 // id: \"dontAsk\",\n // name: \"Don't Ask\",\n // description: \"Don't prompt for permissions, deny if not pre-approved\",\n // },\n];\n\nif (ALLOW_BYPASS) {\n availableModes.push({\n id: \"bypassPermissions\",\n name: \"Auto-accept Permissions\",\n description: \"Auto-accept all permission requests\",\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 // \"dontAsk\",\n \"bypassPermissions\",\n] as const;\n\nexport type CodeExecutionMode = (typeof CODE_EXECUTION_MODES)[number];\n\nexport function getAvailableModes(): ModeInfo[] {\n // When IS_ROOT, do not allow bypassPermissions\n return IS_ROOT\n ? availableModes.filter((m) => m.id !== \"bypassPermissions\")\n : availableModes;\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 default: new Set(BASE_ALLOWED_TOOLS),\n acceptEdits: new Set([...BASE_ALLOWED_TOOLS, ...WRITE_TOOLS]),\n plan: new Set(BASE_ALLOWED_TOOLS),\n // dontAsk: 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 { IS_ROOT } 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 cwd?: 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 cwdLabel = cwd ? ` in ${cwd}` : \"\";\n const label = ruleContent ?? `\\`${cmdName}\\` commands`;\n\n return permissionOptions(\n `Yes, and don't ask again for ${label}${cwdLabel}`,\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 ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;\n\nexport function buildExitPlanModePermissionOptions(): PermissionOption[] {\n const options: PermissionOption[] = [];\n\n if (ALLOW_BYPASS) {\n options.push({\n kind: \"allow_always\",\n name: \"Yes, auto-accept all permissions\",\n optionId: \"bypassPermissions\",\n });\n }\n\n options.push(\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":["ALLOW_BYPASS"]}
|
|
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 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 { IS_ROOT } from \"./utils/common\";\n\nexport interface ModeInfo {\n id: string;\n name: string;\n description: string;\n}\n\n// Helper constant that can easily be toggled for env/feature flag/etc\nconst ALLOW_BYPASS = !IS_ROOT;\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 // id: \"dontAsk\",\n // name: \"Don't Ask\",\n // description: \"Don't prompt for permissions, deny if not pre-approved\",\n // },\n];\n\nif (ALLOW_BYPASS) {\n availableModes.push({\n id: \"bypassPermissions\",\n name: \"Auto-accept Permissions\",\n description: \"Auto-accept all permission requests\",\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 // \"dontAsk\",\n \"bypassPermissions\",\n] as const;\n\nexport type CodeExecutionMode = (typeof CODE_EXECUTION_MODES)[number];\n\nexport function getAvailableModes(): ModeInfo[] {\n // When IS_ROOT, do not allow bypassPermissions\n return IS_ROOT\n ? availableModes.filter((m) => m.id !== \"bypassPermissions\")\n : availableModes;\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\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 IS_ROOT\n ? codexModes.filter((m) => m.id !== \"full-access\")\n : codexModes;\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 default: new Set(BASE_ALLOWED_TOOLS),\n acceptEdits: new Set([...BASE_ALLOWED_TOOLS, ...WRITE_TOOLS]),\n plan: new Set(BASE_ALLOWED_TOOLS),\n // dontAsk: 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 { IS_ROOT } 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 cwd?: 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 cwdLabel = cwd ? ` in ${cwd}` : \"\";\n const label = ruleContent ?? `\\`${cmdName}\\` commands`;\n\n return permissionOptions(\n `Yes, and don't ask again for ${label}${cwdLabel}`,\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 ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;\n\nexport function buildExitPlanModePermissionOptions(): PermissionOption[] {\n const options: PermissionOption[] = [];\n\n if (ALLOW_BYPASS) {\n options.push({\n kind: \"allow_always\",\n name: \"Yes, auto-accept all permissions\",\n optionId: \"bypassPermissions\",\n });\n }\n\n options.push(\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":["ALLOW_BYPASS"]}
|
|
@@ -42,6 +42,25 @@ var CODE_EXECUTION_MODES = [
|
|
|
42
42
|
function getAvailableModes() {
|
|
43
43
|
return IS_ROOT ? availableModes.filter((m) => m.id !== "bypassPermissions") : availableModes;
|
|
44
44
|
}
|
|
45
|
+
var codexModes = [
|
|
46
|
+
{
|
|
47
|
+
id: "read-only",
|
|
48
|
+
name: "Read Only",
|
|
49
|
+
description: "Read-only access, no file modifications"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "auto",
|
|
53
|
+
name: "Auto",
|
|
54
|
+
description: "Standard behavior, prompts for dangerous operations"
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
if (ALLOW_BYPASS) {
|
|
58
|
+
codexModes.push({
|
|
59
|
+
id: "full-access",
|
|
60
|
+
name: "Full Access",
|
|
61
|
+
description: "Auto-accept all permission requests"
|
|
62
|
+
});
|
|
63
|
+
}
|
|
45
64
|
|
|
46
65
|
// src/adapters/claude/mcp/tool-metadata.ts
|
|
47
66
|
var mcpToolMetadataCache = /* @__PURE__ */ new Map();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/common.ts","../../../src/execution-mode.ts","../../../src/adapters/claude/mcp/tool-metadata.ts","../../../src/adapters/claude/tools.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 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 { IS_ROOT } from \"./utils/common\";\n\nexport interface ModeInfo {\n id: CodeExecutionMode;\n name: string;\n description: string;\n}\n\n// Helper constant that can easily be toggled for env/feature flag/etc\nconst ALLOW_BYPASS = !IS_ROOT;\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 // id: \"dontAsk\",\n // name: \"Don't Ask\",\n // description: \"Don't prompt for permissions, deny if not pre-approved\",\n // },\n];\n\nif (ALLOW_BYPASS) {\n availableModes.push({\n id: \"bypassPermissions\",\n name: \"Auto-accept Permissions\",\n description: \"Auto-accept all permission requests\",\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 // \"dontAsk\",\n \"bypassPermissions\",\n] as const;\n\nexport type CodeExecutionMode = (typeof CODE_EXECUTION_MODES)[number];\n\nexport function getAvailableModes(): ModeInfo[] {\n // When IS_ROOT, do not allow bypassPermissions\n return IS_ROOT\n ? availableModes.filter((m) => m.id !== \"bypassPermissions\")\n : availableModes;\n}\n","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","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 default: new Set(BASE_ALLOWED_TOOLS),\n acceptEdits: new Set([...BASE_ALLOWED_TOOLS, ...WRITE_TOOLS]),\n plan: new Set(BASE_ALLOWED_TOOLS),\n // dontAsk: 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"],"mappings":";AAqBO,IAAM,UACX,OAAO,YAAY,gBAClB,QAAQ,UAAU,KAAK,QAAQ,SAAS,OAAO;;;ACdlD,IAAM,eAAe,CAAC;AAEtB,IAAM,iBAA6B;AAAA,EACjC;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF;AAEA,IAAI,cAAc;AAChB,iBAAe,KAAK;AAAA,IAClB,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf,CAAC;AACH;AAGO,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF;AAIO,SAAS,oBAAgC;AAE9C,SAAO,UACH,eAAe,OAAO,CAAC,MAAM,EAAE,OAAO,mBAAmB,IACzD;AACN;;;ACjDA,IAAM,uBAAqD,oBAAI,IAAI;AAmF5D,SAAS,kBAAkB,UAA2B;AAC3D,QAAM,WAAW,qBAAqB,IAAI,QAAQ;AAClD,SAAO,UAAU,aAAa;AAChC;;;ACrFO,IAAM,aAA0B,oBAAI,IAAI,CAAC,QAAQ,cAAc,CAAC;AAEhE,IAAM,cAA2B,oBAAI,IAAI;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,aAA0B,oBAAI,IAAI;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,eAA4B,oBAAI,IAAI,CAAC,QAAQ,QAAQ,IAAI,CAAC;AAEhE,IAAM,YAAyB,oBAAI,IAAI,CAAC,aAAa,UAAU,CAAC;AAEhE,IAAM,cAA2B,oBAAI,IAAI;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,qBAAqB;AAAA,EACzB,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEA,IAAM,qBAAkD;AAAA,EACtD,SAAS,IAAI,IAAI,kBAAkB;AAAA,EACnC,aAAa,oBAAI,IAAI,CAAC,GAAG,oBAAoB,GAAG,WAAW,CAAC;AAAA,EAC5D,MAAM,IAAI,IAAI,kBAAkB;AAAA;AAElC;AAEO,SAAS,qBACd,UACA,MACS;AACT,MAAI,SAAS,qBAAqB;AAChC,WAAO;AAAA,EACT;AACA,MAAI,mBAAmB,IAAI,GAAG,IAAI,QAAQ,MAAM,MAAM;AACpD,WAAO;AAAA,EACT;AACA,MAAI,kBAAkB,QAAQ,GAAG;AAC/B,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/common.ts","../../../src/execution-mode.ts","../../../src/adapters/claude/mcp/tool-metadata.ts","../../../src/adapters/claude/tools.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 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 { IS_ROOT } from \"./utils/common\";\n\nexport interface ModeInfo {\n id: string;\n name: string;\n description: string;\n}\n\n// Helper constant that can easily be toggled for env/feature flag/etc\nconst ALLOW_BYPASS = !IS_ROOT;\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 // id: \"dontAsk\",\n // name: \"Don't Ask\",\n // description: \"Don't prompt for permissions, deny if not pre-approved\",\n // },\n];\n\nif (ALLOW_BYPASS) {\n availableModes.push({\n id: \"bypassPermissions\",\n name: \"Auto-accept Permissions\",\n description: \"Auto-accept all permission requests\",\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 // \"dontAsk\",\n \"bypassPermissions\",\n] as const;\n\nexport type CodeExecutionMode = (typeof CODE_EXECUTION_MODES)[number];\n\nexport function getAvailableModes(): ModeInfo[] {\n // When IS_ROOT, do not allow bypassPermissions\n return IS_ROOT\n ? availableModes.filter((m) => m.id !== \"bypassPermissions\")\n : availableModes;\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\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 IS_ROOT\n ? codexModes.filter((m) => m.id !== \"full-access\")\n : codexModes;\n}\n","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","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 default: new Set(BASE_ALLOWED_TOOLS),\n acceptEdits: new Set([...BASE_ALLOWED_TOOLS, ...WRITE_TOOLS]),\n plan: new Set(BASE_ALLOWED_TOOLS),\n // dontAsk: 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"],"mappings":";AAqBO,IAAM,UACX,OAAO,YAAY,gBAClB,QAAQ,UAAU,KAAK,QAAQ,SAAS,OAAO;;;ACdlD,IAAM,eAAe,CAAC;AAEtB,IAAM,iBAA6B;AAAA,EACjC;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF;AAEA,IAAI,cAAc;AAChB,iBAAe,KAAK;AAAA,IAClB,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf,CAAC;AACH;AAGO,IAAM,uBAAuB;AAAA,EAClC;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF;AAIO,SAAS,oBAAgC;AAE9C,SAAO,UACH,eAAe,OAAO,CAAC,MAAM,EAAE,OAAO,mBAAmB,IACzD;AACN;AAWA,IAAM,aAAyB;AAAA,EAC7B;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf;AACF;AAEA,IAAI,cAAc;AAChB,aAAW,KAAK;AAAA,IACd,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,aAAa;AAAA,EACf,CAAC;AACH;;;AC/EA,IAAM,uBAAqD,oBAAI,IAAI;AAmF5D,SAAS,kBAAkB,UAA2B;AAC3D,QAAM,WAAW,qBAAqB,IAAI,QAAQ;AAClD,SAAO,UAAU,aAAa;AAChC;;;ACrFO,IAAM,aAA0B,oBAAI,IAAI,CAAC,QAAQ,cAAc,CAAC;AAEhE,IAAM,cAA2B,oBAAI,IAAI;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,aAA0B,oBAAI,IAAI;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,IAAM,eAA4B,oBAAI,IAAI,CAAC,QAAQ,QAAQ,IAAI,CAAC;AAEhE,IAAM,YAAyB,oBAAI,IAAI,CAAC,aAAa,UAAU,CAAC;AAEhE,IAAM,cAA2B,oBAAI,IAAI;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,qBAAqB;AAAA,EACzB,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AACL;AAEA,IAAM,qBAAkD;AAAA,EACtD,SAAS,IAAI,IAAI,kBAAkB;AAAA,EACnC,aAAa,oBAAI,IAAI,CAAC,GAAG,oBAAoB,GAAG,WAAW,CAAC;AAAA,EAC5D,MAAM,IAAI,IAAI,kBAAkB;AAAA;AAElC;AAEO,SAAS,qBACd,UACA,MACS;AACT,MAAI,SAAS,qBAAqB;AAChC,WAAO;AAAA,EACT;AACA,MAAI,mBAAmB,IAAI,GAAG,IAAI,QAAQ,MAAM,MAAM;AACpD,WAAO;AAAA,EACT;AACA,MAAI,kBAAkB,QAAQ,GAAG;AAC/B,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
|
package/dist/agent.js
CHANGED
|
@@ -245,7 +245,7 @@ import { v7 as uuidv7 } from "uuid";
|
|
|
245
245
|
// package.json
|
|
246
246
|
var package_default = {
|
|
247
247
|
name: "@posthog/agent",
|
|
248
|
-
version: "2.3.
|
|
248
|
+
version: "2.3.173",
|
|
249
249
|
repository: "https://github.com/PostHog/code",
|
|
250
250
|
description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
|
|
251
251
|
exports: {
|
|
@@ -370,6 +370,44 @@ var package_default = {
|
|
|
370
370
|
}
|
|
371
371
|
};
|
|
372
372
|
|
|
373
|
+
// src/acp-extensions.ts
|
|
374
|
+
var POSTHOG_NOTIFICATIONS = {
|
|
375
|
+
/** Git branch was created for a task */
|
|
376
|
+
BRANCH_CREATED: "_posthog/branch_created",
|
|
377
|
+
/** Task run has started execution */
|
|
378
|
+
RUN_STARTED: "_posthog/run_started",
|
|
379
|
+
/** Task has completed (success or failure) */
|
|
380
|
+
TASK_COMPLETE: "_posthog/task_complete",
|
|
381
|
+
/** Agent finished processing a turn (prompt returned, waiting for next input) */
|
|
382
|
+
TURN_COMPLETE: "_posthog/turn_complete",
|
|
383
|
+
/** Error occurred during task execution */
|
|
384
|
+
ERROR: "_posthog/error",
|
|
385
|
+
/** Console/log output from the agent */
|
|
386
|
+
CONSOLE: "_posthog/console",
|
|
387
|
+
/** Maps taskRunId to agent's sessionId and adapter type (for resumption) */
|
|
388
|
+
SDK_SESSION: "_posthog/sdk_session",
|
|
389
|
+
/** Tree state snapshot captured (git tree hash + file archive) */
|
|
390
|
+
TREE_SNAPSHOT: "_posthog/tree_snapshot",
|
|
391
|
+
/** Agent mode changed (interactive/background) */
|
|
392
|
+
MODE_CHANGE: "_posthog/mode_change",
|
|
393
|
+
/** Request to resume a session from previous state */
|
|
394
|
+
SESSION_RESUME: "_posthog/session/resume",
|
|
395
|
+
/** User message sent from client to agent */
|
|
396
|
+
USER_MESSAGE: "_posthog/user_message",
|
|
397
|
+
/** Request to cancel current operation */
|
|
398
|
+
CANCEL: "_posthog/cancel",
|
|
399
|
+
/** Request to close the session */
|
|
400
|
+
CLOSE: "_posthog/close",
|
|
401
|
+
/** Agent status update (thinking, working, etc.) */
|
|
402
|
+
STATUS: "_posthog/status",
|
|
403
|
+
/** Task-level notification (progress, milestones) */
|
|
404
|
+
TASK_NOTIFICATION: "_posthog/task_notification",
|
|
405
|
+
/** Marks a boundary for log compaction */
|
|
406
|
+
COMPACT_BOUNDARY: "_posthog/compact_boundary",
|
|
407
|
+
/** Token usage update for a session turn */
|
|
408
|
+
USAGE_UPDATE: "_posthog/usage_update"
|
|
409
|
+
};
|
|
410
|
+
|
|
373
411
|
// src/utils/common.ts
|
|
374
412
|
async function withTimeout(operation, timeoutMs) {
|
|
375
413
|
const timeoutPromise = new Promise(
|
|
@@ -2107,6 +2145,25 @@ var CODE_EXECUTION_MODES = [
|
|
|
2107
2145
|
function getAvailableModes() {
|
|
2108
2146
|
return IS_ROOT ? availableModes.filter((m) => m.id !== "bypassPermissions") : availableModes;
|
|
2109
2147
|
}
|
|
2148
|
+
var codexModes = [
|
|
2149
|
+
{
|
|
2150
|
+
id: "read-only",
|
|
2151
|
+
name: "Read Only",
|
|
2152
|
+
description: "Read-only access, no file modifications"
|
|
2153
|
+
},
|
|
2154
|
+
{
|
|
2155
|
+
id: "auto",
|
|
2156
|
+
name: "Auto",
|
|
2157
|
+
description: "Standard behavior, prompts for dangerous operations"
|
|
2158
|
+
}
|
|
2159
|
+
];
|
|
2160
|
+
if (ALLOW_BYPASS) {
|
|
2161
|
+
codexModes.push({
|
|
2162
|
+
id: "full-access",
|
|
2163
|
+
name: "Full Access",
|
|
2164
|
+
description: "Auto-accept all permission requests"
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2110
2167
|
|
|
2111
2168
|
// src/adapters/claude/tools.ts
|
|
2112
2169
|
var READ_TOOLS = /* @__PURE__ */ new Set(["Read", "NotebookRead"]);
|
|
@@ -3473,16 +3530,19 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
|
|
|
3473
3530
|
}
|
|
3474
3531
|
});
|
|
3475
3532
|
}
|
|
3476
|
-
await this.client.extNotification(
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3533
|
+
await this.client.extNotification(
|
|
3534
|
+
POSTHOG_NOTIFICATIONS.USAGE_UPDATE,
|
|
3535
|
+
{
|
|
3536
|
+
sessionId: params.sessionId,
|
|
3537
|
+
used: {
|
|
3538
|
+
inputTokens: message.usage.input_tokens,
|
|
3539
|
+
outputTokens: message.usage.output_tokens,
|
|
3540
|
+
cachedReadTokens: message.usage.cache_read_input_tokens,
|
|
3541
|
+
cachedWriteTokens: message.usage.cache_creation_input_tokens
|
|
3542
|
+
},
|
|
3543
|
+
cost: message.total_cost_usd
|
|
3544
|
+
}
|
|
3545
|
+
);
|
|
3486
3546
|
const usage = {
|
|
3487
3547
|
inputTokens: this.session.accumulatedUsage.inputTokens,
|
|
3488
3548
|
outputTokens: this.session.accumulatedUsage.outputTokens,
|
|
@@ -4108,50 +4168,50 @@ import {
|
|
|
4108
4168
|
ndJsonStream
|
|
4109
4169
|
} from "@agentclientprotocol/sdk";
|
|
4110
4170
|
|
|
4111
|
-
// src/acp-extensions.ts
|
|
4112
|
-
var POSTHOG_NOTIFICATIONS = {
|
|
4113
|
-
/** Git branch was created for a task */
|
|
4114
|
-
BRANCH_CREATED: "_posthog/branch_created",
|
|
4115
|
-
/** Task run has started execution */
|
|
4116
|
-
RUN_STARTED: "_posthog/run_started",
|
|
4117
|
-
/** Task has completed (success or failure) */
|
|
4118
|
-
TASK_COMPLETE: "_posthog/task_complete",
|
|
4119
|
-
/** Agent finished processing a turn (prompt returned, waiting for next input) */
|
|
4120
|
-
TURN_COMPLETE: "_posthog/turn_complete",
|
|
4121
|
-
/** Error occurred during task execution */
|
|
4122
|
-
ERROR: "_posthog/error",
|
|
4123
|
-
/** Console/log output from the agent */
|
|
4124
|
-
CONSOLE: "_posthog/console",
|
|
4125
|
-
/** Maps taskRunId to agent's sessionId and adapter type (for resumption) */
|
|
4126
|
-
SDK_SESSION: "_posthog/sdk_session",
|
|
4127
|
-
/** Tree state snapshot captured (git tree hash + file archive) */
|
|
4128
|
-
TREE_SNAPSHOT: "_posthog/tree_snapshot",
|
|
4129
|
-
/** Agent mode changed (interactive/background) */
|
|
4130
|
-
MODE_CHANGE: "_posthog/mode_change",
|
|
4131
|
-
/** Request to resume a session from previous state */
|
|
4132
|
-
SESSION_RESUME: "_posthog/session/resume",
|
|
4133
|
-
/** User message sent from client to agent */
|
|
4134
|
-
USER_MESSAGE: "_posthog/user_message",
|
|
4135
|
-
/** Request to cancel current operation */
|
|
4136
|
-
CANCEL: "_posthog/cancel",
|
|
4137
|
-
/** Request to close the session */
|
|
4138
|
-
CLOSE: "_posthog/close",
|
|
4139
|
-
/** Agent status update (thinking, working, etc.) */
|
|
4140
|
-
STATUS: "_posthog/status",
|
|
4141
|
-
/** Task-level notification (progress, milestones) */
|
|
4142
|
-
TASK_NOTIFICATION: "_posthog/task_notification",
|
|
4143
|
-
/** Marks a boundary for log compaction */
|
|
4144
|
-
COMPACT_BOUNDARY: "_posthog/compact_boundary"
|
|
4145
|
-
};
|
|
4146
|
-
|
|
4147
4171
|
// src/adapters/codex/codex-client.ts
|
|
4172
|
+
var AUTO_APPROVED_KINDS = {
|
|
4173
|
+
default: /* @__PURE__ */ new Set(["read", "search", "fetch", "think"]),
|
|
4174
|
+
acceptEdits: /* @__PURE__ */ new Set(["read", "edit", "search", "fetch", "think"]),
|
|
4175
|
+
plan: /* @__PURE__ */ new Set(["read", "search", "fetch", "think"]),
|
|
4176
|
+
bypassPermissions: /* @__PURE__ */ new Set([
|
|
4177
|
+
"read",
|
|
4178
|
+
"edit",
|
|
4179
|
+
"delete",
|
|
4180
|
+
"move",
|
|
4181
|
+
"search",
|
|
4182
|
+
"execute",
|
|
4183
|
+
"think",
|
|
4184
|
+
"fetch",
|
|
4185
|
+
"switch_mode",
|
|
4186
|
+
"other"
|
|
4187
|
+
])
|
|
4188
|
+
};
|
|
4189
|
+
function shouldAutoApprove(mode, kind) {
|
|
4190
|
+
if (mode === "bypassPermissions") return true;
|
|
4191
|
+
if (!kind) return false;
|
|
4192
|
+
return AUTO_APPROVED_KINDS[mode]?.has(kind) ?? false;
|
|
4193
|
+
}
|
|
4148
4194
|
function createCodexClient(upstreamClient, logger, sessionState, callbacks) {
|
|
4149
4195
|
const terminalHandles = /* @__PURE__ */ new Map();
|
|
4150
4196
|
return {
|
|
4151
4197
|
async requestPermission(params) {
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4198
|
+
const kind = params.toolCall?.kind;
|
|
4199
|
+
if (shouldAutoApprove(sessionState.permissionMode, kind)) {
|
|
4200
|
+
logger.debug("Auto-approving permission", {
|
|
4201
|
+
mode: sessionState.permissionMode,
|
|
4202
|
+
kind,
|
|
4203
|
+
toolCallId: params.toolCall?.toolCallId
|
|
4204
|
+
});
|
|
4205
|
+
const allowOption = params.options?.find(
|
|
4206
|
+
(o) => o.kind === "allow_once" || o.kind === "allow_always"
|
|
4207
|
+
);
|
|
4208
|
+
return {
|
|
4209
|
+
outcome: {
|
|
4210
|
+
outcome: "selected",
|
|
4211
|
+
optionId: allowOption?.optionId ?? "allow"
|
|
4212
|
+
}
|
|
4213
|
+
};
|
|
4214
|
+
}
|
|
4155
4215
|
return upstreamClient.requestPermission(params);
|
|
4156
4216
|
},
|
|
4157
4217
|
async sessionUpdate(params) {
|
|
@@ -4243,7 +4303,7 @@ function createSessionState(sessionId, cwd, opts) {
|
|
|
4243
4303
|
cachedReadTokens: 0,
|
|
4244
4304
|
cachedWriteTokens: 0
|
|
4245
4305
|
},
|
|
4246
|
-
|
|
4306
|
+
permissionMode: opts?.permissionMode ?? "default",
|
|
4247
4307
|
taskRunId: opts?.taskRunId,
|
|
4248
4308
|
taskId: opts?.taskId
|
|
4249
4309
|
};
|
|
@@ -4357,7 +4417,7 @@ function buildConfigArgs(options) {
|
|
|
4357
4417
|
args.push("-c", `model="${options.model}"`);
|
|
4358
4418
|
}
|
|
4359
4419
|
if (options.instructions) {
|
|
4360
|
-
const escaped = options.instructions.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
4420
|
+
const escaped = options.instructions.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/"/g, '\\"');
|
|
4361
4421
|
args.push("-c", `instructions="${escaped}"`);
|
|
4362
4422
|
}
|
|
4363
4423
|
return args;
|
|
@@ -4437,6 +4497,18 @@ function spawnCodexProcess(options) {
|
|
|
4437
4497
|
}
|
|
4438
4498
|
|
|
4439
4499
|
// src/adapters/codex/codex-agent.ts
|
|
4500
|
+
function toCodeExecutionMode(mode) {
|
|
4501
|
+
if (mode && CODE_EXECUTION_MODES.includes(mode)) {
|
|
4502
|
+
return mode;
|
|
4503
|
+
}
|
|
4504
|
+
return "default";
|
|
4505
|
+
}
|
|
4506
|
+
var CODEX_NATIVE_MODE = {
|
|
4507
|
+
default: "default",
|
|
4508
|
+
acceptEdits: "default",
|
|
4509
|
+
plan: "plan",
|
|
4510
|
+
bypassPermissions: "default"
|
|
4511
|
+
};
|
|
4440
4512
|
var CodexAcpAgent = class extends BaseAcpAgent {
|
|
4441
4513
|
adapterName = "codex";
|
|
4442
4514
|
codexProcess;
|
|
@@ -4462,24 +4534,9 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4462
4534
|
notificationHistory: [],
|
|
4463
4535
|
cancelled: false
|
|
4464
4536
|
};
|
|
4537
|
+
this.sessionState = createSessionState("", cwd);
|
|
4465
4538
|
this.codexConnection = new ClientSideConnection(
|
|
4466
|
-
(_agent) => createCodexClient(
|
|
4467
|
-
this.client,
|
|
4468
|
-
this.logger,
|
|
4469
|
-
this.sessionState ?? {
|
|
4470
|
-
sessionId: "",
|
|
4471
|
-
cwd: "",
|
|
4472
|
-
modeId: "default",
|
|
4473
|
-
configOptions: [],
|
|
4474
|
-
accumulatedUsage: {
|
|
4475
|
-
inputTokens: 0,
|
|
4476
|
-
outputTokens: 0,
|
|
4477
|
-
cachedReadTokens: 0,
|
|
4478
|
-
cachedWriteTokens: 0
|
|
4479
|
-
},
|
|
4480
|
-
cancelled: false
|
|
4481
|
-
}
|
|
4482
|
-
),
|
|
4539
|
+
(_agent) => createCodexClient(this.client, this.logger, this.sessionState),
|
|
4483
4540
|
codexStream
|
|
4484
4541
|
);
|
|
4485
4542
|
}
|
|
@@ -4515,7 +4572,8 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4515
4572
|
taskRunId: meta?.taskRunId,
|
|
4516
4573
|
taskId: meta?.taskId ?? meta?.persistence?.taskId,
|
|
4517
4574
|
modeId: response.modes?.currentModeId ?? "default",
|
|
4518
|
-
modelId: response.models?.currentModelId
|
|
4575
|
+
modelId: response.models?.currentModelId,
|
|
4576
|
+
permissionMode: toCodeExecutionMode(meta?.permissionMode)
|
|
4519
4577
|
});
|
|
4520
4578
|
this.sessionId = response.sessionId;
|
|
4521
4579
|
this.sessionState.configOptions = response.configOptions ?? [];
|
|
@@ -4534,7 +4592,10 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4534
4592
|
}
|
|
4535
4593
|
async loadSession(params) {
|
|
4536
4594
|
const response = await this.codexConnection.loadSession(params);
|
|
4537
|
-
|
|
4595
|
+
const meta = params._meta;
|
|
4596
|
+
this.sessionState = createSessionState(params.sessionId, params.cwd, {
|
|
4597
|
+
permissionMode: toCodeExecutionMode(meta?.permissionMode)
|
|
4598
|
+
});
|
|
4538
4599
|
this.sessionId = params.sessionId;
|
|
4539
4600
|
this.sessionState.configOptions = response.configOptions ?? [];
|
|
4540
4601
|
return response;
|
|
@@ -4545,10 +4606,14 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4545
4606
|
cwd: params.cwd,
|
|
4546
4607
|
mcpServers: params.mcpServers ?? []
|
|
4547
4608
|
});
|
|
4548
|
-
|
|
4609
|
+
const meta = params._meta;
|
|
4610
|
+
this.sessionState = createSessionState(params.sessionId, params.cwd, {
|
|
4611
|
+
taskRunId: meta?.taskRunId,
|
|
4612
|
+
taskId: meta?.taskId ?? meta?.persistence?.taskId,
|
|
4613
|
+
permissionMode: toCodeExecutionMode(meta?.permissionMode)
|
|
4614
|
+
});
|
|
4549
4615
|
this.sessionId = params.sessionId;
|
|
4550
4616
|
this.sessionState.configOptions = loadResponse.configOptions ?? [];
|
|
4551
|
-
const meta = params._meta;
|
|
4552
4617
|
if (meta?.taskRunId) {
|
|
4553
4618
|
await this.client.extNotification(POSTHOG_NOTIFICATIONS.SDK_SESSION, {
|
|
4554
4619
|
taskRunId: meta.taskRunId,
|
|
@@ -4568,7 +4633,12 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4568
4633
|
mcpServers: params.mcpServers ?? [],
|
|
4569
4634
|
_meta: params._meta
|
|
4570
4635
|
});
|
|
4571
|
-
|
|
4636
|
+
const meta = params._meta;
|
|
4637
|
+
this.sessionState = createSessionState(newResponse.sessionId, params.cwd, {
|
|
4638
|
+
taskRunId: meta?.taskRunId,
|
|
4639
|
+
taskId: meta?.taskId ?? meta?.persistence?.taskId,
|
|
4640
|
+
permissionMode: toCodeExecutionMode(meta?.permissionMode)
|
|
4641
|
+
});
|
|
4572
4642
|
this.sessionId = newResponse.sessionId;
|
|
4573
4643
|
this.sessionState.configOptions = newResponse.configOptions ?? [];
|
|
4574
4644
|
return newResponse;
|
|
@@ -4577,22 +4647,14 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4577
4647
|
return this.codexConnection.listSessions(params);
|
|
4578
4648
|
}
|
|
4579
4649
|
async unstable_listSessions(params) {
|
|
4580
|
-
return this.
|
|
4650
|
+
return this.listSessions(params);
|
|
4581
4651
|
}
|
|
4582
4652
|
async prompt(params) {
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
resetUsage(this.sessionState);
|
|
4587
|
-
}
|
|
4653
|
+
this.session.cancelled = false;
|
|
4654
|
+
this.session.interruptReason = void 0;
|
|
4655
|
+
resetUsage(this.sessionState);
|
|
4588
4656
|
const response = await this.codexConnection.prompt(params);
|
|
4589
|
-
if (this.sessionState
|
|
4590
|
-
this.sessionState.accumulatedUsage.inputTokens += response.usage.inputTokens ?? 0;
|
|
4591
|
-
this.sessionState.accumulatedUsage.outputTokens += response.usage.outputTokens ?? 0;
|
|
4592
|
-
this.sessionState.accumulatedUsage.cachedReadTokens += response.usage.cachedReadTokens ?? 0;
|
|
4593
|
-
this.sessionState.accumulatedUsage.cachedWriteTokens += response.usage.cachedWriteTokens ?? 0;
|
|
4594
|
-
}
|
|
4595
|
-
if (this.sessionState?.taskRunId) {
|
|
4657
|
+
if (this.sessionState.taskRunId) {
|
|
4596
4658
|
const { accumulatedUsage } = this.sessionState;
|
|
4597
4659
|
await this.client.extNotification(POSTHOG_NOTIFICATIONS.TURN_COMPLETE, {
|
|
4598
4660
|
sessionId: params.sessionId,
|
|
@@ -4606,7 +4668,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4606
4668
|
}
|
|
4607
4669
|
});
|
|
4608
4670
|
if (response.usage) {
|
|
4609
|
-
await this.client.extNotification(
|
|
4671
|
+
await this.client.extNotification(POSTHOG_NOTIFICATIONS.USAGE_UPDATE, {
|
|
4610
4672
|
sessionId: params.sessionId,
|
|
4611
4673
|
used: {
|
|
4612
4674
|
inputTokens: response.usage.inputTokens ?? 0,
|
|
@@ -4621,33 +4683,24 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4621
4683
|
return response;
|
|
4622
4684
|
}
|
|
4623
4685
|
async interrupt() {
|
|
4624
|
-
if (this.sessionState) {
|
|
4625
|
-
this.sessionState.cancelled = true;
|
|
4626
|
-
}
|
|
4627
4686
|
await this.codexConnection.cancel({
|
|
4628
4687
|
sessionId: this.sessionId
|
|
4629
4688
|
});
|
|
4630
4689
|
}
|
|
4631
|
-
async cancel(params) {
|
|
4632
|
-
if (this.sessionState) {
|
|
4633
|
-
this.sessionState.cancelled = true;
|
|
4634
|
-
const meta = params._meta;
|
|
4635
|
-
if (meta?.interruptReason) {
|
|
4636
|
-
this.sessionState.interruptReason = meta.interruptReason;
|
|
4637
|
-
}
|
|
4638
|
-
}
|
|
4639
|
-
await this.codexConnection.cancel(params);
|
|
4640
|
-
}
|
|
4641
4690
|
async setSessionMode(params) {
|
|
4642
|
-
const
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4691
|
+
const requestedMode = toCodeExecutionMode(params.modeId);
|
|
4692
|
+
const nativeMode = CODEX_NATIVE_MODE[requestedMode];
|
|
4693
|
+
const response = await this.codexConnection.setSessionMode({
|
|
4694
|
+
...params,
|
|
4695
|
+
modeId: nativeMode
|
|
4696
|
+
});
|
|
4697
|
+
this.sessionState.modeId = nativeMode;
|
|
4698
|
+
this.sessionState.permissionMode = requestedMode;
|
|
4646
4699
|
return response ?? {};
|
|
4647
4700
|
}
|
|
4648
4701
|
async setSessionConfigOption(params) {
|
|
4649
4702
|
const response = await this.codexConnection.setSessionConfigOption(params);
|
|
4650
|
-
if (
|
|
4703
|
+
if (response.configOptions) {
|
|
4651
4704
|
this.sessionState.configOptions = response.configOptions;
|
|
4652
4705
|
}
|
|
4653
4706
|
return response;
|
|
@@ -4656,6 +4709,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
|
|
|
4656
4709
|
}
|
|
4657
4710
|
async closeSession() {
|
|
4658
4711
|
this.logger.info("Closing Codex session", { sessionId: this.sessionId });
|
|
4712
|
+
this.session.abortController.abort();
|
|
4659
4713
|
this.session.settingsManager.dispose();
|
|
4660
4714
|
try {
|
|
4661
4715
|
this.codexProcess.kill();
|