factory-factory 0.3.4 → 0.3.6
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/README.md +17 -0
- package/dist/client/assets/_basePickBy-CzLmZHC2.js +1 -0
- package/dist/client/assets/{_baseUniq-DisTPj-I.js → _baseUniq-B2vXSgXW.js} +1 -1
- package/dist/client/assets/arc-Dq49BrkB.js +1 -0
- package/dist/client/assets/architectureDiagram-VXUJARFQ-BGubq_o9.js +36 -0
- package/dist/client/assets/{blockDiagram-VD42YOAC-DXpmez0y.js → blockDiagram-VD42YOAC-CJ7hB7tD.js} +4 -4
- package/dist/client/assets/{c4Diagram-YG6GDRKO-C6sDxR49.js → c4Diagram-YG6GDRKO-C9-3yIl7.js} +3 -3
- package/dist/client/assets/channel-DMaON2vY.js +1 -0
- package/dist/client/assets/{chunk-4BX2VUAB-CQxlRbYu.js → chunk-4BX2VUAB-LA-tkKjD.js} +1 -1
- package/dist/client/assets/{chunk-55IACEB6-DxubFDep.js → chunk-55IACEB6-D8Jq3_Ne.js} +1 -1
- package/dist/client/assets/{chunk-B4BG7PRW-BtTQ0im9.js → chunk-B4BG7PRW-BbB1Mssd.js} +1 -1
- package/dist/client/assets/{chunk-DI55MBZ5-C2tNYDZj.js → chunk-DI55MBZ5-CpO3WS5m.js} +1 -1
- package/dist/client/assets/{chunk-FMBD7UC4-kRQRN6vP.js → chunk-FMBD7UC4-zaxR2CzR.js} +1 -1
- package/dist/client/assets/chunk-QN33PNHL-BMmRcEqx.js +1 -0
- package/dist/client/assets/{chunk-QZHKN3VN-BfxMFZDN.js → chunk-QZHKN3VN-CbCQqsiw.js} +1 -1
- package/dist/client/assets/chunk-TZMSLE5B-BhRzmVVB.js +1 -0
- package/dist/client/assets/classDiagram-2ON5EDUG-BKODUnN9.js +1 -0
- package/dist/client/assets/classDiagram-v2-WZHVMYZB-BKODUnN9.js +1 -0
- package/dist/client/assets/clone-d5fivKBG.js +1 -0
- package/dist/client/assets/{cose-bilkent-S5V4N54A-QPsUxyAe.js → cose-bilkent-S5V4N54A-BZtg5BPr.js} +1 -1
- package/dist/client/assets/{dagre-6UL2VRFP-BAmsmcnI.js → dagre-6UL2VRFP-DiejfPfI.js} +2 -2
- package/dist/client/assets/diagram-PSM6KHXK-CRE7v2e7.js +24 -0
- package/dist/client/assets/diagram-QEK2KX5R-DpAOzBlm.js +43 -0
- package/dist/client/assets/diagram-S2PKOQOG-BOJvuhJd.js +24 -0
- package/dist/client/assets/{erDiagram-Q2GNP2WA-DMKIVzp4.js → erDiagram-Q2GNP2WA-IM11uKRy.js} +4 -4
- package/dist/client/assets/{flowDiagram-NV44I4VS-op3xA_nS.js → flowDiagram-NV44I4VS-DTbQf_7g.js} +5 -5
- package/dist/client/assets/{ganttDiagram-JELNMOA3-nrnzVCJK.js → ganttDiagram-JELNMOA3-Bqd3rUDW.js} +2 -2
- package/dist/client/assets/gitGraphDiagram-V2S2FVAM-Cd1j3VMN.js +65 -0
- package/dist/client/assets/{graph-D_lEcPMk.js → graph-D667hHAk.js} +1 -1
- package/dist/client/assets/{index-C2qHRaOH.js → index-BXRnTMjJ.js} +170 -171
- package/dist/client/assets/index-DllMnbgu.css +1 -0
- package/dist/client/assets/infoDiagram-HS3SLOUP-CzpZPq7Y.js +2 -0
- package/dist/client/assets/{journeyDiagram-XKPGCS4Q-Bnhe4U1x.js → journeyDiagram-XKPGCS4Q-Br2GUbhE.js} +1 -1
- package/dist/client/assets/{kanban-definition-3W4ZIXB7-DpTaTXko.js → kanban-definition-3W4ZIXB7-D0SM1ldH.js} +6 -6
- package/dist/client/assets/{layout-HT5qr--Q.js → layout-BPE9Dzp9.js} +1 -1
- package/dist/client/assets/{linear-CDmQ8HG8.js → linear-5exZFNBA.js} +1 -1
- package/dist/client/assets/{mindmap-definition-VGOIOE7T-zDr7s4o2.js → mindmap-definition-VGOIOE7T-D1W9h2lc.js} +3 -3
- package/dist/client/assets/mobile-baseline-BHP-K4kd.js +10 -0
- package/dist/client/assets/pieDiagram-ADFJNKIX-DG-umOTY.js +30 -0
- package/dist/client/assets/{quadrantDiagram-AYHSOK5B-DzdJzkAJ.js → quadrantDiagram-AYHSOK5B-Cb0ciONq.js} +1 -1
- package/dist/client/assets/{requirementDiagram-UZGBJVZJ-ChrLzx8S.js → requirementDiagram-UZGBJVZJ-BKYaJZ83.js} +1 -1
- package/dist/client/assets/sankeyDiagram-TZEHDZUN-DkR9L4Vw.js +10 -0
- package/dist/client/assets/{sequenceDiagram-WL72ISMW-BHxEpSCU.js → sequenceDiagram-WL72ISMW-Cys03qhv.js} +6 -6
- package/dist/client/assets/stateDiagram-FKZM4ZOC-DQWCRtS7.js +1 -0
- package/dist/client/assets/stateDiagram-v2-4FDKWEC3-DoWi8XaX.js +1 -0
- package/dist/client/assets/terminal-instance-CpEqekOB.js +1 -0
- package/dist/client/assets/{timeline-definition-IT6M3QCI-BcCmIxix.js → timeline-definition-IT6M3QCI-C0mVV_zL.js} +4 -4
- package/dist/client/assets/treemap-GDKQZRPO-DK-Wlxvy.js +160 -0
- package/dist/client/assets/{xychartDiagram-PRI3JC2R-DrgKBPUM.js → xychartDiagram-PRI3JC2R-CFg2MfK9.js} +4 -4
- package/dist/client/index.html +3 -3
- package/dist/prisma/generated/commonInputTypes.d.ts +69 -39
- package/dist/prisma/generated/commonInputTypes.d.ts.map +1 -1
- package/dist/prisma/generated/enums.d.ts +6 -0
- package/dist/prisma/generated/enums.d.ts.map +1 -1
- package/dist/prisma/generated/enums.js +6 -1
- package/dist/prisma/generated/enums.js.map +1 -1
- package/dist/prisma/generated/internal/class.d.ts.map +1 -1
- package/dist/prisma/generated/internal/class.js +12 -4
- package/dist/prisma/generated/internal/class.js.map +1 -1
- package/dist/prisma/generated/internal/prismaNamespace.d.ts +13 -7
- package/dist/prisma/generated/internal/prismaNamespace.d.ts.map +1 -1
- package/dist/prisma/generated/internal/prismaNamespace.js +11 -6
- package/dist/prisma/generated/internal/prismaNamespace.js.map +1 -1
- package/dist/prisma/generated/internal/prismaNamespaceBrowser.d.ts +10 -5
- package/dist/prisma/generated/internal/prismaNamespaceBrowser.d.ts.map +1 -1
- package/dist/prisma/generated/internal/prismaNamespaceBrowser.js +9 -4
- package/dist/prisma/generated/internal/prismaNamespaceBrowser.js.map +1 -1
- package/dist/prisma/generated/models/Project.d.ts +63 -1
- package/dist/prisma/generated/models/Project.d.ts.map +1 -1
- package/dist/prisma/generated/models/Workspace.d.ts +130 -1
- package/dist/prisma/generated/models/Workspace.d.ts.map +1 -1
- package/dist/prompts/quick-actions/screenshots.md +12 -6
- package/dist/prompts/ratchet/dispatch.md +4 -0
- package/dist/src/backend/domains/linear/index.d.ts +3 -0
- package/dist/src/backend/domains/linear/index.d.ts.map +1 -0
- package/dist/src/backend/domains/linear/index.js +3 -0
- package/dist/src/backend/domains/linear/index.js.map +1 -0
- package/dist/src/backend/domains/linear/linear-client.service.d.ts +40 -0
- package/dist/src/backend/domains/linear/linear-client.service.d.ts.map +1 -0
- package/dist/src/backend/domains/linear/linear-client.service.js +134 -0
- package/dist/src/backend/domains/linear/linear-client.service.js.map +1 -0
- package/dist/src/backend/domains/linear/linear-state-sync.service.d.ts +7 -0
- package/dist/src/backend/domains/linear/linear-state-sync.service.d.ts.map +1 -0
- package/dist/src/backend/domains/linear/linear-state-sync.service.js +29 -0
- package/dist/src/backend/domains/linear/linear-state-sync.service.js.map +1 -0
- package/dist/src/backend/domains/ratchet/bridges.d.ts +5 -1
- package/dist/src/backend/domains/ratchet/bridges.d.ts.map +1 -1
- package/dist/src/backend/domains/ratchet/ratchet.service.d.ts +2 -0
- package/dist/src/backend/domains/ratchet/ratchet.service.d.ts.map +1 -1
- package/dist/src/backend/domains/ratchet/ratchet.service.js +43 -53
- package/dist/src/backend/domains/ratchet/ratchet.service.js.map +1 -1
- package/dist/src/backend/domains/ratchet/ratchet.service.test.js +61 -18
- package/dist/src/backend/domains/ratchet/ratchet.service.test.js.map +1 -1
- package/dist/src/backend/domains/session/acp/acp-runtime-manager.d.ts.map +1 -1
- package/dist/src/backend/domains/session/acp/acp-runtime-manager.js +5 -1
- package/dist/src/backend/domains/session/acp/acp-runtime-manager.js.map +1 -1
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.d.ts +13 -2
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.d.ts.map +1 -1
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.js +839 -106
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.js.map +1 -1
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.test.js +735 -8
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-app-server-acp-adapter.test.js.map +1 -1
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.d.ts +20 -0
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.d.ts.map +1 -1
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.js +16 -0
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.js.map +1 -1
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.test.js +15 -0
- package/dist/src/backend/domains/session/acp/codex-app-server-adapter/codex-zod.test.js.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.d.ts +2 -2
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.d.ts.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.js +32 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.js.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.test.js +79 -9
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/load-session.handler.test.js.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.d.ts +2 -2
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.d.ts.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.js +3 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.js.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.test.js +10 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/handlers/stop.handler.test.js.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/registry.js +2 -2
- package/dist/src/backend/domains/session/chat/chat-message-handlers/registry.js.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers/types.d.ts +1 -0
- package/dist/src/backend/domains/session/chat/chat-message-handlers/types.d.ts.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers.service.d.ts +5 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers.service.d.ts.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers.service.js +39 -13
- package/dist/src/backend/domains/session/chat/chat-message-handlers.service.js.map +1 -1
- package/dist/src/backend/domains/session/chat/chat-message-handlers.service.test.js +81 -0
- package/dist/src/backend/domains/session/chat/chat-message-handlers.service.test.js.map +1 -1
- package/dist/src/backend/domains/session/data/codex-session-history-loader.service.d.ts.map +1 -1
- package/dist/src/backend/domains/session/data/codex-session-history-loader.service.js +12 -59
- package/dist/src/backend/domains/session/data/codex-session-history-loader.service.js.map +1 -1
- package/dist/src/backend/domains/session/data/codex-session-history-loader.service.test.js +11 -21
- package/dist/src/backend/domains/session/data/codex-session-history-loader.service.test.js.map +1 -1
- package/dist/src/backend/domains/session/data/session-data.service.d.ts +6 -0
- package/dist/src/backend/domains/session/data/session-data.service.d.ts.map +1 -1
- package/dist/src/backend/domains/session/lifecycle/session.service.d.ts +7 -0
- package/dist/src/backend/domains/session/lifecycle/session.service.d.ts.map +1 -1
- package/dist/src/backend/domains/session/lifecycle/session.service.js +105 -6
- package/dist/src/backend/domains/session/lifecycle/session.service.js.map +1 -1
- package/dist/src/backend/domains/session/lifecycle/session.service.test.js +84 -0
- package/dist/src/backend/domains/session/lifecycle/session.service.test.js.map +1 -1
- package/dist/src/backend/domains/session/session-domain.service.d.ts +8 -1
- package/dist/src/backend/domains/session/session-domain.service.d.ts.map +1 -1
- package/dist/src/backend/domains/session/session-domain.service.js +43 -2
- package/dist/src/backend/domains/session/session-domain.service.js.map +1 -1
- package/dist/src/backend/domains/session/session-domain.service.test.js +21 -0
- package/dist/src/backend/domains/session/session-domain.service.test.js.map +1 -1
- package/dist/src/backend/domains/session/store/session-store.types.d.ts +1 -1
- package/dist/src/backend/domains/session/store/session-store.types.d.ts.map +1 -1
- package/dist/src/backend/domains/session/store/session-transcript.d.ts +1 -0
- package/dist/src/backend/domains/session/store/session-transcript.d.ts.map +1 -1
- package/dist/src/backend/domains/session/store/session-transcript.js +8 -0
- package/dist/src/backend/domains/session/store/session-transcript.js.map +1 -1
- package/dist/src/backend/domains/workspace/lifecycle/creation.service.d.ts +9 -0
- package/dist/src/backend/domains/workspace/lifecycle/creation.service.d.ts.map +1 -1
- package/dist/src/backend/domains/workspace/lifecycle/creation.service.js +18 -0
- package/dist/src/backend/domains/workspace/lifecycle/creation.service.js.map +1 -1
- package/dist/src/backend/domains/workspace/lifecycle/creation.service.test.js +46 -0
- package/dist/src/backend/domains/workspace/lifecycle/creation.service.test.js.map +1 -1
- package/dist/src/backend/domains/workspace/lifecycle/data.service.d.ts +25 -0
- package/dist/src/backend/domains/workspace/lifecycle/data.service.d.ts.map +1 -1
- package/dist/src/backend/domains/workspace/query/project-management.service.d.ts +16 -0
- package/dist/src/backend/domains/workspace/query/project-management.service.d.ts.map +1 -1
- package/dist/src/backend/domains/workspace/query/project-management.service.js.map +1 -1
- package/dist/src/backend/domains/workspace/query/workspace-query.service.d.ts +6 -0
- package/dist/src/backend/domains/workspace/query/workspace-query.service.d.ts.map +1 -1
- package/dist/src/backend/interceptors/pr-detection.interceptor.d.ts.map +1 -1
- package/dist/src/backend/interceptors/pr-detection.interceptor.js +5 -1
- package/dist/src/backend/interceptors/pr-detection.interceptor.js.map +1 -1
- package/dist/src/backend/interceptors/pr-detection.interceptor.test.js +14 -0
- package/dist/src/backend/interceptors/pr-detection.interceptor.test.js.map +1 -1
- package/dist/src/backend/migrate.d.ts.map +1 -1
- package/dist/src/backend/migrate.js +13 -3
- package/dist/src/backend/migrate.js.map +1 -1
- package/dist/src/backend/migrate.test.js +44 -0
- package/dist/src/backend/migrate.test.js.map +1 -1
- package/dist/src/backend/orchestration/cli-health.service.d.ts +1 -0
- package/dist/src/backend/orchestration/cli-health.service.d.ts.map +1 -1
- package/dist/src/backend/orchestration/cli-health.service.js +16 -1
- package/dist/src/backend/orchestration/cli-health.service.js.map +1 -1
- package/dist/src/backend/orchestration/cli-health.service.test.js +23 -0
- package/dist/src/backend/orchestration/cli-health.service.test.js.map +1 -1
- package/dist/src/backend/orchestration/data-backup.service.d.ts.map +1 -1
- package/dist/src/backend/orchestration/data-backup.service.js +21 -1
- package/dist/src/backend/orchestration/data-backup.service.js.map +1 -1
- package/dist/src/backend/orchestration/data-backup.service.test.js +19 -9
- package/dist/src/backend/orchestration/data-backup.service.test.js.map +1 -1
- package/dist/src/backend/orchestration/event-collector.orchestrator.d.ts.map +1 -1
- package/dist/src/backend/orchestration/event-collector.orchestrator.js +63 -3
- package/dist/src/backend/orchestration/event-collector.orchestrator.js.map +1 -1
- package/dist/src/backend/orchestration/event-collector.orchestrator.test.js +49 -3
- package/dist/src/backend/orchestration/event-collector.orchestrator.test.js.map +1 -1
- package/dist/src/backend/orchestration/linear-config.helper.d.ts +9 -0
- package/dist/src/backend/orchestration/linear-config.helper.d.ts.map +1 -0
- package/dist/src/backend/orchestration/linear-config.helper.js +23 -0
- package/dist/src/backend/orchestration/linear-config.helper.js.map +1 -0
- package/dist/src/backend/orchestration/workspace-archive.orchestrator.d.ts +3 -0
- package/dist/src/backend/orchestration/workspace-archive.orchestrator.d.ts.map +1 -1
- package/dist/src/backend/orchestration/workspace-init.orchestrator.d.ts.map +1 -1
- package/dist/src/backend/orchestration/workspace-init.orchestrator.js +228 -3
- package/dist/src/backend/orchestration/workspace-init.orchestrator.js.map +1 -1
- package/dist/src/backend/prompts/ratchet-dispatch.d.ts +8 -1
- package/dist/src/backend/prompts/ratchet-dispatch.d.ts.map +1 -1
- package/dist/src/backend/prompts/ratchet-dispatch.js +20 -3
- package/dist/src/backend/prompts/ratchet-dispatch.js.map +1 -1
- package/dist/src/backend/resource_accessors/project.accessor.d.ts +7 -1
- package/dist/src/backend/resource_accessors/project.accessor.d.ts.map +1 -1
- package/dist/src/backend/resource_accessors/project.accessor.js +8 -1
- package/dist/src/backend/resource_accessors/project.accessor.js.map +1 -1
- package/dist/src/backend/resource_accessors/workspace.accessor.d.ts +4 -1
- package/dist/src/backend/resource_accessors/workspace.accessor.d.ts.map +1 -1
- package/dist/src/backend/resource_accessors/workspace.accessor.js +3 -0
- package/dist/src/backend/resource_accessors/workspace.accessor.js.map +1 -1
- package/dist/src/backend/server.d.ts.map +1 -1
- package/dist/src/backend/server.js +11 -9
- package/dist/src/backend/server.js.map +1 -1
- package/dist/src/backend/services/constants.d.ts +1 -0
- package/dist/src/backend/services/constants.d.ts.map +1 -1
- package/dist/src/backend/services/constants.js +1 -0
- package/dist/src/backend/services/constants.js.map +1 -1
- package/dist/src/backend/services/crypto.service.d.ts +10 -0
- package/dist/src/backend/services/crypto.service.d.ts.map +1 -0
- package/dist/src/backend/services/crypto.service.js +61 -0
- package/dist/src/backend/services/crypto.service.js.map +1 -0
- package/dist/src/backend/trpc/admin.trpc.d.ts +14 -4
- package/dist/src/backend/trpc/admin.trpc.d.ts.map +1 -1
- package/dist/src/backend/trpc/index.d.ts +169 -9
- package/dist/src/backend/trpc/index.d.ts.map +1 -1
- package/dist/src/backend/trpc/index.js +2 -0
- package/dist/src/backend/trpc/index.js.map +1 -1
- package/dist/src/backend/trpc/linear.trpc.d.ts +44 -0
- package/dist/src/backend/trpc/linear.trpc.d.ts.map +1 -0
- package/dist/src/backend/trpc/linear.trpc.js +69 -0
- package/dist/src/backend/trpc/linear.trpc.js.map +1 -0
- package/dist/src/backend/trpc/project.trpc.d.ts +50 -5
- package/dist/src/backend/trpc/project.trpc.d.ts.map +1 -1
- package/dist/src/backend/trpc/project.trpc.js +46 -18
- package/dist/src/backend/trpc/project.trpc.js.map +1 -1
- package/dist/src/backend/trpc/session.trpc.d.ts +13 -0
- package/dist/src/backend/trpc/session.trpc.d.ts.map +1 -1
- package/dist/src/backend/trpc/session.trpc.js +5 -1
- package/dist/src/backend/trpc/session.trpc.js.map +1 -1
- package/dist/src/backend/trpc/workspace/git.trpc.d.ts +10 -0
- package/dist/src/backend/trpc/workspace/git.trpc.d.ts.map +1 -1
- package/dist/src/backend/trpc/workspace/git.trpc.js +25 -0
- package/dist/src/backend/trpc/workspace/git.trpc.js.map +1 -1
- package/dist/src/backend/trpc/workspace/init.trpc.d.ts +3 -0
- package/dist/src/backend/trpc/workspace/init.trpc.d.ts.map +1 -1
- package/dist/src/backend/trpc/workspace/workspace-helpers.d.ts +8 -0
- package/dist/src/backend/trpc/workspace/workspace-helpers.d.ts.map +1 -1
- package/dist/src/backend/trpc/workspace.trpc.d.ts +49 -0
- package/dist/src/backend/trpc/workspace.trpc.d.ts.map +1 -1
- package/dist/src/backend/trpc/workspace.trpc.js +20 -4
- package/dist/src/backend/trpc/workspace.trpc.js.map +1 -1
- package/dist/src/cli/index.js +17 -91
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/proxy.d.ts +80 -0
- package/dist/src/cli/proxy.d.ts.map +1 -0
- package/dist/src/cli/proxy.js +1054 -0
- package/dist/src/cli/proxy.js.map +1 -0
- package/dist/src/cli/proxy.test.d.ts +2 -0
- package/dist/src/cli/proxy.test.d.ts.map +1 -0
- package/dist/src/cli/proxy.test.js +249 -0
- package/dist/src/cli/proxy.test.js.map +1 -0
- package/dist/src/cli/runtime-utils.d.ts +9 -0
- package/dist/src/cli/runtime-utils.d.ts.map +1 -0
- package/dist/src/cli/runtime-utils.js +86 -0
- package/dist/src/cli/runtime-utils.js.map +1 -0
- package/dist/src/shared/core/enums.d.ts +6 -0
- package/dist/src/shared/core/enums.d.ts.map +1 -1
- package/dist/src/shared/core/enums.js +5 -0
- package/dist/src/shared/core/enums.js.map +1 -1
- package/dist/src/shared/core/index.d.ts +1 -1
- package/dist/src/shared/core/index.d.ts.map +1 -1
- package/dist/src/shared/core/index.js +1 -1
- package/dist/src/shared/core/index.js.map +1 -1
- package/dist/src/shared/schemas/export-data.schema.d.ts +19 -1
- package/dist/src/shared/schemas/export-data.schema.d.ts.map +1 -1
- package/dist/src/shared/schemas/export-data.schema.js +8 -2
- package/dist/src/shared/schemas/export-data.schema.js.map +1 -1
- package/dist/src/shared/schemas/issue-tracker-config.schema.d.ts +35 -0
- package/dist/src/shared/schemas/issue-tracker-config.schema.d.ts.map +1 -0
- package/dist/src/shared/schemas/issue-tracker-config.schema.js +29 -0
- package/dist/src/shared/schemas/issue-tracker-config.schema.js.map +1 -0
- package/dist/tsconfig.backend.tsbuildinfo +1 -1
- package/package.json +40 -36
- package/prisma/migrations/20260217190642_add_linear_integration/migration.sql +34 -0
- package/prisma/schema.prisma +13 -0
- package/prompts/quick-actions/screenshots.md +12 -6
- package/prompts/ratchet/dispatch.md +4 -0
- package/dist/client/assets/_basePickBy-kS1IrKFQ.js +0 -1
- package/dist/client/assets/arc-CWpVTRns.js +0 -1
- package/dist/client/assets/architectureDiagram-VXUJARFQ-Dp1AYPMt.js +0 -36
- package/dist/client/assets/channel-D5BCeybW.js +0 -1
- package/dist/client/assets/chunk-QN33PNHL-DP72lCp6.js +0 -1
- package/dist/client/assets/chunk-TZMSLE5B-G3wPktxK.js +0 -1
- package/dist/client/assets/classDiagram-2ON5EDUG-BUS1JDwr.js +0 -1
- package/dist/client/assets/classDiagram-v2-WZHVMYZB-BUS1JDwr.js +0 -1
- package/dist/client/assets/clone-C5xhPZw8.js +0 -1
- package/dist/client/assets/diagram-PSM6KHXK-QA-3O0wr.js +0 -24
- package/dist/client/assets/diagram-QEK2KX5R-VZkRJLXU.js +0 -43
- package/dist/client/assets/diagram-S2PKOQOG-DwLmogjW.js +0 -24
- package/dist/client/assets/gitGraphDiagram-NY62KEGX-CK2ytvyZ.js +0 -65
- package/dist/client/assets/index-D5ywoSOH.css +0 -1
- package/dist/client/assets/infoDiagram-WHAUD3N6-DO5X8HkW.js +0 -2
- package/dist/client/assets/pieDiagram-ADFJNKIX-BVBJCvYL.js +0 -30
- package/dist/client/assets/sankeyDiagram-TZEHDZUN-GIzxIQQB.js +0 -10
- package/dist/client/assets/stateDiagram-FKZM4ZOC-ByvdYZKl.js +0 -1
- package/dist/client/assets/stateDiagram-v2-4FDKWEC3-ynQtAOKH.js +0 -1
- package/dist/client/assets/terminal-instance-xdECz0dx.js +0 -1
- package/dist/client/assets/treemap-KMMF4GRG-CVpLLzhu.js +0 -128
|
@@ -6,6 +6,25 @@ const PENDING_TURN_ID = '__pending_turn__';
|
|
|
6
6
|
const MAX_CLOSE_WATCHER_ATTACH_RETRIES = 50;
|
|
7
7
|
const DEFAULT_APPROVAL_POLICIES = ['on-failure', 'on-request', 'never'];
|
|
8
8
|
const DEFAULT_SANDBOX_MODES = ['read-only', 'workspace-write', 'danger-full-access'];
|
|
9
|
+
const SHAPE_DRIFT_DETAILS_LIMIT = 700;
|
|
10
|
+
const COMMAND_EXECUTION_SESSION_HANDOFF_LINE_PATTERN = /^process running with session id(?:\s*[:#-]?\s*[a-z0-9_-]+)?\.?$/i;
|
|
11
|
+
function toTurnItemKey(turnId, itemId) {
|
|
12
|
+
return `${turnId}:${itemId}`;
|
|
13
|
+
}
|
|
14
|
+
function toShapeDriftDetails(value) {
|
|
15
|
+
try {
|
|
16
|
+
const text = JSON.stringify(value);
|
|
17
|
+
if (typeof text !== 'string') {
|
|
18
|
+
return '[unserializable]';
|
|
19
|
+
}
|
|
20
|
+
return text.length > SHAPE_DRIFT_DETAILS_LIMIT
|
|
21
|
+
? `${text.slice(0, SHAPE_DRIFT_DETAILS_LIMIT)}...`
|
|
22
|
+
: text;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return '[unserializable]';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
9
28
|
function isNonEmptyString(value) {
|
|
10
29
|
return typeof value === 'string' && value.trim().length > 0;
|
|
11
30
|
}
|
|
@@ -107,8 +126,21 @@ function toSessionId(threadId) {
|
|
|
107
126
|
function toThreadId(sessionId) {
|
|
108
127
|
return sessionId.startsWith('sess_') ? sessionId.slice('sess_'.length) : sessionId;
|
|
109
128
|
}
|
|
110
|
-
function
|
|
111
|
-
|
|
129
|
+
function extractToolCallIdFromUnknown(value) {
|
|
130
|
+
if (!isRecord(value)) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
return asString(value.callId) ?? asString(value.call_id) ?? null;
|
|
134
|
+
}
|
|
135
|
+
function resolveToolCallId(params) {
|
|
136
|
+
return extractToolCallIdFromUnknown(params.source) ?? params.itemId;
|
|
137
|
+
}
|
|
138
|
+
function isCommandExecutionSessionHandoffOutput(output) {
|
|
139
|
+
const trimmedOutput = output.trim();
|
|
140
|
+
if (trimmedOutput.length === 0 || /[\r\n]/.test(trimmedOutput)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
return COMMAND_EXECUTION_SESSION_HANDOFF_LINE_PATTERN.test(trimmedOutput);
|
|
112
144
|
}
|
|
113
145
|
function isPlanLikeMode(mode) {
|
|
114
146
|
return /plan/i.test(mode);
|
|
@@ -123,6 +155,16 @@ const PLAN_TEXT_PREFERRED_KEYS = [
|
|
|
123
155
|
'value',
|
|
124
156
|
'message',
|
|
125
157
|
];
|
|
158
|
+
const REASONING_TEXT_MAX_DEPTH = 8;
|
|
159
|
+
const REASONING_TEXT_PREFERRED_KEYS = [
|
|
160
|
+
'summary',
|
|
161
|
+
'summaryText',
|
|
162
|
+
'text',
|
|
163
|
+
'delta',
|
|
164
|
+
'message',
|
|
165
|
+
'content',
|
|
166
|
+
'reasoning',
|
|
167
|
+
];
|
|
126
168
|
function extractFirstPlanText(values, depth) {
|
|
127
169
|
for (const entry of values) {
|
|
128
170
|
const extracted = extractPlanTextLocal(entry, depth + 1);
|
|
@@ -155,6 +197,37 @@ function extractPlanTextLocal(value, depth = 0) {
|
|
|
155
197
|
}
|
|
156
198
|
return extractPlanTextFromRecord(value, depth);
|
|
157
199
|
}
|
|
200
|
+
function collectReasoningText(values, value, depth = 0) {
|
|
201
|
+
if (depth > REASONING_TEXT_MAX_DEPTH) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (typeof value === 'string') {
|
|
205
|
+
if (value.trim().length > 0) {
|
|
206
|
+
values.push(value);
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
if (Array.isArray(value)) {
|
|
211
|
+
for (const entry of value) {
|
|
212
|
+
collectReasoningText(values, entry, depth + 1);
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (!isRecord(value)) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
for (const key of REASONING_TEXT_PREFERRED_KEYS) {
|
|
220
|
+
collectReasoningText(values, value[key], depth + 1);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function extractReasoningTextLocal(value) {
|
|
224
|
+
const collected = [];
|
|
225
|
+
collectReasoningText(collected, value);
|
|
226
|
+
if (collected.length === 0) {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
return dedupeStrings(collected).join('\n\n');
|
|
230
|
+
}
|
|
158
231
|
function toMcpEnvRecord(envVars) {
|
|
159
232
|
const env = {};
|
|
160
233
|
for (const entry of envVars) {
|
|
@@ -293,6 +366,307 @@ function parseToolUserInputAnswersFromPermissionMeta(params) {
|
|
|
293
366
|
function asString(value) {
|
|
294
367
|
return typeof value === 'string' ? value : null;
|
|
295
368
|
}
|
|
369
|
+
function trimOptionalQuotes(token) {
|
|
370
|
+
if (token.length >= 2 && token.startsWith('"') && token.endsWith('"')) {
|
|
371
|
+
return { text: token.slice(1, -1), quote: '"' };
|
|
372
|
+
}
|
|
373
|
+
if (token.length >= 2 && token.startsWith("'") && token.endsWith("'")) {
|
|
374
|
+
return { text: token.slice(1, -1), quote: "'" };
|
|
375
|
+
}
|
|
376
|
+
return { text: token, quote: null };
|
|
377
|
+
}
|
|
378
|
+
function unescapeCommandToken(token, quote) {
|
|
379
|
+
if (quote === "'") {
|
|
380
|
+
return token.replace(/\\'/g, "'").replace(/\\\\/g, '\\');
|
|
381
|
+
}
|
|
382
|
+
return token.replace(/\\(["'\\\s|&;])/g, '$1');
|
|
383
|
+
}
|
|
384
|
+
function sanitizeCommandToken(token) {
|
|
385
|
+
const trimmed = token.trim();
|
|
386
|
+
const { text, quote } = trimOptionalQuotes(trimmed);
|
|
387
|
+
return unescapeCommandToken(text, quote).trim();
|
|
388
|
+
}
|
|
389
|
+
function tokenizeCommand(command) {
|
|
390
|
+
return (command.match(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\S+/g) ?? [])
|
|
391
|
+
.map((token) => sanitizeCommandToken(token))
|
|
392
|
+
.filter((token) => token.length > 0);
|
|
393
|
+
}
|
|
394
|
+
function commandName(token) {
|
|
395
|
+
const unix = token.split('/').at(-1) ?? token;
|
|
396
|
+
return (unix.split('\\').at(-1) ?? unix).toLowerCase();
|
|
397
|
+
}
|
|
398
|
+
function isChainSeparatorChar(char) {
|
|
399
|
+
return char === ';' || char === '\n' || char === '|' || char === '&';
|
|
400
|
+
}
|
|
401
|
+
function readChainSeparatorLength(command, index) {
|
|
402
|
+
const char = command[index];
|
|
403
|
+
if (!(char && isChainSeparatorChar(char))) {
|
|
404
|
+
return 0;
|
|
405
|
+
}
|
|
406
|
+
const next = command[index + 1];
|
|
407
|
+
if ((char === '|' || char === '&') && next === char) {
|
|
408
|
+
return 2;
|
|
409
|
+
}
|
|
410
|
+
return 1;
|
|
411
|
+
}
|
|
412
|
+
function isLikelyPathToken(token) {
|
|
413
|
+
if (!token || token.startsWith('-')) {
|
|
414
|
+
return false;
|
|
415
|
+
}
|
|
416
|
+
if (token.startsWith('./') ||
|
|
417
|
+
token.startsWith('../') ||
|
|
418
|
+
token.startsWith('/') ||
|
|
419
|
+
token.startsWith('~')) {
|
|
420
|
+
return true;
|
|
421
|
+
}
|
|
422
|
+
return (token.includes('/') ||
|
|
423
|
+
token.includes('\\') ||
|
|
424
|
+
token.endsWith('.') ||
|
|
425
|
+
/\.[a-z0-9]+$/i.test(token));
|
|
426
|
+
}
|
|
427
|
+
function normalizeLocationPath(pathToken, cwd) {
|
|
428
|
+
if (pathToken.startsWith('/')) {
|
|
429
|
+
return pathToken;
|
|
430
|
+
}
|
|
431
|
+
if (pathToken.startsWith('~')) {
|
|
432
|
+
return pathToken;
|
|
433
|
+
}
|
|
434
|
+
const base = cwd.endsWith('/') ? cwd.slice(0, -1) : cwd;
|
|
435
|
+
return `${base}/${pathToken}`;
|
|
436
|
+
}
|
|
437
|
+
const READ_COMMANDS = new Set(['cat', 'head', 'tail', 'less', 'more']);
|
|
438
|
+
const LIST_OR_FIND_COMMANDS = new Set(['ls', 'tree', 'find', 'fd']);
|
|
439
|
+
const GREP_LIKE_COMMANDS = new Set(['rg', 'ripgrep', 'grep', 'ag']);
|
|
440
|
+
const SHELL_META_COMMANDS = new Set(['cd', 'export', 'set', 'unset', 'alias', 'unalias', 'source']);
|
|
441
|
+
function pushCommandChainPart(state) {
|
|
442
|
+
const trimmed = state.current.trim();
|
|
443
|
+
if (trimmed.length > 0) {
|
|
444
|
+
state.parts.push(trimmed);
|
|
445
|
+
}
|
|
446
|
+
state.current = '';
|
|
447
|
+
}
|
|
448
|
+
function consumeEscapedCommandChar(state, char) {
|
|
449
|
+
if (!state.escaped) {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
state.current += char;
|
|
453
|
+
state.escaped = false;
|
|
454
|
+
return true;
|
|
455
|
+
}
|
|
456
|
+
function consumeEscapeInitiator(state, char) {
|
|
457
|
+
if (!(char === '\\' && state.quote !== "'")) {
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
state.current += char;
|
|
461
|
+
state.escaped = true;
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
function hasOddTrailingBackslashes(value) {
|
|
465
|
+
let count = 0;
|
|
466
|
+
for (let index = value.length - 1; index >= 0; index -= 1) {
|
|
467
|
+
if (value[index] !== '\\') {
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
count += 1;
|
|
471
|
+
}
|
|
472
|
+
return count % 2 === 1;
|
|
473
|
+
}
|
|
474
|
+
function consumeQuotedCommandChar(state, char) {
|
|
475
|
+
if (!state.quote) {
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
const escapedSingleQuote = state.quote === "'" && char === "'" && hasOddTrailingBackslashes(state.current);
|
|
479
|
+
state.current += char;
|
|
480
|
+
if (char === state.quote && !escapedSingleQuote) {
|
|
481
|
+
state.quote = null;
|
|
482
|
+
}
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
function consumeQuoteStart(state, char) {
|
|
486
|
+
if (!(char === '"' || char === "'")) {
|
|
487
|
+
return false;
|
|
488
|
+
}
|
|
489
|
+
state.quote = char;
|
|
490
|
+
state.current += char;
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
function consumeCommandChainSeparator(state, command, index) {
|
|
494
|
+
const separatorLength = readChainSeparatorLength(command, index);
|
|
495
|
+
if (separatorLength <= 0) {
|
|
496
|
+
return 0;
|
|
497
|
+
}
|
|
498
|
+
pushCommandChainPart(state);
|
|
499
|
+
return separatorLength;
|
|
500
|
+
}
|
|
501
|
+
function splitCommandChain(command) {
|
|
502
|
+
const state = {
|
|
503
|
+
parts: [],
|
|
504
|
+
current: '',
|
|
505
|
+
quote: null,
|
|
506
|
+
escaped: false,
|
|
507
|
+
};
|
|
508
|
+
for (let index = 0; index < command.length; index += 1) {
|
|
509
|
+
const char = command[index];
|
|
510
|
+
if (!char) {
|
|
511
|
+
continue;
|
|
512
|
+
}
|
|
513
|
+
if (consumeEscapedCommandChar(state, char)) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (consumeEscapeInitiator(state, char)) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
if (consumeQuotedCommandChar(state, char)) {
|
|
520
|
+
continue;
|
|
521
|
+
}
|
|
522
|
+
if (consumeQuoteStart(state, char)) {
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const consumedSeparatorLength = consumeCommandChainSeparator(state, command, index);
|
|
526
|
+
if (consumedSeparatorLength > 0) {
|
|
527
|
+
index += consumedSeparatorLength - 1;
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
state.current += char;
|
|
531
|
+
}
|
|
532
|
+
pushCommandChainPart(state);
|
|
533
|
+
return state.parts;
|
|
534
|
+
}
|
|
535
|
+
function buildCommandDisplayContexts(rawCommand, cwd) {
|
|
536
|
+
const command = rawCommand?.trim();
|
|
537
|
+
if (!command) {
|
|
538
|
+
return [];
|
|
539
|
+
}
|
|
540
|
+
const contexts = [];
|
|
541
|
+
const segments = splitCommandChain(command);
|
|
542
|
+
for (const segment of segments) {
|
|
543
|
+
const tokens = tokenizeCommand(segment);
|
|
544
|
+
if (tokens.length === 0) {
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
const [firstToken] = tokens;
|
|
548
|
+
if (!firstToken) {
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
const firstCommand = commandName(firstToken);
|
|
552
|
+
const nonFlagArgs = tokens.slice(1).filter((token) => !token.startsWith('-'));
|
|
553
|
+
const pathArg = nonFlagArgs.find(isLikelyPathToken) ?? null;
|
|
554
|
+
const commandPath = pathArg ? normalizeLocationPath(pathArg, cwd) : null;
|
|
555
|
+
const locations = commandPath ? [{ path: commandPath }] : [];
|
|
556
|
+
contexts.push({
|
|
557
|
+
command: segment,
|
|
558
|
+
firstCommand,
|
|
559
|
+
nonFlagArgs,
|
|
560
|
+
pathArg,
|
|
561
|
+
cwd,
|
|
562
|
+
locations,
|
|
563
|
+
isShellMeta: SHELL_META_COMMANDS.has(firstCommand),
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
return contexts;
|
|
567
|
+
}
|
|
568
|
+
function chooseActionableCommandContexts(contexts) {
|
|
569
|
+
const actionable = contexts.filter((context) => !context.isShellMeta);
|
|
570
|
+
return actionable.length > 0 ? actionable : contexts;
|
|
571
|
+
}
|
|
572
|
+
function selectCombinedCommandKind(displays) {
|
|
573
|
+
const firstNonExecute = displays.find((display) => display.kind !== 'execute');
|
|
574
|
+
return firstNonExecute?.kind ?? 'execute';
|
|
575
|
+
}
|
|
576
|
+
function resolveCommandDisplay(params) {
|
|
577
|
+
const contexts = chooseActionableCommandContexts(buildCommandDisplayContexts(params.command, params.cwd));
|
|
578
|
+
if (contexts.length === 0) {
|
|
579
|
+
return { title: 'commandExecution', kind: 'execute', locations: [] };
|
|
580
|
+
}
|
|
581
|
+
const [singleContext] = contexts;
|
|
582
|
+
if (singleContext && contexts.length === 1) {
|
|
583
|
+
return resolveCommandDisplayFromContext(singleContext);
|
|
584
|
+
}
|
|
585
|
+
const displays = contexts.map((context) => resolveCommandDisplayFromContext(context));
|
|
586
|
+
const title = dedupeStrings(displays.map((display) => display.title)).join(', ');
|
|
587
|
+
const kind = selectCombinedCommandKind(displays);
|
|
588
|
+
const locations = dedupeLocations(displays.flatMap((display) => display.locations)).map((location) => ({ path: location.path }));
|
|
589
|
+
return { title, kind, locations };
|
|
590
|
+
}
|
|
591
|
+
function resolveCommandDisplayFromContext(context) {
|
|
592
|
+
if (READ_COMMANDS.has(context.firstCommand)) {
|
|
593
|
+
const label = context.pathArg ?? context.command;
|
|
594
|
+
return { title: `Read ${label}`, kind: 'read', locations: context.locations };
|
|
595
|
+
}
|
|
596
|
+
if (LIST_OR_FIND_COMMANDS.has(context.firstCommand)) {
|
|
597
|
+
const target = context.pathArg
|
|
598
|
+
? normalizeLocationPath(context.pathArg, context.cwd)
|
|
599
|
+
: context.cwd;
|
|
600
|
+
const title = context.firstCommand === 'find' || context.firstCommand === 'fd'
|
|
601
|
+
? `Search ${target}`
|
|
602
|
+
: `List ${target}`;
|
|
603
|
+
return { title, kind: 'search', locations: context.locations };
|
|
604
|
+
}
|
|
605
|
+
if (GREP_LIKE_COMMANDS.has(context.firstCommand)) {
|
|
606
|
+
const query = context.nonFlagArgs.find((token) => !isLikelyPathToken(token));
|
|
607
|
+
const target = context.pathArg ? ` in ${context.pathArg}` : '';
|
|
608
|
+
const title = query ? `Search ${query}${target}` : `Search ${context.command}`;
|
|
609
|
+
return { title, kind: 'search', locations: context.locations };
|
|
610
|
+
}
|
|
611
|
+
return { title: context.command, kind: 'execute', locations: context.locations };
|
|
612
|
+
}
|
|
613
|
+
function normalizeCwdForScope(cwd) {
|
|
614
|
+
if (cwd.length > 1 && cwd.endsWith('/')) {
|
|
615
|
+
return cwd.slice(0, -1);
|
|
616
|
+
}
|
|
617
|
+
return cwd;
|
|
618
|
+
}
|
|
619
|
+
function normalizeScopeToken(token) {
|
|
620
|
+
return token.replace(/\s+/g, ' ').trim();
|
|
621
|
+
}
|
|
622
|
+
function buildCommandApprovalScopeKey(params) {
|
|
623
|
+
const contexts = buildCommandDisplayContexts(params.command, params.cwd);
|
|
624
|
+
if (contexts.length === 0) {
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
let scopeCwd = normalizeCwdForScope(params.cwd);
|
|
628
|
+
const segments = [];
|
|
629
|
+
for (const context of contexts) {
|
|
630
|
+
if (context.firstCommand === 'cd') {
|
|
631
|
+
const rawTarget = context.nonFlagArgs[0];
|
|
632
|
+
const target = rawTarget ? normalizeScopeToken(rawTarget) : '';
|
|
633
|
+
if (target.length > 0) {
|
|
634
|
+
scopeCwd = normalizeCwdForScope(normalizeLocationPath(target, scopeCwd));
|
|
635
|
+
segments.push(`cd ${target} -> ${scopeCwd}`);
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
segments.push('cd');
|
|
639
|
+
}
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
const args = context.nonFlagArgs.map(normalizeScopeToken).filter((arg) => arg.length > 0);
|
|
643
|
+
const normalized = normalizeScopeToken([context.firstCommand, ...args].join(' '));
|
|
644
|
+
if (normalized.length === 0) {
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
segments.push(`[cwd=${scopeCwd}] ${normalized}`);
|
|
648
|
+
}
|
|
649
|
+
const normalizedSegments = segments
|
|
650
|
+
.map(normalizeScopeToken)
|
|
651
|
+
.filter((segment) => segment.length > 0);
|
|
652
|
+
if (normalizedSegments.length === 0) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
return `cwd=${normalizeCwdForScope(params.cwd)}|${normalizedSegments.join(' && ')}`;
|
|
656
|
+
}
|
|
657
|
+
function dedupeLocations(locations) {
|
|
658
|
+
const seen = new Set();
|
|
659
|
+
const result = [];
|
|
660
|
+
for (const location of locations) {
|
|
661
|
+
const key = `${location.path}:${location.line ?? ''}`;
|
|
662
|
+
if (seen.has(key)) {
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
seen.add(key);
|
|
666
|
+
result.push(location);
|
|
667
|
+
}
|
|
668
|
+
return result;
|
|
669
|
+
}
|
|
296
670
|
function parseTextFromPromptBlock(block) {
|
|
297
671
|
if (block.type === 'text') {
|
|
298
672
|
return block.text;
|
|
@@ -430,6 +804,7 @@ export class CodexAppServerAcpAdapter {
|
|
|
430
804
|
collaborationModes = [];
|
|
431
805
|
mcpServersByThreadId = new Map();
|
|
432
806
|
appliedMcpServerConfigJson = '{}';
|
|
807
|
+
shapeDriftCounts = new Map();
|
|
433
808
|
constructor(connection, codexClient) {
|
|
434
809
|
this.connection = connection;
|
|
435
810
|
this.codex =
|
|
@@ -542,10 +917,14 @@ export class CodexAppServerAcpAdapter {
|
|
|
542
917
|
},
|
|
543
918
|
activeTurn: null,
|
|
544
919
|
toolCallsByItemId: new Map(),
|
|
920
|
+
syntheticallyCompletedToolItemIds: new Set(),
|
|
921
|
+
reasoningDeltaItemIds: new Set(),
|
|
545
922
|
planTextByItemId: new Map(),
|
|
546
923
|
planApprovalRequestedByTurnId: new Set(),
|
|
547
924
|
pendingPlanApprovalsByTurnId: new Map(),
|
|
548
925
|
pendingTurnCompletionsByTurnId: new Map(),
|
|
926
|
+
commandApprovalScopes: new Set(),
|
|
927
|
+
replayedTurnItemKeys: new Set(),
|
|
549
928
|
};
|
|
550
929
|
this.sessions.set(sessionId, session);
|
|
551
930
|
this.sessionIdByThreadId.set(session.threadId, sessionId);
|
|
@@ -587,10 +966,14 @@ export class CodexAppServerAcpAdapter {
|
|
|
587
966
|
},
|
|
588
967
|
activeTurn: null,
|
|
589
968
|
toolCallsByItemId: new Map(),
|
|
969
|
+
syntheticallyCompletedToolItemIds: new Set(),
|
|
970
|
+
reasoningDeltaItemIds: new Set(),
|
|
590
971
|
planTextByItemId: new Map(),
|
|
591
972
|
planApprovalRequestedByTurnId: new Set(),
|
|
592
973
|
pendingPlanApprovalsByTurnId: new Map(),
|
|
593
974
|
pendingTurnCompletionsByTurnId: new Map(),
|
|
975
|
+
commandApprovalScopes: new Set(),
|
|
976
|
+
replayedTurnItemKeys: new Set(),
|
|
594
977
|
};
|
|
595
978
|
this.sessions.set(session.sessionId, session);
|
|
596
979
|
this.sessionIdByThreadId.set(session.threadId, session.sessionId);
|
|
@@ -1202,8 +1585,27 @@ export class CodexAppServerAcpAdapter {
|
|
|
1202
1585
|
});
|
|
1203
1586
|
}
|
|
1204
1587
|
async replayToolLikeHistoryItem(session, sessionId, turnId, item) {
|
|
1588
|
+
if (item.type === 'reasoning') {
|
|
1589
|
+
await this.emitSessionUpdate(sessionId, {
|
|
1590
|
+
sessionUpdate: 'tool_call',
|
|
1591
|
+
toolCallId: resolveToolCallId({ itemId: item.id, source: item }),
|
|
1592
|
+
title: 'reasoning',
|
|
1593
|
+
kind: 'think',
|
|
1594
|
+
status: 'completed',
|
|
1595
|
+
rawInput: item,
|
|
1596
|
+
rawOutput: item,
|
|
1597
|
+
});
|
|
1598
|
+
await this.emitReasoningThoughtChunkFromItem(sessionId, item);
|
|
1599
|
+
session.replayedTurnItemKeys.add(toTurnItemKey(turnId, item.id));
|
|
1600
|
+
return;
|
|
1601
|
+
}
|
|
1205
1602
|
const toolInfo = this.buildToolCallState(session, item, turnId);
|
|
1206
1603
|
if (!toolInfo) {
|
|
1604
|
+
this.reportShapeDrift('unhandled_replay_item', {
|
|
1605
|
+
turnId,
|
|
1606
|
+
itemType: item.type,
|
|
1607
|
+
itemId: item.id,
|
|
1608
|
+
});
|
|
1207
1609
|
return;
|
|
1208
1610
|
}
|
|
1209
1611
|
await this.emitSessionUpdate(sessionId, {
|
|
@@ -1215,11 +1617,15 @@ export class CodexAppServerAcpAdapter {
|
|
|
1215
1617
|
rawInput: item,
|
|
1216
1618
|
rawOutput: item,
|
|
1217
1619
|
});
|
|
1620
|
+
session.replayedTurnItemKeys.add(toTurnItemKey(turnId, item.id));
|
|
1218
1621
|
}
|
|
1219
1622
|
async handleCodexNotification(method, params) {
|
|
1220
1623
|
const parsed = knownCodexNotificationSchema.safeParse({ method, params });
|
|
1221
1624
|
if (!parsed.success) {
|
|
1222
|
-
|
|
1625
|
+
this.reportShapeDrift('malformed_notification', {
|
|
1626
|
+
method,
|
|
1627
|
+
issues: parsed.error.issues.slice(0, 3).map((issue) => issue.message),
|
|
1628
|
+
});
|
|
1223
1629
|
return;
|
|
1224
1630
|
}
|
|
1225
1631
|
const notification = parsed.data;
|
|
@@ -1248,16 +1654,20 @@ export class CodexAppServerAcpAdapter {
|
|
|
1248
1654
|
await this.handlePlanDelta(sessionId, session, notification.params.itemId, notification.params.delta);
|
|
1249
1655
|
return;
|
|
1250
1656
|
}
|
|
1657
|
+
if (notification.method === 'item/reasoning/summaryTextDelta') {
|
|
1658
|
+
await this.emitReasoningThoughtDelta(sessionId, session, notification.params.turnId, notification.params.itemId, notification.params.delta);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1251
1661
|
if (notification.method === 'item/commandExecution/outputDelta') {
|
|
1252
|
-
await this.emitToolCallProgress(sessionId, session, notification.params.itemId, notification.params.delta);
|
|
1662
|
+
await this.emitToolCallProgress(sessionId, session, notification.params.turnId, notification.params.itemId, notification.params.delta, 'commandExecution');
|
|
1253
1663
|
return;
|
|
1254
1664
|
}
|
|
1255
1665
|
if (notification.method === 'item/fileChange/outputDelta') {
|
|
1256
|
-
await this.emitToolCallProgress(sessionId, session, notification.params.itemId, notification.params.delta);
|
|
1666
|
+
await this.emitToolCallProgress(sessionId, session, notification.params.turnId, notification.params.itemId, notification.params.delta, 'fileChange');
|
|
1257
1667
|
return;
|
|
1258
1668
|
}
|
|
1259
1669
|
if (notification.method === 'item/mcpToolCall/progress') {
|
|
1260
|
-
await this.emitToolCallProgress(sessionId, session, notification.params.itemId, notification.params.message);
|
|
1670
|
+
await this.emitToolCallProgress(sessionId, session, notification.params.turnId, notification.params.itemId, notification.params.message, 'mcpToolCall');
|
|
1261
1671
|
return;
|
|
1262
1672
|
}
|
|
1263
1673
|
if (notification.method === 'item/started') {
|
|
@@ -1287,15 +1697,92 @@ export class CodexAppServerAcpAdapter {
|
|
|
1287
1697
|
],
|
|
1288
1698
|
});
|
|
1289
1699
|
}
|
|
1290
|
-
async
|
|
1700
|
+
async emitReasoningThoughtChunkFromItem(sessionId, item) {
|
|
1701
|
+
const text = extractReasoningTextLocal(item);
|
|
1702
|
+
if (!text) {
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
await this.emitSessionUpdate(sessionId, {
|
|
1706
|
+
sessionUpdate: 'agent_thought_chunk',
|
|
1707
|
+
content: { type: 'text', text },
|
|
1708
|
+
});
|
|
1709
|
+
}
|
|
1710
|
+
isReplayedTurnItem(session, turnId, itemId) {
|
|
1711
|
+
return session.replayedTurnItemKeys.has(toTurnItemKey(turnId, itemId));
|
|
1712
|
+
}
|
|
1713
|
+
async emitReasoningThoughtDelta(sessionId, session, turnId, itemId, delta) {
|
|
1714
|
+
if (this.isReplayedTurnItem(session, turnId, itemId)) {
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
if (delta.length === 0) {
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
const existing = session.toolCallsByItemId.get(itemId);
|
|
1721
|
+
if (!existing) {
|
|
1722
|
+
const toolCallId = resolveToolCallId({
|
|
1723
|
+
itemId,
|
|
1724
|
+
});
|
|
1725
|
+
session.toolCallsByItemId.set(itemId, {
|
|
1726
|
+
toolCallId,
|
|
1727
|
+
title: 'reasoning',
|
|
1728
|
+
kind: 'think',
|
|
1729
|
+
locations: [],
|
|
1730
|
+
});
|
|
1731
|
+
await this.emitSessionUpdate(sessionId, {
|
|
1732
|
+
sessionUpdate: 'tool_call',
|
|
1733
|
+
toolCallId,
|
|
1734
|
+
title: 'reasoning',
|
|
1735
|
+
kind: 'think',
|
|
1736
|
+
status: 'pending',
|
|
1737
|
+
rawInput: {
|
|
1738
|
+
type: 'reasoning',
|
|
1739
|
+
id: itemId,
|
|
1740
|
+
},
|
|
1741
|
+
});
|
|
1742
|
+
await this.emitSessionUpdate(sessionId, {
|
|
1743
|
+
sessionUpdate: 'tool_call_update',
|
|
1744
|
+
toolCallId,
|
|
1745
|
+
title: 'reasoning',
|
|
1746
|
+
kind: 'think',
|
|
1747
|
+
status: 'in_progress',
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
session.reasoningDeltaItemIds.add(itemId);
|
|
1751
|
+
await this.emitSessionUpdate(sessionId, {
|
|
1752
|
+
sessionUpdate: 'agent_thought_chunk',
|
|
1753
|
+
content: { type: 'text', text: delta },
|
|
1754
|
+
});
|
|
1755
|
+
}
|
|
1756
|
+
async emitToolCallProgress(sessionId, session, turnId, itemId, output, source) {
|
|
1757
|
+
if (this.isReplayedTurnItem(session, turnId, itemId)) {
|
|
1758
|
+
return;
|
|
1759
|
+
}
|
|
1291
1760
|
const toolCall = session.toolCallsByItemId.get(itemId);
|
|
1292
1761
|
if (!toolCall) {
|
|
1762
|
+
this.reportShapeDrift('tool_progress_without_tool_call', { turnId, itemId });
|
|
1763
|
+
return;
|
|
1764
|
+
}
|
|
1765
|
+
if (session.syntheticallyCompletedToolItemIds.has(itemId)) {
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
if (source === 'commandExecution' && isCommandExecutionSessionHandoffOutput(output)) {
|
|
1769
|
+
session.syntheticallyCompletedToolItemIds.add(itemId);
|
|
1770
|
+
await this.emitSessionUpdate(sessionId, {
|
|
1771
|
+
sessionUpdate: 'tool_call_update',
|
|
1772
|
+
toolCallId: toolCall.toolCallId,
|
|
1773
|
+
status: 'completed',
|
|
1774
|
+
kind: toolCall.kind,
|
|
1775
|
+
title: toolCall.title,
|
|
1776
|
+
...(toolCall.locations.length > 0 ? { locations: toolCall.locations } : {}),
|
|
1777
|
+
rawOutput: output,
|
|
1778
|
+
});
|
|
1293
1779
|
return;
|
|
1294
1780
|
}
|
|
1295
1781
|
await this.emitSessionUpdate(sessionId, {
|
|
1296
1782
|
sessionUpdate: 'tool_call_update',
|
|
1297
1783
|
toolCallId: toolCall.toolCallId,
|
|
1298
1784
|
status: 'in_progress',
|
|
1785
|
+
...(toolCall.locations.length > 0 ? { locations: toolCall.locations } : {}),
|
|
1299
1786
|
rawOutput: output,
|
|
1300
1787
|
});
|
|
1301
1788
|
}
|
|
@@ -1338,10 +1825,52 @@ export class CodexAppServerAcpAdapter {
|
|
|
1338
1825
|
this.settleTurn(session, session.activeTurn?.cancelRequested ? 'cancelled' : 'end_turn');
|
|
1339
1826
|
}
|
|
1340
1827
|
async handleItemStarted(session, item, turnId) {
|
|
1828
|
+
if (this.isReplayedTurnItem(session, turnId, item.id)) {
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
if (item.type === 'reasoning') {
|
|
1832
|
+
const existing = session.toolCallsByItemId.get(item.id);
|
|
1833
|
+
const toolInfo = existing ??
|
|
1834
|
+
{
|
|
1835
|
+
toolCallId: resolveToolCallId({
|
|
1836
|
+
itemId: item.id,
|
|
1837
|
+
source: item,
|
|
1838
|
+
}),
|
|
1839
|
+
title: 'reasoning',
|
|
1840
|
+
kind: 'think',
|
|
1841
|
+
locations: [],
|
|
1842
|
+
};
|
|
1843
|
+
if (!existing) {
|
|
1844
|
+
session.syntheticallyCompletedToolItemIds.delete(item.id);
|
|
1845
|
+
session.toolCallsByItemId.set(item.id, toolInfo);
|
|
1846
|
+
await this.emitSessionUpdate(session.sessionId, {
|
|
1847
|
+
sessionUpdate: 'tool_call',
|
|
1848
|
+
toolCallId: toolInfo.toolCallId,
|
|
1849
|
+
title: toolInfo.title,
|
|
1850
|
+
kind: toolInfo.kind,
|
|
1851
|
+
status: 'pending',
|
|
1852
|
+
rawInput: item,
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
await this.emitSessionUpdate(session.sessionId, {
|
|
1856
|
+
sessionUpdate: 'tool_call_update',
|
|
1857
|
+
toolCallId: toolInfo.toolCallId,
|
|
1858
|
+
title: toolInfo.title,
|
|
1859
|
+
kind: toolInfo.kind,
|
|
1860
|
+
status: 'in_progress',
|
|
1861
|
+
});
|
|
1862
|
+
return;
|
|
1863
|
+
}
|
|
1341
1864
|
const toolInfo = this.buildToolCallState(session, item, turnId);
|
|
1342
1865
|
if (!toolInfo) {
|
|
1866
|
+
this.reportShapeDrift('unhandled_item_started_type', {
|
|
1867
|
+
turnId,
|
|
1868
|
+
itemType: item.type,
|
|
1869
|
+
itemId: item.id,
|
|
1870
|
+
});
|
|
1343
1871
|
return;
|
|
1344
1872
|
}
|
|
1873
|
+
session.syntheticallyCompletedToolItemIds.delete(item.id);
|
|
1345
1874
|
session.toolCallsByItemId.set(item.id, toolInfo);
|
|
1346
1875
|
await this.emitSessionUpdate(session.sessionId, {
|
|
1347
1876
|
sessionUpdate: 'tool_call',
|
|
@@ -1349,6 +1878,7 @@ export class CodexAppServerAcpAdapter {
|
|
|
1349
1878
|
title: toolInfo.title,
|
|
1350
1879
|
kind: toolInfo.kind,
|
|
1351
1880
|
status: 'pending',
|
|
1881
|
+
...(toolInfo.locations.length > 0 ? { locations: toolInfo.locations } : {}),
|
|
1352
1882
|
rawInput: item,
|
|
1353
1883
|
});
|
|
1354
1884
|
const itemStatus = toToolStatus(item.status);
|
|
@@ -1361,8 +1891,53 @@ export class CodexAppServerAcpAdapter {
|
|
|
1361
1891
|
}
|
|
1362
1892
|
}
|
|
1363
1893
|
async handleItemCompleted(session, item, turnId) {
|
|
1894
|
+
if (this.isReplayedTurnItem(session, turnId, item.id)) {
|
|
1895
|
+
return;
|
|
1896
|
+
}
|
|
1897
|
+
if (item.type === 'reasoning') {
|
|
1898
|
+
const existing = session.toolCallsByItemId.get(item.id);
|
|
1899
|
+
const reasoningToolCallId = existing?.toolCallId ??
|
|
1900
|
+
resolveToolCallId({
|
|
1901
|
+
itemId: item.id,
|
|
1902
|
+
source: item,
|
|
1903
|
+
});
|
|
1904
|
+
if (existing) {
|
|
1905
|
+
await this.emitSessionUpdate(session.sessionId, {
|
|
1906
|
+
sessionUpdate: 'tool_call_update',
|
|
1907
|
+
toolCallId: reasoningToolCallId,
|
|
1908
|
+
title: existing.title,
|
|
1909
|
+
kind: existing.kind,
|
|
1910
|
+
status: toToolStatus(item.status) ?? 'completed',
|
|
1911
|
+
rawOutput: item,
|
|
1912
|
+
});
|
|
1913
|
+
}
|
|
1914
|
+
else {
|
|
1915
|
+
await this.emitSessionUpdate(session.sessionId, {
|
|
1916
|
+
sessionUpdate: 'tool_call',
|
|
1917
|
+
toolCallId: reasoningToolCallId,
|
|
1918
|
+
title: 'reasoning',
|
|
1919
|
+
kind: 'think',
|
|
1920
|
+
status: toToolStatus(item.status) ?? 'completed',
|
|
1921
|
+
rawInput: item,
|
|
1922
|
+
rawOutput: item,
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
session.toolCallsByItemId.delete(item.id);
|
|
1926
|
+
session.syntheticallyCompletedToolItemIds.delete(item.id);
|
|
1927
|
+
const sawDelta = session.reasoningDeltaItemIds.has(item.id);
|
|
1928
|
+
session.reasoningDeltaItemIds.delete(item.id);
|
|
1929
|
+
if (!sawDelta) {
|
|
1930
|
+
await this.emitReasoningThoughtChunkFromItem(session.sessionId, item);
|
|
1931
|
+
}
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1364
1934
|
const existing = session.toolCallsByItemId.get(item.id);
|
|
1365
1935
|
if (!existing) {
|
|
1936
|
+
this.reportShapeDrift('item_completed_without_started_state', {
|
|
1937
|
+
turnId,
|
|
1938
|
+
itemType: item.type,
|
|
1939
|
+
itemId: item.id,
|
|
1940
|
+
});
|
|
1366
1941
|
return;
|
|
1367
1942
|
}
|
|
1368
1943
|
const shouldHoldTurnForPlanApproval = item.type === 'plan' &&
|
|
@@ -1374,7 +1949,8 @@ export class CodexAppServerAcpAdapter {
|
|
|
1374
1949
|
}
|
|
1375
1950
|
const statusFromItem = toToolStatus(item.status);
|
|
1376
1951
|
const status = statusFromItem ?? 'completed';
|
|
1377
|
-
const
|
|
1952
|
+
const completionLocations = this.extractLocations(item);
|
|
1953
|
+
const locations = dedupeLocations([...existing.locations, ...completionLocations]);
|
|
1378
1954
|
await this.emitSessionUpdate(session.sessionId, {
|
|
1379
1955
|
sessionUpdate: 'tool_call_update',
|
|
1380
1956
|
toolCallId: existing.toolCallId,
|
|
@@ -1385,6 +1961,7 @@ export class CodexAppServerAcpAdapter {
|
|
|
1385
1961
|
rawOutput: item,
|
|
1386
1962
|
});
|
|
1387
1963
|
session.toolCallsByItemId.delete(item.id);
|
|
1964
|
+
session.syntheticallyCompletedToolItemIds.delete(item.id);
|
|
1388
1965
|
await this.maybeRequestPlanApproval(session, item, turnId, existing);
|
|
1389
1966
|
}
|
|
1390
1967
|
buildPlanApprovalInput(planText, sourceItemId) {
|
|
@@ -1411,28 +1988,43 @@ export class CodexAppServerAcpAdapter {
|
|
|
1411
1988
|
}
|
|
1412
1989
|
return null;
|
|
1413
1990
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1991
|
+
getPlanExitModePriority(modeId) {
|
|
1992
|
+
const normalized = modeId.toLowerCase();
|
|
1993
|
+
const index = PLAN_EXIT_MODE_PREFERENCE.findIndex((preferred) => preferred.toLowerCase() === normalized);
|
|
1994
|
+
return index >= 0 ? index : PLAN_EXIT_MODE_PREFERENCE.length;
|
|
1995
|
+
}
|
|
1996
|
+
comparePlanExitModePreference(left, right) {
|
|
1997
|
+
const priorityDiff = this.getPlanExitModePriority(left) - this.getPlanExitModePriority(right);
|
|
1998
|
+
if (priorityDiff !== 0) {
|
|
1999
|
+
return priorityDiff;
|
|
1417
2000
|
}
|
|
1418
|
-
return
|
|
2001
|
+
return left.localeCompare(right);
|
|
1419
2002
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
2003
|
+
resolveCollaborationModeLabel(modeId) {
|
|
2004
|
+
const entry = this.collaborationModes.find((candidate) => candidate.mode === modeId);
|
|
2005
|
+
if (entry?.name) {
|
|
2006
|
+
return entry.name;
|
|
1423
2007
|
}
|
|
2008
|
+
return sanitizeModeName(modeId);
|
|
2009
|
+
}
|
|
2010
|
+
buildPlanApprovalOptions(session) {
|
|
2011
|
+
const currentMode = session.defaults.collaborationMode;
|
|
1424
2012
|
const availableModes = this.getCollaborationModeValues(currentMode);
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
2013
|
+
const nonPlanModes = availableModes
|
|
2014
|
+
.filter((modeId) => !isPlanLikeMode(modeId))
|
|
2015
|
+
.sort((left, right) => this.comparePlanExitModePreference(left, right));
|
|
2016
|
+
const approvableModeIds = new Set(nonPlanModes);
|
|
2017
|
+
const options = nonPlanModes.map((modeId) => ({
|
|
2018
|
+
optionId: modeId,
|
|
2019
|
+
name: `Approve and switch to ${this.resolveCollaborationModeLabel(modeId)}`,
|
|
2020
|
+
kind: 'allow_once',
|
|
2021
|
+
}));
|
|
2022
|
+
options.push({
|
|
2023
|
+
optionId: currentMode,
|
|
2024
|
+
name: 'Keep planning',
|
|
2025
|
+
kind: 'reject_once',
|
|
2026
|
+
});
|
|
2027
|
+
return { options, approvableModeIds };
|
|
1436
2028
|
}
|
|
1437
2029
|
holdTurnUntilPlanApprovalResolves(session, turnId) {
|
|
1438
2030
|
if (this.hasPendingPlanApprovals(session, turnId)) {
|
|
@@ -1494,6 +2086,18 @@ export class CodexAppServerAcpAdapter {
|
|
|
1494
2086
|
rawInput: approvalInput,
|
|
1495
2087
|
});
|
|
1496
2088
|
try {
|
|
2089
|
+
const { options: planApprovalOptions, approvableModeIds } = this.buildPlanApprovalOptions(session);
|
|
2090
|
+
if (approvableModeIds.size === 0) {
|
|
2091
|
+
await this.emitSessionUpdate(session.sessionId, {
|
|
2092
|
+
sessionUpdate: 'tool_call_update',
|
|
2093
|
+
toolCallId: approvalToolCallId,
|
|
2094
|
+
kind: 'switch_mode',
|
|
2095
|
+
title: 'ExitPlanMode',
|
|
2096
|
+
status: 'failed',
|
|
2097
|
+
rawOutput: 'Plan proposed, but no non-plan collaboration mode is available.',
|
|
2098
|
+
});
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
1497
2101
|
const permissionResult = await this.connection.requestPermission({
|
|
1498
2102
|
sessionId: session.sessionId,
|
|
1499
2103
|
toolCall: {
|
|
@@ -1503,30 +2107,19 @@ export class CodexAppServerAcpAdapter {
|
|
|
1503
2107
|
status: 'pending',
|
|
1504
2108
|
rawInput: approvalInput,
|
|
1505
2109
|
},
|
|
1506
|
-
options:
|
|
1507
|
-
{
|
|
1508
|
-
optionId: 'allow_once',
|
|
1509
|
-
name: 'Approve plan',
|
|
1510
|
-
kind: 'allow_once',
|
|
1511
|
-
},
|
|
1512
|
-
{
|
|
1513
|
-
optionId: 'reject_once',
|
|
1514
|
-
name: 'Request changes',
|
|
1515
|
-
kind: 'reject_once',
|
|
1516
|
-
},
|
|
1517
|
-
],
|
|
2110
|
+
options: planApprovalOptions,
|
|
1518
2111
|
});
|
|
1519
|
-
const
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
}
|
|
2112
|
+
const selectedMode = permissionResult.outcome.outcome === 'selected' &&
|
|
2113
|
+
approvableModeIds.has(permissionResult.outcome.optionId)
|
|
2114
|
+
? permissionResult.outcome.optionId
|
|
2115
|
+
: null;
|
|
2116
|
+
const approved = selectedMode !== null;
|
|
2117
|
+
if (selectedMode && session.defaults.collaborationMode !== selectedMode) {
|
|
2118
|
+
session.defaults.collaborationMode = selectedMode;
|
|
2119
|
+
await this.emitSessionUpdate(session.sessionId, {
|
|
2120
|
+
sessionUpdate: 'config_option_update',
|
|
2121
|
+
configOptions: this.buildConfigOptions(session),
|
|
2122
|
+
});
|
|
1530
2123
|
}
|
|
1531
2124
|
await this.emitSessionUpdate(session.sessionId, {
|
|
1532
2125
|
sessionUpdate: 'tool_call_update',
|
|
@@ -1573,26 +2166,32 @@ export class CodexAppServerAcpAdapter {
|
|
|
1573
2166
|
}
|
|
1574
2167
|
return locations;
|
|
1575
2168
|
}
|
|
1576
|
-
buildToolCallState(session, item,
|
|
2169
|
+
buildToolCallState(session, item, _turnId) {
|
|
1577
2170
|
const kindByType = {
|
|
1578
2171
|
commandExecution: 'execute',
|
|
1579
2172
|
fileChange: 'edit',
|
|
1580
2173
|
mcpToolCall: 'fetch',
|
|
1581
2174
|
webSearch: 'search',
|
|
1582
2175
|
plan: 'think',
|
|
1583
|
-
reasoning: 'think',
|
|
1584
2176
|
};
|
|
1585
2177
|
const kind = kindByType[item.type];
|
|
1586
2178
|
if (!kind) {
|
|
1587
2179
|
return null;
|
|
1588
2180
|
}
|
|
1589
2181
|
let title = item.type;
|
|
2182
|
+
let kindToEmit = kind;
|
|
2183
|
+
let locations = [];
|
|
1590
2184
|
if (item.type === 'commandExecution') {
|
|
1591
2185
|
const command = asString(item.command);
|
|
1592
|
-
|
|
2186
|
+
const cwd = asString(item.cwd) ?? session.cwd;
|
|
2187
|
+
const parsed = resolveCommandDisplay({ command, cwd });
|
|
2188
|
+
title = parsed.title;
|
|
2189
|
+
kindToEmit = parsed.kind;
|
|
2190
|
+
locations = parsed.locations;
|
|
1593
2191
|
}
|
|
1594
2192
|
else if (item.type === 'fileChange') {
|
|
1595
2193
|
title = 'fileChange';
|
|
2194
|
+
locations = this.extractLocations(item);
|
|
1596
2195
|
}
|
|
1597
2196
|
else if (item.type === 'mcpToolCall') {
|
|
1598
2197
|
const server = asString(item.server) ?? 'mcp';
|
|
@@ -1604,15 +2203,81 @@ export class CodexAppServerAcpAdapter {
|
|
|
1604
2203
|
title = query ? `webSearch:${query}` : 'webSearch';
|
|
1605
2204
|
}
|
|
1606
2205
|
return {
|
|
1607
|
-
toolCallId:
|
|
1608
|
-
|
|
2206
|
+
toolCallId: resolveToolCallId({
|
|
2207
|
+
itemId: item.id,
|
|
2208
|
+
source: item,
|
|
2209
|
+
}),
|
|
2210
|
+
kind: kindToEmit,
|
|
1609
2211
|
title,
|
|
2212
|
+
locations,
|
|
1610
2213
|
};
|
|
1611
2214
|
}
|
|
2215
|
+
buildPermissionOptions(params) {
|
|
2216
|
+
if (params.method === 'item/tool/requestUserInput') {
|
|
2217
|
+
return buildToolUserInputPermissionOptions(params.questions);
|
|
2218
|
+
}
|
|
2219
|
+
if (params.method === 'item/commandExecution/requestApproval') {
|
|
2220
|
+
return [
|
|
2221
|
+
{
|
|
2222
|
+
optionId: 'allow_always',
|
|
2223
|
+
name: 'Allow for session',
|
|
2224
|
+
kind: 'allow_always',
|
|
2225
|
+
},
|
|
2226
|
+
{
|
|
2227
|
+
optionId: 'allow_once',
|
|
2228
|
+
name: 'Allow once',
|
|
2229
|
+
kind: 'allow_once',
|
|
2230
|
+
},
|
|
2231
|
+
{
|
|
2232
|
+
optionId: 'reject_once',
|
|
2233
|
+
name: 'Reject',
|
|
2234
|
+
kind: 'reject_once',
|
|
2235
|
+
},
|
|
2236
|
+
];
|
|
2237
|
+
}
|
|
2238
|
+
return [
|
|
2239
|
+
{
|
|
2240
|
+
optionId: 'allow_once',
|
|
2241
|
+
name: 'Allow once',
|
|
2242
|
+
kind: 'allow_once',
|
|
2243
|
+
},
|
|
2244
|
+
{
|
|
2245
|
+
optionId: 'reject_once',
|
|
2246
|
+
name: 'Reject',
|
|
2247
|
+
kind: 'reject_once',
|
|
2248
|
+
},
|
|
2249
|
+
];
|
|
2250
|
+
}
|
|
2251
|
+
async maybeAutoApproveCommandRequest(params) {
|
|
2252
|
+
if (params.request.method !== 'item/commandExecution/requestApproval') {
|
|
2253
|
+
return false;
|
|
2254
|
+
}
|
|
2255
|
+
const scopeKey = buildCommandApprovalScopeKey({
|
|
2256
|
+
command: asString(params.request.params.command),
|
|
2257
|
+
cwd: asString(params.request.params.cwd) ?? params.session.cwd,
|
|
2258
|
+
});
|
|
2259
|
+
if (!(scopeKey && params.session.commandApprovalScopes.has(scopeKey))) {
|
|
2260
|
+
return false;
|
|
2261
|
+
}
|
|
2262
|
+
await this.respondToCodexPermissionRequest({
|
|
2263
|
+
request: params.request,
|
|
2264
|
+
permission: {
|
|
2265
|
+
outcome: { outcome: 'selected', optionId: 'allow_always' },
|
|
2266
|
+
},
|
|
2267
|
+
session: params.session,
|
|
2268
|
+
toolCallId: params.toolCallId,
|
|
2269
|
+
questions: [],
|
|
2270
|
+
});
|
|
2271
|
+
return true;
|
|
2272
|
+
}
|
|
1612
2273
|
async handleCodexServerRequest(request) {
|
|
1613
2274
|
try {
|
|
1614
2275
|
const parsed = knownCodexServerRequestSchema.safeParse(request);
|
|
1615
2276
|
if (!parsed.success) {
|
|
2277
|
+
this.reportShapeDrift('malformed_server_request', {
|
|
2278
|
+
method: request.method,
|
|
2279
|
+
issues: parsed.error.issues.slice(0, 3).map((issue) => issue.message),
|
|
2280
|
+
});
|
|
1616
2281
|
this.codex.respondError(request.id, {
|
|
1617
2282
|
code: -32_602,
|
|
1618
2283
|
message: 'Unsupported codex server request payload',
|
|
@@ -1622,6 +2287,11 @@ export class CodexAppServerAcpAdapter {
|
|
|
1622
2287
|
const typed = parsed.data;
|
|
1623
2288
|
const sessionId = this.sessionIdByThreadId.get(typed.params.threadId);
|
|
1624
2289
|
if (!sessionId) {
|
|
2290
|
+
this.reportShapeDrift('request_for_unknown_thread', {
|
|
2291
|
+
method: typed.method,
|
|
2292
|
+
threadId: typed.params.threadId,
|
|
2293
|
+
itemId: typed.params.itemId,
|
|
2294
|
+
});
|
|
1625
2295
|
this.codex.respondError(typed.id, {
|
|
1626
2296
|
code: -32_603,
|
|
1627
2297
|
message: 'No ACP session mapped for this thread',
|
|
@@ -1630,6 +2300,11 @@ export class CodexAppServerAcpAdapter {
|
|
|
1630
2300
|
}
|
|
1631
2301
|
const session = this.sessions.get(sessionId);
|
|
1632
2302
|
if (!session) {
|
|
2303
|
+
this.reportShapeDrift('request_for_missing_session', {
|
|
2304
|
+
method: typed.method,
|
|
2305
|
+
sessionId,
|
|
2306
|
+
itemId: typed.params.itemId,
|
|
2307
|
+
});
|
|
1633
2308
|
this.codex.respondError(typed.id, {
|
|
1634
2309
|
code: -32_603,
|
|
1635
2310
|
message: 'No ACP session mapped for this thread',
|
|
@@ -1647,24 +2322,30 @@ export class CodexAppServerAcpAdapter {
|
|
|
1647
2322
|
title: toolCall.title,
|
|
1648
2323
|
kind: toolCall.kind,
|
|
1649
2324
|
status: 'pending',
|
|
2325
|
+
...(toolCall.locations.length > 0 ? { locations: toolCall.locations } : {}),
|
|
1650
2326
|
rawInput: typed.params,
|
|
1651
2327
|
});
|
|
1652
2328
|
}
|
|
2329
|
+
if (await this.maybeAutoApproveCommandRequest({
|
|
2330
|
+
request: typed,
|
|
2331
|
+
session,
|
|
2332
|
+
toolCallId: toolCall.toolCallId,
|
|
2333
|
+
})) {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
1653
2336
|
const questions = typed.method === 'item/tool/requestUserInput' ? typed.params.questions : [];
|
|
1654
|
-
const permissionOptions =
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
},
|
|
1667
|
-
];
|
|
2337
|
+
const permissionOptions = this.buildPermissionOptions({
|
|
2338
|
+
method: typed.method,
|
|
2339
|
+
questions,
|
|
2340
|
+
});
|
|
2341
|
+
await this.emitSessionUpdate(sessionId, {
|
|
2342
|
+
sessionUpdate: 'tool_call_update',
|
|
2343
|
+
toolCallId: toolCall.toolCallId,
|
|
2344
|
+
title: toolCall.title,
|
|
2345
|
+
kind: toolCall.kind,
|
|
2346
|
+
status: 'pending',
|
|
2347
|
+
...(toolCall.locations.length > 0 ? { locations: toolCall.locations } : {}),
|
|
2348
|
+
});
|
|
1668
2349
|
const permissionResult = await this.connection.requestPermission({
|
|
1669
2350
|
sessionId,
|
|
1670
2351
|
toolCall: {
|
|
@@ -1693,67 +2374,110 @@ export class CodexAppServerAcpAdapter {
|
|
|
1693
2374
|
});
|
|
1694
2375
|
}
|
|
1695
2376
|
}
|
|
1696
|
-
buildApprovalToolCallState(session, method, itemId,
|
|
2377
|
+
buildApprovalToolCallState(session, method, itemId, _turnId, params) {
|
|
1697
2378
|
if (method === 'item/commandExecution/requestApproval') {
|
|
1698
2379
|
const command = asString(params.command);
|
|
2380
|
+
const cwd = asString(params.cwd) ?? session.cwd;
|
|
2381
|
+
const parsed = resolveCommandDisplay({ command, cwd });
|
|
1699
2382
|
return {
|
|
1700
|
-
toolCallId:
|
|
1701
|
-
|
|
1702
|
-
|
|
2383
|
+
toolCallId: resolveToolCallId({
|
|
2384
|
+
itemId,
|
|
2385
|
+
source: params,
|
|
2386
|
+
}),
|
|
2387
|
+
title: parsed.title,
|
|
2388
|
+
kind: parsed.kind,
|
|
2389
|
+
locations: parsed.locations,
|
|
1703
2390
|
};
|
|
1704
2391
|
}
|
|
1705
2392
|
if (method === 'item/fileChange/requestApproval') {
|
|
2393
|
+
const grantRoot = asString(params.grantRoot);
|
|
1706
2394
|
return {
|
|
1707
|
-
toolCallId:
|
|
2395
|
+
toolCallId: resolveToolCallId({
|
|
2396
|
+
itemId,
|
|
2397
|
+
source: params,
|
|
2398
|
+
}),
|
|
1708
2399
|
title: 'fileChange',
|
|
1709
2400
|
kind: 'edit',
|
|
2401
|
+
locations: grantRoot ? [{ path: grantRoot }] : [],
|
|
1710
2402
|
};
|
|
1711
2403
|
}
|
|
1712
2404
|
return {
|
|
1713
|
-
toolCallId:
|
|
2405
|
+
toolCallId: resolveToolCallId({
|
|
2406
|
+
itemId,
|
|
2407
|
+
source: params,
|
|
2408
|
+
}),
|
|
1714
2409
|
title: 'item/tool/requestUserInput',
|
|
1715
2410
|
kind: 'other',
|
|
2411
|
+
locations: [],
|
|
1716
2412
|
};
|
|
1717
2413
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
toolCallId: params.toolCallId,
|
|
1741
|
-
status: 'failed',
|
|
1742
|
-
rawOutput: { error: message },
|
|
1743
|
-
});
|
|
1744
|
-
return;
|
|
1745
|
-
}
|
|
1746
|
-
this.codex.respondSuccess(params.request.id, {
|
|
1747
|
-
answers,
|
|
2414
|
+
isAllowedPermissionSelection(selectedOptionId) {
|
|
2415
|
+
return selectedOptionId === 'allow_once' || selectedOptionId === 'allow_always';
|
|
2416
|
+
}
|
|
2417
|
+
async handleToolUserInputPermissionResponse(params) {
|
|
2418
|
+
if (params.request.method !== 'item/tool/requestUserInput') {
|
|
2419
|
+
return false;
|
|
2420
|
+
}
|
|
2421
|
+
const rejected = params.selectedOptionId === null || params.selectedOptionId === 'reject_once';
|
|
2422
|
+
let answers;
|
|
2423
|
+
try {
|
|
2424
|
+
answers = buildToolUserInputAnswers({
|
|
2425
|
+
questions: params.questions,
|
|
2426
|
+
permission: params.permission,
|
|
2427
|
+
selectedOptionId: params.selectedOptionId,
|
|
2428
|
+
});
|
|
2429
|
+
}
|
|
2430
|
+
catch (error) {
|
|
2431
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2432
|
+
this.codex.respondError(params.request.id, {
|
|
2433
|
+
code: -32_602,
|
|
2434
|
+
message: 'Failed to map requestUserInput answers',
|
|
2435
|
+
data: { error: message },
|
|
1748
2436
|
});
|
|
1749
2437
|
await this.emitSessionUpdate(params.session.sessionId, {
|
|
1750
2438
|
sessionUpdate: 'tool_call_update',
|
|
1751
2439
|
toolCallId: params.toolCallId,
|
|
1752
|
-
status:
|
|
1753
|
-
rawOutput:
|
|
2440
|
+
status: 'failed',
|
|
2441
|
+
rawOutput: { error: message },
|
|
1754
2442
|
});
|
|
2443
|
+
return true;
|
|
2444
|
+
}
|
|
2445
|
+
this.codex.respondSuccess(params.request.id, {
|
|
2446
|
+
answers,
|
|
2447
|
+
});
|
|
2448
|
+
await this.emitSessionUpdate(params.session.sessionId, {
|
|
2449
|
+
sessionUpdate: 'tool_call_update',
|
|
2450
|
+
toolCallId: params.toolCallId,
|
|
2451
|
+
status: rejected ? 'failed' : 'completed',
|
|
2452
|
+
rawOutput: rejected ? { outcome: 'rejected' } : { answers },
|
|
2453
|
+
});
|
|
2454
|
+
return true;
|
|
2455
|
+
}
|
|
2456
|
+
async respondToCodexPermissionRequest(params) {
|
|
2457
|
+
const selected = params.permission.outcome.outcome === 'selected' ? params.permission.outcome.optionId : null;
|
|
2458
|
+
if (await this.handleToolUserInputPermissionResponse({
|
|
2459
|
+
...params,
|
|
2460
|
+
selectedOptionId: selected,
|
|
2461
|
+
})) {
|
|
1755
2462
|
return;
|
|
1756
2463
|
}
|
|
2464
|
+
if (params.request.method === 'item/commandExecution/requestApproval' &&
|
|
2465
|
+
selected === 'allow_always') {
|
|
2466
|
+
const scopeKey = buildCommandApprovalScopeKey({
|
|
2467
|
+
command: asString(params.request.params.command),
|
|
2468
|
+
cwd: asString(params.request.params.cwd) ?? params.session.cwd,
|
|
2469
|
+
});
|
|
2470
|
+
if (scopeKey) {
|
|
2471
|
+
params.session.commandApprovalScopes.add(scopeKey);
|
|
2472
|
+
}
|
|
2473
|
+
else {
|
|
2474
|
+
this.reportShapeDrift('allow_always_without_scope_key', {
|
|
2475
|
+
itemId: params.request.params.itemId,
|
|
2476
|
+
command: params.request.params.command,
|
|
2477
|
+
});
|
|
2478
|
+
}
|
|
2479
|
+
}
|
|
2480
|
+
const allow = this.isAllowedPermissionSelection(selected);
|
|
1757
2481
|
this.codex.respondSuccess(params.request.id, {
|
|
1758
2482
|
decision: allow ? 'accept' : 'decline',
|
|
1759
2483
|
});
|
|
@@ -1775,8 +2499,17 @@ export class CodexAppServerAcpAdapter {
|
|
|
1775
2499
|
session.planApprovalRequestedByTurnId.clear();
|
|
1776
2500
|
session.pendingPlanApprovalsByTurnId.clear();
|
|
1777
2501
|
session.toolCallsByItemId.clear();
|
|
2502
|
+
session.syntheticallyCompletedToolItemIds.clear();
|
|
2503
|
+
session.reasoningDeltaItemIds.clear();
|
|
1778
2504
|
session.pendingTurnCompletionsByTurnId.clear();
|
|
1779
2505
|
}
|
|
2506
|
+
reportShapeDrift(event, details) {
|
|
2507
|
+
const count = (this.shapeDriftCounts.get(event) ?? 0) + 1;
|
|
2508
|
+
this.shapeDriftCounts.set(event, count);
|
|
2509
|
+
const includeDetails = details !== undefined && (count <= 5 || count % 50 === 0);
|
|
2510
|
+
const detailsSuffix = includeDetails ? ` details=${toShapeDriftDetails(details)}` : '';
|
|
2511
|
+
process.stderr.write(`[codex-app-server-acp] shape-drift event=${event} count=${count}${detailsSuffix}\n`);
|
|
2512
|
+
}
|
|
1780
2513
|
async emitSessionUpdate(sessionId, update) {
|
|
1781
2514
|
try {
|
|
1782
2515
|
await this.connection.sessionUpdate({ sessionId, update });
|