newcraw 1.0.2 → 1.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/dist/REPL-CTTH53A7.js +50 -0
- package/dist/{acp-J4WDYGRX.js → acp-25PIN25O.js} +69 -40
- package/dist/acp-25PIN25O.js.map +7 -0
- package/dist/{agentsValidate-UBOER2IN.js → agentsValidate-BXDD54YP.js} +13 -10
- package/dist/{agentsValidate-UBOER2IN.js.map → agentsValidate-BXDD54YP.js.map} +1 -1
- package/dist/{ask-MGUO3L35.js → ask-EL4XAA5P.js} +62 -52
- package/dist/ask-EL4XAA5P.js.map +7 -0
- package/dist/{autoUpdater-2GS6LRPK.js → autoUpdater-DKMSJXWW.js} +5 -4
- package/dist/{chunk-2C43OXE7.js → chunk-2OVXJBJV.js} +38 -59
- package/dist/chunk-2OVXJBJV.js.map +7 -0
- package/dist/{chunk-53A4JHFW.js → chunk-3D3C7MRI.js} +23 -4
- package/dist/chunk-3D3C7MRI.js.map +7 -0
- package/dist/{chunk-VKI7ORIO.js → chunk-3ZQRACCP.js} +37 -18
- package/dist/{chunk-VKI7ORIO.js.map → chunk-3ZQRACCP.js.map} +1 -1
- package/dist/chunk-4A6CDBDH.js +822 -0
- package/dist/chunk-4A6CDBDH.js.map +7 -0
- package/dist/{chunk-VQSCECTS.js → chunk-53VETVCP.js} +6 -4
- package/dist/{chunk-VQSCECTS.js.map → chunk-53VETVCP.js.map} +1 -1
- package/dist/{chunk-WWDVA4NV.js → chunk-6WT3ZRYF.js} +22 -6
- package/dist/{chunk-WWDVA4NV.js.map → chunk-6WT3ZRYF.js.map} +1 -1
- package/dist/{chunk-RUXIBQ3B.js → chunk-7E2L7EH2.js} +4 -4
- package/dist/{chunk-VHS2MZQS.js → chunk-7PWVUHQ2.js} +9 -6
- package/dist/{chunk-VHS2MZQS.js.map → chunk-7PWVUHQ2.js.map} +1 -1
- package/dist/{chunk-2EFL22PV.js → chunk-ADJ4YEII.js} +7 -3
- package/dist/chunk-ADJ4YEII.js.map +7 -0
- package/dist/chunk-AKNZJBBU.js +372 -0
- package/dist/chunk-AKNZJBBU.js.map +7 -0
- package/dist/chunk-ALQSPHXV.js +135 -0
- package/dist/chunk-ALQSPHXV.js.map +7 -0
- package/dist/{chunk-XS6PU75S.js → chunk-APSIF3YK.js} +1 -1
- package/dist/{chunk-IM33F5CM.js → chunk-BMJ5XGFR.js} +1668 -1623
- package/dist/chunk-BMJ5XGFR.js.map +7 -0
- package/dist/chunk-BQCOSNM3.js +93 -0
- package/dist/chunk-BQCOSNM3.js.map +7 -0
- package/dist/{chunk-OJIMOLIC.js → chunk-BTCASL4X.js} +3621 -7413
- package/dist/chunk-BTCASL4X.js.map +7 -0
- package/dist/chunk-CHB5K4GI.js +107 -0
- package/dist/chunk-CHB5K4GI.js.map +7 -0
- package/dist/{chunk-QH2M65BR.js → chunk-D2FSAFMO.js} +7 -3
- package/dist/{chunk-QH2M65BR.js.map → chunk-D2FSAFMO.js.map} +1 -1
- package/dist/chunk-D4OZACS2.js +35 -0
- package/dist/{chunk-IIFUDVGS.js → chunk-ENLHVQCX.js} +310 -177
- package/dist/chunk-ENLHVQCX.js.map +7 -0
- package/dist/{chunk-A7X6OCZE.js → chunk-ERKWSZ3K.js} +1 -1
- package/dist/{chunk-UYRR6F5S.js → chunk-FSSZHQEJ.js} +9 -3
- package/dist/{chunk-UYRR6F5S.js.map → chunk-FSSZHQEJ.js.map} +1 -1
- package/dist/chunk-GV73HKJO.js +5473 -0
- package/dist/chunk-GV73HKJO.js.map +7 -0
- package/dist/{chunk-GZTCXXSS.js → chunk-GZ4BEVMZ.js} +57 -46
- package/dist/{chunk-GZTCXXSS.js.map → chunk-GZ4BEVMZ.js.map} +1 -1
- package/dist/chunk-HLBLZKZH.js +45 -0
- package/dist/chunk-HLBLZKZH.js.map +7 -0
- package/dist/chunk-JLVECHVJ.js +36 -0
- package/dist/chunk-JLVECHVJ.js.map +7 -0
- package/dist/chunk-KNSAVNMD.js +683 -0
- package/dist/{chunk-F3COCCAE.js.map → chunk-KNSAVNMD.js.map} +1 -1
- package/dist/{chunk-V5U6BHT2.js → chunk-KRN3WHHL.js} +7 -3
- package/dist/{chunk-V5U6BHT2.js.map → chunk-KRN3WHHL.js.map} +1 -1
- package/dist/{chunk-3LMXSKZ7.js → chunk-NFYAVT54.js} +1 -1
- package/dist/chunk-NT7RDVDA.js +33 -0
- package/dist/{chunk-KQSHIOZK.js.map → chunk-NT7RDVDA.js.map} +1 -1
- package/dist/chunk-NW7WSLD5.js +166 -0
- package/dist/{chunk-ZYSVG4X3.js.map → chunk-NW7WSLD5.js.map} +2 -2
- package/dist/{chunk-HSJ6HYAO.js → chunk-P52SGBC4.js} +18 -10
- package/dist/chunk-P52SGBC4.js.map +7 -0
- package/dist/{chunk-XXU2NVOE.js → chunk-PC6QOCGI.js} +30 -6
- package/dist/chunk-PC6QOCGI.js.map +7 -0
- package/dist/{chunk-N5OHRWG2.js → chunk-QSRXXZO7.js} +4 -2
- package/dist/{chunk-N5OHRWG2.js.map → chunk-QSRXXZO7.js.map} +1 -1
- package/dist/{chunk-DEF3KFP7.js → chunk-QZFKONA3.js} +4 -2
- package/dist/{chunk-DEF3KFP7.js.map → chunk-QZFKONA3.js.map} +1 -1
- package/dist/{chunk-JWXQNBBA.js → chunk-RE226X4F.js} +7 -1
- package/dist/{chunk-JWXQNBBA.js.map → chunk-RE226X4F.js.map} +1 -1
- package/dist/chunk-RF57YWGW.js +88 -0
- package/dist/chunk-RF57YWGW.js.map +7 -0
- package/dist/chunk-UGBECBIR.js +62 -0
- package/dist/chunk-UGBECBIR.js.map +7 -0
- package/dist/chunk-UYWZQVH5.js +35 -0
- package/dist/chunk-UYWZQVH5.js.map +7 -0
- package/dist/{chunk-LOIZNQOU.js → chunk-VHZRJ7RI.js} +9 -3
- package/dist/{chunk-LOIZNQOU.js.map → chunk-VHZRJ7RI.js.map} +1 -1
- package/dist/{chunk-XMGUQHMF.js → chunk-VSSVN6WG.js} +11 -1
- package/dist/chunk-VSSVN6WG.js.map +7 -0
- package/dist/{chunk-OZHBEG7U.js → chunk-XV7LPJNT.js} +15 -5
- package/dist/{chunk-OZHBEG7U.js.map → chunk-XV7LPJNT.js.map} +1 -1
- package/dist/chunk-Y7MDOB3N.js +65 -0
- package/dist/chunk-Y7MDOB3N.js.map +7 -0
- package/dist/{chunk-BWYKUDJR.js → chunk-ZLAB3Z4G.js} +14 -8
- package/dist/{chunk-BWYKUDJR.js.map → chunk-ZLAB3Z4G.js.map} +1 -1
- package/dist/{chunk-755HIAI3.js → chunk-ZMO4E7IW.js} +3 -42
- package/dist/chunk-ZMO4E7IW.js.map +7 -0
- package/dist/{cli-KZGF3FV5.js → cli-Z2BNJWHT.js} +251 -485
- package/dist/cli-Z2BNJWHT.js.map +7 -0
- package/dist/commands-3Y3OQOXT.js +54 -0
- package/dist/{config-GTJWCNPF.js → config-5RS7HDIK.js} +9 -6
- package/dist/{context-WF3TTXQU.js → context-XZXRRYKS.js} +8 -7
- package/dist/{costTracker-2G3ZI2JF.js → costTracker-VSWW7SRT.js} +3 -2
- package/dist/{customCommands-QOWK57EX.js → customCommands-6KDAODFQ.js} +6 -5
- package/dist/{env-37BAP7QF.js → env-WIM2DQ4L.js} +10 -7
- package/dist/{gateway-IZYO6YFJ.js → gateway-DKHC7H3K.js} +542 -96
- package/dist/gateway-DKHC7H3K.js.map +7 -0
- package/dist/identity-3KZQQVBG.js +16 -0
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/{kodeAgentSessionId-KTGFX2BE.js → kodeAgentSessionId-4SH24DVH.js} +1 -1
- package/dist/{kodeAgentSessionLoad-6F7SJXBC.js → kodeAgentSessionLoad-4S452GGD.js} +6 -5
- package/dist/{kodeAgentSessionResume-UEEDRJ3N.js → kodeAgentSessionResume-MSMG4QUR.js} +6 -5
- package/dist/{kodeAgentStreamJson-VIXFTYL5.js → kodeAgentStreamJson-4ZKIWKS3.js} +4 -2
- package/dist/{kodeAgentStreamJsonSession-XC3IPREZ.js → kodeAgentStreamJsonSession-CYG6MLKP.js} +15 -4
- package/dist/kodeAgentStreamJsonSession-CYG6MLKP.js.map +7 -0
- package/dist/{kodeAgentStructuredStdio-SI5C7AAD.js → kodeAgentStructuredStdio-5DCUC6V6.js} +3 -3
- package/dist/{kodeHooks-V36SHCTC.js → kodeHooks-WX3N6CL6.js} +6 -5
- package/dist/{llm-CYUDKJNR.js → llm-V2W4KJIA.js} +239 -57
- package/dist/llm-V2W4KJIA.js.map +7 -0
- package/dist/{llmLazy-IXVVBRTN.js → llmLazy-I7SO67YA.js} +2 -2
- package/dist/{loader-OEJ6C3TN.js → loader-YJGRGJNH.js} +6 -5
- package/dist/{mcp-KE3SILMX.js → mcp-WG3RQQCZ.js} +10 -9
- package/dist/{mentionProcessor-GAU2WAYB.js → mentionProcessor-PKWDUKTN.js} +14 -7
- package/dist/{mentionProcessor-GAU2WAYB.js.map → mentionProcessor-PKWDUKTN.js.map} +1 -1
- package/dist/{messages-WCSGGSEU.js → messages-RXHQ6VKL.js} +2 -2
- package/dist/{model-4TQIV5J2.js → model-JNWAZGT7.js} +10 -7
- package/dist/{openai-KTZV6F7N.js → openai-6NL5UXO7.js} +8 -7
- package/dist/{outputStyles-WX5RYQOA.js → outputStyles-BVPXT3MW.js} +6 -5
- package/dist/{pluginRuntime-JXMJZ2LC.js → pluginRuntime-XHI3TCRJ.js} +11 -8
- package/dist/{pluginRuntime-JXMJZ2LC.js.map → pluginRuntime-XHI3TCRJ.js.map} +1 -1
- package/dist/{pluginValidation-JNQZYLUP.js → pluginValidation-WDFL352C.js} +8 -7
- package/dist/prompts-C4RUFGX2.js +58 -0
- package/dist/query-IA3UKMGR.js +58 -0
- package/dist/{responsesStreaming-2AIT6GHG.js → responsesStreaming-JORGEFQC.js} +1 -1
- package/dist/{ripgrep-KDPQAMB2.js → ripgrep-BHDXRABJ.js} +5 -4
- package/dist/sandbox-QOXESHL4.js +63 -0
- package/dist/{skillMarketplace-IXAGP3Q2.js → skillMarketplace-RIAMO2YA.js} +5 -4
- package/dist/{state-MSCYLB6Y.js → state-TM2XZQE2.js} +6 -3
- package/dist/structuredOutput-KAVFUV2Z.js +9 -0
- package/dist/theme-BXUQNXSD.js +15 -0
- package/dist/thinking-BCZ4WDT6.js +18 -0
- package/dist/{toolPermissionContext-I3IXPVED.js → toolPermissionContext-JCQ5MFUT.js} +1 -1
- package/dist/toolPermissionContext-JCQ5MFUT.js.map +7 -0
- package/dist/toolPermissionContextState-ILRPUITK.js +24 -0
- package/dist/toolPermissionContextState-ILRPUITK.js.map +7 -0
- package/dist/{toolPermissionSettings-EUZKGZU2.js → toolPermissionSettings-LNYZ6XFE.js} +9 -8
- package/dist/toolPermissionSettings-LNYZ6XFE.js.map +7 -0
- package/dist/tools-HIPUGTF5.js +55 -0
- package/dist/tools-HIPUGTF5.js.map +7 -0
- package/dist/{userInput-LJL4CVOB.js → userInput-I33T2RX2.js} +49 -34
- package/dist/{userInput-LJL4CVOB.js.map → userInput-I33T2RX2.js.map} +1 -1
- package/dist/{uuid-VA3KVASX.js → uuid-RQH3OZ3W.js} +1 -1
- package/dist/uuid-RQH3OZ3W.js.map +7 -0
- package/dist/workspace-EP63OB5S.js +21 -0
- package/dist/workspace-EP63OB5S.js.map +7 -0
- package/package.json +1 -1
- package/web/dist/assets/index-XuLVvSQF.js +251 -0
- package/web/dist/assets/index-pSid9IlY.css +10 -0
- package/web/dist/index.html +2 -2
- package/dist/REPL-IAK7ZN2Z.js +0 -42
- package/dist/acp-J4WDYGRX.js.map +0 -7
- package/dist/ask-MGUO3L35.js.map +0 -7
- package/dist/chunk-2C43OXE7.js.map +0 -7
- package/dist/chunk-2EFL22PV.js.map +0 -7
- package/dist/chunk-53A4JHFW.js.map +0 -7
- package/dist/chunk-755HIAI3.js.map +0 -7
- package/dist/chunk-AXWJI6N5.js +0 -11
- package/dist/chunk-F3COCCAE.js +0 -654
- package/dist/chunk-HSJ6HYAO.js.map +0 -7
- package/dist/chunk-IIFUDVGS.js.map +0 -7
- package/dist/chunk-IM33F5CM.js.map +0 -7
- package/dist/chunk-KQSHIOZK.js +0 -24
- package/dist/chunk-OJIMOLIC.js.map +0 -7
- package/dist/chunk-XMGUQHMF.js.map +0 -7
- package/dist/chunk-XXU2NVOE.js.map +0 -7
- package/dist/chunk-ZYSVG4X3.js +0 -151
- package/dist/cli-KZGF3FV5.js.map +0 -7
- package/dist/commands-AVEBLFVS.js +0 -46
- package/dist/gateway-IZYO6YFJ.js.map +0 -7
- package/dist/kodeAgentStreamJsonSession-XC3IPREZ.js.map +0 -7
- package/dist/llm-CYUDKJNR.js.map +0 -7
- package/dist/prompts-LE6GK75N.js +0 -48
- package/dist/query-GGIP6PWG.js +0 -50
- package/dist/theme-GAMFOLBW.js +0 -14
- package/dist/tools-3HOUIDM3.js +0 -47
- package/web/dist/assets/index-COAJqX1Z.css +0 -1
- package/web/dist/assets/index-CzS_4LmC.js +0 -179
- /package/dist/{REPL-IAK7ZN2Z.js.map → REPL-CTTH53A7.js.map} +0 -0
- /package/dist/{autoUpdater-2GS6LRPK.js.map → autoUpdater-DKMSJXWW.js.map} +0 -0
- /package/dist/{chunk-RUXIBQ3B.js.map → chunk-7E2L7EH2.js.map} +0 -0
- /package/dist/{chunk-XS6PU75S.js.map → chunk-APSIF3YK.js.map} +0 -0
- /package/dist/{chunk-AXWJI6N5.js.map → chunk-D4OZACS2.js.map} +0 -0
- /package/dist/{chunk-A7X6OCZE.js.map → chunk-ERKWSZ3K.js.map} +0 -0
- /package/dist/{chunk-3LMXSKZ7.js.map → chunk-NFYAVT54.js.map} +0 -0
- /package/dist/{commands-AVEBLFVS.js.map → commands-3Y3OQOXT.js.map} +0 -0
- /package/dist/{config-GTJWCNPF.js.map → config-5RS7HDIK.js.map} +0 -0
- /package/dist/{context-WF3TTXQU.js.map → context-XZXRRYKS.js.map} +0 -0
- /package/dist/{costTracker-2G3ZI2JF.js.map → costTracker-VSWW7SRT.js.map} +0 -0
- /package/dist/{customCommands-QOWK57EX.js.map → customCommands-6KDAODFQ.js.map} +0 -0
- /package/dist/{env-37BAP7QF.js.map → env-WIM2DQ4L.js.map} +0 -0
- /package/dist/{kodeAgentSessionId-KTGFX2BE.js.map → identity-3KZQQVBG.js.map} +0 -0
- /package/dist/{kodeAgentSessionLoad-6F7SJXBC.js.map → kodeAgentSessionId-4SH24DVH.js.map} +0 -0
- /package/dist/{kodeAgentSessionResume-UEEDRJ3N.js.map → kodeAgentSessionLoad-4S452GGD.js.map} +0 -0
- /package/dist/{kodeAgentStreamJson-VIXFTYL5.js.map → kodeAgentSessionResume-MSMG4QUR.js.map} +0 -0
- /package/dist/{kodeAgentStructuredStdio-SI5C7AAD.js.map → kodeAgentStreamJson-4ZKIWKS3.js.map} +0 -0
- /package/dist/{kodeHooks-V36SHCTC.js.map → kodeAgentStructuredStdio-5DCUC6V6.js.map} +0 -0
- /package/dist/{llmLazy-IXVVBRTN.js.map → kodeHooks-WX3N6CL6.js.map} +0 -0
- /package/dist/{loader-OEJ6C3TN.js.map → llmLazy-I7SO67YA.js.map} +0 -0
- /package/dist/{mcp-KE3SILMX.js.map → loader-YJGRGJNH.js.map} +0 -0
- /package/dist/{messages-WCSGGSEU.js.map → mcp-WG3RQQCZ.js.map} +0 -0
- /package/dist/{model-4TQIV5J2.js.map → messages-RXHQ6VKL.js.map} +0 -0
- /package/dist/{openai-KTZV6F7N.js.map → model-JNWAZGT7.js.map} +0 -0
- /package/dist/{outputStyles-WX5RYQOA.js.map → openai-6NL5UXO7.js.map} +0 -0
- /package/dist/{pluginValidation-JNQZYLUP.js.map → outputStyles-BVPXT3MW.js.map} +0 -0
- /package/dist/{prompts-LE6GK75N.js.map → pluginValidation-WDFL352C.js.map} +0 -0
- /package/dist/{query-GGIP6PWG.js.map → prompts-C4RUFGX2.js.map} +0 -0
- /package/dist/{responsesStreaming-2AIT6GHG.js.map → query-IA3UKMGR.js.map} +0 -0
- /package/dist/{ripgrep-KDPQAMB2.js.map → responsesStreaming-JORGEFQC.js.map} +0 -0
- /package/dist/{skillMarketplace-IXAGP3Q2.js.map → ripgrep-BHDXRABJ.js.map} +0 -0
- /package/dist/{state-MSCYLB6Y.js.map → sandbox-QOXESHL4.js.map} +0 -0
- /package/dist/{theme-GAMFOLBW.js.map → skillMarketplace-RIAMO2YA.js.map} +0 -0
- /package/dist/{toolPermissionContext-I3IXPVED.js.map → state-TM2XZQE2.js.map} +0 -0
- /package/dist/{toolPermissionSettings-EUZKGZU2.js.map → structuredOutput-KAVFUV2Z.js.map} +0 -0
- /package/dist/{tools-3HOUIDM3.js.map → theme-BXUQNXSD.js.map} +0 -0
- /package/dist/{uuid-VA3KVASX.js.map → thinking-BCZ4WDT6.js.map} +0 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { createRequire as __newcrawCreateRequire } from "node:module";
|
|
2
|
+
const require = __newcrawCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
Onboarding,
|
|
5
|
+
Select,
|
|
6
|
+
clearTerminal,
|
|
7
|
+
grantReadPermissionForOriginalDir,
|
|
8
|
+
useExitOnCtrlCD
|
|
9
|
+
} from "./chunk-GV73HKJO.js";
|
|
10
|
+
import {
|
|
11
|
+
getMcprcServerStatus
|
|
12
|
+
} from "./chunk-6WT3ZRYF.js";
|
|
13
|
+
import {
|
|
14
|
+
getTheme
|
|
15
|
+
} from "./chunk-QZFKONA3.js";
|
|
16
|
+
import {
|
|
17
|
+
checkHasTrustDialogAccepted,
|
|
18
|
+
getCurrentProjectConfig,
|
|
19
|
+
getGlobalConfig,
|
|
20
|
+
getProjectMcpServerDefinitions,
|
|
21
|
+
init_config,
|
|
22
|
+
saveCurrentProjectConfig,
|
|
23
|
+
saveGlobalConfig
|
|
24
|
+
} from "./chunk-ENLHVQCX.js";
|
|
25
|
+
import {
|
|
26
|
+
getCwd,
|
|
27
|
+
init_state
|
|
28
|
+
} from "./chunk-BMJ5XGFR.js";
|
|
29
|
+
import {
|
|
30
|
+
PRODUCT_COMMAND,
|
|
31
|
+
PRODUCT_NAME,
|
|
32
|
+
init_product
|
|
33
|
+
} from "./chunk-UYWZQVH5.js";
|
|
34
|
+
import {
|
|
35
|
+
MACRO,
|
|
36
|
+
init_macros
|
|
37
|
+
} from "./chunk-NW7WSLD5.js";
|
|
38
|
+
|
|
39
|
+
// src/entrypoints/cli/setupScreens.tsx
|
|
40
|
+
init_macros();
|
|
41
|
+
import React6 from "react";
|
|
42
|
+
|
|
43
|
+
// src/ui/components/TrustDialog.tsx
|
|
44
|
+
import React from "react";
|
|
45
|
+
import { Box, Text, useInput } from "ink";
|
|
46
|
+
init_config();
|
|
47
|
+
init_product();
|
|
48
|
+
init_state();
|
|
49
|
+
import { homedir } from "os";
|
|
50
|
+
function TrustDialog({ onDone }) {
|
|
51
|
+
const theme = getTheme();
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
}, []);
|
|
54
|
+
function onChange(value) {
|
|
55
|
+
const config = getCurrentProjectConfig();
|
|
56
|
+
switch (value) {
|
|
57
|
+
case "yes": {
|
|
58
|
+
const isHomeDir = homedir() === getCwd();
|
|
59
|
+
if (!isHomeDir) {
|
|
60
|
+
saveCurrentProjectConfig({
|
|
61
|
+
...config,
|
|
62
|
+
hasTrustDialogAccepted: true
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
onDone();
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "no": {
|
|
69
|
+
process.exit(1);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const exitState = useExitOnCtrlCD(() => process.exit(0));
|
|
75
|
+
useInput((_input, key) => {
|
|
76
|
+
if (key.escape) {
|
|
77
|
+
process.exit(0);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
|
|
82
|
+
Box,
|
|
83
|
+
{
|
|
84
|
+
flexDirection: "column",
|
|
85
|
+
gap: 1,
|
|
86
|
+
padding: 1,
|
|
87
|
+
borderStyle: "round",
|
|
88
|
+
borderColor: theme.warning
|
|
89
|
+
},
|
|
90
|
+
/* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.warning }, "Do you trust the files in this folder?"),
|
|
91
|
+
/* @__PURE__ */ React.createElement(Text, { bold: true }, process.cwd()),
|
|
92
|
+
/* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React.createElement(Text, null, PRODUCT_NAME, " may read files in this folder. Reading untrusted files may lead to ", PRODUCT_NAME, " to behave in an unexpected ways."), /* @__PURE__ */ React.createElement(Text, null, "With your permission ", PRODUCT_NAME, " may execute files in this folder. Executing untrusted code is unsafe.")),
|
|
93
|
+
/* @__PURE__ */ React.createElement(
|
|
94
|
+
Select,
|
|
95
|
+
{
|
|
96
|
+
options: [
|
|
97
|
+
{ label: "Yes, proceed", value: "yes" },
|
|
98
|
+
{ label: "No, exit", value: "no" }
|
|
99
|
+
],
|
|
100
|
+
onChange: (value) => onChange(value)
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
), /* @__PURE__ */ React.createElement(Box, { marginLeft: 3 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, exitState.pending ? /* @__PURE__ */ React.createElement(React.Fragment, null, "Press ", exitState.keyName, " again to exit") : /* @__PURE__ */ React.createElement(React.Fragment, null, "Enter to confirm \xB7 Esc to exit"))));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/entrypoints/cli/setupScreens.tsx
|
|
107
|
+
init_config();
|
|
108
|
+
|
|
109
|
+
// src/ui/screens/MCPServerApproval.tsx
|
|
110
|
+
import React5 from "react";
|
|
111
|
+
import { render } from "ink";
|
|
112
|
+
|
|
113
|
+
// src/ui/components/MCPServerMultiselectDialog.tsx
|
|
114
|
+
import React3 from "react";
|
|
115
|
+
import { Box as Box2, Text as Text3, useInput as useInput2 } from "ink";
|
|
116
|
+
init_config();
|
|
117
|
+
import { MultiSelect } from "@inkjs/ui";
|
|
118
|
+
import { partition } from "lodash-es";
|
|
119
|
+
|
|
120
|
+
// src/ui/components/MCPServerDialogCopy.tsx
|
|
121
|
+
init_product();
|
|
122
|
+
import React2 from "react";
|
|
123
|
+
import { Text as Text2 } from "ink";
|
|
124
|
+
import Link from "ink-link";
|
|
125
|
+
function MCPServerDialogCopy() {
|
|
126
|
+
return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, "MCP servers provide additional functionality to ", PRODUCT_NAME, ". They may execute code, make network requests, or access system resources via tool calls. All tool calls will require your explicit approval before execution. For more information, see", " ", /* @__PURE__ */ React2.createElement(Link, { url: "https://github.com/YOUR_USERNAME/newcraw/blob/main/docs/mcp.md" }, "MCP documentation")), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "Remember: You can always change these choices later by running `", PRODUCT_COMMAND, " mcp reset-project-choices`"));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/ui/components/MCPServerMultiselectDialog.tsx
|
|
130
|
+
function MCPServerMultiselectDialog({
|
|
131
|
+
serverNames,
|
|
132
|
+
onDone
|
|
133
|
+
}) {
|
|
134
|
+
const theme = getTheme();
|
|
135
|
+
function onSubmit(selectedServers) {
|
|
136
|
+
const config = getCurrentProjectConfig();
|
|
137
|
+
if (!config.approvedMcprcServers) {
|
|
138
|
+
config.approvedMcprcServers = [];
|
|
139
|
+
}
|
|
140
|
+
if (!config.rejectedMcprcServers) {
|
|
141
|
+
config.rejectedMcprcServers = [];
|
|
142
|
+
}
|
|
143
|
+
const [approvedServers, rejectedServers] = partition(
|
|
144
|
+
serverNames,
|
|
145
|
+
(server) => selectedServers.includes(server)
|
|
146
|
+
);
|
|
147
|
+
config.approvedMcprcServers.push(...approvedServers);
|
|
148
|
+
config.rejectedMcprcServers.push(...rejectedServers);
|
|
149
|
+
saveCurrentProjectConfig(config);
|
|
150
|
+
onDone();
|
|
151
|
+
}
|
|
152
|
+
const exitState = useExitOnCtrlCD(() => process.exit());
|
|
153
|
+
useInput2((_input, key) => {
|
|
154
|
+
if (key.escape) {
|
|
155
|
+
const config = getCurrentProjectConfig();
|
|
156
|
+
if (!config.rejectedMcprcServers) {
|
|
157
|
+
config.rejectedMcprcServers = [];
|
|
158
|
+
}
|
|
159
|
+
for (const server of serverNames) {
|
|
160
|
+
if (!config.rejectedMcprcServers.includes(server)) {
|
|
161
|
+
config.rejectedMcprcServers.push(server);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
saveCurrentProjectConfig(config);
|
|
165
|
+
onDone();
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
|
|
170
|
+
Box2,
|
|
171
|
+
{
|
|
172
|
+
flexDirection: "column",
|
|
173
|
+
gap: 1,
|
|
174
|
+
padding: 1,
|
|
175
|
+
borderStyle: "round",
|
|
176
|
+
borderColor: theme.warning
|
|
177
|
+
},
|
|
178
|
+
/* @__PURE__ */ React3.createElement(Text3, { bold: true, color: theme.warning }, "New MCP Servers Detected"),
|
|
179
|
+
/* @__PURE__ */ React3.createElement(Text3, null, "This project contains an MCP config file (.mcp.json or .mcprc) with", " ", serverNames.length, " MCP servers that require your approval."),
|
|
180
|
+
/* @__PURE__ */ React3.createElement(MCPServerDialogCopy, null),
|
|
181
|
+
/* @__PURE__ */ React3.createElement(Text3, null, "Please select the servers you want to enable:"),
|
|
182
|
+
/* @__PURE__ */ React3.createElement(
|
|
183
|
+
MultiSelect,
|
|
184
|
+
{
|
|
185
|
+
options: serverNames.map((server) => ({
|
|
186
|
+
label: server,
|
|
187
|
+
value: server
|
|
188
|
+
})),
|
|
189
|
+
defaultValue: serverNames,
|
|
190
|
+
onSubmit
|
|
191
|
+
}
|
|
192
|
+
)
|
|
193
|
+
), /* @__PURE__ */ React3.createElement(Box2, { marginLeft: 3 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, exitState.pending ? /* @__PURE__ */ React3.createElement(React3.Fragment, null, "Press ", exitState.keyName, " again to exit") : /* @__PURE__ */ React3.createElement(React3.Fragment, null, "Space to select \xB7 Enter to confirm \xB7 Esc to reject all"))));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/ui/components/MCPServerApprovalDialog.tsx
|
|
197
|
+
import React4 from "react";
|
|
198
|
+
import { Box as Box3, Text as Text4, useInput as useInput3 } from "ink";
|
|
199
|
+
init_config();
|
|
200
|
+
function MCPServerApprovalDialog({
|
|
201
|
+
serverName,
|
|
202
|
+
onDone
|
|
203
|
+
}) {
|
|
204
|
+
const theme = getTheme();
|
|
205
|
+
function onChange(value) {
|
|
206
|
+
const config = getCurrentProjectConfig();
|
|
207
|
+
switch (value) {
|
|
208
|
+
case "yes": {
|
|
209
|
+
if (!config.approvedMcprcServers) {
|
|
210
|
+
config.approvedMcprcServers = [];
|
|
211
|
+
}
|
|
212
|
+
if (!config.approvedMcprcServers.includes(serverName)) {
|
|
213
|
+
config.approvedMcprcServers.push(serverName);
|
|
214
|
+
}
|
|
215
|
+
saveCurrentProjectConfig(config);
|
|
216
|
+
onDone();
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
case "no": {
|
|
220
|
+
if (!config.rejectedMcprcServers) {
|
|
221
|
+
config.rejectedMcprcServers = [];
|
|
222
|
+
}
|
|
223
|
+
if (!config.rejectedMcprcServers.includes(serverName)) {
|
|
224
|
+
config.rejectedMcprcServers.push(serverName);
|
|
225
|
+
}
|
|
226
|
+
saveCurrentProjectConfig(config);
|
|
227
|
+
onDone();
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
const exitState = useExitOnCtrlCD(() => process.exit(0));
|
|
233
|
+
useInput3((_input, key) => {
|
|
234
|
+
if (key.escape) {
|
|
235
|
+
onDone();
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
|
|
240
|
+
Box3,
|
|
241
|
+
{
|
|
242
|
+
flexDirection: "column",
|
|
243
|
+
gap: 1,
|
|
244
|
+
padding: 1,
|
|
245
|
+
borderStyle: "round",
|
|
246
|
+
borderColor: theme.warning
|
|
247
|
+
},
|
|
248
|
+
/* @__PURE__ */ React4.createElement(Text4, { bold: true, color: theme.warning }, "New MCP Server Detected"),
|
|
249
|
+
/* @__PURE__ */ React4.createElement(Text4, null, "This project contains an MCP config file (.mcp.json or .mcprc) with an MCP server that requires your approval:"),
|
|
250
|
+
/* @__PURE__ */ React4.createElement(Text4, { bold: true }, serverName),
|
|
251
|
+
/* @__PURE__ */ React4.createElement(MCPServerDialogCopy, null),
|
|
252
|
+
/* @__PURE__ */ React4.createElement(Text4, null, "Do you want to approve this MCP server?"),
|
|
253
|
+
/* @__PURE__ */ React4.createElement(
|
|
254
|
+
Select,
|
|
255
|
+
{
|
|
256
|
+
options: [
|
|
257
|
+
{ label: "Yes, approve this server", value: "yes" },
|
|
258
|
+
{ label: "No, reject this server", value: "no" }
|
|
259
|
+
],
|
|
260
|
+
onChange: (value) => onChange(value)
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
), /* @__PURE__ */ React4.createElement(Box3, { marginLeft: 3 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, exitState.pending ? /* @__PURE__ */ React4.createElement(React4.Fragment, null, "Press ", exitState.keyName, " again to exit") : /* @__PURE__ */ React4.createElement(React4.Fragment, null, "Enter to confirm \xB7 Esc to reject"))));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// src/ui/screens/MCPServerApproval.tsx
|
|
267
|
+
init_config();
|
|
268
|
+
async function handleMcprcServerApprovals() {
|
|
269
|
+
const { servers } = getProjectMcpServerDefinitions();
|
|
270
|
+
const pendingServers = Object.keys(servers).filter(
|
|
271
|
+
(serverName) => getMcprcServerStatus(serverName) === "pending"
|
|
272
|
+
);
|
|
273
|
+
if (pendingServers.length === 0) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
await new Promise((resolve) => {
|
|
277
|
+
const clearScreenAndResolve = () => {
|
|
278
|
+
process.stdout.write("\x1B[2J\x1B[3J\x1B[H", () => {
|
|
279
|
+
resolve();
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
if (pendingServers.length === 1 && pendingServers[0] !== void 0) {
|
|
283
|
+
const result = render(
|
|
284
|
+
/* @__PURE__ */ React5.createElement(
|
|
285
|
+
MCPServerApprovalDialog,
|
|
286
|
+
{
|
|
287
|
+
serverName: pendingServers[0],
|
|
288
|
+
onDone: () => {
|
|
289
|
+
result.unmount?.();
|
|
290
|
+
clearScreenAndResolve();
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
),
|
|
294
|
+
{ exitOnCtrlC: false }
|
|
295
|
+
);
|
|
296
|
+
} else {
|
|
297
|
+
const result = render(
|
|
298
|
+
/* @__PURE__ */ React5.createElement(
|
|
299
|
+
MCPServerMultiselectDialog,
|
|
300
|
+
{
|
|
301
|
+
serverNames: pendingServers,
|
|
302
|
+
onDone: () => {
|
|
303
|
+
result.unmount?.();
|
|
304
|
+
clearScreenAndResolve();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
),
|
|
308
|
+
{ exitOnCtrlC: false }
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/entrypoints/cli/setupScreens.tsx
|
|
315
|
+
function completeOnboarding() {
|
|
316
|
+
const config = getGlobalConfig();
|
|
317
|
+
saveGlobalConfig({
|
|
318
|
+
...config,
|
|
319
|
+
hasCompletedOnboarding: true,
|
|
320
|
+
lastOnboardingVersion: MACRO.VERSION
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
async function showSetupScreens(safeMode, print) {
|
|
324
|
+
if (process.env.NODE_ENV === "test") {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
const config = getGlobalConfig();
|
|
328
|
+
if (!config.theme || !config.hasCompletedOnboarding) {
|
|
329
|
+
await clearTerminal();
|
|
330
|
+
const { render: render2 } = await import("ink");
|
|
331
|
+
await new Promise((resolve) => {
|
|
332
|
+
render2(
|
|
333
|
+
/* @__PURE__ */ React6.createElement(
|
|
334
|
+
Onboarding,
|
|
335
|
+
{
|
|
336
|
+
onDone: async () => {
|
|
337
|
+
completeOnboarding();
|
|
338
|
+
await clearTerminal();
|
|
339
|
+
resolve();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
),
|
|
343
|
+
{
|
|
344
|
+
exitOnCtrlC: false
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
if (!print) {
|
|
350
|
+
if (safeMode) {
|
|
351
|
+
if (!checkHasTrustDialogAccepted()) {
|
|
352
|
+
await new Promise((resolve) => {
|
|
353
|
+
const onDone = () => {
|
|
354
|
+
grantReadPermissionForOriginalDir();
|
|
355
|
+
resolve();
|
|
356
|
+
};
|
|
357
|
+
(async () => {
|
|
358
|
+
const { render: render2 } = await import("ink");
|
|
359
|
+
render2(/* @__PURE__ */ React6.createElement(TrustDialog, { onDone }), {
|
|
360
|
+
exitOnCtrlC: false
|
|
361
|
+
});
|
|
362
|
+
})();
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
await handleMcprcServerApprovals();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export {
|
|
371
|
+
showSetupScreens
|
|
372
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/entrypoints/cli/setupScreens.tsx", "../src/ui/components/TrustDialog.tsx", "../src/ui/screens/MCPServerApproval.tsx", "../src/ui/components/MCPServerMultiselectDialog.tsx", "../src/ui/components/MCPServerDialogCopy.tsx", "../src/ui/components/MCPServerApprovalDialog.tsx"],
|
|
4
|
+
"sourcesContent": ["import React from 'react'\r\n\r\nimport { MACRO } from '@constants/macros'\r\nimport { Onboarding } from '@components/Onboarding'\r\nimport { TrustDialog } from '@components/TrustDialog'\r\nimport {\r\n checkHasTrustDialogAccepted,\r\n getGlobalConfig,\r\n saveGlobalConfig,\r\n} from '@utils/config'\r\nimport { clearTerminal } from '@utils/terminal'\r\nimport { grantReadPermissionForOriginalDir } from '@utils/permissions/filesystem'\r\nimport { handleMcprcServerApprovals } from '@screens/MCPServerApproval'\r\n\r\nexport function completeOnboarding(): void {\r\n const config = getGlobalConfig()\r\n saveGlobalConfig({\r\n ...config,\r\n hasCompletedOnboarding: true,\r\n lastOnboardingVersion: MACRO.VERSION,\r\n })\r\n}\r\n\r\nexport async function showSetupScreens(\r\n safeMode?: boolean,\r\n print?: boolean,\r\n): Promise<void> {\r\n if (process.env.NODE_ENV === 'test') {\r\n return\r\n }\r\n\r\n const config = getGlobalConfig()\r\n if (!config.theme || !config.hasCompletedOnboarding) {\r\n await clearTerminal()\r\n const { render } = await import('ink')\r\n await new Promise<void>(resolve => {\r\n render(\r\n <Onboarding\r\n onDone={async () => {\r\n completeOnboarding()\r\n await clearTerminal()\r\n resolve()\r\n }}\r\n />,\r\n {\r\n exitOnCtrlC: false,\r\n },\r\n )\r\n })\r\n }\r\n\r\n if (!print) {\r\n if (safeMode) {\r\n if (!checkHasTrustDialogAccepted()) {\r\n await new Promise<void>(resolve => {\r\n const onDone = () => {\r\n grantReadPermissionForOriginalDir()\r\n resolve()\r\n }\r\n ;(async () => {\r\n const { render } = await import('ink')\r\n render(<TrustDialog onDone={onDone} />, {\r\n exitOnCtrlC: false,\r\n })\r\n })()\r\n })\r\n }\r\n }\r\n\r\n await handleMcprcServerApprovals()\r\n }\r\n}\r\n", "import React from 'react'\r\nimport { Box, Text, useInput } from 'ink'\r\nimport { getTheme } from '@utils/theme'\r\nimport { Select } from './custom-select/select'\r\nimport {\r\n saveCurrentProjectConfig,\r\n getCurrentProjectConfig,\r\n} from '@utils/config'\r\nimport { PRODUCT_NAME } from '@constants/product'\r\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\r\nimport { homedir } from 'os'\r\nimport { getCwd } from '@utils/state'\r\nimport Link from './Link'\r\n\r\ntype Props = {\r\n onDone(): void\r\n}\r\n\r\nexport function TrustDialog({ onDone }: Props): React.ReactNode {\r\n const theme = getTheme()\r\n React.useEffect(() => {}, [])\r\n\r\n function onChange(value: 'yes' | 'no') {\r\n const config = getCurrentProjectConfig()\r\n switch (value) {\r\n case 'yes': {\r\n const isHomeDir = homedir() === getCwd()\r\n\r\n if (!isHomeDir) {\r\n saveCurrentProjectConfig({\r\n ...config,\r\n hasTrustDialogAccepted: true,\r\n })\r\n }\r\n onDone()\r\n break\r\n }\r\n case 'no': {\r\n process.exit(1)\r\n break\r\n }\r\n }\r\n }\r\n\r\n const exitState = useExitOnCtrlCD(() => process.exit(0))\r\n\r\n useInput((_input, key) => {\r\n if (key.escape) {\r\n process.exit(0)\r\n return\r\n }\r\n })\r\n\r\n return (\r\n <>\r\n <Box\r\n flexDirection=\"column\"\r\n gap={1}\r\n padding={1}\r\n borderStyle=\"round\"\r\n borderColor={theme.warning}\r\n >\r\n <Text bold color={theme.warning}>\r\n Do you trust the files in this folder?\r\n </Text>\r\n <Text bold>{process.cwd()}</Text>\r\n\r\n <Box flexDirection=\"column\" gap={1}>\r\n <Text>\r\n {PRODUCT_NAME} may read files in this folder. Reading untrusted\r\n files may lead to {PRODUCT_NAME} to behave in an unexpected ways.\r\n </Text>\r\n <Text>\r\n With your permission {PRODUCT_NAME} may execute files in this\r\n folder. Executing untrusted code is unsafe.\r\n </Text>\r\n </Box>\r\n\r\n <Select\r\n options={[\r\n { label: 'Yes, proceed', value: 'yes' },\r\n { label: 'No, exit', value: 'no' },\r\n ]}\r\n onChange={value => onChange(value as 'yes' | 'no')}\r\n />\r\n </Box>\r\n <Box marginLeft={3}>\r\n <Text dimColor>\r\n {exitState.pending ? (\r\n <>Press {exitState.keyName} again to exit</>\r\n ) : (\r\n <>Enter to confirm \u00B7 Esc to exit</>\r\n )}\r\n </Text>\r\n </Box>\r\n </>\r\n )\r\n}\r\n", "import React from 'react'\r\nimport { render } from 'ink'\r\nimport { MCPServerMultiselectDialog } from '@components/MCPServerMultiselectDialog'\r\nimport { MCPServerApprovalDialog } from '@components/MCPServerApprovalDialog'\r\nimport { getMcprcServerStatus } from '@services/mcpClient'\r\nimport { getProjectMcpServerDefinitions } from '@utils/config'\r\n\r\nexport async function handleMcprcServerApprovals(): Promise<void> {\r\n const { servers } = getProjectMcpServerDefinitions()\r\n const pendingServers = Object.keys(servers).filter(\r\n serverName => getMcprcServerStatus(serverName) === 'pending',\r\n )\r\n\r\n if (pendingServers.length === 0) {\r\n return\r\n }\r\n\r\n await new Promise<void>(resolve => {\r\n const clearScreenAndResolve = () => {\r\n process.stdout.write('\\x1b[2J\\x1b[3J\\x1b[H', () => {\r\n resolve()\r\n })\r\n }\r\n\r\n if (pendingServers.length === 1 && pendingServers[0] !== undefined) {\r\n const result = render(\r\n <MCPServerApprovalDialog\r\n serverName={pendingServers[0]}\r\n onDone={() => {\r\n result.unmount?.()\r\n clearScreenAndResolve()\r\n }}\r\n />,\r\n { exitOnCtrlC: false },\r\n )\r\n } else {\r\n const result = render(\r\n <MCPServerMultiselectDialog\r\n serverNames={pendingServers}\r\n onDone={() => {\r\n result.unmount?.()\r\n clearScreenAndResolve()\r\n }}\r\n />,\r\n { exitOnCtrlC: false },\r\n )\r\n }\r\n })\r\n}\r\n\r\n", "import React from 'react'\r\nimport { Box, Text, useInput } from 'ink'\r\nimport { getTheme } from '@utils/theme'\r\nimport { MultiSelect } from '@inkjs/ui'\r\nimport {\r\n saveCurrentProjectConfig,\r\n getCurrentProjectConfig,\r\n} from '@utils/config'\r\nimport { partition } from 'lodash-es'\r\nimport { MCPServerDialogCopy } from './MCPServerDialogCopy'\r\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\r\n\r\ntype Props = {\r\n serverNames: string[]\r\n onDone(): void\r\n}\r\n\r\nexport function MCPServerMultiselectDialog({\r\n serverNames,\r\n onDone,\r\n}: Props): React.ReactNode {\r\n const theme = getTheme()\r\n function onSubmit(selectedServers: string[]) {\r\n const config = getCurrentProjectConfig()\r\n\r\n if (!config.approvedMcprcServers) {\r\n config.approvedMcprcServers = []\r\n }\r\n if (!config.rejectedMcprcServers) {\r\n config.rejectedMcprcServers = []\r\n }\r\n\r\n const [approvedServers, rejectedServers] = partition(serverNames, server =>\r\n selectedServers.includes(server),\r\n )\r\n\r\n config.approvedMcprcServers.push(...approvedServers)\r\n config.rejectedMcprcServers.push(...rejectedServers)\r\n\r\n saveCurrentProjectConfig(config)\r\n onDone()\r\n }\r\n\r\n const exitState = useExitOnCtrlCD(() => process.exit())\r\n\r\n useInput((_input, key) => {\r\n if (key.escape) {\r\n const config = getCurrentProjectConfig()\r\n if (!config.rejectedMcprcServers) {\r\n config.rejectedMcprcServers = []\r\n }\r\n\r\n for (const server of serverNames) {\r\n if (!config.rejectedMcprcServers.includes(server)) {\r\n config.rejectedMcprcServers.push(server)\r\n }\r\n }\r\n\r\n saveCurrentProjectConfig(config)\r\n onDone()\r\n return\r\n }\r\n })\r\n\r\n return (\r\n <>\r\n <Box\r\n flexDirection=\"column\"\r\n gap={1}\r\n padding={1}\r\n borderStyle=\"round\"\r\n borderColor={theme.warning}\r\n >\r\n <Text bold color={theme.warning}>\r\n New MCP Servers Detected\r\n </Text>\r\n <Text>\r\n This project contains an MCP config file (.mcp.json or .mcprc) with{' '}\r\n {serverNames.length} MCP servers that require your approval.\r\n </Text>\r\n <MCPServerDialogCopy />\r\n\r\n <Text>Please select the servers you want to enable:</Text>\r\n\r\n <MultiSelect\r\n options={serverNames.map(server => ({\r\n label: server,\r\n value: server,\r\n }))}\r\n defaultValue={serverNames}\r\n onSubmit={onSubmit}\r\n />\r\n </Box>\r\n <Box marginLeft={3}>\r\n <Text dimColor>\r\n {exitState.pending ? (\r\n <>Press {exitState.keyName} again to exit</>\r\n ) : (\r\n <>Space to select \u00B7 Enter to confirm \u00B7 Esc to reject all</>\r\n )}\r\n </Text>\r\n </Box>\r\n </>\r\n )\r\n}\r\n", "import React from 'react'\r\nimport { Text } from 'ink'\r\nimport Link from 'ink-link'\r\nimport { PRODUCT_NAME, PRODUCT_COMMAND } from '@constants/product'\r\n\r\nexport function MCPServerDialogCopy(): React.ReactNode {\r\n return (\r\n <>\r\n <Text>\r\n MCP servers provide additional functionality to {PRODUCT_NAME}. They may\r\n execute code, make network requests, or access system resources via tool\r\n calls. All tool calls will require your explicit approval before\r\n execution. For more information, see{' '}\r\n <Link url=\"https://github.com/YOUR_USERNAME/newcraw/blob/main/docs/mcp.md\">\r\n MCP documentation\r\n </Link>\r\n </Text>\r\n\r\n <Text dimColor>\r\n Remember: You can always change these choices later by running `\r\n {PRODUCT_COMMAND} mcp reset-project-choices`\r\n </Text>\r\n </>\r\n )\r\n}\r\n", "import React from 'react'\r\nimport { Box, Text, useInput } from 'ink'\r\nimport { getTheme } from '@utils/theme'\r\nimport { Select } from './custom-select/select'\r\nimport {\r\n saveCurrentProjectConfig,\r\n getCurrentProjectConfig,\r\n} from '@utils/config'\r\nimport { MCPServerDialogCopy } from './MCPServerDialogCopy'\r\nimport { useExitOnCtrlCD } from '@hooks/useExitOnCtrlCD'\r\n\r\ntype Props = {\r\n serverName: string\r\n onDone(): void\r\n}\r\n\r\nexport function MCPServerApprovalDialog({\r\n serverName,\r\n onDone,\r\n}: Props): React.ReactNode {\r\n const theme = getTheme()\r\n function onChange(value: 'yes' | 'no') {\r\n const config = getCurrentProjectConfig()\r\n switch (value) {\r\n case 'yes': {\r\n if (!config.approvedMcprcServers) {\r\n config.approvedMcprcServers = []\r\n }\r\n if (!config.approvedMcprcServers.includes(serverName)) {\r\n config.approvedMcprcServers.push(serverName)\r\n }\r\n saveCurrentProjectConfig(config)\r\n onDone()\r\n break\r\n }\r\n case 'no': {\r\n if (!config.rejectedMcprcServers) {\r\n config.rejectedMcprcServers = []\r\n }\r\n if (!config.rejectedMcprcServers.includes(serverName)) {\r\n config.rejectedMcprcServers.push(serverName)\r\n }\r\n saveCurrentProjectConfig(config)\r\n onDone()\r\n break\r\n }\r\n }\r\n }\r\n\r\n const exitState = useExitOnCtrlCD(() => process.exit(0))\r\n\r\n useInput((_input, key) => {\r\n if (key.escape) {\r\n onDone()\r\n return\r\n }\r\n })\r\n\r\n return (\r\n <>\r\n <Box\r\n flexDirection=\"column\"\r\n gap={1}\r\n padding={1}\r\n borderStyle=\"round\"\r\n borderColor={theme.warning}\r\n >\r\n <Text bold color={theme.warning}>\r\n New MCP Server Detected\r\n </Text>\r\n <Text>\r\n This project contains an MCP config file (.mcp.json or .mcprc) with an\r\n MCP server that requires your approval:\r\n </Text>\r\n <Text bold>{serverName}</Text>\r\n\r\n <MCPServerDialogCopy />\r\n\r\n <Text>Do you want to approve this MCP server?</Text>\r\n\r\n <Select\r\n options={[\r\n { label: 'Yes, approve this server', value: 'yes' },\r\n { label: 'No, reject this server', value: 'no' },\r\n ]}\r\n onChange={value => onChange(value as 'yes' | 'no')}\r\n />\r\n </Box>\r\n <Box marginLeft={3}>\r\n <Text dimColor>\r\n {exitState.pending ? (\r\n <>Press {exitState.keyName} again to exit</>\r\n ) : (\r\n <>Enter to confirm \u00B7 Esc to reject</>\r\n )}\r\n </Text>\r\n </Box>\r\n </>\r\n )\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["React", "React", "React", "Box", "Text", "useInput", "React", "Text", "useInput", "React", "Box", "Text", "React", "Box", "Text", "useInput", "useInput", "React", "Box", "Text", "React", "render", "React"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createRequire as __newcrawCreateRequire } from "node:module";
|
|
2
|
+
const require = __newcrawCreateRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
debug,
|
|
5
|
+
init_debugLogger
|
|
6
|
+
} from "./chunk-GZ4BEVMZ.js";
|
|
7
|
+
|
|
8
|
+
// src/services/ai/healthCheck.ts
|
|
9
|
+
init_debugLogger();
|
|
10
|
+
var healthRegistry = /* @__PURE__ */ new Map();
|
|
11
|
+
var HEALTH_CHECK_INTERVAL_MS = 6e4;
|
|
12
|
+
var FAILURE_THRESHOLD = 3;
|
|
13
|
+
var RECOVERY_CHECK_INTERVAL_MS = 3e4;
|
|
14
|
+
function getProviderHealth(provider) {
|
|
15
|
+
if (!healthRegistry.has(provider)) {
|
|
16
|
+
healthRegistry.set(provider, {
|
|
17
|
+
provider,
|
|
18
|
+
available: true,
|
|
19
|
+
lastCheckedAt: 0,
|
|
20
|
+
consecutiveFailures: 0
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return healthRegistry.get(provider);
|
|
24
|
+
}
|
|
25
|
+
function markProviderSuccess(provider, latencyMs) {
|
|
26
|
+
const health = getProviderHealth(provider);
|
|
27
|
+
health.available = true;
|
|
28
|
+
health.lastCheckedAt = Date.now();
|
|
29
|
+
health.consecutiveFailures = 0;
|
|
30
|
+
health.latencyMs = latencyMs;
|
|
31
|
+
debug.flow("PROVIDER_HEALTH_SUCCESS", {
|
|
32
|
+
provider,
|
|
33
|
+
latencyMs
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function markProviderFailure(provider, error) {
|
|
37
|
+
const health = getProviderHealth(provider);
|
|
38
|
+
health.consecutiveFailures++;
|
|
39
|
+
health.lastErrorAt = Date.now();
|
|
40
|
+
health.lastCheckedAt = Date.now();
|
|
41
|
+
if (health.consecutiveFailures >= FAILURE_THRESHOLD) {
|
|
42
|
+
health.available = false;
|
|
43
|
+
debug.warn("PROVIDER_MARKED_UNAVAILABLE", {
|
|
44
|
+
provider,
|
|
45
|
+
consecutiveFailures: health.consecutiveFailures,
|
|
46
|
+
error
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function isProviderAvailable(provider) {
|
|
51
|
+
const health = getProviderHealth(provider);
|
|
52
|
+
if (health.available) return true;
|
|
53
|
+
if (health.lastCheckedAt && Date.now() - health.lastCheckedAt > RECOVERY_CHECK_INTERVAL_MS) {
|
|
54
|
+
debug.flow("PROVIDER_RECOVERY_CHECK", { provider });
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
function shouldCheckHealth(provider) {
|
|
60
|
+
const health = getProviderHealth(provider);
|
|
61
|
+
return Date.now() - health.lastCheckedAt > HEALTH_CHECK_INTERVAL_MS;
|
|
62
|
+
}
|
|
63
|
+
function selectAvailableProvider(chain) {
|
|
64
|
+
if (isProviderAvailable(chain.primary)) {
|
|
65
|
+
return chain.primary;
|
|
66
|
+
}
|
|
67
|
+
for (const fallback of chain.fallbacks) {
|
|
68
|
+
if (isProviderAvailable(fallback)) {
|
|
69
|
+
debug.flow("PROVIDER_FAILOVER", {
|
|
70
|
+
from: chain.primary,
|
|
71
|
+
to: fallback
|
|
72
|
+
});
|
|
73
|
+
return fallback;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
debug.warn("ALL_PROVIDERS_UNAVAILABLE", {
|
|
77
|
+
primary: chain.primary,
|
|
78
|
+
fallbacks: chain.fallbacks
|
|
79
|
+
});
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
var probeInterval = null;
|
|
83
|
+
var registeredProbe = null;
|
|
84
|
+
var PROBE_INTERVAL_MS = 12e4;
|
|
85
|
+
function registerHealthProbe(probe) {
|
|
86
|
+
registeredProbe = probe;
|
|
87
|
+
}
|
|
88
|
+
function startPeriodicHealthCheck(providers) {
|
|
89
|
+
if (probeInterval) return;
|
|
90
|
+
probeInterval = setInterval(async () => {
|
|
91
|
+
if (!registeredProbe) return;
|
|
92
|
+
for (const provider of providers) {
|
|
93
|
+
const health = getProviderHealth(provider);
|
|
94
|
+
if (!health.available || shouldCheckHealth(provider)) {
|
|
95
|
+
try {
|
|
96
|
+
const ok = await registeredProbe(provider);
|
|
97
|
+
if (ok) {
|
|
98
|
+
markProviderSuccess(provider);
|
|
99
|
+
} else {
|
|
100
|
+
markProviderFailure(provider, "probe returned false");
|
|
101
|
+
}
|
|
102
|
+
} catch (err) {
|
|
103
|
+
markProviderFailure(
|
|
104
|
+
provider,
|
|
105
|
+
err instanceof Error ? err.message : String(err)
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}, PROBE_INTERVAL_MS);
|
|
111
|
+
if (probeInterval && typeof probeInterval === "object" && "unref" in probeInterval) {
|
|
112
|
+
probeInterval.unref();
|
|
113
|
+
}
|
|
114
|
+
debug.flow("HEALTH_PROBE_STARTED", {
|
|
115
|
+
providers,
|
|
116
|
+
intervalMs: PROBE_INTERVAL_MS
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
function stopPeriodicHealthCheck() {
|
|
120
|
+
if (probeInterval) {
|
|
121
|
+
clearInterval(probeInterval);
|
|
122
|
+
probeInterval = null;
|
|
123
|
+
debug.flow("HEALTH_PROBE_STOPPED", {});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export {
|
|
128
|
+
markProviderSuccess,
|
|
129
|
+
markProviderFailure,
|
|
130
|
+
isProviderAvailable,
|
|
131
|
+
selectAvailableProvider,
|
|
132
|
+
registerHealthProbe,
|
|
133
|
+
startPeriodicHealthCheck,
|
|
134
|
+
stopPeriodicHealthCheck
|
|
135
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/services/ai/healthCheck.ts"],
|
|
4
|
+
"sourcesContent": ["import { logError } from '@utils/log'\r\nimport { debug as debugLogger } from '@utils/log/debugLogger'\r\n\r\nexport interface ProviderHealth {\r\n provider: string\r\n available: boolean\r\n lastCheckedAt: number\r\n lastErrorAt?: number\r\n consecutiveFailures: number\r\n latencyMs?: number\r\n}\r\n\r\nconst healthRegistry = new Map<string, ProviderHealth>()\r\n\r\nconst HEALTH_CHECK_INTERVAL_MS = 60_000\r\nconst FAILURE_THRESHOLD = 3\r\nconst RECOVERY_CHECK_INTERVAL_MS = 30_000\r\n\r\nexport function getProviderHealth(provider: string): ProviderHealth {\r\n if (!healthRegistry.has(provider)) {\r\n healthRegistry.set(provider, {\r\n provider,\r\n available: true,\r\n lastCheckedAt: 0,\r\n consecutiveFailures: 0,\r\n })\r\n }\r\n return healthRegistry.get(provider)!\r\n}\r\n\r\nexport function markProviderSuccess(provider: string, latencyMs?: number): void {\r\n const health = getProviderHealth(provider)\r\n health.available = true\r\n health.lastCheckedAt = Date.now()\r\n health.consecutiveFailures = 0\r\n health.latencyMs = latencyMs\r\n\r\n debugLogger.flow('PROVIDER_HEALTH_SUCCESS', {\r\n provider,\r\n latencyMs,\r\n })\r\n}\r\n\r\nexport function markProviderFailure(provider: string, error?: string): void {\r\n const health = getProviderHealth(provider)\r\n health.consecutiveFailures++\r\n health.lastErrorAt = Date.now()\r\n health.lastCheckedAt = Date.now()\r\n\r\n if (health.consecutiveFailures >= FAILURE_THRESHOLD) {\r\n health.available = false\r\n debugLogger.warn('PROVIDER_MARKED_UNAVAILABLE', {\r\n provider,\r\n consecutiveFailures: health.consecutiveFailures,\r\n error,\r\n })\r\n }\r\n}\r\n\r\nexport function isProviderAvailable(provider: string): boolean {\r\n const health = getProviderHealth(provider)\r\n\r\n if (health.available) return true\r\n\r\n if (\r\n health.lastCheckedAt &&\r\n Date.now() - health.lastCheckedAt > RECOVERY_CHECK_INTERVAL_MS\r\n ) {\r\n debugLogger.flow('PROVIDER_RECOVERY_CHECK', { provider })\r\n return true\r\n }\r\n\r\n return false\r\n}\r\n\r\nexport function shouldCheckHealth(provider: string): boolean {\r\n const health = getProviderHealth(provider)\r\n return Date.now() - health.lastCheckedAt > HEALTH_CHECK_INTERVAL_MS\r\n}\r\n\r\nexport interface FallbackChain {\r\n primary: string\r\n fallbacks: string[]\r\n}\r\n\r\nexport function selectAvailableProvider(chain: FallbackChain): string | null {\r\n if (isProviderAvailable(chain.primary)) {\r\n return chain.primary\r\n }\r\n\r\n for (const fallback of chain.fallbacks) {\r\n if (isProviderAvailable(fallback)) {\r\n debugLogger.flow('PROVIDER_FAILOVER', {\r\n from: chain.primary,\r\n to: fallback,\r\n })\r\n return fallback\r\n }\r\n }\r\n\r\n debugLogger.warn('ALL_PROVIDERS_UNAVAILABLE', {\r\n primary: chain.primary,\r\n fallbacks: chain.fallbacks,\r\n })\r\n return null\r\n}\r\n\r\nexport function getAllProviderHealth(): ProviderHealth[] {\r\n return Array.from(healthRegistry.values())\r\n}\r\n\r\nexport function resetProviderHealth(provider: string): void {\r\n healthRegistry.delete(provider)\r\n}\r\n\r\nexport function resetAllHealth(): void {\r\n healthRegistry.clear()\r\n}\r\n\r\nexport type ProbeFunction = (provider: string) => Promise<boolean>\r\n\r\nlet probeInterval: ReturnType<typeof setInterval> | null = null\r\nlet registeredProbe: ProbeFunction | null = null\r\nconst PROBE_INTERVAL_MS = 120_000\r\n\r\nexport function registerHealthProbe(probe: ProbeFunction): void {\r\n registeredProbe = probe\r\n}\r\n\r\nexport function startPeriodicHealthCheck(providers: string[]): void {\r\n if (probeInterval) return\r\n\r\n probeInterval = setInterval(async () => {\r\n if (!registeredProbe) return\r\n\r\n for (const provider of providers) {\r\n const health = getProviderHealth(provider)\r\n if (!health.available || shouldCheckHealth(provider)) {\r\n try {\r\n const ok = await registeredProbe(provider)\r\n if (ok) {\r\n markProviderSuccess(provider)\r\n } else {\r\n markProviderFailure(provider, 'probe returned false')\r\n }\r\n } catch (err) {\r\n markProviderFailure(\r\n provider,\r\n err instanceof Error ? err.message : String(err),\r\n )\r\n }\r\n }\r\n }\r\n }, PROBE_INTERVAL_MS)\r\n\r\n if (probeInterval && typeof probeInterval === 'object' && 'unref' in probeInterval) {\r\n probeInterval.unref()\r\n }\r\n\r\n debugLogger.flow('HEALTH_PROBE_STARTED', {\r\n providers,\r\n intervalMs: PROBE_INTERVAL_MS,\r\n })\r\n}\r\n\r\nexport function stopPeriodicHealthCheck(): void {\r\n if (probeInterval) {\r\n clearInterval(probeInterval)\r\n probeInterval = null\r\n debugLogger.flow('HEALTH_PROBE_STOPPED', {})\r\n }\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|