dominds 1.5.2 → 1.6.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 (116) hide show
  1. package/dist/apps/configuration-file.js +21 -0
  2. package/dist/apps/enabled-apps.js +3 -53
  3. package/dist/apps/local-package-root.js +41 -0
  4. package/dist/apps/runtime.js +10 -0
  5. package/dist/apps-host/client.js +124 -1
  6. package/dist/apps-host/host.js +53 -0
  7. package/dist/apps-host/ipc-types.js +61 -1
  8. package/dist/cli/install.js +41 -8
  9. package/dist/docs/app-constitution.md +22 -0
  10. package/dist/docs/app-constitution.zh.md +22 -0
  11. package/dist/llm/kernel-driver/runtime.js +112 -22
  12. package/dist/minds/load.js +20 -2
  13. package/dist/minds/system-prompt.js +4 -0
  14. package/dist/priming.js +2 -26
  15. package/dist/server/websocket-handler.js +5 -0
  16. package/dist/server.js +5 -2
  17. package/dist/shared/markdown-frontmatter.js +44 -0
  18. package/dist/shared/team_mgmt-manual.js +9 -0
  19. package/dist/skills/load.js +281 -0
  20. package/dist/static/assets/{_basePickBy-B-A5XrWM.js → _basePickBy-CFicLWwx.js} +3 -3
  21. package/dist/static/assets/{_basePickBy-B-A5XrWM.js.map → _basePickBy-CFicLWwx.js.map} +1 -1
  22. package/dist/static/assets/{_baseUniq-BANLb0cu.js → _baseUniq-DQTl8GFk.js} +2 -2
  23. package/dist/static/assets/{_baseUniq-BANLb0cu.js.map → _baseUniq-DQTl8GFk.js.map} +1 -1
  24. package/dist/static/assets/{arc-CYZYnojf.js → arc-Bc5lgJ6S.js} +2 -2
  25. package/dist/static/assets/{arc-CYZYnojf.js.map → arc-Bc5lgJ6S.js.map} +1 -1
  26. package/dist/static/assets/{architectureDiagram-VXUJARFQ-Cxf4pmYG.js → architectureDiagram-VXUJARFQ-DygUo6iw.js} +7 -7
  27. package/dist/static/assets/{architectureDiagram-VXUJARFQ-Cxf4pmYG.js.map → architectureDiagram-VXUJARFQ-DygUo6iw.js.map} +1 -1
  28. package/dist/static/assets/{blockDiagram-VD42YOAC-wvs0G30c.js → blockDiagram-VD42YOAC-0r3VY3gz.js} +7 -7
  29. package/dist/static/assets/{blockDiagram-VD42YOAC-wvs0G30c.js.map → blockDiagram-VD42YOAC-0r3VY3gz.js.map} +1 -1
  30. package/dist/static/assets/{c4Diagram-YG6GDRKO-BKFNexn4.js → c4Diagram-YG6GDRKO-pQD_vC1A.js} +3 -3
  31. package/dist/static/assets/{c4Diagram-YG6GDRKO-BKFNexn4.js.map → c4Diagram-YG6GDRKO-pQD_vC1A.js.map} +1 -1
  32. package/dist/static/assets/{channel-_1qpxJWy.js → channel-CHWYhNRt.js} +2 -2
  33. package/dist/static/assets/{channel-_1qpxJWy.js.map → channel-CHWYhNRt.js.map} +1 -1
  34. package/dist/static/assets/{chunk-4BX2VUAB-BIdC0phm.js → chunk-4BX2VUAB-K89xP4ET.js} +2 -2
  35. package/dist/static/assets/{chunk-4BX2VUAB-BIdC0phm.js.map → chunk-4BX2VUAB-K89xP4ET.js.map} +1 -1
  36. package/dist/static/assets/{chunk-55IACEB6-BNvGenQ9.js → chunk-55IACEB6-DHAy4AJ-.js} +2 -2
  37. package/dist/static/assets/{chunk-55IACEB6-BNvGenQ9.js.map → chunk-55IACEB6-DHAy4AJ-.js.map} +1 -1
  38. package/dist/static/assets/{chunk-B4BG7PRW-jmf-1Wv7.js → chunk-B4BG7PRW-BrImUg93.js} +5 -5
  39. package/dist/static/assets/{chunk-B4BG7PRW-jmf-1Wv7.js.map → chunk-B4BG7PRW-BrImUg93.js.map} +1 -1
  40. package/dist/static/assets/{chunk-DI55MBZ5-nmEmcikR.js → chunk-DI55MBZ5-_jVBMKQY.js} +4 -4
  41. package/dist/static/assets/{chunk-DI55MBZ5-nmEmcikR.js.map → chunk-DI55MBZ5-_jVBMKQY.js.map} +1 -1
  42. package/dist/static/assets/{chunk-FMBD7UC4-kGysaq_j.js → chunk-FMBD7UC4-BmGs24Z_.js} +2 -2
  43. package/dist/static/assets/{chunk-FMBD7UC4-kGysaq_j.js.map → chunk-FMBD7UC4-BmGs24Z_.js.map} +1 -1
  44. package/dist/static/assets/{chunk-QN33PNHL-8JwMLFIJ.js → chunk-QN33PNHL-Bu8ZzYdl.js} +2 -2
  45. package/dist/static/assets/{chunk-QN33PNHL-8JwMLFIJ.js.map → chunk-QN33PNHL-Bu8ZzYdl.js.map} +1 -1
  46. package/dist/static/assets/{chunk-QZHKN3VN-DZleEj00.js → chunk-QZHKN3VN-D4fM_-kX.js} +2 -2
  47. package/dist/static/assets/{chunk-QZHKN3VN-DZleEj00.js.map → chunk-QZHKN3VN-D4fM_-kX.js.map} +1 -1
  48. package/dist/static/assets/{chunk-TZMSLE5B-CXxl_uqH.js → chunk-TZMSLE5B-xK6Lo8h6.js} +2 -2
  49. package/dist/static/assets/{chunk-TZMSLE5B-CXxl_uqH.js.map → chunk-TZMSLE5B-xK6Lo8h6.js.map} +1 -1
  50. package/dist/static/assets/{classDiagram-2ON5EDUG-C-7R0QB6.js → classDiagram-2ON5EDUG-Bn36uVsZ.js} +6 -6
  51. package/dist/static/assets/{classDiagram-2ON5EDUG-C-7R0QB6.js.map → classDiagram-2ON5EDUG-Bn36uVsZ.js.map} +1 -1
  52. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-C-7R0QB6.js → classDiagram-v2-WZHVMYZB-Bn36uVsZ.js} +6 -6
  53. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-C-7R0QB6.js.map → classDiagram-v2-WZHVMYZB-Bn36uVsZ.js.map} +1 -1
  54. package/dist/static/assets/{clone-BwOKYSj8.js → clone-BUW9sxY1.js} +2 -2
  55. package/dist/static/assets/{clone-BwOKYSj8.js.map → clone-BUW9sxY1.js.map} +1 -1
  56. package/dist/static/assets/{cose-bilkent-S5V4N54A-BCBalM7p.js → cose-bilkent-S5V4N54A-BMTYUmA4.js} +2 -2
  57. package/dist/static/assets/{cose-bilkent-S5V4N54A-BCBalM7p.js.map → cose-bilkent-S5V4N54A-BMTYUmA4.js.map} +1 -1
  58. package/dist/static/assets/{dagre-6UL2VRFP-uV2ekQoj.js → dagre-6UL2VRFP-p-0HOF0Q.js} +7 -7
  59. package/dist/static/assets/{dagre-6UL2VRFP-uV2ekQoj.js.map → dagre-6UL2VRFP-p-0HOF0Q.js.map} +1 -1
  60. package/dist/static/assets/{diagram-PSM6KHXK-D-ZMog1-.js → diagram-PSM6KHXK-CfpXvSJR.js} +8 -8
  61. package/dist/static/assets/{diagram-PSM6KHXK-D-ZMog1-.js.map → diagram-PSM6KHXK-CfpXvSJR.js.map} +1 -1
  62. package/dist/static/assets/{diagram-QEK2KX5R-BThSELUH.js → diagram-QEK2KX5R-3T4XwT5a.js} +7 -7
  63. package/dist/static/assets/{diagram-QEK2KX5R-BThSELUH.js.map → diagram-QEK2KX5R-3T4XwT5a.js.map} +1 -1
  64. package/dist/static/assets/{diagram-S2PKOQOG-Di-YN5cd.js → diagram-S2PKOQOG-CPHGTwGV.js} +7 -7
  65. package/dist/static/assets/{diagram-S2PKOQOG-Di-YN5cd.js.map → diagram-S2PKOQOG-CPHGTwGV.js.map} +1 -1
  66. package/dist/static/assets/{erDiagram-Q2GNP2WA-lBZ9DITn.js → erDiagram-Q2GNP2WA-Bj7OGj2H.js} +5 -5
  67. package/dist/static/assets/{erDiagram-Q2GNP2WA-lBZ9DITn.js.map → erDiagram-Q2GNP2WA-Bj7OGj2H.js.map} +1 -1
  68. package/dist/static/assets/{flowDiagram-NV44I4VS-C_60PNQR.js → flowDiagram-NV44I4VS-DOGilHpN.js} +6 -6
  69. package/dist/static/assets/{flowDiagram-NV44I4VS-C_60PNQR.js.map → flowDiagram-NV44I4VS-DOGilHpN.js.map} +1 -1
  70. package/dist/static/assets/{ganttDiagram-JELNMOA3-Dvqq-VHJ.js → ganttDiagram-JELNMOA3-585cSoqi.js} +3 -3
  71. package/dist/static/assets/{ganttDiagram-JELNMOA3-Dvqq-VHJ.js.map → ganttDiagram-JELNMOA3-585cSoqi.js.map} +1 -1
  72. package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-BTj8orRe.js → gitGraphDiagram-V2S2FVAM-gmTvHjpH.js} +8 -8
  73. package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-BTj8orRe.js.map → gitGraphDiagram-V2S2FVAM-gmTvHjpH.js.map} +1 -1
  74. package/dist/static/assets/{graph-BqCzR2Nl.js → graph-Dtj8yklH.js} +3 -3
  75. package/dist/static/assets/{graph-BqCzR2Nl.js.map → graph-Dtj8yklH.js.map} +1 -1
  76. package/dist/static/assets/{index-DrTqAfFy.js → index-BvNwR1gS.js} +442 -246
  77. package/dist/static/assets/index-BvNwR1gS.js.map +1 -0
  78. package/dist/static/assets/{infoDiagram-HS3SLOUP-DlC6wsrv.js → infoDiagram-HS3SLOUP-BVq8aa78.js} +6 -6
  79. package/dist/static/assets/{infoDiagram-HS3SLOUP-DlC6wsrv.js.map → infoDiagram-HS3SLOUP-BVq8aa78.js.map} +1 -1
  80. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Dg_RgtQX.js → journeyDiagram-XKPGCS4Q-BY5Lcmin.js} +5 -5
  81. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Dg_RgtQX.js.map → journeyDiagram-XKPGCS4Q-BY5Lcmin.js.map} +1 -1
  82. package/dist/static/assets/{kanban-definition-3W4ZIXB7-DuGS3lId.js → kanban-definition-3W4ZIXB7-zEbpyocs.js} +3 -3
  83. package/dist/static/assets/{kanban-definition-3W4ZIXB7-DuGS3lId.js.map → kanban-definition-3W4ZIXB7-zEbpyocs.js.map} +1 -1
  84. package/dist/static/assets/{layout-FDz2bstZ.js → layout-Bst5DR3z.js} +5 -5
  85. package/dist/static/assets/{layout-FDz2bstZ.js.map → layout-Bst5DR3z.js.map} +1 -1
  86. package/dist/static/assets/{linear-CzsdvPGb.js → linear-TSyBw4eX.js} +2 -2
  87. package/dist/static/assets/{linear-CzsdvPGb.js.map → linear-TSyBw4eX.js.map} +1 -1
  88. package/dist/static/assets/{mindmap-definition-VGOIOE7T-WsAF5UNp.js → mindmap-definition-VGOIOE7T-I6ArhFTa.js} +4 -4
  89. package/dist/static/assets/{mindmap-definition-VGOIOE7T-WsAF5UNp.js.map → mindmap-definition-VGOIOE7T-I6ArhFTa.js.map} +1 -1
  90. package/dist/static/assets/{pieDiagram-ADFJNKIX-DJpRJ5ei.js → pieDiagram-ADFJNKIX-DdaOCLgH.js} +8 -8
  91. package/dist/static/assets/{pieDiagram-ADFJNKIX-DJpRJ5ei.js.map → pieDiagram-ADFJNKIX-DdaOCLgH.js.map} +1 -1
  92. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-CMyIzTkY.js → quadrantDiagram-AYHSOK5B-Bp82x7cE.js} +3 -3
  93. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-CMyIzTkY.js.map → quadrantDiagram-AYHSOK5B-Bp82x7cE.js.map} +1 -1
  94. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-D_yqVXGu.js → requirementDiagram-UZGBJVZJ-eSQPrL7r.js} +4 -4
  95. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-D_yqVXGu.js.map → requirementDiagram-UZGBJVZJ-eSQPrL7r.js.map} +1 -1
  96. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-D4-cF724.js → sankeyDiagram-TZEHDZUN-DbMClHuR.js} +2 -2
  97. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-D4-cF724.js.map → sankeyDiagram-TZEHDZUN-DbMClHuR.js.map} +1 -1
  98. package/dist/static/assets/{sequenceDiagram-WL72ISMW-B7J3gWYN.js → sequenceDiagram-WL72ISMW-CxQHJ2QR.js} +4 -4
  99. package/dist/static/assets/{sequenceDiagram-WL72ISMW-B7J3gWYN.js.map → sequenceDiagram-WL72ISMW-CxQHJ2QR.js.map} +1 -1
  100. package/dist/static/assets/{stateDiagram-FKZM4ZOC-DwEYYCcu.js → stateDiagram-FKZM4ZOC-BrJWwcfT.js} +9 -9
  101. package/dist/static/assets/{stateDiagram-FKZM4ZOC-DwEYYCcu.js.map → stateDiagram-FKZM4ZOC-BrJWwcfT.js.map} +1 -1
  102. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-D4LOOQV5.js → stateDiagram-v2-4FDKWEC3-AOoa1rfD.js} +5 -5
  103. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-D4LOOQV5.js.map → stateDiagram-v2-4FDKWEC3-AOoa1rfD.js.map} +1 -1
  104. package/dist/static/assets/{timeline-definition-IT6M3QCI-CyG-TJ_A.js → timeline-definition-IT6M3QCI-CGDQb8vq.js} +3 -3
  105. package/dist/static/assets/{timeline-definition-IT6M3QCI-CyG-TJ_A.js.map → timeline-definition-IT6M3QCI-CGDQb8vq.js.map} +1 -1
  106. package/dist/static/assets/{treemap-GDKQZRPO-yY4GiKmU.js → treemap-GDKQZRPO-DUkGxSl_.js} +5 -5
  107. package/dist/static/assets/{treemap-GDKQZRPO-yY4GiKmU.js.map → treemap-GDKQZRPO-DUkGxSl_.js.map} +1 -1
  108. package/dist/static/assets/{xychartDiagram-PRI3JC2R-5TYN_q15.js → xychartDiagram-PRI3JC2R-DhC3pydn.js} +3 -3
  109. package/dist/static/assets/{xychartDiagram-PRI3JC2R-5TYN_q15.js.map → xychartDiagram-PRI3JC2R-DhC3pydn.js.map} +1 -1
  110. package/dist/static/index.html +1 -1
  111. package/dist/team-config-updates.js +26 -0
  112. package/dist/team.js +23 -5
  113. package/dist/tools/team_mgmt.js +137 -0
  114. package/dist/tools/toolset-manual.js +12 -3
  115. package/package.json +1 -1
  116. package/dist/static/assets/index-DrTqAfFy.js.map +0 -1
@@ -206,6 +206,19 @@ Recommended user mental model:
206
206
  - If `configuration.yaml` is missing, strategy falls back to defaults (`order=['local']`, `localRoots=['dominds-apps']`) and no explicit disables apply.
207
207
  - If `resolution.yaml` is missing, the snapshot starts empty and the kernel re-materializes it from the declared dependency graph.
208
208
 
209
+ (Current: implemented) self-heal behavior for common entrypoints is:
210
+
211
+ - `dominds webui`: the server startup path initializes apps runtime and re-materializes `<rtws>/.apps/resolution.yaml`.
212
+ - `dominds tui` / `dominds run`: before entering interactive runtime, Dominds refreshes enabled-app runtime/tool proxies and re-materializes `resolution.yaml`.
213
+ - `dominds read` / `dominds manual`: Dominds refreshes enabled app tool proxies first; if the root manifest still declares dependencies, this also re-materializes `resolution.yaml`.
214
+
215
+ Self-heal only works when both prerequisites hold:
216
+
217
+ - root `.minds/app.yaml` still declares the correct app id (for example `web-dev`), and
218
+ - the current resolution strategy can actually resolve that app (for example, default `localRoots=['dominds-apps']` contains `dominds-apps/web-dev/`, and that package's install handshake / manifest also declares the same app id).
219
+
220
+ If the root manifest / team config uses the wrong app id (for example, still declaring the legacy id `web_dev` inside `dependencies[].id` or `members.<id>.from` while the app now installs as `web-dev`), refresh will still re-materialize `resolution.yaml` as empty. That means self-heal did run; it just correctly recomputed an empty result from incorrect source declarations.
221
+
209
222
  So even without `<rtws>/.apps/configuration.yaml` or `<rtws>/.apps/resolution.yaml`, as long as `.minds/app.yaml` declares dependencies, the kernel still resolves local apps via the default strategy; if the root manifest has no dependencies, the effective enabled apps set is empty.
210
223
 
211
224
  ## App-provided `.minds/**` assets
@@ -306,6 +319,14 @@ dominds install ./dominds-apps/web-dev --local --enable
306
319
  dominds install @longrun-ai/web-dev --enable
307
320
  ```
308
321
 
322
+ Web Dev App needs three names kept distinct to avoid drift:
323
+
324
+ - installable app id: `web-dev`
325
+ - local development directory: `dominds-apps/web-dev/`
326
+ - npm package name: `@longrun-ai/web-dev`
327
+
328
+ That means workspace `.minds/app.yaml` `dependencies[].id`, `.minds/team.yaml` `members.<id>.from`, and `<rtws>/.apps/resolution.yaml` `apps[].id` must all use `web-dev`; the directory and package naming surfaces also stay `web-dev` so the app no longer carries two spellings.
329
+
309
330
  After installation, the user should expect these files to change:
310
331
 
311
332
  - `.minds/app.yaml`: root dependency declaration is updated.
@@ -380,6 +401,7 @@ Requirements for the `playwright_interactive` toolset design:
380
401
  Current prototype note (`dominds-apps/web-dev`, as of March 8, 2026):
381
402
 
382
403
  - The app is already installable and contributes `web_tester` / `web_developer` teammates plus a live `playwright_interactive` toolset registration.
404
+ - The installable app id remains `web-dev`; the directory name and npm package also keep the same `web-dev` spelling so the app no longer carries split naming.
383
405
  - `playwright_session_new/list/status/eval/attach/detach/close` and cross-dialog reminder sync are already implemented.
384
406
  - `kind: "web"` sessions now create a real Playwright-backed browser/context/page runtime and report live page surfaces via session status/reminders.
385
407
  - `kind: "electron"` is **not** at the same completion level yet: it still falls back to the older prototype runtime path and should be treated as unfinished.
@@ -205,6 +205,19 @@ rtws 是一次运行的工作区根目录(`process.cwd()`)。Kernel 在其
205
205
  - 若 `configuration.yaml` 缺失:strategy 使用默认值(`order=['local']`,`localRoots=['dominds-apps']`),且没有显式 disable。
206
206
  - 若 `resolution.yaml` 缺失:视为空快照,Kernel 会根据当前声明依赖重新解析并写回结果。
207
207
 
208
+ (现状:已实现)常规入口的自愈口径如下:
209
+
210
+ - `dominds webui`:server 启动链会初始化 apps runtime,并重新物化 `<rtws>/.apps/resolution.yaml`。
211
+ - `dominds tui` / `dominds run`:进入交互 runtime 前会刷新 enabled apps runtime / tool proxies,并重新物化 `resolution.yaml`。
212
+ - `dominds read` / `dominds manual`:会先刷新 enabled app tool proxies;若根 manifest 仍声明依赖,也会触发 `resolution.yaml` 的重新物化。
213
+
214
+ 自愈成立的前提必须同时满足:
215
+
216
+ - 根 `.minds/app.yaml` 仍声明了正确的 app id(例如 `web-dev`)。
217
+ - 当前 resolution strategy 能解析到对应 app(例如默认 `localRoots=['dominds-apps']` 下存在 `dominds-apps/web-dev/`,且该包的 install handshake / manifest 也声明同一个 app id)。
218
+
219
+ 若根 manifest / team.yaml 使用了错误的 app id(例如 app 已改为 `web-dev`,但 `dependencies[].id` 或 `members.<id>.from` 里仍保留 legacy `web_dev`),那么 refresh 仍会把 `resolution.yaml` 重新物化为空;这不是“自愈没跑”,而是“它按错误声明正确地重算出了空结果”。
220
+
208
221
  因此,即使缺少 `<rtws>/.apps/configuration.yaml` 或 `<rtws>/.apps/resolution.yaml`,只要 `.minds/app.yaml` 声明了依赖,Kernel 仍会按默认策略去解析本地 app;反之若根 manifest 没有依赖,则最终 enabled apps 为空。
209
222
 
210
223
  ## App 可提供的 `.minds/**` 资产
@@ -304,6 +317,14 @@ dominds install ./dominds-apps/web-dev --local --enable
304
317
  dominds install @longrun-ai/web-dev --enable
305
318
  ```
306
319
 
320
+ Web Dev App 需要明确区分三套命名,避免再次漂移:
321
+
322
+ - installable app id:`web-dev`
323
+ - 本地开发目录:`dominds-apps/web-dev/`
324
+ - npm package name:`@longrun-ai/web-dev`
325
+
326
+ 也就是说,workspace `.minds/app.yaml` 的 `dependencies[].id`、`.minds/team.yaml` 的 `members.<id>.from`,以及 `<rtws>/.apps/resolution.yaml` 的 `apps[].id` 都应使用 `web-dev`;目录名与 package name 也统一保持 `web-dev`,避免同一 app 在不同层面出现双拼写。
327
+
307
328
  安装完成后,用户应预期以下文件发生变化:
308
329
 
309
330
  - `.minds/app.yaml`:增加根依赖声明。
@@ -378,6 +399,7 @@ members:
378
399
  当前 prototype 说明(`dominds-apps/web-dev`,截至 2026-03-08):
379
400
 
380
401
  - 该 app 已可安装,并已贡献 `web_tester` / `web_developer` teammate 与可用的 `playwright_interactive` toolset 注册。
402
+ - installable app id 当前固定为 `web-dev`;目录名与 npm package 名也保持 `web-dev`,避免多套命名并存。
381
403
  - `playwright_session_new/list/status/eval/attach/detach/close` 与跨对话 reminder sync 已落地。
382
404
  - `kind: "web"` 会话现在会创建真实的 Playwright browser/context/page runtime,并通过 status/reminder 报告实时页面 surface。
383
405
  - `kind: "electron"` 还没有达到同等完成度:当前仍回落到旧的 prototype runtime 路径,应视为未完成能力。
@@ -265,6 +265,32 @@ function isRetriableLlmErrorCode(code) {
265
265
  return false;
266
266
  return RETRIABLE_LLM_ERROR_CODES.has(code);
267
267
  }
268
+ function isOpenAiRetriableProcessingFailureMessage(lowerMessage) {
269
+ if (!lowerMessage.includes('processing your request')) {
270
+ return false;
271
+ }
272
+ if (lowerMessage.includes('you can retry your request') ||
273
+ lowerMessage.includes('please retry your request')) {
274
+ return true;
275
+ }
276
+ return lowerMessage.includes('help.openai.com') && lowerMessage.includes('request id');
277
+ }
278
+ function isRetriableLlmMessage(message) {
279
+ const lower = message.toLowerCase();
280
+ if (lower.includes('fetch failed') || lower.includes('socket hang up')) {
281
+ return true;
282
+ }
283
+ if (lower.includes('terminated')) {
284
+ return true;
285
+ }
286
+ if (lower.includes('timeout') || lower.includes('timed out') || lower.includes('rate limit')) {
287
+ return true;
288
+ }
289
+ if (isOpenAiRetriableProcessingFailureMessage(lower)) {
290
+ return true;
291
+ }
292
+ return false;
293
+ }
268
294
  function classifyLlmFailure(err) {
269
295
  const fallbackMessage = err instanceof Error
270
296
  ? err.message || err.name
@@ -292,16 +318,7 @@ function classifyLlmFailure(err) {
292
318
  ? err
293
319
  : undefined;
294
320
  if (typeof msg === 'string' && msg.length > 0) {
295
- const lower = msg.toLowerCase();
296
- if (lower.includes('fetch failed') || lower.includes('socket hang up')) {
297
- return { kind: 'retriable', code: errCode ?? causeCode, message: msg };
298
- }
299
- if (lower.includes('terminated')) {
300
- return { kind: 'retriable', code: errCode ?? causeCode, message: msg };
301
- }
302
- if (lower.includes('timeout') ||
303
- lower.includes('timed out') ||
304
- lower.includes('rate limit')) {
321
+ if (isRetriableLlmMessage(msg)) {
305
322
  return { kind: 'retriable', code: errCode ?? causeCode, message: msg };
306
323
  }
307
324
  }
@@ -327,14 +344,7 @@ function classifyLlmFailure(err) {
327
344
  if (isRetriableLlmErrorCode(code)) {
328
345
  return { kind: 'retriable', code, message: msg };
329
346
  }
330
- const lower = msg.toLowerCase();
331
- if (lower.includes('fetch failed') || lower.includes('socket hang up')) {
332
- return { kind: 'retriable', code: code ?? causeCode, message: msg };
333
- }
334
- if (lower.includes('terminated')) {
335
- return { kind: 'retriable', code: code ?? causeCode, message: msg };
336
- }
337
- if (lower.includes('timeout') || lower.includes('timed out') || lower.includes('rate limit')) {
347
+ if (isRetriableLlmMessage(msg)) {
338
348
  return { kind: 'retriable', code: code ?? causeCode, message: msg };
339
349
  }
340
350
  }
@@ -399,8 +409,23 @@ async function runLlmRequestWithRetry(params) {
399
409
  const retryInitialDelayMs = normalizeRetryInitialDelayMs(params.retryInitialDelayMs);
400
410
  const retryBackoffMultiplier = normalizeRetryBackoffMultiplier(params.retryBackoffMultiplier);
401
411
  const retryMaxDelayMs = normalizeRetryMaxDelayMs(params.retryMaxDelayMs, retryInitialDelayMs);
412
+ const retryFlowStartedAtMs = Date.now();
413
+ let activeRetryContext;
402
414
  for (let attempt = 0; attempt <= params.maxRetries; attempt++) {
403
415
  try {
416
+ if (attempt > 0 && activeRetryContext) {
417
+ emitLlmRetryEventBestEffort({
418
+ dlg: params.dlg,
419
+ phase: 'running',
420
+ provider: params.provider,
421
+ attempt: attempt + 1,
422
+ totalAttempts,
423
+ maxRetries: params.maxRetries,
424
+ retriesRemaining: Math.max(0, params.maxRetries - attempt),
425
+ failure: activeRetryContext.failure,
426
+ errorText: activeRetryContext.errorText,
427
+ });
428
+ }
404
429
  const res = await params.doRequest();
405
430
  (0, problems_1.removeProblem)(providerProblemId);
406
431
  return res;
@@ -496,14 +521,26 @@ async function runLlmRequestWithRetry(params) {
496
521
  catch {
497
522
  // best-effort
498
523
  }
499
- throw new Error(canRetry
500
- ? `LLM failed after retries: ${failure.message}`
501
- : `LLM failed: ${failure.message}`);
524
+ if (canRetry) {
525
+ const interruptionDetail = formatLlmRetryExhaustedInterruptionDetail({
526
+ language: params.dlg.getLastUserLanguageCode(),
527
+ provider: params.provider,
528
+ totalAttempts,
529
+ maxRetries: params.maxRetries,
530
+ elapsedMs: Date.now() - retryFlowStartedAtMs,
531
+ retryInitialDelayMs,
532
+ retryBackoffMultiplier,
533
+ retryMaxDelayMs,
534
+ errorText: detail,
535
+ });
536
+ throw new Error(interruptionDetail);
537
+ }
538
+ throw new Error(`LLM failed: ${failure.message}`);
502
539
  }
503
540
  const backoffMs = Math.min(retryMaxDelayMs, Math.max(0, Math.floor(retryInitialDelayMs * retryBackoffMultiplier ** attempt)));
504
541
  emitLlmRetryEventBestEffort({
505
542
  dlg: params.dlg,
506
- phase: 'retrying',
543
+ phase: 'waiting',
507
544
  provider: params.provider,
508
545
  attempt: attemptNo,
509
546
  totalAttempts,
@@ -513,6 +550,10 @@ async function runLlmRequestWithRetry(params) {
513
550
  failure,
514
551
  errorText: detail,
515
552
  });
553
+ activeRetryContext = {
554
+ failure,
555
+ errorText: detail,
556
+ };
516
557
  log_1.log.warn(`Retrying LLM request after retriable error`, undefined, {
517
558
  provider: params.provider,
518
559
  attempt: attemptNo,
@@ -531,3 +572,52 @@ async function runLlmRequestWithRetry(params) {
531
572
  }
532
573
  throw new Error('LLM failed.');
533
574
  }
575
+ function formatRetryElapsedDuration(language, elapsedMsRaw) {
576
+ const elapsedMs = Math.max(0, Math.floor(elapsedMsRaw));
577
+ if (elapsedMs < 1000) {
578
+ return `${elapsedMs}ms`;
579
+ }
580
+ const totalSeconds = elapsedMs / 1000;
581
+ if (totalSeconds < 60) {
582
+ const text = totalSeconds >= 10 ? totalSeconds.toFixed(1) : totalSeconds.toFixed(2);
583
+ return language === 'zh' ? `${text} 秒` : `${text}s`;
584
+ }
585
+ const wholeSeconds = Math.round(totalSeconds);
586
+ const minutes = Math.floor(wholeSeconds / 60);
587
+ const seconds = wholeSeconds % 60;
588
+ if (language === 'zh') {
589
+ return seconds === 0 ? `${minutes} 分钟` : `${minutes} 分 ${seconds} 秒`;
590
+ }
591
+ return seconds === 0 ? `${minutes}m` : `${minutes}m ${seconds}s`;
592
+ }
593
+ function formatLlmRetryExhaustedInterruptionDetail(args) {
594
+ const providerPath = `providers.${args.provider}`;
595
+ const durationText = formatRetryElapsedDuration(args.language, args.elapsedMs);
596
+ const trimmedError = args.errorText.trim();
597
+ if (args.language === 'zh') {
598
+ return (`LLM 自动重试已耗尽:provider=${args.provider},共尝试 ${args.totalAttempts} 次` +
599
+ `(初始请求 1 次 + 重试 ${args.maxRetries} 次),总耗时 ${durationText}。` +
600
+ `当前重试配置:llm_retry_max_retries=${args.maxRetries},` +
601
+ `llm_retry_initial_delay_ms=${args.retryInitialDelayMs},` +
602
+ `llm_retry_backoff_multiplier=${args.retryBackoffMultiplier},` +
603
+ `llm_retry_max_delay_ms=${args.retryMaxDelayMs}。` +
604
+ `若想增加重试次数或拉长重试间隔,请编辑 \`.minds/llm.yaml\` 中的 ` +
605
+ `\`${providerPath}.llm_retry_max_retries\`、` +
606
+ `\`${providerPath}.llm_retry_initial_delay_ms\`、` +
607
+ `\`${providerPath}.llm_retry_backoff_multiplier\`、` +
608
+ `\`${providerPath}.llm_retry_max_delay_ms\`,并检查 provider / network 稳定性。` +
609
+ `最后错误:${trimmedError}`);
610
+ }
611
+ return (`LLM automatic retries exhausted: provider=${args.provider}, ${args.totalAttempts} attempts total ` +
612
+ `(1 initial request + ${args.maxRetries} retries), elapsed ${durationText}. ` +
613
+ `Current retry config: llm_retry_max_retries=${args.maxRetries}, ` +
614
+ `llm_retry_initial_delay_ms=${args.retryInitialDelayMs}, ` +
615
+ `llm_retry_backoff_multiplier=${args.retryBackoffMultiplier}, ` +
616
+ `llm_retry_max_delay_ms=${args.retryMaxDelayMs}. ` +
617
+ `If you want more retries or longer retry intervals, edit ` +
618
+ `\`.minds/llm.yaml\`: \`${providerPath}.llm_retry_max_retries\`, ` +
619
+ `\`${providerPath}.llm_retry_initial_delay_ms\`, ` +
620
+ `\`${providerPath}.llm_retry_backoff_multiplier\`, ` +
621
+ `\`${providerPath}.llm_retry_max_delay_ms\`, and verify provider/network stability. ` +
622
+ `Last error: ${trimmedError}`);
623
+ }
@@ -11,6 +11,7 @@ const dialog_1 = require("../dialog");
11
11
  const log_1 = require("../log");
12
12
  const runtime_language_1 = require("../shared/runtime-language");
13
13
  const time_1 = require("../shared/utils/time");
14
+ const load_1 = require("../skills/load");
14
15
  const team_1 = require("../team");
15
16
  const ctrl_1 = require("../tools/ctrl");
16
17
  const shell_tools_1 = require("../tools/shell-tools");
@@ -142,6 +143,15 @@ async function loadAgentMinds(agentId, dialog, options) {
142
143
  const knowledge = knowledgeRaw && knowledgeRaw.trim() !== '' ? knowledgeRaw : none;
143
144
  const lessons = lessonsRaw && lessonsRaw.trim() !== '' ? lessonsRaw : none;
144
145
  const envIntro = envIntroRaw && envIntroRaw.trim() !== '' ? envIntroRaw : '';
146
+ const workspaceSkills = await (0, load_1.loadWorkspaceSkills)({
147
+ rtwsRootAbs: process.cwd(),
148
+ memberId: agent.id,
149
+ language: workingLanguage,
150
+ });
151
+ const skillsText = (0, load_1.renderWorkspaceSkillsPrompt)({
152
+ language: workingLanguage,
153
+ skills: workspaceSkills,
154
+ });
145
155
  // Introduction of all team members (mark "(self)" for the current agent)
146
156
  const teamIntro = (0, system_prompt_1.formatTeamIntro)(team, agent.id, workingLanguage);
147
157
  // Compose tool list from member's resolved toolsets and tools + built-in human tool
@@ -149,8 +159,15 @@ async function loadAgentMinds(agentId, dialog, options) {
149
159
  // shell_specialists is intended for visible teammates only. Hidden members are exempt from this
150
160
  // policy and may carry shell tools.
151
161
  const agentIsShellSpecialist = team.shellSpecialists.includes(agent.id) || agent.hidden === true;
162
+ const dynamicToolsetNames = await team_1.Team.listDynamicToolsetNamesForMember({
163
+ member: agent,
164
+ taskDocPath: dialog?.taskDocPath,
165
+ });
152
166
  const baseAgentTools = (() => {
153
- const tools = agent.listTools({ onMissingToolset: missingToolsetPolicy });
167
+ const tools = agent.listTools({
168
+ onMissingToolset: missingToolsetPolicy,
169
+ dynamicToolsetNames,
170
+ });
154
171
  if (agentIsShellSpecialist)
155
172
  return tools;
156
173
  return tools.filter((t) => !(t.type === 'func' && typeof t.name === 'string' && (0, shell_tools_1.isShellToolName)(t.name)));
@@ -179,7 +196,7 @@ async function loadAgentMinds(agentId, dialog, options) {
179
196
  return out;
180
197
  })();
181
198
  const toolsetNames = agent
182
- .listResolvedToolsetNames({ onMissing: missingToolsetPolicy })
199
+ .listResolvedToolsetNames({ onMissing: missingToolsetPolicy, dynamicToolsetNames })
183
200
  .filter((name) => {
184
201
  if (name === 'os')
185
202
  return agentIsShellSpecialist;
@@ -247,6 +264,7 @@ async function loadAgentMinds(agentId, dialog, options) {
247
264
  persona,
248
265
  knowledge,
249
266
  lessons,
267
+ skillsText,
250
268
  envIntro,
251
269
  teamIntro,
252
270
  funcToolRulesText,
@@ -290,6 +290,8 @@ ${input.knowledge}
290
290
 
291
291
  ${input.lessons}
292
292
 
293
+ ${input.skillsText}
294
+
293
295
  ## 运行环境
294
296
 
295
297
  ${input.envIntro}
@@ -381,6 +383,8 @@ ${input.knowledge}
381
383
 
382
384
  ${input.lessons}
383
385
 
386
+ ${input.skillsText}
387
+
384
388
  ## Runtime Environment
385
389
 
386
390
  ${input.envIntro}
package/dist/priming.js CHANGED
@@ -19,6 +19,7 @@ const promises_1 = __importDefault(require("fs/promises"));
19
19
  const path_1 = __importDefault(require("path"));
20
20
  const yaml_1 = __importDefault(require("yaml"));
21
21
  const persistence_1 = require("./persistence");
22
+ const markdown_frontmatter_1 = require("./shared/markdown-frontmatter");
22
23
  const storage_1 = require("./shared/types/storage");
23
24
  const time_1 = require("./shared/utils/time");
24
25
  const registry_1 = require("./tools/registry");
@@ -108,33 +109,8 @@ function scriptRefToAbsolutePath(scriptRef) {
108
109
  }
109
110
  return absPath;
110
111
  }
111
- function stripOptionalBom(text) {
112
- if (text.charCodeAt(0) === 0xfeff) {
113
- return text.slice(1);
114
- }
115
- return text;
116
- }
117
112
  function parseFrontmatter(raw) {
118
- const normalized = stripOptionalBom(raw).replace(/\r\n/g, '\n');
119
- if (!normalized.startsWith('---\n')) {
120
- return { body: normalized, frontmatter: {} };
121
- }
122
- const endWithBody = normalized.indexOf('\n---\n', 4);
123
- const endAtEof = normalized.endsWith('\n---') ? normalized.length - '\n---'.length : -1;
124
- const end = endWithBody >= 0 ? endWithBody : endAtEof;
125
- if (end < 0)
126
- return { body: normalized, frontmatter: {} };
127
- const frontmatterText = normalized.slice(4, end);
128
- const body = endWithBody >= 0
129
- ? normalized.slice(end + '\n---\n'.length)
130
- : normalized.slice(end + '\n---'.length);
131
- try {
132
- const parsed = yaml_1.default.parse(frontmatterText);
133
- return { body, frontmatter: isRecord(parsed) ? parsed : {} };
134
- }
135
- catch (error) {
136
- throw new Error(`Invalid priming frontmatter: ${error instanceof Error ? error.message : String(error)}`);
137
- }
113
+ return (0, markdown_frontmatter_1.parseMarkdownFrontmatter)(raw, 'priming');
138
114
  }
139
115
  function parseApplicableMemberIds(frontmatter) {
140
116
  const raw = frontmatter['applicableMemberIds'] ?? frontmatter['applicable_members'];
@@ -1344,6 +1344,11 @@ function setupWebSocketServer(httpServer, clients, auth, serverWorkLanguage) {
1344
1344
  }
1345
1345
  });
1346
1346
  (0, team_config_updates_1.startTeamConfigWatcher)();
1347
+ httpServer.once('close', () => {
1348
+ (0, team_config_updates_1.stopTeamConfigWatcher)();
1349
+ (0, team_config_updates_1.clearTeamConfigBroadcaster)();
1350
+ void wss.close();
1351
+ });
1347
1352
  wss.on('connection', (ws, req) => {
1348
1353
  const authCheck = (0, auth_1.getWebSocketAuthCheck)(req, auth);
1349
1354
  if (authCheck.kind !== 'ok') {
package/dist/server.js CHANGED
@@ -105,6 +105,7 @@ async function startServer(opts = {}) {
105
105
  const mode = opts.mode || 'prod';
106
106
  const port = opts.port ?? 5666;
107
107
  const host = opts.host || '127.0.0.1';
108
+ const startBackendDriver = opts.startBackendDriver ?? true;
108
109
  log.info(`Starting server in ${mode} mode on ${host}:${port} (working language: ${(0, runtime_language_1.getWorkLanguage)()} from ${source})`);
109
110
  // WebSocket clients set
110
111
  const clients = new Set();
@@ -131,8 +132,10 @@ async function startServer(opts = {}) {
131
132
  await (0, runtime_1.initAppsRuntime)({ rtwsRootAbs: process.cwd(), kernel: { host, port } });
132
133
  // Crash recovery: any dialogs left in "proceeding" state are surfaced as interrupted/resumable.
133
134
  await (0, dialog_run_state_1.reconcileRunStatesAfterRestart)();
134
- // Start backend driver loop (non-blocking)
135
- void (0, kernel_driver_1.runBackendDriver)();
135
+ // Tests may opt out so the process can shut down cleanly without a driver stop API.
136
+ if (startBackendDriver) {
137
+ void (0, kernel_driver_1.runBackendDriver)();
138
+ }
136
139
  // Start listening
137
140
  await httpServer.start();
138
141
  return { httpServer, auth, host, port, mode };
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.stripOptionalBom = stripOptionalBom;
7
+ exports.normalizeMarkdownText = normalizeMarkdownText;
8
+ exports.parseMarkdownFrontmatter = parseMarkdownFrontmatter;
9
+ const yaml_1 = __importDefault(require("yaml"));
10
+ function isRecord(value) {
11
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
12
+ }
13
+ function stripOptionalBom(text) {
14
+ if (text.charCodeAt(0) === 0xfeff) {
15
+ return text.slice(1);
16
+ }
17
+ return text;
18
+ }
19
+ function normalizeMarkdownText(text) {
20
+ return stripOptionalBom(text).replace(/\r\n/g, '\n');
21
+ }
22
+ function parseMarkdownFrontmatter(raw, sourceLabel = 'markdown') {
23
+ const normalized = normalizeMarkdownText(raw);
24
+ if (!normalized.startsWith('---\n')) {
25
+ return { body: normalized, frontmatter: {} };
26
+ }
27
+ const endWithBody = normalized.indexOf('\n---\n', 4);
28
+ const endAtEof = normalized.endsWith('\n---') ? normalized.length - '\n---'.length : -1;
29
+ const end = endWithBody >= 0 ? endWithBody : endAtEof;
30
+ if (end < 0) {
31
+ return { body: normalized, frontmatter: {} };
32
+ }
33
+ const frontmatterText = normalized.slice(4, end);
34
+ const body = endWithBody >= 0
35
+ ? normalized.slice(end + '\n---\n'.length)
36
+ : normalized.slice(end + '\n---'.length);
37
+ try {
38
+ const parsed = yaml_1.default.parse(frontmatterText);
39
+ return { body, frontmatter: isRecord(parsed) ? parsed : {} };
40
+ }
41
+ catch (error) {
42
+ throw new Error(`Invalid ${sourceLabel} frontmatter: ${error instanceof Error ? error.message : String(error)}`);
43
+ }
44
+ }
@@ -25,6 +25,7 @@ exports.TEAM_MGMT_MANUAL_TOPIC_KEYS = [
25
25
  'team',
26
26
  'member-properties',
27
27
  'minds',
28
+ 'skills',
28
29
  'priming',
29
30
  'env',
30
31
  'permissions',
@@ -48,6 +49,9 @@ exports.TEAM_MGMT_MANUAL_TOPIC_META = {
48
49
  minds: {
49
50
  titleI18n: { zh: '角色资产(.minds/team/<id>/*)', en: 'Minds Assets (.minds/team/<id>/*)' },
50
51
  },
52
+ skills: {
53
+ titleI18n: { zh: '技能(.minds/skills/*)', en: 'Skills (.minds/skills/*)' },
54
+ },
51
55
  priming: {
52
56
  titleI18n: {
53
57
  zh: '启动脚本(.minds/priming/*)',
@@ -77,6 +81,7 @@ exports.TEAM_MGMT_MANUAL_UI_TOPIC_ORDER = [
77
81
  'builtin-defaults',
78
82
  'mcp',
79
83
  'minds',
84
+ 'skills',
80
85
  'priming',
81
86
  'env',
82
87
  'troubleshooting',
@@ -97,6 +102,7 @@ exports.TEAM_MGMT_MANUAL_UI_TOOL_TOPICS_BY_KEY = {
97
102
  // Other
98
103
  mcp: ['mcp'],
99
104
  minds: ['minds'],
105
+ skills: ['skills'],
100
106
  priming: ['priming'],
101
107
  env: ['env'],
102
108
  troubleshooting: ['troubleshooting'],
@@ -106,6 +112,7 @@ exports.TEAM_MGMT_MANUAL_PANEL_TOPIC_ORDER = [
106
112
  'permissions',
107
113
  'team',
108
114
  'toolsets',
115
+ 'skills',
109
116
  ];
110
117
  const EMPTY_TOOL_TOPICS = [];
111
118
  exports.TEAM_MGMT_MANUAL_PANEL_TOOL_TOPICS_BY_KEY = {
@@ -113,6 +120,7 @@ exports.TEAM_MGMT_MANUAL_PANEL_TOOL_TOPICS_BY_KEY = {
113
120
  permissions: ['permissions'],
114
121
  team: ['team'],
115
122
  toolsets: ['toolsets'],
123
+ skills: ['skills'],
116
124
  };
117
125
  function isTeamMgmtManualPanelTopicKey(value) {
118
126
  return Object.prototype.hasOwnProperty.call(exports.TEAM_MGMT_MANUAL_PANEL_TOOL_TOPICS_BY_KEY, value);
@@ -122,6 +130,7 @@ exports.TEAM_MGMT_MANUAL_PANEL_TOPIC_META = {
122
130
  permissions: exports.TEAM_MGMT_MANUAL_TOPIC_META.permissions,
123
131
  team: exports.TEAM_MGMT_MANUAL_TOPIC_META.team,
124
132
  toolsets: exports.TEAM_MGMT_MANUAL_TOPIC_META.toolsets,
133
+ skills: exports.TEAM_MGMT_MANUAL_TOPIC_META.skills,
125
134
  };
126
135
  function getTeamMgmtManualPanelTopicTitle(lang, key) {
127
136
  const meta = exports.TEAM_MGMT_MANUAL_PANEL_TOPIC_META[key];