workos 0.0.23 → 0.1.0
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/.claude-plugin/plugin.json +13 -0
- package/LICENSE +47 -0
- package/README.md +154 -1
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +163 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.config.d.ts +52 -0
- package/dist/cli.config.js +70 -0
- package/dist/cli.config.js.map +1 -0
- package/dist/package.json +87 -0
- package/dist/src/commands/install-skill.d.ts +20 -0
- package/dist/src/commands/install-skill.js +130 -0
- package/dist/src/commands/install-skill.js.map +1 -0
- package/dist/src/commands/install.d.ts +22 -0
- package/dist/src/commands/install.js +57 -0
- package/dist/src/commands/install.js.map +1 -0
- package/dist/src/commands/login.d.ts +1 -0
- package/dist/src/commands/login.js +141 -0
- package/dist/src/commands/login.js.map +1 -0
- package/dist/src/commands/logout.d.ts +1 -0
- package/dist/src/commands/logout.js +17 -0
- package/dist/src/commands/logout.js.map +1 -0
- package/dist/src/dashboard/components/AnimatedLogo.d.ts +8 -0
- package/dist/src/dashboard/components/AnimatedLogo.js +16 -0
- package/dist/src/dashboard/components/AnimatedLogo.js.map +1 -0
- package/dist/src/dashboard/components/CompletionView.d.ts +13 -0
- package/dist/src/dashboard/components/CompletionView.js +21 -0
- package/dist/src/dashboard/components/CompletionView.js.map +1 -0
- package/dist/src/dashboard/components/ConfirmPrompt.d.ts +9 -0
- package/dist/src/dashboard/components/ConfirmPrompt.js +25 -0
- package/dist/src/dashboard/components/ConfirmPrompt.js.map +1 -0
- package/dist/src/dashboard/components/CredentialsForm.d.ts +10 -0
- package/dist/src/dashboard/components/CredentialsForm.js +47 -0
- package/dist/src/dashboard/components/CredentialsForm.js.map +1 -0
- package/dist/src/dashboard/components/Dashboard.d.ts +3 -0
- package/dist/src/dashboard/components/Dashboard.js +100 -0
- package/dist/src/dashboard/components/Dashboard.js.map +1 -0
- package/dist/src/dashboard/components/DashboardLayout.d.ts +24 -0
- package/dist/src/dashboard/components/DashboardLayout.js +25 -0
- package/dist/src/dashboard/components/DashboardLayout.js.map +1 -0
- package/dist/src/dashboard/components/DiffPanel.d.ts +9 -0
- package/dist/src/dashboard/components/DiffPanel.js +136 -0
- package/dist/src/dashboard/components/DiffPanel.js.map +1 -0
- package/dist/src/dashboard/components/InlinePrompt.d.ts +8 -0
- package/dist/src/dashboard/components/InlinePrompt.js +19 -0
- package/dist/src/dashboard/components/InlinePrompt.js.map +1 -0
- package/dist/src/dashboard/components/OutputPanel.d.ts +10 -0
- package/dist/src/dashboard/components/OutputPanel.js +100 -0
- package/dist/src/dashboard/components/OutputPanel.js.map +1 -0
- package/dist/src/dashboard/components/Panel.d.ts +12 -0
- package/dist/src/dashboard/components/Panel.js +6 -0
- package/dist/src/dashboard/components/Panel.js.map +1 -0
- package/dist/src/dashboard/components/TextInput.d.ts +13 -0
- package/dist/src/dashboard/components/TextInput.js +57 -0
- package/dist/src/dashboard/components/TextInput.js.map +1 -0
- package/dist/src/dashboard/components/WelcomeArt.d.ts +2 -0
- package/dist/src/dashboard/components/WelcomeArt.js +9 -0
- package/dist/src/dashboard/components/WelcomeArt.js.map +1 -0
- package/dist/src/dashboard/hooks/useAnimation.d.ts +7 -0
- package/dist/src/dashboard/hooks/useAnimation.js +24 -0
- package/dist/src/dashboard/hooks/useAnimation.js.map +1 -0
- package/dist/src/dashboard/hooks/useKeyboard.d.ts +8 -0
- package/dist/src/dashboard/hooks/useKeyboard.js +18 -0
- package/dist/src/dashboard/hooks/useKeyboard.js.map +1 -0
- package/dist/src/dashboard/hooks/useTerminalSize.d.ts +8 -0
- package/dist/src/dashboard/hooks/useTerminalSize.js +23 -0
- package/dist/src/dashboard/hooks/useTerminalSize.js.map +1 -0
- package/dist/src/dashboard/index.d.ts +6 -0
- package/dist/src/dashboard/index.js +36 -0
- package/dist/src/dashboard/index.js.map +1 -0
- package/dist/src/dashboard/lib/diff-utils.d.ts +21 -0
- package/dist/src/dashboard/lib/diff-utils.js +271 -0
- package/dist/src/dashboard/lib/diff-utils.js.map +1 -0
- package/dist/src/dashboard/lib/logo-frames.d.ts +20 -0
- package/dist/src/dashboard/lib/logo-frames.js +109 -0
- package/dist/src/dashboard/lib/logo-frames.js.map +1 -0
- package/dist/src/dashboard/lib/welcome-art.d.ts +1 -0
- package/dist/src/dashboard/lib/welcome-art.js +5 -0
- package/dist/src/dashboard/lib/welcome-art.js.map +1 -0
- package/dist/src/dashboard/types.d.ts +5 -0
- package/dist/src/dashboard/types.js +2 -0
- package/dist/src/dashboard/types.js.map +1 -0
- package/dist/src/lib/__tests__/test-utils.d.ts +40 -0
- package/dist/src/lib/__tests__/test-utils.js +108 -0
- package/dist/src/lib/__tests__/test-utils.js.map +1 -0
- package/dist/src/lib/adapters/cli-adapter.d.ts +56 -0
- package/dist/src/lib/adapters/cli-adapter.js +318 -0
- package/dist/src/lib/adapters/cli-adapter.js.map +1 -0
- package/dist/src/lib/adapters/dashboard-adapter.d.ts +30 -0
- package/dist/src/lib/adapters/dashboard-adapter.js +97 -0
- package/dist/src/lib/adapters/dashboard-adapter.js.map +1 -0
- package/dist/src/lib/adapters/index.d.ts +3 -0
- package/dist/src/lib/adapters/index.js +3 -0
- package/dist/src/lib/adapters/index.js.map +1 -0
- package/dist/src/lib/adapters/types.d.ts +41 -0
- package/dist/src/lib/adapters/types.js +2 -0
- package/dist/src/lib/adapters/types.js.map +1 -0
- package/dist/src/lib/agent-interface.d.ts +75 -0
- package/dist/src/lib/agent-interface.js +563 -0
- package/dist/src/lib/agent-interface.js.map +1 -0
- package/dist/src/lib/agent-runner.d.ts +9 -0
- package/dist/src/lib/agent-runner.js +213 -0
- package/dist/src/lib/agent-runner.js.map +1 -0
- package/dist/src/lib/api.d.ts +25 -0
- package/dist/src/lib/api.js +120 -0
- package/dist/src/lib/api.js.map +1 -0
- package/dist/src/lib/config.d.ts +60 -0
- package/dist/src/lib/config.js +88 -0
- package/dist/src/lib/config.js.map +1 -0
- package/dist/src/lib/constants.d.ts +32 -0
- package/dist/src/lib/constants.js +53 -0
- package/dist/src/lib/constants.js.map +1 -0
- package/dist/src/lib/credentials.d.ts +19 -0
- package/dist/src/lib/credentials.js +55 -0
- package/dist/src/lib/credentials.js.map +1 -0
- package/dist/src/lib/env-writer.d.ts +14 -0
- package/dist/src/lib/env-writer.js +39 -0
- package/dist/src/lib/env-writer.js.map +1 -0
- package/dist/src/lib/events.d.ts +114 -0
- package/dist/src/lib/events.js +19 -0
- package/dist/src/lib/events.js.map +1 -0
- package/dist/src/lib/framework-config.d.ts +108 -0
- package/dist/src/lib/framework-config.js +11 -0
- package/dist/src/lib/framework-config.js.map +1 -0
- package/dist/src/lib/helper-functions.d.ts +1 -0
- package/dist/src/lib/helper-functions.js +2 -0
- package/dist/src/lib/helper-functions.js.map +1 -0
- package/dist/src/lib/port-detection.d.ts +7 -0
- package/dist/src/lib/port-detection.js +112 -0
- package/dist/src/lib/port-detection.js.map +1 -0
- package/dist/src/lib/progress-tracker.d.ts +22 -0
- package/dist/src/lib/progress-tracker.js +47 -0
- package/dist/src/lib/progress-tracker.js.map +1 -0
- package/dist/src/lib/run-with-core.d.ts +2 -0
- package/dist/src/lib/run-with-core.js +266 -0
- package/dist/src/lib/run-with-core.js.map +1 -0
- package/dist/src/lib/safe-tools.d.ts +2 -0
- package/dist/src/lib/safe-tools.js +212 -0
- package/dist/src/lib/safe-tools.js.map +1 -0
- package/dist/src/lib/settings.d.ts +59 -0
- package/dist/src/lib/settings.js +36 -0
- package/dist/src/lib/settings.js.map +1 -0
- package/dist/src/lib/token-refresh.d.ts +12 -0
- package/dist/src/lib/token-refresh.js +26 -0
- package/dist/src/lib/token-refresh.js.map +1 -0
- package/dist/src/lib/validation/build-validator.d.ts +9 -0
- package/dist/src/lib/validation/build-validator.js +118 -0
- package/dist/src/lib/validation/build-validator.js.map +1 -0
- package/dist/src/lib/validation/index.d.ts +3 -0
- package/dist/src/lib/validation/index.js +3 -0
- package/dist/src/lib/validation/index.js.map +1 -0
- package/dist/src/lib/validation/types.d.ts +41 -0
- package/dist/src/lib/validation/types.js +2 -0
- package/dist/src/lib/validation/types.js.map +1 -0
- package/dist/src/lib/validation/validator.d.ts +6 -0
- package/dist/src/lib/validation/validator.js +647 -0
- package/dist/src/lib/validation/validator.js.map +1 -0
- package/dist/src/lib/wizard-core.d.ts +200 -0
- package/dist/src/lib/wizard-core.js +392 -0
- package/dist/src/lib/wizard-core.js.map +1 -0
- package/dist/src/lib/wizard-core.types.d.ts +73 -0
- package/dist/src/lib/wizard-core.types.js +2 -0
- package/dist/src/lib/wizard-core.types.js.map +1 -0
- package/dist/src/lib/workos-management.d.ts +32 -0
- package/dist/src/lib/workos-management.js +142 -0
- package/dist/src/lib/workos-management.js.map +1 -0
- package/dist/src/nextjs/nextjs-wizard-agent.d.ts +6 -0
- package/dist/src/nextjs/nextjs-wizard-agent.js +97 -0
- package/dist/src/nextjs/nextjs-wizard-agent.js.map +1 -0
- package/dist/src/nextjs/utils.d.ts +8 -0
- package/dist/src/nextjs/utils.js +53 -0
- package/dist/src/nextjs/utils.js.map +1 -0
- package/dist/src/react/react-wizard-agent.d.ts +2 -0
- package/dist/src/react/react-wizard-agent.js +47 -0
- package/dist/src/react/react-wizard-agent.js.map +1 -0
- package/dist/src/react-router/react-router-wizard-agent.d.ts +6 -0
- package/dist/src/react-router/react-router-wizard-agent.js +103 -0
- package/dist/src/react-router/react-router-wizard-agent.js.map +1 -0
- package/dist/src/react-router/utils.d.ts +19 -0
- package/dist/src/react-router/utils.js +210 -0
- package/dist/src/react-router/utils.js.map +1 -0
- package/dist/src/run.d.ts +24 -0
- package/dist/src/run.js +48 -0
- package/dist/src/run.js.map +1 -0
- package/dist/src/steps/add-or-update-environment-variables.d.ts +10 -0
- package/dist/src/steps/add-or-update-environment-variables.js +155 -0
- package/dist/src/steps/add-or-update-environment-variables.js.map +1 -0
- package/dist/src/steps/index.d.ts +3 -0
- package/dist/src/steps/index.js +4 -0
- package/dist/src/steps/index.js.map +1 -0
- package/dist/src/steps/run-prettier.d.ts +5 -0
- package/dist/src/steps/run-prettier.js +54 -0
- package/dist/src/steps/run-prettier.js.map +1 -0
- package/dist/src/steps/upload-environment-variables/EnvironmentProvider.d.ts +8 -0
- package/dist/src/steps/upload-environment-variables/EnvironmentProvider.js +7 -0
- package/dist/src/steps/upload-environment-variables/EnvironmentProvider.js.map +1 -0
- package/dist/src/steps/upload-environment-variables/index.d.ts +6 -0
- package/dist/src/steps/upload-environment-variables/index.js +57 -0
- package/dist/src/steps/upload-environment-variables/index.js.map +1 -0
- package/dist/src/steps/upload-environment-variables/providers/vercel.d.ts +14 -0
- package/dist/src/steps/upload-environment-variables/providers/vercel.js +104 -0
- package/dist/src/steps/upload-environment-variables/providers/vercel.js.map +1 -0
- package/dist/src/tanstack-start/tanstack-start-wizard-agent.d.ts +2 -0
- package/dist/src/tanstack-start/tanstack-start-wizard-agent.js +49 -0
- package/dist/src/tanstack-start/tanstack-start-wizard-agent.js.map +1 -0
- package/dist/src/telemetry.d.ts +2 -0
- package/dist/src/telemetry.js +29 -0
- package/dist/src/telemetry.js.map +1 -0
- package/dist/src/utils/analytics.d.ts +24 -0
- package/dist/src/utils/analytics.js +139 -0
- package/dist/src/utils/analytics.js.map +1 -0
- package/dist/src/utils/bash.d.ts +2 -0
- package/dist/src/utils/bash.js +17 -0
- package/dist/src/utils/bash.js.map +1 -0
- package/dist/src/utils/clack-utils.d.ts +93 -0
- package/dist/src/utils/clack-utils.js +397 -0
- package/dist/src/utils/clack-utils.js.map +1 -0
- package/dist/src/utils/clack.d.ts +5 -0
- package/dist/src/utils/clack.js +34 -0
- package/dist/src/utils/clack.js.map +1 -0
- package/dist/src/utils/cli-symbols.d.ts +32 -0
- package/dist/src/utils/cli-symbols.js +46 -0
- package/dist/src/utils/cli-symbols.js.map +1 -0
- package/dist/src/utils/debug.d.ts +7 -0
- package/dist/src/utils/debug.js +88 -0
- package/dist/src/utils/debug.js.map +1 -0
- package/dist/src/utils/env-parser.d.ts +5 -0
- package/dist/src/utils/env-parser.js +18 -0
- package/dist/src/utils/env-parser.js.map +1 -0
- package/dist/src/utils/environment.d.ts +4 -0
- package/dist/src/utils/environment.js +69 -0
- package/dist/src/utils/environment.js.map +1 -0
- package/dist/src/utils/errors.d.ts +3 -0
- package/dist/src/utils/errors.js +7 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/logging.d.ts +9 -0
- package/dist/src/utils/logging.js +36 -0
- package/dist/src/utils/logging.js.map +1 -0
- package/dist/src/utils/package-json.d.ts +25 -0
- package/dist/src/utils/package-json.js +21 -0
- package/dist/src/utils/package-json.js.map +1 -0
- package/dist/src/utils/package-manager.d.ts +21 -0
- package/dist/src/utils/package-manager.js +167 -0
- package/dist/src/utils/package-manager.js.map +1 -0
- package/dist/src/utils/redact.d.ts +5 -0
- package/dist/src/utils/redact.js +29 -0
- package/dist/src/utils/redact.js.map +1 -0
- package/dist/src/utils/semver.d.ts +10 -0
- package/dist/src/utils/semver.js +43 -0
- package/dist/src/utils/semver.js.map +1 -0
- package/dist/src/utils/string.d.ts +1 -0
- package/dist/src/utils/string.js +6 -0
- package/dist/src/utils/string.js.map +1 -0
- package/dist/src/utils/telemetry-client.d.ts +15 -0
- package/dist/src/utils/telemetry-client.js +57 -0
- package/dist/src/utils/telemetry-client.js.map +1 -0
- package/dist/src/utils/telemetry-types.d.ts +51 -0
- package/dist/src/utils/telemetry-types.js +6 -0
- package/dist/src/utils/telemetry-types.js.map +1 -0
- package/dist/src/utils/types.d.ts +80 -0
- package/dist/src/utils/types.js +2 -0
- package/dist/src/utils/types.js.map +1 -0
- package/dist/src/utils/urls.d.ts +7 -0
- package/dist/src/utils/urls.js +8 -0
- package/dist/src/utils/urls.js.map +1 -0
- package/dist/src/utils/vendor/is-unicorn-supported.d.ts +1 -0
- package/dist/src/utils/vendor/is-unicorn-supported.js +21 -0
- package/dist/src/utils/vendor/is-unicorn-supported.js.map +1 -0
- package/dist/src/vanilla-js/vanilla-js-wizard-agent.d.ts +2 -0
- package/dist/src/vanilla-js/vanilla-js-wizard-agent.js +47 -0
- package/dist/src/vanilla-js/vanilla-js-wizard-agent.js.map +1 -0
- package/package.json +76 -84
- package/skills/workos-authkit-base/SKILL.md +113 -0
- package/skills/workos-authkit-nextjs/SKILL.md +115 -0
- package/skills/workos-authkit-react/SKILL.md +91 -0
- package/skills/workos-authkit-react-router/SKILL.md +106 -0
- package/skills/workos-authkit-tanstack-start/SKILL.md +104 -0
- package/skills/workos-authkit-vanilla-js/SKILL.md +81 -0
- package/build/apps/index.js +0 -50
- package/build/apps/slack.js +0 -151
- package/build/cli.js +0 -42
- package/build/config.js +0 -34
- package/build/dev.js +0 -5
- package/build/enable-api-access.png +0 -0
- package/build/groups.js +0 -480
- package/build/index.js +0 -3
- package/build/info.js +0 -69
- package/build/login.js +0 -161
- package/build/main.js +0 -214
- package/build/users.js +0 -402
- package/build/util.js +0 -157
- package/coverage/clover.xml +0 -66
- package/coverage/coverage-final.json +0 -4
- package/coverage/lcov-report/base.css +0 -212
- package/coverage/lcov-report/cli.ts.html +0 -329
- package/coverage/lcov-report/config.ts.html +0 -152
- package/coverage/lcov-report/index.html +0 -119
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -1
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -158
- package/coverage/lcov-report/util.ts.html +0 -350
- package/coverage/lcov.info +0 -121
- package/package-lock.json +0 -7617
- package/tests/util.test.ts +0 -35
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared agent interface for WorkOS wizards
|
|
3
|
+
* Uses Claude Agent SDK directly with WorkOS MCP server
|
|
4
|
+
*/
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { debug, logInfo, logWarn, logError, initLogFile, getLogFilePath } from '../utils/debug.js';
|
|
8
|
+
import { analytics } from '../utils/analytics.js';
|
|
9
|
+
import { WIZARD_INTERACTION_EVENT_NAME } from './constants.js';
|
|
10
|
+
import { LINTING_TOOLS } from './safe-tools.js';
|
|
11
|
+
import { getLlmGatewayUrlFromHost } from '../utils/urls.js';
|
|
12
|
+
import { getConfig } from './settings.js';
|
|
13
|
+
import { getCredentials, hasCredentials } from './credentials.js';
|
|
14
|
+
import { ensureValidToken } from './token-refresh.js';
|
|
15
|
+
// File content cache for computing edit diffs
|
|
16
|
+
const fileContentCache = new Map();
|
|
17
|
+
// Track pending Read operations by tool_use_id
|
|
18
|
+
const pendingReads = new Map();
|
|
19
|
+
// Track tool start times by tool_use_id for telemetry
|
|
20
|
+
const pendingToolCalls = new Map();
|
|
21
|
+
// Dynamic import cache for ESM module
|
|
22
|
+
let _sdkModule = null;
|
|
23
|
+
async function getSDKModule() {
|
|
24
|
+
if (!_sdkModule) {
|
|
25
|
+
_sdkModule = await import('@anthropic-ai/claude-agent-sdk');
|
|
26
|
+
}
|
|
27
|
+
return _sdkModule;
|
|
28
|
+
}
|
|
29
|
+
export const AgentSignals = {
|
|
30
|
+
/** Signal emitted when the agent reports progress to the user */
|
|
31
|
+
STATUS: '[STATUS]',
|
|
32
|
+
/** Signal emitted when the agent cannot access the WorkOS MCP server */
|
|
33
|
+
ERROR_MCP_MISSING: '[ERROR-MCP-MISSING]',
|
|
34
|
+
/** Signal emitted when the agent cannot access the setup resource */
|
|
35
|
+
ERROR_RESOURCE_MISSING: '[ERROR-RESOURCE-MISSING]',
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Error types that can be returned from agent execution.
|
|
39
|
+
* These correspond to the error signals that the agent emits.
|
|
40
|
+
*/
|
|
41
|
+
export var AgentErrorType;
|
|
42
|
+
(function (AgentErrorType) {
|
|
43
|
+
/** Agent could not access the WorkOS MCP server */
|
|
44
|
+
AgentErrorType["MCP_MISSING"] = "WIZARD_MCP_MISSING";
|
|
45
|
+
/** Agent could not access the setup resource */
|
|
46
|
+
AgentErrorType["RESOURCE_MISSING"] = "WIZARD_RESOURCE_MISSING";
|
|
47
|
+
/** Agent execution failed (API error, auth error, etc.) */
|
|
48
|
+
AgentErrorType["EXECUTION_ERROR"] = "WIZARD_EXECUTION_ERROR";
|
|
49
|
+
})(AgentErrorType || (AgentErrorType = {}));
|
|
50
|
+
/**
|
|
51
|
+
* Package managers that can be used to run commands.
|
|
52
|
+
*/
|
|
53
|
+
const PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun', 'npx'];
|
|
54
|
+
/**
|
|
55
|
+
* Safe scripts/commands that can be run with any package manager.
|
|
56
|
+
* Uses startsWith matching, so 'build' matches 'build', 'build:prod', etc.
|
|
57
|
+
* Note: Linting tools are in LINTING_TOOLS and checked separately.
|
|
58
|
+
*/
|
|
59
|
+
const SAFE_SCRIPTS = [
|
|
60
|
+
// Package installation
|
|
61
|
+
'install',
|
|
62
|
+
'add',
|
|
63
|
+
'ci',
|
|
64
|
+
// Build
|
|
65
|
+
'build',
|
|
66
|
+
// Type checking (various naming conventions)
|
|
67
|
+
'tsc',
|
|
68
|
+
'typecheck',
|
|
69
|
+
'type-check',
|
|
70
|
+
'check-types',
|
|
71
|
+
'types',
|
|
72
|
+
// Linting/formatting script names (actual tools are in LINTING_TOOLS)
|
|
73
|
+
'lint',
|
|
74
|
+
'format',
|
|
75
|
+
];
|
|
76
|
+
/**
|
|
77
|
+
* Dangerous shell operators that could allow command injection.
|
|
78
|
+
* Note: We handle `2>&1` and `| tail/head` separately as safe patterns.
|
|
79
|
+
*/
|
|
80
|
+
const DANGEROUS_OPERATORS = /[;`$()]/;
|
|
81
|
+
/**
|
|
82
|
+
* Check if command is an allowed package manager command.
|
|
83
|
+
* Matches: <pkg-manager> [run|exec] <safe-script> [args...]
|
|
84
|
+
*/
|
|
85
|
+
function matchesAllowedPrefix(command) {
|
|
86
|
+
const parts = command.split(/\s+/);
|
|
87
|
+
if (parts.length === 0 || !PACKAGE_MANAGERS.includes(parts[0])) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
// Skip 'run' or 'exec' if present
|
|
91
|
+
let scriptIndex = 1;
|
|
92
|
+
if (parts[scriptIndex] === 'run' || parts[scriptIndex] === 'exec') {
|
|
93
|
+
scriptIndex++;
|
|
94
|
+
}
|
|
95
|
+
// Get the script/command portion (may include args)
|
|
96
|
+
const scriptPart = parts.slice(scriptIndex).join(' ');
|
|
97
|
+
// Check if script starts with any safe script name or linting tool
|
|
98
|
+
return (SAFE_SCRIPTS.some((safe) => scriptPart.startsWith(safe)) ||
|
|
99
|
+
LINTING_TOOLS.some((tool) => scriptPart.startsWith(tool)));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Permission hook that allows only safe commands.
|
|
103
|
+
* - Package manager install commands
|
|
104
|
+
* - Build/typecheck/lint commands for verification
|
|
105
|
+
* - Piping to tail/head for output limiting is allowed
|
|
106
|
+
* - Stderr redirection (2>&1) is allowed
|
|
107
|
+
*/
|
|
108
|
+
export function wizardCanUseTool(toolName, input) {
|
|
109
|
+
// Allow all non-Bash tools
|
|
110
|
+
if (toolName !== 'Bash') {
|
|
111
|
+
return { behavior: 'allow', updatedInput: input };
|
|
112
|
+
}
|
|
113
|
+
const command = (typeof input.command === 'string' ? input.command : '').trim();
|
|
114
|
+
// Block definitely dangerous operators: ; ` $ ( )
|
|
115
|
+
if (DANGEROUS_OPERATORS.test(command)) {
|
|
116
|
+
logWarn(`Denying bash command with dangerous operators: ${command}`);
|
|
117
|
+
debug(`Denying bash command with dangerous operators: ${command}`);
|
|
118
|
+
analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {
|
|
119
|
+
action: 'bash command denied',
|
|
120
|
+
reason: 'dangerous operators',
|
|
121
|
+
command,
|
|
122
|
+
});
|
|
123
|
+
return {
|
|
124
|
+
behavior: 'deny',
|
|
125
|
+
message: `Bash command not allowed. Shell operators like ; \` $ ( ) are not permitted.`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
// Normalize: remove safe stderr redirection (2>&1, 2>&2, etc.)
|
|
129
|
+
const normalized = command.replace(/\s*\d*>&\d+\s*/g, ' ').trim();
|
|
130
|
+
// Check for pipe to tail/head (safe output limiting)
|
|
131
|
+
const pipeMatch = normalized.match(/^(.+?)\s*\|\s*(tail|head)(\s+\S+)*\s*$/);
|
|
132
|
+
if (pipeMatch) {
|
|
133
|
+
const baseCommand = pipeMatch[1].trim();
|
|
134
|
+
// Block if base command has pipes or & (multiple chaining)
|
|
135
|
+
if (/[|&]/.test(baseCommand)) {
|
|
136
|
+
logWarn(`Denying bash command with multiple pipes: ${command}`);
|
|
137
|
+
debug(`Denying bash command with multiple pipes: ${command}`);
|
|
138
|
+
analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {
|
|
139
|
+
action: 'bash command denied',
|
|
140
|
+
reason: 'multiple pipes',
|
|
141
|
+
command,
|
|
142
|
+
});
|
|
143
|
+
return {
|
|
144
|
+
behavior: 'deny',
|
|
145
|
+
message: `Bash command not allowed. Only single pipe to tail/head is permitted.`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (matchesAllowedPrefix(baseCommand)) {
|
|
149
|
+
logInfo(`Allowing bash command with output limiter: ${command}`);
|
|
150
|
+
debug(`Allowing bash command with output limiter: ${command}`);
|
|
151
|
+
return { behavior: 'allow', updatedInput: input };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// Block remaining pipes and & (not covered by tail/head case above)
|
|
155
|
+
if (/[|&]/.test(normalized)) {
|
|
156
|
+
logWarn(`Denying bash command with pipe/&: ${command}`);
|
|
157
|
+
debug(`Denying bash command with pipe/&: ${command}`);
|
|
158
|
+
analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {
|
|
159
|
+
action: 'bash command denied',
|
|
160
|
+
reason: 'disallowed pipe',
|
|
161
|
+
command,
|
|
162
|
+
});
|
|
163
|
+
return {
|
|
164
|
+
behavior: 'deny',
|
|
165
|
+
message: `Bash command not allowed. Pipes are only permitted with tail/head for output limiting.`,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
// Check if command starts with any allowed prefix
|
|
169
|
+
if (matchesAllowedPrefix(normalized)) {
|
|
170
|
+
logInfo(`Allowing bash command: ${command}`);
|
|
171
|
+
debug(`Allowing bash command: ${command}`);
|
|
172
|
+
return { behavior: 'allow', updatedInput: input };
|
|
173
|
+
}
|
|
174
|
+
logWarn(`Denying bash command: ${command}`);
|
|
175
|
+
debug(`Denying bash command: ${command}`);
|
|
176
|
+
analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {
|
|
177
|
+
action: 'bash command denied',
|
|
178
|
+
reason: 'not in allowlist',
|
|
179
|
+
command,
|
|
180
|
+
});
|
|
181
|
+
return {
|
|
182
|
+
behavior: 'deny',
|
|
183
|
+
message: `Bash command not allowed. Only install, build, typecheck, lint, and formatting commands are permitted.`,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Initialize agent configuration for the LLM gateway
|
|
188
|
+
*/
|
|
189
|
+
export async function initializeAgent(config, options) {
|
|
190
|
+
// Initialize log file for this run
|
|
191
|
+
initLogFile();
|
|
192
|
+
logInfo('Agent initialization starting');
|
|
193
|
+
logInfo('Install directory:', options.installDir);
|
|
194
|
+
// Emit status event for adapters to render
|
|
195
|
+
options.emitter?.emit('status', { message: 'Initializing Claude agent...' });
|
|
196
|
+
try {
|
|
197
|
+
// Configure LLM gateway for Claude API calls via LLM_GATEWAY_URL env var
|
|
198
|
+
const gatewayUrl = getLlmGatewayUrlFromHost();
|
|
199
|
+
// Check/refresh authentication for production (unless skipping auth)
|
|
200
|
+
if (!options.skipAuth && !options.local) {
|
|
201
|
+
if (!hasCredentials()) {
|
|
202
|
+
throw new Error('Not authenticated. Run `wizard login` to authenticate.');
|
|
203
|
+
}
|
|
204
|
+
const refreshResult = await ensureValidToken();
|
|
205
|
+
if (!refreshResult.success) {
|
|
206
|
+
throw new Error(refreshResult.error || 'Authentication failed');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// Set gateway URL
|
|
210
|
+
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
|
|
211
|
+
// Only send access token if not skipping auth
|
|
212
|
+
let authMode;
|
|
213
|
+
if (options.skipAuth) {
|
|
214
|
+
delete process.env.ANTHROPIC_AUTH_TOKEN;
|
|
215
|
+
authMode = `skip-auth:${gatewayUrl}`;
|
|
216
|
+
logInfo('Skipping auth - no token sent to gateway');
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
const creds = getCredentials();
|
|
220
|
+
if (!creds) {
|
|
221
|
+
throw new Error('Not authenticated. Run `wizard login` to authenticate.');
|
|
222
|
+
}
|
|
223
|
+
process.env.ANTHROPIC_AUTH_TOKEN = creds.accessToken;
|
|
224
|
+
authMode = options.local ? `local-gateway:${gatewayUrl}` : `workos-gateway:${gatewayUrl}`;
|
|
225
|
+
logInfo('Sending access token to gateway');
|
|
226
|
+
}
|
|
227
|
+
logInfo('Configured LLM gateway:', gatewayUrl);
|
|
228
|
+
// Disable experimental betas (like input_examples) that the LLM gateway doesn't support
|
|
229
|
+
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';
|
|
230
|
+
// Disable SDK telemetry - our gateway doesn't proxy /api/event_logging/batch
|
|
231
|
+
process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = 'true';
|
|
232
|
+
// Configure WorkOS MCP docs server for accessing WorkOS documentation
|
|
233
|
+
const agentRunConfig = {
|
|
234
|
+
workingDirectory: config.workingDirectory,
|
|
235
|
+
mcpServers: {
|
|
236
|
+
workos: {
|
|
237
|
+
command: 'npx',
|
|
238
|
+
args: ['-y', '@workos/mcp-docs-server'],
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
model: getConfig().model,
|
|
242
|
+
allowedTools: ['Skill', 'Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'WebFetch'],
|
|
243
|
+
};
|
|
244
|
+
logInfo('Agent config:', {
|
|
245
|
+
workingDirectory: agentRunConfig.workingDirectory,
|
|
246
|
+
gatewayUrl,
|
|
247
|
+
authMode,
|
|
248
|
+
useMcp: false,
|
|
249
|
+
});
|
|
250
|
+
if (options.debug) {
|
|
251
|
+
debug('Agent config:', {
|
|
252
|
+
workingDirectory: agentRunConfig.workingDirectory,
|
|
253
|
+
gatewayUrl,
|
|
254
|
+
authMode,
|
|
255
|
+
useMcp: false,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
// Emit status events for adapters to render
|
|
259
|
+
const currentLogPath = getLogFilePath();
|
|
260
|
+
if (currentLogPath) {
|
|
261
|
+
options.emitter?.emit('status', { message: `Verbose logs: ${currentLogPath}` });
|
|
262
|
+
}
|
|
263
|
+
options.emitter?.emit('status', { message: "Agent initialized. Let's get cooking!" });
|
|
264
|
+
return agentRunConfig;
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
// Emit error via emitter for adapters to handle
|
|
268
|
+
options.emitter?.emit('error', { message: `Failed to initialize agent: ${error.message}` });
|
|
269
|
+
logError('Agent initialization error:', error);
|
|
270
|
+
debug('Agent initialization error:', error);
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Execute an agent with the provided prompt and options
|
|
276
|
+
* Handles the full lifecycle via event emissions - adapters handle UI rendering.
|
|
277
|
+
*
|
|
278
|
+
* @returns An object containing any error detected in the agent's output
|
|
279
|
+
*/
|
|
280
|
+
export async function runAgent(agentConfig, prompt, options, config, emitter) {
|
|
281
|
+
const { spinnerMessage = 'Setting up WorkOS AuthKit...', successMessage = 'WorkOS AuthKit integration complete', errorMessage = 'Integration failed', } = config ?? {};
|
|
282
|
+
const { query } = await getSDKModule();
|
|
283
|
+
// Emit progress for adapters to handle (e.g., CLI adapter starts spinner)
|
|
284
|
+
emitter?.emit('agent:progress', { step: 'Starting', detail: 'This may take a few minutes. Grab some coffee!' });
|
|
285
|
+
emitter?.emit('agent:progress', { step: spinnerMessage });
|
|
286
|
+
logInfo('Starting agent run');
|
|
287
|
+
logInfo('Prompt:', prompt);
|
|
288
|
+
const startTime = Date.now();
|
|
289
|
+
const collectedText = [];
|
|
290
|
+
try {
|
|
291
|
+
// Workaround for SDK bug: stdin closes before canUseTool responses can be sent.
|
|
292
|
+
// The fix is to use an async generator for the prompt that stays open until
|
|
293
|
+
// the result is received, keeping the stdin stream alive for permission responses.
|
|
294
|
+
// See: https://github.com/anthropics/claude-code/issues/4775
|
|
295
|
+
// See: https://github.com/anthropics/claude-agent-sdk-typescript/issues/41
|
|
296
|
+
let signalDone;
|
|
297
|
+
const resultReceived = new Promise((resolve) => {
|
|
298
|
+
signalDone = resolve;
|
|
299
|
+
});
|
|
300
|
+
const createPromptStream = async function* () {
|
|
301
|
+
yield {
|
|
302
|
+
type: 'user',
|
|
303
|
+
session_id: '',
|
|
304
|
+
message: { role: 'user', content: prompt },
|
|
305
|
+
parent_tool_use_id: null,
|
|
306
|
+
};
|
|
307
|
+
await resultReceived;
|
|
308
|
+
};
|
|
309
|
+
// Load plugin with bundled skills
|
|
310
|
+
// Path from dist/src/lib/ back to package root
|
|
311
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
312
|
+
const __dirname = path.dirname(__filename);
|
|
313
|
+
const pluginPath = path.join(__dirname, '../../..');
|
|
314
|
+
logInfo('Loading plugin from:', pluginPath);
|
|
315
|
+
const response = query({
|
|
316
|
+
prompt: createPromptStream(),
|
|
317
|
+
options: {
|
|
318
|
+
model: agentConfig.model,
|
|
319
|
+
cwd: agentConfig.workingDirectory,
|
|
320
|
+
permissionMode: 'acceptEdits',
|
|
321
|
+
mcpServers: agentConfig.mcpServers,
|
|
322
|
+
env: { ...process.env },
|
|
323
|
+
canUseTool: (toolName, input) => {
|
|
324
|
+
logInfo('canUseTool called:', { toolName, input });
|
|
325
|
+
const result = wizardCanUseTool(toolName, input);
|
|
326
|
+
logInfo('canUseTool result:', result);
|
|
327
|
+
return Promise.resolve(result);
|
|
328
|
+
},
|
|
329
|
+
tools: { type: 'preset', preset: 'claude_code' },
|
|
330
|
+
allowedTools: agentConfig.allowedTools,
|
|
331
|
+
plugins: [{ type: 'local', path: pluginPath }],
|
|
332
|
+
// Capture stderr from CLI subprocess for debugging
|
|
333
|
+
stderr: (data) => {
|
|
334
|
+
logInfo('CLI stderr:', data);
|
|
335
|
+
if (options.debug) {
|
|
336
|
+
debug('CLI stderr:', data);
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
});
|
|
341
|
+
// Process the async generator
|
|
342
|
+
let sdkError;
|
|
343
|
+
for await (const message of response) {
|
|
344
|
+
const messageError = handleSDKMessage(message, options, collectedText, emitter);
|
|
345
|
+
if (messageError) {
|
|
346
|
+
sdkError = messageError;
|
|
347
|
+
}
|
|
348
|
+
// Signal completion when result received
|
|
349
|
+
if (message.type === 'result') {
|
|
350
|
+
signalDone();
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const durationMs = Date.now() - startTime;
|
|
354
|
+
const outputText = collectedText.join('\n');
|
|
355
|
+
// Check for SDK errors first (e.g., API errors, auth failures)
|
|
356
|
+
// Return error type + message - caller decides whether to throw or emit events
|
|
357
|
+
if (sdkError) {
|
|
358
|
+
logError('Agent SDK error:', sdkError);
|
|
359
|
+
return { error: AgentErrorType.EXECUTION_ERROR, errorMessage: sdkError };
|
|
360
|
+
}
|
|
361
|
+
// Check for error markers in the agent's output
|
|
362
|
+
if (outputText.includes(AgentSignals.ERROR_MCP_MISSING)) {
|
|
363
|
+
logError('Agent error: MCP_MISSING');
|
|
364
|
+
return { error: AgentErrorType.MCP_MISSING, errorMessage: 'Could not access WorkOS MCP server' };
|
|
365
|
+
}
|
|
366
|
+
if (outputText.includes(AgentSignals.ERROR_RESOURCE_MISSING)) {
|
|
367
|
+
logError('Agent error: RESOURCE_MISSING');
|
|
368
|
+
return { error: AgentErrorType.RESOURCE_MISSING, errorMessage: 'Could not access setup resource' };
|
|
369
|
+
}
|
|
370
|
+
logInfo(`Agent run completed in ${Math.round(durationMs / 1000)}s`);
|
|
371
|
+
analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {
|
|
372
|
+
action: 'agent integration completed',
|
|
373
|
+
duration_ms: durationMs,
|
|
374
|
+
duration_seconds: Math.round(durationMs / 1000),
|
|
375
|
+
});
|
|
376
|
+
// Don't emit agent:success here - let the state machine handle lifecycle events
|
|
377
|
+
return {};
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
// Don't emit events here - just log and re-throw for state machine to handle
|
|
381
|
+
logError('Agent run failed:', error);
|
|
382
|
+
debug('Full error:', error);
|
|
383
|
+
throw error;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Handle SDK messages and emit events for adapters to render.
|
|
388
|
+
* @returns Error message if this was an error result, undefined otherwise
|
|
389
|
+
*/
|
|
390
|
+
function handleSDKMessage(message, options, collectedText, emitter) {
|
|
391
|
+
logInfo(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
|
|
392
|
+
switch (message.type) {
|
|
393
|
+
case 'assistant': {
|
|
394
|
+
// Extract usage data from Anthropic API response for telemetry
|
|
395
|
+
const usage = message.message?.usage;
|
|
396
|
+
if (usage) {
|
|
397
|
+
const inputTokens = usage.input_tokens ?? 0;
|
|
398
|
+
const outputTokens = usage.output_tokens ?? 0;
|
|
399
|
+
const model = message.message?.model ?? 'unknown';
|
|
400
|
+
analytics.llmRequest(model, inputTokens, outputTokens);
|
|
401
|
+
analytics.incrementAgentIterations();
|
|
402
|
+
}
|
|
403
|
+
// Extract text content from assistant messages
|
|
404
|
+
const content = message.message?.content;
|
|
405
|
+
if (Array.isArray(content)) {
|
|
406
|
+
for (const block of content) {
|
|
407
|
+
if (block.type === 'text' && typeof block.text === 'string') {
|
|
408
|
+
collectedText.push(block.text);
|
|
409
|
+
// Emit output event for dashboard
|
|
410
|
+
emitter?.emit('output', { text: block.text });
|
|
411
|
+
// Check for [STATUS] markers and emit progress events
|
|
412
|
+
const statusRegex = new RegExp(`^.*${AgentSignals.STATUS.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*(.+?)$`, 'm');
|
|
413
|
+
const statusMatch = block.text.match(statusRegex);
|
|
414
|
+
if (statusMatch) {
|
|
415
|
+
const statusText = statusMatch[1].trim();
|
|
416
|
+
// Emit progress event - adapters handle spinner updates
|
|
417
|
+
emitter?.emit('agent:progress', { step: statusText });
|
|
418
|
+
emitter?.emit('status', { message: statusText });
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
// Check for tool_use blocks (Write/Edit operations)
|
|
422
|
+
if (block.type === 'tool_use') {
|
|
423
|
+
const toolName = block.name;
|
|
424
|
+
const toolUseId = block.id;
|
|
425
|
+
const input = block.input;
|
|
426
|
+
// Log tool usage for debugging
|
|
427
|
+
logInfo(`Tool use: ${toolName}`);
|
|
428
|
+
// Track tool start time for telemetry
|
|
429
|
+
if (toolUseId) {
|
|
430
|
+
pendingToolCalls.set(toolUseId, { toolName, startTime: Date.now() });
|
|
431
|
+
}
|
|
432
|
+
// Emit file:write event for Write tool
|
|
433
|
+
if (toolName === 'Write' && input) {
|
|
434
|
+
const filePath = input.file_path;
|
|
435
|
+
const fileContent = input.content;
|
|
436
|
+
if (filePath && fileContent) {
|
|
437
|
+
emitter?.emit('file:write', { path: filePath, content: fileContent });
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
// Emit file:edit event for Edit tool
|
|
441
|
+
if (toolName === 'Edit' && input) {
|
|
442
|
+
const filePath = input.file_path;
|
|
443
|
+
const oldString = input.old_string;
|
|
444
|
+
const newString = input.new_string;
|
|
445
|
+
if (filePath && oldString !== undefined && newString !== undefined) {
|
|
446
|
+
// Emit the actual strings being replaced, not reconstructed full file
|
|
447
|
+
emitter?.emit('file:edit', {
|
|
448
|
+
path: filePath,
|
|
449
|
+
oldContent: oldString,
|
|
450
|
+
newContent: newString,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// Track Read operations for caching file content later
|
|
455
|
+
if (toolName === 'Read' && input && block.id) {
|
|
456
|
+
const filePath = input.file_path;
|
|
457
|
+
if (filePath) {
|
|
458
|
+
pendingReads.set(block.id, filePath);
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
case 'user': {
|
|
467
|
+
// User messages contain tool results
|
|
468
|
+
const content = message.message?.content;
|
|
469
|
+
if (Array.isArray(content)) {
|
|
470
|
+
for (const block of content) {
|
|
471
|
+
// Tool results contain file content from Read operations
|
|
472
|
+
if (block.type === 'tool_result' && block.tool_use_id) {
|
|
473
|
+
const toolUseId = block.tool_use_id;
|
|
474
|
+
// Emit telemetry for completed tool call
|
|
475
|
+
const pendingTool = pendingToolCalls.get(toolUseId);
|
|
476
|
+
if (pendingTool) {
|
|
477
|
+
const durationMs = Date.now() - pendingTool.startTime;
|
|
478
|
+
// Check if tool result indicates error (is_error field or error in content)
|
|
479
|
+
const isError = block.is_error === true;
|
|
480
|
+
analytics.toolCalled(pendingTool.toolName, durationMs, !isError);
|
|
481
|
+
pendingToolCalls.delete(toolUseId);
|
|
482
|
+
}
|
|
483
|
+
const filePath = pendingReads.get(toolUseId);
|
|
484
|
+
if (filePath) {
|
|
485
|
+
// Extract content from the tool result
|
|
486
|
+
let resultContent = '';
|
|
487
|
+
if (typeof block.content === 'string') {
|
|
488
|
+
resultContent = block.content;
|
|
489
|
+
}
|
|
490
|
+
else if (Array.isArray(block.content)) {
|
|
491
|
+
// Content might be array of text blocks
|
|
492
|
+
for (const item of block.content) {
|
|
493
|
+
if (item.type === 'text' && item.text) {
|
|
494
|
+
resultContent += item.text;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
if (resultContent) {
|
|
499
|
+
fileContentCache.set(filePath, resultContent);
|
|
500
|
+
}
|
|
501
|
+
pendingReads.delete(toolUseId);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
case 'tool': {
|
|
509
|
+
// This case may not be used by the current SDK, keeping for compatibility
|
|
510
|
+
const toolName = message.tool;
|
|
511
|
+
const input = message.input;
|
|
512
|
+
if (toolName === 'Read' && message.content) {
|
|
513
|
+
const filePath = input?.file_path;
|
|
514
|
+
if (filePath && typeof message.content === 'string') {
|
|
515
|
+
fileContentCache.set(filePath, message.content);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
break;
|
|
519
|
+
}
|
|
520
|
+
case 'result': {
|
|
521
|
+
if (message.subtype === 'success') {
|
|
522
|
+
logInfo('Agent completed successfully');
|
|
523
|
+
if (typeof message.result === 'string') {
|
|
524
|
+
collectedText.push(message.result);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
// Error result
|
|
529
|
+
logError('Agent error result:', message.subtype);
|
|
530
|
+
if (message.errors && message.errors.length > 0) {
|
|
531
|
+
for (const err of message.errors) {
|
|
532
|
+
logError('ERROR:', err);
|
|
533
|
+
// Emit error event - adapters handle rendering
|
|
534
|
+
emitter?.emit('error', { message: err });
|
|
535
|
+
}
|
|
536
|
+
// Return the first error message
|
|
537
|
+
return message.errors[0];
|
|
538
|
+
}
|
|
539
|
+
// Return generic error if subtype indicates failure but no errors array
|
|
540
|
+
return `Agent execution failed: ${message.subtype}`;
|
|
541
|
+
}
|
|
542
|
+
break;
|
|
543
|
+
}
|
|
544
|
+
case 'system': {
|
|
545
|
+
if (message.subtype === 'init') {
|
|
546
|
+
logInfo('Agent session initialized', {
|
|
547
|
+
model: message.model,
|
|
548
|
+
tools: message.tools?.length,
|
|
549
|
+
mcpServers: message.mcp_servers,
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
break;
|
|
553
|
+
}
|
|
554
|
+
default:
|
|
555
|
+
// Log other message types for debugging
|
|
556
|
+
if (options.debug) {
|
|
557
|
+
debug(`Unhandled message type: ${message.type}`);
|
|
558
|
+
}
|
|
559
|
+
break;
|
|
560
|
+
}
|
|
561
|
+
return undefined;
|
|
562
|
+
}
|
|
563
|
+
//# sourceMappingURL=agent-interface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-interface.js","sourceRoot":"","sources":["../../../src/lib/agent-interface.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared agent interface for WorkOS wizards\n * Uses Claude Agent SDK directly with WorkOS MCP server\n */\n\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { debug, logInfo, logWarn, logError, initLogFile, getLogFilePath } from '../utils/debug.js';\nimport type { WizardOptions } from '../utils/types.js';\nimport { analytics } from '../utils/analytics.js';\nimport { WIZARD_INTERACTION_EVENT_NAME } from './constants.js';\nimport { LINTING_TOOLS } from './safe-tools.js';\nimport { getLlmGatewayUrlFromHost } from '../utils/urls.js';\nimport { getConfig } from './settings.js';\nimport { getCredentials, hasCredentials } from './credentials.js';\nimport { ensureValidToken } from './token-refresh.js';\nimport type { WizardEventEmitter } from './events.js';\n\n// File content cache for computing edit diffs\nconst fileContentCache = new Map<string, string>();\n// Track pending Read operations by tool_use_id\nconst pendingReads = new Map<string, string>();\n// Track tool start times by tool_use_id for telemetry\nconst pendingToolCalls = new Map<string, { toolName: string; startTime: number }>();\n\n// Dynamic import cache for ESM module\nlet _sdkModule: any = null;\nasync function getSDKModule(): Promise<any> {\n if (!_sdkModule) {\n _sdkModule = await import('@anthropic-ai/claude-agent-sdk');\n }\n return _sdkModule;\n}\n\n// Using `any` because typed imports from ESM modules require import attributes\n// syntax which prettier cannot parse. See PR discussion for details.\ntype SDKMessage = any;\ntype McpServersConfig = any;\n\nexport const AgentSignals = {\n /** Signal emitted when the agent reports progress to the user */\n STATUS: '[STATUS]',\n /** Signal emitted when the agent cannot access the WorkOS MCP server */\n ERROR_MCP_MISSING: '[ERROR-MCP-MISSING]',\n /** Signal emitted when the agent cannot access the setup resource */\n ERROR_RESOURCE_MISSING: '[ERROR-RESOURCE-MISSING]',\n} as const;\n\nexport type AgentSignal = (typeof AgentSignals)[keyof typeof AgentSignals];\n\n/**\n * Error types that can be returned from agent execution.\n * These correspond to the error signals that the agent emits.\n */\nexport enum AgentErrorType {\n /** Agent could not access the WorkOS MCP server */\n MCP_MISSING = 'WIZARD_MCP_MISSING',\n /** Agent could not access the setup resource */\n RESOURCE_MISSING = 'WIZARD_RESOURCE_MISSING',\n /** Agent execution failed (API error, auth error, etc.) */\n EXECUTION_ERROR = 'WIZARD_EXECUTION_ERROR',\n}\n\nexport type AgentConfig = {\n workingDirectory: string;\n workOSApiKey: string;\n workOSApiHost: string;\n};\n\n/**\n * Internal configuration object returned by initializeAgent\n */\ntype AgentRunConfig = {\n workingDirectory: string;\n mcpServers: McpServersConfig;\n model: string;\n allowedTools: string[];\n};\n\n/**\n * Package managers that can be used to run commands.\n */\nconst PACKAGE_MANAGERS = ['npm', 'pnpm', 'yarn', 'bun', 'npx'];\n\n/**\n * Safe scripts/commands that can be run with any package manager.\n * Uses startsWith matching, so 'build' matches 'build', 'build:prod', etc.\n * Note: Linting tools are in LINTING_TOOLS and checked separately.\n */\nconst SAFE_SCRIPTS = [\n // Package installation\n 'install',\n 'add',\n 'ci',\n // Build\n 'build',\n // Type checking (various naming conventions)\n 'tsc',\n 'typecheck',\n 'type-check',\n 'check-types',\n 'types',\n // Linting/formatting script names (actual tools are in LINTING_TOOLS)\n 'lint',\n 'format',\n];\n\n/**\n * Dangerous shell operators that could allow command injection.\n * Note: We handle `2>&1` and `| tail/head` separately as safe patterns.\n */\nconst DANGEROUS_OPERATORS = /[;`$()]/;\n\n/**\n * Check if command is an allowed package manager command.\n * Matches: <pkg-manager> [run|exec] <safe-script> [args...]\n */\nfunction matchesAllowedPrefix(command: string): boolean {\n const parts = command.split(/\\s+/);\n if (parts.length === 0 || !PACKAGE_MANAGERS.includes(parts[0])) {\n return false;\n }\n\n // Skip 'run' or 'exec' if present\n let scriptIndex = 1;\n if (parts[scriptIndex] === 'run' || parts[scriptIndex] === 'exec') {\n scriptIndex++;\n }\n\n // Get the script/command portion (may include args)\n const scriptPart = parts.slice(scriptIndex).join(' ');\n\n // Check if script starts with any safe script name or linting tool\n return (\n SAFE_SCRIPTS.some((safe) => scriptPart.startsWith(safe)) ||\n LINTING_TOOLS.some((tool) => scriptPart.startsWith(tool))\n );\n}\n\n/**\n * Permission hook that allows only safe commands.\n * - Package manager install commands\n * - Build/typecheck/lint commands for verification\n * - Piping to tail/head for output limiting is allowed\n * - Stderr redirection (2>&1) is allowed\n */\nexport function wizardCanUseTool(\n toolName: string,\n input: Record<string, unknown>,\n): { behavior: 'allow'; updatedInput: Record<string, unknown> } | { behavior: 'deny'; message: string } {\n // Allow all non-Bash tools\n if (toolName !== 'Bash') {\n return { behavior: 'allow', updatedInput: input };\n }\n\n const command = (typeof input.command === 'string' ? input.command : '').trim();\n\n // Block definitely dangerous operators: ; ` $ ( )\n if (DANGEROUS_OPERATORS.test(command)) {\n logWarn(`Denying bash command with dangerous operators: ${command}`);\n debug(`Denying bash command with dangerous operators: ${command}`);\n analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'dangerous operators',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Shell operators like ; \\` $ ( ) are not permitted.`,\n };\n }\n\n // Normalize: remove safe stderr redirection (2>&1, 2>&2, etc.)\n const normalized = command.replace(/\\s*\\d*>&\\d+\\s*/g, ' ').trim();\n\n // Check for pipe to tail/head (safe output limiting)\n const pipeMatch = normalized.match(/^(.+?)\\s*\\|\\s*(tail|head)(\\s+\\S+)*\\s*$/);\n if (pipeMatch) {\n const baseCommand = pipeMatch[1].trim();\n\n // Block if base command has pipes or & (multiple chaining)\n if (/[|&]/.test(baseCommand)) {\n logWarn(`Denying bash command with multiple pipes: ${command}`);\n debug(`Denying bash command with multiple pipes: ${command}`);\n analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'multiple pipes',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Only single pipe to tail/head is permitted.`,\n };\n }\n\n if (matchesAllowedPrefix(baseCommand)) {\n logInfo(`Allowing bash command with output limiter: ${command}`);\n debug(`Allowing bash command with output limiter: ${command}`);\n return { behavior: 'allow', updatedInput: input };\n }\n }\n\n // Block remaining pipes and & (not covered by tail/head case above)\n if (/[|&]/.test(normalized)) {\n logWarn(`Denying bash command with pipe/&: ${command}`);\n debug(`Denying bash command with pipe/&: ${command}`);\n analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'disallowed pipe',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Pipes are only permitted with tail/head for output limiting.`,\n };\n }\n\n // Check if command starts with any allowed prefix\n if (matchesAllowedPrefix(normalized)) {\n logInfo(`Allowing bash command: ${command}`);\n debug(`Allowing bash command: ${command}`);\n return { behavior: 'allow', updatedInput: input };\n }\n\n logWarn(`Denying bash command: ${command}`);\n debug(`Denying bash command: ${command}`);\n analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {\n action: 'bash command denied',\n reason: 'not in allowlist',\n command,\n });\n return {\n behavior: 'deny',\n message: `Bash command not allowed. Only install, build, typecheck, lint, and formatting commands are permitted.`,\n };\n}\n\n/**\n * Initialize agent configuration for the LLM gateway\n */\nexport async function initializeAgent(config: AgentConfig, options: WizardOptions): Promise<AgentRunConfig> {\n // Initialize log file for this run\n initLogFile();\n logInfo('Agent initialization starting');\n logInfo('Install directory:', options.installDir);\n\n // Emit status event for adapters to render\n options.emitter?.emit('status', { message: 'Initializing Claude agent...' });\n\n try {\n // Configure LLM gateway for Claude API calls via LLM_GATEWAY_URL env var\n const gatewayUrl = getLlmGatewayUrlFromHost();\n\n // Check/refresh authentication for production (unless skipping auth)\n if (!options.skipAuth && !options.local) {\n if (!hasCredentials()) {\n throw new Error('Not authenticated. Run `wizard login` to authenticate.');\n }\n\n const refreshResult = await ensureValidToken();\n if (!refreshResult.success) {\n throw new Error(refreshResult.error || 'Authentication failed');\n }\n }\n\n // Set gateway URL\n process.env.ANTHROPIC_BASE_URL = gatewayUrl;\n\n // Only send access token if not skipping auth\n let authMode: string;\n if (options.skipAuth) {\n delete process.env.ANTHROPIC_AUTH_TOKEN;\n authMode = `skip-auth:${gatewayUrl}`;\n logInfo('Skipping auth - no token sent to gateway');\n } else {\n const creds = getCredentials();\n if (!creds) {\n throw new Error('Not authenticated. Run `wizard login` to authenticate.');\n }\n process.env.ANTHROPIC_AUTH_TOKEN = creds.accessToken;\n authMode = options.local ? `local-gateway:${gatewayUrl}` : `workos-gateway:${gatewayUrl}`;\n logInfo('Sending access token to gateway');\n }\n\n logInfo('Configured LLM gateway:', gatewayUrl);\n\n // Disable experimental betas (like input_examples) that the LLM gateway doesn't support\n process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = 'true';\n\n // Disable SDK telemetry - our gateway doesn't proxy /api/event_logging/batch\n process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = 'true';\n\n // Configure WorkOS MCP docs server for accessing WorkOS documentation\n const agentRunConfig: AgentRunConfig = {\n workingDirectory: config.workingDirectory,\n mcpServers: {\n workos: {\n command: 'npx',\n args: ['-y', '@workos/mcp-docs-server'],\n },\n },\n model: getConfig().model,\n allowedTools: ['Skill', 'Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep', 'WebFetch'],\n };\n\n logInfo('Agent config:', {\n workingDirectory: agentRunConfig.workingDirectory,\n gatewayUrl,\n authMode,\n useMcp: false,\n });\n\n if (options.debug) {\n debug('Agent config:', {\n workingDirectory: agentRunConfig.workingDirectory,\n gatewayUrl,\n authMode,\n useMcp: false,\n });\n }\n\n // Emit status events for adapters to render\n const currentLogPath = getLogFilePath();\n if (currentLogPath) {\n options.emitter?.emit('status', { message: `Verbose logs: ${currentLogPath}` });\n }\n options.emitter?.emit('status', { message: \"Agent initialized. Let's get cooking!\" });\n\n return agentRunConfig;\n } catch (error) {\n // Emit error via emitter for adapters to handle\n options.emitter?.emit('error', { message: `Failed to initialize agent: ${(error as Error).message}` });\n logError('Agent initialization error:', error);\n debug('Agent initialization error:', error);\n throw error;\n }\n}\n\n/**\n * Execute an agent with the provided prompt and options\n * Handles the full lifecycle via event emissions - adapters handle UI rendering.\n *\n * @returns An object containing any error detected in the agent's output\n */\nexport async function runAgent(\n agentConfig: AgentRunConfig,\n prompt: string,\n options: WizardOptions,\n config?: {\n spinnerMessage?: string;\n successMessage?: string;\n errorMessage?: string;\n },\n emitter?: WizardEventEmitter,\n): Promise<{ error?: AgentErrorType; errorMessage?: string }> {\n const {\n spinnerMessage = 'Setting up WorkOS AuthKit...',\n successMessage = 'WorkOS AuthKit integration complete',\n errorMessage = 'Integration failed',\n } = config ?? {};\n\n const { query } = await getSDKModule();\n\n // Emit progress for adapters to handle (e.g., CLI adapter starts spinner)\n emitter?.emit('agent:progress', { step: 'Starting', detail: 'This may take a few minutes. Grab some coffee!' });\n emitter?.emit('agent:progress', { step: spinnerMessage });\n\n logInfo('Starting agent run');\n logInfo('Prompt:', prompt);\n\n const startTime = Date.now();\n const collectedText: string[] = [];\n\n try {\n // Workaround for SDK bug: stdin closes before canUseTool responses can be sent.\n // The fix is to use an async generator for the prompt that stays open until\n // the result is received, keeping the stdin stream alive for permission responses.\n // See: https://github.com/anthropics/claude-code/issues/4775\n // See: https://github.com/anthropics/claude-agent-sdk-typescript/issues/41\n let signalDone: () => void;\n const resultReceived = new Promise<void>((resolve) => {\n signalDone = resolve;\n });\n\n const createPromptStream = async function* () {\n yield {\n type: 'user',\n session_id: '',\n message: { role: 'user', content: prompt },\n parent_tool_use_id: null,\n };\n await resultReceived;\n };\n\n // Load plugin with bundled skills\n // Path from dist/src/lib/ back to package root\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = path.dirname(__filename);\n const pluginPath = path.join(__dirname, '../../..');\n logInfo('Loading plugin from:', pluginPath);\n\n const response = query({\n prompt: createPromptStream(),\n options: {\n model: agentConfig.model,\n cwd: agentConfig.workingDirectory,\n permissionMode: 'acceptEdits',\n mcpServers: agentConfig.mcpServers,\n env: { ...process.env },\n canUseTool: (toolName: string, input: unknown) => {\n logInfo('canUseTool called:', { toolName, input });\n const result = wizardCanUseTool(toolName, input as Record<string, unknown>);\n logInfo('canUseTool result:', result);\n return Promise.resolve(result);\n },\n tools: { type: 'preset', preset: 'claude_code' },\n allowedTools: agentConfig.allowedTools,\n plugins: [{ type: 'local', path: pluginPath }],\n // Capture stderr from CLI subprocess for debugging\n stderr: (data: string) => {\n logInfo('CLI stderr:', data);\n if (options.debug) {\n debug('CLI stderr:', data);\n }\n },\n },\n });\n\n // Process the async generator\n let sdkError: string | undefined;\n for await (const message of response) {\n const messageError = handleSDKMessage(message, options, collectedText, emitter);\n if (messageError) {\n sdkError = messageError;\n }\n // Signal completion when result received\n if (message.type === 'result') {\n signalDone!();\n }\n }\n\n const durationMs = Date.now() - startTime;\n const outputText = collectedText.join('\\n');\n\n // Check for SDK errors first (e.g., API errors, auth failures)\n // Return error type + message - caller decides whether to throw or emit events\n if (sdkError) {\n logError('Agent SDK error:', sdkError);\n return { error: AgentErrorType.EXECUTION_ERROR, errorMessage: sdkError };\n }\n\n // Check for error markers in the agent's output\n if (outputText.includes(AgentSignals.ERROR_MCP_MISSING)) {\n logError('Agent error: MCP_MISSING');\n return { error: AgentErrorType.MCP_MISSING, errorMessage: 'Could not access WorkOS MCP server' };\n }\n\n if (outputText.includes(AgentSignals.ERROR_RESOURCE_MISSING)) {\n logError('Agent error: RESOURCE_MISSING');\n return { error: AgentErrorType.RESOURCE_MISSING, errorMessage: 'Could not access setup resource' };\n }\n\n logInfo(`Agent run completed in ${Math.round(durationMs / 1000)}s`);\n analytics.capture(WIZARD_INTERACTION_EVENT_NAME, {\n action: 'agent integration completed',\n duration_ms: durationMs,\n duration_seconds: Math.round(durationMs / 1000),\n });\n\n // Don't emit agent:success here - let the state machine handle lifecycle events\n return {};\n } catch (error) {\n // Don't emit events here - just log and re-throw for state machine to handle\n logError('Agent run failed:', error);\n debug('Full error:', error);\n throw error;\n }\n}\n\n/**\n * Handle SDK messages and emit events for adapters to render.\n * @returns Error message if this was an error result, undefined otherwise\n */\nfunction handleSDKMessage(\n message: SDKMessage,\n options: WizardOptions,\n collectedText: string[],\n emitter?: WizardEventEmitter,\n): string | undefined {\n logInfo(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));\n\n switch (message.type) {\n case 'assistant': {\n // Extract usage data from Anthropic API response for telemetry\n const usage = message.message?.usage;\n if (usage) {\n const inputTokens = usage.input_tokens ?? 0;\n const outputTokens = usage.output_tokens ?? 0;\n const model = message.message?.model ?? 'unknown';\n analytics.llmRequest(model, inputTokens, outputTokens);\n analytics.incrementAgentIterations();\n }\n\n // Extract text content from assistant messages\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n if (block.type === 'text' && typeof block.text === 'string') {\n collectedText.push(block.text);\n\n // Emit output event for dashboard\n emitter?.emit('output', { text: block.text });\n\n // Check for [STATUS] markers and emit progress events\n const statusRegex = new RegExp(\n `^.*${AgentSignals.STATUS.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}\\\\s*(.+?)$`,\n 'm',\n );\n const statusMatch = block.text.match(statusRegex);\n if (statusMatch) {\n const statusText = statusMatch[1].trim();\n // Emit progress event - adapters handle spinner updates\n emitter?.emit('agent:progress', { step: statusText });\n emitter?.emit('status', { message: statusText });\n }\n }\n\n // Check for tool_use blocks (Write/Edit operations)\n if (block.type === 'tool_use') {\n const toolName = block.name as string;\n const toolUseId = block.id as string;\n const input = block.input as Record<string, unknown>;\n\n // Log tool usage for debugging\n logInfo(`Tool use: ${toolName}`);\n\n // Track tool start time for telemetry\n if (toolUseId) {\n pendingToolCalls.set(toolUseId, { toolName, startTime: Date.now() });\n }\n\n // Emit file:write event for Write tool\n if (toolName === 'Write' && input) {\n const filePath = input.file_path as string;\n const fileContent = input.content as string;\n if (filePath && fileContent) {\n emitter?.emit('file:write', { path: filePath, content: fileContent });\n }\n }\n\n // Emit file:edit event for Edit tool\n if (toolName === 'Edit' && input) {\n const filePath = input.file_path as string;\n const oldString = input.old_string as string;\n const newString = input.new_string as string;\n if (filePath && oldString !== undefined && newString !== undefined) {\n // Emit the actual strings being replaced, not reconstructed full file\n emitter?.emit('file:edit', {\n path: filePath,\n oldContent: oldString,\n newContent: newString,\n });\n }\n }\n\n // Track Read operations for caching file content later\n if (toolName === 'Read' && input && block.id) {\n const filePath = input.file_path as string;\n if (filePath) {\n pendingReads.set(block.id as string, filePath);\n }\n }\n }\n }\n }\n break;\n }\n\n case 'user': {\n // User messages contain tool results\n const content = message.message?.content;\n if (Array.isArray(content)) {\n for (const block of content) {\n // Tool results contain file content from Read operations\n if (block.type === 'tool_result' && block.tool_use_id) {\n const toolUseId = block.tool_use_id as string;\n\n // Emit telemetry for completed tool call\n const pendingTool = pendingToolCalls.get(toolUseId);\n if (pendingTool) {\n const durationMs = Date.now() - pendingTool.startTime;\n // Check if tool result indicates error (is_error field or error in content)\n const isError = block.is_error === true;\n analytics.toolCalled(pendingTool.toolName, durationMs, !isError);\n pendingToolCalls.delete(toolUseId);\n }\n\n const filePath = pendingReads.get(toolUseId);\n if (filePath) {\n // Extract content from the tool result\n let resultContent = '';\n if (typeof block.content === 'string') {\n resultContent = block.content;\n } else if (Array.isArray(block.content)) {\n // Content might be array of text blocks\n for (const item of block.content) {\n if (item.type === 'text' && item.text) {\n resultContent += item.text;\n }\n }\n }\n if (resultContent) {\n fileContentCache.set(filePath, resultContent);\n }\n pendingReads.delete(toolUseId);\n }\n }\n }\n }\n break;\n }\n\n case 'tool': {\n // This case may not be used by the current SDK, keeping for compatibility\n const toolName = message.tool as string;\n const input = message.input as Record<string, unknown> | undefined;\n\n if (toolName === 'Read' && message.content) {\n const filePath = input?.file_path as string;\n if (filePath && typeof message.content === 'string') {\n fileContentCache.set(filePath, message.content);\n }\n }\n\n break;\n }\n\n case 'result': {\n if (message.subtype === 'success') {\n logInfo('Agent completed successfully');\n if (typeof message.result === 'string') {\n collectedText.push(message.result);\n }\n } else {\n // Error result\n logError('Agent error result:', message.subtype);\n if (message.errors && message.errors.length > 0) {\n for (const err of message.errors) {\n logError('ERROR:', err);\n // Emit error event - adapters handle rendering\n emitter?.emit('error', { message: err });\n }\n // Return the first error message\n return message.errors[0];\n }\n // Return generic error if subtype indicates failure but no errors array\n return `Agent execution failed: ${message.subtype}`;\n }\n break;\n }\n\n case 'system': {\n if (message.subtype === 'init') {\n logInfo('Agent session initialized', {\n model: message.model,\n tools: message.tools?.length,\n mcpServers: message.mcp_servers,\n });\n }\n break;\n }\n\n default:\n // Log other message types for debugging\n if (options.debug) {\n debug(`Unhandled message type: ${message.type}`);\n }\n break;\n }\n return undefined;\n}\n"]}
|