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
|
@@ -0,0 +1,1031 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.handleApiRoute = handleApiRoute;
|
|
40
|
+
/**
|
|
41
|
+
* Module: server/api-routes
|
|
42
|
+
*
|
|
43
|
+
* Common API route handlers for both production and development servers
|
|
44
|
+
*/
|
|
45
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const dialog_1 = require("../dialog");
|
|
48
|
+
const dialog_global_registry_1 = require("../dialog-global-registry");
|
|
49
|
+
const log_1 = require("../log");
|
|
50
|
+
const persistence_1 = require("../persistence");
|
|
51
|
+
const diligence_1 = require("../shared/diligence");
|
|
52
|
+
const runtime_language_1 = require("../shared/runtime-language");
|
|
53
|
+
const language_1 = require("../shared/types/language");
|
|
54
|
+
const time_1 = require("../shared/utils/time");
|
|
55
|
+
const team_1 = require("../team");
|
|
56
|
+
const registry_snapshot_1 = require("../tools/registry-snapshot");
|
|
57
|
+
const id_1 = require("../utils/id");
|
|
58
|
+
const task_package_1 = require("../utils/task-package");
|
|
59
|
+
const taskdoc_search_1 = require("../utils/taskdoc-search");
|
|
60
|
+
const prompts_routes_1 = require("./prompts-routes");
|
|
61
|
+
const setup_routes_1 = require("./setup-routes");
|
|
62
|
+
// Dialog lookup is performed via file-backed persistence; no in-memory registry
|
|
63
|
+
const log = (0, log_1.createLogger)('api-routes');
|
|
64
|
+
function getErrorCode(error) {
|
|
65
|
+
if (typeof error !== 'object' || error === null)
|
|
66
|
+
return undefined;
|
|
67
|
+
const maybe = error.code;
|
|
68
|
+
return typeof maybe === 'string' ? maybe : undefined;
|
|
69
|
+
}
|
|
70
|
+
function isRecord(value) {
|
|
71
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Handle API routes
|
|
75
|
+
*/
|
|
76
|
+
async function handleApiRoute(req, res, pathname, context) {
|
|
77
|
+
try {
|
|
78
|
+
// Health check endpoint
|
|
79
|
+
if (pathname === '/api/health' && req.method === 'GET') {
|
|
80
|
+
return await handleHealthCheck(res, context);
|
|
81
|
+
}
|
|
82
|
+
// Live reload endpoint for development
|
|
83
|
+
if (pathname === '/api/live-reload' && req.method === 'GET') {
|
|
84
|
+
return await handleLiveReload(res, context);
|
|
85
|
+
}
|
|
86
|
+
// Team configuration endpoint (renamed)
|
|
87
|
+
if (pathname === '/api/team/config' && req.method === 'GET') {
|
|
88
|
+
return await handleGetTeamConfig(res);
|
|
89
|
+
}
|
|
90
|
+
// Setup status endpoint (WebUI /setup)
|
|
91
|
+
if (pathname === '/api/setup/status' && req.method === 'GET') {
|
|
92
|
+
const payload = await (0, setup_routes_1.buildSetupStatusResponse)();
|
|
93
|
+
respondJson(res, 200, payload);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (pathname === '/api/setup/defaults-yaml' && req.method === 'GET') {
|
|
97
|
+
const payload = await (0, setup_routes_1.buildSetupFileResponse)('defaults_yaml');
|
|
98
|
+
respondJson(res, payload.success ? 200 : 404, payload);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
if (pathname === '/api/setup/workspace-llm-yaml' && req.method === 'GET') {
|
|
102
|
+
const payload = await (0, setup_routes_1.buildSetupFileResponse)('workspace_llm_yaml');
|
|
103
|
+
respondJson(res, payload.success ? 200 : 404, payload);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
// Setup: create/overwrite .minds/llm.yaml with raw YAML
|
|
107
|
+
if (pathname === '/api/setup/write-workspace-llm-yaml' && req.method === 'POST') {
|
|
108
|
+
const rawBody = await readRequestBody(req);
|
|
109
|
+
const result = await (0, setup_routes_1.handleWriteWorkspaceLlmYaml)(rawBody);
|
|
110
|
+
if (result.kind === 'ok') {
|
|
111
|
+
respondJson(res, 200, result.response);
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
if (result.kind === 'conflict') {
|
|
115
|
+
respondJson(res, 409, { success: false, path: result.path, error: result.errorText });
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
if (result.kind === 'bad_request') {
|
|
119
|
+
respondJson(res, 400, { success: false, path: result.path, error: result.errorText });
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
respondJson(res, 500, { success: false, path: result.path, error: result.errorText });
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
// Setup: write env vars to shell rc files
|
|
126
|
+
if (pathname === '/api/setup/write-shell-env' && req.method === 'POST') {
|
|
127
|
+
const rawBody = await readRequestBody(req);
|
|
128
|
+
const result = await (0, setup_routes_1.handleWriteShellEnv)(rawBody);
|
|
129
|
+
if (result.kind === 'ok') {
|
|
130
|
+
respondJson(res, 200, result.response);
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
if (result.kind === 'bad_request') {
|
|
134
|
+
respondJson(res, 400, { success: false, error: result.errorText });
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
respondJson(res, 500, { success: false, error: result.errorText });
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
// Setup: create/overwrite .minds/team.yaml with minimal member_defaults
|
|
141
|
+
if (pathname === '/api/setup/write-team-yaml' && req.method === 'POST') {
|
|
142
|
+
const rawBody = await readRequestBody(req);
|
|
143
|
+
const result = await (0, setup_routes_1.handleWriteTeamYaml)(rawBody);
|
|
144
|
+
if (result.kind === 'ok') {
|
|
145
|
+
respondJson(res, 200, result.response);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
if (result.kind === 'conflict') {
|
|
149
|
+
respondJson(res, 409, { success: false, path: result.path, error: result.errorText });
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
if (result.kind === 'bad_request') {
|
|
153
|
+
respondJson(res, 400, { success: false, path: result.path, error: result.errorText });
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
respondJson(res, 500, { success: false, path: result.path, error: result.errorText });
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
// Dialog list endpoint
|
|
160
|
+
if (pathname === '/api/dialogs' && req.method === 'GET') {
|
|
161
|
+
return await handleGetDialogs(res);
|
|
162
|
+
}
|
|
163
|
+
// Create dialog endpoint
|
|
164
|
+
if (pathname === '/api/dialogs' && req.method === 'POST') {
|
|
165
|
+
return await handleCreateDialog(req, res, context);
|
|
166
|
+
}
|
|
167
|
+
// Move dialogs between status directories (running/completed/archived)
|
|
168
|
+
if (pathname === '/api/dialogs/move' && req.method === 'POST') {
|
|
169
|
+
return await handleMoveDialogs(req, res, context);
|
|
170
|
+
}
|
|
171
|
+
// Delete a dialog (root dialogs only for now)
|
|
172
|
+
if (pathname.startsWith('/api/dialogs/') &&
|
|
173
|
+
!pathname.endsWith('/hierarchy') &&
|
|
174
|
+
req.method === 'DELETE') {
|
|
175
|
+
const parts = pathname.split('/');
|
|
176
|
+
const rawRoot = parts[3];
|
|
177
|
+
if (!rawRoot) {
|
|
178
|
+
respondJson(res, 400, { error: 'Missing root dialog id' });
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
const rawSelf = parts[4];
|
|
182
|
+
const rootId = rawRoot.replace(/%2F/g, '/');
|
|
183
|
+
const selfId = (rawSelf || rawRoot).replace(/%2F/g, '/');
|
|
184
|
+
return await handleDeleteDialog(res, { rootId, selfId }, context);
|
|
185
|
+
}
|
|
186
|
+
// Get full hierarchy for a single root dialog
|
|
187
|
+
if (pathname.startsWith('/api/dialogs/') &&
|
|
188
|
+
pathname.endsWith('/hierarchy') &&
|
|
189
|
+
req.method === 'GET') {
|
|
190
|
+
const parts = pathname.split('/');
|
|
191
|
+
const rootId = parts[3].replace(/%2F/g, '/');
|
|
192
|
+
return await handleGetDialogHierarchy(res, rootId);
|
|
193
|
+
}
|
|
194
|
+
// Get specific dialog
|
|
195
|
+
if (pathname.startsWith('/api/dialogs/') && req.method === 'GET') {
|
|
196
|
+
const parts = pathname.split('/');
|
|
197
|
+
const selfId = (parts[4] || parts[3]).replace(/%2F/g, '/');
|
|
198
|
+
const rootId = parts[3].replace(/%2F/g, '/');
|
|
199
|
+
const dialog = { selfId, rootId };
|
|
200
|
+
return await handleGetDialog(res, dialog);
|
|
201
|
+
}
|
|
202
|
+
// Task documents endpoint
|
|
203
|
+
if (pathname === '/api/task-documents' && req.method === 'GET') {
|
|
204
|
+
return await handleGetTaskDocuments(res);
|
|
205
|
+
}
|
|
206
|
+
// Tools registry endpoint (snapshot)
|
|
207
|
+
if (pathname === '/api/tools-registry' && req.method === 'GET') {
|
|
208
|
+
return await handleGetToolsRegistry(res);
|
|
209
|
+
}
|
|
210
|
+
// Read rtws diligence prompt (workspace file).
|
|
211
|
+
if (pathname === '/api/rtws/diligence' && req.method === 'GET') {
|
|
212
|
+
return await handleGetRtwsDiligence(req, res);
|
|
213
|
+
}
|
|
214
|
+
// Write rtws diligence prompt (workspace file).
|
|
215
|
+
if (pathname === '/api/rtws/diligence' && req.method === 'POST') {
|
|
216
|
+
return await handleWriteRtwsDiligence(req, res);
|
|
217
|
+
}
|
|
218
|
+
// Read Dominds docs markdown (from dominds install root, NOT rtws).
|
|
219
|
+
if (pathname === '/api/docs/read' && req.method === 'GET') {
|
|
220
|
+
return await handleReadDocsMarkdown(req, res);
|
|
221
|
+
}
|
|
222
|
+
if (pathname === '/api/prompts/builtin' && req.method === 'GET') {
|
|
223
|
+
const payload = await (0, prompts_routes_1.handleGetBuiltinPrompts)();
|
|
224
|
+
respondJson(res, payload.success ? 200 : 500, payload);
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
if (pathname === '/api/prompts/workspace' && req.method === 'GET') {
|
|
228
|
+
const payload = await (0, prompts_routes_1.handleGetWorkspacePrompts)();
|
|
229
|
+
respondJson(res, payload.success ? 200 : 500, payload);
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
if (pathname === '/api/prompts/catalog' && req.method === 'GET') {
|
|
233
|
+
const payload = await (0, prompts_routes_1.handleGetPromptCatalog)();
|
|
234
|
+
respondJson(res, payload.success ? 200 : 500, payload);
|
|
235
|
+
return true;
|
|
236
|
+
}
|
|
237
|
+
if (pathname === '/api/prompts/workspace' && req.method === 'POST') {
|
|
238
|
+
const rawBody = await readRequestBody(req);
|
|
239
|
+
const payload = await (0, prompts_routes_1.handleSaveWorkspacePrompt)(rawBody);
|
|
240
|
+
respondJson(res, payload.success ? 200 : 400, payload);
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
if (pathname === '/api/team-mgmt/manual' && req.method === 'POST') {
|
|
244
|
+
const rawBody = await readRequestBody(req);
|
|
245
|
+
const payload = await (0, prompts_routes_1.handleTeamMgmtManual)(rawBody);
|
|
246
|
+
respondJson(res, payload.success ? 200 : 400, payload);
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
return false; // Route not handled
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
log.error('Error handling API route:', error);
|
|
253
|
+
respondJson(res, 500, { error: 'Internal server error' });
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function resolveRtwsDiligencePath(lang) {
|
|
258
|
+
const parsed = typeof lang === 'string' ? (0, language_1.normalizeLanguageCode)(lang) : null;
|
|
259
|
+
if (parsed === 'zh')
|
|
260
|
+
return path.resolve(process.cwd(), '.minds', 'diligence.zh.md');
|
|
261
|
+
if (parsed === 'en')
|
|
262
|
+
return path.resolve(process.cwd(), '.minds', 'diligence.en.md');
|
|
263
|
+
return path.resolve(process.cwd(), '.minds', 'diligence.md');
|
|
264
|
+
}
|
|
265
|
+
async function handleGetRtwsDiligence(req, res) {
|
|
266
|
+
const urlObj = new URL(req.url ?? '', 'http://127.0.0.1');
|
|
267
|
+
const lang = urlObj.searchParams.get('lang');
|
|
268
|
+
const primaryPath = resolveRtwsDiligencePath(lang);
|
|
269
|
+
const genericPath = path.resolve(process.cwd(), '.minds', 'diligence.md');
|
|
270
|
+
const candidates = [primaryPath, genericPath];
|
|
271
|
+
for (const filePath of candidates) {
|
|
272
|
+
try {
|
|
273
|
+
const raw = await promises_1.default.readFile(filePath, 'utf-8');
|
|
274
|
+
respondJson(res, 200, { success: true, path: filePath, raw, source: 'workspace' });
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
if (getErrorCode(error) === 'ENOENT') {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
log.error('Failed to read diligence file', error);
|
|
282
|
+
respondJson(res, 500, { success: false, error: 'Failed to read diligence file' });
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const fallbackLang = typeof lang === 'string' ? (0, language_1.normalizeLanguageCode)(lang) : null;
|
|
287
|
+
const wl = fallbackLang ?? (0, runtime_language_1.getWorkLanguage)();
|
|
288
|
+
respondJson(res, 200, {
|
|
289
|
+
success: true,
|
|
290
|
+
path: primaryPath,
|
|
291
|
+
raw: diligence_1.DILIGENCE_FALLBACK_TEXT[wl],
|
|
292
|
+
source: 'builtin',
|
|
293
|
+
});
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
async function handleWriteRtwsDiligence(req, res) {
|
|
297
|
+
const urlObj = new URL(req.url ?? '', 'http://127.0.0.1');
|
|
298
|
+
const lang = urlObj.searchParams.get('lang');
|
|
299
|
+
const overwrite = urlObj.searchParams.get('overwrite');
|
|
300
|
+
const overwriteBool = overwrite === '1' || overwrite === 'true';
|
|
301
|
+
const filePath = resolveRtwsDiligencePath(lang);
|
|
302
|
+
let parsed;
|
|
303
|
+
try {
|
|
304
|
+
const rawBody = await readRequestBody(req);
|
|
305
|
+
parsed = rawBody ? JSON.parse(rawBody) : {};
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
respondJson(res, 400, { success: false, error: 'Invalid JSON' });
|
|
309
|
+
return true;
|
|
310
|
+
}
|
|
311
|
+
if (!isRecord(parsed) || typeof parsed.raw !== 'string') {
|
|
312
|
+
respondJson(res, 400, { success: false, error: 'Body must be { raw: string }' });
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
const existing = await promises_1.default.readFile(filePath, 'utf-8').then(() => true, (e) => (getErrorCode(e) === 'ENOENT' ? false : Promise.reject(e)));
|
|
317
|
+
if (existing && !overwriteBool) {
|
|
318
|
+
respondJson(res, 409, {
|
|
319
|
+
success: false,
|
|
320
|
+
path: filePath,
|
|
321
|
+
error: 'File exists; retry with overwrite=1 to confirm overwrite',
|
|
322
|
+
});
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
await promises_1.default.mkdir(path.dirname(filePath), { recursive: true });
|
|
326
|
+
await promises_1.default.writeFile(filePath, parsed.raw, 'utf-8');
|
|
327
|
+
respondJson(res, 200, { success: true, path: filePath });
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
log.error('Failed to write diligence file', error);
|
|
332
|
+
respondJson(res, 500, { success: false, error: 'Failed to write diligence file' });
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const DOCS_WHITELIST = new Set([
|
|
337
|
+
'design',
|
|
338
|
+
'dialog-system',
|
|
339
|
+
'keep-going',
|
|
340
|
+
'auth',
|
|
341
|
+
'dominds-terminology',
|
|
342
|
+
'cli-usage',
|
|
343
|
+
'mottos',
|
|
344
|
+
'encapsulated-taskdoc',
|
|
345
|
+
'memory-system',
|
|
346
|
+
'mcp-support',
|
|
347
|
+
'context-health',
|
|
348
|
+
'OEC-philosophy',
|
|
349
|
+
'design.md',
|
|
350
|
+
'dialog-system.md',
|
|
351
|
+
'keep-going.md',
|
|
352
|
+
'auth.md',
|
|
353
|
+
'dominds-terminology.md',
|
|
354
|
+
'cli-usage.md',
|
|
355
|
+
'mottos.md',
|
|
356
|
+
'encapsulated-taskdoc.md',
|
|
357
|
+
'memory-system.md',
|
|
358
|
+
'mcp-support.md',
|
|
359
|
+
'context-health.md',
|
|
360
|
+
'OEC-philosophy.md',
|
|
361
|
+
]);
|
|
362
|
+
async function handleReadDocsMarkdown(req, res) {
|
|
363
|
+
const urlObj = new URL(req.url ?? '', 'http://127.0.0.1');
|
|
364
|
+
const name = urlObj.searchParams.get('name');
|
|
365
|
+
const lang = urlObj.searchParams.get('lang');
|
|
366
|
+
const parsedLang = typeof lang === 'string' ? (0, language_1.normalizeLanguageCode)(lang) : null;
|
|
367
|
+
if (typeof name !== 'string' || name.trim() === '') {
|
|
368
|
+
respondJson(res, 400, { success: false, error: 'Missing name' });
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
if (!DOCS_WHITELIST.has(name)) {
|
|
372
|
+
respondJson(res, 403, { success: false, error: `Unsupported doc name: ${name}` });
|
|
373
|
+
return true;
|
|
374
|
+
}
|
|
375
|
+
const serverRoot = path.resolve(__dirname, '..', '..');
|
|
376
|
+
const docsDir = path.resolve(serverRoot, 'docs');
|
|
377
|
+
const ext = '.md';
|
|
378
|
+
const stem = name.endsWith(ext) ? name.slice(0, -ext.length) : name;
|
|
379
|
+
const basePath = path.resolve(docsDir, `${stem}${ext}`);
|
|
380
|
+
const candidateLocalized = parsedLang === null ? null : path.resolve(docsDir, `${stem}.${parsedLang}${ext}`);
|
|
381
|
+
const candidates = candidateLocalized ? [candidateLocalized, basePath] : [basePath];
|
|
382
|
+
for (const filePath of candidates) {
|
|
383
|
+
try {
|
|
384
|
+
const raw = await promises_1.default.readFile(filePath, 'utf-8');
|
|
385
|
+
respondJson(res, 200, { success: true, name: stem, path: filePath, raw });
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
catch (error) {
|
|
389
|
+
if (getErrorCode(error) === 'ENOENT') {
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
log.error('Failed to read docs file', error);
|
|
393
|
+
respondJson(res, 500, { success: false, error: 'Failed to read docs file' });
|
|
394
|
+
return true;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
respondJson(res, 404, { success: false, error: 'Doc not found' });
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
async function handleGetToolsRegistry(res) {
|
|
401
|
+
try {
|
|
402
|
+
const snapshot = (0, registry_snapshot_1.createToolsRegistrySnapshot)();
|
|
403
|
+
res.writeHead(200, {
|
|
404
|
+
'Content-Type': 'application/json',
|
|
405
|
+
'Cache-Control': 'no-store',
|
|
406
|
+
});
|
|
407
|
+
res.end(JSON.stringify({
|
|
408
|
+
success: true,
|
|
409
|
+
toolsets: snapshot.toolsets,
|
|
410
|
+
timestamp: snapshot.timestamp,
|
|
411
|
+
}));
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
log.error('Error getting tools registry snapshot:', error);
|
|
416
|
+
res.writeHead(500, {
|
|
417
|
+
'Content-Type': 'application/json',
|
|
418
|
+
'Cache-Control': 'no-store',
|
|
419
|
+
});
|
|
420
|
+
res.end(JSON.stringify({ success: false, error: 'Failed to get tools registry' }));
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Health check endpoint
|
|
426
|
+
*/
|
|
427
|
+
async function handleHealthCheck(res, context) {
|
|
428
|
+
try {
|
|
429
|
+
const healthData = {
|
|
430
|
+
ok: true,
|
|
431
|
+
timestamp: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
432
|
+
server: 'dominds',
|
|
433
|
+
version: '1.0.0',
|
|
434
|
+
workspace: process.cwd(),
|
|
435
|
+
mode: context.mode,
|
|
436
|
+
};
|
|
437
|
+
respondJson(res, 200, healthData);
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
log.error('Health check failed:', error);
|
|
442
|
+
respondJson(res, 500, { ok: false, error: 'Health check failed' });
|
|
443
|
+
return true;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Live reload endpoint for development
|
|
448
|
+
*/
|
|
449
|
+
async function handleLiveReload(res, context) {
|
|
450
|
+
try {
|
|
451
|
+
respondJson(res, 200, {
|
|
452
|
+
success: true,
|
|
453
|
+
message: 'Live reload endpoint active',
|
|
454
|
+
timestamp: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
455
|
+
mode: context.mode,
|
|
456
|
+
});
|
|
457
|
+
return true;
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
log.error('Live reload failed:', error);
|
|
461
|
+
respondJson(res, 500, { success: false, error: 'Live reload failed' });
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* Team configuration endpoint
|
|
467
|
+
* Returns full team configuration with member defaults, default responder,
|
|
468
|
+
* and raw members record. Frontend will attach prototypes for defaults.
|
|
469
|
+
*/
|
|
470
|
+
async function handleGetTeamConfig(res) {
|
|
471
|
+
try {
|
|
472
|
+
const team = await team_1.Team.load();
|
|
473
|
+
// Convert Team.Member instances to plain frontend objects without prototypes
|
|
474
|
+
const toFrontendMember = (m) => ({
|
|
475
|
+
id: m.id,
|
|
476
|
+
name: m.name,
|
|
477
|
+
provider: m.provider,
|
|
478
|
+
model: m.model,
|
|
479
|
+
gofor: m.gofor,
|
|
480
|
+
toolsets: m.toolsets,
|
|
481
|
+
tools: m.tools,
|
|
482
|
+
icon: m.icon,
|
|
483
|
+
streaming: m.streaming,
|
|
484
|
+
hidden: m.hidden,
|
|
485
|
+
});
|
|
486
|
+
const memberDefaults = toFrontendMember(team.memberDefaults);
|
|
487
|
+
const members = {};
|
|
488
|
+
for (const [id, member] of Object.entries(team.members)) {
|
|
489
|
+
members[id] = toFrontendMember(member);
|
|
490
|
+
}
|
|
491
|
+
const def = team.getDefaultResponder();
|
|
492
|
+
respondJson(res, 200, {
|
|
493
|
+
configuration: {
|
|
494
|
+
memberDefaults,
|
|
495
|
+
defaultResponder: def ? def.id : undefined,
|
|
496
|
+
members,
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
return true;
|
|
500
|
+
}
|
|
501
|
+
catch (error) {
|
|
502
|
+
log.error('Error getting team configuration:', error);
|
|
503
|
+
respondJson(res, 500, { success: false, error: 'Failed to get team configuration' });
|
|
504
|
+
return true;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Get dialog list - returns root dialogs with subdialogCount
|
|
509
|
+
*/
|
|
510
|
+
async function handleGetDialogs(res) {
|
|
511
|
+
try {
|
|
512
|
+
const statuses = ['running', 'completed', 'archived'];
|
|
513
|
+
const rootDialogs = [];
|
|
514
|
+
for (const status of statuses) {
|
|
515
|
+
const ids = await persistence_1.DialogPersistence.listDialogs(status);
|
|
516
|
+
for (const id of ids) {
|
|
517
|
+
const meta = await persistence_1.DialogPersistence.loadRootDialogMetadata(new dialog_1.DialogID(id), status);
|
|
518
|
+
if (!meta)
|
|
519
|
+
continue;
|
|
520
|
+
// Load latest.yaml for currentRound and lastModified timestamp
|
|
521
|
+
const latest = await persistence_1.DialogPersistence.loadDialogLatest(new dialog_1.DialogID(id), status);
|
|
522
|
+
// Count subdialogs for this root dialog
|
|
523
|
+
const rootPath = persistence_1.DialogPersistence.getRootDialogPath(new dialog_1.DialogID(id), status);
|
|
524
|
+
const subPath = path.join(rootPath, 'subdialogs');
|
|
525
|
+
const subdialogCount = await countSubdialogs(subPath);
|
|
526
|
+
rootDialogs.push({
|
|
527
|
+
rootId: meta.id,
|
|
528
|
+
agentId: meta.agentId,
|
|
529
|
+
taskDocPath: meta.taskDocPath,
|
|
530
|
+
status,
|
|
531
|
+
currentRound: latest?.currentRound || 1,
|
|
532
|
+
createdAt: meta.createdAt,
|
|
533
|
+
lastModified: latest?.lastModified || meta.createdAt,
|
|
534
|
+
runState: latest?.runState,
|
|
535
|
+
subdialogCount,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
respondJson(res, 200, { success: true, dialogs: rootDialogs });
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
catch (error) {
|
|
543
|
+
log.error('Error getting root dialogs:', error);
|
|
544
|
+
respondJson(res, 500, { success: false, error: 'Failed to get root dialogs' });
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Count subdialog directories recursively
|
|
550
|
+
*/
|
|
551
|
+
async function countSubdialogs(dirPath) {
|
|
552
|
+
try {
|
|
553
|
+
const entries = await promises_1.default.readdir(dirPath, { withFileTypes: true });
|
|
554
|
+
let count = 0;
|
|
555
|
+
for (const entry of entries) {
|
|
556
|
+
if (entry.isDirectory()) {
|
|
557
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
558
|
+
const dialogYamlPath = path.join(fullPath, 'dialog.yaml');
|
|
559
|
+
try {
|
|
560
|
+
await promises_1.default.access(dialogYamlPath);
|
|
561
|
+
// This directory contains dialog.yaml - it's a subdialog
|
|
562
|
+
count++;
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
// No dialog.yaml - recurse into this directory
|
|
566
|
+
count += await countSubdialogs(fullPath);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return count;
|
|
571
|
+
}
|
|
572
|
+
catch (error) {
|
|
573
|
+
if (typeof error === 'object' &&
|
|
574
|
+
error !== null &&
|
|
575
|
+
'code' in error &&
|
|
576
|
+
error.code === 'ENOENT') {
|
|
577
|
+
return 0;
|
|
578
|
+
}
|
|
579
|
+
throw error;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Get full hierarchy (root + subdialogs) for a single root dialog
|
|
584
|
+
*/
|
|
585
|
+
async function handleGetDialogHierarchy(res, rootId) {
|
|
586
|
+
try {
|
|
587
|
+
const statuses = ['running', 'completed', 'archived'];
|
|
588
|
+
let foundStatus = null;
|
|
589
|
+
let rootMeta = null;
|
|
590
|
+
for (const status of statuses) {
|
|
591
|
+
const meta = await persistence_1.DialogPersistence.loadRootDialogMetadata(new dialog_1.DialogID(rootId), status);
|
|
592
|
+
if (meta) {
|
|
593
|
+
foundStatus = status;
|
|
594
|
+
rootMeta = meta;
|
|
595
|
+
break;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
if (!foundStatus || !rootMeta) {
|
|
599
|
+
respondJson(res, 404, { success: false, error: `Root dialog ${rootId} not found` });
|
|
600
|
+
return true;
|
|
601
|
+
}
|
|
602
|
+
// Load latest.yaml for root dialog currentRound and lastModified timestamp
|
|
603
|
+
const rootLatest = await persistence_1.DialogPersistence.loadDialogLatest(new dialog_1.DialogID(rootId), foundStatus);
|
|
604
|
+
const rootInfo = {
|
|
605
|
+
id: rootMeta.id,
|
|
606
|
+
agentId: rootMeta.agentId,
|
|
607
|
+
taskDocPath: rootMeta.taskDocPath,
|
|
608
|
+
status: foundStatus,
|
|
609
|
+
currentRound: rootLatest?.currentRound || 1,
|
|
610
|
+
createdAt: rootMeta.createdAt,
|
|
611
|
+
lastModified: rootLatest?.lastModified || rootMeta.createdAt,
|
|
612
|
+
runState: rootLatest?.runState,
|
|
613
|
+
};
|
|
614
|
+
// Enumerate subdialogs under this root
|
|
615
|
+
const rootPath = persistence_1.DialogPersistence.getRootDialogPath(new dialog_1.DialogID(rootId), foundStatus);
|
|
616
|
+
const subPath = path.join(rootPath, 'subdialogs');
|
|
617
|
+
let subdialogs = [];
|
|
618
|
+
// Recursively find all subdialog directories (handles nested paths like c1/78/4c3d759a)
|
|
619
|
+
async function findSubdialogDirs(dir, baseRelative = '') {
|
|
620
|
+
const results = [];
|
|
621
|
+
try {
|
|
622
|
+
const entries = await promises_1.default.readdir(dir, { withFileTypes: true });
|
|
623
|
+
for (const entry of entries) {
|
|
624
|
+
if (entry.isDirectory()) {
|
|
625
|
+
const fullPath = path.join(dir, entry.name);
|
|
626
|
+
const dialogYamlPath = path.join(fullPath, 'dialog.yaml');
|
|
627
|
+
const entryRelative = baseRelative ? path.join(baseRelative, entry.name) : entry.name;
|
|
628
|
+
try {
|
|
629
|
+
await promises_1.default.access(dialogYamlPath);
|
|
630
|
+
// This directory contains dialog.yaml - it's a subdialog
|
|
631
|
+
// Push the FULL relative path (e.g., "5a/e2/4c424f27" not just "5a")
|
|
632
|
+
results.push(entryRelative);
|
|
633
|
+
}
|
|
634
|
+
catch {
|
|
635
|
+
// No dialog.yaml - recurse into this directory
|
|
636
|
+
const nested = await findSubdialogDirs(fullPath, entryRelative);
|
|
637
|
+
results.push(...nested);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
catch (error) {
|
|
643
|
+
if (typeof error === 'object' &&
|
|
644
|
+
error !== null &&
|
|
645
|
+
'code' in error &&
|
|
646
|
+
error.code === 'ENOENT') {
|
|
647
|
+
// No subdialogs directory - return empty
|
|
648
|
+
}
|
|
649
|
+
else {
|
|
650
|
+
throw error;
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
return results;
|
|
654
|
+
}
|
|
655
|
+
try {
|
|
656
|
+
const subIds = await findSubdialogDirs(subPath);
|
|
657
|
+
for (const subId of subIds) {
|
|
658
|
+
const meta = await persistence_1.DialogPersistence.loadDialogMetadata(new dialog_1.DialogID(subId, rootId), foundStatus);
|
|
659
|
+
if (meta) {
|
|
660
|
+
// Load latest.yaml for subdialog currentRound and lastModified timestamp
|
|
661
|
+
const subLatest = await persistence_1.DialogPersistence.loadDialogLatest(new dialog_1.DialogID(subId, rootId), foundStatus);
|
|
662
|
+
subdialogs.push({
|
|
663
|
+
selfId: meta.id,
|
|
664
|
+
rootId: rootId, // For subdialogs, rootId is the supdialog's ID
|
|
665
|
+
agentId: meta.agentId,
|
|
666
|
+
taskDocPath: meta.taskDocPath,
|
|
667
|
+
status: foundStatus,
|
|
668
|
+
currentRound: subLatest?.currentRound || 1,
|
|
669
|
+
createdAt: meta.createdAt,
|
|
670
|
+
lastModified: subLatest?.lastModified || meta.createdAt,
|
|
671
|
+
runState: subLatest?.runState,
|
|
672
|
+
tellaskSession: meta.tellaskSession,
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
catch (error) {
|
|
678
|
+
if (typeof error === 'object' &&
|
|
679
|
+
error !== null &&
|
|
680
|
+
'code' in error &&
|
|
681
|
+
error.code === 'ENOENT') {
|
|
682
|
+
subdialogs = [];
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
throw error;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
respondJson(res, 200, {
|
|
689
|
+
success: true,
|
|
690
|
+
hierarchy: {
|
|
691
|
+
root: rootInfo,
|
|
692
|
+
subdialogs,
|
|
693
|
+
},
|
|
694
|
+
});
|
|
695
|
+
return true;
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
698
|
+
log.error('Error getting dialog hierarchy:', error);
|
|
699
|
+
respondJson(res, 500, { success: false, error: 'Failed to get dialog hierarchy' });
|
|
700
|
+
return true;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Create new dialog
|
|
705
|
+
*/
|
|
706
|
+
async function handleCreateDialog(req, res, context) {
|
|
707
|
+
try {
|
|
708
|
+
const body = await readRequestBody(req);
|
|
709
|
+
const { agentId, taskDocPath } = JSON.parse(body);
|
|
710
|
+
if (!agentId) {
|
|
711
|
+
respondJson(res, 400, { success: false, error: 'agentId is required' });
|
|
712
|
+
return true;
|
|
713
|
+
}
|
|
714
|
+
if (typeof taskDocPath !== 'string' || taskDocPath.trim() === '') {
|
|
715
|
+
respondJson(res, 400, { success: false, error: 'taskDocPath is required' });
|
|
716
|
+
return true;
|
|
717
|
+
}
|
|
718
|
+
if (!(0, task_package_1.isTaskPackagePath)(taskDocPath)) {
|
|
719
|
+
respondJson(res, 400, {
|
|
720
|
+
success: false,
|
|
721
|
+
error: `taskDocPath must be a Task Doc directory ending in '.tsk' (got: '${taskDocPath}')`,
|
|
722
|
+
});
|
|
723
|
+
return true;
|
|
724
|
+
}
|
|
725
|
+
// Generate dialog ID
|
|
726
|
+
const generatedId = (0, id_1.generateDialogID)();
|
|
727
|
+
const dialogId = new dialog_1.DialogID(generatedId);
|
|
728
|
+
// Create dialog UI based on context
|
|
729
|
+
// Always use DiskFileDialogStore for file-based persistence
|
|
730
|
+
const dialogUI = new persistence_1.DiskFileDialogStore(dialogId);
|
|
731
|
+
// Create RootDialog
|
|
732
|
+
const dialog = new dialog_1.RootDialog(dialogUI, taskDocPath, dialogId, agentId);
|
|
733
|
+
dialog_global_registry_1.globalDialogRegistry.register(dialog);
|
|
734
|
+
// Persist dialog metadata and latest.yaml (write-once pattern)
|
|
735
|
+
const metadata = {
|
|
736
|
+
id: dialogId.selfId,
|
|
737
|
+
agentId: agentId,
|
|
738
|
+
taskDocPath: taskDocPath,
|
|
739
|
+
createdAt: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
740
|
+
};
|
|
741
|
+
await persistence_1.DialogPersistence.saveDialogMetadata(new dialog_1.DialogID(dialogId.selfId), metadata);
|
|
742
|
+
// Initialize latest.yaml via the mutation API (write-back will flush).
|
|
743
|
+
await persistence_1.DialogPersistence.mutateDialogLatest(new dialog_1.DialogID(dialogId.selfId), () => ({
|
|
744
|
+
kind: 'replace',
|
|
745
|
+
next: {
|
|
746
|
+
currentRound: 1,
|
|
747
|
+
lastModified: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
748
|
+
status: 'active',
|
|
749
|
+
messageCount: 0,
|
|
750
|
+
functionCallCount: 0,
|
|
751
|
+
subdialogCount: 0,
|
|
752
|
+
runState: { kind: 'idle_waiting_user' },
|
|
753
|
+
disableDiligencePush: false,
|
|
754
|
+
},
|
|
755
|
+
}));
|
|
756
|
+
// Dialog is registered with the global registry on creation
|
|
757
|
+
// No need to call registerDialog
|
|
758
|
+
respondJson(res, 201, { success: true, selfId: dialogId.selfId, rootId: dialogId.rootId });
|
|
759
|
+
broadcastDialogCreates(context.clients, {
|
|
760
|
+
type: 'dialogs_created',
|
|
761
|
+
scope: { kind: 'root', rootId: dialogId.selfId },
|
|
762
|
+
status: 'running',
|
|
763
|
+
createdRootIds: [dialogId.selfId],
|
|
764
|
+
timestamp: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
765
|
+
});
|
|
766
|
+
return true;
|
|
767
|
+
}
|
|
768
|
+
catch (error) {
|
|
769
|
+
log.error('Error creating dialog:', error);
|
|
770
|
+
respondJson(res, 500, { success: false, error: 'Failed to create dialog' });
|
|
771
|
+
return true;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
async function handleMoveDialogs(req, res, context) {
|
|
775
|
+
try {
|
|
776
|
+
const body = await readRequestBody(req);
|
|
777
|
+
const parsed = JSON.parse(body);
|
|
778
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
779
|
+
respondJson(res, 400, { success: false, error: 'Invalid JSON body' });
|
|
780
|
+
return true;
|
|
781
|
+
}
|
|
782
|
+
const kind = parsed.kind;
|
|
783
|
+
if (kind !== 'root' && kind !== 'task') {
|
|
784
|
+
respondJson(res, 400, { success: false, error: 'Invalid move request kind' });
|
|
785
|
+
return true;
|
|
786
|
+
}
|
|
787
|
+
const fromStatus = parsed.fromStatus;
|
|
788
|
+
const toStatus = parsed.toStatus;
|
|
789
|
+
const fromOk = fromStatus === 'running' || fromStatus === 'completed' || fromStatus === 'archived';
|
|
790
|
+
const toOk = toStatus === 'running' || toStatus === 'completed' || toStatus === 'archived';
|
|
791
|
+
if (!fromOk || !toOk) {
|
|
792
|
+
respondJson(res, 400, { success: false, error: 'Invalid fromStatus/toStatus' });
|
|
793
|
+
return true;
|
|
794
|
+
}
|
|
795
|
+
if (fromStatus === toStatus) {
|
|
796
|
+
respondJson(res, 400, { success: false, error: 'fromStatus and toStatus must differ' });
|
|
797
|
+
return true;
|
|
798
|
+
}
|
|
799
|
+
const request = parsed;
|
|
800
|
+
const movedRootIds = [];
|
|
801
|
+
const scope = request.kind === 'root'
|
|
802
|
+
? { kind: 'root', rootId: request.rootId }
|
|
803
|
+
: { kind: 'task', taskDocPath: request.taskDocPath };
|
|
804
|
+
if (request.kind === 'root') {
|
|
805
|
+
const rootId = request.rootId;
|
|
806
|
+
if (typeof rootId !== 'string' || rootId.trim() === '') {
|
|
807
|
+
respondJson(res, 400, { success: false, error: 'rootId must be a non-empty string' });
|
|
808
|
+
return true;
|
|
809
|
+
}
|
|
810
|
+
const meta = await persistence_1.DialogPersistence.loadRootDialogMetadata(new dialog_1.DialogID(rootId), fromStatus);
|
|
811
|
+
if (!meta) {
|
|
812
|
+
respondJson(res, 404, {
|
|
813
|
+
success: false,
|
|
814
|
+
error: `Root dialog ${rootId} not found in ${fromStatus}`,
|
|
815
|
+
});
|
|
816
|
+
return true;
|
|
817
|
+
}
|
|
818
|
+
await persistence_1.DialogPersistence.moveDialogStatus(new dialog_1.DialogID(rootId), fromStatus, toStatus);
|
|
819
|
+
movedRootIds.push(rootId);
|
|
820
|
+
const live = dialog_global_registry_1.globalDialogRegistry.get(rootId);
|
|
821
|
+
if (live) {
|
|
822
|
+
live.setPersistenceStatus(toStatus);
|
|
823
|
+
}
|
|
824
|
+
respondJson(res, 200, { success: true, movedRootIds });
|
|
825
|
+
broadcastDialogMoves(context.clients, {
|
|
826
|
+
type: 'dialogs_moved',
|
|
827
|
+
scope,
|
|
828
|
+
fromStatus,
|
|
829
|
+
toStatus,
|
|
830
|
+
movedRootIds,
|
|
831
|
+
timestamp: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
832
|
+
});
|
|
833
|
+
return true;
|
|
834
|
+
}
|
|
835
|
+
const taskDocPath = request.taskDocPath;
|
|
836
|
+
if (typeof taskDocPath !== 'string' || taskDocPath.trim() === '') {
|
|
837
|
+
respondJson(res, 400, { success: false, error: 'taskDocPath must be a non-empty string' });
|
|
838
|
+
return true;
|
|
839
|
+
}
|
|
840
|
+
const ids = await persistence_1.DialogPersistence.listDialogs(fromStatus);
|
|
841
|
+
for (const id of ids) {
|
|
842
|
+
if (typeof id !== 'string' || id.trim() === '')
|
|
843
|
+
continue;
|
|
844
|
+
const meta = await persistence_1.DialogPersistence.loadRootDialogMetadata(new dialog_1.DialogID(id), fromStatus);
|
|
845
|
+
if (!meta)
|
|
846
|
+
continue;
|
|
847
|
+
if (meta.taskDocPath !== taskDocPath)
|
|
848
|
+
continue;
|
|
849
|
+
await persistence_1.DialogPersistence.moveDialogStatus(new dialog_1.DialogID(id), fromStatus, toStatus);
|
|
850
|
+
movedRootIds.push(id);
|
|
851
|
+
}
|
|
852
|
+
for (const rootId of movedRootIds) {
|
|
853
|
+
const live = dialog_global_registry_1.globalDialogRegistry.get(rootId);
|
|
854
|
+
if (live) {
|
|
855
|
+
live.setPersistenceStatus(toStatus);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
respondJson(res, 200, { success: true, movedRootIds });
|
|
859
|
+
broadcastDialogMoves(context.clients, {
|
|
860
|
+
type: 'dialogs_moved',
|
|
861
|
+
scope,
|
|
862
|
+
fromStatus,
|
|
863
|
+
toStatus,
|
|
864
|
+
movedRootIds,
|
|
865
|
+
timestamp: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
866
|
+
});
|
|
867
|
+
return true;
|
|
868
|
+
}
|
|
869
|
+
catch (error) {
|
|
870
|
+
log.error('Error moving dialogs:', error);
|
|
871
|
+
respondJson(res, 500, { success: false, error: 'Failed to move dialogs' });
|
|
872
|
+
return true;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
function broadcastDialogMoves(clients, message) {
|
|
876
|
+
if (!clients)
|
|
877
|
+
return;
|
|
878
|
+
if (message.movedRootIds.length === 0)
|
|
879
|
+
return;
|
|
880
|
+
const data = JSON.stringify(message);
|
|
881
|
+
for (const ws of clients) {
|
|
882
|
+
if (ws.readyState === 1) {
|
|
883
|
+
ws.send(data);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
function broadcastDialogDeletes(clients, message) {
|
|
888
|
+
if (!clients)
|
|
889
|
+
return;
|
|
890
|
+
if (message.deletedRootIds.length === 0)
|
|
891
|
+
return;
|
|
892
|
+
const data = JSON.stringify(message);
|
|
893
|
+
for (const ws of clients) {
|
|
894
|
+
if (ws.readyState === 1) {
|
|
895
|
+
ws.send(data);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
function broadcastDialogCreates(clients, message) {
|
|
900
|
+
if (!clients)
|
|
901
|
+
return;
|
|
902
|
+
if (message.createdRootIds.length === 0)
|
|
903
|
+
return;
|
|
904
|
+
const data = JSON.stringify(message);
|
|
905
|
+
for (const ws of clients) {
|
|
906
|
+
if (ws.readyState === 1) {
|
|
907
|
+
ws.send(data);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
async function handleDeleteDialog(res, dialog, context) {
|
|
912
|
+
try {
|
|
913
|
+
const { rootId, selfId } = dialog;
|
|
914
|
+
if (typeof rootId !== 'string' || rootId.trim() === '') {
|
|
915
|
+
respondJson(res, 400, { error: 'Invalid root dialog id' });
|
|
916
|
+
return true;
|
|
917
|
+
}
|
|
918
|
+
if (typeof selfId !== 'string' || selfId.trim() === '') {
|
|
919
|
+
respondJson(res, 400, { error: 'Invalid dialog id' });
|
|
920
|
+
return true;
|
|
921
|
+
}
|
|
922
|
+
if (selfId !== rootId) {
|
|
923
|
+
respondJson(res, 400, {
|
|
924
|
+
error: 'Only root dialog deletion is supported (use /api/dialogs/:root)',
|
|
925
|
+
});
|
|
926
|
+
return true;
|
|
927
|
+
}
|
|
928
|
+
const fromStatus = await persistence_1.DialogPersistence.deleteRootDialog(new dialog_1.DialogID(rootId));
|
|
929
|
+
if (!fromStatus) {
|
|
930
|
+
respondJson(res, 404, { error: 'Dialog not found' });
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
log.debug('Deleted dialog via API', undefined, { rootId, fromStatus });
|
|
934
|
+
dialog_global_registry_1.globalDialogRegistry.unregister(rootId);
|
|
935
|
+
respondJson(res, 200, { deleted: true, fromStatus });
|
|
936
|
+
broadcastDialogDeletes(context.clients, {
|
|
937
|
+
type: 'dialogs_deleted',
|
|
938
|
+
scope: { kind: 'root', rootId },
|
|
939
|
+
fromStatus,
|
|
940
|
+
deletedRootIds: [rootId],
|
|
941
|
+
timestamp: (0, time_1.formatUnifiedTimestamp)(new Date()),
|
|
942
|
+
});
|
|
943
|
+
return true;
|
|
944
|
+
}
|
|
945
|
+
catch (error) {
|
|
946
|
+
log.error('Error deleting dialog:', error);
|
|
947
|
+
respondJson(res, 500, { error: 'Failed to delete dialog' });
|
|
948
|
+
return true;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
/**
|
|
952
|
+
* Get specific dialog
|
|
953
|
+
*/
|
|
954
|
+
async function handleGetDialog(res, dialog) {
|
|
955
|
+
try {
|
|
956
|
+
const metadata = await persistence_1.DialogPersistence.loadDialogMetadata(new dialog_1.DialogID(dialog.selfId, dialog.rootId), 'running');
|
|
957
|
+
if (!metadata) {
|
|
958
|
+
respondJson(res, 404, { success: false, error: 'Dialog not found' });
|
|
959
|
+
return true;
|
|
960
|
+
}
|
|
961
|
+
// Enforce structured identification for subdialogs
|
|
962
|
+
if (metadata.supdialogId && dialog.selfId === dialog.rootId) {
|
|
963
|
+
respondJson(res, 400, {
|
|
964
|
+
success: false,
|
|
965
|
+
error: 'Subdialog requires /api/dialogs/:root/:self',
|
|
966
|
+
});
|
|
967
|
+
return true;
|
|
968
|
+
}
|
|
969
|
+
const currentRound = await persistence_1.DialogPersistence.getCurrentRoundNumber(new dialog_1.DialogID(dialog.selfId, dialog.rootId), 'running');
|
|
970
|
+
const dialogData = {
|
|
971
|
+
id: metadata.id,
|
|
972
|
+
agentId: metadata.agentId,
|
|
973
|
+
status: 'running',
|
|
974
|
+
createdAt: metadata.createdAt,
|
|
975
|
+
currentRound,
|
|
976
|
+
};
|
|
977
|
+
respondJson(res, 200, { success: true, dialog: dialogData });
|
|
978
|
+
return true;
|
|
979
|
+
}
|
|
980
|
+
catch (error) {
|
|
981
|
+
log.error('Error getting dialog:', error);
|
|
982
|
+
respondJson(res, 500, { success: false, error: 'Failed to get dialog' });
|
|
983
|
+
return true;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Get task documents
|
|
988
|
+
*/
|
|
989
|
+
async function handleGetTaskDocuments(res) {
|
|
990
|
+
try {
|
|
991
|
+
const taskDocuments = await listTaskDocuments();
|
|
992
|
+
respondJson(res, 200, taskDocuments);
|
|
993
|
+
return true;
|
|
994
|
+
}
|
|
995
|
+
catch (error) {
|
|
996
|
+
log.error('Error getting task documents:', error);
|
|
997
|
+
respondJson(res, 500, { success: false, error: 'Failed to get task documents' });
|
|
998
|
+
return true;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Helper function to read request body
|
|
1003
|
+
*/
|
|
1004
|
+
function readRequestBody(req) {
|
|
1005
|
+
return new Promise((resolve, reject) => {
|
|
1006
|
+
let body = '';
|
|
1007
|
+
req.on('data', (chunk) => {
|
|
1008
|
+
body += chunk.toString();
|
|
1009
|
+
});
|
|
1010
|
+
req.on('end', () => {
|
|
1011
|
+
resolve(body);
|
|
1012
|
+
});
|
|
1013
|
+
req.on('error', reject);
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Helper function to send JSON response
|
|
1018
|
+
*/
|
|
1019
|
+
function respondJson(res, statusCode, data) {
|
|
1020
|
+
res.writeHead(statusCode, { 'Content-Type': 'application/json' });
|
|
1021
|
+
res.end(JSON.stringify(data));
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* List task documents (recursive search; Task Docs are encapsulated `*.tsk/` directories)
|
|
1025
|
+
*/
|
|
1026
|
+
async function listTaskDocuments() {
|
|
1027
|
+
const result = await (0, taskdoc_search_1.listTaskDocumentsInWorkspace)({ rootDir: '.' });
|
|
1028
|
+
if (result.kind === 'ok')
|
|
1029
|
+
return { success: true, taskDocuments: result.taskDocuments };
|
|
1030
|
+
return { success: false, error: result.errorText };
|
|
1031
|
+
}
|