@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,713 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The project-owned Codex provider registry: what `codex.settings.json` says, what the
|
|
3
|
+
* settings API returns, and what a spawn-time lookup resolves.
|
|
4
|
+
*
|
|
5
|
+
* WHY A PROJECT FILE. A Codex process today reads only the operator's `~/.codex/config.toml`,
|
|
6
|
+
* so changing an upstream endpoint means editing a file every instance shares. This module
|
|
7
|
+
* makes the registry a first-class project setting: the file is the only write target, a
|
|
8
|
+
* version hash guards concurrent editors, and the runtime reads it AT SPAWN TIME (not once at
|
|
9
|
+
* boot) so an edit reaches the next launch.
|
|
10
|
+
*
|
|
11
|
+
* THE SECRET IS NEVER IN THE DOCUMENT. A provider names a `tokenFile`; the file is read when a
|
|
12
|
+
* provider is resolved and its value is handed to the caller in memory. `read()` reports only
|
|
13
|
+
* `tokenSet`, and the file's contents never reach a response, a log line or argv.
|
|
14
|
+
*
|
|
15
|
+
* WHAT A CALLER GETS. `read()` is the wire reading (`CodexModelProvidersReading`); `resolve(id)`
|
|
16
|
+
* is the spawn-time lookup, which either yields the resolved entry plus its secret or a
|
|
17
|
+
* readable problem. Resolution NEVER falls back to Codex's `openai` provider: a missing or
|
|
18
|
+
* unusable project provider is an error the caller must report, because silently dialling the
|
|
19
|
+
* default endpoint is the exact failure this registry exists to prevent.
|
|
20
|
+
*
|
|
21
|
+
* Consumers: `settings.module.ts` (the production source), `settings.service.ts` (through the
|
|
22
|
+
* port), and the resident/per-run Codex injection tasks (spawn-time `resolve`).
|
|
23
|
+
*
|
|
24
|
+
* USER PROFILE IMPORT. {@link readCodexUserProviderImports} performs the one other read this
|
|
25
|
+
* module owns: it lists the `[model_providers.*]` blocks of the operator's own
|
|
26
|
+
* `~/.codex` TOML files so the settings page can offer them as bindings. That read is
|
|
27
|
+
* deliberately one-way — it never reads an `env_key` VALUE or a token, and it never writes to
|
|
28
|
+
* the user's files. The project settings file stays the only write target.
|
|
29
|
+
*/
|
|
30
|
+
import { readFileSync, readdirSync } from 'node:fs';
|
|
31
|
+
import os from 'node:os';
|
|
32
|
+
import path from 'node:path';
|
|
33
|
+
|
|
34
|
+
import TOML from '@iarna/toml';
|
|
35
|
+
|
|
36
|
+
import type { CodexModelProvider, CodexModelProvidersReading } from '@/shared/types.js';
|
|
37
|
+
import { AppError, errorMessage, isRecord } from '@/shared/utils.js';
|
|
38
|
+
|
|
39
|
+
import {
|
|
40
|
+
CODEX_PROVIDER_WIRE_API,
|
|
41
|
+
parseCodexProviderEntry,
|
|
42
|
+
type CodexModelProviderEntry,
|
|
43
|
+
type CodexProviderAdvancedSettings,
|
|
44
|
+
} from './codex-model-providers.schema.js';
|
|
45
|
+
import {
|
|
46
|
+
readCodexSettingsDocument,
|
|
47
|
+
readCodexTokenSecret,
|
|
48
|
+
resolveCodexSettingsFileTarget,
|
|
49
|
+
resolveCodexTokenFilePath,
|
|
50
|
+
tokenFileModeWarning,
|
|
51
|
+
writeCodexSettingsDocument,
|
|
52
|
+
writeCodexTokenSecret,
|
|
53
|
+
} from './codex-model-providers.store.js';
|
|
54
|
+
|
|
55
|
+
/** One provider resolved for a launch: the entry plus the secret read from its token file. */
|
|
56
|
+
export type ResolvedCodexModelProvider = CodexModelProviderEntry & { secret: string };
|
|
57
|
+
|
|
58
|
+
/** The outcome of a spawn-time lookup; a false `ok` always carries a reportable line. */
|
|
59
|
+
export type CodexModelProviderResolution =
|
|
60
|
+
| { ok: true; provider: ResolvedCodexModelProvider }
|
|
61
|
+
| { ok: false; problem: string };
|
|
62
|
+
|
|
63
|
+
/** One write: the full replacement registry and the version the caller edited. */
|
|
64
|
+
export type CodexModelProvidersWriteInput = {
|
|
65
|
+
providers: unknown;
|
|
66
|
+
expectedVersion: string;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/** The source a composition root and a criterion both drive. */
|
|
70
|
+
export type CodexModelProvidersSource = {
|
|
71
|
+
read(): CodexModelProvidersReading;
|
|
72
|
+
resolve(id: string): CodexModelProviderResolution;
|
|
73
|
+
write(input: CodexModelProvidersWriteInput): Promise<CodexModelProvidersReading>;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/** The advanced fields of an entry, as the project document spells them (camelCase). */
|
|
77
|
+
function advancedFields(entry: CodexModelProviderEntry): CodexProviderAdvancedSettings {
|
|
78
|
+
return {
|
|
79
|
+
...(entry.httpHeaders === undefined ? {} : { httpHeaders: entry.httpHeaders }),
|
|
80
|
+
...(entry.envHttpHeaders === undefined ? {} : { envHttpHeaders: entry.envHttpHeaders }),
|
|
81
|
+
...(entry.queryParams === undefined ? {} : { queryParams: entry.queryParams }),
|
|
82
|
+
...(entry.requestMaxRetries === undefined ? {} : { requestMaxRetries: entry.requestMaxRetries }),
|
|
83
|
+
...(entry.streamMaxRetries === undefined ? {} : { streamMaxRetries: entry.streamMaxRetries }),
|
|
84
|
+
...(entry.streamIdleTimeoutMs === undefined ? {} : { streamIdleTimeoutMs: entry.streamIdleTimeoutMs }),
|
|
85
|
+
...(entry.modelCatalogUrl === undefined ? {} : { modelCatalogUrl: entry.modelCatalogUrl }),
|
|
86
|
+
...(entry.modelContextWindow === undefined ? {} : { modelContextWindow: entry.modelContextWindow }),
|
|
87
|
+
...(entry.modelAutoCompactTokenLimit === undefined
|
|
88
|
+
? {}
|
|
89
|
+
: { modelAutoCompactTokenLimit: entry.modelAutoCompactTokenLimit }),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Turns validated entries into the wire reading, reading each token file only for `tokenSet`. */
|
|
94
|
+
function projectProviders(
|
|
95
|
+
filePath: string,
|
|
96
|
+
homeDir: string,
|
|
97
|
+
entries: Array<{ entry: CodexModelProviderEntry; warnings: string[] }>,
|
|
98
|
+
): CodexModelProvider[] {
|
|
99
|
+
return entries
|
|
100
|
+
.map(({ entry, warnings }) => {
|
|
101
|
+
const tokenFile = resolveCodexTokenFilePath(filePath, entry.id, entry.tokenFile, homeDir);
|
|
102
|
+
const secret = readCodexTokenSecret(tokenFile);
|
|
103
|
+
const providerWarnings = [...warnings];
|
|
104
|
+
if (secret.ok) {
|
|
105
|
+
const modeWarning = tokenFileModeWarning(tokenFile);
|
|
106
|
+
if (modeWarning !== null) providerWarnings.push(modeWarning);
|
|
107
|
+
} else {
|
|
108
|
+
providerWarnings.push(secret.problem);
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
id: entry.id,
|
|
112
|
+
name: entry.name,
|
|
113
|
+
baseUrl: entry.baseUrl,
|
|
114
|
+
envKey: entry.envKey,
|
|
115
|
+
tokenFile,
|
|
116
|
+
wireApi: entry.wireApi,
|
|
117
|
+
...advancedFields(entry),
|
|
118
|
+
tokenSet: secret.ok,
|
|
119
|
+
warnings: providerWarnings,
|
|
120
|
+
};
|
|
121
|
+
})
|
|
122
|
+
.sort((left, right) => left.id.localeCompare(right.id));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Reads the `modelProviders` block tolerantly: one bad entry is skipped and reported. */
|
|
126
|
+
function readProviderRegistry(
|
|
127
|
+
document: Record<string, unknown>,
|
|
128
|
+
filePath: string,
|
|
129
|
+
homeDir: string,
|
|
130
|
+
): { providers: CodexModelProvider[]; warnings: string[] } {
|
|
131
|
+
const block = document.modelProviders;
|
|
132
|
+
if (block === undefined) {
|
|
133
|
+
return { providers: [], warnings: [] };
|
|
134
|
+
}
|
|
135
|
+
if (!isRecord(block)) {
|
|
136
|
+
throw new AppError('`modelProviders` must be a JSON object; refusing to read it as a registry', {
|
|
137
|
+
code: 'CODEX_SETTINGS_INVALID_SHAPE',
|
|
138
|
+
statusCode: 500,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const warnings: string[] = [];
|
|
142
|
+
const entries: Array<{ entry: CodexModelProviderEntry; warnings: string[] }> = [];
|
|
143
|
+
for (const [key, raw] of Object.entries(block)) {
|
|
144
|
+
const parsed = parseCodexProviderEntry(raw, key, { settingsPath: filePath, homeDir, strict: false });
|
|
145
|
+
if (parsed.entry === null) {
|
|
146
|
+
// A skipped entry's reasons belong at the document level: there is no provider row left
|
|
147
|
+
// to carry them.
|
|
148
|
+
warnings.push(...parsed.warnings);
|
|
149
|
+
} else {
|
|
150
|
+
entries.push({ entry: parsed.entry, warnings: parsed.warnings });
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return { providers: projectProviders(filePath, homeDir, entries), warnings };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** The environment entry Codex itself honours for the directory holding `config.toml`. */
|
|
157
|
+
export const CODEX_HOME_ENV = 'CODEX_HOME';
|
|
158
|
+
|
|
159
|
+
/** One `[model_providers.<id>]` block read from the user's own Codex TOML files. */
|
|
160
|
+
export type CodexUserProviderImport = {
|
|
161
|
+
id: string;
|
|
162
|
+
name: string;
|
|
163
|
+
baseUrl: string;
|
|
164
|
+
envKey: string;
|
|
165
|
+
/**
|
|
166
|
+
* The declared dialect, or `responses` when the block omits it. This project only ever writes
|
|
167
|
+
* `responses`, so a block that declares another dialect is listed but not bindable.
|
|
168
|
+
*/
|
|
169
|
+
wireApi: string;
|
|
170
|
+
/** The user file the block came from; the import view names it so the origin is never lost. */
|
|
171
|
+
source: string;
|
|
172
|
+
/** True when the block can be selected as a model entry's `codexProviderId` unchanged. */
|
|
173
|
+
bindable: boolean;
|
|
174
|
+
/** Unknown fields (Codex's own `api`), and every reason the block cannot be bound. */
|
|
175
|
+
warnings: string[];
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The user-profile import view: the Codex home inspected, the files actually read, every
|
|
180
|
+
* provider block, and file-level problems (an unreadable or malformed file) that belong to no
|
|
181
|
+
* single provider.
|
|
182
|
+
*/
|
|
183
|
+
export type CodexUserProviderImportReading = {
|
|
184
|
+
directory: string;
|
|
185
|
+
files: string[];
|
|
186
|
+
providers: CodexUserProviderImport[];
|
|
187
|
+
warnings: string[];
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/** The user TOML files the import reads, in a stable order: `config.toml` first, then profiles. */
|
|
191
|
+
function userCodexConfigFiles(directory: string): string[] {
|
|
192
|
+
let entries: string[];
|
|
193
|
+
try {
|
|
194
|
+
entries = readdirSync(directory);
|
|
195
|
+
} catch (failure) {
|
|
196
|
+
const code = (failure as NodeJS.ErrnoException | null)?.code;
|
|
197
|
+
// A machine without ~/.codex is the ordinary "nothing to import" state.
|
|
198
|
+
if (code === 'ENOENT') return [];
|
|
199
|
+
throw new AppError(`could not list ${directory}: ${errorMessage(failure)}`, {
|
|
200
|
+
code: 'CODEX_USER_CONFIG_READ_FAILED',
|
|
201
|
+
statusCode: 500,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
const names = entries
|
|
205
|
+
.filter((entry) => entry === 'config.toml' || entry.endsWith('.config.toml'))
|
|
206
|
+
.sort((left, right) => {
|
|
207
|
+
if (left === 'config.toml') return -1;
|
|
208
|
+
if (right === 'config.toml') return 1;
|
|
209
|
+
return left.localeCompare(right);
|
|
210
|
+
});
|
|
211
|
+
return names.map((name) => path.join(directory, name));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/** Reads a TOML string field for the import VIEW; a non-string value is left to the parser's warning. */
|
|
215
|
+
function displayField(block: Record<string, unknown>, key: string): string {
|
|
216
|
+
const value = block[key];
|
|
217
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Turns one user block into an import row, reusing the project schema for every verdict. */
|
|
221
|
+
function readUserProviderImport(
|
|
222
|
+
id: string,
|
|
223
|
+
raw: unknown,
|
|
224
|
+
source: string,
|
|
225
|
+
homeDir: string,
|
|
226
|
+
): CodexUserProviderImport {
|
|
227
|
+
if (!isRecord(raw)) {
|
|
228
|
+
return {
|
|
229
|
+
id,
|
|
230
|
+
name: id,
|
|
231
|
+
baseUrl: '',
|
|
232
|
+
envKey: '',
|
|
233
|
+
wireApi: CODEX_PROVIDER_WIRE_API,
|
|
234
|
+
source,
|
|
235
|
+
bindable: false,
|
|
236
|
+
warnings: [`provider "${id}" in ${source} is not a TOML table; it cannot be imported`],
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// The project parser owns the verdict: reserved ids, an absolute http(s) base_url, a valid
|
|
241
|
+
// env_key, a supported wire_api, and the unknown-field warning (Codex's own `api`). A
|
|
242
|
+
// tolerant parse keeps a bad block visible instead of dropping it from the import view.
|
|
243
|
+
const parsed = parseCodexProviderEntry(raw, id, { settingsPath: source, homeDir, strict: false });
|
|
244
|
+
const warnings = [...parsed.warnings];
|
|
245
|
+
const declaredEnvKey = displayField(raw, 'env_key');
|
|
246
|
+
if (declaredEnvKey === '' && parsed.entry !== null) {
|
|
247
|
+
warnings.push(
|
|
248
|
+
`provider "${id}" in ${source} declares no env_key; importing it would use ${parsed.entry.envKey}`,
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
id,
|
|
254
|
+
name: displayField(raw, 'name') || id,
|
|
255
|
+
baseUrl: displayField(raw, 'base_url'),
|
|
256
|
+
envKey: declaredEnvKey || parsed.entry?.envKey || '',
|
|
257
|
+
wireApi: displayField(raw, 'wire_api') || parsed.entry?.wireApi || CODEX_PROVIDER_WIRE_API,
|
|
258
|
+
source,
|
|
259
|
+
bindable: parsed.entry !== null,
|
|
260
|
+
warnings,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Lists the `[model_providers.*]` blocks of the operator's own Codex TOML files
|
|
266
|
+
* (`$CODEX_HOME`, else `<home>/.codex`; `config.toml` plus every `<name>.config.toml`).
|
|
267
|
+
*
|
|
268
|
+
* READ-ONLY BY CONSTRUCTION. This function only opens the TOML files for reading. It never
|
|
269
|
+
* reads an `env_key`'s value, a token file, or `auth.json`, and it has no write path at all:
|
|
270
|
+
* binding an imported provider goes into the PROJECT settings file, never back into `~/.codex`.
|
|
271
|
+
*
|
|
272
|
+
* Consumers: the settings import endpoint and its criterion. Kept as a free function over
|
|
273
|
+
* injectable `homeDir`/`env` so a criterion can own a temp Codex home instead of the host's.
|
|
274
|
+
*/
|
|
275
|
+
export function readCodexUserProviderImports(
|
|
276
|
+
options: {
|
|
277
|
+
homeDir?: string | undefined;
|
|
278
|
+
env?: Record<string, string | undefined>;
|
|
279
|
+
} = {},
|
|
280
|
+
): CodexUserProviderImportReading {
|
|
281
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
282
|
+
const env = options.env ?? process.env;
|
|
283
|
+
const configured = env[CODEX_HOME_ENV];
|
|
284
|
+
const directory = configured !== undefined && configured.trim() !== ''
|
|
285
|
+
? configured.trim()
|
|
286
|
+
: path.join(homeDir, '.codex');
|
|
287
|
+
|
|
288
|
+
const files: string[] = [];
|
|
289
|
+
const providers: CodexUserProviderImport[] = [];
|
|
290
|
+
const warnings: string[] = [];
|
|
291
|
+
|
|
292
|
+
for (const file of userCodexConfigFiles(directory)) {
|
|
293
|
+
let text: string;
|
|
294
|
+
try {
|
|
295
|
+
text = readFileSync(file, 'utf8');
|
|
296
|
+
} catch (failure) {
|
|
297
|
+
// A file that vanished between the listing and the read is simply not imported; any
|
|
298
|
+
// other failure is a visible warning, never a silently empty import view.
|
|
299
|
+
if ((failure as NodeJS.ErrnoException | null)?.code !== 'ENOENT') {
|
|
300
|
+
warnings.push(`could not read ${file}: ${errorMessage(failure)}`);
|
|
301
|
+
}
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
files.push(file);
|
|
305
|
+
|
|
306
|
+
let parsed: unknown;
|
|
307
|
+
try {
|
|
308
|
+
parsed = TOML.parse(text);
|
|
309
|
+
} catch (failure) {
|
|
310
|
+
warnings.push(`${file} is not valid TOML: ${errorMessage(failure)}`);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
if (!isRecord(parsed)) {
|
|
314
|
+
warnings.push(`${file} did not parse to a TOML table`);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
const block = parsed.model_providers;
|
|
318
|
+
if (block === undefined) continue;
|
|
319
|
+
if (!isRecord(block)) {
|
|
320
|
+
warnings.push(`${file}: model_providers must be a TOML table`);
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
for (const [id, raw] of Object.entries(block)) {
|
|
324
|
+
providers.push(readUserProviderImport(id, raw, file, homeDir));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return { directory, files, providers, warnings };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Creates the registry source over the project file. Reads are uncached and re-read the file,
|
|
333
|
+
* because a spawn-time lookup must see an edit the settings API just wrote; writes are
|
|
334
|
+
* serialised in this instance's closure so a read-check-replace cannot interleave.
|
|
335
|
+
*
|
|
336
|
+
* Options exist for criteria (a temp file) and for the composition root (HOME and env), never
|
|
337
|
+
* for a caller to bypass the file.
|
|
338
|
+
*/
|
|
339
|
+
export function createCodexModelProvidersSource(
|
|
340
|
+
options: {
|
|
341
|
+
settingsPath?: string | null;
|
|
342
|
+
env?: Record<string, string | undefined>;
|
|
343
|
+
homeDir?: string | undefined;
|
|
344
|
+
} = {},
|
|
345
|
+
): CodexModelProvidersSource {
|
|
346
|
+
const homeDir = options.homeDir ?? os.homedir();
|
|
347
|
+
const target = resolveCodexSettingsFileTarget({
|
|
348
|
+
settingsPath: options.settingsPath,
|
|
349
|
+
env: options.env ?? process.env,
|
|
350
|
+
homeDir,
|
|
351
|
+
});
|
|
352
|
+
const filePath = target.path;
|
|
353
|
+
|
|
354
|
+
let tail: Promise<unknown> = Promise.resolve();
|
|
355
|
+
const serial = <T>(operation: () => Promise<T>): Promise<T> => {
|
|
356
|
+
const result = tail.then(operation, operation);
|
|
357
|
+
tail = result.then(() => undefined, () => undefined);
|
|
358
|
+
return result;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
const read = (): CodexModelProvidersReading => {
|
|
362
|
+
const raw = readCodexSettingsDocument(filePath);
|
|
363
|
+
const registry = readProviderRegistry(raw.document, filePath, homeDir);
|
|
364
|
+
return { path: filePath, version: raw.version, ...registry };
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
return {
|
|
368
|
+
read,
|
|
369
|
+
resolve(id: string): CodexModelProviderResolution {
|
|
370
|
+
try {
|
|
371
|
+
const raw = readCodexSettingsDocument(filePath);
|
|
372
|
+
const block = raw.document.modelProviders;
|
|
373
|
+
const rawEntry = isRecord(block) ? block[id] : undefined;
|
|
374
|
+
if (rawEntry === undefined) {
|
|
375
|
+
return { ok: false, problem: `Codex provider "${id}" is not configured in ${filePath}` };
|
|
376
|
+
}
|
|
377
|
+
const parsed = parseCodexProviderEntry(rawEntry, id, {
|
|
378
|
+
settingsPath: filePath,
|
|
379
|
+
homeDir,
|
|
380
|
+
strict: true,
|
|
381
|
+
});
|
|
382
|
+
if (parsed.entry === null) {
|
|
383
|
+
return { ok: false, problem: `Codex provider "${id}" is invalid: ${parsed.warnings.join('; ')}` };
|
|
384
|
+
}
|
|
385
|
+
const tokenFile = resolveCodexTokenFilePath(
|
|
386
|
+
filePath,
|
|
387
|
+
parsed.entry.id,
|
|
388
|
+
parsed.entry.tokenFile,
|
|
389
|
+
homeDir,
|
|
390
|
+
);
|
|
391
|
+
const secret = readCodexTokenSecret(tokenFile);
|
|
392
|
+
if (!secret.ok) {
|
|
393
|
+
return {
|
|
394
|
+
ok: false,
|
|
395
|
+
problem: `Codex provider "${id}" has no usable secret: ${secret.problem}`,
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
return { ok: true, provider: { ...parsed.entry, secret: secret.secret } };
|
|
399
|
+
} catch (failure) {
|
|
400
|
+
return { ok: false, problem: errorMessage(failure) };
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
write(input: CodexModelProvidersWriteInput): Promise<CodexModelProvidersReading> {
|
|
404
|
+
return serial(async () => { if (!Array.isArray(input.providers)) {
|
|
405
|
+
throw new AppError('providers must be an array', {
|
|
406
|
+
code: 'CODEX_PROVIDER_LIST_INVALID',
|
|
407
|
+
statusCode: 400,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
const byId: Record<string, Record<string, unknown>> = {};
|
|
411
|
+
const writeWarnings = new Map<string, string[]>();
|
|
412
|
+
const secrets = new Map<string, { tokenFile: string; secret: string }>();
|
|
413
|
+
for (const raw of input.providers) {
|
|
414
|
+
const parsed = parseCodexProviderEntry(raw, null, {
|
|
415
|
+
settingsPath: filePath,
|
|
416
|
+
homeDir,
|
|
417
|
+
strict: true,
|
|
418
|
+
});
|
|
419
|
+
if (parsed.entry === null) continue;
|
|
420
|
+
if (parsed.warnings.length > 0) writeWarnings.set(parsed.entry.id, parsed.warnings);
|
|
421
|
+
if (byId[parsed.entry.id] !== undefined) {
|
|
422
|
+
throw new AppError(`provider id "${parsed.entry.id}" appears more than once`, {
|
|
423
|
+
code: 'CODEX_PROVIDER_ID_DUPLICATE',
|
|
424
|
+
statusCode: 400,
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
byId[parsed.entry.id] = {
|
|
428
|
+
name: parsed.entry.name,
|
|
429
|
+
baseUrl: parsed.entry.baseUrl,
|
|
430
|
+
envKey: parsed.entry.envKey,
|
|
431
|
+
tokenFile: parsed.entry.tokenFile,
|
|
432
|
+
wireApi: parsed.entry.wireApi,
|
|
433
|
+
...advancedFields(parsed.entry),
|
|
434
|
+
};
|
|
435
|
+
if (parsed.token !== undefined) {
|
|
436
|
+
secrets.set(parsed.entry.id, {
|
|
437
|
+
tokenFile: resolveCodexTokenFilePath(
|
|
438
|
+
filePath,
|
|
439
|
+
parsed.entry.id,
|
|
440
|
+
parsed.entry.tokenFile,
|
|
441
|
+
homeDir,
|
|
442
|
+
),
|
|
443
|
+
secret: parsed.token,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Read once for the value-preserving merge and to fail a stale editor BEFORE any
|
|
449
|
+
// token file is rewritten; the writer below re-checks while it replaces the document.
|
|
450
|
+
const current = readCodexSettingsDocument(filePath);
|
|
451
|
+
if (
|
|
452
|
+
current.document.modelProviders !== undefined
|
|
453
|
+
&& !isRecord(current.document.modelProviders)
|
|
454
|
+
) {
|
|
455
|
+
throw new AppError('`modelProviders` is not a JSON object; refusing to overwrite it.', {
|
|
456
|
+
code: 'CODEX_SETTINGS_INVALID_SHAPE',
|
|
457
|
+
statusCode: 500,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
if (current.version !== input.expectedVersion) {
|
|
461
|
+
throw new AppError('The Codex provider settings changed since they were read; reload and save again.', {
|
|
462
|
+
code: 'VERSION_CONFLICT',
|
|
463
|
+
statusCode: 409,
|
|
464
|
+
details: { expectedVersion: input.expectedVersion, currentVersion: current.version },
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
for (const { tokenFile, secret } of secrets.values()) {
|
|
469
|
+
writeCodexTokenSecret(tokenFile, secret);
|
|
470
|
+
}
|
|
471
|
+
writeCodexSettingsDocument(filePath, { ...current.document, modelProviders: byId }, {
|
|
472
|
+
expectedVersion: input.expectedVersion,
|
|
473
|
+
versionPath: filePath,
|
|
474
|
+
});
|
|
475
|
+
const reading = read();
|
|
476
|
+
// The unknown-field warning belongs to THIS write: the field is intentionally not
|
|
477
|
+
// persisted, so a re-read alone could not report it.
|
|
478
|
+
return {
|
|
479
|
+
...reading,
|
|
480
|
+
providers: reading.providers.map((provider) => {
|
|
481
|
+
const wrote = writeWarnings.get(provider.id);
|
|
482
|
+
return wrote === undefined
|
|
483
|
+
? provider
|
|
484
|
+
: { ...provider, warnings: [...new Set([...provider.warnings, ...wrote])] };
|
|
485
|
+
}),
|
|
486
|
+
};
|
|
487
|
+
});
|
|
488
|
+
},
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/** What one connection probe concluded about the endpoint behind a provider. */
|
|
493
|
+
export type CodexConnectionOutcome =
|
|
494
|
+
/** A Responses-shaped answer arrived; the endpoint is usable. */
|
|
495
|
+
| 'ok'
|
|
496
|
+
/** The host name could not be resolved (ENOTFOUND / EAI_AGAIN / EAI_NODATA). */
|
|
497
|
+
| 'dns'
|
|
498
|
+
/** The endpoint answered 401/403: reachable, credential or scope refused. */
|
|
499
|
+
| 'unauthorized'
|
|
500
|
+
/** The endpoint answered 404: baseUrl almost certainly lacks the right path. */
|
|
501
|
+
| 'not-found'
|
|
502
|
+
/** The URL answered, but not with a Responses-API body (wrong dialect/endpoint). */
|
|
503
|
+
| 'not-responses'
|
|
504
|
+
/** The endpoint answered 5xx: reachable but failing on its side. */
|
|
505
|
+
| 'server-error'
|
|
506
|
+
/** No HTTP answer at all (refused connection, timeout, TLS failure). */
|
|
507
|
+
| 'unreachable';
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* One probe reading.
|
|
511
|
+
*
|
|
512
|
+
* `billable` is always true and the note says why: the probe is a REAL
|
|
513
|
+
* `POST /responses` with one minimal turn, not a health check, so an upstream
|
|
514
|
+
* that bills per request may charge for it. The settings UI must show that
|
|
515
|
+
* sentence before the operator presses the button.
|
|
516
|
+
*/
|
|
517
|
+
export type CodexConnectionProbe = {
|
|
518
|
+
outcome: CodexConnectionOutcome;
|
|
519
|
+
ok: boolean;
|
|
520
|
+
url: string;
|
|
521
|
+
status?: number;
|
|
522
|
+
billable: true;
|
|
523
|
+
billingNote: string;
|
|
524
|
+
detail: string;
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
/** Seams a criterion owns: the request function, the environment and the deadline. */
|
|
528
|
+
export type CodexConnectionProbeOptions = {
|
|
529
|
+
fetchImpl?: typeof fetch;
|
|
530
|
+
env?: Record<string, string | undefined>;
|
|
531
|
+
timeoutMs?: number;
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
/** The one sentence every consumer must show next to a connection-test button. */
|
|
535
|
+
export const CODEX_CONNECTION_BILLING_NOTE =
|
|
536
|
+
'This connection test sends one real request to your upstream provider; the provider may bill it.';
|
|
537
|
+
|
|
538
|
+
const CODEX_CONNECTION_TIMEOUT_MS = 10_000;
|
|
539
|
+
|
|
540
|
+
/** The provider's Responses endpoint: `base_url` with `/responses` appended once. */
|
|
541
|
+
function codexResponsesUrl(
|
|
542
|
+
baseUrl: string,
|
|
543
|
+
queryParams: Record<string, string> | undefined,
|
|
544
|
+
): URL {
|
|
545
|
+
const url = new URL(baseUrl);
|
|
546
|
+
if (!/\/responses\/?$/.test(url.pathname)) {
|
|
547
|
+
url.pathname = `${url.pathname.replace(/\/+$/, '')}/responses`;
|
|
548
|
+
}
|
|
549
|
+
for (const [key, value] of Object.entries(queryParams ?? {})) {
|
|
550
|
+
url.searchParams.set(key, value);
|
|
551
|
+
}
|
|
552
|
+
return url;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** A Responses-API reply has an `object: "response"`, a `resp_` id, or an output list. */
|
|
556
|
+
function looksLikeResponsesReply(value: unknown): boolean {
|
|
557
|
+
if (!isRecord(value)) return false;
|
|
558
|
+
if (value.object === 'response') return true;
|
|
559
|
+
if (typeof value.id === 'string' && value.id.startsWith('resp_')) return true;
|
|
560
|
+
return Array.isArray(value.output);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function readErrorCode(failure: unknown): string | undefined {
|
|
564
|
+
const cause = isRecord(failure) ? failure.cause : undefined;
|
|
565
|
+
if (isRecord(cause) && typeof cause.code === 'string') return cause.code;
|
|
566
|
+
if (isRecord(failure) && typeof failure.code === 'string') return failure.code;
|
|
567
|
+
return undefined;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function failureName(failure: unknown): string | undefined {
|
|
571
|
+
return isRecord(failure) && typeof failure.name === 'string' ? failure.name : undefined;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/** The minimal request body: one input token-ish turn, never a stream. */
|
|
575
|
+
function connectionProbeBody(): string {
|
|
576
|
+
return JSON.stringify({
|
|
577
|
+
model: 'codex-connection-probe',
|
|
578
|
+
input: [{ role: 'user', content: [{ type: 'input_text', text: 'ping' }] }],
|
|
579
|
+
max_output_tokens: 1,
|
|
580
|
+
stream: false,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Probes one resolved provider's endpoint.
|
|
586
|
+
*
|
|
587
|
+
* WHY A REAL REQUEST. DNS, TLS, auth and the wire dialect are exactly the four
|
|
588
|
+
* things a configured-but-unusable provider gets wrong, and none of them can be
|
|
589
|
+
* read from configuration alone. The path is the same `/responses` a turn uses,
|
|
590
|
+
* so a 404 means the baseUrl is wrong and a Responses-shaped 2xx means the
|
|
591
|
+
* provider is usable; the outcome vocabulary keeps those apart from a DNS
|
|
592
|
+
* failure and from an endpoint that speaks a different dialect.
|
|
593
|
+
*
|
|
594
|
+
* The provider's own `httpHeaders`, `envHttpHeaders` (values read from the
|
|
595
|
+
* environment named per header) and `queryParams` are attached, so the probe
|
|
596
|
+
* exercises the same connection settings a real turn will use.
|
|
597
|
+
*
|
|
598
|
+
* Consumers: the Settings → Agents → Codex connection-test action and its
|
|
599
|
+
* criterion. Injected `fetchImpl`/`env` keep both off the host's network and
|
|
600
|
+
* environment.
|
|
601
|
+
*/
|
|
602
|
+
export async function probeCodexProviderConnection(
|
|
603
|
+
provider: ResolvedCodexModelProvider,
|
|
604
|
+
options: CodexConnectionProbeOptions = {},
|
|
605
|
+
): Promise<CodexConnectionProbe> {
|
|
606
|
+
const env = options.env ?? process.env;
|
|
607
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
608
|
+
const timeoutMs = options.timeoutMs ?? CODEX_CONNECTION_TIMEOUT_MS;
|
|
609
|
+
const url = codexResponsesUrl(provider.baseUrl, provider.queryParams);
|
|
610
|
+
|
|
611
|
+
const headers: Record<string, string> = {
|
|
612
|
+
'content-type': 'application/json',
|
|
613
|
+
accept: 'application/json',
|
|
614
|
+
authorization: `Bearer ${provider.secret}`,
|
|
615
|
+
...provider.httpHeaders,
|
|
616
|
+
};
|
|
617
|
+
for (const [header, variable] of Object.entries(provider.envHttpHeaders ?? {})) {
|
|
618
|
+
const value = env[variable];
|
|
619
|
+
if (typeof value === 'string' && value !== '') {
|
|
620
|
+
headers[header] = value;
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const base: Pick<CodexConnectionProbe, 'billable' | 'billingNote' | 'url'> = {
|
|
625
|
+
billable: true,
|
|
626
|
+
billingNote: CODEX_CONNECTION_BILLING_NOTE,
|
|
627
|
+
url: url.toString(),
|
|
628
|
+
};
|
|
629
|
+
|
|
630
|
+
let response: Awaited<ReturnType<typeof fetch>>;
|
|
631
|
+
try {
|
|
632
|
+
response = await fetchImpl(url.toString(), {
|
|
633
|
+
method: 'POST',
|
|
634
|
+
headers,
|
|
635
|
+
body: connectionProbeBody(),
|
|
636
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
637
|
+
});
|
|
638
|
+
} catch (failure) {
|
|
639
|
+
const code = readErrorCode(failure);
|
|
640
|
+
if (code === 'ENOTFOUND' || code === 'EAI_AGAIN' || code === 'EAI_NODATA') {
|
|
641
|
+
return {
|
|
642
|
+
...base,
|
|
643
|
+
outcome: 'dns',
|
|
644
|
+
ok: false,
|
|
645
|
+
detail: `could not resolve the host of ${provider.baseUrl} (${code})`,
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
const name = failureName(failure);
|
|
649
|
+
const timedOut = name === 'AbortError' || name === 'TimeoutError';
|
|
650
|
+
return {
|
|
651
|
+
...base,
|
|
652
|
+
outcome: 'unreachable',
|
|
653
|
+
ok: false,
|
|
654
|
+
detail: timedOut
|
|
655
|
+
? `no response within ${timeoutMs}ms`
|
|
656
|
+
: `request failed: ${errorMessage(failure)}`,
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
const text = await response.text().catch(() => '');
|
|
661
|
+
let parsed: unknown;
|
|
662
|
+
try {
|
|
663
|
+
parsed = text === '' ? undefined : JSON.parse(text);
|
|
664
|
+
} catch {
|
|
665
|
+
parsed = undefined;
|
|
666
|
+
}
|
|
667
|
+
const status = response.status;
|
|
668
|
+
if (status === 401 || status === 403) {
|
|
669
|
+
return {
|
|
670
|
+
...base,
|
|
671
|
+
outcome: 'unauthorized',
|
|
672
|
+
ok: false,
|
|
673
|
+
status,
|
|
674
|
+
detail: `the endpoint answered ${status}: the token-file secret or its scope was refused`,
|
|
675
|
+
};
|
|
676
|
+
}
|
|
677
|
+
if (status === 404) {
|
|
678
|
+
return {
|
|
679
|
+
...base,
|
|
680
|
+
outcome: 'not-found',
|
|
681
|
+
ok: false,
|
|
682
|
+
status,
|
|
683
|
+
detail: `the endpoint answered 404 at ${url.pathname}: check base_url and its path`,
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
if (status >= 500) {
|
|
687
|
+
return {
|
|
688
|
+
...base,
|
|
689
|
+
outcome: 'server-error',
|
|
690
|
+
ok: false,
|
|
691
|
+
status,
|
|
692
|
+
detail: `the endpoint answered ${status}`,
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
if (status >= 200 && status < 300) {
|
|
696
|
+
return looksLikeResponsesReply(parsed)
|
|
697
|
+
? { ...base, outcome: 'ok', ok: true, status, detail: 'Responses-shaped reply received' }
|
|
698
|
+
: {
|
|
699
|
+
...base,
|
|
700
|
+
outcome: 'not-responses',
|
|
701
|
+
ok: false,
|
|
702
|
+
status,
|
|
703
|
+
detail: 'the endpoint answered 2xx but not with a Responses-API body',
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
return {
|
|
707
|
+
...base,
|
|
708
|
+
outcome: 'not-responses',
|
|
709
|
+
ok: false,
|
|
710
|
+
status,
|
|
711
|
+
detail: `the endpoint answered ${status}, which is not a Responses-API reply`,
|
|
712
|
+
};
|
|
713
|
+
}
|