dominds 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +157 -0
- package/README.md +250 -0
- package/README.zh.md +161 -0
- package/dist/access-control.js +253 -0
- package/dist/cli/create.js +263 -0
- package/dist/cli/read.js +84 -0
- package/dist/cli/tui.js +199 -0
- package/dist/cli/webui.js +169 -0
- package/dist/cli.js +227 -0
- package/dist/dialog-factory.js +53 -0
- package/dist/dialog-global-registry.js +68 -0
- package/dist/dialog-instance-registry.js +78 -0
- package/dist/dialog-run-state.js +198 -0
- package/dist/dialog.js +1024 -0
- package/dist/evt-registry.js +103 -0
- package/dist/index.js +8 -0
- package/dist/llm/client.js +69 -0
- package/dist/llm/defaults.yaml +386 -0
- package/dist/llm/driver.js +3214 -0
- package/dist/llm/gen/anthropic.js +611 -0
- package/dist/llm/gen/codex.js +375 -0
- package/dist/llm/gen/mock.js +326 -0
- package/dist/llm/gen/openai.js +470 -0
- package/dist/llm/gen/registry.js +26 -0
- package/dist/llm/gen.js +2 -0
- package/dist/llm/tools-projection.js +37 -0
- package/dist/log.js +228 -0
- package/dist/mcp/config.js +230 -0
- package/dist/mcp/sdk-client.js +129 -0
- package/dist/mcp/server-runtime.js +57 -0
- package/dist/mcp/stdio-client.js +280 -0
- package/dist/mcp/supervisor.js +979 -0
- package/dist/mcp/tool-names.js +109 -0
- package/dist/minds/builtin/cmdr/persona.md +3 -0
- package/dist/minds/builtin/dijiang/knowledge.md +287 -0
- package/dist/minds/builtin/dijiang/persona.md +7 -0
- package/dist/minds/builtin/fuxi/persona.en.md +59 -0
- package/dist/minds/builtin/fuxi/persona.zh.md +49 -0
- package/dist/minds/builtin/pangu/persona.en.md +78 -0
- package/dist/minds/builtin/pangu/persona.zh.md +71 -0
- package/dist/minds/load.js +617 -0
- package/dist/minds/minds-i18n.js +131 -0
- package/dist/minds/system-prompt.js +281 -0
- package/dist/persistence.js +3128 -0
- package/dist/problems.js +109 -0
- package/dist/server/api-routes.js +1031 -0
- package/dist/server/auth.js +180 -0
- package/dist/server/mime-types.js +32 -0
- package/dist/server/prompts-routes.js +543 -0
- package/dist/server/server-core.js +235 -0
- package/dist/server/setup-routes.js +697 -0
- package/dist/server/static-server.js +132 -0
- package/dist/server/websocket-handler.js +1011 -0
- package/dist/server.js +164 -0
- package/dist/shared/async-fifo-mutex.js +36 -0
- package/dist/shared/diligence.js +20 -0
- package/dist/shared/dotenv.js +144 -0
- package/dist/shared/evt.js +195 -0
- package/dist/shared/i18n/driver-messages.js +267 -0
- package/dist/shared/i18n/text.js +9 -0
- package/dist/shared/i18n/tool-result-messages.js +51 -0
- package/dist/shared/rtws-cli.js +73 -0
- package/dist/shared/runtime-language.js +47 -0
- package/dist/shared/team-mgmt-manual.js +116 -0
- package/dist/shared/types/context-health.js +2 -0
- package/dist/shared/types/dialog.js +11 -0
- package/dist/shared/types/i18n.js +2 -0
- package/dist/shared/types/index.js +26 -0
- package/dist/shared/types/language.js +40 -0
- package/dist/shared/types/problems.js +2 -0
- package/dist/shared/types/prompts.js +2 -0
- package/dist/shared/types/q4h.js +7 -0
- package/dist/shared/types/run-state.js +8 -0
- package/dist/shared/types/setup.js +2 -0
- package/dist/shared/types/storage.js +10 -0
- package/dist/shared/types/tellask.js +8 -0
- package/dist/shared/types/tools-registry.js +2 -0
- package/dist/shared/types/wire.js +12 -0
- package/dist/shared/utils/fmt.js +9 -0
- package/dist/shared/utils/html.js +20 -0
- package/dist/shared/utils/id.js +18 -0
- package/dist/shared/utils/inter-dialog-format.js +101 -0
- package/dist/shared/utils/time.js +13 -0
- package/dist/static/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/static/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/static/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/static/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/static/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/static/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/static/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/static/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/static/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/static/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/static/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/static/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/static/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/static/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/static/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/static/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/static/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/static/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/static/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/static/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/static/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/static/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/static/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/static/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/static/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/static/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/static/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/static/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/static/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/static/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/static/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/static/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/static/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/static/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/static/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/static/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/static/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/static/assets/_baseUniq-Crfl3d5Y.js +661 -0
- package/dist/static/assets/_baseUniq-Crfl3d5Y.js.map +1 -0
- package/dist/static/assets/arc-CbA_x9GD.js +132 -0
- package/dist/static/assets/arc-CbA_x9GD.js.map +1 -0
- package/dist/static/assets/architectureDiagram-VXUJARFQ-lcFS8ZQJ.js +8685 -0
- package/dist/static/assets/architectureDiagram-VXUJARFQ-lcFS8ZQJ.js.map +1 -0
- package/dist/static/assets/blockDiagram-VD42YOAC-B3Q36qRc.js +3608 -0
- package/dist/static/assets/blockDiagram-VD42YOAC-B3Q36qRc.js.map +1 -0
- package/dist/static/assets/c4Diagram-YG6GDRKO-Mt-aq3VH.js +2482 -0
- package/dist/static/assets/c4Diagram-YG6GDRKO-Mt-aq3VH.js.map +1 -0
- package/dist/static/assets/channel-BVr1Yke-.js +8 -0
- package/dist/static/assets/channel-BVr1Yke-.js.map +1 -0
- package/dist/static/assets/chunk-4BX2VUAB-qCIn5Iic.js +17 -0
- package/dist/static/assets/chunk-4BX2VUAB-qCIn5Iic.js.map +1 -0
- package/dist/static/assets/chunk-55IACEB6-q172NeCV.js +14 -0
- package/dist/static/assets/chunk-55IACEB6-q172NeCV.js.map +1 -0
- package/dist/static/assets/chunk-B4BG7PRW-CMJmtYzq.js +1827 -0
- package/dist/static/assets/chunk-B4BG7PRW-CMJmtYzq.js.map +1 -0
- package/dist/static/assets/chunk-DI55MBZ5-DiuwwZPL.js +1916 -0
- package/dist/static/assets/chunk-DI55MBZ5-DiuwwZPL.js.map +1 -0
- package/dist/static/assets/chunk-FMBD7UC4-06sqZTTn.js +20 -0
- package/dist/static/assets/chunk-FMBD7UC4-06sqZTTn.js.map +1 -0
- package/dist/static/assets/chunk-QN33PNHL-CnpBNkpP.js +25 -0
- package/dist/static/assets/chunk-QN33PNHL-CnpBNkpP.js.map +1 -0
- package/dist/static/assets/chunk-QZHKN3VN-CNgjMR-e.js +18 -0
- package/dist/static/assets/chunk-QZHKN3VN-CNgjMR-e.js.map +1 -0
- package/dist/static/assets/chunk-TZMSLE5B-BxtzW6--.js +109 -0
- package/dist/static/assets/chunk-TZMSLE5B-BxtzW6--.js.map +1 -0
- package/dist/static/assets/classDiagram-2ON5EDUG-29huvmn-.js +23 -0
- package/dist/static/assets/classDiagram-2ON5EDUG-29huvmn-.js.map +1 -0
- package/dist/static/assets/classDiagram-v2-WZHVMYZB-29huvmn-.js +23 -0
- package/dist/static/assets/classDiagram-v2-WZHVMYZB-29huvmn-.js.map +1 -0
- package/dist/static/assets/clone-D2OgLSSn.js +9 -0
- package/dist/static/assets/clone-D2OgLSSn.js.map +1 -0
- package/dist/static/assets/cose-bilkent-S5V4N54A-BNegDCxl.js +4943 -0
- package/dist/static/assets/cose-bilkent-S5V4N54A-BNegDCxl.js.map +1 -0
- package/dist/static/assets/cytoscape.esm-Bm8DJGmZ.js +30240 -0
- package/dist/static/assets/cytoscape.esm-Bm8DJGmZ.js.map +1 -0
- package/dist/static/assets/dagre-6UL2VRFP-f1XrTRSn.js +695 -0
- package/dist/static/assets/dagre-6UL2VRFP-f1XrTRSn.js.map +1 -0
- package/dist/static/assets/defaultLocale-DVr69WTU.js +207 -0
- package/dist/static/assets/defaultLocale-DVr69WTU.js.map +1 -0
- package/dist/static/assets/diagram-PSM6KHXK-8w1WbeDi.js +849 -0
- package/dist/static/assets/diagram-PSM6KHXK-8w1WbeDi.js.map +1 -0
- package/dist/static/assets/diagram-QEK2KX5R-CF4wtMmR.js +303 -0
- package/dist/static/assets/diagram-QEK2KX5R-CF4wtMmR.js.map +1 -0
- package/dist/static/assets/diagram-S2PKOQOG-8p3Avgn2.js +213 -0
- package/dist/static/assets/diagram-S2PKOQOG-8p3Avgn2.js.map +1 -0
- package/dist/static/assets/erDiagram-Q2GNP2WA-BMKLxlM9.js +1159 -0
- package/dist/static/assets/erDiagram-Q2GNP2WA-BMKLxlM9.js.map +1 -0
- package/dist/static/assets/favicon-Cmg5RbCj.svg +8 -0
- package/dist/static/assets/flowDiagram-NV44I4VS-CgEuPNK2.js +2332 -0
- package/dist/static/assets/flowDiagram-NV44I4VS-CgEuPNK2.js.map +1 -0
- package/dist/static/assets/ganttDiagram-JELNMOA3-bJkDCf-9.js +3681 -0
- package/dist/static/assets/ganttDiagram-JELNMOA3-bJkDCf-9.js.map +1 -0
- package/dist/static/assets/gitGraphDiagram-NY62KEGX-4QE9kesp.js +1206 -0
- package/dist/static/assets/gitGraphDiagram-NY62KEGX-4QE9kesp.js.map +1 -0
- package/dist/static/assets/graph-CS0Pmm7c.js +597 -0
- package/dist/static/assets/graph-CS0Pmm7c.js.map +1 -0
- package/dist/static/assets/index-BS6HnGzC.js +112303 -0
- package/dist/static/assets/index-BS6HnGzC.js.map +1 -0
- package/dist/static/assets/index-DaIsSzC_.css +483 -0
- package/dist/static/assets/infoDiagram-WHAUD3N6-ypBcKfUs.js +34 -0
- package/dist/static/assets/infoDiagram-WHAUD3N6-ypBcKfUs.js.map +1 -0
- package/dist/static/assets/init-ZxktEp_H.js +17 -0
- package/dist/static/assets/init-ZxktEp_H.js.map +1 -0
- package/dist/static/assets/journeyDiagram-XKPGCS4Q-QnrxDowJ.js +1255 -0
- package/dist/static/assets/journeyDiagram-XKPGCS4Q-QnrxDowJ.js.map +1 -0
- package/dist/static/assets/kanban-definition-3W4ZIXB7-CfvEc4z5.js +1048 -0
- package/dist/static/assets/kanban-definition-3W4ZIXB7-CfvEc4z5.js.map +1 -0
- package/dist/static/assets/layout-8TGxpm23.js +2218 -0
- package/dist/static/assets/layout-8TGxpm23.js.map +1 -0
- package/dist/static/assets/linear-BATBPQQv.js +341 -0
- package/dist/static/assets/linear-BATBPQQv.js.map +1 -0
- package/dist/static/assets/min-B3oVH3AC.js +42 -0
- package/dist/static/assets/min-B3oVH3AC.js.map +1 -0
- package/dist/static/assets/mindmap-definition-VGOIOE7T-L7VLwwF8.js +1127 -0
- package/dist/static/assets/mindmap-definition-VGOIOE7T-L7VLwwF8.js.map +1 -0
- package/dist/static/assets/ordinal-CxptdPJm.js +77 -0
- package/dist/static/assets/ordinal-CxptdPJm.js.map +1 -0
- package/dist/static/assets/pieDiagram-ADFJNKIX-CFW3zIhM.js +241 -0
- package/dist/static/assets/pieDiagram-ADFJNKIX-CFW3zIhM.js.map +1 -0
- package/dist/static/assets/quadrantDiagram-AYHSOK5B-B7ssen3E.js +1338 -0
- package/dist/static/assets/quadrantDiagram-AYHSOK5B-B7ssen3E.js.map +1 -0
- package/dist/static/assets/requirementDiagram-UZGBJVZJ-D0v5BArv.js +1162 -0
- package/dist/static/assets/requirementDiagram-UZGBJVZJ-D0v5BArv.js.map +1 -0
- package/dist/static/assets/sankeyDiagram-TZEHDZUN-B7slncJe.js +1195 -0
- package/dist/static/assets/sankeyDiagram-TZEHDZUN-B7slncJe.js.map +1 -0
- package/dist/static/assets/sequenceDiagram-WL72ISMW-oXU2lRh_.js +3875 -0
- package/dist/static/assets/sequenceDiagram-WL72ISMW-oXU2lRh_.js.map +1 -0
- package/dist/static/assets/stateDiagram-FKZM4ZOC-CFYsEd0x.js +452 -0
- package/dist/static/assets/stateDiagram-FKZM4ZOC-CFYsEd0x.js.map +1 -0
- package/dist/static/assets/stateDiagram-v2-4FDKWEC3-C0UWaNA7.js +22 -0
- package/dist/static/assets/stateDiagram-v2-4FDKWEC3-C0UWaNA7.js.map +1 -0
- package/dist/static/assets/timeline-definition-IT6M3QCI-C3KODUrh.js +1223 -0
- package/dist/static/assets/timeline-definition-IT6M3QCI-C3KODUrh.js.map +1 -0
- package/dist/static/assets/treemap-KMMF4GRG-DAGDLhj2.js +18753 -0
- package/dist/static/assets/treemap-KMMF4GRG-DAGDLhj2.js.map +1 -0
- package/dist/static/assets/xychartDiagram-PRI3JC2R-C0J9iwTO.js +1888 -0
- package/dist/static/assets/xychartDiagram-PRI3JC2R-C0J9iwTO.js.map +1 -0
- package/dist/static/index.html +71 -0
- package/dist/static/testing/dom-observation-utils.js +425 -0
- package/dist/static/testing/e2e-test-helper.js +3119 -0
- package/dist/team.js +1160 -0
- package/dist/tellask.js +431 -0
- package/dist/tool.js +150 -0
- package/dist/tools/apply-patch.js +542 -0
- package/dist/tools/builtins.js +196 -0
- package/dist/tools/context-health.js +177 -0
- package/dist/tools/ctrl.js +478 -0
- package/dist/tools/diag.js +583 -0
- package/dist/tools/env.js +184 -0
- package/dist/tools/fs.js +818 -0
- package/dist/tools/mcp.js +138 -0
- package/dist/tools/mem.js +349 -0
- package/dist/tools/os.js +751 -0
- package/dist/tools/prompts/team_mgmt.en.md +70 -0
- package/dist/tools/prompts/team_mgmt.zh.md +70 -0
- package/dist/tools/prompts/ws_mod.en.md +86 -0
- package/dist/tools/prompts/ws_mod.zh.md +87 -0
- package/dist/tools/registry-snapshot.js +31 -0
- package/dist/tools/registry.js +121 -0
- package/dist/tools/ripgrep.js +678 -0
- package/dist/tools/team-mgmt.js +3300 -0
- package/dist/tools/txt.js +3178 -0
- package/dist/utils/id.js +72 -0
- package/dist/utils/task-doc.js +236 -0
- package/dist/utils/task-package.js +522 -0
- package/dist/utils/taskdoc-search.js +280 -0
- package/dist/utils/taskdoc.js +400 -0
- package/package.json +69 -0
package/dist/log.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.log = exports.Logger = void 0;
|
|
4
|
+
exports.extractErrorDetails = extractErrorDetails;
|
|
5
|
+
exports.createLogger = createLogger;
|
|
6
|
+
/**
|
|
7
|
+
* Module: log
|
|
8
|
+
*
|
|
9
|
+
* Lightweight structured logger with levels and tags.
|
|
10
|
+
* - `Logger` formats records and prints to console
|
|
11
|
+
* - `log` default instance and `createLogger(tag)` helper
|
|
12
|
+
*/
|
|
13
|
+
const util_1 = require("util");
|
|
14
|
+
const levelPriority = {
|
|
15
|
+
debug: 10,
|
|
16
|
+
info: 20,
|
|
17
|
+
warn: 30,
|
|
18
|
+
error: 40,
|
|
19
|
+
};
|
|
20
|
+
function resolveDefaultLevel() {
|
|
21
|
+
const envLevel = (process.env.DOMINDS_LOG_LEVEL || '').toLowerCase();
|
|
22
|
+
if (envLevel && envLevel in levelPriority) {
|
|
23
|
+
return envLevel;
|
|
24
|
+
}
|
|
25
|
+
return process.env.NODE_ENV === 'dev' ? 'debug' : 'info';
|
|
26
|
+
}
|
|
27
|
+
function nowTsStr() {
|
|
28
|
+
const date = new Date();
|
|
29
|
+
const year = date.getFullYear();
|
|
30
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
31
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
32
|
+
const hour = String(date.getHours()).padStart(2, '0');
|
|
33
|
+
const minute = String(date.getMinutes()).padStart(2, '0');
|
|
34
|
+
const second = String(date.getSeconds()).padStart(2, '0');
|
|
35
|
+
return `${year}/${month}/${day}-${hour}:${minute}:${second}`;
|
|
36
|
+
}
|
|
37
|
+
function inspectValue(value) {
|
|
38
|
+
if (typeof value === 'string')
|
|
39
|
+
return value;
|
|
40
|
+
return (0, util_1.inspect)(value, { depth: 5, breakLength: 120, compact: false, sorted: true });
|
|
41
|
+
}
|
|
42
|
+
function extractErrorDetails(error) {
|
|
43
|
+
if (!error)
|
|
44
|
+
return {
|
|
45
|
+
message: `Strange error type='${typeof error}'`,
|
|
46
|
+
};
|
|
47
|
+
if (error instanceof Error) {
|
|
48
|
+
return {
|
|
49
|
+
name: error.name,
|
|
50
|
+
message: error.message,
|
|
51
|
+
stack: error.stack,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (typeof error === 'object' && error !== null) {
|
|
55
|
+
const maybeError = error;
|
|
56
|
+
const messageValue = maybeError.message;
|
|
57
|
+
return {
|
|
58
|
+
name: typeof maybeError.name === 'string' ? maybeError.name : undefined,
|
|
59
|
+
message: typeof messageValue === 'string'
|
|
60
|
+
? messageValue
|
|
61
|
+
: messageValue === undefined
|
|
62
|
+
? 'Error object has undefined message property'
|
|
63
|
+
: `Error object has non-string message property of type '${typeof messageValue}'`,
|
|
64
|
+
stack: typeof maybeError.stack === 'string' ? maybeError.stack : undefined,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
message: inspectValue(error),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function getCallerLocation(skipFrames = 0) {
|
|
72
|
+
const stack = new Error().stack;
|
|
73
|
+
if (!stack)
|
|
74
|
+
return undefined;
|
|
75
|
+
const lines = stack.split('\n');
|
|
76
|
+
// Skip the first few lines which are the error creation and our own logger methods
|
|
77
|
+
// skipFrames allows precise caller identification for different logger methods
|
|
78
|
+
for (let i = 3 + skipFrames; i < Math.min(lines.length, skipFrames + 10); i++) {
|
|
79
|
+
const line = lines[i];
|
|
80
|
+
const match = line.match(/at\s+(?:.*\s+)?\(?(.+?):(\d+):(\d+)\)?/);
|
|
81
|
+
if (match) {
|
|
82
|
+
const [, file, lineNum, column] = match;
|
|
83
|
+
// Skip internal Node.js, logger files, and utility functions
|
|
84
|
+
const skipPatterns = ['node:', 'inspect', 'formatLine', 'extractErrorDetails'];
|
|
85
|
+
const shouldSkip = skipPatterns.some((pattern) => file.includes(pattern));
|
|
86
|
+
if (!shouldSkip) {
|
|
87
|
+
return {
|
|
88
|
+
file: file,
|
|
89
|
+
line: parseInt(lineNum, 10),
|
|
90
|
+
column: parseInt(column, 10),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const pkgFilePathPrefix = (() => {
|
|
97
|
+
const loc = getCallerLocation(0);
|
|
98
|
+
if (loc?.file) {
|
|
99
|
+
for (const thisModuPart of ['/src/log.', '/log.']) {
|
|
100
|
+
const thisModuIdx = loc.file.lastIndexOf(thisModuPart);
|
|
101
|
+
if (thisModuIdx > 0) {
|
|
102
|
+
return loc.file.substring(0, thisModuIdx);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
})();
|
|
107
|
+
function stripPkgPrefix(file) {
|
|
108
|
+
if (pkgFilePathPrefix && file.startsWith(pkgFilePathPrefix)) {
|
|
109
|
+
return file.substring(pkgFilePathPrefix.length + 1); // +1 to remove the leading slash
|
|
110
|
+
}
|
|
111
|
+
return file;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Logger
|
|
115
|
+
*
|
|
116
|
+
* Structured console logger with level gating, tagging, and rich error/extra formatting.
|
|
117
|
+
* Levels: debug, info, warn, error.
|
|
118
|
+
*/
|
|
119
|
+
class Logger {
|
|
120
|
+
constructor(tag, level = resolveDefaultLevel()) {
|
|
121
|
+
this.tag = tag;
|
|
122
|
+
this.level = level;
|
|
123
|
+
}
|
|
124
|
+
setLevel(level) {
|
|
125
|
+
this.level = level;
|
|
126
|
+
}
|
|
127
|
+
shouldLog(level) {
|
|
128
|
+
return levelPriority[level] >= levelPriority[this.level];
|
|
129
|
+
}
|
|
130
|
+
formatRecord(level, message, error, extraData = []) {
|
|
131
|
+
const timestamp = nowTsStr();
|
|
132
|
+
const extraEntries = extraData.map((value) => inspectValue(value));
|
|
133
|
+
const record = {
|
|
134
|
+
timestamp,
|
|
135
|
+
level,
|
|
136
|
+
message,
|
|
137
|
+
};
|
|
138
|
+
if (this.tag) {
|
|
139
|
+
record.tag = this.tag;
|
|
140
|
+
}
|
|
141
|
+
// Include location info for debug level
|
|
142
|
+
if (this.level === 'debug') {
|
|
143
|
+
record.location = getCallerLocation(2);
|
|
144
|
+
}
|
|
145
|
+
if (error !== undefined && error !== null) {
|
|
146
|
+
record.error = extractErrorDetails(error);
|
|
147
|
+
}
|
|
148
|
+
if (extraEntries.length > 0) {
|
|
149
|
+
record.extra = extraEntries;
|
|
150
|
+
}
|
|
151
|
+
return record;
|
|
152
|
+
}
|
|
153
|
+
formatLine(record) {
|
|
154
|
+
let errorText = '';
|
|
155
|
+
if (record.error) {
|
|
156
|
+
const { name, message, stack } = record.error;
|
|
157
|
+
if (stack) {
|
|
158
|
+
// When an error object is passed, show only the stack trace to avoid duplication
|
|
159
|
+
// The log message should already contain the error description
|
|
160
|
+
errorText = `\n${stack}`;
|
|
161
|
+
}
|
|
162
|
+
else if (message) {
|
|
163
|
+
// Fallback for error objects without stack
|
|
164
|
+
if (name && message !== name) {
|
|
165
|
+
errorText = ` Error: ${name}: ${message}`;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
errorText = ` Error: ${message}`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
// Fallback to inspect for complex error objects
|
|
173
|
+
errorText = ` Error: ${inspectValue(record.error)}`;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
const extraText = record.extra && record.extra.length > 0
|
|
177
|
+
? ` Extra: ${record.extra.map((entry) => inspectValue(entry)).join('; ')}`
|
|
178
|
+
: '';
|
|
179
|
+
if (record.location) {
|
|
180
|
+
const prefix = `[${record.timestamp}] ${record.tag ? `[${record.tag}] ` : ''}${record.level.toUpperCase()}\n @ ${stripPkgPrefix(record.location.file)}:${record.location.line}:${record.location.column}`;
|
|
181
|
+
return `${prefix}\n${record.message}${errorText}${extraText}`;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
const prefix = `[${record.timestamp}] ${record.tag ? `[${record.tag}] ` : ''}${record.level.toUpperCase()}:`;
|
|
185
|
+
return `${prefix} ${record.message}${errorText}${extraText}`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
log(level, message, error, ...extraData) {
|
|
189
|
+
if (!this.shouldLog(level))
|
|
190
|
+
return;
|
|
191
|
+
const record = this.formatRecord(level, message, error, extraData);
|
|
192
|
+
const line = this.formatLine(record);
|
|
193
|
+
switch (level) {
|
|
194
|
+
case 'debug':
|
|
195
|
+
console.debug(line);
|
|
196
|
+
break;
|
|
197
|
+
case 'info':
|
|
198
|
+
console.info(line);
|
|
199
|
+
break;
|
|
200
|
+
case 'warn':
|
|
201
|
+
console.warn(line);
|
|
202
|
+
break;
|
|
203
|
+
case 'error':
|
|
204
|
+
console.error(line);
|
|
205
|
+
break;
|
|
206
|
+
default:
|
|
207
|
+
console.log(line);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
debug(message, error, ...extraData) {
|
|
212
|
+
this.log('debug', message, error, ...extraData);
|
|
213
|
+
}
|
|
214
|
+
info(message, error, ...extraData) {
|
|
215
|
+
this.log('info', message, error, ...extraData);
|
|
216
|
+
}
|
|
217
|
+
warn(message, error, ...extraData) {
|
|
218
|
+
this.log('warn', message, error, ...extraData);
|
|
219
|
+
}
|
|
220
|
+
error(message, error, ...extraData) {
|
|
221
|
+
this.log('error', message, error, ...extraData);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
exports.Logger = Logger;
|
|
225
|
+
exports.log = new Logger();
|
|
226
|
+
function createLogger(tag) {
|
|
227
|
+
return new Logger(tag);
|
|
228
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseMcpYaml = parseMcpYaml;
|
|
7
|
+
const yaml_1 = __importDefault(require("yaml"));
|
|
8
|
+
const log_1 = require("../log");
|
|
9
|
+
const log = (0, log_1.createLogger)('mcp/config');
|
|
10
|
+
/**
|
|
11
|
+
* NOTE: This loader parses external YAML (untrusted input). Runtime type checks are unavoidable
|
|
12
|
+
* here to keep the core code statically safe.
|
|
13
|
+
*/
|
|
14
|
+
function parseMcpYaml(rawText) {
|
|
15
|
+
const doc = yaml_1.default.parseDocument(rawText, { prettyErrors: true });
|
|
16
|
+
if (doc.errors.length > 0) {
|
|
17
|
+
const errText = doc.errors.map((e) => String(e)).join('\n');
|
|
18
|
+
return { ok: false, errorText: errText, rawText };
|
|
19
|
+
}
|
|
20
|
+
const parsed = doc.toJS();
|
|
21
|
+
try {
|
|
22
|
+
const res = parseWorkspaceConfig(parsed);
|
|
23
|
+
return {
|
|
24
|
+
ok: true,
|
|
25
|
+
config: res.config,
|
|
26
|
+
invalidServers: res.invalidServers,
|
|
27
|
+
serverIdsInYamlOrder: res.serverIdsInYamlOrder,
|
|
28
|
+
validServerIdsInYamlOrder: res.validServerIdsInYamlOrder,
|
|
29
|
+
rawText,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
return { ok: false, errorText: err instanceof Error ? err.message : String(err), rawText };
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function parseWorkspaceConfig(value) {
|
|
37
|
+
const root = asRecord(value, 'mcp.yaml root');
|
|
38
|
+
const version = root.version;
|
|
39
|
+
if (version !== 1) {
|
|
40
|
+
throw new Error(`Invalid mcp.yaml: expected version: 1`);
|
|
41
|
+
}
|
|
42
|
+
const serversVal = root.servers;
|
|
43
|
+
const serversRecord = serversVal === undefined ? {} : asRecord(serversVal, 'servers');
|
|
44
|
+
const servers = {};
|
|
45
|
+
const invalidServers = [];
|
|
46
|
+
const serverIdsInYamlOrder = [];
|
|
47
|
+
const validServerIdsInYamlOrder = [];
|
|
48
|
+
for (const [serverId, serverRaw] of Object.entries(serversRecord)) {
|
|
49
|
+
serverIdsInYamlOrder.push(serverId);
|
|
50
|
+
try {
|
|
51
|
+
servers[serverId] = parseServerConfig(serverId, serverRaw);
|
|
52
|
+
validServerIdsInYamlOrder.push(serverId);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
invalidServers.push({
|
|
56
|
+
serverId,
|
|
57
|
+
errorText: err instanceof Error ? err.message : String(err),
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
config: { version: 1, servers },
|
|
63
|
+
invalidServers,
|
|
64
|
+
serverIdsInYamlOrder,
|
|
65
|
+
validServerIdsInYamlOrder,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function parseServerConfig(serverId, value) {
|
|
69
|
+
const obj = asRecord(value, `servers.${serverId}`);
|
|
70
|
+
const truelyStatelessVal = obj['truely-stateless'];
|
|
71
|
+
const truelyStateless = truelyStatelessVal === undefined
|
|
72
|
+
? false
|
|
73
|
+
: typeof truelyStatelessVal === 'boolean'
|
|
74
|
+
? truelyStatelessVal
|
|
75
|
+
: (() => {
|
|
76
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.truely-stateless must be a boolean`);
|
|
77
|
+
})();
|
|
78
|
+
const transport = obj.transport;
|
|
79
|
+
if (transport !== 'stdio' && transport !== 'streamable_http') {
|
|
80
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.transport must be 'stdio' or 'streamable_http'`);
|
|
81
|
+
}
|
|
82
|
+
const toolsVal = obj.tools;
|
|
83
|
+
const toolsObj = toolsVal === undefined ? {} : asRecord(toolsVal, `servers.${serverId}.tools`);
|
|
84
|
+
const whitelist = parseStringArrayOptional(toolsObj.whitelist, `servers.${serverId}.tools.whitelist`);
|
|
85
|
+
const blacklist = parseStringArrayOptional(toolsObj.blacklist, `servers.${serverId}.tools.blacklist`);
|
|
86
|
+
const transformVal = obj.transform;
|
|
87
|
+
const transform = transformVal === undefined ? [] : parseTransformArray(transformVal, serverId);
|
|
88
|
+
if (transport === 'stdio') {
|
|
89
|
+
const command = obj.command;
|
|
90
|
+
if (typeof command !== 'string' || !command.trim()) {
|
|
91
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.command must be a non-empty string`);
|
|
92
|
+
}
|
|
93
|
+
const argsVal = obj.args;
|
|
94
|
+
const args = argsVal === undefined
|
|
95
|
+
? []
|
|
96
|
+
: Array.isArray(argsVal) && argsVal.every((a) => typeof a === 'string')
|
|
97
|
+
? argsVal
|
|
98
|
+
: (() => {
|
|
99
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.args must be string[]`);
|
|
100
|
+
})();
|
|
101
|
+
const envVal = obj.env;
|
|
102
|
+
const envRecord = envVal === undefined ? {} : asRecord(envVal, `servers.${serverId}.env`);
|
|
103
|
+
const env = {};
|
|
104
|
+
for (const [k, v] of Object.entries(envRecord)) {
|
|
105
|
+
if (typeof v === 'string') {
|
|
106
|
+
env[k] = { kind: 'literal', value: v };
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const mapped = asRecord(v, `servers.${serverId}.env.${k}`);
|
|
110
|
+
const fromEnv = mapped.env;
|
|
111
|
+
if (typeof fromEnv !== 'string' || !fromEnv.trim()) {
|
|
112
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.env.${k} must be a string or { env: 'NAME' }`);
|
|
113
|
+
}
|
|
114
|
+
env[k] = { kind: 'from_env', env: fromEnv };
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
serverId,
|
|
118
|
+
truelyStateless,
|
|
119
|
+
transport: 'stdio',
|
|
120
|
+
command,
|
|
121
|
+
args,
|
|
122
|
+
env,
|
|
123
|
+
tools: { whitelist, blacklist },
|
|
124
|
+
transform,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const url = obj.url;
|
|
128
|
+
if (typeof url !== 'string' || !url.trim()) {
|
|
129
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.url must be a non-empty string`);
|
|
130
|
+
}
|
|
131
|
+
const parsedUrl = safeParseUrl(url);
|
|
132
|
+
if (!parsedUrl) {
|
|
133
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.url must be a valid http(s) URL`);
|
|
134
|
+
}
|
|
135
|
+
const headersVal = obj.headers;
|
|
136
|
+
const headersRecord = headersVal === undefined ? {} : asRecord(headersVal, `servers.${serverId}.headers`);
|
|
137
|
+
const headers = {};
|
|
138
|
+
for (const [k, v] of Object.entries(headersRecord)) {
|
|
139
|
+
if (typeof v === 'string') {
|
|
140
|
+
headers[k] = { kind: 'literal', value: v };
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const mapped = asRecord(v, `servers.${serverId}.headers.${k}`);
|
|
144
|
+
const fromEnv = mapped.env;
|
|
145
|
+
if (typeof fromEnv !== 'string' || !fromEnv.trim()) {
|
|
146
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.headers.${k} must be a string or { env: 'NAME' }`);
|
|
147
|
+
}
|
|
148
|
+
headers[k] = { kind: 'from_env', env: fromEnv };
|
|
149
|
+
}
|
|
150
|
+
const sessionIdVal = obj.sessionId;
|
|
151
|
+
const sessionId = sessionIdVal === undefined
|
|
152
|
+
? undefined
|
|
153
|
+
: typeof sessionIdVal === 'string' && sessionIdVal.trim()
|
|
154
|
+
? sessionIdVal
|
|
155
|
+
: (() => {
|
|
156
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.sessionId must be a string`);
|
|
157
|
+
})();
|
|
158
|
+
return {
|
|
159
|
+
serverId,
|
|
160
|
+
truelyStateless,
|
|
161
|
+
transport: 'streamable_http',
|
|
162
|
+
url: parsedUrl.toString(),
|
|
163
|
+
headers,
|
|
164
|
+
sessionId,
|
|
165
|
+
tools: { whitelist, blacklist },
|
|
166
|
+
transform,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
function parseTransformArray(value, serverId) {
|
|
170
|
+
if (!Array.isArray(value)) {
|
|
171
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.transform must be an array`);
|
|
172
|
+
}
|
|
173
|
+
const out = [];
|
|
174
|
+
for (let i = 0; i < value.length; i++) {
|
|
175
|
+
const item = asRecord(value[i], `servers.${serverId}.transform[${i}]`);
|
|
176
|
+
if ('prefix' in item) {
|
|
177
|
+
const p = item.prefix;
|
|
178
|
+
if (typeof p === 'string') {
|
|
179
|
+
out.push({ kind: 'prefix_add', add: p });
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const po = asRecord(p, `servers.${serverId}.transform[${i}].prefix`);
|
|
183
|
+
const remove = po.remove;
|
|
184
|
+
const add = po.add;
|
|
185
|
+
if (typeof remove !== 'string' || typeof add !== 'string') {
|
|
186
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.transform[${i}].prefix must be string or { remove, add }`);
|
|
187
|
+
}
|
|
188
|
+
out.push({ kind: 'prefix_replace', remove, add });
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if ('suffix' in item) {
|
|
192
|
+
const s = item.suffix;
|
|
193
|
+
if (typeof s !== 'string') {
|
|
194
|
+
throw new Error(`Invalid mcp.yaml: servers.${serverId}.transform[${i}].suffix must be a string`);
|
|
195
|
+
}
|
|
196
|
+
out.push({ kind: 'suffix_add', add: s });
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
log.warn(`Unknown transform entry ignored in servers.${serverId}.transform[${i}]`);
|
|
200
|
+
}
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
function parseStringArrayOptional(value, pathLabel) {
|
|
204
|
+
if (value === undefined)
|
|
205
|
+
return [];
|
|
206
|
+
if (!Array.isArray(value) || !value.every((v) => typeof v === 'string')) {
|
|
207
|
+
throw new Error(`Invalid mcp.yaml: ${pathLabel} must be string[]`);
|
|
208
|
+
}
|
|
209
|
+
return value.filter((s) => s.trim().length > 0);
|
|
210
|
+
}
|
|
211
|
+
function asRecord(value, label) {
|
|
212
|
+
if (!isRecord(value) || Array.isArray(value)) {
|
|
213
|
+
throw new Error(`Invalid mcp.yaml: expected object at ${label}`);
|
|
214
|
+
}
|
|
215
|
+
return value;
|
|
216
|
+
}
|
|
217
|
+
function isRecord(value) {
|
|
218
|
+
return typeof value === 'object' && value !== null;
|
|
219
|
+
}
|
|
220
|
+
function safeParseUrl(value) {
|
|
221
|
+
try {
|
|
222
|
+
const u = new URL(value);
|
|
223
|
+
if (u.protocol !== 'http:' && u.protocol !== 'https:')
|
|
224
|
+
return undefined;
|
|
225
|
+
return u;
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpSdkClient = void 0;
|
|
4
|
+
const client_1 = require("@modelcontextprotocol/sdk/client");
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
6
|
+
const streamableHttp_js_1 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
7
|
+
const log_1 = require("../log");
|
|
8
|
+
const log = (0, log_1.createLogger)('mcp/sdk-client');
|
|
9
|
+
class McpSdkClient {
|
|
10
|
+
constructor(params) {
|
|
11
|
+
this.closed = false;
|
|
12
|
+
this.serverId = params.serverId;
|
|
13
|
+
this.client = params.client;
|
|
14
|
+
}
|
|
15
|
+
static async connectStdio(params) {
|
|
16
|
+
const transport = new stdio_js_1.StdioClientTransport({
|
|
17
|
+
command: params.command,
|
|
18
|
+
args: params.args,
|
|
19
|
+
env: params.env,
|
|
20
|
+
cwd: params.cwd,
|
|
21
|
+
stderr: 'pipe',
|
|
22
|
+
});
|
|
23
|
+
const stderr = transport.stderr;
|
|
24
|
+
if (stderr) {
|
|
25
|
+
stderr.on('data', (chunk) => {
|
|
26
|
+
const text = typeof chunk === 'string'
|
|
27
|
+
? chunk
|
|
28
|
+
: Buffer.isBuffer(chunk)
|
|
29
|
+
? chunk.toString('utf8')
|
|
30
|
+
: String(chunk);
|
|
31
|
+
const trimmed = text.trimEnd();
|
|
32
|
+
if (!trimmed)
|
|
33
|
+
return;
|
|
34
|
+
log.debug(`[${params.serverId}][stderr] ${trimmed}`);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return await McpSdkClient.connectWithTransport(params.serverId, transport);
|
|
38
|
+
}
|
|
39
|
+
static async connectStreamableHttp(params) {
|
|
40
|
+
const transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(params.url), {
|
|
41
|
+
requestInit: { headers: params.headers },
|
|
42
|
+
sessionId: params.sessionId,
|
|
43
|
+
});
|
|
44
|
+
return await McpSdkClient.connectWithTransport(params.serverId, transport);
|
|
45
|
+
}
|
|
46
|
+
static async connectWithTransport(serverId, transport) {
|
|
47
|
+
const client = new client_1.Client({ name: 'dominds', version: 'dev' }, {
|
|
48
|
+
capabilities: {},
|
|
49
|
+
});
|
|
50
|
+
await client.connect(transport, { timeout: 15000 });
|
|
51
|
+
return new McpSdkClient({ serverId, client });
|
|
52
|
+
}
|
|
53
|
+
async listTools(timeoutMs = 15000) {
|
|
54
|
+
this.ensureOpen();
|
|
55
|
+
const out = [];
|
|
56
|
+
let cursor;
|
|
57
|
+
for (let i = 0; i < 50; i++) {
|
|
58
|
+
const res = await this.client.listTools(cursor ? { cursor } : {}, { timeout: timeoutMs });
|
|
59
|
+
for (const t of res.tools) {
|
|
60
|
+
out.push({
|
|
61
|
+
name: t.name,
|
|
62
|
+
description: t.description,
|
|
63
|
+
inputSchema: t.inputSchema,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
cursor = res.nextCursor;
|
|
67
|
+
if (!cursor)
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
async callTool(mcpToolName, args, timeoutMs = 60000) {
|
|
73
|
+
this.ensureOpen();
|
|
74
|
+
const res = await this.client.callTool({ name: mcpToolName, arguments: args }, undefined, {
|
|
75
|
+
timeout: timeoutMs,
|
|
76
|
+
});
|
|
77
|
+
return stringifyToolCallResult(res);
|
|
78
|
+
}
|
|
79
|
+
async close() {
|
|
80
|
+
if (this.closed)
|
|
81
|
+
return;
|
|
82
|
+
this.closed = true;
|
|
83
|
+
try {
|
|
84
|
+
await this.client.close();
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
log.debug('MCP SDK client close failed', { serverId: this.serverId, err });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
ensureOpen() {
|
|
91
|
+
if (this.closed) {
|
|
92
|
+
throw new Error(`MCP client is closed (${this.serverId})`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
exports.McpSdkClient = McpSdkClient;
|
|
97
|
+
function stringifyToolCallResult(value) {
|
|
98
|
+
if (!isRecord(value) || Array.isArray(value)) {
|
|
99
|
+
return JSON.stringify(value);
|
|
100
|
+
}
|
|
101
|
+
if ('content' in value) {
|
|
102
|
+
const content = value.content;
|
|
103
|
+
if (!Array.isArray(content)) {
|
|
104
|
+
return JSON.stringify(value);
|
|
105
|
+
}
|
|
106
|
+
const parts = [];
|
|
107
|
+
for (const item of content) {
|
|
108
|
+
if (isRecord(item) && !Array.isArray(item)) {
|
|
109
|
+
const t = item.type;
|
|
110
|
+
if (t === 'text' && typeof item.text === 'string') {
|
|
111
|
+
parts.push(item.text);
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
parts.push(JSON.stringify(item));
|
|
116
|
+
}
|
|
117
|
+
const joined = parts.join('\n').trim();
|
|
118
|
+
if (joined)
|
|
119
|
+
return joined;
|
|
120
|
+
return JSON.stringify(value);
|
|
121
|
+
}
|
|
122
|
+
if ('toolResult' in value) {
|
|
123
|
+
return JSON.stringify(value.toolResult);
|
|
124
|
+
}
|
|
125
|
+
return JSON.stringify(value);
|
|
126
|
+
}
|
|
127
|
+
function isRecord(value) {
|
|
128
|
+
return typeof value === 'object' && value !== null;
|
|
129
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.McpServerRuntime = void 0;
|
|
4
|
+
const log_1 = require("../log");
|
|
5
|
+
const log = (0, log_1.createLogger)('mcp/server-runtime');
|
|
6
|
+
class McpServerRuntime {
|
|
7
|
+
constructor(params) {
|
|
8
|
+
this.inFlightCount = 0;
|
|
9
|
+
this.stopRequested = false;
|
|
10
|
+
this.closed = false;
|
|
11
|
+
this.serverId = params.serverId;
|
|
12
|
+
this.toolsetName = params.toolsetName;
|
|
13
|
+
this.client = params.client;
|
|
14
|
+
}
|
|
15
|
+
async callTool(mcpToolName, args) {
|
|
16
|
+
if (this.closed) {
|
|
17
|
+
throw new Error(`MCP server ${this.serverId} is closed`);
|
|
18
|
+
}
|
|
19
|
+
this.inFlightCount++;
|
|
20
|
+
try {
|
|
21
|
+
return await this.client.callTool(mcpToolName, args);
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
this.inFlightCount--;
|
|
25
|
+
if (this.stopRequested && this.inFlightCount <= 0) {
|
|
26
|
+
await this.closeNow();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
requestStop(params) {
|
|
31
|
+
if (this.stopRequested)
|
|
32
|
+
return;
|
|
33
|
+
this.stopRequested = true;
|
|
34
|
+
const forceKillAfterMs = params?.forceKillAfterMs ?? 30000;
|
|
35
|
+
if (this.inFlightCount <= 0) {
|
|
36
|
+
void this.closeNow();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (!this.forceKillTimer) {
|
|
40
|
+
this.forceKillTimer = setTimeout(() => {
|
|
41
|
+
log.warn(`Force-killing MCP server after timeout`, { serverId: this.serverId });
|
|
42
|
+
void this.closeNow();
|
|
43
|
+
}, forceKillAfterMs);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async closeNow() {
|
|
47
|
+
if (this.closed)
|
|
48
|
+
return;
|
|
49
|
+
this.closed = true;
|
|
50
|
+
if (this.forceKillTimer) {
|
|
51
|
+
clearTimeout(this.forceKillTimer);
|
|
52
|
+
this.forceKillTimer = undefined;
|
|
53
|
+
}
|
|
54
|
+
await this.client.close();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.McpServerRuntime = McpServerRuntime;
|