@excitedjs/tm 1.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/bin/tm +76 -0
- package/package.json +39 -0
- package/resolver-register.mjs +7 -0
- package/resolver.mjs +86 -0
- package/src/cli/context.ts +63 -0
- package/src/cli/dispatch.ts +444 -0
- package/src/cli/errors.ts +45 -0
- package/src/cli/parse.ts +265 -0
- package/src/cli.ts +12 -0
- package/src/codex-protocol/AbsolutePathBuf.ts +14 -0
- package/src/codex-protocol/AgentPath.ts +5 -0
- package/src/codex-protocol/ApplyPatchApprovalParams.ts +21 -0
- package/src/codex-protocol/ApplyPatchApprovalResponse.ts +6 -0
- package/src/codex-protocol/AuthMode.ts +8 -0
- package/src/codex-protocol/AutoCompactTokenLimitScope.ts +9 -0
- package/src/codex-protocol/ClientInfo.ts +5 -0
- package/src/codex-protocol/ClientNotification.ts +5 -0
- package/src/codex-protocol/ClientRequest.ts +110 -0
- package/src/codex-protocol/CollaborationMode.ts +10 -0
- package/src/codex-protocol/ContentItem.ts +6 -0
- package/src/codex-protocol/ConversationGitInfo.ts +5 -0
- package/src/codex-protocol/ConversationSummary.ts +8 -0
- package/src/codex-protocol/ExecCommandApprovalParams.ts +16 -0
- package/src/codex-protocol/ExecCommandApprovalResponse.ts +6 -0
- package/src/codex-protocol/ExecPolicyAmendment.ts +12 -0
- package/src/codex-protocol/FileChange.ts +5 -0
- package/src/codex-protocol/ForcedLoginMethod.ts +5 -0
- package/src/codex-protocol/FunctionCallOutputBody.ts +6 -0
- package/src/codex-protocol/FunctionCallOutputContentItem.ts +10 -0
- package/src/codex-protocol/FuzzyFileSearchMatchType.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchParams.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchResponse.ts +6 -0
- package/src/codex-protocol/FuzzyFileSearchResult.ts +9 -0
- package/src/codex-protocol/FuzzyFileSearchSessionCompletedNotification.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchSessionStartParams.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchSessionStartResponse.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchSessionStopParams.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchSessionStopResponse.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchSessionUpdateParams.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchSessionUpdateResponse.ts +5 -0
- package/src/codex-protocol/FuzzyFileSearchSessionUpdatedNotification.ts +6 -0
- package/src/codex-protocol/GetAuthStatusParams.ts +5 -0
- package/src/codex-protocol/GetAuthStatusResponse.ts +6 -0
- package/src/codex-protocol/GetConversationSummaryParams.ts +6 -0
- package/src/codex-protocol/GetConversationSummaryResponse.ts +6 -0
- package/src/codex-protocol/GitDiffToRemoteParams.ts +5 -0
- package/src/codex-protocol/GitDiffToRemoteResponse.ts +6 -0
- package/src/codex-protocol/GitSha.ts +5 -0
- package/src/codex-protocol/ImageDetail.ts +5 -0
- package/src/codex-protocol/InitializeCapabilities.ts +21 -0
- package/src/codex-protocol/InitializeParams.ts +7 -0
- package/src/codex-protocol/InitializeResponse.ts +20 -0
- package/src/codex-protocol/InputModality.ts +8 -0
- package/src/codex-protocol/InternalSessionSource.ts +5 -0
- package/src/codex-protocol/LocalShellAction.ts +6 -0
- package/src/codex-protocol/LocalShellExecAction.ts +5 -0
- package/src/codex-protocol/LocalShellStatus.ts +5 -0
- package/src/codex-protocol/MessagePhase.ts +11 -0
- package/src/codex-protocol/ModeKind.ts +8 -0
- package/src/codex-protocol/NetworkPolicyAmendment.ts +6 -0
- package/src/codex-protocol/NetworkPolicyRuleAction.ts +5 -0
- package/src/codex-protocol/ParsedCommand.ts +12 -0
- package/src/codex-protocol/Personality.ts +5 -0
- package/src/codex-protocol/PlanType.ts +5 -0
- package/src/codex-protocol/RealtimeConversationVersion.ts +5 -0
- package/src/codex-protocol/RealtimeOutputModality.ts +5 -0
- package/src/codex-protocol/RealtimeVoice.ts +5 -0
- package/src/codex-protocol/RealtimeVoicesList.ts +6 -0
- package/src/codex-protocol/ReasoningEffort.ts +8 -0
- package/src/codex-protocol/ReasoningItemContent.ts +5 -0
- package/src/codex-protocol/ReasoningItemReasoningSummary.ts +5 -0
- package/src/codex-protocol/ReasoningSummary.ts +10 -0
- package/src/codex-protocol/RequestId.ts +5 -0
- package/src/codex-protocol/Resource.ts +9 -0
- package/src/codex-protocol/ResourceContent.ts +17 -0
- package/src/codex-protocol/ResourceTemplate.ts +9 -0
- package/src/codex-protocol/ResponseItem.ts +17 -0
- package/src/codex-protocol/ReviewDecision.ts +10 -0
- package/src/codex-protocol/ServerNotification.ts +73 -0
- package/src/codex-protocol/ServerRequest.ts +19 -0
- package/src/codex-protocol/SessionSource.ts +7 -0
- package/src/codex-protocol/Settings.ts +9 -0
- package/src/codex-protocol/SubAgentSource.ts +7 -0
- package/src/codex-protocol/ThreadId.ts +5 -0
- package/src/codex-protocol/ThreadMemoryMode.ts +5 -0
- package/src/codex-protocol/Tool.ts +9 -0
- package/src/codex-protocol/Verbosity.ts +9 -0
- package/src/codex-protocol/WebSearchAction.ts +5 -0
- package/src/codex-protocol/WebSearchContextSize.ts +5 -0
- package/src/codex-protocol/WebSearchLocation.ts +5 -0
- package/src/codex-protocol/WebSearchMode.ts +5 -0
- package/src/codex-protocol/WebSearchToolConfig.ts +7 -0
- package/src/codex-protocol/index.ts +86 -0
- package/src/codex-protocol/serde_json/JsonValue.ts +5 -0
- package/src/codex-protocol/v2/Account.ts +6 -0
- package/src/codex-protocol/v2/AccountLoginCompletedNotification.ts +5 -0
- package/src/codex-protocol/v2/AccountRateLimitsUpdatedNotification.ts +6 -0
- package/src/codex-protocol/v2/AccountUpdatedNotification.ts +7 -0
- package/src/codex-protocol/v2/ActivePermissionProfile.ts +15 -0
- package/src/codex-protocol/v2/AddCreditsNudgeCreditType.ts +5 -0
- package/src/codex-protocol/v2/AddCreditsNudgeEmailStatus.ts +5 -0
- package/src/codex-protocol/v2/AdditionalFileSystemPermissions.ts +15 -0
- package/src/codex-protocol/v2/AdditionalNetworkPermissions.ts +5 -0
- package/src/codex-protocol/v2/AdditionalPermissionProfile.ts +11 -0
- package/src/codex-protocol/v2/AgentMessageDeltaNotification.ts +5 -0
- package/src/codex-protocol/v2/AnalyticsConfig.ts +6 -0
- package/src/codex-protocol/v2/AppBranding.ts +8 -0
- package/src/codex-protocol/v2/AppInfo.ts +19 -0
- package/src/codex-protocol/v2/AppListUpdatedNotification.ts +9 -0
- package/src/codex-protocol/v2/AppMetadata.ts +7 -0
- package/src/codex-protocol/v2/AppReview.ts +5 -0
- package/src/codex-protocol/v2/AppScreenshot.ts +5 -0
- package/src/codex-protocol/v2/AppSummary.ts +8 -0
- package/src/codex-protocol/v2/AppToolApproval.ts +5 -0
- package/src/codex-protocol/v2/AppToolsConfig.ts +6 -0
- package/src/codex-protocol/v2/ApprovalsReviewer.ts +12 -0
- package/src/codex-protocol/v2/AppsConfig.ts +8 -0
- package/src/codex-protocol/v2/AppsDefaultConfig.ts +5 -0
- package/src/codex-protocol/v2/AppsListParams.ts +24 -0
- package/src/codex-protocol/v2/AppsListResponse.ts +14 -0
- package/src/codex-protocol/v2/AskForApproval.ts +5 -0
- package/src/codex-protocol/v2/AttestationGenerateParams.ts +5 -0
- package/src/codex-protocol/v2/AttestationGenerateResponse.ts +9 -0
- package/src/codex-protocol/v2/AutoReviewDecisionSource.ts +8 -0
- package/src/codex-protocol/v2/ByteRange.ts +5 -0
- package/src/codex-protocol/v2/CancelLoginAccountParams.ts +5 -0
- package/src/codex-protocol/v2/CancelLoginAccountResponse.ts +6 -0
- package/src/codex-protocol/v2/CancelLoginAccountStatus.ts +5 -0
- package/src/codex-protocol/v2/ChatgptAuthTokensRefreshParams.ts +16 -0
- package/src/codex-protocol/v2/ChatgptAuthTokensRefreshReason.ts +5 -0
- package/src/codex-protocol/v2/ChatgptAuthTokensRefreshResponse.ts +5 -0
- package/src/codex-protocol/v2/CodexErrorInfo.ts +12 -0
- package/src/codex-protocol/v2/CollabAgentState.ts +6 -0
- package/src/codex-protocol/v2/CollabAgentStatus.ts +5 -0
- package/src/codex-protocol/v2/CollabAgentTool.ts +5 -0
- package/src/codex-protocol/v2/CollabAgentToolCallStatus.ts +5 -0
- package/src/codex-protocol/v2/CollaborationModeListParams.ts +8 -0
- package/src/codex-protocol/v2/CollaborationModeListResponse.ts +9 -0
- package/src/codex-protocol/v2/CollaborationModeMask.ts +10 -0
- package/src/codex-protocol/v2/CommandAction.ts +6 -0
- package/src/codex-protocol/v2/CommandExecOutputDeltaNotification.ts +30 -0
- package/src/codex-protocol/v2/CommandExecOutputStream.ts +8 -0
- package/src/codex-protocol/v2/CommandExecParams.ts +105 -0
- package/src/codex-protocol/v2/CommandExecResizeParams.ts +18 -0
- package/src/codex-protocol/v2/CommandExecResizeResponse.ts +8 -0
- package/src/codex-protocol/v2/CommandExecResponse.ts +24 -0
- package/src/codex-protocol/v2/CommandExecTerminalSize.ts +16 -0
- package/src/codex-protocol/v2/CommandExecTerminateParams.ts +13 -0
- package/src/codex-protocol/v2/CommandExecTerminateResponse.ts +8 -0
- package/src/codex-protocol/v2/CommandExecWriteParams.ts +22 -0
- package/src/codex-protocol/v2/CommandExecWriteResponse.ts +8 -0
- package/src/codex-protocol/v2/CommandExecutionApprovalDecision.ts +7 -0
- package/src/codex-protocol/v2/CommandExecutionOutputDeltaNotification.ts +5 -0
- package/src/codex-protocol/v2/CommandExecutionRequestApprovalParams.ts +62 -0
- package/src/codex-protocol/v2/CommandExecutionRequestApprovalResponse.ts +6 -0
- package/src/codex-protocol/v2/CommandExecutionSource.ts +5 -0
- package/src/codex-protocol/v2/CommandExecutionStatus.ts +5 -0
- package/src/codex-protocol/v2/CommandMigration.ts +5 -0
- package/src/codex-protocol/v2/ComputerUseRequirements.ts +5 -0
- package/src/codex-protocol/v2/Config.ts +26 -0
- package/src/codex-protocol/v2/ConfigBatchWriteParams.ts +14 -0
- package/src/codex-protocol/v2/ConfigEdit.ts +7 -0
- package/src/codex-protocol/v2/ConfigLayer.ts +7 -0
- package/src/codex-protocol/v2/ConfigLayerMetadata.ts +6 -0
- package/src/codex-protocol/v2/ConfigLayerSource.ts +21 -0
- package/src/codex-protocol/v2/ConfigReadParams.ts +11 -0
- package/src/codex-protocol/v2/ConfigReadResponse.ts +8 -0
- package/src/codex-protocol/v2/ConfigRequirements.ts +13 -0
- package/src/codex-protocol/v2/ConfigRequirementsReadResponse.ts +10 -0
- package/src/codex-protocol/v2/ConfigValueWriteParams.ts +11 -0
- package/src/codex-protocol/v2/ConfigWarningNotification.ts +22 -0
- package/src/codex-protocol/v2/ConfigWriteResponse.ts +12 -0
- package/src/codex-protocol/v2/ConfiguredHookHandler.ts +5 -0
- package/src/codex-protocol/v2/ConfiguredHookMatcherGroup.ts +6 -0
- package/src/codex-protocol/v2/ContextCompactedNotification.ts +8 -0
- package/src/codex-protocol/v2/CreditsSnapshot.ts +5 -0
- package/src/codex-protocol/v2/DeprecationNoticeNotification.ts +13 -0
- package/src/codex-protocol/v2/DynamicToolCallOutputContentItem.ts +5 -0
- package/src/codex-protocol/v2/DynamicToolCallParams.ts +6 -0
- package/src/codex-protocol/v2/DynamicToolCallResponse.ts +6 -0
- package/src/codex-protocol/v2/DynamicToolCallStatus.ts +5 -0
- package/src/codex-protocol/v2/DynamicToolSpec.ts +6 -0
- package/src/codex-protocol/v2/EnvironmentAddParams.ts +5 -0
- package/src/codex-protocol/v2/EnvironmentAddResponse.ts +5 -0
- package/src/codex-protocol/v2/ErrorNotification.ts +6 -0
- package/src/codex-protocol/v2/ExecPolicyAmendment.ts +5 -0
- package/src/codex-protocol/v2/ExperimentalFeature.ts +37 -0
- package/src/codex-protocol/v2/ExperimentalFeatureEnablementSetParams.ts +12 -0
- package/src/codex-protocol/v2/ExperimentalFeatureEnablementSetResponse.ts +9 -0
- package/src/codex-protocol/v2/ExperimentalFeatureListParams.ts +19 -0
- package/src/codex-protocol/v2/ExperimentalFeatureListResponse.ts +11 -0
- package/src/codex-protocol/v2/ExperimentalFeatureStage.ts +5 -0
- package/src/codex-protocol/v2/ExternalAgentConfigDetectParams.ts +13 -0
- package/src/codex-protocol/v2/ExternalAgentConfigDetectResponse.ts +6 -0
- package/src/codex-protocol/v2/ExternalAgentConfigImportCompletedNotification.ts +5 -0
- package/src/codex-protocol/v2/ExternalAgentConfigImportParams.ts +6 -0
- package/src/codex-protocol/v2/ExternalAgentConfigImportResponse.ts +5 -0
- package/src/codex-protocol/v2/ExternalAgentConfigMigrationItem.ts +11 -0
- package/src/codex-protocol/v2/ExternalAgentConfigMigrationItemType.ts +5 -0
- package/src/codex-protocol/v2/FeedbackUploadParams.ts +5 -0
- package/src/codex-protocol/v2/FeedbackUploadResponse.ts +5 -0
- package/src/codex-protocol/v2/FileChangeApprovalDecision.ts +5 -0
- package/src/codex-protocol/v2/FileChangeOutputDeltaNotification.ts +10 -0
- package/src/codex-protocol/v2/FileChangePatchUpdatedNotification.ts +6 -0
- package/src/codex-protocol/v2/FileChangeRequestApprovalParams.ts +18 -0
- package/src/codex-protocol/v2/FileChangeRequestApprovalResponse.ts +6 -0
- package/src/codex-protocol/v2/FileSystemAccessMode.ts +5 -0
- package/src/codex-protocol/v2/FileSystemPath.ts +7 -0
- package/src/codex-protocol/v2/FileSystemSandboxEntry.ts +7 -0
- package/src/codex-protocol/v2/FileSystemSpecialPath.ts +5 -0
- package/src/codex-protocol/v2/FileUpdateChange.ts +6 -0
- package/src/codex-protocol/v2/ForcedChatgptWorkspaceIds.ts +8 -0
- package/src/codex-protocol/v2/FsChangedNotification.ts +17 -0
- package/src/codex-protocol/v2/FsCopyParams.ts +21 -0
- package/src/codex-protocol/v2/FsCopyResponse.ts +8 -0
- package/src/codex-protocol/v2/FsCreateDirectoryParams.ts +17 -0
- package/src/codex-protocol/v2/FsCreateDirectoryResponse.ts +8 -0
- package/src/codex-protocol/v2/FsGetMetadataParams.ts +13 -0
- package/src/codex-protocol/v2/FsGetMetadataResponse.ts +28 -0
- package/src/codex-protocol/v2/FsReadDirectoryEntry.ts +20 -0
- package/src/codex-protocol/v2/FsReadDirectoryParams.ts +13 -0
- package/src/codex-protocol/v2/FsReadDirectoryResponse.ts +13 -0
- package/src/codex-protocol/v2/FsReadFileParams.ts +13 -0
- package/src/codex-protocol/v2/FsReadFileResponse.ts +12 -0
- package/src/codex-protocol/v2/FsRemoveParams.ts +21 -0
- package/src/codex-protocol/v2/FsRemoveResponse.ts +8 -0
- package/src/codex-protocol/v2/FsUnwatchParams.ts +12 -0
- package/src/codex-protocol/v2/FsUnwatchResponse.ts +8 -0
- package/src/codex-protocol/v2/FsWatchParams.ts +17 -0
- package/src/codex-protocol/v2/FsWatchResponse.ts +13 -0
- package/src/codex-protocol/v2/FsWriteFileParams.ts +17 -0
- package/src/codex-protocol/v2/FsWriteFileResponse.ts +8 -0
- package/src/codex-protocol/v2/GetAccountParams.ts +13 -0
- package/src/codex-protocol/v2/GetAccountRateLimitsResponse.ts +14 -0
- package/src/codex-protocol/v2/GetAccountResponse.ts +6 -0
- package/src/codex-protocol/v2/GitInfo.ts +5 -0
- package/src/codex-protocol/v2/GrantedPermissionProfile.ts +7 -0
- package/src/codex-protocol/v2/GuardianApprovalReview.ts +13 -0
- package/src/codex-protocol/v2/GuardianApprovalReviewAction.ts +9 -0
- package/src/codex-protocol/v2/GuardianApprovalReviewStatus.ts +8 -0
- package/src/codex-protocol/v2/GuardianCommandSource.ts +5 -0
- package/src/codex-protocol/v2/GuardianRiskLevel.ts +8 -0
- package/src/codex-protocol/v2/GuardianUserAuthorization.ts +8 -0
- package/src/codex-protocol/v2/GuardianWarningNotification.ts +13 -0
- package/src/codex-protocol/v2/HookCompletedNotification.ts +6 -0
- package/src/codex-protocol/v2/HookErrorInfo.ts +5 -0
- package/src/codex-protocol/v2/HookEventName.ts +5 -0
- package/src/codex-protocol/v2/HookExecutionMode.ts +5 -0
- package/src/codex-protocol/v2/HookHandlerType.ts +5 -0
- package/src/codex-protocol/v2/HookMetadata.ts +10 -0
- package/src/codex-protocol/v2/HookMigration.ts +5 -0
- package/src/codex-protocol/v2/HookOutputEntry.ts +6 -0
- package/src/codex-protocol/v2/HookOutputEntryKind.ts +5 -0
- package/src/codex-protocol/v2/HookPromptFragment.ts +5 -0
- package/src/codex-protocol/v2/HookRunStatus.ts +5 -0
- package/src/codex-protocol/v2/HookRunSummary.ts +13 -0
- package/src/codex-protocol/v2/HookScope.ts +5 -0
- package/src/codex-protocol/v2/HookSource.ts +5 -0
- package/src/codex-protocol/v2/HookStartedNotification.ts +6 -0
- package/src/codex-protocol/v2/HookTrustStatus.ts +5 -0
- package/src/codex-protocol/v2/HooksListEntry.ts +7 -0
- package/src/codex-protocol/v2/HooksListParams.ts +9 -0
- package/src/codex-protocol/v2/HooksListResponse.ts +6 -0
- package/src/codex-protocol/v2/ItemCompletedNotification.ts +10 -0
- package/src/codex-protocol/v2/ItemGuardianApprovalReviewCompletedNotification.ts +38 -0
- package/src/codex-protocol/v2/ItemGuardianApprovalReviewStartedNotification.ts +33 -0
- package/src/codex-protocol/v2/ItemStartedNotification.ts +10 -0
- package/src/codex-protocol/v2/ListMcpServerStatusParams.ts +19 -0
- package/src/codex-protocol/v2/ListMcpServerStatusResponse.ts +11 -0
- package/src/codex-protocol/v2/LoginAccountParams.ts +21 -0
- package/src/codex-protocol/v2/LoginAccountResponse.ts +17 -0
- package/src/codex-protocol/v2/LogoutAccountResponse.ts +5 -0
- package/src/codex-protocol/v2/ManagedHooksRequirements.ts +6 -0
- package/src/codex-protocol/v2/MarketplaceAddParams.ts +5 -0
- package/src/codex-protocol/v2/MarketplaceAddResponse.ts +6 -0
- package/src/codex-protocol/v2/MarketplaceInterface.ts +5 -0
- package/src/codex-protocol/v2/MarketplaceLoadErrorInfo.ts +6 -0
- package/src/codex-protocol/v2/MarketplaceRemoveParams.ts +5 -0
- package/src/codex-protocol/v2/MarketplaceRemoveResponse.ts +6 -0
- package/src/codex-protocol/v2/MarketplaceUpgradeErrorInfo.ts +5 -0
- package/src/codex-protocol/v2/MarketplaceUpgradeParams.ts +5 -0
- package/src/codex-protocol/v2/MarketplaceUpgradeResponse.ts +7 -0
- package/src/codex-protocol/v2/McpAuthStatus.ts +5 -0
- package/src/codex-protocol/v2/McpElicitationArrayType.ts +5 -0
- package/src/codex-protocol/v2/McpElicitationBooleanSchema.ts +6 -0
- package/src/codex-protocol/v2/McpElicitationBooleanType.ts +5 -0
- package/src/codex-protocol/v2/McpElicitationConstOption.ts +5 -0
- package/src/codex-protocol/v2/McpElicitationEnumSchema.ts +8 -0
- package/src/codex-protocol/v2/McpElicitationLegacyTitledEnumSchema.ts +6 -0
- package/src/codex-protocol/v2/McpElicitationMultiSelectEnumSchema.ts +7 -0
- package/src/codex-protocol/v2/McpElicitationNumberSchema.ts +6 -0
- package/src/codex-protocol/v2/McpElicitationNumberType.ts +5 -0
- package/src/codex-protocol/v2/McpElicitationObjectType.ts +5 -0
- package/src/codex-protocol/v2/McpElicitationPrimitiveSchema.ts +9 -0
- package/src/codex-protocol/v2/McpElicitationSchema.ts +13 -0
- package/src/codex-protocol/v2/McpElicitationSingleSelectEnumSchema.ts +7 -0
- package/src/codex-protocol/v2/McpElicitationStringFormat.ts +5 -0
- package/src/codex-protocol/v2/McpElicitationStringSchema.ts +7 -0
- package/src/codex-protocol/v2/McpElicitationStringType.ts +5 -0
- package/src/codex-protocol/v2/McpElicitationTitledEnumItems.ts +6 -0
- package/src/codex-protocol/v2/McpElicitationTitledMultiSelectEnumSchema.ts +7 -0
- package/src/codex-protocol/v2/McpElicitationTitledSingleSelectEnumSchema.ts +7 -0
- package/src/codex-protocol/v2/McpElicitationUntitledEnumItems.ts +6 -0
- package/src/codex-protocol/v2/McpElicitationUntitledMultiSelectEnumSchema.ts +7 -0
- package/src/codex-protocol/v2/McpElicitationUntitledSingleSelectEnumSchema.ts +6 -0
- package/src/codex-protocol/v2/McpResourceReadParams.ts +5 -0
- package/src/codex-protocol/v2/McpResourceReadResponse.ts +6 -0
- package/src/codex-protocol/v2/McpServerElicitationAction.ts +5 -0
- package/src/codex-protocol/v2/McpServerElicitationRequestParams.ts +16 -0
- package/src/codex-protocol/v2/McpServerElicitationRequestResponse.ts +17 -0
- package/src/codex-protocol/v2/McpServerMigration.ts +5 -0
- package/src/codex-protocol/v2/McpServerOauthLoginCompletedNotification.ts +5 -0
- package/src/codex-protocol/v2/McpServerOauthLoginParams.ts +5 -0
- package/src/codex-protocol/v2/McpServerOauthLoginResponse.ts +5 -0
- package/src/codex-protocol/v2/McpServerRefreshResponse.ts +5 -0
- package/src/codex-protocol/v2/McpServerStartupState.ts +5 -0
- package/src/codex-protocol/v2/McpServerStatus.ts +9 -0
- package/src/codex-protocol/v2/McpServerStatusDetail.ts +5 -0
- package/src/codex-protocol/v2/McpServerStatusUpdatedNotification.ts +6 -0
- package/src/codex-protocol/v2/McpServerToolCallParams.ts +6 -0
- package/src/codex-protocol/v2/McpServerToolCallResponse.ts +6 -0
- package/src/codex-protocol/v2/McpToolCallError.ts +5 -0
- package/src/codex-protocol/v2/McpToolCallProgressNotification.ts +5 -0
- package/src/codex-protocol/v2/McpToolCallResult.ts +6 -0
- package/src/codex-protocol/v2/McpToolCallStatus.ts +5 -0
- package/src/codex-protocol/v2/MemoryCitation.ts +6 -0
- package/src/codex-protocol/v2/MemoryCitationEntry.ts +5 -0
- package/src/codex-protocol/v2/MemoryResetResponse.ts +5 -0
- package/src/codex-protocol/v2/MergeStrategy.ts +5 -0
- package/src/codex-protocol/v2/MigrationDetails.ts +11 -0
- package/src/codex-protocol/v2/MockExperimentalMethodParams.ts +9 -0
- package/src/codex-protocol/v2/MockExperimentalMethodResponse.ts +9 -0
- package/src/codex-protocol/v2/Model.ts +19 -0
- package/src/codex-protocol/v2/ModelAvailabilityNux.ts +5 -0
- package/src/codex-protocol/v2/ModelListParams.ts +17 -0
- package/src/codex-protocol/v2/ModelListResponse.ts +11 -0
- package/src/codex-protocol/v2/ModelProviderCapabilitiesReadParams.ts +5 -0
- package/src/codex-protocol/v2/ModelProviderCapabilitiesReadResponse.ts +5 -0
- package/src/codex-protocol/v2/ModelRerouteReason.ts +5 -0
- package/src/codex-protocol/v2/ModelReroutedNotification.ts +6 -0
- package/src/codex-protocol/v2/ModelServiceTier.ts +5 -0
- package/src/codex-protocol/v2/ModelUpgradeInfo.ts +5 -0
- package/src/codex-protocol/v2/ModelVerification.ts +5 -0
- package/src/codex-protocol/v2/ModelVerificationNotification.ts +6 -0
- package/src/codex-protocol/v2/NetworkAccess.ts +5 -0
- package/src/codex-protocol/v2/NetworkApprovalContext.ts +6 -0
- package/src/codex-protocol/v2/NetworkApprovalProtocol.ts +5 -0
- package/src/codex-protocol/v2/NetworkDomainPermission.ts +5 -0
- package/src/codex-protocol/v2/NetworkPolicyAmendment.ts +6 -0
- package/src/codex-protocol/v2/NetworkPolicyRuleAction.ts +5 -0
- package/src/codex-protocol/v2/NetworkRequirements.ts +32 -0
- package/src/codex-protocol/v2/NetworkUnixSocketPermission.ts +5 -0
- package/src/codex-protocol/v2/NonSteerableTurnKind.ts +5 -0
- package/src/codex-protocol/v2/OverriddenMetadata.ts +7 -0
- package/src/codex-protocol/v2/PatchApplyStatus.ts +5 -0
- package/src/codex-protocol/v2/PatchChangeKind.ts +5 -0
- package/src/codex-protocol/v2/PermissionGrantScope.ts +5 -0
- package/src/codex-protocol/v2/PermissionProfileListParams.ts +17 -0
- package/src/codex-protocol/v2/PermissionProfileListResponse.ts +11 -0
- package/src/codex-protocol/v2/PermissionProfileSummary.ts +13 -0
- package/src/codex-protocol/v2/PermissionsRequestApprovalParams.ts +11 -0
- package/src/codex-protocol/v2/PermissionsRequestApprovalResponse.ts +11 -0
- package/src/codex-protocol/v2/PlanDeltaNotification.ts +9 -0
- package/src/codex-protocol/v2/PluginAuthPolicy.ts +5 -0
- package/src/codex-protocol/v2/PluginAvailability.ts +5 -0
- package/src/codex-protocol/v2/PluginDetail.ts +10 -0
- package/src/codex-protocol/v2/PluginHookSummary.ts +6 -0
- package/src/codex-protocol/v2/PluginInstallParams.ts +6 -0
- package/src/codex-protocol/v2/PluginInstallPolicy.ts +5 -0
- package/src/codex-protocol/v2/PluginInstallResponse.ts +7 -0
- package/src/codex-protocol/v2/PluginInstalledParams.ts +15 -0
- package/src/codex-protocol/v2/PluginInstalledResponse.ts +7 -0
- package/src/codex-protocol/v2/PluginInterface.ts +35 -0
- package/src/codex-protocol/v2/PluginListMarketplaceKind.ts +5 -0
- package/src/codex-protocol/v2/PluginListParams.ts +17 -0
- package/src/codex-protocol/v2/PluginListResponse.ts +7 -0
- package/src/codex-protocol/v2/PluginMarketplaceEntry.ts +13 -0
- package/src/codex-protocol/v2/PluginReadParams.ts +6 -0
- package/src/codex-protocol/v2/PluginReadResponse.ts +6 -0
- package/src/codex-protocol/v2/PluginShareCheckoutParams.ts +5 -0
- package/src/codex-protocol/v2/PluginShareCheckoutResponse.ts +6 -0
- package/src/codex-protocol/v2/PluginShareContext.ts +11 -0
- package/src/codex-protocol/v2/PluginShareDeleteParams.ts +5 -0
- package/src/codex-protocol/v2/PluginShareDeleteResponse.ts +5 -0
- package/src/codex-protocol/v2/PluginShareDiscoverability.ts +5 -0
- package/src/codex-protocol/v2/PluginShareListItem.ts +7 -0
- package/src/codex-protocol/v2/PluginShareListParams.ts +5 -0
- package/src/codex-protocol/v2/PluginShareListResponse.ts +6 -0
- package/src/codex-protocol/v2/PluginSharePrincipal.ts +7 -0
- package/src/codex-protocol/v2/PluginSharePrincipalRole.ts +5 -0
- package/src/codex-protocol/v2/PluginSharePrincipalType.ts +5 -0
- package/src/codex-protocol/v2/PluginShareSaveParams.ts +8 -0
- package/src/codex-protocol/v2/PluginShareSaveResponse.ts +5 -0
- package/src/codex-protocol/v2/PluginShareTarget.ts +7 -0
- package/src/codex-protocol/v2/PluginShareTargetRole.ts +5 -0
- package/src/codex-protocol/v2/PluginShareUpdateDiscoverability.ts +5 -0
- package/src/codex-protocol/v2/PluginShareUpdateTargetsParams.ts +7 -0
- package/src/codex-protocol/v2/PluginShareUpdateTargetsResponse.ts +7 -0
- package/src/codex-protocol/v2/PluginSkillReadParams.ts +5 -0
- package/src/codex-protocol/v2/PluginSkillReadResponse.ts +5 -0
- package/src/codex-protocol/v2/PluginSource.ts +6 -0
- package/src/codex-protocol/v2/PluginSummary.ts +27 -0
- package/src/codex-protocol/v2/PluginUninstallParams.ts +5 -0
- package/src/codex-protocol/v2/PluginUninstallResponse.ts +5 -0
- package/src/codex-protocol/v2/PluginsMigration.ts +5 -0
- package/src/codex-protocol/v2/ProcessExitedNotification.ts +42 -0
- package/src/codex-protocol/v2/ProcessKillParams.ts +12 -0
- package/src/codex-protocol/v2/ProcessKillResponse.ts +8 -0
- package/src/codex-protocol/v2/ProcessOutputDeltaNotification.ts +26 -0
- package/src/codex-protocol/v2/ProcessOutputStream.ts +8 -0
- package/src/codex-protocol/v2/ProcessResizePtyParams.ts +17 -0
- package/src/codex-protocol/v2/ProcessResizePtyResponse.ts +8 -0
- package/src/codex-protocol/v2/ProcessSpawnParams.ts +73 -0
- package/src/codex-protocol/v2/ProcessSpawnResponse.ts +8 -0
- package/src/codex-protocol/v2/ProcessTerminalSize.ts +16 -0
- package/src/codex-protocol/v2/ProcessWriteStdinParams.ts +21 -0
- package/src/codex-protocol/v2/ProcessWriteStdinResponse.ts +8 -0
- package/src/codex-protocol/v2/ProfileV2.ts +19 -0
- package/src/codex-protocol/v2/RateLimitReachedType.ts +5 -0
- package/src/codex-protocol/v2/RateLimitSnapshot.ts +9 -0
- package/src/codex-protocol/v2/RateLimitWindow.ts +5 -0
- package/src/codex-protocol/v2/RawResponseItemCompletedNotification.ts +6 -0
- package/src/codex-protocol/v2/ReasoningEffortOption.ts +6 -0
- package/src/codex-protocol/v2/ReasoningSummaryPartAddedNotification.ts +5 -0
- package/src/codex-protocol/v2/ReasoningSummaryTextDeltaNotification.ts +5 -0
- package/src/codex-protocol/v2/ReasoningTextDeltaNotification.ts +5 -0
- package/src/codex-protocol/v2/RemoteControlConnectionStatus.ts +5 -0
- package/src/codex-protocol/v2/RemoteControlDisableResponse.ts +6 -0
- package/src/codex-protocol/v2/RemoteControlEnableResponse.ts +6 -0
- package/src/codex-protocol/v2/RemoteControlStatusChangedNotification.ts +9 -0
- package/src/codex-protocol/v2/RemoteControlStatusReadResponse.ts +6 -0
- package/src/codex-protocol/v2/RequestPermissionProfile.ts +7 -0
- package/src/codex-protocol/v2/ResidencyRequirement.ts +5 -0
- package/src/codex-protocol/v2/ReviewDelivery.ts +5 -0
- package/src/codex-protocol/v2/ReviewStartParams.ts +12 -0
- package/src/codex-protocol/v2/ReviewStartResponse.ts +13 -0
- package/src/codex-protocol/v2/ReviewTarget.ts +9 -0
- package/src/codex-protocol/v2/SandboxMode.ts +5 -0
- package/src/codex-protocol/v2/SandboxPolicy.ts +7 -0
- package/src/codex-protocol/v2/SandboxWorkspaceWrite.ts +5 -0
- package/src/codex-protocol/v2/SendAddCreditsNudgeEmailParams.ts +6 -0
- package/src/codex-protocol/v2/SendAddCreditsNudgeEmailResponse.ts +6 -0
- package/src/codex-protocol/v2/ServerRequestResolvedNotification.ts +6 -0
- package/src/codex-protocol/v2/SessionMigration.ts +5 -0
- package/src/codex-protocol/v2/SessionSource.ts +6 -0
- package/src/codex-protocol/v2/SkillDependencies.ts +6 -0
- package/src/codex-protocol/v2/SkillErrorInfo.ts +5 -0
- package/src/codex-protocol/v2/SkillInterface.ts +6 -0
- package/src/codex-protocol/v2/SkillMetadata.ts +13 -0
- package/src/codex-protocol/v2/SkillScope.ts +5 -0
- package/src/codex-protocol/v2/SkillSummary.ts +7 -0
- package/src/codex-protocol/v2/SkillToolDependency.ts +5 -0
- package/src/codex-protocol/v2/SkillsChangedNotification.ts +11 -0
- package/src/codex-protocol/v2/SkillsConfigWriteParams.ts +14 -0
- package/src/codex-protocol/v2/SkillsConfigWriteResponse.ts +5 -0
- package/src/codex-protocol/v2/SkillsListEntry.ts +7 -0
- package/src/codex-protocol/v2/SkillsListParams.ts +13 -0
- package/src/codex-protocol/v2/SkillsListResponse.ts +6 -0
- package/src/codex-protocol/v2/SortDirection.ts +5 -0
- package/src/codex-protocol/v2/SubagentMigration.ts +5 -0
- package/src/codex-protocol/v2/TerminalInteractionNotification.ts +5 -0
- package/src/codex-protocol/v2/TextElement.ts +14 -0
- package/src/codex-protocol/v2/TextPosition.ts +13 -0
- package/src/codex-protocol/v2/TextRange.ts +6 -0
- package/src/codex-protocol/v2/Thread.ts +86 -0
- package/src/codex-protocol/v2/ThreadActiveFlag.ts +5 -0
- package/src/codex-protocol/v2/ThreadApproveGuardianDeniedActionParams.ts +10 -0
- package/src/codex-protocol/v2/ThreadApproveGuardianDeniedActionResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadArchiveParams.ts +5 -0
- package/src/codex-protocol/v2/ThreadArchiveResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadArchivedNotification.ts +5 -0
- package/src/codex-protocol/v2/ThreadBackgroundTerminalsCleanParams.ts +5 -0
- package/src/codex-protocol/v2/ThreadBackgroundTerminalsCleanResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadClosedNotification.ts +5 -0
- package/src/codex-protocol/v2/ThreadCompactStartParams.ts +5 -0
- package/src/codex-protocol/v2/ThreadCompactStartResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadDecrementElicitationParams.ts +12 -0
- package/src/codex-protocol/v2/ThreadDecrementElicitationResponse.ts +16 -0
- package/src/codex-protocol/v2/ThreadForkParams.ts +60 -0
- package/src/codex-protocol/v2/ThreadForkResponse.ts +35 -0
- package/src/codex-protocol/v2/ThreadGoal.ts +6 -0
- package/src/codex-protocol/v2/ThreadGoalClearParams.ts +5 -0
- package/src/codex-protocol/v2/ThreadGoalClearResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadGoalClearedNotification.ts +5 -0
- package/src/codex-protocol/v2/ThreadGoalGetParams.ts +5 -0
- package/src/codex-protocol/v2/ThreadGoalGetResponse.ts +6 -0
- package/src/codex-protocol/v2/ThreadGoalSetParams.ts +6 -0
- package/src/codex-protocol/v2/ThreadGoalSetResponse.ts +6 -0
- package/src/codex-protocol/v2/ThreadGoalStatus.ts +5 -0
- package/src/codex-protocol/v2/ThreadGoalUpdatedNotification.ts +6 -0
- package/src/codex-protocol/v2/ThreadIncrementElicitationParams.ts +12 -0
- package/src/codex-protocol/v2/ThreadIncrementElicitationResponse.ts +16 -0
- package/src/codex-protocol/v2/ThreadInjectItemsParams.ts +10 -0
- package/src/codex-protocol/v2/ThreadInjectItemsResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadItem.ts +101 -0
- package/src/codex-protocol/v2/ThreadListParams.ts +54 -0
- package/src/codex-protocol/v2/ThreadListResponse.ts +18 -0
- package/src/codex-protocol/v2/ThreadLoadedListParams.ts +13 -0
- package/src/codex-protocol/v2/ThreadLoadedListResponse.ts +14 -0
- package/src/codex-protocol/v2/ThreadMemoryModeSetParams.ts +6 -0
- package/src/codex-protocol/v2/ThreadMemoryModeSetResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadMetadataGitInfoUpdateParams.ts +20 -0
- package/src/codex-protocol/v2/ThreadMetadataUpdateParams.ts +12 -0
- package/src/codex-protocol/v2/ThreadMetadataUpdateResponse.ts +6 -0
- package/src/codex-protocol/v2/ThreadNameUpdatedNotification.ts +5 -0
- package/src/codex-protocol/v2/ThreadReadParams.ts +9 -0
- package/src/codex-protocol/v2/ThreadReadResponse.ts +6 -0
- package/src/codex-protocol/v2/ThreadRealtimeAppendAudioParams.ts +9 -0
- package/src/codex-protocol/v2/ThreadRealtimeAppendAudioResponse.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeAppendTextParams.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeAppendTextResponse.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeAudioChunk.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeClosedNotification.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeErrorNotification.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeItemAddedNotification.ts +9 -0
- package/src/codex-protocol/v2/ThreadRealtimeListVoicesParams.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeListVoicesResponse.ts +9 -0
- package/src/codex-protocol/v2/ThreadRealtimeOutputAudioDeltaNotification.ts +9 -0
- package/src/codex-protocol/v2/ThreadRealtimeSdpNotification.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeStartParams.ts +16 -0
- package/src/codex-protocol/v2/ThreadRealtimeStartResponse.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeStartTransport.ts +13 -0
- package/src/codex-protocol/v2/ThreadRealtimeStartedNotification.ts +9 -0
- package/src/codex-protocol/v2/ThreadRealtimeStopParams.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeStopResponse.ts +8 -0
- package/src/codex-protocol/v2/ThreadRealtimeTranscriptDeltaNotification.ts +13 -0
- package/src/codex-protocol/v2/ThreadRealtimeTranscriptDoneNotification.ts +13 -0
- package/src/codex-protocol/v2/ThreadResumeParams.ts +71 -0
- package/src/codex-protocol/v2/ThreadResumeResponse.ts +35 -0
- package/src/codex-protocol/v2/ThreadRollbackParams.ts +12 -0
- package/src/codex-protocol/v2/ThreadRollbackResponse.ts +14 -0
- package/src/codex-protocol/v2/ThreadSetNameParams.ts +5 -0
- package/src/codex-protocol/v2/ThreadSetNameResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadSettings.ts +14 -0
- package/src/codex-protocol/v2/ThreadSettingsUpdateParams.ts +61 -0
- package/src/codex-protocol/v2/ThreadSettingsUpdateResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadSettingsUpdatedNotification.ts +6 -0
- package/src/codex-protocol/v2/ThreadShellCommandParams.ts +12 -0
- package/src/codex-protocol/v2/ThreadShellCommandResponse.ts +5 -0
- package/src/codex-protocol/v2/ThreadSortKey.ts +5 -0
- package/src/codex-protocol/v2/ThreadSource.ts +5 -0
- package/src/codex-protocol/v2/ThreadSourceKind.ts +5 -0
- package/src/codex-protocol/v2/ThreadStartParams.ts +57 -0
- package/src/codex-protocol/v2/ThreadStartResponse.ts +35 -0
- package/src/codex-protocol/v2/ThreadStartSource.ts +5 -0
- package/src/codex-protocol/v2/ThreadStartedNotification.ts +6 -0
- package/src/codex-protocol/v2/ThreadStatus.ts +6 -0
- package/src/codex-protocol/v2/ThreadStatusChangedNotification.ts +6 -0
- package/src/codex-protocol/v2/ThreadTokenUsage.ts +6 -0
- package/src/codex-protocol/v2/ThreadTokenUsageUpdatedNotification.ts +6 -0
- package/src/codex-protocol/v2/ThreadTurnsItemsListParams.ts +18 -0
- package/src/codex-protocol/v2/ThreadTurnsItemsListResponse.ts +16 -0
- package/src/codex-protocol/v2/ThreadTurnsListParams.ts +23 -0
- package/src/codex-protocol/v2/ThreadTurnsListResponse.ts +18 -0
- package/src/codex-protocol/v2/ThreadUnarchiveParams.ts +5 -0
- package/src/codex-protocol/v2/ThreadUnarchiveResponse.ts +6 -0
- package/src/codex-protocol/v2/ThreadUnarchivedNotification.ts +5 -0
- package/src/codex-protocol/v2/ThreadUnsubscribeParams.ts +5 -0
- package/src/codex-protocol/v2/ThreadUnsubscribeResponse.ts +6 -0
- package/src/codex-protocol/v2/ThreadUnsubscribeStatus.ts +5 -0
- package/src/codex-protocol/v2/TokenUsageBreakdown.ts +5 -0
- package/src/codex-protocol/v2/ToolRequestUserInputAnswer.ts +8 -0
- package/src/codex-protocol/v2/ToolRequestUserInputOption.ts +8 -0
- package/src/codex-protocol/v2/ToolRequestUserInputParams.ts +9 -0
- package/src/codex-protocol/v2/ToolRequestUserInputQuestion.ts +9 -0
- package/src/codex-protocol/v2/ToolRequestUserInputResponse.ts +9 -0
- package/src/codex-protocol/v2/ToolsV2.ts +6 -0
- package/src/codex-protocol/v2/Turn.ts +33 -0
- package/src/codex-protocol/v2/TurnCompletedNotification.ts +6 -0
- package/src/codex-protocol/v2/TurnDiffUpdatedNotification.ts +9 -0
- package/src/codex-protocol/v2/TurnEnvironmentParams.ts +6 -0
- package/src/codex-protocol/v2/TurnError.ts +6 -0
- package/src/codex-protocol/v2/TurnInterruptParams.ts +5 -0
- package/src/codex-protocol/v2/TurnInterruptResponse.ts +5 -0
- package/src/codex-protocol/v2/TurnItemsView.ts +5 -0
- package/src/codex-protocol/v2/TurnPlanStep.ts +6 -0
- package/src/codex-protocol/v2/TurnPlanStepStatus.ts +5 -0
- package/src/codex-protocol/v2/TurnPlanUpdatedNotification.ts +6 -0
- package/src/codex-protocol/v2/TurnStartParams.ts +88 -0
- package/src/codex-protocol/v2/TurnStartResponse.ts +6 -0
- package/src/codex-protocol/v2/TurnStartedNotification.ts +6 -0
- package/src/codex-protocol/v2/TurnStatus.ts +5 -0
- package/src/codex-protocol/v2/TurnSteerParams.ts +15 -0
- package/src/codex-protocol/v2/TurnSteerResponse.ts +5 -0
- package/src/codex-protocol/v2/UserInput.ts +11 -0
- package/src/codex-protocol/v2/WarningNotification.ts +13 -0
- package/src/codex-protocol/v2/WebSearchAction.ts +5 -0
- package/src/codex-protocol/v2/WindowsSandboxReadiness.ts +5 -0
- package/src/codex-protocol/v2/WindowsSandboxReadinessResponse.ts +6 -0
- package/src/codex-protocol/v2/WindowsSandboxSetupCompletedNotification.ts +6 -0
- package/src/codex-protocol/v2/WindowsSandboxSetupMode.ts +5 -0
- package/src/codex-protocol/v2/WindowsSandboxSetupStartParams.ts +7 -0
- package/src/codex-protocol/v2/WindowsSandboxSetupStartResponse.ts +5 -0
- package/src/codex-protocol/v2/WindowsWorldWritableWarningNotification.ts +5 -0
- package/src/codex-protocol/v2/WriteStatus.ts +5 -0
- package/src/codex-protocol/v2/index.ts +503 -0
- package/src/column.ts +44 -0
- package/src/engines/claude/claude-engine.ts +769 -0
- package/src/engines/claude/clock.ts +48 -0
- package/src/engines/claude/compact.ts +107 -0
- package/src/engines/claude/ctx.ts +239 -0
- package/src/engines/claude/doctor.ts +202 -0
- package/src/engines/claude/env.ts +16 -0
- package/src/engines/claude/history.ts +504 -0
- package/src/engines/claude/identifiers.ts +25 -0
- package/src/engines/claude/identity-migration.ts +16 -0
- package/src/engines/claude/idle.ts +91 -0
- package/src/engines/claude/keys.ts +163 -0
- package/src/engines/claude/last.ts +52 -0
- package/src/engines/claude/mem.ts +124 -0
- package/src/engines/claude/persistence.ts +41 -0
- package/src/engines/claude/post-turn.ts +45 -0
- package/src/engines/claude/reload.ts +53 -0
- package/src/engines/claude/repo-fs.ts +63 -0
- package/src/engines/claude/resume.ts +145 -0
- package/src/engines/claude/send.ts +86 -0
- package/src/engines/claude/spawn.ts +435 -0
- package/src/engines/claude/state.ts +124 -0
- package/src/engines/claude/tmux.ts +99 -0
- package/src/engines/claude/wait-signals.ts +128 -0
- package/src/engines/claude/wait.ts +59 -0
- package/src/engines/codex/ask.ts +69 -0
- package/src/engines/codex/engine.ts +1261 -0
- package/src/engines/codex/events.ts +106 -0
- package/src/engines/codex/history.ts +385 -0
- package/src/engines/codex/identity-migration.ts +14 -0
- package/src/engines/codex/ipc-bridge-process.ts +14 -0
- package/src/engines/codex/ipc-bridge.ts +844 -0
- package/src/engines/codex/persistence.ts +236 -0
- package/src/engines/codex/rollout.ts +384 -0
- package/src/engines/codex/rpc.ts +311 -0
- package/src/engines/codex/supervisor.ts +648 -0
- package/src/engines/codex/ui-ipc.ts +374 -0
- package/src/engines/codex/verb-common.ts +34 -0
- package/src/engines/codex/verb-lifecycle.ts +94 -0
- package/src/engines/codex/verb-state.ts +19 -0
- package/src/engines/codex/verb-turns.ts +49 -0
- package/src/engines/codex/verbs.ts +15 -0
- package/src/engines/engine.ts +91 -0
- package/src/engines/git-worktree.ts +137 -0
- package/src/engines/production.ts +19 -0
- package/src/engines/registry.ts +70 -0
- package/src/engines/teammate-record.ts +113 -0
- package/src/engines/types.ts +334 -0
- package/src/env.ts +29 -0
- package/src/grep.ts +39 -0
- package/src/help.ts +433 -0
- package/src/identity/name.ts +58 -0
- package/src/identity/router.ts +80 -0
- package/src/identity/uuid-prefix.ts +40 -0
- package/src/main.ts +39 -0
- package/src/persistence/atomic-file.ts +74 -0
- package/src/persistence/identity-store.ts +294 -0
- package/src/persistence/identity-writer.ts +28 -0
- package/src/persistence/paths.ts +138 -0
- package/src/plugin-root.ts +26 -0
- package/src/proc.ts +66 -0
- package/src/shared/verb-args.ts +331 -0
- package/src/tm.ts +54 -0
- package/src/tmux.ts +57 -0
- package/src/verbs/archive.ts +211 -0
- package/src/verbs/ask.ts +29 -0
- package/src/verbs/compact.ts +25 -0
- package/src/verbs/context.ts +68 -0
- package/src/verbs/ctx.ts +21 -0
- package/src/verbs/format.ts +213 -0
- package/src/verbs/history.ts +190 -0
- package/src/verbs/kill.ts +61 -0
- package/src/verbs/last.ts +34 -0
- package/src/verbs/ls.ts +27 -0
- package/src/verbs/mem.ts +40 -0
- package/src/verbs/poll.ts +61 -0
- package/src/verbs/reload.ts +17 -0
- package/src/verbs/resolve.ts +14 -0
- package/src/verbs/resume.ts +170 -0
- package/src/verbs/send.ts +36 -0
- package/src/verbs/spawn.ts +81 -0
- package/src/verbs/states.ts +74 -0
- package/src/verbs/status.ts +26 -0
- package/src/verbs/wait.ts +40 -0
- package/src/verbs.ts +56 -0
- package/src/ws-types.d.ts +9 -0
- package/third_party/ws/LICENSE +20 -0
- package/third_party/ws/README.md +548 -0
- package/third_party/ws/UPSTREAM.md +55 -0
- package/third_party/ws/browser.js +8 -0
- package/third_party/ws/index.js +22 -0
- package/third_party/ws/lib/buffer-util.js +131 -0
- package/third_party/ws/lib/constants.js +19 -0
- package/third_party/ws/lib/event-target.js +292 -0
- package/third_party/ws/lib/extension.js +203 -0
- package/third_party/ws/lib/limiter.js +55 -0
- package/third_party/ws/lib/permessage-deflate.js +528 -0
- package/third_party/ws/lib/receiver.js +760 -0
- package/third_party/ws/lib/sender.js +607 -0
- package/third_party/ws/lib/stream.js +161 -0
- package/third_party/ws/lib/subprotocol.js +62 -0
- package/third_party/ws/lib/validation.js +152 -0
- package/third_party/ws/lib/websocket-server.js +562 -0
- package/third_party/ws/lib/websocket.js +1407 -0
- package/third_party/ws/package.json +13 -0
- package/third_party/ws/wrapper.mjs +21 -0
|
@@ -0,0 +1,1261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex Engine implementation.
|
|
3
|
+
*
|
|
4
|
+
* This is the Phase 2b migration target for the former root-level
|
|
5
|
+
* `codex-verbs.ts` logic. Codex keeps its JSON-RPC notification stream,
|
|
6
|
+
* daemon supervision, and `/tmp/teammate-codex/<name>/` registry private to
|
|
7
|
+
* this directory; the public surface is the shared `Engine` interface.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { Buffer } from 'node:buffer'
|
|
11
|
+
import { existsSync } from 'node:fs'
|
|
12
|
+
|
|
13
|
+
import type { Engine } from '../engine'
|
|
14
|
+
import type {
|
|
15
|
+
CompactRequest,
|
|
16
|
+
CompactResult,
|
|
17
|
+
DoctorFinding,
|
|
18
|
+
ContextRequest,
|
|
19
|
+
ContextResult,
|
|
20
|
+
DoctorSection,
|
|
21
|
+
EngineCapabilities,
|
|
22
|
+
EngineContext,
|
|
23
|
+
EngineKind,
|
|
24
|
+
EngineSnapshot,
|
|
25
|
+
HistoryRequest,
|
|
26
|
+
HistoryResult,
|
|
27
|
+
InspectRequest,
|
|
28
|
+
InteractionItem,
|
|
29
|
+
KillRequest,
|
|
30
|
+
KillResult,
|
|
31
|
+
LastRequest,
|
|
32
|
+
MemoryRequest,
|
|
33
|
+
ReloadRequest,
|
|
34
|
+
ReloadResult,
|
|
35
|
+
ResumeRequest,
|
|
36
|
+
ResumeResult,
|
|
37
|
+
SendRequest,
|
|
38
|
+
SpawnRequest,
|
|
39
|
+
SpawnResult,
|
|
40
|
+
StatusRequest,
|
|
41
|
+
TeammateListing,
|
|
42
|
+
TeammateStatus,
|
|
43
|
+
TextResult,
|
|
44
|
+
TurnResult,
|
|
45
|
+
WaitRequest,
|
|
46
|
+
} from '../types'
|
|
47
|
+
import type { ClientInfo, InitializeResponse } from '../../codex-protocol/index.js'
|
|
48
|
+
import type { Turn } from '../../codex-protocol/v2/Turn.js'
|
|
49
|
+
import type { TurnItemsView } from '../../codex-protocol/v2/TurnItemsView.js'
|
|
50
|
+
import type { ThreadItem } from '../../codex-protocol/v2/ThreadItem.js'
|
|
51
|
+
import type { ThreadListResponse } from '../../codex-protocol/v2/ThreadListResponse.js'
|
|
52
|
+
import type { ThreadReadResponse } from '../../codex-protocol/v2/ThreadReadResponse.js'
|
|
53
|
+
import type { ThreadResumeResponse } from '../../codex-protocol/v2/ThreadResumeResponse.js'
|
|
54
|
+
import type { ThreadStartResponse } from '../../codex-protocol/v2/ThreadStartResponse.js'
|
|
55
|
+
import type { ThreadTokenUsage } from '../../codex-protocol/v2/ThreadTokenUsage.js'
|
|
56
|
+
import { EXIT_SYNC_WAIT_EXPIRED, type TmResult } from '../../tm'
|
|
57
|
+
import type { CollectedTurn, TurnCompletedNotification } from './events.js'
|
|
58
|
+
import { codexHistory } from './history.js'
|
|
59
|
+
import { CodexWsClient } from './rpc.js'
|
|
60
|
+
import { runTurn, subscribeTurnCollection } from './events.js'
|
|
61
|
+
import {
|
|
62
|
+
CodexDaemonAlreadyAliveError,
|
|
63
|
+
CodexDaemonSpawnInProgressError,
|
|
64
|
+
daemonAlive,
|
|
65
|
+
daemonBorrowed,
|
|
66
|
+
daemonSpawnInProgress,
|
|
67
|
+
ensureCodexIpcBridge,
|
|
68
|
+
isProcessAlive,
|
|
69
|
+
listDaemons,
|
|
70
|
+
readDaemonState,
|
|
71
|
+
reapDaemon,
|
|
72
|
+
releaseDaemonBorrow,
|
|
73
|
+
spawnDaemon,
|
|
74
|
+
touchLastSeen,
|
|
75
|
+
tryBorrowDaemon,
|
|
76
|
+
writeThreadId,
|
|
77
|
+
} from './supervisor.js'
|
|
78
|
+
import {
|
|
79
|
+
CodexTeammateRecord,
|
|
80
|
+
codexLastTurnFile,
|
|
81
|
+
readBaseRecord,
|
|
82
|
+
readCodexMeta,
|
|
83
|
+
readCodexLastTurn,
|
|
84
|
+
removeBaseRecord,
|
|
85
|
+
reserveBaseRecord,
|
|
86
|
+
writeCodexLastTurn,
|
|
87
|
+
} from './persistence.js'
|
|
88
|
+
import {
|
|
89
|
+
type CodexRolloutSnapshot,
|
|
90
|
+
CODEX_ROLLOUT_BUSY_WINDOW_MS,
|
|
91
|
+
readCodexRolloutSnapshot,
|
|
92
|
+
rolloutRecentlyActive,
|
|
93
|
+
} from './rollout.js'
|
|
94
|
+
import { validateTeammateName } from '../../identity/name.js'
|
|
95
|
+
import { looksLikeUuidPrefix } from '../../identity/uuid-prefix.js'
|
|
96
|
+
import { provisionCodexWorktree, reapCodexWorktree } from '../git-worktree.js'
|
|
97
|
+
|
|
98
|
+
export const CODEX_CLIENT_INFO: ClientInfo = {
|
|
99
|
+
name: 'claudemux',
|
|
100
|
+
title: null,
|
|
101
|
+
version: '1.0.0',
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const COMPACT_REASON =
|
|
105
|
+
'codex compacts its own context automatically when the 252k window fills'
|
|
106
|
+
const CODEX_STATUS_RPC_TIMEOUT_MS = 250
|
|
107
|
+
const CODEX_THREAD_ID_RE =
|
|
108
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
|
|
109
|
+
const NO_TEXT_REPLY =
|
|
110
|
+
'(no text reply this turn — tool-only, /compact, /clear, or fresh spawn)'
|
|
111
|
+
|
|
112
|
+
export interface CodexEngineOptions {
|
|
113
|
+
readonly binPath?: string
|
|
114
|
+
readonly readyTimeoutMs?: number
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function notSupported(reason: string): TextResult {
|
|
118
|
+
return { kind: 'not-supported', reason }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function itemToInteractions(item: ThreadItem): readonly InteractionItem[] {
|
|
122
|
+
if (item.type === 'agentMessage') {
|
|
123
|
+
return [{ kind: 'assistant-text', text: item.text }]
|
|
124
|
+
}
|
|
125
|
+
if (item.type === 'commandExecution') {
|
|
126
|
+
return [
|
|
127
|
+
{ kind: 'tool-call', tool: 'commandExecution', argsJson: item.command },
|
|
128
|
+
{
|
|
129
|
+
kind: 'tool-result',
|
|
130
|
+
tool: 'commandExecution',
|
|
131
|
+
ok: item.exitCode === 0,
|
|
132
|
+
textOrJson: item.aggregatedOutput ?? '',
|
|
133
|
+
},
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
if (item.type === 'mcpToolCall') {
|
|
137
|
+
return [
|
|
138
|
+
{ kind: 'tool-call', tool: item.tool, argsJson: JSON.stringify(item.arguments) },
|
|
139
|
+
{
|
|
140
|
+
kind: 'tool-result',
|
|
141
|
+
tool: item.tool,
|
|
142
|
+
ok: item.error === null,
|
|
143
|
+
textOrJson: JSON.stringify(item.result ?? item.error ?? null),
|
|
144
|
+
},
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
return [{ kind: 'system-note', text: JSON.stringify(item) }]
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function finalAssistantText(items: readonly ThreadItem[]): string | null {
|
|
151
|
+
for (let i = items.length - 1; i >= 0; i -= 1) {
|
|
152
|
+
const item = items[i]
|
|
153
|
+
if (item?.type !== 'agentMessage') continue
|
|
154
|
+
if (item.text.length === 0) continue
|
|
155
|
+
return item.text
|
|
156
|
+
}
|
|
157
|
+
return null
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function ensureTrailingNewline(text: string): string {
|
|
161
|
+
return text.endsWith('\n') ? text : `${text}\n`
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function fmtTokenWindow(tokens: number): string {
|
|
165
|
+
if (tokens >= 1_000_000 && tokens % 1_000_000 === 0) return `${tokens / 1_000_000}M`
|
|
166
|
+
if (tokens >= 1000 && tokens % 1000 === 0) return `${tokens / 1000}k`
|
|
167
|
+
return String(tokens)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function contextFromThreadTokenUsage(tokenUsage: ThreadTokenUsage | null): ContextResult | null {
|
|
171
|
+
if (tokenUsage === null) return null
|
|
172
|
+
const window = tokenUsage.modelContextWindow
|
|
173
|
+
if (window === null || window <= 0) return null
|
|
174
|
+
const used = tokenUsage.last.totalTokens
|
|
175
|
+
return {
|
|
176
|
+
kind: 'usage',
|
|
177
|
+
tokensUsed: used,
|
|
178
|
+
tokensTotal: window,
|
|
179
|
+
pct: Math.floor((used * 100) / window),
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function contextFromRollout(threadId: string, ctx: EngineContext): ContextResult | null {
|
|
184
|
+
const usage = readCodexRolloutSnapshot(threadId, ctx.env)?.tokenUsage ?? null
|
|
185
|
+
if (usage === null) return null
|
|
186
|
+
return {
|
|
187
|
+
kind: 'usage',
|
|
188
|
+
tokensUsed: usage.tokensUsed,
|
|
189
|
+
tokensTotal: usage.tokensTotal,
|
|
190
|
+
pct: usage.pct,
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function contextForCollectedTurn(outcome: CollectedTurn, ctx: EngineContext): ContextResult | null {
|
|
195
|
+
return contextFromThreadTokenUsage(outcome.tokenUsage) ?? contextFromRollout(outcome.completed.threadId, ctx)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function formatCtxForStderr(context: ContextResult | null): string {
|
|
199
|
+
if (context?.kind !== 'usage') return 'ctx: (no usage data)\n'
|
|
200
|
+
return `ctx: ${context.tokensUsed} tokens · ${context.pct}% of ${fmtTokenWindow(context.tokensTotal)}\n`
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function codexTurnStderr(args: {
|
|
204
|
+
readonly name: string
|
|
205
|
+
readonly action: 'sent' | 'waited'
|
|
206
|
+
readonly threadId: string
|
|
207
|
+
readonly context: ContextResult | null
|
|
208
|
+
readonly rawPath: string
|
|
209
|
+
}): string {
|
|
210
|
+
const prefix = args.action === 'sent' ? `sent to ${args.name}` : `waited on ${args.name}`
|
|
211
|
+
return (
|
|
212
|
+
`${prefix} (codex)\n` +
|
|
213
|
+
`sid=${args.threadId}\n` +
|
|
214
|
+
formatCtxForStderr(args.context) +
|
|
215
|
+
`raw: ${args.rawPath}\n`
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function writeLastTurn(name: string, completed: TurnCompletedNotification): string {
|
|
220
|
+
const rawPath = codexLastTurnFile(name)
|
|
221
|
+
writeCodexLastTurn(name, ensureTrailingNewline(JSON.stringify(completed, null, 2)))
|
|
222
|
+
return rawPath
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Pick the latest `Turn` from a `thread/read` snapshot that reached a
|
|
227
|
+
* terminal state AFTER the daemon's `lastSeen` marker — the candidate
|
|
228
|
+
* `tm wait` should surface as a backfill instead of subscribing to a
|
|
229
|
+
* future event the dispatcher would never see.
|
|
230
|
+
*
|
|
231
|
+
* Why this exists: `tm send` on Codex opens a WS, posts a turn, and
|
|
232
|
+
* closes on `--timeout` expiry (exit 124). The follow-up `tm wait` opens
|
|
233
|
+
* a fresh WS and `subscribeTurnCollection` only ever receives events
|
|
234
|
+
* that fire AFTER the subscription is in place — so a turn that finished
|
|
235
|
+
* in the window [send-timeout, wait-subscribe] is invisible to the
|
|
236
|
+
* notification stream alone. `tm wait` now calls `thread/read` with
|
|
237
|
+
* `includeTurns: true` alongside the subscription and races them; if
|
|
238
|
+
* `lastSeen` < some terminal turn, that turn becomes the resolved value
|
|
239
|
+
* and `tm wait` returns it.
|
|
240
|
+
*
|
|
241
|
+
* Filters:
|
|
242
|
+
* - `inProgress` is skipped — the live subscription will deliver it.
|
|
243
|
+
* Every OTHER status is terminal (the Codex protocol's `TurnStatus`
|
|
244
|
+
* union is `completed | failed | interrupted | inProgress`) and must
|
|
245
|
+
* be eligible for backfill: the dispatcher needs the late `failed` /
|
|
246
|
+
* `interrupted` outcome just as much as a late `completed`, or the
|
|
247
|
+
* next `tm wait` keeps spinning to 124 on a turn that already
|
|
248
|
+
* settled into an error state. `turnNotificationToResult` is the
|
|
249
|
+
* single mapping site that translates any terminal status to a
|
|
250
|
+
* `TurnResult`, so backfill and live paths cannot drift.
|
|
251
|
+
* - `completedAt === null` is defensive — a turn whose timestamp
|
|
252
|
+
* didn't survive serialization cannot be ordered against `lastSeen`.
|
|
253
|
+
* - `completedAt <= lastSeen` means the dispatcher already saw it.
|
|
254
|
+
*
|
|
255
|
+
* Picks the max `completedAt` among survivors — `thread.turns` ordering
|
|
256
|
+
* is not documented as ascending, so a scan is the contract-safe form.
|
|
257
|
+
*/
|
|
258
|
+
export function pickBackfillTurn(
|
|
259
|
+
turns: readonly Turn[],
|
|
260
|
+
lastSeen: number,
|
|
261
|
+
threadId: string,
|
|
262
|
+
): TurnCompletedNotification | null {
|
|
263
|
+
let best: Turn | null = null
|
|
264
|
+
let bestCompletedAt = 0
|
|
265
|
+
for (const turn of turns) {
|
|
266
|
+
if (turn.status === 'inProgress') continue
|
|
267
|
+
if (turn.completedAt === null) continue
|
|
268
|
+
if (turn.completedAt <= lastSeen) continue
|
|
269
|
+
if (best === null || turn.completedAt > bestCompletedAt) {
|
|
270
|
+
best = turn
|
|
271
|
+
bestCompletedAt = turn.completedAt
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (best === null) return null
|
|
275
|
+
// Match `subscribeTurnCollection`'s synthesis convention so downstream
|
|
276
|
+
// `turnNotificationToResult` reads the same shape regardless of source.
|
|
277
|
+
const itemsView: TurnItemsView = best.items.length > 0 ? 'full' : 'notLoaded'
|
|
278
|
+
return {
|
|
279
|
+
threadId,
|
|
280
|
+
turn: { ...best, itemsView },
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function turnNotificationToResult(
|
|
285
|
+
completed: TurnCompletedNotification,
|
|
286
|
+
options: {
|
|
287
|
+
readonly name?: string
|
|
288
|
+
readonly action?: 'sent' | 'waited'
|
|
289
|
+
readonly context?: ContextResult | null
|
|
290
|
+
readonly rawPath?: string
|
|
291
|
+
} = {},
|
|
292
|
+
): TurnResult {
|
|
293
|
+
const items = completed.turn.items.flatMap((item) => itemToInteractions(item))
|
|
294
|
+
if (completed.turn.status === 'failed') {
|
|
295
|
+
return {
|
|
296
|
+
kind: 'failed',
|
|
297
|
+
message: completed.turn.error?.message ?? 'codex turn failed',
|
|
298
|
+
recoverable: false,
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (completed.turn.status === 'interrupted') {
|
|
302
|
+
return {
|
|
303
|
+
kind: 'failed',
|
|
304
|
+
message: 'codex turn was interrupted',
|
|
305
|
+
recoverable: true,
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const text = ensureTrailingNewline(finalAssistantText(completed.turn.items) ?? NO_TEXT_REPLY)
|
|
309
|
+
const context = options.context ?? null
|
|
310
|
+
const base = { kind: 'completed' as const, text, items, context }
|
|
311
|
+
if (options.name === undefined || options.action === undefined || options.rawPath === undefined) {
|
|
312
|
+
return base
|
|
313
|
+
}
|
|
314
|
+
return {
|
|
315
|
+
...base,
|
|
316
|
+
tmResult: {
|
|
317
|
+
code: 0,
|
|
318
|
+
stdout: text,
|
|
319
|
+
stderr: codexTurnStderr({
|
|
320
|
+
name: options.name,
|
|
321
|
+
action: options.action,
|
|
322
|
+
threadId: completed.threadId,
|
|
323
|
+
context,
|
|
324
|
+
rawPath: options.rawPath,
|
|
325
|
+
}),
|
|
326
|
+
},
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async function withTimeout<T>(
|
|
331
|
+
promise: Promise<T>,
|
|
332
|
+
timeoutMs: number | null,
|
|
333
|
+
): Promise<T | { timedOut: true }> {
|
|
334
|
+
if (timeoutMs === null) return promise
|
|
335
|
+
let timer: ReturnType<typeof setTimeout> | null = null
|
|
336
|
+
try {
|
|
337
|
+
return await Promise.race([
|
|
338
|
+
promise,
|
|
339
|
+
new Promise<{ timedOut: true }>((resolve) => {
|
|
340
|
+
timer = setTimeout(() => resolve({ timedOut: true }), timeoutMs)
|
|
341
|
+
}),
|
|
342
|
+
])
|
|
343
|
+
} finally {
|
|
344
|
+
if (timer !== null) clearTimeout(timer)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function isTimedOut<T>(value: T | { timedOut: true }): value is { timedOut: true } {
|
|
349
|
+
return (
|
|
350
|
+
typeof value === 'object' &&
|
|
351
|
+
value !== null &&
|
|
352
|
+
(value as { timedOut?: unknown }).timedOut === true
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function closeClientWhenSettled(clientPromise: Promise<CodexWsClient>): void {
|
|
357
|
+
clientPromise.then(
|
|
358
|
+
(lateClient) => lateClient.close(),
|
|
359
|
+
() => {},
|
|
360
|
+
)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function codexNameFailure(name: string): string | null {
|
|
364
|
+
const validation = validateTeammateName(name)
|
|
365
|
+
return validation.kind === 'ok'
|
|
366
|
+
? null
|
|
367
|
+
: `invalid codex teammate name '${name}': ${validation.reason}`
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function codexThreadIdFailure(threadId: string, name: string | null = null): string | null {
|
|
371
|
+
if (CODEX_THREAD_ID_RE.test(threadId)) return null
|
|
372
|
+
if (name !== null && looksLikeUuidPrefix(threadId)) {
|
|
373
|
+
return (
|
|
374
|
+
`received '${threadId}', looks like a thread-id prefix; resume ` +
|
|
375
|
+
`requires the full thread id. Run 'tm history ${name} ${threadId}' to ` +
|
|
376
|
+
`expand it, or 'tm history ${name}' to list past threads with full ids.`
|
|
377
|
+
)
|
|
378
|
+
}
|
|
379
|
+
return `codex thread id is not a valid uuid: ${threadId}`
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
async function latestCodexThreadIdForCwd(
|
|
383
|
+
client: CodexWsClient,
|
|
384
|
+
cwd: string,
|
|
385
|
+
): Promise<string | null> {
|
|
386
|
+
const response = await client.request<'thread/list', ThreadListResponse>('thread/list', {
|
|
387
|
+
limit: 1,
|
|
388
|
+
sortKey: 'updated_at',
|
|
389
|
+
sortDirection: 'desc',
|
|
390
|
+
archived: false,
|
|
391
|
+
cwd,
|
|
392
|
+
useStateDbOnly: false,
|
|
393
|
+
})
|
|
394
|
+
return response.data[0]?.id ?? null
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function codexSpawnHeader(name: string): string {
|
|
398
|
+
const state = readDaemonState(name)
|
|
399
|
+
return state === null
|
|
400
|
+
? `spawned: ${name}\n`
|
|
401
|
+
: `spawned: ${name} (pid=${state.pid}, socket=${state.socketPath})\n`
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function codexResumeHeader(name: string): string {
|
|
405
|
+
const state = readDaemonState(name)
|
|
406
|
+
return state === null
|
|
407
|
+
? `resumed: ${name}\n`
|
|
408
|
+
: `resumed: ${name} (pid=${state.pid}, socket=${state.socketPath})\n`
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function formatFirstTurn(turn: TurnResult): TmResult {
|
|
412
|
+
if (turn.tmResult !== undefined) return turn.tmResult
|
|
413
|
+
switch (turn.kind) {
|
|
414
|
+
case 'completed':
|
|
415
|
+
return { code: 0, stdout: turn.text.endsWith('\n') ? turn.text : `${turn.text}\n`, stderr: '' }
|
|
416
|
+
case 'failed':
|
|
417
|
+
return { code: 1, stdout: '', stderr: `tm: turn failed: ${turn.message}\n` }
|
|
418
|
+
case 'timed-out':
|
|
419
|
+
return {
|
|
420
|
+
code: EXIT_SYNC_WAIT_EXPIRED,
|
|
421
|
+
stdout: '',
|
|
422
|
+
stderr:
|
|
423
|
+
`tm: sync wait expired after ${turn.elapsedMs}ms (the codex daemon ` +
|
|
424
|
+
`did not return a Turn within the window; it is still running). ` +
|
|
425
|
+
`exit ${EXIT_SYNC_WAIT_EXPIRED}.\n`,
|
|
426
|
+
}
|
|
427
|
+
case 'not-supported':
|
|
428
|
+
return { code: 0, stdout: '', stderr: ` not supported: ${turn.reason}\n` }
|
|
429
|
+
case 'no-op':
|
|
430
|
+
return { code: 0, stdout: '', stderr: ` no-op: ${turn.reason}\n` }
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function fmtAge(age: number): string {
|
|
435
|
+
if (age < 60) return `${age}s`
|
|
436
|
+
if (age < 3600) return `${Math.floor(age / 60)}m`
|
|
437
|
+
if (age < 86400) return `${Math.floor(age / 3600)}h`
|
|
438
|
+
return `${Math.floor(age / 86400)}d`
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
interface CodexRuntimeProbe {
|
|
442
|
+
readonly socketReachable: 'yes' | 'no' | 'unknown'
|
|
443
|
+
readonly threadStatus: string | null
|
|
444
|
+
readonly threadState: 'idle' | 'busy' | 'unknown' | null
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function statusState(statusType: string | null): CodexRuntimeProbe['threadState'] {
|
|
448
|
+
switch (statusType) {
|
|
449
|
+
case 'active':
|
|
450
|
+
return 'busy'
|
|
451
|
+
case 'idle':
|
|
452
|
+
case 'notLoaded':
|
|
453
|
+
return 'idle'
|
|
454
|
+
case 'systemError':
|
|
455
|
+
return 'unknown'
|
|
456
|
+
default:
|
|
457
|
+
return null
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function codexDaemonState(
|
|
462
|
+
name: string,
|
|
463
|
+
state: ReturnType<typeof readDaemonState> = readDaemonState(name),
|
|
464
|
+
runtime: CodexRuntimeProbe | null = null,
|
|
465
|
+
rollout: CodexRolloutSnapshot | null = null,
|
|
466
|
+
nowMs = Date.now(),
|
|
467
|
+
): 'idle' | 'busy' | 'unknown' {
|
|
468
|
+
if (state === null || !isProcessAlive(state.pid)) return 'unknown'
|
|
469
|
+
if (runtime?.threadState === 'busy') return 'busy'
|
|
470
|
+
if (daemonBorrowed(name)) return 'busy'
|
|
471
|
+
if (rolloutRecentlyActive(rollout, nowMs)) return 'busy'
|
|
472
|
+
if (runtime?.threadState === 'idle') return 'idle'
|
|
473
|
+
if (runtime?.threadState === 'unknown' || runtime?.socketReachable === 'no') return 'unknown'
|
|
474
|
+
return 'idle'
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function codexPreview(text: string): string {
|
|
478
|
+
const preview = [...(text.split('\n')[0] ?? '')]
|
|
479
|
+
.filter((ch) => (ch.codePointAt(0) ?? 0) > 0x1f)
|
|
480
|
+
.slice(0, 50)
|
|
481
|
+
.join('')
|
|
482
|
+
return preview.length > 0 ? preview : '(no first line)'
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function codexLastTextCells(
|
|
486
|
+
rollout: CodexRolloutSnapshot | null,
|
|
487
|
+
nowSec: number,
|
|
488
|
+
): { readonly last: string; readonly preview: string } | null {
|
|
489
|
+
if (rollout?.lastAssistantText === null || rollout?.lastAssistantText === undefined) return null
|
|
490
|
+
const assistantAtMs = rollout.lastAssistantAtMs ?? rollout.mtimeMs
|
|
491
|
+
const age = Math.max(0, nowSec - Math.floor(assistantAtMs / 1000))
|
|
492
|
+
return {
|
|
493
|
+
last: `${Buffer.byteLength(rollout.lastAssistantText, 'utf8')}B/${fmtAge(age)}`,
|
|
494
|
+
preview: codexPreview(rollout.lastAssistantText),
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function codexListExtras(
|
|
499
|
+
nowSec: number,
|
|
500
|
+
state: ReturnType<typeof readDaemonState>,
|
|
501
|
+
daemonState: 'idle' | 'busy' | 'unknown',
|
|
502
|
+
rollout: CodexRolloutSnapshot | null,
|
|
503
|
+
runtime: CodexRuntimeProbe | null,
|
|
504
|
+
): Readonly<Record<string, string>> {
|
|
505
|
+
const pid = state?.pid === undefined ? '' : String(state.pid)
|
|
506
|
+
const thread = state?.threadId ?? ''
|
|
507
|
+
const rolloutSeen = rollout === null ? null : Math.floor(rollout.mtimeMs / 1000)
|
|
508
|
+
const lastText = codexLastTextCells(rollout, nowSec)
|
|
509
|
+
const recordedSeen = state?.lastSeen ?? null
|
|
510
|
+
const activitySeen =
|
|
511
|
+
recordedSeen === null ? rolloutSeen : rolloutSeen === null ? recordedSeen : Math.max(recordedSeen, rolloutSeen)
|
|
512
|
+
const lastSeen = activitySeen === null ? '' : String(activitySeen)
|
|
513
|
+
return {
|
|
514
|
+
sidShort: thread.length === 0 ? 'codex' : thread.slice(0, 8),
|
|
515
|
+
busy: daemonState === 'busy' ? 'yes' : daemonState === 'idle' ? 'no' : '?',
|
|
516
|
+
last: lastText?.last ?? '-',
|
|
517
|
+
preview: lastText?.preview ?? '-',
|
|
518
|
+
pid,
|
|
519
|
+
socket: state?.socketPath ?? '',
|
|
520
|
+
socketReachable: runtime?.socketReachable ?? 'unknown',
|
|
521
|
+
thread,
|
|
522
|
+
lastSeen,
|
|
523
|
+
rollout: rollout?.path ?? '',
|
|
524
|
+
threadStatus: runtime?.threadStatus ?? '',
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function statusPane(args: {
|
|
529
|
+
readonly name: string
|
|
530
|
+
readonly state: ReturnType<typeof readDaemonState>
|
|
531
|
+
readonly base: ReturnType<typeof readBaseRecord>
|
|
532
|
+
readonly meta: ReturnType<typeof readCodexMeta>
|
|
533
|
+
readonly daemonState: 'idle' | 'busy' | 'unknown'
|
|
534
|
+
readonly rollout: CodexRolloutSnapshot | null
|
|
535
|
+
readonly runtime: CodexRuntimeProbe | null
|
|
536
|
+
readonly nowSec: number
|
|
537
|
+
}): string {
|
|
538
|
+
const activitySeen =
|
|
539
|
+
args.rollout === null
|
|
540
|
+
? args.state?.lastSeen ?? null
|
|
541
|
+
: Math.max(args.state?.lastSeen ?? 0, Math.floor(args.rollout.mtimeMs / 1000))
|
|
542
|
+
const activityAge = activitySeen === null ? '-' : fmtAge(Math.max(0, args.nowSec - activitySeen))
|
|
543
|
+
return [
|
|
544
|
+
`codex: ${args.name}`,
|
|
545
|
+
`state: ${args.daemonState}`,
|
|
546
|
+
`cwd: ${args.base?.cwd ?? args.meta?.cwd ?? ''}`,
|
|
547
|
+
`pid: ${args.state?.pid === undefined ? '-' : String(args.state.pid)}`,
|
|
548
|
+
`socket: ${args.state?.socketPath ?? '-'}`,
|
|
549
|
+
`socket reachable: ${args.runtime?.socketReachable ?? 'unknown'}`,
|
|
550
|
+
`thread: ${args.state?.threadId ?? '-'}`,
|
|
551
|
+
`thread status: ${args.runtime?.threadStatus ?? '-'}`,
|
|
552
|
+
`started: ${args.state?.startedAt === undefined ? '-' : String(args.state.startedAt)}`,
|
|
553
|
+
`last activity: ${activitySeen === null ? '-' : `${activitySeen} (${activityAge} ago)`}`,
|
|
554
|
+
`rollout: ${args.rollout?.path ?? '-'}`,
|
|
555
|
+
].join('\n') + '\n'
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export class CodexEngine implements Engine {
|
|
559
|
+
readonly kind: EngineKind = 'codex'
|
|
560
|
+
readonly capabilities: EngineCapabilities = {
|
|
561
|
+
atomicSend: true,
|
|
562
|
+
atomicSpawnPrompt: true,
|
|
563
|
+
compaction: 'auto',
|
|
564
|
+
contextUsage: 'transcript-jsonl',
|
|
565
|
+
history: 'transcript-files',
|
|
566
|
+
memory: 'unsupported',
|
|
567
|
+
reload: 'unsupported',
|
|
568
|
+
resume: 'thread-id',
|
|
569
|
+
detachedTurn: 'unsupported',
|
|
570
|
+
events: 'push',
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
constructor(private readonly options: CodexEngineOptions = {}) {}
|
|
574
|
+
|
|
575
|
+
async spawn(req: SpawnRequest, ctx: EngineContext): Promise<SpawnResult> {
|
|
576
|
+
const invalidName = codexNameFailure(req.name)
|
|
577
|
+
if (invalidName !== null) return { kind: 'failed', message: invalidName }
|
|
578
|
+
if (req.resumeCheckpoint !== null) {
|
|
579
|
+
return { kind: 'failed', message: '--resume is not supported for codex teammates' }
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const existing = readBaseRecord(req.name)
|
|
583
|
+
if (existing !== null) {
|
|
584
|
+
if (existing.engine !== 'codex') return { kind: 'already-exists', existingEngine: existing.engine }
|
|
585
|
+
if (daemonAlive(req.name)) return { kind: 'already-exists', existingEngine: 'codex' }
|
|
586
|
+
if (daemonSpawnInProgress(req.name)) return { kind: 'already-exists', existingEngine: 'codex' }
|
|
587
|
+
removeBaseRecord(req.name)
|
|
588
|
+
}
|
|
589
|
+
if (daemonAlive(req.name)) return { kind: 'already-exists', existingEngine: 'codex' }
|
|
590
|
+
|
|
591
|
+
const createdAt = Math.floor(ctx.now() / 1000)
|
|
592
|
+
const record = new CodexTeammateRecord({
|
|
593
|
+
name: req.name,
|
|
594
|
+
repo: req.repo,
|
|
595
|
+
cwd: req.cwd,
|
|
596
|
+
worktreeSlug: req.worktreeSlug,
|
|
597
|
+
createdAt,
|
|
598
|
+
displayName: req.displayName,
|
|
599
|
+
})
|
|
600
|
+
const reserved = reserveBaseRecord(record)
|
|
601
|
+
if (reserved.kind === 'taken') {
|
|
602
|
+
return { kind: 'already-exists', existingEngine: reserved.existing.engine }
|
|
603
|
+
}
|
|
604
|
+
if (reserved.kind === 'failed') return { kind: 'failed', message: reserved.message }
|
|
605
|
+
|
|
606
|
+
if (req.worktreeSlug !== null) {
|
|
607
|
+
const worktreeError = await provisionCodexWorktree(req.repo, req.worktreeSlug)
|
|
608
|
+
if (worktreeError !== null) {
|
|
609
|
+
removeBaseRecord(req.name)
|
|
610
|
+
return { kind: 'failed', message: worktreeError }
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
try {
|
|
615
|
+
await spawnDaemon({
|
|
616
|
+
name: req.name,
|
|
617
|
+
binPath: this.options.binPath,
|
|
618
|
+
cwd: req.cwd,
|
|
619
|
+
env: ctx.env,
|
|
620
|
+
readyTimeoutMs: this.options.readyTimeoutMs,
|
|
621
|
+
meta: {
|
|
622
|
+
schema: 1,
|
|
623
|
+
name: req.name,
|
|
624
|
+
cwd: req.cwd,
|
|
625
|
+
displayName: req.displayName,
|
|
626
|
+
spawnedAt: createdAt,
|
|
627
|
+
},
|
|
628
|
+
})
|
|
629
|
+
|
|
630
|
+
await this.healthCheck(req.name)
|
|
631
|
+
ensureCodexIpcBridge(req.name, { cwd: req.cwd, env: ctx.env })
|
|
632
|
+
|
|
633
|
+
if (req.prompt === null) {
|
|
634
|
+
return {
|
|
635
|
+
kind: 'spawned',
|
|
636
|
+
name: req.name,
|
|
637
|
+
firstTurn: null,
|
|
638
|
+
tmResult: { code: 0, stdout: '', stderr: codexSpawnHeader(req.name) },
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
const firstTurn = await this.send(
|
|
642
|
+
{ name: req.name, prompt: req.prompt, timeoutMs: req.timeoutMs, paneQuiet: false },
|
|
643
|
+
ctx,
|
|
644
|
+
)
|
|
645
|
+
const turn = formatFirstTurn(firstTurn)
|
|
646
|
+
return {
|
|
647
|
+
kind: 'spawned',
|
|
648
|
+
name: req.name,
|
|
649
|
+
firstTurn,
|
|
650
|
+
tmResult: {
|
|
651
|
+
code: turn.code,
|
|
652
|
+
stdout: turn.stdout,
|
|
653
|
+
stderr: codexSpawnHeader(req.name) + turn.stderr,
|
|
654
|
+
},
|
|
655
|
+
}
|
|
656
|
+
} catch (e) {
|
|
657
|
+
removeBaseRecord(req.name)
|
|
658
|
+
if (e instanceof CodexDaemonAlreadyAliveError) {
|
|
659
|
+
return { kind: 'already-exists', existingEngine: 'codex' }
|
|
660
|
+
}
|
|
661
|
+
if (!(e instanceof CodexDaemonSpawnInProgressError)) {
|
|
662
|
+
await reapDaemon(req.name)
|
|
663
|
+
}
|
|
664
|
+
return {
|
|
665
|
+
kind: 'failed',
|
|
666
|
+
message: e instanceof Error ? e.message : String(e),
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
async send(req: SendRequest, ctx: EngineContext): Promise<TurnResult> {
|
|
672
|
+
const invalidName = codexNameFailure(req.name)
|
|
673
|
+
if (invalidName !== null) {
|
|
674
|
+
return { kind: 'failed', message: invalidName, recoverable: false }
|
|
675
|
+
}
|
|
676
|
+
if (req.paneQuiet) {
|
|
677
|
+
return {
|
|
678
|
+
kind: 'failed',
|
|
679
|
+
message: 'tm send: --pane-quiet is not supported for codex teammates',
|
|
680
|
+
recoverable: false,
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
if (!daemonAlive(req.name)) {
|
|
684
|
+
return {
|
|
685
|
+
kind: 'failed',
|
|
686
|
+
message: `codex teammate '${req.name}' is not alive — try 'tm spawn ${req.name} --engine codex' first`,
|
|
687
|
+
recoverable: false,
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
ensureCodexIpcBridge(req.name, {
|
|
691
|
+
cwd: readBaseRecord(req.name)?.cwd ?? readCodexMeta(req.name)?.cwd ?? undefined,
|
|
692
|
+
env: ctx.env,
|
|
693
|
+
})
|
|
694
|
+
if (req.prompt.length === 0) {
|
|
695
|
+
return { kind: 'failed', message: 'usage: tm send <teammate> "<prompt>"', recoverable: false }
|
|
696
|
+
}
|
|
697
|
+
if (!tryBorrowDaemon(req.name)) {
|
|
698
|
+
return { kind: 'failed', message: `codex teammate '${req.name}' is busy`, recoverable: true }
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
let client: CodexWsClient | null = null
|
|
702
|
+
try {
|
|
703
|
+
client = await openInitializedCodexClient(req.name)
|
|
704
|
+
let threadId = readDaemonState(req.name)?.threadId ?? null
|
|
705
|
+
if (threadId === null) {
|
|
706
|
+
const resp = await client.request<'thread/start', ThreadStartResponse>('thread/start', {
|
|
707
|
+
experimentalRawEvents: false,
|
|
708
|
+
persistExtendedHistory: false,
|
|
709
|
+
})
|
|
710
|
+
threadId = resp.thread.id
|
|
711
|
+
writeThreadId(req.name, threadId)
|
|
712
|
+
} else {
|
|
713
|
+
await client.request<'thread/resume', ThreadResumeResponse>('thread/resume', {
|
|
714
|
+
threadId,
|
|
715
|
+
persistExtendedHistory: false,
|
|
716
|
+
})
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
const outcome = await withTimeout(
|
|
720
|
+
runTurn(client, threadId, req.prompt, { wait: true, cwd: null }),
|
|
721
|
+
req.timeoutMs,
|
|
722
|
+
)
|
|
723
|
+
if (isTimedOut(outcome)) return { kind: 'timed-out', elapsedMs: req.timeoutMs ?? 0 }
|
|
724
|
+
if (outcome === null) return { kind: 'no-op', reason: 'turn was started without waiting' }
|
|
725
|
+
const rawPath = writeLastTurn(req.name, outcome.completed)
|
|
726
|
+
touchLastSeen(req.name)
|
|
727
|
+
return turnNotificationToResult(outcome.completed, {
|
|
728
|
+
name: req.name,
|
|
729
|
+
action: 'sent',
|
|
730
|
+
context: contextForCollectedTurn(outcome, ctx),
|
|
731
|
+
rawPath,
|
|
732
|
+
})
|
|
733
|
+
} catch (e) {
|
|
734
|
+
return {
|
|
735
|
+
kind: 'failed',
|
|
736
|
+
message: `codex send on '${req.name}' failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
737
|
+
recoverable: true,
|
|
738
|
+
}
|
|
739
|
+
} finally {
|
|
740
|
+
if (client !== null) client.close()
|
|
741
|
+
releaseDaemonBorrow(req.name)
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
async wait(req: WaitRequest, ctx: EngineContext): Promise<TurnResult> {
|
|
746
|
+
const invalidName = codexNameFailure(req.name)
|
|
747
|
+
if (invalidName !== null) {
|
|
748
|
+
return { kind: 'failed', message: invalidName, recoverable: false }
|
|
749
|
+
}
|
|
750
|
+
if (req.fresh) {
|
|
751
|
+
return {
|
|
752
|
+
kind: 'failed',
|
|
753
|
+
message: 'tm wait: --fresh is not supported for codex teammates',
|
|
754
|
+
recoverable: false,
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (req.paneQuiet) {
|
|
758
|
+
return {
|
|
759
|
+
kind: 'failed',
|
|
760
|
+
message: 'tm wait: --pane-quiet is not supported for codex teammates',
|
|
761
|
+
recoverable: false,
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
if (!daemonAlive(req.name)) {
|
|
765
|
+
return { kind: 'failed', message: `codex teammate '${req.name}' is not alive`, recoverable: false }
|
|
766
|
+
}
|
|
767
|
+
const threadId = readDaemonState(req.name)?.threadId ?? null
|
|
768
|
+
if (threadId === null) {
|
|
769
|
+
return {
|
|
770
|
+
kind: 'failed',
|
|
771
|
+
message: `codex teammate '${req.name}' has no started thread yet — run 'tm send ${req.name} --prompt "…"' first`,
|
|
772
|
+
recoverable: false,
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
let client: CodexWsClient | null = null
|
|
777
|
+
try {
|
|
778
|
+
client = await openInitializedCodexClient(req.name)
|
|
779
|
+
await client.request<'thread/resume', ThreadResumeResponse>('thread/resume', {
|
|
780
|
+
threadId,
|
|
781
|
+
persistExtendedHistory: false,
|
|
782
|
+
})
|
|
783
|
+
// Order matters: subscribe BEFORE issuing thread/read, so a turn that
|
|
784
|
+
// completes between the read response and the subscription setup is
|
|
785
|
+
// not dropped (subscribeTurnCollection registers a notification
|
|
786
|
+
// handler immediately; lateInbounds buffer until awaitTurn fires).
|
|
787
|
+
const collector = subscribeTurnCollection(client, threadId)
|
|
788
|
+
const lastSeen = readDaemonState(req.name)?.lastSeen ?? 0
|
|
789
|
+
const readPromise = client.request<'thread/read', ThreadReadResponse>('thread/read', {
|
|
790
|
+
threadId,
|
|
791
|
+
includeTurns: true,
|
|
792
|
+
})
|
|
793
|
+
// Race the live subscription against the backfill read. If a turn
|
|
794
|
+
// completed in [send-timeout, wait-subscribe], the read finds it
|
|
795
|
+
// and resolves first; otherwise the read returns no candidate and
|
|
796
|
+
// we hand off to the collector (which may already have a live
|
|
797
|
+
// event cached from notifications that arrived during the read).
|
|
798
|
+
// The 124 contract — "still running, re-collect with tm wait" —
|
|
799
|
+
// now actually holds for Codex: the second wait recovers the
|
|
800
|
+
// in-window completion. If the wall-clock --timeout fires before
|
|
801
|
+
// the read RPC returns, control still reaches `isTimedOut(outcome)`
|
|
802
|
+
// and the caller gets the documented 124; the next `tm wait`
|
|
803
|
+
// catches the completion via the same backfill path.
|
|
804
|
+
//
|
|
805
|
+
// A thread/read RPC error is non-fatal here: the live subscription
|
|
806
|
+
// is the original (pre-backfill) source of truth, and a snapshot
|
|
807
|
+
// failure should not turn a healthy wait into a failed verb. Swallow
|
|
808
|
+
// the rejection and fall through to the collector.
|
|
809
|
+
const backfillRace: Promise<CollectedTurn> = readPromise.then(
|
|
810
|
+
(read) => {
|
|
811
|
+
const backfill = pickBackfillTurn(read.thread.turns, lastSeen, threadId)
|
|
812
|
+
if (backfill !== null) return { completed: backfill, tokenUsage: null }
|
|
813
|
+
return collector.awaitTurn()
|
|
814
|
+
},
|
|
815
|
+
() => collector.awaitTurn(),
|
|
816
|
+
)
|
|
817
|
+
const outcome = await withTimeout(
|
|
818
|
+
Promise.race([collector.awaitTurn(), backfillRace]),
|
|
819
|
+
req.timeoutMs,
|
|
820
|
+
)
|
|
821
|
+
if (isTimedOut(outcome)) {
|
|
822
|
+
// Swallow the readPromise rejection (if any) so the WS close in
|
|
823
|
+
// `finally` does not race with an unhandled rejection.
|
|
824
|
+
readPromise.catch(() => {})
|
|
825
|
+
return { kind: 'timed-out', elapsedMs: req.timeoutMs ?? 0 }
|
|
826
|
+
}
|
|
827
|
+
const rawPath = writeLastTurn(req.name, outcome.completed)
|
|
828
|
+
touchLastSeen(req.name)
|
|
829
|
+
return turnNotificationToResult(outcome.completed, {
|
|
830
|
+
name: req.name,
|
|
831
|
+
action: 'waited',
|
|
832
|
+
context: contextForCollectedTurn(outcome, ctx),
|
|
833
|
+
rawPath,
|
|
834
|
+
})
|
|
835
|
+
} catch (e) {
|
|
836
|
+
return {
|
|
837
|
+
kind: 'failed',
|
|
838
|
+
message: `codex wait on '${req.name}' failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
839
|
+
recoverable: true,
|
|
840
|
+
}
|
|
841
|
+
} finally {
|
|
842
|
+
if (client !== null) client.close()
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
async kill(req: KillRequest, _ctx: EngineContext): Promise<KillResult> {
|
|
847
|
+
const state = readDaemonState(req.name)
|
|
848
|
+
const base = readBaseRecord(req.name)
|
|
849
|
+
const meta = readCodexMeta(req.name)
|
|
850
|
+
if (state === null && base === null && meta === null) return { kind: 'not-found' }
|
|
851
|
+
try {
|
|
852
|
+
await reapDaemon(req.name)
|
|
853
|
+
let worktreeNote = ''
|
|
854
|
+
if (base !== null && base.worktreeSlug !== null) {
|
|
855
|
+
const reap = await reapCodexWorktree(base.repo, base.worktreeSlug)
|
|
856
|
+
if (reap.kind === 'preserved-dirty') {
|
|
857
|
+
worktreeNote =
|
|
858
|
+
`worktree preserved at ${reap.path} ` +
|
|
859
|
+
`(uncommitted changes — run 'git -C ${base.repo} worktree remove --force ${reap.path}' once safe)\n`
|
|
860
|
+
} else if (reap.kind === 'preserved-unmerged') {
|
|
861
|
+
worktreeNote =
|
|
862
|
+
`worktree preserved at ${reap.path} ` +
|
|
863
|
+
`(branch '${reap.branch}' has commits not merged into HEAD — ` +
|
|
864
|
+
`merge or rebase the branch first, then ` +
|
|
865
|
+
`'git -C ${base.repo} worktree remove --force ${reap.path} && ` +
|
|
866
|
+
`git -C ${base.repo} branch -D ${reap.branch}' to clean up)\n`
|
|
867
|
+
} else if (reap.kind === 'failed') {
|
|
868
|
+
worktreeNote = `worktree cleanup failed: ${reap.message}\n`
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
// Per the Engine.kill contract, identity teardown belongs to
|
|
872
|
+
// `killVerb` — it archives + removes the base record after we
|
|
873
|
+
// return, so the post-kill recovery path for `tm resume` /
|
|
874
|
+
// `tm history` sees a snapshot of the launch context.
|
|
875
|
+
if (worktreeNote.length > 0) {
|
|
876
|
+
// We still return `killed` — the teammate is gone, the
|
|
877
|
+
// worktree leftover is communicated separately so a stale
|
|
878
|
+
// dirty checkout never blocks `tm kill` from completing.
|
|
879
|
+
// The verb layer surfaces the note through stderr.
|
|
880
|
+
return { kind: 'killed', note: worktreeNote }
|
|
881
|
+
}
|
|
882
|
+
return { kind: 'killed' }
|
|
883
|
+
} catch (e) {
|
|
884
|
+
return { kind: 'failed', message: e instanceof Error ? e.message : String(e) }
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
async list(ctx: EngineContext): Promise<readonly TeammateListing[]> {
|
|
889
|
+
const nowSec = Math.floor(ctx.now() / 1000)
|
|
890
|
+
const nowMs = ctx.now()
|
|
891
|
+
return Promise.all(listDaemons().map(async (name) => {
|
|
892
|
+
const state = readDaemonState(name)
|
|
893
|
+
const base = readBaseRecord(name)
|
|
894
|
+
const meta = readCodexMeta(name)
|
|
895
|
+
const rollout = state?.threadId === null || state?.threadId === undefined
|
|
896
|
+
? null
|
|
897
|
+
: readCodexRolloutSnapshot(state.threadId, ctx.env)
|
|
898
|
+
const runtime = await this.probeRuntime(name, state)
|
|
899
|
+
const daemonState = codexDaemonState(name, state, runtime, rollout, nowMs)
|
|
900
|
+
return {
|
|
901
|
+
name,
|
|
902
|
+
engine: 'codex',
|
|
903
|
+
state: daemonState,
|
|
904
|
+
repo: base?.repo ?? base?.cwd ?? meta?.cwd ?? '',
|
|
905
|
+
cwd: base?.cwd ?? meta?.cwd ?? '',
|
|
906
|
+
worktreeSlug: base?.worktreeSlug ?? null,
|
|
907
|
+
displayName: base?.displayName ?? meta?.displayName ?? null,
|
|
908
|
+
extras: codexListExtras(nowSec, state, daemonState, rollout, runtime),
|
|
909
|
+
}
|
|
910
|
+
}))
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
async status(req: StatusRequest, ctx: EngineContext): Promise<TeammateStatus> {
|
|
914
|
+
const state = readDaemonState(req.name)
|
|
915
|
+
const base = readBaseRecord(req.name)
|
|
916
|
+
const meta = readCodexMeta(req.name)
|
|
917
|
+
if (state === null && base === null && meta === null) return { kind: 'not-found' }
|
|
918
|
+
const rollout = state?.threadId === null || state?.threadId === undefined
|
|
919
|
+
? null
|
|
920
|
+
: readCodexRolloutSnapshot(state.threadId, ctx.env)
|
|
921
|
+
const runtime = await this.probeRuntime(req.name, state)
|
|
922
|
+
const daemonState = codexDaemonState(req.name, state, runtime, rollout, ctx.now())
|
|
923
|
+
return {
|
|
924
|
+
kind: 'present',
|
|
925
|
+
name: req.name,
|
|
926
|
+
engine: 'codex',
|
|
927
|
+
state: daemonState,
|
|
928
|
+
cwd: base?.cwd ?? meta?.cwd ?? '',
|
|
929
|
+
pane: statusPane({
|
|
930
|
+
name: req.name,
|
|
931
|
+
state,
|
|
932
|
+
base,
|
|
933
|
+
meta,
|
|
934
|
+
daemonState,
|
|
935
|
+
rollout,
|
|
936
|
+
runtime,
|
|
937
|
+
nowSec: Math.floor(ctx.now() / 1000),
|
|
938
|
+
}),
|
|
939
|
+
diagnostics: {
|
|
940
|
+
pid: state?.pid === undefined ? '' : String(state.pid),
|
|
941
|
+
socket: state?.socketPath ?? '',
|
|
942
|
+
socketReachable: runtime?.socketReachable ?? 'unknown',
|
|
943
|
+
thread: state?.threadId ?? '',
|
|
944
|
+
threadStatus: runtime?.threadStatus ?? '',
|
|
945
|
+
startedAt: state?.startedAt === undefined ? '' : String(state.startedAt),
|
|
946
|
+
lastSeen: state?.lastSeen === null || state?.lastSeen === undefined ? '' : String(state.lastSeen),
|
|
947
|
+
rollout: rollout?.path ?? '',
|
|
948
|
+
rolloutMtime: rollout === null ? '' : String(Math.floor(rollout.mtimeMs / 1000)),
|
|
949
|
+
busyWindowMs: String(CODEX_ROLLOUT_BUSY_WINDOW_MS),
|
|
950
|
+
},
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
async compact(_req: CompactRequest, _ctx: EngineContext): Promise<CompactResult> {
|
|
955
|
+
return { kind: 'not-supported', reason: COMPACT_REASON }
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
async resume(req: ResumeRequest, ctx: EngineContext): Promise<ResumeResult> {
|
|
959
|
+
const invalidName = codexNameFailure(req.name)
|
|
960
|
+
if (invalidName !== null) return { kind: 'failed', message: invalidName }
|
|
961
|
+
let threadId = req.checkpoint
|
|
962
|
+
const invalidThreadId = threadId === null ? null : codexThreadIdFailure(threadId, req.name)
|
|
963
|
+
if (invalidThreadId !== null) return { kind: 'failed', message: invalidThreadId }
|
|
964
|
+
|
|
965
|
+
const existing = readBaseRecord(req.name)
|
|
966
|
+
if (existing !== null) {
|
|
967
|
+
if (existing.engine !== 'codex') {
|
|
968
|
+
return { kind: 'failed', message: `'${req.name}' already exists as a ${existing.engine} teammate` }
|
|
969
|
+
}
|
|
970
|
+
if (daemonAlive(req.name) || daemonSpawnInProgress(req.name)) {
|
|
971
|
+
return { kind: 'failed', message: `codex teammate '${req.name}' is already running` }
|
|
972
|
+
}
|
|
973
|
+
removeBaseRecord(req.name)
|
|
974
|
+
}
|
|
975
|
+
if (daemonAlive(req.name)) {
|
|
976
|
+
return { kind: 'failed', message: `codex teammate '${req.name}' is already running` }
|
|
977
|
+
}
|
|
978
|
+
if (daemonSpawnInProgress(req.name)) {
|
|
979
|
+
return { kind: 'failed', message: `codex teammate '${req.name}' is already being spawned` }
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
const createdAt = Math.floor(ctx.now() / 1000)
|
|
983
|
+
const cwd = req.cwd ?? process.cwd()
|
|
984
|
+
const repo = req.repo ?? cwd
|
|
985
|
+
const record = new CodexTeammateRecord({
|
|
986
|
+
name: req.name,
|
|
987
|
+
repo,
|
|
988
|
+
cwd,
|
|
989
|
+
worktreeSlug: req.worktreeSlug,
|
|
990
|
+
createdAt,
|
|
991
|
+
displayName: req.displayName,
|
|
992
|
+
})
|
|
993
|
+
const reserved = reserveBaseRecord(record)
|
|
994
|
+
if (reserved.kind === 'taken') {
|
|
995
|
+
return { kind: 'failed', message: `'${req.name}' already exists as a ${reserved.existing.engine} teammate` }
|
|
996
|
+
}
|
|
997
|
+
if (reserved.kind === 'failed') return { kind: 'failed', message: reserved.message }
|
|
998
|
+
|
|
999
|
+
// Resume-after-clean-kill recovery: if the resumed teammate ran
|
|
1000
|
+
// in a worktree and that worktree path was cleared by the prior
|
|
1001
|
+
// `tm kill` (default for clean state), re-create it from `repo` +
|
|
1002
|
+
// `worktreeSlug` now so the daemon's `spawnDaemon` cwd actually
|
|
1003
|
+
// exists. The `tm resume` verb layer parses the rollout's
|
|
1004
|
+
// `session_meta.cwd` and forwards repo / worktreeSlug for exactly
|
|
1005
|
+
// this path. If `--no-worktree`, or the worktree dir still
|
|
1006
|
+
// exists, the provision is a no-op.
|
|
1007
|
+
if (req.worktreeSlug !== null && !existsSync(cwd)) {
|
|
1008
|
+
const error = await provisionCodexWorktree(repo, req.worktreeSlug)
|
|
1009
|
+
if (error !== null) {
|
|
1010
|
+
removeBaseRecord(req.name)
|
|
1011
|
+
return {
|
|
1012
|
+
kind: 'failed',
|
|
1013
|
+
message:
|
|
1014
|
+
`failed to re-provision worktree for resume at ${cwd}: ${error}`,
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
let client: CodexWsClient | null = null
|
|
1020
|
+
try {
|
|
1021
|
+
await spawnDaemon({
|
|
1022
|
+
name: req.name,
|
|
1023
|
+
binPath: this.options.binPath,
|
|
1024
|
+
cwd,
|
|
1025
|
+
env: ctx.env,
|
|
1026
|
+
readyTimeoutMs: this.options.readyTimeoutMs,
|
|
1027
|
+
meta: {
|
|
1028
|
+
schema: 1,
|
|
1029
|
+
name: req.name,
|
|
1030
|
+
cwd,
|
|
1031
|
+
displayName: req.displayName,
|
|
1032
|
+
spawnedAt: createdAt,
|
|
1033
|
+
},
|
|
1034
|
+
})
|
|
1035
|
+
|
|
1036
|
+
await this.healthCheck(req.name)
|
|
1037
|
+
ensureCodexIpcBridge(req.name, { cwd, env: ctx.env })
|
|
1038
|
+
client = await openInitializedCodexClient(req.name)
|
|
1039
|
+
if (threadId === null) {
|
|
1040
|
+
threadId = await latestCodexThreadIdForCwd(client, cwd)
|
|
1041
|
+
if (threadId === null) {
|
|
1042
|
+
client.close()
|
|
1043
|
+
client = null
|
|
1044
|
+
removeBaseRecord(req.name)
|
|
1045
|
+
await reapDaemon(req.name)
|
|
1046
|
+
return { kind: 'not-found', reason: `no codex threads found for cwd ${cwd}` }
|
|
1047
|
+
}
|
|
1048
|
+
const latestInvalidThreadId = codexThreadIdFailure(threadId)
|
|
1049
|
+
if (latestInvalidThreadId !== null) {
|
|
1050
|
+
throw new Error(`thread/list returned invalid thread id: ${threadId}`)
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
writeThreadId(req.name, threadId)
|
|
1054
|
+
await client.request<'thread/resume', ThreadResumeResponse>('thread/resume', {
|
|
1055
|
+
threadId,
|
|
1056
|
+
persistExtendedHistory: false,
|
|
1057
|
+
})
|
|
1058
|
+
touchLastSeen(req.name)
|
|
1059
|
+
client.close()
|
|
1060
|
+
client = null
|
|
1061
|
+
|
|
1062
|
+
if (req.prompt === null) {
|
|
1063
|
+
return {
|
|
1064
|
+
kind: 'resumed',
|
|
1065
|
+
checkpoint: threadId,
|
|
1066
|
+
tmResult: {
|
|
1067
|
+
code: 0,
|
|
1068
|
+
stdout: `resumed: ${threadId}\n`,
|
|
1069
|
+
stderr: codexResumeHeader(req.name),
|
|
1070
|
+
},
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
const turn = formatFirstTurn(await this.send(
|
|
1074
|
+
{ name: req.name, prompt: req.prompt, timeoutMs: null, paneQuiet: false },
|
|
1075
|
+
ctx,
|
|
1076
|
+
))
|
|
1077
|
+
return {
|
|
1078
|
+
kind: 'resumed',
|
|
1079
|
+
checkpoint: threadId,
|
|
1080
|
+
tmResult: {
|
|
1081
|
+
code: turn.code,
|
|
1082
|
+
stdout: turn.stdout,
|
|
1083
|
+
stderr: codexResumeHeader(req.name) + turn.stderr,
|
|
1084
|
+
},
|
|
1085
|
+
}
|
|
1086
|
+
} catch (e) {
|
|
1087
|
+
removeBaseRecord(req.name)
|
|
1088
|
+
if (e instanceof CodexDaemonAlreadyAliveError) {
|
|
1089
|
+
return { kind: 'failed', message: e.message }
|
|
1090
|
+
}
|
|
1091
|
+
if (!(e instanceof CodexDaemonSpawnInProgressError)) {
|
|
1092
|
+
await reapDaemon(req.name)
|
|
1093
|
+
}
|
|
1094
|
+
return {
|
|
1095
|
+
kind: 'failed',
|
|
1096
|
+
message: e instanceof Error ? e.message : String(e),
|
|
1097
|
+
}
|
|
1098
|
+
} finally {
|
|
1099
|
+
if (client !== null) client.close()
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
async last(req: LastRequest, ctx: EngineContext): Promise<TextResult> {
|
|
1104
|
+
if (req.verbose) {
|
|
1105
|
+
const raw = readCodexLastTurn(req.name)
|
|
1106
|
+
if (raw === null) return { kind: 'not-found', reason: `codex teammate '${req.name}' has no raw last turn` }
|
|
1107
|
+
return { kind: 'text', text: ensureTrailingNewline(raw) }
|
|
1108
|
+
}
|
|
1109
|
+
const threadId = readDaemonState(req.name)?.threadId ?? null
|
|
1110
|
+
if (threadId === null) return { kind: 'not-found', reason: `codex teammate '${req.name}' has no thread id` }
|
|
1111
|
+
const rollout = readCodexRolloutSnapshot(threadId, ctx.env)
|
|
1112
|
+
if (rollout === null) return { kind: 'not-found', reason: `codex rollout for thread '${threadId}' not found` }
|
|
1113
|
+
if (rollout.lastAssistantText === null) {
|
|
1114
|
+
return { kind: 'not-found', reason: `no assistant text in codex rollout ${rollout.path}` }
|
|
1115
|
+
}
|
|
1116
|
+
return {
|
|
1117
|
+
kind: 'text',
|
|
1118
|
+
text: rollout.lastAssistantText.endsWith('\n')
|
|
1119
|
+
? rollout.lastAssistantText
|
|
1120
|
+
: `${rollout.lastAssistantText}\n`,
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
async ctx(req: ContextRequest, ctx: EngineContext): Promise<ContextResult> {
|
|
1125
|
+
const threadId = readDaemonState(req.name)?.threadId ?? null
|
|
1126
|
+
if (threadId === null) {
|
|
1127
|
+
return { kind: 'not-supported', reason: `codex teammate '${req.name}' has no thread id` }
|
|
1128
|
+
}
|
|
1129
|
+
const rollout = readCodexRolloutSnapshot(threadId, ctx.env)
|
|
1130
|
+
if (rollout === null) {
|
|
1131
|
+
return { kind: 'not-supported', reason: `codex rollout for thread '${threadId}' not found` }
|
|
1132
|
+
}
|
|
1133
|
+
if (rollout.tokenUsage === null) {
|
|
1134
|
+
return { kind: 'not-supported', reason: `no token usage in codex rollout ${rollout.path}` }
|
|
1135
|
+
}
|
|
1136
|
+
return {
|
|
1137
|
+
kind: 'usage',
|
|
1138
|
+
tokensUsed: rollout.tokenUsage.tokensUsed,
|
|
1139
|
+
tokensTotal: rollout.tokenUsage.tokensTotal,
|
|
1140
|
+
pct: rollout.tokenUsage.pct,
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
async history(_req: HistoryRequest, _ctx: EngineContext): Promise<HistoryResult> {
|
|
1145
|
+
return codexHistory(_req, _ctx)
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
async mem(_req: MemoryRequest, _ctx: EngineContext): Promise<TextResult> {
|
|
1149
|
+
return notSupported('codex does not use Claude project memory files')
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
async reload(_req: ReloadRequest, _ctx: EngineContext): Promise<ReloadResult> {
|
|
1153
|
+
return { kind: 'not-supported', reason: 'codex has no reload prompt command' }
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
async inspect(req: InspectRequest, _ctx: EngineContext): Promise<EngineSnapshot> {
|
|
1157
|
+
const status = await this.status({ name: req.name, lines: null }, _ctx)
|
|
1158
|
+
if (status.kind !== 'present') return { engine: 'codex', name: req.name, fields: { status: status.kind } }
|
|
1159
|
+
return { engine: 'codex', name: req.name, fields: status.diagnostics }
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
async doctor(_ctx: EngineContext): Promise<DoctorSection> {
|
|
1163
|
+
const findings: DoctorFinding[] = []
|
|
1164
|
+
for (const name of listDaemons()) {
|
|
1165
|
+
const state = readDaemonState(name)
|
|
1166
|
+
if (state === null) {
|
|
1167
|
+
await reapDaemon(name)
|
|
1168
|
+
removeBaseRecord(name)
|
|
1169
|
+
findings.push({ severity: 'warn', summary: `reaped malformed codex daemon entry ${name}`, fix: null })
|
|
1170
|
+
} else if (!isProcessAlive(state.pid)) {
|
|
1171
|
+
await reapDaemon(name)
|
|
1172
|
+
removeBaseRecord(name)
|
|
1173
|
+
findings.push({ severity: 'warn', summary: `reaped stale codex daemon ${name} (pid=${state.pid})`, fix: null })
|
|
1174
|
+
} else {
|
|
1175
|
+
findings.push({ severity: 'ok', summary: `${name} alive (pid=${state.pid})`, fix: null })
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return { engine: 'codex', findings }
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
private async healthCheck(name: string): Promise<void> {
|
|
1182
|
+
const clientPromise = openInitializedCodexClient(name)
|
|
1183
|
+
const initialized = await withTimeout(clientPromise, this.options.readyTimeoutMs ?? 10000)
|
|
1184
|
+
if (isTimedOut(initialized)) {
|
|
1185
|
+
closeClientWhenSettled(clientPromise)
|
|
1186
|
+
throw new Error(`codex daemon '${name}' did not answer initialize within health-check timeout`)
|
|
1187
|
+
}
|
|
1188
|
+
const client = initialized
|
|
1189
|
+
client.close()
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
private async probeRuntime(
|
|
1193
|
+
name: string,
|
|
1194
|
+
state: ReturnType<typeof readDaemonState>,
|
|
1195
|
+
): Promise<CodexRuntimeProbe | null> {
|
|
1196
|
+
if (state === null || !isProcessAlive(state.pid)) return null
|
|
1197
|
+
let client: CodexWsClient | null = null
|
|
1198
|
+
try {
|
|
1199
|
+
const clientPromise = openInitializedCodexClient(name)
|
|
1200
|
+
const initialized = await withTimeout(clientPromise, CODEX_STATUS_RPC_TIMEOUT_MS)
|
|
1201
|
+
if (isTimedOut(initialized)) {
|
|
1202
|
+
closeClientWhenSettled(clientPromise)
|
|
1203
|
+
return { socketReachable: 'no', threadStatus: null, threadState: null }
|
|
1204
|
+
}
|
|
1205
|
+
client = initialized
|
|
1206
|
+
if (state.threadId === null) {
|
|
1207
|
+
return { socketReachable: 'yes', threadStatus: null, threadState: null }
|
|
1208
|
+
}
|
|
1209
|
+
try {
|
|
1210
|
+
const readPromise = client.request<'thread/read', ThreadReadResponse>('thread/read', {
|
|
1211
|
+
threadId: state.threadId,
|
|
1212
|
+
includeTurns: false,
|
|
1213
|
+
})
|
|
1214
|
+
const read = await withTimeout(readPromise, CODEX_STATUS_RPC_TIMEOUT_MS)
|
|
1215
|
+
if (isTimedOut(read)) {
|
|
1216
|
+
readPromise.catch(() => {})
|
|
1217
|
+
client.close()
|
|
1218
|
+
client = null
|
|
1219
|
+
return { socketReachable: 'yes', threadStatus: null, threadState: null }
|
|
1220
|
+
}
|
|
1221
|
+
const statusType = read.thread.status.type
|
|
1222
|
+
return {
|
|
1223
|
+
socketReachable: 'yes',
|
|
1224
|
+
threadStatus: statusType,
|
|
1225
|
+
threadState: statusState(statusType),
|
|
1226
|
+
}
|
|
1227
|
+
} catch {
|
|
1228
|
+
return { socketReachable: 'yes', threadStatus: null, threadState: null }
|
|
1229
|
+
}
|
|
1230
|
+
} catch {
|
|
1231
|
+
return { socketReachable: 'no', threadStatus: null, threadState: null }
|
|
1232
|
+
} finally {
|
|
1233
|
+
if (client !== null) client.close()
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
/**
|
|
1239
|
+
* Open a fresh initialized connection to one per-teammate codex daemon.
|
|
1240
|
+
* Exported for the thin CLI compatibility wrappers and tests; the stream
|
|
1241
|
+
* itself remains codex-engine private and is not part of the Engine contract.
|
|
1242
|
+
*/
|
|
1243
|
+
export async function openInitializedCodexClient(name: string): Promise<CodexWsClient> {
|
|
1244
|
+
const state = readDaemonState(name)
|
|
1245
|
+
if (state === null) throw new Error(`codex daemon '${name}' has no registry state`)
|
|
1246
|
+
const client = new CodexWsClient({ socketPath: state.socketPath })
|
|
1247
|
+
try {
|
|
1248
|
+
await client.ready()
|
|
1249
|
+
await client.request<'initialize', InitializeResponse>('initialize', {
|
|
1250
|
+
clientInfo: CODEX_CLIENT_INFO,
|
|
1251
|
+
capabilities: {
|
|
1252
|
+
experimentalApi: true,
|
|
1253
|
+
requestAttestation: false,
|
|
1254
|
+
},
|
|
1255
|
+
})
|
|
1256
|
+
return client
|
|
1257
|
+
} catch (e) {
|
|
1258
|
+
client.close()
|
|
1259
|
+
throw e
|
|
1260
|
+
}
|
|
1261
|
+
}
|