dominds 1.20.3 → 1.20.4
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/README.md +4 -4
- package/README.zh.md +2 -2
- package/dist/access-control.js +2 -2
- package/dist/cli/webui.d.ts +1 -1
- package/dist/cli/webui.js +29 -9
- package/dist/docs/cli-usage.md +2 -1
- package/dist/docs/cli-usage.zh.md +6 -3
- package/dist/docs/context-health.md +2 -2
- package/dist/docs/context-health.zh.md +2 -2
- package/dist/docs/design.md +3 -3
- package/dist/docs/design.zh.md +3 -3
- package/dist/docs/dialog-system.md +18 -10
- package/dist/docs/dialog-system.zh.md +18 -10
- package/dist/docs/dominds-terminology.md +4 -4
- package/dist/docs/encapsulated-taskdoc.md +17 -10
- package/dist/docs/encapsulated-taskdoc.zh.md +18 -11
- package/dist/minds/load.js +14 -4
- package/dist/minds/minds-i18n.js +2 -2
- package/dist/minds/system-prompt-parts.js +8 -8
- package/dist/runtime/driver-messages.js +8 -4
- package/dist/server/port-selection.d.ts +19 -0
- package/dist/server/port-selection.js +57 -0
- package/dist/server/server-core.d.ts +2 -2
- package/dist/server/server-core.js +21 -7
- package/dist/server.d.ts +3 -0
- package/dist/server.js +109 -44
- package/dist/team.d.ts +2 -3
- package/dist/team.js +17 -4
- package/dist/tools/builtins.js +3 -0
- package/dist/tools/ctrl.d.ts +10 -8
- package/dist/tools/ctrl.js +141 -22
- package/dist/tools/prompts/control/en/errors.md +2 -2
- package/dist/tools/prompts/control/en/principles.md +13 -12
- package/dist/tools/prompts/control/en/tools.md +23 -5
- package/dist/tools/prompts/control/zh/errors.md +2 -2
- package/dist/tools/prompts/control/zh/principles.md +13 -12
- package/dist/tools/prompts/control/zh/tools.md +23 -5
- package/dist/tools/prompts/personal_memory/en/principles.md +1 -1
- package/dist/tools/prompts/personal_memory/zh/principles.md +1 -1
- package/dist/tools/prompts/team_memory/en/principles.md +1 -1
- package/dist/tools/prompts/team_memory/zh/principles.md +1 -1
- package/dist/tools/registry.d.ts +6 -0
- package/dist/tools/team_mgmt.js +5 -5
- package/dist/utils/task-package.d.ts +15 -1
- package/dist/utils/task-package.js +51 -1
- package/dist/utils/taskdoc.js +60 -22
- package/package.json +3 -3
- package/webapp/dist/assets/{_basePickBy-B2wYdQcR.js → _basePickBy-BrC49DPW.js} +3 -3
- package/webapp/dist/assets/{_basePickBy-B2wYdQcR.js.map → _basePickBy-BrC49DPW.js.map} +1 -1
- package/webapp/dist/assets/{_baseUniq-zKoHgk38.js → _baseUniq-C_Wcx-_S.js} +2 -2
- package/webapp/dist/assets/{_baseUniq-zKoHgk38.js.map → _baseUniq-C_Wcx-_S.js.map} +1 -1
- package/webapp/dist/assets/{arc-D8bQ-Nzm.js → arc-X5iIdpx0.js} +2 -2
- package/webapp/dist/assets/{arc-D8bQ-Nzm.js.map → arc-X5iIdpx0.js.map} +1 -1
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-BiimGQW5.js → architectureDiagram-2XIMDMQ5-DFfhMGkT.js} +7 -7
- package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-BiimGQW5.js.map → architectureDiagram-2XIMDMQ5-DFfhMGkT.js.map} +1 -1
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-BXPbS_wx.js → blockDiagram-WCTKOSBZ-BAt4BaxZ.js} +7 -7
- package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-BXPbS_wx.js.map → blockDiagram-WCTKOSBZ-BAt4BaxZ.js.map} +1 -1
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-BZC0c1Ke.js → c4Diagram-IC4MRINW-BYxKH5AA.js} +3 -3
- package/webapp/dist/assets/{c4Diagram-IC4MRINW-BZC0c1Ke.js.map → c4Diagram-IC4MRINW-BYxKH5AA.js.map} +1 -1
- package/webapp/dist/assets/{channel-BP3Qyxui.js → channel-CuYhL59H.js} +2 -2
- package/webapp/dist/assets/{channel-BP3Qyxui.js.map → channel-CuYhL59H.js.map} +1 -1
- package/webapp/dist/assets/{chunk-4BX2VUAB-BXABHFQC.js → chunk-4BX2VUAB-Ch1PfLiD.js} +2 -2
- package/webapp/dist/assets/{chunk-4BX2VUAB-BXABHFQC.js.map → chunk-4BX2VUAB-Ch1PfLiD.js.map} +1 -1
- package/webapp/dist/assets/{chunk-55IACEB6-KdM20zpJ.js → chunk-55IACEB6-B3rzakPd.js} +2 -2
- package/webapp/dist/assets/{chunk-55IACEB6-KdM20zpJ.js.map → chunk-55IACEB6-B3rzakPd.js.map} +1 -1
- package/webapp/dist/assets/{chunk-FMBD7UC4-B2T04oKB.js → chunk-FMBD7UC4-CCZWJRJ5.js} +2 -2
- package/webapp/dist/assets/{chunk-FMBD7UC4-B2T04oKB.js.map → chunk-FMBD7UC4-CCZWJRJ5.js.map} +1 -1
- package/webapp/dist/assets/{chunk-JSJVCQXG-Bz-hhsBJ.js → chunk-JSJVCQXG-Dqd_MOPD.js} +2 -2
- package/webapp/dist/assets/{chunk-JSJVCQXG-Bz-hhsBJ.js.map → chunk-JSJVCQXG-Dqd_MOPD.js.map} +1 -1
- package/webapp/dist/assets/{chunk-KX2RTZJC-B1TcA_CH.js → chunk-KX2RTZJC-DOpPZD_q.js} +2 -2
- package/webapp/dist/assets/{chunk-KX2RTZJC-B1TcA_CH.js.map → chunk-KX2RTZJC-DOpPZD_q.js.map} +1 -1
- package/webapp/dist/assets/{chunk-NQ4KR5QH-BwsfKfyl.js → chunk-NQ4KR5QH-CUj2LNV0.js} +4 -4
- package/webapp/dist/assets/{chunk-NQ4KR5QH-BwsfKfyl.js.map → chunk-NQ4KR5QH-CUj2LNV0.js.map} +1 -1
- package/webapp/dist/assets/{chunk-QZHKN3VN-BX453Nua.js → chunk-QZHKN3VN-DXeWDyzh.js} +2 -2
- package/webapp/dist/assets/{chunk-QZHKN3VN-BX453Nua.js.map → chunk-QZHKN3VN-DXeWDyzh.js.map} +1 -1
- package/webapp/dist/assets/{chunk-WL4C6EOR-COCTYZ-S.js → chunk-WL4C6EOR-CqTowzs6.js} +6 -6
- package/webapp/dist/assets/{chunk-WL4C6EOR-COCTYZ-S.js.map → chunk-WL4C6EOR-CqTowzs6.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-aWgCJGiX.js → classDiagram-VBA2DB6C-CvsxEN3D.js} +7 -7
- package/webapp/dist/assets/{classDiagram-VBA2DB6C-aWgCJGiX.js.map → classDiagram-VBA2DB6C-CvsxEN3D.js.map} +1 -1
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-aWgCJGiX.js → classDiagram-v2-RAHNMMFH-CvsxEN3D.js} +7 -7
- package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-aWgCJGiX.js.map → classDiagram-v2-RAHNMMFH-CvsxEN3D.js.map} +1 -1
- package/webapp/dist/assets/{clone-UCWLNsJ4.js → clone-PGWIYNYc.js} +2 -2
- package/webapp/dist/assets/{clone-UCWLNsJ4.js.map → clone-PGWIYNYc.js.map} +1 -1
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-Blf43_-z.js → cose-bilkent-S5V4N54A-Cf8RR_8j.js} +2 -2
- package/webapp/dist/assets/{cose-bilkent-S5V4N54A-Blf43_-z.js.map → cose-bilkent-S5V4N54A-Cf8RR_8j.js.map} +1 -1
- package/webapp/dist/assets/{dagre-KLK3FWXG-BLTVAduG.js → dagre-KLK3FWXG-C1yQDg-6.js} +7 -7
- package/webapp/dist/assets/{dagre-KLK3FWXG-BLTVAduG.js.map → dagre-KLK3FWXG-C1yQDg-6.js.map} +1 -1
- package/webapp/dist/assets/{diagram-E7M64L7V-eHyGJiW2.js → diagram-E7M64L7V-CrT4qBJh.js} +8 -8
- package/webapp/dist/assets/{diagram-E7M64L7V-eHyGJiW2.js.map → diagram-E7M64L7V-CrT4qBJh.js.map} +1 -1
- package/webapp/dist/assets/{diagram-IFDJBPK2-BzZS2fFL.js → diagram-IFDJBPK2-B8WaCOcr.js} +7 -7
- package/webapp/dist/assets/{diagram-IFDJBPK2-BzZS2fFL.js.map → diagram-IFDJBPK2-B8WaCOcr.js.map} +1 -1
- package/webapp/dist/assets/{diagram-P4PSJMXO-CUUSxkwu.js → diagram-P4PSJMXO-BCZeNfu_.js} +7 -7
- package/webapp/dist/assets/{diagram-P4PSJMXO-CUUSxkwu.js.map → diagram-P4PSJMXO-BCZeNfu_.js.map} +1 -1
- package/webapp/dist/assets/{erDiagram-INFDFZHY-DF_doi5_.js → erDiagram-INFDFZHY-BrYt0-mW.js} +5 -5
- package/webapp/dist/assets/{erDiagram-INFDFZHY-DF_doi5_.js.map → erDiagram-INFDFZHY-BrYt0-mW.js.map} +1 -1
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-YcqCG3mt.js → flowDiagram-PKNHOUZH-8lZ5d5y-.js} +7 -7
- package/webapp/dist/assets/{flowDiagram-PKNHOUZH-YcqCG3mt.js.map → flowDiagram-PKNHOUZH-8lZ5d5y-.js.map} +1 -1
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-BZNRb7SP.js → ganttDiagram-A5KZAMGK-CQ8pOLf-.js} +3 -3
- package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-BZNRb7SP.js.map → ganttDiagram-A5KZAMGK-CQ8pOLf-.js.map} +1 -1
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-nAdujBg_.js → gitGraphDiagram-K3NZZRJ6-aOTOe0HP.js} +8 -8
- package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-nAdujBg_.js.map → gitGraphDiagram-K3NZZRJ6-aOTOe0HP.js.map} +1 -1
- package/webapp/dist/assets/{graph-Cv-ZJ4Fl.js → graph-CyMR1egR.js} +3 -3
- package/webapp/dist/assets/{graph-Cv-ZJ4Fl.js.map → graph-CyMR1egR.js.map} +1 -1
- package/webapp/dist/assets/{index-Dhf_wAfo.js → index-B9TTmMv-.js} +274 -56
- package/webapp/dist/assets/{index-Dhf_wAfo.js.map → index-B9TTmMv-.js.map} +1 -1
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-CwtMOnIR.js → infoDiagram-LFFYTUFH-CXR9XjRe.js} +6 -6
- package/webapp/dist/assets/{infoDiagram-LFFYTUFH-CwtMOnIR.js.map → infoDiagram-LFFYTUFH-CXR9XjRe.js.map} +1 -1
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-Cfb8MPoG.js → ishikawaDiagram-PHBUUO56-zwe-cqRW.js} +2 -2
- package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-Cfb8MPoG.js.map → ishikawaDiagram-PHBUUO56-zwe-cqRW.js.map} +1 -1
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-u0xpmaEL.js → journeyDiagram-4ABVD52K-BV-8X5hz.js} +5 -5
- package/webapp/dist/assets/{journeyDiagram-4ABVD52K-u0xpmaEL.js.map → journeyDiagram-4ABVD52K-BV-8X5hz.js.map} +1 -1
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-BuwDgdXi.js → kanban-definition-K7BYSVSG-E3W-szUv.js} +3 -3
- package/webapp/dist/assets/{kanban-definition-K7BYSVSG-BuwDgdXi.js.map → kanban-definition-K7BYSVSG-E3W-szUv.js.map} +1 -1
- package/webapp/dist/assets/{layout-DwFR5fz7.js → layout-DvIjuV8I.js} +5 -5
- package/webapp/dist/assets/{layout-DwFR5fz7.js.map → layout-DvIjuV8I.js.map} +1 -1
- package/webapp/dist/assets/{linear-DK9kuyt6.js → linear-C-SIS0ki.js} +2 -2
- package/webapp/dist/assets/{linear-DK9kuyt6.js.map → linear-C-SIS0ki.js.map} +1 -1
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-BP26yHUE.js → mindmap-definition-YRQLILUH-wigkPJ2B.js} +4 -4
- package/webapp/dist/assets/{mindmap-definition-YRQLILUH-BP26yHUE.js.map → mindmap-definition-YRQLILUH-wigkPJ2B.js.map} +1 -1
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Dg05ljR9.js → pieDiagram-SKSYHLDU-BKrYJ0LE.js} +8 -8
- package/webapp/dist/assets/{pieDiagram-SKSYHLDU-Dg05ljR9.js.map → pieDiagram-SKSYHLDU-BKrYJ0LE.js.map} +1 -1
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-BZwWQDeQ.js → quadrantDiagram-337W2JSQ-fjwd0gVY.js} +3 -3
- package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-BZwWQDeQ.js.map → quadrantDiagram-337W2JSQ-fjwd0gVY.js.map} +1 -1
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-IZuN0Vt3.js → requirementDiagram-Z7DCOOCP-vgTMObSA.js} +4 -4
- package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-IZuN0Vt3.js.map → requirementDiagram-Z7DCOOCP-vgTMObSA.js.map} +1 -1
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-BsVp8N4k.js → sankeyDiagram-WA2Y5GQK-B-ZV3LF7.js} +2 -2
- package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-BsVp8N4k.js.map → sankeyDiagram-WA2Y5GQK-B-ZV3LF7.js.map} +1 -1
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-BkAT5uON.js → sequenceDiagram-2WXFIKYE-DPhZYHhW.js} +4 -4
- package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-BkAT5uON.js.map → sequenceDiagram-2WXFIKYE-DPhZYHhW.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-qk_ajPAy.js → stateDiagram-RAJIS63D-DLsw3SC8.js} +9 -9
- package/webapp/dist/assets/{stateDiagram-RAJIS63D-qk_ajPAy.js.map → stateDiagram-RAJIS63D-DLsw3SC8.js.map} +1 -1
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-CNtP8Lfm.js → stateDiagram-v2-FVOUBMTO-DqXB3dNs.js} +5 -5
- package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-CNtP8Lfm.js.map → stateDiagram-v2-FVOUBMTO-DqXB3dNs.js.map} +1 -1
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-DLU-Pyr1.js → timeline-definition-YZTLITO2-BFSqlDfo.js} +3 -3
- package/webapp/dist/assets/{timeline-definition-YZTLITO2-DLU-Pyr1.js.map → timeline-definition-YZTLITO2-BFSqlDfo.js.map} +1 -1
- package/webapp/dist/assets/{treemap-KZPCXAKY-hHk6fxaq.js → treemap-KZPCXAKY-sdfq6mHG.js} +5 -5
- package/webapp/dist/assets/{treemap-KZPCXAKY-hHk6fxaq.js.map → treemap-KZPCXAKY-sdfq6mHG.js.map} +1 -1
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-CM1zd5GO.js → vennDiagram-LZ73GAT5-D7Cioksz.js} +2 -2
- package/webapp/dist/assets/{vennDiagram-LZ73GAT5-CM1zd5GO.js.map → vennDiagram-LZ73GAT5-D7Cioksz.js.map} +1 -1
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-CccDexUn.js → xychartDiagram-JWTSCODW-No65aXqH.js} +3 -3
- package/webapp/dist/assets/{xychartDiagram-JWTSCODW-CccDexUn.js.map → xychartDiagram-JWTSCODW-No65aXqH.js.map} +1 -1
- package/webapp/dist/index.html +1 -1
package/dist/minds/load.js
CHANGED
|
@@ -26,6 +26,12 @@ const toolset_manual_1 = require("../tools/toolset-manual");
|
|
|
26
26
|
const minds_i18n_1 = require("./minds-i18n");
|
|
27
27
|
const system_prompt_1 = require("./system-prompt");
|
|
28
28
|
const system_prompt_parts_1 = require("./system-prompt-parts");
|
|
29
|
+
const TASKDOC_MUTATION_TOOL_NAMES = new Set([
|
|
30
|
+
ctrl_1.doMindTool.name,
|
|
31
|
+
ctrl_1.mindMoreTool.name,
|
|
32
|
+
ctrl_1.changeMindTool.name,
|
|
33
|
+
ctrl_1.neverMindTool.name,
|
|
34
|
+
]);
|
|
29
35
|
async function readAgentMindResult(id, fn, source) {
|
|
30
36
|
const mindFn = source === 'rtws'
|
|
31
37
|
? path_1.default.join('.minds', 'team', id, fn)
|
|
@@ -190,8 +196,8 @@ async function loadAgentMinds(agentId, dialog, options) {
|
|
|
190
196
|
});
|
|
191
197
|
// Introduction of all team members (mark "(self)" for the current agent)
|
|
192
198
|
const teamIntro = (0, system_prompt_1.formatTeamIntro)(team, agent.id, workingLanguage);
|
|
193
|
-
// Compose tool list from member's resolved toolsets and tools + built-in human tool
|
|
194
|
-
// Get base tools from agent
|
|
199
|
+
// Compose tool list from member's resolved toolsets and tools + built-in human tool.
|
|
200
|
+
// Get base tools from agent; runtime injects allowed intrinsic dialog-control tools afterward.
|
|
195
201
|
// shell_specialists is intended for visible teammates only. Hidden members are exempt from this
|
|
196
202
|
// policy and may carry shell tools.
|
|
197
203
|
const agentIsShellSpecialist = team.shellSpecialists.includes(agent.id) || agent.hidden === true;
|
|
@@ -210,7 +216,7 @@ async function loadAgentMinds(agentId, dialog, options) {
|
|
|
210
216
|
return tools;
|
|
211
217
|
return tools.filter((t) => !(t.type === 'func' && typeof t.name === 'string' && (0, shell_tools_1.isShellToolName)(t.name)));
|
|
212
218
|
})();
|
|
213
|
-
// Inject intrinsic dialog
|
|
219
|
+
// Inject intrinsic dialog-control tools as function tools according to dialog scope.
|
|
214
220
|
const intrinsicFuncTools = [
|
|
215
221
|
ctrl_1.addReminderTool,
|
|
216
222
|
ctrl_1.deleteReminderTool,
|
|
@@ -220,10 +226,12 @@ async function loadAgentMinds(agentId, dialog, options) {
|
|
|
220
226
|
];
|
|
221
227
|
// Taskdoc mutation tools are only available in main dialogs (not sideDialogs).
|
|
222
228
|
if (dialog === undefined || dialog.askerDialog === undefined) {
|
|
229
|
+
intrinsicFuncTools.push(ctrl_1.doMindTool);
|
|
223
230
|
intrinsicFuncTools.push(ctrl_1.mindMoreTool);
|
|
224
231
|
intrinsicFuncTools.push(ctrl_1.changeMindTool);
|
|
225
232
|
intrinsicFuncTools.push(ctrl_1.neverMindTool);
|
|
226
233
|
}
|
|
234
|
+
const shouldHideTaskdocMutationTools = dialog !== undefined && dialog.askerDialog !== undefined;
|
|
227
235
|
const agentTools = (() => {
|
|
228
236
|
const out = [...baseAgentTools];
|
|
229
237
|
const seenNames = new Set(out.map((t) => t.name));
|
|
@@ -233,7 +241,9 @@ async function loadAgentMinds(agentId, dialog, options) {
|
|
|
233
241
|
seenNames.add(t.name);
|
|
234
242
|
}
|
|
235
243
|
}
|
|
236
|
-
|
|
244
|
+
if (!shouldHideTaskdocMutationTools)
|
|
245
|
+
return out;
|
|
246
|
+
return out.filter((t) => !TASKDOC_MUTATION_TOOL_NAMES.has(t.name));
|
|
237
247
|
})();
|
|
238
248
|
const toolsetNames = agent
|
|
239
249
|
.listResolvedToolsetNames({
|
package/dist/minds/minds-i18n.js
CHANGED
|
@@ -54,7 +54,7 @@ function taskdocCanonicalCopy(language) {
|
|
|
54
54
|
'**Taskdoc 封装与访问限制**',
|
|
55
55
|
'',
|
|
56
56
|
'- 任何 `.tsk/` 目录及其子路径(`**/*.tsk/**`)都是封装状态:禁止使用任何通用文件工具读取/写入/列目录(例如 `read_file` / `write_file` / `list_dir` 等)。',
|
|
57
|
-
'- 更新 Taskdoc 只能使用函数工具 `mind_more` / `change_mind` / `never_mind
|
|
57
|
+
'- 更新 Taskdoc 只能使用函数工具 `do_mind` / `mind_more` / `change_mind` / `never_mind`:缺失章节用 `do_mind` 创建;少量新增用 `mind_more` 追加(默认 progress);需要删除陈旧项、重排或压缩时用 `change_mind` 整章替换;确需删除整章文件时用 `never_mind`。',
|
|
58
58
|
'- 读取“不会自动注入上下文”的额外章节,只能使用函数工具 `recall_taskdoc({ category, selector })`。',
|
|
59
59
|
'',
|
|
60
60
|
'**Taskdoc 自动注入规则(系统提示)**',
|
|
@@ -70,7 +70,7 @@ function taskdocCanonicalCopy(language) {
|
|
|
70
70
|
'**Taskdoc encapsulation & access restrictions**',
|
|
71
71
|
'',
|
|
72
72
|
'- Any `.tsk/` directory and its subpaths (`**/*.tsk/**`) are encapsulated state: general file tools MUST NOT read/write/list them (e.g. `read_file` / `write_file` / `list_dir`).',
|
|
73
|
-
'- Taskdoc updates MUST go through `mind_more` / `change_mind` / `never_mind`: use `mind_more` for small append-only additions (defaults to progress), use `change_mind` for full-section replacement when cleanup, reordering, or compression is needed, and use `never_mind` when a whole section file should be deleted.',
|
|
73
|
+
'- Taskdoc updates MUST go through `do_mind` / `mind_more` / `change_mind` / `never_mind`: use `do_mind` to create missing sections, use `mind_more` for small append-only additions (defaults to progress), use `change_mind` for full-section replacement when cleanup, reordering, or compression is needed, and use `never_mind` when a whole section file should be deleted.',
|
|
74
74
|
'- To read extra sections that are NOT auto-injected, use the function tool `recall_taskdoc({ category, selector })`.',
|
|
75
75
|
'',
|
|
76
76
|
'**Taskdoc auto-injection rules (system prompt)**',
|
|
@@ -148,11 +148,11 @@ function getMemoryPromptCopy(ctx) {
|
|
|
148
148
|
const taskdocLogLineZh = ctx.contextHealthPromptMode === 'critical'
|
|
149
149
|
? ctx.isSideDialog
|
|
150
150
|
? '当前是告急处置态:支线对话不要维护差遣牒,也不要整理差遣牒更新提案;把当前对话历史中下一程需要知道的讨论细节、下一步、关键定位、运行/验证信息、临时路径/ID/样例输入和恢复依据写入接续包提醒项。提醒项长度没有技术限制,宁可完整一些;允许多条粗略提醒项求稳,但不要在当前程提前做“新一程清醒复核”。系统真正开启新一程后,第一步再复核整理:删除冗余、纠正偏激/失真思路,再收敛成高质量提醒项。'
|
|
151
|
-
: '不要把长日志/大段 tool output
|
|
151
|
+
: '不要把长日志/大段 tool output 直接塞进差遣牒;差遣牒只写结论+下一步。当前是告急处置态:先检查当前对话历史里尚未落文档的讨论细节;能作为全队共享状态/决策/约束/目标的,主线优先用 `do_mind` 新增章节保存;只有在确实需要改写已有章节、且已完成合并时,才用 `change_mind`。接续包提醒项只留差遣牒仍未覆盖、但恢复工作容易丢的细节;本程允许先保留多条粗略提醒项求稳,但不要在当前程提前做“新一程清醒复核”。系统真正开启新一程后,第一步再复核整理:删除冗余、纠正偏激/失真思路,再收敛成高质量提醒项。'
|
|
152
152
|
: ctx.contextHealthPromptMode === 'caution'
|
|
153
153
|
? ctx.isSideDialog
|
|
154
154
|
? '当前是吃紧处置态:支线对话不要维护差遣牒,也不要整理差遣牒更新提案;把当前对话历史中下一程需要知道的讨论细节、下一步、关键定位、运行/验证信息、临时路径/ID/样例输入和恢复依据写入接续包提醒项。提醒项长度没有技术限制,宁可完整一些;若一时来不及,可先保留多条粗略提醒项过桥,但不要在当前程提前做“新一程清醒复核”。系统真正开启新一程后,第一步再复核整理:删除冗余、纠正偏激/失真思路,再收敛成高质量提醒项。'
|
|
155
|
-
: '不要把长日志/大段 tool output
|
|
155
|
+
: '不要把长日志/大段 tool output 直接塞进差遣牒;差遣牒只写结论+下一步。当前是吃紧处置态:先检查当前对话历史里尚未落文档的讨论细节;能作为全队共享状态/决策/约束/目标的,主线优先用 `do_mind` 新增章节保存;只有在确实需要改写已有章节、且已完成合并时,才用 `change_mind`。接续包提醒项只留差遣牒仍未覆盖、但恢复工作容易丢的细节;若一时来不及,可先保留多条粗略提醒项过桥,但不要在当前程提前做“新一程清醒复核”。系统真正开启新一程后,第一步再复核整理:删除冗余、纠正偏激/失真思路,再收敛成高质量提醒项。'
|
|
156
156
|
: '不要把长日志/大段 tool output 直接塞进差遣牒;差遣牒只写结论+下一步;提醒项也只留可扫读摘录。接续包提醒项默认应保持结构化、便于快速恢复。';
|
|
157
157
|
const contextHealthLineEn = ctx.contextHealthPromptMode === 'critical'
|
|
158
158
|
? ctx.isSideDialog
|
|
@@ -166,11 +166,11 @@ function getMemoryPromptCopy(ctx) {
|
|
|
166
166
|
const taskdocLogLineEn = ctx.contextHealthPromptMode === 'critical'
|
|
167
167
|
? ctx.isSideDialog
|
|
168
168
|
? 'Current mode is critical remediation: in a Side Dialog, do not maintain Taskdoc and do not draft Taskdoc update proposals. Put discussion details from current dialog history that the next course needs to know, next actions, key pointers, run/verify info, volatile paths/IDs/sample inputs, and resume reasoning into continuation-package reminders. Reminder length has no technical limit, so prefer being complete. Rough multi-reminder bridge notes are acceptable in this course, but do not perform the new-course “clear-headed review” early. Once the system actually starts the new course, the first step is to review/rewrite them: remove redundancy, correct biased or distorted bridge notes, then compress them into high-quality reminders.'
|
|
169
|
-
: 'Do not paste long logs/tool outputs into Taskdoc; Taskdoc should record decisions + next steps. Current mode is critical remediation: first review current-dialog discussion details not yet written into documentation. If they belong to team-shared state, decisions, constraints, or goals,
|
|
169
|
+
: 'Do not paste long logs/tool outputs into Taskdoc; Taskdoc should record decisions + next steps. Current mode is critical remediation: first review current-dialog discussion details not yet written into documentation. If they belong to team-shared state, decisions, constraints, or goals, prefer creating a new section with `do_mind`; use `change_mind` only when an existing section truly needs rewriting and you have merged against the current content. Continuation-package reminders should keep only details still not covered by Taskdoc but easy to lose during resume. Rough multi-reminder bridge notes are acceptable in this course, but do not perform the new-course “clear-headed review” early. Once the system actually starts the new course, the first step is to review/rewrite them: remove redundancy, correct biased or distorted bridge notes, then compress them into high-quality reminders.'
|
|
170
170
|
: ctx.contextHealthPromptMode === 'caution'
|
|
171
171
|
? ctx.isSideDialog
|
|
172
172
|
? 'Current mode is caution remediation: in a Side Dialog, do not maintain Taskdoc and do not draft Taskdoc update proposals. Put discussion details from current dialog history that the next course needs to know, next actions, key pointers, run/verify info, volatile paths/IDs/sample inputs, and resume reasoning into continuation-package reminders. Reminder length has no technical limit, so prefer being complete. If needed, rough multi-reminder bridge notes are acceptable, but do not perform the new-course “clear-headed review” early. Once the system actually starts the new course, the first step is to review/rewrite them: remove redundancy, correct biased or distorted bridge notes, then compress them into high-quality reminders.'
|
|
173
|
-
: 'Do not paste long logs/tool outputs into Taskdoc; Taskdoc should record decisions + next steps. Current mode is caution remediation: first review current-dialog discussion details not yet written into documentation. If they belong to team-shared state, decisions, constraints, or goals,
|
|
173
|
+
: 'Do not paste long logs/tool outputs into Taskdoc; Taskdoc should record decisions + next steps. Current mode is caution remediation: first review current-dialog discussion details not yet written into documentation. If they belong to team-shared state, decisions, constraints, or goals, prefer creating a new section with `do_mind`; use `change_mind` only when an existing section truly needs rewriting and you have merged against the current content. Continuation-package reminders should keep only details still not covered by Taskdoc but easy to lose during resume. If needed, rough multi-reminder bridge notes are acceptable, but do not perform the new-course “clear-headed review” early. Once the system actually starts the new course, the first step is to review/rewrite them: remove redundancy, correct biased or distorted bridge notes, then compress them into high-quality reminders.'
|
|
174
174
|
: 'Do not paste long logs/tool outputs into Taskdoc; Taskdoc should record decisions + next steps; reminders should also keep only scannable excerpts. Keep continuation-package reminders structured and fast to resume from by default.';
|
|
175
175
|
if (ctx.language === 'zh') {
|
|
176
176
|
return {
|
|
@@ -181,7 +181,7 @@ function getMemoryPromptCopy(ctx) {
|
|
|
181
181
|
taskdocSemanticsLine: '- 章节语义约定:`progress` 是全队共享、准实时、可扫读的任务公告牌,用来记录当前有效状态、关键决策、下一步与仍成立阻塞;不是流水账,也不是个人工作记录。`goals` / `constraints` 是较稳定的任务契约;每次更新都必须保留仍然有效的他人条目。',
|
|
182
182
|
taskdocSectionReplaceLine: ctx.isSideDialog && ctx.contextHealthPromptMode !== 'normal'
|
|
183
183
|
? '- 当前处于支线对话的上下文健康处置态:本程不要维护差遣牒,也不要整理差遣牒更新提案;把下一程需要恢复的细节写入足够详尽的接续包提醒项。'
|
|
184
|
-
: `- 更新差遣牒时:少量新增条目可用 \`mind_more\` 追加(默认 progress
|
|
184
|
+
: `- 更新差遣牒时:少量新增条目可用 \`mind_more\` 追加(默认 progress);缺失章节用 \`do_mind\` 创建;需要删除陈旧项、重排结构或压缩时,用 \`change_mind\` 整章替换并先对照“上下文中注入的当前内容”做合并;需要删除整章文件时用 \`never_mind\`;禁止覆盖/抹掉他人条目;自己负责维护的条目必须标注责任人(例如 \`- [owner:@${ctx.agentId}] ...\` 或用 \`### @${ctx.agentId}\` 分块)。`,
|
|
185
185
|
progressLine: ctx.isSideDialog && ctx.contextHealthPromptMode !== 'normal'
|
|
186
186
|
? '- 当前处于支线对话的上下文健康处置态:本程不更新 `progress`;只把下一程接续所需信息写入提醒项。'
|
|
187
187
|
: '- 更新 `progress` 时:它必须始终是可供全队扫读的完整当前快照,而不是只追加自己这一轮的零散笔记。',
|
|
@@ -193,7 +193,7 @@ function getMemoryPromptCopy(ctx) {
|
|
|
193
193
|
teamMemoryLine: '- 团队记忆:稳定的团队约定/工程规约(跨任务共享)。',
|
|
194
194
|
personalMemoryLine: '- 个人记忆:稳定的个人习惯/偏好与职责域知识;记忆会在每次生成时自动注入上下文,应保持少量且准确(关键文档/代码的精确路径 + 最小必要事实)。不要记录具体任务状态。',
|
|
195
195
|
sideDialogDutyLine: ctx.contextHealthPromptMode === 'normal'
|
|
196
|
-
? `你当前处于支线对话:此处不允许 \`mind_more\` / \`change_mind\` / \`never_mind\`。当你判断需要更新差遣牒(尤其是 progress 公告牌)时,请在合适时机直接诉请差遣牒维护人 \`@${ctx.taskdocMaintainerId}\`
|
|
196
|
+
? `你当前处于支线对话:此处不允许 \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\`。当你判断需要更新差遣牒(尤其是 progress 公告牌)时,请在合适时机直接诉请差遣牒维护人 \`@${ctx.taskdocMaintainerId}\` 执行更新,并给出要新增的章节、要追加的条目、已合并好的“新全文/替换稿”,或要删除的章节。不要声称已更新,除非看到回执。`
|
|
197
197
|
: '你当前处于支线对话,且上下文已进入吃紧/告急处置态:本程不要维护差遣牒,也不要整理差遣牒更新提案。请把下一程需要恢复的讨论细节、定位、验证方式和临时信息写入足够详尽的接续包提醒项。',
|
|
198
198
|
mainDialogDutyLine: '你当前处于主线对话:你负责综合维护全队共享差遣牒(尤其是 progress 公告牌)。当队友/支线对话提出更新建议时,及时合并、压缩并保持清晰。',
|
|
199
199
|
teammateTellaskRoundDoneLine: `队友诉请重要语义:当你在诉请者上下文中收到带${runtimeMarkers.finalCompleted}标记的回贴,表示该轮诉请已经结束;对方不会继续执行同一轮诉请。此时如果目标未达成,“等待”是错误的:必须显式发起新一轮 tellask 才能继续推进。`,
|
|
@@ -215,7 +215,7 @@ function getMemoryPromptCopy(ctx) {
|
|
|
215
215
|
taskdocSemanticsLine: '- Section semantics: `progress` is the team-shared, quasi-real-time, scannable task bulletin board for current effective state, key decisions, next steps, and still-active blockers; it is not a raw log or personal work record. `goals` / `constraints` are the more stable task contract; every update must preserve still-valid entries from others.',
|
|
216
216
|
taskdocSectionReplaceLine: ctx.isSideDialog && ctx.contextHealthPromptMode !== 'normal'
|
|
217
217
|
? '- Current mode is context-health remediation in a Side Dialog: do not maintain Taskdoc and do not draft Taskdoc update proposals in this course; put resume-critical details into sufficiently detailed continuation-package reminders.'
|
|
218
|
-
: `- When updating Taskdoc: use \`mind_more\` for small append-only additions (defaults to progress); when stale entries must be removed, reordered, or compressed, use \`change_mind\` for a full-section replacement based on the current injected content; when a whole section file should be removed, use \`never_mind\`; do not overwrite other contributors; add an explicit owner tag for entries you maintain (e.g., \`- [owner:@${ctx.agentId}] ...\` or a \`### @${ctx.agentId}\` block).`,
|
|
218
|
+
: `- When updating Taskdoc: use \`mind_more\` for small append-only additions (defaults to progress); create missing sections with \`do_mind\`; when stale entries must be removed, reordered, or compressed, use \`change_mind\` for a full-section replacement based on the current injected content; when a whole section file should be removed, use \`never_mind\`; do not overwrite other contributors; add an explicit owner tag for entries you maintain (e.g., \`- [owner:@${ctx.agentId}] ...\` or a \`### @${ctx.agentId}\` block).`,
|
|
219
219
|
progressLine: ctx.isSideDialog && ctx.contextHealthPromptMode !== 'normal'
|
|
220
220
|
? '- Current mode is context-health remediation in a Side Dialog: do not update `progress` in this course; put resume-critical information into reminders only.'
|
|
221
221
|
: '- When updating `progress`, keep it as a complete, team-scannable current snapshot instead of appending only your own latest notes.',
|
|
@@ -227,7 +227,7 @@ function getMemoryPromptCopy(ctx) {
|
|
|
227
227
|
teamMemoryLine: '- Team memory: stable shared conventions (cross-task).',
|
|
228
228
|
personalMemoryLine: '- Personal memory: stable personal habits/preferences and responsibility-scope knowledge. Memory is automatically injected into context on each generation: keep it small and accurate (exact key doc/code paths + minimal key facts); do not store per-task state.',
|
|
229
229
|
sideDialogDutyLine: ctx.contextHealthPromptMode === 'normal'
|
|
230
|
-
? `You are currently in a Side Dialog: \`mind_more\` / \`change_mind\` / \`never_mind\` are not allowed here. When Taskdoc should be updated (especially the shared progress bulletin board), tellask the Taskdoc maintainer \`@${ctx.taskdocMaintainerId}\` with entries to append, a fully merged replacement draft, or the section to delete. Do not claim it is updated until you see a receipt.`
|
|
230
|
+
? `You are currently in a Side Dialog: \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\` are not allowed here. When Taskdoc should be updated (especially the shared progress bulletin board), tellask the Taskdoc maintainer \`@${ctx.taskdocMaintainerId}\` with the new section to create, entries to append, a fully merged replacement draft, or the section to delete. Do not claim it is updated until you see a receipt.`
|
|
231
231
|
: 'You are currently in a Side Dialog under caution/critical context-health remediation: do not maintain Taskdoc and do not draft Taskdoc update proposals in this course. Put discussion details, pointers, verification method, and volatile resume information into sufficiently detailed continuation-package reminders.',
|
|
232
232
|
mainDialogDutyLine: 'You are currently in the Main Dialog: you are responsible for keeping the team-shared Taskdoc coherent and up to date (especially the progress bulletin board). Merge proposals from teammates/Side Dialogs promptly and keep it concise.',
|
|
233
233
|
teammateTellaskRoundDoneLine: `Teammate Tellask semantics: when you receive a tellasker reply with the ${runtimeMarkers.finalCompleted} marker, that Tellask round is finished; the tellaskee will not keep executing the same call in the background. If the objective is not met, “waiting” is wrong: you must explicitly start a new Tellask round to continue.`,
|
|
@@ -406,7 +406,8 @@ function formatAgentFacingContextHealthV3RemediationGuide(language, args) {
|
|
|
406
406
|
'当前已处于吃紧处置阶段:不要继续扩张上下文,也不要提前进入“按接续包做清醒复核”的模式;那是系统真正开启新一程后的第一步。当前程的目标是先把未落文档的讨论细节补进差遣牒,再把差遣牒仍未覆盖、但恢复工作会丢的信息带过桥;真正清理冗余、合并提醒项,放到新一程再做。然后主动 clear_mind,开启新一程对话继续工作。',
|
|
407
407
|
'',
|
|
408
408
|
'操作:',
|
|
409
|
-
'-
|
|
409
|
+
'- 优先新增差遣牒章节保存讨论细节:do_mind({ "category": "<category>", "selector": "<selector>", "content": "..." })',
|
|
410
|
+
'- 只有在确实需要改写已有章节、且已对照当前差遣牒内容完成合并时,才更新:change_mind({ ... })',
|
|
410
411
|
'- 优先新增过桥提醒项:add_reminder({ "content": "..." })',
|
|
411
412
|
'- 只有在确实能就地复用现有提醒项、且不会额外增加当前程认知负担时,才更新:update_reminder({ "reminder_id": "<现有 reminder_id>", "content": "..." })',
|
|
412
413
|
].join('\n');
|
|
@@ -441,7 +442,8 @@ function formatAgentFacingContextHealthV3RemediationGuide(language, args) {
|
|
|
441
442
|
'行动:你当前处于主线对话。尽快保住易丢信息,然后 clear_mind。当前处于告急处置阶段时,先把当前对话历史中尚未落实到文档、且下一程需要知会的讨论细节落到差遣牒合适章节。然后再把差遣牒仍未覆盖、但恢复工作会丢的信息新增提醒项带过桥;允许先保留多条粗略提醒项,甚至带一定冗余也可以,不必在当前程强行整理干净。',
|
|
442
443
|
'',
|
|
443
444
|
'操作:',
|
|
444
|
-
'-
|
|
445
|
+
'- 优先新增差遣牒章节保存讨论细节:do_mind({ "category": "<category>", "selector": "<selector>", "content": "..." })',
|
|
446
|
+
'- 只有在确实需要改写已有章节、且已对照当前差遣牒内容完成合并时,才更新:change_mind({ ... })',
|
|
445
447
|
'- 优先新增过桥提醒项:add_reminder({ "content": "..." })',
|
|
446
448
|
'- 只有在确实能就地复用现有提醒项、且不会额外增加当前程认知负担时,才更新:update_reminder({ "reminder_id": "<现有 reminder_id>", "content": "..." })',
|
|
447
449
|
'- clear_mind({})',
|
|
@@ -481,7 +483,8 @@ function formatAgentFacingContextHealthV3RemediationGuide(language, args) {
|
|
|
481
483
|
'You are already in caution remediation for the current course, so do not keep expanding context and do not switch early into “clear-headed continuation-package review” mode; that is the first step only after the system actually starts the new course. In the current course, the goal is to first fill Taskdoc with undocumented discussion details, then carry forward details still not covered by Taskdoc; reminder cleanup and dedup belong to the new course. Then proactively clear_mind to start a new dialog course.',
|
|
482
484
|
'',
|
|
483
485
|
'Operations:',
|
|
484
|
-
'-
|
|
486
|
+
'- Prefer creating a new Taskdoc section for discussion details: do_mind({ "category": "<category>", "selector": "<selector>", "content": "..." })',
|
|
487
|
+
'- Only update when an existing section truly needs rewriting and you have merged against the current Taskdoc content: change_mind({ ... })',
|
|
485
488
|
'- Prefer adding a bridge reminder first: add_reminder({ "content": "..." })',
|
|
486
489
|
'- Only if an existing reminder is clearly the right place, and updating it would not add extra cognitive load in the current course: update_reminder({ "reminder_id": "<existing reminder_id>", "content": "..." })',
|
|
487
490
|
].join('\n');
|
|
@@ -516,7 +519,8 @@ function formatAgentFacingContextHealthV3RemediationGuide(language, args) {
|
|
|
516
519
|
'Action: you are in the Main Dialog. Preserve easy-to-lose information, then clear_mind. In critical remediation, first record current-dialog discussion details that are not yet documented but the next course needs to know into the appropriate Taskdoc sections. Then add bridge reminders for information still not covered by Taskdoc but easy to lose. Multiple rough reminders, including some redundancy, are acceptable as a bridge; do not spend the current course forcing them into a clean final package.',
|
|
517
520
|
'',
|
|
518
521
|
'Operations:',
|
|
519
|
-
'-
|
|
522
|
+
'- Prefer creating a new Taskdoc section for discussion details: do_mind({ "category": "<category>", "selector": "<selector>", "content": "..." })',
|
|
523
|
+
'- Only update when an existing section truly needs rewriting and you have merged against the current Taskdoc content: change_mind({ ... })',
|
|
520
524
|
'- Prefer adding a bridge reminder first: add_reminder({ "content": "..." })',
|
|
521
525
|
'- Only if an existing reminder is clearly the right place, and updating it would not add extra cognitive load in the current course: update_reminder({ "reminder_id": "<existing reminder_id>", "content": "..." })',
|
|
522
526
|
'- clear_mind({})',
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const DEFAULT_WEBUI_PORT = 5666;
|
|
2
|
+
export declare const MIN_AUTO_WEBUI_PORT = 1024;
|
|
3
|
+
export type WebuiPortAutoDirection = 'down' | 'up';
|
|
4
|
+
export type ParsedPortSpec = {
|
|
5
|
+
port: number;
|
|
6
|
+
strictPort: boolean;
|
|
7
|
+
portAutoDirection: WebuiPortAutoDirection;
|
|
8
|
+
};
|
|
9
|
+
export declare function parseWebuiPortSpec(raw: string): ParsedPortSpec | null;
|
|
10
|
+
export declare function validateWebuiPort(port: number, context: string): void;
|
|
11
|
+
export declare function buildWebuiPortCandidates(params: {
|
|
12
|
+
preferredPort: number;
|
|
13
|
+
strictPort: boolean;
|
|
14
|
+
direction: WebuiPortAutoDirection;
|
|
15
|
+
}): number[];
|
|
16
|
+
export declare function formatWebuiPortScanBound(params: {
|
|
17
|
+
preferredPort: number;
|
|
18
|
+
direction: WebuiPortAutoDirection;
|
|
19
|
+
}): string;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MIN_AUTO_WEBUI_PORT = exports.DEFAULT_WEBUI_PORT = void 0;
|
|
4
|
+
exports.parseWebuiPortSpec = parseWebuiPortSpec;
|
|
5
|
+
exports.validateWebuiPort = validateWebuiPort;
|
|
6
|
+
exports.buildWebuiPortCandidates = buildWebuiPortCandidates;
|
|
7
|
+
exports.formatWebuiPortScanBound = formatWebuiPortScanBound;
|
|
8
|
+
exports.DEFAULT_WEBUI_PORT = 5666;
|
|
9
|
+
exports.MIN_AUTO_WEBUI_PORT = 1024;
|
|
10
|
+
function parseWebuiPortSpec(raw) {
|
|
11
|
+
let numericText = raw;
|
|
12
|
+
let strictPort = true;
|
|
13
|
+
let portAutoDirection = 'down';
|
|
14
|
+
if (raw.endsWith('+')) {
|
|
15
|
+
numericText = raw.slice(0, -1);
|
|
16
|
+
strictPort = false;
|
|
17
|
+
portAutoDirection = 'up';
|
|
18
|
+
}
|
|
19
|
+
else if (raw.endsWith('-')) {
|
|
20
|
+
numericText = raw.slice(0, -1);
|
|
21
|
+
strictPort = false;
|
|
22
|
+
portAutoDirection = 'down';
|
|
23
|
+
}
|
|
24
|
+
if (!/^[0-9]+$/.test(numericText))
|
|
25
|
+
return null;
|
|
26
|
+
const port = Number(numericText);
|
|
27
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535)
|
|
28
|
+
return null;
|
|
29
|
+
return { port, strictPort, portAutoDirection };
|
|
30
|
+
}
|
|
31
|
+
function validateWebuiPort(port, context) {
|
|
32
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
33
|
+
throw new Error(`${context} must be an integer in [0, 65535] (got ${String(port)})`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function buildWebuiPortCandidates(params) {
|
|
37
|
+
validateWebuiPort(params.preferredPort, 'WebUI port');
|
|
38
|
+
if (params.strictPort || params.preferredPort === 0)
|
|
39
|
+
return [params.preferredPort];
|
|
40
|
+
const candidates = [params.preferredPort];
|
|
41
|
+
if (params.direction === 'down') {
|
|
42
|
+
for (let candidate = params.preferredPort - 1; candidate >= exports.MIN_AUTO_WEBUI_PORT; candidate -= 1) {
|
|
43
|
+
candidates.push(candidate);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
for (let candidate = params.preferredPort + 1; candidate <= 65535; candidate += 1) {
|
|
48
|
+
candidates.push(candidate);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return candidates;
|
|
52
|
+
}
|
|
53
|
+
function formatWebuiPortScanBound(params) {
|
|
54
|
+
return params.direction === 'down'
|
|
55
|
+
? `down to ${Math.min(params.preferredPort, exports.MIN_AUTO_WEBUI_PORT)}`
|
|
56
|
+
: 'up to 65535';
|
|
57
|
+
}
|
|
@@ -46,9 +46,9 @@ export declare class HttpServerCore {
|
|
|
46
46
|
private sendError;
|
|
47
47
|
private sendUnauthorized;
|
|
48
48
|
/**
|
|
49
|
-
* Start the server
|
|
49
|
+
* Start the server on the configured port.
|
|
50
50
|
*/
|
|
51
|
-
start(): Promise<
|
|
51
|
+
start(): Promise<number>;
|
|
52
52
|
/**
|
|
53
53
|
* Stop the server
|
|
54
54
|
*/
|
|
@@ -182,17 +182,31 @@ class HttpServerCore {
|
|
|
182
182
|
res.end(JSON.stringify({ error: 'unauthorized' }));
|
|
183
183
|
}
|
|
184
184
|
/**
|
|
185
|
-
* Start the server
|
|
185
|
+
* Start the server on the configured port.
|
|
186
186
|
*/
|
|
187
187
|
start() {
|
|
188
188
|
return new Promise((resolve, reject) => {
|
|
189
|
-
|
|
189
|
+
const cleanup = () => {
|
|
190
|
+
this.server.off('error', onError);
|
|
191
|
+
this.server.off('listening', onListening);
|
|
192
|
+
};
|
|
193
|
+
const onError = (error) => {
|
|
194
|
+
cleanup();
|
|
190
195
|
reject(error);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
+
};
|
|
197
|
+
const onListening = () => {
|
|
198
|
+
cleanup();
|
|
199
|
+
const address = this.server.address();
|
|
200
|
+
const actualPort = typeof address === 'object' && address !== null
|
|
201
|
+
? address.port
|
|
202
|
+
: this.config.port;
|
|
203
|
+
this.config = { ...this.config, port: actualPort };
|
|
204
|
+
log.debug(`Server listening on http://${this.config.host}:${actualPort}`);
|
|
205
|
+
resolve(actualPort);
|
|
206
|
+
};
|
|
207
|
+
this.server.once('error', onError);
|
|
208
|
+
this.server.once('listening', onListening);
|
|
209
|
+
this.server.listen(this.config.port, this.config.host);
|
|
196
210
|
});
|
|
197
211
|
}
|
|
198
212
|
/**
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AuthConfig } from './server/auth';
|
|
2
|
+
import { type WebuiPortAutoDirection } from './server/port-selection';
|
|
2
3
|
import { HttpServerCore } from './server/server-core';
|
|
3
4
|
import './tools/builtins';
|
|
4
5
|
export type ServerOptions = {
|
|
@@ -6,6 +7,8 @@ export type ServerOptions = {
|
|
|
6
7
|
host?: string;
|
|
7
8
|
mode?: 'dev' | 'prod';
|
|
8
9
|
startBackendDriver?: boolean;
|
|
10
|
+
strictPort?: boolean;
|
|
11
|
+
portAutoDirection?: WebuiPortAutoDirection;
|
|
9
12
|
};
|
|
10
13
|
export type StartedServer = {
|
|
11
14
|
httpServer: HttpServerCore;
|
package/dist/server.js
CHANGED
|
@@ -42,7 +42,7 @@ exports.startServer = startServer;
|
|
|
42
42
|
* - Provides `/api/*` endpoints and `/ws` WebSocket communication
|
|
43
43
|
* - CLI bootstrap with optional cwd/port/host/mode parameters
|
|
44
44
|
* - Development mode: `tsx --watch src/server.ts -p <port> --mode dev`
|
|
45
|
-
* - Production mode: `node dist/server.js` (default port 5666)
|
|
45
|
+
* - Production mode: `node dist/server.js` (default port behavior: 5666-)
|
|
46
46
|
*/
|
|
47
47
|
const path = __importStar(require("path"));
|
|
48
48
|
const runtime_1 = require("./apps/runtime");
|
|
@@ -54,6 +54,7 @@ const reply_special_1 = require("./recovery/reply-special");
|
|
|
54
54
|
const work_language_1 = require("./runtime/work-language");
|
|
55
55
|
const auth_1 = require("./server/auth");
|
|
56
56
|
const dominds_self_update_1 = require("./server/dominds-self-update");
|
|
57
|
+
const port_selection_1 = require("./server/port-selection");
|
|
57
58
|
const server_core_1 = require("./server/server-core");
|
|
58
59
|
const websocket_handler_1 = require("./server/websocket-handler");
|
|
59
60
|
require("./tools/builtins");
|
|
@@ -87,74 +88,131 @@ function parseArgs(argv) {
|
|
|
87
88
|
i++;
|
|
88
89
|
continue;
|
|
89
90
|
}
|
|
91
|
+
if (a.startsWith('--port=')) {
|
|
92
|
+
out['p'] = a.slice('--port='.length);
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
90
95
|
if (a === '-H' || a === '--host') {
|
|
91
96
|
out['H'] = argv[i + 1];
|
|
92
97
|
i++;
|
|
93
98
|
continue;
|
|
94
99
|
}
|
|
100
|
+
if (a.startsWith('--host=')) {
|
|
101
|
+
out['H'] = a.slice('--host='.length);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
95
104
|
if (a === '--mode') {
|
|
96
105
|
out['mode'] = argv[i + 1];
|
|
97
106
|
i++;
|
|
98
107
|
continue;
|
|
99
108
|
}
|
|
109
|
+
if (a.startsWith('--mode=')) {
|
|
110
|
+
out['mode'] = a.slice('--mode='.length);
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
100
113
|
}
|
|
101
114
|
return out;
|
|
102
115
|
}
|
|
116
|
+
function getErrnoCode(error) {
|
|
117
|
+
if (!(error instanceof Error))
|
|
118
|
+
return undefined;
|
|
119
|
+
const withCode = error;
|
|
120
|
+
return typeof withCode.code === 'string' ? withCode.code : undefined;
|
|
121
|
+
}
|
|
103
122
|
async function startServer(opts = {}) {
|
|
104
123
|
const { language: resolvedLanguage, source } = (0, work_language_1.resolveWorkLanguage)({ env: process.env });
|
|
105
124
|
(0, work_language_1.setWorkLanguage)(resolvedLanguage);
|
|
106
125
|
// Get port and host from options
|
|
107
126
|
const mode = opts.mode || 'prod';
|
|
108
|
-
const
|
|
127
|
+
const preferredPort = opts.port ?? port_selection_1.DEFAULT_WEBUI_PORT;
|
|
128
|
+
const strictPort = opts.strictPort ?? opts.port !== undefined;
|
|
129
|
+
const portAutoDirection = opts.portAutoDirection ?? 'down';
|
|
109
130
|
const host = opts.host || '127.0.0.1';
|
|
110
131
|
const startBackendDriver = opts.startBackendDriver ?? true;
|
|
111
|
-
|
|
132
|
+
const portCandidates = (0, port_selection_1.buildWebuiPortCandidates)({
|
|
133
|
+
preferredPort,
|
|
134
|
+
strictPort,
|
|
135
|
+
direction: portAutoDirection,
|
|
136
|
+
});
|
|
137
|
+
log.info(`Starting server in ${mode} mode on ${host}:${preferredPort} (${strictPort ? 'strict port' : `auto port ${portAutoDirection}`}; working language: ${(0, work_language_1.getWorkLanguage)()} from ${source})`);
|
|
112
138
|
// WebSocket clients set
|
|
113
139
|
const clients = new Set();
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
mode:
|
|
117
|
-
|
|
118
|
-
host,
|
|
119
|
-
port,
|
|
120
|
-
clients,
|
|
121
|
-
auth: (0, auth_1.computeAuthConfig)({
|
|
122
|
-
mode: mode === 'dev' ? 'development' : 'production',
|
|
123
|
-
env: process.env,
|
|
124
|
-
}),
|
|
125
|
-
};
|
|
126
|
-
const auth = config.auth ?? { kind: 'disabled' };
|
|
127
|
-
// Create HTTP server
|
|
128
|
-
const httpServer = (0, server_core_1.createHttpServer)(config);
|
|
129
|
-
(0, dominds_self_update_1.configureDomindsSelfUpdate)({
|
|
130
|
-
host,
|
|
131
|
-
port,
|
|
132
|
-
mode: config.mode,
|
|
133
|
-
stopServer: async () => {
|
|
134
|
-
await httpServer.stop();
|
|
135
|
-
},
|
|
140
|
+
const serverMode = mode === 'dev' ? 'development' : 'production';
|
|
141
|
+
const auth = (0, auth_1.computeAuthConfig)({
|
|
142
|
+
mode: serverMode,
|
|
143
|
+
env: process.env,
|
|
136
144
|
});
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
145
|
+
let startedCore = null;
|
|
146
|
+
let boundPort = null;
|
|
147
|
+
for (const candidatePort of portCandidates) {
|
|
148
|
+
const config = {
|
|
149
|
+
mode: serverMode,
|
|
150
|
+
staticRoot: 'webapp/dist',
|
|
151
|
+
host,
|
|
152
|
+
port: candidatePort,
|
|
153
|
+
clients,
|
|
154
|
+
auth,
|
|
155
|
+
};
|
|
156
|
+
const candidateServer = (0, server_core_1.createHttpServer)(config);
|
|
157
|
+
try {
|
|
158
|
+
boundPort = await candidateServer.start();
|
|
159
|
+
(0, websocket_handler_1.setupWebSocketServer)(candidateServer.getHttpServer(), clients, auth, (0, work_language_1.getWorkLanguage)(), config.mode);
|
|
160
|
+
startedCore = candidateServer;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
if (!strictPort && getErrnoCode(error) === 'EADDRINUSE') {
|
|
165
|
+
const nextDirection = portAutoDirection === 'down' ? 'lower' : 'higher';
|
|
166
|
+
log.warn(`WebUI port ${candidatePort} is already in use; trying the next ${nextDirection} port`);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (boundPort !== null && startedCore === null) {
|
|
170
|
+
await candidateServer.stop();
|
|
171
|
+
}
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (startedCore === null || boundPort === null) {
|
|
176
|
+
const boundText = (0, port_selection_1.formatWebuiPortScanBound)({
|
|
177
|
+
preferredPort,
|
|
178
|
+
direction: portAutoDirection,
|
|
179
|
+
});
|
|
180
|
+
throw new Error(`Failed to start WebUI: no available port found from ${preferredPort} ${boundText}`);
|
|
181
|
+
}
|
|
182
|
+
if (!strictPort && boundPort !== preferredPort) {
|
|
183
|
+
log.warn(`WebUI preferred port ${preferredPort} was unavailable; listening on ${boundPort}`);
|
|
184
|
+
}
|
|
142
185
|
try {
|
|
143
|
-
|
|
186
|
+
(0, dominds_self_update_1.configureDomindsSelfUpdate)({
|
|
187
|
+
host,
|
|
188
|
+
port: boundPort,
|
|
189
|
+
mode: serverMode,
|
|
190
|
+
stopServer: async () => {
|
|
191
|
+
await startedCore.stop();
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
// MCP is best-effort: startup must not be blocked by MCP config/server issues.
|
|
195
|
+
(0, supervisor_1.startMcpSupervisor)();
|
|
196
|
+
// Apps host is optional for server boot: app failures must stay loud, but they must not block WebUI startup.
|
|
197
|
+
try {
|
|
198
|
+
await (0, runtime_1.initAppsRuntime)({ rtwsRootAbs: process.cwd(), kernel: { host, port: boundPort } });
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
log.warn('Apps runtime initialization failed during server startup; continuing without app runtime capabilities until the app issue is fixed', error instanceof Error ? error : new Error(String(error)));
|
|
202
|
+
}
|
|
203
|
+
// Crash recovery: any dialogs left in "proceeding" state are surfaced as interrupted/resumable.
|
|
204
|
+
await (0, dialog_display_state_1.reconcileDisplayStatesAfterRestart)();
|
|
205
|
+
await (0, reply_special_1.recoverPendingReplyTellaskCallsAfterRestart)();
|
|
206
|
+
// Tests may opt out so the process can shut down cleanly without a driver stop API.
|
|
207
|
+
if (startBackendDriver) {
|
|
208
|
+
void (0, kernel_driver_1.runBackendDriver)();
|
|
209
|
+
}
|
|
144
210
|
}
|
|
145
211
|
catch (error) {
|
|
146
|
-
|
|
212
|
+
await startedCore.stop();
|
|
213
|
+
throw error;
|
|
147
214
|
}
|
|
148
|
-
|
|
149
|
-
await (0, dialog_display_state_1.reconcileDisplayStatesAfterRestart)();
|
|
150
|
-
await (0, reply_special_1.recoverPendingReplyTellaskCallsAfterRestart)();
|
|
151
|
-
// Tests may opt out so the process can shut down cleanly without a driver stop API.
|
|
152
|
-
if (startBackendDriver) {
|
|
153
|
-
void (0, kernel_driver_1.runBackendDriver)();
|
|
154
|
-
}
|
|
155
|
-
// Start listening
|
|
156
|
-
await httpServer.start();
|
|
157
|
-
return { httpServer, auth, host, port, mode };
|
|
215
|
+
return { httpServer: startedCore, auth, host, port: boundPort, mode };
|
|
158
216
|
}
|
|
159
217
|
// Main function for CLI execution
|
|
160
218
|
async function main() {
|
|
@@ -172,10 +230,17 @@ async function main() {
|
|
|
172
230
|
}
|
|
173
231
|
}
|
|
174
232
|
// Get port, host, and mode from CLI args
|
|
175
|
-
const
|
|
233
|
+
const portSpecRaw = cliArgs['p'];
|
|
234
|
+
const parsedPort = typeof portSpecRaw === 'string' ? (0, port_selection_1.parseWebuiPortSpec)(portSpecRaw) : undefined;
|
|
235
|
+
if (portSpecRaw !== undefined && parsedPort === null) {
|
|
236
|
+
throw new Error('Invalid --port value: expected a port number, optionally suffixed with + or -');
|
|
237
|
+
}
|
|
238
|
+
const port = parsedPort?.port;
|
|
239
|
+
const strictPort = parsedPort?.strictPort;
|
|
240
|
+
const portAutoDirection = parsedPort?.portAutoDirection;
|
|
176
241
|
const host = cliArgs['H'] || undefined;
|
|
177
242
|
const mode = cliArgs['mode'] || undefined;
|
|
178
|
-
await startServer({ port, host, mode });
|
|
243
|
+
await startServer({ port, host, mode, strictPort, portAutoDirection });
|
|
179
244
|
}
|
|
180
245
|
// Start server if this file is run directly
|
|
181
246
|
if (require.main === module) {
|
package/dist/team.d.ts
CHANGED
|
@@ -152,9 +152,8 @@ export declare namespace Team {
|
|
|
152
152
|
setStreaming(streaming: boolean | undefined): void;
|
|
153
153
|
setHidden(hidden: boolean | undefined): void;
|
|
154
154
|
/**
|
|
155
|
-
* Returns a flat list of
|
|
156
|
-
* Honors declaration order
|
|
157
|
-
* that resolve to different Tool objects. Returns no duplicate tools per name.
|
|
155
|
+
* Returns a flat list of assignable toolset names after expanding wildcards and exclusions.
|
|
156
|
+
* Honors declaration order and returns each toolset at most once.
|
|
158
157
|
*/
|
|
159
158
|
listResolvedToolsetNames(options?: {
|
|
160
159
|
onMissing?: 'warn' | 'silent';
|