@shareai-lab/kode 2.0.1 → 2.0.3
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/LICENSE +201 -0
- package/README.md +649 -25
- package/README.zh-CN.md +579 -0
- package/cli-acp.js +3 -17
- package/cli.js +5 -7
- package/dist/chunks/Doctor-M3J7GRTJ.js +12 -0
- package/dist/chunks/LogList-ISWZ6DDD.js +121 -0
- package/dist/chunks/LogList-ISWZ6DDD.js.map +7 -0
- package/dist/chunks/REPL-RQ6LO6S7.js +56 -0
- package/dist/chunks/ResumeConversation-6DMVBEGH.js +56 -0
- package/dist/chunks/agentLoader-FCRG3TFJ.js +31 -0
- package/dist/{agentsValidate-7LH4HTNR.js → chunks/agentsValidate-PEWMYN4Q.js} +97 -69
- package/dist/chunks/agentsValidate-PEWMYN4Q.js.map +7 -0
- package/dist/{ask-3NHFFUQG.js → chunks/ask-D7SOHJ6Z.js} +36 -44
- package/dist/chunks/ask-D7SOHJ6Z.js.map +7 -0
- package/dist/chunks/autoUpdater-CNESBOKO.js +19 -0
- package/dist/{chunk-AFFSCMYS.js → chunks/chunk-2JN5MY67.js} +12 -14
- package/dist/chunks/chunk-2JN5MY67.js.map +7 -0
- package/dist/chunks/chunk-2QONJ5MG.js +14 -0
- package/dist/chunks/chunk-2QONJ5MG.js.map +7 -0
- package/dist/chunks/chunk-2WEXPKHH.js +903 -0
- package/dist/chunks/chunk-2WEXPKHH.js.map +7 -0
- package/dist/{chunk-ARZSBOAO.js → chunks/chunk-3BYE3ME6.js} +717 -792
- package/dist/chunks/chunk-3BYE3ME6.js.map +7 -0
- package/dist/chunks/chunk-3JDNWX7W.js +1264 -0
- package/dist/chunks/chunk-3JDNWX7W.js.map +7 -0
- package/dist/chunks/chunk-3OEJVB5A.js +906 -0
- package/dist/chunks/chunk-3OEJVB5A.js.map +7 -0
- package/dist/chunks/chunk-3TNIOEBO.js +369 -0
- package/dist/chunks/chunk-3TNIOEBO.js.map +7 -0
- package/dist/chunks/chunk-4A46ZXMJ.js +67 -0
- package/dist/chunks/chunk-4A46ZXMJ.js.map +7 -0
- package/dist/{chunk-UHYRLID6.js → chunks/chunk-4ATBQOFO.js} +107 -55
- package/dist/chunks/chunk-4ATBQOFO.js.map +7 -0
- package/dist/chunks/chunk-4CRUCZR4.js +0 -0
- package/dist/{chunk-YC6LJCDE.js → chunks/chunk-4EO6SIQY.js} +32 -75
- package/dist/chunks/chunk-4EO6SIQY.js.map +7 -0
- package/dist/chunks/chunk-53M46S5I.js +64 -0
- package/dist/chunks/chunk-53M46S5I.js.map +7 -0
- package/dist/{chunk-JC6NCUG5.js → chunks/chunk-54KOYG5C.js} +0 -2
- package/dist/{chunk-EZXMVTDU.js → chunks/chunk-6BAS4WY6.js} +29 -45
- package/dist/chunks/chunk-6BAS4WY6.js.map +7 -0
- package/dist/{chunk-3IN27HA5.js → chunks/chunk-6KRRFSDN.js} +4 -6
- package/dist/chunks/chunk-6KRRFSDN.js.map +7 -0
- package/dist/chunks/chunk-6LJNZK4K.js +39 -0
- package/dist/chunks/chunk-6LJNZK4K.js.map +7 -0
- package/dist/chunks/chunk-6ZWEOSEI.js +666 -0
- package/dist/chunks/chunk-6ZWEOSEI.js.map +7 -0
- package/dist/chunks/chunk-77XDJMBP.js +3326 -0
- package/dist/chunks/chunk-77XDJMBP.js.map +7 -0
- package/dist/chunks/chunk-7RRW4NTB.js +6454 -0
- package/dist/chunks/chunk-7RRW4NTB.js.map +7 -0
- package/dist/chunks/chunk-7X3TW4JB.js +4520 -0
- package/dist/chunks/chunk-7X3TW4JB.js.map +7 -0
- package/dist/chunks/chunk-B3MW3YGY.js +1409 -0
- package/dist/chunks/chunk-B3MW3YGY.js.map +7 -0
- package/dist/chunks/chunk-BBJFHTBC.js +28 -0
- package/dist/chunks/chunk-BBJFHTBC.js.map +7 -0
- package/dist/chunks/chunk-BHDHXOXB.js +24 -0
- package/dist/chunks/chunk-BHDHXOXB.js.map +7 -0
- package/dist/{chunk-73WGVYLQ.js → chunks/chunk-BTA7SZ26.js} +152 -223
- package/dist/chunks/chunk-BTA7SZ26.js.map +7 -0
- package/dist/chunks/chunk-CDGRYGPZ.js +103 -0
- package/dist/chunks/chunk-CDGRYGPZ.js.map +7 -0
- package/dist/{chunk-S6HRABTA.js → chunks/chunk-CP6E5UG6.js} +1 -4
- package/dist/chunks/chunk-CP6E5UG6.js.map +7 -0
- package/dist/{chunk-QVLYOPO5.js → chunks/chunk-DQ4JHXMT.js} +462 -424
- package/dist/chunks/chunk-DQ4JHXMT.js.map +7 -0
- package/dist/chunks/chunk-DXD76CMV.js +208 -0
- package/dist/chunks/chunk-DXD76CMV.js.map +7 -0
- package/dist/chunks/chunk-GCQCAXJZ.js +0 -0
- package/dist/chunks/chunk-GELCZWMB.js +42 -0
- package/dist/chunks/chunk-GELCZWMB.js.map +7 -0
- package/dist/{chunk-K2CWOTI2.js → chunks/chunk-HJYOH4HC.js} +23 -18
- package/dist/chunks/chunk-HJYOH4HC.js.map +7 -0
- package/dist/chunks/chunk-HPYNW6TT.js +744 -0
- package/dist/chunks/chunk-HPYNW6TT.js.map +7 -0
- package/dist/{chunk-RZWOUA25.js → chunks/chunk-HRJ3ICQK.js} +59 -55
- package/dist/chunks/chunk-HRJ3ICQK.js.map +7 -0
- package/dist/{chunk-DZE5YA7L.js → chunks/chunk-IFCIADS3.js} +571 -573
- package/dist/chunks/chunk-IFCIADS3.js.map +7 -0
- package/dist/chunks/chunk-IN7XZ7BC.js +27 -0
- package/dist/chunks/chunk-IN7XZ7BC.js.map +7 -0
- package/dist/chunks/chunk-L7P4M4KW.js +193 -0
- package/dist/chunks/chunk-L7P4M4KW.js.map +7 -0
- package/dist/chunks/chunk-LB6TCPDI.js +0 -0
- package/dist/{chunk-3RUXVV4S.js → chunks/chunk-LOCXPQNJ.js} +1 -4
- package/dist/{chunk-3RUXVV4S.js.map → chunks/chunk-LOCXPQNJ.js.map} +2 -2
- package/dist/{chunk-7M2YN6TU.js → chunks/chunk-LOD5ZHCI.js} +213 -208
- package/dist/chunks/chunk-LOD5ZHCI.js.map +7 -0
- package/dist/{chunk-S3J2TLV6.js → chunks/chunk-M7P3QNRU.js} +1 -4
- package/dist/{chunk-S3J2TLV6.js.map → chunks/chunk-M7P3QNRU.js.map} +2 -2
- package/dist/chunks/chunk-PPHLQVL7.js +4234 -0
- package/dist/chunks/chunk-PPHLQVL7.js.map +7 -0
- package/dist/{chunk-ABLVTESJ.js → chunks/chunk-QAXE37B5.js} +1 -4
- package/dist/chunks/chunk-QAXE37B5.js.map +7 -0
- package/dist/chunks/chunk-QHQOBUF6.js +60 -0
- package/dist/chunks/chunk-QHQOBUF6.js.map +7 -0
- package/dist/{chunk-W7GRKO7Q.js → chunks/chunk-RPJXO7GG.js} +241 -214
- package/dist/chunks/chunk-RPJXO7GG.js.map +7 -0
- package/dist/{chunk-NPFOMITO.js → chunks/chunk-SWQV4KSY.js} +1 -4
- package/dist/{chunk-NPFOMITO.js.map → chunks/chunk-SWQV4KSY.js.map} +2 -2
- package/dist/chunks/chunk-SZLAPULP.js +28 -0
- package/dist/chunks/chunk-SZLAPULP.js.map +7 -0
- package/dist/{chunk-7U7L4NMD.js → chunks/chunk-T7RB5V5J.js} +23 -25
- package/dist/chunks/chunk-T7RB5V5J.js.map +7 -0
- package/dist/{chunk-HN4E4UUQ.js → chunks/chunk-TI2CTTMA.js} +25 -17
- package/dist/chunks/chunk-TI2CTTMA.js.map +7 -0
- package/dist/{chunk-ZVDRDPII.js → chunks/chunk-TNGVRTO5.js} +45 -20
- package/dist/chunks/chunk-TNGVRTO5.js.map +7 -0
- package/dist/chunks/chunk-TNWB3U5Y.js +2077 -0
- package/dist/chunks/chunk-TNWB3U5Y.js.map +7 -0
- package/dist/chunks/chunk-U2IHWPCU.js +12 -0
- package/dist/chunks/chunk-U2IHWPCU.js.map +7 -0
- package/dist/{chunk-KAA5BGMQ.js → chunks/chunk-UNOY3VJ2.js} +1 -4
- package/dist/{chunk-KAA5BGMQ.js.map → chunks/chunk-UNOY3VJ2.js.map} +2 -2
- package/dist/{chunk-MWRSY4X6.js → chunks/chunk-UVDJL6ZZ.js} +97 -58
- package/dist/chunks/chunk-UVDJL6ZZ.js.map +7 -0
- package/dist/chunks/chunk-VNCW4C2Z.js +13452 -0
- package/dist/chunks/chunk-VNCW4C2Z.js.map +7 -0
- package/dist/chunks/chunk-W5EGGA44.js +15 -0
- package/dist/chunks/chunk-W5EGGA44.js.map +7 -0
- package/dist/chunks/chunk-XR2W3MAM.js +1533 -0
- package/dist/chunks/chunk-XR2W3MAM.js.map +7 -0
- package/dist/{chunk-STSX7GIX.js → chunks/chunk-YIO5EBMQ.js} +423 -377
- package/dist/chunks/chunk-YIO5EBMQ.js.map +7 -0
- package/dist/chunks/chunk-ZBVLKZ5V.js +1062 -0
- package/dist/chunks/chunk-ZBVLKZ5V.js.map +7 -0
- package/dist/{chunk-E6YNABER.js → chunks/chunk-ZCLTZIVP.js} +1 -4
- package/dist/chunks/chunk-ZCLTZIVP.js.map +7 -0
- package/dist/chunks/client-SILZNM5N.js +42 -0
- package/dist/{config-RUSD6G5Y.js → chunks/config-25HRTPSP.js} +48 -10
- package/dist/chunks/cost-tracker-Z2UZT2J5.js +28 -0
- package/dist/{customCommands-TOIJFZAL.js → chunks/customCommands-TYMYZRG5.js} +11 -8
- package/dist/chunks/engine-MRVF6FK6.js +39 -0
- package/dist/{env-XGKBLU3D.js → chunks/env-TJ5NOBEB.js} +7 -5
- package/dist/{kodeAgentSessionId-X6XWQW7B.js → chunks/kodeAgentSessionId-VTNISJ2L.js} +2 -4
- package/dist/chunks/kodeAgentSessionLoad-YB2RKBGJ.js +15 -0
- package/dist/chunks/kodeAgentSessionResume-DZSIVKVA.js +13 -0
- package/dist/chunks/kodeAgentStreamJson-X5PLS2S6.js +11 -0
- package/dist/{kodeAgentStreamJsonSession-UGEZJJEB.js → chunks/kodeAgentStreamJsonSession-RDXM4XYF.js} +38 -24
- package/dist/chunks/kodeAgentStreamJsonSession-RDXM4XYF.js.map +7 -0
- package/dist/{chunk-4RTX4AG4.js → chunks/kodeAgentStructuredStdio-SVGDSB4P.js} +14 -9
- package/dist/chunks/kodeAgentStructuredStdio-SVGDSB4P.js.map +7 -0
- package/dist/{kodeHooks-QWM36A3D.js → chunks/kodeHooks-RVKYRJHG.js} +11 -9
- package/dist/{llm-ZUQC4WYM.js → chunks/llm-62N6T5ZT.js} +1734 -1526
- package/dist/chunks/llm-62N6T5ZT.js.map +7 -0
- package/dist/chunks/llmLazy-ZUSSE3ZA.js +13 -0
- package/dist/{mentionProcessor-EE3XFHCJ.js → chunks/mentionProcessor-RJW5UPJD.js} +46 -16
- package/dist/chunks/mentionProcessor-RJW5UPJD.js.map +7 -0
- package/dist/{messages-EOYQKPGM.js → chunks/messages-EEWWLPHN.js} +2 -6
- package/dist/chunks/model-5TIEKQPD.js +37 -0
- package/dist/{openai-RRCWW33N.js → chunks/openai-XXK3YZG4.js} +13 -10
- package/dist/{outputStyles-62Q3VH2J.js → chunks/outputStyles-FAJTXN2A.js} +6 -9
- package/dist/chunks/permissions-HO7INPWM.js +27 -0
- package/dist/{pluginRuntime-6ETCZ2LL.js → chunks/pluginRuntime-C7K5ULK2.js} +31 -48
- package/dist/chunks/pluginRuntime-C7K5ULK2.js.map +7 -0
- package/dist/chunks/pluginValidation-DAM7WRTC.js +20 -0
- package/dist/chunks/registry-XYJXMOA5.js +60 -0
- package/dist/chunks/responsesStreaming-JNGE2P3D.js +8 -0
- package/dist/chunks/runNonTextPrintMode-SVBLCZQX.js +577 -0
- package/dist/chunks/runNonTextPrintMode-SVBLCZQX.js.map +7 -0
- package/dist/chunks/server-REXXF5IK.js +46 -0
- package/dist/{skillMarketplace-3RXQBVOL.js → chunks/skillMarketplace-N4HVHNST.js} +8 -6
- package/dist/chunks/src-OROQIWP3.js +44 -0
- package/dist/chunks/src-QXLGGMUW.js +1647 -0
- package/dist/chunks/src-QXLGGMUW.js.map +7 -0
- package/dist/{cli-DOPVY2CW.js → chunks/src-SSDT6MVP.js} +2659 -3384
- package/dist/chunks/src-SSDT6MVP.js.map +7 -0
- package/dist/chunks/theme-YBJUIMWK.js +10 -0
- package/dist/{toolPermissionContext-65L65VEZ.js → chunks/toolPermissionContext-MOCTRR7N.js} +2 -4
- package/dist/chunks/toolPermissionSettings-EV2EJAXL.js +18 -0
- package/dist/chunks/toolPermissionSettings-EV2EJAXL.js.map +7 -0
- package/dist/chunks/uuid-6577SO6X.js +7 -0
- package/dist/chunks/uuid-6577SO6X.js.map +7 -0
- package/dist/chunks/webOnlyMode-ALXX7UQY.js +66 -0
- package/dist/chunks/webOnlyMode-ALXX7UQY.js.map +7 -0
- package/dist/entrypoints/cli.js +10 -0
- package/dist/entrypoints/cli.js.map +7 -0
- package/dist/entrypoints/daemon.js +10 -0
- package/dist/entrypoints/daemon.js.map +7 -0
- package/dist/entrypoints/mcp.js +71 -0
- package/dist/entrypoints/mcp.js.map +7 -0
- package/dist/index.js +6 -7
- package/dist/index.js.map +3 -3
- package/dist/sdk/client.cjs +391 -0
- package/dist/sdk/client.cjs.map +7 -0
- package/dist/sdk/client.js +364 -0
- package/dist/sdk/client.js.map +7 -0
- package/dist/sdk/core.cjs +19932 -0
- package/dist/sdk/core.cjs.map +7 -0
- package/dist/sdk/core.js +19893 -0
- package/dist/sdk/core.js.map +7 -0
- package/dist/sdk/daemon-client.cjs +257 -0
- package/dist/sdk/daemon-client.cjs.map +7 -0
- package/dist/sdk/daemon-client.js +221 -0
- package/dist/sdk/daemon-client.js.map +7 -0
- package/dist/sdk/protocol.cjs +170 -0
- package/dist/sdk/protocol.cjs.map +7 -0
- package/dist/sdk/protocol.js +140 -0
- package/dist/sdk/protocol.js.map +7 -0
- package/dist/sdk/runtime-node.cjs +236 -0
- package/dist/sdk/runtime-node.cjs.map +7 -0
- package/dist/sdk/runtime-node.js +222 -0
- package/dist/sdk/runtime-node.js.map +7 -0
- package/dist/sdk/runtime.cjs +17 -0
- package/dist/sdk/runtime.cjs.map +7 -0
- package/dist/sdk/runtime.js +0 -0
- package/dist/sdk/runtime.js.map +7 -0
- package/dist/sdk/tools.cjs +30300 -0
- package/dist/sdk/tools.cjs.map +7 -0
- package/dist/sdk/tools.js +30282 -0
- package/dist/sdk/tools.js.map +7 -0
- package/dist/webui/assets/index-5hlfByVS.css +1 -0
- package/dist/webui/assets/index-BR9lm1lA.js +82 -0
- package/dist/webui/index.html +28 -0
- package/package.json +93 -22
- package/scripts/binary-utils.cjs +12 -4
- package/scripts/cli-acp-wrapper.cjs +3 -17
- package/scripts/cli-wrapper.cjs +5 -7
- package/scripts/postinstall.js +8 -4
- package/dist/REPL-CW7AYLVL.js +0 -42
- package/dist/acp-VEPJ74LT.js +0 -1357
- package/dist/acp-VEPJ74LT.js.map +0 -7
- package/dist/agentsValidate-7LH4HTNR.js.map +0 -7
- package/dist/ask-3NHFFUQG.js.map +0 -7
- package/dist/autoUpdater-ITPIHCOI.js +0 -17
- package/dist/chunk-3IN27HA5.js.map +0 -7
- package/dist/chunk-4FX3IVPT.js +0 -164
- package/dist/chunk-4FX3IVPT.js.map +0 -7
- package/dist/chunk-4RTX4AG4.js.map +0 -7
- package/dist/chunk-5PDP7R6N.js +0 -515
- package/dist/chunk-5PDP7R6N.js.map +0 -7
- package/dist/chunk-73WGVYLQ.js.map +0 -7
- package/dist/chunk-7M2YN6TU.js.map +0 -7
- package/dist/chunk-7U7L4NMD.js.map +0 -7
- package/dist/chunk-ABLVTESJ.js.map +0 -7
- package/dist/chunk-AFFSCMYS.js.map +0 -7
- package/dist/chunk-ARZSBOAO.js.map +0 -7
- package/dist/chunk-CIG63V4E.js +0 -72
- package/dist/chunk-CIG63V4E.js.map +0 -7
- package/dist/chunk-CM3EGTG6.js +0 -1609
- package/dist/chunk-CM3EGTG6.js.map +0 -7
- package/dist/chunk-DZE5YA7L.js.map +0 -7
- package/dist/chunk-E6YNABER.js.map +0 -7
- package/dist/chunk-EZXMVTDU.js.map +0 -7
- package/dist/chunk-F2SJXUDI.js +0 -148
- package/dist/chunk-F2SJXUDI.js.map +0 -7
- package/dist/chunk-FC5ZCKBI.js +0 -30167
- package/dist/chunk-FC5ZCKBI.js.map +0 -7
- package/dist/chunk-HCBELH4J.js +0 -145
- package/dist/chunk-HCBELH4J.js.map +0 -7
- package/dist/chunk-HN4E4UUQ.js.map +0 -7
- package/dist/chunk-IZVMU4S2.js +0 -654
- package/dist/chunk-IZVMU4S2.js.map +0 -7
- package/dist/chunk-K2CWOTI2.js.map +0 -7
- package/dist/chunk-LC4TVOCZ.js +0 -835
- package/dist/chunk-LC4TVOCZ.js.map +0 -7
- package/dist/chunk-MIW7N2MY.js +0 -2613
- package/dist/chunk-MIW7N2MY.js.map +0 -7
- package/dist/chunk-MWRSY4X6.js.map +0 -7
- package/dist/chunk-ND3XWFO6.js +0 -34
- package/dist/chunk-ND3XWFO6.js.map +0 -7
- package/dist/chunk-QVLYOPO5.js.map +0 -7
- package/dist/chunk-RZWOUA25.js.map +0 -7
- package/dist/chunk-S6HRABTA.js.map +0 -7
- package/dist/chunk-STSX7GIX.js.map +0 -7
- package/dist/chunk-UHYRLID6.js.map +0 -7
- package/dist/chunk-UKHTVRJM.js +0 -47
- package/dist/chunk-UKHTVRJM.js.map +0 -7
- package/dist/chunk-UYXEDKOZ.js +0 -24
- package/dist/chunk-UYXEDKOZ.js.map +0 -7
- package/dist/chunk-W7GRKO7Q.js.map +0 -7
- package/dist/chunk-WVHORZQ5.js +0 -17
- package/dist/chunk-WVHORZQ5.js.map +0 -7
- package/dist/chunk-WWUWDNWW.js +0 -49
- package/dist/chunk-WWUWDNWW.js.map +0 -7
- package/dist/chunk-YC6LJCDE.js.map +0 -7
- package/dist/chunk-YXYYDIMI.js +0 -2931
- package/dist/chunk-YXYYDIMI.js.map +0 -7
- package/dist/chunk-ZVDRDPII.js.map +0 -7
- package/dist/cli-DOPVY2CW.js.map +0 -7
- package/dist/commands-2BF2CJ3A.js +0 -46
- package/dist/context-6FXPETYH.js +0 -30
- package/dist/costTracker-6SL26FDB.js +0 -19
- package/dist/kodeAgentSessionLoad-MITZADPB.js +0 -18
- package/dist/kodeAgentSessionResume-GVRWB4WO.js +0 -16
- package/dist/kodeAgentStreamJson-NXFN7TXH.js +0 -13
- package/dist/kodeAgentStreamJsonSession-UGEZJJEB.js.map +0 -7
- package/dist/kodeAgentStructuredStdio-HGWJT7CU.js +0 -10
- package/dist/llm-ZUQC4WYM.js.map +0 -7
- package/dist/llmLazy-54QQHA54.js +0 -15
- package/dist/loader-FYHJQES5.js +0 -28
- package/dist/mcp-J332IKT3.js +0 -49
- package/dist/mentionProcessor-EE3XFHCJ.js.map +0 -7
- package/dist/model-FV3JDJKH.js +0 -30
- package/dist/pluginRuntime-6ETCZ2LL.js.map +0 -7
- package/dist/pluginValidation-I4YKUWGS.js +0 -17
- package/dist/prompts-ZLEKDD77.js +0 -48
- package/dist/query-VFRJPBGD.js +0 -50
- package/dist/responsesStreaming-AW344PQO.js +0 -10
- package/dist/ripgrep-3NTIKQYW.js +0 -17
- package/dist/state-P5G6CO5V.js +0 -16
- package/dist/theme-3LWP3BG7.js +0 -14
- package/dist/toolPermissionSettings-3ROBVTUK.js +0 -18
- package/dist/tools-RO7HSSE5.js +0 -47
- package/dist/userInput-JSBJRFSK.js +0 -311
- package/dist/userInput-JSBJRFSK.js.map +0 -7
- package/dist/uuid-QN2CNKKN.js +0 -9
- /package/dist/{REPL-CW7AYLVL.js.map → chunks/Doctor-M3J7GRTJ.js.map} +0 -0
- /package/dist/{autoUpdater-ITPIHCOI.js.map → chunks/REPL-RQ6LO6S7.js.map} +0 -0
- /package/dist/{chunk-JC6NCUG5.js.map → chunks/ResumeConversation-6DMVBEGH.js.map} +0 -0
- /package/dist/{commands-2BF2CJ3A.js.map → chunks/agentLoader-FCRG3TFJ.js.map} +0 -0
- /package/dist/{config-RUSD6G5Y.js.map → chunks/autoUpdater-CNESBOKO.js.map} +0 -0
- /package/dist/{context-6FXPETYH.js.map → chunks/chunk-4CRUCZR4.js.map} +0 -0
- /package/dist/{costTracker-6SL26FDB.js.map → chunks/chunk-54KOYG5C.js.map} +0 -0
- /package/dist/{customCommands-TOIJFZAL.js.map → chunks/chunk-GCQCAXJZ.js.map} +0 -0
- /package/dist/{env-XGKBLU3D.js.map → chunks/chunk-LB6TCPDI.js.map} +0 -0
- /package/dist/{kodeAgentSessionId-X6XWQW7B.js.map → chunks/client-SILZNM5N.js.map} +0 -0
- /package/dist/{kodeAgentSessionLoad-MITZADPB.js.map → chunks/config-25HRTPSP.js.map} +0 -0
- /package/dist/{kodeAgentSessionResume-GVRWB4WO.js.map → chunks/cost-tracker-Z2UZT2J5.js.map} +0 -0
- /package/dist/{kodeAgentStreamJson-NXFN7TXH.js.map → chunks/customCommands-TYMYZRG5.js.map} +0 -0
- /package/dist/{kodeAgentStructuredStdio-HGWJT7CU.js.map → chunks/engine-MRVF6FK6.js.map} +0 -0
- /package/dist/{kodeHooks-QWM36A3D.js.map → chunks/env-TJ5NOBEB.js.map} +0 -0
- /package/dist/{llmLazy-54QQHA54.js.map → chunks/kodeAgentSessionId-VTNISJ2L.js.map} +0 -0
- /package/dist/{loader-FYHJQES5.js.map → chunks/kodeAgentSessionLoad-YB2RKBGJ.js.map} +0 -0
- /package/dist/{mcp-J332IKT3.js.map → chunks/kodeAgentSessionResume-DZSIVKVA.js.map} +0 -0
- /package/dist/{messages-EOYQKPGM.js.map → chunks/kodeAgentStreamJson-X5PLS2S6.js.map} +0 -0
- /package/dist/{model-FV3JDJKH.js.map → chunks/kodeHooks-RVKYRJHG.js.map} +0 -0
- /package/dist/{openai-RRCWW33N.js.map → chunks/llmLazy-ZUSSE3ZA.js.map} +0 -0
- /package/dist/{outputStyles-62Q3VH2J.js.map → chunks/messages-EEWWLPHN.js.map} +0 -0
- /package/dist/{pluginValidation-I4YKUWGS.js.map → chunks/model-5TIEKQPD.js.map} +0 -0
- /package/dist/{prompts-ZLEKDD77.js.map → chunks/openai-XXK3YZG4.js.map} +0 -0
- /package/dist/{query-VFRJPBGD.js.map → chunks/outputStyles-FAJTXN2A.js.map} +0 -0
- /package/dist/{responsesStreaming-AW344PQO.js.map → chunks/permissions-HO7INPWM.js.map} +0 -0
- /package/dist/{ripgrep-3NTIKQYW.js.map → chunks/pluginValidation-DAM7WRTC.js.map} +0 -0
- /package/dist/{skillMarketplace-3RXQBVOL.js.map → chunks/registry-XYJXMOA5.js.map} +0 -0
- /package/dist/{state-P5G6CO5V.js.map → chunks/responsesStreaming-JNGE2P3D.js.map} +0 -0
- /package/dist/{theme-3LWP3BG7.js.map → chunks/server-REXXF5IK.js.map} +0 -0
- /package/dist/{toolPermissionContext-65L65VEZ.js.map → chunks/skillMarketplace-N4HVHNST.js.map} +0 -0
- /package/dist/{toolPermissionSettings-3ROBVTUK.js.map → chunks/src-OROQIWP3.js.map} +0 -0
- /package/dist/{tools-RO7HSSE5.js.map → chunks/theme-YBJUIMWK.js.map} +0 -0
- /package/dist/{uuid-QN2CNKKN.js.map → chunks/toolPermissionContext-MOCTRR7N.js.map} +0 -0
|
@@ -0,0 +1,1533 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BunShell
|
|
3
|
+
} from "./chunk-B3MW3YGY.js";
|
|
4
|
+
|
|
5
|
+
// packages/config/src/schema.ts
|
|
6
|
+
import { homedir } from "node:os";
|
|
7
|
+
var DEFAULT_PROJECT_CONFIG = {
|
|
8
|
+
allowedTools: [],
|
|
9
|
+
deniedTools: [],
|
|
10
|
+
askedTools: [],
|
|
11
|
+
context: {},
|
|
12
|
+
history: [],
|
|
13
|
+
dontCrawlDirectory: false,
|
|
14
|
+
enableArchitectTool: false,
|
|
15
|
+
mcpContextUris: [],
|
|
16
|
+
mcpServers: {},
|
|
17
|
+
approvedMcprcServers: [],
|
|
18
|
+
rejectedMcprcServers: [],
|
|
19
|
+
hasTrustDialogAccepted: false
|
|
20
|
+
};
|
|
21
|
+
function defaultConfigForProject(projectPath) {
|
|
22
|
+
const config = { ...DEFAULT_PROJECT_CONFIG };
|
|
23
|
+
if (projectPath === homedir()) {
|
|
24
|
+
config.dontCrawlDirectory = true;
|
|
25
|
+
}
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
function isAutoUpdaterStatus(value) {
|
|
29
|
+
return ["disabled", "enabled", "no_permissions", "not_configured"].includes(
|
|
30
|
+
value
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
var DEFAULT_GLOBAL_CONFIG = {
|
|
34
|
+
numStartups: 0,
|
|
35
|
+
autoUpdaterStatus: "not_configured",
|
|
36
|
+
theme: "dark",
|
|
37
|
+
preferredNotifChannel: "iterm2",
|
|
38
|
+
verbose: false,
|
|
39
|
+
primaryProvider: "anthropic",
|
|
40
|
+
customApiKeyResponses: {
|
|
41
|
+
approved: [],
|
|
42
|
+
rejected: []
|
|
43
|
+
},
|
|
44
|
+
stream: true,
|
|
45
|
+
modelProfiles: [],
|
|
46
|
+
modelPointers: {
|
|
47
|
+
main: "",
|
|
48
|
+
task: "",
|
|
49
|
+
compact: "",
|
|
50
|
+
quick: ""
|
|
51
|
+
},
|
|
52
|
+
lastDismissedUpdateVersion: void 0
|
|
53
|
+
};
|
|
54
|
+
var GLOBAL_CONFIG_KEYS = [
|
|
55
|
+
"autoUpdaterStatus",
|
|
56
|
+
"theme",
|
|
57
|
+
"hasCompletedOnboarding",
|
|
58
|
+
"lastOnboardingVersion",
|
|
59
|
+
"lastReleaseNotesSeen",
|
|
60
|
+
"verbose",
|
|
61
|
+
"customApiKeyResponses",
|
|
62
|
+
"primaryProvider",
|
|
63
|
+
"preferredNotifChannel",
|
|
64
|
+
"maxTokens"
|
|
65
|
+
];
|
|
66
|
+
function isGlobalConfigKey(key) {
|
|
67
|
+
return GLOBAL_CONFIG_KEYS.includes(key);
|
|
68
|
+
}
|
|
69
|
+
var PROJECT_CONFIG_KEYS = [
|
|
70
|
+
"dontCrawlDirectory",
|
|
71
|
+
"enableArchitectTool",
|
|
72
|
+
"hasTrustDialogAccepted",
|
|
73
|
+
"hasCompletedProjectOnboarding"
|
|
74
|
+
];
|
|
75
|
+
function isProjectConfigKey(key) {
|
|
76
|
+
return PROJECT_CONFIG_KEYS.includes(key);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// packages/config/src/paths.ts
|
|
80
|
+
import { join } from "node:path";
|
|
81
|
+
import { homedir as homedir2 } from "node:os";
|
|
82
|
+
var CONFIG_BASE_DIR = ".kode";
|
|
83
|
+
var CONFIG_FILE = ".kode.json";
|
|
84
|
+
function getKodeBaseDir() {
|
|
85
|
+
return process.env.KODE_CONFIG_DIR ?? process.env.CLAUDE_CONFIG_DIR ?? join(homedir2(), CONFIG_BASE_DIR);
|
|
86
|
+
}
|
|
87
|
+
function getGlobalConfigFilePath() {
|
|
88
|
+
return process.env.KODE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR ? join(getKodeBaseDir(), "config.json") : join(homedir2(), CONFIG_FILE);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// packages/config/src/errors.ts
|
|
92
|
+
var ConfigParseError = class extends Error {
|
|
93
|
+
filePath;
|
|
94
|
+
defaultConfig;
|
|
95
|
+
constructor(message, filePath, defaultConfig) {
|
|
96
|
+
super(message);
|
|
97
|
+
this.name = "ConfigParseError";
|
|
98
|
+
this.filePath = filePath;
|
|
99
|
+
this.defaultConfig = defaultConfig;
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// packages/config/src/loader.ts
|
|
104
|
+
import { randomBytes } from "node:crypto";
|
|
105
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
106
|
+
import { resolve } from "node:path";
|
|
107
|
+
import { cloneDeep } from "lodash-es";
|
|
108
|
+
|
|
109
|
+
// packages/config/src/json.ts
|
|
110
|
+
function safeParseJSON(value) {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(value);
|
|
113
|
+
} catch {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// packages/config/src/debugLogger.ts
|
|
119
|
+
function shouldLog() {
|
|
120
|
+
const enabled = process.env.KODE_DEBUG_CONFIG ?? process.env.KODE_DEBUG ?? process.env.DEBUG ?? "";
|
|
121
|
+
return ["1", "true", "yes", "on"].includes(
|
|
122
|
+
String(enabled).trim().toLowerCase()
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
function write(level, event, data) {
|
|
126
|
+
if (!shouldLog()) return;
|
|
127
|
+
const suffix = data ? ` ${JSON.stringify(data)}` : "";
|
|
128
|
+
console.log(`[config:${level}] ${event}${suffix}`);
|
|
129
|
+
}
|
|
130
|
+
var debug = {
|
|
131
|
+
state(event, data) {
|
|
132
|
+
write("state", event, data);
|
|
133
|
+
},
|
|
134
|
+
info(event, data) {
|
|
135
|
+
write("info", event, data);
|
|
136
|
+
},
|
|
137
|
+
api(event, data) {
|
|
138
|
+
write("api", event, data);
|
|
139
|
+
},
|
|
140
|
+
warn(event, data) {
|
|
141
|
+
write("warn", event, data);
|
|
142
|
+
},
|
|
143
|
+
error(event, data) {
|
|
144
|
+
write("error", event, data);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// packages/config/src/cwd.ts
|
|
149
|
+
function getCwd() {
|
|
150
|
+
return BunShell.getInstance().pwd();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// packages/config/src/models/migrations.ts
|
|
154
|
+
function isRecord(value) {
|
|
155
|
+
return typeof value === "object" && value !== null;
|
|
156
|
+
}
|
|
157
|
+
function readString(record, key) {
|
|
158
|
+
if (!record) return "";
|
|
159
|
+
const value = record[key];
|
|
160
|
+
return typeof value === "string" ? value : "";
|
|
161
|
+
}
|
|
162
|
+
function migrateModelProfilesRemoveId(config) {
|
|
163
|
+
if (!config.modelProfiles || config.modelProfiles.length === 0) return config;
|
|
164
|
+
const idToModelNameMap = /* @__PURE__ */ new Map();
|
|
165
|
+
const migratedProfiles = config.modelProfiles.map((profile) => {
|
|
166
|
+
const raw = profile;
|
|
167
|
+
if (!isRecord(raw)) return profile;
|
|
168
|
+
const maybeId = raw["id"];
|
|
169
|
+
if (typeof maybeId === "string" && profile.modelName) {
|
|
170
|
+
idToModelNameMap.set(maybeId, profile.modelName);
|
|
171
|
+
}
|
|
172
|
+
const { id: _ignored, ...rest } = raw;
|
|
173
|
+
return rest;
|
|
174
|
+
});
|
|
175
|
+
const migratedPointers = {
|
|
176
|
+
main: "",
|
|
177
|
+
task: "",
|
|
178
|
+
compact: "",
|
|
179
|
+
quick: ""
|
|
180
|
+
};
|
|
181
|
+
const pointersRaw = config.modelPointers;
|
|
182
|
+
const pointers = isRecord(pointersRaw) ? pointersRaw : null;
|
|
183
|
+
const rawMain = readString(pointers, "main");
|
|
184
|
+
const rawTask = readString(pointers, "task");
|
|
185
|
+
const rawQuick = readString(pointers, "quick");
|
|
186
|
+
const rawCompact = readString(pointers, "compact") || readString(pointers, "reasoning");
|
|
187
|
+
if (rawMain) migratedPointers.main = idToModelNameMap.get(rawMain) ?? rawMain;
|
|
188
|
+
if (rawTask) migratedPointers.task = idToModelNameMap.get(rawTask) ?? rawTask;
|
|
189
|
+
if (rawCompact)
|
|
190
|
+
migratedPointers.compact = idToModelNameMap.get(rawCompact) ?? rawCompact;
|
|
191
|
+
if (rawQuick)
|
|
192
|
+
migratedPointers.quick = idToModelNameMap.get(rawQuick) ?? rawQuick;
|
|
193
|
+
const configRaw = config;
|
|
194
|
+
const configRecord = isRecord(configRaw) ? configRaw : null;
|
|
195
|
+
const legacyDefaultModelId = readString(configRecord, "defaultModelId");
|
|
196
|
+
const legacyDefaultModelName = readString(configRecord, "defaultModelName");
|
|
197
|
+
let defaultModelName = config.defaultModelName;
|
|
198
|
+
if (legacyDefaultModelId) {
|
|
199
|
+
defaultModelName = idToModelNameMap.get(legacyDefaultModelId) ?? legacyDefaultModelId;
|
|
200
|
+
} else if (legacyDefaultModelName) {
|
|
201
|
+
defaultModelName = legacyDefaultModelName;
|
|
202
|
+
}
|
|
203
|
+
if (!configRecord) {
|
|
204
|
+
return {
|
|
205
|
+
...config,
|
|
206
|
+
modelProfiles: migratedProfiles,
|
|
207
|
+
modelPointers: migratedPointers,
|
|
208
|
+
defaultModelName
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
const migratedConfig = { ...configRecord };
|
|
212
|
+
delete migratedConfig["defaultModelId"];
|
|
213
|
+
delete migratedConfig["currentSelectedModelId"];
|
|
214
|
+
delete migratedConfig["mainAgentModelId"];
|
|
215
|
+
delete migratedConfig["taskToolModelId"];
|
|
216
|
+
return {
|
|
217
|
+
...migratedConfig,
|
|
218
|
+
modelProfiles: migratedProfiles,
|
|
219
|
+
modelPointers: migratedPointers,
|
|
220
|
+
defaultModelName
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// packages/config/src/loader.ts
|
|
225
|
+
function isRecord2(value) {
|
|
226
|
+
return typeof value === "object" && value !== null;
|
|
227
|
+
}
|
|
228
|
+
function isStringArray(value) {
|
|
229
|
+
return Array.isArray(value) && value.every((v) => typeof v === "string");
|
|
230
|
+
}
|
|
231
|
+
function normalizeStringArray(value) {
|
|
232
|
+
if (isStringArray(value)) return value;
|
|
233
|
+
if (typeof value === "string") {
|
|
234
|
+
const parsed = safeParseJSON(value);
|
|
235
|
+
if (isStringArray(parsed)) return parsed;
|
|
236
|
+
}
|
|
237
|
+
return void 0;
|
|
238
|
+
}
|
|
239
|
+
function normalizeLegacyProjectConfig(projectConfig) {
|
|
240
|
+
const raw = projectConfig;
|
|
241
|
+
if (!isRecord2(raw)) return projectConfig;
|
|
242
|
+
const allowedTools = normalizeStringArray(raw["allowedTools"]) ?? projectConfig.allowedTools;
|
|
243
|
+
const deniedTools = normalizeStringArray(raw["deniedTools"]) ?? projectConfig.deniedTools;
|
|
244
|
+
const askedTools = normalizeStringArray(raw["askedTools"]) ?? projectConfig.askedTools;
|
|
245
|
+
return { ...projectConfig, allowedTools, deniedTools, askedTools };
|
|
246
|
+
}
|
|
247
|
+
function saveConfig(file, config, defaultConfig) {
|
|
248
|
+
const filteredConfig = Object.fromEntries(
|
|
249
|
+
Object.entries(config).filter(
|
|
250
|
+
([key, value]) => JSON.stringify(value) !== JSON.stringify(defaultConfig[key])
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
try {
|
|
254
|
+
writeFileSync(file, JSON.stringify(filteredConfig, null, 2), "utf-8");
|
|
255
|
+
} catch (error) {
|
|
256
|
+
const err = error;
|
|
257
|
+
if (err.code === "EACCES" || err.code === "EPERM" || err.code === "EROFS") {
|
|
258
|
+
debug.state("CONFIG_SAVE_SKIPPED", {
|
|
259
|
+
file,
|
|
260
|
+
reason: String(err.code)
|
|
261
|
+
});
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
throw error;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
function getConfig(file, defaultConfig, throwOnInvalid) {
|
|
268
|
+
debug.state("CONFIG_LOAD_START", {
|
|
269
|
+
file,
|
|
270
|
+
fileExists: String(existsSync(file)),
|
|
271
|
+
throwOnInvalid: String(Boolean(throwOnInvalid))
|
|
272
|
+
});
|
|
273
|
+
if (!existsSync(file)) {
|
|
274
|
+
debug.state("CONFIG_LOAD_DEFAULT", {
|
|
275
|
+
file,
|
|
276
|
+
reason: "file_not_exists",
|
|
277
|
+
defaultConfigKeys: Object.keys(defaultConfig).join(", ")
|
|
278
|
+
});
|
|
279
|
+
return cloneDeep(defaultConfig);
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
const fileContent = readFileSync(file, "utf-8");
|
|
283
|
+
debug.state("CONFIG_FILE_READ", {
|
|
284
|
+
file,
|
|
285
|
+
contentLength: String(fileContent.length),
|
|
286
|
+
contentPreview: fileContent.substring(0, 100) + (fileContent.length > 100 ? "..." : "")
|
|
287
|
+
});
|
|
288
|
+
try {
|
|
289
|
+
const parsedConfig = JSON.parse(fileContent);
|
|
290
|
+
debug.state("CONFIG_JSON_PARSED", {
|
|
291
|
+
file,
|
|
292
|
+
parsedKeys: isRecord2(parsedConfig) ? Object.keys(parsedConfig).join(", ") : ""
|
|
293
|
+
});
|
|
294
|
+
const finalConfig = {
|
|
295
|
+
...cloneDeep(defaultConfig),
|
|
296
|
+
...isRecord2(parsedConfig) ? parsedConfig : {}
|
|
297
|
+
};
|
|
298
|
+
debug.state("CONFIG_LOAD_SUCCESS", {
|
|
299
|
+
file,
|
|
300
|
+
finalConfigKeys: Object.keys(finalConfig).join(", ")
|
|
301
|
+
});
|
|
302
|
+
return finalConfig;
|
|
303
|
+
} catch (error) {
|
|
304
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
305
|
+
debug.error("CONFIG_JSON_PARSE_ERROR", {
|
|
306
|
+
file,
|
|
307
|
+
errorMessage: message,
|
|
308
|
+
errorType: error instanceof Error ? error.constructor.name : typeof error,
|
|
309
|
+
contentLength: String(fileContent.length)
|
|
310
|
+
});
|
|
311
|
+
throw new ConfigParseError(message, file, defaultConfig);
|
|
312
|
+
}
|
|
313
|
+
} catch (error) {
|
|
314
|
+
if (error instanceof ConfigParseError && throwOnInvalid) {
|
|
315
|
+
debug.error("CONFIG_PARSE_ERROR_RETHROWN", {
|
|
316
|
+
file,
|
|
317
|
+
throwOnInvalid: String(Boolean(throwOnInvalid)),
|
|
318
|
+
errorMessage: error.message
|
|
319
|
+
});
|
|
320
|
+
throw error;
|
|
321
|
+
}
|
|
322
|
+
debug.warn("CONFIG_FALLBACK_TO_DEFAULT", {
|
|
323
|
+
file,
|
|
324
|
+
errorType: error instanceof Error ? error.constructor.name : typeof error,
|
|
325
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
326
|
+
action: "using_default_config"
|
|
327
|
+
});
|
|
328
|
+
return cloneDeep(defaultConfig);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
var TEST_GLOBAL_CONFIG_FOR_TESTING = {
|
|
332
|
+
...DEFAULT_GLOBAL_CONFIG,
|
|
333
|
+
autoUpdaterStatus: "disabled"
|
|
334
|
+
};
|
|
335
|
+
var TEST_PROJECT_CONFIG_FOR_TESTING = {
|
|
336
|
+
...defaultConfigForProject(getCwd())
|
|
337
|
+
};
|
|
338
|
+
function enableConfigs() {
|
|
339
|
+
getConfig(getGlobalConfigFilePath(), DEFAULT_GLOBAL_CONFIG, true);
|
|
340
|
+
}
|
|
341
|
+
function saveGlobalConfig(config) {
|
|
342
|
+
if (process.env.NODE_ENV === "test") {
|
|
343
|
+
Object.assign(TEST_GLOBAL_CONFIG_FOR_TESTING, config);
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
saveConfig(
|
|
347
|
+
getGlobalConfigFilePath(),
|
|
348
|
+
{
|
|
349
|
+
...config,
|
|
350
|
+
projects: getConfig(getGlobalConfigFilePath(), DEFAULT_GLOBAL_CONFIG).projects
|
|
351
|
+
},
|
|
352
|
+
DEFAULT_GLOBAL_CONFIG
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
function getGlobalConfig() {
|
|
356
|
+
if (process.env.NODE_ENV === "test") return TEST_GLOBAL_CONFIG_FOR_TESTING;
|
|
357
|
+
const config = getConfig(getGlobalConfigFilePath(), DEFAULT_GLOBAL_CONFIG);
|
|
358
|
+
return migrateModelProfilesRemoveId(config);
|
|
359
|
+
}
|
|
360
|
+
function checkHasTrustDialogAccepted() {
|
|
361
|
+
let currentPath = getCwd();
|
|
362
|
+
const config = getConfig(getGlobalConfigFilePath(), DEFAULT_GLOBAL_CONFIG);
|
|
363
|
+
while (true) {
|
|
364
|
+
const projectConfig = config.projects?.[currentPath];
|
|
365
|
+
if (projectConfig?.hasTrustDialogAccepted) return true;
|
|
366
|
+
const parentPath = resolve(currentPath, "..");
|
|
367
|
+
if (parentPath === currentPath) break;
|
|
368
|
+
currentPath = parentPath;
|
|
369
|
+
}
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
function getCurrentProjectConfig() {
|
|
373
|
+
if (process.env.NODE_ENV === "test") return TEST_PROJECT_CONFIG_FOR_TESTING;
|
|
374
|
+
const absolutePath = resolve(getCwd());
|
|
375
|
+
const config = getConfig(getGlobalConfigFilePath(), DEFAULT_GLOBAL_CONFIG);
|
|
376
|
+
if (!config.projects) return defaultConfigForProject(absolutePath);
|
|
377
|
+
const projectConfig = config.projects[absolutePath] ?? defaultConfigForProject(absolutePath);
|
|
378
|
+
return normalizeLegacyProjectConfig(projectConfig);
|
|
379
|
+
}
|
|
380
|
+
function saveCurrentProjectConfig(projectConfig) {
|
|
381
|
+
if (process.env.NODE_ENV === "test") {
|
|
382
|
+
Object.assign(TEST_PROJECT_CONFIG_FOR_TESTING, projectConfig);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
const config = getConfig(getGlobalConfigFilePath(), DEFAULT_GLOBAL_CONFIG);
|
|
386
|
+
saveConfig(
|
|
387
|
+
getGlobalConfigFilePath(),
|
|
388
|
+
{
|
|
389
|
+
...config,
|
|
390
|
+
projects: {
|
|
391
|
+
...config.projects,
|
|
392
|
+
[resolve(getCwd())]: projectConfig
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
DEFAULT_GLOBAL_CONFIG
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
async function isAutoUpdaterDisabled() {
|
|
399
|
+
const status = getGlobalConfig().autoUpdaterStatus;
|
|
400
|
+
return status !== "enabled";
|
|
401
|
+
}
|
|
402
|
+
function getOrCreateUserID() {
|
|
403
|
+
const config = getGlobalConfig();
|
|
404
|
+
if (config.userID) return config.userID;
|
|
405
|
+
const userID = randomBytes(32).toString("hex");
|
|
406
|
+
saveGlobalConfig({ ...config, userID });
|
|
407
|
+
return userID;
|
|
408
|
+
}
|
|
409
|
+
function normalizeApiKeyForConfig(apiKey) {
|
|
410
|
+
return apiKey.slice(-20);
|
|
411
|
+
}
|
|
412
|
+
function getCustomApiKeyStatus(truncatedApiKey) {
|
|
413
|
+
const config = getGlobalConfig();
|
|
414
|
+
if (config.customApiKeyResponses?.approved?.includes(truncatedApiKey)) {
|
|
415
|
+
return "approved";
|
|
416
|
+
}
|
|
417
|
+
if (config.customApiKeyResponses?.rejected?.includes(truncatedApiKey)) {
|
|
418
|
+
return "rejected";
|
|
419
|
+
}
|
|
420
|
+
return "new";
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// packages/config/src/mcp.ts
|
|
424
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
425
|
+
import { join as join2 } from "node:path";
|
|
426
|
+
import { memoize } from "lodash-es";
|
|
427
|
+
var TEST_MCPRC_CONFIG_FOR_TESTING = {};
|
|
428
|
+
function clearMcprcConfigForTesting() {
|
|
429
|
+
if (process.env.NODE_ENV !== "test") return;
|
|
430
|
+
for (const key of Object.keys(TEST_MCPRC_CONFIG_FOR_TESTING)) {
|
|
431
|
+
delete TEST_MCPRC_CONFIG_FOR_TESTING[key];
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
function addMcprcServerForTesting(name, server) {
|
|
435
|
+
if (process.env.NODE_ENV === "test") {
|
|
436
|
+
TEST_MCPRC_CONFIG_FOR_TESTING[name] = server;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
function removeMcprcServerForTesting(name) {
|
|
440
|
+
if (process.env.NODE_ENV !== "test") return;
|
|
441
|
+
if (!TEST_MCPRC_CONFIG_FOR_TESTING[name]) {
|
|
442
|
+
throw new Error(`No MCP server found with name: ${name} in .mcprc`);
|
|
443
|
+
}
|
|
444
|
+
delete TEST_MCPRC_CONFIG_FOR_TESTING[name];
|
|
445
|
+
}
|
|
446
|
+
function isRecord3(value) {
|
|
447
|
+
return typeof value === "object" && value !== null;
|
|
448
|
+
}
|
|
449
|
+
var getMcprcConfig = memoize(
|
|
450
|
+
() => {
|
|
451
|
+
if (process.env.NODE_ENV === "test") return TEST_MCPRC_CONFIG_FOR_TESTING;
|
|
452
|
+
const mcprcPath = join2(getCwd(), ".mcprc");
|
|
453
|
+
if (!existsSync2(mcprcPath)) return {};
|
|
454
|
+
try {
|
|
455
|
+
const mcprcContent = readFileSync2(mcprcPath, "utf-8");
|
|
456
|
+
const parsed = safeParseJSON(mcprcContent);
|
|
457
|
+
if (isRecord3(parsed)) return parsed;
|
|
458
|
+
} catch {
|
|
459
|
+
}
|
|
460
|
+
return {};
|
|
461
|
+
},
|
|
462
|
+
() => {
|
|
463
|
+
const cwd = getCwd();
|
|
464
|
+
const mcprcPath = join2(cwd, ".mcprc");
|
|
465
|
+
if (!existsSync2(mcprcPath)) return cwd;
|
|
466
|
+
try {
|
|
467
|
+
return `${cwd}:${readFileSync2(mcprcPath, "utf-8")}`;
|
|
468
|
+
} catch {
|
|
469
|
+
return cwd;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
);
|
|
473
|
+
function parseMcpServersFromMcpJson(value) {
|
|
474
|
+
if (!isRecord3(value)) return {};
|
|
475
|
+
const raw = value["mcpServers"];
|
|
476
|
+
if (!isRecord3(raw)) return {};
|
|
477
|
+
return raw;
|
|
478
|
+
}
|
|
479
|
+
function parseMcpServersFromMcprc(value) {
|
|
480
|
+
if (!isRecord3(value)) return {};
|
|
481
|
+
const maybeNested = value["mcpServers"];
|
|
482
|
+
if (isRecord3(maybeNested))
|
|
483
|
+
return maybeNested;
|
|
484
|
+
return value;
|
|
485
|
+
}
|
|
486
|
+
var getProjectMcpServerDefinitions = memoize(
|
|
487
|
+
() => {
|
|
488
|
+
if (process.env.NODE_ENV === "test") {
|
|
489
|
+
return {
|
|
490
|
+
servers: {},
|
|
491
|
+
sources: {},
|
|
492
|
+
mcpJsonPath: join2(getCwd(), ".mcp.json"),
|
|
493
|
+
mcprcPath: join2(getCwd(), ".mcprc")
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
const cwd = getCwd();
|
|
497
|
+
const mcpJsonPath = join2(cwd, ".mcp.json");
|
|
498
|
+
const mcprcPath = join2(cwd, ".mcprc");
|
|
499
|
+
let mcpJsonServers = {};
|
|
500
|
+
let mcprcServers = {};
|
|
501
|
+
if (existsSync2(mcpJsonPath)) {
|
|
502
|
+
try {
|
|
503
|
+
const parsed = safeParseJSON(readFileSync2(mcpJsonPath, "utf-8"));
|
|
504
|
+
mcpJsonServers = parseMcpServersFromMcpJson(parsed);
|
|
505
|
+
} catch {
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
if (existsSync2(mcprcPath)) {
|
|
509
|
+
try {
|
|
510
|
+
const parsed = safeParseJSON(readFileSync2(mcprcPath, "utf-8"));
|
|
511
|
+
mcprcServers = parseMcpServersFromMcprc(parsed);
|
|
512
|
+
} catch {
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
const sources = {};
|
|
516
|
+
for (const name of Object.keys(mcpJsonServers)) sources[name] = ".mcp.json";
|
|
517
|
+
for (const name of Object.keys(mcprcServers)) sources[name] = ".mcprc";
|
|
518
|
+
return {
|
|
519
|
+
servers: { ...mcpJsonServers, ...mcprcServers },
|
|
520
|
+
sources,
|
|
521
|
+
mcpJsonPath,
|
|
522
|
+
mcprcPath
|
|
523
|
+
};
|
|
524
|
+
},
|
|
525
|
+
() => {
|
|
526
|
+
const cwd = getCwd();
|
|
527
|
+
const mcpJsonPath = join2(cwd, ".mcp.json");
|
|
528
|
+
const mcprcPath = join2(cwd, ".mcprc");
|
|
529
|
+
const parts = [cwd];
|
|
530
|
+
if (existsSync2(mcpJsonPath)) {
|
|
531
|
+
try {
|
|
532
|
+
parts.push("mcp.json", readFileSync2(mcpJsonPath, "utf-8"));
|
|
533
|
+
} catch {
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
if (existsSync2(mcprcPath)) {
|
|
537
|
+
try {
|
|
538
|
+
parts.push("mcprc", readFileSync2(mcprcPath, "utf-8"));
|
|
539
|
+
} catch {
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return parts.join(":");
|
|
543
|
+
}
|
|
544
|
+
);
|
|
545
|
+
|
|
546
|
+
// packages/config/src/cli.ts
|
|
547
|
+
import { pick } from "lodash-es";
|
|
548
|
+
function getConfigForCLI(key, global) {
|
|
549
|
+
if (global) {
|
|
550
|
+
if (!isGlobalConfigKey(key)) {
|
|
551
|
+
console.error(
|
|
552
|
+
`Error: '${key}' is not a valid config key. Valid keys are: ${GLOBAL_CONFIG_KEYS.join(", ")}`
|
|
553
|
+
);
|
|
554
|
+
process.exit(1);
|
|
555
|
+
}
|
|
556
|
+
return getGlobalConfig()[key];
|
|
557
|
+
}
|
|
558
|
+
if (!isProjectConfigKey(key)) {
|
|
559
|
+
console.error(
|
|
560
|
+
`Error: '${key}' is not a valid config key. Valid keys are: ${PROJECT_CONFIG_KEYS.join(", ")}`
|
|
561
|
+
);
|
|
562
|
+
process.exit(1);
|
|
563
|
+
}
|
|
564
|
+
return getCurrentProjectConfig()[key];
|
|
565
|
+
}
|
|
566
|
+
function setConfigForCLI(key, value, global) {
|
|
567
|
+
if (global) {
|
|
568
|
+
if (!isGlobalConfigKey(key)) {
|
|
569
|
+
console.error(
|
|
570
|
+
`Error: Cannot set '${key}'. Only these keys can be modified: ${GLOBAL_CONFIG_KEYS.join(", ")}`
|
|
571
|
+
);
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
if (key === "autoUpdaterStatus" && !isAutoUpdaterStatus(String(value))) {
|
|
575
|
+
console.error(
|
|
576
|
+
`Error: Invalid value for autoUpdaterStatus. Must be one of: disabled, enabled, no_permissions, not_configured`
|
|
577
|
+
);
|
|
578
|
+
process.exit(1);
|
|
579
|
+
}
|
|
580
|
+
const currentConfig = getGlobalConfig();
|
|
581
|
+
saveGlobalConfig({
|
|
582
|
+
...currentConfig,
|
|
583
|
+
[key]: value
|
|
584
|
+
});
|
|
585
|
+
} else {
|
|
586
|
+
if (!isProjectConfigKey(key)) {
|
|
587
|
+
console.error(
|
|
588
|
+
`Error: Cannot set '${key}'. Only these keys can be modified: ${PROJECT_CONFIG_KEYS.join(", ")}. Did you mean --global?`
|
|
589
|
+
);
|
|
590
|
+
process.exit(1);
|
|
591
|
+
}
|
|
592
|
+
const currentConfig = getCurrentProjectConfig();
|
|
593
|
+
saveCurrentProjectConfig({
|
|
594
|
+
...currentConfig,
|
|
595
|
+
[key]: value
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
setTimeout(() => process.exit(0), 100);
|
|
599
|
+
}
|
|
600
|
+
function deleteConfigForCLI(key, global) {
|
|
601
|
+
if (global) {
|
|
602
|
+
if (!isGlobalConfigKey(key)) {
|
|
603
|
+
console.error(
|
|
604
|
+
`Error: Cannot delete '${key}'. Only these keys can be modified: ${GLOBAL_CONFIG_KEYS.join(", ")}`
|
|
605
|
+
);
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
const currentConfig2 = getGlobalConfig();
|
|
609
|
+
const next2 = { ...currentConfig2 };
|
|
610
|
+
delete next2[key];
|
|
611
|
+
saveGlobalConfig(next2);
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
if (!isProjectConfigKey(key)) {
|
|
615
|
+
console.error(
|
|
616
|
+
`Error: Cannot delete '${key}'. Only these keys can be modified: ${PROJECT_CONFIG_KEYS.join(", ")}. Did you mean --global?`
|
|
617
|
+
);
|
|
618
|
+
process.exit(1);
|
|
619
|
+
}
|
|
620
|
+
const currentConfig = getCurrentProjectConfig();
|
|
621
|
+
const next = { ...currentConfig };
|
|
622
|
+
delete next[key];
|
|
623
|
+
saveCurrentProjectConfig(next);
|
|
624
|
+
}
|
|
625
|
+
function listConfigForCLI(global) {
|
|
626
|
+
if (global) return pick(getGlobalConfig(), GLOBAL_CONFIG_KEYS);
|
|
627
|
+
return pick(getCurrentProjectConfig(), PROJECT_CONFIG_KEYS);
|
|
628
|
+
}
|
|
629
|
+
function getOpenAIApiKey() {
|
|
630
|
+
return process.env.OPENAI_API_KEY;
|
|
631
|
+
}
|
|
632
|
+
function getAnthropicApiKey() {
|
|
633
|
+
return process.env.ANTHROPIC_API_KEY || "";
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// packages/config/src/connectionTest/responsesAPI.ts
|
|
637
|
+
async function testResponsesAPI(config, baseURL, startTime) {
|
|
638
|
+
const testURL = `${baseURL.replace(/\/+$/, "")}/responses`;
|
|
639
|
+
const testPayload = {
|
|
640
|
+
model: config.model,
|
|
641
|
+
input: [
|
|
642
|
+
{
|
|
643
|
+
role: "user",
|
|
644
|
+
content: 'Please respond with exactly "YES" (in capital letters) to confirm this connection is working.'
|
|
645
|
+
}
|
|
646
|
+
],
|
|
647
|
+
max_completion_tokens: Math.max(config.maxTokens || 8192, 8192),
|
|
648
|
+
temperature: 1,
|
|
649
|
+
// GPT-5 requirement
|
|
650
|
+
reasoning: {
|
|
651
|
+
effort: "low"
|
|
652
|
+
// Fast response for connection test
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
const headers = {
|
|
656
|
+
"Content-Type": "application/json",
|
|
657
|
+
Authorization: `Bearer ${config.apiKey}`
|
|
658
|
+
};
|
|
659
|
+
debug.api("GPT5_CONNECTION_TEST_RESPONSES_REQUEST", {
|
|
660
|
+
model: config.model,
|
|
661
|
+
url: testURL
|
|
662
|
+
});
|
|
663
|
+
try {
|
|
664
|
+
const response = await fetch(testURL, {
|
|
665
|
+
method: "POST",
|
|
666
|
+
headers,
|
|
667
|
+
body: JSON.stringify(testPayload)
|
|
668
|
+
});
|
|
669
|
+
const responseTime = Date.now() - startTime;
|
|
670
|
+
if (response.ok) {
|
|
671
|
+
const data = await response.json();
|
|
672
|
+
debug.api("GPT5_CONNECTION_TEST_RESPONSES_RESPONSE", {
|
|
673
|
+
model: config.model,
|
|
674
|
+
status: response.status
|
|
675
|
+
});
|
|
676
|
+
let responseContent = "";
|
|
677
|
+
if (data.output_text) {
|
|
678
|
+
responseContent = data.output_text;
|
|
679
|
+
} else if (data.output && Array.isArray(data.output)) {
|
|
680
|
+
const messageOutput = data.output.find(
|
|
681
|
+
(item) => item.type === "message"
|
|
682
|
+
);
|
|
683
|
+
if (messageOutput && messageOutput.content) {
|
|
684
|
+
const textContent = messageOutput.content.find(
|
|
685
|
+
(c) => c.type === "output_text"
|
|
686
|
+
);
|
|
687
|
+
responseContent = textContent?.text || "";
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
const containsYes = responseContent.toLowerCase().includes("yes");
|
|
691
|
+
if (containsYes) {
|
|
692
|
+
return {
|
|
693
|
+
success: true,
|
|
694
|
+
message: "\u2705 GPT-5 Responses API connection successful",
|
|
695
|
+
endpoint: "/responses",
|
|
696
|
+
details: `Model responded correctly: "${responseContent.trim()}"`,
|
|
697
|
+
apiUsed: "responses",
|
|
698
|
+
responseTime
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
return {
|
|
702
|
+
success: false,
|
|
703
|
+
message: "\u26A0\uFE0F Responses API connected but unexpected response",
|
|
704
|
+
endpoint: "/responses",
|
|
705
|
+
details: `Expected "YES" but got: "${responseContent.trim() || "(empty response)"}"`,
|
|
706
|
+
apiUsed: "responses",
|
|
707
|
+
responseTime
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
const errorData = await response.json().catch(() => null);
|
|
711
|
+
const errorMessage = errorData?.error?.message || errorData?.message || response.statusText;
|
|
712
|
+
debug.warn("GPT5_CONNECTION_TEST_RESPONSES_ERROR", {
|
|
713
|
+
model: config.model,
|
|
714
|
+
status: response.status,
|
|
715
|
+
error: errorMessage
|
|
716
|
+
});
|
|
717
|
+
return {
|
|
718
|
+
success: false,
|
|
719
|
+
message: `\u274C Responses API failed (${response.status})`,
|
|
720
|
+
endpoint: "/responses",
|
|
721
|
+
details: `Error: ${errorMessage}`,
|
|
722
|
+
apiUsed: "responses",
|
|
723
|
+
responseTime: Date.now() - startTime
|
|
724
|
+
};
|
|
725
|
+
} catch (error) {
|
|
726
|
+
debug.warn("GPT5_CONNECTION_TEST_RESPONSES_NETWORK_ERROR", {
|
|
727
|
+
model: config.model,
|
|
728
|
+
error: error instanceof Error ? error.message : String(error)
|
|
729
|
+
});
|
|
730
|
+
return {
|
|
731
|
+
success: false,
|
|
732
|
+
message: "\u274C Responses API connection failed",
|
|
733
|
+
endpoint: "/responses",
|
|
734
|
+
details: error instanceof Error ? error.message : String(error),
|
|
735
|
+
apiUsed: "responses",
|
|
736
|
+
responseTime: Date.now() - startTime
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// packages/config/src/connectionTest/chatCompletions.ts
|
|
742
|
+
async function testChatCompletionsAPI(config, baseURL, startTime) {
|
|
743
|
+
const testURL = `${baseURL.replace(/\/+$/, "")}/chat/completions`;
|
|
744
|
+
const isGPT5 = config.model.toLowerCase().includes("gpt-5");
|
|
745
|
+
const testPayload = {
|
|
746
|
+
model: config.model,
|
|
747
|
+
messages: [
|
|
748
|
+
{
|
|
749
|
+
role: "user",
|
|
750
|
+
content: 'Please respond with exactly "YES" (in capital letters) to confirm this connection is working.'
|
|
751
|
+
}
|
|
752
|
+
],
|
|
753
|
+
temperature: isGPT5 ? 1 : 0,
|
|
754
|
+
// GPT-5 requires temperature=1
|
|
755
|
+
stream: false
|
|
756
|
+
};
|
|
757
|
+
if (isGPT5) {
|
|
758
|
+
testPayload.max_completion_tokens = Math.max(config.maxTokens || 8192, 8192);
|
|
759
|
+
delete testPayload.max_tokens;
|
|
760
|
+
debug.api("GPT5_CONNECTION_TEST_MAX_COMPLETION_TOKENS", {
|
|
761
|
+
model: config.model,
|
|
762
|
+
max_completion_tokens: testPayload.max_completion_tokens
|
|
763
|
+
});
|
|
764
|
+
} else {
|
|
765
|
+
testPayload.max_tokens = Math.max(config.maxTokens || 8192, 8192);
|
|
766
|
+
}
|
|
767
|
+
const headers = {
|
|
768
|
+
"Content-Type": "application/json"
|
|
769
|
+
};
|
|
770
|
+
if (config.provider === "azure") {
|
|
771
|
+
headers["api-key"] = config.apiKey;
|
|
772
|
+
} else {
|
|
773
|
+
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
774
|
+
}
|
|
775
|
+
debug.api("GPT5_CONNECTION_TEST_CHAT_COMPLETIONS_REQUEST", {
|
|
776
|
+
model: config.model,
|
|
777
|
+
url: testURL
|
|
778
|
+
});
|
|
779
|
+
try {
|
|
780
|
+
const response = await fetch(testURL, {
|
|
781
|
+
method: "POST",
|
|
782
|
+
headers,
|
|
783
|
+
body: JSON.stringify(testPayload)
|
|
784
|
+
});
|
|
785
|
+
const responseTime = Date.now() - startTime;
|
|
786
|
+
if (response.ok) {
|
|
787
|
+
const data = await response.json();
|
|
788
|
+
debug.api("GPT5_CONNECTION_TEST_CHAT_COMPLETIONS_RESPONSE", {
|
|
789
|
+
model: config.model,
|
|
790
|
+
status: response.status
|
|
791
|
+
});
|
|
792
|
+
const responseContent = data.choices?.[0]?.message?.content || "";
|
|
793
|
+
const containsYes = responseContent.toLowerCase().includes("yes");
|
|
794
|
+
if (containsYes) {
|
|
795
|
+
return {
|
|
796
|
+
success: true,
|
|
797
|
+
message: `\u2705 ${isGPT5 ? "GPT-5" : "Model"} Chat Completions connection successful`,
|
|
798
|
+
endpoint: "/chat/completions",
|
|
799
|
+
details: `Model responded correctly: "${responseContent.trim()}"`,
|
|
800
|
+
apiUsed: "chat_completions",
|
|
801
|
+
responseTime
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
return {
|
|
805
|
+
success: false,
|
|
806
|
+
message: "\u26A0\uFE0F Chat Completions connected but unexpected response",
|
|
807
|
+
endpoint: "/chat/completions",
|
|
808
|
+
details: `Expected "YES" but got: "${responseContent.trim() || "(empty response)"}"`,
|
|
809
|
+
apiUsed: "chat_completions",
|
|
810
|
+
responseTime
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
const errorData = await response.json().catch(() => null);
|
|
814
|
+
const errorMessage = errorData?.error?.message || errorData?.message || response.statusText;
|
|
815
|
+
debug.warn("GPT5_CONNECTION_TEST_CHAT_COMPLETIONS_ERROR", {
|
|
816
|
+
model: config.model,
|
|
817
|
+
status: response.status,
|
|
818
|
+
error: errorMessage
|
|
819
|
+
});
|
|
820
|
+
let details = `Error: ${errorMessage}`;
|
|
821
|
+
if (response.status === 400 && errorMessage.includes("max_tokens") && isGPT5) {
|
|
822
|
+
details += "\n\n\u{1F527} GPT-5 Fix Applied: This error suggests a parameter compatibility issue. Please check if the provider supports GPT-5 with max_completion_tokens.";
|
|
823
|
+
}
|
|
824
|
+
return {
|
|
825
|
+
success: false,
|
|
826
|
+
message: `\u274C Chat Completions failed (${response.status})`,
|
|
827
|
+
endpoint: "/chat/completions",
|
|
828
|
+
details,
|
|
829
|
+
apiUsed: "chat_completions",
|
|
830
|
+
responseTime: Date.now() - startTime
|
|
831
|
+
};
|
|
832
|
+
} catch (error) {
|
|
833
|
+
debug.warn("GPT5_CONNECTION_TEST_CHAT_COMPLETIONS_NETWORK_ERROR", {
|
|
834
|
+
model: config.model,
|
|
835
|
+
error: error instanceof Error ? error.message : String(error)
|
|
836
|
+
});
|
|
837
|
+
return {
|
|
838
|
+
success: false,
|
|
839
|
+
message: "\u274C Chat Completions connection failed",
|
|
840
|
+
endpoint: "/chat/completions",
|
|
841
|
+
details: error instanceof Error ? error.message : String(error),
|
|
842
|
+
apiUsed: "chat_completions",
|
|
843
|
+
responseTime: Date.now() - startTime
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// packages/config/src/connectionTest.ts
|
|
849
|
+
function getModelFeaturesForConnectionTest(modelName) {
|
|
850
|
+
const normalized = modelName.toLowerCase();
|
|
851
|
+
if (normalized.includes("gpt-5-chat-latest")) {
|
|
852
|
+
return { supportsResponsesAPI: false };
|
|
853
|
+
}
|
|
854
|
+
if (normalized.includes("gpt-5")) {
|
|
855
|
+
return { supportsResponsesAPI: true };
|
|
856
|
+
}
|
|
857
|
+
return { supportsResponsesAPI: false };
|
|
858
|
+
}
|
|
859
|
+
async function testGPT5Connection(config) {
|
|
860
|
+
const startTime = Date.now();
|
|
861
|
+
if (!config.model || !config.apiKey) {
|
|
862
|
+
return {
|
|
863
|
+
success: false,
|
|
864
|
+
message: "Invalid configuration",
|
|
865
|
+
details: "Model name and API key are required"
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
const isGPT5 = config.model.toLowerCase().includes("gpt-5");
|
|
869
|
+
const modelFeatures = getModelFeaturesForConnectionTest(config.model);
|
|
870
|
+
const baseURL = config.baseURL || "https://api.openai.com/v1";
|
|
871
|
+
const isOfficialOpenAI = !config.baseURL || config.baseURL.includes("api.openai.com");
|
|
872
|
+
debug.api("GPT5_CONNECTION_TEST_START", {
|
|
873
|
+
model: config.model,
|
|
874
|
+
baseURL,
|
|
875
|
+
isOfficialOpenAI,
|
|
876
|
+
supportsResponsesAPI: modelFeatures.supportsResponsesAPI
|
|
877
|
+
});
|
|
878
|
+
if (isGPT5 && modelFeatures.supportsResponsesAPI && isOfficialOpenAI) {
|
|
879
|
+
debug.api("GPT5_CONNECTION_TEST_TRY_RESPONSES", {
|
|
880
|
+
model: config.model
|
|
881
|
+
});
|
|
882
|
+
const responsesResult = await testResponsesAPI(config, baseURL, startTime);
|
|
883
|
+
if (responsesResult.success) {
|
|
884
|
+
debug.api("GPT5_CONNECTION_TEST_RESPONSES_OK", {
|
|
885
|
+
model: config.model
|
|
886
|
+
});
|
|
887
|
+
return responsesResult;
|
|
888
|
+
}
|
|
889
|
+
debug.warn("GPT5_CONNECTION_TEST_RESPONSES_FAILED", {
|
|
890
|
+
model: config.model,
|
|
891
|
+
details: responsesResult.details
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
debug.api("GPT5_CONNECTION_TEST_FALLBACK_CHAT_COMPLETIONS", {
|
|
895
|
+
model: config.model
|
|
896
|
+
});
|
|
897
|
+
return await testChatCompletionsAPI(config, baseURL, startTime);
|
|
898
|
+
}
|
|
899
|
+
function validateGPT5Config(config) {
|
|
900
|
+
debug.state("GPT5_VALIDATE_CONFIG_CALLED", {
|
|
901
|
+
model: config.model,
|
|
902
|
+
hasApiKey: !!config.apiKey,
|
|
903
|
+
baseURL: config.baseURL,
|
|
904
|
+
provider: config.provider
|
|
905
|
+
});
|
|
906
|
+
const errors = [];
|
|
907
|
+
if (!config.model) {
|
|
908
|
+
errors.push("Model name is required");
|
|
909
|
+
}
|
|
910
|
+
if (!config.apiKey) {
|
|
911
|
+
errors.push("API key is required");
|
|
912
|
+
}
|
|
913
|
+
const isGPT5 = config.model?.toLowerCase().includes("gpt-5");
|
|
914
|
+
if (isGPT5) {
|
|
915
|
+
debug.state("GPT5_VALIDATE_CONFIG", {
|
|
916
|
+
model: config.model,
|
|
917
|
+
maxTokens: config.maxTokens
|
|
918
|
+
});
|
|
919
|
+
if (config.maxTokens && config.maxTokens < 1e3) {
|
|
920
|
+
errors.push("GPT-5 models typically require at least 1000 max tokens");
|
|
921
|
+
}
|
|
922
|
+
debug.state("GPT5_VALIDATE_CONFIG_NO_PROVIDER_RESTRICTIONS", {
|
|
923
|
+
model: config.model
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
debug.state("GPT5_VALIDATE_CONFIG_RESULT", {
|
|
927
|
+
valid: errors.length === 0,
|
|
928
|
+
errors
|
|
929
|
+
});
|
|
930
|
+
return {
|
|
931
|
+
valid: errors.length === 0,
|
|
932
|
+
errors
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
// packages/config/src/models/gpt5.ts
|
|
937
|
+
function isGPT5ModelName(modelName) {
|
|
938
|
+
if (!modelName || typeof modelName !== "string") return false;
|
|
939
|
+
const lowerName = modelName.toLowerCase();
|
|
940
|
+
return lowerName.startsWith("gpt-5") || lowerName.includes("gpt-5");
|
|
941
|
+
}
|
|
942
|
+
function validateAndRepairGPT5Profile(profile) {
|
|
943
|
+
const isGPT5 = isGPT5ModelName(profile.modelName);
|
|
944
|
+
const now = Date.now();
|
|
945
|
+
const repairedProfile = { ...profile };
|
|
946
|
+
let wasRepaired = false;
|
|
947
|
+
if (isGPT5 !== profile.isGPT5) {
|
|
948
|
+
repairedProfile.isGPT5 = isGPT5;
|
|
949
|
+
wasRepaired = true;
|
|
950
|
+
}
|
|
951
|
+
if (isGPT5) {
|
|
952
|
+
const validReasoningEfforts = ["minimal", "low", "medium", "high"];
|
|
953
|
+
if (!profile.reasoningEffort || !validReasoningEfforts.includes(profile.reasoningEffort)) {
|
|
954
|
+
repairedProfile.reasoningEffort = "medium";
|
|
955
|
+
wasRepaired = true;
|
|
956
|
+
debug.state("GPT5_CONFIG_AUTO_REPAIR", {
|
|
957
|
+
model: profile.modelName,
|
|
958
|
+
field: "reasoningEffort",
|
|
959
|
+
value: "medium"
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
if (profile.contextLength < 128e3) {
|
|
963
|
+
repairedProfile.contextLength = 128e3;
|
|
964
|
+
wasRepaired = true;
|
|
965
|
+
debug.state("GPT5_CONFIG_AUTO_REPAIR", {
|
|
966
|
+
model: profile.modelName,
|
|
967
|
+
field: "contextLength",
|
|
968
|
+
value: 128e3
|
|
969
|
+
});
|
|
970
|
+
}
|
|
971
|
+
if (profile.maxTokens < 4e3) {
|
|
972
|
+
repairedProfile.maxTokens = 8192;
|
|
973
|
+
wasRepaired = true;
|
|
974
|
+
debug.state("GPT5_CONFIG_AUTO_REPAIR", {
|
|
975
|
+
model: profile.modelName,
|
|
976
|
+
field: "maxTokens",
|
|
977
|
+
value: 8192
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
if (profile.provider !== "openai" && profile.provider !== "custom-openai" && profile.provider !== "azure") {
|
|
981
|
+
debug.warn("GPT5_CONFIG_UNEXPECTED_PROVIDER", {
|
|
982
|
+
model: profile.modelName,
|
|
983
|
+
provider: profile.provider,
|
|
984
|
+
expectedProviders: ["openai", "custom-openai", "azure"]
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
if (profile.modelName.includes("gpt-5") && !profile.baseURL) {
|
|
988
|
+
repairedProfile.baseURL = "https://api.openai.com/v1";
|
|
989
|
+
wasRepaired = true;
|
|
990
|
+
debug.state("GPT5_CONFIG_AUTO_REPAIR", {
|
|
991
|
+
model: profile.modelName,
|
|
992
|
+
field: "baseURL",
|
|
993
|
+
value: "https://api.openai.com/v1"
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
repairedProfile.validationStatus = wasRepaired ? "auto_repaired" : "valid";
|
|
998
|
+
repairedProfile.lastValidation = now;
|
|
999
|
+
if (wasRepaired) {
|
|
1000
|
+
debug.info("GPT5_CONFIG_AUTO_REPAIRED", { model: profile.modelName });
|
|
1001
|
+
}
|
|
1002
|
+
return repairedProfile;
|
|
1003
|
+
}
|
|
1004
|
+
function getGPT5ConfigRecommendations(modelName) {
|
|
1005
|
+
if (!isGPT5ModelName(modelName)) return {};
|
|
1006
|
+
const recommendations = {
|
|
1007
|
+
contextLength: 128e3,
|
|
1008
|
+
maxTokens: 8192,
|
|
1009
|
+
reasoningEffort: "medium",
|
|
1010
|
+
isGPT5: true
|
|
1011
|
+
};
|
|
1012
|
+
if (modelName.includes("gpt-5-mini")) {
|
|
1013
|
+
recommendations.maxTokens = 4096;
|
|
1014
|
+
recommendations.reasoningEffort = "low";
|
|
1015
|
+
} else if (modelName.includes("gpt-5-nano")) {
|
|
1016
|
+
recommendations.maxTokens = 2048;
|
|
1017
|
+
recommendations.reasoningEffort = "minimal";
|
|
1018
|
+
}
|
|
1019
|
+
return recommendations;
|
|
1020
|
+
}
|
|
1021
|
+
function createGPT5ModelProfile(name, modelName, apiKey, baseURL, provider = "openai") {
|
|
1022
|
+
const recommendations = getGPT5ConfigRecommendations(modelName);
|
|
1023
|
+
return {
|
|
1024
|
+
name,
|
|
1025
|
+
provider,
|
|
1026
|
+
modelName,
|
|
1027
|
+
baseURL: baseURL || "https://api.openai.com/v1",
|
|
1028
|
+
apiKey,
|
|
1029
|
+
maxTokens: recommendations.maxTokens || 8192,
|
|
1030
|
+
contextLength: recommendations.contextLength || 128e3,
|
|
1031
|
+
reasoningEffort: recommendations.reasoningEffort || "medium",
|
|
1032
|
+
isActive: true,
|
|
1033
|
+
createdAt: Date.now(),
|
|
1034
|
+
isGPT5: true,
|
|
1035
|
+
validationStatus: "valid",
|
|
1036
|
+
lastValidation: Date.now()
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// packages/config/src/models/pointers.ts
|
|
1041
|
+
function setAllPointersToModel(modelName) {
|
|
1042
|
+
const config = getGlobalConfig();
|
|
1043
|
+
const updatedConfig = {
|
|
1044
|
+
...config,
|
|
1045
|
+
modelPointers: {
|
|
1046
|
+
main: modelName,
|
|
1047
|
+
task: modelName,
|
|
1048
|
+
compact: modelName,
|
|
1049
|
+
quick: modelName
|
|
1050
|
+
},
|
|
1051
|
+
defaultModelName: modelName
|
|
1052
|
+
};
|
|
1053
|
+
saveGlobalConfig(updatedConfig);
|
|
1054
|
+
}
|
|
1055
|
+
function setModelPointer(pointer, modelName) {
|
|
1056
|
+
const config = getGlobalConfig();
|
|
1057
|
+
const updatedConfig = {
|
|
1058
|
+
...config,
|
|
1059
|
+
modelPointers: {
|
|
1060
|
+
...config.modelPointers,
|
|
1061
|
+
[pointer]: modelName
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
saveGlobalConfig(updatedConfig);
|
|
1065
|
+
}
|
|
1066
|
+
function validateAndRepairAllGPT5Profiles() {
|
|
1067
|
+
const config = getGlobalConfig();
|
|
1068
|
+
if (!config.modelProfiles) return { repaired: 0, total: 0 };
|
|
1069
|
+
let repairCount = 0;
|
|
1070
|
+
const repairedProfiles = config.modelProfiles.map((profile) => {
|
|
1071
|
+
const repaired = validateAndRepairGPT5Profile(profile);
|
|
1072
|
+
if (repaired.validationStatus === "auto_repaired") repairCount++;
|
|
1073
|
+
return repaired;
|
|
1074
|
+
});
|
|
1075
|
+
if (repairCount > 0) {
|
|
1076
|
+
saveGlobalConfig({ ...config, modelProfiles: repairedProfiles });
|
|
1077
|
+
}
|
|
1078
|
+
return { repaired: repairCount, total: config.modelProfiles.length };
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
// packages/config/src/sources.ts
|
|
1082
|
+
var CLI_TO_SETTING_SOURCE = {
|
|
1083
|
+
user: "userSettings",
|
|
1084
|
+
project: "projectSettings",
|
|
1085
|
+
local: "localSettings"
|
|
1086
|
+
};
|
|
1087
|
+
var enabledSettingSources = new Set(
|
|
1088
|
+
Object.values(CLI_TO_SETTING_SOURCE)
|
|
1089
|
+
);
|
|
1090
|
+
function setEnabledSettingSourcesFromCli(sources) {
|
|
1091
|
+
if (sources === void 0) return;
|
|
1092
|
+
const trimmed = sources.trim();
|
|
1093
|
+
if (!trimmed) {
|
|
1094
|
+
throw new Error(
|
|
1095
|
+
`Invalid --setting-sources value: ${JSON.stringify(sources)}. Expected a comma-separated list of: user, project, local.`
|
|
1096
|
+
);
|
|
1097
|
+
}
|
|
1098
|
+
const parts = trimmed.split(",").map((p) => p.trim()).filter(Boolean);
|
|
1099
|
+
const next = /* @__PURE__ */ new Set();
|
|
1100
|
+
const unknown = [];
|
|
1101
|
+
for (const part of parts) {
|
|
1102
|
+
const key = part.toLowerCase();
|
|
1103
|
+
const mapped = CLI_TO_SETTING_SOURCE[key];
|
|
1104
|
+
if (!mapped) {
|
|
1105
|
+
unknown.push(part);
|
|
1106
|
+
continue;
|
|
1107
|
+
}
|
|
1108
|
+
next.add(mapped);
|
|
1109
|
+
}
|
|
1110
|
+
if (unknown.length > 0) {
|
|
1111
|
+
throw new Error(
|
|
1112
|
+
`Unknown setting source(s): ${unknown.join(", ")}. Expected: user, project, local.`
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
enabledSettingSources = next;
|
|
1116
|
+
}
|
|
1117
|
+
function isSettingSourceEnabled(source) {
|
|
1118
|
+
return enabledSettingSources.has(source);
|
|
1119
|
+
}
|
|
1120
|
+
function __resetSettingSourcesForTests() {
|
|
1121
|
+
enabledSettingSources = new Set(Object.values(CLI_TO_SETTING_SOURCE));
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// packages/config/src/files.ts
|
|
1125
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1126
|
+
import { homedir as homedir3 } from "node:os";
|
|
1127
|
+
import { dirname, join as join3, resolve as resolve2 } from "node:path";
|
|
1128
|
+
function logError(error) {
|
|
1129
|
+
if (process.env.NODE_ENV === "test") {
|
|
1130
|
+
console.error(error);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
function normalizeOverride(value) {
|
|
1134
|
+
if (typeof value !== "string") return null;
|
|
1135
|
+
const trimmed = value.trim();
|
|
1136
|
+
return trimmed ? resolve2(trimmed) : null;
|
|
1137
|
+
}
|
|
1138
|
+
function dedupeStrings(values) {
|
|
1139
|
+
const out = [];
|
|
1140
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1141
|
+
for (const value of values) {
|
|
1142
|
+
if (!value) continue;
|
|
1143
|
+
if (seen.has(value)) continue;
|
|
1144
|
+
seen.add(value);
|
|
1145
|
+
out.push(value);
|
|
1146
|
+
}
|
|
1147
|
+
return out;
|
|
1148
|
+
}
|
|
1149
|
+
function getDefaultHomeDir() {
|
|
1150
|
+
const envHome = typeof process.env.HOME === "string" ? process.env.HOME : typeof process.env.USERPROFILE === "string" ? process.env.USERPROFILE : "";
|
|
1151
|
+
const trimmed = envHome.trim();
|
|
1152
|
+
if (trimmed) return trimmed;
|
|
1153
|
+
return homedir3();
|
|
1154
|
+
}
|
|
1155
|
+
function getUserKodeBaseDir(options) {
|
|
1156
|
+
const respectEnvOverride = options?.respectEnvOverride ?? true;
|
|
1157
|
+
if (respectEnvOverride) {
|
|
1158
|
+
const override = normalizeOverride(
|
|
1159
|
+
process.env.KODE_CONFIG_DIR ?? process.env.CLAUDE_CONFIG_DIR
|
|
1160
|
+
);
|
|
1161
|
+
if (override) return override;
|
|
1162
|
+
}
|
|
1163
|
+
const home = options?.homeDir ?? getDefaultHomeDir();
|
|
1164
|
+
return join3(home, ".kode");
|
|
1165
|
+
}
|
|
1166
|
+
function getUserLegacyBaseDir(options) {
|
|
1167
|
+
const respectEnvOverride = options?.respectEnvOverride ?? true;
|
|
1168
|
+
if (respectEnvOverride) {
|
|
1169
|
+
const override = normalizeOverride(process.env.CLAUDE_CONFIG_DIR);
|
|
1170
|
+
if (override) return override;
|
|
1171
|
+
}
|
|
1172
|
+
const home = options?.homeDir ?? getDefaultHomeDir();
|
|
1173
|
+
return join3(home, ".claude");
|
|
1174
|
+
}
|
|
1175
|
+
function getSettingsFileCandidates(options) {
|
|
1176
|
+
const projectDir = options.projectDir ?? getCwd();
|
|
1177
|
+
const homeDir = options.homeDir ?? getDefaultHomeDir();
|
|
1178
|
+
const respectEnvOverride = options.homeDir === void 0;
|
|
1179
|
+
switch (options.destination) {
|
|
1180
|
+
case "localSettings": {
|
|
1181
|
+
const primary = join3(projectDir, ".kode", "settings.local.json");
|
|
1182
|
+
const legacy = [join3(projectDir, ".claude", "settings.local.json")];
|
|
1183
|
+
return { primary, legacy };
|
|
1184
|
+
}
|
|
1185
|
+
case "projectSettings": {
|
|
1186
|
+
const primary = join3(projectDir, ".kode", "settings.json");
|
|
1187
|
+
const legacy = [join3(projectDir, ".claude", "settings.json")];
|
|
1188
|
+
return { primary, legacy };
|
|
1189
|
+
}
|
|
1190
|
+
case "userSettings": {
|
|
1191
|
+
const primary = join3(
|
|
1192
|
+
getUserKodeBaseDir({ homeDir, respectEnvOverride }),
|
|
1193
|
+
"settings.json"
|
|
1194
|
+
);
|
|
1195
|
+
const legacy = dedupeStrings([
|
|
1196
|
+
join3(
|
|
1197
|
+
getUserLegacyBaseDir({ homeDir, respectEnvOverride }),
|
|
1198
|
+
"settings.json"
|
|
1199
|
+
),
|
|
1200
|
+
join3(homeDir, ".claude", "settings.json")
|
|
1201
|
+
]);
|
|
1202
|
+
return { primary, legacy };
|
|
1203
|
+
}
|
|
1204
|
+
default:
|
|
1205
|
+
return null;
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
function readSettingsFile(filePath) {
|
|
1209
|
+
if (!existsSync3(filePath)) return null;
|
|
1210
|
+
try {
|
|
1211
|
+
const raw = readFileSync3(filePath, "utf-8");
|
|
1212
|
+
const parsed = JSON.parse(raw);
|
|
1213
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
1214
|
+
return parsed;
|
|
1215
|
+
} catch (error) {
|
|
1216
|
+
logError(error);
|
|
1217
|
+
return null;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
function writeSettingsFile(filePath, settings) {
|
|
1221
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
1222
|
+
writeFileSync2(filePath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
1223
|
+
}
|
|
1224
|
+
function loadSettingsWithLegacyFallback(options) {
|
|
1225
|
+
const candidates = getSettingsFileCandidates(options);
|
|
1226
|
+
if (!candidates) return { settings: null, usedPath: null };
|
|
1227
|
+
const primarySettings = readSettingsFile(candidates.primary);
|
|
1228
|
+
if (primarySettings)
|
|
1229
|
+
return { settings: primarySettings, usedPath: candidates.primary };
|
|
1230
|
+
for (const legacyPath of candidates.legacy) {
|
|
1231
|
+
const legacySettings = readSettingsFile(legacyPath);
|
|
1232
|
+
if (!legacySettings) continue;
|
|
1233
|
+
if (options.migrateToPrimary && legacyPath !== candidates.primary) {
|
|
1234
|
+
try {
|
|
1235
|
+
if (!existsSync3(candidates.primary)) {
|
|
1236
|
+
writeSettingsFile(candidates.primary, legacySettings);
|
|
1237
|
+
}
|
|
1238
|
+
} catch (error) {
|
|
1239
|
+
logError(error);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
return { settings: legacySettings, usedPath: legacyPath };
|
|
1243
|
+
}
|
|
1244
|
+
return { settings: null, usedPath: null };
|
|
1245
|
+
}
|
|
1246
|
+
function saveSettingsToPrimaryAndSyncLegacy(options) {
|
|
1247
|
+
const candidates = getSettingsFileCandidates(options);
|
|
1248
|
+
if (!candidates) return;
|
|
1249
|
+
writeSettingsFile(candidates.primary, options.settings);
|
|
1250
|
+
if (!options.syncLegacyIfExists) return;
|
|
1251
|
+
for (const legacyPath of candidates.legacy) {
|
|
1252
|
+
if (legacyPath === candidates.primary) continue;
|
|
1253
|
+
if (!existsSync3(legacyPath)) continue;
|
|
1254
|
+
try {
|
|
1255
|
+
writeSettingsFile(legacyPath, options.settings);
|
|
1256
|
+
} catch (error) {
|
|
1257
|
+
logError(error);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// packages/config/src/local.ts
|
|
1263
|
+
import { join as join4 } from "node:path";
|
|
1264
|
+
function getLocalSettingsPath(options) {
|
|
1265
|
+
const projectDir = options?.projectDir ?? getCwd();
|
|
1266
|
+
return join4(projectDir, ".kode", "settings.local.json");
|
|
1267
|
+
}
|
|
1268
|
+
function readLocalSettings(options) {
|
|
1269
|
+
const projectDir = options?.projectDir ?? getCwd();
|
|
1270
|
+
const loaded = loadSettingsWithLegacyFallback({
|
|
1271
|
+
destination: "localSettings",
|
|
1272
|
+
projectDir,
|
|
1273
|
+
migrateToPrimary: true
|
|
1274
|
+
});
|
|
1275
|
+
return loaded.settings ?? {};
|
|
1276
|
+
}
|
|
1277
|
+
function updateLocalSettings(patch, options) {
|
|
1278
|
+
const projectDir = options?.projectDir ?? getCwd();
|
|
1279
|
+
const candidates = getSettingsFileCandidates({
|
|
1280
|
+
destination: "localSettings",
|
|
1281
|
+
projectDir
|
|
1282
|
+
});
|
|
1283
|
+
const existing = (candidates ? loadSettingsWithLegacyFallback({
|
|
1284
|
+
destination: "localSettings",
|
|
1285
|
+
projectDir,
|
|
1286
|
+
migrateToPrimary: true
|
|
1287
|
+
}).settings : null) ?? {};
|
|
1288
|
+
const next = { ...existing, ...patch };
|
|
1289
|
+
if (candidates) {
|
|
1290
|
+
saveSettingsToPrimaryAndSyncLegacy({
|
|
1291
|
+
destination: "localSettings",
|
|
1292
|
+
projectDir,
|
|
1293
|
+
settings: next,
|
|
1294
|
+
syncLegacyIfExists: true
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
return next;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
// packages/config/src/modelYaml.ts
|
|
1301
|
+
import yaml from "js-yaml";
|
|
1302
|
+
import { z } from "zod";
|
|
1303
|
+
var ApiKeySpecSchema = z.union([
|
|
1304
|
+
z.object({
|
|
1305
|
+
fromEnv: z.string().min(1)
|
|
1306
|
+
}).strict(),
|
|
1307
|
+
z.object({
|
|
1308
|
+
value: z.string()
|
|
1309
|
+
}).strict()
|
|
1310
|
+
]);
|
|
1311
|
+
var ModelProfileYamlSchema = z.object({
|
|
1312
|
+
name: z.string().min(1),
|
|
1313
|
+
provider: z.string().min(1),
|
|
1314
|
+
modelName: z.string().min(1),
|
|
1315
|
+
baseURL: z.string().min(1).optional(),
|
|
1316
|
+
maxTokens: z.number().int().positive(),
|
|
1317
|
+
contextLength: z.number().int().positive(),
|
|
1318
|
+
reasoningEffort: z.string().optional(),
|
|
1319
|
+
isActive: z.boolean().optional(),
|
|
1320
|
+
apiKey: ApiKeySpecSchema.optional(),
|
|
1321
|
+
apiKeyEnv: z.string().min(1).optional(),
|
|
1322
|
+
createdAt: z.number().int().positive().optional(),
|
|
1323
|
+
lastUsed: z.number().int().positive().optional()
|
|
1324
|
+
}).strict();
|
|
1325
|
+
var ModelPointersYamlSchema = z.object({
|
|
1326
|
+
main: z.string().min(1).optional(),
|
|
1327
|
+
task: z.string().min(1).optional(),
|
|
1328
|
+
compact: z.string().min(1).optional(),
|
|
1329
|
+
quick: z.string().min(1).optional()
|
|
1330
|
+
}).strict().optional();
|
|
1331
|
+
var ModelConfigYamlSchema = z.object({
|
|
1332
|
+
version: z.number().int().positive().default(1),
|
|
1333
|
+
profiles: z.array(ModelProfileYamlSchema).default([]),
|
|
1334
|
+
pointers: ModelPointersYamlSchema
|
|
1335
|
+
}).strict();
|
|
1336
|
+
function suggestedApiKeyEnvForProvider(provider) {
|
|
1337
|
+
switch (provider) {
|
|
1338
|
+
case "anthropic":
|
|
1339
|
+
return "ANTHROPIC_API_KEY";
|
|
1340
|
+
case "openai":
|
|
1341
|
+
case "custom-openai":
|
|
1342
|
+
return "OPENAI_API_KEY";
|
|
1343
|
+
case "azure":
|
|
1344
|
+
return "AZURE_OPENAI_API_KEY";
|
|
1345
|
+
case "gemini":
|
|
1346
|
+
return "GEMINI_API_KEY";
|
|
1347
|
+
default:
|
|
1348
|
+
return void 0;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
function resolveApiKeyFromYaml(input, existingApiKey) {
|
|
1352
|
+
const warnings = [];
|
|
1353
|
+
if (input.apiKeyEnv) {
|
|
1354
|
+
const envValue = process.env[input.apiKeyEnv];
|
|
1355
|
+
if (envValue) return { apiKey: envValue, warnings };
|
|
1356
|
+
if (existingApiKey) return { apiKey: existingApiKey, warnings };
|
|
1357
|
+
warnings.push(`Missing env var '${input.apiKeyEnv}' for apiKey`);
|
|
1358
|
+
return { apiKey: "", warnings };
|
|
1359
|
+
}
|
|
1360
|
+
if (input.apiKey && "fromEnv" in input.apiKey) {
|
|
1361
|
+
const envValue = process.env[input.apiKey.fromEnv];
|
|
1362
|
+
if (envValue) return { apiKey: envValue, warnings };
|
|
1363
|
+
if (existingApiKey) return { apiKey: existingApiKey, warnings };
|
|
1364
|
+
warnings.push(`Missing env var '${input.apiKey.fromEnv}' for apiKey`);
|
|
1365
|
+
return { apiKey: "", warnings };
|
|
1366
|
+
}
|
|
1367
|
+
if (input.apiKey && "value" in input.apiKey) {
|
|
1368
|
+
return { apiKey: input.apiKey.value, warnings };
|
|
1369
|
+
}
|
|
1370
|
+
if (existingApiKey) return { apiKey: existingApiKey, warnings };
|
|
1371
|
+
warnings.push(
|
|
1372
|
+
"Missing apiKey (set apiKey.fromEnv, apiKeyEnv, or apiKey.value)"
|
|
1373
|
+
);
|
|
1374
|
+
return { apiKey: "", warnings };
|
|
1375
|
+
}
|
|
1376
|
+
function resolvePointerTarget(pointerValue, profiles) {
|
|
1377
|
+
if (profiles.some((p) => p.modelName === pointerValue)) return pointerValue;
|
|
1378
|
+
const byName = profiles.find((p) => p.name === pointerValue);
|
|
1379
|
+
return byName?.modelName ?? null;
|
|
1380
|
+
}
|
|
1381
|
+
function parseModelConfigYaml(yamlText) {
|
|
1382
|
+
const parsed = yaml.load(yamlText);
|
|
1383
|
+
return ModelConfigYamlSchema.parse(parsed);
|
|
1384
|
+
}
|
|
1385
|
+
function formatModelConfigYamlForSharing(config) {
|
|
1386
|
+
const modelProfiles = config.modelProfiles ?? [];
|
|
1387
|
+
const pointers = config.modelPointers;
|
|
1388
|
+
const exported = {
|
|
1389
|
+
version: 1,
|
|
1390
|
+
profiles: modelProfiles.map((p) => {
|
|
1391
|
+
const suggestedEnv = suggestedApiKeyEnvForProvider(p.provider);
|
|
1392
|
+
return {
|
|
1393
|
+
name: p.name,
|
|
1394
|
+
provider: p.provider,
|
|
1395
|
+
modelName: p.modelName,
|
|
1396
|
+
...p.baseURL ? { baseURL: p.baseURL } : {},
|
|
1397
|
+
maxTokens: p.maxTokens,
|
|
1398
|
+
contextLength: p.contextLength,
|
|
1399
|
+
...p.reasoningEffort ? { reasoningEffort: p.reasoningEffort } : {},
|
|
1400
|
+
isActive: p.isActive,
|
|
1401
|
+
createdAt: p.createdAt,
|
|
1402
|
+
...typeof p.lastUsed === "number" ? { lastUsed: p.lastUsed } : {},
|
|
1403
|
+
apiKey: { fromEnv: suggestedEnv ?? "API_KEY" }
|
|
1404
|
+
};
|
|
1405
|
+
}),
|
|
1406
|
+
...pointers ? { pointers } : {}
|
|
1407
|
+
};
|
|
1408
|
+
return yaml.dump(exported, {
|
|
1409
|
+
noRefs: true,
|
|
1410
|
+
lineWidth: 120
|
|
1411
|
+
});
|
|
1412
|
+
}
|
|
1413
|
+
function applyModelConfigYamlImport(existingConfig, yamlText, options = {}) {
|
|
1414
|
+
const parsed = parseModelConfigYaml(yamlText);
|
|
1415
|
+
const warnings = [];
|
|
1416
|
+
const existingProfiles = existingConfig.modelProfiles ?? [];
|
|
1417
|
+
const existingByModelName = new Map(
|
|
1418
|
+
existingProfiles.map((p) => [p.modelName, p])
|
|
1419
|
+
);
|
|
1420
|
+
const now = Date.now();
|
|
1421
|
+
const importedProfiles = parsed.profiles.map((profile) => {
|
|
1422
|
+
const existing = existingByModelName.get(profile.modelName);
|
|
1423
|
+
const resolved = resolveApiKeyFromYaml(
|
|
1424
|
+
{ apiKey: profile.apiKey, apiKeyEnv: profile.apiKeyEnv },
|
|
1425
|
+
existing?.apiKey
|
|
1426
|
+
);
|
|
1427
|
+
warnings.push(...resolved.warnings.map((w) => `[${profile.modelName}] ${w}`));
|
|
1428
|
+
return {
|
|
1429
|
+
name: profile.name,
|
|
1430
|
+
provider: profile.provider,
|
|
1431
|
+
modelName: profile.modelName,
|
|
1432
|
+
...profile.baseURL ? { baseURL: profile.baseURL } : {},
|
|
1433
|
+
apiKey: resolved.apiKey,
|
|
1434
|
+
maxTokens: profile.maxTokens,
|
|
1435
|
+
contextLength: profile.contextLength,
|
|
1436
|
+
...profile.reasoningEffort ? { reasoningEffort: profile.reasoningEffort } : {},
|
|
1437
|
+
isActive: profile.isActive ?? true,
|
|
1438
|
+
createdAt: profile.createdAt ?? existing?.createdAt ?? now,
|
|
1439
|
+
...profile.lastUsed ? { lastUsed: profile.lastUsed } : existing?.lastUsed ? { lastUsed: existing.lastUsed } : {},
|
|
1440
|
+
...existing?.isGPT5 ? { isGPT5: existing.isGPT5 } : {},
|
|
1441
|
+
...existing?.validationStatus ? { validationStatus: existing.validationStatus } : {},
|
|
1442
|
+
...existing?.lastValidation ? { lastValidation: existing.lastValidation } : {}
|
|
1443
|
+
};
|
|
1444
|
+
});
|
|
1445
|
+
const mergedProfiles = options.replace ? importedProfiles : [...existingProfiles, ...importedProfiles].reduce((acc, p) => {
|
|
1446
|
+
const i = acc.findIndex((x) => x.modelName === p.modelName);
|
|
1447
|
+
if (i >= 0) acc[i] = p;
|
|
1448
|
+
else acc.push(p);
|
|
1449
|
+
return acc;
|
|
1450
|
+
}, []);
|
|
1451
|
+
let nextPointers = existingConfig.modelPointers;
|
|
1452
|
+
if (parsed.pointers) {
|
|
1453
|
+
const mapped = {
|
|
1454
|
+
main: parsed.pointers.main,
|
|
1455
|
+
task: parsed.pointers.task,
|
|
1456
|
+
compact: parsed.pointers.compact,
|
|
1457
|
+
quick: parsed.pointers.quick
|
|
1458
|
+
};
|
|
1459
|
+
nextPointers = {
|
|
1460
|
+
main: (mapped.main ? resolvePointerTarget(mapped.main, mergedProfiles) : null) ?? existingConfig.modelPointers?.main ?? "",
|
|
1461
|
+
task: (mapped.task ? resolvePointerTarget(mapped.task, mergedProfiles) : null) ?? existingConfig.modelPointers?.task ?? "",
|
|
1462
|
+
compact: (mapped.compact ? resolvePointerTarget(mapped.compact, mergedProfiles) : null) ?? existingConfig.modelPointers?.compact ?? "",
|
|
1463
|
+
quick: (mapped.quick ? resolvePointerTarget(mapped.quick, mergedProfiles) : null) ?? existingConfig.modelPointers?.quick ?? ""
|
|
1464
|
+
};
|
|
1465
|
+
}
|
|
1466
|
+
return {
|
|
1467
|
+
nextConfig: {
|
|
1468
|
+
...existingConfig,
|
|
1469
|
+
modelProfiles: mergedProfiles,
|
|
1470
|
+
modelPointers: nextPointers
|
|
1471
|
+
},
|
|
1472
|
+
warnings
|
|
1473
|
+
};
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
export {
|
|
1477
|
+
DEFAULT_PROJECT_CONFIG,
|
|
1478
|
+
defaultConfigForProject,
|
|
1479
|
+
isAutoUpdaterStatus,
|
|
1480
|
+
DEFAULT_GLOBAL_CONFIG,
|
|
1481
|
+
GLOBAL_CONFIG_KEYS,
|
|
1482
|
+
isGlobalConfigKey,
|
|
1483
|
+
PROJECT_CONFIG_KEYS,
|
|
1484
|
+
isProjectConfigKey,
|
|
1485
|
+
getKodeBaseDir,
|
|
1486
|
+
getGlobalConfigFilePath,
|
|
1487
|
+
ConfigParseError,
|
|
1488
|
+
enableConfigs,
|
|
1489
|
+
saveGlobalConfig,
|
|
1490
|
+
getGlobalConfig,
|
|
1491
|
+
checkHasTrustDialogAccepted,
|
|
1492
|
+
getCurrentProjectConfig,
|
|
1493
|
+
saveCurrentProjectConfig,
|
|
1494
|
+
isAutoUpdaterDisabled,
|
|
1495
|
+
getOrCreateUserID,
|
|
1496
|
+
normalizeApiKeyForConfig,
|
|
1497
|
+
getCustomApiKeyStatus,
|
|
1498
|
+
TEST_MCPRC_CONFIG_FOR_TESTING,
|
|
1499
|
+
clearMcprcConfigForTesting,
|
|
1500
|
+
addMcprcServerForTesting,
|
|
1501
|
+
removeMcprcServerForTesting,
|
|
1502
|
+
getMcprcConfig,
|
|
1503
|
+
getProjectMcpServerDefinitions,
|
|
1504
|
+
getConfigForCLI,
|
|
1505
|
+
setConfigForCLI,
|
|
1506
|
+
deleteConfigForCLI,
|
|
1507
|
+
listConfigForCLI,
|
|
1508
|
+
getOpenAIApiKey,
|
|
1509
|
+
getAnthropicApiKey,
|
|
1510
|
+
testGPT5Connection,
|
|
1511
|
+
validateGPT5Config,
|
|
1512
|
+
isGPT5ModelName,
|
|
1513
|
+
validateAndRepairGPT5Profile,
|
|
1514
|
+
getGPT5ConfigRecommendations,
|
|
1515
|
+
createGPT5ModelProfile,
|
|
1516
|
+
setAllPointersToModel,
|
|
1517
|
+
setModelPointer,
|
|
1518
|
+
validateAndRepairAllGPT5Profiles,
|
|
1519
|
+
setEnabledSettingSourcesFromCli,
|
|
1520
|
+
isSettingSourceEnabled,
|
|
1521
|
+
__resetSettingSourcesForTests,
|
|
1522
|
+
getSettingsFileCandidates,
|
|
1523
|
+
readSettingsFile,
|
|
1524
|
+
writeSettingsFile,
|
|
1525
|
+
loadSettingsWithLegacyFallback,
|
|
1526
|
+
saveSettingsToPrimaryAndSyncLegacy,
|
|
1527
|
+
getLocalSettingsPath,
|
|
1528
|
+
readLocalSettings,
|
|
1529
|
+
updateLocalSettings,
|
|
1530
|
+
parseModelConfigYaml,
|
|
1531
|
+
formatModelConfigYamlForSharing,
|
|
1532
|
+
applyModelConfigYamlImport
|
|
1533
|
+
};
|