dominds 0.8.19 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/README.md +5 -1
  2. package/README.zh.md +5 -1
  3. package/dist/access-control.js +72 -23
  4. package/dist/docs/team_mgmt-toolset.md +1 -0
  5. package/dist/docs/team_mgmt-toolset.zh.md +1 -0
  6. package/dist/server/setup-routes.js +92 -26
  7. package/dist/static/assets/{_baseUniq-Bz-BK38X.js → _baseUniq-CoUduYbj.js} +2 -2
  8. package/dist/static/assets/{_baseUniq-Bz-BK38X.js.map → _baseUniq-CoUduYbj.js.map} +1 -1
  9. package/dist/static/assets/{arc-9gq7MlM9.js → arc-B79evgv8.js} +2 -2
  10. package/dist/static/assets/{arc-9gq7MlM9.js.map → arc-B79evgv8.js.map} +1 -1
  11. package/dist/static/assets/{architectureDiagram-VXUJARFQ-CZIvAcDK.js → architectureDiagram-VXUJARFQ-rLlQb9R_.js} +6 -6
  12. package/dist/static/assets/{architectureDiagram-VXUJARFQ-CZIvAcDK.js.map → architectureDiagram-VXUJARFQ-rLlQb9R_.js.map} +1 -1
  13. package/dist/static/assets/{blockDiagram-VD42YOAC-8XKqYs9h.js → blockDiagram-VD42YOAC-DKsP6RFH.js} +7 -7
  14. package/dist/static/assets/{blockDiagram-VD42YOAC-8XKqYs9h.js.map → blockDiagram-VD42YOAC-DKsP6RFH.js.map} +1 -1
  15. package/dist/static/assets/{c4Diagram-YG6GDRKO-01_3zzE3.js → c4Diagram-YG6GDRKO-BrSPmLIb.js} +3 -3
  16. package/dist/static/assets/{c4Diagram-YG6GDRKO-01_3zzE3.js.map → c4Diagram-YG6GDRKO-BrSPmLIb.js.map} +1 -1
  17. package/dist/static/assets/{channel-BGHx3NMy.js → channel-CQ18oNtY.js} +2 -2
  18. package/dist/static/assets/{channel-BGHx3NMy.js.map → channel-CQ18oNtY.js.map} +1 -1
  19. package/dist/static/assets/{chunk-4BX2VUAB-B12vclXR.js → chunk-4BX2VUAB-D8e6GJKc.js} +2 -2
  20. package/dist/static/assets/{chunk-4BX2VUAB-B12vclXR.js.map → chunk-4BX2VUAB-D8e6GJKc.js.map} +1 -1
  21. package/dist/static/assets/{chunk-55IACEB6-G6Q4T2VW.js → chunk-55IACEB6-0_nYvlGV.js} +2 -2
  22. package/dist/static/assets/{chunk-55IACEB6-G6Q4T2VW.js.map → chunk-55IACEB6-0_nYvlGV.js.map} +1 -1
  23. package/dist/static/assets/{chunk-B4BG7PRW-DV03ZyO0.js → chunk-B4BG7PRW-c3Osrj3P.js} +5 -5
  24. package/dist/static/assets/{chunk-B4BG7PRW-DV03ZyO0.js.map → chunk-B4BG7PRW-c3Osrj3P.js.map} +1 -1
  25. package/dist/static/assets/{chunk-DI55MBZ5-CMjP9HRy.js → chunk-DI55MBZ5-B3wy4mTI.js} +4 -4
  26. package/dist/static/assets/{chunk-DI55MBZ5-CMjP9HRy.js.map → chunk-DI55MBZ5-B3wy4mTI.js.map} +1 -1
  27. package/dist/static/assets/{chunk-FMBD7UC4-BX3p-W9Z.js → chunk-FMBD7UC4-DrcK9WUz.js} +2 -2
  28. package/dist/static/assets/{chunk-FMBD7UC4-BX3p-W9Z.js.map → chunk-FMBD7UC4-DrcK9WUz.js.map} +1 -1
  29. package/dist/static/assets/{chunk-QN33PNHL-CeixSGPE.js → chunk-QN33PNHL-fn6UG5b8.js} +2 -2
  30. package/dist/static/assets/{chunk-QN33PNHL-CeixSGPE.js.map → chunk-QN33PNHL-fn6UG5b8.js.map} +1 -1
  31. package/dist/static/assets/{chunk-QZHKN3VN-DHmlRthm.js → chunk-QZHKN3VN-lwz9tfKX.js} +2 -2
  32. package/dist/static/assets/{chunk-QZHKN3VN-DHmlRthm.js.map → chunk-QZHKN3VN-lwz9tfKX.js.map} +1 -1
  33. package/dist/static/assets/{chunk-TZMSLE5B-BQoTFJrz.js → chunk-TZMSLE5B-aXbZylkp.js} +2 -2
  34. package/dist/static/assets/{chunk-TZMSLE5B-BQoTFJrz.js.map → chunk-TZMSLE5B-aXbZylkp.js.map} +1 -1
  35. package/dist/static/assets/{classDiagram-2ON5EDUG-DmGBGhQA.js → classDiagram-2ON5EDUG-ByC6PvUi.js} +6 -6
  36. package/dist/static/assets/{classDiagram-2ON5EDUG-DmGBGhQA.js.map → classDiagram-2ON5EDUG-ByC6PvUi.js.map} +1 -1
  37. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-DmGBGhQA.js → classDiagram-v2-WZHVMYZB-ByC6PvUi.js} +6 -6
  38. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-DmGBGhQA.js.map → classDiagram-v2-WZHVMYZB-ByC6PvUi.js.map} +1 -1
  39. package/dist/static/assets/{clone-iHXiGToF.js → clone-BDJhQHyk.js} +2 -2
  40. package/dist/static/assets/{clone-iHXiGToF.js.map → clone-BDJhQHyk.js.map} +1 -1
  41. package/dist/static/assets/{cose-bilkent-S5V4N54A-M1lEFQCe.js → cose-bilkent-S5V4N54A-HAsn54-S.js} +2 -2
  42. package/dist/static/assets/{cose-bilkent-S5V4N54A-M1lEFQCe.js.map → cose-bilkent-S5V4N54A-HAsn54-S.js.map} +1 -1
  43. package/dist/static/assets/{dagre-6UL2VRFP-DCdK_t3m.js → dagre-6UL2VRFP-DgBnUfQ7.js} +7 -7
  44. package/dist/static/assets/{dagre-6UL2VRFP-DCdK_t3m.js.map → dagre-6UL2VRFP-DgBnUfQ7.js.map} +1 -1
  45. package/dist/static/assets/{diagram-PSM6KHXK-hjak5A8Z.js → diagram-PSM6KHXK-B0Oej_SM.js} +7 -7
  46. package/dist/static/assets/{diagram-PSM6KHXK-hjak5A8Z.js.map → diagram-PSM6KHXK-B0Oej_SM.js.map} +1 -1
  47. package/dist/static/assets/{diagram-QEK2KX5R-B4lGYVPl.js → diagram-QEK2KX5R-B-P9Chdj.js} +6 -6
  48. package/dist/static/assets/{diagram-QEK2KX5R-B4lGYVPl.js.map → diagram-QEK2KX5R-B-P9Chdj.js.map} +1 -1
  49. package/dist/static/assets/{diagram-S2PKOQOG-aeydbv9S.js → diagram-S2PKOQOG-BrnNRpnf.js} +6 -6
  50. package/dist/static/assets/{diagram-S2PKOQOG-aeydbv9S.js.map → diagram-S2PKOQOG-BrnNRpnf.js.map} +1 -1
  51. package/dist/static/assets/{erDiagram-Q2GNP2WA-Bjrr_17N.js → erDiagram-Q2GNP2WA-CjhZUP-_.js} +5 -5
  52. package/dist/static/assets/{erDiagram-Q2GNP2WA-Bjrr_17N.js.map → erDiagram-Q2GNP2WA-CjhZUP-_.js.map} +1 -1
  53. package/dist/static/assets/{flowDiagram-NV44I4VS-CmJUhZIL.js → flowDiagram-NV44I4VS-DW5irfHa.js} +6 -6
  54. package/dist/static/assets/{flowDiagram-NV44I4VS-CmJUhZIL.js.map → flowDiagram-NV44I4VS-DW5irfHa.js.map} +1 -1
  55. package/dist/static/assets/{ganttDiagram-JELNMOA3-D6FQehn7.js → ganttDiagram-JELNMOA3-CkFnAxLO.js} +3 -3
  56. package/dist/static/assets/{ganttDiagram-JELNMOA3-D6FQehn7.js.map → ganttDiagram-JELNMOA3-CkFnAxLO.js.map} +1 -1
  57. package/dist/static/assets/{gitGraphDiagram-NY62KEGX-Df_n9jMf.js → gitGraphDiagram-NY62KEGX-CW5UQfhl.js} +7 -7
  58. package/dist/static/assets/{gitGraphDiagram-NY62KEGX-Df_n9jMf.js.map → gitGraphDiagram-NY62KEGX-CW5UQfhl.js.map} +1 -1
  59. package/dist/static/assets/{graph--pnRzOJm.js → graph-QsUQvOUG.js} +3 -3
  60. package/dist/static/assets/{graph--pnRzOJm.js.map → graph-QsUQvOUG.js.map} +1 -1
  61. package/dist/static/assets/{index-BRtsWi20.js → index-BWgwzFdG.js} +64 -47
  62. package/dist/static/assets/index-BWgwzFdG.js.map +1 -0
  63. package/dist/static/assets/{infoDiagram-WHAUD3N6-DPBHtM_B.js → infoDiagram-WHAUD3N6-1hutUswv.js} +5 -5
  64. package/dist/static/assets/{infoDiagram-WHAUD3N6-DPBHtM_B.js.map → infoDiagram-WHAUD3N6-1hutUswv.js.map} +1 -1
  65. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Bj7Wxlq5.js → journeyDiagram-XKPGCS4Q-CYEB2gYA.js} +5 -5
  66. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Bj7Wxlq5.js.map → journeyDiagram-XKPGCS4Q-CYEB2gYA.js.map} +1 -1
  67. package/dist/static/assets/{kanban-definition-3W4ZIXB7-C3R4ZPwh.js → kanban-definition-3W4ZIXB7-B_rokrwL.js} +3 -3
  68. package/dist/static/assets/{kanban-definition-3W4ZIXB7-C3R4ZPwh.js.map → kanban-definition-3W4ZIXB7-B_rokrwL.js.map} +1 -1
  69. package/dist/static/assets/{layout-BJpf8jM4.js → layout-DD4e7kuc.js} +5 -5
  70. package/dist/static/assets/{layout-BJpf8jM4.js.map → layout-DD4e7kuc.js.map} +1 -1
  71. package/dist/static/assets/{linear-CNE3iYsu.js → linear-CpmZo_ZS.js} +2 -2
  72. package/dist/static/assets/{linear-CNE3iYsu.js.map → linear-CpmZo_ZS.js.map} +1 -1
  73. package/dist/static/assets/{min-Cswe2bqk.js → min-CFkzEekk.js} +3 -3
  74. package/dist/static/assets/{min-Cswe2bqk.js.map → min-CFkzEekk.js.map} +1 -1
  75. package/dist/static/assets/{mindmap-definition-VGOIOE7T-CeuQ--gx.js → mindmap-definition-VGOIOE7T-WLy2VPYm.js} +4 -4
  76. package/dist/static/assets/{mindmap-definition-VGOIOE7T-CeuQ--gx.js.map → mindmap-definition-VGOIOE7T-WLy2VPYm.js.map} +1 -1
  77. package/dist/static/assets/{pieDiagram-ADFJNKIX-BnHq9l2P.js → pieDiagram-ADFJNKIX-2nx2cHS8.js} +7 -7
  78. package/dist/static/assets/{pieDiagram-ADFJNKIX-BnHq9l2P.js.map → pieDiagram-ADFJNKIX-2nx2cHS8.js.map} +1 -1
  79. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-2WOn9ed4.js → quadrantDiagram-AYHSOK5B-ELd4blG4.js} +3 -3
  80. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-2WOn9ed4.js.map → quadrantDiagram-AYHSOK5B-ELd4blG4.js.map} +1 -1
  81. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-CzbOZbJ8.js → requirementDiagram-UZGBJVZJ-BEleMcvW.js} +4 -4
  82. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-CzbOZbJ8.js.map → requirementDiagram-UZGBJVZJ-BEleMcvW.js.map} +1 -1
  83. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-BCY4ttm3.js → sankeyDiagram-TZEHDZUN-_xcwg8aT.js} +2 -2
  84. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-BCY4ttm3.js.map → sankeyDiagram-TZEHDZUN-_xcwg8aT.js.map} +1 -1
  85. package/dist/static/assets/{sequenceDiagram-WL72ISMW-DV3CMHo6.js → sequenceDiagram-WL72ISMW-B5W6BMbd.js} +4 -4
  86. package/dist/static/assets/{sequenceDiagram-WL72ISMW-DV3CMHo6.js.map → sequenceDiagram-WL72ISMW-B5W6BMbd.js.map} +1 -1
  87. package/dist/static/assets/{stateDiagram-FKZM4ZOC-B69ywNB2.js → stateDiagram-FKZM4ZOC-BtAHVsVQ.js} +9 -9
  88. package/dist/static/assets/{stateDiagram-FKZM4ZOC-B69ywNB2.js.map → stateDiagram-FKZM4ZOC-BtAHVsVQ.js.map} +1 -1
  89. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-YAQW9OlS.js → stateDiagram-v2-4FDKWEC3-DzGcYKQT.js} +5 -5
  90. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-YAQW9OlS.js.map → stateDiagram-v2-4FDKWEC3-DzGcYKQT.js.map} +1 -1
  91. package/dist/static/assets/{timeline-definition-IT6M3QCI-DrrUTBG7.js → timeline-definition-IT6M3QCI-UdhLD6FT.js} +3 -3
  92. package/dist/static/assets/{timeline-definition-IT6M3QCI-DrrUTBG7.js.map → timeline-definition-IT6M3QCI-UdhLD6FT.js.map} +1 -1
  93. package/dist/static/assets/{treemap-KMMF4GRG-Ld__veZ8.js → treemap-KMMF4GRG-C9kUtGO2.js} +4 -4
  94. package/dist/static/assets/{treemap-KMMF4GRG-Ld__veZ8.js.map → treemap-KMMF4GRG-C9kUtGO2.js.map} +1 -1
  95. package/dist/static/assets/{xychartDiagram-PRI3JC2R-DnCUF4Ds.js → xychartDiagram-PRI3JC2R-BZCzGwDm.js} +3 -3
  96. package/dist/static/assets/{xychartDiagram-PRI3JC2R-DnCUF4Ds.js.map → xychartDiagram-PRI3JC2R-BZCzGwDm.js.map} +1 -1
  97. package/dist/static/index.html +1 -1
  98. package/dist/team.js +84 -0
  99. package/dist/tools/builtins.js +16 -14
  100. package/dist/tools/os.js +55 -6
  101. package/dist/tools/prompts/os/en/tools.md +1 -1
  102. package/dist/tools/prompts/os/zh/tools.md +1 -1
  103. package/dist/tools/prompts/team_mgmt/en/index.md +1 -0
  104. package/dist/tools/prompts/team_mgmt/en/tools.md +11 -1
  105. package/dist/tools/prompts/team_mgmt/zh/index.md +1 -0
  106. package/dist/tools/prompts/team_mgmt/zh/tools.md +11 -1
  107. package/dist/tools/team_mgmt.js +115 -26
  108. package/package.json +1 -1
  109. package/dist/static/assets/index-BRtsWi20.js.map +0 -1
package/README.md CHANGED
@@ -167,9 +167,13 @@ Then:
167
167
  1. Your browser should land on `http://localhost:5666/setup` (either directly, or via an automatic redirect).
168
168
  2. In **Setup**, pick a provider + model. If your template didn’t create `.minds/team.yaml`, use Setup to create/overwrite it (this writes a minimal `member_defaults` config).
169
169
  3. Still in **Setup**, set the required provider env var (the name comes from the provider catalog, e.g. `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `CODEX_HOME`, etc.).
170
- - The setup UI can write it into `~/.zshrc` / `~/.bashrc` in a managed block, and also applies it to the running server process immediately.
170
+ - The setup UI can write it to `.env.local` (all platforms), and on Linux/macOS it can also write into `~/.zshrc` / `~/.bashrc` in managed blocks. It also applies the value to the running server process immediately.
171
171
  4. Click **Go to App**, create a dialog, and start working.
172
172
 
173
+ Platform note:
174
+
175
+ - On Windows, the runtime does not register the `codex_style_tools` toolset. Do not grant `codex_style_tools` in `.minds/team.yaml` for Windows hosts.
176
+
173
177
  ## Start from scratch
174
178
 
175
179
  Starting from scratch means: create an empty folder, run `dominds`, let Setup generate the minimal `.minds/team.yaml`, then use the shadow team manager (`@fuxi`) to design a real team for your product.
package/README.zh.md CHANGED
@@ -89,9 +89,13 @@ dominds
89
89
  首次启动后,通常会自动跳转至 `http://localhost:5666/setup` 配置页面,按以下步骤操作:
90
90
 
91
91
  1. 选择提供商(provider)及模型(model),创建或覆盖 `.minds/team.yaml`(最小化可运行配置文件)。
92
- 2. 根据提示设置提供商所需的环境变量(配置页可协助将变量写入 `~/.zshrc` 或 `~/.bashrc` 的托管区块)。
92
+ 2. 根据提示设置提供商所需的环境变量(配置页可将变量写入 `.env.local`,并在 Linux/macOS 上额外支持写入 `~/.zshrc` 或 `~/.bashrc` 的托管区块)。
93
93
  3. 进入主界面,创建对话即可开始工作(对话、记忆、差遣牒等运行态数据均存储在当前 rtws 下)。
94
94
 
95
+ 平台说明:
96
+
97
+ - Windows 运行时不会注册 `codex_style_tools` 工具集。在 Windows 主机上的 `.minds/team.yaml` 中不要授予 `codex_style_tools`。
98
+
95
99
  ## 从零开始(空文件夹启动)
96
100
 
97
101
  若暂无模板或团队配置,可直接从空目录启动:
@@ -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. If no whitelist patterns are defined, allow access (default allow)
146
- * 4. If whitelist patterns exist but none match, deny access
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
- if (whitelist.length === 0) {
187
- return true;
188
- }
189
- // Check if path matches any whitelist pattern
190
- for (const pattern of whitelist) {
191
- if (matchesPattern(relativePath, pattern)) {
192
- return true; // Explicitly allowed
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
- // Path doesn't match any whitelist pattern
196
- return false;
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. If no whitelist patterns are defined, allow access (default allow)
205
- * 4. If whitelist patterns exist but none match, deny access
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
- if (whitelist.length === 0) {
246
- return true;
247
- }
248
- // Check if path matches any whitelist pattern
249
- for (const pattern of whitelist) {
250
- if (matchesPattern(relativePath, pattern)) {
251
- return true; // Explicitly allowed
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
- // Path doesn't match any whitelist pattern
255
- return false;
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
  }
@@ -424,6 +424,7 @@ Best practices:
424
424
 
425
425
  - Make `member_defaults` conservative. Grant additional tools/dirs on a per-member basis.
426
426
  - Prefer toolsets over individually enumerating tools unless you need a one-off tool.
427
+ - Platform note: Windows runtime intentionally does not register `codex_style_tools`; do not grant that toolset in `.minds/team.yaml` on Windows hosts.
427
428
  - Keep `.minds/team.yaml` ownership tight; only the team manager should be able to edit it.
428
429
  - Avoid repeating built-in constraints in `team.yaml`:
429
430
  - `*.tsk/**` (encapsulated Taskdocs) are hard-denied for all general file tools.
@@ -370,6 +370,7 @@ members:
370
370
 
371
371
  - 使 `member_defaults` 保守。按成员授予额外的工具/目录
372
372
  - 优先使用工具集而不是单独枚举工具,除非你需要一次性工具
373
+ - 平台说明:Windows 运行时不会注册 `codex_style_tools`;在 Windows 主机上的 `.minds/team.yaml` 中不要授予该工具集
373
374
  - 保持 `.minds/team.yaml` 的所有权严格;只有团队管理者应该能够编辑它
374
375
  - 避免在 `team.yaml` 中重复内置约束:
375
376
  - `*.tsk/**`(封装的 Taskdocs)对所有通用文件工具被硬性拒绝
@@ -19,14 +19,17 @@ const team_config_updates_1 = require("../team-config-updates");
19
19
  const log = (0, log_1.createLogger)('setup-routes');
20
20
  const TEAM_YAML_PATH = path_1.default.join('.minds', 'team.yaml');
21
21
  const RTWS_LLM_YAML_PATH = path_1.default.join('.minds', 'llm.yaml');
22
+ const RTWS_ENV_LOCAL_PATH = '.env.local';
22
23
  const BUILTIN_DEFAULTS_YAML_PATH = path_1.default.join(__dirname, '..', 'llm', 'defaults.yaml');
23
24
  const DOMINDS_ENV_BLOCK_START = '# >>> dominds env >>>';
24
25
  const DOMINDS_ENV_BLOCK_END = '# <<< dominds env <<<';
25
26
  async function buildSetupStatusResponse() {
26
27
  const builtin = await loadBuiltinProviders();
27
28
  const merged = await client_1.LlmConfig.load();
29
+ const shellPlatform = resolveSetupPlatform(process.platform);
28
30
  const shellEnv = typeof process.env.SHELL === 'string' ? process.env.SHELL : null;
29
31
  const shellKind = resolveShellKind(shellEnv);
32
+ const envLocal = await statRcFile(RTWS_ENV_LOCAL_PATH);
30
33
  const home = os_1.default.homedir();
31
34
  const bashrcPath = path_1.default.join(home, '.bashrc');
32
35
  const zshrcPath = path_1.default.join(home, '.zshrc');
@@ -44,7 +47,13 @@ async function buildSetupStatusResponse() {
44
47
  return {
45
48
  success: false,
46
49
  requirement,
47
- shell: { env: shellEnv, kind: shellKind, defaultRc: shellKindToDefaultRc(shellKind) },
50
+ shell: {
51
+ platform: shellPlatform,
52
+ env: shellEnv,
53
+ kind: shellKind,
54
+ defaultRc: shellKindToDefaultRc(shellKind),
55
+ },
56
+ envLocal,
48
57
  rc,
49
58
  teamYaml,
50
59
  rtwsLlmYaml,
@@ -53,13 +62,20 @@ async function buildSetupStatusResponse() {
53
62
  };
54
63
  }
55
64
  const providers = await buildProviderSummaries(builtin.providers, builtin.providerKeysInOrder, {
65
+ envLocalPath: RTWS_ENV_LOCAL_PATH,
56
66
  bashrcPath,
57
67
  zshrcPath,
58
68
  });
59
69
  return {
60
70
  success: true,
61
71
  requirement,
62
- shell: { env: shellEnv, kind: shellKind, defaultRc: shellKindToDefaultRc(shellKind) },
72
+ shell: {
73
+ platform: shellPlatform,
74
+ env: shellEnv,
75
+ kind: shellKind,
76
+ defaultRc: shellKindToDefaultRc(shellKind),
77
+ },
78
+ envLocal,
63
79
  rc,
64
80
  teamYaml,
65
81
  rtwsLlmYaml,
@@ -117,15 +133,27 @@ async function handleWriteShellEnv(rawBody) {
117
133
  try {
118
134
  // Apply to the current backend process immediately so setup can proceed without a restart.
119
135
  process.env[req.envVar] = req.value;
120
- const home = os_1.default.homedir();
121
- const targets = req.targets;
122
- const outcomes = [];
123
- for (const target of targets) {
124
- const filePath = path_1.default.join(home, target === 'bashrc' ? '.bashrc' : '.zshrc');
125
- const result = await upsertEnvVarIntoRcFile(filePath, req.envVar, req.value);
126
- outcomes.push({ target, path: filePath, result });
136
+ let filePath;
137
+ let result;
138
+ if (req.target === 'env_local') {
139
+ filePath = RTWS_ENV_LOCAL_PATH;
140
+ result = await upsertEnvVarIntoDotenvFile(filePath, req.envVar, req.value);
141
+ }
142
+ else {
143
+ if (!isPosixSetupPlatform(process.platform)) {
144
+ return {
145
+ kind: 'bad_request',
146
+ errorText: `Unsupported target on this platform: ${req.target}`,
147
+ };
148
+ }
149
+ const home = os_1.default.homedir();
150
+ filePath = path_1.default.join(home, req.target === 'bashrc' ? '.bashrc' : '.zshrc');
151
+ result = await upsertEnvVarIntoRcFile(filePath, req.envVar, req.value);
127
152
  }
128
- return { kind: 'ok', response: { success: true, outcomes } };
153
+ return {
154
+ kind: 'ok',
155
+ response: { success: true, outcome: { target: req.target, path: filePath, result } },
156
+ };
129
157
  }
130
158
  catch (error) {
131
159
  log.error('Failed to write shell env vars', error);
@@ -270,8 +298,9 @@ async function buildProviderSummaries(providers, providerKeysInOrder, paths) {
270
298
  for (const [providerKey, cfg] of orderedProviderEntries(providers, providerKeysInOrder)) {
271
299
  const envVar = cfg.apiKeyEnvVar;
272
300
  const envVarIsSet = typeof process.env[envVar] === 'string' && process.env[envVar] !== '';
273
- const bashrcHas = await rcHasEnvVar(paths.bashrcPath, envVar);
274
- const zshrcHas = await rcHasEnvVar(paths.zshrcPath, envVar);
301
+ const envLocalHas = await fileHasEnvVar(paths.envLocalPath, envVar);
302
+ const bashrcHas = await fileHasEnvVar(paths.bashrcPath, envVar);
303
+ const zshrcHas = await fileHasEnvVar(paths.zshrcPath, envVar);
275
304
  const models = Object.entries(cfg.models ?? {}).map(([modelKey, modelInfo]) => {
276
305
  const info = isRecord(modelInfo) ? modelInfo : {};
277
306
  const name = typeof info.name === 'string' ? info.name : undefined;
@@ -298,7 +327,7 @@ async function buildProviderSummaries(providers, providerKeysInOrder, paths) {
298
327
  apiKeyEnvVar: envVar,
299
328
  techSpecUrl: cfg.tech_spec_url,
300
329
  apiMgmtUrl: cfg.api_mgmt_url,
301
- envVar: { isSet: envVarIsSet, bashrcHas, zshrcHas },
330
+ envVar: { isSet: envVarIsSet, envLocalHas, bashrcHas, zshrcHas },
302
331
  models,
303
332
  ...(prominent.length > 0 ? { prominentModelParams: prominent } : {}),
304
333
  };
@@ -515,6 +544,18 @@ async function resolveSetupRequirement(params) {
515
544
  }
516
545
  return { kind: 'ok' };
517
546
  }
547
+ function resolveSetupPlatform(platform) {
548
+ if (platform === 'win32')
549
+ return 'windows';
550
+ if (platform === 'darwin')
551
+ return 'macos';
552
+ if (platform === 'linux')
553
+ return 'linux';
554
+ return 'other';
555
+ }
556
+ function isPosixSetupPlatform(platform) {
557
+ return platform === 'darwin' || platform === 'linux';
558
+ }
518
559
  function resolveShellKind(shellEnv) {
519
560
  if (!shellEnv)
520
561
  return 'other';
@@ -537,21 +578,14 @@ function parseWriteShellEnvRequest(value) {
537
578
  return null;
538
579
  const envVar = value['envVar'];
539
580
  const rawVal = value['value'];
540
- const targetsUnknown = value['targets'];
581
+ const target = value['target'];
541
582
  if (typeof envVar !== 'string' || !isSafeEnvVarName(envVar))
542
583
  return null;
543
584
  if (typeof rawVal !== 'string')
544
585
  return null;
545
- if (!Array.isArray(targetsUnknown))
546
- return null;
547
- const targets = [];
548
- for (const t of targetsUnknown) {
549
- if (t === 'bashrc' || t === 'zshrc')
550
- targets.push(t);
551
- }
552
- if (targets.length === 0)
586
+ if (target !== 'env_local' && target !== 'bashrc' && target !== 'zshrc')
553
587
  return null;
554
- return { envVar, value: rawVal, targets };
588
+ return { envVar, value: rawVal, target };
555
589
  }
556
590
  function parseWriteTeamYamlRequest(value) {
557
591
  if (!isRecord(value))
@@ -640,10 +674,10 @@ async function isWritable(filePath) {
640
674
  return false;
641
675
  }
642
676
  }
643
- async function rcHasEnvVar(rcPath, envVar) {
677
+ async function fileHasEnvVar(filePath, envVar) {
644
678
  try {
645
- const raw = await promises_1.default.readFile(rcPath, 'utf-8');
646
- const re = new RegExp(`(^|\\n)\\s*export\\s+${escapeRegExp(envVar)}=`, 'm');
679
+ const raw = await promises_1.default.readFile(filePath, 'utf-8');
680
+ const re = new RegExp(`(^|\\n)\\s*(?:export\\s+)?${escapeRegExp(envVar)}\\s*=`, 'm');
647
681
  return re.test(raw);
648
682
  }
649
683
  catch {
@@ -657,6 +691,28 @@ function shellQuoteSingle(value) {
657
691
  // Safe POSIX shell single-quoted string: close quote, escape single quote, reopen.
658
692
  return `'${value.replace(/'/g, "'\\''")}'`;
659
693
  }
694
+ function dotenvQuoteDouble(value) {
695
+ const escaped = value
696
+ .replace(/\\/g, '\\\\')
697
+ .replace(/\n/g, '\\n')
698
+ .replace(/\r/g, '\\r')
699
+ .replace(/\t/g, '\\t')
700
+ .replace(/"/g, '\\"');
701
+ return `"${escaped}"`;
702
+ }
703
+ async function upsertEnvVarIntoDotenvFile(filePath, envVar, value) {
704
+ const line = `${envVar}=${dotenvQuoteDouble(value)}`;
705
+ const exists = await fileExists(filePath);
706
+ const original = exists ? await promises_1.default.readFile(filePath, 'utf-8') : '';
707
+ const normalized = original.replace(/\r\n/g, '\n');
708
+ const lines = normalized === '' ? [] : normalized.split('\n');
709
+ const nextLines = upsertDotenvLine(lines, envVar, line);
710
+ let next = nextLines.join('\n');
711
+ if (!next.endsWith('\n'))
712
+ next += '\n';
713
+ await promises_1.default.writeFile(filePath, next, 'utf-8');
714
+ return exists ? 'updated' : 'created';
715
+ }
660
716
  async function upsertEnvVarIntoRcFile(filePath, envVar, value) {
661
717
  const exportLine = `export ${envVar}=${shellQuoteSingle(value)}`;
662
718
  const exists = await fileExists(filePath);
@@ -684,6 +740,16 @@ async function upsertEnvVarIntoRcFile(filePath, envVar, value) {
684
740
  await promises_1.default.writeFile(filePath, next, 'utf-8');
685
741
  return exists ? 'updated' : 'created';
686
742
  }
743
+ function upsertDotenvLine(lines, envVar, envLine) {
744
+ const re = new RegExp(`^\\s*(?:export\\s+)?${escapeRegExp(envVar)}\\s*=`);
745
+ const idx = lines.findIndex((l) => re.test(l));
746
+ if (idx >= 0) {
747
+ const copy = [...lines];
748
+ copy[idx] = envLine;
749
+ return copy;
750
+ }
751
+ return [...lines, envLine];
752
+ }
687
753
  function upsertExportLine(lines, envVar, exportLine) {
688
754
  const re = new RegExp(`^\\s*export\\s+${escapeRegExp(envVar)}=`);
689
755
  const idx = lines.findIndex((l) => re.test(l));
@@ -1,4 +1,4 @@
1
- import { aV as isObjectLike, br as baseGetTag, aE as isArray, aT as Symbol$1, bs as arrayLikeKeys, bt as baseKeys, aD as isArrayLike, bu as memoize, bv as isArguments, bw as MapCache, bm as eq, bx as Uint8Array, aW as getTag, a$ as isBuffer, b2 as Stack, by as isTypedArray, aZ as isObject, bz as isLength, bp as isIndex, aF as identity, bn as baseFor, bA as Set } from "./index-BRtsWi20.js";
1
+ import { aV as isObjectLike, br as baseGetTag, aE as isArray, aT as Symbol$1, bs as arrayLikeKeys, bt as baseKeys, aD as isArrayLike, bu as memoize, bv as isArguments, bw as MapCache, bm as eq, bx as Uint8Array, aW as getTag, a$ as isBuffer, b2 as Stack, by as isTypedArray, aZ as isObject, bz as isLength, bp as isIndex, aF as identity, bn as baseFor, bA as Set } from "./index-BWgwzFdG.js";
2
2
  var symbolTag$1 = "[object Symbol]";
3
3
  function isSymbol(value) {
4
4
  return typeof value == "symbol" || isObjectLike(value) && baseGetTag(value) == symbolTag$1;
@@ -658,4 +658,4 @@ export {
658
658
  hasIn as x,
659
659
  toString as y
660
660
  };
661
- //# sourceMappingURL=_baseUniq-Bz-BK38X.js.map
661
+ //# sourceMappingURL=_baseUniq-CoUduYbj.js.map