dominds 0.6.2 → 0.6.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/dist/access-control.js +2 -2
- package/dist/agent-priming.js +826 -92
- package/dist/cli/read.js +406 -12
- package/dist/dialog.js +4 -0
- package/dist/docs/design.md +1 -0
- package/dist/docs/design.zh.md +1 -0
- package/dist/docs/dialog-system.md +12 -7
- package/dist/docs/dialog-system.zh.md +7 -3
- package/dist/docs/dominds-agent-priming.md +10 -1
- package/dist/docs/dominds-agent-priming.zh.md +9 -1
- package/dist/docs/dominds-terminology.md +8 -8
- package/dist/docs/fbr-implementation.md +77 -0
- package/dist/docs/fbr-implementation.zh.md +77 -0
- package/dist/docs/fbr.md +142 -141
- package/dist/docs/fbr.zh.md +129 -123
- package/dist/docs/keep-going.zh.md +162 -0
- package/dist/docs/showing-by-doing.md +208 -0
- package/dist/docs/showing-by-doing.zh.md +177 -0
- package/dist/docs/tellask-collab.md +250 -0
- package/dist/docs/tellask-collab.zh.md +254 -0
- package/dist/docs/txt-editing-tools.md +2 -2
- package/dist/docs/txt-editing-tools.zh.md +2 -2
- package/dist/llm/defaults.yaml +82 -4
- package/dist/llm/driver.js +280 -104
- package/dist/llm/gen/codex.js +49 -2
- package/dist/log.js +385 -30
- package/dist/mcp/supervisor.js +113 -40
- package/dist/minds/builtin/pangu/persona.zh.md +2 -2
- package/dist/minds/load.js +49 -284
- package/dist/minds/minds-i18n.js +2 -2
- package/dist/minds/promptdocs.js +263 -0
- package/dist/minds/system-prompt-parts.js +231 -0
- package/dist/minds/system-prompt.js +190 -223
- package/dist/persistence.js +66 -1
- package/dist/server/websocket-handler.js +14 -0
- package/dist/shared/diligence.js +40 -6
- package/dist/shared/utils/inter-dialog-format.js +3 -5
- package/dist/showing-by-doing.js +34 -31
- package/dist/snippets/README.en.md +3 -0
- package/dist/static/assets/{_baseUniq-C9vbtHF9.js → _baseUniq-C7IpU2Uk.js} +2 -2
- package/dist/static/assets/{_baseUniq-C9vbtHF9.js.map → _baseUniq-C7IpU2Uk.js.map} +1 -1
- package/dist/static/assets/{arc-hulXG01i.js → arc-1bhQqjON.js} +2 -2
- package/dist/static/assets/{arc-hulXG01i.js.map → arc-1bhQqjON.js.map} +1 -1
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-DdLIAMT5.js → architectureDiagram-VXUJARFQ-CkEi1QpB.js} +6 -6
- package/dist/static/assets/{architectureDiagram-VXUJARFQ-DdLIAMT5.js.map → architectureDiagram-VXUJARFQ-CkEi1QpB.js.map} +1 -1
- package/dist/static/assets/{blockDiagram-VD42YOAC-DACsx66C.js → blockDiagram-VD42YOAC-DaBQ5-pY.js} +7 -7
- package/dist/static/assets/{blockDiagram-VD42YOAC-DACsx66C.js.map → blockDiagram-VD42YOAC-DaBQ5-pY.js.map} +1 -1
- package/dist/static/assets/{c4Diagram-YG6GDRKO-Cd5xZlLy.js → c4Diagram-YG6GDRKO-ChUgpgkP.js} +3 -3
- package/dist/static/assets/{c4Diagram-YG6GDRKO-Cd5xZlLy.js.map → c4Diagram-YG6GDRKO-ChUgpgkP.js.map} +1 -1
- package/dist/static/assets/{channel-NQehis0Z.js → channel-CxvmwllM.js} +2 -2
- package/dist/static/assets/{channel-NQehis0Z.js.map → channel-CxvmwllM.js.map} +1 -1
- package/dist/static/assets/{chunk-4BX2VUAB-DZDPl76b.js → chunk-4BX2VUAB-CKsrU2yk.js} +2 -2
- package/dist/static/assets/{chunk-4BX2VUAB-DZDPl76b.js.map → chunk-4BX2VUAB-CKsrU2yk.js.map} +1 -1
- package/dist/static/assets/{chunk-55IACEB6-CFSRDUbl.js → chunk-55IACEB6-BAau9SFt.js} +2 -2
- package/dist/static/assets/{chunk-55IACEB6-CFSRDUbl.js.map → chunk-55IACEB6-BAau9SFt.js.map} +1 -1
- package/dist/static/assets/{chunk-B4BG7PRW-BqQQ9M_z.js → chunk-B4BG7PRW--IiJ7W1m.js} +5 -5
- package/dist/static/assets/{chunk-B4BG7PRW-BqQQ9M_z.js.map → chunk-B4BG7PRW--IiJ7W1m.js.map} +1 -1
- package/dist/static/assets/{chunk-DI55MBZ5-FiFzz1Gh.js → chunk-DI55MBZ5-B83KrPQj.js} +4 -4
- package/dist/static/assets/{chunk-DI55MBZ5-FiFzz1Gh.js.map → chunk-DI55MBZ5-B83KrPQj.js.map} +1 -1
- package/dist/static/assets/{chunk-FMBD7UC4-DqqtCyWK.js → chunk-FMBD7UC4-BlDXzeza.js} +2 -2
- package/dist/static/assets/{chunk-FMBD7UC4-DqqtCyWK.js.map → chunk-FMBD7UC4-BlDXzeza.js.map} +1 -1
- package/dist/static/assets/{chunk-QN33PNHL-F0laQQ-J.js → chunk-QN33PNHL-B596W_v7.js} +2 -2
- package/dist/static/assets/{chunk-QN33PNHL-F0laQQ-J.js.map → chunk-QN33PNHL-B596W_v7.js.map} +1 -1
- package/dist/static/assets/{chunk-QZHKN3VN-CWhEZPaV.js → chunk-QZHKN3VN-UBBCxgBb.js} +2 -2
- package/dist/static/assets/{chunk-QZHKN3VN-CWhEZPaV.js.map → chunk-QZHKN3VN-UBBCxgBb.js.map} +1 -1
- package/dist/static/assets/{chunk-TZMSLE5B-Dx9cnwUy.js → chunk-TZMSLE5B-D-wCX2wJ.js} +2 -2
- package/dist/static/assets/{chunk-TZMSLE5B-Dx9cnwUy.js.map → chunk-TZMSLE5B-D-wCX2wJ.js.map} +1 -1
- package/dist/static/assets/{classDiagram-2ON5EDUG-Dp-dyEGy.js → classDiagram-2ON5EDUG-DvtmzPcu.js} +6 -6
- package/dist/static/assets/{classDiagram-2ON5EDUG-Dp-dyEGy.js.map → classDiagram-2ON5EDUG-DvtmzPcu.js.map} +1 -1
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-Dp-dyEGy.js → classDiagram-v2-WZHVMYZB-DvtmzPcu.js} +6 -6
- package/dist/static/assets/{classDiagram-v2-WZHVMYZB-Dp-dyEGy.js.map → classDiagram-v2-WZHVMYZB-DvtmzPcu.js.map} +1 -1
- package/dist/static/assets/{clone-C6mKvxs5.js → clone-DgJ0ZR-k.js} +2 -2
- package/dist/static/assets/{clone-C6mKvxs5.js.map → clone-DgJ0ZR-k.js.map} +1 -1
- package/dist/static/assets/{cose-bilkent-S5V4N54A-Dbwh3GoX.js → cose-bilkent-S5V4N54A-DXMyFQvy.js} +2 -2
- package/dist/static/assets/{cose-bilkent-S5V4N54A-Dbwh3GoX.js.map → cose-bilkent-S5V4N54A-DXMyFQvy.js.map} +1 -1
- package/dist/static/assets/{dagre-6UL2VRFP-BD_6e0Uk.js → dagre-6UL2VRFP-BdaUG-j_.js} +7 -7
- package/dist/static/assets/{dagre-6UL2VRFP-BD_6e0Uk.js.map → dagre-6UL2VRFP-BdaUG-j_.js.map} +1 -1
- package/dist/static/assets/{diagram-PSM6KHXK-BWt7Q59-.js → diagram-PSM6KHXK-NLiqKBzn.js} +7 -7
- package/dist/static/assets/{diagram-PSM6KHXK-BWt7Q59-.js.map → diagram-PSM6KHXK-NLiqKBzn.js.map} +1 -1
- package/dist/static/assets/{diagram-QEK2KX5R-D0BvBR_a.js → diagram-QEK2KX5R-D-0fyvY_.js} +6 -6
- package/dist/static/assets/{diagram-QEK2KX5R-D0BvBR_a.js.map → diagram-QEK2KX5R-D-0fyvY_.js.map} +1 -1
- package/dist/static/assets/{diagram-S2PKOQOG-D8uRdKXp.js → diagram-S2PKOQOG-BQ_FU59m.js} +6 -6
- package/dist/static/assets/{diagram-S2PKOQOG-D8uRdKXp.js.map → diagram-S2PKOQOG-BQ_FU59m.js.map} +1 -1
- package/dist/static/assets/{erDiagram-Q2GNP2WA-CQoifjFq.js → erDiagram-Q2GNP2WA-DyftKeuC.js} +5 -5
- package/dist/static/assets/{erDiagram-Q2GNP2WA-CQoifjFq.js.map → erDiagram-Q2GNP2WA-DyftKeuC.js.map} +1 -1
- package/dist/static/assets/{flowDiagram-NV44I4VS-CGhdeaG8.js → flowDiagram-NV44I4VS-9SGefONA.js} +6 -6
- package/dist/static/assets/{flowDiagram-NV44I4VS-CGhdeaG8.js.map → flowDiagram-NV44I4VS-9SGefONA.js.map} +1 -1
- package/dist/static/assets/{ganttDiagram-JELNMOA3-D8W0wb9H.js → ganttDiagram-JELNMOA3-k_WLhf-r.js} +3 -3
- package/dist/static/assets/{ganttDiagram-JELNMOA3-D8W0wb9H.js.map → ganttDiagram-JELNMOA3-k_WLhf-r.js.map} +1 -1
- package/dist/static/assets/{gitGraphDiagram-NY62KEGX-ChHni_jP.js → gitGraphDiagram-NY62KEGX-3eoLlCOY.js} +7 -7
- package/dist/static/assets/{gitGraphDiagram-NY62KEGX-ChHni_jP.js.map → gitGraphDiagram-NY62KEGX-3eoLlCOY.js.map} +1 -1
- package/dist/static/assets/{graph-BWoi_FgC.js → graph-vUevIs4s.js} +3 -3
- package/dist/static/assets/{graph-BWoi_FgC.js.map → graph-vUevIs4s.js.map} +1 -1
- package/dist/static/assets/{index-th_praGg.js → index-BNBG2CE1.js} +399 -68
- package/dist/static/assets/index-BNBG2CE1.js.map +1 -0
- package/dist/static/assets/{infoDiagram-WHAUD3N6-B_XKKZTV.js → infoDiagram-WHAUD3N6-CwEhVxkU.js} +5 -5
- package/dist/static/assets/{infoDiagram-WHAUD3N6-B_XKKZTV.js.map → infoDiagram-WHAUD3N6-CwEhVxkU.js.map} +1 -1
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-ChGuQ6T9.js → journeyDiagram-XKPGCS4Q-Dtdq4G4Q.js} +5 -5
- package/dist/static/assets/{journeyDiagram-XKPGCS4Q-ChGuQ6T9.js.map → journeyDiagram-XKPGCS4Q-Dtdq4G4Q.js.map} +1 -1
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-BjWe623u.js → kanban-definition-3W4ZIXB7-Bli-AycJ.js} +3 -3
- package/dist/static/assets/{kanban-definition-3W4ZIXB7-BjWe623u.js.map → kanban-definition-3W4ZIXB7-Bli-AycJ.js.map} +1 -1
- package/dist/static/assets/{layout-BPyT310w.js → layout-CGlA8c09.js} +5 -5
- package/dist/static/assets/{layout-BPyT310w.js.map → layout-CGlA8c09.js.map} +1 -1
- package/dist/static/assets/{linear-xUsVjXWq.js → linear-Da2jDWL3.js} +2 -2
- package/dist/static/assets/{linear-xUsVjXWq.js.map → linear-Da2jDWL3.js.map} +1 -1
- package/dist/static/assets/{min-xFt7zeOd.js → min-Co741hTV.js} +3 -3
- package/dist/static/assets/{min-xFt7zeOd.js.map → min-Co741hTV.js.map} +1 -1
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-DT_dvf2c.js → mindmap-definition-VGOIOE7T-DvkIjoq8.js} +4 -4
- package/dist/static/assets/{mindmap-definition-VGOIOE7T-DT_dvf2c.js.map → mindmap-definition-VGOIOE7T-DvkIjoq8.js.map} +1 -1
- package/dist/static/assets/{pieDiagram-ADFJNKIX-B1DQ-OaG.js → pieDiagram-ADFJNKIX-BGuGhTu8.js} +7 -7
- package/dist/static/assets/{pieDiagram-ADFJNKIX-B1DQ-OaG.js.map → pieDiagram-ADFJNKIX-BGuGhTu8.js.map} +1 -1
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-IHqyr3iT.js → quadrantDiagram-AYHSOK5B-DAZcrJMg.js} +3 -3
- package/dist/static/assets/{quadrantDiagram-AYHSOK5B-IHqyr3iT.js.map → quadrantDiagram-AYHSOK5B-DAZcrJMg.js.map} +1 -1
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-CKBpht7B.js → requirementDiagram-UZGBJVZJ-CXN0DxZs.js} +4 -4
- package/dist/static/assets/{requirementDiagram-UZGBJVZJ-CKBpht7B.js.map → requirementDiagram-UZGBJVZJ-CXN0DxZs.js.map} +1 -1
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-D2uGjv3i.js → sankeyDiagram-TZEHDZUN-B7-yAePZ.js} +2 -2
- package/dist/static/assets/{sankeyDiagram-TZEHDZUN-D2uGjv3i.js.map → sankeyDiagram-TZEHDZUN-B7-yAePZ.js.map} +1 -1
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-wLFRhAKd.js → sequenceDiagram-WL72ISMW-DfBNY6h_.js} +4 -4
- package/dist/static/assets/{sequenceDiagram-WL72ISMW-wLFRhAKd.js.map → sequenceDiagram-WL72ISMW-DfBNY6h_.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-BFGQTbx5.js → stateDiagram-FKZM4ZOC-BLo1xRVY.js} +9 -9
- package/dist/static/assets/{stateDiagram-FKZM4ZOC-BFGQTbx5.js.map → stateDiagram-FKZM4ZOC-BLo1xRVY.js.map} +1 -1
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-DF7AjJuk.js → stateDiagram-v2-4FDKWEC3-Dq7MAD0I.js} +5 -5
- package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-DF7AjJuk.js.map → stateDiagram-v2-4FDKWEC3-Dq7MAD0I.js.map} +1 -1
- package/dist/static/assets/{timeline-definition-IT6M3QCI-ChHFOb0o.js → timeline-definition-IT6M3QCI-ySWyBF3b.js} +3 -3
- package/dist/static/assets/{timeline-definition-IT6M3QCI-ChHFOb0o.js.map → timeline-definition-IT6M3QCI-ySWyBF3b.js.map} +1 -1
- package/dist/static/assets/{treemap-KMMF4GRG-BxaNvQU4.js → treemap-KMMF4GRG-DOp4sqOh.js} +4 -4
- package/dist/static/assets/{treemap-KMMF4GRG-BxaNvQU4.js.map → treemap-KMMF4GRG-DOp4sqOh.js.map} +1 -1
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-CrNKeY_-.js → xychartDiagram-PRI3JC2R-vkmh67qb.js} +3 -3
- package/dist/static/assets/{xychartDiagram-PRI3JC2R-CrNKeY_-.js.map → xychartDiagram-PRI3JC2R-vkmh67qb.js.map} +1 -1
- package/dist/static/index.html +1 -1
- package/dist/team.js +29 -6
- package/dist/tool.js +56 -0
- package/dist/tools/builtins.js +4 -2
- package/dist/tools/context-health.js +7 -7
- package/dist/tools/os.js +267 -30
- package/dist/tools/pending-tellask-reminder.js +185 -0
- package/dist/tools/plan.js +1 -0
- package/dist/tools/ripgrep.js +145 -4
- package/dist/tools/shell-tools.js +21 -0
- package/dist/tools/team-mgmt.js +4 -4
- package/dist/tools/toolset-manual.js +74 -0
- package/dist/utils/task-doc.js +16 -16
- package/package.json +1 -1
- package/dist/minds/builtin/cmdr/persona.md +0 -3
- package/dist/minds/builtin/dijiang/knowledge.md +0 -287
- package/dist/minds/builtin/dijiang/persona.md +0 -7
- package/dist/static/assets/index-th_praGg.js.map +0 -1
- package/dist/static/testing/dom-observation-utils.js +0 -425
- package/dist/static/testing/e2e-test-helper.js +0 -3119
package/dist/static/index.html
CHANGED
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
padding: 20px;
|
|
53
53
|
}
|
|
54
54
|
</style>
|
|
55
|
-
<script type="module" crossorigin src="/assets/index-
|
|
55
|
+
<script type="module" crossorigin src="/assets/index-BNBG2CE1.js"></script>
|
|
56
56
|
<link rel="stylesheet" crossorigin href="/assets/index-DaIsSzC_.css">
|
|
57
57
|
</head>
|
|
58
58
|
<body>
|
package/dist/team.js
CHANGED
|
@@ -249,9 +249,10 @@ exports.Team = Team;
|
|
|
249
249
|
* Honors declaration order of toolsets and tools. Logs warnings for duplicate tool names
|
|
250
250
|
* that resolve to different Tool objects. Returns no duplicate tools per name.
|
|
251
251
|
*/
|
|
252
|
-
listResolvedToolsetNames() {
|
|
252
|
+
listResolvedToolsetNames(options) {
|
|
253
253
|
if (!this.toolsets)
|
|
254
254
|
return [];
|
|
255
|
+
const onMissing = options?.onMissing ?? 'warn';
|
|
255
256
|
const excludedToolsets = new Set();
|
|
256
257
|
for (const entry of this.toolsets) {
|
|
257
258
|
if (entry.startsWith('!') && entry.length > 1) {
|
|
@@ -273,7 +274,9 @@ exports.Team = Team;
|
|
|
273
274
|
continue;
|
|
274
275
|
const tools = (0, registry_1.getToolset)(resolvedToolsetName);
|
|
275
276
|
if (!tools) {
|
|
276
|
-
|
|
277
|
+
if (onMissing === 'warn') {
|
|
278
|
+
log_1.log.warn(`Toolset '${resolvedToolsetName}' not found in registry for member '${this.id}'`);
|
|
279
|
+
}
|
|
277
280
|
continue;
|
|
278
281
|
}
|
|
279
282
|
resolved.push(resolvedToolsetName);
|
|
@@ -282,11 +285,13 @@ exports.Team = Team;
|
|
|
282
285
|
}
|
|
283
286
|
return resolved;
|
|
284
287
|
}
|
|
285
|
-
listTools() {
|
|
288
|
+
listTools(options) {
|
|
286
289
|
const toolMap = new Map();
|
|
287
290
|
const seenNames = new Set();
|
|
291
|
+
const onMissingToolset = options?.onMissingToolset ?? 'warn';
|
|
292
|
+
const onMissingTool = options?.onMissingTool ?? 'warn';
|
|
288
293
|
// Process toolsets (in declaration order)
|
|
289
|
-
for (const toolsetName of this.listResolvedToolsetNames()) {
|
|
294
|
+
for (const toolsetName of this.listResolvedToolsetNames({ onMissing: onMissingToolset })) {
|
|
290
295
|
const tools = (0, registry_1.getToolset)(toolsetName);
|
|
291
296
|
if (!tools)
|
|
292
297
|
continue;
|
|
@@ -307,7 +312,9 @@ exports.Team = Team;
|
|
|
307
312
|
for (const toolName of this.tools) {
|
|
308
313
|
const tool = (0, registry_1.getTool)(toolName);
|
|
309
314
|
if (!tool) {
|
|
310
|
-
|
|
315
|
+
if (onMissingTool === 'warn') {
|
|
316
|
+
log_1.log.warn(`Tool '${toolName}' not found in registry for member '${this.id}'`);
|
|
317
|
+
}
|
|
311
318
|
continue;
|
|
312
319
|
}
|
|
313
320
|
if (seenNames.has(toolName)) {
|
|
@@ -331,6 +338,12 @@ exports.Team = Team;
|
|
|
331
338
|
id: 'defaulter',
|
|
332
339
|
name: 'Defaulter',
|
|
333
340
|
fbr_effort: 3,
|
|
341
|
+
// FBR defaults to tool-less web search policy, but users can override via
|
|
342
|
+
// member_defaults.fbr_model_params / members.<id>.fbr_model_params.
|
|
343
|
+
fbr_model_params: {
|
|
344
|
+
codex: { web_search: 'disabled' },
|
|
345
|
+
openai: { web_search: 'disabled' },
|
|
346
|
+
},
|
|
334
347
|
});
|
|
335
348
|
const fuxi = new Team.Member({
|
|
336
349
|
id: 'fuxi',
|
|
@@ -380,7 +393,7 @@ exports.Team = Team;
|
|
|
380
393
|
}
|
|
381
394
|
function listShellTools(member) {
|
|
382
395
|
const out = [];
|
|
383
|
-
for (const t of member.listTools()) {
|
|
396
|
+
for (const t of member.listTools({ onMissingToolset: 'silent', onMissingTool: 'silent' })) {
|
|
384
397
|
if (t.type !== 'func')
|
|
385
398
|
continue;
|
|
386
399
|
if (!isShellToolName(t.name))
|
|
@@ -723,6 +736,7 @@ exports.Team = Team;
|
|
|
723
736
|
'reasoning_effort',
|
|
724
737
|
'verbosity',
|
|
725
738
|
'parallel_tool_calls',
|
|
739
|
+
'web_search',
|
|
726
740
|
];
|
|
727
741
|
Team.TEAM_YAML_MODEL_PARAMS_CODEX_KEYS = Team.TEAM_YAML_MODEL_PARAMS_OPENAI_KEYS;
|
|
728
742
|
Team.TEAM_YAML_MODEL_PARAMS_ANTHROPIC_KEYS = [
|
|
@@ -756,6 +770,7 @@ exports.Team = Team;
|
|
|
756
770
|
reasoning_effort: `Did you mean \`${atPrefix}.model_params.codex.reasoning_effort\` (preferred for provider: codex) or \`${atPrefix}.model_params.openai.reasoning_effort\`? (not supported at ${atPrefix} root)`,
|
|
757
771
|
verbosity: `Did you mean \`${atPrefix}.model_params.codex.verbosity\` (preferred for provider: codex) or \`${atPrefix}.model_params.openai.verbosity\`? (not supported at ${atPrefix} root)`,
|
|
758
772
|
parallel_tool_calls: `Did you mean \`${atPrefix}.model_params.codex.parallel_tool_calls\` (preferred for provider: codex) or \`${atPrefix}.model_params.openai.parallel_tool_calls\`? (not supported at ${atPrefix} root)`,
|
|
773
|
+
web_search: `Did you mean \`${atPrefix}.model_params.codex.web_search\` (preferred for provider: codex) or \`${atPrefix}.model_params.openai.web_search\`? (not supported at ${atPrefix} root)`,
|
|
759
774
|
};
|
|
760
775
|
const unknownAtMember = listUnknownKeys(memberObj, Team.TEAM_YAML_MEMBER_KEYS);
|
|
761
776
|
if (unknownAtMember.length > 0) {
|
|
@@ -776,6 +791,7 @@ exports.Team = Team;
|
|
|
776
791
|
reasoning_effort: `Did you mean \`${modelParamsAt}.codex.reasoning_effort\` (preferred for provider: codex) or \`${modelParamsAt}.openai.reasoning_effort\`?`,
|
|
777
792
|
verbosity: `Did you mean \`${modelParamsAt}.codex.verbosity\` (preferred for provider: codex) or \`${modelParamsAt}.openai.verbosity\`?`,
|
|
778
793
|
parallel_tool_calls: `Did you mean \`${modelParamsAt}.codex.parallel_tool_calls\` (preferred for provider: codex) or \`${modelParamsAt}.openai.parallel_tool_calls\`?`,
|
|
794
|
+
web_search: `Did you mean \`${modelParamsAt}.codex.web_search\` (preferred for provider: codex) or \`${modelParamsAt}.openai.web_search\`?`,
|
|
779
795
|
temperature: `Did you mean \`${modelParamsAt}.codex.temperature\` / \`${modelParamsAt}.openai.temperature\` (or \`${modelParamsAt}.anthropic.temperature\`)?`,
|
|
780
796
|
top_p: `Did you mean \`${modelParamsAt}.codex.top_p\` / \`${modelParamsAt}.openai.top_p\` (or \`${modelParamsAt}.anthropic.top_p\`)?`,
|
|
781
797
|
max_tokens: `Did you mean \`${modelParamsAt}.max_tokens\` / \`${modelParamsAt}.general.max_tokens\` (provider-agnostic), or \`${modelParamsAt}.codex.max_tokens\` / \`${modelParamsAt}.openai.max_tokens\` / \`${modelParamsAt}.anthropic.max_tokens\`?`,
|
|
@@ -1351,6 +1367,13 @@ exports.Team = Team;
|
|
|
1351
1367
|
verbosity !== 'high') {
|
|
1352
1368
|
throw new Error(`Invalid ${at2}.verbosity: expected low|medium|high (got ${describeValueType(verbosity)})`);
|
|
1353
1369
|
}
|
|
1370
|
+
const webSearch = params.web_search;
|
|
1371
|
+
if (webSearch !== undefined &&
|
|
1372
|
+
webSearch !== 'disabled' &&
|
|
1373
|
+
webSearch !== 'cached' &&
|
|
1374
|
+
webSearch !== 'live') {
|
|
1375
|
+
throw new Error(`Invalid ${at2}.web_search: expected disabled|cached|live (got ${describeValueType(webSearch)})`);
|
|
1376
|
+
}
|
|
1354
1377
|
};
|
|
1355
1378
|
const codex = obj.codex === undefined ? undefined : asRecord(obj.codex, `${at}.codex`);
|
|
1356
1379
|
const openai = obj.openai === undefined ? undefined : asRecord(obj.openai, `${at}.openai`);
|
package/dist/tool.js
CHANGED
|
@@ -44,11 +44,67 @@ function validateArgs(schema, args) {
|
|
|
44
44
|
}
|
|
45
45
|
return { ok: true };
|
|
46
46
|
}
|
|
47
|
+
function isJsonPrimitiveValue(value) {
|
|
48
|
+
return (typeof value === 'string' ||
|
|
49
|
+
typeof value === 'number' ||
|
|
50
|
+
typeof value === 'boolean' ||
|
|
51
|
+
value === null);
|
|
52
|
+
}
|
|
53
|
+
function formatJsonPrimitiveValue(value) {
|
|
54
|
+
return JSON.stringify(value);
|
|
55
|
+
}
|
|
56
|
+
function describeShortValue(value) {
|
|
57
|
+
if (isJsonPrimitiveValue(value))
|
|
58
|
+
return formatJsonPrimitiveValue(value);
|
|
59
|
+
if (Array.isArray(value))
|
|
60
|
+
return '[array]';
|
|
61
|
+
if (typeof value === 'object' && value !== null)
|
|
62
|
+
return '[object]';
|
|
63
|
+
return JSON.stringify(value);
|
|
64
|
+
}
|
|
65
|
+
function formatEnumAllowedList(values, maxShown) {
|
|
66
|
+
const shown = values.slice(0, Math.max(0, Math.floor(maxShown)));
|
|
67
|
+
const shownText = shown.map((v) => formatJsonPrimitiveValue(v)).join(', ');
|
|
68
|
+
const remaining = values.length - shown.length;
|
|
69
|
+
if (remaining <= 0)
|
|
70
|
+
return shownText;
|
|
71
|
+
return shownText.length > 0
|
|
72
|
+
? `${shownText}, ... (+${remaining} more)`
|
|
73
|
+
: `... (+${remaining} more)`;
|
|
74
|
+
}
|
|
47
75
|
function validateValue(schema, value, path) {
|
|
48
76
|
if (!isRecord(schema)) {
|
|
49
77
|
// Unknown schema shape: don't block execution.
|
|
50
78
|
return { ok: true };
|
|
51
79
|
}
|
|
80
|
+
// Best-effort const validation (only supports primitive const).
|
|
81
|
+
// For complex/object const, keep permissive behavior.
|
|
82
|
+
if ('const' in schema && isJsonPrimitiveValue(schema.const)) {
|
|
83
|
+
const expected = schema.const;
|
|
84
|
+
if (!isJsonPrimitiveValue(value) || value !== expected) {
|
|
85
|
+
return {
|
|
86
|
+
ok: false,
|
|
87
|
+
error: `Field ${path} must be ${formatJsonPrimitiveValue(expected)}; got ${describeShortValue(value)}`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Best-effort enum validation (only supports primitive enums).
|
|
92
|
+
// For complex/object enums, keep permissive behavior.
|
|
93
|
+
if ('enum' in schema && Array.isArray(schema.enum)) {
|
|
94
|
+
const enumValues = schema.enum;
|
|
95
|
+
const allPrimitive = enumValues.every((v) => isJsonPrimitiveValue(v));
|
|
96
|
+
if (allPrimitive) {
|
|
97
|
+
const allowedValues = enumValues;
|
|
98
|
+
const allowed = isJsonPrimitiveValue(value) && allowedValues.some((v) => v === value);
|
|
99
|
+
if (!allowed) {
|
|
100
|
+
const allowedText = formatEnumAllowedList(allowedValues, 10);
|
|
101
|
+
return {
|
|
102
|
+
ok: false,
|
|
103
|
+
error: `Field ${path} must be one of ${allowedText}; got ${describeShortValue(value)}`,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
52
108
|
const typeValue = 'type' in schema ? schema.type : undefined;
|
|
53
109
|
const schemaType = typeof typeValue === 'string'
|
|
54
110
|
? typeValue
|
package/dist/tools/builtins.js
CHANGED
|
@@ -15,6 +15,7 @@ const fs_1 = require("./fs");
|
|
|
15
15
|
const mcp_1 = require("./mcp");
|
|
16
16
|
const mem_1 = require("./mem");
|
|
17
17
|
const os_1 = require("./os");
|
|
18
|
+
const pending_tellask_reminder_1 = require("./pending-tellask-reminder");
|
|
18
19
|
const plan_1 = require("./plan");
|
|
19
20
|
const registry_1 = require("./registry");
|
|
20
21
|
const ripgrep_1 = require("./ripgrep");
|
|
@@ -178,8 +179,8 @@ for (const tool of team_mgmt_1.teamMgmtTools) {
|
|
|
178
179
|
zh: 'Codex 风格工具(apply_patch + readonly_shell + update_plan)',
|
|
179
180
|
},
|
|
180
181
|
promptI18n: {
|
|
181
|
-
en: 'Use `apply_patch` (Codex-style patch format) to modify files. Use `readonly_shell` for simple rtws (runtime workspace) inspection via
|
|
182
|
-
zh: '使用 `apply_patch`(Codex 风格 patch 格式)修改文件;使用 `readonly_shell`
|
|
182
|
+
en: 'Use `apply_patch` (Codex-style patch format) to modify files. Use `readonly_shell` for simple rtws (runtime workspace) inspection via its small allowlist; commands outside the allowlist are rejected. For node/python, only exact version probes are allowed (no scripts). Chains via |/&&/|| are validated segment-by-segment. Use `update_plan` to record/update the task plan (stored as a reminder). You are explicitly authorized to call `readonly_shell` yourself; do not delegate it to a shell specialist. Avoid multi-line script-style commands; single-line is preferred (|, &&, || are ok). Paths must be relative to the rtws (runtime workspace). Hard denies: `readonly_shell` refuses rtws-root `.minds/` and `.dialogs/`; `apply_patch` is subject to the same access-control (including hard denies for `*.tsk/`, `.minds/`, and rtws-root `.dialogs/`).',
|
|
183
|
+
zh: '使用 `apply_patch`(Codex 风格 patch 格式)修改文件;使用 `readonly_shell` 做少量只读命令行检查,仅允许白名单命令前缀,白名单之外的命令会被拒绝。对 node/python 仅允许版本探针(不允许脚本执行)。通过 |/&&/|| 串联命令时会按子命令逐段校验。使用 `update_plan` 记录/更新任务计划(作为 reminder 存储)。你已被明确授权自行调用 `readonly_shell`,不要把它委派给 shell 专员。不建议多行脚本式命令,优先单行(允许 |、&&、||)。路径必须相对 rtws(运行时工作区)根目录。硬拒绝点:`readonly_shell` 无条件拒绝访问 rtws root 的 `.minds/` 与 `.dialogs/`;`apply_patch` 也受相同的访问控制约束(包含对 `*.tsk/`、`.minds/`、rtws root `.dialogs/` 的硬拒绝)。',
|
|
183
184
|
},
|
|
184
185
|
});
|
|
185
186
|
(0, registry_1.registerToolset)('team-mgmt', [...team_mgmt_1.teamMgmtTools]);
|
|
@@ -196,3 +197,4 @@ for (const tool of team_mgmt_1.teamMgmtTools) {
|
|
|
196
197
|
// Register ReminderOwners
|
|
197
198
|
(0, registry_1.registerReminderOwner)(os_1.shellCmdReminderOwner);
|
|
198
199
|
(0, registry_1.registerReminderOwner)(mcp_1.mcpLeaseReminderOwner);
|
|
200
|
+
(0, registry_1.registerReminderOwner)(pending_tellask_reminder_1.pendingTellaskReminderOwner);
|
|
@@ -39,12 +39,12 @@ function formatContextHealthOwnerHeader(args) {
|
|
|
39
39
|
];
|
|
40
40
|
if (!snapshot) {
|
|
41
41
|
lines.push('- 状态:未知(尚未获取上下文统计)');
|
|
42
|
-
lines.push('-
|
|
42
|
+
lines.push('- 优先动作:change_mind(progress) → clear_mind');
|
|
43
43
|
return lines.join('\n');
|
|
44
44
|
}
|
|
45
45
|
if (snapshot.kind !== 'available') {
|
|
46
46
|
lines.push('- 状态:未知(token 统计不可用)');
|
|
47
|
-
lines.push('-
|
|
47
|
+
lines.push('- 优先动作:change_mind(progress) → clear_mind');
|
|
48
48
|
return lines.join('\n');
|
|
49
49
|
}
|
|
50
50
|
switch (snapshot.level) {
|
|
@@ -53,16 +53,16 @@ function formatContextHealthOwnerHeader(args) {
|
|
|
53
53
|
return lines.join('\n');
|
|
54
54
|
}
|
|
55
55
|
case 'caution': {
|
|
56
|
-
lines.push('- 状态:🟡
|
|
57
|
-
lines.push('-
|
|
56
|
+
lines.push('- 状态:🟡 黄(警告)');
|
|
57
|
+
lines.push('- 优先动作:change_mind(progress) → clear_mind');
|
|
58
58
|
return lines.join('\n');
|
|
59
59
|
}
|
|
60
60
|
case 'critical': {
|
|
61
|
-
lines.push('- 状态:🔴
|
|
61
|
+
lines.push('- 状态:🔴 红(危险)');
|
|
62
62
|
if (remainingGenTurns !== undefined) {
|
|
63
|
-
lines.push(`- 倒数:剩余 ${remainingGenTurns} 次生成机会;到 0
|
|
63
|
+
lines.push(`- 倒数:剩余 ${remainingGenTurns} 次生成机会;到 0 系统将自动开启新一轮以保持稳定性`);
|
|
64
64
|
}
|
|
65
|
-
lines.push('-
|
|
65
|
+
lines.push('- 立刻:change_mind(progress) → clear_mind');
|
|
66
66
|
return lines.join('\n');
|
|
67
67
|
}
|
|
68
68
|
default: {
|
package/dist/tools/os.js
CHANGED
|
@@ -290,7 +290,7 @@ const readonlyShellSchema = {
|
|
|
290
290
|
properties: {
|
|
291
291
|
command: {
|
|
292
292
|
type: 'string',
|
|
293
|
-
description: 'Read-only shell command (allowed prefixes: cat, rg, sed, ls, nl, wc, head, tail, stat, file, uname, whoami, id, echo, pwd, which, date, diff, realpath, readlink, printf, cut, sort, uniq, tr, awk, shasum, sha256sum, md5sum, uuid, git show, git status, git diff, git log, git blame, find, tree, jq; also allows: git -C <relative-path> <show|status|diff|log|blame> ...; also allows: cd <relative-path> && <allowed command...> (or ||))',
|
|
293
|
+
description: 'Read-only shell command (allowed prefixes: cat, rg, sed, ls, nl, wc, head, tail, stat, file, uname, whoami, id, echo, pwd, which, date, diff, realpath, readlink, printf, cut, sort, uniq, tr, awk, shasum, sha256sum, md5sum, uuid, git show, git status, git diff, git log, git blame, find, tree, jq, true; exact version probes: node --version|-v, python3 --version|-V; also allows: git -C <relative-path> <show|status|diff|log|blame> ...; also allows: cd <relative-path> && <allowed command...> (or ||); command chains via |/&&/|| are validated segment-by-segment)',
|
|
294
294
|
},
|
|
295
295
|
timeout_ms: {
|
|
296
296
|
type: 'number',
|
|
@@ -591,23 +591,69 @@ const readonlyShellAllowedPrefixes = [
|
|
|
591
591
|
'find',
|
|
592
592
|
'tree',
|
|
593
593
|
'jq',
|
|
594
|
+
'true',
|
|
594
595
|
];
|
|
595
|
-
function
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
}
|
|
599
|
-
function isAllowedReadonlyShellCommandInternal(command, depth) {
|
|
600
|
-
if (depth > 8)
|
|
596
|
+
function isAllowedReadonlyShellVersionProbe(command) {
|
|
597
|
+
const tokens = splitShellTokens(command);
|
|
598
|
+
if (tokens.length !== 2)
|
|
601
599
|
return false;
|
|
600
|
+
const cmd = tokens[0]?.text ?? '';
|
|
601
|
+
const flag = tokens[1]?.text ?? '';
|
|
602
|
+
if (cmd === 'node')
|
|
603
|
+
return flag === '--version' || flag === '-v';
|
|
604
|
+
if (cmd === 'python3')
|
|
605
|
+
return flag === '--version' || flag === '-V';
|
|
606
|
+
return false;
|
|
607
|
+
}
|
|
608
|
+
function validateReadonlyShellCommand(command) {
|
|
609
|
+
return validateReadonlyShellCommandInternal(command.trimStart(), 0);
|
|
610
|
+
}
|
|
611
|
+
function validateReadonlyShellCommandInternal(command, depth) {
|
|
612
|
+
if (depth > 8) {
|
|
613
|
+
return {
|
|
614
|
+
ok: false,
|
|
615
|
+
failure: {
|
|
616
|
+
reason: 'MAX_DEPTH',
|
|
617
|
+
rejectedSegment: command.trim() === '' ? command : command.trim(),
|
|
618
|
+
},
|
|
619
|
+
};
|
|
620
|
+
}
|
|
602
621
|
const trimmed = command.trimStart();
|
|
603
622
|
if (trimmed.startsWith('cd ')) {
|
|
604
623
|
const parsed = parseCdChain(trimmed);
|
|
605
|
-
if (!parsed)
|
|
606
|
-
return false;
|
|
624
|
+
if (!parsed) {
|
|
625
|
+
return { ok: false, failure: { reason: 'INVALID_CD_SYNTAX', rejectedSegment: trimmed } };
|
|
626
|
+
}
|
|
607
627
|
const dir = parsed.dir.replace(/^["']|["']$/g, '');
|
|
608
|
-
if (!isSafeRelativePath(dir))
|
|
609
|
-
return
|
|
610
|
-
|
|
628
|
+
if (!isSafeRelativePath(dir)) {
|
|
629
|
+
return {
|
|
630
|
+
ok: false,
|
|
631
|
+
failure: {
|
|
632
|
+
reason: 'UNSAFE_RELATIVE_PATH',
|
|
633
|
+
rejectedSegment: `cd ${parsed.dir}`,
|
|
634
|
+
},
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
return validateReadonlyShellCommandInternal(parsed.rest, depth + 1);
|
|
638
|
+
}
|
|
639
|
+
const chainParsed = splitTopLevelReadonlyShellChain(trimmed);
|
|
640
|
+
if (!chainParsed.ok) {
|
|
641
|
+
return {
|
|
642
|
+
ok: false,
|
|
643
|
+
failure: {
|
|
644
|
+
reason: chainParsed.reason,
|
|
645
|
+
rejectedSegment: chainParsed.rejectedSegment,
|
|
646
|
+
},
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
if (chainParsed.segments.length > 1) {
|
|
650
|
+
for (const segment of chainParsed.segments) {
|
|
651
|
+
const segmentValidation = validateReadonlyShellCommandInternal(segment, depth + 1);
|
|
652
|
+
if (!segmentValidation.ok) {
|
|
653
|
+
return segmentValidation;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return { ok: true };
|
|
611
657
|
}
|
|
612
658
|
if (trimmed.startsWith('git -C ')) {
|
|
613
659
|
// Allow a narrow, read-only subset of `git -C <dir> <subcommand> ...` as long as <dir> looks
|
|
@@ -619,23 +665,129 @@ function isAllowedReadonlyShellCommandInternal(command, depth) {
|
|
|
619
665
|
const dirRaw = tokens[2] ?? '';
|
|
620
666
|
const dir = dirRaw.replace(/^["']|["']$/g, '');
|
|
621
667
|
const subcommand = tokens[3] ?? '';
|
|
622
|
-
if (isSafeRelativePath(dir)) {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
668
|
+
if (!isSafeRelativePath(dir)) {
|
|
669
|
+
return { ok: false, failure: { reason: 'GIT_C_UNSAFE_PATH', rejectedSegment: trimmed } };
|
|
670
|
+
}
|
|
671
|
+
if (subcommand === 'show' ||
|
|
672
|
+
subcommand === 'status' ||
|
|
673
|
+
subcommand === 'diff' ||
|
|
674
|
+
subcommand === 'log' ||
|
|
675
|
+
subcommand === 'blame') {
|
|
676
|
+
return { ok: true };
|
|
630
677
|
}
|
|
678
|
+
return {
|
|
679
|
+
ok: false,
|
|
680
|
+
failure: { reason: 'GIT_C_UNSUPPORTED_SUBCOMMAND', rejectedSegment: trimmed },
|
|
681
|
+
};
|
|
631
682
|
}
|
|
683
|
+
return { ok: false, failure: { reason: 'GIT_C_INVALID', rejectedSegment: trimmed } };
|
|
684
|
+
}
|
|
685
|
+
if (isAllowedReadonlyShellVersionProbe(trimmed)) {
|
|
686
|
+
return { ok: true };
|
|
632
687
|
}
|
|
633
688
|
for (const prefix of readonlyShellAllowedPrefixes) {
|
|
634
689
|
if (trimmed === prefix || trimmed.startsWith(`${prefix} `)) {
|
|
635
|
-
return true;
|
|
690
|
+
return { ok: true };
|
|
636
691
|
}
|
|
637
692
|
}
|
|
638
|
-
return false;
|
|
693
|
+
return { ok: false, failure: { reason: 'COMMAND_NOT_ALLOWLISTED', rejectedSegment: trimmed } };
|
|
694
|
+
}
|
|
695
|
+
function splitTopLevelReadonlyShellChain(command) {
|
|
696
|
+
const segments = [];
|
|
697
|
+
let quote = null;
|
|
698
|
+
let escape = false;
|
|
699
|
+
let segmentStart = 0;
|
|
700
|
+
const pushSegment = (endExclusive) => {
|
|
701
|
+
const segment = command.slice(segmentStart, endExclusive).trim();
|
|
702
|
+
if (segment === '')
|
|
703
|
+
return false;
|
|
704
|
+
segments.push(segment);
|
|
705
|
+
return true;
|
|
706
|
+
};
|
|
707
|
+
for (let i = 0; i < command.length; i++) {
|
|
708
|
+
const ch = command[i] ?? '';
|
|
709
|
+
if (escape) {
|
|
710
|
+
escape = false;
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
if (quote) {
|
|
714
|
+
if (ch === quote) {
|
|
715
|
+
quote = null;
|
|
716
|
+
}
|
|
717
|
+
else if (ch === '\\' && quote === '"') {
|
|
718
|
+
escape = true;
|
|
719
|
+
}
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
if (ch === '\\') {
|
|
723
|
+
escape = true;
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
if (ch === "'" || ch === '"') {
|
|
727
|
+
quote = ch;
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
const next = command[i + 1] ?? '';
|
|
731
|
+
if ((ch === '&' && next === '&') || (ch === '|' && next === '|')) {
|
|
732
|
+
if (!pushSegment(i)) {
|
|
733
|
+
return {
|
|
734
|
+
ok: false,
|
|
735
|
+
reason: 'CHAIN_PARSE_EMPTY_SEGMENT',
|
|
736
|
+
rejectedSegment: command.trim(),
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
i += 1;
|
|
740
|
+
segmentStart = i + 1;
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
if (ch === '|') {
|
|
744
|
+
if (!pushSegment(i)) {
|
|
745
|
+
return {
|
|
746
|
+
ok: false,
|
|
747
|
+
reason: 'CHAIN_PARSE_EMPTY_SEGMENT',
|
|
748
|
+
rejectedSegment: command.trim(),
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
segmentStart = i + 1;
|
|
752
|
+
continue;
|
|
753
|
+
}
|
|
754
|
+
if (ch === ';') {
|
|
755
|
+
return {
|
|
756
|
+
ok: false,
|
|
757
|
+
reason: 'CHAIN_PARSE_UNSUPPORTED_OPERATOR',
|
|
758
|
+
rejectedSegment: command.slice(segmentStart).trim() || command.trim(),
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
if (ch === '&') {
|
|
762
|
+
return {
|
|
763
|
+
ok: false,
|
|
764
|
+
reason: 'CHAIN_PARSE_UNSUPPORTED_OPERATOR',
|
|
765
|
+
rejectedSegment: command.slice(segmentStart).trim() || command.trim(),
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (quote) {
|
|
770
|
+
return {
|
|
771
|
+
ok: false,
|
|
772
|
+
reason: 'CHAIN_PARSE_UNTERMINATED_QUOTE',
|
|
773
|
+
rejectedSegment: command.trim(),
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
if (escape) {
|
|
777
|
+
return {
|
|
778
|
+
ok: false,
|
|
779
|
+
reason: 'CHAIN_PARSE_TRAILING_ESCAPE',
|
|
780
|
+
rejectedSegment: command.trim(),
|
|
781
|
+
};
|
|
782
|
+
}
|
|
783
|
+
if (!pushSegment(command.length)) {
|
|
784
|
+
return {
|
|
785
|
+
ok: false,
|
|
786
|
+
reason: 'CHAIN_PARSE_EMPTY_SEGMENT',
|
|
787
|
+
rejectedSegment: command.trim(),
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
return { ok: true, segments };
|
|
639
791
|
}
|
|
640
792
|
function isSafeRelativePath(dir) {
|
|
641
793
|
const hasParentTraversal = /(^|[\\/])\.\.([\\/]|$)/.test(dir);
|
|
@@ -722,6 +874,80 @@ function splitShellTokens(command) {
|
|
|
722
874
|
push();
|
|
723
875
|
return out;
|
|
724
876
|
}
|
|
877
|
+
function firstReadonlyShellToken(segment) {
|
|
878
|
+
const tokens = splitShellTokens(segment.trim());
|
|
879
|
+
return tokens[0]?.text ?? '';
|
|
880
|
+
}
|
|
881
|
+
function getReadonlyShellSuggestionEn(failure) {
|
|
882
|
+
const token = firstReadonlyShellToken(failure.rejectedSegment);
|
|
883
|
+
if (failure.reason === 'CHAIN_PARSE_UNSUPPORTED_OPERATOR' ||
|
|
884
|
+
failure.reason === 'CHAIN_PARSE_EMPTY_SEGMENT') {
|
|
885
|
+
return 'Use only `|`, `&&`, `||` for chaining. Example: `ls || true`.';
|
|
886
|
+
}
|
|
887
|
+
if (failure.reason === 'CHAIN_PARSE_UNTERMINATED_QUOTE' ||
|
|
888
|
+
failure.reason === 'CHAIN_PARSE_TRAILING_ESCAPE') {
|
|
889
|
+
return 'Fix shell quoting first, then run an allowlisted segment (for example: `ls` or `rg <pattern>`).';
|
|
890
|
+
}
|
|
891
|
+
if (failure.reason === 'INVALID_CD_SYNTAX' || failure.reason === 'UNSAFE_RELATIVE_PATH') {
|
|
892
|
+
return 'Use `cd <relative-path> && <allowed command...>`.';
|
|
893
|
+
}
|
|
894
|
+
if (failure.reason === 'GIT_C_INVALID' ||
|
|
895
|
+
failure.reason === 'GIT_C_UNSAFE_PATH' ||
|
|
896
|
+
failure.reason === 'GIT_C_UNSUPPORTED_SUBCOMMAND') {
|
|
897
|
+
return 'Use `git -C <relative-path> <show|status|diff|log|blame> ...`.';
|
|
898
|
+
}
|
|
899
|
+
if (failure.reason === 'MAX_DEPTH') {
|
|
900
|
+
return 'Reduce nested chaining depth (for example split into smaller `readonly_shell` calls).';
|
|
901
|
+
}
|
|
902
|
+
if (token === 'node')
|
|
903
|
+
return 'Only version probes are allowed: `node --version || true`.';
|
|
904
|
+
if (token === 'python3' || token === 'python') {
|
|
905
|
+
return 'Only version probes are allowed: `python3 --version || true`.';
|
|
906
|
+
}
|
|
907
|
+
if (token === 'false')
|
|
908
|
+
return 'Use `true` as fallback (for example: `ls || true`).';
|
|
909
|
+
if (token === 'git') {
|
|
910
|
+
return 'Use `git <show|status|diff|log|blame> ...` or `git -C <relative-path> <show|status|diff|log|blame> ...`.';
|
|
911
|
+
}
|
|
912
|
+
if (token === 'cd')
|
|
913
|
+
return 'Use `cd <relative-path> && <allowed command...>`.';
|
|
914
|
+
return 'Use an allowlisted read-only segment (for example: `ls`, `rg <pattern>`, or `git status`).';
|
|
915
|
+
}
|
|
916
|
+
function getReadonlyShellSuggestionZh(failure) {
|
|
917
|
+
const token = firstReadonlyShellToken(failure.rejectedSegment);
|
|
918
|
+
if (failure.reason === 'CHAIN_PARSE_UNSUPPORTED_OPERATOR' ||
|
|
919
|
+
failure.reason === 'CHAIN_PARSE_EMPTY_SEGMENT') {
|
|
920
|
+
return '仅使用 `|`、`&&`、`||` 串联;示例:`ls || true`。';
|
|
921
|
+
}
|
|
922
|
+
if (failure.reason === 'CHAIN_PARSE_UNTERMINATED_QUOTE' ||
|
|
923
|
+
failure.reason === 'CHAIN_PARSE_TRAILING_ESCAPE') {
|
|
924
|
+
return '先修正引号/转义,再执行白名单子命令(例如:`ls` 或 `rg <pattern>`)。';
|
|
925
|
+
}
|
|
926
|
+
if (failure.reason === 'INVALID_CD_SYNTAX' || failure.reason === 'UNSAFE_RELATIVE_PATH') {
|
|
927
|
+
return '请使用 `cd <相对路径> && <允许命令...>`。';
|
|
928
|
+
}
|
|
929
|
+
if (failure.reason === 'GIT_C_INVALID' ||
|
|
930
|
+
failure.reason === 'GIT_C_UNSAFE_PATH' ||
|
|
931
|
+
failure.reason === 'GIT_C_UNSUPPORTED_SUBCOMMAND') {
|
|
932
|
+
return '请使用 `git -C <相对路径> <show|status|diff|log|blame> ...`。';
|
|
933
|
+
}
|
|
934
|
+
if (failure.reason === 'MAX_DEPTH') {
|
|
935
|
+
return '请降低链式嵌套深度(可拆成多次 `readonly_shell` 调用)。';
|
|
936
|
+
}
|
|
937
|
+
if (token === 'node')
|
|
938
|
+
return '仅允许版本探针:`node --version || true`。';
|
|
939
|
+
if (token === 'python3' || token === 'python') {
|
|
940
|
+
return '仅允许版本探针:`python3 --version || true`。';
|
|
941
|
+
}
|
|
942
|
+
if (token === 'false')
|
|
943
|
+
return '兜底请用 `true`(例如:`ls || true`)。';
|
|
944
|
+
if (token === 'git') {
|
|
945
|
+
return '可改为 `git <show|status|diff|log|blame> ...`,或 `git -C <相对路径> <show|status|diff|log|blame> ...`。';
|
|
946
|
+
}
|
|
947
|
+
if (token === 'cd')
|
|
948
|
+
return '可改为 `cd <相对路径> && <允许命令...>`。';
|
|
949
|
+
return '请改用白名单只读子命令(例如:`ls`、`rg <pattern>`、`git status`)。';
|
|
950
|
+
}
|
|
725
951
|
function normalizeRelFromRtwsRoot(relPath) {
|
|
726
952
|
return relPath.replace(/\\/g, '/').replace(/^\/+/, '');
|
|
727
953
|
}
|
|
@@ -892,10 +1118,10 @@ function detectReadonlyShellForbiddenHiddenDirAccess(workspaceRootAbs, command)
|
|
|
892
1118
|
exports.readonlyShellTool = {
|
|
893
1119
|
type: 'func',
|
|
894
1120
|
name: 'readonly_shell',
|
|
895
|
-
description: 'Execute a read-only shell command from a small allowlist
|
|
1121
|
+
description: 'Execute a read-only shell command from a small allowlist. Only exact version probes are allowed for node/python (no scripts such as `node -e` or `python3 -c`). Command chains via |/&&/|| are validated segment-by-segment. Commands outside the allowlist are rejected.',
|
|
896
1122
|
descriptionI18n: {
|
|
897
|
-
en: 'Execute a read-only shell command from a small allowlist
|
|
898
|
-
zh: '执行只读 shell
|
|
1123
|
+
en: 'Execute a read-only shell command from a small allowlist. Only exact version probes are allowed for node/python (no scripts such as `node -e` or `python3 -c`). Command chains via |/&&/|| are validated segment-by-segment. You are explicitly authorized to call this tool yourself (no delegation). Commands outside the allowlist are rejected.',
|
|
1124
|
+
zh: '执行只读 shell 命令,仅允许少量白名单命令前缀。对 node/python 仅允许版本探针(不允许 `node -e` / `python3 -c` 这类脚本)。通过 |/&&/|| 串联时会按子命令逐段校验。你已被明确授权自行调用该工具(无需委派)。不在允许列表内的命令会被拒绝。',
|
|
899
1125
|
},
|
|
900
1126
|
parameters: readonlyShellSchema,
|
|
901
1127
|
async call(dlg, caller, args) {
|
|
@@ -908,17 +1134,28 @@ exports.readonlyShellTool = {
|
|
|
908
1134
|
? `❌ readonly_shell 不建议执行多行脚本式命令(检测到换行符)。请用单行命令(允许 |、&&、||)。\n收到:${command}`
|
|
909
1135
|
: `❌ readonly_shell does not allow multi-line script-style commands (newline detected). Use a single-line command (|, &&, || are allowed).\nGot: ${command}`;
|
|
910
1136
|
}
|
|
911
|
-
|
|
1137
|
+
const validation = validateReadonlyShellCommand(command);
|
|
1138
|
+
if (!validation.ok) {
|
|
912
1139
|
const allowedList = readonlyShellAllowedPrefixes.join(', ');
|
|
1140
|
+
const rejectedSegment = validation.failure.rejectedSegment.trim();
|
|
1141
|
+
const rejectedSegmentOrCommand = rejectedSegment === '' ? command : rejectedSegment;
|
|
1142
|
+
const suggestion = language === 'zh'
|
|
1143
|
+
? getReadonlyShellSuggestionZh(validation.failure)
|
|
1144
|
+
: getReadonlyShellSuggestionEn(validation.failure);
|
|
913
1145
|
return language === 'zh'
|
|
914
|
-
? `❌ readonly_shell 仅允许以下命令前缀:${allowedList}\n另外允许:git -C <相对路径> <show|status|diff|log|blame> ...\n另外允许:cd <相对路径> && <允许命令...>(或 ||)\n收到:${command}`
|
|
915
|
-
: `❌ readonly_shell only allows these command prefixes: ${allowedList}\nAlso allowed: git -C <relative-path> <show|status|diff|log|blame> ...\nAlso allowed: cd <relative-path> && <allowed command...> (or ||)\nGot: ${command}`;
|
|
1146
|
+
? `❌ readonly_shell 仅允许以下命令前缀:${allowedList}\n另外允许(仅版本探针):node --version|-v、python3 --version|-V\n脚本执行(如 node -e / python3 -c)一律拒绝。\n另外允许:git -C <相对路径> <show|status|diff|log|blame> ...\n另外允许:cd <相对路径> && <允许命令...>(或 ||)\n说明:通过 |/&&/|| 串联时会按子命令逐段校验。\n被拒子命令段:${rejectedSegmentOrCommand}\n允许的等价写法:${suggestion}\n收到:${command}`
|
|
1147
|
+
: `❌ readonly_shell only allows these command prefixes: ${allowedList}\nAlso allowed (exact version probes only): node --version|-v, python3 --version|-V\nNode/python scripts (for example: node -e, python3 -c) are rejected.\nAlso allowed: git -C <relative-path> <show|status|diff|log|blame> ...\nAlso allowed: cd <relative-path> && <allowed command...> (or ||)\nNote: chains via |/&&/|| are validated segment-by-segment.\nRejected segment: ${rejectedSegmentOrCommand}\nAllowed equivalent: ${suggestion}\nGot: ${command}`;
|
|
916
1148
|
}
|
|
917
1149
|
const forbiddenHiddenDir = detectReadonlyShellForbiddenHiddenDirAccess(path_1.default.resolve(process.cwd()), command);
|
|
918
1150
|
if (forbiddenHiddenDir) {
|
|
1151
|
+
if (forbiddenHiddenDir === '.minds') {
|
|
1152
|
+
return language === 'zh'
|
|
1153
|
+
? `❌ **访问被拒绝**\n\n- 工具:\`readonly_shell\`\n- 路径:\`.minds/\`\n- 代码:\`ACCESS_DENIED\`\n\n说明:\`.minds/\` 是 rtws 根目录下的保留目录,readonly_shell 无条件拒绝访问。\n\n提示:\n- 若团队配置了 \`team-mgmt\` 工具集,请使用其中工具(\`team_mgmt_*\`)代管 \`.minds/**\`。\n- 若团队未配置该工具集或你不具备权限,请诉请具备 \`team-mgmt\` 权限的成员/团队管理员成员代管。\n- 若需要排查 Dominds,请在子目录 rtws 下复现(例如 \`ux-rtws/.dialogs/**\`)。`
|
|
1154
|
+
: `❌ **Access Denied**\n\n- Tool: \`readonly_shell\`\n- Path: \`.minds/\`\n- Code: \`ACCESS_DENIED\`\n\nNote: \`.minds/\` is a reserved directory at the rtws root; readonly_shell hard-denies access.\n\nHints:\n- If your team configured the \`team-mgmt\` toolset, use its tools (\`team_mgmt_*\`) to manage \`.minds/**\`.\n- If the toolset is not configured or you don\'t have permission, tellask a team-admin / a member with \`team-mgmt\` access to manage it for you.\n- For Dominds debugging, reproduce under a nested rtws (e.g. \`ux-rtws/.dialogs/**\`).`;
|
|
1155
|
+
}
|
|
919
1156
|
return language === 'zh'
|
|
920
|
-
? `❌ **访问被拒绝**\n\n- 工具:\`readonly_shell\`\n-
|
|
921
|
-
: `❌ **Access Denied**\n\n- Tool: \`readonly_shell\`\n- Path:
|
|
1157
|
+
? `❌ **访问被拒绝**\n\n- 工具:\`readonly_shell\`\n- 路径:\`.dialogs/\`\n- 代码:\`ACCESS_DENIED\`\n\n说明:\`.dialogs/\` 是 rtws 根目录下的保留目录,readonly_shell 无条件拒绝访问。\n\n提示:\n- 若需要排查 Dominds,请在子目录 rtws 下复现(例如 \`ux-rtws/.dialogs/**\`)。`
|
|
1158
|
+
: `❌ **Access Denied**\n\n- Tool: \`readonly_shell\`\n- Path: \`.dialogs/\`\n- Code: \`ACCESS_DENIED\`\n\nNote: \`.dialogs/\` is a reserved directory at the rtws root; readonly_shell hard-denies access.\n\nHints:\n- For Dominds debugging, reproduce under a nested rtws (e.g. \`ux-rtws/.dialogs/**\`).`;
|
|
922
1159
|
}
|
|
923
1160
|
const stdoutBuffer = new HeadTailByteBuffer(1024 * 1024);
|
|
924
1161
|
const stderrBuffer = new HeadTailByteBuffer(1024 * 1024);
|