@cloudcli-ai/cloudcli 1.37.1 → 1.37.3
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 +1 -1
- package/dist/assets/abnfDiagram-N423BO3Z-CJntskwA.js +1 -0
- package/dist/assets/arc-CIfH4uMN.js +1 -0
- package/dist/assets/architectureDiagram-T3A2C74G-_IpEkukg.js +36 -0
- package/dist/assets/blockDiagram-VBNYF7ZC-BttxrpgZ.js +132 -0
- package/dist/assets/c4Diagram-5PPSVZJV-g51dSRr1.js +10 -0
- package/dist/assets/channel-C5xU9jMw.js +1 -0
- package/dist/assets/chunk-2GRJ4B5K-D_-LbQUa.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-BtlHzwaO.js +1 -0
- package/dist/assets/chunk-5RXB4S5H-UzkpvpAT.js +231 -0
- package/dist/assets/chunk-5VM5RSS4-BKwx5Gag.js +15 -0
- package/dist/assets/chunk-6Q2QTUOP-D_KEBH5f.js +88 -0
- package/dist/assets/chunk-GF5L2VYU-rK2DGyto.js +206 -0
- package/dist/assets/chunk-JWPE2WC7-CeBl_N9i.js +1 -0
- package/dist/assets/chunk-KBJHAD2P-BiQLWVIr.js +1 -0
- package/dist/assets/chunk-RYQCIY6F-C1knVGV5.js +1 -0
- package/dist/assets/chunk-XXDRQBXY-CtKbJkvF.js +1 -0
- package/dist/assets/classDiagram-JCYQIIEL-CRrL3vp7.js +1 -0
- package/dist/assets/classDiagram-v2-OCEON4UE-CRrL3vp7.js +1 -0
- package/dist/assets/cose-bilkent-JH36ORCC-DjX8y40Z.js +1 -0
- package/dist/assets/cynefin-VYW2F7L2-DM6YeRba.js +178 -0
- package/dist/assets/cynefinDiagram-MW4NZA55-wZJ-vy5B.js +62 -0
- package/dist/assets/cytoscape.esm-C10L9Icf.js +331 -0
- package/dist/assets/dagre-VZM6K2ZE-BzP0ejkH.js +4 -0
- package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/assets/diagram-7IWD3JNH-BTL_j23J.js +30 -0
- package/dist/assets/diagram-B4RE2ZJO-Cf1Norgu.js +3 -0
- package/dist/assets/diagram-LBJQPF4R-DPiUEKr-.js +24 -0
- package/dist/assets/diagram-Q27KOJAE-CTcTpiz5.js +24 -0
- package/dist/assets/diagram-UB23O5K3-DPMSdYm0.js +41 -0
- package/dist/assets/ebnfDiagram-BXEA7PRR-7yvD6uiF.js +1 -0
- package/dist/assets/erDiagram-JOGREHBK-CfgeDoV6.js +85 -0
- package/dist/assets/flowDiagram-UKHOOZJN-B27ng5zu.js +156 -0
- package/dist/assets/ganttDiagram-PKOTCBZU-CcC6b_7t.js +292 -0
- package/dist/assets/gitGraphDiagram-DS77QQ5N-BX5kPGrO.js +106 -0
- package/dist/assets/graph-Cx-EqisW.js +1 -0
- package/dist/assets/index-BTDHQ6Id.css +32 -0
- package/dist/assets/index-sFfz8iBR.js +4931 -0
- package/dist/assets/infoDiagram-6WML65LV-CUP-SlN4.js +2 -0
- package/dist/assets/init-Gi6I4Gst.js +1 -0
- package/dist/assets/ishikawaDiagram-WSZJBQD7-BTTDhOpX.js +70 -0
- package/dist/assets/journeyDiagram-NVQOT4AX-ARXcc61m.js +139 -0
- package/dist/assets/kanban-definition-27J2QSJJ-BieMpqMA.js +89 -0
- package/dist/assets/layout-D6BstSzF.js +1 -0
- package/dist/assets/linear-61vxjRnP.js +1 -0
- package/dist/assets/map-CV9uif0g.js +1 -0
- package/dist/assets/mermaid.core-nhnwkfQx.js +312 -0
- package/dist/assets/mindmap-definition-FAOFIHXS-Cm6x5vT1.js +96 -0
- package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/assets/pegDiagram-VL7TDLO6-CcYBq_9H.js +1 -0
- package/dist/assets/pieDiagram-7S7Q4E2Y-CfvIjfzo.js +39 -0
- package/dist/assets/quadrantDiagram-CIZ2JOQS-SgYoWPNb.js +7 -0
- package/dist/assets/railroadDiagram-AXF67PYL-D2Mu5E_f.js +1 -0
- package/dist/assets/requirementDiagram-LRYGKXZP-Azwe_k4Q.js +84 -0
- package/dist/assets/sankeyDiagram-W5VNT64P-DN1Ju3PA.js +40 -0
- package/dist/assets/sequenceDiagram-SI44F4Z6-Bj4qC34S.js +162 -0
- package/dist/assets/server.browser-CtX3Hdl5.js +27 -0
- package/dist/assets/sizeCapture-X5ZJPWSS-Co4PdklG.js +1 -0
- package/dist/assets/stateDiagram-OKZ733FA-nOvL9dRC.js +1 -0
- package/dist/assets/stateDiagram-v2-UEYNNEHI-DNv8ppw7.js +1 -0
- package/dist/assets/swimlanes-SLNWSIFB-CCK3wMid.js +2 -0
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-DnfbNQEp.js +8 -0
- package/dist/assets/timeline-definition-Z64GVDOM-BC29RNFm.js +120 -0
- package/dist/assets/{vendor-codemirror-OwyKSvPE.js → vendor-codemirror-CYrSt7-U.js} +18 -18
- package/dist/assets/vennDiagram-T6HMQDX7-pZlZCtEo.js +34 -0
- package/dist/assets/wardleyDiagram-T6FBY63Y-De8k2-zM.js +78 -0
- package/dist/assets/xychartDiagram-ELKLHX3M-Bk8ykH0w.js +7 -0
- package/dist/index.html +3 -3
- package/dist-server/server/index.js +8 -5
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/agent/agent.module.js +2 -1
- package/dist-server/server/modules/agent/agent.module.js.map +1 -1
- package/dist-server/server/modules/agent/agent.routes.js +2 -2
- package/dist-server/server/modules/agent/agent.routes.js.map +1 -1
- package/dist-server/server/modules/agent/tests/agent.routes.test.js +30 -1
- package/dist-server/server/modules/agent/tests/agent.routes.test.js.map +1 -1
- package/dist-server/server/modules/auth/auth.middleware.js +1 -1
- package/dist-server/server/modules/auth/auth.middleware.js.map +1 -1
- package/dist-server/server/modules/browser-use/browser-use-runtime.js +10 -0
- package/dist-server/server/modules/browser-use/browser-use-runtime.js.map +1 -0
- package/dist-server/server/modules/browser-use/browser-use.routes.js +39 -33
- package/dist-server/server/modules/browser-use/browser-use.routes.js.map +1 -1
- package/dist-server/server/modules/browser-use/browser-use.service.js +3 -6
- package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -1
- package/dist-server/server/modules/browser-use/index.js +2 -0
- package/dist-server/server/modules/browser-use/index.js.map +1 -1
- package/dist-server/server/modules/cli/cli.js +9 -3
- package/dist-server/server/modules/cli/cli.js.map +1 -1
- package/dist-server/server/modules/cli/cli.module.js +0 -1
- package/dist-server/server/modules/cli/cli.module.js.map +1 -1
- package/dist-server/server/modules/cli/cli.service.js +0 -18
- package/dist-server/server/modules/cli/cli.service.js.map +1 -1
- package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js +154 -0
- package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js.map +1 -0
- package/dist-server/server/modules/cli/tests/cli.service.test.js +0 -3
- package/dist-server/server/modules/cli/tests/cli.service.test.js.map +1 -1
- package/dist-server/server/modules/database/connection.js +1 -1
- package/dist-server/server/modules/database/connection.js.map +1 -1
- package/dist-server/server/modules/database/index.js +5 -0
- package/dist-server/server/modules/database/index.js.map +1 -1
- package/dist-server/server/modules/database/migrations.js +32 -1
- package/dist-server/server/modules/database/migrations.js.map +1 -1
- package/dist-server/server/modules/database/repositories/scheduled-messages.db.js +71 -0
- package/dist-server/server/modules/database/repositories/scheduled-messages.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/session-drafts.db.js +105 -0
- package/dist-server/server/modules/database/repositories/session-drafts.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js +137 -5
- package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
- package/dist-server/server/modules/database/repositories/user-preferences.db.js +65 -0
- package/dist-server/server/modules/database/repositories/user-preferences.db.js.map +1 -0
- package/dist-server/server/modules/database/schema.js +92 -0
- package/dist-server/server/modules/database/schema.js.map +1 -1
- package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +39 -0
- package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -1
- package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js +105 -0
- package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/file-tree/file-tree.service.js +18 -10
- package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -1
- package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +62 -11
- package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -1
- package/dist-server/server/modules/git/git-branch.service.js +15 -0
- package/dist-server/server/modules/git/git-branch.service.js.map +1 -0
- package/dist-server/server/modules/git/git.routes.js +15 -7
- package/dist-server/server/modules/git/git.routes.js.map +1 -1
- package/dist-server/server/modules/git/tests/git-branch.service.test.js +52 -0
- package/dist-server/server/modules/git/tests/git-branch.service.test.js.map +1 -0
- package/dist-server/server/modules/git/tests/git-init.routes.test.js +84 -0
- package/dist-server/server/modules/git/tests/git-init.routes.test.js.map +1 -1
- package/dist-server/server/modules/notifications/index.js +3 -1
- package/dist-server/server/modules/notifications/index.js.map +1 -1
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js +22 -1
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js.map +1 -1
- package/dist-server/server/modules/projects/services/project-delete.service.js +12 -1
- package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -1
- package/dist-server/server/modules/projects/services/project-star.service.js +2 -2
- package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -1
- package/dist-server/server/modules/providers/index.js +3 -0
- package/dist-server/server/modules/providers/index.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +20 -1
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js +46 -0
- package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +35 -6
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js +422 -86
- package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +388 -50
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +4 -1
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude.provider.js +2 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js +204 -0
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js +32 -0
- package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +16 -0
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js +60 -49
- package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +8 -0
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +1565 -432
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex.provider.js +2 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js +8 -6
- package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +258 -6
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/provider.routes.js +29 -0
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js +14 -0
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-token-usage.service.js +139 -35
- package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js +63 -7
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/session-history-cache.service.js +87 -0
- package/dist-server/server/modules/providers/services/session-history-cache.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js +105 -32
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js +3 -60
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/sessions.service.js +179 -9
- package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
- package/dist-server/server/modules/providers/tests/claude-auth.test.js +52 -0
- package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/claude-models.test.js +39 -0
- package/dist-server/server/modules/providers/tests/claude-models.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-sessions.test.js +465 -39
- package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js +16 -0
- package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-token-budget.test.js +85 -0
- package/dist-server/server/modules/providers/tests/claude-token-budget.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-message-editing.test.js +338 -0
- package/dist-server/server/modules/providers/tests/codex-message-editing.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-runtime.test.js +51 -0
- package/dist-server/server/modules/providers/tests/codex-runtime.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-session-fork.test.js +54 -0
- package/dist-server/server/modules/providers/tests/codex-session-fork.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js +304 -15
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/opencode-models.test.js +117 -4
- package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +164 -1
- package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/provider.routes.test.js +35 -0
- package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/session-fork.test.js +113 -0
- package/dist-server/server/modules/providers/tests/session-fork.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js +120 -0
- package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js +90 -0
- package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js +122 -0
- package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/sessions.service.test.js +45 -1
- package/dist-server/server/modules/providers/tests/sessions.service.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/skills.test.js +15 -3
- package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -1
- package/dist-server/server/modules/scheduled-messages/index.js +5 -0
- package/dist-server/server/modules/scheduled-messages/index.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js +47 -0
- package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js +163 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js +95 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js +255 -0
- package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js.map +1 -0
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js +23 -23
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -1
- package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +48 -0
- package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -1
- package/dist-server/server/modules/user/tests/user.service.test.js +70 -0
- package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -1
- package/dist-server/server/modules/user/user.module.js +10 -1
- package/dist-server/server/modules/user/user.module.js.map +1 -1
- package/dist-server/server/modules/user/user.routes.js +44 -0
- package/dist-server/server/modules/user/user.routes.js.map +1 -1
- package/dist-server/server/modules/user/user.service.js +75 -0
- package/dist-server/server/modules/user/user.service.js.map +1 -1
- package/dist-server/server/modules/voice/tests/voice.service.test.js +3 -2
- package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -1
- package/dist-server/server/modules/websocket/index.js +7 -0
- package/dist-server/server/modules/websocket/index.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +10 -44
- package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +35 -5
- package/dist-server/server/modules/websocket/services/chat-session-writer.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js +166 -9
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js +94 -0
- package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js +9 -3
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -1
- package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js +263 -0
- package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +29 -3
- package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -1
- package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js +106 -0
- package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +80 -0
- package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -1
- package/dist-server/server/shared/claude-cli-path.js +22 -5
- package/dist-server/server/shared/claude-cli-path.js.map +1 -1
- package/dist-server/server/shared/index.js +3 -0
- package/dist-server/server/shared/index.js.map +1 -0
- package/dist-server/server/shared/message-unification.js +376 -0
- package/dist-server/server/shared/message-unification.js.map +1 -0
- package/dist-server/server/shared/tests/claude-cli-path.test.js +45 -1
- package/dist-server/server/shared/tests/claude-cli-path.test.js.map +1 -1
- package/dist-server/server/shared/tests/message-unification.test.js +174 -0
- package/dist-server/server/shared/tests/message-unification.test.js.map +1 -0
- package/dist-server/server/shared/utils.js +42 -0
- package/dist-server/server/shared/utils.js.map +1 -1
- package/package.json +23 -16
- package/scripts/promote-dist-server.mjs +50 -0
- package/server/index.ts +12 -6
- package/server/modules/agent/agent.module.ts +2 -1
- package/server/modules/agent/agent.routes.ts +2 -2
- package/server/modules/agent/tests/agent.routes.test.ts +33 -1
- package/server/modules/auth/auth.middleware.ts +2 -2
- package/server/modules/browser-use/browser-use-runtime.ts +10 -0
- package/server/modules/browser-use/browser-use.routes.ts +96 -33
- package/server/modules/browser-use/browser-use.service.ts +5 -8
- package/server/modules/browser-use/index.ts +3 -0
- package/server/modules/cli/cli.module.ts +0 -1
- package/server/modules/cli/cli.service.ts +0 -20
- package/server/modules/cli/cli.ts +9 -3
- package/server/modules/cli/tests/cli-environment-bootstrap.test.ts +186 -0
- package/server/modules/cli/tests/cli.service.test.ts +0 -3
- package/server/modules/database/connection.ts +2 -1
- package/server/modules/database/index.ts +10 -0
- package/server/modules/database/migrations.ts +37 -0
- package/server/modules/database/repositories/scheduled-messages.db.ts +127 -0
- package/server/modules/database/repositories/session-drafts.db.ts +171 -0
- package/server/modules/database/repositories/sessions.db.ts +196 -3
- package/server/modules/database/repositories/user-preferences.db.ts +80 -0
- package/server/modules/database/schema.ts +96 -0
- package/server/modules/database/tests/sessions.db.integration.test.ts +52 -0
- package/server/modules/database/tests/user-preferences.db.integration.test.ts +135 -0
- package/server/modules/file-tree/file-tree.service.ts +21 -10
- package/server/modules/file-tree/tests/file-tree.service.test.ts +65 -11
- package/server/modules/git/git-branch.service.ts +43 -0
- package/server/modules/git/git.routes.ts +16 -9
- package/server/modules/git/tests/git-branch.service.test.ts +60 -0
- package/server/modules/git/tests/git-init.routes.test.ts +83 -0
- package/server/modules/notifications/index.ts +2 -0
- package/server/modules/notifications/services/notification-orchestrator.service.js +24 -1
- package/server/modules/projects/services/project-delete.service.ts +13 -1
- package/server/modules/projects/services/project-star.service.ts +2 -2
- package/server/modules/providers/index.ts +4 -0
- package/server/modules/providers/list/claude/claude-auth.provider.ts +21 -1
- package/server/modules/providers/list/claude/claude-fork.provider.ts +57 -0
- package/server/modules/providers/list/claude/claude-models.provider.ts +38 -6
- package/server/modules/providers/list/claude/claude-runtime.provider.js +463 -93
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +478 -54
- package/server/modules/providers/list/claude/claude-skills.provider.ts +4 -1
- package/server/modules/providers/list/claude/claude.provider.ts +3 -0
- package/server/modules/providers/list/codex/codex-app-server.client.ts +243 -0
- package/server/modules/providers/list/codex/codex-fork.provider.ts +40 -0
- package/server/modules/providers/list/codex/codex-models.provider.ts +16 -0
- package/server/modules/providers/list/codex/{codex-runtime.provider.js → codex-runtime.provider.ts} +93 -66
- package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +9 -0
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +1806 -477
- package/server/modules/providers/list/codex/codex.provider.ts +3 -0
- package/server/modules/providers/list/cursor/cursor-runtime.provider.js +8 -6
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +0 -1
- package/server/modules/providers/list/opencode/opencode-models.provider.ts +279 -6
- package/server/modules/providers/provider.routes.ts +36 -0
- package/server/modules/providers/services/provider-capabilities.service.ts +23 -0
- package/server/modules/providers/services/provider-token-usage.service.ts +166 -39
- package/server/modules/providers/services/session-conversations-search.service.ts +94 -7
- package/server/modules/providers/services/session-history-cache.service.ts +139 -0
- package/server/modules/providers/services/session-synchronizer.service.ts +125 -38
- package/server/modules/providers/services/sessions-watcher.service.ts +3 -64
- package/server/modules/providers/services/sessions.service.ts +201 -9
- package/server/modules/providers/tests/claude-auth.test.ts +58 -0
- package/server/modules/providers/tests/claude-models.test.ts +87 -0
- package/server/modules/providers/tests/claude-sessions.test.ts +552 -40
- package/server/modules/providers/tests/claude-subagent-echo.test.ts +25 -0
- package/server/modules/providers/tests/claude-token-budget.test.ts +104 -0
- package/server/modules/providers/tests/codex-message-editing.test.ts +419 -0
- package/server/modules/providers/tests/codex-runtime.test.ts +58 -0
- package/server/modules/providers/tests/codex-session-fork.test.ts +59 -0
- package/server/modules/providers/tests/codex-sessions.test.ts +337 -15
- package/server/modules/providers/tests/opencode-models.test.ts +166 -8
- package/server/modules/providers/tests/provider-token-usage.service.test.ts +188 -1
- package/server/modules/providers/tests/provider.routes.test.ts +61 -0
- package/server/modules/providers/tests/session-fork.test.ts +173 -0
- package/server/modules/providers/tests/session-history-cache.service.test.ts +143 -0
- package/server/modules/providers/tests/session-orphan-prune.test.ts +107 -0
- package/server/modules/providers/tests/session-synchronizer-coalescing.test.ts +136 -0
- package/server/modules/providers/tests/sessions.service.test.ts +67 -1
- package/server/modules/providers/tests/skills.test.ts +21 -5
- package/server/modules/scheduled-messages/index.ts +8 -0
- package/server/modules/scheduled-messages/scheduled-messages.routes.ts +68 -0
- package/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.ts +203 -0
- package/server/modules/scheduled-messages/services/scheduled-messages.service.ts +121 -0
- package/server/modules/scheduled-messages/tests/scheduled-messages.test.ts +310 -0
- package/server/modules/taskmaster/taskmaster.routes.ts +23 -33
- package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +57 -0
- package/server/modules/user/tests/user.service.test.ts +90 -0
- package/server/modules/user/user.module.ts +10 -1
- package/server/modules/user/user.routes.ts +44 -0
- package/server/modules/user/user.service.ts +105 -0
- package/server/modules/voice/tests/voice.service.test.ts +3 -2
- package/server/modules/websocket/index.ts +8 -0
- package/server/modules/websocket/services/chat-run-registry.service.ts +17 -50
- package/server/modules/websocket/services/chat-session-writer.service.ts +36 -6
- package/server/modules/websocket/services/chat-websocket.service.ts +244 -15
- package/server/modules/websocket/services/session-upsert-broadcast.service.ts +108 -0
- package/server/modules/websocket/services/shell-websocket.service.ts +10 -3
- package/server/modules/websocket/tests/chat-edit-send.test.ts +309 -0
- package/server/modules/websocket/tests/chat-run-registry.test.ts +34 -3
- package/server/modules/websocket/tests/session-upsert-broadcast.test.ts +138 -0
- package/server/modules/websocket/tests/shell-websocket.service.test.ts +108 -0
- package/server/shared/claude-cli-path.ts +24 -6
- package/server/shared/index.ts +3 -0
- package/server/shared/interfaces.ts +62 -0
- package/server/shared/message-unification.ts +449 -0
- package/server/shared/tests/claude-cli-path.test.ts +58 -1
- package/server/shared/tests/message-unification.test.ts +218 -0
- package/server/shared/types.ts +123 -3
- package/server/shared/utils.ts +50 -0
- package/server/tsconfig.json +6 -2
- package/README.de.md +0 -257
- package/README.ja.md +0 -249
- package/README.ko.md +0 -249
- package/README.ru.md +0 -257
- package/README.tr.md +0 -258
- package/README.zh-CN.md +0 -249
- package/README.zh-TW.md +0 -249
- package/dist/assets/index-D3jfzuKN.css +0 -32
- package/dist/assets/index-DTMWjJj8.js +0 -1550
- package/dist-server/server/constants/config.js +0 -6
- package/dist-server/server/constants/config.js.map +0 -1
- package/server/constants/config.ts +0 -5
|
@@ -6,7 +6,7 @@ import test from 'node:test';
|
|
|
6
6
|
|
|
7
7
|
import { closeConnection, initializeDatabase, sessionsDb } from '@/modules/database/index.js';
|
|
8
8
|
import { CodexSessionSynchronizer } from '@/modules/providers/list/codex/codex-session-synchronizer.provider.js';
|
|
9
|
-
import { CodexSessionsProvider } from '@/modules/providers/list/codex/codex-sessions.provider.js';
|
|
9
|
+
import { CodexSessionsProvider, parseCodexExecScript, readCodexMemoryCitations } from '@/modules/providers/list/codex/codex-sessions.provider.js';
|
|
10
10
|
|
|
11
11
|
const patchHomeDir = (nextHomeDir: string) => {
|
|
12
12
|
const original = os.homedir;
|
|
@@ -152,7 +152,7 @@ test('Codex synchronizer leaves indexed sessions untitled when no name is availa
|
|
|
152
152
|
}
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
test('Codex history
|
|
155
|
+
test('Codex history translates wrapped exec scripts into the tools they ran', { concurrency: false }, async () => {
|
|
156
156
|
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'codex-exec-history-'));
|
|
157
157
|
const workspacePath = path.join(tempRoot, 'workspace');
|
|
158
158
|
await mkdir(workspacePath, { recursive: true });
|
|
@@ -161,6 +161,8 @@ test('Codex history preserves wrapped exec tool calls and results', { concurrenc
|
|
|
161
161
|
try {
|
|
162
162
|
const providerSessionId = 'codex-exec-1';
|
|
163
163
|
const transcriptPath = await writeCodexTranscript(tempRoot, providerSessionId, workspacePath);
|
|
164
|
+
// Every shape Codex's "code mode" emits. Only a wrapper nothing recognizes
|
|
165
|
+
// may stay labelled `exec`; the rest must name the work they performed.
|
|
164
166
|
const wrappedCalls = [
|
|
165
167
|
{
|
|
166
168
|
callId: 'shell-command-1',
|
|
@@ -176,14 +178,22 @@ test('Codex history preserves wrapped exec tool calls and results', { concurrenc
|
|
|
176
178
|
},
|
|
177
179
|
{
|
|
178
180
|
callId: 'exec-command-1',
|
|
179
|
-
input: 'await tools.exec_command({"
|
|
181
|
+
input: 'await tools.exec_command({"cmd":"npm test","workdir":"/repo","yield_time_ms":10000});',
|
|
180
182
|
expectedToolName: 'Bash',
|
|
181
|
-
expectedToolInput: JSON.stringify({ command: '
|
|
183
|
+
expectedToolInput: JSON.stringify({ command: 'npm test' }),
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
callId: 'web-run-1',
|
|
187
|
+
input: 'await tools.web__run({ search_query: [{ q: "Codex" }, { q: "rollout format" }] });',
|
|
188
|
+
expectedToolName: 'WebSearch',
|
|
189
|
+
expectedToolInput: JSON.stringify({ query: 'Codex | rollout format' }),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
callId: 'unknown-1',
|
|
193
|
+
input: 'await tools.unknown_wrapper({ value: true });',
|
|
194
|
+
expectedToolName: 'exec',
|
|
195
|
+
expectedToolInput: 'await tools.unknown_wrapper({ value: true });',
|
|
182
196
|
},
|
|
183
|
-
{ callId: 'apply-patch-1', input: 'await tools.apply_patch("*** Begin Patch\\n*** End Patch");' },
|
|
184
|
-
{ callId: 'web-run-1', input: 'await tools.web__run({ search_query: [{ q: "Codex" }] });' },
|
|
185
|
-
{ callId: 'update-plan-1', input: 'await tools.update_plan({ plan: [] });' },
|
|
186
|
-
{ callId: 'unknown-1', input: 'await tools.unknown_wrapper({ value: true });' },
|
|
187
197
|
];
|
|
188
198
|
const transcriptLines = [
|
|
189
199
|
JSON.stringify({ type: 'session_meta', payload: { id: providerSessionId, cwd: workspacePath } }),
|
|
@@ -209,19 +219,15 @@ test('Codex history preserves wrapped exec tool calls and results', { concurrenc
|
|
|
209
219
|
|
|
210
220
|
const history = await new CodexSessionsProvider().fetchHistory('app-exec-1');
|
|
211
221
|
const toolUses = history.messages.filter((message) => message.kind === 'tool_use');
|
|
212
|
-
const toolResults = history.messages.filter((message) => message.kind === 'tool_result');
|
|
213
222
|
const toolUsesById = new Map(toolUses.map((message) => [message.toolId, message]));
|
|
214
|
-
const toolResultsById = new Map(toolResults.map((message) => [message.toolId, message]));
|
|
215
223
|
|
|
216
224
|
assert.equal(toolUses.length, wrappedCalls.length);
|
|
217
|
-
assert.equal(toolResults.length, wrappedCalls.length);
|
|
218
225
|
for (const call of wrappedCalls) {
|
|
219
226
|
const toolUse = toolUsesById.get(call.callId);
|
|
220
|
-
assert.ok(toolUse);
|
|
221
|
-
assert.equal(toolUse.toolName, call.expectedToolName
|
|
222
|
-
assert.equal(toolUse.toolInput, call.expectedToolInput
|
|
227
|
+
assert.ok(toolUse, `missing row for ${call.callId}`);
|
|
228
|
+
assert.equal(toolUse.toolName, call.expectedToolName);
|
|
229
|
+
assert.equal(toolUse.toolInput, call.expectedToolInput);
|
|
223
230
|
assert.equal(toolUse.toolResult?.content, `result:${call.callId}`);
|
|
224
|
-
assert.equal(toolResultsById.get(call.callId)?.content, `result:${call.callId}`);
|
|
225
231
|
}
|
|
226
232
|
});
|
|
227
233
|
} finally {
|
|
@@ -229,3 +235,319 @@ test('Codex history preserves wrapped exec tool calls and results', { concurrenc
|
|
|
229
235
|
await rm(tempRoot, { recursive: true, force: true });
|
|
230
236
|
}
|
|
231
237
|
});
|
|
238
|
+
|
|
239
|
+
test('Codex history strips the sandbox envelopes from shell output', { concurrency: false }, async () => {
|
|
240
|
+
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'codex-exec-output-'));
|
|
241
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
242
|
+
await mkdir(workspacePath, { recursive: true });
|
|
243
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
244
|
+
|
|
245
|
+
try {
|
|
246
|
+
const providerSessionId = 'codex-output-1';
|
|
247
|
+
const transcriptPath = await writeCodexTranscript(tempRoot, providerSessionId, workspacePath);
|
|
248
|
+
await writeFile(transcriptPath, `${[
|
|
249
|
+
JSON.stringify({ type: 'session_meta', payload: { id: providerSessionId, cwd: workspacePath } }),
|
|
250
|
+
JSON.stringify({
|
|
251
|
+
type: 'response_item',
|
|
252
|
+
payload: {
|
|
253
|
+
type: 'custom_tool_call',
|
|
254
|
+
name: 'exec',
|
|
255
|
+
call_id: 'failing-1',
|
|
256
|
+
input: 'await tools.shell_command({ command: "npm test" });',
|
|
257
|
+
},
|
|
258
|
+
}),
|
|
259
|
+
// Codex nests two report headers: one for the sandbox script and one for
|
|
260
|
+
// the command it ran. Neither belongs in a chat transcript.
|
|
261
|
+
JSON.stringify({
|
|
262
|
+
type: 'response_item',
|
|
263
|
+
payload: {
|
|
264
|
+
type: 'custom_tool_call_output',
|
|
265
|
+
call_id: 'failing-1',
|
|
266
|
+
output: [
|
|
267
|
+
{ type: 'input_text', text: 'Script failed\nWall time 1.2 seconds\nOutput:\n' },
|
|
268
|
+
{ type: 'input_text', text: 'Script error:\nExit code: 1\nWall time: 1.1 seconds\nOutput:\n1 test failed\n' },
|
|
269
|
+
],
|
|
270
|
+
},
|
|
271
|
+
}),
|
|
272
|
+
].join('\n')}\n`, 'utf8');
|
|
273
|
+
|
|
274
|
+
await withIsolatedDatabase(async () => {
|
|
275
|
+
sessionsDb.createAppSession('app-output-1', 'codex', workspacePath);
|
|
276
|
+
sessionsDb.assignProviderSessionId('app-output-1', providerSessionId);
|
|
277
|
+
await new CodexSessionSynchronizer().synchronize();
|
|
278
|
+
|
|
279
|
+
const history = await new CodexSessionsProvider().fetchHistory('app-output-1');
|
|
280
|
+
const bash = history.messages.find((message) => message.kind === 'tool_use');
|
|
281
|
+
|
|
282
|
+
assert.equal(bash?.toolName, 'Bash');
|
|
283
|
+
assert.equal(bash?.toolResult?.content, '1 test failed\n');
|
|
284
|
+
assert.equal(bash?.toolResult?.isError, true, 'a non-zero exit code must mark the row failed');
|
|
285
|
+
});
|
|
286
|
+
} finally {
|
|
287
|
+
restoreHomeDir();
|
|
288
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
test('Codex history renders one file row per patched file, from the applied diff', { concurrency: false }, async () => {
|
|
293
|
+
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'codex-patch-history-'));
|
|
294
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
295
|
+
await mkdir(workspacePath, { recursive: true });
|
|
296
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
const providerSessionId = 'codex-patch-1';
|
|
300
|
+
const transcriptPath = await writeCodexTranscript(tempRoot, providerSessionId, workspacePath);
|
|
301
|
+
const patch = [
|
|
302
|
+
'*** Begin Patch',
|
|
303
|
+
'*** Update File: /repo/a.ts',
|
|
304
|
+
'@@',
|
|
305
|
+
'-const a = 1;',
|
|
306
|
+
'+const a = 2;',
|
|
307
|
+
'*** Update File: /repo/b.ts',
|
|
308
|
+
'@@',
|
|
309
|
+
'-const b = 1;',
|
|
310
|
+
'+const b = 2;',
|
|
311
|
+
'*** End Patch',
|
|
312
|
+
].join('\n');
|
|
313
|
+
|
|
314
|
+
await writeFile(transcriptPath, `${[
|
|
315
|
+
JSON.stringify({ type: 'session_meta', payload: { id: providerSessionId, cwd: workspacePath } }),
|
|
316
|
+
JSON.stringify({
|
|
317
|
+
type: 'response_item',
|
|
318
|
+
payload: { type: 'custom_tool_call', name: 'apply_patch', call_id: 'patch-1', input: patch },
|
|
319
|
+
}),
|
|
320
|
+
// The out-of-band report carries the real diffs, keyed by path in an
|
|
321
|
+
// order that does not follow the patch body.
|
|
322
|
+
JSON.stringify({
|
|
323
|
+
type: 'event_msg',
|
|
324
|
+
payload: {
|
|
325
|
+
type: 'patch_apply_end',
|
|
326
|
+
call_id: 'patch-1',
|
|
327
|
+
success: true,
|
|
328
|
+
changes: {
|
|
329
|
+
'/repo/b.ts': { type: 'update', unified_diff: '@@\n-const b = 1;\n+const b = 22;\n' },
|
|
330
|
+
'/repo/a.ts': { type: 'update', unified_diff: '@@\n-const a = 1;\n+const a = 22;\n' },
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
}),
|
|
334
|
+
JSON.stringify({
|
|
335
|
+
type: 'response_item',
|
|
336
|
+
payload: { type: 'custom_tool_call_output', call_id: 'patch-1', output: '{}' },
|
|
337
|
+
}),
|
|
338
|
+
].join('\n')}\n`, 'utf8');
|
|
339
|
+
|
|
340
|
+
await withIsolatedDatabase(async () => {
|
|
341
|
+
sessionsDb.createAppSession('app-patch-1', 'codex', workspacePath);
|
|
342
|
+
sessionsDb.assignProviderSessionId('app-patch-1', providerSessionId);
|
|
343
|
+
await new CodexSessionSynchronizer().synchronize();
|
|
344
|
+
|
|
345
|
+
const history = await new CodexSessionsProvider().fetchHistory('app-patch-1');
|
|
346
|
+
const edits = history.messages.filter((message) => message.kind === 'tool_use');
|
|
347
|
+
|
|
348
|
+
assert.equal(edits.length, 2, 'the patch must not be rendered twice');
|
|
349
|
+
const byPath = new Map(edits.map((edit) => {
|
|
350
|
+
const input = JSON.parse(String(edit.toolInput)) as { file_path: string; new_string: string };
|
|
351
|
+
return [input.file_path, { edit, input }];
|
|
352
|
+
}));
|
|
353
|
+
|
|
354
|
+
assert.equal(byPath.get('/repo/a.ts')?.edit.toolName, 'Edit');
|
|
355
|
+
// The applied diff wins over the one reconstructed from the call input,
|
|
356
|
+
// and it must land on the row for its own file.
|
|
357
|
+
assert.equal(byPath.get('/repo/a.ts')?.input.new_string, 'const a = 22;');
|
|
358
|
+
assert.equal(byPath.get('/repo/b.ts')?.input.new_string, 'const b = 22;');
|
|
359
|
+
for (const edit of edits) {
|
|
360
|
+
assert.equal(edit.toolResult?.isError, false, 'a successful patch must resolve its row');
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
} finally {
|
|
364
|
+
restoreHomeDir();
|
|
365
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
test('Codex history attaches a spawned agent\'s own transcript to the Task row', { concurrency: false }, async () => {
|
|
370
|
+
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'codex-subagent-history-'));
|
|
371
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
372
|
+
await mkdir(workspacePath, { recursive: true });
|
|
373
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
374
|
+
|
|
375
|
+
try {
|
|
376
|
+
const providerSessionId = 'codex-parent-2';
|
|
377
|
+
const agentThreadId = 'codex-agent-thread-2';
|
|
378
|
+
const transcriptPath = await writeCodexTranscript(tempRoot, providerSessionId, workspacePath);
|
|
379
|
+
|
|
380
|
+
await writeFile(transcriptPath, `${[
|
|
381
|
+
JSON.stringify({ type: 'session_meta', payload: { id: providerSessionId, cwd: workspacePath } }),
|
|
382
|
+
JSON.stringify({
|
|
383
|
+
type: 'response_item',
|
|
384
|
+
payload: {
|
|
385
|
+
type: 'function_call',
|
|
386
|
+
name: 'spawn_agent',
|
|
387
|
+
call_id: 'spawn-1',
|
|
388
|
+
arguments: JSON.stringify({ task_name: 'test_agent_1' }),
|
|
389
|
+
},
|
|
390
|
+
}),
|
|
391
|
+
JSON.stringify({
|
|
392
|
+
type: 'event_msg',
|
|
393
|
+
payload: {
|
|
394
|
+
type: 'sub_agent_activity',
|
|
395
|
+
kind: 'started',
|
|
396
|
+
event_id: 'spawn-1',
|
|
397
|
+
agent_thread_id: agentThreadId,
|
|
398
|
+
agent_path: '/root/test_agent_1',
|
|
399
|
+
},
|
|
400
|
+
}),
|
|
401
|
+
JSON.stringify({
|
|
402
|
+
type: 'response_item',
|
|
403
|
+
payload: {
|
|
404
|
+
type: 'agent_message',
|
|
405
|
+
author: '/root/test_agent_1',
|
|
406
|
+
content: [{ type: 'input_text', text: 'Message Type: FINAL_ANSWER\nSender: /root/test_agent_1\nPayload:\nAll done.' }],
|
|
407
|
+
},
|
|
408
|
+
}),
|
|
409
|
+
].join('\n')}\n`, 'utf8');
|
|
410
|
+
|
|
411
|
+
// Codex writes a spawned agent's rollout next to its parent's, named after
|
|
412
|
+
// the agent thread id.
|
|
413
|
+
await writeFile(
|
|
414
|
+
path.join(path.dirname(transcriptPath), `rollout-2026-07-07T00-00-00-${agentThreadId}.jsonl`),
|
|
415
|
+
`${[
|
|
416
|
+
JSON.stringify({
|
|
417
|
+
type: 'session_meta',
|
|
418
|
+
payload: { id: agentThreadId, cwd: workspacePath, thread_source: 'subagent', agent_nickname: 'Hegel' },
|
|
419
|
+
}),
|
|
420
|
+
JSON.stringify({
|
|
421
|
+
type: 'response_item',
|
|
422
|
+
payload: {
|
|
423
|
+
type: 'custom_tool_call',
|
|
424
|
+
name: 'exec',
|
|
425
|
+
call_id: 'agent-call-1',
|
|
426
|
+
input: 'await tools.shell_command({ command: "ls" });',
|
|
427
|
+
},
|
|
428
|
+
}),
|
|
429
|
+
JSON.stringify({
|
|
430
|
+
type: 'response_item',
|
|
431
|
+
payload: { type: 'custom_tool_call_output', call_id: 'agent-call-1', output: 'Exit code: 0\nOutput:\nREADME.md\n' },
|
|
432
|
+
}),
|
|
433
|
+
].join('\n')}\n`,
|
|
434
|
+
'utf8',
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
await withIsolatedDatabase(async () => {
|
|
438
|
+
sessionsDb.createAppSession('app-parent-2', 'codex', workspacePath);
|
|
439
|
+
sessionsDb.assignProviderSessionId('app-parent-2', providerSessionId);
|
|
440
|
+
await new CodexSessionSynchronizer().synchronize();
|
|
441
|
+
|
|
442
|
+
const history = await new CodexSessionsProvider().fetchHistory('app-parent-2');
|
|
443
|
+
const task = history.messages.find((message) => message.kind === 'tool_use' && message.toolName === 'Task');
|
|
444
|
+
|
|
445
|
+
assert.ok(task, 'a spawned agent must produce a Task row');
|
|
446
|
+
assert.equal(task.subagent?.id, agentThreadId);
|
|
447
|
+
assert.equal(task.subagent?.name, 'Hegel');
|
|
448
|
+
assert.equal(task.subagent?.status, 'completed');
|
|
449
|
+
assert.equal(task.toolResult?.content, 'All done.');
|
|
450
|
+
|
|
451
|
+
// The agent's own shell call is translated exactly like the parent's.
|
|
452
|
+
assert.equal(task.subagentTools?.length, 1);
|
|
453
|
+
assert.equal(task.subagentTools?.[0].kind, 'tool');
|
|
454
|
+
assert.equal(task.subagentTools?.[0].toolName, 'Bash');
|
|
455
|
+
assert.equal(task.subagentTools?.[0].toolResult?.content, 'README.md\n');
|
|
456
|
+
});
|
|
457
|
+
} finally {
|
|
458
|
+
restoreHomeDir();
|
|
459
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
test('Codex memory citations are lifted out of the reply they trail', () => {
|
|
464
|
+
const reply = [
|
|
465
|
+
'Here is the answer.',
|
|
466
|
+
'',
|
|
467
|
+
'<oai-mem-citation>',
|
|
468
|
+
'<citation_entries>',
|
|
469
|
+
'MEMORY.md:137-142|note=[used verified container provisioning details]',
|
|
470
|
+
'notes/deploy.md:4-9',
|
|
471
|
+
'</citation_entries>',
|
|
472
|
+
'<rollout_ids>',
|
|
473
|
+
'019eda6d-c2f7-70c1-8b42-bf03c44a1f35',
|
|
474
|
+
'</rollout_ids>',
|
|
475
|
+
'</oai-mem-citation>',
|
|
476
|
+
].join('\n');
|
|
477
|
+
|
|
478
|
+
const { text, memoryCitations } = readCodexMemoryCitations(reply);
|
|
479
|
+
|
|
480
|
+
assert.equal(text, 'Here is the answer.');
|
|
481
|
+
assert.deepEqual(memoryCitations, [
|
|
482
|
+
{ source: 'MEMORY.md:137-142', note: 'used verified container provisioning details' },
|
|
483
|
+
{ source: 'notes/deploy.md:4-9' },
|
|
484
|
+
]);
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
test('a plan followed by a memory citation is still recognized as a plan', async () => {
|
|
488
|
+
const tempRoot = await mkdtemp(path.join(os.tmpdir(), 'codex-plan-citation-'));
|
|
489
|
+
const workspacePath = path.join(tempRoot, 'workspace');
|
|
490
|
+
await mkdir(workspacePath, { recursive: true });
|
|
491
|
+
const restoreHomeDir = patchHomeDir(tempRoot);
|
|
492
|
+
|
|
493
|
+
try {
|
|
494
|
+
const providerSessionId = 'codex-plan-citation-1';
|
|
495
|
+
const sessionsDir = path.join(tempRoot, '.codex', 'sessions', '2026', '07', '07');
|
|
496
|
+
await mkdir(sessionsDir, { recursive: true });
|
|
497
|
+
await writeFile(path.join(sessionsDir, `rollout-${providerSessionId}.jsonl`), `${[
|
|
498
|
+
JSON.stringify({ type: 'session_meta', payload: { id: providerSessionId, cwd: workspacePath } }),
|
|
499
|
+
JSON.stringify({
|
|
500
|
+
type: 'response_item',
|
|
501
|
+
payload: {
|
|
502
|
+
type: 'message',
|
|
503
|
+
role: 'assistant',
|
|
504
|
+
id: 'plan-1',
|
|
505
|
+
content: [{
|
|
506
|
+
type: 'output_text',
|
|
507
|
+
text: '<proposed_plan>\n# Ship it\n</proposed_plan>\n\n<oai-mem-citation>\n<citation_entries>\nMEMORY.md:1-2|note=[prior deploy steps]\n</citation_entries>\n</oai-mem-citation>',
|
|
508
|
+
}],
|
|
509
|
+
},
|
|
510
|
+
}),
|
|
511
|
+
].join('\n')}\n`, 'utf8');
|
|
512
|
+
|
|
513
|
+
await withIsolatedDatabase(async () => {
|
|
514
|
+
sessionsDb.createAppSession('app-plan-citation-1', 'codex', workspacePath);
|
|
515
|
+
sessionsDb.assignProviderSessionId('app-plan-citation-1', providerSessionId);
|
|
516
|
+
await new CodexSessionSynchronizer().synchronize();
|
|
517
|
+
|
|
518
|
+
const history = await new CodexSessionsProvider().fetchHistory('app-plan-citation-1');
|
|
519
|
+
const plan = history.messages.find((message) => message.toolName === 'ExitPlanMode');
|
|
520
|
+
|
|
521
|
+
assert.ok(plan, 'the trailing citation block must not hide the plan envelope');
|
|
522
|
+
assert.equal(JSON.parse(String(plan.toolInput)).plan, '# Ship it');
|
|
523
|
+
assert.deepEqual(plan.memoryCitations, [{ source: 'MEMORY.md:1-2', note: 'prior deploy steps' }]);
|
|
524
|
+
assert.ok(
|
|
525
|
+
!history.messages.some((message) => JSON.stringify(message).includes('oai-mem-citation')),
|
|
526
|
+
'no transcript row may still carry the raw citation markup',
|
|
527
|
+
);
|
|
528
|
+
});
|
|
529
|
+
} finally {
|
|
530
|
+
restoreHomeDir();
|
|
531
|
+
await rm(tempRoot, { recursive: true, force: true });
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
test('an exec script that updates the plan yields the steps it set', () => {
|
|
536
|
+
const operations = parseCodexExecScript([
|
|
537
|
+
'const p = await tools.update_plan({plan:[',
|
|
538
|
+
' {step:"Confirm the current workspace",status:"completed"},',
|
|
539
|
+
' {step:"Check the Git working-tree status",status:"in_progress"},',
|
|
540
|
+
' {step:"Identify the project",status:"pending"}',
|
|
541
|
+
']});',
|
|
542
|
+
'text(p);',
|
|
543
|
+
].join('\n'));
|
|
544
|
+
|
|
545
|
+
assert.deepEqual(operations, [{
|
|
546
|
+
kind: 'plan',
|
|
547
|
+
todos: [
|
|
548
|
+
{ content: 'Confirm the current workspace', status: 'completed' },
|
|
549
|
+
{ content: 'Check the Git working-tree status', status: 'in_progress' },
|
|
550
|
+
{ content: 'Identify the project', status: 'pending' },
|
|
551
|
+
],
|
|
552
|
+
}]);
|
|
553
|
+
});
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import assert from 'node:assert/strict';
|
|
2
|
+
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
2
5
|
import test from 'node:test';
|
|
3
6
|
|
|
4
7
|
import {
|
|
@@ -6,20 +9,64 @@ import {
|
|
|
6
9
|
OPENCODE_PREDEFINED_MODELS,
|
|
7
10
|
} from '@/modules/providers/list/opencode/opencode-models.provider.js';
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
const adapter = new OpenCodeProviderModels();
|
|
12
|
+
const OPENCODE_ENV_KEYS = ['OPENCODE_API_KEY', 'ANTHROPIC_API_KEY', 'OPENAI_API_KEY'];
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Runs one case against a throwaway OpenCode home, so the catalog the adapter
|
|
16
|
+
* reports depends on the fixture rather than on the providers the machine
|
|
17
|
+
* running the suite happens to be logged into.
|
|
18
|
+
*/
|
|
19
|
+
const withOpenCodeHome = async (
|
|
20
|
+
setUp: (homeDir: string) => Promise<void>,
|
|
21
|
+
runTest: (adapter: OpenCodeProviderModels) => Promise<void>,
|
|
22
|
+
): Promise<void> => {
|
|
23
|
+
const homeDir = await mkdtemp(path.join(os.tmpdir(), 'opencode-catalog-'));
|
|
24
|
+
const originalHomedir = os.homedir;
|
|
25
|
+
const originalEnv = OPENCODE_ENV_KEYS.map((key) => [key, process.env[key]] as const);
|
|
26
|
+
|
|
27
|
+
(os as any).homedir = () => homeDir;
|
|
28
|
+
for (const key of OPENCODE_ENV_KEYS) {
|
|
29
|
+
delete process.env[key];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
await setUp(homeDir);
|
|
34
|
+
await runTest(new OpenCodeProviderModels());
|
|
35
|
+
} finally {
|
|
36
|
+
(os as any).homedir = originalHomedir;
|
|
37
|
+
for (const [key, value] of originalEnv) {
|
|
38
|
+
if (value === undefined) {
|
|
39
|
+
delete process.env[key];
|
|
40
|
+
} else {
|
|
41
|
+
process.env[key] = value;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
await rm(homeDir, { recursive: true, force: true });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const writeOpenCodeAuth = async (homeDir: string, auth: Record<string, unknown>): Promise<void> => {
|
|
49
|
+
const authDir = path.join(homeDir, '.local', 'share', 'opencode');
|
|
50
|
+
await mkdir(authDir, { recursive: true });
|
|
51
|
+
await writeFile(path.join(authDir, 'auth.json'), JSON.stringify(auth), 'utf8');
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
test('OpenCode exposes only the curated predefined catalog', async () => {
|
|
55
|
+
await withOpenCodeHome(async () => {}, async (adapter) => {
|
|
56
|
+
// Nothing readable about this install, so the picker keeps every option
|
|
57
|
+
// rather than coming up empty.
|
|
58
|
+
assert.deepEqual(await adapter.getSupportedModels(), OPENCODE_PREDEFINED_MODELS);
|
|
59
|
+
assert.equal(
|
|
60
|
+
(await adapter.getCurrentActiveModel()).model,
|
|
61
|
+
OPENCODE_PREDEFINED_MODELS.DEFAULT,
|
|
62
|
+
);
|
|
63
|
+
});
|
|
17
64
|
// OpenCode routes by `<providerID>/<modelID>`, so every option has to carry a
|
|
18
65
|
// provider prefix that `opencode models --verbose` reports.
|
|
19
66
|
const providerIds = new Set(
|
|
20
67
|
OPENCODE_PREDEFINED_MODELS.OPTIONS.map((option) => option.value.split('/')[0]),
|
|
21
68
|
);
|
|
22
|
-
assert.deepEqual([...providerIds].sort(), ['anthropic', 'opencode', 'openai'].sort());
|
|
69
|
+
assert.deepEqual([...providerIds].sort(), ['anthropic', 'opencode', 'opencode-go', 'openai'].sort());
|
|
23
70
|
assert.equal(
|
|
24
71
|
OPENCODE_PREDEFINED_MODELS.OPTIONS.every((option) => /^[a-z0-9-]+\/.+/.test(option.value)),
|
|
25
72
|
true,
|
|
@@ -38,4 +85,115 @@ test('OpenCode exposes only the curated predefined catalog', async () => {
|
|
|
38
85
|
assert.ok(
|
|
39
86
|
OPENCODE_PREDEFINED_MODELS.OPTIONS.some((option) => option.value === 'openai/gpt-5.6'),
|
|
40
87
|
);
|
|
88
|
+
// The Go gateway carries its own provider id, so its models must be curated
|
|
89
|
+
// too - a Go subscriber otherwise authenticates while the picker offers
|
|
90
|
+
// nothing they can run.
|
|
91
|
+
const opencodeGoOptions = OPENCODE_PREDEFINED_MODELS.OPTIONS.filter(
|
|
92
|
+
(option) => option.value.startsWith('opencode-go/'),
|
|
93
|
+
);
|
|
94
|
+
assert.equal(opencodeGoOptions.length, 27);
|
|
95
|
+
assert.ok(opencodeGoOptions.every((option) => option.description === 'OpenCode Go'));
|
|
96
|
+
const glmFlash = opencodeGoOptions.find(
|
|
97
|
+
(option) => option.value === 'opencode-go/glm-5.3-flash',
|
|
98
|
+
);
|
|
99
|
+
assert.ok(glmFlash);
|
|
100
|
+
// Effort choices come from `opencode models --verbose` variants; the runtime
|
|
101
|
+
// turns a selected value into `--variant`, so the values have to match the
|
|
102
|
+
// CLI's exactly.
|
|
103
|
+
assert.deepEqual(
|
|
104
|
+
glmFlash?.effort?.values.map((value) => value.value),
|
|
105
|
+
['low', 'high', 'max'],
|
|
106
|
+
);
|
|
107
|
+
assert.ok(
|
|
108
|
+
opencodeGoOptions
|
|
109
|
+
.filter((option) => !option.effort)
|
|
110
|
+
.every((option) =>
|
|
111
|
+
['glm-5.1', 'kimi-k2.6', 'kimi-k2.7-code', 'mimo-v2.5', 'mimo-v2.5-pro',
|
|
112
|
+
'minimax-m2.7', 'qwen3.6-plus', 'qwen3.7-max', 'qwen3.7-plus']
|
|
113
|
+
.includes(option.value.slice('opencode-go/'.length)),
|
|
114
|
+
),
|
|
115
|
+
);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test('OpenCode offers only models the install can route to', async () => {
|
|
119
|
+
// Asking for a provider the user never connected fails the whole run with
|
|
120
|
+
// "Model <id> is not valid", so an OpenCode Zen model must not be offered -
|
|
121
|
+
// or defaulted to - on a machine that only holds an Anthropic key.
|
|
122
|
+
await withOpenCodeHome(
|
|
123
|
+
(homeDir) => writeOpenCodeAuth(homeDir, { anthropic: { type: 'api', key: 'test' } }),
|
|
124
|
+
async (adapter) => {
|
|
125
|
+
const catalog = await adapter.getSupportedModels();
|
|
126
|
+
const providerIds = new Set(catalog.OPTIONS.map((option) => option.value.split('/')[0]));
|
|
127
|
+
|
|
128
|
+
assert.deepEqual([...providerIds], ['anthropic']);
|
|
129
|
+
assert.ok(catalog.OPTIONS.length > 0);
|
|
130
|
+
assert.equal(catalog.DEFAULT.startsWith('anthropic/'), true);
|
|
131
|
+
assert.ok(catalog.OPTIONS.some((option) => option.value === catalog.DEFAULT));
|
|
132
|
+
assert.equal((await adapter.getCurrentActiveModel()).model, catalog.DEFAULT);
|
|
133
|
+
},
|
|
134
|
+
);
|
|
135
|
+
|
|
136
|
+
// A Go subscriber's auth store holds only `opencode-go`, so the whole catalog
|
|
137
|
+
// has to resolve to Go models and the default has to move onto one of them
|
|
138
|
+
// instead of the unreachable Zen default.
|
|
139
|
+
await withOpenCodeHome(
|
|
140
|
+
(homeDir) => writeOpenCodeAuth(homeDir, { 'opencode-go': { type: 'api', key: 'test' } }),
|
|
141
|
+
async (adapter) => {
|
|
142
|
+
const catalog = await adapter.getSupportedModels();
|
|
143
|
+
const providerIds = new Set(catalog.OPTIONS.map((option) => option.value.split('/')[0]));
|
|
144
|
+
|
|
145
|
+
assert.deepEqual([...providerIds], ['opencode-go']);
|
|
146
|
+
assert.equal(catalog.OPTIONS.length, 27);
|
|
147
|
+
assert.equal(catalog.DEFAULT, 'opencode-go/grok-4.6');
|
|
148
|
+
assert.ok(catalog.OPTIONS.some((option) => option.value === catalog.DEFAULT));
|
|
149
|
+
assert.equal((await adapter.getCurrentActiveModel()).model, catalog.DEFAULT);
|
|
150
|
+
},
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
// The catalog default survives whenever its own provider is connected.
|
|
154
|
+
await withOpenCodeHome(
|
|
155
|
+
(homeDir) => writeOpenCodeAuth(homeDir, {
|
|
156
|
+
opencode: { type: 'api', key: 'test' },
|
|
157
|
+
openai: { type: 'oauth' },
|
|
158
|
+
}),
|
|
159
|
+
async (adapter) => {
|
|
160
|
+
const catalog = await adapter.getSupportedModels();
|
|
161
|
+
const providerIds = new Set(catalog.OPTIONS.map((option) => option.value.split('/')[0]));
|
|
162
|
+
|
|
163
|
+
assert.deepEqual([...providerIds].sort(), ['opencode', 'openai'].sort());
|
|
164
|
+
assert.equal(catalog.DEFAULT, OPENCODE_PREDEFINED_MODELS.DEFAULT);
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
// Providers configured rather than logged into count too.
|
|
169
|
+
await withOpenCodeHome(
|
|
170
|
+
async (homeDir) => {
|
|
171
|
+
const configDir = path.join(homeDir, '.config', 'opencode');
|
|
172
|
+
await mkdir(configDir, { recursive: true });
|
|
173
|
+
await writeFile(
|
|
174
|
+
path.join(configDir, 'opencode.json'),
|
|
175
|
+
JSON.stringify({ provider: { anthropic: { options: {} } } }),
|
|
176
|
+
'utf8',
|
|
177
|
+
);
|
|
178
|
+
},
|
|
179
|
+
async (adapter) => {
|
|
180
|
+
const catalog = await adapter.getSupportedModels();
|
|
181
|
+
const providerIds = new Set(catalog.OPTIONS.map((option) => option.value.split('/')[0]));
|
|
182
|
+
|
|
183
|
+
assert.deepEqual([...providerIds], ['anthropic']);
|
|
184
|
+
},
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
// An API key in the environment is enough on its own.
|
|
188
|
+
await withOpenCodeHome(
|
|
189
|
+
async () => {
|
|
190
|
+
process.env.OPENAI_API_KEY = 'test';
|
|
191
|
+
},
|
|
192
|
+
async (adapter) => {
|
|
193
|
+
const catalog = await adapter.getSupportedModels();
|
|
194
|
+
const providerIds = new Set(catalog.OPTIONS.map((option) => option.value.split('/')[0]));
|
|
195
|
+
|
|
196
|
+
assert.deepEqual([...providerIds], ['openai']);
|
|
197
|
+
},
|
|
198
|
+
);
|
|
41
199
|
});
|