dominds 0.8.18 → 0.8.20
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 +72 -23
- package/dist/llm/defaults.yaml +8 -0
- package/dist/llm/driver-v2/context-health.js +45 -6
- package/dist/llm/driver-v2/core.js +5 -0
- package/dist/llm/driver-v2/round.js +12 -0
- package/dist/team.js +84 -0
- package/dist/tools/prompts/team_mgmt/en/index.md +1 -0
- package/dist/tools/prompts/team_mgmt/en/tools.md +1 -0
- package/dist/tools/prompts/team_mgmt/zh/index.md +1 -0
- package/dist/tools/prompts/team_mgmt/zh/tools.md +1 -0
- package/dist/tools/team_mgmt.js +25 -16
- package/package.json +1 -1
package/dist/access-control.js
CHANGED
|
@@ -10,7 +10,7 @@ exports.getAccessDeniedMessage = getAccessDeniedMessage;
|
|
|
10
10
|
/**
|
|
11
11
|
* Module: access-control
|
|
12
12
|
*
|
|
13
|
-
* Directory-based access control helpers:
|
|
13
|
+
* Directory/file-extension based access control helpers:
|
|
14
14
|
* - `matchesPattern` for glob-like directory scope matching (supports `*` and `**`)
|
|
15
15
|
* - `hasReadAccess`/`hasWriteAccess` to evaluate member permissions
|
|
16
16
|
* - `getAccessDeniedMessage` to format denial responses
|
|
@@ -31,6 +31,41 @@ function isRootDialogsPath(targetPath) {
|
|
|
31
31
|
const normalized = targetPath.replace(/\\/g, '/').replace(/^\/+/, '');
|
|
32
32
|
return normalized === '.dialogs' || normalized.startsWith('.dialogs/');
|
|
33
33
|
}
|
|
34
|
+
function normalizeFileExtName(raw) {
|
|
35
|
+
return raw.trim().toLowerCase().replace(/^\.+/, '');
|
|
36
|
+
}
|
|
37
|
+
function extractFileExtName(targetPath) {
|
|
38
|
+
const normalized = targetPath.replace(/\\/g, '/').replace(/\/+$/g, '');
|
|
39
|
+
if (normalized === '' || normalized === '.')
|
|
40
|
+
return undefined;
|
|
41
|
+
const baseName = normalized.split('/').pop();
|
|
42
|
+
if (!baseName || baseName === '.' || baseName === '..')
|
|
43
|
+
return undefined;
|
|
44
|
+
const dotIndex = baseName.lastIndexOf('.');
|
|
45
|
+
if (dotIndex <= 0 || dotIndex === baseName.length - 1)
|
|
46
|
+
return undefined;
|
|
47
|
+
return normalizeFileExtName(baseName.slice(dotIndex + 1));
|
|
48
|
+
}
|
|
49
|
+
function hasFileExtAccess(fileExtName, whitelist, blacklist) {
|
|
50
|
+
// Extension rules only apply to file-like paths with a detectable extension.
|
|
51
|
+
if (!fileExtName)
|
|
52
|
+
return true;
|
|
53
|
+
for (const ext of blacklist ?? []) {
|
|
54
|
+
if (normalizeFileExtName(ext) === fileExtName) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const allow = whitelist ?? [];
|
|
59
|
+
if (allow.length === 0) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
for (const ext of allow) {
|
|
63
|
+
if (normalizeFileExtName(ext) === fileExtName) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
34
69
|
/**
|
|
35
70
|
* Directory-specific pattern matching for access control.
|
|
36
71
|
* This function determines if a target path (file or directory) should be controlled
|
|
@@ -142,8 +177,10 @@ function matchesPattern(targetPath, dirPattern) {
|
|
|
142
177
|
* Access control logic:
|
|
143
178
|
* 1. Check blacklist first (no_read_dirs) - if path matches any blacklist pattern, deny access
|
|
144
179
|
* 2. Check whitelist (read_dirs) - if path matches any whitelist pattern, allow access
|
|
145
|
-
* 3.
|
|
146
|
-
* 4.
|
|
180
|
+
* 3. Check extension blacklist (no_read_file_ext_names) - if extension matches, deny access
|
|
181
|
+
* 4. Check extension whitelist (read_file_ext_names)
|
|
182
|
+
* 5. If no whitelist patterns are defined for a dimension, allow access (default allow)
|
|
183
|
+
* 6. If whitelist patterns exist but none match, deny access
|
|
147
184
|
*/
|
|
148
185
|
function hasReadAccess(member, targetPath) {
|
|
149
186
|
// Get resolved relative path from rtws root
|
|
@@ -183,17 +220,19 @@ function hasReadAccess(member, targetPath) {
|
|
|
183
220
|
const whitelist = member.read_dirs || [];
|
|
184
221
|
// Note: `.minds/**` is handled above as a hard deny (unless internal bypass is enabled).
|
|
185
222
|
// If no whitelist is defined, allow access (after blacklist check)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
223
|
+
let directoryAllowed = whitelist.length === 0;
|
|
224
|
+
if (!directoryAllowed) {
|
|
225
|
+
// Check if path matches any whitelist pattern
|
|
226
|
+
for (const pattern of whitelist) {
|
|
227
|
+
if (matchesPattern(relativePath, pattern)) {
|
|
228
|
+
directoryAllowed = true;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
193
231
|
}
|
|
194
232
|
}
|
|
195
|
-
|
|
196
|
-
|
|
233
|
+
if (!directoryAllowed)
|
|
234
|
+
return false;
|
|
235
|
+
return hasFileExtAccess(extractFileExtName(relativePath), member.read_file_ext_names, member.no_read_file_ext_names);
|
|
197
236
|
}
|
|
198
237
|
/**
|
|
199
238
|
* Check if a member has write access to a specific path.
|
|
@@ -201,8 +240,10 @@ function hasReadAccess(member, targetPath) {
|
|
|
201
240
|
* Access control logic:
|
|
202
241
|
* 1. Check blacklist first (no_write_dirs) - if path matches any blacklist pattern, deny access
|
|
203
242
|
* 2. Check whitelist (write_dirs) - if path matches any whitelist pattern, allow access
|
|
204
|
-
* 3.
|
|
205
|
-
* 4.
|
|
243
|
+
* 3. Check extension blacklist (no_write_file_ext_names) - if extension matches, deny access
|
|
244
|
+
* 4. Check extension whitelist (write_file_ext_names)
|
|
245
|
+
* 5. If no whitelist patterns are defined for a dimension, allow access (default allow)
|
|
246
|
+
* 6. If whitelist patterns exist but none match, deny access
|
|
206
247
|
*/
|
|
207
248
|
function hasWriteAccess(member, targetPath) {
|
|
208
249
|
// Get resolved relative path from rtws root
|
|
@@ -242,17 +283,19 @@ function hasWriteAccess(member, targetPath) {
|
|
|
242
283
|
const whitelist = member.write_dirs || [];
|
|
243
284
|
// Note: `.minds/**` is handled above as a hard deny (unless internal bypass is enabled).
|
|
244
285
|
// If no whitelist is defined, allow access (after blacklist check)
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
286
|
+
let directoryAllowed = whitelist.length === 0;
|
|
287
|
+
if (!directoryAllowed) {
|
|
288
|
+
// Check if path matches any whitelist pattern
|
|
289
|
+
for (const pattern of whitelist) {
|
|
290
|
+
if (matchesPattern(relativePath, pattern)) {
|
|
291
|
+
directoryAllowed = true;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
252
294
|
}
|
|
253
295
|
}
|
|
254
|
-
|
|
255
|
-
|
|
296
|
+
if (!directoryAllowed)
|
|
297
|
+
return false;
|
|
298
|
+
return hasFileExtAccess(extractFileExtName(relativePath), member.write_file_ext_names, member.no_write_file_ext_names);
|
|
256
299
|
}
|
|
257
300
|
/**
|
|
258
301
|
* Get an access denied error message for a specific operation and path.
|
|
@@ -308,5 +351,11 @@ function getAccessDeniedMessage(operation, targetPath, language = 'en') {
|
|
|
308
351
|
lines.push(`- Hint: For Dominds debugging, reproduce in a nested rtws (e.g. \`ux-rtws/.dialogs/\`), which is not covered by this hard deny.`);
|
|
309
352
|
}
|
|
310
353
|
}
|
|
354
|
+
if (language === 'zh') {
|
|
355
|
+
lines.push(`- 说明:该路径可能命中目录权限(\`read_dirs/write_dirs/no_*_dirs\`)或扩展名权限(\`*_file_ext_names/no_*_file_ext_names\`)。`);
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
lines.push(`- Note: This path may be blocked by directory rules (\`read_dirs/write_dirs/no_*_dirs\`) or file-extension rules (\`*_file_ext_names/no_*_file_ext_names\`).`);
|
|
359
|
+
}
|
|
311
360
|
return lines.join('\n');
|
|
312
361
|
}
|
package/dist/llm/defaults.yaml
CHANGED
|
@@ -63,6 +63,8 @@ providers:
|
|
|
63
63
|
gpt-5.3-codex:
|
|
64
64
|
name: GPT-5.3 Codex
|
|
65
65
|
optimal_max_tokens: 200000
|
|
66
|
+
# Caution remediation reinjection cadence in generation turns (default: 10).
|
|
67
|
+
caution_remediation_cadence_generations: 10
|
|
66
68
|
context_length: 272000
|
|
67
69
|
input_length: 272000
|
|
68
70
|
output_length: 32768
|
|
@@ -70,6 +72,8 @@ providers:
|
|
|
70
72
|
gpt-5.3-codex-spark:
|
|
71
73
|
name: GPT-5.3 Codex Spark
|
|
72
74
|
optimal_max_tokens: 80000
|
|
75
|
+
# Caution remediation reinjection cadence in generation turns (default: 10).
|
|
76
|
+
caution_remediation_cadence_generations: 3
|
|
73
77
|
context_length: 128000
|
|
74
78
|
input_length: 128000
|
|
75
79
|
output_length: 32768
|
|
@@ -77,6 +81,8 @@ providers:
|
|
|
77
81
|
gpt-5.2-codex:
|
|
78
82
|
name: GPT-5.2 Codex
|
|
79
83
|
optimal_max_tokens: 200000
|
|
84
|
+
# Caution remediation reinjection cadence in generation turns (default: 10).
|
|
85
|
+
caution_remediation_cadence_generations: 10
|
|
80
86
|
context_length: 272000
|
|
81
87
|
input_length: 272000
|
|
82
88
|
output_length: 32768
|
|
@@ -84,6 +90,8 @@ providers:
|
|
|
84
90
|
gpt-5.2:
|
|
85
91
|
name: GPT-5.2
|
|
86
92
|
optimal_max_tokens: 200000
|
|
93
|
+
# Caution remediation reinjection cadence in generation turns (default: 10).
|
|
94
|
+
caution_remediation_cadence_generations: 10
|
|
87
95
|
context_length: 272000
|
|
88
96
|
input_length: 272000
|
|
89
97
|
output_length: 32768
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS = void 0;
|
|
3
|
+
exports.DRIVER_V2_DEFAULT_CAUTION_REMEDIATION_CADENCE_GENERATIONS = exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS = void 0;
|
|
4
4
|
exports.resetContextHealthRoundState = resetContextHealthRoundState;
|
|
5
5
|
exports.resolveCriticalCountdownRemaining = resolveCriticalCountdownRemaining;
|
|
6
6
|
exports.consumeCriticalCountdown = consumeCriticalCountdown;
|
|
7
|
+
exports.resolveCautionRemediationCadenceGenerations = resolveCautionRemediationCadenceGenerations;
|
|
7
8
|
exports.decideDriverV2ContextHealth = decideDriverV2ContextHealth;
|
|
8
9
|
exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS = 5;
|
|
10
|
+
exports.DRIVER_V2_DEFAULT_CAUTION_REMEDIATION_CADENCE_GENERATIONS = 10;
|
|
9
11
|
const contextHealthRoundStateByDialogKey = new Map();
|
|
10
12
|
function getContextHealthRoundState(dialogKey) {
|
|
11
13
|
const existing = contextHealthRoundStateByDialogKey.get(dialogKey);
|
|
@@ -30,7 +32,6 @@ function resolveCriticalCountdownRemaining(dialogKey, snapshot) {
|
|
|
30
32
|
return exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS;
|
|
31
33
|
}
|
|
32
34
|
const state = getContextHealthRoundState(dialogKey);
|
|
33
|
-
state.lastSeenLevel = snapshot.level;
|
|
34
35
|
state.criticalCountdownRemaining = undefined;
|
|
35
36
|
return exports.DRIVER_V2_DEFAULT_CRITICAL_COUNTDOWN_GENERATIONS;
|
|
36
37
|
}
|
|
@@ -56,8 +57,18 @@ function consumeCriticalCountdown(dialogKey) {
|
|
|
56
57
|
state.criticalCountdownRemaining = next;
|
|
57
58
|
return next;
|
|
58
59
|
}
|
|
60
|
+
function resolveCautionRemediationCadenceGenerations(configured) {
|
|
61
|
+
if (typeof configured !== 'number' || !Number.isFinite(configured)) {
|
|
62
|
+
return exports.DRIVER_V2_DEFAULT_CAUTION_REMEDIATION_CADENCE_GENERATIONS;
|
|
63
|
+
}
|
|
64
|
+
const normalized = Math.floor(configured);
|
|
65
|
+
if (normalized <= 0) {
|
|
66
|
+
return exports.DRIVER_V2_DEFAULT_CAUTION_REMEDIATION_CADENCE_GENERATIONS;
|
|
67
|
+
}
|
|
68
|
+
return normalized;
|
|
69
|
+
}
|
|
59
70
|
function decideDriverV2ContextHealth(args) {
|
|
60
|
-
const { snapshot } = args;
|
|
71
|
+
const { snapshot, dialogKey } = args;
|
|
61
72
|
if (!snapshot || snapshot.kind !== 'available') {
|
|
62
73
|
return { kind: 'proceed' };
|
|
63
74
|
}
|
|
@@ -65,11 +76,39 @@ function decideDriverV2ContextHealth(args) {
|
|
|
65
76
|
return { kind: 'proceed' };
|
|
66
77
|
}
|
|
67
78
|
if (snapshot.level === 'caution') {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
const state = getContextHealthRoundState(dialogKey);
|
|
80
|
+
const cadence = resolveCautionRemediationCadenceGenerations(args.cautionRemediationCadenceGenerations);
|
|
81
|
+
const enteringCaution = state.lastSeenLevel !== 'caution';
|
|
82
|
+
state.lastSeenLevel = 'caution';
|
|
83
|
+
state.criticalCountdownRemaining = undefined;
|
|
84
|
+
if (enteringCaution) {
|
|
85
|
+
state.cautionPromptDue = true;
|
|
86
|
+
state.cautionGenerationsSincePrompt = 0;
|
|
87
|
+
}
|
|
88
|
+
else if (state.cautionPromptDue !== true) {
|
|
89
|
+
const previous = typeof state.cautionGenerationsSincePrompt === 'number' &&
|
|
90
|
+
Number.isFinite(state.cautionGenerationsSincePrompt)
|
|
91
|
+
? Math.max(0, Math.floor(state.cautionGenerationsSincePrompt))
|
|
92
|
+
: 0;
|
|
93
|
+
const next = previous + 1;
|
|
94
|
+
state.cautionGenerationsSincePrompt = next;
|
|
95
|
+
if (next >= cadence) {
|
|
96
|
+
state.cautionPromptDue = true;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const shouldInjectPrompt = state.cautionPromptDue === true && !args.hadUserPromptThisGen && args.canInjectPromptThisGen;
|
|
100
|
+
if (!shouldInjectPrompt) {
|
|
101
|
+
return { kind: 'proceed' };
|
|
102
|
+
}
|
|
103
|
+
state.cautionPromptDue = false;
|
|
104
|
+
state.cautionGenerationsSincePrompt = 0;
|
|
105
|
+
return { kind: 'continue', reason: 'caution_soft_remediation' };
|
|
71
106
|
}
|
|
72
107
|
if (snapshot.level === 'critical') {
|
|
108
|
+
const state = getContextHealthRoundState(dialogKey);
|
|
109
|
+
state.lastSeenLevel = 'critical';
|
|
110
|
+
state.cautionPromptDue = undefined;
|
|
111
|
+
state.cautionGenerationsSincePrompt = undefined;
|
|
73
112
|
if (args.criticalCountdownRemaining <= 0) {
|
|
74
113
|
return { kind: 'continue', reason: 'critical_force_new_course' };
|
|
75
114
|
}
|
|
@@ -819,10 +819,15 @@ async function driveDialogStreamCoreV2(dlg, humanPrompt, driveOptions, callbacks
|
|
|
819
819
|
if (genIterNo > 1) {
|
|
820
820
|
const snapshot = dlg.getLastContextHealth();
|
|
821
821
|
const hasQueuedUpNext = dlg.hasUpNext() || pendingPrompt !== undefined;
|
|
822
|
+
const modelInfoForRemediation = resolveModelInfo(providerCfg, model);
|
|
823
|
+
const cautionRemediationCadenceGenerations = (0, context_health_1.resolveCautionRemediationCadenceGenerations)(modelInfoForRemediation?.caution_remediation_cadence_generations);
|
|
822
824
|
const criticalCountdownRemaining = (0, context_health_1.resolveCriticalCountdownRemaining)(dlg.id.key(), snapshot);
|
|
823
825
|
const healthDecision = (0, context_health_1.decideDriverV2ContextHealth)({
|
|
826
|
+
dialogKey: dlg.id.key(),
|
|
824
827
|
snapshot,
|
|
825
828
|
hadUserPromptThisGen: isUserOriginPrompt(pendingPrompt),
|
|
829
|
+
canInjectPromptThisGen: !hasQueuedUpNext,
|
|
830
|
+
cautionRemediationCadenceGenerations,
|
|
826
831
|
criticalCountdownRemaining,
|
|
827
832
|
});
|
|
828
833
|
if (healthDecision.kind === 'suspend') {
|
|
@@ -10,6 +10,7 @@ const persistence_1 = require("../../persistence");
|
|
|
10
10
|
const driver_messages_1 = require("../../shared/i18n/driver-messages");
|
|
11
11
|
const runtime_language_1 = require("../../shared/runtime-language");
|
|
12
12
|
const id_1 = require("../../shared/utils/id");
|
|
13
|
+
const client_1 = require("../client");
|
|
13
14
|
const context_health_1 = require("./context-health");
|
|
14
15
|
const core_1 = require("./core");
|
|
15
16
|
const policy_1 = require("./policy");
|
|
@@ -164,10 +165,21 @@ async function executeDriveRound(args) {
|
|
|
164
165
|
}
|
|
165
166
|
const snapshot = dialog.getLastContextHealth();
|
|
166
167
|
const hasQueuedUpNext = dialog.hasUpNext();
|
|
168
|
+
const provider = policy.effectiveAgent.provider ?? minds.team.memberDefaults.provider;
|
|
169
|
+
const model = policy.effectiveAgent.model ?? minds.team.memberDefaults.model;
|
|
170
|
+
let cautionRemediationCadenceGenerations = (0, context_health_1.resolveCautionRemediationCadenceGenerations)(undefined);
|
|
171
|
+
if (provider && model) {
|
|
172
|
+
const llmCfg = await client_1.LlmConfig.load();
|
|
173
|
+
const providerCfg = llmCfg.getProvider(provider);
|
|
174
|
+
cautionRemediationCadenceGenerations = (0, context_health_1.resolveCautionRemediationCadenceGenerations)(providerCfg?.models[model]?.caution_remediation_cadence_generations);
|
|
175
|
+
}
|
|
167
176
|
const criticalCountdownRemaining = (0, context_health_1.resolveCriticalCountdownRemaining)(dialog.id.key(), snapshot);
|
|
168
177
|
const healthDecision = (0, context_health_1.decideDriverV2ContextHealth)({
|
|
178
|
+
dialogKey: dialog.id.key(),
|
|
169
179
|
snapshot,
|
|
170
180
|
hadUserPromptThisGen: humanPrompt !== undefined,
|
|
181
|
+
canInjectPromptThisGen: !hasQueuedUpNext,
|
|
182
|
+
cautionRemediationCadenceGenerations,
|
|
171
183
|
criticalCountdownRemaining,
|
|
172
184
|
});
|
|
173
185
|
if (healthDecision.kind === 'suspend') {
|
package/dist/team.js
CHANGED
|
@@ -94,6 +94,14 @@ exports.Team = Team;
|
|
|
94
94
|
this.no_read_dirs = params.no_read_dirs;
|
|
95
95
|
if (params.no_write_dirs !== undefined)
|
|
96
96
|
this.no_write_dirs = params.no_write_dirs;
|
|
97
|
+
if (params.read_file_ext_names !== undefined)
|
|
98
|
+
this.read_file_ext_names = params.read_file_ext_names;
|
|
99
|
+
if (params.write_file_ext_names !== undefined)
|
|
100
|
+
this.write_file_ext_names = params.write_file_ext_names;
|
|
101
|
+
if (params.no_read_file_ext_names !== undefined)
|
|
102
|
+
this.no_read_file_ext_names = params.no_read_file_ext_names;
|
|
103
|
+
if (params.no_write_file_ext_names !== undefined)
|
|
104
|
+
this.no_write_file_ext_names = params.no_write_file_ext_names;
|
|
97
105
|
if (params.icon !== undefined)
|
|
98
106
|
this.icon = params.icon;
|
|
99
107
|
if (params.streaming !== undefined)
|
|
@@ -119,6 +127,10 @@ exports.Team = Team;
|
|
|
119
127
|
'write_dirs',
|
|
120
128
|
'no_read_dirs',
|
|
121
129
|
'no_write_dirs',
|
|
130
|
+
'read_file_ext_names',
|
|
131
|
+
'write_file_ext_names',
|
|
132
|
+
'no_read_file_ext_names',
|
|
133
|
+
'no_write_file_ext_names',
|
|
122
134
|
'icon',
|
|
123
135
|
'streaming',
|
|
124
136
|
'hidden',
|
|
@@ -224,6 +236,34 @@ exports.Team = Team;
|
|
|
224
236
|
}
|
|
225
237
|
this.no_write_dirs = noWriteDirs;
|
|
226
238
|
}
|
|
239
|
+
setReadFileExtNames(readFileExtNames) {
|
|
240
|
+
if (readFileExtNames === undefined) {
|
|
241
|
+
delete this.read_file_ext_names;
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
this.read_file_ext_names = readFileExtNames;
|
|
245
|
+
}
|
|
246
|
+
setWriteFileExtNames(writeFileExtNames) {
|
|
247
|
+
if (writeFileExtNames === undefined) {
|
|
248
|
+
delete this.write_file_ext_names;
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
this.write_file_ext_names = writeFileExtNames;
|
|
252
|
+
}
|
|
253
|
+
setNoReadFileExtNames(noReadFileExtNames) {
|
|
254
|
+
if (noReadFileExtNames === undefined) {
|
|
255
|
+
delete this.no_read_file_ext_names;
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
this.no_read_file_ext_names = noReadFileExtNames;
|
|
259
|
+
}
|
|
260
|
+
setNoWriteFileExtNames(noWriteFileExtNames) {
|
|
261
|
+
if (noWriteFileExtNames === undefined) {
|
|
262
|
+
delete this.no_write_file_ext_names;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
this.no_write_file_ext_names = noWriteFileExtNames;
|
|
266
|
+
}
|
|
227
267
|
setIcon(icon) {
|
|
228
268
|
if (icon === undefined) {
|
|
229
269
|
delete this.icon;
|
|
@@ -798,6 +838,10 @@ exports.Team = Team;
|
|
|
798
838
|
'write_dirs',
|
|
799
839
|
'no_read_dirs',
|
|
800
840
|
'no_write_dirs',
|
|
841
|
+
'read_file_ext_names',
|
|
842
|
+
'write_file_ext_names',
|
|
843
|
+
'no_read_file_ext_names',
|
|
844
|
+
'no_write_file_ext_names',
|
|
801
845
|
'icon',
|
|
802
846
|
'streaming',
|
|
803
847
|
'hidden',
|
|
@@ -1117,6 +1161,38 @@ exports.Team = Team;
|
|
|
1117
1161
|
errors.push(asErrorText(err));
|
|
1118
1162
|
}
|
|
1119
1163
|
}
|
|
1164
|
+
if (hasOwnKey(rv, 'read_file_ext_names')) {
|
|
1165
|
+
try {
|
|
1166
|
+
overrides.read_file_ext_names = requireDefined(asOptionalStringArray(rv['read_file_ext_names'], `${at}.read_file_ext_names`), `${at}.read_file_ext_names`);
|
|
1167
|
+
}
|
|
1168
|
+
catch (err) {
|
|
1169
|
+
errors.push(asErrorText(err));
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
if (hasOwnKey(rv, 'write_file_ext_names')) {
|
|
1173
|
+
try {
|
|
1174
|
+
overrides.write_file_ext_names = requireDefined(asOptionalStringArray(rv['write_file_ext_names'], `${at}.write_file_ext_names`), `${at}.write_file_ext_names`);
|
|
1175
|
+
}
|
|
1176
|
+
catch (err) {
|
|
1177
|
+
errors.push(asErrorText(err));
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
if (hasOwnKey(rv, 'no_read_file_ext_names')) {
|
|
1181
|
+
try {
|
|
1182
|
+
overrides.no_read_file_ext_names = requireDefined(asOptionalStringArray(rv['no_read_file_ext_names'], `${at}.no_read_file_ext_names`), `${at}.no_read_file_ext_names`);
|
|
1183
|
+
}
|
|
1184
|
+
catch (err) {
|
|
1185
|
+
errors.push(asErrorText(err));
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
if (hasOwnKey(rv, 'no_write_file_ext_names')) {
|
|
1189
|
+
try {
|
|
1190
|
+
overrides.no_write_file_ext_names = requireDefined(asOptionalStringArray(rv['no_write_file_ext_names'], `${at}.no_write_file_ext_names`), `${at}.no_write_file_ext_names`);
|
|
1191
|
+
}
|
|
1192
|
+
catch (err) {
|
|
1193
|
+
errors.push(asErrorText(err));
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1120
1196
|
if (hasOwnKey(rv, 'icon')) {
|
|
1121
1197
|
try {
|
|
1122
1198
|
overrides.icon = requireDefined(asOptionalString(rv['icon'], `${at}.icon`), `${at}.icon`);
|
|
@@ -1174,6 +1250,14 @@ exports.Team = Team;
|
|
|
1174
1250
|
member.setNoReadDirs(overrides.no_read_dirs);
|
|
1175
1251
|
if (overrides.no_write_dirs !== undefined)
|
|
1176
1252
|
member.setNoWriteDirs(overrides.no_write_dirs);
|
|
1253
|
+
if (overrides.read_file_ext_names !== undefined)
|
|
1254
|
+
member.setReadFileExtNames(overrides.read_file_ext_names);
|
|
1255
|
+
if (overrides.write_file_ext_names !== undefined)
|
|
1256
|
+
member.setWriteFileExtNames(overrides.write_file_ext_names);
|
|
1257
|
+
if (overrides.no_read_file_ext_names !== undefined)
|
|
1258
|
+
member.setNoReadFileExtNames(overrides.no_read_file_ext_names);
|
|
1259
|
+
if (overrides.no_write_file_ext_names !== undefined)
|
|
1260
|
+
member.setNoWriteFileExtNames(overrides.no_write_file_ext_names);
|
|
1177
1261
|
if (overrides.icon !== undefined)
|
|
1178
1262
|
member.setIcon(overrides.icon);
|
|
1179
1263
|
if (overrides.streaming !== undefined)
|
|
@@ -30,6 +30,7 @@ team_mgmt is Dominds' toolset for managing `.minds/` (team configuration and rtw
|
|
|
30
30
|
- **Only operates in `.minds/`**: This toolset only operates within the `.minds/` subtree and should not touch other rtws files
|
|
31
31
|
- **Shell guardrail**: toolset `os` includes `shell_cmd` / `stop_daemon` / `get_daemon_output`; any member with these shell tools must be listed in top-level `shell_specialists`
|
|
32
32
|
- **Member assets recommended**: strongly recommend `persona/knowledge/lessons` files for every `members.<id>` to define ownership, boundaries, and reusable lessons
|
|
33
|
+
- **Default responder recommendation**: `default_responder` is not technically required, but should be set explicitly to avoid implicit fallback drift
|
|
33
34
|
|
|
34
35
|
## Quick Navigation
|
|
35
36
|
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
- Must run after modifying `team.yaml`
|
|
62
62
|
- Clear all team.yaml errors in Problems panel before proceeding
|
|
63
63
|
- Also reads declarations from `.minds/mcp.yaml` for toolset binding checks; even when MCP toolsets are not loaded in the current scene (e.g. read-mind flows), it still detects unknown/invalid MCP serverId references in `members.<id>.toolsets`
|
|
64
|
+
- Also recommended to confirm `default_responder` is explicitly set (not hard-required, but best practice)
|
|
64
65
|
- `team_mgmt_validate_mcp_cfg({})`: Validate `.minds/mcp.yaml` and MCP-related problems
|
|
65
66
|
- Must run after modifying `mcp.yaml`
|
|
66
67
|
- Clear all MCP-related errors in Problems panel before proceeding
|
|
@@ -30,6 +30,7 @@ team_mgmt 是 Dominds 用于管理 `.minds/`(团队配置与 rtws 记忆)的
|
|
|
30
30
|
- **只操作 `.minds/`**:该 toolset 只允许操作 `.minds/` 子树,不会也不应触碰 rtws 其他文件
|
|
31
31
|
- **shell 权限约束**:`os` toolset 包含 `shell_cmd` / `stop_daemon` / `get_daemon_output`;任何拿到这些工具的成员都必须出现在顶层 `shell_specialists`
|
|
32
32
|
- **成员资产推荐**:强烈建议为每个 `members.<id>` 配置 `persona/knowledge/lessons` 资产文件,显式定义角色职责、边界和经验复用
|
|
33
|
+
- **默认响应者建议**:`default_responder` 虽非技术必填,但强烈建议显式配置,避免隐式兜底带来的行为漂移
|
|
33
34
|
|
|
34
35
|
## 快速导航
|
|
35
36
|
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
- 修改完 `team.yaml` 后必须运行
|
|
62
62
|
- 清空 Problems 面板里的 team.yaml 错误后再继续
|
|
63
63
|
- 会读取 `.minds/mcp.yaml` 声明做 toolset 绑定校验;即使当前场景未加载 MCP toolsets(例如 read mind),也会检查 `members.<id>.toolsets` 是否引用了不存在/无效的 MCP serverId
|
|
64
|
+
- 同时建议检查是否显式设置了 `default_responder`(不是硬性必填,但推荐)
|
|
64
65
|
- `team_mgmt_validate_mcp_cfg({})`:验证 `.minds/mcp.yaml` 配置与 MCP 相关问题
|
|
65
66
|
- 修改完 `mcp.yaml` 后必须运行
|
|
66
67
|
- 清空 Problems 面板里的 MCP 相关错误后再继续
|
package/dist/tools/team_mgmt.js
CHANGED
|
@@ -2698,7 +2698,7 @@ function renderMemberProperties(language) {
|
|
|
2698
2698
|
'`diligence-push-max`:鞭策 上限(number)。也接受兼容别名 `diligence_push_max`,但请优先用 `diligence-push-max`。',
|
|
2699
2699
|
'`streaming`:是否启用流式输出。注意:若该成员解析后的 provider 的 `apiType` 是 `codex`,则 `streaming: false` 属于配置错误(Codex 仅支持流式);会在 team 校验与运行期被视为严重问题并中止请求。',
|
|
2700
2700
|
'`hidden`(影子/隐藏成员:不出现在系统提示的团队目录里,但仍可被诉请)',
|
|
2701
|
-
'`read_dirs` / `write_dirs` / `no_read_dirs` / `no_write_dirs`(冲突规则见 `team_mgmt_manual({ topics: ["permissions"] })`;read 与 write 是独立控制,别默认 write implies read)',
|
|
2701
|
+
'`read_dirs` / `write_dirs` / `no_read_dirs` / `no_write_dirs` / `read_file_ext_names` / `write_file_ext_names` / `no_read_file_ext_names` / `no_write_file_ext_names`(冲突规则见 `team_mgmt_manual({ topics: ["permissions"] })`;read 与 write 是独立控制,别默认 write implies read)',
|
|
2702
2702
|
]));
|
|
2703
2703
|
}
|
|
2704
2704
|
return (fmtHeader('Member Properties (members.<id>)') +
|
|
@@ -2711,12 +2711,13 @@ function renderMemberProperties(language) {
|
|
|
2711
2711
|
'`diligence-push-max`: Diligence Push cap (number). Compatibility alias `diligence_push_max` is accepted, but prefer `diligence-push-max`.',
|
|
2712
2712
|
'`streaming`: whether to enable streaming output. Note: if the member resolves to a provider whose `apiType` is `codex`, then `streaming: false` is a configuration error (Codex is streaming-only); it is treated as a severe issue during validation/runtime and the request will be aborted.',
|
|
2713
2713
|
'`hidden` (shadow/hidden member: excluded from system-prompt team directory, but callable)',
|
|
2714
|
-
'`read_dirs` / `write_dirs` / `no_read_dirs` / `no_write_dirs`(冲突规则见 `team_mgmt_manual({ topics: ["permissions"] })`;read 与 write 是独立控制,别默认 write implies read)',
|
|
2714
|
+
'`read_dirs` / `write_dirs` / `no_read_dirs` / `no_write_dirs` / `read_file_ext_names` / `write_file_ext_names` / `no_read_file_ext_names` / `no_write_file_ext_names`(冲突规则见 `team_mgmt_manual({ topics: ["permissions"] })`;read 与 write 是独立控制,别默认 write implies read)',
|
|
2715
2715
|
]));
|
|
2716
2716
|
}
|
|
2717
2717
|
function renderTeamManual(language) {
|
|
2718
2718
|
const common = [
|
|
2719
2719
|
'member_defaults: strongly recommended to set provider/model explicitly (omitting may fall back to built-in defaults)',
|
|
2720
|
+
'default_responder: not a hard requirement, but strongly recommended to set explicitly to avoid implicit fallback responder selection and cross-run drift',
|
|
2720
2721
|
'members: per-agent overrides inherit from member_defaults via prototype fallback',
|
|
2721
2722
|
'after every modification to `.minds/team.yaml`: you must run `team_mgmt_validate_team_cfg({})` and resolve any Problems panel errors before proceeding to avoid runtime issues (e.g., wrong field types, missing fields, or broken path bindings)',
|
|
2722
2723
|
'when changing provider/model: validate provider exists + env var is configured (use `team_mgmt_check_provider({ provider_key: "<providerKey>", model: "", all_models: false, live: false, max_models: 0 })`)',
|
|
@@ -2731,6 +2732,7 @@ function renderTeamManual(language) {
|
|
|
2731
2732
|
fmtList([
|
|
2732
2733
|
'团队定义入口文件是 `.minds/team.yaml`(当前没有 `.minds/team.yml` / `.minds/team.json` 等别名;也不使用 `.minds/team.yaml` 以外的“等效入口”)。',
|
|
2733
2734
|
'强烈建议显式设置 `member_defaults.provider` 与 `member_defaults.model`:如果省略,可能会使用实现内置的默认值(以当前实现为准),但可移植性/可复现性会变差,也更容易在环境变量未配置时把系统刷成板砖。',
|
|
2735
|
+
'`default_responder` 虽然不是技术必填项,但实践上强烈建议显式设置:否则会退回到实现内置的响应者选择逻辑(例如按可见成员/内置成员兜底),容易造成跨环境或跨轮次行为漂移。',
|
|
2734
2736
|
'每次修改 `.minds/team.yaml` 必须运行 `team_mgmt_validate_team_cfg({})`,并在继续之前先清空 Problems 面板里的 team.yaml 相关错误,避免潜在错误进入运行期(例如字段类型错误/字段缺失/路径绑定错误)。',
|
|
2735
2737
|
'强烈建议为每个成员配置 `.minds/team/<id>/{persona,knowledge,lessons}.*.md` 三类资产,用来明确角色职责、工作边界与可复用经验;同一个 `<id>` 必须在 `team.yaml` 的 `members` 里出现,且在 `.minds/team/<id>/` 下存在对应的 mind 文件。',
|
|
2736
2738
|
'典型内容示例(可直接作为起点,按团队语境改写):\n```markdown\n# .minds/team/coder/persona.zh.md\n# @coder 角色设定\n## 核心身份\n- 专业程序员,负责按规格完成代码开发。\n## 工作边界\n- 不负责需求分析或产品策略决策。\n- 只根据已确认的开发规格进行实现与重构。\n## 交付标准\n- 输出可运行代码,并附关键验证步骤。\n```\n```markdown\n# .minds/team/coder/lessons.zh.md\n# @coder 经验教训\n- 修改前先定位调用链与数据流,避免“只改表面”。\n- 涉及权限/配置时,改完立即运行对应校验工具并清空 Problems。\n- 涉及高风险改动时,先给最小可审查方案,再逐步扩展。\n```',
|
|
@@ -2798,6 +2800,7 @@ function renderTeamManual(language) {
|
|
|
2798
2800
|
return (fmtHeader('.minds/team.yaml') +
|
|
2799
2801
|
fmtList(common.concat([
|
|
2800
2802
|
'The team definition entrypoint is `.minds/team.yaml` (no `.minds/team.yml` alias today).',
|
|
2803
|
+
'`default_responder` is not technically required, but strongly recommended in practice: without it, runtime falls back to implementation-defined responder selection (for example visible-member/built-in fallback), which can drift across environments/runs.',
|
|
2801
2804
|
'Strongly recommended: for each member, configure `.minds/team/<id>/{persona,knowledge,lessons}.*.md` assets to define role ownership, work boundaries, and reusable lessons. The same `<id>` must exist in `members.<id>` in `team.yaml`.',
|
|
2802
2805
|
'Typical content examples (use as a starting point, then adapt to your team context):\n```markdown\n# .minds/team/coder/persona.en.md\n# @coder Persona\n## Core Identity\n- Professional programmer responsible for implementing approved development specs.\n## Work Boundaries\n- Not responsible for requirement discovery or product strategy.\n- Implements/refactors only against confirmed specs.\n## Delivery Standard\n- Deliver runnable code plus key verification steps.\n```\n```markdown\n# .minds/team/coder/lessons.en.md\n# @coder Lessons\n- Trace call chain and data flow before editing; avoid patching only symptoms.\n- After changing permissions/config, run corresponding validators and clear Problems.\n- For high-risk changes, start with a minimal reviewable plan before expansion.\n```',
|
|
2803
2806
|
'The team mechanism default is long-lived agents (long-lived teammates): `members` is a stable roster of callable teammates, not “on-demand sub-roles”. This is a product mechanism, not a deployment preference.\nTo pick who acts, use `-m/--member <id>` in CLI/TUI.\n`members.<id>.gofor` is a responsibility flashcard / scope / deliverables summary (≤ 5 lines). Use it for fast routing/reminders; put detailed specs in Markdown assets like `.minds/team/<id>/*` or `.minds/team/domains/*.md`.\nExample (`gofor`):\n```yaml\nmembers:\n qa_guard:\n name: QA Guard\n gofor:\n - Own release regression checklist and pass/fail gate\n - Maintain runnable smoke tests and docs\n - Flag high-risk changes and required manual checks\n```\nExample (`gofor`, object; rendered in YAML key order):\n```yaml\nmembers:\n qa_guard:\n name: QA Guard\n gofor:\n Scope: release regression gate\n Deliverables: checklist + runnable scripts\n Non-goals: feature dev\n Interfaces: coordinates with server/webui owners\n```',
|
|
@@ -2853,7 +2856,7 @@ async function renderMcpManual(language) {
|
|
|
2853
2856
|
'默认按“每个对话租用一个 MCP client”运行(更安全):首次使用该 toolset 会产生 sticky reminder,完成后用 `mcp_release` 释放;如确实是无状态服务器,可配置 `truely-stateless: true` 允许跨对话共享。',
|
|
2854
2857
|
'stdio 配置格式:`command` 必须是字符串(可执行命令),参数放在 `args`(string[],可省略,默认空数组)。`cwd` 可选(字符串):用于固定相对路径解析目录。',
|
|
2855
2858
|
'用 `tools.whitelist/blacklist` 控制暴露的工具,用 `transform` 做命名变换。',
|
|
2856
|
-
'常见坑:stdio transport
|
|
2859
|
+
'常见坑:stdio transport 需要可执行命令路径正确,且受成员权限(目录 + 扩展名:`*_dirs/no_*_dirs/*_file_ext_names/no_*_file_ext_names`)约束;HTTP transport 需要服务可达(url/端口/网络)。',
|
|
2857
2860
|
'高频坑(stdio 路径):若未设置 `cwd`,相对路径按 Dominds 进程工作目录(通常 rtws 根目录)解析;建议显式配置 `cwd` 或直接使用绝对路径。`cwd` 必须存在且是目录。',
|
|
2858
2861
|
'最小诊断流程(建议顺序):1) 先用 `team_mgmt_check_provider({ provider_key: \"<providerKey>\", model: \"\", all_models: false, live: false, max_models: 0 })` 确认 LLM provider 可用;2) 再检查该成员的目录权限(`team_mgmt_manual({ topics: [\"permissions\"] })`);3) 运行 `team_mgmt_validate_mcp_cfg({})` 汇总 `.minds/mcp.yaml` 与 MCP 问题;4) 必要时 `mcp_restart`,用完记得 `mcp_release`。',
|
|
2859
2862
|
]) +
|
|
@@ -2903,7 +2906,7 @@ async function renderMcpManual(language) {
|
|
|
2903
2906
|
"Default is per-dialog MCP client leasing (safer): first use adds a sticky reminder; call `mcp_release` when you're sure you won't need the toolset soon. If the server is truly stateless, set `truely-stateless: true` to allow cross-dialog sharing.",
|
|
2904
2907
|
'Stdio shape: `command` must be a string executable; parameters go in `args` (string[], optional, defaults to empty). Optional `cwd` (string) fixes the working directory used for relative paths.',
|
|
2905
2908
|
'Use `tools.whitelist/blacklist` for exposure control and `transform` for naming transforms.',
|
|
2906
|
-
'Common pitfalls: stdio transport needs a correct executable/command path, and is subject to member directory
|
|
2909
|
+
'Common pitfalls: stdio transport needs a correct executable/command path, and is subject to member permissions (directory + extension: `*_dirs/no_*_dirs/*_file_ext_names/no_*_file_ext_names`); HTTP transport requires the server URL to be reachable.',
|
|
2907
2910
|
'High-frequency pitfall (stdio paths): if `cwd` is omitted, relative paths are resolved from Dominds process cwd (usually rtws root). Prefer setting `cwd` explicitly or use absolute paths. `cwd` must exist and be a directory.',
|
|
2908
2911
|
'Minimal diagnostic flow: 1) run `team_mgmt_check_provider({ provider_key: \"<providerKey>\", model: \"\", all_models: false, live: false, max_models: 0 })` to confirm the LLM provider works; 2) review member directory permissions (`team_mgmt_manual({ topics: [\"permissions\"] })`); 3) run `team_mgmt_validate_mcp_cfg({})` to summarize `.minds/mcp.yaml` + MCP issues; 4) use `mcp_restart` if needed, and `mcp_release` when done.',
|
|
2909
2912
|
]) +
|
|
@@ -2948,12 +2951,15 @@ async function renderMcpManual(language) {
|
|
|
2948
2951
|
}
|
|
2949
2952
|
function renderPermissionsManual(language) {
|
|
2950
2953
|
if (language === 'zh') {
|
|
2951
|
-
return (fmtHeader('
|
|
2954
|
+
return (fmtHeader('权限(目录 + 扩展名)') +
|
|
2952
2955
|
fmtList([
|
|
2953
|
-
'
|
|
2954
|
-
'
|
|
2955
|
-
'
|
|
2956
|
+
'目录字段:`read_dirs` / `write_dirs` / `no_read_dirs` / `no_write_dirs`。',
|
|
2957
|
+
'扩展名字段:`read_file_ext_names` / `write_file_ext_names` / `no_read_file_ext_names` / `no_write_file_ext_names`。',
|
|
2958
|
+
'deny-list(`no_*`)优先于 allow-list(`*`)。目录与扩展名两个维度都需要通过。',
|
|
2959
|
+
'若某维度未配置 allow-list,则该维度默认允许(在 deny-list 不命中的前提下)。这很方便,但也更容易“权限过大”;如需最小权限,建议显式收敛 allow-list 并对敏感目录/扩展名加 deny-list。',
|
|
2956
2960
|
'`read_dirs` 与 `write_dirs` 是独立控制:不要默认 write implies read(以当前实现的权限检查为准)。',
|
|
2961
|
+
'`read_file_ext_names` 与 `write_file_ext_names` 同样是独立控制。',
|
|
2962
|
+
'扩展名按文件名后缀精确匹配(大小写不敏感,配置项可写 `ts` 或 `.ts`)。',
|
|
2957
2963
|
'模式支持 `*` 和 `**`,按“目录范围”语义匹配(按目录/路径前缀范围来理解)。',
|
|
2958
2964
|
'示例:`dominds/**` 会匹配 `dominds/README.md`、`dominds/main/server.ts`、`dominds/webapp/src/...` 等路径。',
|
|
2959
2965
|
'示例:`.minds/**` 会匹配 `.minds/team.yaml`、`.minds/team/<id>/persona.zh.md` 等;常用于限制普通成员访问 minds 资产。',
|
|
@@ -2971,12 +2977,15 @@ function renderPermissionsManual(language) {
|
|
|
2971
2977
|
' no_write_dirs: [".minds/**"]',
|
|
2972
2978
|
]));
|
|
2973
2979
|
}
|
|
2974
|
-
return (fmtHeader('
|
|
2980
|
+
return (fmtHeader('Permissions (Directory + Extension)') +
|
|
2975
2981
|
fmtList([
|
|
2976
|
-
'
|
|
2977
|
-
'
|
|
2978
|
-
'
|
|
2982
|
+
'Directory fields: `read_dirs` / `write_dirs` / `no_read_dirs` / `no_write_dirs`.',
|
|
2983
|
+
'Extension fields: `read_file_ext_names` / `write_file_ext_names` / `no_read_file_ext_names` / `no_write_file_ext_names`.',
|
|
2984
|
+
'Deny-lists (`no_*`) override allow-lists (`*`). Both directory and extension dimensions must pass.',
|
|
2985
|
+
'If a dimension has no allow-list, that dimension defaults to allow (after deny-list check). This is convenient but can be overly permissive; for least privilege, explicitly narrow allow-lists and deny sensitive directories/extensions.',
|
|
2979
2986
|
'`read_dirs` and `write_dirs` are controlled independently (do not assume write implies read; follow current implementation).',
|
|
2987
|
+
'`read_file_ext_names` and `write_file_ext_names` are also controlled independently.',
|
|
2988
|
+
'Extension names are exact suffix matches (case-insensitive; config accepts `ts` or `.ts`).',
|
|
2980
2989
|
'Patterns support `*` and `**` with directory-scope semantics (think directory/path-range matching).',
|
|
2981
2990
|
'Example: `dominds/**` matches `dominds/README.md`, `dominds/main/server.ts`, `dominds/webapp/src/...`, etc.',
|
|
2982
2991
|
'Example: `.minds/**` matches `.minds/team.yaml` and `.minds/team/<id>/persona.*.md`; commonly used to restrict normal members from minds assets.',
|
|
@@ -3114,7 +3123,7 @@ function renderTroubleshooting(language) {
|
|
|
3114
3123
|
'症状:提示“缺少 provider/model” → 原因:`member_defaults` 或成员覆盖缺失 → 步骤:检查 `.minds/team.yaml` 的 `member_defaults.provider/model`(以及 `members.<id>.provider/model` 是否写错)。',
|
|
3115
3124
|
'症状:提示“Provider not found” → 原因:provider key 未定义/拼写错误/未按预期合并 defaults → 步骤:检查 `.minds/llm.yaml` 的 provider keys,并确认 `.minds/team.yaml` 引用的 key 存在。',
|
|
3116
3125
|
'症状:提示“Model not found” → 原因:model key 未定义/拼写错误/不在该 provider 下 → 步骤:用 `team_mgmt_list_models({ provider_pattern: \"<providerKey>\", model_pattern: \"*\" })` 查已有模型 key,再修正 `.minds/team.yaml` 引用或补全 `.minds/llm.yaml`。',
|
|
3117
|
-
'症状:提示“permission denied / forbidden / not allowed” →
|
|
3126
|
+
'症状:提示“permission denied / forbidden / not allowed” → 原因:权限规则(目录或扩展名)命中 deny-list 或未被 allow-list 覆盖 → 步骤:用 `team_mgmt_manual({ topics: [\"permissions\"] })` 复核规则,并检查该成员的 `*_dirs/no_*_dirs/*_file_ext_names/no_*_file_ext_names` 配置。',
|
|
3118
3127
|
'症状:MCP 不生效 → 原因:mcp 配置错误/服务不可用/租用未释放 → 步骤:先运行 `team_mgmt_validate_mcp_cfg({})` 汇总错误;必要时用 `mcp_restart`;完成后用 `mcp_release` 释放租用。',
|
|
3119
3128
|
]));
|
|
3120
3129
|
}
|
|
@@ -3124,7 +3133,7 @@ function renderTroubleshooting(language) {
|
|
|
3124
3133
|
'Symptom: "Missing provider/model" → Cause: missing `member_defaults` or member overrides → Steps: check `.minds/team.yaml` `member_defaults.provider/model` (and `members.<id>.provider/model`).',
|
|
3125
3134
|
'Symptom: "Provider not found" → Cause: provider key not defined / typo / unexpected merge with defaults → Steps: check `.minds/llm.yaml` provider keys and ensure `.minds/team.yaml` references an existing key.',
|
|
3126
3135
|
'Symptom: "Model not found" → Cause: model key not defined / typo / not under that provider → Steps: run `team_mgmt_list_models({ provider_pattern: \"<providerKey>\", model_pattern: \"*\" })` and fix `.minds/team.yaml` references or update `.minds/llm.yaml`.',
|
|
3127
|
-
'Symptom: "permission denied / forbidden / not allowed" → Cause: directory
|
|
3136
|
+
'Symptom: "permission denied / forbidden / not allowed" → Cause: permission rules (directory or extension) hit deny-list or are not covered by allow-list → Steps: review `team_mgmt_manual({ topics: [\"permissions\"] })` and the member `*_dirs/no_*_dirs/*_file_ext_names/no_*_file_ext_names` config.',
|
|
3128
3137
|
'Symptom: MCP not working → Cause: bad config / server down / leasing issues → Steps: run `team_mgmt_validate_mcp_cfg({})` first, then use `mcp_restart` if needed; call `mcp_release` when done.',
|
|
3129
3138
|
]));
|
|
3130
3139
|
}
|
|
@@ -3802,7 +3811,7 @@ exports.teamMgmtManualTool = {
|
|
|
3802
3811
|
`\`team_mgmt_manual({ topics: ["team"] })\`:${topicTitle('team')} — .minds/team.yaml(团队花名册、工具集、目录权限入口)`,
|
|
3803
3812
|
`\`team_mgmt_manual({ topics: ["minds"] })\`:${topicTitle('minds')} — .minds/team/<id>/*(persona/knowledge/lessons 资产怎么写)`,
|
|
3804
3813
|
`\`team_mgmt_manual({ topics: ["env"] })\`:${topicTitle('env')} — .minds/env.*.md(运行环境提示:在团队介绍之前注入)`,
|
|
3805
|
-
`\`team_mgmt_manual({ topics: ["permissions"] })\`:${topicTitle('permissions')} —
|
|
3814
|
+
`\`team_mgmt_manual({ topics: ["permissions"] })\`:${topicTitle('permissions')} — 目录+扩展名权限(*_dirs/no_*_dirs/*_file_ext_names/no_*_file_ext_names 语义与冲突规则)`,
|
|
3806
3815
|
`\`team_mgmt_manual({ topics: ["toolsets"] })\`:${topicTitle('toolsets')} — toolsets 列表(当前已注册 toolsets;常见三种授权模式)`,
|
|
3807
3816
|
`\`team_mgmt_manual({ topics: ["llm"] })\`:${topicTitle('llm')} — .minds/llm.yaml(provider key 如何定义/引用;env var 安全边界)`,
|
|
3808
3817
|
`\`team_mgmt_manual({ topics: ["mcp"] })\`:${topicTitle('mcp')} — .minds/mcp.yaml(MCP serverId→toolset;热重载与租用;可复制最小模板)`,
|
|
@@ -3822,7 +3831,7 @@ exports.teamMgmtManualTool = {
|
|
|
3822
3831
|
`\`team_mgmt_manual({ topics: ["team"] })\`: ${topicTitle('team')} — .minds/team.yaml (roster/toolsets/permissions entrypoint)`,
|
|
3823
3832
|
`\`team_mgmt_manual({ topics: ["minds"] })\`: ${topicTitle('minds')} — .minds/team/<id>/* (persona/knowledge/lessons assets)`,
|
|
3824
3833
|
`\`team_mgmt_manual({ topics: ["env"] })\`: ${topicTitle('env')} — .minds/env.*.md (runtime intro injected before Team Directory)`,
|
|
3825
|
-
`\`team_mgmt_manual({ topics: ["permissions"] })\`: ${topicTitle('permissions')} — directory permissions (semantics + conflict rules)`,
|
|
3834
|
+
`\`team_mgmt_manual({ topics: ["permissions"] })\`: ${topicTitle('permissions')} — directory + extension permissions (semantics + conflict rules)`,
|
|
3826
3835
|
`\`team_mgmt_manual({ topics: ["toolsets"] })\`: ${topicTitle('toolsets')} — toolsets list (registered toolsets + common patterns)`,
|
|
3827
3836
|
`\`team_mgmt_manual({ topics: ["llm"] })\`: ${topicTitle('llm')} — .minds/llm.yaml (provider keys, env var boundaries)`,
|
|
3828
3837
|
`\`team_mgmt_manual({ topics: ["mcp"] })\`: ${topicTitle('mcp')} — .minds/mcp.yaml (serverId→toolset, hot reload, leasing, minimal templates)`,
|