@prismshadow/penguin-server 0.2.11 → 0.2.15
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/types.d.ts +3650 -85
- package/dist/api/types.js +9 -0
- package/dist/auth-token.d.ts +22 -1
- package/dist/auth-token.js +7 -5
- package/dist/auth-token.js.map +1 -1
- package/dist/benchmark-package.d.ts +39 -0
- package/dist/benchmark-package.js +97 -0
- package/dist/benchmark-package.js.map +1 -0
- package/dist/chunk-54E64LWB.js +63 -0
- package/dist/chunk-54E64LWB.js.map +1 -0
- package/dist/{chunk-Q65VPAQS.js → chunk-5Z4UCHDB.js} +172 -108
- package/dist/chunk-5Z4UCHDB.js.map +1 -0
- package/dist/chunk-B5IP37ZQ.js +56 -0
- package/dist/chunk-HX3WBUYX.js +18 -0
- package/dist/chunk-HX3WBUYX.js.map +1 -0
- package/dist/chunk-JKJXQTHH.js +19 -0
- package/dist/chunk-JKJXQTHH.js.map +1 -0
- package/dist/chunk-LPPVGHYD.js +83 -0
- package/dist/chunk-LPPVGHYD.js.map +1 -0
- package/dist/chunk-NVWAYYRX.js +981 -0
- package/dist/chunk-NVWAYYRX.js.map +1 -0
- package/dist/chunk-Q4ON2L6E.js +52 -0
- package/dist/chunk-Q4ON2L6E.js.map +1 -0
- package/dist/chunk-QFV3ERQO.js +20 -0
- package/dist/chunk-QFV3ERQO.js.map +1 -0
- package/dist/{chunk-HOS3W3UP.js → chunk-TOOTEEM4.js} +50 -8
- package/dist/chunk-TOOTEEM4.js.map +1 -0
- package/dist/hmr/manifest.d.ts +1 -77
- package/dist/hmr/manifest.js +6 -1
- package/dist/index.js +86336 -22980
- package/dist/index.js.map +1 -1
- package/dist/initial-password.js +1 -0
- package/dist/install.ps1 +16 -6
- package/dist/install.sh +24 -10
- package/dist/lock.js +1 -0
- package/dist/machine-status.js +2 -1
- package/dist/machine-status.js.map +1 -1
- package/dist/plugin/index.d.ts +3384 -0
- package/dist/plugin/index.js.map +1 -0
- package/dist/reset-admin-password.js +8 -5
- package/dist/reset-admin-password.js.map +1 -1
- package/dist/secret-file.js +4 -13
- package/dist/secret-file.js.map +1 -1
- package/dist/version-report.d.ts +3 -0
- package/dist/version-report.js +3 -2
- package/package.json +19 -11
- package/web-dist/assets/KaTeX_Size3-Regular-gV2CO0n9.woff2 +0 -0
- package/web-dist/assets/abnfDiagram-VCTEODGH-CKWh4hoA.js +1 -0
- package/web-dist/assets/{addon-clipboard-1cARCaK9.js → addon-clipboard-DxLqat7q.js} +1 -1
- package/web-dist/assets/{addon-fit-BWdzl8Er.js → addon-fit-B8oPGPkW.js} +1 -1
- package/web-dist/assets/{addon-web-links-DjXuvn4Z.js → addon-web-links-C0W5TcK0.js} +1 -1
- package/web-dist/assets/arc-Dp9EkaAH.js +1 -0
- package/web-dist/assets/architectureDiagram-5GKGNRK7-BQ3LUcle.js +36 -0
- package/web-dist/assets/blockDiagram-I7D4REHJ-CZzyU0Jj.js +129 -0
- package/web-dist/assets/c-BG-tZi7o.js +1 -0
- package/web-dist/assets/c4Diagram-7LVT6UL2-Qps3jeAu.js +38 -0
- package/web-dist/assets/channel--PblgLlC.js +1 -0
- package/web-dist/assets/chunk-2Q5K7J3B-CQMntzuX.js +1 -0
- package/web-dist/assets/chunk-5VM5RSS4-2H2ZJAte.js +15 -0
- package/web-dist/assets/chunk-F27PBJKO-B30xCNBv.js +1 -0
- package/web-dist/assets/chunk-IMKFNOWR-Cyfx4zDs.js +231 -0
- package/web-dist/assets/chunk-JWPE2WC7-DADUytTh.js +1 -0
- package/web-dist/assets/chunk-POPQ4Y6H-9bjsAxLS.js +1 -0
- package/web-dist/assets/chunk-SVP7TREG-B9xO1VpN.js +88 -0
- package/web-dist/assets/chunk-TICWLB2K-B6oDkrep.js +206 -0
- package/web-dist/assets/chunk-XXDRQBXY-BbU8DR4B.js +1 -0
- package/web-dist/assets/classDiagram-ZZMXUADV-mn8tbuqa.js +1 -0
- package/web-dist/assets/classDiagram-v2-VYDZK3BY-mn8tbuqa.js +1 -0
- package/web-dist/assets/cose-bilkent-JH36ORCC-pkbuyec-.js +1 -0
- package/web-dist/assets/cpp-CaeG3uDQ.js +1 -0
- package/web-dist/assets/css-Br67jR8j.js +1 -0
- package/web-dist/assets/cynefin-OW5HDTMX-DU9YQQnc.js +166 -0
- package/web-dist/assets/cynefinDiagram-5FMLGOSQ-3a3XuhQq.js +62 -0
- package/web-dist/assets/cytoscape.esm-BB4DxJjf.js +321 -0
- package/web-dist/assets/dagre-GXQ25YYZ-BfZ9C5CZ.js +4 -0
- package/web-dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/web-dist/assets/diagram-S7CK7UJ4-BoGhVBMn.js +30 -0
- package/web-dist/assets/diagram-UQ7AKVKN-zE67quty.js +41 -0
- package/web-dist/assets/diagram-VSXAHHWV-NihoXeXm.js +3 -0
- package/web-dist/assets/diagram-VX7I27RA-1627np0S.js +24 -0
- package/web-dist/assets/diagram-Z3DM3KII-Ddg_bUan.js +24 -0
- package/web-dist/assets/diff-jW5kmiru.js +1 -0
- package/web-dist/assets/ebnfDiagram-PWID7BFC-CmPUOM4j.js +1 -0
- package/web-dist/assets/erDiagram-RLTQ6QDP-DiTnEK72.js +99 -0
- package/web-dist/assets/flowDiagram-HODETNUW-mGQ38tRM.js +168 -0
- package/web-dist/assets/ganttDiagram-EL5Y4UJY-DU7MlzpW.js +292 -0
- package/web-dist/assets/gitGraphDiagram-WWUBYQGX-CRE_3vjl.js +106 -0
- package/web-dist/assets/github-dark-BQV5ugrc.js +1 -0
- package/web-dist/assets/github-light-Rcb2q3L5.js +1 -0
- package/web-dist/assets/go-B7VTfpnm.js +1 -0
- package/web-dist/assets/highlighter-CzfXQ6yd.js +2 -0
- package/web-dist/assets/{highlighter-Cu43iYr8.js → highlighter-core-B5CvXcEK.js} +7 -7
- package/web-dist/assets/highlighter.worker-D6D9fPma.js +152 -0
- package/web-dist/assets/html-BW_6VhB7.js +1 -0
- package/web-dist/assets/ibm-plex-sans-condensed-latin-600-normal-CRd5VyFf.woff2 +0 -0
- package/web-dist/assets/ibm-plex-sans-condensed-latin-ext-600-normal-CBdNZ9Ci.woff2 +0 -0
- package/web-dist/assets/ibm-plex-sans-latin-ext-wght-normal-CIII54If.woff2 +0 -0
- package/web-dist/assets/ibm-plex-sans-latin-wght-normal-IvpUvPa2.woff2 +0 -0
- package/web-dist/assets/index-BdG4qRyI.js +1275 -0
- package/web-dist/assets/index-W-xYFoIm.css +1 -0
- package/web-dist/assets/infoDiagram-27XIBGKW-Cdo6Ar-a.js +2 -0
- package/web-dist/assets/ini-Dix3pTmg.js +1 -0
- package/web-dist/assets/init-Gi6I4Gst.js +1 -0
- package/web-dist/assets/ishikawaDiagram-5VMMS53U-C27pgect.js +70 -0
- package/web-dist/assets/java-BTDmaRNO.js +1 -0
- package/web-dist/assets/javascript-WyGyM1wV.js +1 -0
- package/web-dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/web-dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/web-dist/assets/journeyDiagram-3NMN7TZE-CVxtKpLG.js +139 -0
- package/web-dist/assets/json-B8JryHcM.js +1 -0
- package/web-dist/assets/jsx-8cLv2Six.js +1 -0
- package/web-dist/assets/kanban-definition-UXKFOSKX-DWA31Da7.js +89 -0
- package/web-dist/assets/layout-DWKCU9PO.js +1 -0
- package/web-dist/assets/linear-BwCthj_k.js +1 -0
- package/web-dist/assets/log-CcaF_xNv.js +1 -0
- package/web-dist/assets/markdown-DX-TNHnc.js +1 -0
- package/web-dist/assets/mermaid.core-BcTrmPOv.js +310 -0
- package/web-dist/assets/mindmap-definition-YA3MSWOX-BLEDhbn1.js +96 -0
- package/web-dist/assets/misans-400-100-DHkMCix2.woff2 +0 -0
- package/web-dist/assets/misans-400-101-CwgSLsmc.woff2 +0 -0
- package/web-dist/assets/misans-400-102-BQgefHPQ.woff2 +0 -0
- package/web-dist/assets/misans-400-103-CP58Mc_T.woff2 +0 -0
- package/web-dist/assets/misans-400-104-Ta_Xu1gd.woff2 +0 -0
- package/web-dist/assets/misans-400-105-CDop11AR.woff2 +0 -0
- package/web-dist/assets/misans-400-106-Dv8y0ubk.woff2 +0 -0
- package/web-dist/assets/misans-400-107-CjnHtp9E.woff2 +0 -0
- package/web-dist/assets/misans-400-108-BA8nQUBw.woff2 +0 -0
- package/web-dist/assets/misans-400-109-B6uEN0pG.woff2 +0 -0
- package/web-dist/assets/misans-400-110-BQqnShrY.woff2 +0 -0
- package/web-dist/assets/misans-400-111-CHB-Jj5X.woff2 +0 -0
- package/web-dist/assets/misans-400-112-D1dh4Cjx.woff2 +0 -0
- package/web-dist/assets/misans-400-113-Bw_wNCFp.woff2 +0 -0
- package/web-dist/assets/misans-400-114-CUb-5IzE.woff2 +0 -0
- package/web-dist/assets/misans-400-115-BICOatsO.woff2 +0 -0
- package/web-dist/assets/misans-400-116-B3_gmYW6.woff2 +0 -0
- package/web-dist/assets/misans-400-117-B8k_y3cv.woff2 +0 -0
- package/web-dist/assets/misans-400-118-C-2Cf5C6.woff2 +0 -0
- package/web-dist/assets/misans-400-119-CmLP7xnX.woff2 +0 -0
- package/web-dist/assets/misans-400-21-DsSSD_Zj.woff2 +0 -0
- package/web-dist/assets/misans-400-22-rtkxWOv4.woff2 +0 -0
- package/web-dist/assets/misans-400-23-CDDB4M1H.woff2 +0 -0
- package/web-dist/assets/misans-400-24-Dqf_XeOL.woff2 +0 -0
- package/web-dist/assets/misans-400-25-C4U1tJ5J.woff2 +0 -0
- package/web-dist/assets/misans-400-26-CEXOK-nT.woff2 +0 -0
- package/web-dist/assets/misans-400-27-BrNOAScF.woff2 +0 -0
- package/web-dist/assets/misans-400-28-CPpEnCkG.woff2 +0 -0
- package/web-dist/assets/misans-400-29-C9JMVw8g.woff2 +0 -0
- package/web-dist/assets/misans-400-30-CD-QimXa.woff2 +0 -0
- package/web-dist/assets/misans-400-31-S4k06NbS.woff2 +0 -0
- package/web-dist/assets/misans-400-32-zRMBDkz6.woff2 +0 -0
- package/web-dist/assets/misans-400-33-sQ_tNZSM.woff2 +0 -0
- package/web-dist/assets/misans-400-34-8LEGljja.woff2 +0 -0
- package/web-dist/assets/misans-400-35-CxSPyuiU.woff2 +0 -0
- package/web-dist/assets/misans-400-36-BY1i4WtO.woff2 +0 -0
- package/web-dist/assets/misans-400-37-C0oF42pu.woff2 +0 -0
- package/web-dist/assets/misans-400-38-y7xcB90w.woff2 +0 -0
- package/web-dist/assets/misans-400-39-C307YgZx.woff2 +0 -0
- package/web-dist/assets/misans-400-40-ByZr736f.woff2 +0 -0
- package/web-dist/assets/misans-400-41-ChKEw5zV.woff2 +0 -0
- package/web-dist/assets/misans-400-42-CD__zJu5.woff2 +0 -0
- package/web-dist/assets/misans-400-43-CqNV6_TG.woff2 +0 -0
- package/web-dist/assets/misans-400-44-zE-akmW8.woff2 +0 -0
- package/web-dist/assets/misans-400-45-Du98otwc.woff2 +0 -0
- package/web-dist/assets/misans-400-46-B6JXbEy2.woff2 +0 -0
- package/web-dist/assets/misans-400-47-DpqW0kSq.woff2 +0 -0
- package/web-dist/assets/misans-400-48-BprON5Q_.woff2 +0 -0
- package/web-dist/assets/misans-400-49-N-ct3sN6.woff2 +0 -0
- package/web-dist/assets/misans-400-5-ton_4jCN.woff2 +0 -0
- package/web-dist/assets/misans-400-50-JgU49P0U.woff2 +0 -0
- package/web-dist/assets/misans-400-51-DSS3Moge.woff2 +0 -0
- package/web-dist/assets/misans-400-52-BMoXFmwE.woff2 +0 -0
- package/web-dist/assets/misans-400-53-BaLMGl4z.woff2 +0 -0
- package/web-dist/assets/misans-400-54-CaeSn3OR.woff2 +0 -0
- package/web-dist/assets/misans-400-55-BBqrtLxN.woff2 +0 -0
- package/web-dist/assets/misans-400-56-DAZ5BnbO.woff2 +0 -0
- package/web-dist/assets/misans-400-57-F-n3b0gI.woff2 +0 -0
- package/web-dist/assets/misans-400-58-DEUuPQAq.woff2 +0 -0
- package/web-dist/assets/misans-400-59-DXP5rhCL.woff2 +0 -0
- package/web-dist/assets/misans-400-6-DWCCUO_c.woff2 +0 -0
- package/web-dist/assets/misans-400-60-BE6IO6zJ.woff2 +0 -0
- package/web-dist/assets/misans-400-61-5Qb1gaxK.woff2 +0 -0
- package/web-dist/assets/misans-400-62-D_tJKNAj.woff2 +0 -0
- package/web-dist/assets/misans-400-63-hwmne8yB.woff2 +0 -0
- package/web-dist/assets/misans-400-64-BGedxReM.woff2 +0 -0
- package/web-dist/assets/misans-400-65-BaKPsugb.woff2 +0 -0
- package/web-dist/assets/misans-400-66-IdaOMzCz.woff2 +0 -0
- package/web-dist/assets/misans-400-67-BdWyS83H.woff2 +0 -0
- package/web-dist/assets/misans-400-68-DrZ_1swq.woff2 +0 -0
- package/web-dist/assets/misans-400-69-B3jsSD92.woff2 +0 -0
- package/web-dist/assets/misans-400-70-D6UZI2Ua.woff2 +0 -0
- package/web-dist/assets/misans-400-71-HFxyMCYg.woff2 +0 -0
- package/web-dist/assets/misans-400-72-CP5A-yQP.woff2 +0 -0
- package/web-dist/assets/misans-400-73-BoD_bu6s.woff2 +0 -0
- package/web-dist/assets/misans-400-74-CbJlhZlZ.woff2 +0 -0
- package/web-dist/assets/misans-400-75-BsbWuELX.woff2 +0 -0
- package/web-dist/assets/misans-400-76-DkwiQhof.woff2 +0 -0
- package/web-dist/assets/misans-400-77-6pVHXHnF.woff2 +0 -0
- package/web-dist/assets/misans-400-78-CfUF6pih.woff2 +0 -0
- package/web-dist/assets/misans-400-79-BCS3Dx4e.woff2 +0 -0
- package/web-dist/assets/misans-400-80-BEYSdQ_N.woff2 +0 -0
- package/web-dist/assets/misans-400-81-BzL-Gncx.woff2 +0 -0
- package/web-dist/assets/misans-400-82-CaENmdUU.woff2 +0 -0
- package/web-dist/assets/misans-400-83-Bvq1eBcA.woff2 +0 -0
- package/web-dist/assets/misans-400-84-Ctd90hiP.woff2 +0 -0
- package/web-dist/assets/misans-400-85-DWuOxfL1.woff2 +0 -0
- package/web-dist/assets/misans-400-86-D5niZS5c.woff2 +0 -0
- package/web-dist/assets/misans-400-87-DkOIADQJ.woff2 +0 -0
- package/web-dist/assets/misans-400-88-CGY4WTcC.woff2 +0 -0
- package/web-dist/assets/misans-400-89-CA3eoMTt.woff2 +0 -0
- package/web-dist/assets/misans-400-90-CzxR9MYb.woff2 +0 -0
- package/web-dist/assets/misans-400-91-Dyr85txc.woff2 +0 -0
- package/web-dist/assets/misans-400-97-qEZrCUNe.woff2 +0 -0
- package/web-dist/assets/misans-400-cyrillic--hFcG0Xp.woff2 +0 -0
- package/web-dist/assets/misans-400-extra-ZRI9n2Hu.woff2 +0 -0
- package/web-dist/assets/misans-400-latin-BRDR1WaL.woff2 +0 -0
- package/web-dist/assets/misans-400-latin-ext-6xS-MvHW.woff2 +0 -0
- package/web-dist/assets/misans-400-vietnamese-D7xD7kBB.woff2 +0 -0
- package/web-dist/assets/misans-500-100-BHuGA96E.woff2 +0 -0
- package/web-dist/assets/misans-500-101-CDMYUz0c.woff2 +0 -0
- package/web-dist/assets/misans-500-102-CWcqYYCV.woff2 +0 -0
- package/web-dist/assets/misans-500-103-BE1QSEzY.woff2 +0 -0
- package/web-dist/assets/misans-500-104-CDp743BV.woff2 +0 -0
- package/web-dist/assets/misans-500-105-y7dY6Foi.woff2 +0 -0
- package/web-dist/assets/misans-500-106-CP-kGZ6j.woff2 +0 -0
- package/web-dist/assets/misans-500-107-CUc8Hvle.woff2 +0 -0
- package/web-dist/assets/misans-500-108-ItN_x8jX.woff2 +0 -0
- package/web-dist/assets/misans-500-109-CEtf3R4D.woff2 +0 -0
- package/web-dist/assets/misans-500-110-BSZSHYRL.woff2 +0 -0
- package/web-dist/assets/misans-500-111-DfdArrjn.woff2 +0 -0
- package/web-dist/assets/misans-500-112-DRtNyrQw.woff2 +0 -0
- package/web-dist/assets/misans-500-113-CDT7tKuB.woff2 +0 -0
- package/web-dist/assets/misans-500-114-CCh4jwL8.woff2 +0 -0
- package/web-dist/assets/misans-500-115-DplUgPp0.woff2 +0 -0
- package/web-dist/assets/misans-500-116-C7eCklyK.woff2 +0 -0
- package/web-dist/assets/misans-500-117-BA0KabyT.woff2 +0 -0
- package/web-dist/assets/misans-500-118-V_M0eu2q.woff2 +0 -0
- package/web-dist/assets/misans-500-119-Cgf3Hszt.woff2 +0 -0
- package/web-dist/assets/misans-500-21-Di6DyR6O.woff2 +0 -0
- package/web-dist/assets/misans-500-22-CSnXvtL-.woff2 +0 -0
- package/web-dist/assets/misans-500-23-A06Hm9a6.woff2 +0 -0
- package/web-dist/assets/misans-500-24-Df97RCik.woff2 +0 -0
- package/web-dist/assets/misans-500-25-bOSJ6YXH.woff2 +0 -0
- package/web-dist/assets/misans-500-26-C65icgBb.woff2 +0 -0
- package/web-dist/assets/misans-500-27-C_GRm0va.woff2 +0 -0
- package/web-dist/assets/misans-500-28-CzZkqO0l.woff2 +0 -0
- package/web-dist/assets/misans-500-29-BReyeRyX.woff2 +0 -0
- package/web-dist/assets/misans-500-30-DzfjlROz.woff2 +0 -0
- package/web-dist/assets/misans-500-31-B2nLpgdU.woff2 +0 -0
- package/web-dist/assets/misans-500-32-Bz3rHm8X.woff2 +0 -0
- package/web-dist/assets/misans-500-33-AU3lZ1vY.woff2 +0 -0
- package/web-dist/assets/misans-500-34-CBAWkH-I.woff2 +0 -0
- package/web-dist/assets/misans-500-35-VgnGd14P.woff2 +0 -0
- package/web-dist/assets/misans-500-36-B2kfXv6A.woff2 +0 -0
- package/web-dist/assets/misans-500-37-DhKo8ykb.woff2 +0 -0
- package/web-dist/assets/misans-500-38-D8tTxFuc.woff2 +0 -0
- package/web-dist/assets/misans-500-39-DTm3aqJQ.woff2 +0 -0
- package/web-dist/assets/misans-500-40-C_akwj8_.woff2 +0 -0
- package/web-dist/assets/misans-500-41-RVM1JHQW.woff2 +0 -0
- package/web-dist/assets/misans-500-42-MVWIN_il.woff2 +0 -0
- package/web-dist/assets/misans-500-43-BtLZYNyD.woff2 +0 -0
- package/web-dist/assets/misans-500-44-D0QHMl6G.woff2 +0 -0
- package/web-dist/assets/misans-500-45-DRlclX7-.woff2 +0 -0
- package/web-dist/assets/misans-500-46-BEWswL4N.woff2 +0 -0
- package/web-dist/assets/misans-500-47-COSoxWaW.woff2 +0 -0
- package/web-dist/assets/misans-500-48-DZAISq3n.woff2 +0 -0
- package/web-dist/assets/misans-500-49-KSfi7MW0.woff2 +0 -0
- package/web-dist/assets/misans-500-5-h1SBcwuW.woff2 +0 -0
- package/web-dist/assets/misans-500-50-CIVMfG11.woff2 +0 -0
- package/web-dist/assets/misans-500-51-BdeNBhBL.woff2 +0 -0
- package/web-dist/assets/misans-500-52-CEW4e7ex.woff2 +0 -0
- package/web-dist/assets/misans-500-53-lmPCsEnt.woff2 +0 -0
- package/web-dist/assets/misans-500-54-B_7AqKQW.woff2 +0 -0
- package/web-dist/assets/misans-500-55-B-3RtUnH.woff2 +0 -0
- package/web-dist/assets/misans-500-56-g6D0e0cW.woff2 +0 -0
- package/web-dist/assets/misans-500-57-D5hp5Yqr.woff2 +0 -0
- package/web-dist/assets/misans-500-58-ilnDgEKt.woff2 +0 -0
- package/web-dist/assets/misans-500-59-DJYXz8tr.woff2 +0 -0
- package/web-dist/assets/misans-500-6-uCdpdDQy.woff2 +0 -0
- package/web-dist/assets/misans-500-60-B3Iaqx0p.woff2 +0 -0
- package/web-dist/assets/misans-500-61-CMxqg5hc.woff2 +0 -0
- package/web-dist/assets/misans-500-62-7FY8O2NQ.woff2 +0 -0
- package/web-dist/assets/misans-500-63-JP6vEuJf.woff2 +0 -0
- package/web-dist/assets/misans-500-64-Cdub62jh.woff2 +0 -0
- package/web-dist/assets/misans-500-65-DVHk_mlC.woff2 +0 -0
- package/web-dist/assets/misans-500-66-BX39wRtF.woff2 +0 -0
- package/web-dist/assets/misans-500-67-BcsepI3X.woff2 +0 -0
- package/web-dist/assets/misans-500-68-etUIUjrh.woff2 +0 -0
- package/web-dist/assets/misans-500-69-DfhVmnuA.woff2 +0 -0
- package/web-dist/assets/misans-500-70-D6dgy6-B.woff2 +0 -0
- package/web-dist/assets/misans-500-71-PkeKjcVn.woff2 +0 -0
- package/web-dist/assets/misans-500-72-D66Fnb30.woff2 +0 -0
- package/web-dist/assets/misans-500-73-jr9z9870.woff2 +0 -0
- package/web-dist/assets/misans-500-74-DsCkPKwe.woff2 +0 -0
- package/web-dist/assets/misans-500-75-Dkooq6KM.woff2 +0 -0
- package/web-dist/assets/misans-500-76-B0sfieHl.woff2 +0 -0
- package/web-dist/assets/misans-500-77-8tflq1ji.woff2 +0 -0
- package/web-dist/assets/misans-500-78-COKdMbdp.woff2 +0 -0
- package/web-dist/assets/misans-500-79-Bm0rBjSF.woff2 +0 -0
- package/web-dist/assets/misans-500-80-B9OoAnyy.woff2 +0 -0
- package/web-dist/assets/misans-500-81-DsQ9tpfX.woff2 +0 -0
- package/web-dist/assets/misans-500-82-VKsL2Tk2.woff2 +0 -0
- package/web-dist/assets/misans-500-83-Ce6mfHYD.woff2 +0 -0
- package/web-dist/assets/misans-500-84-D7kPSZLm.woff2 +0 -0
- package/web-dist/assets/misans-500-85-W5L0cEfd.woff2 +0 -0
- package/web-dist/assets/misans-500-86-DukGOEET.woff2 +0 -0
- package/web-dist/assets/misans-500-87-BJ_Lok6j.woff2 +0 -0
- package/web-dist/assets/misans-500-88-DbJ11zcA.woff2 +0 -0
- package/web-dist/assets/misans-500-89-LNKcEq6M.woff2 +0 -0
- package/web-dist/assets/misans-500-90-DNDDgSCd.woff2 +0 -0
- package/web-dist/assets/misans-500-91-rT8Q0evu.woff2 +0 -0
- package/web-dist/assets/misans-500-97-c8zW_WRq.woff2 +0 -0
- package/web-dist/assets/misans-500-cyrillic-CLHOGwgx.woff2 +0 -0
- package/web-dist/assets/misans-500-extra-CTAMEQ59.woff2 +0 -0
- package/web-dist/assets/misans-500-latin-Be606ott.woff2 +0 -0
- package/web-dist/assets/misans-500-latin-ext-BzDyL4sU.woff2 +0 -0
- package/web-dist/assets/misans-500-vietnamese-DBOLOqZH.woff2 +0 -0
- package/web-dist/assets/mona-sans-latin-ext-wght-normal-BqSk0Z3x.woff2 +0 -0
- package/web-dist/assets/mona-sans-latin-wght-normal-Pz49MTQZ.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-100-wght-normal-DrqXJETY.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-101-wght-normal-c94LAl5p.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-102-wght-normal-C1RtbCZr.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-103-wght-normal-DGHo20nu.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-104-wght-normal-CJT2ioDJ.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-105-wght-normal-BFoiJwz2.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-106-wght-normal-D6uUHw3w.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-107-wght-normal-kFQzJDLH.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-108-wght-normal-7aXvqIa2.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-109-wght-normal-CnjNbNmw.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-110-wght-normal-D2JBr045.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-111-wght-normal-ClFr5QXM.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-112-wght-normal-CiZxJMyY.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-113-wght-normal-OgQXOX6x.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-114-wght-normal-CRH9SDZu.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-115-wght-normal-BN__2iBG.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-116-wght-normal-vdFVzbO2.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-117-wght-normal-Dsz3vkzU.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-118-wght-normal-BPEb0gM9.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-119-wght-normal-BfzSEbFz.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-21-wght-normal-DIu_1ZBI.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-22-wght-normal-VXjdYcT-.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-23-wght-normal-4HrHKhpL.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-24-wght-normal-B58DWgHS.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-25-wght-normal-C3Jm6l7O.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-26-wght-normal-YNOygvr_.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-27-wght-normal-BP2pEGQH.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-28-wght-normal-BWPKDbtH.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-29-wght-normal-45aVmHn_.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-30-wght-normal-B8_s30jZ.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-31-wght-normal-DW0t445S.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-32-wght-normal-ShbWPcei.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-33-wght-normal-BOTZYTjM.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-34-wght-normal-BF1rqDSt.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-35-wght-normal-Bosspiyr.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-36-wght-normal-CtU9CyKw.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-37-wght-normal-ghDiyiuv.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-38-wght-normal-4Nz8k_dt.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-39-wght-normal-Ddtm1XVC.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-4-wght-normal-BRbPMj-C.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-40-wght-normal-BVn4-kgX.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-41-wght-normal-CZqajZnl.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-42-wght-normal-CQ4lY28u.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-43-wght-normal-psppu0d8.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-44-wght-normal-cbKJlTUe.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-45-wght-normal-MKIEVRIC.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-46-wght-normal-CErGc6Mt.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-47-wght-normal-C5Kgg1_m.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-48-wght-normal-DFMjDDY6.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-49-wght-normal-B7l_3BZr.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-5-wght-normal-DI846rD9.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-50-wght-normal-C5KfAmFp.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-51-wght-normal-C2bq6hC8.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-52-wght-normal-P18e_Y0j.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-53-wght-normal-Bgkuo2tF.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-54-wght-normal-DL5lmlUd.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-55-wght-normal-BV_Oy6IF.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-56-wght-normal-B4L7Hj8f.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-57-wght-normal-DU8YBsDj.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-58-wght-normal-CE0BKS9u.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-59-wght-normal-Azv2Ku9_.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-6-wght-normal-ozUCEY9O.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-60-wght-normal-C1lngC61.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-61-wght-normal-BxWkGF5M.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-62-wght-normal-CXXMAq-5.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-63-wght-normal-4La5uKvS.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-64-wght-normal-CbIuD2Eg.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-65-wght-normal-BGqvKda2.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-66-wght-normal-BvNozWOY.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-67-wght-normal-CC-WRBV-.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-68-wght-normal-c0FjfUaj.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-69-wght-normal-D596Jjl2.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-70-wght-normal-ColEcmtJ.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-71-wght-normal-ChZfXpdg.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-72-wght-normal-D1VyfEG3.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-73-wght-normal-DwSJRYPJ.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-74-wght-normal-Cte7o1QG.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-75-wght-normal-B0qL41rF.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-76-wght-normal-BPLMO_2x.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-77-wght-normal-Dkbi3pye.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-78-wght-normal-BFUXeSw6.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-79-wght-normal-DoJG4UTB.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-80-wght-normal-BEFypWOO.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-81-wght-normal-ed_TZlfo.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-82-wght-normal-DcxfR5OJ.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-83-wght-normal-C9UjAcMM.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-84-wght-normal-C7NxT478.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-85-wght-normal-DBcDBu1n.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-86-wght-normal-CLJIoPpl.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-87-wght-normal-DYfJ-vGE.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-88-wght-normal-ClNDOCGW.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-89-wght-normal-IQU_KQA8.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-90-wght-normal-BWcrRNoG.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-91-wght-normal-CGekvDdH.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-97-wght-normal-BsBHkXi3.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-98-wght-normal-BZqSA1r_.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-99-wght-normal-Q_IptJM5.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-cyrillic-wght-normal-CRA5_Pf1.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-latin-ext-wght-normal-CqPqLCfe.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-latin-wght-normal-DYAKOyvl.woff2 +0 -0
- package/web-dist/assets/noto-sans-sc-vietnamese-wght-normal-y5SU35Rl.woff2 +0 -0
- package/web-dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/web-dist/assets/pegDiagram-XKGWAZYB-CLEM1SDU.js +1 -0
- package/web-dist/assets/php-CNeTOyEV.js +1 -0
- package/web-dist/assets/pieDiagram-E7YTZNPT-B__g6eF0.js +39 -0
- package/web-dist/assets/python-B6Ihcp-E.js +1 -0
- package/web-dist/assets/quadrantDiagram-AXDQQJYC-C7VQ2LMY.js +7 -0
- package/web-dist/assets/railroadDiagram-O6MQD6OU-eWNnzjwS.js +1 -0
- package/web-dist/assets/requirementDiagram-BXWQKSXE-Bi5qeD4b.js +84 -0
- package/web-dist/assets/ruby-CYiNE6ps.js +1 -0
- package/web-dist/assets/rust-CxuBE0J8.js +1 -0
- package/web-dist/assets/sankeyDiagram-P5KCCOFB-DG1VOpXX.js +40 -0
- package/web-dist/assets/sequenceDiagram-WJ2MYXX4-Fhkw73Th.js +162 -0
- package/web-dist/assets/shellscript-DgJyDXW6.js +1 -0
- package/web-dist/assets/sizeCapture-INFHLROL-D9E_17SF.js +1 -0
- package/web-dist/assets/sql-Dq2MiB0T.js +1 -0
- package/web-dist/assets/stateDiagram-D77RDMKH-Cs5Y0xhW.js +1 -0
- package/web-dist/assets/stateDiagram-v2-MP3YSRHH-CEM51fAf.js +1 -0
- package/web-dist/assets/swimlanes-42K2YHIH-t-EocvKZ.js +1 -0
- package/web-dist/assets/swimlanesDiagram-VR7AAH4N-BrR66vrK.js +8 -0
- package/web-dist/assets/timeline-definition-24CTP7MA-CozGCxuA.js +120 -0
- package/web-dist/assets/toml-Ms459DBw.js +1 -0
- package/web-dist/assets/tsx-D6116Ycy.js +1 -0
- package/web-dist/assets/typescript-BqvgUolh.js +1 -0
- package/web-dist/assets/vennDiagram-4TSXK5OY-ewU8ycSa.js +34 -0
- package/web-dist/assets/wardleyDiagram-VM6X3IG4-DuAhDu-0.js +78 -0
- package/web-dist/assets/xml-BkAJuBCc.js +1 -0
- package/web-dist/assets/{xterm-DKcY6q-I.js → xterm-v5e56GC9.js} +1 -1
- package/web-dist/assets/xychartDiagram-S5SC5T6Z-BxGuZO23.js +7 -0
- package/web-dist/assets/yaml-Bopit2L3.js +1 -0
- package/web-dist/fonts-licenses/ibm-plex-sans-condensed.txt +93 -0
- package/web-dist/fonts-licenses/ibm-plex-sans.txt +93 -0
- package/web-dist/fonts-licenses/jetbrains-mono.txt +93 -0
- package/web-dist/fonts-licenses/misans.txt +119 -0
- package/web-dist/fonts-licenses/mona-sans.txt +93 -0
- package/web-dist/fonts-licenses/noto-sans-sc.txt +93 -0
- package/web-dist/index.html +18 -4
- package/web-dist/workflow-ui.css +261 -0
- package/dist/chunk-4SXGU7RO.js +0 -50
- package/dist/chunk-4SXGU7RO.js.map +0 -1
- package/dist/chunk-ADZJYDNC.js +0 -421
- package/dist/chunk-ADZJYDNC.js.map +0 -1
- package/dist/chunk-HOS3W3UP.js.map +0 -1
- package/dist/chunk-Q65VPAQS.js.map +0 -1
- package/dist/chunk-TTGGJDNA.js +0 -14
- package/dist/chunk-TTGGJDNA.js.map +0 -1
- package/dist/extension/index.d.ts +0 -212
- package/web-dist/assets/index-Bm9n7ZV-.js +0 -457
- package/web-dist/assets/index-DR4PrRzS.css +0 -1
- /package/dist/{extension/index.js.map → chunk-B5IP37ZQ.js.map} +0 -0
- /package/dist/{extension → plugin}/index.js +0 -0
package/dist/api/types.d.ts
CHANGED
|
@@ -1,6 +1,96 @@
|
|
|
1
|
-
import { OmniMessage, ToolCallPayload, CompactionMode } from '@prismshadow/penguin-core/omnimessage';
|
|
1
|
+
import { SessionSource, OmniMessage, ToolCallPayload, CompactionMode } from '@prismshadow/penguin-core/omnimessage';
|
|
2
|
+
export { SessionSource } from '@prismshadow/penguin-core/omnimessage';
|
|
2
3
|
import { ThinkingLevelName, ToolDefinitionConfig, MCPServerConfig } from '@prismshadow/penguin-core/interfaces';
|
|
3
|
-
import { VersionReport } from '@prismshadow/penguin-core';
|
|
4
|
+
import { HarnessHistory, VersionReport } from '@prismshadow/penguin-core';
|
|
5
|
+
export { HarnessHistoryEntry, IfacesSummary } from '@prismshadow/penguin-core';
|
|
6
|
+
import { IfacesDiff } from '@prismshadow/penguin-hmr';
|
|
7
|
+
export { IfaceChange, IfacesDiff, MemberChange, ModuleChange } from '@prismshadow/penguin-hmr';
|
|
8
|
+
|
|
9
|
+
/** A request the workflow's handler receives (the HTTP shape, minus the transport). */
|
|
10
|
+
interface WorkflowRequest {
|
|
11
|
+
method: string;
|
|
12
|
+
/** Path below the workflow's `api/` mount, always starting with `/`. */
|
|
13
|
+
path: string;
|
|
14
|
+
query: Record<string, string>;
|
|
15
|
+
/** Request headers, names lower-cased. The app's own credentials (`cookie`, `authorization`) are withheld. */
|
|
16
|
+
headers: Record<string, string>;
|
|
17
|
+
/** The parsed body of a JSON request; `null` otherwise (GET/HEAD, no body, another content type). */
|
|
18
|
+
body: unknown;
|
|
19
|
+
/** The body as sent, when there is one and it is not JSON: a form, an upload, plain text. */
|
|
20
|
+
bytes?: Uint8Array;
|
|
21
|
+
}
|
|
22
|
+
interface WorkflowResponse {
|
|
23
|
+
/** HTTP status; 200 when absent. */
|
|
24
|
+
status?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Response headers. Naming a `content-type` is what makes the response something other than
|
|
27
|
+
* JSON; `location` with a 3xx status redirects. `set-cookie` is dropped — a workflow does not
|
|
28
|
+
* write the app's cookies.
|
|
29
|
+
*/
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
/** JSON by default (`null` when absent); with a `content-type` header, a string sent as written. */
|
|
32
|
+
body?: unknown;
|
|
33
|
+
/** A binary body (an image, a font, a download); wins over `body`. */
|
|
34
|
+
bytes?: Uint8Array;
|
|
35
|
+
/**
|
|
36
|
+
* A body sent as it is produced — server-sent events, a model's answer token by token, a
|
|
37
|
+
* large download — each chunk written to the client when the iterator yields it; wins over
|
|
38
|
+
* `bytes` and `body`. A client that goes away ends the iteration: `return()` is called, so
|
|
39
|
+
* a `finally` in the generator is where an upstream request is aborted — but a generator
|
|
40
|
+
* suspended inside an `await` receives it only once that await settles, so a relay whose
|
|
41
|
+
* upstream can hang should carry its own deadline rather than rely on the disconnect.
|
|
42
|
+
*/
|
|
43
|
+
stream?: AsyncIterable<Uint8Array | string>;
|
|
44
|
+
}
|
|
45
|
+
/** How the Web App draws a contributed tab: a page of the workflow, or a renderer it carries. */
|
|
46
|
+
type WorkflowTabRenderer = {
|
|
47
|
+
iframe: {
|
|
48
|
+
src: string;
|
|
49
|
+
};
|
|
50
|
+
} | {
|
|
51
|
+
builtin: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* One tab beside Chat, as the workflow contributed it (`WebModule.sessionTabs`). In a
|
|
55
|
+
* manifest `renderer.iframe.src` is a path inside the workflow folder, under `ui/`; in a
|
|
56
|
+
* `WorkflowInfo` it is the URL that file is served from.
|
|
57
|
+
*/
|
|
58
|
+
interface WorkflowTab {
|
|
59
|
+
id: string;
|
|
60
|
+
/** Unique within the workflow; the tab's stable name (it appears in the full-page URL). */
|
|
61
|
+
key: string;
|
|
62
|
+
title: string;
|
|
63
|
+
titleZh?: string;
|
|
64
|
+
renderer: WorkflowTabRenderer;
|
|
65
|
+
}
|
|
66
|
+
interface WorkflowInfo {
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
version: string | null;
|
|
70
|
+
/** Content revision of the whole folder (what history records). */
|
|
71
|
+
revision: string;
|
|
72
|
+
/** Content revision of `ui/`: the cache key of the workflow's pages. Null when it has no `ui/`. */
|
|
73
|
+
uiRev: string | null;
|
|
74
|
+
/** The tabs of the instance that is SERVING — the previous one's while `error` is set. */
|
|
75
|
+
tabs: WorkflowTab[];
|
|
76
|
+
loadedAt: string;
|
|
77
|
+
/** The boot error when the current files do not load (the previous instance, if any, keeps serving). */
|
|
78
|
+
error: string | null;
|
|
79
|
+
/**
|
|
80
|
+
* What loaded but is probably not what its author meant, each with the edit that settles it
|
|
81
|
+
* — pages under `ui/` that no tab shows, say. Never a failure: `error` is that.
|
|
82
|
+
*/
|
|
83
|
+
hints: string[];
|
|
84
|
+
}
|
|
85
|
+
interface WorkflowVersion {
|
|
86
|
+
revision: string;
|
|
87
|
+
savedAt: string;
|
|
88
|
+
name: string;
|
|
89
|
+
version: string | null;
|
|
90
|
+
uiRev: string | null;
|
|
91
|
+
/** The files of that version (relative paths), for display. */
|
|
92
|
+
files: string[];
|
|
93
|
+
}
|
|
4
94
|
|
|
5
95
|
/**
|
|
6
96
|
* Web API DTO contract — request/response types shared between server routes and the
|
|
@@ -18,19 +108,26 @@ import { VersionReport } from '@prismshadow/penguin-core';
|
|
|
18
108
|
* public route/SSE reference for this contract — keep it in sync when changing DTOs.
|
|
19
109
|
*/
|
|
20
110
|
|
|
21
|
-
/**
|
|
111
|
+
/**
|
|
112
|
+
* Unified error response body: `code` is a machine-readable error code, `message` an English
|
|
113
|
+
* user-facing message, and `details`, on the errors that have them, the facts a client acts on
|
|
114
|
+
* beside the code (the Benchmark id a 409 `benchmark_exists` is about, say) — read from there,
|
|
115
|
+
* never parsed out of the message.
|
|
116
|
+
*/
|
|
22
117
|
interface ErrorBody {
|
|
23
118
|
error: {
|
|
24
119
|
code: string;
|
|
25
120
|
message: string;
|
|
121
|
+
details?: ErrorDetails;
|
|
26
122
|
};
|
|
27
123
|
}
|
|
124
|
+
/** An error's structured facts, by name; each code that carries them documents its own. */
|
|
125
|
+
type ErrorDetails = Readonly<Record<string, string>>;
|
|
28
126
|
/** Session approval mode (reuses the CLI enum). */
|
|
29
127
|
type ApprovalMode = "allow-all" | "deny-all" | "read-only" | "always-ask";
|
|
30
128
|
/** Session run status: idle / Task in progress / compacting. */
|
|
31
129
|
type SessionStatus = "idle" | "running" | "compacting";
|
|
32
|
-
|
|
33
|
-
type SessionSource = "schedule" | "subagent";
|
|
130
|
+
|
|
34
131
|
interface UserInfo {
|
|
35
132
|
/** Semantic id, i.e. login name: `^[a-z][a-z0-9_-]{1,31}$`, immutable after creation. */
|
|
36
133
|
userId: string;
|
|
@@ -38,8 +135,31 @@ interface UserInfo {
|
|
|
38
135
|
isAdmin: boolean;
|
|
39
136
|
/** Still using the initial password (seeded/set by admin): frontend prompts the user to change it soon. */
|
|
40
137
|
passwordIsInitial: boolean;
|
|
138
|
+
/**
|
|
139
|
+
* Nickname the account chose (1-32 characters), shown wherever the id would otherwise be.
|
|
140
|
+
* Omitted when unset — every account that predates the Profile page starts without one, and
|
|
141
|
+
* a surface with no value falls back to `userId`.
|
|
142
|
+
*/
|
|
143
|
+
displayName?: string;
|
|
144
|
+
/**
|
|
145
|
+
* Avatar as a `data:image/...;base64,` URL, at most 131072 characters. Omitted when unset,
|
|
146
|
+
* and a surface with no value draws the letter placeholder instead.
|
|
147
|
+
*/
|
|
148
|
+
avatar?: string;
|
|
41
149
|
createdAt: string;
|
|
42
150
|
}
|
|
151
|
+
/**
|
|
152
|
+
* PUT /api/me/profile — a patch, not a replacement: an absent field keeps what is stored,
|
|
153
|
+
* `null` clears it, a string sets it. A body naming neither field is a 400, since it can only
|
|
154
|
+
* be a mistake.
|
|
155
|
+
*/
|
|
156
|
+
interface UpdateProfileRequest {
|
|
157
|
+
displayName?: string | null;
|
|
158
|
+
avatar?: string | null;
|
|
159
|
+
}
|
|
160
|
+
interface UpdateProfileResponse {
|
|
161
|
+
user: UserInfo;
|
|
162
|
+
}
|
|
43
163
|
interface AuthLoginRequest {
|
|
44
164
|
userId: string;
|
|
45
165
|
password: string;
|
|
@@ -95,6 +215,12 @@ interface MeResponse {
|
|
|
95
215
|
* just an admin's.
|
|
96
216
|
*/
|
|
97
217
|
uploadLimits: UploadLimits;
|
|
218
|
+
/**
|
|
219
|
+
* Whether company mode is enabled server-wide (the admin switch in server settings, default
|
|
220
|
+
* on). Off hides the mode switch in every client and 404s every organization route; the
|
|
221
|
+
* user's own preference (`UiPrefs.companyMode`) only hides the switch for that user.
|
|
222
|
+
*/
|
|
223
|
+
companyMode: boolean;
|
|
98
224
|
}
|
|
99
225
|
/**
|
|
100
226
|
* Upload limits as the web app sees them: whole MB, the same unit the admin form uses, so the
|
|
@@ -184,6 +310,26 @@ interface ServerSettings {
|
|
|
184
310
|
* image and the JSON framing), which is why raising it needs no separate setting.
|
|
185
311
|
*/
|
|
186
312
|
attachmentTotalMb: number;
|
|
313
|
+
/**
|
|
314
|
+
* Company mode master switch (default on). Off stops the organization scheduler (no
|
|
315
|
+
* calendar event or chat mention fires, nothing is backfilled when it is turned on again),
|
|
316
|
+
* every `/api/projects/:projectId/organizations` route answers 404, and `GET /api/me`
|
|
317
|
+
* reports it so clients hide the mode switch. Organizations on disk are untouched.
|
|
318
|
+
*/
|
|
319
|
+
companyMode: boolean;
|
|
320
|
+
/**
|
|
321
|
+
* Whether users may drive their own Chrome through the PenguinHarness Browser extension
|
|
322
|
+
* (default on). Off closes every connected extension (close code 4009), refuses new
|
|
323
|
+
* connections, and makes the chrome backend unavailable (`extension_disabled`); pairings are
|
|
324
|
+
* kept, so turning it on again lets the extensions reconnect.
|
|
325
|
+
*/
|
|
326
|
+
browserExtensionsEnabled: boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Whether external programs may talk to Agents through the Agent API (default on). Off answers
|
|
329
|
+
* every `/api/amsp/v1` request 403 `agent_api_disabled` (a CORS preflight excepted); every
|
|
330
|
+
* Agent's API switch, approval mode and keys are kept, so turning it on again restores them.
|
|
331
|
+
*/
|
|
332
|
+
agentApiEnabled: boolean;
|
|
187
333
|
}
|
|
188
334
|
interface ServerSettingsResponse {
|
|
189
335
|
settings: ServerSettings;
|
|
@@ -192,6 +338,12 @@ interface ServerSettingsResponse {
|
|
|
192
338
|
interface ServerSettingsUpdateRequest {
|
|
193
339
|
proxyForApp?: boolean;
|
|
194
340
|
proxyForAgent?: boolean;
|
|
341
|
+
/** Company mode master switch; see `ServerSettings.companyMode`. */
|
|
342
|
+
companyMode?: boolean;
|
|
343
|
+
/** Chrome extension switch; see `ServerSettings.browserExtensionsEnabled`. */
|
|
344
|
+
browserExtensionsEnabled?: boolean;
|
|
345
|
+
/** Agent API switch; see `ServerSettings.agentApiEnabled`. */
|
|
346
|
+
agentApiEnabled?: boolean;
|
|
195
347
|
/**
|
|
196
348
|
* New proxy address. Accepted forms: any proxy URL undici's dispatcher takes —
|
|
197
349
|
* `http://`, `https://`, `socks5://` / `socks://`, credentials allowed — or bare
|
|
@@ -214,6 +366,53 @@ interface ServerSettingsUpdateRequest {
|
|
|
214
366
|
*/
|
|
215
367
|
attachmentTotalMb?: number;
|
|
216
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* The endpoints the proxy reachability probe covers. A fixed list: the route takes a provider
|
|
371
|
+
* id from this set and never a URL, so nothing a caller sends decides what the server fetches.
|
|
372
|
+
*
|
|
373
|
+
* GLM is two entries rather than one because it is two hosts: Z.AI serves the global endpoint
|
|
374
|
+
* and BigModel the mainland one, they are reached over different routes, and a proxy can carry
|
|
375
|
+
* one and not the other.
|
|
376
|
+
*/
|
|
377
|
+
type ProxyProbeProvider = "openai" | "anthropic" | "gemini" | "deepseek" | "zai" | "bigmodel";
|
|
378
|
+
/**
|
|
379
|
+
* One probe's verdict. `reachable` means an HTTP answer arrived, whatever its status — a
|
|
380
|
+
* rejected credential still proves the whole path works. The rest are transport failures,
|
|
381
|
+
* named so a proxy that swallows connections can be told apart from one whose address does
|
|
382
|
+
* not resolve: `timeout` (no answer within the probe's window), `dns` (the name never
|
|
383
|
+
* became an address), `refused` (the connection was refused at the TCP level), `tls` (the
|
|
384
|
+
* handshake or the certificate failed) and `network` (anything else).
|
|
385
|
+
*/
|
|
386
|
+
type ProxyProbeOutcome = "reachable" | "timeout" | "dns" | "refused" | "tls" | "network";
|
|
387
|
+
/**
|
|
388
|
+
* One probe target. Served before any probe runs so the page can list what it is about to
|
|
389
|
+
* request — the URLs are the concrete answer to "what does no API key mean here".
|
|
390
|
+
*/
|
|
391
|
+
interface ProxyProbeTargetDto {
|
|
392
|
+
provider: ProxyProbeProvider;
|
|
393
|
+
/** The exact URL a probe requests, unauthenticated. */
|
|
394
|
+
url: string;
|
|
395
|
+
}
|
|
396
|
+
/** What the probe endpoint would request, without requesting it. */
|
|
397
|
+
interface ProxyProbeTargetsResponse {
|
|
398
|
+
targets: ProxyProbeTargetDto[];
|
|
399
|
+
}
|
|
400
|
+
/** One provider's probe result. */
|
|
401
|
+
interface ProxyProbeDto extends ProxyProbeTargetDto {
|
|
402
|
+
outcome: ProxyProbeOutcome;
|
|
403
|
+
/** Wall time in milliseconds until the answer's headers arrived, or until the attempt failed. */
|
|
404
|
+
ms: number;
|
|
405
|
+
/** The HTTP status, present only when `outcome` is `reachable`. */
|
|
406
|
+
status?: number;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* One probe's answer. The route measures a single target per call: the page asks for all of
|
|
410
|
+
* them at once and fills each row the moment its own answer lands, so one black-holed host
|
|
411
|
+
* cannot hold every other result behind its timeout.
|
|
412
|
+
*/
|
|
413
|
+
interface ProxyProbeResponse {
|
|
414
|
+
probe: ProxyProbeDto;
|
|
415
|
+
}
|
|
217
416
|
/**
|
|
218
417
|
* One draft-screen shortcut: a prompt the user wrote, filed under a name they chose. Clicking it
|
|
219
418
|
* fills the composer exactly like a built-in example does, and sends nothing. Deliberately holds
|
|
@@ -226,6 +425,19 @@ interface DraftShortcut {
|
|
|
226
425
|
title: string;
|
|
227
426
|
prompt: string;
|
|
228
427
|
}
|
|
428
|
+
/**
|
|
429
|
+
* The account's keyboard shortcut overrides, one section per platform (the Web App's `Mod` token
|
|
430
|
+
* is ⌘ on macOS and Ctrl elsewhere, so a deliberate macOS-only binding must not leak to Windows).
|
|
431
|
+
* Each section maps a command id to a chord string ("Mod+Shift+KeyW") or null (explicitly
|
|
432
|
+
* unbound); only rows that differ from the Web App's default are present. Bounded on write by
|
|
433
|
+
* services/keybindings.ts.
|
|
434
|
+
*/
|
|
435
|
+
interface StoredKeybindings {
|
|
436
|
+
v: 1;
|
|
437
|
+
mac?: Record<string, string | null>;
|
|
438
|
+
windows?: Record<string, string | null>;
|
|
439
|
+
linux?: Record<string, string | null>;
|
|
440
|
+
}
|
|
229
441
|
/** User UI preferences (SQLite ui_prefs, free-form JSON; known keys declared here). */
|
|
230
442
|
interface UiPrefs {
|
|
231
443
|
theme?: "light" | "dark";
|
|
@@ -249,8 +461,29 @@ interface UiPrefs {
|
|
|
249
461
|
* known key holding user-authored text rather than a flag or an id.
|
|
250
462
|
*/
|
|
251
463
|
draftShortcuts?: DraftShortcut[];
|
|
464
|
+
/** Keyboard shortcut overrides, replaced whole on every write and validated by services/keybindings.ts. */
|
|
465
|
+
keybindings?: StoredKeybindings;
|
|
466
|
+
/** Personal company-mode switch (default on): off only hides this user's mode switch; organizations keep running. */
|
|
467
|
+
companyMode?: boolean;
|
|
468
|
+
/** The work mode the user last chose in the shell: development (default) or company. */
|
|
469
|
+
workMode?: "dev" | "company";
|
|
470
|
+
/** The organization last opened in company mode, as `<projectId>/<orgId>`. */
|
|
471
|
+
lastOrgKey?: string;
|
|
472
|
+
/** The one group balance shown beside the user name (pinned on the models page); null when unpinned. */
|
|
473
|
+
pinnedBalance?: PinnedBalance | null;
|
|
474
|
+
/**
|
|
475
|
+
* The browser this user's agents drive. Written only through PUT /api/builtin-browser/backend
|
|
476
|
+
* (PUT /api/me/prefs refuses it): absent means built-in for an admin on the desktop, chrome
|
|
477
|
+
* everywhere else.
|
|
478
|
+
*/
|
|
479
|
+
browserBackend?: BrowserBackend;
|
|
252
480
|
[key: string]: unknown;
|
|
253
481
|
}
|
|
482
|
+
/** A group balance pinned beside the user name: which Project's key reads which group's balance. */
|
|
483
|
+
interface PinnedBalance {
|
|
484
|
+
projectId: string;
|
|
485
|
+
provider: string;
|
|
486
|
+
}
|
|
254
487
|
interface PrefsResponse {
|
|
255
488
|
prefs: UiPrefs;
|
|
256
489
|
}
|
|
@@ -304,7 +537,7 @@ interface MemberAddResponse {
|
|
|
304
537
|
}
|
|
305
538
|
/**
|
|
306
539
|
* Model reference DTO: `(provider, modelId)` pair.
|
|
307
|
-
* `modelId` is the upstream request id, sent to
|
|
540
|
+
* `modelId` is the upstream request id, sent to MMSP as-is — `<provider>/<id>` string
|
|
308
541
|
* concatenation is forbidden throughout the pipeline.
|
|
309
542
|
*/
|
|
310
543
|
interface ModelRefDto {
|
|
@@ -317,6 +550,37 @@ interface ModelPricingDto {
|
|
|
317
550
|
cacheWrite: number;
|
|
318
551
|
output: number;
|
|
319
552
|
}
|
|
553
|
+
/**
|
|
554
|
+
* One group's `[providers.<id>]` connection as the page reads it: the values the GROUP stores
|
|
555
|
+
* (never the catalog's), the key masked. An absent field is unset: a row with no value of its
|
|
556
|
+
* own then gets the client's default.
|
|
557
|
+
*/
|
|
558
|
+
interface ProviderConnectionDto {
|
|
559
|
+
baseUrl?: string;
|
|
560
|
+
clientType?: string;
|
|
561
|
+
apiKeyMasked?: string;
|
|
562
|
+
/** When the group key was written (ISO 8601). */
|
|
563
|
+
createdAt?: string;
|
|
564
|
+
}
|
|
565
|
+
/** Where an effective connection value comes from: the row itself, its group, or nowhere (the client's default). */
|
|
566
|
+
type ConnectionSourceDto = "model" | "provider" | "none";
|
|
567
|
+
/**
|
|
568
|
+
* What a row is actually used with, after core's effectiveConnection (row -> group -> none,
|
|
569
|
+
* per field; the file's values only — the catalog is not consulted), and where each value
|
|
570
|
+
* came from. The group's key counts only where it reaches the row (core's groupKeyReaches).
|
|
571
|
+
* The row's own values stay in `clientType` / `credential` (what the form edits); this is for
|
|
572
|
+
* display.
|
|
573
|
+
*/
|
|
574
|
+
interface ModelEffectiveConnection {
|
|
575
|
+
baseUrl?: string;
|
|
576
|
+
baseUrlSource: ConnectionSourceDto;
|
|
577
|
+
clientType?: string;
|
|
578
|
+
clientTypeSource: ConnectionSourceDto;
|
|
579
|
+
/** `env` = no row or group key, and the environment lends one on the effective endpoint (modelEnvFallback). */
|
|
580
|
+
apiKeySource: "model" | "provider" | "env" | "none";
|
|
581
|
+
/** Mask of the key the row would use, whichever source; absent when none. */
|
|
582
|
+
apiKeyMasked?: string;
|
|
583
|
+
}
|
|
320
584
|
/** Read-only credential display: masked key and creation time; plaintext is never sent. */
|
|
321
585
|
interface CredentialInfo {
|
|
322
586
|
apiKeyMasked?: string;
|
|
@@ -326,17 +590,25 @@ interface CredentialInfo {
|
|
|
326
590
|
interface ModelInfo {
|
|
327
591
|
/** Provider group id (anthropic / openai / …, see core's MODEL_PROVIDERS; custom models use `custom`). */
|
|
328
592
|
provider: string;
|
|
329
|
-
/** Upstream model id (the request id actually sent to
|
|
593
|
+
/** Upstream model id (the request id actually sent to MMSP); paired with `provider` forms the entry's unique key. */
|
|
330
594
|
modelId: string;
|
|
331
|
-
/**
|
|
595
|
+
/**
|
|
596
|
+
* Display name: explicit TOML field (user-edited) takes priority, then the built-in catalog;
|
|
597
|
+
* falls back to unset (frontend shows modelId). The empty string is reported as such and
|
|
598
|
+
* means the user cleared the name on a model the catalog does name — render it as modelId,
|
|
599
|
+
* and send it back unchanged, since absent would ask for the catalog's name instead.
|
|
600
|
+
*/
|
|
332
601
|
displayName?: string;
|
|
333
602
|
contextWindow?: number;
|
|
334
|
-
/**
|
|
603
|
+
/**
|
|
604
|
+
* The row's OWN MMSP client type (`openai-chat`, `openai-responses`, etc.) — an override of
|
|
605
|
+
* its group's; absent = the row follows its group (see `effective`).
|
|
606
|
+
*/
|
|
335
607
|
clientType?: string;
|
|
336
608
|
/**
|
|
337
|
-
* Whether image input (vision/multimodal) is supported: the TOML `vision` annotation
|
|
338
|
-
*
|
|
339
|
-
*
|
|
609
|
+
* Whether image input (vision/multimodal) is supported: the TOML `vision` annotation only
|
|
610
|
+
* (a new Project writes `false` where the catalog says so); absent = unset, treated as
|
|
611
|
+
* supported. The catalog is not consulted.
|
|
340
612
|
*/
|
|
341
613
|
vision?: boolean;
|
|
342
614
|
/**
|
|
@@ -349,22 +621,36 @@ interface ModelInfo {
|
|
|
349
621
|
/**
|
|
350
622
|
* Per-model fast mode (TOML `fast_mode` annotation; user-only, never preset by the
|
|
351
623
|
* built-in catalog): when true, session requests opt into the provider's faster serving
|
|
352
|
-
* tier at premium pricing (
|
|
624
|
+
* tier at premium pricing (MMSP UniConfig `fast_mode`). Only `true` is reported;
|
|
353
625
|
* unset = off. Models without a fast tier reject requests carrying it.
|
|
354
626
|
*/
|
|
355
627
|
fastMode?: boolean;
|
|
356
628
|
pricing?: ModelPricingDto;
|
|
357
|
-
/**
|
|
629
|
+
/** Running promotion for this row — a fraction in (0, 1) off `pricing`, which is the list price — read from web.db. Absent when the row has none. */
|
|
630
|
+
discount?: number;
|
|
631
|
+
/**
|
|
632
|
+
* Environment variable name the entry falls back to when api_key is empty (e.g.
|
|
633
|
+
* ANTHROPIC_API_KEY); unset when it gets no fallback — an id nothing routes, or an entry
|
|
634
|
+
* whose base URL is not the vendor's own official endpoint (a gateway preset, a custom /
|
|
635
|
+
* vLLM / user-created row with its own endpoint, a vendor row re-pointed at a proxy).
|
|
636
|
+
*/
|
|
358
637
|
envKey?: string;
|
|
359
638
|
/**
|
|
360
639
|
* Masked preview (same rule as `credential.apiKeyMasked`) of the value the server process
|
|
361
|
-
* currently holds for `envKey` — the plaintext is never serialized. Reported only
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
640
|
+
* currently holds for `envKey` — the plaintext is never serialized. Reported only where the
|
|
641
|
+
* fallback may be presented as covering the entry (core's modelEnvPreviewKey): a row whose
|
|
642
|
+
* effective base URL is a vendor endpoint (or the Penguin Go relay), or a row with no base URL
|
|
643
|
+
* in a built-in group other than custom, on the client its id's family names. Gateway rows
|
|
644
|
+
* never carry it, and neither do custom / vLLM / user-defined rows with no base URL,
|
|
645
|
+
* although those do fall back. Absent = the variable is unset or empty, or the entry is not
|
|
646
|
+
* previewable. Computed on the effective shape, and only when no row or group key reaches
|
|
647
|
+
* the row.
|
|
365
648
|
*/
|
|
366
649
|
envKeyMasked?: string;
|
|
650
|
+
/** The row's OWN key (masked) and base URL — overrides of its group's; see `effective`. */
|
|
367
651
|
credential?: CredentialInfo;
|
|
652
|
+
/** The connection the row is actually used with, and where each value comes from. */
|
|
653
|
+
effective: ModelEffectiveConnection;
|
|
368
654
|
isDefault: boolean;
|
|
369
655
|
}
|
|
370
656
|
interface ModelsResponse {
|
|
@@ -379,15 +665,38 @@ interface ModelsResponse {
|
|
|
379
665
|
* (the key was fixed since). Absent when the Project has no config file yet.
|
|
380
666
|
*/
|
|
381
667
|
updatedAt?: string;
|
|
668
|
+
/** Every group's stored connection (`[providers.<id>]`), keyed by provider id; a group with none is absent. */
|
|
669
|
+
providers: Record<string, ProviderConnectionDto>;
|
|
382
670
|
models: ModelInfo[];
|
|
383
671
|
}
|
|
672
|
+
/**
|
|
673
|
+
* A change to one group's connection (`PUT /models/providers/:provider`, or a member of
|
|
674
|
+
* `ModelsUpdateRequest.providers`). Omitted fields are kept.
|
|
675
|
+
*/
|
|
676
|
+
interface ProviderConnectionUpdate {
|
|
677
|
+
/** `null` clears it; omitted keeps it. */
|
|
678
|
+
baseUrl?: string | null;
|
|
679
|
+
/**
|
|
680
|
+
* `null` or `""` clears it; omitted keeps it. Any group takes one: a row that stores its own
|
|
681
|
+
* protocol keeps it.
|
|
682
|
+
*/
|
|
683
|
+
clientType?: string | null;
|
|
684
|
+
/** A non-empty key; sets `createdAt`. Rows with their own key keep it. */
|
|
685
|
+
apiKey?: string;
|
|
686
|
+
/** When true, clears the group key (rows with their own key keep it). */
|
|
687
|
+
clearApiKey?: boolean;
|
|
688
|
+
}
|
|
384
689
|
/** PUT full-table replace semantics: models not present are deleted; omitting apiKey = keep existing value. Key = (provider, modelId). */
|
|
385
690
|
interface ModelUpdateEntry {
|
|
386
691
|
/** Provider group (an independent entry field, always submitted with the request). */
|
|
387
692
|
provider: string;
|
|
388
|
-
/** Upstream model id (sent to
|
|
693
|
+
/** Upstream model id (sent to MMSP as-is). */
|
|
389
694
|
modelId: string;
|
|
390
|
-
/**
|
|
695
|
+
/**
|
|
696
|
+
* Display name; the server does not persist it when it matches the built-in catalog (keeps
|
|
697
|
+
* the config file clean). Absent and empty are different requests: absent inherits whatever
|
|
698
|
+
* the catalog calls the model, the empty string records that the user cleared the name.
|
|
699
|
+
*/
|
|
391
700
|
displayName?: string;
|
|
392
701
|
/**
|
|
393
702
|
* The pair reference this entry was renamed from (provided when either the group or the
|
|
@@ -397,7 +706,10 @@ interface ModelUpdateEntry {
|
|
|
397
706
|
*/
|
|
398
707
|
renamedFrom?: ModelRefDto;
|
|
399
708
|
contextWindow?: number;
|
|
400
|
-
/**
|
|
709
|
+
/**
|
|
710
|
+
* Empty string/omitted = the row stores none: it follows its group's protocol, else MMSP
|
|
711
|
+
* routes by the vendor family the modelId begins with.
|
|
712
|
+
*/
|
|
401
713
|
clientType?: string;
|
|
402
714
|
/** Whether image input (vision/multimodal) is supported; omitted = supported (not persisted). */
|
|
403
715
|
vision?: boolean;
|
|
@@ -406,6 +718,12 @@ interface ModelUpdateEntry {
|
|
|
406
718
|
/** Per-model fast mode: only `true` is persisted; omitted or `false` clears the annotation (absent = off). */
|
|
407
719
|
fastMode?: boolean;
|
|
408
720
|
pricing?: ModelPricingDto;
|
|
721
|
+
/**
|
|
722
|
+
* Promotion to store for this row, a fraction in (0, 1) off `pricing`; `null` clears it. Omitted
|
|
723
|
+
* keeps the stored promotion — unless this entry renames the row or changes its pricing, which
|
|
724
|
+
* clears it.
|
|
725
|
+
*/
|
|
726
|
+
discount?: number | null;
|
|
409
727
|
/** Providing it overwrites and updates createdAt; omitting it keeps the existing value. */
|
|
410
728
|
apiKey?: string;
|
|
411
729
|
/** When true, clears the stored api_key. */
|
|
@@ -418,8 +736,29 @@ interface ModelsUpdateRequest {
|
|
|
418
736
|
defaultModel?: ModelRefDto;
|
|
419
737
|
/** Vision model used as a proxy reader for read_file: must be included in models and not annotated vision=false; omitted keeps the existing value. */
|
|
420
738
|
visionModel?: ModelRefDto;
|
|
739
|
+
/** Group connection changes, merged per provider; a provider absent here keeps its table. */
|
|
740
|
+
providers?: Record<string, ProviderConnectionUpdate>;
|
|
421
741
|
models: ModelUpdateEntry[];
|
|
422
742
|
}
|
|
743
|
+
/**
|
|
744
|
+
* `POST /models/sync-presets` (owner): `add` adds the catalog's presets the Project lacks
|
|
745
|
+
* (retired rows never), as a new Project stores them, writes the catalog's
|
|
746
|
+
* `[providers.<id>]` table for a group that has neither rows nor a table yet, and seeds the
|
|
747
|
+
* added rows' promotions, touching nothing else; `restore` puts every built-in row and
|
|
748
|
+
* built-in group table back to the catalog (facts reset, base URLs and protocols set on models
|
|
749
|
+
* or groups return to the catalog's, keys and the user's own rows and groups kept, promotions
|
|
750
|
+
* reset, deleted presets added back).
|
|
751
|
+
*/
|
|
752
|
+
type PresetSyncMode = "add" | "restore";
|
|
753
|
+
interface PresetSyncRequest {
|
|
754
|
+
mode: PresetSyncMode;
|
|
755
|
+
}
|
|
756
|
+
interface PresetSyncResponse extends ModelsResponse {
|
|
757
|
+
/** Preset rows added (both modes). */
|
|
758
|
+
added: number;
|
|
759
|
+
/** Built-in rows reset to the catalog (`restore`; 0 for `add`). */
|
|
760
|
+
restored: number;
|
|
761
|
+
}
|
|
423
762
|
/**
|
|
424
763
|
* Connectivity test (POST /api/projects/:p/models/test): the model reference is submitted as
|
|
425
764
|
* a pair in the request body; the rest are optional overrides (for trying out an unsaved
|
|
@@ -429,7 +768,7 @@ interface ModelsUpdateRequest {
|
|
|
429
768
|
interface ModelTestRequest {
|
|
430
769
|
/** Provider group of the model under test (paired with modelId). */
|
|
431
770
|
provider: string;
|
|
432
|
-
/** Upstream id of the model under test (sent to
|
|
771
|
+
/** Upstream id of the model under test (sent to MMSP as-is). */
|
|
433
772
|
modelId: string;
|
|
434
773
|
/** Newly entered API key (plaintext); used for the test if provided. */
|
|
435
774
|
apiKey?: string;
|
|
@@ -443,7 +782,7 @@ interface ModelTestRequest {
|
|
|
443
782
|
* `undefined` means fall back to the stored value only when not provided.
|
|
444
783
|
*/
|
|
445
784
|
baseUrl?: string | null;
|
|
446
|
-
/**
|
|
785
|
+
/** MMSP client type; required for an unsaved custom model whose id begins with no known vendor family (otherwise it can't be routed). */
|
|
447
786
|
clientType?: string;
|
|
448
787
|
/**
|
|
449
788
|
* Test with fast mode (the frontend always sends the form's current value, so an unsaved
|
|
@@ -506,7 +845,7 @@ interface ModelTestResponse {
|
|
|
506
845
|
}
|
|
507
846
|
/**
|
|
508
847
|
* Protocol auto-detection (POST /api/projects/:p/models/detect, owner): probes which of
|
|
509
|
-
*
|
|
848
|
+
* MMSP's generic protocol clients a custom base URL serves — `openai-responses` first,
|
|
510
849
|
* then `ant-messages`, then `openai-chat` — and reports the first hit. Used by the custom
|
|
511
850
|
* model dialog to fill `clientType` from the endpoint itself; costs no tokens (each probe
|
|
512
851
|
* is a minimal invalid request whose error reveals the protocol shape).
|
|
@@ -518,7 +857,12 @@ interface ModelProtocolDetectRequest {
|
|
|
518
857
|
apiKey?: string;
|
|
519
858
|
/** "Clear saved API key" is checked: do not fall back to the stored key (probe the current draft). */
|
|
520
859
|
clearApiKey?: boolean;
|
|
521
|
-
/**
|
|
860
|
+
/**
|
|
861
|
+
* Optional paired reference: when it names a stored entry and no apiKey is given, that
|
|
862
|
+
* entry's saved key backs the probes (mirrors the connectivity test), else its group's.
|
|
863
|
+
* `provider` may be sent without `modelId` (the group settings dialog has no model): the
|
|
864
|
+
* group key backs the probes.
|
|
865
|
+
*/
|
|
522
866
|
provider?: string;
|
|
523
867
|
modelId?: string;
|
|
524
868
|
}
|
|
@@ -532,7 +876,7 @@ interface ModelProtocolDetectRequest {
|
|
|
532
876
|
type ProtocolProbeOutcome = "served" | "route_missing" | "server_error" | "junk" | "timeout" | "network_error";
|
|
533
877
|
/** One probe, for debugging display: the probed URL derives from baseUrl only (never contains the key). */
|
|
534
878
|
interface ModelProtocolProbeDto {
|
|
535
|
-
/**
|
|
879
|
+
/** MMSP client type this probe stands for (`openai-responses` / `ant-messages` / `openai-chat`). */
|
|
536
880
|
clientType: string;
|
|
537
881
|
/** Full URL probed (base URL + the protocol's path). */
|
|
538
882
|
url: string;
|
|
@@ -540,22 +884,34 @@ interface ModelProtocolProbeDto {
|
|
|
540
884
|
/** HTTP status, when a response arrived at all. */
|
|
541
885
|
status?: number;
|
|
542
886
|
}
|
|
543
|
-
/**
|
|
887
|
+
/**
|
|
888
|
+
* Detection result: probes run sequentially over the candidate base URLs derived from the
|
|
889
|
+
* one that was typed and stop at the first served protocol, so `probes` lists only the
|
|
890
|
+
* ones actually run, in order.
|
|
891
|
+
*/
|
|
544
892
|
interface ModelProtocolDetectResponse {
|
|
545
|
-
/** The first protocol
|
|
893
|
+
/** The first protocol an endpoint serves (an MMSP client type); absent when none of the three matched. */
|
|
546
894
|
detected?: string;
|
|
895
|
+
/**
|
|
896
|
+
* The base URL the detected protocol answered at — the typed URL normalized (endpoint
|
|
897
|
+
* path stripped, repeated `/v1` collapsed) and possibly with a trailing `/v1` added or
|
|
898
|
+
* removed, so `https://host/v1/chat/completions` comes back as `https://host/v1`.
|
|
899
|
+
* Present only alongside `detected`; callers write it back into their base URL field,
|
|
900
|
+
* since that is where the protocol is served.
|
|
901
|
+
*/
|
|
902
|
+
baseUrl?: string;
|
|
547
903
|
probes: ModelProtocolProbeDto[];
|
|
548
904
|
}
|
|
549
905
|
/**
|
|
550
906
|
* Endpoint model listing (POST /api/projects/:p/models/list, owner): given a base URL and
|
|
551
|
-
* the protocol `/detect` reported, returns every model id the endpoint serves (
|
|
907
|
+
* the protocol `/detect` reported, returns every model id the endpoint serves (MMSP's
|
|
552
908
|
* `listModels()` on the routed client). Used by the add-group dialog to import a provider's
|
|
553
909
|
* whole listing in one go; the ids come back in the endpoint's own order.
|
|
554
910
|
*/
|
|
555
911
|
interface EndpointModelListRequest {
|
|
556
912
|
/** Endpoint base URL (as typed in the add-group dialog). */
|
|
557
913
|
baseUrl: string;
|
|
558
|
-
/**
|
|
914
|
+
/** MMSP client type to speak (normally a detected generic protocol; whole-endpoint listings need one). */
|
|
559
915
|
clientType: string;
|
|
560
916
|
/** Newly entered API key (plaintext); omitted = the SDK's environment fallback for the protocol. */
|
|
561
917
|
apiKey?: string;
|
|
@@ -565,7 +921,7 @@ interface EndpointModelListResponse {
|
|
|
565
921
|
ok: boolean;
|
|
566
922
|
/** The model ids the endpoint serves, in the order the endpoint returned them (ok only). */
|
|
567
923
|
models?: string[];
|
|
568
|
-
/** The routed client has no models endpoint (
|
|
924
|
+
/** The routed client has no models endpoint (MMSP UnsupportedOperationError) — callers offer the manual path. */
|
|
569
925
|
unsupported?: boolean;
|
|
570
926
|
message?: string;
|
|
571
927
|
}
|
|
@@ -583,6 +939,54 @@ interface DefaultModelUpdateRequest {
|
|
|
583
939
|
interface DefaultModelResponse {
|
|
584
940
|
defaultModel: ModelRefDto;
|
|
585
941
|
}
|
|
942
|
+
/** One balance in one currency. */
|
|
943
|
+
interface ModelBalanceAmount {
|
|
944
|
+
/** Decimal string in `currency`'s major unit, as the vendor states it (TokenDance's micro-yuan are converted to yuan). */
|
|
945
|
+
amount: string;
|
|
946
|
+
/** ISO 4217 code: `CNY`, `USD`, … */
|
|
947
|
+
currency: string;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Why a group's balance could not be read:
|
|
951
|
+
* - `unsupported`: the group publishes no balance endpoint (no `balance` descriptor in the catalog);
|
|
952
|
+
* - `no_key`: the group has no API key to ask with — none stored, and no environment variable
|
|
953
|
+
* the credential rule lends its rows for the balance endpoint's host;
|
|
954
|
+
* - `upstream_failed`: the vendor could not be reached in time, refused the request, or answered
|
|
955
|
+
* without a readable balance.
|
|
956
|
+
*/
|
|
957
|
+
type ModelBalanceErrorCode = "unsupported" | "no_key" | "upstream_failed";
|
|
958
|
+
/**
|
|
959
|
+
* GET /api/projects/:p/models/balance?provider=<group>[&force=1] (Project member): the account
|
|
960
|
+
* balance behind the group's API key — the stored one, or else the environment key its rows
|
|
961
|
+
* fall back to under the credential rule (DeepSeek's DEEPSEEK_API_KEY) — read server-side from
|
|
962
|
+
* the endpoint the catalog's `balance` descriptor names. The key never reaches the browser, and
|
|
963
|
+
* neither does the vendor's own text. Like the connectivity test, a balance that cannot be read is an answer
|
|
964
|
+
* (`ok: false` with a code), not a failed request. Readings and vendor failures are cached for
|
|
965
|
+
* 60 s per Project and group, for as long as the group's key is the same; `force=1` skips the
|
|
966
|
+
* cache and refreshes it.
|
|
967
|
+
*/
|
|
968
|
+
type ModelBalanceResponse = ModelBalanceReading | ModelBalanceFailure;
|
|
969
|
+
interface ModelBalanceReading extends ModelBalanceAmount {
|
|
970
|
+
ok: true;
|
|
971
|
+
provider: string;
|
|
972
|
+
/** Whether the account can make requests right now (DeepSeek's `is_available`); absent when the vendor does not say. */
|
|
973
|
+
available?: boolean;
|
|
974
|
+
/** Further currencies the account holds, after the one in `amount` / `currency`; absent when there is only one. */
|
|
975
|
+
others?: ModelBalanceAmount[];
|
|
976
|
+
/** When the server read it from the vendor (ISO 8601); a cached answer keeps its original time. */
|
|
977
|
+
fetchedAt: string;
|
|
978
|
+
}
|
|
979
|
+
interface ModelBalanceFailure {
|
|
980
|
+
ok: false;
|
|
981
|
+
provider: string;
|
|
982
|
+
error: ModelBalanceErrorCode;
|
|
983
|
+
/** The vendor's HTTP status, when it answered with an error. */
|
|
984
|
+
status?: number;
|
|
985
|
+
/** English detail for logs and bug reports; the Web App words each code itself. */
|
|
986
|
+
message: string;
|
|
987
|
+
/** When the answer was settled (ISO 8601). */
|
|
988
|
+
fetchedAt: string;
|
|
989
|
+
}
|
|
586
990
|
/**
|
|
587
991
|
* How the authorization code travels back. `callback` sends the browser to a harness URL
|
|
588
992
|
* the provider redirects to; `manual` asks the provider for a one-time code the user copies
|
|
@@ -637,6 +1041,33 @@ interface ModelOAuthCodeResponse {
|
|
|
637
1041
|
applied?: number;
|
|
638
1042
|
error?: ModelOAuthErrorCode;
|
|
639
1043
|
}
|
|
1044
|
+
interface PlatformAuthStartResponse {
|
|
1045
|
+
flowId: string;
|
|
1046
|
+
authorizeUrl: string;
|
|
1047
|
+
expiresAt: string;
|
|
1048
|
+
}
|
|
1049
|
+
type PlatformAuthFlowErrorCode = "unreachable" | "upstream_failed" | "invalid_key" | "expired" | "locked" | "already_delivered" | "apply_failed";
|
|
1050
|
+
interface PlatformAuthFlowStatusResponse {
|
|
1051
|
+
status: "pending" | "applying" | "completed" | "cancelled" | "apply_failed" | "error";
|
|
1052
|
+
error?: PlatformAuthFlowErrorCode;
|
|
1053
|
+
applied?: number;
|
|
1054
|
+
}
|
|
1055
|
+
/** Result of refreshing Penguin Go's catalog with the Project's stored platform key. */
|
|
1056
|
+
interface PlatformModelSyncResponse extends ModelsResponse {
|
|
1057
|
+
added: number;
|
|
1058
|
+
updated: number;
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* The wire shapes are Penguin Go's, deliberately: both flows create a request, poll it, and
|
|
1062
|
+
* report the same six states and the same seven failure codes, so the App drives both with one
|
|
1063
|
+
* dialog. They are aliases rather than a second declaration because a copy would be the same
|
|
1064
|
+
* fields with the same meaning, and a shape that drifted apart in one of the two would be a
|
|
1065
|
+
* bug rather than a distinction. The endpoints stay separate regardless — a flow id issued by
|
|
1066
|
+
* one is not accepted by the other.
|
|
1067
|
+
*/
|
|
1068
|
+
type ModelScopeAuthStartResponse = PlatformAuthStartResponse;
|
|
1069
|
+
type ModelScopeAuthFlowErrorCode = PlatformAuthFlowErrorCode;
|
|
1070
|
+
type ModelScopeAuthFlowStatusResponse = PlatformAuthFlowStatusResponse;
|
|
640
1071
|
/**
|
|
641
1072
|
* Per-Project new-chat defaults: prefill for the chat draft page. Every key is optional —
|
|
642
1073
|
* an absent key means "not set" (the pre-existing behavior). Serves as the GET response,
|
|
@@ -658,6 +1089,11 @@ interface ChatDefaultsDto {
|
|
|
658
1089
|
* "none" — only the selectable tiers.
|
|
659
1090
|
*/
|
|
660
1091
|
thinkingLevel?: Exclude<ThinkingLevelName, "none">;
|
|
1092
|
+
/**
|
|
1093
|
+
* Read-only, GET only: the sandbox policy a new Session starts with — the server's Sandbox
|
|
1094
|
+
* settings. Not part of the Project's block; PUT ignores it.
|
|
1095
|
+
*/
|
|
1096
|
+
sandbox?: SessionSandbox;
|
|
661
1097
|
}
|
|
662
1098
|
/**
|
|
663
1099
|
* One deny rule of the sandbox command policy — plain project-editable data. The factory
|
|
@@ -708,11 +1144,15 @@ interface VaultEntryUpdate {
|
|
|
708
1144
|
interface VaultUpdateRequest {
|
|
709
1145
|
entries: VaultEntryUpdate[];
|
|
710
1146
|
}
|
|
711
|
-
/** One
|
|
1147
|
+
/** One library plugin an Agent's installed copy is behind on — one of its skills or its hook package carries an older dated version than the library's same part (see {@link AgentSummary.pluginUpdates}). */
|
|
712
1148
|
interface PluginUpdateRef {
|
|
713
1149
|
/** Plugin name — what `POST …/plugins` reinstalls to bring the Agent up to date. */
|
|
714
1150
|
name: string;
|
|
715
|
-
/**
|
|
1151
|
+
/**
|
|
1152
|
+
* The LIBRARY's content version: the newest dated version (`YYYY.MM.DD.N`) among the plugin's
|
|
1153
|
+
* parts, i.e. the date of what installing again would bring, not what is on disk. A label —
|
|
1154
|
+
* it moves whenever any part changes, so a dismissed update comes back for the next one.
|
|
1155
|
+
*/
|
|
716
1156
|
version: string;
|
|
717
1157
|
}
|
|
718
1158
|
interface AgentSummary {
|
|
@@ -744,15 +1184,35 @@ interface AgentSummary {
|
|
|
744
1184
|
hookCount: number;
|
|
745
1185
|
/**
|
|
746
1186
|
* Installed plugins the built-in library has moved past — a skill or a hook package whose
|
|
747
|
-
* on-disk version is behind the library
|
|
748
|
-
*
|
|
749
|
-
*
|
|
750
|
-
*
|
|
751
|
-
*
|
|
1187
|
+
* on-disk dated version is behind the library's same part (compared part by part, never
|
|
1188
|
+
* against the plugin's npm version) — each with the library's content version on offer: the
|
|
1189
|
+
* plugin-library update gate, riding along on the Agent list so a badge over that page costs
|
|
1190
|
+
* no request of its own. Empty when nothing is behind. Skills the library does not carry
|
|
1191
|
+
* (installed from a zip or a picked directory) are never listed: there is no library version
|
|
1192
|
+
* for them to be behind.
|
|
752
1193
|
*/
|
|
753
1194
|
pluginUpdates: PluginUpdateRef[];
|
|
754
1195
|
/** Memory count (topic files summed over the scope directories under agent_state/memory/, independent of the memory switch). */
|
|
755
1196
|
memoryCount: number;
|
|
1197
|
+
/** Whether the Agent's API tab switch is on (this server's web.db, see AgentApiSettings.enabled): the list card's API mark. */
|
|
1198
|
+
apiEnabled: boolean;
|
|
1199
|
+
/**
|
|
1200
|
+
* The organizations of this Project that employ the Agent, one entry per organization:
|
|
1201
|
+
* every organization directory the Project holds, paused ones included, plus the CEO id of
|
|
1202
|
+
* an organization whose chart does not parse. Absent or empty = not an employee. An
|
|
1203
|
+
* employed Agent cannot be deleted (`DELETE` answers 409 `agent_employed`) until it leaves
|
|
1204
|
+
* every one of them; development mode lists employees in a section of their own.
|
|
1205
|
+
*/
|
|
1206
|
+
employments?: Employment[];
|
|
1207
|
+
}
|
|
1208
|
+
/** One organization employing an Agent, as the Agent list carries it (see {@link AgentSummary.employments}). */
|
|
1209
|
+
interface Employment {
|
|
1210
|
+
orgId: string;
|
|
1211
|
+
/** The organization's display name (`org_config.toml`), the id when the config does not parse. */
|
|
1212
|
+
orgName: string;
|
|
1213
|
+
/** The Agent's title in that organization's chart; "CEO" for the CEO of a chart that does not parse. */
|
|
1214
|
+
title: string;
|
|
1215
|
+
status: OrgStatus;
|
|
756
1216
|
}
|
|
757
1217
|
interface AgentsResponse {
|
|
758
1218
|
agents: AgentSummary[];
|
|
@@ -900,13 +1360,20 @@ interface AgentKernelUpdateResponse {
|
|
|
900
1360
|
/** The kernel stamp written (the current defaults generation). */
|
|
901
1361
|
kernelVersion: string;
|
|
902
1362
|
}
|
|
903
|
-
/**
|
|
1363
|
+
/**
|
|
1364
|
+
* POST …/config/mcp-test result: reachability of one MCP Server entry. Its `${KEY}` references
|
|
1365
|
+
* are filled in from the Agent's vault only when the entry is saved on the Agent exactly as
|
|
1366
|
+
* tested (same name, same config — the user's rule); a new or changed entry that references the
|
|
1367
|
+
* vault is not filled in and not contacted (`saveFirst`).
|
|
1368
|
+
*/
|
|
904
1369
|
interface McpServerTestResponse {
|
|
905
1370
|
ok: boolean;
|
|
906
1371
|
/** Discovered tool names (`mcp__<server>__<tool>`), present on success. */
|
|
907
1372
|
tools?: string[];
|
|
908
|
-
/** Failure detail (connect error, timeout, server stderr tail), present on failure. */
|
|
1373
|
+
/** Failure detail (connect error, timeout, server stderr tail; "needs setup: …" naming a vault key a saved entry references and the vault lacks, with nothing contacted), present on failure. */
|
|
909
1374
|
error?: string;
|
|
1375
|
+
/** The entry references the vault and is not saved as it is: nothing was filled in or contacted — save it, then test (`error` says so in English). */
|
|
1376
|
+
saveFirst?: boolean;
|
|
910
1377
|
/** Connect + discovery wall time (both outcomes) — the models test reports latency, this matches. */
|
|
911
1378
|
latencyMs?: number;
|
|
912
1379
|
}
|
|
@@ -942,6 +1409,61 @@ interface AgentConfigUpdateRequest {
|
|
|
942
1409
|
mcpServers?: MCPServerConfig[];
|
|
943
1410
|
};
|
|
944
1411
|
}
|
|
1412
|
+
/** One API key of an Agent, as listed: the secret itself is shown once, at creation, and never again. */
|
|
1413
|
+
interface AgentApiKeyInfo {
|
|
1414
|
+
keyId: string;
|
|
1415
|
+
/** 1-64 characters, given by whoever created it. */
|
|
1416
|
+
name: string;
|
|
1417
|
+
/** The key's first 16 characters (`penguin_` + 8), enough to tell keys apart. */
|
|
1418
|
+
prefix: string;
|
|
1419
|
+
/** user_id of the Project owner who created it. */
|
|
1420
|
+
createdBy: string;
|
|
1421
|
+
createdAt: string;
|
|
1422
|
+
/** Last run request that authenticated with it; null = never used. */
|
|
1423
|
+
lastUsedAt: string | null;
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* One Agent's public API settings — this server's, kept in web.db, never in the Agent State or
|
|
1427
|
+
* the Project file, so the Agent cannot expose itself or loosen its own approvals. An Agent
|
|
1428
|
+
* never configured reads as disabled, keyed, allow-all, with no keys.
|
|
1429
|
+
*/
|
|
1430
|
+
interface AgentApiSettings {
|
|
1431
|
+
/** The API tab's switch; off = every AMSP request for this Agent is 404 `agent_not_found`. */
|
|
1432
|
+
enabled: boolean;
|
|
1433
|
+
/** Keyless access: a request without `Authorization` is accepted; off = 401 `unauthorized`. */
|
|
1434
|
+
open: boolean;
|
|
1435
|
+
/**
|
|
1436
|
+
* The approval mode an API Session is created with. It is copied onto each API Session when
|
|
1437
|
+
* that Session is created, and the Session's own mode is what every decision reads, so a
|
|
1438
|
+
* change here applies to API Sessions created afterwards.
|
|
1439
|
+
*/
|
|
1440
|
+
approvalMode: ApprovalMode;
|
|
1441
|
+
keys: AgentApiKeyInfo[];
|
|
1442
|
+
}
|
|
1443
|
+
interface AgentApiResponse {
|
|
1444
|
+
api: AgentApiSettings;
|
|
1445
|
+
/**
|
|
1446
|
+
* The admin's server-wide switch (`ServerSettings.agentApiEnabled`), which only an admin can
|
|
1447
|
+
* read through /api/admin/settings: off, every Agent's API is refused (403) whatever `api` says.
|
|
1448
|
+
*/
|
|
1449
|
+
serverEnabled: boolean;
|
|
1450
|
+
}
|
|
1451
|
+
/** PUT body (owner only): every field optional, omitted fields keep their current value. */
|
|
1452
|
+
interface AgentApiUpdateRequest {
|
|
1453
|
+
enabled?: boolean;
|
|
1454
|
+
open?: boolean;
|
|
1455
|
+
approvalMode?: ApprovalMode;
|
|
1456
|
+
}
|
|
1457
|
+
/** POST …/api/keys body (owner only). */
|
|
1458
|
+
interface AgentApiKeyCreateRequest {
|
|
1459
|
+
/** 1-64 characters. */
|
|
1460
|
+
name: string;
|
|
1461
|
+
}
|
|
1462
|
+
/** The one response that carries the secret (`penguin_` + 43 base64url characters); only its hash is stored. */
|
|
1463
|
+
interface AgentApiKeyCreateResponse {
|
|
1464
|
+
key: AgentApiKeyInfo;
|
|
1465
|
+
secret: string;
|
|
1466
|
+
}
|
|
945
1467
|
/** One Memory scope directory: `agent_state/memory/user/` or `agent_state/memory/<workspaceKey>/`. */
|
|
946
1468
|
interface MemoryScopeInfo {
|
|
947
1469
|
/** Directory name under `memory/`: `user`, or a Workspace's `<safe-basename>-<hash>` key. */
|
|
@@ -1051,16 +1573,119 @@ interface MemoryImportResponse {
|
|
|
1051
1573
|
/** Whether the scope's `MEMORY.md` was written or extended. */
|
|
1052
1574
|
indexWritten: boolean;
|
|
1053
1575
|
}
|
|
1576
|
+
/** How far a Session's commands may reach the filesystem (the sandbox's confinement mode). */
|
|
1577
|
+
type SessionSandboxMode = "read-only" | "workspace-write" | "danger-full-access";
|
|
1578
|
+
/**
|
|
1579
|
+
* The part of a Session's sandbox policy a person picks from the composer: the filesystem
|
|
1580
|
+
* mode and the network level. The Session keeps its own copy — taken from the server's
|
|
1581
|
+
* Sandbox settings when it was created — so editing those settings only changes what NEW
|
|
1582
|
+
* Sessions start with.
|
|
1583
|
+
*/
|
|
1584
|
+
interface SessionSandbox {
|
|
1585
|
+
mode: SessionSandboxMode;
|
|
1586
|
+
/** `open` = unrestricted, `local` = only the host's localhost, `none` = no network. */
|
|
1587
|
+
network: SessionSandboxNetwork;
|
|
1588
|
+
/**
|
|
1589
|
+
* Response only, ignored in requests: whether a sandbox backend on this server can enforce
|
|
1590
|
+
* the `read-only` and `workspace-write` modes. False on a deployment with no backend
|
|
1591
|
+
* installed, where either mode would refuse every command: the composer shows them greyed
|
|
1592
|
+
* out, saying no backend is installed.
|
|
1593
|
+
*/
|
|
1594
|
+
confinementSupported?: boolean;
|
|
1595
|
+
/** Response only, ignored in requests: the same for the `none` network level. */
|
|
1596
|
+
noNetworkSupported?: boolean;
|
|
1597
|
+
/**
|
|
1598
|
+
* Response only, ignored in requests: whether a sandbox backend on this server can enforce
|
|
1599
|
+
* the `local` level. When false the composer shows it greyed out, and picking it is refused
|
|
1600
|
+
* (400 `sandbox_unsupported`).
|
|
1601
|
+
*/
|
|
1602
|
+
localNetworkSupported?: boolean;
|
|
1603
|
+
/** Response only, ignored in requests: whether a backend here can enforce `masksPaths`. */
|
|
1604
|
+
maskPathsSupported?: boolean;
|
|
1605
|
+
/**
|
|
1606
|
+
* Response only, ignored in requests: true when this policy hides paths (the Sandbox card's
|
|
1607
|
+
* masked paths, kept by every pick). Where `maskPathsSupported` is false, every level then
|
|
1608
|
+
* refuses every command, and the composer says so.
|
|
1609
|
+
*/
|
|
1610
|
+
masksPaths?: boolean;
|
|
1611
|
+
/**
|
|
1612
|
+
* Response only, ignored in requests: the names of the sandbox backends in use here, which the
|
|
1613
|
+
* composer names when a level is beyond what they enforce. Absent with none in use.
|
|
1614
|
+
*/
|
|
1615
|
+
backendsInUse?: string[];
|
|
1616
|
+
/**
|
|
1617
|
+
* Response only, ignored in requests: the sandbox backends that are enabled here but failed
|
|
1618
|
+
* to load or failed their check (a WSL distro not set up, a wrong program path), each with
|
|
1619
|
+
* why. A backend for another platform is not listed. With none mounted and one listed, the
|
|
1620
|
+
* composer marks the confining levels unavailable and gives the first one's reason.
|
|
1621
|
+
*/
|
|
1622
|
+
unavailableBackends?: UnavailableSandboxBackend[];
|
|
1623
|
+
/**
|
|
1624
|
+
* Response only, ignored in requests: the server's sandbox presets (the Sandbox card's table),
|
|
1625
|
+
* in table order, disabled rows included. The composer lists the enabled ones and names the
|
|
1626
|
+
* Session's level by the first row matching its mode, network and approval mode. A server
|
|
1627
|
+
* that does not report it gets the composer's built-in table.
|
|
1628
|
+
*/
|
|
1629
|
+
presets?: SessionSandboxPreset[];
|
|
1630
|
+
/**
|
|
1631
|
+
* Response only, ignored in requests: true when this Session's policy holds something the
|
|
1632
|
+
* presets do not show — masked paths, or the temp directory not writable.
|
|
1633
|
+
*/
|
|
1634
|
+
advanced?: boolean;
|
|
1635
|
+
/**
|
|
1636
|
+
* Response only, chat defaults only: the approval mode a new Session starts with when its
|
|
1637
|
+
* request names none — the Sandbox card's default preset's, while the switch is on. Absent:
|
|
1638
|
+
* the server's own fallback (`allow-all`).
|
|
1639
|
+
*/
|
|
1640
|
+
defaultApprovalMode?: ApprovalMode;
|
|
1641
|
+
/**
|
|
1642
|
+
* Response only, ignored in requests: the Sandbox card's switch on this server — whether new
|
|
1643
|
+
* Sessions start confined. Off, the composer offers the approval modes alone (a Session keeps
|
|
1644
|
+
* its own policy either way). A server that does not report it is read as on.
|
|
1645
|
+
*/
|
|
1646
|
+
switchOn?: boolean;
|
|
1647
|
+
}
|
|
1648
|
+
/** One sandbox preset: a named mode, network level and approval mode. */
|
|
1649
|
+
interface SessionSandboxPreset {
|
|
1650
|
+
id: string;
|
|
1651
|
+
/** The name an administrator gave it, or its declared English name. */
|
|
1652
|
+
name: string;
|
|
1653
|
+
/** Its declared Chinese name, while it has not been renamed. */
|
|
1654
|
+
nameZh?: string;
|
|
1655
|
+
/** Whether the composer's menu lists it. */
|
|
1656
|
+
enabled: boolean;
|
|
1657
|
+
mode: SessionSandboxMode;
|
|
1658
|
+
network: SessionSandboxNetwork;
|
|
1659
|
+
approvalMode: ApprovalMode;
|
|
1660
|
+
/**
|
|
1661
|
+
* Response-only: its file mode or network is wider than the server's sandbox settings (the
|
|
1662
|
+
* ceiling for non-admins), so a non-admin's pick of it is refused with `403 sandbox_forbidden`.
|
|
1663
|
+
* The same comparison as that refusal; absent when it is within them.
|
|
1664
|
+
*/
|
|
1665
|
+
aboveCeiling?: true;
|
|
1666
|
+
}
|
|
1667
|
+
/** An enabled sandbox backend that is not in use on this server, and why. */
|
|
1668
|
+
interface UnavailableSandboxBackend {
|
|
1669
|
+
name: string;
|
|
1670
|
+
reason: string;
|
|
1671
|
+
}
|
|
1672
|
+
/** The network levels, widest first. */
|
|
1673
|
+
type SessionSandboxNetwork = "open" | "local" | "none";
|
|
1054
1674
|
interface SessionInfo {
|
|
1055
1675
|
sessionId: string;
|
|
1056
1676
|
projectId: string;
|
|
1057
1677
|
agentId: string;
|
|
1058
|
-
/**
|
|
1678
|
+
/**
|
|
1679
|
+
* Provider group of the session's **current** model (paired with `modelId` to form a model
|
|
1680
|
+
* reference). It moves with each in-session switch (`POST /api/sessions/:id/switch-model`).
|
|
1681
|
+
*/
|
|
1059
1682
|
provider: string;
|
|
1060
|
-
/** Upstream model_id of the session's model (the request id sent to
|
|
1683
|
+
/** Upstream model_id of the session's current model (the request id sent to MMSP). */
|
|
1061
1684
|
modelId: string;
|
|
1062
1685
|
workspace: string;
|
|
1063
1686
|
approvalMode: ApprovalMode;
|
|
1687
|
+
/** The Session's own sandbox policy (see {@link SessionSandbox}). */
|
|
1688
|
+
sandbox: SessionSandbox;
|
|
1064
1689
|
/**
|
|
1065
1690
|
* Thinking level pinned for this Session (set via PATCH; the Web App's in-chat picker).
|
|
1066
1691
|
* Unset = never pinned: each model context the Session opens reads the Agent config's
|
|
@@ -1073,7 +1698,18 @@ interface SessionInfo {
|
|
|
1073
1698
|
thinkingLevel?: ThinkingLevelName;
|
|
1074
1699
|
/** Short title auto-generated by the model after the first turn; unset until generated (frontend shows "New Chat"). */
|
|
1075
1700
|
title?: string;
|
|
1076
|
-
/**
|
|
1701
|
+
/**
|
|
1702
|
+
* What kind of conversation this is, read from core session_meta — the single source of
|
|
1703
|
+
* truth (the DB stores no source). With the user's marks it decides where the Session is
|
|
1704
|
+
* listed (`archived`): a `user` Session is in the sidebar until archived; an `api`,
|
|
1705
|
+
* `schedule` or `cli` Session is archived until the user keeps it, and in the sidebar marked
|
|
1706
|
+
* with its source once kept; a `subagent` or `company` Session is in no list — its parent's
|
|
1707
|
+
* Agent panel and company mode's own views open them. A Trace head that records no source
|
|
1708
|
+
* (written before it was required) reads as `company` for a row the organization runtime
|
|
1709
|
+
* opened (`client: "org"`), else as `user`; so does such a row before its first run. Absent
|
|
1710
|
+
* only while any other row is not yet classified (its Trace head has not been read yet),
|
|
1711
|
+
* which renders as `user`.
|
|
1712
|
+
*/
|
|
1077
1713
|
source?: SessionSource;
|
|
1078
1714
|
createdAt: string;
|
|
1079
1715
|
/**
|
|
@@ -1099,7 +1735,13 @@ interface SessionInfo {
|
|
|
1099
1735
|
pendingFollowUpCount: number;
|
|
1100
1736
|
/** Whether a Trace record exists (a Task has been started). */
|
|
1101
1737
|
hasTrace: boolean;
|
|
1102
|
-
/**
|
|
1738
|
+
/**
|
|
1739
|
+
* Whether the Session is archived — the listing rule's answer, never the bare mark: the user
|
|
1740
|
+
* archived it, or a program opened it (source `api`, `schedule` or `cli`) and the user has
|
|
1741
|
+
* not kept it. An archived Session is left out of the sidebar and listed on the archive page
|
|
1742
|
+
* (`/api/me/archived-sessions`). Always false for a `subagent` or `company` Session, which is
|
|
1743
|
+
* in no list.
|
|
1744
|
+
*/
|
|
1103
1745
|
archived: boolean;
|
|
1104
1746
|
/**
|
|
1105
1747
|
* Absolute path of the session's latest Trace file (the current context shard); absent
|
|
@@ -1111,6 +1753,26 @@ interface SessionInfo {
|
|
|
1111
1753
|
tracePath?: string;
|
|
1112
1754
|
/** Present when the Session has an ENABLED messaging binding: its channel (the sidebar row's per-channel indicator). */
|
|
1113
1755
|
messagingChannel?: MessagingChannel;
|
|
1756
|
+
/**
|
|
1757
|
+
* Company mode: the organization that owns this Session — a desk session of one of its
|
|
1758
|
+
* employees, or a session contributing to one of its tickets — read from the organization
|
|
1759
|
+
* caches. Absent for every ordinary Session. Development mode's list asks the server to
|
|
1760
|
+
* leave every such row out (`excludeOrg=1` on the list route — page and totals alike) and
|
|
1761
|
+
* still drops one that reaches it by another door; the company sidebar's 工位 group and the
|
|
1762
|
+
* tickets are where these Sessions are reached instead.
|
|
1763
|
+
*/
|
|
1764
|
+
orgId?: string;
|
|
1765
|
+
/**
|
|
1766
|
+
* Which client opened the Session, as stored on the index row: "cli" from the CLI (a
|
|
1767
|
+
* Session adopted from a legacy CLI-direct Trace included), "org" from the organization
|
|
1768
|
+
* runtime (a desk or a ticket session, and every sub-session one of those spawns), "api"
|
|
1769
|
+
* from an Agent API run (the only Sessions the API may continue), "web" otherwise. Absent
|
|
1770
|
+
* only on a row that predates the column, which reads as "web". Unlike
|
|
1771
|
+
* {@link SessionInfo.orgId} — projected from the organization caches, so it disappears with
|
|
1772
|
+
* the organization and is not read while company mode is off — this is a durable stamp on
|
|
1773
|
+
* the row: development mode's list hides an "org" Session either way.
|
|
1774
|
+
*/
|
|
1775
|
+
client?: "web" | "cli" | "org" | "api";
|
|
1114
1776
|
/**
|
|
1115
1777
|
* Background work the Session's loaded runtime still owns: command sessions running past
|
|
1116
1778
|
* their yield window (`exec_command` promotions and `run_in_background` launches) and
|
|
@@ -1130,45 +1792,241 @@ interface SessionBackgroundTasks {
|
|
|
1130
1792
|
subagents: number;
|
|
1131
1793
|
}
|
|
1132
1794
|
/**
|
|
1133
|
-
* Session list category, the
|
|
1134
|
-
*
|
|
1135
|
-
*
|
|
1795
|
+
* Session list category, the listing rule applied server-side: `archived` when the user
|
|
1796
|
+
* archived the Session, or when a program opened it (source `api`, `schedule` or `cli`) and the
|
|
1797
|
+
* user has not kept it — unarchiving keeps it; otherwise `active`. A `subagent` or `company`
|
|
1798
|
+
* Session belongs to neither, whatever its marks: the list leaves it out of every category and
|
|
1799
|
+
* every total (a parent's Agent panel and company mode's own views open them).
|
|
1136
1800
|
*/
|
|
1137
|
-
type SessionCategory = "active" |
|
|
1801
|
+
type SessionCategory = "active" | "archived";
|
|
1138
1802
|
/** Per-category totals across an Agent's whole Session list (returned when the list is requested with counts). */
|
|
1139
1803
|
type SessionCategoryCounts = Record<SessionCategory, number>;
|
|
1804
|
+
/**
|
|
1805
|
+
* GET /api/projects/:projectId/agents/:agentId/sessions. Every query parameter is optional:
|
|
1806
|
+
*
|
|
1807
|
+
* - `order`: `created` (the default) lists newest creation first; `activity` lists most recent
|
|
1808
|
+
* `lastActiveAt` first, ties broken by `sessionId` descending, both compared as plain strings
|
|
1809
|
+
* (code points, never locale collation) so a client can compute the same order.
|
|
1810
|
+
* - `limit` (1–1000) with `offset` (≥ 0): an offset page, in either order. Offsets suit only the
|
|
1811
|
+
* `created` order, which activity never reshuffles.
|
|
1812
|
+
* - `before=<lastActiveAt>,<sessionId>` with `limit`: under `order=activity` only, the rows
|
|
1813
|
+
* strictly below that cursor — the key of the last row the client holds. A row that becomes
|
|
1814
|
+
* active between pages moves above the cursor and is not served again, and no other row is
|
|
1815
|
+
* skipped (`session_state` tells the client about the moved one). 400 without
|
|
1816
|
+
* `order=activity`, beside `offset`, without `limit`, or when not a parseable stamp and a
|
|
1817
|
+
* valid id split at the first comma.
|
|
1818
|
+
* - `category`, `workspaceGroup`, `excludeOrg=1` filter before paging; `counts=1` adds the
|
|
1819
|
+
* whole-list totals below, which no cursor or offset narrows. A request with `category`,
|
|
1820
|
+
* `workspaceGroup` or `counts=1` leaves every `subagent` and `company` Session out of the page
|
|
1821
|
+
* and the totals (they are in no category); one with none of them serves every row.
|
|
1822
|
+
*/
|
|
1140
1823
|
interface SessionsResponse {
|
|
1824
|
+
/**
|
|
1825
|
+
* The page. With `excludeOrg=1` on the request, the rows an organization owns — its desk
|
|
1826
|
+
* and ticket sessions and the sub-sessions they spawned — are left out of it and of every
|
|
1827
|
+
* total below, so a caller drawing the user's own conversations is never handed a total
|
|
1828
|
+
* for rows it will not be handed. Without the flag every row is served, whichever client
|
|
1829
|
+
* created it.
|
|
1830
|
+
*/
|
|
1141
1831
|
sessions: SessionInfo[];
|
|
1142
1832
|
/** Present when the request asked for counts (`counts=1`): totals per category over the full list, not just the returned page. */
|
|
1143
1833
|
counts?: SessionCategoryCounts;
|
|
1144
1834
|
/**
|
|
1145
1835
|
* Present with `counts`: the same totals broken down by Workspace path (only paths
|
|
1146
1836
|
* with at least one Session appear). The sidebar's workspace grouping decides each
|
|
1147
|
-
* group's
|
|
1837
|
+
* group's existence and "More" from its own active share, so a group never advertises
|
|
1148
1838
|
* content that lives in other Workspaces.
|
|
1149
1839
|
*/
|
|
1150
1840
|
workspaceCounts?: Record<string, SessionCategoryCounts>;
|
|
1151
1841
|
/**
|
|
1152
1842
|
* Present with `counts`: each Workspace path's newest Session (any category), as its
|
|
1153
|
-
* `createdAt
|
|
1154
|
-
*
|
|
1155
|
-
* of their rows.
|
|
1843
|
+
* `createdAt` — the Workspace picker's "recently used", which counts every Session that
|
|
1844
|
+
* worked there.
|
|
1156
1845
|
*/
|
|
1157
1846
|
workspaceLatest?: Record<string, string>;
|
|
1847
|
+
/**
|
|
1848
|
+
* Present with `counts`: each Workspace path's newest `active` Session, as its `createdAt`
|
|
1849
|
+
* (a path holding none is absent). With `workspaceCounts` this is what lets the sidebar list
|
|
1850
|
+
* every Workspace that holds conversations and place the groups by recency before — or
|
|
1851
|
+
* without — loading any of their rows; an archived Session does not move a group it is not
|
|
1852
|
+
* shown in.
|
|
1853
|
+
*/
|
|
1854
|
+
workspaceLatestActive?: Record<string, string>;
|
|
1855
|
+
}
|
|
1856
|
+
/**
|
|
1857
|
+
* The archive page's source filter: `user` is a conversation the user archived by hand (source
|
|
1858
|
+
* `user`, or a row whose Trace has not been read yet); the other three are what a program
|
|
1859
|
+
* opened. `subagent` and `company` Sessions are never archived, so never listed.
|
|
1860
|
+
*/
|
|
1861
|
+
type ArchivedSessionSource = "user" | "api" | "schedule" | "cli";
|
|
1862
|
+
/** Query of GET /api/me/archived-sessions/groups, and the part every archive query shares. */
|
|
1863
|
+
interface ArchivedSessionsQuery {
|
|
1864
|
+
/** Case-insensitive substring of the title (the DB title, else the Trace's first-prompt title); at most 200 characters. */
|
|
1865
|
+
q?: string;
|
|
1866
|
+
source?: ArchivedSessionSource;
|
|
1867
|
+
/** One Project the user can open (404 `project_not_found` otherwise); absent = every Project they own or are a member of. */
|
|
1868
|
+
projectId?: string;
|
|
1869
|
+
}
|
|
1870
|
+
/** One group of the archive page: one Workspace of one Project. */
|
|
1871
|
+
interface ArchivedSessionGroup {
|
|
1872
|
+
projectId: string;
|
|
1873
|
+
projectName: string;
|
|
1874
|
+
/** The Workspace path, as the sidebar groups it; `temp` for the merged temporary Workspaces. */
|
|
1875
|
+
workspace: string;
|
|
1876
|
+
/** Archived Sessions in the group matching the query. */
|
|
1877
|
+
count: number;
|
|
1878
|
+
/** The newest `lastActiveAt` in the group — the order the groups come in, newest first. */
|
|
1879
|
+
latest: string;
|
|
1880
|
+
}
|
|
1881
|
+
/** GET /api/me/archived-sessions/groups. */
|
|
1882
|
+
interface ArchivedSessionGroupsResponse {
|
|
1883
|
+
groups: ArchivedSessionGroup[];
|
|
1884
|
+
/** Sum of the groups' counts. */
|
|
1885
|
+
total: number;
|
|
1886
|
+
/**
|
|
1887
|
+
* The server's time when these counts were taken (ISO). A group's batch passes it as its
|
|
1888
|
+
* filter's `until`, so it acts on the Sessions the count saw and on none that came after.
|
|
1889
|
+
*/
|
|
1890
|
+
asOf: string;
|
|
1891
|
+
}
|
|
1892
|
+
/** Query of GET /api/me/archived-sessions: one group's page, newest activity first. */
|
|
1893
|
+
interface ArchivedSessionsRowsQuery extends ArchivedSessionsQuery {
|
|
1894
|
+
projectId: string;
|
|
1895
|
+
/** The group's `workspace` (a path, or `temp`). */
|
|
1896
|
+
workspace: string;
|
|
1897
|
+
/** 1–100. */
|
|
1898
|
+
limit: number;
|
|
1899
|
+
/** `<lastActiveAt>,<sessionId>` of the last row held, as the Session list's cursor. */
|
|
1900
|
+
before?: string;
|
|
1901
|
+
}
|
|
1902
|
+
/** GET /api/me/archived-sessions. */
|
|
1903
|
+
interface ArchivedSessionsResponse {
|
|
1904
|
+
/** `title` falls back to the Trace's first-prompt title when the row has none. */
|
|
1905
|
+
sessions: SessionInfo[];
|
|
1906
|
+
hasMore: boolean;
|
|
1907
|
+
}
|
|
1908
|
+
/** What an archive-page batch acts on: explicit ids (1–500), or every archived row a filter matches. */
|
|
1909
|
+
type ArchivedSessionsBatch = {
|
|
1910
|
+
sessionIds: string[];
|
|
1911
|
+
} | {
|
|
1912
|
+
filter: ArchivedSessionsBatchFilter;
|
|
1913
|
+
};
|
|
1914
|
+
/** A batch's filter: the archive query, one group's Workspace, and the snapshot it was counted at. */
|
|
1915
|
+
interface ArchivedSessionsBatchFilter extends ArchivedSessionsQuery {
|
|
1916
|
+
workspace?: string;
|
|
1917
|
+
/**
|
|
1918
|
+
* The groups response's `asOf` the user acted on (ISO): only Sessions archived by then and
|
|
1919
|
+
* not active since are acted on, so one archived or run after the count is left alone.
|
|
1920
|
+
*/
|
|
1921
|
+
until?: string;
|
|
1922
|
+
/** Sessions left out although the filter matches them — rows unticked after Select all (1–500). */
|
|
1923
|
+
exclude?: string[];
|
|
1924
|
+
}
|
|
1925
|
+
/** POST /api/me/archived-sessions/unarchive and /delete. */
|
|
1926
|
+
interface ArchivedSessionsBatchResponse {
|
|
1927
|
+
/**
|
|
1928
|
+
* Sessions acted on. Unarchive counts only the ones that were archived. Delete counts every
|
|
1929
|
+
* named one; a filter's delete leaves a running Session alone (it is not aborted) and does not
|
|
1930
|
+
* count it.
|
|
1931
|
+
*/
|
|
1932
|
+
done: number;
|
|
1933
|
+
/** Ids that name nothing the user can open (the ids form only; a filter never reports any). */
|
|
1934
|
+
missing: string[];
|
|
1935
|
+
}
|
|
1936
|
+
/**
|
|
1937
|
+
* One page request inside POST /api/projects/:p/sessions/batch — the same knobs the
|
|
1938
|
+
* Agent-level list takes, carried per entry so one call can stand in for a whole sidebar
|
|
1939
|
+
* reload (one first page per Agent, plus every other page pair already open).
|
|
1940
|
+
*/
|
|
1941
|
+
interface SessionBatchPageRequest {
|
|
1942
|
+
agentId: string;
|
|
1943
|
+
/** Rows per page, 1–1000. */
|
|
1944
|
+
limit: number;
|
|
1945
|
+
/** `activity`: last activity first — the sidebar's order. Omitted: creation order. */
|
|
1946
|
+
order?: "created" | "activity";
|
|
1947
|
+
/** Rows to skip from the top (default 0). Not beside `before`. */
|
|
1948
|
+
offset?: number;
|
|
1949
|
+
/**
|
|
1950
|
+
* Activity order only: rows strictly below this cursor — the last row of the previous page
|
|
1951
|
+
* (`lastActiveAt` + `sessionId`, the pair the list endpoint's `before` param carries).
|
|
1952
|
+
*/
|
|
1953
|
+
before?: {
|
|
1954
|
+
lastActiveAt: string;
|
|
1955
|
+
sessionId: string;
|
|
1956
|
+
};
|
|
1957
|
+
category?: SessionCategory;
|
|
1958
|
+
workspaceGroup?: string;
|
|
1959
|
+
/**
|
|
1960
|
+
* Totals per category over the Agent's whole list, with the per-Workspace counts and newest
|
|
1961
|
+
* stamps beside them (`counts=1` on the Agent-level list).
|
|
1962
|
+
*/
|
|
1963
|
+
withCounts?: boolean;
|
|
1964
|
+
/** The user's own rows only: leave an organization's own sessions out of page and totals. */
|
|
1965
|
+
excludeOrg?: boolean;
|
|
1158
1966
|
}
|
|
1159
|
-
/**
|
|
1967
|
+
/**
|
|
1968
|
+
* One entry's answer. `ok: false` is a real answer about THAT Agent, never about the batch:
|
|
1969
|
+
* `absent` is an Agent this server does not host (its rows come from the machine that does),
|
|
1970
|
+
* `error` is a failure to answer at all — which the caller must not read as "no rows".
|
|
1971
|
+
*/
|
|
1972
|
+
type SessionBatchResult = ({
|
|
1973
|
+
agentId: string;
|
|
1974
|
+
ok: true;
|
|
1975
|
+
} & SessionsResponse) | {
|
|
1976
|
+
agentId: string;
|
|
1977
|
+
ok: false;
|
|
1978
|
+
reason: "absent" | "error";
|
|
1979
|
+
};
|
|
1980
|
+
interface SessionsBatchRequest {
|
|
1981
|
+
requests: SessionBatchPageRequest[];
|
|
1982
|
+
}
|
|
1983
|
+
interface SessionsBatchResponse {
|
|
1984
|
+
/** One entry per requested page, in request order (repeated Agent ids stay repeated). */
|
|
1985
|
+
results: SessionBatchResult[];
|
|
1986
|
+
}
|
|
1987
|
+
/** Server directory browsing (the Workspace picker): starts from the home directory by default, can navigate up to the root. */
|
|
1160
1988
|
interface DirEntryInfo {
|
|
1161
1989
|
name: string;
|
|
1162
|
-
/** Absolute path of this
|
|
1990
|
+
/** Absolute path of this entry (a folder's can be submitted directly as a Workspace). */
|
|
1163
1991
|
path: string;
|
|
1992
|
+
/**
|
|
1993
|
+
* `file` for anything that is not a folder (a symlink counts as what it points to). Absent
|
|
1994
|
+
* means a folder: a machine listed over ssh reports folders only.
|
|
1995
|
+
*/
|
|
1996
|
+
kind?: "dir" | "file";
|
|
1997
|
+
/** Last modification, epoch milliseconds; absent when unknown (listings over ssh, an entry stat could not reach). */
|
|
1998
|
+
mtime?: number;
|
|
1999
|
+
/** Hidden by the machine's own rules beyond the dot-name convention (Windows hidden/system attribute). */
|
|
2000
|
+
hidden?: true;
|
|
2001
|
+
}
|
|
2002
|
+
/** A storage location the machine offers beside its folders: a Windows drive, a macOS volume, a Linux root or mount. */
|
|
2003
|
+
interface DirLocation {
|
|
2004
|
+
/** Absolute path it opens (`C:\`, `/`, `/Volumes/USB`, `/media/me/USB`, `/mnt/c`). */
|
|
2005
|
+
path: string;
|
|
2006
|
+
kind: "drive" | "removable" | "network" | "optical" | "volume" | "root";
|
|
2007
|
+
/** The machine's own name for it (volume label, volume name, share `\\nas\media`, WSL `C:`); absent when none. */
|
|
2008
|
+
label?: string;
|
|
2009
|
+
}
|
|
2010
|
+
/** The platform's standard folders as that machine resolves them; only those that exist. */
|
|
2011
|
+
interface DirStandardFolders {
|
|
2012
|
+
desktop?: string;
|
|
2013
|
+
documents?: string;
|
|
2014
|
+
downloads?: string;
|
|
2015
|
+
pictures?: string;
|
|
1164
2016
|
}
|
|
1165
2017
|
interface DirListResponse {
|
|
1166
2018
|
/** Absolute path of the current directory (realpath). */
|
|
1167
2019
|
path: string;
|
|
1168
2020
|
/** Absolute path of the parent directory; null when already at the root. */
|
|
1169
2021
|
parent: string | null;
|
|
1170
|
-
/**
|
|
2022
|
+
/** Entries sorted by name, hidden ones included (the picker drops them). */
|
|
1171
2023
|
entries: DirEntryInfo[];
|
|
2024
|
+
/** The listed machine's `process.platform`; absent for a machine listed over ssh. */
|
|
2025
|
+
platform?: string;
|
|
2026
|
+
/** Home request with `places=1` only. */
|
|
2027
|
+
standardFolders?: DirStandardFolders;
|
|
2028
|
+
/** Home request with `places=1` only, in the order the sidebar lists them. */
|
|
2029
|
+
locations?: DirLocation[];
|
|
1172
2030
|
}
|
|
1173
2031
|
/** One Skill found in a picked directory: metadata plus which of the two layouts it came from. */
|
|
1174
2032
|
interface DirectorySkillItem extends SkillMetadataItem {
|
|
@@ -1194,12 +2052,29 @@ interface SessionCreateRequest {
|
|
|
1194
2052
|
workspace?: string;
|
|
1195
2053
|
/** Defaults to allow-all. */
|
|
1196
2054
|
approvalMode?: ApprovalMode;
|
|
2055
|
+
/**
|
|
2056
|
+
* The Session's sandbox policy; either half omitted takes the server's Sandbox settings.
|
|
2057
|
+
* A non-admin may not pick anything looser than those settings (403 `sandbox_forbidden`).
|
|
2058
|
+
*/
|
|
2059
|
+
sandbox?: Partial<SessionSandbox>;
|
|
1197
2060
|
/**
|
|
1198
2061
|
* Creating-client hint stored on the Session row: "cli" when the CLI creates the
|
|
1199
|
-
* Session through the API
|
|
1200
|
-
*
|
|
2062
|
+
* Session through the API, "org" when the organization runtime opened it (a desk or a
|
|
2063
|
+
* ticket session — company mode's own, kept out of development mode's lists whether or
|
|
2064
|
+
* not the organization still exists); defaults to "web". A REQUEST may send only "web" or
|
|
2065
|
+
* "cli": the runtime writes "org" by calling the service directly, so no caller can claim
|
|
2066
|
+
* an organization's provenance for its own Session. Lists serve every row regardless of
|
|
2067
|
+
* client unless asked for the user's own rows only (`excludeOrg=1`), which is what
|
|
2068
|
+
* development mode's session list asks for.
|
|
2069
|
+
*/
|
|
2070
|
+
client?: "web" | "cli" | "org";
|
|
2071
|
+
/**
|
|
2072
|
+
* The Session's source, when it is not a person's conversation: only `cli` is accepted from
|
|
2073
|
+
* a client (`penguin run` sends it); every other source is the server's own to write, and
|
|
2074
|
+
* absent means `user`. The retired `benchmark` is still accepted, as `cli`, until 0.3.0, for
|
|
2075
|
+
* an older CLI or Web App that still sends it.
|
|
1201
2076
|
*/
|
|
1202
|
-
|
|
2077
|
+
source?: "cli";
|
|
1203
2078
|
}
|
|
1204
2079
|
interface SessionCreateResponse {
|
|
1205
2080
|
session: SessionInfo;
|
|
@@ -1227,6 +2102,11 @@ interface SessionResponse {
|
|
|
1227
2102
|
}
|
|
1228
2103
|
interface SessionPatchRequest {
|
|
1229
2104
|
approvalMode?: ApprovalMode;
|
|
2105
|
+
/**
|
|
2106
|
+
* Change this Session's sandbox policy; applies from its next command. A non-admin may not
|
|
2107
|
+
* pick anything looser than the server's Sandbox settings (403 `sandbox_forbidden`).
|
|
2108
|
+
*/
|
|
2109
|
+
sandbox?: Partial<SessionSandbox>;
|
|
1230
2110
|
/**
|
|
1231
2111
|
* Pin this Session's thinking level (`none | low | medium | high | xhigh | max`, anything else
|
|
1232
2112
|
* is a 400). It replaces the Agent-config fallback for this Session and applies from the
|
|
@@ -1235,7 +2115,11 @@ interface SessionPatchRequest {
|
|
|
1235
2115
|
* is no unpin: the picker only offers concrete levels.
|
|
1236
2116
|
*/
|
|
1237
2117
|
thinkingLevel?: ThinkingLevelName;
|
|
1238
|
-
/**
|
|
2118
|
+
/**
|
|
2119
|
+
* `true` archives (clears the keep mark); `false` unarchives and writes the keep mark, so a
|
|
2120
|
+
* background Session stays in the sidebar through later runs. Announced as `session_archived`.
|
|
2121
|
+
* 409 `session_not_listed` on a `subagent` or `company` Session, which is in no list.
|
|
2122
|
+
*/
|
|
1239
2123
|
archived?: boolean;
|
|
1240
2124
|
/** Manual rename; non-empty string, overrides the auto-generated title. */
|
|
1241
2125
|
title?: string;
|
|
@@ -1271,7 +2155,10 @@ interface MessagesLiveTail {
|
|
|
1271
2155
|
* only; the parameterless full read never carries it). A window is a run of whole
|
|
1272
2156
|
* message-bearing units — one unit = one Task in the Web reducer's sense, opened by a
|
|
1273
2157
|
* main-session user prompt — cut so that no pairing (tool_call/output), compaction span
|
|
1274
|
-
* or steering group ever splits across windows.
|
|
2158
|
+
* or steering group ever splits across windows. Besides the unit count, a window stops
|
|
2159
|
+
* before the unit that would take its serialized messages past 4 MiB, but always holds at
|
|
2160
|
+
* least one unit; such a window carries `before` like any other, with fewer units than
|
|
2161
|
+
* asked for.
|
|
1275
2162
|
*/
|
|
1276
2163
|
interface MessagesPageInfo {
|
|
1277
2164
|
/**
|
|
@@ -1307,9 +2194,26 @@ interface MessagesPageInfo {
|
|
|
1307
2194
|
sessionTokens: number;
|
|
1308
2195
|
contextTokens: number;
|
|
1309
2196
|
};
|
|
2197
|
+
/**
|
|
2198
|
+
* The model of the context this window starts in — what the `session_meta` heading that
|
|
2199
|
+
* context's Trace file names. A Session can switch models between contexts, and a window
|
|
2200
|
+
* that starts partway into one does not hold that record: the client seeds it, so the Tasks
|
|
2201
|
+
* ahead of the window's first `session_meta` have their model, and a switch further down the
|
|
2202
|
+
* window is told from a plain rotation. Absent when the Session has no Trace yet.
|
|
2203
|
+
*/
|
|
2204
|
+
contextModel?: ModelRefDto;
|
|
1310
2205
|
}
|
|
1311
2206
|
/** Message history: the full messages and events from concatenating all of this Session's Trace files in order (excludes partial_*). */
|
|
1312
2207
|
interface MessagesResponse {
|
|
2208
|
+
/**
|
|
2209
|
+
* On windowed requests, images are served by reference: in every record that carries a
|
|
2210
|
+
* `tracePosition`, an inline PNG / JPEG / GIF / WebP `data:` URL — a user `image_url`, or
|
|
2211
|
+
* an entry of a tool output's `images` — is replaced by
|
|
2212
|
+
* `/api/sessions/<sessionId>/trace-image?file=<fileIndex>&ordinal=<ordinal>[&i=<k>]`
|
|
2213
|
+
* (`i` = the index into `images`), an immutable, access-checked image response. Expanded
|
|
2214
|
+
* subagent messages, held inputs not yet in the Trace, other image types and the
|
|
2215
|
+
* parameterless full read keep their data URLs.
|
|
2216
|
+
*/
|
|
1313
2217
|
messages: HistoryMessage[];
|
|
1314
2218
|
/**
|
|
1315
2219
|
* Present only while the Session is running/compacting: the in-progress stream tail
|
|
@@ -1392,6 +2296,32 @@ interface GoalResponse {
|
|
|
1392
2296
|
/** The Session's most recent goal run; null if it never ran one. */
|
|
1393
2297
|
goal: GoalStateView | null;
|
|
1394
2298
|
}
|
|
2299
|
+
/**
|
|
2300
|
+
* `POST /api/sessions/:sessionId/switch-model`: switch this Session to another model in place.
|
|
2301
|
+
* The running context is closed on the model it ran on, then the next one opens on the target.
|
|
2302
|
+
*
|
|
2303
|
+
* - **202** {@link TaskCreateResponse} — the switch streams, the Session status `compacting`.
|
|
2304
|
+
* A context with a completed turn is closed by an ordinary `manual` compaction pair (always
|
|
2305
|
+
* summarize); one without — just compacted, or its first request never finished — has
|
|
2306
|
+
* nothing to summarize and streams no pair. Then come the new context's opener records
|
|
2307
|
+
* and, last, its `session_meta`: its `provider` / `model_id` name the model the Session now
|
|
2308
|
+
* runs on, the Session reads report that pair from this record on, and `task_state` turns
|
|
2309
|
+
* idle after it.
|
|
2310
|
+
* A compaction that ends other than `completed` means no switch — no `session_meta` follows
|
|
2311
|
+
* and the Session keeps its model.
|
|
2312
|
+
* - **200** {@link SessionResponse} — a Session that never ran has no context to close: it
|
|
2313
|
+
* switched inside the request, and nothing is streamed.
|
|
2314
|
+
* - **409**, one code per refusal, before any event: `task_in_progress` / `compacting` (busy),
|
|
2315
|
+
* `same_model`, `model_not_configured` (the target is not in the Project config),
|
|
2316
|
+
* `model_unavailable` (its client cannot be constructed, e.g. no credential), and
|
|
2317
|
+
* `compaction_not_configured`.
|
|
2318
|
+
*/
|
|
2319
|
+
interface SessionSwitchModelRequest {
|
|
2320
|
+
/** Provider group of the target model. */
|
|
2321
|
+
provider: string;
|
|
2322
|
+
/** Upstream model_id of the target model. */
|
|
2323
|
+
modelId: string;
|
|
2324
|
+
}
|
|
1395
2325
|
interface TaskCreateResponse {
|
|
1396
2326
|
/** Current actual session_id: a Trace-less invalid Session self-heals and returns a new id; the frontend updates its route accordingly. */
|
|
1397
2327
|
sessionId: string;
|
|
@@ -1593,6 +2523,20 @@ interface MessagingRuntimeStatus {
|
|
|
1593
2523
|
at: string;
|
|
1594
2524
|
detail: string;
|
|
1595
2525
|
};
|
|
2526
|
+
/**
|
|
2527
|
+
* Since when (ISO 8601) the bot has been HOLDING replies it could not deliver yet, to send
|
|
2528
|
+
* them with the chat's next inbound message; absent while nothing is held. WeChat only: the
|
|
2529
|
+
* platform accepts a bot's messages only for a while after the user's last one, and only
|
|
2530
|
+
* about ten per message, so a long run or a quiet user leaves replies waiting rather than
|
|
2531
|
+
* lost.
|
|
2532
|
+
*
|
|
2533
|
+
* Not a failure, and deliberately not `lastDeliveryError`: nothing is broken and nobody has
|
|
2534
|
+
* to act beyond what the panel says — message the bot in WeChat and the held replies arrive
|
|
2535
|
+
* first. Cleared the moment they have been delivered. Unlike the fields above it is not
|
|
2536
|
+
* scoped to one connection: held replies are stored, so a backlog from before a restart is
|
|
2537
|
+
* reported again as soon as the connection opens.
|
|
2538
|
+
*/
|
|
2539
|
+
heldReplySince?: string;
|
|
1596
2540
|
}
|
|
1597
2541
|
/**
|
|
1598
2542
|
* What a messaging binding carries whatever channel it is: the connection intent, the three
|
|
@@ -2086,11 +3030,17 @@ type ServerEvent =
|
|
|
2086
3030
|
* that has now run from one that never has — a first run would otherwise settle back into the
|
|
2087
3031
|
* blank "never ran" row the client still believes in.
|
|
2088
3032
|
*
|
|
3033
|
+
* `projectId` names the Session's Project: a list showing one Project ignores another's flips
|
|
3034
|
+
* without a request, and a flip for a Session of its own Project that it holds no row for is a
|
|
3035
|
+
* row it is missing — one that became active below its activity cursor (see SessionsResponse) —
|
|
3036
|
+
* which it fetches by id.
|
|
3037
|
+
*
|
|
2089
3038
|
* Published only to the user channels of the Project's owner and members.
|
|
2090
3039
|
*/
|
|
2091
3040
|
| {
|
|
2092
3041
|
type: "session_state";
|
|
2093
3042
|
sessionId: string;
|
|
3043
|
+
projectId: string;
|
|
2094
3044
|
state: SessionStatus;
|
|
2095
3045
|
lastActiveAt: string;
|
|
2096
3046
|
hasTrace: boolean;
|
|
@@ -2108,6 +3058,19 @@ type ServerEvent =
|
|
|
2108
3058
|
processes: number;
|
|
2109
3059
|
subagents: number;
|
|
2110
3060
|
}
|
|
3061
|
+
/**
|
|
3062
|
+
* A Session's count of tool calls waiting for a person's approval changed: a call was
|
|
3063
|
+
* escalated (every call under always-ask, rw/unknown calls under read-only), answered, or
|
|
3064
|
+
* denied by an interrupt. The count is the row's `pendingApprovalCount` as it stands after
|
|
3065
|
+
* the change, zeros included, so a list moves its mark without refetching; the calls
|
|
3066
|
+
* themselves are on the Session's own stream (`approval_request`, replayed on subscribe).
|
|
3067
|
+
* Published to the user channels of the Project's owner and members, like `session_state`.
|
|
3068
|
+
*/
|
|
3069
|
+
| {
|
|
3070
|
+
type: "session_approvals";
|
|
3071
|
+
sessionId: string;
|
|
3072
|
+
count: number;
|
|
3073
|
+
}
|
|
2111
3074
|
/** Last-Event-ID has been evicted from the buffer: the frontend should re-fetch the history endpoint before continuing to consume this connection. */
|
|
2112
3075
|
| {
|
|
2113
3076
|
type: "resync_required";
|
|
@@ -2131,14 +3094,67 @@ type ServerEvent =
|
|
|
2131
3094
|
type: "web_updated";
|
|
2132
3095
|
rev: string;
|
|
2133
3096
|
}
|
|
2134
|
-
/**
|
|
3097
|
+
/**
|
|
3098
|
+
* A Session now exists. On the user channel for every creation — the CLI, another tab,
|
|
3099
|
+
* a schedule, an agent spawning a child — so the list learns about rows it did not make;
|
|
3100
|
+
* and on the parent Session's channel for a subagent, which no list shows. `source` is what
|
|
3101
|
+
* the new Session's meta records, and it tells a client which list, if any, the row joins.
|
|
3102
|
+
*/
|
|
2135
3103
|
| {
|
|
2136
3104
|
type: "session_created";
|
|
2137
3105
|
projectId: string;
|
|
2138
3106
|
agentId: string;
|
|
2139
3107
|
sessionId: string;
|
|
2140
3108
|
source: SessionSource;
|
|
2141
|
-
}
|
|
3109
|
+
}
|
|
3110
|
+
/**
|
|
3111
|
+
* The user's listing decision on one Session changed (PATCH `archived`, the archive page's
|
|
3112
|
+
* batch unarchive): an archived row leaves the sidebar, an unarchived one joins it. One per
|
|
3113
|
+
* Session, to the Project's users.
|
|
3114
|
+
*/
|
|
3115
|
+
| {
|
|
3116
|
+
type: "session_archived";
|
|
3117
|
+
sessionId: string;
|
|
3118
|
+
projectId: string;
|
|
3119
|
+
agentId: string;
|
|
3120
|
+
archived: boolean;
|
|
3121
|
+
}
|
|
3122
|
+
/**
|
|
3123
|
+
* A Session was deleted (DELETE, the subagent children deleted with it, the archive page's
|
|
3124
|
+
* batch delete): every client drops the row. One per Session, to the Project's users.
|
|
3125
|
+
*/
|
|
3126
|
+
| {
|
|
3127
|
+
type: "session_deleted";
|
|
3128
|
+
sessionId: string;
|
|
3129
|
+
projectId: string;
|
|
3130
|
+
} | ScheduleServerEvent | GoalServerEvent | CompanyServerEvent | BuiltinBrowserServerEvent | MachineServerEvent;
|
|
3131
|
+
/**
|
|
3132
|
+
* The machines' two events on the user channel, published to admins only — the Machines page,
|
|
3133
|
+
* and the `/server/<id>` proxy everything else about a machine goes through, are admin-only.
|
|
3134
|
+
*/
|
|
3135
|
+
type MachineServerEvent =
|
|
3136
|
+
/**
|
|
3137
|
+
* Something the machines list reports changed — a job queued, started, moved to its next
|
|
3138
|
+
* step, logged a line or ended; a connection was held or dropped; a reconnect began, failed
|
|
3139
|
+
* or succeeded; a machine joined or left a Project; a checkout's install image started or
|
|
3140
|
+
* finished building. No payload: a page re-reads `GET …/machines`, which is its one account
|
|
3141
|
+
* of every machine. Coalesced, so a burst of log lines costs a few reads, not one per line.
|
|
3142
|
+
*/
|
|
3143
|
+
{
|
|
3144
|
+
type: "machines_changed";
|
|
3145
|
+
}
|
|
3146
|
+
/**
|
|
3147
|
+
* One of a connected machine's own user-channel events, relayed by this server from that
|
|
3148
|
+
* machine's `GET /api/events` (machines/event-relay.ts). The page holds one event stream to
|
|
3149
|
+
* this server whatever the number of machines: a stream per machine made five connected
|
|
3150
|
+
* machines take the browser's whole HTTP/1.1 allowance of six connections to one origin, and
|
|
3151
|
+
* every other request of the page then waited behind them for good.
|
|
3152
|
+
*/
|
|
3153
|
+
| {
|
|
3154
|
+
type: "machine_event";
|
|
3155
|
+
machineId: string;
|
|
3156
|
+
event: ServerEvent;
|
|
3157
|
+
};
|
|
2142
3158
|
/** Goal-mode progress on the session channel (the chat page drives its goal banner from these). */
|
|
2143
3159
|
type GoalServerEvent =
|
|
2144
3160
|
/** A goal run began (published before the first round). */
|
|
@@ -2181,6 +3197,20 @@ type ScheduleServerEvent =
|
|
|
2181
3197
|
agentId: string;
|
|
2182
3198
|
name: string;
|
|
2183
3199
|
sessionId: string;
|
|
3200
|
+
}
|
|
3201
|
+
/** A workflow of the Agent was (re)loaded — its folder changed, a reload was requested, or a version was restored. */
|
|
3202
|
+
| {
|
|
3203
|
+
type: "workflow_updated";
|
|
3204
|
+
projectId: string;
|
|
3205
|
+
agentId: string;
|
|
3206
|
+
workflow: WorkflowInfo;
|
|
3207
|
+
}
|
|
3208
|
+
/** A workflow's folder is gone — removed from the Web App or deleted on disk. */
|
|
3209
|
+
| {
|
|
3210
|
+
type: "workflow_removed";
|
|
3211
|
+
projectId: string;
|
|
3212
|
+
agentId: string;
|
|
3213
|
+
workflowId: string;
|
|
2184
3214
|
};
|
|
2185
3215
|
interface TraceFileInfo {
|
|
2186
3216
|
/** Trace file index (one file corresponds to one complete model context). */
|
|
@@ -2263,7 +3293,10 @@ interface TraceEventsResponse {
|
|
|
2263
3293
|
events: OmniMessage[];
|
|
2264
3294
|
offset: number;
|
|
2265
3295
|
limit: number;
|
|
2266
|
-
/**
|
|
3296
|
+
/**
|
|
3297
|
+
* Record count of the file (basis for pagination), in the ordinals `tracePosition` and the
|
|
3298
|
+
* analysis' `messageFrom` / `messageTo` use: malformed lines are not records.
|
|
3299
|
+
*/
|
|
2267
3300
|
total: number;
|
|
2268
3301
|
}
|
|
2269
3302
|
/** Duration span of a single LLM Request (request_begin/request_end paired by proximity). */
|
|
@@ -2415,7 +3448,11 @@ interface WorkspaceFilesResponse {
|
|
|
2415
3448
|
path: string;
|
|
2416
3449
|
entries: WorkspaceFileEntry[];
|
|
2417
3450
|
}
|
|
2418
|
-
/**
|
|
3451
|
+
/**
|
|
3452
|
+
* Write one Workspace file whole (the Upload button, a drop, and the Files panel's editor). A
|
|
3453
|
+
* write answers 204 with the written file's version in `ETag` — the marker the next conditional
|
|
3454
|
+
* write of the same file carries, so an editor can keep editing after a save.
|
|
3455
|
+
*/
|
|
2419
3456
|
interface FilesWriteRequest {
|
|
2420
3457
|
/** The entire file, base64-encoded (≤14MB decoded). */
|
|
2421
3458
|
dataBase64: string;
|
|
@@ -2430,6 +3467,58 @@ interface FilesWriteRequest {
|
|
|
2430
3467
|
*/
|
|
2431
3468
|
ifVersion?: string;
|
|
2432
3469
|
}
|
|
3470
|
+
/** Move or rename one Workspace file or folder (the Files panel's context menu). */
|
|
3471
|
+
interface FilesMoveRequest {
|
|
3472
|
+
/** Source path, relative to the Workspace root. */
|
|
3473
|
+
from: string;
|
|
3474
|
+
/** Destination path, relative to the Workspace root. Its parent directory is created when missing. */
|
|
3475
|
+
to: string;
|
|
3476
|
+
/**
|
|
3477
|
+
* Move precondition, read exactly like {@link FilesWriteRequest.ifVersion}: the marker the
|
|
3478
|
+
* caller got from this file's `ETag` on `GET files/content`, which the file must still
|
|
3479
|
+
* carry. It differs on only one point — the marker guards the **source**. The destination
|
|
3480
|
+
* has none, because the caller never read it, which is why an occupied destination is
|
|
3481
|
+
* refused with 409 `target_exists` rather than overwritten.
|
|
3482
|
+
*
|
|
3483
|
+
* A directory `from` takes none, and one sent with it is a 400: a directory carries no
|
|
3484
|
+
* single version marker, so no precondition can be stated for it. A folder moves whole and
|
|
3485
|
+
* unconditionally — nothing is lost that way, since whatever the Agent wrote into it meanwhile
|
|
3486
|
+
* moves with it — and is refused only when the destination is occupied or lies inside it.
|
|
3487
|
+
*/
|
|
3488
|
+
ifVersion?: string;
|
|
3489
|
+
}
|
|
3490
|
+
/**
|
|
3491
|
+
* Create one empty text file or one folder in a Workspace (the Files panel's New menu). Missing
|
|
3492
|
+
* parent directories are created as a write creates them. Anything already at `path` — a file,
|
|
3493
|
+
* a folder or a link — is refused with 409 `target_exists` and nothing is written.
|
|
3494
|
+
*/
|
|
3495
|
+
interface FilesCreateRequest {
|
|
3496
|
+
/** The new entry's path, relative to the Workspace root. */
|
|
3497
|
+
path: string;
|
|
3498
|
+
kind: "file" | "dir";
|
|
3499
|
+
}
|
|
3500
|
+
/**
|
|
3501
|
+
* One Workspace search match. `kind`, `sizeBytes` and `mtime` are named and typed exactly as
|
|
3502
|
+
* {@link WorkspaceFileEntry} names them: a hit is drawn by the same row renderer as a tree
|
|
3503
|
+
* entry, and it can only render identically if it carries the same fields.
|
|
3504
|
+
*/
|
|
3505
|
+
interface WorkspaceSearchHit {
|
|
3506
|
+
/** Workspace-relative, "/"-separated, with no leading "./" (a tree entry's `name` is only its last segment). */
|
|
3507
|
+
path: string;
|
|
3508
|
+
kind: "dir" | "file";
|
|
3509
|
+
sizeBytes: number;
|
|
3510
|
+
mtime: string;
|
|
3511
|
+
}
|
|
3512
|
+
interface WorkspaceSearchResponse {
|
|
3513
|
+
/** Shallowest first, then directories before files, then by name — the order the breadth-first walk produced. */
|
|
3514
|
+
hits: WorkspaceSearchHit[];
|
|
3515
|
+
/**
|
|
3516
|
+
* A cap stopped the walk (200 hits, or 20000 directory entries visited), so this is a
|
|
3517
|
+
* partial list. Breadth-first is what makes that degrade well: the hits that survive
|
|
3518
|
+
* truncation are the shallowest ones, not the ones that happened to be enumerated first.
|
|
3519
|
+
*/
|
|
3520
|
+
truncated: boolean;
|
|
3521
|
+
}
|
|
2433
3522
|
/** Batch file existence check (message file cards only list files that actually exist). */
|
|
2434
3523
|
interface FilesStatRequest {
|
|
2435
3524
|
/** Paths relative to the Workspace root (≤100 items, each ≤512 characters). */
|
|
@@ -2518,6 +3607,19 @@ interface TraceAnalysisResponse {
|
|
|
2518
3607
|
* scope every total here shares). Absent exactly when the turns carry no `cost`.
|
|
2519
3608
|
*/
|
|
2520
3609
|
cost?: number;
|
|
3610
|
+
/**
|
|
3611
|
+
* `cost` split by pricing bucket: every Request's Tokens at the rates and tier its share of
|
|
3612
|
+
* `cost` was priced at, summed per bucket over the file. Present exactly when `cost` is; the
|
|
3613
|
+
* turns carry no split.
|
|
3614
|
+
*/
|
|
3615
|
+
costParts?: CostParts;
|
|
3616
|
+
/**
|
|
3617
|
+
* The model's context window as the file's head `session_meta` records it
|
|
3618
|
+
* (`model_context_window`), for the context ring. The panel no longer reads every event, so the
|
|
3619
|
+
* analysis carries it; absent when the head records none (an older server, or a file without
|
|
3620
|
+
* one), and the panel then falls back as it always has.
|
|
3621
|
+
*/
|
|
3622
|
+
modelContextWindow?: number | string;
|
|
2521
3623
|
requests: RequestSpan[];
|
|
2522
3624
|
/** Token / duration aggregated per Task (used directly by the Trace page's context ring and per-turn TPS). */
|
|
2523
3625
|
tasks: TraceTaskStats[];
|
|
@@ -2610,6 +3712,17 @@ interface TraceImportResponse {
|
|
|
2610
3712
|
date: string;
|
|
2611
3713
|
}
|
|
2612
3714
|
type UsageGroupBy = "date" | "agent" | "model" | "session";
|
|
3715
|
+
/**
|
|
3716
|
+
* A cost split by the three pricing buckets, in USD: cached input (`cacheRead`), uncached input
|
|
3717
|
+
* (`cacheWrite`, input Tokens on a cache miss) and output. Each part is its bucket's Tokens at the
|
|
3718
|
+
* rate the whole cost was priced at, so the three sum to the cost they accompany (up to
|
|
3719
|
+
* floating-point rounding).
|
|
3720
|
+
*/
|
|
3721
|
+
interface CostParts {
|
|
3722
|
+
cacheRead: number;
|
|
3723
|
+
cacheWrite: number;
|
|
3724
|
+
output: number;
|
|
3725
|
+
}
|
|
2613
3726
|
interface UsageBucket {
|
|
2614
3727
|
total: number;
|
|
2615
3728
|
requests: number;
|
|
@@ -2629,6 +3742,12 @@ interface UsageGroupRow {
|
|
|
2629
3742
|
total: number;
|
|
2630
3743
|
requests: number;
|
|
2631
3744
|
cost: number | null;
|
|
3745
|
+
/**
|
|
3746
|
+
* `cost` split by pricing bucket, each record at the same rates, tier and promotion that
|
|
3747
|
+
* priced it in `cost`. Present exactly when `cost` is not null; a row's unpriced usage is in
|
|
3748
|
+
* neither.
|
|
3749
|
+
*/
|
|
3750
|
+
costParts?: CostParts;
|
|
2632
3751
|
hasUncosted: boolean;
|
|
2633
3752
|
}
|
|
2634
3753
|
/** Time-series precision for the usage series (`granularity` query parameter). `minute` requires the `fromTs`/`toTs` window bounds. */
|
|
@@ -2703,13 +3822,22 @@ interface UsageErrorCount {
|
|
|
2703
3822
|
kind: string;
|
|
2704
3823
|
count: number;
|
|
2705
3824
|
}
|
|
2706
|
-
/**
|
|
3825
|
+
/**
|
|
3826
|
+
* One row of the stats center's error panel table: the records of one calendar day that share
|
|
3827
|
+
* a source, code, kind and message. The day is the viewer's when the request carried
|
|
3828
|
+
* `utcOffsetMinutes`, and the server's own otherwise.
|
|
3829
|
+
*/
|
|
2707
3830
|
interface UsageErrorItem {
|
|
3831
|
+
/** The latest of the records this row stands for. */
|
|
2708
3832
|
ts: string;
|
|
2709
3833
|
source: string;
|
|
2710
3834
|
code: string;
|
|
2711
3835
|
kind: string;
|
|
2712
3836
|
message: string;
|
|
3837
|
+
/** How many records this row stands for (the panel's "×N"). */
|
|
3838
|
+
count: number;
|
|
3839
|
+
/** The earliest of them; equal to `ts` for a single record. */
|
|
3840
|
+
firstTs: string;
|
|
2713
3841
|
}
|
|
2714
3842
|
/**
|
|
2715
3843
|
* Server-side error capture stats: not affected by the model
|
|
@@ -2720,14 +3848,16 @@ interface UsageErrorItem {
|
|
|
2720
3848
|
* items.
|
|
2721
3849
|
*/
|
|
2722
3850
|
interface UsageErrors {
|
|
2723
|
-
/** Filtered
|
|
3851
|
+
/** Filtered record count — also what a clear of the same filter takes (see {@link UsageErrorsClearResponse}). */
|
|
2724
3852
|
total: number;
|
|
2725
3853
|
/** Count of unexpected ones (500 / runtime exceptions) among them — the part the frontend highlights. */
|
|
2726
3854
|
unexpected: number;
|
|
2727
3855
|
/** The most frequent source · code (null when there are no errors). */
|
|
2728
3856
|
topCode: UsageErrorCount | null;
|
|
2729
|
-
/** Most recent N
|
|
3857
|
+
/** Most recent N rows (reverse chronological) — the first page; older ones come from `GET /usage/errors`. */
|
|
2730
3858
|
recent: UsageErrorItem[];
|
|
3859
|
+
/** How many rows the table has for this filter (records folded per {@link UsageErrorItem}) — what the pager counts. */
|
|
3860
|
+
rows: number;
|
|
2731
3861
|
}
|
|
2732
3862
|
/**
|
|
2733
3863
|
* GET /api/projects/:projectId/usage/errors — one page of the error detail table, newest
|
|
@@ -2737,12 +3867,15 @@ interface UsageErrors {
|
|
|
2737
3867
|
* or neither), so a page never widens what the summary counted, plus an optional `kind`
|
|
2738
3868
|
* ({@link UsageErrorKind}) narrowing to one of the two categories — which
|
|
2739
3869
|
* is how the cost-center badge asks "are there unexpected errors, and how new is the newest"
|
|
2740
|
-
* with `limit=1` instead of pulling the whole dashboard aggregate.
|
|
3870
|
+
* with `limit=1` instead of pulling the whole dashboard aggregate. `utcOffsetMinutes` (minutes
|
|
3871
|
+
* east of UTC, the dashboard takes it too) says whose calendar day a row's records share.
|
|
2741
3872
|
*/
|
|
2742
3873
|
interface UsageErrorsPage {
|
|
2743
3874
|
items: UsageErrorItem[];
|
|
2744
|
-
/** Filtered
|
|
3875
|
+
/** Filtered record count — the occurrences, which is what the cost-center badge counts. */
|
|
2745
3876
|
total: number;
|
|
3877
|
+
/** Filtered row count (records folded per {@link UsageErrorItem}), so the caller knows when it has reached the end. */
|
|
3878
|
+
rows: number;
|
|
2746
3879
|
}
|
|
2747
3880
|
/**
|
|
2748
3881
|
* DELETE /api/projects/:projectId/usage/errors — empties the error table for the filter the
|
|
@@ -2833,6 +3966,23 @@ interface SchedulesResponse {
|
|
|
2833
3966
|
error: string;
|
|
2834
3967
|
}>;
|
|
2835
3968
|
}
|
|
3969
|
+
/**
|
|
3970
|
+
* One task in the Project-wide listing (GET /api/projects/:projectId/schedules): the agent's
|
|
3971
|
+
* item plus the agent whose schedule directory holds it, since the list spans every agent.
|
|
3972
|
+
*/
|
|
3973
|
+
interface ProjectScheduleItem extends ScheduleItem {
|
|
3974
|
+
agentId: string;
|
|
3975
|
+
}
|
|
3976
|
+
interface ProjectSchedulesResponse {
|
|
3977
|
+
/** Every agent's tasks: agents in id order, each agent's tasks in the order its own listing returns them. */
|
|
3978
|
+
schedules: ProjectScheduleItem[];
|
|
3979
|
+
/** Files that failed to parse (skipped from scheduling and logged as errors), with the agent that holds each. */
|
|
3980
|
+
invalidFiles: Array<{
|
|
3981
|
+
agentId: string;
|
|
3982
|
+
name: string;
|
|
3983
|
+
error: string;
|
|
3984
|
+
}>;
|
|
3985
|
+
}
|
|
2836
3986
|
interface ScheduleUpsertRequest {
|
|
2837
3987
|
prompt: string;
|
|
2838
3988
|
enabled: boolean;
|
|
@@ -2882,6 +4032,11 @@ interface BenchmarkCaseScore {
|
|
|
2882
4032
|
interface BenchmarkEvaluation {
|
|
2883
4033
|
/** Evaluation timestamp (ISO 8601). */
|
|
2884
4034
|
time: string;
|
|
4035
|
+
/**
|
|
4036
|
+
* Agent under test in this round (the `agent_id` field), part of the record's label; `null`
|
|
4037
|
+
* when the record carries none, as a Benchmark evaluates whichever Agents it is pointed at.
|
|
4038
|
+
*/
|
|
4039
|
+
agentId: string | null;
|
|
2885
4040
|
/** Evaluation summary title (a one-line conclusion; shown separately from the body summary; required when generating, tolerated as unset when displaying). */
|
|
2886
4041
|
summaryTitle?: string;
|
|
2887
4042
|
/** Evaluation summary body: how the score was derived, what optimizations were made to the Agent this round (required when generating, tolerated as unset when displaying). */
|
|
@@ -2902,18 +4057,88 @@ interface BenchmarkEvaluation {
|
|
|
2902
4057
|
durationMs: number;
|
|
2903
4058
|
cases: BenchmarkCaseScore[];
|
|
2904
4059
|
}
|
|
4060
|
+
/**
|
|
4061
|
+
* Whether the Skill that builds a Benchmark is done with it, and how it ended; see
|
|
4062
|
+
* `BenchmarkSummary.status`.
|
|
4063
|
+
*/
|
|
4064
|
+
type BenchmarkStatus = "draft" | "published" | "failed";
|
|
4065
|
+
/**
|
|
4066
|
+
* Where a Benchmark's copy came from: `builtin` (seeded when the Project was created), `manual`
|
|
4067
|
+
* (the create form), `agent` (the benchmark-design Skill wrote it), `git` (an Agent imported a
|
|
4068
|
+
* repository folder), `zip` (an uploaded package).
|
|
4069
|
+
*/
|
|
4070
|
+
type BenchmarkOriginKind = "builtin" | "manual" | "agent" | "git" | "zip";
|
|
4071
|
+
/**
|
|
4072
|
+
* Why a Benchmark's manifest cannot be read: the code of core's `BenchmarkManifestError`
|
|
4073
|
+
* (`benchmark_id_mismatch` for an `id` that is not the directory's, `benchmark_manifest_invalid`
|
|
4074
|
+
* for a file that is not TOML or a `version` or `[origin]` out of shape) and its message, which
|
|
4075
|
+
* names the key or the file.
|
|
4076
|
+
*/
|
|
4077
|
+
interface BenchmarkManifestProblem {
|
|
4078
|
+
code: string;
|
|
4079
|
+
message: string;
|
|
4080
|
+
}
|
|
4081
|
+
/** The `[origin]` table of a Benchmark's benchmark_config.toml. */
|
|
4082
|
+
interface BenchmarkOrigin {
|
|
4083
|
+
kind: BenchmarkOriginKind;
|
|
4084
|
+
/** git: the folder link as the user gave it (a GitHub tree URL). Always an http(s) URL. */
|
|
4085
|
+
url?: string;
|
|
4086
|
+
/** git: the 40-hex commit the import resolved the link to. */
|
|
4087
|
+
ref?: string;
|
|
4088
|
+
/** git: the folder inside the repository. */
|
|
4089
|
+
path?: string;
|
|
4090
|
+
/** git / zip: when this copy was written (ISO 8601; `imported_at` in the file). */
|
|
4091
|
+
importedAt?: string;
|
|
4092
|
+
}
|
|
2905
4093
|
interface BenchmarkSummary {
|
|
2906
4094
|
/** Directory name is the identifier (semantic naming, e.g. swe-bench-v1). */
|
|
2907
4095
|
id: string;
|
|
2908
|
-
/** Title from benchmark_config.toml;
|
|
4096
|
+
/** Title from benchmark_config.toml; the directory name when it gives none or the manifest cannot be read. */
|
|
2909
4097
|
title: string;
|
|
2910
4098
|
description?: string;
|
|
2911
|
-
/**
|
|
4099
|
+
/** The description in Chinese (`description_zh` in benchmark_config.toml), when the manifest gives one. */
|
|
4100
|
+
descriptionZh?: string;
|
|
4101
|
+
/** Number of runs per case (the `runs` key in benchmark_config.toml, an integer ≥ 1); absent when it gives none or the manifest cannot be read, which reads as 1. */
|
|
2912
4102
|
runs?: number;
|
|
4103
|
+
/**
|
|
4104
|
+
* `draft` while the Skill that builds the Benchmark is still writing its cases and
|
|
4105
|
+
* calibrating their difficulty — the Web App masks such a Benchmark; `published` once the
|
|
4106
|
+
* Benchmark is frozen and its Formal Baseline recorded; `failed` when calibration ended
|
|
4107
|
+
* without a Pilot result that could be frozen, which leaves the Benchmark unusable — the Web
|
|
4108
|
+
* App masks it too and says it has to be deleted and created again. benchmark_config.toml is
|
|
4109
|
+
* read literally: only `draft` is a draft and only `failed` is a failure, so a missing key, or
|
|
4110
|
+
* any other value, reads as published. A Benchmark whose manifest cannot be read lists as
|
|
4111
|
+
* failed, with `manifestError`.
|
|
4112
|
+
*/
|
|
4113
|
+
status: BenchmarkStatus;
|
|
4114
|
+
/**
|
|
4115
|
+
* The manifest's date version, `YYYY.MM.DD.N`: the revision of the Benchmark's content. Absent
|
|
4116
|
+
* when the manifest has none (one written before versions is unversioned), when it cannot be
|
|
4117
|
+
* read, and from a machine whose server predates versions.
|
|
4118
|
+
*/
|
|
4119
|
+
version?: string;
|
|
4120
|
+
/**
|
|
4121
|
+
* Where this copy came from, the manifest's `[origin]`. Absent when the manifest has none (where
|
|
4122
|
+
* a copy written before origins came from is unknown), when it cannot be read, and from a
|
|
4123
|
+
* machine whose server predates origins.
|
|
4124
|
+
*/
|
|
4125
|
+
origin?: BenchmarkOrigin;
|
|
4126
|
+
/**
|
|
4127
|
+
* Set when the manifest cannot be read. Such a Benchmark lists under its directory name, as
|
|
4128
|
+
* `failed`, with no version or origin, and nothing may use or export it until the file is
|
|
4129
|
+
* fixed; the Web App masks it with this reason.
|
|
4130
|
+
*/
|
|
4131
|
+
manifestError?: BenchmarkManifestProblem;
|
|
2913
4132
|
/** Case count (number of case subfolders). */
|
|
2914
4133
|
caseCount: number;
|
|
2915
4134
|
/** Time-ordered evaluation records (the evaluations[] in scoreboard.yaml). */
|
|
2916
4135
|
evaluations: BenchmarkEvaluation[];
|
|
4136
|
+
/**
|
|
4137
|
+
* Agents this Benchmark has evaluated: the distinct non-null `agentId`s of `evaluations`, in
|
|
4138
|
+
* first-seen order. Empty while nothing has been evaluated — a Benchmark names no Agent of its
|
|
4139
|
+
* own.
|
|
4140
|
+
*/
|
|
4141
|
+
agentIds: string[];
|
|
2917
4142
|
}
|
|
2918
4143
|
interface BenchmarksResponse {
|
|
2919
4144
|
benchmarks: BenchmarkSummary[];
|
|
@@ -2928,6 +4153,80 @@ interface BenchmarkCaseSummary {
|
|
|
2928
4153
|
interface BenchmarkCasesResponse {
|
|
2929
4154
|
cases: BenchmarkCaseSummary[];
|
|
2930
4155
|
}
|
|
4156
|
+
/**
|
|
4157
|
+
* POST /api/projects/:p/benchmarks (owner only): create a Benchmark by hand. The
|
|
4158
|
+
* server writes the on-disk layout the evaluation Skills read — `benchmark_config.toml`
|
|
4159
|
+
* (published, the day's first version, origin `manual`), a `scoreboard.yaml` holding
|
|
4160
|
+
* `evaluations: []`, and one `<case id>/` per case with `statement/README.md` and
|
|
4161
|
+
* `rubric/README.md`. 409 `benchmark_exists` when the directory is already there; nothing is
|
|
4162
|
+
* merged into an existing Benchmark.
|
|
4163
|
+
*/
|
|
4164
|
+
interface BenchmarkCreateRequest {
|
|
4165
|
+
/** Directory name, which is the identifier: letters, digits, `_` and `-` only. */
|
|
4166
|
+
id: string;
|
|
4167
|
+
title: string;
|
|
4168
|
+
description?: string;
|
|
4169
|
+
/** Runs per case for the optimization loop (integer ≥ 1; default 1). */
|
|
4170
|
+
runs?: number;
|
|
4171
|
+
/** At least one case; ids must be unique within the request. */
|
|
4172
|
+
cases: BenchmarkCreateCase[];
|
|
4173
|
+
}
|
|
4174
|
+
interface BenchmarkCreateCase {
|
|
4175
|
+
/** Case directory name: `CASE-` followed by letters, digits, `_` and `-` (for example `CASE-001-excel-task`). */
|
|
4176
|
+
id: string;
|
|
4177
|
+
/** Written as the statement README's first heading, which the case list reads back as the case title. */
|
|
4178
|
+
title: string;
|
|
4179
|
+
/** Statement body (Markdown), written after that heading; the Target Agent sees only this side. */
|
|
4180
|
+
statement: string;
|
|
4181
|
+
/** Scoring rubric (Markdown, items totalling 100 points), written verbatim as `rubric/README.md`. */
|
|
4182
|
+
rubric: string;
|
|
4183
|
+
}
|
|
4184
|
+
interface BenchmarkCreateResponse {
|
|
4185
|
+
benchmark: BenchmarkSummary;
|
|
4186
|
+
}
|
|
4187
|
+
/**
|
|
4188
|
+
* POST /api/projects/:p/benchmarks/archive (any Project member): import a Benchmark package from
|
|
4189
|
+
* a zip. The zip holds `benchmark_config.toml` and the `CASE-*` directories, at its root (where the
|
|
4190
|
+
* manifest must name its `id`) or inside exactly one top-level directory named by the Benchmark's
|
|
4191
|
+
* id — the shape `GET …/benchmarks/:benchmarkId/archive` exports. A zip carrying
|
|
4192
|
+
* `scoreboard.yaml`, `.jobs/` or anything else at its top level, a link, a manifest past the
|
|
4193
|
+
* create form's limits, a package that is not `published` or a case without both READMEs is
|
|
4194
|
+
* refused (400); so is a zip past the caps (413 `benchmark_too_large`: 14MB
|
|
4195
|
+
* zipped, 1000 files, 5MB a file, 20MB inflated). The copy is written with origin `zip` and an
|
|
4196
|
+
* empty scoreboard — or origin `git`, when the request says the package is a repository folder
|
|
4197
|
+
* fetched at a commit. An id already taken is 409 `benchmark_exists` (`details.benchmarkId` names
|
|
4198
|
+
* it) unless `overwrite`.
|
|
4199
|
+
*/
|
|
4200
|
+
interface BenchmarkArchiveImportRequest {
|
|
4201
|
+
/** The zip, base64-encoded. */
|
|
4202
|
+
dataBase64: string;
|
|
4203
|
+
/**
|
|
4204
|
+
* Replace the Benchmark of the same id whole — its evaluation records and `.jobs/` included.
|
|
4205
|
+
* Refused with 409 `benchmark_busy` while an evaluation of it is still running a trial there.
|
|
4206
|
+
*/
|
|
4207
|
+
overwrite?: boolean;
|
|
4208
|
+
/**
|
|
4209
|
+
* The repository folder the package was fetched from, at one commit: what
|
|
4210
|
+
* `penguin benchmark import --origin-url … --origin-ref … --origin-path …` sends for an Agent's
|
|
4211
|
+
* import of a folder link. The copy's origin is then `git` with these fields and the time of the
|
|
4212
|
+
* import, instead of `zip`.
|
|
4213
|
+
*/
|
|
4214
|
+
origin?: BenchmarkArchiveGitOrigin;
|
|
4215
|
+
}
|
|
4216
|
+
/** Where a package fetched from a git repository came from. */
|
|
4217
|
+
interface BenchmarkArchiveGitOrigin {
|
|
4218
|
+
kind: "git";
|
|
4219
|
+
/** The folder link as the user gave it: an http(s) URL, at most 2048 characters. */
|
|
4220
|
+
url: string;
|
|
4221
|
+
/** The 40-character commit the link was resolved to. */
|
|
4222
|
+
ref: string;
|
|
4223
|
+
/** The folder inside the repository, at most 1024 characters. */
|
|
4224
|
+
path: string;
|
|
4225
|
+
}
|
|
4226
|
+
interface BenchmarkArchiveImportResponse {
|
|
4227
|
+
/** The imported Benchmark, as the list now reads it. */
|
|
4228
|
+
benchmark: BenchmarkSummary;
|
|
4229
|
+
}
|
|
2931
4230
|
interface SkillMetadataItem {
|
|
2932
4231
|
/** Skill directory name (the identity key for install / uninstall / Prompt addressing). */
|
|
2933
4232
|
name: string;
|
|
@@ -2942,7 +4241,7 @@ interface SkillMetadataItem {
|
|
|
2942
4241
|
* which the plugin item carries once. Absent, the frontend draws the book glyph.
|
|
2943
4242
|
*/
|
|
2944
4243
|
icon?: string;
|
|
2945
|
-
/**
|
|
4244
|
+
/** The skill's own dated version (`YYYY.MM.DD.N`, frontmatter version; a copy installed before that spelling still carries `YYYY-MM-DD.N`); an empty string when the frontmatter carries none or a malformed one. */
|
|
2946
4245
|
version: string;
|
|
2947
4246
|
}
|
|
2948
4247
|
/** One installed hook package (`agent_state/hooks/<name>/`): its manifest, without the scripts. */
|
|
@@ -2958,21 +4257,77 @@ interface HookItem {
|
|
|
2958
4257
|
/** The plugin's raw icon.svg, written beside the manifest at install time; absent when the plugin ships none (the frontend draws the hook glyph). */
|
|
2959
4258
|
icon?: string;
|
|
2960
4259
|
}
|
|
2961
|
-
/**
|
|
4260
|
+
/**
|
|
4261
|
+
* One library plugin as the listing describes it: the manifest fields (its package.json — npm's
|
|
4262
|
+
* fields and the `penguin` block) plus what it ships (skill bodies and scripts are never sent).
|
|
4263
|
+
* Every field but the identity, the version and the contents is optional: a field the package
|
|
4264
|
+
* does not carry is missing here, and the page says so rather than inventing one.
|
|
4265
|
+
*/
|
|
2962
4266
|
interface PluginItem {
|
|
2963
4267
|
name: string;
|
|
4268
|
+
/** Display name (`penguin.title`, `title_zh`); absent → the page shows `name`. */
|
|
4269
|
+
title?: string;
|
|
4270
|
+
titleZh?: string;
|
|
4271
|
+
/** English one-liner (package.json `description`); "" when the package carries none. */
|
|
2964
4272
|
description: string;
|
|
2965
4273
|
descriptionZh?: string;
|
|
2966
4274
|
shortDescription?: string;
|
|
2967
4275
|
shortDescriptionZh?: string;
|
|
2968
|
-
/**
|
|
4276
|
+
/** The plugin's npm version (its package.json, following the release) — what the card shows. Installed copies are compared part by part instead: each skill's `version`, and {@link hookVersion}. */
|
|
2969
4277
|
version: string;
|
|
2970
|
-
/** The plugin's
|
|
4278
|
+
/** The npm package the plugin is, e.g. `@penguinharness/a2ui` — what Delete and a server module's row name it by. */
|
|
4279
|
+
package: string;
|
|
4280
|
+
/** Where the plugin comes from: `builtin` — a package this build ships; `installed` — one an admin installed on the server (by name, link or zip). */
|
|
4281
|
+
source: "builtin" | "installed";
|
|
4282
|
+
/** The package's npm `author` (a name), `license`, `homepage` and `repository` URL, for the detail dialog. */
|
|
4283
|
+
author?: string;
|
|
4284
|
+
license?: string;
|
|
4285
|
+
homepage?: string;
|
|
4286
|
+
repository?: string;
|
|
4287
|
+
/** The plugin's skills (metadata only), each with its own dated `version`. */
|
|
2971
4288
|
skills: SkillMetadataItem[];
|
|
2972
4289
|
/** The hook points the plugin's hook package answers at (`[]` without one). */
|
|
2973
4290
|
hooks: string[];
|
|
2974
|
-
/** The
|
|
4291
|
+
/** The hook package's own dated version (`penguin.hooks.version`, `YYYY.MM.DD.N`); absent without a hook package. */
|
|
4292
|
+
hookVersion?: string;
|
|
4293
|
+
/** The plugin's raw icon SVG (`icon.svg` at the package root, or `penguin.icon` — every built-in plugin ships one; an unsafe one is never sent), the icon of everything it ships; the frontend draws the puzzle-piece plugin glyph without it. */
|
|
2975
4294
|
icon?: string;
|
|
4295
|
+
/** The demo the Plugins page's quick start pre-fills (`penguin.quick_start`); absent = pre-select its first skill. */
|
|
4296
|
+
quickStart?: QuickStartItem;
|
|
4297
|
+
/** The MCP servers the plugin installs into an Agent's `tools.mcpServers` (`penguin.mcp_servers`); `[]` without any. */
|
|
4298
|
+
mcpServers: PluginMcpServerItem[];
|
|
4299
|
+
}
|
|
4300
|
+
/** An MCP transport, as an entry resolves it (`transport`, else inferred from `command` / `url`). */
|
|
4301
|
+
type McpTransport = "stdio" | "http" | "sse";
|
|
4302
|
+
/** One vault key a plugin's MCP server needs before it can connect: declared in the manifest, or only referenced (then the key is all there is to show). */
|
|
4303
|
+
interface PluginSetupKeyItem {
|
|
4304
|
+
key: string;
|
|
4305
|
+
label?: string;
|
|
4306
|
+
labelZh?: string;
|
|
4307
|
+
/** Where to get the value (a URL), or one sentence. */
|
|
4308
|
+
help?: string;
|
|
4309
|
+
}
|
|
4310
|
+
/** A plugin's MCP server as the library lists it: identity and target only — no header, env or oauth value. */
|
|
4311
|
+
interface PluginMcpServerItem {
|
|
4312
|
+
name: string;
|
|
4313
|
+
transport: McpTransport;
|
|
4314
|
+
/** The URL (http/sse), or `command args…` (stdio), as written: `${PLUGIN_ROOT}` and `${KEY}` references unresolved. */
|
|
4315
|
+
target: string;
|
|
4316
|
+
/** Every vault key the server's config references, declared ones first. */
|
|
4317
|
+
setup: PluginSetupKeyItem[];
|
|
4318
|
+
/** The server offers OAuth sign-in (`config.oauth`). */
|
|
4319
|
+
oauth: boolean;
|
|
4320
|
+
/** It needs that sign-in — OAuth and no `Authorization` header of its own — which this version cannot do: an Agent skips it. */
|
|
4321
|
+
signIn: boolean;
|
|
4322
|
+
}
|
|
4323
|
+
/** A quick start: a prompt pre-filled into a new-chat draft — never sent by the page. */
|
|
4324
|
+
interface QuickStartItem {
|
|
4325
|
+
prompt: string;
|
|
4326
|
+
promptZh?: string;
|
|
4327
|
+
/** Skills to pre-select (a library plugin's own). */
|
|
4328
|
+
skills?: string[];
|
|
4329
|
+
/** Open the draft in goal mode. */
|
|
4330
|
+
goal?: boolean;
|
|
2976
4331
|
}
|
|
2977
4332
|
interface PluginGroupItem {
|
|
2978
4333
|
id: string;
|
|
@@ -3006,6 +4361,28 @@ interface PluginInstallRequest {
|
|
|
3006
4361
|
interface AgentPluginsInstallResponse {
|
|
3007
4362
|
skills: SkillMetadataItem[];
|
|
3008
4363
|
hooks: HookItem[];
|
|
4364
|
+
/** The Agent's MCP servers after the install (a plugin's servers join its `tools.mcpServers`). A server name the Agent already has from someone else is 409 `mcp_server_name_taken`, nothing installed. */
|
|
4365
|
+
mcpServers: AgentMcpServerItem[];
|
|
4366
|
+
}
|
|
4367
|
+
/**
|
|
4368
|
+
* One `tools.mcpServers` entry of an Agent, as the Plugins page and the Agent settings read it:
|
|
4369
|
+
* identity, target and what keeps it from connecting — never a header, env or oauth value.
|
|
4370
|
+
*/
|
|
4371
|
+
interface AgentMcpServerItem {
|
|
4372
|
+
name: string;
|
|
4373
|
+
transport: McpTransport;
|
|
4374
|
+
/** The URL (http/sse), or `command args…` (stdio): `${PLUGIN_ROOT}` already resolved at install, `${KEY}` references left as written. */
|
|
4375
|
+
target: string;
|
|
4376
|
+
/** The plugin that installed it; absent for an entry the user added. */
|
|
4377
|
+
plugin?: string;
|
|
4378
|
+
/** `${KEY}` references of its config that the Agent's vault does not hold (names only); empty = nothing to set up. */
|
|
4379
|
+
missingKeys: string[];
|
|
4380
|
+
/** It needs an OAuth sign-in, which this version cannot do: skipped at connect time. */
|
|
4381
|
+
signIn: boolean;
|
|
4382
|
+
}
|
|
4383
|
+
/** GET /api/projects/:p/agents/:a/mcp-servers: the Agent's MCP servers in config order; DELETE …/mcp-servers/:name removes one (204, 404 `unknown_mcp_server`). */
|
|
4384
|
+
interface AgentMcpServersResponse {
|
|
4385
|
+
servers: AgentMcpServerItem[];
|
|
3009
4386
|
}
|
|
3010
4387
|
/** GET /api/projects/:p/agents/:a/skills: Skills installed on this Agent. */
|
|
3011
4388
|
interface AgentSkillsResponse {
|
|
@@ -3041,6 +4418,92 @@ interface SkillArchiveInstallRequest {
|
|
|
3041
4418
|
/** Replace an already-installed Skill of the same name (deletes its directory first). */
|
|
3042
4419
|
overwrite?: boolean;
|
|
3043
4420
|
}
|
|
4421
|
+
/**
|
|
4422
|
+
* One published version of a plugin — the index entry format every plugin registry
|
|
4423
|
+
* speaks (modeled on the typst/packages `index.json` schema: a flat array of
|
|
4424
|
+
* per-version entries; a plugin published at several versions appears once per
|
|
4425
|
+
* version). Installation is out of scope here: an entry's `name` is the package
|
|
4426
|
+
* specifier a Project's plugin list names.
|
|
4427
|
+
*/
|
|
4428
|
+
interface PluginIndexEntry {
|
|
4429
|
+
/** Package specifier — the string a Project's plugin list names. */
|
|
4430
|
+
name: string;
|
|
4431
|
+
/** Semantic version of this entry. */
|
|
4432
|
+
version: string;
|
|
4433
|
+
description: string;
|
|
4434
|
+
/** Chinese description (optional; the UI picks per language, English without it). */
|
|
4435
|
+
descriptionZh?: string;
|
|
4436
|
+
/** One-line descriptions for the card (optional; the card falls back to `description`). */
|
|
4437
|
+
shortDescription?: string;
|
|
4438
|
+
shortDescriptionZh?: string;
|
|
4439
|
+
/**
|
|
4440
|
+
* The plugin's raw icon SVG (optional; the card draws the puzzle piece without it). The
|
|
4441
|
+
* listing fills these display fields from the package's own package.json (its `penguin`
|
|
4442
|
+
* block) and icon when the package is on this server, over whatever the index row says.
|
|
4443
|
+
*/
|
|
4444
|
+
icon?: string;
|
|
4445
|
+
authors: string[];
|
|
4446
|
+
/** SPDX license identifier. */
|
|
4447
|
+
license: string;
|
|
4448
|
+
/** Source repository URL. */
|
|
4449
|
+
repository?: string;
|
|
4450
|
+
homepage?: string;
|
|
4451
|
+
/** Free-form searchable terms; the Web App renders them as chips (e.g. the target OS). */
|
|
4452
|
+
keywords?: string[];
|
|
4453
|
+
/** Capability floor(s) the plugin provides on (e.g. "sandbox"). */
|
|
4454
|
+
categories?: string[];
|
|
4455
|
+
/** Unix timestamp (seconds) of the entry's last update. */
|
|
4456
|
+
updatedAt?: number;
|
|
4457
|
+
}
|
|
4458
|
+
/** GET /api/plugins/registry: the merged index of every configured registry (currently the builtin one). */
|
|
4459
|
+
interface PluginIndexResponse {
|
|
4460
|
+
plugins: PluginIndexEntry[];
|
|
4461
|
+
/**
|
|
4462
|
+
* Sources that could not be read, by `source` and reason. Present and empty when every
|
|
4463
|
+
* source answered. A remote index that is down shortens the listing rather than emptying
|
|
4464
|
+
* it, so the page needs to be able to say so instead of silently showing less.
|
|
4465
|
+
*/
|
|
4466
|
+
failures: {
|
|
4467
|
+
source: string;
|
|
4468
|
+
error: string;
|
|
4469
|
+
}[];
|
|
4470
|
+
/**
|
|
4471
|
+
* Sources the server was still reading when it answered, by `source`. Present and empty when
|
|
4472
|
+
* every source answered. The listing does not wait long for a published index, so one on a slow
|
|
4473
|
+
* or unreachable network is named here and its entries are missing; a later read lists them
|
|
4474
|
+
* once they have arrived, or names the source under `failures` once it has failed.
|
|
4475
|
+
*/
|
|
4476
|
+
pending: string[];
|
|
4477
|
+
}
|
|
4478
|
+
/**
|
|
4479
|
+
* A plugin's long-form docs: the README.md at its package root, as npm ships it.
|
|
4480
|
+
* GET /api/plugins/registry/readme?name= answers for an index entry, with `readme` null when
|
|
4481
|
+
* the package is not on this server or has none; GET /api/plugins/:plugin/readme answers for a
|
|
4482
|
+
* library plugin, 404 when it ships none.
|
|
4483
|
+
*/
|
|
4484
|
+
interface PluginReadmeResponse {
|
|
4485
|
+
name: string;
|
|
4486
|
+
/** Markdown, rendered by the Web App. Null when this entry has no readme. */
|
|
4487
|
+
readme: string | null;
|
|
4488
|
+
}
|
|
4489
|
+
/**
|
|
4490
|
+
* One language a plugin contributes, as the listing reports it. The grammar itself is not
|
|
4491
|
+
* here: it is tens to hundreds of kilobytes, and only the languages a conversation actually
|
|
4492
|
+
* shows are worth fetching (`GET /api/languages/:id/grammar`).
|
|
4493
|
+
*/
|
|
4494
|
+
interface LanguageSummary {
|
|
4495
|
+
/** Canonical id: the fence info string, and the id both endpoints address. */
|
|
4496
|
+
id: string;
|
|
4497
|
+
displayName: string;
|
|
4498
|
+
/** Alternative fence info strings, needed BEFORE the grammar loads (it is what decides to load it). */
|
|
4499
|
+
aliases?: string[];
|
|
4500
|
+
/** File extensions without the dot, for the Workspace file viewer. */
|
|
4501
|
+
extensions?: string[];
|
|
4502
|
+
}
|
|
4503
|
+
/** GET /api/languages: every language this App's plugins contributed, by id. */
|
|
4504
|
+
interface LanguageIndexResponse {
|
|
4505
|
+
languages: LanguageSummary[];
|
|
4506
|
+
}
|
|
3044
4507
|
/**
|
|
3045
4508
|
* GET /api/version: the running build's identity plus this root's pushed harness, verbatim
|
|
3046
4509
|
* from `versionReport()` — the same record `penguin version --json` prints, so the two
|
|
@@ -3050,6 +4513,17 @@ interface SkillArchiveInstallRequest {
|
|
|
3050
4513
|
* predating the stamping — v0.1.2 and earlier — where the UI shows the version alone).
|
|
3051
4514
|
*/
|
|
3052
4515
|
type VersionResponse = VersionReport;
|
|
4516
|
+
|
|
4517
|
+
/** GET /api/version/history: the harness versions this data root has committed, newest first. */
|
|
4518
|
+
type VersionHistoryResponse = HarnessHistory;
|
|
4519
|
+
/** POST /api/version/history/rollback `{ id }`: the push back has started; the swap follows. */
|
|
4520
|
+
interface VersionRollbackResponse {
|
|
4521
|
+
started: true;
|
|
4522
|
+
id: string;
|
|
4523
|
+
}
|
|
4524
|
+
/** GET /api/version/history/diff?from=&to=: what changed between two stored interface tables. */
|
|
4525
|
+
type VersionHistoryDiffResponse = IfacesDiff;
|
|
4526
|
+
|
|
3053
4527
|
/**
|
|
3054
4528
|
* GET /api/version/update-check: newest published release vs the running version.
|
|
3055
4529
|
* Always HTTP 200 (fail-soft): a lookup failure sets `error` and leaves `latestVersion`
|
|
@@ -3124,6 +4598,88 @@ interface DesktopUpdaterCommandMessage {
|
|
|
3124
4598
|
type: "desktop-updater-command";
|
|
3125
4599
|
action: "check" | "download" | "install";
|
|
3126
4600
|
}
|
|
4601
|
+
/** The two languages the Web App has; the shell's tray menu follows whichever is in use. */
|
|
4602
|
+
type DesktopTrayLocale = "zh" | "en";
|
|
4603
|
+
/** What the shell is currently doing about its tray icon. */
|
|
4604
|
+
interface DesktopTrayStatus {
|
|
4605
|
+
/** Whether an icon is shown in the system tray while the app runs. */
|
|
4606
|
+
showTrayIcon: boolean;
|
|
4607
|
+
/**
|
|
4608
|
+
* The language the tray menu is drawn in. Until a page reports one the shell uses the
|
|
4609
|
+
* device language, so this can differ from the Web App's until the first report lands.
|
|
4610
|
+
*/
|
|
4611
|
+
locale: DesktopTrayLocale;
|
|
4612
|
+
}
|
|
4613
|
+
/**
|
|
4614
|
+
* What one PUT asks the shell to change. Every field is optional and a request must carry at
|
|
4615
|
+
* least one: the switch and the language reach this route from different parts of the page.
|
|
4616
|
+
*/
|
|
4617
|
+
interface DesktopTrayPatch {
|
|
4618
|
+
showTrayIcon?: boolean;
|
|
4619
|
+
locale?: DesktopTrayLocale;
|
|
4620
|
+
}
|
|
4621
|
+
/**
|
|
4622
|
+
* GET / PUT /api/desktop/tray (desktop-shell sessions only): the tray preference.
|
|
4623
|
+
* `status` is null until the shell's first push lands (a beat after server start); a
|
|
4624
|
+
* client that finds null reads it as on, which is the shell's own default.
|
|
4625
|
+
*/
|
|
4626
|
+
interface DesktopTrayStatusResponse {
|
|
4627
|
+
status: DesktopTrayStatus | null;
|
|
4628
|
+
}
|
|
4629
|
+
/** Shell → server push over the utilityProcess message channel. */
|
|
4630
|
+
interface DesktopTrayStatusMessage {
|
|
4631
|
+
type: "desktop-tray-status";
|
|
4632
|
+
status: DesktopTrayStatus;
|
|
4633
|
+
}
|
|
4634
|
+
/**
|
|
4635
|
+
* Server → shell command over the utilityProcess message channel (relayed from PUT
|
|
4636
|
+
* /api/desktop/tray). A patch, not a snapshot: the switch and the language are written by
|
|
4637
|
+
* different parts of the page at different moments, and neither should have to restate the
|
|
4638
|
+
* other's value to change its own.
|
|
4639
|
+
*/
|
|
4640
|
+
interface DesktopTrayCommandMessage {
|
|
4641
|
+
type: "desktop-tray-command";
|
|
4642
|
+
showTrayIcon?: boolean;
|
|
4643
|
+
locale?: DesktopTrayLocale;
|
|
4644
|
+
}
|
|
4645
|
+
/** What the shell's read of one folder came to. */
|
|
4646
|
+
interface DesktopFolderAccessResult {
|
|
4647
|
+
/** The folder could be read. Always true off macOS, where the shell reads nothing. */
|
|
4648
|
+
granted: boolean;
|
|
4649
|
+
/** The failed read's errno code (`EPERM`, `EACCES`, `ENOENT`, …); `EINVAL` for a path that is not absolute. */
|
|
4650
|
+
code?: string;
|
|
4651
|
+
/**
|
|
4652
|
+
* Whether the app is a packaged build (Electron's `app.isPackaged`). An unpackaged one is a
|
|
4653
|
+
* development instance started from a terminal, and macOS holds that terminal responsible
|
|
4654
|
+
* for its reads rather than the app.
|
|
4655
|
+
*/
|
|
4656
|
+
packaged: boolean;
|
|
4657
|
+
}
|
|
4658
|
+
/** Server → shell request over the utilityProcess message channel (relayed from POST /api/projects/:projectId/dirs/access). */
|
|
4659
|
+
interface DesktopFolderAccessMessage {
|
|
4660
|
+
type: "desktop-folder-access";
|
|
4661
|
+
/** Pairs the reply with its request. */
|
|
4662
|
+
id: string;
|
|
4663
|
+
/** The folder to read, as an absolute path. */
|
|
4664
|
+
path: string;
|
|
4665
|
+
}
|
|
4666
|
+
/** Shell → server reply to one {@link DesktopFolderAccessMessage}, carrying its `id`. */
|
|
4667
|
+
interface DesktopFolderAccessResultMessage extends DesktopFolderAccessResult {
|
|
4668
|
+
type: "desktop-folder-access-result";
|
|
4669
|
+
id: string;
|
|
4670
|
+
}
|
|
4671
|
+
/** POST /api/projects/:projectId/dirs/access: the shell's answer, for the picker to act on. */
|
|
4672
|
+
interface DirAccessResponse {
|
|
4673
|
+
granted: boolean;
|
|
4674
|
+
packaged: boolean;
|
|
4675
|
+
}
|
|
4676
|
+
/** The Privacy & Security panes the page may open: Files and Folders, and Full Disk Access. */
|
|
4677
|
+
type DesktopPrivacyPane = "files" | "fullDisk";
|
|
4678
|
+
/** Server → shell command over the utilityProcess message channel (relayed from POST /api/desktop/privacy-settings). No reply. */
|
|
4679
|
+
interface DesktopOpenPrivacySettingsMessage {
|
|
4680
|
+
type: "desktop-open-privacy-settings";
|
|
4681
|
+
pane: DesktopPrivacyPane;
|
|
4682
|
+
}
|
|
3127
4683
|
/**
|
|
3128
4684
|
* The outcome of one self-update run (`penguin update --yes` on the server host), carried
|
|
3129
4685
|
* by {@link UpdateJobStatus.result}. `unsupported` covers both a server not launched via
|
|
@@ -3214,6 +4770,16 @@ interface MachineInfo {
|
|
|
3214
4770
|
version: string;
|
|
3215
4771
|
at: string;
|
|
3216
4772
|
};
|
|
4773
|
+
/** This server signs in to the machine with a password it stores for the alias, not a key. */
|
|
4774
|
+
passwordSaved?: true;
|
|
4775
|
+
/**
|
|
4776
|
+
* In this Project's list: the Machines page shows a card for it. A machine joins the list when
|
|
4777
|
+
* it is added (`POST …/machines/add`, which installs nothing) or when an install or a use for
|
|
4778
|
+
* this Project runs on it, and leaves it with stop-using or release. Absent for a host that is
|
|
4779
|
+
* only in the ssh config, or only in another Project's list; never set on `local`, which is
|
|
4780
|
+
* always shown.
|
|
4781
|
+
*/
|
|
4782
|
+
member?: true;
|
|
3217
4783
|
/**
|
|
3218
4784
|
* The machine's OWN id — 16 base64url characters minted by the server that runs there,
|
|
3219
4785
|
* stable across renames, re-aliasing and reinstalls. Null until a server has started on
|
|
@@ -3238,6 +4804,19 @@ interface MachineInfo {
|
|
|
3238
4804
|
connection: {
|
|
3239
4805
|
pid: number;
|
|
3240
4806
|
} | null;
|
|
4807
|
+
/**
|
|
4808
|
+
* Present while this server is bringing a machine it keeps connected back — the connection
|
|
4809
|
+
* dropped, its server stopped or restarted, or this server itself just started — and absent
|
|
4810
|
+
* otherwise. A machine is kept connected from the moment it is enabled until it is stopped
|
|
4811
|
+
* (`POST …/stop`) or deleted (`POST …/stop-using`); see machines/service.ts's supervision.
|
|
4812
|
+
*/
|
|
4813
|
+
reconnect?: MachineReconnect;
|
|
4814
|
+
/**
|
|
4815
|
+
* This server keeps a connection to it: it was enabled, or started, and has not been stopped
|
|
4816
|
+
* or deleted since. Absent otherwise — a machine only added, one whose server was stopped
|
|
4817
|
+
* here, one that never got as far as a connection.
|
|
4818
|
+
*/
|
|
4819
|
+
keepConnected?: true;
|
|
3241
4820
|
/**
|
|
3242
4821
|
* The machine's API as last seen by this server's proxy — stamped by traffic passing
|
|
3243
4822
|
* through, never by a probe of its own. `answeredAt` when the last forwarded request got
|
|
@@ -3253,6 +4832,12 @@ interface MachineInfo {
|
|
|
3253
4832
|
failedAt: string;
|
|
3254
4833
|
detail: string;
|
|
3255
4834
|
} | null;
|
|
4835
|
+
/**
|
|
4836
|
+
* What the last time this server handed it the Project config came to: at a connect, a Sync
|
|
4837
|
+
* config job, or an automatic sync after a config edit here. Absent until the first one since
|
|
4838
|
+
* this server started; kept in memory only.
|
|
4839
|
+
*/
|
|
4840
|
+
configSync?: MachineConfigSync;
|
|
3256
4841
|
/**
|
|
3257
4842
|
* What the last probe found over there, or null when none has been taken. Never filled in
|
|
3258
4843
|
* at list time: a probe costs an ssh round trip per machine, so the list reports the last
|
|
@@ -3260,6 +4845,80 @@ interface MachineInfo {
|
|
|
3260
4845
|
* since each probe is an ssh round trip while the list is only the config's text.
|
|
3261
4846
|
*/
|
|
3262
4847
|
status: MachineServerStatus | null;
|
|
4848
|
+
/**
|
|
4849
|
+
* The data root the server there runs on (`PENGUIN_HOME`). This instance's PROFILE decides
|
|
4850
|
+
* it — a dev instance names the machine's dev root and never the release one beside it
|
|
4851
|
+
* (machines/layout.ts) — which is exactly what a reader looking at two instances of this
|
|
4852
|
+
* page needs to tell them apart. Written in that machine's own spelling once its platform
|
|
4853
|
+
* is known, and in the POSIX one before that; for `local` it is this process's own root,
|
|
4854
|
+
* already resolved to an absolute path.
|
|
4855
|
+
*/
|
|
4856
|
+
root: string;
|
|
4857
|
+
}
|
|
4858
|
+
/**
|
|
4859
|
+
* One config sync to a machine: when it ended, whether every part of it reached the machine for
|
|
4860
|
+
* every Project using it, and what did not, in the far side's words.
|
|
4861
|
+
*/
|
|
4862
|
+
interface MachineConfigSync {
|
|
4863
|
+
/** ISO timestamp the sync ended. */
|
|
4864
|
+
at: string;
|
|
4865
|
+
ok: boolean;
|
|
4866
|
+
/** The parts that did not go through, one per line; absent when `ok`. */
|
|
4867
|
+
detail?: string;
|
|
4868
|
+
/**
|
|
4869
|
+
* The values the Project's models take from this server's environment variables rather than
|
|
4870
|
+
* its config (an API key, or a base URL), which no sync can carry: one row per variable. On
|
|
4871
|
+
* the list answered for a Project, that Project's rows only.
|
|
4872
|
+
*/
|
|
4873
|
+
envOnly: MachineEnvOnly[];
|
|
4874
|
+
/**
|
|
4875
|
+
* The model entries the machine refused by name — a hand-added model in a group that takes
|
|
4876
|
+
* only its built-in ones there — left out while the rest of the table went. On the list
|
|
4877
|
+
* answered for a Project, that Project's rows only.
|
|
4878
|
+
*/
|
|
4879
|
+
skipped: MachineSkippedModel[];
|
|
4880
|
+
}
|
|
4881
|
+
/** A model entry a machine would not take: its error code and its own words for why. */
|
|
4882
|
+
interface MachineSkippedModel {
|
|
4883
|
+
projectId: string;
|
|
4884
|
+
provider: string;
|
|
4885
|
+
modelId: string;
|
|
4886
|
+
/** The far side's error code (`model_not_addable`, `model_not_routable`). */
|
|
4887
|
+
code: string;
|
|
4888
|
+
reason: string;
|
|
4889
|
+
}
|
|
4890
|
+
/** A model entry that takes `variable` from this server's environment. */
|
|
4891
|
+
interface MachineEnvOnly {
|
|
4892
|
+
projectId: string;
|
|
4893
|
+
provider: string;
|
|
4894
|
+
modelId: string;
|
|
4895
|
+
variable: string;
|
|
4896
|
+
}
|
|
4897
|
+
/**
|
|
4898
|
+
* A machine this server keeps connected, while it is being brought back. Attempts back off
|
|
4899
|
+
* from 5 s, doubling to a 5-minute cap, so a machine that is down for a day costs a probe every
|
|
4900
|
+
* five minutes; after three failures in a row the connection check runs on its own, and its
|
|
4901
|
+
* answer is what the page shows as the explanation.
|
|
4902
|
+
*/
|
|
4903
|
+
interface MachineReconnect {
|
|
4904
|
+
/** When this streak began: the moment the machine was found not connected. */
|
|
4905
|
+
since: string;
|
|
4906
|
+
/** Attempts that failed in this streak; 0 while the first is still to run or running. */
|
|
4907
|
+
attempts: number;
|
|
4908
|
+
/** When the next attempt runs; null while one is running. */
|
|
4909
|
+
nextAt: string | null;
|
|
4910
|
+
/** The last attempt's failure in the far side's words; null before the first one fails. */
|
|
4911
|
+
lastError: string | null;
|
|
4912
|
+
/** Why ssh refused, when the last failure was ssh's own — for the page to say in its language. */
|
|
4913
|
+
sshReason?: MachineSshFailure;
|
|
4914
|
+
/** The connection check run after three failures in a row; null until then. */
|
|
4915
|
+
diagnosis: MachineDiagnosis | null;
|
|
4916
|
+
/**
|
|
4917
|
+
* The password stored for the machine was refused, or its host takes none (`sshReason`
|
|
4918
|
+
* says which): no attempt runs until a password is saved for it again or removed, since
|
|
4919
|
+
* retrying could lock the account. `nextAt` is null meanwhile.
|
|
4920
|
+
*/
|
|
4921
|
+
waitsForPassword?: true;
|
|
3263
4922
|
}
|
|
3264
4923
|
/**
|
|
3265
4924
|
* One machine's server state. There is deliberately no separate "ssh" status: ssh is the
|
|
@@ -3282,11 +4941,38 @@ interface MachineServerStatus {
|
|
|
3282
4941
|
* refused key or an unusable Node than a paraphrase would.
|
|
3283
4942
|
*/
|
|
3284
4943
|
interface MachineJob {
|
|
3285
|
-
|
|
4944
|
+
/**
|
|
4945
|
+
* `use` is the whole pipeline — install if needed, hand over, connect, sync — as one job;
|
|
4946
|
+
* `connect` is what the page calls Start service; `stop` stops the machine's server and stops
|
|
4947
|
+
* keeping it connected; `uninstall` stops it and removes the program, and the data directory
|
|
4948
|
+
* when asked; `sync` hands a connected machine the Project config.
|
|
4949
|
+
*/
|
|
4950
|
+
kind: "install" | "connect" | "restart" | "use" | "stop" | "uninstall" | "sync";
|
|
3286
4951
|
machineId: string;
|
|
3287
4952
|
alias: string;
|
|
4953
|
+
/** Waiting its turn: a few machines are worked on at once, and a batch queues the rest. */
|
|
4954
|
+
queued: boolean;
|
|
3288
4955
|
running: boolean;
|
|
4956
|
+
/**
|
|
4957
|
+
* The steps this job goes through, in order — what the page draws as its stepper. Fixed when
|
|
4958
|
+
* the job is queued; a step the job turns out not to need is passed over, never revisited.
|
|
4959
|
+
*/
|
|
4960
|
+
steps: MachinePhase[];
|
|
4961
|
+
/**
|
|
4962
|
+
* Which of `steps` the job is on. Only moves forward. Null until the first step is named; a
|
|
4963
|
+
* finished job keeps its last phase.
|
|
4964
|
+
*/
|
|
4965
|
+
phase: MachinePhase | null;
|
|
3289
4966
|
log: string[];
|
|
4967
|
+
/**
|
|
4968
|
+
* The connection check run after the job failed at a step it can explain — checking,
|
|
4969
|
+
* installing, connecting: running, then its answer. Absent for every other job.
|
|
4970
|
+
*/
|
|
4971
|
+
diagnosis?: {
|
|
4972
|
+
state: "running";
|
|
4973
|
+
} | ({
|
|
4974
|
+
state: "done";
|
|
4975
|
+
} & MachineDiagnosis);
|
|
3290
4976
|
result: null | {
|
|
3291
4977
|
ok: true;
|
|
3292
4978
|
installed: "installed" | "already-installed";
|
|
@@ -3294,30 +4980,1909 @@ interface MachineJob {
|
|
|
3294
4980
|
} | {
|
|
3295
4981
|
ok: true;
|
|
3296
4982
|
connected: true;
|
|
4983
|
+
}
|
|
4984
|
+
/** The machine's server is stopped and stays so until it is started again. */
|
|
4985
|
+
| {
|
|
4986
|
+
ok: true;
|
|
4987
|
+
stopped: true;
|
|
4988
|
+
}
|
|
4989
|
+
/** The program is gone from the machine; `dataRemoved` says whether its data root went too. */
|
|
4990
|
+
| {
|
|
4991
|
+
ok: true;
|
|
4992
|
+
uninstalled: true;
|
|
4993
|
+
dataRemoved: boolean;
|
|
4994
|
+
}
|
|
4995
|
+
/** Every part of the Project config reached the machine (its `configSync` says the same). */
|
|
4996
|
+
| {
|
|
4997
|
+
ok: true;
|
|
4998
|
+
synced: true;
|
|
3297
4999
|
} | {
|
|
3298
5000
|
ok: false;
|
|
3299
5001
|
step: string;
|
|
3300
5002
|
message: string;
|
|
3301
5003
|
/**
|
|
3302
5004
|
* The failure has a next step this side can take, and it needs saying yes to:
|
|
3303
|
-
* installing the PROGRAM over there and restarting it.
|
|
3304
|
-
*
|
|
3305
|
-
*
|
|
3306
|
-
*
|
|
5005
|
+
* installing the PROGRAM over there and restarting it. Every failed install or
|
|
5006
|
+
* connect offers it — a failure that leaves no next step leaves a person stuck —
|
|
5007
|
+
* except a run that was itself that install, and one this server could not act on
|
|
5008
|
+
* (no build of its own to send), which says `false`. Offered rather than done,
|
|
5009
|
+
* because it restarts a server this Project does not own alone.
|
|
3307
5010
|
*/
|
|
3308
|
-
canReplaceProgram?:
|
|
5011
|
+
canReplaceProgram?: boolean;
|
|
5012
|
+
/**
|
|
5013
|
+
* Why ssh refused, when the failure is ssh's own (a host key, a key, a host name, a
|
|
5014
|
+
* route), for the page to say in its language; `message` says it in English, with
|
|
5015
|
+
* ssh's own words after `(ssh: …)`.
|
|
5016
|
+
*/
|
|
5017
|
+
sshReason?: MachineSshFailure;
|
|
3309
5018
|
};
|
|
3310
5019
|
}
|
|
5020
|
+
/**
|
|
5021
|
+
* A source checkout's install image (machines/checkout-image.ts), built from the checkout
|
|
5022
|
+
* again at each install or use: not built yet, building, built, or failed with the build's
|
|
5023
|
+
* own last words.
|
|
5024
|
+
*/
|
|
5025
|
+
type MachinesCheckoutImage = {
|
|
5026
|
+
state: "unbuilt";
|
|
5027
|
+
} | {
|
|
5028
|
+
state: "building";
|
|
5029
|
+
} | {
|
|
5030
|
+
state: "built";
|
|
5031
|
+
} | {
|
|
5032
|
+
state: "failed";
|
|
5033
|
+
detail: string;
|
|
5034
|
+
};
|
|
3311
5035
|
/** GET /api/machines, and the 202 body of POST /api/machines/:machineId/install. */
|
|
3312
5036
|
interface MachinesResponse {
|
|
3313
5037
|
machines: MachineInfo[];
|
|
3314
5038
|
/**
|
|
3315
5039
|
* The version an install would leave on the remote — the base release, plus a `+hmr.<sha>`
|
|
3316
|
-
* suffix when this server carries a pushed version to replicate.
|
|
3317
|
-
*
|
|
5040
|
+
* suffix when this server carries a pushed version to replicate. A source checkout answers
|
|
5041
|
+
* with the image it last built, and null before its first build (see `checkoutImage`).
|
|
5042
|
+
* Null otherwise only for a server that carries no image and builds none.
|
|
3318
5043
|
*/
|
|
3319
5044
|
imageVersion: string | null;
|
|
5045
|
+
/**
|
|
5046
|
+
* Present only when this server runs from a source checkout: it builds its install image
|
|
5047
|
+
* from the checkout at each install or use, so no image yet is not a reason to refuse one.
|
|
5048
|
+
*/
|
|
5049
|
+
checkoutImage?: MachinesCheckoutImage;
|
|
5050
|
+
/** The most recently started job, running or finished. */
|
|
3320
5051
|
job: MachineJob | null;
|
|
5052
|
+
/**
|
|
5053
|
+
* Every job worth showing this generation: the queued ones, the running one, and the last
|
|
5054
|
+
* finished one per machine — so a batch reads as a list of rows each saying where it is.
|
|
5055
|
+
*/
|
|
5056
|
+
jobs: MachineJob[];
|
|
5057
|
+
}
|
|
5058
|
+
/**
|
|
5059
|
+
* Every step a job may name, in the order they can occur. A job lists its own subset as
|
|
5060
|
+
* `MachineJob.steps`: a source checkout's enable starts by building its install image
|
|
5061
|
+
* (`build`); a stop is `check`, `stop`; an uninstall `check`, `stop`, `remove`; a config sync
|
|
5062
|
+
* `check`, `sync`.
|
|
5063
|
+
*/
|
|
5064
|
+
declare const MACHINE_PHASES: readonly ["build", "check", "install", "handover", "restart", "connect", "sync", "stop", "remove"];
|
|
5065
|
+
type MachinePhase = (typeof MACHINE_PHASES)[number];
|
|
5066
|
+
/** `POST /api/projects/:projectId/machines/:machineId/uninstall`. */
|
|
5067
|
+
interface MachineUninstallRequest {
|
|
5068
|
+
/** Remove the machine's data root too — its Sessions, Agents and config there. Default false. */
|
|
5069
|
+
removeData?: boolean;
|
|
5070
|
+
}
|
|
5071
|
+
/**
|
|
5072
|
+
* `POST /api/projects/:projectId/machines/ssh-hosts`: append a host block to this server's
|
|
5073
|
+
* `~/.ssh/config`. Answers the machines list (201), or 400 `ssh_host_invalid` naming the
|
|
5074
|
+
* field, or 409 `ssh_host_exists`.
|
|
5075
|
+
*/
|
|
5076
|
+
interface SshHostRequest {
|
|
5077
|
+
/** The alias — what `ssh <alias>` will take, and the machine's name everywhere here. */
|
|
5078
|
+
alias: string;
|
|
5079
|
+
hostName: string;
|
|
5080
|
+
user?: string;
|
|
5081
|
+
port?: number;
|
|
5082
|
+
identityFile?: string;
|
|
5083
|
+
/**
|
|
5084
|
+
* Sign in with this password instead of a key: stored on this server in a 0600 file under its
|
|
5085
|
+
* data root, never in the ssh config, and never sent back. On a PUT, `null` deletes the stored
|
|
5086
|
+
* one (back to key sign-in) and leaving it out keeps it. A PUT on a block written by hand may
|
|
5087
|
+
* set it when the other fields are the block as it stands. 400 `ssh_password_invalid` for an
|
|
5088
|
+
* empty or multi-line one; 409 `ssh_password_unsupported` (`details.ssh`: what `ssh -V` said)
|
|
5089
|
+
* when this computer's ssh cannot be handed a password.
|
|
5090
|
+
*/
|
|
5091
|
+
password?: string | null;
|
|
5092
|
+
}
|
|
5093
|
+
/**
|
|
5094
|
+
* `GET /api/projects/:projectId/machines/ssh-hosts/:alias`: a host's block read back, and
|
|
5095
|
+
* whether this app wrote it. Only a block this app wrote may be rewritten
|
|
5096
|
+
* (`PUT …/ssh-hosts/:alias`, the same fields less the alias): a hand-written one may carry
|
|
5097
|
+
* options this app does not know, and rewriting it would drop them.
|
|
5098
|
+
*/
|
|
5099
|
+
interface SshHostResponse extends Omit<SshHostRequest, "password"> {
|
|
5100
|
+
editable: boolean;
|
|
5101
|
+
/** A password is stored for this host, which then signs in with it rather than with a key. */
|
|
5102
|
+
passwordSaved?: true;
|
|
5103
|
+
}
|
|
5104
|
+
/**
|
|
5105
|
+
* `GET /api/projects/:projectId/machines/ssh-hosts`: every host this server's ssh config declares,
|
|
5106
|
+
* its included files' too, with what each one's own block says about reaching it — the literal
|
|
5107
|
+
* lines, not what ssh resolves (no `ssh -G`): a `Host *` default or a `Match` block is not
|
|
5108
|
+
* applied. For the add dialog's rows; an option the block leaves out is absent.
|
|
5109
|
+
*/
|
|
5110
|
+
interface SshHostSummary {
|
|
5111
|
+
alias: string;
|
|
5112
|
+
hostName?: string;
|
|
5113
|
+
user?: string;
|
|
5114
|
+
port?: number;
|
|
5115
|
+
}
|
|
5116
|
+
interface SshHostsResponse {
|
|
5117
|
+
hosts: SshHostSummary[];
|
|
5118
|
+
}
|
|
5119
|
+
/**
|
|
5120
|
+
* `POST /api/projects/:projectId/machines/add`: put these machines in this Project's list without
|
|
5121
|
+
* installing anything there — each then has a card whose one thing to do is enabling it. Answers
|
|
5122
|
+
* like `…/use`, refusals by id (`unknown-machine`, `self`).
|
|
5123
|
+
*/
|
|
5124
|
+
interface MachinesAddRequest {
|
|
5125
|
+
machines: string[];
|
|
5126
|
+
}
|
|
5127
|
+
/** `POST /api/projects/:projectId/machines/use`: bring these machines into use, as one queued batch. */
|
|
5128
|
+
interface MachinesUseRequest {
|
|
5129
|
+
/** Machine ids (`ssh:<alias>`). Every one is queued; refusals come back by id. */
|
|
5130
|
+
machines: string[];
|
|
5131
|
+
/** Install the program even where its version matches, and restart there — the answer to a job that asked for it. */
|
|
5132
|
+
replaceProgram?: boolean;
|
|
5133
|
+
}
|
|
5134
|
+
/** Why one machine of a batch was not queued; the rest were. */
|
|
5135
|
+
type MachineUseRefusal = "unknown-machine" | "self" | "no-image";
|
|
5136
|
+
/**
|
|
5137
|
+
* Why ssh could not get a session to a machine, read from its own diagnostic
|
|
5138
|
+
* (machines/ssh-failure.ts); `other` when it printed none of the ones with a fixed meaning.
|
|
5139
|
+
*/
|
|
5140
|
+
type MachineSshFailure = "host-key-unknown" | "host-key-changed" | "key-file" | "auth" | "password-rejected" | "password-not-offered" | "host-not-found" | "refused" | "timeout" | "closed" | "ssh-config" | "other";
|
|
5141
|
+
/** Whether a machine reaches one release source: the package is there, the source answered without it, or no answer. */
|
|
5142
|
+
type MachineSourceReach = "ok" | "missing" | "unreachable";
|
|
5143
|
+
/**
|
|
5144
|
+
* One check of a machine (machines/diagnose.ts), as facts for the page to word. `pass` is
|
|
5145
|
+
* fine, `warn` works with a caveat, `fail` stops an install or a connect, `skip` could not be
|
|
5146
|
+
* asked (an earlier check failed, or it does not apply).
|
|
5147
|
+
*/
|
|
5148
|
+
type MachineCheck =
|
|
5149
|
+
/** A session came up (keys, or the stored password), as this account on that host. */
|
|
5150
|
+
{
|
|
5151
|
+
id: "ssh";
|
|
5152
|
+
state: "pass";
|
|
5153
|
+
user: string;
|
|
5154
|
+
host: string;
|
|
5155
|
+
}
|
|
5156
|
+
/** It did not; `said` is ssh's own words, led by what they mean. */
|
|
5157
|
+
| {
|
|
5158
|
+
id: "ssh";
|
|
5159
|
+
state: "fail";
|
|
5160
|
+
reason: MachineSshFailure;
|
|
5161
|
+
said: string;
|
|
5162
|
+
}
|
|
5163
|
+
/**
|
|
5164
|
+
* `warn` for Windows (installable, not connectable yet), and for a Linux whose glibc runs the
|
|
5165
|
+
* release but is older than `terminalsNeed`, the one its terminal binding loads on.
|
|
5166
|
+
*/
|
|
5167
|
+
| {
|
|
5168
|
+
id: "platform";
|
|
5169
|
+
state: "pass" | "warn";
|
|
5170
|
+
os: string;
|
|
5171
|
+
arch: string;
|
|
5172
|
+
glibc?: string;
|
|
5173
|
+
terminalsNeed?: string;
|
|
5174
|
+
}
|
|
5175
|
+
/**
|
|
5176
|
+
* What the release's Node cannot run on: an OS or architecture no release is published for
|
|
5177
|
+
* (`unsupported`, `said` what the machine answered), a glibc older than `need` (`glibc`), or
|
|
5178
|
+
* a musl libc such as Alpine's (`musl`).
|
|
5179
|
+
*/
|
|
5180
|
+
| {
|
|
5181
|
+
id: "platform";
|
|
5182
|
+
state: "fail";
|
|
5183
|
+
reason: "unsupported" | "glibc" | "musl";
|
|
5184
|
+
os?: string;
|
|
5185
|
+
arch?: string;
|
|
5186
|
+
glibc?: string;
|
|
5187
|
+
need?: string;
|
|
5188
|
+
said?: string;
|
|
5189
|
+
}
|
|
5190
|
+
/**
|
|
5191
|
+
* What the release installer needs and the machine lacks. `warn` when curl alone is missing:
|
|
5192
|
+
* the release is then sent over ssh rather than downloaded there.
|
|
5193
|
+
*/
|
|
5194
|
+
| {
|
|
5195
|
+
id: "tools";
|
|
5196
|
+
state: "pass" | "warn" | "fail";
|
|
5197
|
+
missing: string[];
|
|
5198
|
+
}
|
|
5199
|
+
/**
|
|
5200
|
+
* Whether the machine itself reaches release `version` for its platform. `warn`: out of
|
|
5201
|
+
* reach, so an install cannot download it there; `fail`: both sources answered and neither
|
|
5202
|
+
* has it (not published).
|
|
5203
|
+
*/
|
|
5204
|
+
| {
|
|
5205
|
+
id: "download";
|
|
5206
|
+
state: "pass" | "warn" | "fail";
|
|
5207
|
+
version: string;
|
|
5208
|
+
github: MachineSourceReach;
|
|
5209
|
+
oss: MachineSourceReach;
|
|
5210
|
+
}
|
|
5211
|
+
/** Free space in the machine's home against what an install needs, in MB. */
|
|
5212
|
+
| {
|
|
5213
|
+
id: "disk";
|
|
5214
|
+
state: "pass" | "warn" | "fail";
|
|
5215
|
+
freeMb: number;
|
|
5216
|
+
needMb: number;
|
|
5217
|
+
}
|
|
5218
|
+
/** The port its server would start on: free, already its PenguinHarness server's, or taken by something else. */
|
|
5219
|
+
| {
|
|
5220
|
+
id: "port";
|
|
5221
|
+
state: "pass" | "fail";
|
|
5222
|
+
port: number;
|
|
5223
|
+
holder: "free" | "penguin" | "other";
|
|
5224
|
+
} | {
|
|
5225
|
+
id: "platform" | "tools" | "download" | "disk" | "port";
|
|
5226
|
+
state: "skip";
|
|
5227
|
+
};
|
|
5228
|
+
/**
|
|
5229
|
+
* `POST /api/projects/:projectId/machines/:machineId/diagnose`: the checks, in order. Nothing
|
|
5230
|
+
* is written on the machine; 409 `job_running` while a job works on it.
|
|
5231
|
+
*/
|
|
5232
|
+
interface MachineDiagnosis {
|
|
5233
|
+
machineId: string;
|
|
5234
|
+
checkedAt: string;
|
|
5235
|
+
checks: MachineCheck[];
|
|
5236
|
+
}
|
|
5237
|
+
interface MachinesUseResponse extends MachinesResponse {
|
|
5238
|
+
refused: {
|
|
5239
|
+
machineId: string;
|
|
5240
|
+
why: MachineUseRefusal;
|
|
5241
|
+
}[];
|
|
5242
|
+
}
|
|
5243
|
+
/** `POST /api/projects/:projectId/machines/stop-using`: let go of these machines — connection dropped, Project membership released; the install stays. */
|
|
5244
|
+
interface MachinesStopUsingRequest {
|
|
5245
|
+
machines: string[];
|
|
5246
|
+
}
|
|
5247
|
+
/**
|
|
5248
|
+
* Organization status: `paused` stops every automatic trigger; humans can still talk to any
|
|
5249
|
+
* desk. These two values are the whole lifecycle — no route deletes an organization, so a
|
|
5250
|
+
* paused one keeps its conversations, employees, desks and tickets.
|
|
5251
|
+
*/
|
|
5252
|
+
type OrgStatus = "active" | "paused";
|
|
5253
|
+
/** Approval mode for desk and ticket sessions; unattended runs never get always-ask. */
|
|
5254
|
+
type OrgApprovalMode = "allow-all" | "read-only" | "deny-all";
|
|
5255
|
+
/** The five kanban columns, each a directory under `tickets/<yyyy-mm>/`. */
|
|
5256
|
+
type OrgTicketStatus = "proposed" | "in_progress" | "review" | "done" | "rejected";
|
|
5257
|
+
type OrgTicketPriority = "P0" | "P1" | "P2";
|
|
5258
|
+
/** Live employee state: running when the desk or any ticket session has a Task in progress; paused when budget-paused. */
|
|
5259
|
+
type OrgEmployeeState = "running" | "idle" | "paused";
|
|
5260
|
+
/**
|
|
5261
|
+
* The trigger kinds an `[org_trigger]` block carries. `ticket_notice` is read-only: a ticket
|
|
5262
|
+
* change starts no run of its own, so nothing writes that kind any more, and it stays in the
|
|
5263
|
+
* union because Traces recorded while it did still carry it.
|
|
5264
|
+
*/
|
|
5265
|
+
type OrgTriggerKind = "init" | "event" | "mention" | "ticket_notice" | "ticket_work";
|
|
5266
|
+
/** The ticket changes an employee is told about, listed in the body of its next calendar sweep. */
|
|
5267
|
+
type OrgTicketChange = "assigned" | "blocked" | "blocker_closed" | "done" | "rejected";
|
|
5268
|
+
/** What the last evaluation of a calendar event did. */
|
|
5269
|
+
type OrgCalendarOutcome = "fired" | "queued" | "paused" | "missed" | "error";
|
|
5270
|
+
/**
|
|
5271
|
+
* The organization's working language: the language its handbook, its CEO's initialization
|
|
5272
|
+
* run, every employee brief and every desk and ticket run are written in. Detected from the
|
|
5273
|
+
* mission at creation (CJK text → `zh`, anything else → `en`) unless the request names one.
|
|
5274
|
+
*/
|
|
5275
|
+
type OrgLanguage = "zh" | "en";
|
|
5276
|
+
/** The organization's settings as `org_config.toml` records them. */
|
|
5277
|
+
interface OrganizationSettings {
|
|
5278
|
+
name: string;
|
|
5279
|
+
mission: string;
|
|
5280
|
+
status: OrgStatus;
|
|
5281
|
+
/** IANA timezone: budget periods (natural months) and chat day files follow it. */
|
|
5282
|
+
timezone: string;
|
|
5283
|
+
approvalMode: OrgApprovalMode;
|
|
5284
|
+
/** Chat @-chain limit: a message whose hop reaches it records its mentions without triggering anyone. */
|
|
5285
|
+
mentionChainLimit: number;
|
|
5286
|
+
budgetWarnRatio: number;
|
|
5287
|
+
budgetPauseRatio: number;
|
|
5288
|
+
createdBy: string;
|
|
5289
|
+
/** The shared workspace root when it is not the organization's own `workspace/` (absolute path). */
|
|
5290
|
+
workspace?: string;
|
|
5291
|
+
/** The model desks and ticket sessions run on when the employee names none; absent = the Project default. */
|
|
5292
|
+
model?: {
|
|
5293
|
+
provider: string;
|
|
5294
|
+
modelId: string;
|
|
5295
|
+
};
|
|
5296
|
+
/** The working language (`language` in `org_config.toml`); absent on an organization written before the field existed, which reads as `en`. */
|
|
5297
|
+
language?: OrgLanguage;
|
|
5298
|
+
}
|
|
5299
|
+
/** Period spend against the CEO's budget (= the whole organization). */
|
|
5300
|
+
interface OrgSpendSummary {
|
|
5301
|
+
/** `yyyy-mm` in the organization's timezone. */
|
|
5302
|
+
period: string;
|
|
5303
|
+
cost: number;
|
|
5304
|
+
budget?: number;
|
|
5305
|
+
/** cost / budget; absent without a budget. */
|
|
5306
|
+
ratio?: number;
|
|
5307
|
+
}
|
|
5308
|
+
interface OrganizationSummary {
|
|
5309
|
+
projectId: string;
|
|
5310
|
+
orgId: string;
|
|
5311
|
+
name: string;
|
|
5312
|
+
mission: string;
|
|
5313
|
+
status: OrgStatus;
|
|
5314
|
+
employeeCount: number;
|
|
5315
|
+
runningCount: number;
|
|
5316
|
+
pausedCount: number;
|
|
5317
|
+
/** proposed + in_progress + review. */
|
|
5318
|
+
openTickets: number;
|
|
5319
|
+
blockedTickets: number;
|
|
5320
|
+
createdBy: string;
|
|
5321
|
+
spend: OrgSpendSummary;
|
|
5322
|
+
/** Present when `org_config.toml` / `org_chart.yaml` fail validation: the organization is listed but every automatic trigger is held until it is fixed. */
|
|
5323
|
+
invalid?: string;
|
|
5324
|
+
}
|
|
5325
|
+
interface OrganizationsResponse {
|
|
5326
|
+
organizations: OrganizationSummary[];
|
|
5327
|
+
}
|
|
5328
|
+
interface OrgEmployeeItem {
|
|
5329
|
+
agentId: string;
|
|
5330
|
+
/**
|
|
5331
|
+
* What this employee goes by in the organization, unique across it: the chart's `name`, else
|
|
5332
|
+
* the Agent's display name, else the id — with the id noted (`name (id)`) when the name is
|
|
5333
|
+
* not this employee's alone. It is what every surface shows and what works after `@`.
|
|
5334
|
+
*/
|
|
5335
|
+
name: string;
|
|
5336
|
+
/** The `name` as written in the chart, for editing; absent when the entry has none. */
|
|
5337
|
+
givenName?: string;
|
|
5338
|
+
/**
|
|
5339
|
+
* Present when the employee has an avatar: the content revision of the image served at
|
|
5340
|
+
* `GET …/employees/:agentId/avatar` (append it as `?rev=` — the image is cached for good).
|
|
5341
|
+
* Absent, surfaces draw the letter tile.
|
|
5342
|
+
*/
|
|
5343
|
+
avatarRev?: string;
|
|
5344
|
+
title: string;
|
|
5345
|
+
/** null for the CEO (the root). */
|
|
5346
|
+
reportsTo: string | null;
|
|
5347
|
+
duties?: string;
|
|
5348
|
+
/** As written in the chart: a sub-directory of the shared workspace (`.` = all of it) or an absolute path. */
|
|
5349
|
+
workspace: string;
|
|
5350
|
+
/** Where that resolves to; absent when the directory does not exist (the entry is then invalid). */
|
|
5351
|
+
resolvedWorkspace?: string;
|
|
5352
|
+
/** Monthly budget in USD for this employee plus all subordinates; absent = unbounded. */
|
|
5353
|
+
budget?: number;
|
|
5354
|
+
model?: {
|
|
5355
|
+
provider: string;
|
|
5356
|
+
modelId: string;
|
|
5357
|
+
};
|
|
5358
|
+
state: OrgEmployeeState;
|
|
5359
|
+
/**
|
|
5360
|
+
* The employee's current desk. Absent while the ledger names none, and while the Session
|
|
5361
|
+
* it names no longer exists (deleted by hand, or with its Agent): a desk is listed only
|
|
5362
|
+
* once it can be opened, and the reconcile pass re-opens a missing one when it can.
|
|
5363
|
+
*/
|
|
5364
|
+
desk?: {
|
|
5365
|
+
sessionId: string;
|
|
5366
|
+
workspace: string;
|
|
5367
|
+
openedAt: string;
|
|
5368
|
+
};
|
|
5369
|
+
/** Period spend: own sessions, and cumulative (own + every subordinate). */
|
|
5370
|
+
spend: {
|
|
5371
|
+
own: number;
|
|
5372
|
+
cumulative: number;
|
|
5373
|
+
ratio?: number;
|
|
5374
|
+
};
|
|
5375
|
+
/** Why the entry cannot be triggered (missing Agent, missing workspace directory). */
|
|
5376
|
+
invalid?: string;
|
|
5377
|
+
/**
|
|
5378
|
+
* The entry's Agent no longer exists (`invalid` carries the sentence). Its desk cannot be
|
|
5379
|
+
* opened; the entry stays until a person makes the employee leave, or until an Agent with
|
|
5380
|
+
* the same id is created again (which is how a deleted CEO is restored).
|
|
5381
|
+
*/
|
|
5382
|
+
agentMissing?: true;
|
|
5383
|
+
}
|
|
5384
|
+
interface OrgChartResponse {
|
|
5385
|
+
ceoAgentId: string;
|
|
5386
|
+
employees: OrgEmployeeItem[];
|
|
5387
|
+
}
|
|
5388
|
+
interface OrgCalendarItem {
|
|
5389
|
+
agentId: string;
|
|
5390
|
+
name: string;
|
|
5391
|
+
title?: string;
|
|
5392
|
+
prompt: string;
|
|
5393
|
+
enabled: boolean;
|
|
5394
|
+
startAt: string;
|
|
5395
|
+
period?: string;
|
|
5396
|
+
endAt?: string;
|
|
5397
|
+
status: ScheduleStatus;
|
|
5398
|
+
invalidReason?: string;
|
|
5399
|
+
nextFireAt?: string;
|
|
5400
|
+
lastFiredAt?: string;
|
|
5401
|
+
/** What the most recent evaluation did (absent until the event has been evaluated once). */
|
|
5402
|
+
lastOutcome?: OrgCalendarOutcome;
|
|
5403
|
+
/** The organization or this employee is paused, so due slots are skipped, not fired. */
|
|
5404
|
+
paused: boolean;
|
|
5405
|
+
}
|
|
5406
|
+
interface OrgCalendarResponse {
|
|
5407
|
+
events: OrgCalendarItem[];
|
|
5408
|
+
invalidFiles: Array<{
|
|
5409
|
+
agentId: string;
|
|
5410
|
+
name: string;
|
|
5411
|
+
error: string;
|
|
5412
|
+
}>;
|
|
5413
|
+
}
|
|
5414
|
+
/**
|
|
5415
|
+
* One line of a ticket's operation history, kept in the file's frontmatter apart from the
|
|
5416
|
+
* progress prose: what was done, by whom (`agent:<id>` / `user:<id>` — an employee is recognised
|
|
5417
|
+
* from the Agent id its command subprocesses carry, a person otherwise), and when.
|
|
5418
|
+
*/
|
|
5419
|
+
type OrgTicketHistoryAction = "created" | "assigned" | "moved" | "blocked" | "unblocked" | "progress" | "session_started" | "session_attached" | "edited";
|
|
5420
|
+
interface OrgTicketHistoryEntry {
|
|
5421
|
+
at: string;
|
|
5422
|
+
by: string;
|
|
5423
|
+
action: OrgTicketHistoryAction;
|
|
5424
|
+
/** The action's detail: the column moved to, the new owner, the block reason, the session id. */
|
|
5425
|
+
note?: string;
|
|
5426
|
+
}
|
|
5427
|
+
/**
|
|
5428
|
+
* The ticket id's slug: lowercase letters in hyphen-joined words, no digits (the date prefix
|
|
5429
|
+
* already carries the numbers), chosen for meaning — derived from an ASCII title, proposed by
|
|
5430
|
+
* the Project's model for a title in another language, or passed explicitly.
|
|
5431
|
+
*/
|
|
5432
|
+
declare const TICKET_SLUG_PATTERN: RegExp;
|
|
5433
|
+
interface OrgTicketItem {
|
|
5434
|
+
ticketId: string;
|
|
5435
|
+
title: string;
|
|
5436
|
+
status: OrgTicketStatus;
|
|
5437
|
+
/** The ONE responsible principal (`agent:<id>` / `user:<id>`); who filed it is the history's `created` entry. */
|
|
5438
|
+
owner: string;
|
|
5439
|
+
parent?: string;
|
|
5440
|
+
notify: string[];
|
|
5441
|
+
priority: OrgTicketPriority;
|
|
5442
|
+
due?: string;
|
|
5443
|
+
/** Non-empty = blocked; the ticket stays in its column. */
|
|
5444
|
+
blocked?: string;
|
|
5445
|
+
blockedBy?: string;
|
|
5446
|
+
/** Contributing session ids, in the order they were attached. */
|
|
5447
|
+
sessions: string[];
|
|
5448
|
+
/** Any contributing session has a Task in progress. */
|
|
5449
|
+
running: boolean;
|
|
5450
|
+
/** Period cost of the contributing sessions (a session attached to n tickets counts 1/n here). */
|
|
5451
|
+
cost: number;
|
|
5452
|
+
/** Header/column disagreement or a duplicate id: shown with a danger mark, left where it is. */
|
|
5453
|
+
invalid?: string;
|
|
5454
|
+
}
|
|
5455
|
+
interface OrgTicketSessionItem {
|
|
5456
|
+
sessionId: string;
|
|
5457
|
+
agentId: string;
|
|
5458
|
+
title?: string;
|
|
5459
|
+
status: SessionStatus;
|
|
5460
|
+
lastActiveAt?: string;
|
|
5461
|
+
}
|
|
5462
|
+
interface OrgTicketDetail extends OrgTicketItem {
|
|
5463
|
+
goal: string;
|
|
5464
|
+
acceptanceCriteria: string;
|
|
5465
|
+
/** `## Progress` as plain sentences; who wrote one and when is the matching history entry. */
|
|
5466
|
+
progress: string[];
|
|
5467
|
+
result: string;
|
|
5468
|
+
/** The operation history from the frontmatter, oldest first. */
|
|
5469
|
+
history: OrgTicketHistoryEntry[];
|
|
5470
|
+
/** The whole file, for the Markdown view and for clients that prefer to edit it as text. */
|
|
5471
|
+
body: string;
|
|
5472
|
+
children: string[];
|
|
5473
|
+
/** Own cost plus every descendant's along `Parent`. */
|
|
5474
|
+
rolledUpCost: number;
|
|
5475
|
+
sessionItems: OrgTicketSessionItem[];
|
|
5476
|
+
}
|
|
5477
|
+
interface OrgTicketsResponse {
|
|
5478
|
+
columns: Record<OrgTicketStatus, OrgTicketItem[]>;
|
|
5479
|
+
/** Files that failed to parse (skipped; also recorded as errors). */
|
|
5480
|
+
invalidFiles: Array<{
|
|
5481
|
+
path: string;
|
|
5482
|
+
error: string;
|
|
5483
|
+
}>;
|
|
5484
|
+
}
|
|
5485
|
+
/**
|
|
5486
|
+
* What a `system` line records, structured: the kind of event and its parameters, so a client
|
|
5487
|
+
* renders the sentence in the reader's language and with the principals' display names instead
|
|
5488
|
+
* of showing the English `text` verbatim. `text` stays the English sentence (the CLI, older
|
|
5489
|
+
* clients and the file itself read it); `notice` is the same fact for a client that can do better.
|
|
5490
|
+
*/
|
|
5491
|
+
type OrgChannelNoticeKind = "employee_joined" | "employee_left" | "channel_created" | "channel_archived" | "channel_unarchived" | "channel_joined" | "channel_invited" | "channel_left" | "channel_removed" | "budget_warned" | "budget_paused"
|
|
5492
|
+
/**
|
|
5493
|
+
* Legacy, read-only: ticket changes no longer write into a channel — the board is read from
|
|
5494
|
+
* the board and the overview's inbox. These three kinds stay so the lines already in an
|
|
5495
|
+
* organization's message files keep rendering; nothing writes them any more.
|
|
5496
|
+
*/
|
|
5497
|
+
| "ticket_blocked" | "ticket_done" | "ticket_rejected";
|
|
5498
|
+
/**
|
|
5499
|
+
* The parameters each kind carries, all strings: principals as `agent:<id>` / `user:<id>`
|
|
5500
|
+
* (`agent`, `principal`, `by`, `reportsTo`), a ticket as `ticket` + `title`, a budget event as
|
|
5501
|
+
* `agent`, `period`, `percent`, `cost`, `budget`.
|
|
5502
|
+
*/
|
|
5503
|
+
interface OrgChannelNotice {
|
|
5504
|
+
kind: OrgChannelNoticeKind;
|
|
5505
|
+
params: Record<string, string>;
|
|
5506
|
+
}
|
|
5507
|
+
interface OrgChannelMessage {
|
|
5508
|
+
id: string;
|
|
5509
|
+
/** ISO 8601 UTC. */
|
|
5510
|
+
time: string;
|
|
5511
|
+
/** `agent:<id>` / `user:<id>` / `system`. */
|
|
5512
|
+
sender: string;
|
|
5513
|
+
hop: number;
|
|
5514
|
+
text: string;
|
|
5515
|
+
/** Principals mentioned, `all` included. */
|
|
5516
|
+
mentions: string[];
|
|
5517
|
+
refs?: {
|
|
5518
|
+
ticket?: string;
|
|
5519
|
+
session?: string;
|
|
5520
|
+
replyTo?: string;
|
|
5521
|
+
};
|
|
5522
|
+
/** Present on `system` lines the server wrote with a structured notice; absent on lines from before the field existed. */
|
|
5523
|
+
notice?: OrgChannelNotice;
|
|
5524
|
+
}
|
|
5525
|
+
/**
|
|
5526
|
+
* One channel as the API reports it. The all-hands channel (`default_channel`,
|
|
5527
|
+
* `everyone: true`) exists for as long as the organization does and every employee and
|
|
5528
|
+
* Project member is in it; every other channel carries the membership its members edit.
|
|
5529
|
+
*/
|
|
5530
|
+
interface OrgChannelItem {
|
|
5531
|
+
channelId: string;
|
|
5532
|
+
/** As stored; the UI renders the all-hands channel's label itself. */
|
|
5533
|
+
name: string;
|
|
5534
|
+
/** "" when unset. */
|
|
5535
|
+
purpose: string;
|
|
5536
|
+
/** True only for `default_channel`: membership is implicit. */
|
|
5537
|
+
everyone: boolean;
|
|
5538
|
+
/** An archived channel is read-only and folded away. */
|
|
5539
|
+
archived: boolean;
|
|
5540
|
+
/** `user:<id>` / `agent:<id>` / `system`. */
|
|
5541
|
+
createdBy: string;
|
|
5542
|
+
/** ISO 8601 UTC. */
|
|
5543
|
+
createdAt: string;
|
|
5544
|
+
/** Implicit membership counted for the all-hands channel. */
|
|
5545
|
+
memberCount: number;
|
|
5546
|
+
/** Whether the caller (person or employee) is a member. */
|
|
5547
|
+
isMember: boolean;
|
|
5548
|
+
/** People only; 0 for an employee caller. */
|
|
5549
|
+
unread: number;
|
|
5550
|
+
/** People only; 0 for an employee caller. */
|
|
5551
|
+
mentionsMe: number;
|
|
5552
|
+
lastMessageAt: string | null;
|
|
5553
|
+
}
|
|
5554
|
+
interface OrgChannelMember {
|
|
5555
|
+
/** `agent:<id>` or `user:<id>`. */
|
|
5556
|
+
principal: string;
|
|
5557
|
+
name: string;
|
|
5558
|
+
kind: "agent" | "user";
|
|
5559
|
+
}
|
|
5560
|
+
interface OrgChannelDetail extends OrgChannelItem {
|
|
5561
|
+
/** The all-hands channel resolves to every employee plus every Project member. */
|
|
5562
|
+
members: OrgChannelMember[];
|
|
5563
|
+
}
|
|
5564
|
+
interface OrgChannelsResponse {
|
|
5565
|
+
/** `default_channel` first, then by name. */
|
|
5566
|
+
channels: OrgChannelItem[];
|
|
5567
|
+
}
|
|
5568
|
+
interface OrgChannelCreateRequest {
|
|
5569
|
+
channelId: string;
|
|
5570
|
+
name?: string;
|
|
5571
|
+
purpose?: string;
|
|
5572
|
+
}
|
|
5573
|
+
interface OrgChannelPatchRequest {
|
|
5574
|
+
name?: string;
|
|
5575
|
+
purpose?: string;
|
|
5576
|
+
archived?: boolean;
|
|
5577
|
+
}
|
|
5578
|
+
interface OrgChannelMemberRequest {
|
|
5579
|
+
/** `agent:<id>` (an employee) or `user:<id>` (a Project member). */
|
|
5580
|
+
principal: string;
|
|
5581
|
+
}
|
|
5582
|
+
interface OrgChannelMessagesResponse {
|
|
5583
|
+
/** The channel served. */
|
|
5584
|
+
channelId: string;
|
|
5585
|
+
/** The day file served (`yyyy-mm-dd` in the organization's timezone). */
|
|
5586
|
+
date: string;
|
|
5587
|
+
/** The days this channel has a file for, newest first, for paging back. */
|
|
5588
|
+
days: string[];
|
|
5589
|
+
messages: OrgChannelMessage[];
|
|
5590
|
+
/** Messages of this channel after the caller's read cursor in it, across the recent days. */
|
|
5591
|
+
unread: number;
|
|
5592
|
+
/** Of those, the ones that mention the caller (or all). */
|
|
5593
|
+
mentionsMe: number;
|
|
5594
|
+
lastReadId?: string;
|
|
5595
|
+
}
|
|
5596
|
+
interface OrgBudgetAlert {
|
|
5597
|
+
agentId: string;
|
|
5598
|
+
period: string;
|
|
5599
|
+
warnedAt?: string;
|
|
5600
|
+
pausedAt?: string;
|
|
5601
|
+
}
|
|
5602
|
+
interface OrgFinanceEmployee {
|
|
5603
|
+
agentId: string;
|
|
5604
|
+
name: string;
|
|
5605
|
+
title: string;
|
|
5606
|
+
reportsTo: string | null;
|
|
5607
|
+
own: number;
|
|
5608
|
+
cumulative: number;
|
|
5609
|
+
budget?: number;
|
|
5610
|
+
ratio?: number;
|
|
5611
|
+
warned: boolean;
|
|
5612
|
+
paused: boolean;
|
|
5613
|
+
}
|
|
5614
|
+
interface OrgFinanceTicket {
|
|
5615
|
+
ticketId: string;
|
|
5616
|
+
title: string;
|
|
5617
|
+
status: OrgTicketStatus;
|
|
5618
|
+
parent?: string;
|
|
5619
|
+
cost: number;
|
|
5620
|
+
rolledUp: number;
|
|
5621
|
+
}
|
|
5622
|
+
interface OrgFinanceResponse {
|
|
5623
|
+
period: string;
|
|
5624
|
+
currency: "USD";
|
|
5625
|
+
employees: OrgFinanceEmployee[];
|
|
5626
|
+
tickets: OrgFinanceTicket[];
|
|
5627
|
+
/** Daily cost of the organization's sessions over the period. */
|
|
5628
|
+
daily: Array<{
|
|
5629
|
+
date: string;
|
|
5630
|
+
cost: number;
|
|
5631
|
+
}>;
|
|
5632
|
+
alerts: OrgBudgetAlert[];
|
|
5633
|
+
total: number;
|
|
5634
|
+
/** Some usage ran on a model without pricing: tokens were counted, cost is a lower bound. */
|
|
5635
|
+
unpriced: boolean;
|
|
5636
|
+
}
|
|
5637
|
+
interface OrgDeskItem {
|
|
5638
|
+
agentId: string;
|
|
5639
|
+
name: string;
|
|
5640
|
+
sessionId: string;
|
|
5641
|
+
title?: string;
|
|
5642
|
+
status: SessionStatus;
|
|
5643
|
+
workspace: string;
|
|
5644
|
+
lastActiveAt?: string;
|
|
5645
|
+
/**
|
|
5646
|
+
* Present when the desk session has an ENABLED messaging binding: its channel, read as
|
|
5647
|
+
* `SessionInfo.messagingChannel` is (the company sidebar's desk row draws the same mark as a
|
|
5648
|
+
* development row, and the development list never holds a desk).
|
|
5649
|
+
*/
|
|
5650
|
+
messagingChannel?: MessagingChannel;
|
|
5651
|
+
}
|
|
5652
|
+
interface OrgSessionsResponse {
|
|
5653
|
+
/** One per employee whose current desk Session exists; a desk the ledger names but the server no longer has is left out. */
|
|
5654
|
+
desks: OrgDeskItem[];
|
|
5655
|
+
tickets: Array<{
|
|
5656
|
+
ticketId: string;
|
|
5657
|
+
title: string;
|
|
5658
|
+
status: OrgTicketStatus;
|
|
5659
|
+
sessions: OrgTicketSessionItem[];
|
|
5660
|
+
}>;
|
|
5661
|
+
}
|
|
5662
|
+
interface OrgDeskResponse {
|
|
5663
|
+
agentId: string;
|
|
5664
|
+
sessionId: string;
|
|
5665
|
+
workspace: string;
|
|
5666
|
+
openedAt: string;
|
|
5667
|
+
/** True when this call created the desk session. */
|
|
5668
|
+
created: boolean;
|
|
5669
|
+
}
|
|
5670
|
+
interface OrganizationDetail extends OrganizationSummary {
|
|
5671
|
+
settings: OrganizationSettings;
|
|
5672
|
+
board: Record<OrgTicketStatus, number>;
|
|
5673
|
+
/** Today's calendar events (organization timezone) with their outcomes. */
|
|
5674
|
+
today: OrgCalendarItem[];
|
|
5675
|
+
pending: {
|
|
5676
|
+
/** Unread messages mentioning the caller (or all). */
|
|
5677
|
+
mentions: number;
|
|
5678
|
+
reviewTickets: OrgTicketItem[];
|
|
5679
|
+
blockedByMe: OrgTicketItem[];
|
|
5680
|
+
};
|
|
5681
|
+
/** The last messages of the all-hands channel. */
|
|
5682
|
+
recentMessages: OrgChannelMessage[];
|
|
5683
|
+
alerts: OrgBudgetAlert[];
|
|
5684
|
+
/** What the overview's inbox lists; absent only from a server older than the field. */
|
|
5685
|
+
inbox?: OrgInbox;
|
|
5686
|
+
/** The CEO's desk session once opened (creation opens it). */
|
|
5687
|
+
ceoDeskSessionId?: string;
|
|
5688
|
+
}
|
|
5689
|
+
/**
|
|
5690
|
+
* The overview's inbox: the three things a person is waited on or told about — messages
|
|
5691
|
+
* that name them (or `@all`) in the all-hands channel, the tickets that are blocked (all of
|
|
5692
|
+
* them, whoever they wait on), and the tickets closed as done this period. Newest first in
|
|
5693
|
+
* each list; each capped at a page.
|
|
5694
|
+
*/
|
|
5695
|
+
interface OrgInbox {
|
|
5696
|
+
mentions: OrgChannelMessage[];
|
|
5697
|
+
blockedTickets: OrgTicketItem[];
|
|
5698
|
+
doneTickets: Array<OrgTicketItem & {
|
|
5699
|
+
closedAt?: string;
|
|
5700
|
+
}>;
|
|
5701
|
+
}
|
|
5702
|
+
interface OrganizationCreateRequest {
|
|
5703
|
+
/** Semantic id, unique within the Project; also the directory name. */
|
|
5704
|
+
orgId: string;
|
|
5705
|
+
name?: string;
|
|
5706
|
+
mission: string;
|
|
5707
|
+
timezone?: string;
|
|
5708
|
+
/** An existing absolute directory to use as the shared workspace; default = the organization's own `workspace/`. */
|
|
5709
|
+
workspace?: string;
|
|
5710
|
+
/** The model for desks and ticket sessions (a configured pair); default = the Project default. */
|
|
5711
|
+
model?: {
|
|
5712
|
+
provider: string;
|
|
5713
|
+
modelId: string;
|
|
5714
|
+
};
|
|
5715
|
+
/**
|
|
5716
|
+
* The CEO's monthly budget in USD, written as the `budget` of its `org_chart.yaml` entry.
|
|
5717
|
+
* Budgets are compared on the cumulative line, so the CEO's is the whole company's.
|
|
5718
|
+
* Omitted = 100; 0 is a real (zero) budget, not "unbounded" — only clearing the field
|
|
5719
|
+
* later (`PATCH …/employees/:agentId` with `budget: null`) leaves the CEO unbounded.
|
|
5720
|
+
*/
|
|
5721
|
+
ceoBudget?: number;
|
|
5722
|
+
/** The working language; omitted = detected from the mission. */
|
|
5723
|
+
language?: OrgLanguage;
|
|
5724
|
+
}
|
|
5725
|
+
interface OrganizationPatchRequest {
|
|
5726
|
+
name?: string;
|
|
5727
|
+
mission?: string;
|
|
5728
|
+
status?: OrgStatus;
|
|
5729
|
+
approvalMode?: OrgApprovalMode;
|
|
5730
|
+
timezone?: string;
|
|
5731
|
+
mentionChainLimit?: number;
|
|
5732
|
+
budgetWarnRatio?: number;
|
|
5733
|
+
budgetPauseRatio?: number;
|
|
5734
|
+
/** null returns to the organization's own `workspace/`. */
|
|
5735
|
+
workspace?: string | null;
|
|
5736
|
+
/** null returns to the Project default. */
|
|
5737
|
+
model?: {
|
|
5738
|
+
provider: string;
|
|
5739
|
+
modelId: string;
|
|
5740
|
+
} | null;
|
|
5741
|
+
language?: OrgLanguage;
|
|
5742
|
+
}
|
|
5743
|
+
/**
|
|
5744
|
+
* What a proposed semantic id names. Each kind has its own shape — organization and channel
|
|
5745
|
+
* ids carry a `co_` / `ch_` prefix, a non-admin's Project id its owner's `<username>-`, a
|
|
5746
|
+
* Benchmark id is kebab-case — and its own set of ids to avoid.
|
|
5747
|
+
*/
|
|
5748
|
+
type SemanticIdKind = "org" | "channel" | "project" | "agent" | "benchmark";
|
|
5749
|
+
/**
|
|
5750
|
+
* A semantic id proposed for a display name — every create dialog that names an object with a
|
|
5751
|
+
* semantic id (a Project, an Agent, a Benchmark, an organization, a channel) lets the user name
|
|
5752
|
+
* the thing first and derive the id from that name. The server asks the Project's default
|
|
5753
|
+
* model for a short English id in the kind's spelling (a Chinese name has no mechanical
|
|
5754
|
+
* transliteration), falling back to an ASCII slug of the name when the model is unavailable,
|
|
5755
|
+
* and to a dated placeholder when neither can name it. The request never fails for a name it
|
|
5756
|
+
* cannot translate: a dialog that asked for an id always gets one back.
|
|
5757
|
+
*/
|
|
5758
|
+
interface SemanticIdSuggestRequest {
|
|
5759
|
+
/** The display name typed so far (or the mission / description, when nothing else names the thing). */
|
|
5760
|
+
name: string;
|
|
5761
|
+
/** What the id is for: decides the id's shape, the prompt's examples and the ids avoided. */
|
|
5762
|
+
kind: SemanticIdKind;
|
|
5763
|
+
/**
|
|
5764
|
+
* Ids already in use in the target scope; the proposal avoids them. For a Project, an Agent or
|
|
5765
|
+
* a Benchmark, the server also avoids, on its own, every id that kind's create route refuses
|
|
5766
|
+
* as taken, a leftover folder no list shows included.
|
|
5767
|
+
*/
|
|
5768
|
+
taken?: string[];
|
|
5769
|
+
}
|
|
5770
|
+
/**
|
|
5771
|
+
* Why a proposal fell all the way through to a placeholder — what the client tells the user to
|
|
5772
|
+
* explain the id it was just handed. `no_default_model`: the Project has no default model to
|
|
5773
|
+
* ask. `model_failed`: it was asked and the request failed (no credential, a rejection, a
|
|
5774
|
+
* timeout). `unusable_answer`: it answered twice and neither answer yielded an id.
|
|
5775
|
+
* `no_ascii`: no model was consulted at all and the name carries no ASCII to transliterate.
|
|
5776
|
+
*/
|
|
5777
|
+
type SemanticIdSuggestReason = "no_default_model" | "model_failed" | "unusable_answer" | "no_ascii";
|
|
5778
|
+
interface SemanticIdSuggestResponse {
|
|
5779
|
+
/**
|
|
5780
|
+
* An id the kind's create route accepts, not in `taken`: `^[a-z][a-z0-9_]{1,63}$` for most
|
|
5781
|
+
* kinds, `<username>-<suffix>` for a non-admin's Project, kebab-case for a Benchmark.
|
|
5782
|
+
*/
|
|
5783
|
+
id: string;
|
|
5784
|
+
/** Who produced it: the model, the ASCII fallback, or the dated placeholder that names nothing. */
|
|
5785
|
+
source: "model" | "fallback" | "placeholder";
|
|
5786
|
+
/** Present only with `source: "placeholder"`: why the two real paths produced nothing. */
|
|
5787
|
+
reason?: SemanticIdSuggestReason;
|
|
5788
|
+
}
|
|
5789
|
+
interface OrgHireRequest {
|
|
5790
|
+
/** Employ an existing Agent … */
|
|
5791
|
+
agentId?: string;
|
|
5792
|
+
/** … or create one (the two are exclusive). Plugins default to agent-company + agent-development. */
|
|
5793
|
+
newAgent?: {
|
|
5794
|
+
agentId: string;
|
|
5795
|
+
name?: string;
|
|
5796
|
+
description?: string;
|
|
5797
|
+
plugins?: string[];
|
|
5798
|
+
};
|
|
5799
|
+
/**
|
|
5800
|
+
* What the organization calls the employee (any script, one line, no `@`, ≤ 64 characters).
|
|
5801
|
+
* Omitted, a new Agent's `name` is used; with neither, the Agent's display name stands in.
|
|
5802
|
+
*/
|
|
5803
|
+
name?: string;
|
|
5804
|
+
title: string;
|
|
5805
|
+
reportsTo: string;
|
|
5806
|
+
workspace?: string;
|
|
5807
|
+
budget?: number;
|
|
5808
|
+
duties?: string;
|
|
5809
|
+
model?: {
|
|
5810
|
+
provider: string;
|
|
5811
|
+
modelId: string;
|
|
5812
|
+
};
|
|
5813
|
+
}
|
|
5814
|
+
interface OrgEmployeePatchRequest {
|
|
5815
|
+
/** null (or an empty string) clears the name: back to the Agent's display name. */
|
|
5816
|
+
name?: string | null;
|
|
5817
|
+
title?: string;
|
|
5818
|
+
reportsTo?: string;
|
|
5819
|
+
workspace?: string;
|
|
5820
|
+
/** null clears the budget. */
|
|
5821
|
+
budget?: number | null;
|
|
5822
|
+
duties?: string;
|
|
5823
|
+
/** null clears the model (back to the Project default). */
|
|
5824
|
+
model?: {
|
|
5825
|
+
provider: string;
|
|
5826
|
+
modelId: string;
|
|
5827
|
+
} | null;
|
|
5828
|
+
}
|
|
5829
|
+
interface OrgCalendarUpsertRequest {
|
|
5830
|
+
/** POST only: the employee the event belongs to. */
|
|
5831
|
+
agentId?: string;
|
|
5832
|
+
/** POST only: the file name. */
|
|
5833
|
+
name?: string;
|
|
5834
|
+
title?: string;
|
|
5835
|
+
prompt: string;
|
|
5836
|
+
enabled: boolean;
|
|
5837
|
+
startAt: string;
|
|
5838
|
+
period?: string;
|
|
5839
|
+
endAt?: string;
|
|
5840
|
+
}
|
|
5841
|
+
/**
|
|
5842
|
+
* What a calendar write answers: the stored event, plus advisory `warnings` — one line each —
|
|
5843
|
+
* about the rota: another employee's recurring event on the same start minute, or the same
|
|
5844
|
+
* employee already holding a recurring event (desks that fire together compete for the same
|
|
5845
|
+
* budget minute and the same tickets). The write succeeds regardless; the CLI prints the
|
|
5846
|
+
* lines so the scheduling employee can stagger.
|
|
5847
|
+
*/
|
|
5848
|
+
interface OrgCalendarWriteResponse extends OrgCalendarItem {
|
|
5849
|
+
warnings?: string[];
|
|
5850
|
+
}
|
|
5851
|
+
interface OrgTicketCreateRequest {
|
|
5852
|
+
title: string;
|
|
5853
|
+
/** Overrides the slug derived from the title; lowercase English words joined by hyphens. */
|
|
5854
|
+
slug?: string;
|
|
5855
|
+
goal?: string;
|
|
5856
|
+
acceptanceCriteria?: string;
|
|
5857
|
+
/** The whole Markdown body instead of goal + acceptanceCriteria (the frontmatter is still generated). */
|
|
5858
|
+
body?: string;
|
|
5859
|
+
/**
|
|
5860
|
+
* The responsible principal: an employee's `agent:<id>` (or bare Agent id) or a member's
|
|
5861
|
+
* `user:<id>`. Default = the caller — the session's employee inside a desk or ticket
|
|
5862
|
+
* session, else the token's or cookie's user.
|
|
5863
|
+
*/
|
|
5864
|
+
owner?: string;
|
|
5865
|
+
parent?: string;
|
|
5866
|
+
notify?: string[];
|
|
5867
|
+
priority?: OrgTicketPriority;
|
|
5868
|
+
due?: string;
|
|
5869
|
+
}
|
|
5870
|
+
interface OrgTicketUpdateRequest {
|
|
5871
|
+
title?: string;
|
|
5872
|
+
/** The new responsible principal; never null — a ticket always has an owner. */
|
|
5873
|
+
owner?: string;
|
|
5874
|
+
parent?: string | null;
|
|
5875
|
+
notify?: string[];
|
|
5876
|
+
priority?: OrgTicketPriority;
|
|
5877
|
+
due?: string | null;
|
|
5878
|
+
goal?: string;
|
|
5879
|
+
acceptanceCriteria?: string;
|
|
5880
|
+
result?: string;
|
|
5881
|
+
}
|
|
5882
|
+
interface OrgTicketMoveRequest {
|
|
5883
|
+
status: OrgTicketStatus;
|
|
5884
|
+
/** Required when moving into rejected; recorded under Result. */
|
|
5885
|
+
reason?: string;
|
|
5886
|
+
}
|
|
5887
|
+
interface OrgTicketBlockRequest {
|
|
5888
|
+
reason: string;
|
|
5889
|
+
/** A ticket id or a principal. */
|
|
5890
|
+
by?: string;
|
|
5891
|
+
}
|
|
5892
|
+
interface OrgTicketProgressRequest {
|
|
5893
|
+
text: string;
|
|
5894
|
+
/**
|
|
5895
|
+
* The calling session (CLI: PENGUIN_SESSION_ID); the session is booked as a contributing
|
|
5896
|
+
* session and the history entry is attributed to its employee. Honoured only for a request
|
|
5897
|
+
* carrying the local API token — the control environment's credential; a signed-in user's
|
|
5898
|
+
* write is attributed to the user.
|
|
5899
|
+
*/
|
|
5900
|
+
sessionId?: string;
|
|
5901
|
+
/**
|
|
5902
|
+
* The calling employee's Agent id (CLI: PENGUIN_AGENT_ID from the control environment), the
|
|
5903
|
+
* identity a write is recorded under; it wins over the session's employee, is honoured only
|
|
5904
|
+
* with the local API token, like sessionId, and is ignored — the write falls back to the
|
|
5905
|
+
* session's employee, then to the person — when it names no employee.
|
|
5906
|
+
*/
|
|
5907
|
+
agentId?: string;
|
|
5908
|
+
}
|
|
5909
|
+
interface OrgTicketStartRequest {
|
|
5910
|
+
/** The employee the ticket session runs as (CLI: PENGUIN_AGENT_ID); defaults to the ticket owner. */
|
|
5911
|
+
agentId?: string;
|
|
5912
|
+
message?: string;
|
|
5913
|
+
/** Another directory inside the shared workspace; defaults to the employee's desk workspace. */
|
|
5914
|
+
workspace?: string;
|
|
5915
|
+
}
|
|
5916
|
+
interface OrgTicketStartResponse {
|
|
5917
|
+
sessionId: string;
|
|
5918
|
+
}
|
|
5919
|
+
interface OrgTicketAttachRequest {
|
|
5920
|
+
sessionId: string;
|
|
5921
|
+
}
|
|
5922
|
+
interface OrgChannelMessageSendRequest {
|
|
5923
|
+
text: string;
|
|
5924
|
+
refs?: {
|
|
5925
|
+
ticket?: string;
|
|
5926
|
+
session?: string;
|
|
5927
|
+
replyTo?: string;
|
|
5928
|
+
};
|
|
5929
|
+
/**
|
|
5930
|
+
* The calling session (CLI: PENGUIN_SESSION_ID): the message is sent as its Agent and
|
|
5931
|
+
* inherits its hop. Honoured only for a request carrying the local API token — the control
|
|
5932
|
+
* environment's credential; a signed-in user's message is sent as the user, at hop 0.
|
|
5933
|
+
*/
|
|
5934
|
+
sessionId?: string;
|
|
5935
|
+
}
|
|
5936
|
+
interface OrgChannelReadRequest {
|
|
5937
|
+
/** Mark everything up to this message id as read. */
|
|
5938
|
+
upTo: string;
|
|
5939
|
+
}
|
|
5940
|
+
/** The handbook index (`handbook/README.md`), the file every work run reads first. */
|
|
5941
|
+
interface OrgHandbookResponse {
|
|
5942
|
+
content: string;
|
|
5943
|
+
}
|
|
5944
|
+
/** One file of the organization handbook (`handbook/`, the company's knowledge base); `path` is relative to that directory. */
|
|
5945
|
+
interface OrgHandbookFile {
|
|
5946
|
+
path: string;
|
|
5947
|
+
size: number;
|
|
5948
|
+
updatedAt: string;
|
|
5949
|
+
}
|
|
5950
|
+
interface OrgHandbookFilesResponse {
|
|
5951
|
+
/** The index first, then the other documents by path. */
|
|
5952
|
+
files: OrgHandbookFile[];
|
|
5953
|
+
}
|
|
5954
|
+
interface OrgHandbookFileResponse {
|
|
5955
|
+
path: string;
|
|
5956
|
+
content: string;
|
|
5957
|
+
}
|
|
5958
|
+
interface OrgHandbookFileWriteRequest {
|
|
5959
|
+
content: string;
|
|
5960
|
+
}
|
|
5961
|
+
/** Company-mode notifications on the user-level event stream (best effort; the query routes carry the durable state). */
|
|
5962
|
+
type CompanyServerEvent =
|
|
5963
|
+
/** A work run (desk session) or ticket session was started by the organization scheduler or a ticket start. */
|
|
5964
|
+
{
|
|
5965
|
+
type: "org_run";
|
|
5966
|
+
projectId: string;
|
|
5967
|
+
orgId: string;
|
|
5968
|
+
agentId: string;
|
|
5969
|
+
sessionId: string;
|
|
5970
|
+
kind: OrgTriggerKind;
|
|
5971
|
+
}
|
|
5972
|
+
/** A new channel message (mentions included, so the client can tell whether it is addressed). */
|
|
5973
|
+
| {
|
|
5974
|
+
type: "org_channel";
|
|
5975
|
+
projectId: string;
|
|
5976
|
+
orgId: string;
|
|
5977
|
+
channelId: string;
|
|
5978
|
+
message: OrgChannelMessage;
|
|
5979
|
+
}
|
|
5980
|
+
/** A ticket's status, owner, blocked state or contributing sessions changed. */
|
|
5981
|
+
| {
|
|
5982
|
+
type: "org_ticket";
|
|
5983
|
+
projectId: string;
|
|
5984
|
+
orgId: string;
|
|
5985
|
+
ticketId: string;
|
|
5986
|
+
change: string;
|
|
5987
|
+
}
|
|
5988
|
+
/** Budget warning, pause or resume for an employee. */
|
|
5989
|
+
| {
|
|
5990
|
+
type: "org_budget";
|
|
5991
|
+
projectId: string;
|
|
5992
|
+
orgId: string;
|
|
5993
|
+
agentId: string;
|
|
5994
|
+
state: "warned" | "paused" | "resumed";
|
|
5995
|
+
ratio: number;
|
|
5996
|
+
};
|
|
5997
|
+
/** How the web app renders a contributed surface: a name from its own registry, or an iframe. */
|
|
5998
|
+
type RendererRef = {
|
|
5999
|
+
builtin: string;
|
|
6000
|
+
} | {
|
|
6001
|
+
iframe: {
|
|
6002
|
+
src: string;
|
|
6003
|
+
namespace: string;
|
|
6004
|
+
};
|
|
6005
|
+
};
|
|
6006
|
+
/** One contribution to a web slot: its id, the contributing module, and the slot's data. */
|
|
6007
|
+
interface WebContribution {
|
|
6008
|
+
id: string;
|
|
6009
|
+
from: string;
|
|
6010
|
+
[key: string]: unknown;
|
|
6011
|
+
}
|
|
6012
|
+
interface ContributionsResponse {
|
|
6013
|
+
pages: WebContribution[];
|
|
6014
|
+
agentTabs: WebContribution[];
|
|
6015
|
+
sessionTabs: WebContribution[];
|
|
6016
|
+
}
|
|
6017
|
+
/**
|
|
6018
|
+
* One field of a settings group a module declares (its `PluginConfigProvider.groups`
|
|
6019
|
+
* contribution's `properties.<name>`): what the Settings dialog draws for it. `secret` is
|
|
6020
|
+
* drawn as a password field and masked on the way out; `enum` is a choice among `options`;
|
|
6021
|
+
* `list` is a list of strings, drawn one per line; `table` is a fixed set of `rows`, each a
|
|
6022
|
+
* value per one of its `columns`, drawn as a table.
|
|
6023
|
+
*/
|
|
6024
|
+
interface PluginConfigField {
|
|
6025
|
+
type: "string" | "secret" | "boolean" | "number" | "enum" | "list" | "table";
|
|
6026
|
+
title: string;
|
|
6027
|
+
titleZh?: string;
|
|
6028
|
+
/** What the field means: disclosed behind a "?" beside its title. */
|
|
6029
|
+
description?: string;
|
|
6030
|
+
descriptionZh?: string;
|
|
6031
|
+
/**
|
|
6032
|
+
* The shape a value must take ("one absolute path per line"): shown under the field at all
|
|
6033
|
+
* times, since it is read while typing.
|
|
6034
|
+
*/
|
|
6035
|
+
hint?: string;
|
|
6036
|
+
hintZh?: string;
|
|
6037
|
+
placeholder?: string;
|
|
6038
|
+
/** The value a package with nothing stored reads; also what an empty field falls back to. */
|
|
6039
|
+
default?: string | number | boolean | string[];
|
|
6040
|
+
/**
|
|
6041
|
+
* Drawn in the card's Advanced fold, collapsed by default, rather than among the basic
|
|
6042
|
+
* fields. Presentation only: it is stored, validated and read like any other field.
|
|
6043
|
+
*/
|
|
6044
|
+
advanced?: boolean;
|
|
6045
|
+
/** A save that would leave this field empty is refused. */
|
|
6046
|
+
required?: boolean;
|
|
6047
|
+
/** `enum` only: the values it may take, in display order. */
|
|
6048
|
+
options?: PluginConfigOption[];
|
|
6049
|
+
/** `list` only: the most entries a save may leave (after trimming and de-duplicating). */
|
|
6050
|
+
maxItems?: number;
|
|
6051
|
+
/** `number` only: the smallest and largest value a save may store. */
|
|
6052
|
+
minimum?: number;
|
|
6053
|
+
maximum?: number;
|
|
6054
|
+
/** `string` / `list` only: a regular expression every value (every line) must match. */
|
|
6055
|
+
pattern?: string;
|
|
6056
|
+
/** What a save refused by `pattern` says, after the field's name (e.g. "must be an absolute path"). */
|
|
6057
|
+
patternErrorMessage?: string;
|
|
6058
|
+
/**
|
|
6059
|
+
* `table` only: its columns, in display order, and its rows, in display order. The table
|
|
6060
|
+
* has no `default`: the rows' declared cells are its defaults, and what is stored is only
|
|
6061
|
+
* the cells that differ from them — `{ [row id]: { [column]: value } }`.
|
|
6062
|
+
*/
|
|
6063
|
+
columns?: PluginConfigTableColumn[];
|
|
6064
|
+
rows?: PluginConfigTableRow[];
|
|
6065
|
+
/**
|
|
6066
|
+
* `table` only: a single choice of one row — the sandbox's default preset. The choice is
|
|
6067
|
+
* stored in `field`, an `enum` field of the same group whose options are the row ids (plus,
|
|
6068
|
+
* in an `extensible` table, the ids of the rows added to it); the page draws that field only
|
|
6069
|
+
* as its title in brackets after the chosen row's name ("(Default)"), and picks it from a
|
|
6070
|
+
* row's "…" menu.
|
|
6071
|
+
*/
|
|
6072
|
+
rowChoice?: PluginConfigRowChoice;
|
|
6073
|
+
/**
|
|
6074
|
+
* `table` only: rows may be added (and only those deleted, from the row's "…" menu) and every
|
|
6075
|
+
* row reordered. A new row
|
|
6076
|
+
* starts from these values. What is stored, beside the declared rows' changed cells, is the
|
|
6077
|
+
* added rows under `"$added"` (`{ [row id]: { [column]: value } }`, every column present) and
|
|
6078
|
+
* the row order under `"$order"` (row ids); neither key can be a row id. A save sends either
|
|
6079
|
+
* key whole; a document without them reads as the declared rows in declared order.
|
|
6080
|
+
*/
|
|
6081
|
+
extensible?: PluginConfigNewRow;
|
|
6082
|
+
/**
|
|
6083
|
+
* `table` only: a header drawn over adjacent columns that belong together (the sandbox's
|
|
6084
|
+
* Pin, under "Action"). `columns` names them. When the group ends the columns, the row's drag
|
|
6085
|
+
* handle and "…" menu join it.
|
|
6086
|
+
*/
|
|
6087
|
+
columnGroup?: PluginConfigColumnGroup;
|
|
6088
|
+
/**
|
|
6089
|
+
* `table` only: a `boolean` column drawn as a pin toggle rather than a switch — a row pinned
|
|
6090
|
+
* to a list (the sandbox presets in the composer's menu). The texts are its tooltip in each
|
|
6091
|
+
* state. Declared on the table, not the column, so every column keeps one shape.
|
|
6092
|
+
*/
|
|
6093
|
+
pin?: PluginConfigPinColumn;
|
|
6094
|
+
}
|
|
6095
|
+
/** A table's pin column: which boolean column, and its tooltip pinned and not. */
|
|
6096
|
+
interface PluginConfigPinColumn {
|
|
6097
|
+
column: string;
|
|
6098
|
+
on: string;
|
|
6099
|
+
onZh?: string;
|
|
6100
|
+
off: string;
|
|
6101
|
+
offZh?: string;
|
|
6102
|
+
}
|
|
6103
|
+
/**
|
|
6104
|
+
* A table's single choice of a row: the `enum` field it stores into, and its title, drawn in
|
|
6105
|
+
* brackets after the chosen row's name. The choice may name no row (nothing stored, and the
|
|
6106
|
+
* group's `derive` gives none): no row is marked and a save is not refused for it. A save that
|
|
6107
|
+
* leaves it naming a row the table no longer has is refused.
|
|
6108
|
+
*/
|
|
6109
|
+
interface PluginConfigRowChoice {
|
|
6110
|
+
field: string;
|
|
6111
|
+
title: string;
|
|
6112
|
+
titleZh?: string;
|
|
6113
|
+
}
|
|
6114
|
+
/** One column of a `table` field: a scalar field type (`string`, `boolean`, or an `enum` with `options`). */
|
|
6115
|
+
interface PluginConfigTableColumn {
|
|
6116
|
+
name: string;
|
|
6117
|
+
type: "string" | "boolean" | "enum";
|
|
6118
|
+
title: string;
|
|
6119
|
+
titleZh?: string;
|
|
6120
|
+
/** What the column means: disclosed behind a "?" beside its header. */
|
|
6121
|
+
description?: string;
|
|
6122
|
+
descriptionZh?: string;
|
|
6123
|
+
options?: PluginConfigOption[];
|
|
6124
|
+
}
|
|
6125
|
+
/** One row of a `table` field: its id and its declared cells. */
|
|
6126
|
+
interface PluginConfigTableRow {
|
|
6127
|
+
id: string;
|
|
6128
|
+
/** Every column's declared value. */
|
|
6129
|
+
values: Record<string, string | boolean>;
|
|
6130
|
+
/** A string cell's declared value in Chinese, shown until a save changes the cell. */
|
|
6131
|
+
valuesZh?: Record<string, string>;
|
|
6132
|
+
/** Columns whose cell in this row a save may not change. */
|
|
6133
|
+
locked?: string[];
|
|
6134
|
+
/** A row added to an `extensible` table (not declared): the only kind that may be deleted. */
|
|
6135
|
+
added?: boolean;
|
|
6136
|
+
/**
|
|
6137
|
+
* What the row is for, disclosed behind a "?" beside its name while its `enum` cells hold
|
|
6138
|
+
* their declared values. A row without one, or whose choices changed, gets a "?" listing its
|
|
6139
|
+
* `enum` cells' values and what each does (the options' `description`s).
|
|
6140
|
+
*/
|
|
6141
|
+
description?: string;
|
|
6142
|
+
descriptionZh?: string;
|
|
6143
|
+
}
|
|
6144
|
+
/** A header over adjacent table columns, with its own "?". */
|
|
6145
|
+
interface PluginConfigColumnGroup {
|
|
6146
|
+
title: string;
|
|
6147
|
+
titleZh?: string;
|
|
6148
|
+
description?: string;
|
|
6149
|
+
descriptionZh?: string;
|
|
6150
|
+
columns: string[];
|
|
6151
|
+
}
|
|
6152
|
+
/** The values a row added to an `extensible` table starts from. */
|
|
6153
|
+
interface PluginConfigNewRow {
|
|
6154
|
+
/** The add button's text ("Add preset"). */
|
|
6155
|
+
add?: string;
|
|
6156
|
+
addZh?: string;
|
|
6157
|
+
values: Record<string, string | boolean>;
|
|
6158
|
+
/** A string column's starting text in Chinese. */
|
|
6159
|
+
valuesZh?: Record<string, string>;
|
|
6160
|
+
}
|
|
6161
|
+
/** One choice of an `enum` field. */
|
|
6162
|
+
interface PluginConfigOption {
|
|
6163
|
+
value: string;
|
|
6164
|
+
title: string;
|
|
6165
|
+
titleZh?: string;
|
|
6166
|
+
/** What picking it does: listed, for a table column's option, in a row's "?" (see the row's `description`). */
|
|
6167
|
+
description?: string;
|
|
6168
|
+
descriptionZh?: string;
|
|
6169
|
+
}
|
|
6170
|
+
/** A declared configuration: a titled group of fields, in declaration order. */
|
|
6171
|
+
interface PluginConfiguration {
|
|
6172
|
+
title?: string;
|
|
6173
|
+
titleZh?: string;
|
|
6174
|
+
description?: string;
|
|
6175
|
+
descriptionZh?: string;
|
|
6176
|
+
/**
|
|
6177
|
+
* A `boolean` field that turns the group on (the sandbox's `enabled`). While it is off, as
|
|
6178
|
+
* drafted, the card draws that field alone: no other field, notice or action, and none of the
|
|
6179
|
+
* groups drawn inside it. Turning it on in a group that reports a `backend` it lacks offers
|
|
6180
|
+
* to install one.
|
|
6181
|
+
*/
|
|
6182
|
+
switch?: string;
|
|
6183
|
+
properties: Record<string, PluginConfigField>;
|
|
6184
|
+
}
|
|
6185
|
+
/** A line of live status a contributed group reports beside its fields (e.g. that nothing can enforce it). */
|
|
6186
|
+
interface PluginConfigNotice {
|
|
6187
|
+
/**
|
|
6188
|
+
* `progress` = work the group started is still running (an install, a download): the page
|
|
6189
|
+
* reads the groups again every few seconds while any notice says so, and the text is the
|
|
6190
|
+
* step it is on.
|
|
6191
|
+
*/
|
|
6192
|
+
tone: "attention" | "muted" | "progress";
|
|
6193
|
+
text: string;
|
|
6194
|
+
textZh?: string;
|
|
6195
|
+
/** More about the notice, disclosed under it on request; lines separated by `\n`. */
|
|
6196
|
+
details?: string;
|
|
6197
|
+
detailsZh?: string;
|
|
6198
|
+
}
|
|
6199
|
+
/** One settings group (GET /api/admin/plugin-config): its schema and its values, secrets masked. */
|
|
6200
|
+
interface PluginConfigEntry {
|
|
6201
|
+
/** The group's name — the id of the contribution that declared it; also the store key. */
|
|
6202
|
+
name: string;
|
|
6203
|
+
configuration: PluginConfiguration;
|
|
6204
|
+
/** Stored values merged onto the defaults; a secret arrives masked (`first4…last4` or `***`), never in the clear. */
|
|
6205
|
+
values: Record<string, unknown>;
|
|
6206
|
+
/** Drawn inside that entry's card and saved with it (a sandbox backend's options inside the sandbox's). */
|
|
6207
|
+
parent?: string;
|
|
6208
|
+
/** Live status beside the fields; absent when there is none. */
|
|
6209
|
+
notices?: PluginConfigNotice[];
|
|
6210
|
+
/** What this group can DO once, on the machine, drawn as buttons beneath its notices. */
|
|
6211
|
+
actions?: PluginConfigActionDecl[];
|
|
6212
|
+
/** Enum options this machine cannot honour now: drawn greyed out with the reason; a save choosing one is refused. */
|
|
6213
|
+
unavailable?: PluginConfigUnavailableDecl[];
|
|
6214
|
+
/**
|
|
6215
|
+
* For a group whose settings a backend plugin enforces (the sandbox): whether one that
|
|
6216
|
+
* applies to this machine's OS is installed, and which packages this OS defaults to. The card
|
|
6217
|
+
* offers to install `recommended` when the group's switch is turned on and none is installed.
|
|
6218
|
+
* Asked per read, like the notices; the client never guesses the OS.
|
|
6219
|
+
*/
|
|
6220
|
+
backend?: PluginConfigBackend;
|
|
6221
|
+
}
|
|
6222
|
+
/** Whether a backend that applies to this machine is installed, and this OS's default ones. */
|
|
6223
|
+
interface PluginConfigBackend {
|
|
6224
|
+
/** A backend for this OS is installed: loaded, or installed and failing its check. */
|
|
6225
|
+
installed: boolean;
|
|
6226
|
+
/**
|
|
6227
|
+
* The npm packages this OS defaults to, installed together; absent on an OS with no default
|
|
6228
|
+
* backend. Linux names two: bubblewrap, and sandbox-dsh, which confines files through
|
|
6229
|
+
* Landlock where bubblewrap is refused.
|
|
6230
|
+
*/
|
|
6231
|
+
recommended?: string[];
|
|
6232
|
+
}
|
|
6233
|
+
/** One enum option (or boolean position) a settings group cannot honour on this machine, and why. */
|
|
6234
|
+
interface PluginConfigUnavailableDecl {
|
|
6235
|
+
field: string;
|
|
6236
|
+
/** A `table` field's column: the option is unavailable in every cell of that column. */
|
|
6237
|
+
column?: string;
|
|
6238
|
+
/** An enum option, or a boolean field's position: "true" or "false". */
|
|
6239
|
+
value: string;
|
|
6240
|
+
reason: string;
|
|
6241
|
+
reasonZh?: string;
|
|
6242
|
+
}
|
|
6243
|
+
/** One button under a settings group: what it is called, and what pressing it will do. */
|
|
6244
|
+
interface PluginConfigActionDecl {
|
|
6245
|
+
id: string;
|
|
6246
|
+
title: string;
|
|
6247
|
+
titleZh?: string;
|
|
6248
|
+
description?: string;
|
|
6249
|
+
descriptionZh?: string;
|
|
6250
|
+
}
|
|
6251
|
+
/** POST /api/admin/plugin-config/action — what running one reported. */
|
|
6252
|
+
interface PluginConfigActionResponse {
|
|
6253
|
+
ok: boolean;
|
|
6254
|
+
message: string;
|
|
6255
|
+
messageZh?: string;
|
|
6256
|
+
/** The groups as they stand after it ran: a setup that worked changes what the page says. */
|
|
6257
|
+
plugins: PluginConfigEntry[];
|
|
6258
|
+
}
|
|
6259
|
+
interface PluginConfigResponse {
|
|
6260
|
+
plugins: PluginConfigEntry[];
|
|
6261
|
+
}
|
|
6262
|
+
/**
|
|
6263
|
+
* PUT /api/admin/plugin-config — one group's update. Every named field is validated
|
|
6264
|
+
* against its type; an omitted field keeps its stored value; a secret sent as the masked
|
|
6265
|
+
* value keeps the stored one, and `null` or `""` clears any field. 400 `plugin_config_invalid`
|
|
6266
|
+
* (with `field`) on a value that does not fit or a required field left empty; 404
|
|
6267
|
+
* `plugin_config_unknown` for a name no group answers to.
|
|
6268
|
+
*/
|
|
6269
|
+
interface PluginConfigUpdateRequest {
|
|
6270
|
+
name: string;
|
|
6271
|
+
values: Record<string, unknown>;
|
|
6272
|
+
}
|
|
6273
|
+
/**
|
|
6274
|
+
* An installed plugin the running build cannot fully run (plugin/unsatisfied.ts): it
|
|
6275
|
+
* contributes to a slot, or wires to a module or interface, that this build does not have.
|
|
6276
|
+
* Also what a refused push names (`plugins_unsatisfied`) and a confirmed one reports.
|
|
6277
|
+
*/
|
|
6278
|
+
interface UnsatisfiedPlugin {
|
|
6279
|
+
/** The package specifier, as the installed-plugins list spells it. */
|
|
6280
|
+
specifier: string;
|
|
6281
|
+
/** True when the whole plugin is left out of this generation; false when only the contributions this build has no slot for were dropped and the rest of it runs. */
|
|
6282
|
+
disabled: boolean;
|
|
6283
|
+
/** What this build lacks, in the platform's own words. */
|
|
6284
|
+
reason: string;
|
|
6285
|
+
}
|
|
6286
|
+
/** One plugin a Project lists (GET /api/projects/:projectId/plugins/installed). */
|
|
6287
|
+
interface InstalledPlugin {
|
|
6288
|
+
/** The package specifier as written in the file. */
|
|
6289
|
+
specifier: string;
|
|
6290
|
+
/** Whether the running process holds this package — its modules are in the tree. */
|
|
6291
|
+
active: boolean;
|
|
6292
|
+
/**
|
|
6293
|
+
* Where the package came from: shipped with the build (a hot push's assets, or the
|
|
6294
|
+
* installation's own `plugins/`) rather than fetched from npm. A tag on an installed
|
|
6295
|
+
* plugin — being shipped is not being installed.
|
|
6296
|
+
*/
|
|
6297
|
+
builtin: boolean;
|
|
6298
|
+
/** Module names the package declares it adds. */
|
|
6299
|
+
modules: string[];
|
|
6300
|
+
/** Node names the package declares it stands in for. */
|
|
6301
|
+
replaces: string[];
|
|
6302
|
+
/**
|
|
6303
|
+
* Why the package is not running: unresolvable, or a load that
|
|
6304
|
+
* failed (an import that threw, a module name another plugin already took). Only ever
|
|
6305
|
+
* reported for a plugin this server is asked to run (`here`).
|
|
6306
|
+
*/
|
|
6307
|
+
error?: string;
|
|
6308
|
+
/**
|
|
6309
|
+
* Present when this build cannot fully run the package (see {@link UnsatisfiedPlugin}).
|
|
6310
|
+
* With `disabled`, `active` is false and a restart would not load it; without, the package
|
|
6311
|
+
* runs minus the contributions this build has no slot for. Only reported for a plugin this
|
|
6312
|
+
* server is asked to run (`here`).
|
|
6313
|
+
*/
|
|
6314
|
+
unsatisfied?: Pick<UnsatisfiedPlugin, "disabled" | "reason">;
|
|
6315
|
+
/** Listed in the shared `[plugins]` table: every machine runs it. */
|
|
6316
|
+
everywhere: boolean;
|
|
6317
|
+
/** The machines whose own `[plugins.<machineId>]` table lists it, by machine id. */
|
|
6318
|
+
machines: string[];
|
|
6319
|
+
/**
|
|
6320
|
+
* Whether THIS server is asked to run it — shared, or listed for this server's own id. A
|
|
6321
|
+
* plugin listed only for other machines is neither installed nor loaded here, so `active`
|
|
6322
|
+
* is false and no `error` is reported for it.
|
|
6323
|
+
*/
|
|
6324
|
+
here: boolean;
|
|
6325
|
+
}
|
|
6326
|
+
/** What an install put on this server (POST …/plugins/installed and …/installed/archive). */
|
|
6327
|
+
interface PluginInstallOutcome {
|
|
6328
|
+
/** The package name npm installed — for a link, the name its package.json carries. */
|
|
6329
|
+
name: string;
|
|
6330
|
+
version: string | null;
|
|
6331
|
+
/** It carries skills, a hook package or MCP servers: the library lists it, and nothing loads it. */
|
|
6332
|
+
library: boolean;
|
|
6333
|
+
/** It carries server modules: the Project's list loads it. */
|
|
6334
|
+
modules: boolean;
|
|
6335
|
+
/** The zip held the version already installed: nothing was installed. */
|
|
6336
|
+
unchanged?: boolean;
|
|
6337
|
+
}
|
|
6338
|
+
/** POST /api/projects/:projectId/plugins/installed/archive (admin): a plugin package zip, base64. */
|
|
6339
|
+
interface PluginArchiveImportRequest {
|
|
6340
|
+
dataBase64: string;
|
|
6341
|
+
/** Replace another installed version of the package (the 409 `plugin_exists` question). */
|
|
6342
|
+
overwrite?: boolean;
|
|
6343
|
+
}
|
|
6344
|
+
interface InstalledPluginsResponse {
|
|
6345
|
+
plugins: InstalledPlugin[];
|
|
6346
|
+
/** After an install: what landed on this server. */
|
|
6347
|
+
installed?: PluginInstallOutcome;
|
|
6348
|
+
/**
|
|
6349
|
+
* Specifiers this build SHIPS (the hot push's assets, or the installation's own
|
|
6350
|
+
* `plugins/`): installable without a download, and not installed until listed.
|
|
6351
|
+
*/
|
|
6352
|
+
shipped: string[];
|
|
6353
|
+
/** The file the list lives in, named for the page that explains where to edit it by hand. */
|
|
6354
|
+
file: string;
|
|
6355
|
+
/** This server's own machine id — the key of its `[plugins.<machineId>]` table. */
|
|
6356
|
+
machineId: string;
|
|
6357
|
+
/** A listed plugin neither runs, nor failed to load, nor is one this build cannot run: the App could not be re-assembled around it (the previous one was restored), so a restart is what applies it. */
|
|
6358
|
+
restartPending: boolean;
|
|
6359
|
+
}
|
|
6360
|
+
/** The browser an agent drives: the desktop's built-in one, or the user's own Chrome. */
|
|
6361
|
+
type BrowserBackend = "builtin" | "chrome";
|
|
6362
|
+
/**
|
|
6363
|
+
* What a backend's link can do. The shell cannot create tabs (the Web App's <webview> does) and
|
|
6364
|
+
* throttles and measures its guests; the extension creates, closes and focuses tabs itself and
|
|
6365
|
+
* has no cookie store the server may touch.
|
|
6366
|
+
*/
|
|
6367
|
+
interface BrowserLinkCapabilities {
|
|
6368
|
+
/** `open-tab`, `close-tab` and `activate-tab` are answered (chrome). */
|
|
6369
|
+
createsTabs: boolean;
|
|
6370
|
+
/** `throttle` and the `metrics` events (builtin). */
|
|
6371
|
+
throttles: boolean;
|
|
6372
|
+
/** `set-cookies` and `clear-data` (builtin). */
|
|
6373
|
+
cookieStore: boolean;
|
|
6374
|
+
}
|
|
6375
|
+
/**
|
|
6376
|
+
* One tab of the agent browser. Built-in: a guest page, `id` its webContents id. Chrome: a tab
|
|
6377
|
+
* the extension drives (one it created in the Penguin tab group, or one the user added), `id`
|
|
6378
|
+
* Chrome's tab id; `canGoBack`/`canGoForward` are always false there (the tabs API cannot read
|
|
6379
|
+
* them).
|
|
6380
|
+
*/
|
|
6381
|
+
interface BuiltinBrowserTab {
|
|
6382
|
+
id: number;
|
|
6383
|
+
url: string;
|
|
6384
|
+
title: string;
|
|
6385
|
+
loading: boolean;
|
|
6386
|
+
canGoBack: boolean;
|
|
6387
|
+
canGoForward: boolean;
|
|
6388
|
+
favicon?: string;
|
|
6389
|
+
/**
|
|
6390
|
+
* Present while the page's renderer is gone, with Electron's reason (`crashed`, `oom`,
|
|
6391
|
+
* `killed`, …): the panel shows the crash until the page is reloaded, and an agent action on
|
|
6392
|
+
* the tab answers 409 `tab_crashed`.
|
|
6393
|
+
*/
|
|
6394
|
+
crashed?: string;
|
|
6395
|
+
}
|
|
6396
|
+
/**
|
|
6397
|
+
* Why the agent browser cannot be driven. Built-in: not under the desktop shell, a shell too old
|
|
6398
|
+
* to host it, or no app window to host a new tab. Chrome: this user has no paired extension, it
|
|
6399
|
+
* is paired but not connected now, or an admin switched Chrome connections off server-wide.
|
|
6400
|
+
*/
|
|
6401
|
+
type BuiltinBrowserUnavailableReason = "not_desktop" | "shell_unsupported" | "no_window" | "extension_not_paired" | "extension_disconnected" | "extension_disabled";
|
|
6402
|
+
/** One backend as GET /status lists it for the caller. */
|
|
6403
|
+
interface BrowserBackendInfo {
|
|
6404
|
+
backend: BrowserBackend;
|
|
6405
|
+
available: boolean;
|
|
6406
|
+
reason?: BuiltinBrowserUnavailableReason;
|
|
6407
|
+
/** chrome: the caller's connected extension, else the one seen most recently; absent when none is paired. */
|
|
6408
|
+
extension?: {
|
|
6409
|
+
id: string;
|
|
6410
|
+
name: string;
|
|
6411
|
+
version: string;
|
|
6412
|
+
connected: boolean;
|
|
6413
|
+
lastSeenAt: string | null;
|
|
6414
|
+
};
|
|
6415
|
+
}
|
|
6416
|
+
/**
|
|
6417
|
+
* GET /api/builtin-browser/status: the caller's effective backend (`backend`) — whether it can
|
|
6418
|
+
* be driven now, its tabs — and every backend this server offers the caller (`backends`).
|
|
6419
|
+
*/
|
|
6420
|
+
interface BuiltinBrowserStatus {
|
|
6421
|
+
/** Whether the effective backend can be driven now. */
|
|
6422
|
+
available: boolean;
|
|
6423
|
+
reason?: BuiltinBrowserUnavailableReason;
|
|
6424
|
+
backend: BrowserBackend;
|
|
6425
|
+
backends: BrowserBackendInfo[];
|
|
6426
|
+
tabs: BuiltinBrowserTab[];
|
|
6427
|
+
activeTabId: number | null;
|
|
6428
|
+
/** The shell's latest measurement of the built-in browser's load; absent before its first one, and on chrome. */
|
|
6429
|
+
metrics?: BuiltinBrowserMetrics;
|
|
6430
|
+
}
|
|
6431
|
+
/** GET / PUT /api/builtin-browser/backend: the caller's backend and the ones they may choose. */
|
|
6432
|
+
interface BrowserBackendResponse {
|
|
6433
|
+
backend: BrowserBackend;
|
|
6434
|
+
choices: BrowserBackend[];
|
|
6435
|
+
}
|
|
6436
|
+
/** One Chrome paired to the caller's account (a row of `browser_extensions`). */
|
|
6437
|
+
interface BrowserExtensionRecord {
|
|
6438
|
+
id: string;
|
|
6439
|
+
/** As the extension names itself, e.g. "Chrome 130 on macOS". */
|
|
6440
|
+
name: string;
|
|
6441
|
+
version: string;
|
|
6442
|
+
createdAt: string;
|
|
6443
|
+
lastSeenAt: string | null;
|
|
6444
|
+
/** Whether this one holds the caller's connection now (one at a time per user). */
|
|
6445
|
+
connected: boolean;
|
|
6446
|
+
}
|
|
6447
|
+
/** GET /api/builtin-browser/extension. */
|
|
6448
|
+
interface BrowserExtensionsResponse {
|
|
6449
|
+
paired: BrowserExtensionRecord[];
|
|
6450
|
+
/** The id of the connected one, when one is. */
|
|
6451
|
+
connected?: string;
|
|
6452
|
+
/** The admin's server-wide switch (`ServerSettings.browserExtensionsEnabled`). */
|
|
6453
|
+
enabled: boolean;
|
|
6454
|
+
}
|
|
6455
|
+
/**
|
|
6456
|
+
* POST /api/builtin-browser/extension/pairings: a one-time code for the signed-in user, valid
|
|
6457
|
+
* for ten minutes, used once; the dialog shows it beside the server address.
|
|
6458
|
+
*/
|
|
6459
|
+
interface BrowserExtensionPairingResponse {
|
|
6460
|
+
/** 43 base64url characters. */
|
|
6461
|
+
code: string;
|
|
6462
|
+
/** ISO time the code stops working. */
|
|
6463
|
+
expiresAt: string;
|
|
6464
|
+
/** The request's Origin, when it carried one: the address the browser reaches this server at. */
|
|
6465
|
+
origin: string | null;
|
|
6466
|
+
}
|
|
6467
|
+
/** POST /api/builtin-browser/extension/pair (no cookie: the extension's own request). */
|
|
6468
|
+
interface BrowserExtensionPairRequest {
|
|
6469
|
+
code: string;
|
|
6470
|
+
/** How the extension names this Chrome, e.g. "Chrome 130 on macOS" (1–80 characters). */
|
|
6471
|
+
name: string;
|
|
6472
|
+
/** The extension's own version (manifest.version). */
|
|
6473
|
+
version: string;
|
|
6474
|
+
}
|
|
6475
|
+
/** What /extension/pair answers: the long-lived token, shown once and stored only hashed here. */
|
|
6476
|
+
interface BrowserExtensionPairResponse {
|
|
6477
|
+
extensionId: string;
|
|
6478
|
+
/** Rides the WebSocket's subprotocol list as `token.<token>`; never a URL. */
|
|
6479
|
+
token: string;
|
|
6480
|
+
/** This server's install id (a stable name for the data root); null when it is unknown. */
|
|
6481
|
+
installId: string | null;
|
|
6482
|
+
user: {
|
|
6483
|
+
userId: string;
|
|
6484
|
+
displayName: string | null;
|
|
6485
|
+
};
|
|
6486
|
+
serverVersion: string;
|
|
6487
|
+
}
|
|
6488
|
+
/**
|
|
6489
|
+
* The extension WebSocket's close codes (`/api/builtin-browser/extension/ws`). Besides these the
|
|
6490
|
+
* server closes with 1012 when it restarts or hot-swaps (reconnect with the usual backoff).
|
|
6491
|
+
*
|
|
6492
|
+
* - 4001 replaced: another extension of the same user connected (last connected wins); do not
|
|
6493
|
+
* auto-retry.
|
|
6494
|
+
* - 4003 revoked: the pairing was revoked (or the token was); forget this server.
|
|
6495
|
+
* - 4005 protocol_mismatch: no `penguin-browser.1` subprotocol, or a hello the server does not
|
|
6496
|
+
* speak; the extension needs updating.
|
|
6497
|
+
* - 4008 ping_timeout: two pings (or the hello) went unanswered.
|
|
6498
|
+
* - 4009 disabled: an admin switched Chrome connections off; retry hourly.
|
|
6499
|
+
*/
|
|
6500
|
+
type BrowserExtensionCloseCode = 4001 | 4003 | 4005 | 4008 | 4009;
|
|
6501
|
+
/** One tab's share of the built-in browser's load, as the shell last measured it. */
|
|
6502
|
+
interface BuiltinBrowserTabMetrics {
|
|
6503
|
+
tabId: number;
|
|
6504
|
+
/** The memory held by the processes behind the page (its own and its cross-site frames'), KB. */
|
|
6505
|
+
memoryKB: number;
|
|
6506
|
+
/** Their CPU use since the previous measurement, in percent of one core. */
|
|
6507
|
+
cpuPercent: number;
|
|
6508
|
+
}
|
|
6509
|
+
/** Why the built-in browser should be lighter. */
|
|
6510
|
+
type BuiltinBrowserLoadWarning =
|
|
6511
|
+
/** Its pages together hold more memory than they should. */
|
|
6512
|
+
"memory"
|
|
6513
|
+
/** This computer is running out of memory. */
|
|
6514
|
+
| "low_system_memory"
|
|
6515
|
+
/** More tabs are open than the browser should hold. */
|
|
6516
|
+
| "many_tabs";
|
|
6517
|
+
/**
|
|
6518
|
+
* The built-in browser's load: GET /status's `metrics`, and the `builtin_browser_metrics` event
|
|
6519
|
+
* after each of the shell's measurements (every ~10 s while tabs are open, and soon after one
|
|
6520
|
+
* closes). The thresholds are the server's; the UI and the CLI only word what it concluded.
|
|
6521
|
+
*/
|
|
6522
|
+
interface BuiltinBrowserMetrics {
|
|
6523
|
+
/** When the server received the measurement (epoch ms). */
|
|
6524
|
+
at: number;
|
|
6525
|
+
tabs: BuiltinBrowserTabMetrics[];
|
|
6526
|
+
/** All the pages' memory, a process two tabs share counted once, KB. */
|
|
6527
|
+
totalKB: number;
|
|
6528
|
+
/**
|
|
6529
|
+
* This computer's memory, KB. Absent on macOS, whose free count leaves out the memory it would
|
|
6530
|
+
* readily hand back, so that "free" there reads as nearly none on a healthy machine.
|
|
6531
|
+
*/
|
|
6532
|
+
system?: {
|
|
6533
|
+
freeKB: number;
|
|
6534
|
+
totalKB: number;
|
|
6535
|
+
};
|
|
6536
|
+
/** What to warn about now; empty when all is well. */
|
|
6537
|
+
warnings: BuiltinBrowserLoadWarning[];
|
|
6538
|
+
/** While a memory warning stands: the tabs holding the most memory, heaviest first. */
|
|
6539
|
+
heavyTabIds: number[];
|
|
6540
|
+
}
|
|
6541
|
+
/** GET /api/builtin-browser/tabs. */
|
|
6542
|
+
interface BuiltinBrowserTabsResponse {
|
|
6543
|
+
tabs: BuiltinBrowserTab[];
|
|
6544
|
+
activeTabId: number | null;
|
|
6545
|
+
}
|
|
6546
|
+
/** POST /api/builtin-browser/tabs/:tab/scan — GenericAgent's web_scan. */
|
|
6547
|
+
interface BuiltinBrowserScanResult {
|
|
6548
|
+
tab: BuiltinBrowserTab;
|
|
6549
|
+
tabs: BuiltinBrowserTab[];
|
|
6550
|
+
activeTabId: number | null;
|
|
6551
|
+
/** Simplified HTML, or plain text with `textOnly`. */
|
|
6552
|
+
content?: string;
|
|
6553
|
+
truncated?: boolean;
|
|
6554
|
+
}
|
|
6555
|
+
/** POST /api/builtin-browser/tabs/:tab/exec (and click / type) — GenericAgent's web_execute_js. */
|
|
6556
|
+
interface BuiltinBrowserExecResult {
|
|
6557
|
+
status: "success" | "failed";
|
|
6558
|
+
tabId: number;
|
|
6559
|
+
/** The script's JSON-safe return value. */
|
|
6560
|
+
value?: unknown;
|
|
6561
|
+
error?: string;
|
|
6562
|
+
/** The page navigated or reloaded while the script ran. */
|
|
6563
|
+
reloaded?: boolean;
|
|
6564
|
+
/** Tabs opened while the call ran (popups, target=_blank). */
|
|
6565
|
+
newTabs?: {
|
|
6566
|
+
id: number;
|
|
6567
|
+
url: string;
|
|
6568
|
+
}[];
|
|
6569
|
+
/** Text that appeared during the call and may be gone again (toasts, flashes). */
|
|
6570
|
+
transients?: string[];
|
|
6571
|
+
diff?: {
|
|
6572
|
+
changed: number;
|
|
6573
|
+
topChange?: string;
|
|
6574
|
+
};
|
|
6575
|
+
suggestion?: string;
|
|
6576
|
+
/** click only: where the trusted click landed. */
|
|
6577
|
+
clicked?: {
|
|
6578
|
+
x: number;
|
|
6579
|
+
y: number;
|
|
6580
|
+
tag?: string;
|
|
6581
|
+
text?: string;
|
|
6582
|
+
};
|
|
6583
|
+
/** The page's dialogs the call answered, in order (see BuiltinBrowserDialog). */
|
|
6584
|
+
dialogs?: BuiltinBrowserDialog[];
|
|
6585
|
+
}
|
|
6586
|
+
/**
|
|
6587
|
+
* A dialog the page opened during an exec, click or type, which the call answered so the page
|
|
6588
|
+
* would not block: an alert is accepted, and a confirm, prompt or leave-page dialog dismissed
|
|
6589
|
+
* unless the request said `acceptDialogs`.
|
|
6590
|
+
*/
|
|
6591
|
+
interface BuiltinBrowserDialog {
|
|
6592
|
+
type: "alert" | "confirm" | "prompt" | "beforeunload";
|
|
6593
|
+
message: string;
|
|
6594
|
+
accepted: boolean;
|
|
6595
|
+
}
|
|
6596
|
+
/** POST /api/builtin-browser/tabs/:tab/screenshot. */
|
|
6597
|
+
interface BuiltinBrowserScreenshot {
|
|
6598
|
+
mime: "image/png";
|
|
6599
|
+
/** Base64. */
|
|
6600
|
+
data: string;
|
|
6601
|
+
}
|
|
6602
|
+
type BuiltinBrowserImportBrowser = "chrome" | "edge" | "brave" | "chromium" | "vivaldi" | "opera" | "arc" | "firefox";
|
|
6603
|
+
/** One profile of a system browser that can be imported from. */
|
|
6604
|
+
interface BuiltinBrowserImportSource {
|
|
6605
|
+
/** `<browser>:<profile dir>`, e.g. `chrome:Default`. */
|
|
6606
|
+
id: string;
|
|
6607
|
+
browser: BuiltinBrowserImportBrowser;
|
|
6608
|
+
browserName: string;
|
|
6609
|
+
/** The profile's directory name. */
|
|
6610
|
+
profile: string;
|
|
6611
|
+
/** The profile's display name. */
|
|
6612
|
+
profileName: string;
|
|
6613
|
+
hasCookies: boolean;
|
|
6614
|
+
hasHistory: boolean;
|
|
6615
|
+
}
|
|
6616
|
+
interface BuiltinBrowserImportSourcesResponse {
|
|
6617
|
+
sources: BuiltinBrowserImportSource[];
|
|
6618
|
+
}
|
|
6619
|
+
/** POST /api/builtin-browser/import. */
|
|
6620
|
+
interface BuiltinBrowserImportRequest {
|
|
6621
|
+
sourceId: string;
|
|
6622
|
+
cookies?: boolean;
|
|
6623
|
+
history?: boolean;
|
|
6624
|
+
/** Only cookies of these sites (a domain matches itself and its subdomains). */
|
|
6625
|
+
domains?: string[];
|
|
6626
|
+
}
|
|
6627
|
+
interface BuiltinBrowserImportResult {
|
|
6628
|
+
sourceId: string;
|
|
6629
|
+
cookies?: {
|
|
6630
|
+
found: number;
|
|
6631
|
+
imported: number;
|
|
6632
|
+
skipped: number;
|
|
6633
|
+
failed: number;
|
|
6634
|
+
};
|
|
6635
|
+
history?: {
|
|
6636
|
+
found: number;
|
|
6637
|
+
imported: number;
|
|
6638
|
+
};
|
|
6639
|
+
warnings: string[];
|
|
6640
|
+
}
|
|
6641
|
+
interface BuiltinBrowserHistoryEntry {
|
|
6642
|
+
url: string;
|
|
6643
|
+
title: string;
|
|
6644
|
+
visitCount: number;
|
|
6645
|
+
/** Epoch ms. */
|
|
6646
|
+
lastVisitAt: number;
|
|
6647
|
+
/** `builtin` for pages visited in the built-in browser, else the browser it was imported from. */
|
|
6648
|
+
source: string;
|
|
6649
|
+
}
|
|
6650
|
+
interface BuiltinBrowserHistoryResponse {
|
|
6651
|
+
entries: BuiltinBrowserHistoryEntry[];
|
|
6652
|
+
}
|
|
6653
|
+
/**
|
|
6654
|
+
* GET / PUT /api/builtin-browser/settings: the browser's own settings, a file of the server's
|
|
6655
|
+
* that is read and written without the desktop shell. PUT takes the whole object.
|
|
6656
|
+
*/
|
|
6657
|
+
interface BuiltinBrowserSettings {
|
|
6658
|
+
/**
|
|
6659
|
+
* The page a new tab opens when it is given no address — the panel's "+", an agent's new tab
|
|
6660
|
+
* — and the toolbar's Home button goes to: an http(s) address, or null for none (a new tab is
|
|
6661
|
+
* then blank). PUT takes a bare host too and answers the address as stored.
|
|
6662
|
+
*/
|
|
6663
|
+
homepage: string | null;
|
|
6664
|
+
}
|
|
6665
|
+
type BuiltinBrowserAction = "navigate" | "scan" | "exec" | "click" | "type" | "screenshot" | "cdp";
|
|
6666
|
+
/**
|
|
6667
|
+
* User-channel events of the agent browser. The built-in backend's go to every admin; a chrome
|
|
6668
|
+
* backend's go to the user whose Chrome it is, as do `builtin_browser_backend` and
|
|
6669
|
+
* `builtin_browser_extension`.
|
|
6670
|
+
*/
|
|
6671
|
+
type BuiltinBrowserServerEvent =
|
|
6672
|
+
/**
|
|
6673
|
+
* A backend's whole tab list. `backend` names whose: a desktop admin hears both the built-in
|
|
6674
|
+
* browser's and their own Chrome's, and the two lists must not overwrite each other.
|
|
6675
|
+
*/
|
|
6676
|
+
{
|
|
6677
|
+
type: "builtin_browser_tabs";
|
|
6678
|
+
tabs: BuiltinBrowserTab[];
|
|
6679
|
+
activeTabId: number | null;
|
|
6680
|
+
backend: BrowserBackend;
|
|
6681
|
+
}
|
|
6682
|
+
/** Create a guest for `url`, then POST /tabs/claim with `requestId` once it has a webContents id. */
|
|
6683
|
+
| {
|
|
6684
|
+
type: "builtin_browser_open";
|
|
6685
|
+
requestId: string;
|
|
6686
|
+
url: string;
|
|
6687
|
+
activate: boolean;
|
|
6688
|
+
openerTabId?: number;
|
|
6689
|
+
sessionId?: string;
|
|
6690
|
+
} | {
|
|
6691
|
+
type: "builtin_browser_close";
|
|
6692
|
+
tabId: number;
|
|
6693
|
+
} | {
|
|
6694
|
+
type: "builtin_browser_activity";
|
|
6695
|
+
tabId: number;
|
|
6696
|
+
busy: boolean;
|
|
6697
|
+
action: BuiltinBrowserAction;
|
|
6698
|
+
sessionId?: string;
|
|
6699
|
+
}
|
|
6700
|
+
/** The shell measured the browser's load (see BuiltinBrowserMetrics). */
|
|
6701
|
+
| {
|
|
6702
|
+
type: "builtin_browser_metrics";
|
|
6703
|
+
metrics: BuiltinBrowserMetrics;
|
|
6704
|
+
}
|
|
6705
|
+
/** The user switched backend (PUT /backend); every window of theirs follows. */
|
|
6706
|
+
| {
|
|
6707
|
+
type: "builtin_browser_backend";
|
|
6708
|
+
backend: BrowserBackend;
|
|
6709
|
+
}
|
|
6710
|
+
/** The user's Chrome connected, went away, was replaced by another Chrome of theirs, or was revoked. */
|
|
6711
|
+
| {
|
|
6712
|
+
type: "builtin_browser_extension";
|
|
6713
|
+
state: "connected" | "disconnected" | "replaced" | "revoked";
|
|
6714
|
+
extension?: BrowserExtensionRecord;
|
|
6715
|
+
};
|
|
6716
|
+
/** A cookie as the shell writes it (Electron's CookiesSetDetails). */
|
|
6717
|
+
interface DesktopBrowserCookie {
|
|
6718
|
+
url: string;
|
|
6719
|
+
name: string;
|
|
6720
|
+
value: string;
|
|
6721
|
+
domain?: string;
|
|
6722
|
+
path?: string;
|
|
6723
|
+
secure?: boolean;
|
|
6724
|
+
httpOnly?: boolean;
|
|
6725
|
+
/** Unix seconds; absent = session cookie. */
|
|
6726
|
+
expirationDate?: number;
|
|
6727
|
+
sameSite?: "unspecified" | "no_restriction" | "lax" | "strict";
|
|
6728
|
+
}
|
|
6729
|
+
/**
|
|
6730
|
+
* Server → browser link: what the shell (built-in) or the extension (chrome) does with its tabs.
|
|
6731
|
+
* Mechanism only — the product logic stays on the server. The names are historical: the same
|
|
6732
|
+
* envelopes travel the extension's WebSocket as JSON text frames.
|
|
6733
|
+
*/
|
|
6734
|
+
type DesktopBrowserCommand =
|
|
6735
|
+
/** Reply: a BrowserHello. An older shell never answers. */
|
|
6736
|
+
{
|
|
6737
|
+
op: "hello";
|
|
6738
|
+
}
|
|
6739
|
+
/** Reply: `{ tabs: BuiltinBrowserTab[] }`. */
|
|
6740
|
+
| {
|
|
6741
|
+
op: "tabs";
|
|
6742
|
+
}
|
|
6743
|
+
/**
|
|
6744
|
+
* Reply: the CDP method's result object. `events` names the tab's CDP events the shell relays
|
|
6745
|
+
* from then on, as `cdp-event`s: it replaces the list before (empty relays none), and is set
|
|
6746
|
+
* before the command runs, so an event the command itself causes is not missed. Without it
|
|
6747
|
+
* the list stays as it is.
|
|
6748
|
+
*/
|
|
6749
|
+
| {
|
|
6750
|
+
op: "cdp";
|
|
6751
|
+
tabId: number;
|
|
6752
|
+
method: string;
|
|
6753
|
+
params?: Record<string, unknown>;
|
|
6754
|
+
events?: string[];
|
|
6755
|
+
}
|
|
6756
|
+
/** Reply: `{ set: number; failed: number; errors: string[] }` (at most 10 errors). */
|
|
6757
|
+
| {
|
|
6758
|
+
op: "set-cookies";
|
|
6759
|
+
cookies: DesktopBrowserCookie[];
|
|
6760
|
+
}
|
|
6761
|
+
/** Reply: `{}`. */
|
|
6762
|
+
| {
|
|
6763
|
+
op: "clear-data";
|
|
6764
|
+
storages: ("cookies" | "cache" | "storage")[];
|
|
6765
|
+
}
|
|
6766
|
+
/**
|
|
6767
|
+
* Reply: `{}`. The tabs whose pages may be throttled while out of sight (Electron's background
|
|
6768
|
+
* throttling, applied at once); every other tab runs at full speed. It replaces the list
|
|
6769
|
+
* before. A tab is unthrottled until a command lists it, so a server that never sends one
|
|
6770
|
+
* changes nothing. A shell older than this command answers `unknown_op`.
|
|
6771
|
+
*/
|
|
6772
|
+
| {
|
|
6773
|
+
op: "throttle";
|
|
6774
|
+
tabIds: number[];
|
|
6775
|
+
}
|
|
6776
|
+
/**
|
|
6777
|
+
* Chrome only (the shell answers `unknown_op`). Reply: `{ tab: BuiltinBrowserTab }`. A tab at
|
|
6778
|
+
* `url` (http(s) or about:blank, checked by the server) in the extension's Penguin tab group;
|
|
6779
|
+
* `activate` asks for it to be the selected tab of its window.
|
|
6780
|
+
*/
|
|
6781
|
+
| {
|
|
6782
|
+
op: "open-tab";
|
|
6783
|
+
url: string;
|
|
6784
|
+
activate: boolean;
|
|
6785
|
+
}
|
|
6786
|
+
/** Chrome only. Reply: `{}`. Closes a tab the extension drives. */
|
|
6787
|
+
| {
|
|
6788
|
+
op: "close-tab";
|
|
6789
|
+
tabId: number;
|
|
6790
|
+
}
|
|
6791
|
+
/** Chrome only. Reply: `{}`. Shows the tab in the user's Chrome (selects it, focuses its window). */
|
|
6792
|
+
| {
|
|
6793
|
+
op: "activate-tab";
|
|
6794
|
+
tabId: number;
|
|
6795
|
+
}
|
|
6796
|
+
/** Chrome only. Reply: `{}`. Sent every 20 s; the traffic keeps the MV3 service worker alive. */
|
|
6797
|
+
| {
|
|
6798
|
+
op: "ping";
|
|
6799
|
+
};
|
|
6800
|
+
/**
|
|
6801
|
+
* The `hello` reply. Built-in: `{ version: 1, partition }` (an older shell sends no `backend`).
|
|
6802
|
+
* Chrome: `{ version: 1, backend: "chrome", extension }`; any other version is closed 4005.
|
|
6803
|
+
*/
|
|
6804
|
+
interface BrowserHello {
|
|
6805
|
+
version: 1;
|
|
6806
|
+
backend?: BrowserBackend;
|
|
6807
|
+
partition?: string;
|
|
6808
|
+
extension?: {
|
|
6809
|
+
version: string;
|
|
6810
|
+
chrome: string;
|
|
6811
|
+
name: string;
|
|
6812
|
+
};
|
|
6813
|
+
}
|
|
6814
|
+
interface DesktopBrowserCommandMessage {
|
|
6815
|
+
type: "desktop-browser-command";
|
|
6816
|
+
id: string;
|
|
6817
|
+
command: DesktopBrowserCommand;
|
|
6818
|
+
}
|
|
6819
|
+
interface DesktopBrowserReplyMessage {
|
|
6820
|
+
type: "desktop-browser-reply";
|
|
6821
|
+
id: string;
|
|
6822
|
+
ok: boolean;
|
|
6823
|
+
result?: unknown;
|
|
6824
|
+
error?: string;
|
|
6825
|
+
}
|
|
6826
|
+
type DesktopBrowserEvent = {
|
|
6827
|
+
kind: "tab";
|
|
6828
|
+
tab: BuiltinBrowserTab;
|
|
6829
|
+
} | {
|
|
6830
|
+
kind: "tab-closed";
|
|
6831
|
+
tabId: number;
|
|
6832
|
+
}
|
|
6833
|
+
/**
|
|
6834
|
+
* window.open / target=_blank inside a guest (the shell denied it and asks for a tab instead),
|
|
6835
|
+
* or the context menu's "Open link in new tab". `background`: the tab should open behind the
|
|
6836
|
+
* current one, as a middle-click or that menu entry does in Chrome.
|
|
6837
|
+
*/
|
|
6838
|
+
| {
|
|
6839
|
+
kind: "open-request";
|
|
6840
|
+
url: string;
|
|
6841
|
+
openerTabId: number;
|
|
6842
|
+
background?: boolean;
|
|
6843
|
+
}
|
|
6844
|
+
/** One of the tab's CDP events a `cdp` command's `events` asked for. */
|
|
6845
|
+
| {
|
|
6846
|
+
kind: "cdp-event";
|
|
6847
|
+
tabId: number;
|
|
6848
|
+
method: string;
|
|
6849
|
+
params: Record<string, unknown>;
|
|
6850
|
+
}
|
|
6851
|
+
/**
|
|
6852
|
+
* The tab's renderer went away (Electron's render-process-gone reason and exit code). The tab
|
|
6853
|
+
* stays; its `tab` events carry `crashed` until the page is reloaded, and the shell refuses
|
|
6854
|
+
* CDP commands for it meanwhile (`tab_crashed`).
|
|
6855
|
+
*/
|
|
6856
|
+
| {
|
|
6857
|
+
kind: "tab-crashed";
|
|
6858
|
+
tabId: number;
|
|
6859
|
+
reason: string;
|
|
6860
|
+
exitCode: number;
|
|
6861
|
+
}
|
|
6862
|
+
/**
|
|
6863
|
+
* The shell's measurement of its guests (every ~10 s while there are any, and once more
|
|
6864
|
+
* shortly after one closes, empty after the last): each tab's memory and CPU, and the pages'
|
|
6865
|
+
* memory together, a process shared by two tabs counted once.
|
|
6866
|
+
*/
|
|
6867
|
+
| {
|
|
6868
|
+
kind: "metrics";
|
|
6869
|
+
tabs: BuiltinBrowserTabMetrics[];
|
|
6870
|
+
totalKB: number;
|
|
6871
|
+
}
|
|
6872
|
+
/**
|
|
6873
|
+
* Chrome only: the tab still exists in Chrome but the agent may no longer drive it — the user
|
|
6874
|
+
* pressed Cancel on Chrome's debugging bar (`user`), the debugger went away otherwise
|
|
6875
|
+
* (`detached`), or the page is one Chrome lets no extension attach to (`restricted`). The
|
|
6876
|
+
* extension fails that tab's pending commands with the error `tab_released`.
|
|
6877
|
+
*/
|
|
6878
|
+
| {
|
|
6879
|
+
kind: "tab-released";
|
|
6880
|
+
tabId: number;
|
|
6881
|
+
reason: "user" | "detached" | "restricted";
|
|
6882
|
+
};
|
|
6883
|
+
interface DesktopBrowserEventMessage {
|
|
6884
|
+
type: "desktop-browser-event";
|
|
6885
|
+
event: DesktopBrowserEvent;
|
|
3321
6886
|
}
|
|
3322
6887
|
|
|
3323
|
-
export type { AdminPasswordResetRequest, AdminUserCreateRequest, AdminUserCreateResponse, AdminUsersResponse, AgentCompactionConfigDto, AgentConfigDto, AgentConfigResponse, AgentConfigUpdateRequest, AgentCreateRequest, AgentCreateResponse, AgentHooksConfigDto, AgentHooksResponse, AgentImportRequest, AgentImportResponse, AgentKernelUpdateResponse, AgentMemoryConfigDto, AgentModelConfigDto, AgentPluginsInstallResponse, AgentSchedulesConfigDto, AgentSkillsConfigDto, AgentSkillsResponse, AgentSummary, AgentTraceDateGroup, AgentTraceFileRef, AgentTraceSessionEntry, AgentTraceSessionFile, AgentTraceSessionGroup, AgentTracesResponse, AgentVaultConfigDto, AgentsResponse, ApprovalDecisionRequest, ApprovalMode, AuthLoginRequest, AuthResponse, BenchmarkCaseScore, BenchmarkCaseSummary, BenchmarkCasesResponse, BenchmarkEvaluation, BenchmarkRunScore, BenchmarkSummary, BenchmarksResponse, CaseMaterial, ChatDefaultsDto, CommandPolicyDto, CommandPolicyRuleDto, ContextFileShare, ContextToolShare, CredentialInfo, DefaultModelResponse, DefaultModelUpdateRequest, DesktopUpdateStatus, DesktopUpdateStatusResponse, DesktopUpdaterCommandMessage, DesktopUpdaterStatusMessage, DirEntryInfo, DirListResponse, DirectorySkillItem, DirectorySkillsResponse, DraftShortcut, EndpointModelListRequest, EndpointModelListResponse, ErrorBody, FeishuBindingInfo, FeishuBindingPutRequest, FeishuBindingResponse, FeishuTestRequest, FeishuTestResponse, FilesStatRequest, FilesStatResponse, FilesWriteRequest, GoalResponse, GoalServerEvent, GoalStateView, HistoryMessage, HookArchiveInstallRequest, HookItem, InstallResponse, MachineInfo, MachineJob, MachineServerStatus, MachinesResponse, McpServerTestResponse, MeResponse, MemberAddRequest, MemberAddResponse, MemberInfo, MembersResponse, MemoryFileInfo, MemoryFileResponse, MemoryFilesResponse, MemoryImportMode, MemoryImportRequest, MemoryImportResponse, MemoryOverviewResponse, MemoryScopeExport, MemoryScopeInfo, MemoryTransferFile, MessagesLiveTail, MessagesPageInfo, MessagesResponse, MessagingBindingCommon, MessagingBindingInfo, MessagingBindingStateRequest, MessagingBindingsResponse, MessagingChannel, MessagingChannelState, MessagingDeliveryError, MessagingDeliveryPatch, MessagingRuntimeState, MessagingRuntimeStatus, MessagingTestMessageResponse, ModelInfo, ModelOAuthCodeRequest, ModelOAuthCodeResponse, ModelOAuthErrorCode, ModelOAuthMode, ModelOAuthStartRequest, ModelOAuthStartResponse, ModelOAuthStatusResponse, ModelPricingDto, ModelProtocolDetectRequest, ModelProtocolDetectResponse, ModelProtocolProbeDto, ModelRefDto, ModelTestRequest, ModelTestResponse, ModelUpdateEntry, ModelVisionDetectRequest, ModelVisionDetectResponse, ModelVisionOutcome, ModelsResponse, ModelsUpdateRequest, PasswordChangeRequest, PendingFollowUpInfo, PendingSteeringInfo, PluginFilesResponse, PluginGroupItem, PluginInstallRequest, PluginItem, PluginLibraryResponse, PluginUpdateRef, PrefsResponse, ProjectCreateRequest, ProjectCreateResponse, ProjectRole, ProjectSummary, ProjectUpdateRequest, ProjectUpdateResponse, ProjectsResponse, ProtocolProbeOutcome, QQBindingInfo, QQBindingPutRequest, QQBindingResponse, QQScanPollResponse, QQScanStartResponse, QQTestRequest, QQTestResponse, RecalledMessageResponse, RequestSpan, RestartResponse, RetryNowResponse, ScheduleItem, ScheduleServerEvent, ScheduleStatus, ScheduleUpsertRequest, SchedulesResponse, ServerEvent, ServerSettings, ServerSettingsResponse, ServerSettingsUpdateRequest, SessionBackgroundTasks, SessionCategory, SessionCategoryCounts, SessionContextParts, SessionContextResponse, SessionCreateRequest, SessionCreateResponse, SessionForkRequest, SessionForkResponse, SessionInfo, SessionPatchRequest, SessionProcessInfo, SessionProcessesResponse, SessionResponse, SessionSource, SessionStatus, SessionTracesResponse, SessionsResponse, SkillArchiveInstallRequest, SkillMetadataItem, SteerRequest, SubagentMessageResponse, SubagentRuntimeInfo, TaskCreateRequest, TaskCreateResponse, TaskInputPart, TelegramBindingInfo, TelegramBindingPutRequest, TelegramBindingResponse, TelegramTestRequest, TelegramTestResponse, ToolCallSpan, TraceAnalysisResponse, TraceEventsResponse, TraceFileInfo, TraceImportRequest, TraceImportResponse, TraceModelSegment, TraceOtherSpan, TracePosition, TraceTaskStats, TraceToolSpan, UiPrefs, UpdateCheckResponse, UpdateJobPhase, UpdateJobStatus, UpdateRunResponse, UploadLimits, UsageAgentSeries, UsageBucket, UsageEntitySeriesCounts, UsageErrorCount, UsageErrorItem, UsageErrorKind, UsageErrors, UsageErrorsClearResponse, UsageErrorsPage, UsageGranularity, UsageGroupBy, UsageGroupRow, UsageModelSeries, UsageModelTotal, UsageModelTotals, UsageResponse, UsageSeriesPoint, UsageTrendPointInTrace, UserInfo, VaultEntryInfo, VaultEntryUpdate, VaultResponse, VaultUpdateRequest, VersionResponse, WeChatBindingInfo, WeChatBindingPutRequest, WeChatBindingResponse, WeChatScanPollResponse, WeChatScanStartResponse, WeChatScanStatus, WeChatScanVerifyRequest, WeChatTestResponse, WorkspaceFileEntry, WorkspaceFilesResponse };
|
|
6888
|
+
export { type AdminPasswordResetRequest, type AdminUserCreateRequest, type AdminUserCreateResponse, type AdminUsersResponse, type AgentApiKeyCreateRequest, type AgentApiKeyCreateResponse, type AgentApiKeyInfo, type AgentApiResponse, type AgentApiSettings, type AgentApiUpdateRequest, type AgentCompactionConfigDto, type AgentConfigDto, type AgentConfigResponse, type AgentConfigUpdateRequest, type AgentCreateRequest, type AgentCreateResponse, type AgentHooksConfigDto, type AgentHooksResponse, type AgentImportRequest, type AgentImportResponse, type AgentKernelUpdateResponse, type AgentMcpServerItem, type AgentMcpServersResponse, type AgentMemoryConfigDto, type AgentModelConfigDto, type AgentPluginsInstallResponse, type AgentSchedulesConfigDto, type AgentSkillsConfigDto, type AgentSkillsResponse, type AgentSummary, type AgentTraceDateGroup, type AgentTraceFileRef, type AgentTraceSessionEntry, type AgentTraceSessionFile, type AgentTraceSessionGroup, type AgentTracesResponse, type AgentVaultConfigDto, type AgentsResponse, type ApprovalDecisionRequest, type ApprovalMode, type ArchivedSessionGroup, type ArchivedSessionGroupsResponse, type ArchivedSessionSource, type ArchivedSessionsBatch, type ArchivedSessionsBatchFilter, type ArchivedSessionsBatchResponse, type ArchivedSessionsQuery, type ArchivedSessionsResponse, type ArchivedSessionsRowsQuery, type AuthLoginRequest, type AuthResponse, type BenchmarkArchiveGitOrigin, type BenchmarkArchiveImportRequest, type BenchmarkArchiveImportResponse, type BenchmarkCaseScore, type BenchmarkCaseSummary, type BenchmarkCasesResponse, type BenchmarkCreateCase, type BenchmarkCreateRequest, type BenchmarkCreateResponse, type BenchmarkEvaluation, type BenchmarkManifestProblem, type BenchmarkOrigin, type BenchmarkOriginKind, type BenchmarkRunScore, type BenchmarkStatus, type BenchmarkSummary, type BenchmarksResponse, type BrowserBackend, type BrowserBackendInfo, type BrowserBackendResponse, type BrowserExtensionCloseCode, type BrowserExtensionPairRequest, type BrowserExtensionPairResponse, type BrowserExtensionPairingResponse, type BrowserExtensionRecord, type BrowserExtensionsResponse, type BrowserHello, type BrowserLinkCapabilities, type BuiltinBrowserAction, type BuiltinBrowserDialog, type BuiltinBrowserExecResult, type BuiltinBrowserHistoryEntry, type BuiltinBrowserHistoryResponse, type BuiltinBrowserImportBrowser, type BuiltinBrowserImportRequest, type BuiltinBrowserImportResult, type BuiltinBrowserImportSource, type BuiltinBrowserImportSourcesResponse, type BuiltinBrowserLoadWarning, type BuiltinBrowserMetrics, type BuiltinBrowserScanResult, type BuiltinBrowserScreenshot, type BuiltinBrowserServerEvent, type BuiltinBrowserSettings, type BuiltinBrowserStatus, type BuiltinBrowserTab, type BuiltinBrowserTabMetrics, type BuiltinBrowserTabsResponse, type BuiltinBrowserUnavailableReason, type CaseMaterial, type ChatDefaultsDto, type CommandPolicyDto, type CommandPolicyRuleDto, type CompanyServerEvent, type ConnectionSourceDto, type ContextFileShare, type ContextToolShare, type ContributionsResponse, type CostParts, type CredentialInfo, type DefaultModelResponse, type DefaultModelUpdateRequest, type DesktopBrowserCommand, type DesktopBrowserCommandMessage, type DesktopBrowserCookie, type DesktopBrowserEvent, type DesktopBrowserEventMessage, type DesktopBrowserReplyMessage, type DesktopFolderAccessMessage, type DesktopFolderAccessResult, type DesktopFolderAccessResultMessage, type DesktopOpenPrivacySettingsMessage, type DesktopPrivacyPane, type DesktopTrayCommandMessage, type DesktopTrayLocale, type DesktopTrayPatch, type DesktopTrayStatus, type DesktopTrayStatusMessage, type DesktopTrayStatusResponse, type DesktopUpdateStatus, type DesktopUpdateStatusResponse, type DesktopUpdaterCommandMessage, type DesktopUpdaterStatusMessage, type DirAccessResponse, type DirEntryInfo, type DirListResponse, type DirLocation, type DirStandardFolders, type DirectorySkillItem, type DirectorySkillsResponse, type DraftShortcut, type Employment, type EndpointModelListRequest, type EndpointModelListResponse, type ErrorBody, type ErrorDetails, type FeishuBindingInfo, type FeishuBindingPutRequest, type FeishuBindingResponse, type FeishuTestRequest, type FeishuTestResponse, type FilesCreateRequest, type FilesMoveRequest, type FilesStatRequest, type FilesStatResponse, type FilesWriteRequest, type GoalResponse, type GoalServerEvent, type GoalStateView, type HistoryMessage, type HookArchiveInstallRequest, type HookItem, type InstallResponse, type InstalledPlugin, type InstalledPluginsResponse, type LanguageIndexResponse, type LanguageSummary, MACHINE_PHASES, type MachineCheck, type MachineConfigSync, type MachineDiagnosis, type MachineEnvOnly, type MachineInfo, type MachineJob, type MachinePhase, type MachineReconnect, type MachineServerEvent, type MachineServerStatus, type MachineSkippedModel, type MachineSourceReach, type MachineSshFailure, type MachineUninstallRequest, type MachineUseRefusal, type MachinesAddRequest, type MachinesCheckoutImage, type MachinesResponse, type MachinesStopUsingRequest, type MachinesUseRequest, type MachinesUseResponse, type McpServerTestResponse, type McpTransport, type MeResponse, type MemberAddRequest, type MemberAddResponse, type MemberInfo, type MembersResponse, type MemoryFileInfo, type MemoryFileResponse, type MemoryFilesResponse, type MemoryImportMode, type MemoryImportRequest, type MemoryImportResponse, type MemoryOverviewResponse, type MemoryScopeExport, type MemoryScopeInfo, type MemoryTransferFile, type MessagesLiveTail, type MessagesPageInfo, type MessagesResponse, type MessagingBindingCommon, type MessagingBindingInfo, type MessagingBindingStateRequest, type MessagingBindingsResponse, type MessagingChannel, type MessagingChannelState, type MessagingDeliveryError, type MessagingDeliveryPatch, type MessagingRuntimeState, type MessagingRuntimeStatus, type MessagingTestMessageResponse, type ModelBalanceAmount, type ModelBalanceErrorCode, type ModelBalanceFailure, type ModelBalanceReading, type ModelBalanceResponse, type ModelEffectiveConnection, type ModelInfo, type ModelOAuthCodeRequest, type ModelOAuthCodeResponse, type ModelOAuthErrorCode, type ModelOAuthMode, type ModelOAuthStartRequest, type ModelOAuthStartResponse, type ModelOAuthStatusResponse, type ModelPricingDto, type ModelProtocolDetectRequest, type ModelProtocolDetectResponse, type ModelProtocolProbeDto, type ModelRefDto, type ModelScopeAuthFlowErrorCode, type ModelScopeAuthFlowStatusResponse, type ModelScopeAuthStartResponse, type ModelTestRequest, type ModelTestResponse, type ModelUpdateEntry, type ModelVisionDetectRequest, type ModelVisionDetectResponse, type ModelVisionOutcome, type ModelsResponse, type ModelsUpdateRequest, type OrgApprovalMode, type OrgBudgetAlert, type OrgCalendarItem, type OrgCalendarOutcome, type OrgCalendarResponse, type OrgCalendarUpsertRequest, type OrgCalendarWriteResponse, type OrgChannelCreateRequest, type OrgChannelDetail, type OrgChannelItem, type OrgChannelMember, type OrgChannelMemberRequest, type OrgChannelMessage, type OrgChannelMessageSendRequest, type OrgChannelMessagesResponse, type OrgChannelNotice, type OrgChannelNoticeKind, type OrgChannelPatchRequest, type OrgChannelReadRequest, type OrgChannelsResponse, type OrgChartResponse, type OrgDeskItem, type OrgDeskResponse, type OrgEmployeeItem, type OrgEmployeePatchRequest, type OrgEmployeeState, type OrgFinanceEmployee, type OrgFinanceResponse, type OrgFinanceTicket, type OrgHandbookFile, type OrgHandbookFileResponse, type OrgHandbookFileWriteRequest, type OrgHandbookFilesResponse, type OrgHandbookResponse, type OrgHireRequest, type OrgInbox, type OrgLanguage, type OrgSessionsResponse, type OrgSpendSummary, type OrgStatus, type OrgTicketAttachRequest, type OrgTicketBlockRequest, type OrgTicketChange, type OrgTicketCreateRequest, type OrgTicketDetail, type OrgTicketHistoryAction, type OrgTicketHistoryEntry, type OrgTicketItem, type OrgTicketMoveRequest, type OrgTicketPriority, type OrgTicketProgressRequest, type OrgTicketSessionItem, type OrgTicketStartRequest, type OrgTicketStartResponse, type OrgTicketStatus, type OrgTicketUpdateRequest, type OrgTicketsResponse, type OrgTriggerKind, type OrganizationCreateRequest, type OrganizationDetail, type OrganizationPatchRequest, type OrganizationSettings, type OrganizationSummary, type OrganizationsResponse, type PasswordChangeRequest, type PendingFollowUpInfo, type PendingSteeringInfo, type PinnedBalance, type PlatformAuthFlowErrorCode, type PlatformAuthFlowStatusResponse, type PlatformAuthStartResponse, type PlatformModelSyncResponse, type PluginArchiveImportRequest, type PluginConfigActionDecl, type PluginConfigActionResponse, type PluginConfigBackend, type PluginConfigColumnGroup, type PluginConfigEntry, type PluginConfigField, type PluginConfigNewRow, type PluginConfigNotice, type PluginConfigOption, type PluginConfigPinColumn, type PluginConfigResponse, type PluginConfigRowChoice, type PluginConfigTableColumn, type PluginConfigTableRow, type PluginConfigUnavailableDecl, type PluginConfigUpdateRequest, type PluginConfiguration, type PluginFilesResponse, type PluginGroupItem, type PluginIndexEntry, type PluginIndexResponse, type PluginInstallOutcome, type PluginInstallRequest, type PluginItem, type PluginLibraryResponse, type PluginMcpServerItem, type PluginReadmeResponse, type PluginSetupKeyItem, type PluginUpdateRef, type PrefsResponse, type PresetSyncMode, type PresetSyncRequest, type PresetSyncResponse, type ProjectCreateRequest, type ProjectCreateResponse, type ProjectRole, type ProjectScheduleItem, type ProjectSchedulesResponse, type ProjectSummary, type ProjectUpdateRequest, type ProjectUpdateResponse, type ProjectsResponse, type ProtocolProbeOutcome, type ProviderConnectionDto, type ProviderConnectionUpdate, type ProxyProbeDto, type ProxyProbeOutcome, type ProxyProbeProvider, type ProxyProbeResponse, type ProxyProbeTargetDto, type ProxyProbeTargetsResponse, type QQBindingInfo, type QQBindingPutRequest, type QQBindingResponse, type QQScanPollResponse, type QQScanStartResponse, type QQTestRequest, type QQTestResponse, type QuickStartItem, type RecalledMessageResponse, type RendererRef, type RequestSpan, type RestartResponse, type RetryNowResponse, type ScheduleItem, type ScheduleServerEvent, type ScheduleStatus, type ScheduleUpsertRequest, type SchedulesResponse, type SemanticIdKind, type SemanticIdSuggestReason, type SemanticIdSuggestRequest, type SemanticIdSuggestResponse, type ServerEvent, type ServerSettings, type ServerSettingsResponse, type ServerSettingsUpdateRequest, type SessionBackgroundTasks, type SessionBatchPageRequest, type SessionBatchResult, type SessionCategory, type SessionCategoryCounts, type SessionContextParts, type SessionContextResponse, type SessionCreateRequest, type SessionCreateResponse, type SessionForkRequest, type SessionForkResponse, type SessionInfo, type SessionPatchRequest, type SessionProcessInfo, type SessionProcessesResponse, type SessionResponse, type SessionSandbox, type SessionSandboxMode, type SessionSandboxNetwork, type SessionSandboxPreset, type SessionStatus, type SessionSwitchModelRequest, type SessionTracesResponse, type SessionsBatchRequest, type SessionsBatchResponse, type SessionsResponse, type SkillArchiveInstallRequest, type SkillMetadataItem, type SshHostRequest, type SshHostResponse, type SshHostSummary, type SshHostsResponse, type SteerRequest, type StoredKeybindings, type SubagentMessageResponse, type SubagentRuntimeInfo, TICKET_SLUG_PATTERN, type TaskCreateRequest, type TaskCreateResponse, type TaskInputPart, type TelegramBindingInfo, type TelegramBindingPutRequest, type TelegramBindingResponse, type TelegramTestRequest, type TelegramTestResponse, type ToolCallSpan, type TraceAnalysisResponse, type TraceEventsResponse, type TraceFileInfo, type TraceImportRequest, type TraceImportResponse, type TraceModelSegment, type TraceOtherSpan, type TracePosition, type TraceTaskStats, type TraceToolSpan, type UiPrefs, type UnavailableSandboxBackend, type UnsatisfiedPlugin, type UpdateCheckResponse, type UpdateJobPhase, type UpdateJobStatus, type UpdateProfileRequest, type UpdateProfileResponse, type UpdateRunResponse, type UploadLimits, type UsageAgentSeries, type UsageBucket, type UsageEntitySeriesCounts, type UsageErrorCount, type UsageErrorItem, type UsageErrorKind, type UsageErrors, type UsageErrorsClearResponse, type UsageErrorsPage, type UsageGranularity, type UsageGroupBy, type UsageGroupRow, type UsageModelSeries, type UsageModelTotal, type UsageModelTotals, type UsageResponse, type UsageSeriesPoint, type UsageTrendPointInTrace, type UserInfo, type VaultEntryInfo, type VaultEntryUpdate, type VaultResponse, type VaultUpdateRequest, type VersionHistoryDiffResponse, type VersionHistoryResponse, type VersionResponse, type VersionRollbackResponse, type WeChatBindingInfo, type WeChatBindingPutRequest, type WeChatBindingResponse, type WeChatScanPollResponse, type WeChatScanStartResponse, type WeChatScanStatus, type WeChatScanVerifyRequest, type WeChatTestResponse, type WebContribution, type WorkflowInfo, type WorkflowRequest, type WorkflowResponse, type WorkflowVersion, type WorkspaceFileEntry, type WorkspaceFilesResponse, type WorkspaceSearchHit, type WorkspaceSearchResponse };
|