@pasko70/pibo 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex/skills/pi-agent-harness/SKILL.md +319 -0
- package/.codex/skills/pi-agent-harness/agents/openai.yaml +4 -0
- package/README.md +318 -0
- package/context/codex-base-prompt.md +144 -0
- package/context/pibo-compaction-prompt.md +100 -0
- package/context/pibo-system-prompt.md +17 -0
- package/dist/apps/chat/agent-profiles.js +26 -0
- package/dist/apps/chat/agent-store.js +336 -0
- package/dist/apps/chat/event-log.js +307 -0
- package/dist/apps/chat/read-model.js +218 -0
- package/dist/apps/chat/rooms.js +321 -0
- package/dist/apps/chat/session-metadata.js +14 -0
- package/dist/apps/chat/stream.js +122 -0
- package/dist/apps/chat/trace.js +1182 -0
- package/dist/apps/chat/web-app.js +2569 -0
- package/dist/apps/chat-ui/assets/apl-BxEMbctQ.js +1 -0
- package/dist/apps/chat-ui/assets/asciiarmor-eFjeGRuZ.js +1 -0
- package/dist/apps/chat-ui/assets/asn1-Cfx-0pt9.js +1 -0
- package/dist/apps/chat-ui/assets/asterisk-B5BHTsBr.js +1 -0
- package/dist/apps/chat-ui/assets/brainfuck-CAA2xofr.js +1 -0
- package/dist/apps/chat-ui/assets/clike-BoDCOLzN.js +1 -0
- package/dist/apps/chat-ui/assets/clojure-kVFSWX0o.js +1 -0
- package/dist/apps/chat-ui/assets/cmake-BUPAhezI.js +1 -0
- package/dist/apps/chat-ui/assets/cobol-BfgHZgup.js +1 -0
- package/dist/apps/chat-ui/assets/coffeescript-G1Pe_1AZ.js +1 -0
- package/dist/apps/chat-ui/assets/commonlisp-B3N0CjHn.js +1 -0
- package/dist/apps/chat-ui/assets/crystal-C15ndaGM.js +1 -0
- package/dist/apps/chat-ui/assets/css-BqOeyZOV.js +1 -0
- package/dist/apps/chat-ui/assets/cypher-KjIKv-wW.js +1 -0
- package/dist/apps/chat-ui/assets/d-BlT5AEC-.js +1 -0
- package/dist/apps/chat-ui/assets/diff-oF98tbqj.js +1 -0
- package/dist/apps/chat-ui/assets/dist--55mTWk3.js +1 -0
- package/dist/apps/chat-ui/assets/dist-B5rcjVCj.js +1 -0
- package/dist/apps/chat-ui/assets/dist-BPv5MdlL.js +1 -0
- package/dist/apps/chat-ui/assets/dist-BZ39rB1W.js +1 -0
- package/dist/apps/chat-ui/assets/dist-BsedZGJo.js +1 -0
- package/dist/apps/chat-ui/assets/dist-BvO6SpaM.js +9 -0
- package/dist/apps/chat-ui/assets/dist-C5YJOwhH.js +1 -0
- package/dist/apps/chat-ui/assets/dist-C5oXtFSP.js +1 -0
- package/dist/apps/chat-ui/assets/dist-CG_gRSwv.js +23 -0
- package/dist/apps/chat-ui/assets/dist-CKM5j-iy.js +1 -0
- package/dist/apps/chat-ui/assets/dist-CUp9us2q.js +1 -0
- package/dist/apps/chat-ui/assets/dist-CZ9T4Cly.js +1 -0
- package/dist/apps/chat-ui/assets/dist-D4HhiFWB.js +6 -0
- package/dist/apps/chat-ui/assets/dist-DHE-yBLH.js +1 -0
- package/dist/apps/chat-ui/assets/dist-DSKQpPaz.js +1 -0
- package/dist/apps/chat-ui/assets/dist-L1B-KWZO.js +1 -0
- package/dist/apps/chat-ui/assets/dist-SVPsM5Oi.js +13 -0
- package/dist/apps/chat-ui/assets/dist-Zqt9kNG9.js +1 -0
- package/dist/apps/chat-ui/assets/dist-_DPv0-QF.js +1 -0
- package/dist/apps/chat-ui/assets/dist-_oM7g0eh.js +11 -0
- package/dist/apps/chat-ui/assets/dist-laadbMWg.js +1 -0
- package/dist/apps/chat-ui/assets/dist-nFui3f-r.js +2 -0
- package/dist/apps/chat-ui/assets/dist-tGfufz3b.js +1 -0
- package/dist/apps/chat-ui/assets/dockerfile-CUaqzcqp.js +1 -0
- package/dist/apps/chat-ui/assets/dtd-VCA9yr61.js +1 -0
- package/dist/apps/chat-ui/assets/dylan-O-V5Dw5W.js +1 -0
- package/dist/apps/chat-ui/assets/ebnf-SPmdBkvT.js +1 -0
- package/dist/apps/chat-ui/assets/ecl-ChfCttfI.js +1 -0
- package/dist/apps/chat-ui/assets/eiffel-cB9EbjeN.js +1 -0
- package/dist/apps/chat-ui/assets/elm-BTiVflBU.js +1 -0
- package/dist/apps/chat-ui/assets/erlang-egf0TXFm.js +1 -0
- package/dist/apps/chat-ui/assets/factor-C2tAxNob.js +1 -0
- package/dist/apps/chat-ui/assets/fcl-BiCjh1tj.js +1 -0
- package/dist/apps/chat-ui/assets/forth-C4kDGW6u.js +1 -0
- package/dist/apps/chat-ui/assets/fortran-DzkLaPnd.js +1 -0
- package/dist/apps/chat-ui/assets/gas-DMOxskQF.js +1 -0
- package/dist/apps/chat-ui/assets/gherkin-BPxBpp-k.js +1 -0
- package/dist/apps/chat-ui/assets/groovy-CkEnc0ZY.js +1 -0
- package/dist/apps/chat-ui/assets/haskell-Dadpo9-w.js +1 -0
- package/dist/apps/chat-ui/assets/haxe-CDNZL9MW.js +1 -0
- package/dist/apps/chat-ui/assets/http-jy9Zxxt3.js +1 -0
- package/dist/apps/chat-ui/assets/idl-CGSB6iiy.js +1 -0
- package/dist/apps/chat-ui/assets/index-BdcqTugD.js +151 -0
- package/dist/apps/chat-ui/assets/index-Dk-opWl3.css +1 -0
- package/dist/apps/chat-ui/assets/javascript-DSlzRUd8.js +1 -0
- package/dist/apps/chat-ui/assets/julia-DTiF9v6R.js +1 -0
- package/dist/apps/chat-ui/assets/livescript-Ci8Xxna6.js +1 -0
- package/dist/apps/chat-ui/assets/lua-eVxIrt9t.js +1 -0
- package/dist/apps/chat-ui/assets/mathematica-Da3grj36.js +1 -0
- package/dist/apps/chat-ui/assets/mbox-BWBMSafM.js +1 -0
- package/dist/apps/chat-ui/assets/mirc-CtHu9S1B.js +1 -0
- package/dist/apps/chat-ui/assets/mllike-wTFlPWXS.js +1 -0
- package/dist/apps/chat-ui/assets/modelica-cKbQ0UXu.js +1 -0
- package/dist/apps/chat-ui/assets/mscgen-C5pXQCMK.js +1 -0
- package/dist/apps/chat-ui/assets/mumps-CKBHkOQq.js +1 -0
- package/dist/apps/chat-ui/assets/nginx-B00AiQel.js +1 -0
- package/dist/apps/chat-ui/assets/nsis-SMDwKltR.js +1 -0
- package/dist/apps/chat-ui/assets/ntriples-B_36EBV0.js +1 -0
- package/dist/apps/chat-ui/assets/octave-BXPjzAif.js +1 -0
- package/dist/apps/chat-ui/assets/oz-Dedpat1M.js +1 -0
- package/dist/apps/chat-ui/assets/pascal-CMcUg72K.js +1 -0
- package/dist/apps/chat-ui/assets/perl-DoVTbnzt.js +1 -0
- package/dist/apps/chat-ui/assets/pig-CULXT1YV.js +1 -0
- package/dist/apps/chat-ui/assets/powershell-Cv5Uhf6b.js +1 -0
- package/dist/apps/chat-ui/assets/properties-CQ1C2P-M.js +1 -0
- package/dist/apps/chat-ui/assets/protobuf-SRlvzrl6.js +1 -0
- package/dist/apps/chat-ui/assets/pug-Bo3wfL-f.js +1 -0
- package/dist/apps/chat-ui/assets/puppet-ClSqCGj6.js +1 -0
- package/dist/apps/chat-ui/assets/python-C2_X1GpX.js +1 -0
- package/dist/apps/chat-ui/assets/q-B_6Gdyzl.js +1 -0
- package/dist/apps/chat-ui/assets/r-BD07NGED.js +1 -0
- package/dist/apps/chat-ui/assets/rolldown-runtime-S-ySWqyJ.js +1 -0
- package/dist/apps/chat-ui/assets/rpm-CRu5Z2Jl.js +1 -0
- package/dist/apps/chat-ui/assets/ruby-dZPnOz8h.js +1 -0
- package/dist/apps/chat-ui/assets/sas-S2t8_sDI.js +1 -0
- package/dist/apps/chat-ui/assets/scheme-WcyFWLW2.js +1 -0
- package/dist/apps/chat-ui/assets/shell-DUelnYSh.js +1 -0
- package/dist/apps/chat-ui/assets/sieve-jDjlVhNh.js +1 -0
- package/dist/apps/chat-ui/assets/simple-mode-CL04yRVp.js +1 -0
- package/dist/apps/chat-ui/assets/smalltalk-ddWDYy10.js +1 -0
- package/dist/apps/chat-ui/assets/solr-C7rQhLuW.js +1 -0
- package/dist/apps/chat-ui/assets/sparql--fPCCgVd.js +1 -0
- package/dist/apps/chat-ui/assets/spreadsheet-DjthqD5G.js +1 -0
- package/dist/apps/chat-ui/assets/sql-D_dieYbr.js +1 -0
- package/dist/apps/chat-ui/assets/stex-rHcFYcA0.js +1 -0
- package/dist/apps/chat-ui/assets/stylus-DxF70RNr.js +1 -0
- package/dist/apps/chat-ui/assets/swift-T0hDoOb-.js +1 -0
- package/dist/apps/chat-ui/assets/tcl-Dlzy1mPk.js +1 -0
- package/dist/apps/chat-ui/assets/textile-Dy5rFZe5.js +1 -0
- package/dist/apps/chat-ui/assets/tiddlywiki-DQP1OymS.js +1 -0
- package/dist/apps/chat-ui/assets/tiki-0vOj3DB2.js +1 -0
- package/dist/apps/chat-ui/assets/toml-DEltN0lI.js +1 -0
- package/dist/apps/chat-ui/assets/troff-CRbBpEqY.js +1 -0
- package/dist/apps/chat-ui/assets/ttcn-M5q1nLKg.js +1 -0
- package/dist/apps/chat-ui/assets/ttcn-cfg-Rmw9NWq9.js +1 -0
- package/dist/apps/chat-ui/assets/turtle-BCDWhJK0.js +1 -0
- package/dist/apps/chat-ui/assets/vb-QQ7LGlOz.js +1 -0
- package/dist/apps/chat-ui/assets/vbscript-BiSEdUzz.js +1 -0
- package/dist/apps/chat-ui/assets/velocity-CzMg5_6w.js +1 -0
- package/dist/apps/chat-ui/assets/verilog-BJOO83gk.js +1 -0
- package/dist/apps/chat-ui/assets/vhdl-ed4zAZAA.js +1 -0
- package/dist/apps/chat-ui/assets/webidl-Ddy6hbV6.js +1 -0
- package/dist/apps/chat-ui/assets/xquery-Bw1zwhh6.js +1 -0
- package/dist/apps/chat-ui/assets/yacas-DZdTXy3s.js +1 -0
- package/dist/apps/chat-ui/assets/z80-DMG02_YV.js +1 -0
- package/dist/apps/chat-ui/index.html +15 -0
- package/dist/apps/context-files-ui/assets/apl-14BqhLYK.js +1 -0
- package/dist/apps/context-files-ui/assets/asciiarmor-WLvjqI7d.js +1 -0
- package/dist/apps/context-files-ui/assets/asn1-Bg4FbdCg.js +1 -0
- package/dist/apps/context-files-ui/assets/asterisk-B2MO-X4d.js +1 -0
- package/dist/apps/context-files-ui/assets/brainfuck-CV9kufud.js +1 -0
- package/dist/apps/context-files-ui/assets/clike-CjmcUpt6.js +1 -0
- package/dist/apps/context-files-ui/assets/clojure-De3QGfx6.js +1 -0
- package/dist/apps/context-files-ui/assets/cmake-i2VDNaRq.js +1 -0
- package/dist/apps/context-files-ui/assets/cobol-BwO6DF08.js +1 -0
- package/dist/apps/context-files-ui/assets/coffeescript-BtivDvRz.js +1 -0
- package/dist/apps/context-files-ui/assets/commonlisp-DFkEQdLP.js +1 -0
- package/dist/apps/context-files-ui/assets/crystal-CU0NkcVL.js +1 -0
- package/dist/apps/context-files-ui/assets/css-CbMZAQ1W.js +1 -0
- package/dist/apps/context-files-ui/assets/cypher-Dke5QOzv.js +1 -0
- package/dist/apps/context-files-ui/assets/d-TPqSVaHM.js +1 -0
- package/dist/apps/context-files-ui/assets/diff-B365LSoZ.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-B5PTVnox.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-B5ZAfwf5.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-BJW3917N.js +11 -0
- package/dist/apps/context-files-ui/assets/dist-BkUONE3N.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-CKQF1zEu.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-CwbH_3RN.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-CxRLRmMx.js +2 -0
- package/dist/apps/context-files-ui/assets/dist-D1KyNDg5.js +13 -0
- package/dist/apps/context-files-ui/assets/dist-DFi2YGux.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-DKoyMSNr.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-DLMjd26T.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-DQXzt2Ng.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-DotDq_kD.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-DyfSeBMu.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-MyZgX9K2.js +9 -0
- package/dist/apps/context-files-ui/assets/dist-QQuDy4KA.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-YwR9dpb-.js +1 -0
- package/dist/apps/context-files-ui/assets/dist-dTBsFYAl.js +1 -0
- package/dist/apps/context-files-ui/assets/dockerfile-CJb2sekW.js +1 -0
- package/dist/apps/context-files-ui/assets/dtd-CBMymJ7O.js +1 -0
- package/dist/apps/context-files-ui/assets/dylan-08Azy1NK.js +1 -0
- package/dist/apps/context-files-ui/assets/ebnf-Dkum_1J8.js +1 -0
- package/dist/apps/context-files-ui/assets/ecl-dhxjHL8y.js +1 -0
- package/dist/apps/context-files-ui/assets/eiffel-C446m6dI.js +1 -0
- package/dist/apps/context-files-ui/assets/elm-po1E9de0.js +1 -0
- package/dist/apps/context-files-ui/assets/erlang-BD5LkVkR.js +1 -0
- package/dist/apps/context-files-ui/assets/factor-B2EMQZkP.js +1 -0
- package/dist/apps/context-files-ui/assets/fcl-DkEOamHd.js +1 -0
- package/dist/apps/context-files-ui/assets/forth-dCg2_HVB.js +1 -0
- package/dist/apps/context-files-ui/assets/fortran-3ZpXLFh1.js +1 -0
- package/dist/apps/context-files-ui/assets/gas-DMmxLZRI.js +1 -0
- package/dist/apps/context-files-ui/assets/gherkin-DUSFg2R6.js +1 -0
- package/dist/apps/context-files-ui/assets/groovy-Cmduloe1.js +1 -0
- package/dist/apps/context-files-ui/assets/haskell-Cyr255R9.js +1 -0
- package/dist/apps/context-files-ui/assets/haxe-BJVKtprM.js +1 -0
- package/dist/apps/context-files-ui/assets/http-DszHFpc-.js +1 -0
- package/dist/apps/context-files-ui/assets/idl-Cati9Nrv.js +1 -0
- package/dist/apps/context-files-ui/assets/index-BwRDoHMC.css +1 -0
- package/dist/apps/context-files-ui/assets/index-GwvjXytt.js +202 -0
- package/dist/apps/context-files-ui/assets/javascript-C5pDVaoP.js +1 -0
- package/dist/apps/context-files-ui/assets/julia-DlqY1cTU.js +1 -0
- package/dist/apps/context-files-ui/assets/livescript-C6p8-2W1.js +1 -0
- package/dist/apps/context-files-ui/assets/lua-BxuTHaF7.js +1 -0
- package/dist/apps/context-files-ui/assets/mathematica-nDHZUMJT.js +1 -0
- package/dist/apps/context-files-ui/assets/mbox-DAaR0Hcz.js +1 -0
- package/dist/apps/context-files-ui/assets/mirc-CCA0FRfl.js +1 -0
- package/dist/apps/context-files-ui/assets/mllike-Cw3Iccsb.js +1 -0
- package/dist/apps/context-files-ui/assets/modelica-Czx80fNR.js +1 -0
- package/dist/apps/context-files-ui/assets/mscgen-BmfuTbzG.js +1 -0
- package/dist/apps/context-files-ui/assets/mumps-Ds_ZaumL.js +1 -0
- package/dist/apps/context-files-ui/assets/nginx-D9M2PQ4U.js +1 -0
- package/dist/apps/context-files-ui/assets/nsis-DOo3SJmd.js +1 -0
- package/dist/apps/context-files-ui/assets/ntriples-DLHGTvHs.js +1 -0
- package/dist/apps/context-files-ui/assets/octave-8jj96JiC.js +1 -0
- package/dist/apps/context-files-ui/assets/oz-BmMq7iC4.js +1 -0
- package/dist/apps/context-files-ui/assets/pascal-BgMr6XpT.js +1 -0
- package/dist/apps/context-files-ui/assets/perl-D6YJObi_.js +1 -0
- package/dist/apps/context-files-ui/assets/pig-nx7uchs8.js +1 -0
- package/dist/apps/context-files-ui/assets/powershell-B4IPkVxR.js +1 -0
- package/dist/apps/context-files-ui/assets/properties-CoavQdLC.js +1 -0
- package/dist/apps/context-files-ui/assets/protobuf-D5EWhcmc.js +1 -0
- package/dist/apps/context-files-ui/assets/pug-QU72BPAa.js +1 -0
- package/dist/apps/context-files-ui/assets/puppet-B_0GFuyD.js +1 -0
- package/dist/apps/context-files-ui/assets/python-Cs7sNzy_.js +1 -0
- package/dist/apps/context-files-ui/assets/q-BIB9pPtI.js +1 -0
- package/dist/apps/context-files-ui/assets/r-CN5s4f3o.js +1 -0
- package/dist/apps/context-files-ui/assets/rpm-Ct_Ck8mQ.js +1 -0
- package/dist/apps/context-files-ui/assets/ruby-BVPradRk.js +1 -0
- package/dist/apps/context-files-ui/assets/sas-DN4j74IF.js +1 -0
- package/dist/apps/context-files-ui/assets/scheme-CvNgHAnh.js +1 -0
- package/dist/apps/context-files-ui/assets/shell-BjiMLAaM.js +1 -0
- package/dist/apps/context-files-ui/assets/sieve-C2U1O5Z4.js +1 -0
- package/dist/apps/context-files-ui/assets/simple-mode-DnMbQuKW.js +1 -0
- package/dist/apps/context-files-ui/assets/smalltalk-DkYwYufV.js +1 -0
- package/dist/apps/context-files-ui/assets/solr-BopnSD-v.js +1 -0
- package/dist/apps/context-files-ui/assets/sparql-Cpg3YQfd.js +1 -0
- package/dist/apps/context-files-ui/assets/spreadsheet-kRxtVt9J.js +1 -0
- package/dist/apps/context-files-ui/assets/sql-DYI2GwJR.js +1 -0
- package/dist/apps/context-files-ui/assets/stex-BCRT8IJ3.js +1 -0
- package/dist/apps/context-files-ui/assets/stylus-CARoeVE9.js +1 -0
- package/dist/apps/context-files-ui/assets/swift-DKNaLAK6.js +1 -0
- package/dist/apps/context-files-ui/assets/tcl-CQyXkgMH.js +1 -0
- package/dist/apps/context-files-ui/assets/textile-Yg_UWn-t.js +1 -0
- package/dist/apps/context-files-ui/assets/tiddlywiki-dqVbkfX4.js +1 -0
- package/dist/apps/context-files-ui/assets/tiki-CC_ic8g0.js +1 -0
- package/dist/apps/context-files-ui/assets/toml-B7gGzVkJ.js +1 -0
- package/dist/apps/context-files-ui/assets/troff-Bq3z6oAu.js +1 -0
- package/dist/apps/context-files-ui/assets/ttcn-GvRgs2AT.js +1 -0
- package/dist/apps/context-files-ui/assets/ttcn-cfg-CGCXz7Vo.js +1 -0
- package/dist/apps/context-files-ui/assets/turtle-CwIpz2yy.js +1 -0
- package/dist/apps/context-files-ui/assets/vb-BmcHUM2C.js +1 -0
- package/dist/apps/context-files-ui/assets/vbscript-Cs9dylre.js +1 -0
- package/dist/apps/context-files-ui/assets/velocity-CBWU0VCy.js +1 -0
- package/dist/apps/context-files-ui/assets/verilog-DVCHmufx.js +1 -0
- package/dist/apps/context-files-ui/assets/vhdl-BGDk4f1d.js +1 -0
- package/dist/apps/context-files-ui/assets/webidl-egXQEWlC.js +1 -0
- package/dist/apps/context-files-ui/assets/xquery-5f0hn7cg.js +1 -0
- package/dist/apps/context-files-ui/assets/yacas-DNs9XkmQ.js +1 -0
- package/dist/apps/context-files-ui/assets/z80-B7Dfb4UO.js +1 -0
- package/dist/apps/context-files-ui/index.html +14 -0
- package/dist/auth/better-auth.js +129 -0
- package/dist/auth/types.js +14 -0
- package/dist/bin/pibo.js +3 -0
- package/dist/channels/types.js +1 -0
- package/dist/cli-errors.js +18 -0
- package/dist/cli.js +264 -0
- package/dist/config/config.js +167 -0
- package/dist/core/base-prompt.js +104 -0
- package/dist/core/codex-compat.js +44 -0
- package/dist/core/compaction-prompt.js +258 -0
- package/dist/core/events.js +1 -0
- package/dist/core/profiles.js +138 -0
- package/dist/core/routed-session.js +538 -0
- package/dist/core/runtime.js +323 -0
- package/dist/core/session-router.js +437 -0
- package/dist/core/system-prompt-template.js +56 -0
- package/dist/core/thinking.js +9 -0
- package/dist/core/workspace.js +5 -0
- package/dist/debug/events.js +92 -0
- package/dist/debug/index.js +631 -0
- package/dist/debug/session.js +200 -0
- package/dist/debug/sql.js +238 -0
- package/dist/debug/stores.js +49 -0
- package/dist/debug/trace.js +245 -0
- package/dist/env.js +32 -0
- package/dist/gateway/client.js +200 -0
- package/dist/gateway/protocol.js +46 -0
- package/dist/gateway/request.js +146 -0
- package/dist/gateway/server.js +221 -0
- package/dist/gateway/tool.js +69 -0
- package/dist/gateway/web.js +80 -0
- package/dist/index.js +23 -0
- package/dist/local/client.js +77 -0
- package/dist/local/extension.js +548 -0
- package/dist/local/tui.js +25 -0
- package/dist/mcp/agent-context.js +123 -0
- package/dist/mcp/client.js +332 -0
- package/dist/mcp/commands/call.js +146 -0
- package/dist/mcp/commands/grep.js +145 -0
- package/dist/mcp/commands/info.js +71 -0
- package/dist/mcp/commands/list.js +94 -0
- package/dist/mcp/config-command.js +217 -0
- package/dist/mcp/config.js +440 -0
- package/dist/mcp/daemon-client.js +266 -0
- package/dist/mcp/daemon.js +327 -0
- package/dist/mcp/errors.js +287 -0
- package/dist/mcp/index.js +431 -0
- package/dist/mcp/output.js +171 -0
- package/dist/mcp/python-runtime.js +131 -0
- package/dist/mcp/registry.js +116 -0
- package/dist/mcp/version.js +5 -0
- package/dist/pi-packages/cli.js +92 -0
- package/dist/pi-packages/installer.js +70 -0
- package/dist/pi-packages/metadata.js +231 -0
- package/dist/pi-packages/runtime.js +61 -0
- package/dist/pi-packages/store.js +175 -0
- package/dist/pi-packages/types.js +1 -0
- package/dist/plugins/better-auth.js +11 -0
- package/dist/plugins/builtin.js +249 -0
- package/dist/plugins/chat-web.js +11 -0
- package/dist/plugins/codex-compat.js +72 -0
- package/dist/plugins/context-files-store.js +354 -0
- package/dist/plugins/context-files.js +999 -0
- package/dist/plugins/core-tools.js +94 -0
- package/dist/plugins/example.js +67 -0
- package/dist/plugins/registry.js +368 -0
- package/dist/plugins/remote-agent.js +9 -0
- package/dist/plugins/types.js +1 -0
- package/dist/plugins/web.js +11 -0
- package/dist/reliability/store.js +759 -0
- package/dist/remote/channel.js +176 -0
- package/dist/remote/client.js +92 -0
- package/dist/remote/examples/tui-controller.js +263 -0
- package/dist/remote/protocol.js +55 -0
- package/dist/remote/session-client.js +189 -0
- package/dist/runs/registry.js +323 -0
- package/dist/runs/tools.js +185 -0
- package/dist/sessions/bindings.js +41 -0
- package/dist/sessions/sqlite-store.js +154 -0
- package/dist/sessions/store.js +125 -0
- package/dist/shared/trace-order.js +83 -0
- package/dist/subagents/tool.js +63 -0
- package/dist/tools/browser-use-cdp.js +207 -0
- package/dist/tools/browser-use-leases.js +338 -0
- package/dist/tools/browser-use-wrapper.js +338 -0
- package/dist/tools/codex-compat.js +85 -0
- package/dist/tools/desktop-env.js +90 -0
- package/dist/tools/guides.js +276 -0
- package/dist/tools/index.js +366 -0
- package/dist/tools/python-runtime.js +154 -0
- package/dist/tools/registry.js +107 -0
- package/dist/tools/web-search.js +137 -0
- package/dist/web/auth.js +10 -0
- package/dist/web/channel.js +151 -0
- package/dist/web/http.js +110 -0
- package/dist/web/types.js +1 -0
- package/package.json +74 -0
- package/src/mcp/LICENSE.mcp-cli +21 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Client - Connection management for MCP servers
|
|
3
|
+
*/
|
|
4
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
6
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
7
|
+
import { debug, filterTools, getConcurrencyLimit, getMaxRetries, getRetryDelayMs, getTimeoutMs, isDaemonEnabled, isHttpServer, isToolAllowed, } from './config.js';
|
|
8
|
+
import { cleanupOrphanedDaemons, getDaemonConnection, } from './daemon-client.js';
|
|
9
|
+
import { VERSION } from './version.js';
|
|
10
|
+
// Re-export config utilities for convenience
|
|
11
|
+
export { debug, getTimeoutMs, getConcurrencyLimit };
|
|
12
|
+
/**
|
|
13
|
+
* Get retry config respecting MCP_TIMEOUT budget
|
|
14
|
+
*/
|
|
15
|
+
function getRetryConfig() {
|
|
16
|
+
const totalBudgetMs = getTimeoutMs();
|
|
17
|
+
const maxRetries = getMaxRetries();
|
|
18
|
+
const baseDelayMs = getRetryDelayMs();
|
|
19
|
+
// Reserve at least 5s for the final attempt
|
|
20
|
+
const retryBudgetMs = Math.max(0, totalBudgetMs - 5000);
|
|
21
|
+
return {
|
|
22
|
+
maxRetries,
|
|
23
|
+
baseDelayMs,
|
|
24
|
+
maxDelayMs: Math.min(10000, retryBudgetMs / 2),
|
|
25
|
+
totalBudgetMs,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check if an error is transient and worth retrying
|
|
30
|
+
* Uses error codes when available, falls back to message matching
|
|
31
|
+
*/
|
|
32
|
+
export function isTransientError(error) {
|
|
33
|
+
// Check error code first (more reliable than message matching)
|
|
34
|
+
const nodeError = error;
|
|
35
|
+
if (nodeError.code) {
|
|
36
|
+
const transientCodes = [
|
|
37
|
+
'ECONNREFUSED',
|
|
38
|
+
'ECONNRESET',
|
|
39
|
+
'ETIMEDOUT',
|
|
40
|
+
'ENOTFOUND',
|
|
41
|
+
'EPIPE',
|
|
42
|
+
'ENETUNREACH',
|
|
43
|
+
'EHOSTUNREACH',
|
|
44
|
+
'EAI_AGAIN',
|
|
45
|
+
];
|
|
46
|
+
if (transientCodes.includes(nodeError.code)) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// Fallback to message matching for errors without codes
|
|
51
|
+
const message = error.message;
|
|
52
|
+
// HTTP transient errors - require status code at start or with HTTP context
|
|
53
|
+
// Pattern: "502", "502 Bad Gateway", "HTTP 502", "status 502", "status code 502"
|
|
54
|
+
if (/^(502|503|504|429)\b/.test(message))
|
|
55
|
+
return true;
|
|
56
|
+
if (/\b(http|status(\s+code)?)\s*(502|503|504|429)\b/i.test(message))
|
|
57
|
+
return true;
|
|
58
|
+
if (/\b(502|503|504|429)\s+(bad gateway|service unavailable|gateway timeout|too many requests)/i.test(message))
|
|
59
|
+
return true;
|
|
60
|
+
// Generic network terms - more specific patterns
|
|
61
|
+
if (/network\s*(error|fail|unavailable|timeout)/i.test(message))
|
|
62
|
+
return true;
|
|
63
|
+
if (/connection\s*(reset|refused|timeout)/i.test(message))
|
|
64
|
+
return true;
|
|
65
|
+
if (/\btimeout\b/i.test(message))
|
|
66
|
+
return true;
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Calculate delay with exponential backoff and jitter
|
|
71
|
+
*/
|
|
72
|
+
function calculateDelay(attempt, config) {
|
|
73
|
+
const exponentialDelay = config.baseDelayMs * 2 ** attempt;
|
|
74
|
+
const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs);
|
|
75
|
+
// Add jitter (±25%)
|
|
76
|
+
const jitter = cappedDelay * 0.25 * (Math.random() * 2 - 1);
|
|
77
|
+
return Math.round(cappedDelay + jitter);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Sleep for specified milliseconds
|
|
81
|
+
*/
|
|
82
|
+
function sleep(ms) {
|
|
83
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Execute a function with retry logic for transient failures
|
|
87
|
+
* Respects overall timeout budget from MCP_TIMEOUT
|
|
88
|
+
*/
|
|
89
|
+
async function withRetry(fn, operationName, config = getRetryConfig()) {
|
|
90
|
+
let lastError;
|
|
91
|
+
const startTime = Date.now();
|
|
92
|
+
for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
|
|
93
|
+
// Check if we've exceeded the total timeout budget
|
|
94
|
+
const elapsed = Date.now() - startTime;
|
|
95
|
+
if (elapsed >= config.totalBudgetMs) {
|
|
96
|
+
debug(`${operationName}: timeout budget exhausted after ${elapsed}ms`);
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
return await fn();
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
lastError = error;
|
|
104
|
+
const remainingBudget = config.totalBudgetMs - (Date.now() - startTime);
|
|
105
|
+
const shouldRetry = attempt < config.maxRetries &&
|
|
106
|
+
isTransientError(lastError) &&
|
|
107
|
+
remainingBudget > 1000; // At least 1s remaining
|
|
108
|
+
if (shouldRetry) {
|
|
109
|
+
const delay = Math.min(calculateDelay(attempt, config), remainingBudget - 1000);
|
|
110
|
+
debug(`${operationName} failed (attempt ${attempt + 1}/${config.maxRetries + 1}): ${lastError.message}. Retrying in ${delay}ms...`);
|
|
111
|
+
await sleep(delay);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
throw lastError;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
throw lastError;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Safely close a connection, logging but not throwing on error
|
|
122
|
+
*/
|
|
123
|
+
export async function safeClose(close) {
|
|
124
|
+
try {
|
|
125
|
+
await close();
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
debug(`Failed to close connection: ${err.message}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Connect to an MCP server with retry logic
|
|
133
|
+
* Captures stderr from stdio servers to include in error messages
|
|
134
|
+
*/
|
|
135
|
+
export async function connectToServer(serverName, config) {
|
|
136
|
+
// Collect stderr for better error messages
|
|
137
|
+
const stderrChunks = [];
|
|
138
|
+
return withRetry(async () => {
|
|
139
|
+
const client = new Client({
|
|
140
|
+
name: 'mcp-cli',
|
|
141
|
+
version: VERSION,
|
|
142
|
+
}, {
|
|
143
|
+
capabilities: {},
|
|
144
|
+
});
|
|
145
|
+
let transport;
|
|
146
|
+
if (isHttpServer(config)) {
|
|
147
|
+
transport = createHttpTransport(config);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
transport = createStdioTransport(config);
|
|
151
|
+
// Capture stderr for debugging - attach BEFORE connect
|
|
152
|
+
// Always stream stderr immediately so auth prompts are visible
|
|
153
|
+
const stderrStream = transport.stderr;
|
|
154
|
+
if (stderrStream) {
|
|
155
|
+
stderrStream.on('data', (chunk) => {
|
|
156
|
+
const text = chunk.toString();
|
|
157
|
+
stderrChunks.push(text);
|
|
158
|
+
// Always stream stderr immediately so users can see auth prompts
|
|
159
|
+
process.stderr.write(`[${serverName}] ${text}`);
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
try {
|
|
164
|
+
await client.connect(transport);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
// Enhance error with captured stderr
|
|
168
|
+
const stderrOutput = stderrChunks.join('').trim();
|
|
169
|
+
if (stderrOutput) {
|
|
170
|
+
const err = error;
|
|
171
|
+
err.message = `${err.message}\n\nServer stderr:\n${stderrOutput}`;
|
|
172
|
+
}
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
// For successful connections, forward stderr to console
|
|
176
|
+
if (!isHttpServer(config)) {
|
|
177
|
+
const stderrStream = transport.stderr;
|
|
178
|
+
if (stderrStream) {
|
|
179
|
+
stderrStream.on('data', (chunk) => {
|
|
180
|
+
process.stderr.write(chunk);
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
client,
|
|
186
|
+
close: async () => {
|
|
187
|
+
await client.close();
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}, `connect to ${serverName}`);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Create HTTP transport for remote servers
|
|
194
|
+
*/
|
|
195
|
+
function createHttpTransport(config) {
|
|
196
|
+
const url = new URL(config.url);
|
|
197
|
+
return new StreamableHTTPClientTransport(url, {
|
|
198
|
+
requestInit: {
|
|
199
|
+
headers: config.headers,
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Create stdio transport for local servers
|
|
205
|
+
* Uses stderr: 'pipe' to capture server output for debugging
|
|
206
|
+
*/
|
|
207
|
+
function createStdioTransport(config) {
|
|
208
|
+
// Merge process.env with config.env, filtering out undefined values
|
|
209
|
+
const mergedEnv = {};
|
|
210
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
211
|
+
if (value !== undefined) {
|
|
212
|
+
mergedEnv[key] = value;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (config.env) {
|
|
216
|
+
Object.assign(mergedEnv, config.env);
|
|
217
|
+
}
|
|
218
|
+
return new StdioClientTransport({
|
|
219
|
+
command: config.command,
|
|
220
|
+
args: config.args,
|
|
221
|
+
env: mergedEnv,
|
|
222
|
+
cwd: config.cwd,
|
|
223
|
+
stderr: 'pipe', // Capture stderr for better error messages
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* List all tools from a connected client with retry logic
|
|
228
|
+
*/
|
|
229
|
+
export async function listTools(client) {
|
|
230
|
+
return withRetry(async () => {
|
|
231
|
+
const result = await client.listTools();
|
|
232
|
+
return result.tools.map((tool) => ({
|
|
233
|
+
name: tool.name,
|
|
234
|
+
description: tool.description,
|
|
235
|
+
inputSchema: tool.inputSchema,
|
|
236
|
+
}));
|
|
237
|
+
}, 'list tools');
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get a specific tool by name
|
|
241
|
+
*/
|
|
242
|
+
export async function getTool(client, toolName) {
|
|
243
|
+
const tools = await listTools(client);
|
|
244
|
+
return tools.find((t) => t.name === toolName);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Call a tool with arguments and retry logic
|
|
248
|
+
*/
|
|
249
|
+
export async function callTool(client, toolName, args) {
|
|
250
|
+
return withRetry(async () => {
|
|
251
|
+
const result = await client.callTool({
|
|
252
|
+
name: toolName,
|
|
253
|
+
arguments: args,
|
|
254
|
+
}, undefined, { timeout: getTimeoutMs() });
|
|
255
|
+
return result;
|
|
256
|
+
}, `call tool ${toolName}`);
|
|
257
|
+
}
|
|
258
|
+
// ============================================================================
|
|
259
|
+
// Unified Connection Interface (Daemon + Direct)
|
|
260
|
+
// ============================================================================
|
|
261
|
+
/**
|
|
262
|
+
* Get a unified connection to an MCP server
|
|
263
|
+
*
|
|
264
|
+
* If daemon mode is enabled (default), tries to use a cached daemon connection.
|
|
265
|
+
* Falls back to direct connection if daemon fails or is disabled.
|
|
266
|
+
*
|
|
267
|
+
* @param serverName - Name of the server from config
|
|
268
|
+
* @param config - Server configuration
|
|
269
|
+
* @returns McpConnection with listTools, callTool, and close methods
|
|
270
|
+
*/
|
|
271
|
+
export async function getConnection(serverName, config) {
|
|
272
|
+
// Clean up any orphaned daemons on first call
|
|
273
|
+
await cleanupOrphanedDaemons();
|
|
274
|
+
// Try daemon connection if enabled
|
|
275
|
+
if (isDaemonEnabled()) {
|
|
276
|
+
try {
|
|
277
|
+
const daemonConn = await getDaemonConnection(serverName, config);
|
|
278
|
+
if (daemonConn) {
|
|
279
|
+
debug(`Using daemon connection for ${serverName}`);
|
|
280
|
+
return {
|
|
281
|
+
async listTools() {
|
|
282
|
+
const data = await daemonConn.listTools();
|
|
283
|
+
const tools = data;
|
|
284
|
+
// Apply tool filtering from config
|
|
285
|
+
return filterTools(tools, config);
|
|
286
|
+
},
|
|
287
|
+
async callTool(toolName, args) {
|
|
288
|
+
// Check if tool is allowed before calling
|
|
289
|
+
if (!isToolAllowed(toolName, config)) {
|
|
290
|
+
throw new Error(`Tool "${toolName}" is disabled by configuration`);
|
|
291
|
+
}
|
|
292
|
+
return daemonConn.callTool(toolName, args);
|
|
293
|
+
},
|
|
294
|
+
async getInstructions() {
|
|
295
|
+
return daemonConn.getInstructions();
|
|
296
|
+
},
|
|
297
|
+
async close() {
|
|
298
|
+
await daemonConn.close();
|
|
299
|
+
},
|
|
300
|
+
isDaemon: true,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
debug(`Daemon connection failed for ${serverName}: ${err.message}, falling back to direct`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// Fall back to direct connection
|
|
309
|
+
debug(`Using direct connection for ${serverName}`);
|
|
310
|
+
const { client, close } = await connectToServer(serverName, config);
|
|
311
|
+
return {
|
|
312
|
+
async listTools() {
|
|
313
|
+
const tools = await listTools(client);
|
|
314
|
+
// Apply tool filtering from config
|
|
315
|
+
return filterTools(tools, config);
|
|
316
|
+
},
|
|
317
|
+
async callTool(toolName, args) {
|
|
318
|
+
// Check if tool is allowed before calling
|
|
319
|
+
if (!isToolAllowed(toolName, config)) {
|
|
320
|
+
throw new Error(`Tool "${toolName}" is disabled by configuration`);
|
|
321
|
+
}
|
|
322
|
+
return callTool(client, toolName, args);
|
|
323
|
+
},
|
|
324
|
+
async getInstructions() {
|
|
325
|
+
return client.getInstructions();
|
|
326
|
+
},
|
|
327
|
+
async close() {
|
|
328
|
+
await close();
|
|
329
|
+
},
|
|
330
|
+
isDaemon: false,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Call command - Execute a tool with arguments
|
|
3
|
+
*
|
|
4
|
+
* Output behavior:
|
|
5
|
+
* - Default: Raw text content to stdout (CLI-friendly)
|
|
6
|
+
* - With --json: Full JSON response to stdout
|
|
7
|
+
* - Errors always go to stderr
|
|
8
|
+
*/
|
|
9
|
+
import { getConnection, getTimeoutMs, safeClose, } from '../client.js';
|
|
10
|
+
import { getServerConfig, loadConfig, } from '../config.js';
|
|
11
|
+
import { ErrorCode, formatCliError, invalidJsonArgsError, invalidTargetError, serverConnectionError, toolExecutionError, toolNotFoundError, } from '../errors.js';
|
|
12
|
+
import { formatToolResult } from '../output.js';
|
|
13
|
+
/**
|
|
14
|
+
* Parse target into server and tool name
|
|
15
|
+
*/
|
|
16
|
+
function parseTarget(target) {
|
|
17
|
+
const slashIndex = target.indexOf('/');
|
|
18
|
+
if (slashIndex === -1) {
|
|
19
|
+
throw new Error(formatCliError(invalidTargetError(target)));
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
server: target.substring(0, slashIndex),
|
|
23
|
+
tool: target.substring(slashIndex + 1),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse JSON arguments from string or stdin
|
|
28
|
+
*/
|
|
29
|
+
async function parseArgs(argsString) {
|
|
30
|
+
let jsonString;
|
|
31
|
+
if (argsString) {
|
|
32
|
+
jsonString = argsString;
|
|
33
|
+
}
|
|
34
|
+
else if (!process.stdin.isTTY) {
|
|
35
|
+
// Read from stdin with timeout - use timer cleanup to prevent memory leak
|
|
36
|
+
const timeoutMs = getTimeoutMs();
|
|
37
|
+
const chunks = [];
|
|
38
|
+
let timeoutId;
|
|
39
|
+
const readPromise = (async () => {
|
|
40
|
+
for await (const chunk of process.stdin) {
|
|
41
|
+
chunks.push(chunk);
|
|
42
|
+
}
|
|
43
|
+
return Buffer.concat(chunks).toString('utf-8').trim();
|
|
44
|
+
})();
|
|
45
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
46
|
+
timeoutId = setTimeout(() => reject(new Error(`stdin read timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
jsonString = await Promise.race([readPromise, timeoutPromise]);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
if (timeoutId)
|
|
53
|
+
clearTimeout(timeoutId);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// No arguments provided
|
|
58
|
+
return {};
|
|
59
|
+
}
|
|
60
|
+
if (!jsonString) {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(jsonString);
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
throw new Error(formatCliError(invalidJsonArgsError(jsonString, e.message)));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Execute the call command
|
|
72
|
+
*/
|
|
73
|
+
export async function callCommand(options) {
|
|
74
|
+
let config;
|
|
75
|
+
try {
|
|
76
|
+
config = await loadConfig(options.configPath);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(error.message);
|
|
80
|
+
process.exit(ErrorCode.CLIENT_ERROR);
|
|
81
|
+
}
|
|
82
|
+
let serverName;
|
|
83
|
+
let toolName;
|
|
84
|
+
try {
|
|
85
|
+
const parsed = parseTarget(options.target);
|
|
86
|
+
serverName = parsed.server;
|
|
87
|
+
toolName = parsed.tool;
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
console.error(error.message);
|
|
91
|
+
process.exit(ErrorCode.CLIENT_ERROR);
|
|
92
|
+
}
|
|
93
|
+
let serverConfig;
|
|
94
|
+
try {
|
|
95
|
+
serverConfig = getServerConfig(config, serverName);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error(error.message);
|
|
99
|
+
process.exit(ErrorCode.CLIENT_ERROR);
|
|
100
|
+
}
|
|
101
|
+
let args;
|
|
102
|
+
try {
|
|
103
|
+
args = await parseArgs(options.args);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error(error.message);
|
|
107
|
+
process.exit(ErrorCode.CLIENT_ERROR);
|
|
108
|
+
}
|
|
109
|
+
let connection;
|
|
110
|
+
try {
|
|
111
|
+
connection = await getConnection(serverName, serverConfig);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
console.error(formatCliError(serverConnectionError(serverName, error.message)));
|
|
115
|
+
process.exit(ErrorCode.NETWORK_ERROR);
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const result = await connection.callTool(toolName, args);
|
|
119
|
+
// Extract text content from MCP response for CLI-friendly output
|
|
120
|
+
// Uses formatToolResult which extracts text from MCP content array
|
|
121
|
+
console.log(formatToolResult(result));
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
// Try to get available tools for better error message
|
|
125
|
+
let availableTools;
|
|
126
|
+
try {
|
|
127
|
+
const tools = await connection.listTools();
|
|
128
|
+
availableTools = tools.map((t) => t.name);
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// Ignore - we'll show error without tool list
|
|
132
|
+
}
|
|
133
|
+
const errMsg = error.message;
|
|
134
|
+
// Check if it's a "tool not found" type error
|
|
135
|
+
if (errMsg.includes('not found') || errMsg.includes('unknown tool')) {
|
|
136
|
+
console.error(formatCliError(toolNotFoundError(toolName, serverName, availableTools)));
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
console.error(formatCliError(toolExecutionError(toolName, serverName, errMsg)));
|
|
140
|
+
}
|
|
141
|
+
process.exit(ErrorCode.SERVER_ERROR);
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
await safeClose(connection.close);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grep command - Search tools by pattern
|
|
3
|
+
*/
|
|
4
|
+
import { debug, getConcurrencyLimit, getConnection, safeClose, } from '../client.js';
|
|
5
|
+
import { getServerConfig, listServerNames, loadConfig, } from '../config.js';
|
|
6
|
+
import { ErrorCode } from '../errors.js';
|
|
7
|
+
import { formatSearchResults } from '../output.js';
|
|
8
|
+
/**
|
|
9
|
+
* Convert glob pattern to regex
|
|
10
|
+
* Handles: * (any chars), ? (single char), ** (globstar)
|
|
11
|
+
*
|
|
12
|
+
* Examples:
|
|
13
|
+
* - "*file*" matches "read_file", "file_utils"
|
|
14
|
+
* - "**test**" matches "test", "my_test_tool", "testing"
|
|
15
|
+
* - "server/*" matches "server/tool" but not "server/sub/tool"
|
|
16
|
+
* - "server/**" matches "server/tool" and "server/sub/tool"
|
|
17
|
+
*/
|
|
18
|
+
export function globToRegex(pattern) {
|
|
19
|
+
let escaped = '';
|
|
20
|
+
let i = 0;
|
|
21
|
+
while (i < pattern.length) {
|
|
22
|
+
const char = pattern[i];
|
|
23
|
+
if (char === '*' && pattern[i + 1] === '*') {
|
|
24
|
+
// ** (globstar) - match anything including slashes (zero or more chars)
|
|
25
|
+
escaped += '.*';
|
|
26
|
+
i += 2;
|
|
27
|
+
// Skip any immediately following * (e.g., *** becomes .*)
|
|
28
|
+
while (pattern[i] === '*') {
|
|
29
|
+
i++;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else if (char === '*') {
|
|
33
|
+
// * - match any chars except slash (zero or more)
|
|
34
|
+
escaped += '[^/]*';
|
|
35
|
+
i += 1;
|
|
36
|
+
}
|
|
37
|
+
else if (char === '?') {
|
|
38
|
+
// ? - match single char (not slash)
|
|
39
|
+
escaped += '[^/]';
|
|
40
|
+
i += 1;
|
|
41
|
+
}
|
|
42
|
+
else if ('[.+^${}()|\\]'.includes(char)) {
|
|
43
|
+
// Escape special regex chars
|
|
44
|
+
escaped += `\\${char}`;
|
|
45
|
+
i += 1;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
escaped += char;
|
|
49
|
+
i += 1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return new RegExp(`^${escaped}$`, 'i');
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Process items with limited concurrency, preserving order
|
|
56
|
+
*/
|
|
57
|
+
async function processWithConcurrency(items, processor, maxConcurrency) {
|
|
58
|
+
const results = new Array(items.length);
|
|
59
|
+
let currentIndex = 0;
|
|
60
|
+
async function worker() {
|
|
61
|
+
while (currentIndex < items.length) {
|
|
62
|
+
const index = currentIndex++;
|
|
63
|
+
results[index] = await processor(items[index], index);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Start workers up to concurrency limit
|
|
67
|
+
const workers = Array.from({ length: Math.min(maxConcurrency, items.length) }, () => worker());
|
|
68
|
+
await Promise.all(workers);
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Search tools in a single server (uses daemon if enabled)
|
|
73
|
+
*/
|
|
74
|
+
async function searchServerTools(serverName, config, pattern) {
|
|
75
|
+
let connection = null;
|
|
76
|
+
try {
|
|
77
|
+
const serverConfig = getServerConfig(config, serverName);
|
|
78
|
+
connection = await getConnection(serverName, serverConfig);
|
|
79
|
+
const tools = await connection.listTools();
|
|
80
|
+
const results = [];
|
|
81
|
+
for (const tool of tools) {
|
|
82
|
+
// Match against tool name only (not server name or description)
|
|
83
|
+
if (pattern.test(tool.name)) {
|
|
84
|
+
results.push({ server: serverName, tool });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
debug(`${serverName}: found ${results.length} matches`);
|
|
88
|
+
return { serverName, results };
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
const errorMsg = error.message;
|
|
92
|
+
debug(`${serverName}: connection failed - ${errorMsg}`);
|
|
93
|
+
return { serverName, results: [], error: errorMsg };
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
if (connection) {
|
|
97
|
+
await safeClose(connection.close);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Execute the grep command
|
|
103
|
+
*/
|
|
104
|
+
export async function grepCommand(options) {
|
|
105
|
+
let config;
|
|
106
|
+
try {
|
|
107
|
+
config = await loadConfig(options.configPath);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error(error.message);
|
|
111
|
+
process.exit(ErrorCode.CLIENT_ERROR);
|
|
112
|
+
}
|
|
113
|
+
const pattern = globToRegex(options.pattern);
|
|
114
|
+
const serverNames = listServerNames(config);
|
|
115
|
+
if (serverNames.length === 0) {
|
|
116
|
+
console.log('No MCP servers configured.');
|
|
117
|
+
console.log('Next: pibo mcp config help');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const concurrencyLimit = getConcurrencyLimit();
|
|
121
|
+
debug(`Searching ${serverNames.length} servers for pattern "${options.pattern}" (concurrency: ${concurrencyLimit})`);
|
|
122
|
+
// Process servers in parallel with concurrency limit
|
|
123
|
+
const serverResults = await processWithConcurrency(serverNames, (serverName) => searchServerTools(serverName, config, pattern), concurrencyLimit);
|
|
124
|
+
const allResults = [];
|
|
125
|
+
const failedServers = [];
|
|
126
|
+
for (const result of serverResults) {
|
|
127
|
+
allResults.push(...result.results);
|
|
128
|
+
if (result.error) {
|
|
129
|
+
failedServers.push(result.serverName);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
// Show failed servers warning
|
|
133
|
+
if (failedServers.length > 0) {
|
|
134
|
+
console.error(`Warning: ${failedServers.length} server(s) failed to connect: ${failedServers.join(', ')}`);
|
|
135
|
+
}
|
|
136
|
+
if (allResults.length === 0) {
|
|
137
|
+
console.log(`No tools found matching "${options.pattern}"`);
|
|
138
|
+
console.log(' Tip: Pattern matches tool names only (not server names)');
|
|
139
|
+
console.log(` Tip: Use '*' for wildcards, e.g. '*file*' or 'read_*'`);
|
|
140
|
+
console.log(` Tip: Run 'pibo mcp' to list all available tools`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// Human-readable output
|
|
144
|
+
console.log(formatSearchResults(allResults, options.withDescriptions));
|
|
145
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Info command - Show server or tool details
|
|
3
|
+
*/
|
|
4
|
+
import { getConnection, safeClose } from '../client.js';
|
|
5
|
+
import { getServerConfig, loadConfig, } from '../config.js';
|
|
6
|
+
import { ErrorCode, formatCliError, serverConnectionError, toolNotFoundError, } from '../errors.js';
|
|
7
|
+
import { formatServerDetails, formatToolSchema } from '../output.js';
|
|
8
|
+
/**
|
|
9
|
+
* Parse target into server and optional tool name
|
|
10
|
+
*/
|
|
11
|
+
function parseTarget(target) {
|
|
12
|
+
const parts = target.split('/');
|
|
13
|
+
if (parts.length === 1) {
|
|
14
|
+
return { server: parts[0] };
|
|
15
|
+
}
|
|
16
|
+
return { server: parts[0], tool: parts.slice(1).join('/') };
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Execute the info command
|
|
20
|
+
*/
|
|
21
|
+
export async function infoCommand(options) {
|
|
22
|
+
let config;
|
|
23
|
+
try {
|
|
24
|
+
config = await loadConfig(options.configPath);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error(error.message);
|
|
28
|
+
process.exit(ErrorCode.CLIENT_ERROR);
|
|
29
|
+
}
|
|
30
|
+
const { server: serverName, tool: toolName } = parseTarget(options.target);
|
|
31
|
+
let serverConfig;
|
|
32
|
+
try {
|
|
33
|
+
serverConfig = getServerConfig(config, serverName);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
console.error(error.message);
|
|
37
|
+
process.exit(ErrorCode.CLIENT_ERROR);
|
|
38
|
+
}
|
|
39
|
+
let connection;
|
|
40
|
+
try {
|
|
41
|
+
connection = await getConnection(serverName, serverConfig);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.error(formatCliError(serverConnectionError(serverName, error.message)));
|
|
45
|
+
process.exit(ErrorCode.NETWORK_ERROR);
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
if (toolName) {
|
|
49
|
+
// Show specific tool schema
|
|
50
|
+
const tools = await connection.listTools();
|
|
51
|
+
const tool = tools.find((t) => t.name === toolName);
|
|
52
|
+
if (!tool) {
|
|
53
|
+
const availableTools = tools.map((t) => t.name);
|
|
54
|
+
console.error(formatCliError(toolNotFoundError(toolName, serverName, availableTools)));
|
|
55
|
+
process.exit(ErrorCode.CLIENT_ERROR);
|
|
56
|
+
}
|
|
57
|
+
// Human-readable output
|
|
58
|
+
console.log(formatToolSchema(serverName, tool));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Show server details
|
|
62
|
+
const tools = await connection.listTools();
|
|
63
|
+
const instructions = await connection.getInstructions();
|
|
64
|
+
// Human-readable output
|
|
65
|
+
console.log(formatServerDetails(serverName, serverConfig, tools, options.withDescriptions, instructions));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
await safeClose(connection.close);
|
|
70
|
+
}
|
|
71
|
+
}
|