@shepai/cli 1.152.0 → 1.153.0-pr468.72ce36b
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/apis/json-schema/AgentType.yaml +1 -0
- package/dist/packages/core/src/application/ports/output/repositories/interactive-session-repository.interface.d.ts +5 -0
- package/dist/packages/core/src/application/ports/output/repositories/interactive-session-repository.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/interactive-session-service.interface.d.ts +5 -0
- package/dist/packages/core/src/application/ports/output/services/interactive-session-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/domain/generated/output.d.ts +1 -0
- package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
- package/dist/packages/core/src/domain/generated/output.js +1 -0
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +4 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-interactive-session.repository.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-interactive-session.repository.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/repositories/sqlite-interactive-session.repository.js +15 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.js +22 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-validator.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-validator.service.js +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-interactive-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-interactive-executor.service.js +8 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/codex-cli-executor.service.d.ts +65 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/codex-cli-executor.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/codex-cli-executor.service.js +655 -0
- package/dist/packages/core/src/infrastructure/services/agents/sessions/codex-cli-session.repository.d.ts +62 -0
- package/dist/packages/core/src/infrastructure/services/agents/sessions/codex-cli-session.repository.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/sessions/codex-cli-session.repository.js +356 -0
- package/dist/packages/core/src/infrastructure/services/interactive/interactive-session.service.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/services/interactive/interactive-session.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/interactive/interactive-session.service.js +51 -5
- package/dist/src/presentation/tui/prompts/agent-select.prompt.d.ts +6 -2
- package/dist/src/presentation/tui/prompts/agent-select.prompt.d.ts.map +1 -1
- package/dist/src/presentation/tui/prompts/agent-select.prompt.js +7 -2
- package/dist/src/presentation/web/app/actions/get-all-agent-models.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/get-all-agent-models.js +4 -2
- package/dist/src/presentation/web/app/api/interactive/chat/turn-statuses/route.d.ts +4 -5
- package/dist/src/presentation/web/app/api/interactive/chat/turn-statuses/route.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/interactive/chat/turn-statuses/route.js +5 -13
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.js +26 -1
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.d.ts +2 -0
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer-tabs/event-log-viewer.stories.js +21 -0
- package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.d.ts +1 -1
- package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.js +2 -0
- package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/agent-type-icons.stories.js +1 -0
- package/dist/src/presentation/web/components/common/floating-action-button/floating-action-button.d.ts +8 -2
- package/dist/src/presentation/web/components/common/floating-action-button/floating-action-button.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/floating-action-button/floating-action-button.js +10 -7
- package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node.js +2 -3
- package/dist/src/presentation/web/components/features/chat/ChatSheet.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/chat/ChatSheet.js +43 -30
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +66 -3
- package/dist/src/presentation/web/components/features/features-canvas/canvas-toolbar.d.ts +1 -6
- package/dist/src/presentation/web/components/features/features-canvas/canvas-toolbar.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/features-canvas/canvas-toolbar.js +5 -6
- package/dist/src/presentation/web/components/features/features-canvas/features-canvas.js +1 -1
- package/dist/src/presentation/web/components/features/settings/AgentModelPicker/AgentModelPicker.stories.d.ts +1 -0
- package/dist/src/presentation/web/components/features/settings/AgentModelPicker/AgentModelPicker.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/AgentModelPicker/AgentModelPicker.stories.js +7 -0
- package/dist/src/presentation/web/components/features/settings/agent-settings-section.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/agent-settings-section.js +1 -0
- package/dist/src/presentation/web/components/features/settings/agent-settings-section.stories.d.ts +1 -0
- package/dist/src/presentation/web/components/features/settings/agent-settings-section.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/agent-settings-section.stories.js +8 -0
- package/dist/src/presentation/web/components/layouts/app-shell/app-shell.d.ts.map +1 -1
- package/dist/src/presentation/web/components/layouts/app-shell/app-shell.js +9 -5
- package/dist/src/presentation/web/hooks/turn-statuses-provider.d.ts +4 -8
- package/dist/src/presentation/web/hooks/turn-statuses-provider.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/turn-statuses-provider.js +4 -4
- package/dist/src/presentation/web/hooks/use-turn-statuses.d.ts +4 -5
- package/dist/src/presentation/web/hooks/use-turn-statuses.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-turn-statuses.js +7 -12
- package/dist/src/presentation/web/lib/parse-log-line.d.ts +1 -1
- package/dist/src/presentation/web/lib/parse-log-line.d.ts.map +1 -1
- package/dist/src/presentation/web/lib/parse-log-line.js +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/@drawer/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +36 -36
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +26 -26
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +5 -5
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
- package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
- package/web/.next/server/app/api/interactive/chat/[featureId]/messages/route.js.nft.json +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +10 -10
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +10 -10
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +5 -5
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__ab4951b1._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__ab4951b1._.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__beda892a._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__beda892a._.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js +3 -3
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0b150ddf._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__17ed7ed1._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__17ed7ed1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__28d0d265._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__28d0d265._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__42bf1807._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__42bf1807._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__56b70465._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__56b70465._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__88f7e8e6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__88f7e8e6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8b0aac03._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8b0aac03._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c30f1f82._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c30f1f82._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f80bfc75._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f80bfc75._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f8dd4422._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f8dd4422._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_05c23ad9._.js +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_3a0b989f._.js +2 -2
- package/web/.next/server/chunks/ssr/_3a0b989f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_cf1c5b73._.js → _45afffa1._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_cf1c5b73._.js.map → _45afffa1._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_5f69c13f._.js +1 -1
- package/web/.next/server/chunks/ssr/_5f69c13f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_7c5b97c6._.js +1 -1
- package/web/.next/server/chunks/ssr/_7c5b97c6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_82c57f10._.js +1 -1
- package/web/.next/server/chunks/ssr/_82c57f10._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_9495d50b._.js +1 -1
- package/web/.next/server/chunks/ssr/_9495d50b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_a0e3f7e4._.js +1 -1
- package/web/.next/server/chunks/ssr/_a0e3f7e4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_ac4a3873._.js +1 -1
- package/web/.next/server/chunks/ssr/_ca0aa7f0._.js +1 -1
- package/web/.next/server/chunks/ssr/_ca0aa7f0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_cb1b56ff._.js +3 -0
- package/web/.next/server/chunks/ssr/{_f78b4b9d._.js.map → _cb1b56ff._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_cb5a021e._.js +1 -1
- package/web/.next/server/chunks/ssr/_cb5a021e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_5fce01a7._.js → _cb98ca72._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_5fce01a7._.js.map → _cb98ca72._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_d4b20e29._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_d86175ae._.js +1 -1
- package/web/.next/server/chunks/ssr/_d86175ae._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_d8bedf13._.js +1 -1
- package/web/.next/server/chunks/ssr/_d8bedf13._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_e9a73a63._.js +1 -1
- package/web/.next/server/chunks/ssr/_e9a73a63._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_fa7efce3._.js +2 -2
- package/web/.next/server/chunks/ssr/_fa7efce3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_324a47da._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_324a47da._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_cdc632e3.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_cdc632e3.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_39ca0924.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_39ca0924.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_357e3eb0._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_357e3eb0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +45 -45
- package/web/.next/static/chunks/{a2257ffb1349f838.js → 19e276d1db01686c.js} +1 -1
- package/web/.next/static/chunks/{bdd340ad42a34b41.js → 2d971ae371d47be6.js} +1 -1
- package/web/.next/static/chunks/{f9a80d3854a8d453.js → 56b4a56ab5ec232c.js} +1 -1
- package/web/.next/static/chunks/{277a7f64d4ec189d.js → 644d66ef35bcf689.js} +1 -1
- package/web/.next/static/chunks/{80c4c8b3a5c8e0b6.js → 6b21720f1af9d81d.js} +1 -1
- package/web/.next/static/chunks/6e873694566b5b29.js +1 -0
- package/web/.next/static/chunks/812aef7275df9f5c.js +1 -0
- package/web/.next/static/chunks/8590bd2e69b24b9e.css +1 -0
- package/web/.next/static/chunks/{ef1c9f43aafff65f.js → 8ad4f8b8b02e48e3.js} +3 -3
- package/web/.next/static/chunks/{6bf775818e4ad42e.js → a02bfd8c7a760ec5.js} +1 -1
- package/web/.next/static/chunks/bc7522e582566e5b.js +7 -0
- package/web/.next/static/chunks/{1b4429259bbf3064.js → c054c1cf57e444e3.js} +2 -2
- package/web/.next/static/chunks/{f33efe6a12242a8a.js → e6564e0bc86474b2.js} +1 -1
- package/web/public/icons/agents/openai.svg +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__563f2f7a._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__563f2f7a._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_f78b4b9d._.js +0 -3
- package/web/.next/static/chunks/4908997348bd55f8.js +0 -1
- package/web/.next/static/chunks/76858a51f2fbe99a.js +0 -7
- package/web/.next/static/chunks/a919a9df4ab12a5c.css +0 -1
- package/web/.next/static/chunks/ee20803fb301d59e.js +0 -1
- /package/web/.next/static/{lPbWG8a1RwBDDcvRngp58 → k_Awt-2YfRvvLIUlgT2bA}/_buildManifest.js +0 -0
- /package/web/.next/static/{lPbWG8a1RwBDDcvRngp58 → k_Awt-2YfRvvLIUlgT2bA}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{lPbWG8a1RwBDDcvRngp58 → k_Awt-2YfRvvLIUlgT2bA}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,655 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codex CLI Executor Service
|
|
3
|
+
*
|
|
4
|
+
* Infrastructure implementation of IAgentExecutor for the OpenAI Codex CLI agent.
|
|
5
|
+
* Executes prompts via the `codex` CLI subprocess with JSONL output format.
|
|
6
|
+
*
|
|
7
|
+
* Uses constructor dependency injection for the spawn function
|
|
8
|
+
* to enable testability without mocking node:child_process directly.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as os from 'node:os';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { getCurrentPhase, getLogPrefix } from '../../feature-agent/log-context.js';
|
|
14
|
+
/** Features supported by Codex CLI */
|
|
15
|
+
const SUPPORTED_FEATURES = new Set([
|
|
16
|
+
'session-resume',
|
|
17
|
+
'streaming',
|
|
18
|
+
'structured-output',
|
|
19
|
+
'session-listing',
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* Fatal stderr patterns indicating API-level failures even when exit code is 0.
|
|
23
|
+
* Codex CLI may exit 0 after encountering auth or rate-limit errors.
|
|
24
|
+
*/
|
|
25
|
+
const FATAL_STDERR_PATTERNS = [
|
|
26
|
+
/authentication.*failed/i,
|
|
27
|
+
/rate.?limit/i,
|
|
28
|
+
/quota.*exceeded/i,
|
|
29
|
+
/invalid.*api.?key/i,
|
|
30
|
+
/RESOURCE_EXHAUSTED/i,
|
|
31
|
+
];
|
|
32
|
+
/**
|
|
33
|
+
* Executor service for OpenAI Codex CLI agent.
|
|
34
|
+
* Uses subprocess spawning to interact with the `codex` CLI.
|
|
35
|
+
*/
|
|
36
|
+
export class CodexCliExecutorService {
|
|
37
|
+
spawn;
|
|
38
|
+
authConfig;
|
|
39
|
+
agentType = 'codex-cli';
|
|
40
|
+
/** When true, suppresses debug logging (set per-call via options.silent) */
|
|
41
|
+
silent = false;
|
|
42
|
+
constructor(spawn, authConfig) {
|
|
43
|
+
this.spawn = spawn;
|
|
44
|
+
this.authConfig = authConfig;
|
|
45
|
+
}
|
|
46
|
+
/** Debug logging — writes to stdout so it appears in the worker log file */
|
|
47
|
+
log(message) {
|
|
48
|
+
if (this.silent)
|
|
49
|
+
return;
|
|
50
|
+
const ts = new Date().toISOString();
|
|
51
|
+
process.stdout.write(`[${ts}] ${getCurrentPhase()}${getLogPrefix()}${message}\n`);
|
|
52
|
+
}
|
|
53
|
+
supportsFeature(feature) {
|
|
54
|
+
return SUPPORTED_FEATURES.has(feature);
|
|
55
|
+
}
|
|
56
|
+
async execute(prompt, options) {
|
|
57
|
+
this.silent = options?.silent ?? false;
|
|
58
|
+
const isResume = !!options?.resumeSession;
|
|
59
|
+
let tempSchemaPath;
|
|
60
|
+
try {
|
|
61
|
+
if (options?.outputSchema) {
|
|
62
|
+
tempSchemaPath = path.join(os.tmpdir(), `codex-schema-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
63
|
+
fs.writeFileSync(tempSchemaPath, JSON.stringify(options.outputSchema));
|
|
64
|
+
}
|
|
65
|
+
const args = this.buildArgs(prompt, options, tempSchemaPath);
|
|
66
|
+
const spawnOpts = this.buildSpawnOptions(options);
|
|
67
|
+
this.log(`Spawning: codex ${args.map((a) => (a.length > 80 ? `${a.slice(0, 77)}...` : a)).join(' ')}`);
|
|
68
|
+
this.log(`Spawn cwd: ${spawnOpts.cwd ?? '(inherited)'}`);
|
|
69
|
+
const proc = this.spawn('codex', args, spawnOpts);
|
|
70
|
+
this.log(`Subprocess PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
|
|
71
|
+
this.log(`Prompt length: ${prompt.length} chars${isResume ? ' (positional arg for resume)' : ' (piped via stdin)'}`);
|
|
72
|
+
// Log the actual prompt for debugging (truncate very long prompts)
|
|
73
|
+
const promptPreview = prompt.length > 500 ? `${prompt.slice(0, 497)}...` : prompt;
|
|
74
|
+
this.log(`[text] Prompt: ${promptPreview.replace(/\n/g, ' ')}`);
|
|
75
|
+
// For initial executions, pipe the prompt via stdin.
|
|
76
|
+
// For resume, the prompt is already in the CLI args.
|
|
77
|
+
if (!isResume && proc.stdin) {
|
|
78
|
+
proc.stdin.write(prompt);
|
|
79
|
+
proc.stdin.end();
|
|
80
|
+
}
|
|
81
|
+
return await new Promise((resolve, reject) => {
|
|
82
|
+
let lineBuffer = '';
|
|
83
|
+
let stderr = '';
|
|
84
|
+
let timedOut = false;
|
|
85
|
+
let timeoutId;
|
|
86
|
+
// State accumulated from JSONL events
|
|
87
|
+
let resultText = '';
|
|
88
|
+
let sessionId;
|
|
89
|
+
let usage;
|
|
90
|
+
if (options?.timeout) {
|
|
91
|
+
timeoutId = setTimeout(() => {
|
|
92
|
+
timedOut = true;
|
|
93
|
+
proc.kill();
|
|
94
|
+
}, options.timeout);
|
|
95
|
+
}
|
|
96
|
+
const processLine = (line) => {
|
|
97
|
+
this.logStreamEvent(line);
|
|
98
|
+
try {
|
|
99
|
+
const parsed = JSON.parse(line);
|
|
100
|
+
const type = parsed.type;
|
|
101
|
+
if (type === 'thread.started' && parsed.thread_id) {
|
|
102
|
+
sessionId = parsed.thread_id;
|
|
103
|
+
}
|
|
104
|
+
else if (type === 'item.completed' &&
|
|
105
|
+
CodexCliExecutorService.MESSAGE_ITEM_TYPES.has(parsed.item?.type)) {
|
|
106
|
+
// Accumulate response text from completed agent messages
|
|
107
|
+
// Codex CLI uses item.text directly; fallback to content blocks
|
|
108
|
+
const text = this.extractItemText(parsed);
|
|
109
|
+
if (text)
|
|
110
|
+
resultText += text;
|
|
111
|
+
}
|
|
112
|
+
else if (type === 'turn.completed' && parsed.usage) {
|
|
113
|
+
usage = this.extractUsage(parsed.usage);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Malformed JSON line — skip gracefully
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
proc.stdout?.on('data', (chunk) => {
|
|
121
|
+
lineBuffer += chunk.toString();
|
|
122
|
+
const lines = lineBuffer.split('\n');
|
|
123
|
+
lineBuffer = lines.pop() ?? '';
|
|
124
|
+
for (const line of lines) {
|
|
125
|
+
const trimmed = line.trim();
|
|
126
|
+
if (trimmed)
|
|
127
|
+
processLine(trimmed);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
proc.stderr?.on('data', (chunk) => {
|
|
131
|
+
const data = chunk.toString();
|
|
132
|
+
stderr += data;
|
|
133
|
+
this.log(`stderr: ${data.trimEnd()}`);
|
|
134
|
+
});
|
|
135
|
+
proc.on('error', (error) => {
|
|
136
|
+
this.log(`Process error event: ${error.message}`);
|
|
137
|
+
if (timeoutId)
|
|
138
|
+
clearTimeout(timeoutId);
|
|
139
|
+
if (error.code === 'ENOENT') {
|
|
140
|
+
reject(new Error('Codex CLI ("codex") not found. Please install it: npm i -g @openai/codex'));
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
reject(error);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
proc.on('close', (code) => {
|
|
147
|
+
// Flush remaining buffer
|
|
148
|
+
if (lineBuffer.trim())
|
|
149
|
+
processLine(lineBuffer.trim());
|
|
150
|
+
this.log(`Process closed with code ${code}, result=${resultText.length} chars`);
|
|
151
|
+
if (timeoutId)
|
|
152
|
+
clearTimeout(timeoutId);
|
|
153
|
+
if (timedOut) {
|
|
154
|
+
reject(new Error('Agent execution timed out'));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (code !== 0 && code !== null) {
|
|
158
|
+
const message = stderr.trim()
|
|
159
|
+
? `Process exited with code ${code}: ${stderr.trim()}`
|
|
160
|
+
: `Process exited with code ${code}`;
|
|
161
|
+
reject(new Error(message));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Codex CLI may exit 0 despite fatal API errors.
|
|
165
|
+
// Check stderr for known fatal patterns before trusting the output.
|
|
166
|
+
const fatalError = this.detectFatalStderrError(stderr);
|
|
167
|
+
if (fatalError) {
|
|
168
|
+
reject(new Error(fatalError));
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (!resultText && !sessionId) {
|
|
172
|
+
reject(new Error(`Empty response from Codex CLI. stderr: ${stderr.slice(0, 300)}`));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const result = { result: resultText };
|
|
176
|
+
if (sessionId)
|
|
177
|
+
result.sessionId = sessionId;
|
|
178
|
+
if (usage)
|
|
179
|
+
result.usage = usage;
|
|
180
|
+
resolve(result);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
finally {
|
|
185
|
+
// Clean up temp schema file
|
|
186
|
+
if (tempSchemaPath) {
|
|
187
|
+
try {
|
|
188
|
+
fs.unlinkSync(tempSchemaPath);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Best effort cleanup
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async *executeStream(prompt, options) {
|
|
197
|
+
this.silent = options?.silent ?? false;
|
|
198
|
+
const isResume = !!options?.resumeSession;
|
|
199
|
+
let tempSchemaPath;
|
|
200
|
+
try {
|
|
201
|
+
if (options?.outputSchema) {
|
|
202
|
+
tempSchemaPath = path.join(os.tmpdir(), `codex-schema-${Date.now()}-${Math.random().toString(36).slice(2)}.json`);
|
|
203
|
+
fs.writeFileSync(tempSchemaPath, JSON.stringify(options.outputSchema));
|
|
204
|
+
}
|
|
205
|
+
const args = this.buildArgs(prompt, options, tempSchemaPath);
|
|
206
|
+
const spawnOpts = this.buildSpawnOptions(options);
|
|
207
|
+
const proc = this.spawn('codex', args, spawnOpts);
|
|
208
|
+
// For initial executions, pipe the prompt via stdin.
|
|
209
|
+
// For resume, the prompt is already in the CLI args.
|
|
210
|
+
if (!isResume && proc.stdin) {
|
|
211
|
+
proc.stdin.write(prompt);
|
|
212
|
+
proc.stdin.end();
|
|
213
|
+
}
|
|
214
|
+
let lineBuffer = '';
|
|
215
|
+
let stderr = '';
|
|
216
|
+
let timedOut = false;
|
|
217
|
+
let timeoutId;
|
|
218
|
+
// State accumulated across events
|
|
219
|
+
let resultText = '';
|
|
220
|
+
const queue = [];
|
|
221
|
+
let resolve = null;
|
|
222
|
+
let spawnError = null;
|
|
223
|
+
function enqueue(event) {
|
|
224
|
+
queue.push(event);
|
|
225
|
+
if (resolve) {
|
|
226
|
+
resolve();
|
|
227
|
+
resolve = null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function waitForItem() {
|
|
231
|
+
if (queue.length > 0)
|
|
232
|
+
return Promise.resolve();
|
|
233
|
+
return new Promise((r) => {
|
|
234
|
+
resolve = r;
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
if (options?.timeout) {
|
|
238
|
+
timeoutId = setTimeout(() => {
|
|
239
|
+
timedOut = true;
|
|
240
|
+
proc.kill();
|
|
241
|
+
enqueue({ type: 'error', content: 'Agent execution timed out', timestamp: new Date() });
|
|
242
|
+
enqueue(null);
|
|
243
|
+
}, options.timeout);
|
|
244
|
+
}
|
|
245
|
+
const processStreamLine = (line) => {
|
|
246
|
+
this.logStreamEvent(line);
|
|
247
|
+
try {
|
|
248
|
+
const parsed = JSON.parse(line);
|
|
249
|
+
const type = parsed.type;
|
|
250
|
+
if (type === 'thread.started') {
|
|
251
|
+
// Internal state — no event yielded (thread_id tracked for logging)
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const isMessage = CodexCliExecutorService.MESSAGE_ITEM_TYPES.has(parsed.item?.type);
|
|
255
|
+
if (type === 'item.started' && isMessage) {
|
|
256
|
+
enqueue({ type: 'progress', content: '', timestamp: new Date() });
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (type === 'item.updated' && isMessage) {
|
|
260
|
+
const delta = this.extractDeltaText(parsed);
|
|
261
|
+
if (delta) {
|
|
262
|
+
enqueue({ type: 'progress', content: delta, timestamp: new Date() });
|
|
263
|
+
}
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
if (type === 'item.completed' && isMessage) {
|
|
267
|
+
const text = this.extractItemText(parsed);
|
|
268
|
+
if (text)
|
|
269
|
+
resultText += text;
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (type === 'item.started' && parsed.item?.type === 'command_execution') {
|
|
273
|
+
const cmd = parsed.item.command ?? parsed.item.name ?? 'command';
|
|
274
|
+
enqueue({ type: 'progress', content: `Running: ${cmd}`, timestamp: new Date() });
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (type === 'item.completed' && parsed.item?.type === 'command_execution') {
|
|
278
|
+
const exitCode = parsed.item.exit_code ?? '';
|
|
279
|
+
enqueue({
|
|
280
|
+
type: 'progress',
|
|
281
|
+
content: `Command completed (exit ${exitCode})`,
|
|
282
|
+
timestamp: new Date(),
|
|
283
|
+
});
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
if (type === 'item.started' && parsed.item?.type === 'file_change') {
|
|
287
|
+
enqueue({ type: 'progress', content: 'Modifying files', timestamp: new Date() });
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
if (type === 'item.completed' && parsed.item?.type === 'file_change') {
|
|
291
|
+
const file = parsed.item.file ?? parsed.item.path ?? '';
|
|
292
|
+
enqueue({
|
|
293
|
+
type: 'progress',
|
|
294
|
+
content: file ? `Modified: ${file}` : 'File change completed',
|
|
295
|
+
timestamp: new Date(),
|
|
296
|
+
});
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
if (type === 'turn.completed') {
|
|
300
|
+
// Yield final result event
|
|
301
|
+
enqueue({
|
|
302
|
+
type: 'result',
|
|
303
|
+
content: resultText,
|
|
304
|
+
timestamp: new Date(),
|
|
305
|
+
});
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
if (type === 'turn.failed') {
|
|
309
|
+
const msg = parsed.error?.message ?? parsed.message ?? 'Turn failed';
|
|
310
|
+
enqueue({ type: 'error', content: msg, timestamp: new Date() });
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (type === 'error') {
|
|
314
|
+
const msg = parsed.message ?? parsed.error ?? 'Unknown error';
|
|
315
|
+
enqueue({ type: 'error', content: msg, timestamp: new Date() });
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
// Unknown event type — skip gracefully
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
// Non-JSON line — emit as raw progress
|
|
322
|
+
enqueue({ type: 'progress', content: line, timestamp: new Date() });
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
proc.stdout?.on('data', (chunk) => {
|
|
326
|
+
lineBuffer += chunk.toString();
|
|
327
|
+
const lines = lineBuffer.split('\n');
|
|
328
|
+
lineBuffer = lines.pop() ?? '';
|
|
329
|
+
for (const line of lines) {
|
|
330
|
+
const trimmed = line.trim();
|
|
331
|
+
if (!trimmed)
|
|
332
|
+
continue;
|
|
333
|
+
processStreamLine(trimmed);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
proc.stderr?.on('data', (chunk) => {
|
|
337
|
+
stderr += chunk.toString();
|
|
338
|
+
});
|
|
339
|
+
proc.on('error', (err) => {
|
|
340
|
+
if (timeoutId)
|
|
341
|
+
clearTimeout(timeoutId);
|
|
342
|
+
spawnError = err;
|
|
343
|
+
enqueue(null);
|
|
344
|
+
});
|
|
345
|
+
proc.on('close', (code) => {
|
|
346
|
+
if (timeoutId)
|
|
347
|
+
clearTimeout(timeoutId);
|
|
348
|
+
if (timedOut)
|
|
349
|
+
return; // already handled by timeout callback
|
|
350
|
+
if (lineBuffer.trim()) {
|
|
351
|
+
processStreamLine(lineBuffer.trim());
|
|
352
|
+
}
|
|
353
|
+
if (code !== 0 && code !== null) {
|
|
354
|
+
const msg = stderr.trim()
|
|
355
|
+
? `Process exited with code ${code}: ${stderr.trim()}`
|
|
356
|
+
: `Process exited with code ${code}`;
|
|
357
|
+
enqueue({ type: 'error', content: msg, timestamp: new Date() });
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
// Check for fatal stderr patterns on exit 0
|
|
361
|
+
const fatalError = this.detectFatalStderrError(stderr);
|
|
362
|
+
if (fatalError) {
|
|
363
|
+
enqueue({ type: 'error', content: fatalError, timestamp: new Date() });
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
enqueue(null);
|
|
367
|
+
});
|
|
368
|
+
// Yield events as they arrive
|
|
369
|
+
while (true) {
|
|
370
|
+
await waitForItem();
|
|
371
|
+
const item = queue.shift();
|
|
372
|
+
if (item === null || item === undefined) {
|
|
373
|
+
if (spawnError !== null) {
|
|
374
|
+
yield {
|
|
375
|
+
type: 'error',
|
|
376
|
+
content: spawnError.message,
|
|
377
|
+
timestamp: new Date(),
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
yield item;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
finally {
|
|
386
|
+
// Clean up temp schema file
|
|
387
|
+
if (tempSchemaPath) {
|
|
388
|
+
try {
|
|
389
|
+
fs.unlinkSync(tempSchemaPath);
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
// Best effort cleanup
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* Log a JSONL stream line as a human-readable event in the worker log.
|
|
399
|
+
* Extracts tool calls (function_call), assistant text, command executions,
|
|
400
|
+
* and result summaries for verbose debugging.
|
|
401
|
+
*/
|
|
402
|
+
/** Item types that represent assistant text messages */
|
|
403
|
+
static MESSAGE_ITEM_TYPES = new Set(['agent_message', 'message']);
|
|
404
|
+
logStreamEvent(line) {
|
|
405
|
+
try {
|
|
406
|
+
const parsed = JSON.parse(line);
|
|
407
|
+
const type = parsed.type;
|
|
408
|
+
const itemType = parsed.item?.type;
|
|
409
|
+
// Thread lifecycle
|
|
410
|
+
if (type === 'thread.started') {
|
|
411
|
+
this.log(`[thread] started thread_id=${parsed.thread_id ?? 'unknown'}`);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
// Agent/assistant message text — log the content
|
|
415
|
+
if (type === 'item.completed' &&
|
|
416
|
+
itemType &&
|
|
417
|
+
CodexCliExecutorService.MESSAGE_ITEM_TYPES.has(itemType)) {
|
|
418
|
+
const text = this.extractItemText(parsed);
|
|
419
|
+
if (text) {
|
|
420
|
+
const preview = text.length > 200 ? `${text.slice(0, 197)}...` : text;
|
|
421
|
+
this.log(`[text] ${preview.replace(/\n/g, ' ')}`);
|
|
422
|
+
}
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
// Delta/partial updates for messages — log text fragments
|
|
426
|
+
if (type === 'item.updated' &&
|
|
427
|
+
itemType &&
|
|
428
|
+
CodexCliExecutorService.MESSAGE_ITEM_TYPES.has(itemType)) {
|
|
429
|
+
const delta = this.extractDeltaText(parsed);
|
|
430
|
+
if (delta) {
|
|
431
|
+
this.log(`[delta] ${delta.replace(/\n/g, ' ')}`);
|
|
432
|
+
}
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
// Reasoning items — model's chain-of-thought
|
|
436
|
+
if (type === 'item.completed' && itemType === 'reasoning') {
|
|
437
|
+
const text = this.extractItemText(parsed);
|
|
438
|
+
if (text) {
|
|
439
|
+
const preview = text.length > 200 ? `${text.slice(0, 197)}...` : text;
|
|
440
|
+
this.log(`[text] Reasoning: ${preview.replace(/\n/g, ' ')}`);
|
|
441
|
+
}
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
// Function/tool calls — log name and arguments
|
|
445
|
+
if (type === 'item.started' && itemType === 'function_call') {
|
|
446
|
+
const name = parsed.item.name ?? parsed.item.call_id ?? 'unknown';
|
|
447
|
+
const args = parsed.item.arguments ?? '';
|
|
448
|
+
this.log(`[tool] ${name} ${typeof args === 'string' ? args : JSON.stringify(args)}`);
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (type === 'item.completed' && itemType === 'function_call') {
|
|
452
|
+
const name = parsed.item.name ?? 'unknown';
|
|
453
|
+
this.log(`[tool] ${name} completed`);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
// Function call output — log truncated result
|
|
457
|
+
if (type === 'item.completed' && itemType === 'function_call_output') {
|
|
458
|
+
const output = parsed.item.output ?? '';
|
|
459
|
+
const preview = typeof output === 'string'
|
|
460
|
+
? output.length > 200
|
|
461
|
+
? `${output.slice(0, 197)}...`
|
|
462
|
+
: output
|
|
463
|
+
: JSON.stringify(output).slice(0, 200);
|
|
464
|
+
this.log(`[tool-result] ${preview.replace(/\n/g, ' ')}`);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
// Command executions (Codex shell tool)
|
|
468
|
+
if (type === 'item.started' && itemType === 'command_execution') {
|
|
469
|
+
const cmd = parsed.item.command ?? parsed.item.name ?? 'command';
|
|
470
|
+
this.log(`[cmd] running: ${cmd}`);
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (type === 'item.completed' && itemType === 'command_execution') {
|
|
474
|
+
const exitCode = parsed.item.exit_code ?? '';
|
|
475
|
+
const output = parsed.item.output ?? '';
|
|
476
|
+
const preview = typeof output === 'string'
|
|
477
|
+
? output.length > 200
|
|
478
|
+
? `${output.slice(0, 197)}...`
|
|
479
|
+
: output
|
|
480
|
+
: '';
|
|
481
|
+
this.log(`[cmd] exit=${exitCode}${preview ? ` output: ${preview.replace(/\n/g, ' ')}` : ''}`);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
// File changes
|
|
485
|
+
if (type === 'item.started' && itemType === 'file_change') {
|
|
486
|
+
const file = parsed.item.file ?? parsed.item.path ?? '';
|
|
487
|
+
this.log(`[file] modifying: ${file}`);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (type === 'item.completed' && itemType === 'file_change') {
|
|
491
|
+
const file = parsed.item.file ?? parsed.item.path ?? '';
|
|
492
|
+
this.log(`[file] modified: ${file}`);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
// Turn lifecycle with usage stats
|
|
496
|
+
if (type === 'turn.completed') {
|
|
497
|
+
const u = parsed.usage;
|
|
498
|
+
if (u) {
|
|
499
|
+
const inTokens = u.input_tokens ?? 0;
|
|
500
|
+
const outTokens = u.output_tokens ?? 0;
|
|
501
|
+
this.log(`[tokens] ${inTokens} in / ${outTokens} out`);
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
this.log('[turn] completed');
|
|
505
|
+
}
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (type === 'turn.failed') {
|
|
509
|
+
const msg = parsed.error?.message ?? parsed.message ?? 'unknown';
|
|
510
|
+
this.log(`[turn] FAILED: ${msg}`);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
// Error events
|
|
514
|
+
if (type === 'error') {
|
|
515
|
+
const msg = parsed.message ?? parsed.error ?? 'unknown';
|
|
516
|
+
this.log(`[error] ${msg}`);
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
// Catch-all: log any unhandled event so nothing is silently dropped
|
|
520
|
+
const summary = itemType ? `${type} (${itemType})` : type;
|
|
521
|
+
const snippet = line.length > 200 ? `${line.slice(0, 197)}...` : line;
|
|
522
|
+
this.log(`[event] ${summary}: ${snippet}`);
|
|
523
|
+
}
|
|
524
|
+
catch {
|
|
525
|
+
// Non-JSON line — log raw
|
|
526
|
+
if (line.length > 0) {
|
|
527
|
+
this.log(`[raw] ${line}`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Build CLI arguments for codex exec.
|
|
533
|
+
*
|
|
534
|
+
* For initial execution: `codex exec - --json --sandbox danger-full-access ...`
|
|
535
|
+
* For resume: `codex exec resume <threadId> "prompt" --json --sandbox danger-full-access ...`
|
|
536
|
+
*/
|
|
537
|
+
buildArgs(prompt, options, tempSchemaPath) {
|
|
538
|
+
const baseFlags = [
|
|
539
|
+
'--json',
|
|
540
|
+
'--sandbox',
|
|
541
|
+
'danger-full-access',
|
|
542
|
+
'--skip-git-repo-check',
|
|
543
|
+
'--color',
|
|
544
|
+
'never',
|
|
545
|
+
];
|
|
546
|
+
if (options?.model)
|
|
547
|
+
baseFlags.push('--model', options.model);
|
|
548
|
+
if (options?.cwd)
|
|
549
|
+
baseFlags.push('--cd', options.cwd);
|
|
550
|
+
if (tempSchemaPath)
|
|
551
|
+
baseFlags.push('--output-schema', tempSchemaPath);
|
|
552
|
+
if (options?.resumeSession) {
|
|
553
|
+
// Resume mode: codex exec resume <threadId> "prompt" [flags]
|
|
554
|
+
return ['exec', 'resume', options.resumeSession, prompt, ...baseFlags];
|
|
555
|
+
}
|
|
556
|
+
// Initial execution: codex exec - [flags]
|
|
557
|
+
// The `-` indicates prompt is piped via stdin
|
|
558
|
+
return ['exec', '-', ...baseFlags];
|
|
559
|
+
}
|
|
560
|
+
buildSpawnOptions(_options) {
|
|
561
|
+
const spawnOpts = {};
|
|
562
|
+
// Explicitly pipe stdio so streams are available even when parent disconnects
|
|
563
|
+
spawnOpts.stdio = ['pipe', 'pipe', 'pipe'];
|
|
564
|
+
// On Windows: windowsHide=true to prevent blank console windows.
|
|
565
|
+
// Codex CLI is a native Rust binary, so shell=true is NOT needed.
|
|
566
|
+
if (process.platform === 'win32') {
|
|
567
|
+
spawnOpts.windowsHide = true;
|
|
568
|
+
}
|
|
569
|
+
// Strip CLAUDECODE env var to prevent "nested session" error when shep
|
|
570
|
+
// is invoked from within a Claude Code session.
|
|
571
|
+
const { CLAUDECODE: _, ...cleanEnv } = process.env;
|
|
572
|
+
// Inject CODEX_API_KEY when using token auth
|
|
573
|
+
if (this.authConfig?.authMethod === 'token' && this.authConfig.token) {
|
|
574
|
+
spawnOpts.env = { ...cleanEnv, CODEX_API_KEY: this.authConfig.token };
|
|
575
|
+
}
|
|
576
|
+
else {
|
|
577
|
+
spawnOpts.env = cleanEnv;
|
|
578
|
+
}
|
|
579
|
+
return spawnOpts;
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Extract token usage from Codex CLI turn.completed usage object.
|
|
583
|
+
*/
|
|
584
|
+
extractUsage(usageObj) {
|
|
585
|
+
if (usageObj.input_tokens === undefined && usageObj.output_tokens === undefined) {
|
|
586
|
+
return undefined;
|
|
587
|
+
}
|
|
588
|
+
return {
|
|
589
|
+
inputTokens: usageObj.input_tokens ?? 0,
|
|
590
|
+
outputTokens: usageObj.output_tokens ?? 0,
|
|
591
|
+
};
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Extract delta text from an item.updated event.
|
|
595
|
+
* Codex CLI uses `item.text` directly, while other formats use content blocks or `item.delta`.
|
|
596
|
+
*/
|
|
597
|
+
extractDeltaText(parsed) {
|
|
598
|
+
const item = parsed.item;
|
|
599
|
+
if (!item)
|
|
600
|
+
return undefined;
|
|
601
|
+
// Codex CLI format: item.text is a plain string (accumulated so far)
|
|
602
|
+
if (typeof item.text === 'string' && item.text)
|
|
603
|
+
return item.text;
|
|
604
|
+
// Fallback: content block array
|
|
605
|
+
const content = item.content;
|
|
606
|
+
if (Array.isArray(content)) {
|
|
607
|
+
for (const block of content) {
|
|
608
|
+
if (block.type === 'text' && block.text)
|
|
609
|
+
return block.text;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
if (typeof item.delta === 'string')
|
|
613
|
+
return item.delta;
|
|
614
|
+
return undefined;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Extract final text from an item.completed event.
|
|
618
|
+
* Codex CLI uses `item.text` directly, while other formats use `item.content` blocks.
|
|
619
|
+
*/
|
|
620
|
+
extractItemText(parsed) {
|
|
621
|
+
const item = parsed.item;
|
|
622
|
+
if (!item)
|
|
623
|
+
return undefined;
|
|
624
|
+
// Codex CLI format: item.text is a plain string
|
|
625
|
+
if (typeof item.text === 'string' && item.text)
|
|
626
|
+
return item.text;
|
|
627
|
+
// Fallback: content block array format
|
|
628
|
+
const content = item.content;
|
|
629
|
+
if (Array.isArray(content)) {
|
|
630
|
+
const parts = [];
|
|
631
|
+
for (const block of content) {
|
|
632
|
+
if (block.type === 'text' && block.text)
|
|
633
|
+
parts.push(block.text);
|
|
634
|
+
}
|
|
635
|
+
return parts.length > 0 ? parts.join('') : undefined;
|
|
636
|
+
}
|
|
637
|
+
if (typeof content === 'string')
|
|
638
|
+
return content;
|
|
639
|
+
return undefined;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Check stderr for patterns indicating fatal API errors.
|
|
643
|
+
* Returns an error message if fatal patterns are found, null otherwise.
|
|
644
|
+
*/
|
|
645
|
+
detectFatalStderrError(stderr) {
|
|
646
|
+
for (const pattern of FATAL_STDERR_PATTERNS) {
|
|
647
|
+
if (pattern.test(stderr)) {
|
|
648
|
+
const lines = stderr.split('\n').filter((l) => l.trim());
|
|
649
|
+
const summary = lines.slice(0, 3).join(' | ').slice(0, 300);
|
|
650
|
+
return `Codex CLI exited 0 but fatal error detected in stderr: ${summary}`;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
}
|