@yalehwang/cloudpit 2.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api-docs.html +3 -3
- package/dist/assets/{abnfDiagram-N423BO3Z-D5yLnMt9.js → abnfDiagram-N423BO3Z-D7Xt05gV.js} +1 -1
- package/dist/assets/{abnfDiagram-N423BO3Z-bTHtQIhR.js → abnfDiagram-N423BO3Z-dmPRRPEm.js} +1 -1
- package/dist/assets/{arc-1DmrBEyG.js → arc-B7W3R5qH.js} +1 -1
- package/dist/assets/{arc-BlGK--01.js → arc-BHMlIcaQ.js} +1 -1
- package/dist/assets/{architectureDiagram-T3A2C74G--lzbKBn9.js → architectureDiagram-T3A2C74G-CUUpAoN0.js} +1 -1
- package/dist/assets/{architectureDiagram-T3A2C74G-7lKNAbUU.js → architectureDiagram-T3A2C74G-DpXhbHxu.js} +1 -1
- package/dist/assets/{blockDiagram-VBNYF7ZC-17cdO9zs.js → blockDiagram-VBNYF7ZC-Bf0yfNxj.js} +1 -1
- package/dist/assets/{blockDiagram-VBNYF7ZC-BPavJfDj.js → blockDiagram-VBNYF7ZC-Cki9AOhc.js} +1 -1
- package/dist/assets/{c4Diagram-5PPSVZJV-Bm1-2w3b.js → c4Diagram-5PPSVZJV-DK2RqNDO.js} +1 -1
- package/dist/assets/{c4Diagram-5PPSVZJV-aHvFL3Wb.js → c4Diagram-5PPSVZJV-DyhTF0e5.js} +1 -1
- package/dist/assets/channel-DTLMNzbH.js +1 -0
- package/dist/assets/channel-DiqxUuPf.js +1 -0
- package/dist/assets/{chunk-2GRJ4B5K-D7WqZewM.js → chunk-2GRJ4B5K-BYtByJbf.js} +1 -1
- package/dist/assets/{chunk-2GRJ4B5K-DbwzBiPF.js → chunk-2GRJ4B5K-CksFgocc.js} +1 -1
- package/dist/assets/{chunk-2Q5K7J3B-DdCr89uy.js → chunk-2Q5K7J3B-D2kQa5TZ.js} +1 -1
- package/dist/assets/{chunk-2Q5K7J3B-TFd0ECKO.js → chunk-2Q5K7J3B-NSSX86FA.js} +1 -1
- package/dist/assets/{chunk-5RXB4S5H-BdhRBpEi.js → chunk-5RXB4S5H-DNNYC8_t.js} +1 -1
- package/dist/assets/{chunk-5RXB4S5H-D0SQ3nIe.js → chunk-5RXB4S5H-Rx0YaqNI.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-B9Lv3cWR.js → chunk-5VM5RSS4-B1k4I4CX.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DioqTIvB.js → chunk-5VM5RSS4-CsvQj3QC.js} +1 -1
- package/dist/assets/{chunk-6Q2QTUOP-09bwlcIv.js → chunk-6Q2QTUOP-48-dEgAs.js} +1 -1
- package/dist/assets/{chunk-6Q2QTUOP-JuhPJZZL.js → chunk-6Q2QTUOP-DCMSW5_0.js} +1 -1
- package/dist/assets/{chunk-GF5L2VYU-C6f2SgCw.js → chunk-GF5L2VYU-CGyvOsdN.js} +1 -1
- package/dist/assets/{chunk-GF5L2VYU-DzD9aOyp.js → chunk-GF5L2VYU-YXe113hp.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-BggnWNZv.js → chunk-JWPE2WC7-BT7vCW4x.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-Dte_Ax9K.js → chunk-JWPE2WC7-D2K1Oywq.js} +1 -1
- package/dist/assets/{chunk-KBJHAD2P-9TCQV92m.js → chunk-KBJHAD2P-CQZWamtE.js} +1 -1
- package/dist/assets/{chunk-KBJHAD2P-DDnJp7kJ.js → chunk-KBJHAD2P-gpEwZrNy.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-CE2Y4D_h.js → chunk-RYQCIY6F-BI0fMtjY.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-DsgFSTNw.js → chunk-RYQCIY6F-vguRdb4F.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-B1FIfsqq.js → chunk-XXDRQBXY-B99qH1_w.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-B4YfaqTO.js → chunk-XXDRQBXY-DZLJnbBB.js} +1 -1
- package/dist/assets/classDiagram-JCYQIIEL-BaV-s6x8.js +1 -0
- package/dist/assets/classDiagram-JCYQIIEL-D4M03B4L.js +1 -0
- package/dist/assets/classDiagram-v2-OCEON4UE-BaV-s6x8.js +1 -0
- package/dist/assets/classDiagram-v2-OCEON4UE-D4M03B4L.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-C1AG5Pib.js → cose-bilkent-JH36ORCC-EsVnz-E6.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-lMwWDibI.js → cose-bilkent-JH36ORCC-VI2OjCIx.js} +1 -1
- package/dist/assets/{cynefin-VYW2F7L2-BlabniRL.js → cynefin-VYW2F7L2-BVYg0ixs.js} +1 -1
- package/dist/assets/{cynefin-VYW2F7L2-W-c-z4IW.js → cynefin-VYW2F7L2-BnHmA5I2.js} +1 -1
- package/dist/assets/{cynefinDiagram-MW4NZA55-BtTep_pq.js → cynefinDiagram-MW4NZA55-B-OCRLIw.js} +1 -1
- package/dist/assets/{cynefinDiagram-MW4NZA55-Due6EIPh.js → cynefinDiagram-MW4NZA55-ItLlzjDR.js} +1 -1
- package/dist/assets/{dagre-VZM6K2ZE-CWLaFfdt.js → dagre-VZM6K2ZE-DkVDkAWJ.js} +1 -1
- package/dist/assets/{dagre-VZM6K2ZE-DZldvqiQ.js → dagre-VZM6K2ZE-bYR4z8-Z.js} +1 -1
- package/dist/assets/{diagram-7IWD3JNH-RnmUHYwN.js → diagram-7IWD3JNH-DjXMue67.js} +1 -1
- package/dist/assets/{diagram-7IWD3JNH-Di-7-nSA.js → diagram-7IWD3JNH-FNEXlm5k.js} +1 -1
- package/dist/assets/{diagram-B4RE2ZJO-Wybyn8fw.js → diagram-B4RE2ZJO-73NYiO_P.js} +1 -1
- package/dist/assets/{diagram-B4RE2ZJO-mrK79C2E.js → diagram-B4RE2ZJO-dB4QHq0D.js} +1 -1
- package/dist/assets/{diagram-LBJQPF4R-JY6FqSFu.js → diagram-LBJQPF4R-DyKT610O.js} +1 -1
- package/dist/assets/{diagram-LBJQPF4R-sWhu2VLy.js → diagram-LBJQPF4R-rMgmnjvd.js} +1 -1
- package/dist/assets/{diagram-Q27KOJAE-BJ4T0WGp.js → diagram-Q27KOJAE-BvsfmmQt.js} +1 -1
- package/dist/assets/{diagram-Q27KOJAE-DyGT9KhB.js → diagram-Q27KOJAE-c6DEjLQX.js} +1 -1
- package/dist/assets/{diagram-UB23O5K3-oXFJAndB.js → diagram-UB23O5K3-BMo2VXVb.js} +1 -1
- package/dist/assets/{diagram-UB23O5K3-tTd8qwEM.js → diagram-UB23O5K3-DRMKefnZ.js} +1 -1
- package/dist/assets/{ebnfDiagram-BXEA7PRR-DV67cBe6.js → ebnfDiagram-BXEA7PRR-BrOAekWh.js} +1 -1
- package/dist/assets/{ebnfDiagram-BXEA7PRR-OQGm8tPs.js → ebnfDiagram-BXEA7PRR-YmQkylwV.js} +1 -1
- package/dist/assets/{elk-BRx4gEGg.js → elk-Hz3WRESK.js} +1 -1
- package/dist/assets/{elk-CdAQJ-NA.js → elk-tPSZwRVB.js} +1 -1
- package/dist/assets/{erDiagram-JOGREHBK-BhD2xZ2I.js → erDiagram-JOGREHBK-BlaZnoQi.js} +1 -1
- package/dist/assets/{erDiagram-JOGREHBK-BqP8DqqW.js → erDiagram-JOGREHBK-CRCfRUXt.js} +1 -1
- package/dist/assets/{flowDiagram-UKHOOZJN-B4AjZxPJ.js → flowDiagram-UKHOOZJN-DQ1gbjxo.js} +1 -1
- package/dist/assets/{flowDiagram-UKHOOZJN-CP_1WsW4.js → flowDiagram-UKHOOZJN-Dinlbmds.js} +1 -1
- package/dist/assets/{ganttDiagram-PKOTCBZU-BMk6nngr.js → ganttDiagram-PKOTCBZU-CMGpcBZO.js} +1 -1
- package/dist/assets/{ganttDiagram-PKOTCBZU-B_ce39Ld.js → ganttDiagram-PKOTCBZU-Eh94zuPI.js} +1 -1
- package/dist/assets/{gitGraphDiagram-DS77QQ5N-CnZA42iA.js → gitGraphDiagram-DS77QQ5N-Bp8xIZbk.js} +1 -1
- package/dist/assets/{gitGraphDiagram-DS77QQ5N-DqEz_iTn.js → gitGraphDiagram-DS77QQ5N-Cu-b4YNw.js} +1 -1
- package/dist/assets/index-51e8fagd.css +32 -0
- package/dist/assets/{index-D5nLH7qP.js → index-CQE9C6k6.js} +356 -356
- package/dist/assets/{index-CqyOGerp.js → index-S8ow0XfK.js} +356 -356
- package/dist/assets/{infoDiagram-6WML65LV-BQf7m4X4.js → infoDiagram-6WML65LV-CClEEtTq.js} +1 -1
- package/dist/assets/{infoDiagram-6WML65LV-Dntf4YFM.js → infoDiagram-6WML65LV-QmHeojgl.js} +1 -1
- package/dist/assets/{ishikawaDiagram-WSZJBQD7-BDjsldAI.js → ishikawaDiagram-WSZJBQD7-BemSj9lN.js} +1 -1
- package/dist/assets/{ishikawaDiagram-WSZJBQD7-BqXpJeoL.js → ishikawaDiagram-WSZJBQD7-nw48g1vr.js} +1 -1
- package/dist/assets/{journeyDiagram-NVQOT4AX-CBcFzP2M.js → journeyDiagram-NVQOT4AX-DeNtO6OU.js} +1 -1
- package/dist/assets/{journeyDiagram-NVQOT4AX-DoWKjgKd.js → journeyDiagram-NVQOT4AX-q1lCfOYn.js} +1 -1
- package/dist/assets/{kanban-definition-27J2QSJJ-9bspl7j-.js → kanban-definition-27J2QSJJ-Bzhu6hql.js} +1 -1
- package/dist/assets/{kanban-definition-27J2QSJJ-Cjxa-Fbb.js → kanban-definition-27J2QSJJ-VfvD33YG.js} +1 -1
- package/dist/assets/{linear-YogAXmU_.js → linear-C0Kwu3Yp.js} +1 -1
- package/dist/assets/{linear-lIhI5Y8l.js → linear-CbM_4-fP.js} +1 -1
- package/dist/assets/{mermaid.core-2Spxcrg7.js → mermaid.core-G2huIsXn.js} +5 -5
- package/dist/assets/{mermaid.core-BxxInCBm.js → mermaid.core-fvTQFUX1.js} +5 -5
- package/dist/assets/{mindmap-definition-FAOFIHXS-DblO5EG4.js → mindmap-definition-FAOFIHXS-BONvuyvz.js} +1 -1
- package/dist/assets/{mindmap-definition-FAOFIHXS-_nlvJ9VK.js → mindmap-definition-FAOFIHXS-BzYawGKQ.js} +1 -1
- package/dist/assets/{pegDiagram-VL7TDLO6-BBJFPAZG.js → pegDiagram-VL7TDLO6-Df2HAKGH.js} +1 -1
- package/dist/assets/{pegDiagram-VL7TDLO6-DhRH7YRf.js → pegDiagram-VL7TDLO6-DnMwBHn_.js} +1 -1
- package/dist/assets/{pieDiagram-7S7Q4E2Y-4Qy7Nk4U.js → pieDiagram-7S7Q4E2Y-Cd3-a-dM.js} +1 -1
- package/dist/assets/{pieDiagram-7S7Q4E2Y-BUtdeYBT.js → pieDiagram-7S7Q4E2Y-LV6TOhOD.js} +1 -1
- package/dist/assets/{quadrantDiagram-CIZ2JOQS-BUoIDY1r.js → quadrantDiagram-CIZ2JOQS-8VOnA3FV.js} +1 -1
- package/dist/assets/{quadrantDiagram-CIZ2JOQS-D90kdHA1.js → quadrantDiagram-CIZ2JOQS-CnwxFPxh.js} +1 -1
- package/dist/assets/{railroadDiagram-AXF67PYL-CJf9--tj.js → railroadDiagram-AXF67PYL-CXBFj3Iu.js} +1 -1
- package/dist/assets/{railroadDiagram-AXF67PYL-D3S1oliC.js → railroadDiagram-AXF67PYL-DLoAPcsb.js} +1 -1
- package/dist/assets/{requirementDiagram-LRYGKXZP-C04jhjS6.js → requirementDiagram-LRYGKXZP-LrVlZXSz.js} +1 -1
- package/dist/assets/{requirementDiagram-LRYGKXZP-cQaGai5h.js → requirementDiagram-LRYGKXZP-pakITowN.js} +1 -1
- package/dist/assets/{sankeyDiagram-W5VNT64P-AT4cTVbY.js → sankeyDiagram-W5VNT64P-BIQQ8A1I.js} +1 -1
- package/dist/assets/{sankeyDiagram-W5VNT64P-DfFUdqYO.js → sankeyDiagram-W5VNT64P-C6QWOxNM.js} +1 -1
- package/dist/assets/{sequenceDiagram-SI44F4Z6-DbjhG030.js → sequenceDiagram-SI44F4Z6-CpHBe2CG.js} +1 -1
- package/dist/assets/{sequenceDiagram-SI44F4Z6-DKjdupix.js → sequenceDiagram-SI44F4Z6-cnLxaxcV.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-CCcKLP8m.js → sizeCapture-X5ZJPWSS-3g-1onHD.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-DGxRWxeo.js → sizeCapture-X5ZJPWSS-4U6b3PSL.js} +1 -1
- package/dist/assets/{stateDiagram-OKZ733FA-D7wGCNb7.js → stateDiagram-OKZ733FA-CFwVDdlY.js} +1 -1
- package/dist/assets/{stateDiagram-OKZ733FA-qdMAailp.js → stateDiagram-OKZ733FA-CKVGJcM2.js} +1 -1
- package/dist/assets/{stateDiagram-v2-UEYNNEHI-BbmmtA9w.js → stateDiagram-v2-UEYNNEHI-Dnbk8ftm.js} +1 -1
- package/dist/assets/{stateDiagram-v2-UEYNNEHI-Diz_hFvh.js → stateDiagram-v2-UEYNNEHI-rlA-woxH.js} +1 -1
- package/dist/assets/{swimlanes-SLNWSIFB-CZgIPz6I.js → swimlanes-SLNWSIFB-DCwz8-mf.js} +2 -2
- package/dist/assets/{swimlanes-SLNWSIFB-B16H-6OU.js → swimlanes-SLNWSIFB-M9Oumwnl.js} +2 -2
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-CTtTyW6-.js +8 -0
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-Caohx6WZ.js +8 -0
- package/dist/assets/{timeline-definition-Z64GVDOM-7r7OVlrT.js → timeline-definition-Z64GVDOM-BVmfjoWH.js} +1 -1
- package/dist/assets/{timeline-definition-Z64GVDOM-nhnkS_wy.js → timeline-definition-Z64GVDOM-DyXvto1l.js} +1 -1
- package/dist/assets/{vennDiagram-T6HMQDX7-B1piFYrz.js → vennDiagram-T6HMQDX7-CNe6zorb.js} +1 -1
- package/dist/assets/{vennDiagram-T6HMQDX7-x8SJTFhK.js → vennDiagram-T6HMQDX7-DyzOWKx3.js} +1 -1
- package/dist/assets/{wardleyDiagram-T6FBY63Y-BdD4GExj.js → wardleyDiagram-T6FBY63Y-D5YvMVwa.js} +1 -1
- package/dist/assets/{wardleyDiagram-T6FBY63Y-C90xqNVS.js → wardleyDiagram-T6FBY63Y-DXo8BCrA.js} +1 -1
- package/dist/assets/{xychartDiagram-ELKLHX3M--Ndoz0Cq.js → xychartDiagram-ELKLHX3M-CIBffVxC.js} +1 -1
- package/dist/assets/{xychartDiagram-ELKLHX3M-BAKns-7o.js → xychartDiagram-ELKLHX3M-XlsWelDb.js} +1 -1
- package/dist/build-info.json +2 -2
- package/dist/convert-icons.md +10 -46
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +1 -9
- package/dist/generate-icons.js +67 -47
- package/dist/icons/icon-128x128.png +0 -0
- package/dist/icons/icon-144x144.png +0 -0
- package/dist/icons/icon-152x152.png +0 -0
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-384x384.png +0 -0
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-72x72.png +0 -0
- package/dist/icons/icon-96x96.png +0 -0
- package/dist/index.html +2 -2
- package/dist/logo-128.png +0 -0
- package/dist/logo-256.png +0 -0
- package/dist/logo-32.png +0 -0
- package/dist/logo-512.png +0 -0
- package/dist/logo-64.png +0 -0
- package/dist/logo-source.png +0 -0
- package/dist/logo.svg +1 -17
- package/dist/sw.js +7 -9
- package/dist-server/build-info.json +2 -2
- package/dist-server/server/load-env.js +12 -4
- package/dist-server/server/load-env.js.map +1 -1
- package/dist-server/server/modules/browser-use/browser-use.service.js +33 -11
- package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -1
- package/dist-server/server/modules/browser-use/index.js +4 -4
- package/dist-server/server/modules/browser-use/index.js.map +1 -1
- package/dist-server/server/modules/browser-use/mcp-server-names.js +6 -4
- package/dist-server/server/modules/browser-use/mcp-server-names.js.map +1 -1
- package/dist-server/server/modules/browser-use/tests/browser-use.service.test.js +49 -1
- package/dist-server/server/modules/browser-use/tests/browser-use.service.test.js.map +1 -1
- package/dist-server/server/modules/cli/asset-migration-files.js +74 -0
- package/dist-server/server/modules/cli/asset-migration-files.js.map +1 -0
- package/dist-server/server/modules/cli/asset-migration-report.js +80 -0
- package/dist-server/server/modules/cli/asset-migration-report.js.map +1 -0
- package/dist-server/server/modules/cli/asset-migration-store.js +153 -0
- package/dist-server/server/modules/cli/asset-migration-store.js.map +1 -0
- package/dist-server/server/modules/cli/asset-migration.service.js +161 -0
- package/dist-server/server/modules/cli/asset-migration.service.js.map +1 -0
- package/dist-server/server/modules/cli/browser-use-mcp.js +9 -4
- package/dist-server/server/modules/cli/browser-use-mcp.js.map +1 -1
- package/dist-server/server/modules/cli/cli.module.js +21 -1
- package/dist-server/server/modules/cli/cli.module.js.map +1 -1
- package/dist-server/server/modules/cli/cli.service.js +6 -1
- package/dist-server/server/modules/cli/cli.service.js.map +1 -1
- package/dist-server/server/modules/cli/tests/asset-migration.service.test.js +275 -0
- package/dist-server/server/modules/cli/tests/asset-migration.service.test.js.map +1 -0
- package/dist-server/server/modules/cli/tests/browser-use-mcp-entry.test.js +157 -0
- package/dist-server/server/modules/cli/tests/browser-use-mcp-entry.test.js.map +1 -1
- package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js +1 -0
- package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js.map +1 -1
- package/dist-server/server/modules/cli/tests/cli.service.test.js +6 -1
- package/dist-server/server/modules/cli/tests/cli.service.test.js.map +1 -1
- package/dist-server/server/modules/cockpit/cockpit-brief-prompt.js +1 -1
- package/dist-server/server/modules/cockpit/cockpit-card-actions.js +19 -3
- package/dist-server/server/modules/cockpit/cockpit-card-actions.js.map +1 -1
- package/dist-server/server/modules/cockpit/cockpit-card-feedback-store.js +94 -9
- package/dist-server/server/modules/cockpit/cockpit-card-feedback-store.js.map +1 -1
- package/dist-server/server/modules/cockpit/cockpit-card-registry.js +1 -1
- package/dist-server/server/modules/cockpit/cockpit-fleet-card-projection.js +3 -0
- package/dist-server/server/modules/cockpit/cockpit-fleet-card-projection.js.map +1 -1
- package/dist-server/server/modules/cockpit/cockpit-knowledge-reading.js +16 -0
- package/dist-server/server/modules/cockpit/cockpit-knowledge-reading.js.map +1 -1
- package/dist-server/server/modules/cockpit/cockpit.module.js +1 -1
- package/dist-server/server/modules/cockpit/tests/cockpit-card-feedback.test.js +96 -1
- package/dist-server/server/modules/cockpit/tests/cockpit-card-feedback.test.js.map +1 -1
- package/dist-server/server/modules/cockpit/tests/cockpit-fleet-card-provider.test.js +2 -2
- package/dist-server/server/modules/cockpit/tests/cockpit-knowledge-decision-handoff.test.js +169 -3
- package/dist-server/server/modules/cockpit/tests/cockpit-knowledge-decision-handoff.test.js.map +1 -1
- package/dist-server/server/modules/context-events/context-event-writer.js +5 -5
- package/dist-server/server/modules/context-events/context-events.module.js +2 -2
- package/dist-server/server/modules/context-events/session-ask-stream-reader.js +1 -1
- package/dist-server/server/modules/context-events/session-blocked-events.js +3 -3
- package/dist-server/server/modules/context-events/tests/session-ask-event-writer.test.js +1 -1
- package/dist-server/server/modules/context-events/tests/session-blocked-events.test.js +3 -3
- package/dist-server/server/modules/context-events/tests/session-run-events.test.js +1 -1
- package/dist-server/server/modules/database/migrations.js +23 -1
- package/dist-server/server/modules/database/migrations.js.map +1 -1
- package/dist-server/server/modules/database/repositories/sessions.db.js +25 -4
- package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -1
- package/dist-server/server/modules/database/repositories/voice-user-identifiers.db.js +1 -1
- package/dist-server/server/modules/database/schema.js +16 -2
- package/dist-server/server/modules/database/schema.js.map +1 -1
- package/dist-server/server/modules/database/tests/migrations-ensure-columns.test.js +2 -0
- package/dist-server/server/modules/database/tests/migrations-ensure-columns.test.js.map +1 -1
- package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js +2 -2
- package/dist-server/server/modules/debug-agent/tests/debug-agent-permission-popup.test.js +2 -2
- package/dist-server/server/modules/liaison/liaison-deliver.service.js +3 -3
- package/dist-server/server/modules/liaison/liaison.module.js +1 -1
- package/dist-server/server/modules/mcp-gateway/mcp-gateway.auth.js +3 -2
- package/dist-server/server/modules/mcp-gateway/mcp-gateway.auth.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/mcp-self-target.js +2 -2
- package/dist-server/server/modules/mcp-gateway/mcp-session-send.js +7 -0
- package/dist-server/server/modules/mcp-gateway/mcp-session-send.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/mcp-tool-annotations.js +4 -4
- package/dist-server/server/modules/mcp-gateway/oauth-metadata.gate.js +4 -2
- package/dist-server/server/modules/mcp-gateway/oauth-metadata.gate.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/knowledge-effective-config-proof.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/knowledge-peer-correlation-proof.test.js +2 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-approvals.test.js +3 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-approvals.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-audit-route.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-audit.test.js +4 -4
- package/dist-server/server/modules/mcp-gateway/tests/mcp-auth.test.js +3 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-auth.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-cancel-queued.test.js +3 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-cancel-queued.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-cockpit-tools.test.js +7 -3
- package/dist-server/server/modules/mcp-gateway/tests/mcp-cockpit-tools.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-correlation-id.test.js +8 -8
- package/dist-server/server/modules/mcp-gateway/tests/mcp-draft.test.js +3 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-draft.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-english-only.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-gateway-wiring.test.js +2 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-insufficient-scope.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-insufficient-scope.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-knowledge-facts.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-not-found-semantics.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-not-found-semantics.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-oauth-challenge.test.js +3 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-oauth-challenge.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-overview.test.js +2 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-pending-interaction.test.js +2 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-read-tools.test.js +3 -3
- package/dist-server/server/modules/mcp-gateway/tests/mcp-read-tools.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-run-get.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-self-target.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-self-target.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-background.test.js +2 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-background.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-host-control.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-host-control.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-lifecycle.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-lifecycle.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-reconfigure.test.js +2 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-reconfigure.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-search-pruning.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-search.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-send.test.js +2 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-session-send.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-ui-last-opened.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-usage-stats.test.js +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-usage-stats.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/mcp-write-notification.test.js +2 -2
- package/dist-server/server/modules/mcp-gateway/tests/mcp-write-notification.test.js.map +1 -1
- package/dist-server/server/modules/mcp-gateway/tests/oauth-flow.e2e.test.js +3 -3
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js +1 -1
- package/dist-server/server/modules/oauth/access-tokens.service.js +8 -8
- package/dist-server/server/modules/oauth/oauth-consent.service.js +20 -15
- package/dist-server/server/modules/oauth/oauth-consent.service.js.map +1 -1
- package/dist-server/server/modules/oauth/tests/access-token-scopes.test.js +54 -34
- package/dist-server/server/modules/oauth/tests/access-token-scopes.test.js.map +1 -1
- package/dist-server/server/modules/oauth/tests/access-tokens.service.test.js +35 -14
- package/dist-server/server/modules/oauth/tests/access-tokens.service.test.js.map +1 -1
- package/dist-server/server/modules/oauth/tests/oauth-consent-page.test.js +27 -22
- package/dist-server/server/modules/oauth/tests/oauth-consent-page.test.js.map +1 -1
- package/dist-server/server/modules/oauth/tests/oauth-consent-ratelimit.test.js +2 -2
- package/dist-server/server/modules/oauth/tests/token-info.routes.test.js +2 -2
- package/dist-server/server/modules/oauth/tests/token-info.routes.test.js.map +1 -1
- package/dist-server/server/modules/observation/blind-spots.js +1 -1
- package/dist-server/server/modules/observation/observation-store.js +50 -17
- package/dist-server/server/modules/observation/observation-store.js.map +1 -1
- package/dist-server/server/modules/observation/observation-uri.js +31 -19
- package/dist-server/server/modules/observation/observation-uri.js.map +1 -1
- package/dist-server/server/modules/observation/observation.routes.js +1 -1
- package/dist-server/server/modules/observation/project-truth.js +1 -1
- package/dist-server/server/modules/observation/session-ask-decision-answer.js +2 -1
- package/dist-server/server/modules/observation/session-ask-decision-answer.js.map +1 -1
- package/dist-server/server/modules/observation/session-digest-llm.js +7 -1
- package/dist-server/server/modules/observation/session-digest-llm.js.map +1 -1
- package/dist-server/server/modules/observation/session-digest.js +39 -5
- package/dist-server/server/modules/observation/session-digest.js.map +1 -1
- package/dist-server/server/modules/observation/tests/architecture-delta.test.js +1 -1
- package/dist-server/server/modules/observation/tests/observation-routes.test.js +9 -0
- package/dist-server/server/modules/observation/tests/observation-routes.test.js.map +1 -1
- package/dist-server/server/modules/observation/tests/observation-store.test.js +38 -0
- package/dist-server/server/modules/observation/tests/observation-store.test.js.map +1 -1
- package/dist-server/server/modules/observation/tests/project-truth.test.js +2 -2
- package/dist-server/server/modules/observation/tests/session-ask-decision-digest.test.js +150 -0
- package/dist-server/server/modules/observation/tests/session-ask-decision-digest.test.js.map +1 -1
- package/dist-server/server/modules/observation/tests/session-digest.test.js +24 -1
- package/dist-server/server/modules/observation/tests/session-digest.test.js.map +1 -1
- package/dist-server/server/modules/providers/index.js +9 -0
- package/dist-server/server/modules/providers/index.js.map +1 -1
- package/dist-server/server/modules/providers/list/claude/claude-host-driver.provider.js +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js +22 -3
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-app-server.connection.js +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-host-driver.contract.js +11 -9
- package/dist-server/server/modules/providers/list/codex/codex-host-driver.contract.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-host-driver.provider.js +15 -1
- package/dist-server/server/modules/providers/list/codex/codex-host-driver.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +14 -3
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-provider-injection.js +248 -0
- package/dist-server/server/modules/providers/list/codex/codex-provider-injection.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-resident-provider-launch.js +37 -0
- package/dist-server/server/modules/providers/list/codex/codex-resident-provider-launch.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js +19 -1
- package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +1 -1
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +1 -1
- package/dist-server/server/modules/providers/provider.routes.js +23 -2
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-models.service.js +136 -106
- package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/provider-runtime.service.js +3 -0
- package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -1
- package/dist-server/server/modules/providers/services/session-model-resolver.js +106 -0
- package/dist-server/server/modules/providers/services/session-model-resolver.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-provider-binding.js +89 -0
- package/dist-server/server/modules/providers/services/session-provider-binding.js.map +1 -0
- package/dist-server/server/modules/providers/services/sessions.service.js +5 -1
- package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -1
- package/dist-server/server/modules/providers/tests/claude-resident-addressable.test.js +2 -2
- package/dist-server/server/modules/providers/tests/claude-session-name-authority.test.js +4 -4
- package/dist-server/server/modules/providers/tests/codex-app-server-protocol.test.js +1 -1
- package/dist-server/server/modules/providers/tests/codex-host-driver-persistent.test.js +2 -2
- package/dist-server/server/modules/providers/tests/codex-provider-model-binding.test.js +270 -0
- package/dist-server/server/modules/providers/tests/codex-provider-model-binding.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-resident-provider-injection.test.js +484 -0
- package/dist-server/server/modules/providers/tests/codex-resident-provider-injection.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-runtime-provider-injection.test.js +228 -0
- package/dist-server/server/modules/providers/tests/codex-runtime-provider-injection.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-session-provider-binding.test.js +306 -0
- package/dist-server/server/modules/providers/tests/codex-session-provider-binding.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js +1 -1
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +2 -2
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js +15 -0
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -1
- package/dist-server/server/modules/providers/tests/provider.routes.test.js +1 -1
- package/dist-server/server/modules/quay/index.js +1 -1
- package/dist-server/server/modules/quay/quay-fleet-cli.js +1 -1
- package/dist-server/server/modules/quay/quay-fleet-locator.js +2 -2
- package/dist-server/server/modules/quay/quay-fleet-project-id.js +7 -7
- package/dist-server/server/modules/quay/quay-fleet-registry.js +3 -3
- package/dist-server/server/modules/quay/quay-suite-fanin-reader.js +1 -1
- package/dist-server/server/modules/quay/quay-uri-resolve.js +6 -6
- package/dist-server/server/modules/quay/quay.module.js +3 -3
- package/dist-server/server/modules/quay/quay.routes.js +1 -1
- package/dist-server/server/modules/quay/quay.service.js +4 -4
- package/dist-server/server/modules/quay/tests/contracts/fleet-cli-contracts.test.js +3 -3
- package/dist-server/server/modules/quay/tests/contracts/shapes.js +9 -9
- package/dist-server/server/modules/quay/tests/quay-fleet-locator.test.js +1 -1
- package/dist-server/server/modules/quay/tests/quay-fleet-project-id.test.js +4 -4
- package/dist-server/server/modules/quay/tests/quay-uri-resolve.test.js +10 -10
- package/dist-server/server/modules/session-hosts/tests/resident-server-restart.test.js +1 -1
- package/dist-server/server/modules/settings/codex-mcp-gateway.settings.js +1 -1
- package/dist-server/server/modules/settings/codex-model-providers.schema.js +349 -0
- package/dist-server/server/modules/settings/codex-model-providers.schema.js.map +1 -0
- package/dist-server/server/modules/settings/codex-model-providers.service.js +199 -0
- package/dist-server/server/modules/settings/codex-model-providers.service.js.map +1 -0
- package/dist-server/server/modules/settings/codex-model-providers.settings.js +547 -0
- package/dist-server/server/modules/settings/codex-model-providers.settings.js.map +1 -0
- package/dist-server/server/modules/settings/codex-model-providers.store.js +200 -0
- package/dist-server/server/modules/settings/codex-model-providers.store.js.map +1 -0
- package/dist-server/server/modules/settings/index.js +10 -0
- package/dist-server/server/modules/settings/index.js.map +1 -1
- package/dist-server/server/modules/settings/server-settings-file.js +28 -32
- package/dist-server/server/modules/settings/server-settings-file.js.map +1 -1
- package/dist-server/server/modules/settings/server-settings.js +2 -2
- package/dist-server/server/modules/settings/server-settings.js.map +1 -1
- package/dist-server/server/modules/settings/settings.module.js +35 -0
- package/dist-server/server/modules/settings/settings.module.js.map +1 -1
- package/dist-server/server/modules/settings/settings.routes.js +42 -0
- package/dist-server/server/modules/settings/settings.routes.js.map +1 -1
- package/dist-server/server/modules/settings/settings.service.js +8 -21
- package/dist-server/server/modules/settings/settings.service.js.map +1 -1
- package/dist-server/server/modules/settings/tests/cockpit-session-start-settings.routes.test.js +1 -0
- package/dist-server/server/modules/settings/tests/cockpit-session-start-settings.routes.test.js.map +1 -1
- package/dist-server/server/modules/settings/tests/codex-model-providers-settings.test.js +336 -0
- package/dist-server/server/modules/settings/tests/codex-model-providers-settings.test.js.map +1 -0
- package/dist-server/server/modules/settings/tests/codex-provider-advanced.test.js +466 -0
- package/dist-server/server/modules/settings/tests/codex-provider-advanced.test.js.map +1 -0
- package/dist-server/server/modules/settings/tests/codex-provider-import.test.js +475 -0
- package/dist-server/server/modules/settings/tests/codex-provider-import.test.js.map +1 -0
- package/dist-server/server/modules/voice/tests/voice-lexicon.test.js +9 -9
- package/dist-server/server/modules/voice/tests/voice-lexicon.test.js.map +1 -1
- package/dist-server/server/modules/voice/voice-lexicon.js +1 -1
- package/dist-server/server/modules/websocket/services/chat-control.service.js +21 -1
- package/dist-server/server/modules/websocket/services/chat-control.service.js.map +1 -1
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js +25 -1
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -1
- package/dist-server/server/modules/websocket/tests/chat-background-task.test.js +18 -1
- package/dist-server/server/modules/websocket/tests/chat-background-task.test.js.map +1 -1
- package/dist-server/server/modules/websocket/tests/chat-stop-task.test.js +18 -1
- package/dist-server/server/modules/websocket/tests/chat-stop-task.test.js.map +1 -1
- package/dist-server/server/modules/worktrees/services/worktree-list.service.js +1 -1
- package/dist-server/server/modules/worktrees/services/worktree-open.service.js +1 -1
- package/dist-server/server/modules/worktrees/services/worktree-remove.service.js +1 -1
- package/dist-server/server/shared/brand.js +18 -20
- package/dist-server/server/shared/brand.js.map +1 -1
- package/dist-server/server/shared/data-root-migration.js +3 -2
- package/dist-server/server/shared/data-root-migration.js.map +1 -1
- package/dist-server/server/shared/data-root.js +54 -59
- package/dist-server/server/shared/data-root.js.map +1 -1
- package/dist-server/server/shared/mcp-contract/types.js +20 -15
- package/dist-server/server/shared/mcp-contract/types.js.map +1 -1
- package/dist-server/server/shared/ports/codex-provider-registry.port.js +66 -0
- package/dist-server/server/shared/ports/codex-provider-registry.port.js.map +1 -0
- package/dist-server/server/shared/settings-file.js +120 -6
- package/dist-server/server/shared/settings-file.js.map +1 -1
- package/dist-server/server/shared/tests/cloudpit-brand-env.test.js +76 -34
- package/dist-server/server/shared/tests/cloudpit-brand-env.test.js.map +1 -1
- package/dist-server/server/shared/tests/cloudpit-data-root.test.js +35 -18
- package/dist-server/server/shared/tests/cloudpit-data-root.test.js.map +1 -1
- package/dist-server/server/shared/tests/cloudpit-goal-exit-gate.test.js +153 -17
- package/dist-server/server/shared/tests/cloudpit-goal-exit-gate.test.js.map +1 -1
- package/dist-server/server/shared/tests/cloudpit-runtime-flip.test.js +116 -114
- package/dist-server/server/shared/tests/cloudpit-runtime-flip.test.js.map +1 -1
- package/dist-server/server/shared/tests/frontend-import-cycle-budget.test.js +9 -1
- package/dist-server/server/shared/tests/frontend-import-cycle-budget.test.js.map +1 -1
- package/dist-server/server/shared/tests/quay-test-script.test.js +40 -6
- package/dist-server/server/shared/tests/quay-test-script.test.js.map +1 -1
- package/dist-server/server/shared/tests/settings-file.test.js +58 -2
- package/dist-server/server/shared/tests/settings-file.test.js.map +1 -1
- package/dist-server/server/shared/types.js.map +1 -1
- package/dist-server/server/shared/utils.js +1 -1
- package/electron/appIdMigration.js +467 -0
- package/electron/assets/logo-macos.icns +0 -0
- package/electron/assets/logo-macos.png +0 -0
- package/electron/assets/logo-windows.ico +0 -0
- package/electron/brandEnv.js +64 -0
- package/electron/cloud.js +3 -3
- package/electron/desktopNotifications.js +1 -1
- package/electron/launcher/index.html +1 -1
- package/electron/localServer.js +41 -7
- package/electron/main.js +33 -15
- package/electron/scripts/generate-macos-icon.js +34 -28
- package/electron/scripts/generate-windows-icon.js +66 -0
- package/electron/serverInstaller.js +20 -11
- package/electron/tests/cloudpit-appid-migration.test.mjs +514 -0
- package/electron/tests/cloudpit-brand-env-wiring.test.mjs +324 -0
- package/electron/tests/cloudpit-desktop-identity.test.mjs +42 -19
- package/electron/tests/cloudpit-runtime-identity-surfaces.test.mjs +10 -4
- package/electron/tests/cloudpit-userdata-migration.test.mjs +18 -5
- package/electron/userDataMigration.js +3 -0
- package/package.json +7 -6
- package/public/api-docs.html +3 -3
- package/scripts/brand-allowlist-check.mjs +233 -12
- package/scripts/brand-allowlist-check.test.mjs +270 -1
- package/scripts/cloudpit-distribution-check.mjs +57 -23
- package/scripts/cloudpit-distribution-check.test.mjs +42 -9
- package/scripts/codex-protocol-smoke.mjs +1 -1
- package/scripts/isolated-instance.sh +1 -1
- package/scripts/mcp-smoke.mjs +2 -2
- package/scripts/release/tests/fork-release-workflows.test.mjs +45 -0
- package/scripts/release/tests/server-installer-bundle-url.test.mjs +57 -9
- package/scripts/restart-when-idle.sh +1 -1
- package/scripts/shadow-prediction-report.mjs +1 -1
- package/scripts/suite-duration-baseline.tsv +45 -0
- package/scripts/ui-scenario.mjs +195 -0
- package/scripts/ui-scenarios/codex-provider-import.json +63 -0
- package/scripts/ui-scenarios/codex-provider-settings.json +77 -0
- package/scripts/voice-capture-process-check.false-forms.test.mjs +1 -1
- package/scripts/voice-phase0-report.test.mjs +1 -1
- package/server/load-env.ts +15 -4
- package/server/modules/browser-use/browser-use.service.ts +45 -14
- package/server/modules/browser-use/index.ts +3 -4
- package/server/modules/browser-use/mcp-server-names.ts +6 -5
- package/server/modules/browser-use/tests/browser-use.service.test.ts +63 -1
- package/server/modules/cli/asset-migration-files.ts +96 -0
- package/server/modules/cli/asset-migration-report.ts +123 -0
- package/server/modules/cli/asset-migration-store.ts +228 -0
- package/server/modules/cli/asset-migration.service.ts +236 -0
- package/server/modules/cli/browser-use-mcp.ts +9 -4
- package/server/modules/cli/cli.module.ts +21 -1
- package/server/modules/cli/cli.service.ts +14 -1
- package/server/modules/cli/tests/asset-migration.service.test.ts +349 -0
- package/server/modules/cli/tests/browser-use-mcp-entry.test.ts +202 -0
- package/server/modules/cli/tests/cli-environment-bootstrap.test.ts +1 -0
- package/server/modules/cli/tests/cli.service.test.ts +6 -1
- package/server/modules/cockpit/cockpit-brief-prompt.ts +1 -1
- package/server/modules/cockpit/cockpit-card-actions.ts +20 -3
- package/server/modules/cockpit/cockpit-card-feedback-store.ts +104 -9
- package/server/modules/cockpit/cockpit-card-registry.ts +2 -2
- package/server/modules/cockpit/cockpit-fleet-card-projection.ts +3 -0
- package/server/modules/cockpit/cockpit-fleet-executor.ts +1 -1
- package/server/modules/cockpit/cockpit-knowledge-reading.ts +17 -0
- package/server/modules/cockpit/cockpit.module.ts +2 -2
- package/server/modules/cockpit/cockpit.reducer.ts +1 -1
- package/server/modules/cockpit/tests/cockpit-card-feedback.test.ts +116 -1
- package/server/modules/cockpit/tests/cockpit-fleet-card-provider.test.ts +2 -2
- package/server/modules/cockpit/tests/cockpit-knowledge-decision-handoff.test.ts +205 -3
- package/server/modules/context-events/context-event-writer.ts +6 -6
- package/server/modules/context-events/context-events.module.ts +2 -2
- package/server/modules/context-events/session-ask-stream-reader.ts +1 -1
- package/server/modules/context-events/session-blocked-events.ts +3 -3
- package/server/modules/context-events/tests/session-ask-event-writer.test.ts +1 -1
- package/server/modules/context-events/tests/session-blocked-events.test.ts +3 -3
- package/server/modules/context-events/tests/session-run-events.test.ts +1 -1
- package/server/modules/database/migrations.ts +24 -1
- package/server/modules/database/repositories/sessions.db.ts +41 -4
- package/server/modules/database/repositories/voice-user-identifiers.db.ts +1 -1
- package/server/modules/database/schema.ts +16 -2
- package/server/modules/database/tests/migrations-ensure-columns.test.ts +2 -0
- package/server/modules/database/tests/sessions-provider-mapping.test.ts +2 -2
- package/server/modules/debug-agent/tests/debug-agent-permission-popup.test.ts +2 -2
- package/server/modules/liaison/liaison-deliver.service.ts +4 -4
- package/server/modules/liaison/liaison.module.ts +1 -1
- package/server/modules/mcp-gateway/mcp-gateway.auth.ts +3 -2
- package/server/modules/mcp-gateway/mcp-self-target.ts +2 -2
- package/server/modules/mcp-gateway/mcp-session-send.ts +21 -2
- package/server/modules/mcp-gateway/mcp-tool-annotations.ts +4 -4
- package/server/modules/mcp-gateway/oauth-metadata.gate.ts +4 -5
- package/server/modules/mcp-gateway/tests/knowledge-effective-config-proof.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/knowledge-peer-correlation-proof.test.ts +2 -2
- package/server/modules/mcp-gateway/tests/mcp-approvals.test.ts +3 -2
- package/server/modules/mcp-gateway/tests/mcp-audit-route.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-audit.test.ts +4 -4
- package/server/modules/mcp-gateway/tests/mcp-auth.test.ts +3 -1
- package/server/modules/mcp-gateway/tests/mcp-cancel-queued.test.ts +3 -2
- package/server/modules/mcp-gateway/tests/mcp-cockpit-tools.test.ts +7 -3
- package/server/modules/mcp-gateway/tests/mcp-correlation-id.test.ts +8 -8
- package/server/modules/mcp-gateway/tests/mcp-draft.test.ts +3 -2
- package/server/modules/mcp-gateway/tests/mcp-english-only.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-gateway-wiring.test.ts +2 -2
- package/server/modules/mcp-gateway/tests/mcp-insufficient-scope.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-knowledge-facts.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-not-found-semantics.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-oauth-challenge.test.ts +3 -2
- package/server/modules/mcp-gateway/tests/mcp-overview.test.ts +2 -2
- package/server/modules/mcp-gateway/tests/mcp-pending-interaction.test.ts +2 -2
- package/server/modules/mcp-gateway/tests/mcp-read-tools.test.ts +3 -3
- package/server/modules/mcp-gateway/tests/mcp-run-get.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-self-target.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-session-background.test.ts +2 -2
- package/server/modules/mcp-gateway/tests/mcp-session-host-control.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-session-lifecycle.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-session-reconfigure.test.ts +2 -2
- package/server/modules/mcp-gateway/tests/mcp-session-search-pruning.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-session-search.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-session-send.test.ts +2 -2
- package/server/modules/mcp-gateway/tests/mcp-ui-last-opened.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-usage-stats.test.ts +1 -1
- package/server/modules/mcp-gateway/tests/mcp-write-notification.test.ts +2 -2
- package/server/modules/mcp-gateway/tests/oauth-flow.e2e.test.ts +3 -3
- package/server/modules/notifications/services/notification-orchestrator.service.js +1 -1
- package/server/modules/oauth/access-tokens.service.ts +8 -8
- package/server/modules/oauth/oauth-consent.service.ts +20 -15
- package/server/modules/oauth/tests/access-token-scopes.test.ts +55 -34
- package/server/modules/oauth/tests/access-tokens.service.test.ts +50 -14
- package/server/modules/oauth/tests/oauth-consent-page.test.ts +29 -21
- package/server/modules/oauth/tests/oauth-consent-ratelimit.test.ts +2 -2
- package/server/modules/oauth/tests/token-info.routes.test.ts +2 -2
- package/server/modules/observation/architecture-delta.producer.ts +1 -1
- package/server/modules/observation/blind-spots.ts +1 -1
- package/server/modules/observation/observation-store.ts +54 -16
- package/server/modules/observation/observation-uri.ts +34 -21
- package/server/modules/observation/observation.routes.ts +1 -1
- package/server/modules/observation/project-truth.ts +3 -3
- package/server/modules/observation/session-ask-decision-answer.ts +2 -1
- package/server/modules/observation/session-digest-llm.ts +7 -1
- package/server/modules/observation/session-digest.ts +39 -5
- package/server/modules/observation/tests/architecture-delta.test.ts +1 -1
- package/server/modules/observation/tests/observation-routes.test.ts +13 -0
- package/server/modules/observation/tests/observation-store.test.ts +58 -0
- package/server/modules/observation/tests/project-truth.test.ts +2 -2
- package/server/modules/observation/tests/session-ask-decision-digest.test.ts +189 -0
- package/server/modules/observation/tests/session-digest.test.ts +43 -0
- package/server/modules/providers/index.ts +13 -0
- package/server/modules/providers/list/claude/claude-host-driver.provider.ts +1 -1
- package/server/modules/providers/list/codex/codex-app-server.client.ts +37 -5
- package/server/modules/providers/list/codex/codex-app-server.connection.ts +1 -1
- package/server/modules/providers/list/codex/codex-host-driver.contract.ts +18 -9
- package/server/modules/providers/list/codex/codex-host-driver.provider.ts +15 -1
- package/server/modules/providers/list/codex/codex-models.provider.ts +16 -3
- package/server/modules/providers/list/codex/codex-provider-injection.ts +323 -0
- package/server/modules/providers/list/codex/codex-resident-provider-launch.ts +71 -0
- package/server/modules/providers/list/codex/codex-runtime.provider.ts +20 -1
- package/server/modules/providers/list/cursor/cursor-models.provider.ts +1 -1
- package/server/modules/providers/list/opencode/opencode-models.provider.ts +1 -1
- package/server/modules/providers/provider.routes.ts +23 -2
- package/server/modules/providers/services/provider-models.service.ts +187 -124
- package/server/modules/providers/services/provider-runtime.service.ts +3 -0
- package/server/modules/providers/services/session-model-resolver.ts +180 -0
- package/server/modules/providers/services/session-provider-binding.ts +176 -0
- package/server/modules/providers/services/sessions.service.ts +5 -1
- package/server/modules/providers/tests/claude-resident-addressable.test.ts +2 -2
- package/server/modules/providers/tests/claude-session-name-authority.test.ts +4 -4
- package/server/modules/providers/tests/codex-app-server-protocol.test.ts +1 -1
- package/server/modules/providers/tests/codex-host-driver-persistent.test.ts +2 -2
- package/server/modules/providers/tests/codex-provider-model-binding.test.ts +345 -0
- package/server/modules/providers/tests/codex-resident-provider-injection.test.ts +561 -0
- package/server/modules/providers/tests/codex-runtime-provider-injection.test.ts +269 -0
- package/server/modules/providers/tests/codex-session-provider-binding.test.ts +386 -0
- package/server/modules/providers/tests/codex-sessions.test.ts +1 -1
- package/server/modules/providers/tests/opencode-sessions.test.ts +2 -2
- package/server/modules/providers/tests/provider-models.service.test.ts +15 -0
- package/server/modules/providers/tests/provider.routes.test.ts +1 -1
- package/server/modules/quay/index.ts +1 -1
- package/server/modules/quay/quay-dispatch-carrier.ts +1 -1
- package/server/modules/quay/quay-fleet-cli.ts +1 -1
- package/server/modules/quay/quay-fleet-locator.ts +2 -2
- package/server/modules/quay/quay-fleet-project-id.ts +14 -14
- package/server/modules/quay/quay-fleet-registry.ts +8 -8
- package/server/modules/quay/quay-suite-fanin-reader.ts +1 -1
- package/server/modules/quay/quay-uri-resolve.ts +8 -8
- package/server/modules/quay/quay.module.ts +3 -3
- package/server/modules/quay/quay.routes.ts +1 -1
- package/server/modules/quay/quay.service.ts +6 -6
- package/server/modules/quay/session-task-chain.service.ts +1 -1
- package/server/modules/quay/tests/contracts/fleet-cli-contracts.test.ts +3 -3
- package/server/modules/quay/tests/contracts/shapes.ts +10 -10
- package/server/modules/quay/tests/quay-fleet-locator.test.ts +1 -1
- package/server/modules/quay/tests/quay-fleet-project-id.test.ts +6 -6
- package/server/modules/quay/tests/quay-uri-resolve.test.ts +10 -10
- package/server/modules/session-hosts/tests/resident-server-restart.test.ts +1 -1
- package/server/modules/settings/codex-mcp-gateway.settings.ts +1 -1
- package/server/modules/settings/codex-model-providers.schema.ts +460 -0
- package/server/modules/settings/codex-model-providers.service.ts +235 -0
- package/server/modules/settings/codex-model-providers.settings.ts +713 -0
- package/server/modules/settings/codex-model-providers.store.ts +244 -0
- package/server/modules/settings/index.ts +18 -0
- package/server/modules/settings/server-settings-file.ts +29 -41
- package/server/modules/settings/server-settings.ts +2 -3
- package/server/modules/settings/settings.module.ts +41 -0
- package/server/modules/settings/settings.routes.ts +37 -0
- package/server/modules/settings/settings.service.ts +21 -26
- package/server/modules/settings/tests/cockpit-session-start-settings.routes.test.ts +1 -0
- package/server/modules/settings/tests/codex-model-providers-settings.test.ts +413 -0
- package/server/modules/settings/tests/codex-provider-advanced.test.ts +540 -0
- package/server/modules/settings/tests/codex-provider-import.test.ts +621 -0
- package/server/modules/voice/tests/voice-lexicon.test.ts +10 -10
- package/server/modules/voice/voice-lexicon.ts +1 -1
- package/server/modules/websocket/services/chat-control.service.ts +35 -2
- package/server/modules/websocket/services/chat-websocket.service.ts +25 -1
- package/server/modules/websocket/tests/chat-background-task.test.ts +17 -1
- package/server/modules/websocket/tests/chat-stop-task.test.ts +17 -1
- package/server/modules/worktrees/services/worktree-list.service.ts +1 -1
- package/server/modules/worktrees/services/worktree-open.service.ts +1 -1
- package/server/modules/worktrees/services/worktree-remove.service.ts +1 -1
- package/server/shared/brand.ts +24 -38
- package/server/shared/data-root-migration.ts +3 -2
- package/server/shared/data-root.ts +73 -79
- package/server/shared/interfaces.ts +1 -1
- package/server/shared/mcp-contract/types.ts +20 -15
- package/server/shared/ports/codex-provider-registry.port.ts +133 -0
- package/server/shared/ports/session-blocked-events.port.ts +1 -1
- package/server/shared/ports/session-run-events.port.ts +2 -2
- package/server/shared/settings-file.ts +167 -6
- package/server/shared/tests/architecture-ratchet.baseline.json +15 -15
- package/server/shared/tests/cloudpit-brand-env.test.ts +106 -36
- package/server/shared/tests/cloudpit-data-root.test.ts +42 -18
- package/server/shared/tests/cloudpit-goal-exit-gate.baseline.json +6 -2
- package/server/shared/tests/cloudpit-goal-exit-gate.test.ts +179 -17
- package/server/shared/tests/cloudpit-runtime-flip.test.ts +162 -123
- package/server/shared/tests/frontend-import-cycle-budget.baseline.json +8 -6
- package/server/shared/tests/frontend-import-cycle-budget.test.ts +9 -1
- package/server/shared/tests/quay-test-script.test.ts +40 -6
- package/server/shared/tests/settings-file.test.ts +83 -1
- package/server/shared/types.ts +121 -8
- package/server/shared/utils.ts +1 -1
- package/dist/assets/channel-D7XqNTJC.js +0 -1
- package/dist/assets/channel-sbQyI1an.js +0 -1
- package/dist/assets/classDiagram-JCYQIIEL-DHudi-zH.js +0 -1
- package/dist/assets/classDiagram-JCYQIIEL-DV7ybJJG.js +0 -1
- package/dist/assets/classDiagram-v2-OCEON4UE-DHudi-zH.js +0 -1
- package/dist/assets/classDiagram-v2-OCEON4UE-DV7ybJJG.js +0 -1
- package/dist/assets/index-BsACp0s2.css +0 -32
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-CNMNp6YA.js +0 -8
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-DOjtDEUW.js +0 -8
- package/dist/icons/icon-128x128.svg +0 -12
- package/dist/icons/icon-144x144.svg +0 -12
- package/dist/icons/icon-152x152.svg +0 -12
- package/dist/icons/icon-192x192.svg +0 -12
- package/dist/icons/icon-384x384.svg +0 -12
- package/dist/icons/icon-512x512.svg +0 -12
- package/dist/icons/icon-72x72.svg +0 -12
- package/dist/icons/icon-96x96.svg +0 -12
- package/dist/icons/icon-template.svg +0 -12
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The upstream-provider binding a session carries (AC-462).
|
|
3
|
+
*
|
|
4
|
+
* WHY A SESSION HAS ONE. A custom model entry may name the Codex provider it
|
|
5
|
+
* dials (`codexProviderId`, AC-461). Codex records that provider inside the
|
|
6
|
+
* thread it starts and checks it again on every resume: a thread started under
|
|
7
|
+
* provider `bob` refuses a turn when the process is launched under `alice`
|
|
8
|
+
* (`modelProviderMismatch`). The binding therefore belongs to the SESSION, not
|
|
9
|
+
* only to the model currently selected — changing the model of a running
|
|
10
|
+
* session to one from another provider does not switch providers, it breaks
|
|
11
|
+
* the conversation. A session that has run under a bound provider must be
|
|
12
|
+
* forked or recreated to run under a different one.
|
|
13
|
+
*
|
|
14
|
+
* WHAT THIS FILE OWNS. The three answers every reader needs, and nothing else:
|
|
15
|
+
* 1. which provider id a selected model resolves to;
|
|
16
|
+
* 2. whether a recorded id still names a provider the project defines (a
|
|
17
|
+
* deleted or renamed provider is MARKED, never silently replaced by the
|
|
18
|
+
* provider default);
|
|
19
|
+
* 3. whether a switch from the recorded id to the requested one is allowed.
|
|
20
|
+
*
|
|
21
|
+
* TWO ABSENCES ARE DIFFERENT. `model_provider_id` NULL means "no binding has
|
|
22
|
+
* been recorded" — an unbound model, a session from before the column, or one
|
|
23
|
+
* that has never been sent on. NULL is NOT "the default provider", so a
|
|
24
|
+
* selection may establish a binding on such a session; once recorded, the
|
|
25
|
+
* binding only ever changes through a new session. A model that declares no
|
|
26
|
+
* provider resolves to NULL, and moving a BOUND session to it is a switch
|
|
27
|
+
* (it would run under Codex's process-global provider) and is refused.
|
|
28
|
+
*
|
|
29
|
+
* WHAT THIS FILE DOES NOT DO. It never writes rows, never reads settings, and
|
|
30
|
+
* never imports a feature module: the registry is handed in as a reading (the
|
|
31
|
+
* shared port's `CodexProviderRegistryReading`) and the catalog as the one
|
|
32
|
+
* lookup it needs. `provider-models.service.ts` composes it with both.
|
|
33
|
+
*
|
|
34
|
+
* Consumers: `provider-models.service.ts` (recording and resolving a session's
|
|
35
|
+
* selection) and, through it, `chat-websocket.service.ts` (the pre-admission
|
|
36
|
+
* refusal of a send that would switch providers).
|
|
37
|
+
*/
|
|
38
|
+
import type { CodexProviderRegistryReading } from '@/shared/ports/codex-provider-registry.port.js';
|
|
39
|
+
import type { CustomProviderModelRecord, LLMProvider } from '@/shared/types.js';
|
|
40
|
+
import { AppError } from '@/shared/utils.js';
|
|
41
|
+
|
|
42
|
+
/** The catalog lookup a binding reading needs; `providerModelsDb` satisfies it. */
|
|
43
|
+
export type SessionProviderBindingCatalog = {
|
|
44
|
+
findCustomProviderModelByModelId(
|
|
45
|
+
provider: LLMProvider,
|
|
46
|
+
modelId: string,
|
|
47
|
+
): CustomProviderModelRecord | null;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A recorded binding as a reader should see it.
|
|
52
|
+
*
|
|
53
|
+
* `modelProviderProblem` is the explicit mark the AC asks for instead of a
|
|
54
|
+
* silent fallback: it is non-null only when the session carries an upstream
|
|
55
|
+
* provider id the registry no longer defines, and it names the id and the way
|
|
56
|
+
* out. `modelProviderId` is always the recorded value, unchanged — a provider
|
|
57
|
+
* that disappeared must not make the session look unbound.
|
|
58
|
+
*/
|
|
59
|
+
export type SessionProviderBinding = {
|
|
60
|
+
modelProviderId: string | null;
|
|
61
|
+
modelProviderProblem: string | null;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The upstream provider a selected model runs under, or null when it declares
|
|
66
|
+
* none (the entry inherits the provider's own default).
|
|
67
|
+
*
|
|
68
|
+
* The value is read from the model entry, never from the session: the session
|
|
69
|
+
* only records what the entry said at the time it first ran.
|
|
70
|
+
*/
|
|
71
|
+
export function resolveModelProviderId(
|
|
72
|
+
catalog: SessionProviderBindingCatalog,
|
|
73
|
+
provider: LLMProvider,
|
|
74
|
+
modelId: string,
|
|
75
|
+
): string | null {
|
|
76
|
+
const record = catalog.findCustomProviderModelByModelId(provider, modelId);
|
|
77
|
+
return record?.config?.codexProviderId?.trim() || null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Whether the registry defines this id.
|
|
82
|
+
*
|
|
83
|
+
* A project entry and a Codex built-in both count: a model may bind either
|
|
84
|
+
* (`RESERVED_CODEX_PROVIDER_IDS` is the settings source's list, carried here as
|
|
85
|
+
* data). An absent reading cannot judge, so it answers true — refusing every
|
|
86
|
+
* selection merely because the composition root has not installed the port yet
|
|
87
|
+
* would break the callers that ran before this feature existed.
|
|
88
|
+
*/
|
|
89
|
+
function isKnownProvider(registry: CodexProviderRegistryReading | null, providerId: string): boolean {
|
|
90
|
+
if (registry === null) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
return registry.reservedIds.includes(providerId)
|
|
94
|
+
|| registry.providers.some((provider) => provider.id === providerId);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Reads a recorded provider id plus, when the registry no longer defines it,
|
|
99
|
+
* the readable mark that says so.
|
|
100
|
+
*
|
|
101
|
+
* The model itself is NEVER re-resolved here: a session whose provider was
|
|
102
|
+
* deleted keeps the model it ran with, so every reader still shows what the
|
|
103
|
+
* conversation actually used. Falling back to the catalog default is the exact
|
|
104
|
+
* silent change this mark exists to prevent.
|
|
105
|
+
*/
|
|
106
|
+
export function readRecordedProviderBinding(
|
|
107
|
+
registry: CodexProviderRegistryReading | null,
|
|
108
|
+
providerId: string | null,
|
|
109
|
+
): SessionProviderBinding {
|
|
110
|
+
if (!providerId) {
|
|
111
|
+
return { modelProviderId: null, modelProviderProblem: null };
|
|
112
|
+
}
|
|
113
|
+
if (isKnownProvider(registry, providerId)) {
|
|
114
|
+
return { modelProviderId: providerId, modelProviderProblem: null };
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
modelProviderId: providerId,
|
|
118
|
+
modelProviderProblem:
|
|
119
|
+
`This session is bound to provider "${providerId}", which is no longer defined. `
|
|
120
|
+
+ 'Fork this session or start a new one to run it under another provider.',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Refuses moving an already-bound session to a selection that runs under a
|
|
126
|
+
* different upstream provider.
|
|
127
|
+
*
|
|
128
|
+
* Returns silently when the session has no recorded binding (any selection may
|
|
129
|
+
* establish one), or when the requested model resolves to the same id (another
|
|
130
|
+
* model on the same provider is an ordinary model switch).
|
|
131
|
+
*
|
|
132
|
+
* The refusal names both ids and the action, because "cannot switch" without
|
|
133
|
+
* "here is what to do instead" leaves the person with a dead composer.
|
|
134
|
+
*/
|
|
135
|
+
export function assertProviderSwitchAllowed(
|
|
136
|
+
recordedProviderId: string | null,
|
|
137
|
+
requestedProviderId: string | null,
|
|
138
|
+
requestedModel: string,
|
|
139
|
+
): void {
|
|
140
|
+
if (!recordedProviderId || requestedProviderId === recordedProviderId) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const attempted = requestedProviderId === null
|
|
144
|
+
? 'a model that inherits the provider default'
|
|
145
|
+
: `provider "${requestedProviderId}"`;
|
|
146
|
+
throw new AppError(
|
|
147
|
+
`This session is bound to provider "${recordedProviderId}"; `
|
|
148
|
+
+ `model "${requestedModel}" runs under ${attempted}. A session cannot change upstream `
|
|
149
|
+
+ 'provider in place — fork this session or start a new one to switch.',
|
|
150
|
+
{ code: 'SESSION_PROVIDER_MISMATCH', statusCode: 409 },
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Refuses recording a binding the registry does not know.
|
|
156
|
+
*
|
|
157
|
+
* A model entry can outlive the provider it names (the provider registry is a
|
|
158
|
+
* full-file replacement, so deleting or renaming an entry leaves every model
|
|
159
|
+
* entry bound to the old id pointing at nothing). Recording such an id would
|
|
160
|
+
* make a fresh session look bound to a provider that cannot be launched, so the
|
|
161
|
+
* selection is refused with the id and the two ways out.
|
|
162
|
+
*/
|
|
163
|
+
export function assertProviderAvailable(
|
|
164
|
+
registry: CodexProviderRegistryReading | null,
|
|
165
|
+
providerId: string | null,
|
|
166
|
+
requestedModel: string,
|
|
167
|
+
): void {
|
|
168
|
+
if (!providerId || isKnownProvider(registry, providerId)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
throw new AppError(
|
|
172
|
+
`Model "${requestedModel}" is bound to provider "${providerId}", which no longer exists. `
|
|
173
|
+
+ 'Pick another model, or restore the provider in the Codex provider settings.',
|
|
174
|
+
{ code: 'SESSION_PROVIDER_UNKNOWN', statusCode: 409 },
|
|
175
|
+
);
|
|
176
|
+
}
|
|
@@ -481,7 +481,7 @@ export const sessionsService = {
|
|
|
481
481
|
* chat, navigates to the returned id immediately, and the id never changes
|
|
482
482
|
* for the lifetime of the conversation. The provider-native id is mapped to
|
|
483
483
|
* this row later, when the provider runtime announces it mid-run. Its title
|
|
484
|
-
* comes directly from the first visible
|
|
484
|
+
* comes directly from the first visible Cloudpit message and is limited to
|
|
485
485
|
* four whole words before any provider-owned storage exists.
|
|
486
486
|
*
|
|
487
487
|
* `selection` is the model/effort/permission-mode the caller is creating the
|
|
@@ -615,6 +615,10 @@ export const sessionsService = {
|
|
|
615
615
|
// differently from the conversation it was branched from.
|
|
616
616
|
model: source.model,
|
|
617
617
|
effort: source.effort,
|
|
618
|
+
// The branch continues a thread the provider started under one upstream
|
|
619
|
+
// provider: resuming it under the process default is the mismatch this
|
|
620
|
+
// column exists to prevent, so the binding comes along.
|
|
621
|
+
modelProviderId: source.model_provider_id ?? null,
|
|
618
622
|
// Same reasoning for the permission mode: a fork inherits how the
|
|
619
623
|
// conversation it branches from was actually being run.
|
|
620
624
|
permissionMode: source.permission_mode,
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* A resident host holds one CLI across turns, and every CLI process registers a
|
|
6
6
|
* name for itself when it starts: other sessions on the machine can address it
|
|
7
|
-
* by that name. Claude Code picks that name; **
|
|
7
|
+
* by that name. Claude Code picks that name; **Cloudpit does not**. It used to
|
|
8
8
|
* (`--name <slug>-<id6>`, proposal §12), and that is the design this criterion
|
|
9
9
|
* was rewritten for: an app-invented name outranked the session's own `ai-title`
|
|
10
10
|
* and grew a new suffix on every restart. The app now launches the process with
|
|
@@ -1462,7 +1462,7 @@ test('a resident session publishes the address it answers to, and a peer reaches
|
|
|
1462
1462
|
null,
|
|
1463
1463
|
'the registry entry must carry the socket the address resolves to, or the address is not reachable',
|
|
1464
1464
|
);
|
|
1465
|
-
// The pollution shape itself, read on the published address:
|
|
1465
|
+
// The pollution shape itself, read on the published address: Cloudpit's
|
|
1466
1466
|
// suffix was the app session id's first six characters appended to a slug.
|
|
1467
1467
|
// A derived name is the CLI's and has no such tail.
|
|
1468
1468
|
assert.strictEqual(
|
|
@@ -22,9 +22,9 @@ import { ClaudeSessionSynchronizer } from '@/modules/providers/list/claude/claud
|
|
|
22
22
|
import { sessionsService } from '@/modules/providers/services/sessions.service.js';
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Who owns a session's name: a human, Claude Code, or
|
|
25
|
+
* Who owns a session's name: a human, Claude Code, or Cloudpit.
|
|
26
26
|
*
|
|
27
|
-
*
|
|
27
|
+
* Cloudpit does not own it. That is the settled design ((a) in the task
|
|
28
28
|
* record): the app no longer hands the CLI a `--name` at all, and the name a
|
|
29
29
|
* session has is the one Claude Code gives it. What remains to guard here is
|
|
30
30
|
* everything an *older* build left behind — the launch address it wrote into
|
|
@@ -41,7 +41,7 @@ import { sessionsService } from '@/modules/providers/services/sessions.service.j
|
|
|
41
41
|
* - a real `agent-name` an agent chose, and a name the user chose, both still
|
|
42
42
|
* outrank it — without those two, the simplest way to pass the case above
|
|
43
43
|
* would be to demote every name the CLI writes;
|
|
44
|
-
* - the rank table itself has to keep
|
|
44
|
+
* - the rank table itself has to keep Cloudpit's own sources below `ai`, or the
|
|
45
45
|
* ladder above is unreachable through the other door into the same row.
|
|
46
46
|
*
|
|
47
47
|
* The fixtures are real transcript lines in a real temporary Claude home,
|
|
@@ -687,7 +687,7 @@ test('the discriminator is anchored on the session it is asked about', () => {
|
|
|
687
687
|
assert.strictEqual(isSelfAssignedSessionName('The Agent That Owns This', appSessionId), false);
|
|
688
688
|
});
|
|
689
689
|
|
|
690
|
-
test('the rank table keeps every
|
|
690
|
+
test('the rank table keeps every Cloudpit-made source below a real title', async () => {
|
|
691
691
|
await withIsolatedDatabase(async () => {
|
|
692
692
|
const projectPath = await mkdtemp(path.join(os.tmpdir(), 'claude-name-authority-rank-'));
|
|
693
693
|
projectsDb.createProjectPath(projectPath);
|
|
@@ -439,7 +439,7 @@ test('the declaration is what switches thread/queue/add on and off (AC3)', async
|
|
|
439
439
|
jsonrpc: '2.0',
|
|
440
440
|
id: 1,
|
|
441
441
|
method: 'initialize',
|
|
442
|
-
params: { clientInfo: { name: '
|
|
442
|
+
params: { clientInfo: { name: 'cloudpit', version: '1' }, capabilities: {} },
|
|
443
443
|
}));
|
|
444
444
|
undeclared.write(JSON.stringify({
|
|
445
445
|
jsonrpc: '2.0',
|
|
@@ -484,11 +484,11 @@ test('driver conforms to IProviderHostDriver with multiplexedHost=false (AC8)',
|
|
|
484
484
|
});
|
|
485
485
|
|
|
486
486
|
/**
|
|
487
|
-
* The failure this criterion pins:
|
|
487
|
+
* The failure this criterion pins: Cloudpit's `default` effort sentinel is not
|
|
488
488
|
* a codex effort, and the locked 0.153.4 app-server refuses the whole turn with
|
|
489
489
|
* `Invalid value: 'default'` rather than ignoring the field.
|
|
490
490
|
*/
|
|
491
|
-
test("turn/start omits
|
|
491
|
+
test("turn/start omits Cloudpit's 'default' effort and forwards a codex value (AC1)", () => {
|
|
492
492
|
const withDefault = turnParams('thread-effort', { command: 'hi', options: { effort: 'default' } });
|
|
493
493
|
const withHigh = turnParams('thread-effort', { command: 'hi', options: { effort: 'high' } });
|
|
494
494
|
const withUltracode = turnParams('thread-effort', { command: 'hi', options: { effort: 'ultracode' } });
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { once } from 'node:events';
|
|
3
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import type { AddressInfo } from 'node:net';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import test from 'node:test';
|
|
8
|
+
|
|
9
|
+
import Database from 'better-sqlite3';
|
|
10
|
+
import express, { type NextFunction, type Request, type Response } from 'express';
|
|
11
|
+
|
|
12
|
+
import { closeConnection, initializeDatabase } from '@/modules/database/index.js';
|
|
13
|
+
import providerRouter from '@/modules/providers/provider.routes.js';
|
|
14
|
+
import { createProviderModelsService } from '@/modules/providers/services/provider-models.service.js';
|
|
15
|
+
import {
|
|
16
|
+
installCodexProviderRegistryPort,
|
|
17
|
+
type CodexProviderRegistryReading,
|
|
18
|
+
} from '@/shared/ports/codex-provider-registry.port.js';
|
|
19
|
+
import type {
|
|
20
|
+
CustomProviderModelInput,
|
|
21
|
+
CustomProviderModelRecord,
|
|
22
|
+
LLMProvider,
|
|
23
|
+
ProviderModelsDefinition,
|
|
24
|
+
} from '@/shared/types.js';
|
|
25
|
+
import { AppError } from '@/shared/utils.js';
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The model-entry → Codex provider binding (AC-461).
|
|
29
|
+
*
|
|
30
|
+
* Legs:
|
|
31
|
+
* 1. a declared `codexProviderId` is normalized, persisted, and shown as
|
|
32
|
+
* `model · provider` in the merged catalog;
|
|
33
|
+
* 2. an id that no provider defines (never existed, or was deleted) is refused
|
|
34
|
+
* with a readable 409 that names it, and nothing is written;
|
|
35
|
+
* 3. an entry that declares no provider keeps the pre-existing behaviour —
|
|
36
|
+
* bare display name, no stored binding, "inherit the Codex global default";
|
|
37
|
+
* 4. a reserved Codex built-in id is bindable even though the project file may
|
|
38
|
+
* not define it;
|
|
39
|
+
* 5. duplicating an entry copies its binding;
|
|
40
|
+
* 6. the HTTP route carries `codexProviderId` through to storage.
|
|
41
|
+
*
|
|
42
|
+
* The registry itself is a shared port (the settings module installs the real
|
|
43
|
+
* reading at boot); these legs install a fake reading so the model service is
|
|
44
|
+
* driven without touching a settings file, and the route leg installs the same
|
|
45
|
+
* fake for the process-wide singleton the router uses.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
const PREDEFINED: ProviderModelsDefinition = {
|
|
49
|
+
OPTIONS: [{ value: 'codex-default', label: 'Codex default' }],
|
|
50
|
+
DEFAULT: 'codex-default',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/** In-memory stand-in for the `provider_models` table; update persists the config like the DB. */
|
|
54
|
+
const createCatalogStore = () => {
|
|
55
|
+
const rows = new Map<LLMProvider, CustomProviderModelRecord[]>();
|
|
56
|
+
let nextRecordId = 1;
|
|
57
|
+
const readRows = (provider: LLMProvider) => rows.get(provider) ?? [];
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
rows,
|
|
61
|
+
listCustomProviderModels(provider: LLMProvider) {
|
|
62
|
+
return [...readRows(provider)];
|
|
63
|
+
},
|
|
64
|
+
getCustomProviderModel(provider: LLMProvider, recordId: number) {
|
|
65
|
+
return readRows(provider).find((record) => record.recordId === recordId) ?? null;
|
|
66
|
+
},
|
|
67
|
+
findCustomProviderModelByModelId(provider: LLMProvider, modelId: string) {
|
|
68
|
+
return readRows(provider).find((record) => record.modelId === modelId) ?? null;
|
|
69
|
+
},
|
|
70
|
+
createCustomProviderModel(provider: LLMProvider, input: CustomProviderModelInput) {
|
|
71
|
+
const record: CustomProviderModelRecord = {
|
|
72
|
+
recordId: nextRecordId++,
|
|
73
|
+
provider,
|
|
74
|
+
modelId: input.id,
|
|
75
|
+
model: input.model,
|
|
76
|
+
config: input.config ?? null,
|
|
77
|
+
sortOrder: readRows(provider).length,
|
|
78
|
+
};
|
|
79
|
+
rows.set(provider, [...readRows(provider), record]);
|
|
80
|
+
return record;
|
|
81
|
+
},
|
|
82
|
+
updateCustomProviderModel(
|
|
83
|
+
provider: LLMProvider,
|
|
84
|
+
recordId: number,
|
|
85
|
+
input: CustomProviderModelInput,
|
|
86
|
+
) {
|
|
87
|
+
const existing = readRows(provider).find((record) => record.recordId === recordId);
|
|
88
|
+
if (!existing) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
const updated: CustomProviderModelRecord = {
|
|
92
|
+
...existing,
|
|
93
|
+
modelId: input.id,
|
|
94
|
+
model: input.model,
|
|
95
|
+
config: input.config === undefined ? existing.config : input.config,
|
|
96
|
+
};
|
|
97
|
+
rows.set(provider, readRows(provider).map((record) => (
|
|
98
|
+
record.recordId === recordId ? updated : record
|
|
99
|
+
)));
|
|
100
|
+
return updated;
|
|
101
|
+
},
|
|
102
|
+
deleteCustomProviderModel(provider: LLMProvider, recordId: number, _fallbackModelId: string) {
|
|
103
|
+
const existing = readRows(provider).find((record) => record.recordId === recordId);
|
|
104
|
+
if (!existing) {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
rows.set(provider, readRows(provider).filter((record) => record.recordId !== recordId));
|
|
108
|
+
return existing;
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const createService = (read: () => CodexProviderRegistryReading | null) => {
|
|
114
|
+
const catalog = createCatalogStore();
|
|
115
|
+
const service = createProviderModelsService({
|
|
116
|
+
resolveProvider: () => ({
|
|
117
|
+
models: {
|
|
118
|
+
getSupportedModels: async () => PREDEFINED,
|
|
119
|
+
getCurrentActiveModel: async () => ({ model: PREDEFINED.DEFAULT }),
|
|
120
|
+
},
|
|
121
|
+
}),
|
|
122
|
+
catalog,
|
|
123
|
+
sessions: {
|
|
124
|
+
getSessionById: () => null,
|
|
125
|
+
setSessionModel: () => undefined,
|
|
126
|
+
// No row in this file's fixture, so no session-binding write can land;
|
|
127
|
+
// the method exists to satisfy the service's narrowed store seam.
|
|
128
|
+
setSessionModelProviderId: () => false,
|
|
129
|
+
setSessionEffort: () => undefined,
|
|
130
|
+
setSessionPermissionMode: () => false,
|
|
131
|
+
},
|
|
132
|
+
codexProviders: { read },
|
|
133
|
+
});
|
|
134
|
+
return { catalog, service };
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/** One fake registry reading; `providers` is the mutable project half, reserved ids are fixed. */
|
|
138
|
+
const createRegistry = (
|
|
139
|
+
initialIds: string[] = [],
|
|
140
|
+
reservedIds: string[] = ['openai', 'ollama', 'lmstudio'],
|
|
141
|
+
) => {
|
|
142
|
+
const ids = new Set(initialIds);
|
|
143
|
+
const reading = (): CodexProviderRegistryReading => ({
|
|
144
|
+
providers: [...ids].map((id) => ({ id })),
|
|
145
|
+
reservedIds,
|
|
146
|
+
});
|
|
147
|
+
return { ids, reading };
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const modelInput = (codexProviderId?: string): CustomProviderModelInput => ({
|
|
151
|
+
id: 'bound-model',
|
|
152
|
+
model: 'Bound Model',
|
|
153
|
+
config: codexProviderId === undefined ? { env: [] } : { env: [], codexProviderId },
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
const assertRefused = (error: unknown, providerId: string): boolean => {
|
|
157
|
+
assert.ok(error instanceof AppError, `expected AppError, got ${String(error)}`);
|
|
158
|
+
assert.equal(error.statusCode, 409);
|
|
159
|
+
assert.equal(error.code, 'CODEX_PROVIDER_UNKNOWN');
|
|
160
|
+
assert.match(error.message, new RegExp(providerId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
|
|
161
|
+
assert.match(error.message, /omit codexProviderId/);
|
|
162
|
+
return true;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
test('a declared provider is persisted and the merged catalog row shows model · provider', async () => {
|
|
166
|
+
const registry = createRegistry(['bob']);
|
|
167
|
+
const { catalog, service } = createService(registry.reading);
|
|
168
|
+
|
|
169
|
+
const created = await service.createCustomModel('codex', modelInput('bob'));
|
|
170
|
+
|
|
171
|
+
assert.equal(created.model.label, 'Bound Model · bob');
|
|
172
|
+
assert.equal(created.model.config?.codexProviderId, 'bob');
|
|
173
|
+
assert.deepEqual(created.model.config?.env, []);
|
|
174
|
+
const stored = catalog.rows.get('codex')?.[0];
|
|
175
|
+
assert.ok(stored, 'the row must be written');
|
|
176
|
+
assert.deepEqual(stored.config, { codexProviderId: 'bob', env: [] });
|
|
177
|
+
|
|
178
|
+
const merged = await service.getProviderModels('codex');
|
|
179
|
+
const option = merged.OPTIONS.find((entry) => entry.value === 'bound-model');
|
|
180
|
+
assert.equal(option?.label, 'Bound Model · bob');
|
|
181
|
+
assert.equal(option?.config?.codexProviderId, 'bob');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test('an unknown provider is refused with a readable 409 naming it, and nothing is written', async () => {
|
|
185
|
+
const { catalog, service } = createService(createRegistry([]).reading);
|
|
186
|
+
|
|
187
|
+
await assert.rejects(
|
|
188
|
+
service.createCustomModel('codex', modelInput('nobody')),
|
|
189
|
+
(error) => assertRefused(error, 'nobody'),
|
|
190
|
+
);
|
|
191
|
+
assert.deepEqual(catalog.rows.get('codex'), undefined, 'no row may be persisted');
|
|
192
|
+
|
|
193
|
+
const merged = await service.getProviderModels('codex');
|
|
194
|
+
assert.deepEqual(
|
|
195
|
+
merged.OPTIONS.map((entry) => entry.value),
|
|
196
|
+
['codex-default'],
|
|
197
|
+
'a refused entry must not appear in the catalog',
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test('a provider deleted since the entry was written is refused on update, and the row is untouched', async () => {
|
|
202
|
+
const registry = createRegistry(['bob']);
|
|
203
|
+
const { catalog, service } = createService(registry.reading);
|
|
204
|
+
const created = await service.createCustomModel('codex', modelInput('bob'));
|
|
205
|
+
const recordId = created.model.recordId;
|
|
206
|
+
assert.ok(recordId);
|
|
207
|
+
|
|
208
|
+
registry.ids.delete('bob');
|
|
209
|
+
|
|
210
|
+
await assert.rejects(
|
|
211
|
+
service.updateCustomModel('codex', recordId, {
|
|
212
|
+
id: 'bound-model',
|
|
213
|
+
model: 'Renamed',
|
|
214
|
+
config: { env: [], codexProviderId: 'bob' },
|
|
215
|
+
}),
|
|
216
|
+
(error) => assertRefused(error, 'bob'),
|
|
217
|
+
);
|
|
218
|
+
const stored = catalog.rows.get('codex')?.[0];
|
|
219
|
+
assert.equal(stored?.model, 'Bound Model', 'the refused update must not rename the row');
|
|
220
|
+
assert.equal(stored?.config?.codexProviderId, 'bob');
|
|
221
|
+
|
|
222
|
+
// A create that binds the same deleted id is refused too: no dangling reference may be added.
|
|
223
|
+
await assert.rejects(
|
|
224
|
+
service.createCustomModel('codex', { ...modelInput('bob'), id: 'second-model' }),
|
|
225
|
+
(error) => assertRefused(error, 'bob'),
|
|
226
|
+
);
|
|
227
|
+
assert.equal(catalog.rows.get('codex')?.length, 1);
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test('an entry that declares no provider keeps the passthrough baseline', async () => {
|
|
231
|
+
const { catalog, service } = createService(createRegistry(['bob']).reading);
|
|
232
|
+
|
|
233
|
+
const withoutBinding = await service.createCustomModel('codex', modelInput());
|
|
234
|
+
assert.equal(withoutBinding.model.label, 'Bound Model');
|
|
235
|
+
assert.deepEqual(withoutBinding.model.config, { env: [] });
|
|
236
|
+
|
|
237
|
+
// No config at all: the stored config is null, exactly as before this field existed.
|
|
238
|
+
const withoutConfig = await service.createCustomModel('codex', { id: 'bare', model: 'Bare' });
|
|
239
|
+
assert.equal(withoutConfig.model.label, 'Bare');
|
|
240
|
+
assert.equal(withoutConfig.model.config, null);
|
|
241
|
+
|
|
242
|
+
assert.deepEqual(
|
|
243
|
+
catalog.rows.get('codex')?.map((record) => record.config),
|
|
244
|
+
[{ env: [] }, null],
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test('a reserved Codex built-in id is bindable without a project registry entry', async () => {
|
|
249
|
+
const registry = createRegistry([]);
|
|
250
|
+
const { service } = createService(registry.reading);
|
|
251
|
+
|
|
252
|
+
const created = await service.createCustomModel('codex', modelInput('openai'));
|
|
253
|
+
assert.equal(created.model.label, 'Bound Model · openai');
|
|
254
|
+
assert.equal(created.model.config?.codexProviderId, 'openai');
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('duplicating an entry copies its provider binding', async () => {
|
|
258
|
+
const { service } = createService(createRegistry(['bob']).reading);
|
|
259
|
+
const source = await service.createCustomModel('codex', modelInput('bob'));
|
|
260
|
+
assert.ok(source.model.recordId);
|
|
261
|
+
|
|
262
|
+
const copy = await service.duplicateCustomModel('codex', source.model.recordId, {
|
|
263
|
+
id: 'copy-model',
|
|
264
|
+
model: 'Copy',
|
|
265
|
+
});
|
|
266
|
+
assert.equal(copy.model.label, 'Copy · bob');
|
|
267
|
+
assert.equal(copy.model.config?.codexProviderId, 'bob');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
/** Mounts the production router over a temp SQLite database, like `model-config-write-path`. */
|
|
271
|
+
async function withServer(run: (baseUrl: string, dbPath: string) => Promise<void>): Promise<void> {
|
|
272
|
+
const previous = process.env.DATABASE_PATH;
|
|
273
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), 'codex-binding-'));
|
|
274
|
+
const dbPath = path.join(dir, 'auth.db');
|
|
275
|
+
closeConnection();
|
|
276
|
+
process.env.DATABASE_PATH = dbPath;
|
|
277
|
+
await writeFile(dbPath, '');
|
|
278
|
+
await initializeDatabase();
|
|
279
|
+
|
|
280
|
+
const app = express().use(express.json()).use('/api/providers', providerRouter);
|
|
281
|
+
app.use((error: unknown, _req: Request, res: Response, _next: NextFunction) => {
|
|
282
|
+
if (error instanceof AppError) {
|
|
283
|
+
res.status(error.statusCode).json({ success: false, error: { code: error.code, message: error.message } });
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
res.status(500).json({ success: false });
|
|
287
|
+
});
|
|
288
|
+
const server = app.listen(0, '127.0.0.1');
|
|
289
|
+
await once(server, 'listening');
|
|
290
|
+
try {
|
|
291
|
+
await run(`http://127.0.0.1:${(server.address() as AddressInfo).port}`, dbPath);
|
|
292
|
+
} finally {
|
|
293
|
+
await new Promise<void>((resolve, reject) => server.close((e) => (e ? reject(e) : resolve())));
|
|
294
|
+
closeConnection();
|
|
295
|
+
if (previous === undefined) delete process.env.DATABASE_PATH;
|
|
296
|
+
else process.env.DATABASE_PATH = previous;
|
|
297
|
+
await rm(dir, { recursive: true, force: true });
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const postModel = (base: string, provider: string, body: unknown) => fetch(
|
|
302
|
+
`${base}/api/providers/${provider}/models`,
|
|
303
|
+
{ method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) },
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
test('the HTTP route carries codexProviderId through to storage and refuses an unknown id', async () => {
|
|
307
|
+
const registry = createRegistry(['bob']);
|
|
308
|
+
installCodexProviderRegistryPort({ read: registry.reading });
|
|
309
|
+
|
|
310
|
+
await withServer(async (base, dbPath) => {
|
|
311
|
+
const accepted = await postModel(base, 'claude', {
|
|
312
|
+
id: 'route-bound',
|
|
313
|
+
model: 'Route Bound',
|
|
314
|
+
config: { env: [], codexProviderId: 'bob' },
|
|
315
|
+
});
|
|
316
|
+
assert.equal(accepted.status, 201);
|
|
317
|
+
const acceptedBody = (await accepted.json()) as {
|
|
318
|
+
data: { model: { label: string; config?: { codexProviderId?: string } } };
|
|
319
|
+
};
|
|
320
|
+
assert.equal(acceptedBody.data.model.label, 'Route Bound · bob');
|
|
321
|
+
assert.equal(acceptedBody.data.model.config?.codexProviderId, 'bob');
|
|
322
|
+
|
|
323
|
+
const refused = await postModel(base, 'claude', {
|
|
324
|
+
id: 'route-unknown',
|
|
325
|
+
model: 'Route Unknown',
|
|
326
|
+
config: { env: [], codexProviderId: 'nobody' },
|
|
327
|
+
});
|
|
328
|
+
assert.equal(refused.status, 409);
|
|
329
|
+
const refusedBody = (await refused.json()) as { error?: { code?: string; message?: string } };
|
|
330
|
+
assert.equal(refusedBody.error?.code, 'CODEX_PROVIDER_UNKNOWN');
|
|
331
|
+
assert.match(refusedBody.error?.message ?? '', /nobody/);
|
|
332
|
+
|
|
333
|
+
const db = new Database(dbPath, { readonly: true });
|
|
334
|
+
const rows = db.prepare('SELECT model_id, config_json FROM provider_models ORDER BY id').all() as Array<{
|
|
335
|
+
model_id: string;
|
|
336
|
+
config_json: string | null;
|
|
337
|
+
}>;
|
|
338
|
+
db.close();
|
|
339
|
+
assert.deepEqual(rows.map((row) => row.model_id), ['route-bound']);
|
|
340
|
+
assert.deepEqual(JSON.parse(rows[0].config_json ?? 'null'), {
|
|
341
|
+
codexProviderId: 'bob',
|
|
342
|
+
env: [],
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
});
|