@nextclaw/ui 0.15.25 → 0.15.27
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/CHANGELOG.md +34 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-DvTjgVMf.js → abnfDiagram-VRR7QNED-BcFJp_1X.js} +1 -1
- package/dist/assets/{aiden0z-pptx-renderer.es-C1nfBAXR.js → aiden0z-pptx-renderer.es-Dp2ezlQn.js} +1 -1
- package/dist/assets/{api-FK7tikI1.js → api-a_GaOFc7.js} +6 -6
- package/dist/assets/appearance-settings-page-DlGXLgff.js +1 -0
- package/dist/assets/{arc-BvhODBXv.js → arc-CkgyPMyW.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-DO2x53FK.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-BKO9RgNS.js → architectureDiagram-ZJ3FMSHR-CMd4cIjI.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-DHpDXy7D.js → blockDiagram-677ZJIJ3-Bz3tbhet.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-BG_iQnDr.js → c4Diagram-LMCZKHZV-D9hFNAGv.js} +1 -1
- package/dist/assets/channel-nBvMaVyP.js +1 -0
- package/dist/assets/{channels-list-page-CocdcIko.js → channels-list-page-BEEk4Uc9.js} +2 -2
- package/dist/assets/chat-page-DUQXXqQm.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-CJgqFDS4.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-DR9M0LLx.js → chunk-32BRIVSS-7NrjEITq.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-698iC3BB.js → chunk-52WLFC77-viIcqj9q.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-DikTj9Ey.js → chunk-5FCAYU7R-Vsu4J-VM.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-ko0o7_q0.js → chunk-5HE753X5-C-w6CQZK.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-CEHufhgo.js → chunk-5JV3BV7I-CuKgJQ4W.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-CGgno1cu.js → chunk-5TONJI2A-CYeiWZKb.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DkiB4cUQ.js → chunk-5VM5RSS4-DRCbfwIn.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-DzptcytQ.js → chunk-7BUUIJ7U-BvydOcm3.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-DMRSQJvT.js → chunk-BIQX33UG-RlppOXKo.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-Bw1BwwuY.js → chunk-C7G6YPKG-DAizzYwr.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-C0z6eHBk.js → chunk-CQNSW5MT-5eChJHca.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-ByPyAouO.js → chunk-CYSBUYHQ-YHPr53fv.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-CJlAXWZg.js → chunk-EMLP6XTP-CK4D7Hz5.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-Dqq4zKJu.js → chunk-EX3LRPZG-BmlDFIRW.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-B0SNoCmi.js → chunk-FWX5IMBZ-D0ksHZZ9.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-DG_GJih_.js → chunk-HOUHSVGY-DPkq8FCm.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-Drxk_6bE.js → chunk-ICXQ74PX-FAatv5fC.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-DdLFPpnd.js → chunk-JG7HCLWE-DLkIi4F7.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-B8M4G76F.js → chunk-JWPE2WC7-DawOjNE3.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-XP6FJHY_.js → chunk-MOJQB5TN-Di52TorW.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-C_6x18Qw.js → chunk-MOZMSUNE-PfyK9w1-.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-N25BzCmG.js → chunk-OGEWGWER-C3jdH3Ty.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-ASDEm7y0.js → chunk-OSBZ3O6U-CecHo-f0.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-CTlvAcn7.js → chunk-PUDLZKDR-f3IJh3sN.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-Da9BWfB6.js → chunk-Q4XR5HBZ-DQFeUPxZ.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-Bi6RpTJO.js → chunk-QBLGF6JB-BhUeG0y2.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-DkMsSPvK.js → chunk-R7FJI6CG-C3XpZ-2u.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-DZp0eU-j.js → chunk-RYQCIY6F-CAqa5klQ.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-vfinDSrj.js → chunk-U6XO7XAA-D_WXezeD.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-C9Nksccs.js → chunk-V7JOEXUC-CZ70oOtp.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-BGvh3yIx.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-Xv6zfwXs.js → chunk-VR4S4FIN-B7AHEYYk.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-mOJNzbWl.js → chunk-WYO6CB5R-Dn9To_OI.js} +2 -2
- package/dist/assets/chunk-XXDRQBXY-DaBxG5gs.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-1-aKSu4o.js → chunk-YOTPTUD7-BYEgRBk3.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-OJ8veMpK.js → chunk-ZGVPDNZ5-C6YtZDU0.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-SR_Nq_PP.js → chunk-ZIRB5QZD-DMuYtnHF.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-P6N03G2R.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-B1_uLvMv.js +1 -0
- package/dist/assets/config-split-page-ps1Aod3g.js +1 -0
- package/dist/assets/confirm-dialog-DJSUNG33.js +5 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-NjVgz2Bw.js → cose-bilkent-JH36ORCC-Bc2Ex5Y3.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-B-H8Qp-n.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-B_17LDqD.js → cynefinDiagram-TSTJHNR4-DVysQoGz.js} +1 -1
- package/dist/assets/{dagre-CMe101gk.js → dagre-CMhQ1cAG.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-qo8nLb3B.js → dagre-VKFMJZFB-RYyWpPJZ.js} +1 -1
- package/dist/assets/desktop-update-config--zagjHic.js +1 -0
- package/dist/assets/{diagram-FQU43EPY-Ba3XIklC.js → diagram-FQU43EPY-BD6KONdF.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-CG45TcUx.js → diagram-G47NLZAW-CGB2ptRR.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-2F2HrwV-.js → diagram-NH7WQ7WH-DnkOI6cU.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-CXfWH9NZ.js → diagram-OA4YK3LP-DF82RZ7P.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-CH_4yepc.js → diagram-WEI45ONY-Be2v7Ck9.js} +1 -1
- package/dist/assets/{dist-CaYdVVeO.js → dist-BkTYNzm_.js} +1 -1
- package/dist/assets/{dist-BH7W5yCi.js → dist-DkR7_Dpl.js} +1 -1
- package/dist/assets/doc-browser-DahzJEWj.js +1 -0
- package/dist/assets/doc-browser-Q67TOGVS.js +1 -0
- package/dist/assets/doc-browser-context-BQim8SqD.js +1 -0
- package/dist/assets/{docx-preview-CoM4JK7_.js → docx-preview-BqwAjrj3.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BwiG4Ea1.js → ebnfDiagram-CCIWWBDH-CP98OYk8.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-BML3hpnQ.js → erDiagram-Q63AITRT-ZLlx8xfs.js} +1 -1
- package/dist/assets/eventmodeling-45OFAUF4-YVtShyFA.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-BeKXabVO.js +1 -0
- package/dist/assets/{form-actions-0c0aw_bl.js → form-actions-B2-bpFie.js} +1 -1
- package/dist/assets/{ganttDiagram-NO4QXBWP-80enfWbD.js → ganttDiagram-NO4QXBWP-DXCDjHR2.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-jTSiBj-p.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-CVLqXr-b.js → gitGraphDiagram-IHSO6WYX-l2HWrTJp.js} +1 -1
- package/dist/assets/index-Ba_o5fu9.js +109 -0
- package/dist/assets/index-DSLK7zgR.css +1 -0
- package/dist/assets/info-DKCQHKI2-BIporNWb.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-Dyvs2t0i.js → infoDiagram-FWYZ7A6U-D-DjX-bn.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-sSnxDKfh.js → ishikawaDiagram-FXEZZL3T-y_Xy128F.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-D22V71Mf.js → journeyDiagram-5HDEW3XC-DJn5xYcQ.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-D3ds0p-g.js → kanban-definition-HUTT4EX6-DJVIOR21.js} +1 -1
- package/dist/assets/{line-CbyFs065.js → line-Cos7PIOj.js} +1 -1
- package/dist/assets/{linear-4DKtnZBS.js → linear-BtDLqtzF.js} +1 -1
- package/dist/assets/loader-circle-DyXZU92l.js +1 -0
- package/dist/assets/{map-CcZzEoz6.js → map-BKnQyvd0.js} +1 -1
- package/dist/assets/mcp-marketplace-page-B0dBE5CV.js +1 -0
- package/dist/assets/mcp-marketplace-page-w8panjZG.js +9 -0
- package/dist/assets/{mermaid-parser.core-DPmMOjXD.js → mermaid-parser.core-XUNZhr2W.js} +2 -2
- package/dist/assets/{mermaid.core-BSf-ddRa.js → mermaid.core-ySrvolIe.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-BUTwWPyx.js → mindmap-definition-LN4V7U3C-BypL9tei.js} +1 -1
- package/dist/assets/model-config-page-rrhFaque.js +1 -0
- package/dist/assets/{navigation-link-CVy0_kVl.js → navigation-link-mpHFXwRr.js} +2 -2
- package/dist/assets/{ordinal-BgLYtOZE.js → ordinal-CxxVWxYU.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-CuFMADV0.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-BEu_ZBjc.js → pegDiagram-2B236MQR-D-U2KBGv.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-XUeIXhM9.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-CAwAwuBd.js → pieDiagram-ENE6RG2P-CBi3GusJ.js} +1 -1
- package/dist/assets/plus-Dhb4KuMH.js +1 -0
- package/dist/assets/provider-scoped-model-input-CFsfWEt9.js +1 -0
- package/dist/assets/providers-config-page-D-TYFZsF.js +1 -0
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-CwE6F-_2.js → quadrantDiagram-ABIIQ3AL-H0ZuvnZL.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-D-NNGh1k.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-C67_uDaM.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-BZ8Yflnd.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-B7zO7RoK.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-R63PTgLz.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-xgLekU3B.js → railroadDiagram-RFXS5EU6-D7Y2EqSd.js} +1 -1
- package/dist/assets/react-BlXwvOLo.js +8 -0
- package/dist/assets/{refresh-cw-j2bl79Ea.js → refresh-cw-JFuyDj_P.js} +1 -1
- package/dist/assets/remote-BwVv_Qq-.js +1 -0
- package/dist/assets/{requirementDiagram-TGXJPOKE-CyVUzEX5.js → requirementDiagram-TGXJPOKE-BiXNX1NN.js} +1 -1
- package/dist/assets/rotate-cw-DjbbiIW_.js +1 -0
- package/dist/assets/runtime-config-page-Br9j9Vxe.js +1 -0
- package/dist/assets/{sankeyDiagram-HTMAVEWB-JK6bFmYB.js → sankeyDiagram-HTMAVEWB-qzDeLztW.js} +1 -1
- package/dist/assets/{save-BKNrtK81.js → save-BL8P8CLX.js} +1 -1
- package/dist/assets/{search-CkOm65W_.js → search-bZL75Pgc.js} +1 -1
- package/dist/assets/search-config-page-B3fvzMd1.js +1 -0
- package/dist/assets/secrets-config-page-ClwTxtXd.js +3 -0
- package/dist/assets/security-config-DmJw9QZA.js +1 -0
- package/dist/assets/{select-Ea7ffKCE.js → select-rUZ8nIZu.js} +2 -2
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BR5IokXV.js → sequenceDiagram-DBY2YBRQ-BtRbPQtL.js} +1 -1
- package/dist/assets/{settings-2-CtyN3m_V.js → settings-2-BI4SCkxQ.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-SxG_YnMA.js → sizeCapture-X5ZJPWSS-CMYvM3SL.js} +1 -1
- package/dist/assets/skeleton-CVmEPG43.js +1 -0
- package/dist/assets/{src-vgz8E_-O.js → src-Bw-mzbQb.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-DD4OoYhn.js → stateDiagram-2N3HPSRC-BJ-mFeOz.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-BE-HqxOK.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-BWkFeyCT.js → swimlanes-5IMT3BWC-BsucVOO2.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-Dr1H9LJH.js +8 -0
- package/dist/assets/{tag-chip-C9l4xsKp.js → tag-chip-BdI_yIOA.js} +1 -1
- package/dist/assets/{timeline-definition-FHXFAJF6-VTRPy6KA.js → timeline-definition-FHXFAJF6-Bicewlzo.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-npJ5dbqS.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-pYrBx6oa.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-Bvk42Pek.js → vennDiagram-L72KCM5P-BxOOnO9x.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-CmSRKLR8.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-DOFjx2s3.js → wardleyDiagram-EHGQE667-Cl7NltMv.js} +1 -1
- package/dist/assets/x-BcEayhV6.js +1 -0
- package/dist/assets/{xychartDiagram-FW5EYKEG-DY5yRTUc.js → xychartDiagram-FW5EYKEG-DiMIxQ7N.js} +1 -1
- package/dist/index.html +21 -22
- package/package.json +6 -6
- package/src/app/components/layout/app-layout.tsx +38 -2
- package/src/app/hooks/__tests__/use-app-event-consumers.test.ts +20 -0
- package/src/app/hooks/use-app-event-consumers.ts +21 -0
- package/src/app/presenters/app.presenter.ts +6 -0
- package/src/features/apps/components/__tests__/app-packages-panel.test.tsx +312 -0
- package/src/features/apps/components/__tests__/apps-panel.test.tsx +58 -0
- package/src/features/apps/components/app-artwork.tsx +49 -0
- package/src/features/apps/components/app-marketplace-catalog.tsx +332 -0
- package/src/features/apps/components/app-marketplace-cover.tsx +64 -0
- package/src/features/apps/components/app-marketplace-detail.tsx +161 -0
- package/src/features/apps/components/app-marketplace-dialog.tsx +152 -0
- package/src/features/apps/components/app-marketplace-operation.tsx +84 -0
- package/src/features/apps/components/app-package-card.tsx +417 -0
- package/src/features/apps/components/app-packages-panel.tsx +373 -0
- package/src/features/apps/components/apps-panel.tsx +31 -23
- package/src/features/apps/hooks/use-app-marketplace.test.ts +144 -0
- package/src/features/apps/hooks/use-app-marketplace.ts +65 -0
- package/src/features/apps/hooks/use-app-packages.ts +114 -0
- package/src/features/apps/index.ts +1 -0
- package/src/features/apps/managers/__tests__/app-package-operation-settlement.manager.test.ts +81 -0
- package/src/features/apps/managers/app-package-operation-settlement.manager.ts +80 -0
- package/src/features/apps/services/app-marketplace.service.ts +223 -0
- package/src/features/apps/types/app-marketplace.types.ts +75 -0
- package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +27 -4
- package/src/features/chat/components/layout/__tests__/chat-sidebar-session-area.test.tsx +36 -5
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +12 -13
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +49 -1
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +68 -7
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +25 -4
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +3 -0
- package/src/features/chat/features/conversation/components/session-queued-input-rows.tsx +24 -14
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-conversation-controller.test.tsx +53 -0
- package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx +18 -0
- package/src/features/chat/features/conversation/hooks/use-chat-composer-reference-intent.ts +4 -1
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +126 -32
- package/src/features/chat/features/conversation/hooks/use-session-run-queue.ts +12 -2
- package/src/features/chat/features/conversation/hooks/use-system-object-reference-select.ts +27 -0
- package/src/features/chat/features/conversation/utils/session-message-composer.utils.ts +5 -0
- package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +102 -0
- package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +71 -120
- package/src/features/chat/features/input/input-surface-plugins/__tests__/context-reference-plugin.test.ts +265 -18
- package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +7 -2
- package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.utils.ts +124 -0
- package/src/features/chat/features/input/input-surface-plugins/context-reference-items.utils.ts +99 -15
- package/src/features/chat/features/input/input-surface-plugins/context-reference-plugin.utils.ts +143 -139
- package/src/features/chat/features/input/input-surface-plugins/panel-app-input-surface-items.utils.ts +116 -0
- package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +1 -1
- package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +84 -1
- package/src/features/chat/features/input/utils/chat-composer-token-protocol.utils.ts +10 -0
- package/src/features/chat/features/input/utils/chat-inline-token-composer.utils.ts +148 -0
- package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +55 -101
- package/src/features/chat/features/input/utils/chat-system-object-reference.utils.test.ts +44 -0
- package/src/features/chat/features/input/utils/chat-system-object-reference.utils.ts +46 -0
- package/src/features/chat/features/message/hooks/use-chat-inline-token-actions.ts +8 -1
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +155 -18
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-text-selection.test.tsx +12 -8
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +80 -62
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +9 -2
- package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +83 -13
- package/src/features/chat/features/workspace/components/project-files/workspace-project-tree-view.tsx +93 -0
- package/src/features/chat/features/workspace/hooks/use-workspace-explorer-layout.ts +8 -11
- package/src/features/chat/features/workspace/hooks/use-workspace-file-actions.ts +68 -46
- package/src/features/chat/features/workspace/stores/__tests__/workspace-project-tree.store.test.ts +38 -0
- package/src/features/chat/features/workspace/stores/workspace-project-tree.store.ts +160 -0
- package/src/features/chat/index.ts +2 -1
- package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +29 -0
- package/src/features/chat/managers/chat-composer-intent.manager.ts +29 -2
- package/src/features/chat/managers/chat-draft-intent.manager.ts +18 -2
- package/src/features/chat/presenters/chat.presenter.ts +2 -2
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +6 -0
- package/src/features/chat/stores/chat-thread.store.ts +6 -0
- package/src/features/inbox/components/inbox-reader-dialog.test.tsx +38 -5
- package/src/features/inbox/components/inbox-reader-dialog.tsx +5 -3
- package/src/features/inbox/managers/inbox.manager.test.ts +28 -3
- package/src/features/inbox/managers/inbox.manager.ts +14 -4
- package/src/features/inbox/pages/inbox-page.test.ts +121 -2
- package/src/features/inbox/pages/inbox-page.tsx +5 -3
- package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +85 -1
- package/src/features/marketplace/hooks/__tests__/use-marketplace.test.tsx +44 -1
- package/src/features/marketplace/hooks/use-marketplace-item-actions.ts +23 -2
- package/src/features/marketplace/hooks/use-marketplace.ts +10 -0
- package/src/features/marketplace/index.ts +4 -0
- package/src/features/panel-apps/components/__tests__/panel-apps-list.test.tsx +1 -1
- package/src/features/panel-apps/components/panel-apps-list.tsx +1 -6
- package/src/features/panel-apps/index.ts +5 -1
- package/src/features/panel-apps/utils/__tests__/panel-app-doc-browser.utils.test.ts +13 -6
- package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +6 -3
- package/src/features/right-panel-resources/index.ts +1 -0
- package/src/features/right-panel-resources/utils/__tests__/right-panel-resource-uri.utils.test.ts +34 -0
- package/src/features/right-panel-resources/utils/right-panel-resource-uri.utils.ts +36 -4
- package/src/features/service-apps/components/service-apps-panel.tsx +3 -17
- package/src/features/system-status/components/__tests__/desktop-update-config.test.tsx +20 -1
- package/src/features/system-status/components/desktop-update-config.tsx +14 -13
- package/src/features/system-status/managers/__tests__/runtime-update.manager.test.ts +99 -0
- package/src/features/system-status/managers/runtime-update.manager.ts +22 -0
- package/src/features/system-status/stores/runtime-update.store.ts +1 -0
- package/src/platforms/desktop/components/desktop-app-shell.tsx +5 -0
- package/src/platforms/mobile/components/mobile-app-shell.tsx +9 -1
- package/src/shared/components/actions/__tests__/navigation-link.test.tsx +12 -0
- package/src/shared/components/actions/navigation-link.tsx +6 -3
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +34 -0
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +5 -0
- package/src/shared/components/doc-browser/doc-browser.tsx +11 -1
- package/src/shared/components/doc-browser/managers/doc-browser.manager.ts +13 -0
- package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +15 -0
- package/src/shared/components/ui/actions/icon-action-button.tsx +4 -2
- package/src/shared/components/ui/tabs.tsx +24 -1
- package/src/shared/hooks/use-server-path-watch.ts +42 -0
- package/src/shared/hooks/use-system-object-references.ts +22 -0
- package/src/shared/lib/api/server-path/server-path.types.ts +10 -0
- package/src/shared/lib/api/types.ts +13 -0
- package/src/shared/lib/api/utils/server-path.utils.ts +10 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +17 -9
- package/src/shared/lib/i18n/locales/en-US/desktop-update.json +7 -4
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +82 -0
- package/src/shared/lib/i18n/locales/en-US/marketplace.json +3 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +19 -11
- package/src/shared/lib/i18n/locales/zh-CN/desktop-update.json +7 -4
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +82 -0
- package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +3 -0
- package/vite.config.ts +32 -1
- package/dist/assets/appearance-settings-page-BYbvl2wj.js +0 -1
- package/dist/assets/architecture-TIHT7OUA-Bjp9jf0h.js +0 -1
- package/dist/assets/channel-5T3pdR-s.js +0 -1
- package/dist/assets/chat-page-C5E-LLVd.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-DTZ3tGfE.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-HLGIHQ6k.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-Dl0m6Ni-.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-DcDnzGNX.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-BKXKMzKM.js +0 -1
- package/dist/assets/config-split-page-CA_a0AJ5.js +0 -1
- package/dist/assets/confirm-dialog-CxZfenjK.js +0 -5
- package/dist/assets/cynefin-VYW2F7L2-BWg7U2UD.js +0 -1
- package/dist/assets/desktop-update-config-BEKC8Ly9.js +0 -1
- package/dist/assets/doc-browser-Cl2ldE3f.js +0 -1
- package/dist/assets/doc-browser-DXCSd63E.js +0 -1
- package/dist/assets/doc-browser-context-FDPs3gJf.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-SB-J4tpq.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-BQ_u-eLM.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-DPxNwsFd.js +0 -1
- package/dist/assets/i18n-provider-DkITJNz8.js +0 -1
- package/dist/assets/index-CQ2LcI2p.css +0 -1
- package/dist/assets/index-CrdfvBVg.js +0 -107
- package/dist/assets/info-DKCQHKI2-DNlNGH90.js +0 -1
- package/dist/assets/loader-circle-DHtUxCIA.js +0 -1
- package/dist/assets/mcp-marketplace-page-Bc_jI5iH.js +0 -9
- package/dist/assets/mcp-marketplace-page-CzCieD9r.js +0 -1
- package/dist/assets/model-config-page-C4jw-pcj.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BpeiqkBZ.js +0 -1
- package/dist/assets/pie-RZYD4A2V-Cy1yxsPd.js +0 -1
- package/dist/assets/plus-CG1RwZQq.js +0 -1
- package/dist/assets/provider-scoped-model-input-CmH4BFvc.js +0 -1
- package/dist/assets/providers-config-page-CJQjwzaw.js +0 -1
- package/dist/assets/radar-I7S5WNFK-CEcPKCj8.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-CW38eNDs.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-ByrylcXf.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-CNB6GwP-.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-x6hnqlBG.js +0 -1
- package/dist/assets/react-DjFBVA0n.js +0 -8
- package/dist/assets/remote-BIlpD3yL.js +0 -1
- package/dist/assets/rotate-cw-bKG8zH8M.js +0 -1
- package/dist/assets/runtime-config-page-B_x2Glz5.js +0 -1
- package/dist/assets/search-config-page-BaIijtmO.js +0 -1
- package/dist/assets/secrets-config-page-CJjtdFAl.js +0 -3
- package/dist/assets/security-config-DB8apj09.js +0 -1
- package/dist/assets/skeleton-Bt6zxcAB.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-ZC6dFORv.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-CRkh51Im.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-Bw0DSCH7.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-DFWBFcfh.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-CoWturk0.js +0 -1
- package/dist/assets/x-CowtCu9Z.js +0 -1
- /package/dist/assets/{array-NADKd9aU.js → array-BQVzeGRt.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-BuyuzJJL.js → chunk-KEIR6QF5-f9psyCXK.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-D_B2ZRNt.js → chunk-Y2CYZVJY-D1mAU_Po.js} +0 -0
- /package/dist/assets/{config-hints-BcfVUMij.js → config-hints-nV5HPOvq.js} +0 -0
- /package/dist/assets/{cytoscape.esm-BANTlgza.js → cytoscape.esm-0uDtdD0l.js} +0 -0
- /package/dist/assets/{defaultLocale-C4_L0aEs.js → defaultLocale-DSWXGgt0.js} +0 -0
- /package/dist/assets/{dist-DAPEIJbz.js → dist--ta5rX12.js} +0 -0
- /package/dist/assets/{graphlib-ChqXg0dI.js → graphlib-CQ6QV4yP.js} +0 -0
- /package/dist/assets/{host-capabilities-D9C4CBK5.js → host-capabilities-Tk038i04.js} +0 -0
- /package/dist/assets/{init-D8wZg9xq.js → init-Y6h9jGtZ.js} +0 -0
- /package/dist/assets/{jszip.min-CkbBfwAQ.js → jszip.min-8hyJpgpx.js} +0 -0
- /package/dist/assets/{katex-TZJFa0J_.js → katex-ARhY9PS1.js} +0 -0
- /package/dist/assets/{middleware-B3k-TSmZ.js → middleware-DXsbf9xI.js} +0 -0
- /package/dist/assets/{path-DodfxcX7.js → path-10BjdyLh.js} +0 -0
- /package/dist/assets/{rough.esm-CUaa1Rbe.js → rough.esm-DxgC_14r.js} +0 -0
- /package/dist/assets/{xlsx-CxByi7bR.js → xlsx-DrDuDNAa.js} +0 -0
|
@@ -25,13 +25,34 @@ function renderSessionArea(isProjectFirstView: boolean) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
describe("ChatSidebarSessionArea", () => {
|
|
28
|
-
it("
|
|
28
|
+
it("renders an accessible animated segmented control for list modes", () => {
|
|
29
29
|
const { onSelectMode } = renderSessionArea(false);
|
|
30
|
+
const modeGroup = screen.getByRole("group", { name: "Session list view" });
|
|
31
|
+
const timeButton = screen.getByRole("button", { name: "Time" });
|
|
32
|
+
const projectButton = screen.getByRole("button", { name: "Project" });
|
|
30
33
|
|
|
31
|
-
expect(
|
|
32
|
-
|
|
33
|
-
).toContain("
|
|
34
|
-
|
|
34
|
+
expect(modeGroup.className).toContain("h-7");
|
|
35
|
+
expect(modeGroup.className).toContain("rounded-full");
|
|
36
|
+
expect(modeGroup.className).toContain("bg-foreground/[0.04]");
|
|
37
|
+
expect(modeGroup.className).not.toContain("border");
|
|
38
|
+
expect(modeGroup.className).not.toContain("shadow-inner");
|
|
39
|
+
const modeIndicator = modeGroup.querySelector("span[aria-hidden='true']");
|
|
40
|
+
expect(modeIndicator?.className).toContain("rounded-full");
|
|
41
|
+
expect(modeIndicator?.className).toContain("bg-gray-200/70");
|
|
42
|
+
expect(modeIndicator?.className).not.toContain("shadow-");
|
|
43
|
+
expect(modeIndicator?.className).not.toContain("ring-");
|
|
44
|
+
expect(modeIndicator?.className).toContain("transition-transform");
|
|
45
|
+
expect(timeButton.getAttribute("aria-pressed")).toBe("true");
|
|
46
|
+
expect(projectButton.getAttribute("aria-pressed")).toBe("false");
|
|
47
|
+
expect(timeButton.className).toContain("rounded-full");
|
|
48
|
+
expect(projectButton.className).toContain("rounded-full");
|
|
49
|
+
expect(timeButton.querySelector("svg")).not.toBeNull();
|
|
50
|
+
expect(projectButton.querySelector("svg")).not.toBeNull();
|
|
51
|
+
expect(modeGroup.parentElement?.className).toContain("justify-end");
|
|
52
|
+
expect(modeGroup.parentElement?.className).toContain("h-8");
|
|
53
|
+
expect(modeGroup.parentElement?.lastElementChild).toBe(modeGroup);
|
|
54
|
+
|
|
55
|
+
fireEvent.click(projectButton);
|
|
35
56
|
|
|
36
57
|
expect(onSelectMode).toHaveBeenCalledWith("project-first");
|
|
37
58
|
});
|
|
@@ -39,12 +60,22 @@ describe("ChatSidebarSessionArea", () => {
|
|
|
39
60
|
it("uses a folder-plus icon for the add-project action", () => {
|
|
40
61
|
const { onAddProject } = renderSessionArea(true);
|
|
41
62
|
const addProjectButton = screen.getByRole("button", { name: "Add Project" });
|
|
63
|
+
const modeIndicator = screen
|
|
64
|
+
.getByRole("group", { name: "Session list view" })
|
|
65
|
+
.querySelector("span[aria-hidden='true']");
|
|
42
66
|
|
|
43
67
|
expect(
|
|
44
68
|
addProjectButton
|
|
45
69
|
.querySelector("svg")
|
|
46
70
|
?.classList.contains("lucide-folder-plus"),
|
|
47
71
|
).toBe(true);
|
|
72
|
+
expect(addProjectButton.className).toContain("hover:bg-gray-200/60");
|
|
73
|
+
expect(modeIndicator?.className).toContain("translate-x-full");
|
|
74
|
+
expect(modeIndicator?.className).toContain("motion-reduce:transition-none");
|
|
75
|
+
expect(screen.getByRole("button", { name: "Project" }).getAttribute("aria-pressed")).toBe(
|
|
76
|
+
"true",
|
|
77
|
+
);
|
|
78
|
+
expect(modeIndicator?.parentElement?.previousElementSibling).toBe(addProjectButton);
|
|
48
79
|
fireEvent.click(addProjectButton);
|
|
49
80
|
|
|
50
81
|
expect(onAddProject).toHaveBeenCalledOnce();
|
|
@@ -165,20 +165,19 @@ export function ChatSidebarSessionArea({
|
|
|
165
165
|
|
|
166
166
|
return (
|
|
167
167
|
<>
|
|
168
|
-
<div className="flex items-center justify-end
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
<
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
/>
|
|
176
|
-
) : null}
|
|
177
|
-
<ChatSidebarListModeSwitch
|
|
178
|
-
isProjectFirstView={isProjectFirstView}
|
|
179
|
-
onSelectMode={onSelectMode}
|
|
168
|
+
<div className="flex h-8 items-center justify-end gap-1 px-3">
|
|
169
|
+
{isProjectFirstView ? (
|
|
170
|
+
<IconActionButton
|
|
171
|
+
icon={<FolderPlus className="h-3.5 w-3.5" />}
|
|
172
|
+
label={t("chatProjectAdd")}
|
|
173
|
+
tone="surface"
|
|
174
|
+
onClick={onAddProject}
|
|
180
175
|
/>
|
|
181
|
-
|
|
176
|
+
) : null}
|
|
177
|
+
<ChatSidebarListModeSwitch
|
|
178
|
+
isProjectFirstView={isProjectFirstView}
|
|
179
|
+
onSelectMode={onSelectMode}
|
|
180
|
+
/>
|
|
182
181
|
</div>
|
|
183
182
|
|
|
184
183
|
<div
|
|
@@ -4,6 +4,7 @@ import { MemoryRouter } from "react-router-dom";
|
|
|
4
4
|
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
5
5
|
|
|
6
6
|
import { SessionConversationArea } from "@/features/chat/features/conversation/components/session-conversation-area";
|
|
7
|
+
import type { ChatDraftIntent } from "@/features/chat/managers/chat-draft-intent.manager";
|
|
7
8
|
|
|
8
9
|
const mocks = vi.hoisted(() => {
|
|
9
10
|
const inputRenderSpy = vi.fn();
|
|
@@ -118,7 +119,7 @@ const mocks = vi.hoisted(() => {
|
|
|
118
119
|
},
|
|
119
120
|
appPresenter: {
|
|
120
121
|
chatDraftIntentManager: {
|
|
121
|
-
consumePending: vi.fn(() => null),
|
|
122
|
+
consumePending: vi.fn<() => ChatDraftIntent | null>(() => null),
|
|
122
123
|
markConsumed: vi.fn(),
|
|
123
124
|
subscribe: vi.fn(() => vi.fn()),
|
|
124
125
|
},
|
|
@@ -409,6 +410,53 @@ describe("SessionConversationArea input boundary", () => {
|
|
|
409
410
|
);
|
|
410
411
|
});
|
|
411
412
|
|
|
413
|
+
it("consumes a system object draft intent as a visible composer token", () => {
|
|
414
|
+
const reference = {
|
|
415
|
+
uri: "nextclaw://objects/inbox-delivery/delivery-1",
|
|
416
|
+
objectType: "inbox-delivery",
|
|
417
|
+
objectId: "delivery-1",
|
|
418
|
+
label: "OOM investigation report",
|
|
419
|
+
description: "Root cause and mitigation",
|
|
420
|
+
updatedAt: "2026-08-11T00:00:00.000Z",
|
|
421
|
+
version: "sha256-report",
|
|
422
|
+
assetUri: "asset://store/report",
|
|
423
|
+
fileName: "oom-investigation-report.md",
|
|
424
|
+
mimeType: "text/markdown",
|
|
425
|
+
sizeBytes: 128,
|
|
426
|
+
};
|
|
427
|
+
mocks.appPresenter.chatDraftIntentManager.consumePending.mockReturnValueOnce({
|
|
428
|
+
id: 1,
|
|
429
|
+
kind: "system-object-reference",
|
|
430
|
+
reference,
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
render(
|
|
434
|
+
<MemoryRouter>
|
|
435
|
+
<SessionConversationArea
|
|
436
|
+
consumeDraftIntent
|
|
437
|
+
sessionKey={null}
|
|
438
|
+
/>
|
|
439
|
+
</MemoryRouter>,
|
|
440
|
+
);
|
|
441
|
+
|
|
442
|
+
expect(mocks.presenter.chatSessionListManager.createSession).toHaveBeenCalledOnce();
|
|
443
|
+
expect(mocks.appPresenter.chatDraftIntentManager.markConsumed).toHaveBeenCalledWith(1);
|
|
444
|
+
const update = mocks.inputActions.update.mock.calls.at(-1)?.[0] as (
|
|
445
|
+
current: { nodes: []; text: string },
|
|
446
|
+
) => { nodes: Array<Record<string, unknown>>; text: string };
|
|
447
|
+
const next = update({ nodes: [], text: "" });
|
|
448
|
+
expect(next.nodes).toEqual([
|
|
449
|
+
expect.objectContaining({
|
|
450
|
+
type: "token",
|
|
451
|
+
tokenKind: "system_object",
|
|
452
|
+
tokenKey: reference.uri,
|
|
453
|
+
label: reference.label,
|
|
454
|
+
data: { reference },
|
|
455
|
+
}),
|
|
456
|
+
]);
|
|
457
|
+
expect(next.text).toBe("");
|
|
458
|
+
});
|
|
459
|
+
|
|
412
460
|
it("syncs draft preferences with the selected runtime context", () => {
|
|
413
461
|
mocks.inputQuery.defaultModel = "openai/gpt-5";
|
|
414
462
|
mocks.inputQuery.fallbackPreferredModel = "minimax/MiniMax-M3";
|
|
@@ -349,7 +349,7 @@ describe('SessionConversationInput streaming stability', () => {
|
|
|
349
349
|
|
|
350
350
|
it('inserts a project file reference at the saved composer caret', async () => {
|
|
351
351
|
const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
|
|
352
|
-
|
|
352
|
+
renderInput(
|
|
353
353
|
<StreamingSessionConversationInputHarness
|
|
354
354
|
controlRef={controlRef}
|
|
355
355
|
initialText="Hello"
|
|
@@ -427,11 +427,31 @@ describe('SessionConversationInput streaming stability', () => {
|
|
|
427
427
|
expect(deleteQueuedInput).toHaveBeenCalledWith('queued-2');
|
|
428
428
|
});
|
|
429
429
|
|
|
430
|
+
it('renders a submitting queue row immediately without premature edit actions', () => {
|
|
431
|
+
const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
|
|
432
|
+
renderInput(
|
|
433
|
+
<StreamingSessionConversationInputHarness
|
|
434
|
+
controlRef={controlRef}
|
|
435
|
+
controllerOverride={{
|
|
436
|
+
...controller,
|
|
437
|
+
queuedInputs: [
|
|
438
|
+
{ id: 'submitting-1', isSubmitting: true, preview: '正在提交的任务' },
|
|
439
|
+
],
|
|
440
|
+
}}
|
|
441
|
+
/>,
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
expect(screen.getByText('正在提交的任务')).toBeTruthy();
|
|
445
|
+
expect(screen.getByLabelText('Adding to queue…')).toBeTruthy();
|
|
446
|
+
expect(screen.queryByRole('button', { name: 'Edit queued input' })).toBeNull();
|
|
447
|
+
expect(screen.queryByRole('button', { name: 'Delete queued input' })).toBeNull();
|
|
448
|
+
});
|
|
449
|
+
|
|
430
450
|
it('leaves send-error rendering to the conversation surface', () => {
|
|
431
451
|
const controlRef: MutableRefObject<StreamingInputControl | null> = { current: null };
|
|
432
452
|
const providerError = 'Chat Completions API failed (402): raw provider error';
|
|
433
453
|
|
|
434
|
-
|
|
454
|
+
renderInput(
|
|
435
455
|
<StreamingSessionConversationInputHarness
|
|
436
456
|
controlRef={controlRef}
|
|
437
457
|
sendError={providerError}
|
|
@@ -456,9 +476,13 @@ function createAttachmentRunHandle(): NcpRunHandle {
|
|
|
456
476
|
|
|
457
477
|
function AttachmentSubmitHarness({
|
|
458
478
|
initialPrompt,
|
|
479
|
+
isRunning = false,
|
|
480
|
+
refreshQueuedInputs = async () => [],
|
|
459
481
|
send,
|
|
460
482
|
}: {
|
|
461
483
|
readonly initialPrompt?: string;
|
|
484
|
+
readonly isRunning?: boolean;
|
|
485
|
+
readonly refreshQueuedInputs?: () => Promise<readonly never[]>;
|
|
462
486
|
readonly send: AttachmentSubmitAgentSend;
|
|
463
487
|
}) {
|
|
464
488
|
const { inputActions, inputSnapshot } = useSessionConversationInputState(
|
|
@@ -503,14 +527,14 @@ function AttachmentSubmitHarness({
|
|
|
503
527
|
continueRun: vi.fn(),
|
|
504
528
|
editMessage: vi.fn(),
|
|
505
529
|
isHydrating: false,
|
|
506
|
-
isRunning
|
|
530
|
+
isRunning,
|
|
507
531
|
isSending: false,
|
|
508
532
|
send,
|
|
509
533
|
snapshot: {
|
|
510
|
-
activeRun: null,
|
|
534
|
+
activeRun: isRunning ? { sessionId: 'session-attachment' } : null,
|
|
511
535
|
},
|
|
512
536
|
visibleMessages: [],
|
|
513
|
-
}), [send]);
|
|
537
|
+
}), [isRunning, send]);
|
|
514
538
|
const controller = useSessionConversationController({
|
|
515
539
|
agent,
|
|
516
540
|
inputSnapshot,
|
|
@@ -518,6 +542,7 @@ function AttachmentSubmitHarness({
|
|
|
518
542
|
isRuntimeBlocked: false,
|
|
519
543
|
runQueue: {
|
|
520
544
|
inputs: [],
|
|
545
|
+
refreshQueuedInputs,
|
|
521
546
|
removeQueuedInput: async () => null,
|
|
522
547
|
},
|
|
523
548
|
selectedAgentId: 'main',
|
|
@@ -543,10 +568,46 @@ function AttachmentSubmitHarness({
|
|
|
543
568
|
}
|
|
544
569
|
|
|
545
570
|
describe('SessionConversationInput attachment submit', () => {
|
|
571
|
+
it('shows immediate queue feedback from the real send button before backend acknowledgement', async () => {
|
|
572
|
+
let resolveSend!: (handle: NcpRunHandle) => void;
|
|
573
|
+
const send = vi.fn<AttachmentSubmitAgentSend>(() => new Promise((resolve) => {
|
|
574
|
+
resolveSend = resolve;
|
|
575
|
+
}));
|
|
576
|
+
const refreshQueuedInputs = vi.fn(async () => [] as const);
|
|
577
|
+
|
|
578
|
+
renderInput(
|
|
579
|
+
<AttachmentSubmitHarness
|
|
580
|
+
initialPrompt="稍后继续这个任务"
|
|
581
|
+
isRunning
|
|
582
|
+
refreshQueuedInputs={refreshQueuedInputs}
|
|
583
|
+
send={send}
|
|
584
|
+
/>,
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
await act(async () => {
|
|
588
|
+
fireEvent.click(screen.getByRole('button', { name: /Queue|排队发送/ }));
|
|
589
|
+
await Promise.resolve();
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
expect(send).toHaveBeenCalledTimes(1);
|
|
593
|
+
const submittingStatus = screen.getByLabelText('Adding to queue…');
|
|
594
|
+
expect(submittingStatus.parentElement?.textContent).toContain('稍后继续这个任务');
|
|
595
|
+
await waitFor(() => expect(screen.getByRole('textbox').textContent).toBe(''));
|
|
596
|
+
expect(refreshQueuedInputs).not.toHaveBeenCalled();
|
|
597
|
+
|
|
598
|
+
await act(async () => {
|
|
599
|
+
resolveSend({ ...createAttachmentRunHandle(), runId: null });
|
|
600
|
+
await Promise.resolve();
|
|
601
|
+
});
|
|
602
|
+
|
|
603
|
+
await waitFor(() => expect(refreshQueuedInputs).toHaveBeenCalledTimes(1));
|
|
604
|
+
await waitFor(() => expect(screen.queryByLabelText('Adding to queue…')).toBeNull());
|
|
605
|
+
});
|
|
606
|
+
|
|
546
607
|
it('preserves a project file reference in the outgoing user message and AI context', async () => {
|
|
547
608
|
const send = vi.fn<AttachmentSubmitAgentSend>(async () => createAttachmentRunHandle());
|
|
548
609
|
|
|
549
|
-
|
|
610
|
+
renderInput(<AttachmentSubmitHarness initialPrompt="这里面有啥" send={send} />);
|
|
550
611
|
|
|
551
612
|
const textbox = screen.getByRole('textbox');
|
|
552
613
|
fireEvent.focus(textbox);
|
|
@@ -605,7 +666,7 @@ describe('SessionConversationInput attachment submit', () => {
|
|
|
605
666
|
|
|
606
667
|
it('preserves an exact workspace excerpt in the outgoing message metadata', async () => {
|
|
607
668
|
const send = vi.fn<AttachmentSubmitAgentSend>(async () => createAttachmentRunHandle());
|
|
608
|
-
|
|
669
|
+
renderInput(<AttachmentSubmitHarness initialPrompt="解释一下" send={send} />);
|
|
609
670
|
|
|
610
671
|
const textbox = screen.getByRole('textbox');
|
|
611
672
|
await waitFor(() => expect(textbox.textContent).toBe('解释一下'));
|
|
@@ -18,6 +18,10 @@ import { ChatConversationWelcome } from "@/features/chat/features/welcome/compon
|
|
|
18
18
|
import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
|
|
19
19
|
import { useSystemStatus } from "@/features/system-status";
|
|
20
20
|
import { t } from "@/shared/lib/i18n";
|
|
21
|
+
import type { SystemObjectResolvedReference } from "@nextclaw/shared";
|
|
22
|
+
import { deriveChatComposerDraft } from "@/features/chat/features/input/utils/chat-composer-state.utils";
|
|
23
|
+
import { appendSystemObjectReferenceToken } from "@/features/chat/features/input/utils/chat-system-object-reference.utils";
|
|
24
|
+
import type { ChatDraftIntent } from "@/features/chat/managers/chat-draft-intent.manager";
|
|
21
25
|
|
|
22
26
|
import {
|
|
23
27
|
useSessionConversationController,
|
|
@@ -42,18 +46,23 @@ type SessionConversationAreaProps = {
|
|
|
42
46
|
function useSessionConversationDraftIntent(params: {
|
|
43
47
|
readonly consumeDraftIntent: boolean;
|
|
44
48
|
readonly applyPromptSuggestion: (prompt: string) => void;
|
|
49
|
+
readonly applySystemObjectReference: (reference: SystemObjectResolvedReference) => void;
|
|
45
50
|
}) {
|
|
46
|
-
const { applyPromptSuggestion, consumeDraftIntent } = params;
|
|
51
|
+
const { applyPromptSuggestion, applySystemObjectReference, consumeDraftIntent } = params;
|
|
47
52
|
const appPresenter = useAppPresenter();
|
|
48
53
|
const presenter = usePresenter();
|
|
49
54
|
useEffect(() => {
|
|
50
55
|
if (!consumeDraftIntent) {
|
|
51
56
|
return undefined;
|
|
52
57
|
}
|
|
53
|
-
const applyIntent = (intent:
|
|
58
|
+
const applyIntent = (intent: ChatDraftIntent) => {
|
|
54
59
|
presenter.chatSessionListManager.createSession();
|
|
55
60
|
presenter.chatSessionListManager.setSelectedAgentId("main");
|
|
56
|
-
|
|
61
|
+
if (intent.kind === 'prompt') {
|
|
62
|
+
applyPromptSuggestion(intent.prompt);
|
|
63
|
+
} else {
|
|
64
|
+
applySystemObjectReference(intent.reference);
|
|
65
|
+
}
|
|
57
66
|
appPresenter.chatDraftIntentManager.markConsumed(intent.id);
|
|
58
67
|
};
|
|
59
68
|
const unsubscribe =
|
|
@@ -63,7 +72,7 @@ function useSessionConversationDraftIntent(params: {
|
|
|
63
72
|
applyIntent(pendingIntent);
|
|
64
73
|
}
|
|
65
74
|
return unsubscribe;
|
|
66
|
-
}, [appPresenter, applyPromptSuggestion, consumeDraftIntent, presenter]);
|
|
75
|
+
}, [appPresenter, applyPromptSuggestion, applySystemObjectReference, consumeDraftIntent, presenter]);
|
|
67
76
|
}
|
|
68
77
|
|
|
69
78
|
type ChatDraftRouteState = {
|
|
@@ -204,6 +213,17 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
|
|
|
204
213
|
initialPrompt,
|
|
205
214
|
sessionKey,
|
|
206
215
|
);
|
|
216
|
+
const applySystemObjectReference = useCallback((reference: SystemObjectResolvedReference) => {
|
|
217
|
+
inputActions.update((current) => {
|
|
218
|
+
const nodes = appendSystemObjectReferenceToken(current.nodes, reference);
|
|
219
|
+
return {
|
|
220
|
+
nodes,
|
|
221
|
+
text: deriveChatComposerDraft(nodes),
|
|
222
|
+
composerFocusRequestId: Date.now(),
|
|
223
|
+
sendError: null,
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
}, [inputActions]);
|
|
207
227
|
const inputQuery = useSessionConversationInputQuery({
|
|
208
228
|
sessionKey,
|
|
209
229
|
inputSnapshot,
|
|
@@ -355,6 +375,7 @@ export function SessionConversationArea(props: SessionConversationAreaProps) {
|
|
|
355
375
|
useSessionConversationDraftIntent({
|
|
356
376
|
consumeDraftIntent,
|
|
357
377
|
applyPromptSuggestion: inputActions.applyPromptSuggestion,
|
|
378
|
+
applySystemObjectReference,
|
|
358
379
|
});
|
|
359
380
|
const renderInput = useCallback(
|
|
360
381
|
(surface: "default" | "embedded", placeholder?: string) => (
|
|
@@ -47,6 +47,7 @@ import { useSessionConversationInputAttachments } from '@/features/chat/features
|
|
|
47
47
|
import { useChatComposerReferenceIntent } from '@/features/chat/features/conversation/hooks/use-chat-composer-reference-intent';
|
|
48
48
|
import { useSessionConversationComposerNodes } from '@/features/chat/features/conversation/hooks/use-session-conversation-composer-nodes';
|
|
49
49
|
import { useSessionConversationSlashCommands } from '@/features/chat/features/conversation/hooks/use-session-conversation-slash-commands';
|
|
50
|
+
import { useSystemObjectReferenceSelect } from '@/features/chat/features/conversation/hooks/use-system-object-reference-select';
|
|
50
51
|
import { ChatConversationTrack } from '@/features/chat/components/conversation/chat-conversation-track';
|
|
51
52
|
import { useChatMessageLayoutStore } from '@/features/chat/stores/chat-message-layout.store';
|
|
52
53
|
import type { useSessionConversationInputQuery } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-query';
|
|
@@ -231,6 +232,7 @@ export const SessionConversationInput = memo(function SessionConversationInput(p
|
|
|
231
232
|
const contextReferenceProjectRoot = inputQuery.selectedSessionKey
|
|
232
233
|
? inputQuery.selectedSession?.projectRoot ?? inputQuery.defaultProjectRoot ?? ''
|
|
233
234
|
: inputSnapshot.pendingProjectRoot ?? inputQuery.defaultProjectRoot ?? '';
|
|
235
|
+
const handleSystemObjectSelect = useSystemObjectReferenceSelect(inputBarRef);
|
|
234
236
|
const { inputSurfaceState, setInputSurfaceTrigger } = useChatInputSurfaceState({
|
|
235
237
|
commands: slashCommands,
|
|
236
238
|
isSkillsLoading: inputQuery.isSkillsLoading,
|
|
@@ -240,6 +242,7 @@ export const SessionConversationInput = memo(function SessionConversationInput(p
|
|
|
240
242
|
language,
|
|
241
243
|
onSelectPanelApp: handleSlashPanelAppSelect,
|
|
242
244
|
onSelectSkill: chatRecentSkillsManager.remember,
|
|
245
|
+
onSelectSystemObject: handleSystemObjectSelect,
|
|
243
246
|
projectRoot: contextReferenceProjectRoot,
|
|
244
247
|
recentSkillValues,
|
|
245
248
|
skillRecords,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import { CornerDownRight, Pencil, Trash2 } from 'lucide-react';
|
|
2
|
+
import { CornerDownRight, LoaderCircle, Pencil, Trash2 } from 'lucide-react';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
Tooltip,
|
|
@@ -74,20 +74,30 @@ export function SessionQueuedInputRows({
|
|
|
74
74
|
<span className="min-w-0 flex-1 truncate font-medium text-foreground/80">
|
|
75
75
|
{item.preview || t('chatQueuedBannerAttachmentFallback')}
|
|
76
76
|
</span>
|
|
77
|
-
|
|
78
|
-
<
|
|
79
|
-
label={t('
|
|
80
|
-
|
|
77
|
+
{item.isSubmitting ? (
|
|
78
|
+
<span
|
|
79
|
+
aria-label={t('chatQueuedSubmitting')}
|
|
80
|
+
className="inline-flex shrink-0 items-center gap-1.5 text-xs text-muted-foreground"
|
|
81
81
|
>
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
82
|
+
<LoaderCircle className="h-3.5 w-3.5 animate-spin" />
|
|
83
|
+
{t('chatQueuedSubmitting')}
|
|
84
|
+
</span>
|
|
85
|
+
) : (
|
|
86
|
+
<div className="flex shrink-0 items-center gap-1.5">
|
|
87
|
+
<QueuedInputIconButton
|
|
88
|
+
label={t('chatQueuedEdit')}
|
|
89
|
+
onClick={() => controller.editQueuedInput(item.id)}
|
|
90
|
+
>
|
|
91
|
+
<Pencil className="h-4 w-4" />
|
|
92
|
+
</QueuedInputIconButton>
|
|
93
|
+
<QueuedInputIconButton
|
|
94
|
+
label={t('chatQueuedDelete')}
|
|
95
|
+
onClick={() => controller.deleteQueuedInput(item.id)}
|
|
96
|
+
>
|
|
97
|
+
<Trash2 className="h-4 w-4" />
|
|
98
|
+
</QueuedInputIconButton>
|
|
99
|
+
</div>
|
|
100
|
+
)}
|
|
91
101
|
</div>
|
|
92
102
|
))}
|
|
93
103
|
</div>
|
|
@@ -59,6 +59,7 @@ function createControllerParams(params: {
|
|
|
59
59
|
const removeQueuedInput = vi.fn(async (id: string) =>
|
|
60
60
|
queuedInputs.find((item) => item.id === id) ?? null,
|
|
61
61
|
);
|
|
62
|
+
const refreshQueuedInputs = vi.fn(async () => queuedInputs);
|
|
62
63
|
return {
|
|
63
64
|
agent: {
|
|
64
65
|
abort: vi.fn(),
|
|
@@ -116,6 +117,7 @@ function createControllerParams(params: {
|
|
|
116
117
|
isRuntimeBlocked: false,
|
|
117
118
|
runQueue: {
|
|
118
119
|
inputs: queuedInputs,
|
|
120
|
+
refreshQueuedInputs,
|
|
119
121
|
removeQueuedInput,
|
|
120
122
|
},
|
|
121
123
|
selectedAgentId: 'main',
|
|
@@ -178,6 +180,57 @@ describe('useSessionConversationController backend run queue', () => {
|
|
|
178
180
|
expect(params.resetComposer).toHaveBeenCalledTimes(1);
|
|
179
181
|
});
|
|
180
182
|
|
|
183
|
+
it('projects a submitting queue row before the backend acknowledges the message', async () => {
|
|
184
|
+
let resolveSend!: (handle: NcpRunHandle) => void;
|
|
185
|
+
const send = vi.fn<TestAgentSend>(() => new Promise((resolve) => {
|
|
186
|
+
resolveSend = resolve;
|
|
187
|
+
}));
|
|
188
|
+
const params = createControllerParams({ isRunning: true, send });
|
|
189
|
+
const { result } = renderHook(() => useSessionConversationController(params));
|
|
190
|
+
let submission!: Promise<void>;
|
|
191
|
+
|
|
192
|
+
act(() => {
|
|
193
|
+
submission = result.current.send();
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
expect(params.resetComposer).toHaveBeenCalledTimes(1);
|
|
197
|
+
expect(result.current.queuedInputs).toEqual([
|
|
198
|
+
expect.objectContaining({
|
|
199
|
+
isSubmitting: true,
|
|
200
|
+
preview: 'next task',
|
|
201
|
+
}),
|
|
202
|
+
]);
|
|
203
|
+
expect(params.runQueue.refreshQueuedInputs).not.toHaveBeenCalled();
|
|
204
|
+
|
|
205
|
+
await act(async () => {
|
|
206
|
+
resolveSend(createRunHandle({ runId: null }));
|
|
207
|
+
await submission;
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
expect(params.runQueue.refreshQueuedInputs).toHaveBeenCalledTimes(1);
|
|
211
|
+
expect(result.current.queuedInputs).toEqual([]);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('removes the submitting queue row and restores the draft when submission fails', async () => {
|
|
215
|
+
const sendError = new Error('queue submission failed');
|
|
216
|
+
const send = vi.fn<TestAgentSend>(async () => {
|
|
217
|
+
throw sendError;
|
|
218
|
+
});
|
|
219
|
+
const params = createControllerParams({ isRunning: true, send });
|
|
220
|
+
const { result } = renderHook(() => useSessionConversationController(params));
|
|
221
|
+
|
|
222
|
+
await act(async () => {
|
|
223
|
+
await expect(result.current.send()).rejects.toThrow(sendError);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
expect(result.current.queuedInputs).toEqual([]);
|
|
227
|
+
expect(params.restoreComposer).toHaveBeenCalledWith(expect.objectContaining({
|
|
228
|
+
text: 'next task',
|
|
229
|
+
}));
|
|
230
|
+
expect(params.setSendError).toHaveBeenLastCalledWith(sendError.message);
|
|
231
|
+
expect(params.runQueue.refreshQueuedInputs).not.toHaveBeenCalled();
|
|
232
|
+
});
|
|
233
|
+
|
|
181
234
|
it('keeps an existing session bound to its agent instead of the global draft selection', async () => {
|
|
182
235
|
const send = createSendMock();
|
|
183
236
|
const params = createControllerParams({ isRunning: false, send });
|
package/src/features/chat/features/conversation/hooks/__tests__/use-session-run-queue.test.tsx
CHANGED
|
@@ -83,6 +83,24 @@ describe('useSessionRunQueue', () => {
|
|
|
83
83
|
unmount();
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
+
it('refreshes the authoritative queue on demand after a submission is accepted', async () => {
|
|
87
|
+
const listQueuedInputs = vi.spyOn(nextclawClient.sessions, 'listQueuedInputs')
|
|
88
|
+
.mockResolvedValue(createQueue('session-1', 'queued'));
|
|
89
|
+
const { result } = renderHook(
|
|
90
|
+
() => useSessionRunQueue('session-1'),
|
|
91
|
+
{ wrapper: createWrapper() },
|
|
92
|
+
);
|
|
93
|
+
await waitFor(() => expect(listQueuedInputs).toHaveBeenCalledTimes(1));
|
|
94
|
+
|
|
95
|
+
let refreshed: UiNcpSessionQueuedInputsView['inputs'] = [];
|
|
96
|
+
await act(async () => {
|
|
97
|
+
refreshed = [...await result.current.refreshQueuedInputs()];
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
expect(listQueuedInputs).toHaveBeenCalledTimes(2);
|
|
101
|
+
expect(refreshed[0]?.message.parts[0]).toMatchObject({ text: 'queued' });
|
|
102
|
+
});
|
|
103
|
+
|
|
86
104
|
it('replaces an in-flight stale queue read after the queue changes', async () => {
|
|
87
105
|
let resolveInitialRead!: (queue: UiNcpSessionQueuedInputsView) => void;
|
|
88
106
|
const initialRead = new Promise<UiNcpSessionQueuedInputsView>((resolve) => {
|
|
@@ -2,6 +2,7 @@ import { useEffect, type RefObject } from 'react';
|
|
|
2
2
|
import { type ChatInputBarHandle } from '@nextclaw/agent-chat-ui';
|
|
3
3
|
import {
|
|
4
4
|
CHAT_CONVERSATION_EXCERPT_TOKEN_KIND,
|
|
5
|
+
CHAT_UI_RESOURCE_TOKEN_KIND,
|
|
5
6
|
CHAT_WORKSPACE_EXCERPT_TOKEN_KIND,
|
|
6
7
|
} from '@nextclaw/shared';
|
|
7
8
|
|
|
@@ -41,7 +42,9 @@ export function useChatComposerReferenceIntent(params: {
|
|
|
41
42
|
role: intent.role,
|
|
42
43
|
excerpt: intent.excerpt,
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
+
: intent.kind === CHAT_UI_RESOURCE_TOKEN_KIND
|
|
46
|
+
? { reference: intent.reference }
|
|
47
|
+
: undefined,
|
|
45
48
|
});
|
|
46
49
|
intentManager.markConsumed(intent.id);
|
|
47
50
|
};
|