dominds 1.3.1 → 1.4.2

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 (184) hide show
  1. package/README.md +9 -2
  2. package/README.zh.md +9 -2
  3. package/dist/apps/app-lock-file.js +33 -57
  4. package/dist/apps/configuration-file.js +267 -0
  5. package/dist/apps/enabled-apps.js +217 -252
  6. package/dist/apps/manifest.js +132 -0
  7. package/dist/apps/resolution-file.js +80 -192
  8. package/dist/apps/workspace-app-state.js +8 -0
  9. package/dist/cli/disable.js +18 -22
  10. package/dist/cli/enable.js +20 -58
  11. package/dist/cli/install.js +74 -80
  12. package/dist/cli/uninstall.js +48 -25
  13. package/dist/cli/update.js +36 -80
  14. package/dist/docs/app-constitution.md +12 -7
  15. package/dist/docs/app-constitution.zh.md +13 -8
  16. package/dist/llm/kernel-driver/engine.js +10 -4
  17. package/dist/llm/kernel-driver/flow.js +93 -0
  18. package/dist/llm/kernel-driver/loop.js +4 -1
  19. package/dist/llm/kernel-driver/subdialog.js +5 -1
  20. package/dist/llm/kernel-driver/tellask-special.js +48 -6
  21. package/dist/server/server-core.js +19 -4
  22. package/dist/server/websocket-handler.js +26 -6
  23. package/dist/static/assets/{_basePickBy-CmziIRM9.js → _basePickBy-B2o4z1Hf.js} +3 -3
  24. package/dist/static/assets/{_basePickBy-CmziIRM9.js.map → _basePickBy-B2o4z1Hf.js.map} +1 -1
  25. package/dist/static/assets/{_baseUniq-CgDZxcD0.js → _baseUniq-CLmcxjdl.js} +2 -2
  26. package/dist/static/assets/{_baseUniq-CgDZxcD0.js.map → _baseUniq-CLmcxjdl.js.map} +1 -1
  27. package/dist/static/assets/{arc-Df9rjNNk.js → arc-CymD_KN7.js} +2 -2
  28. package/dist/static/assets/{arc-Df9rjNNk.js.map → arc-CymD_KN7.js.map} +1 -1
  29. package/dist/static/assets/{architectureDiagram-VXUJARFQ-Bif8topC.js → architectureDiagram-VXUJARFQ-DJQfSJUH.js} +7 -7
  30. package/dist/static/assets/{architectureDiagram-VXUJARFQ-Bif8topC.js.map → architectureDiagram-VXUJARFQ-DJQfSJUH.js.map} +1 -1
  31. package/dist/static/assets/{blockDiagram-VD42YOAC-D9Egoflr.js → blockDiagram-VD42YOAC-pHVz60D0.js} +7 -7
  32. package/dist/static/assets/{blockDiagram-VD42YOAC-D9Egoflr.js.map → blockDiagram-VD42YOAC-pHVz60D0.js.map} +1 -1
  33. package/dist/static/assets/{c4Diagram-YG6GDRKO-DBf1NeBf.js → c4Diagram-YG6GDRKO-B0WnCfAT.js} +3 -3
  34. package/dist/static/assets/{c4Diagram-YG6GDRKO-DBf1NeBf.js.map → c4Diagram-YG6GDRKO-B0WnCfAT.js.map} +1 -1
  35. package/dist/static/assets/{channel-Dc34yAJl.js → channel-CX9BlKil.js} +2 -2
  36. package/dist/static/assets/{channel-Dc34yAJl.js.map → channel-CX9BlKil.js.map} +1 -1
  37. package/dist/static/assets/{chunk-4BX2VUAB-B65G1dJI.js → chunk-4BX2VUAB-lXArRj3o.js} +2 -2
  38. package/dist/static/assets/{chunk-4BX2VUAB-B65G1dJI.js.map → chunk-4BX2VUAB-lXArRj3o.js.map} +1 -1
  39. package/dist/static/assets/{chunk-55IACEB6-CSDEOGl2.js → chunk-55IACEB6-CdqwynH9.js} +2 -2
  40. package/dist/static/assets/{chunk-55IACEB6-CSDEOGl2.js.map → chunk-55IACEB6-CdqwynH9.js.map} +1 -1
  41. package/dist/static/assets/{chunk-B4BG7PRW-Cb6W3QWJ.js → chunk-B4BG7PRW-Y-uXcJst.js} +5 -5
  42. package/dist/static/assets/{chunk-B4BG7PRW-Cb6W3QWJ.js.map → chunk-B4BG7PRW-Y-uXcJst.js.map} +1 -1
  43. package/dist/static/assets/{chunk-DI55MBZ5-ZAJWeVWH.js → chunk-DI55MBZ5-C5xSbRST.js} +4 -4
  44. package/dist/static/assets/{chunk-DI55MBZ5-ZAJWeVWH.js.map → chunk-DI55MBZ5-C5xSbRST.js.map} +1 -1
  45. package/dist/static/assets/{chunk-FMBD7UC4-DiwRlImb.js → chunk-FMBD7UC4-5uefwCjI.js} +2 -2
  46. package/dist/static/assets/{chunk-FMBD7UC4-DiwRlImb.js.map → chunk-FMBD7UC4-5uefwCjI.js.map} +1 -1
  47. package/dist/static/assets/{chunk-QN33PNHL-wilj7fb5.js → chunk-QN33PNHL-DzWVcvpI.js} +2 -2
  48. package/dist/static/assets/{chunk-QN33PNHL-wilj7fb5.js.map → chunk-QN33PNHL-DzWVcvpI.js.map} +1 -1
  49. package/dist/static/assets/{chunk-QZHKN3VN-DGmviJfR.js → chunk-QZHKN3VN-BrrvAZdP.js} +2 -2
  50. package/dist/static/assets/{chunk-QZHKN3VN-DGmviJfR.js.map → chunk-QZHKN3VN-BrrvAZdP.js.map} +1 -1
  51. package/dist/static/assets/{chunk-TZMSLE5B-Nm5wTXa_.js → chunk-TZMSLE5B-DyKOlPTY.js} +2 -2
  52. package/dist/static/assets/{chunk-TZMSLE5B-Nm5wTXa_.js.map → chunk-TZMSLE5B-DyKOlPTY.js.map} +1 -1
  53. package/dist/static/assets/{classDiagram-2ON5EDUG-BvUbXD6H.js → classDiagram-2ON5EDUG-FCrnlCWC.js} +6 -6
  54. package/dist/static/assets/{classDiagram-2ON5EDUG-BvUbXD6H.js.map → classDiagram-2ON5EDUG-FCrnlCWC.js.map} +1 -1
  55. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-BvUbXD6H.js → classDiagram-v2-WZHVMYZB-FCrnlCWC.js} +6 -6
  56. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-BvUbXD6H.js.map → classDiagram-v2-WZHVMYZB-FCrnlCWC.js.map} +1 -1
  57. package/dist/static/assets/{clone-0VLS7GaA.js → clone-BlI81KqZ.js} +2 -2
  58. package/dist/static/assets/{clone-0VLS7GaA.js.map → clone-BlI81KqZ.js.map} +1 -1
  59. package/dist/static/assets/{cose-bilkent-S5V4N54A-anaPs-75.js → cose-bilkent-S5V4N54A-yM7S2atz.js} +2 -2
  60. package/dist/static/assets/{cose-bilkent-S5V4N54A-anaPs-75.js.map → cose-bilkent-S5V4N54A-yM7S2atz.js.map} +1 -1
  61. package/dist/static/assets/{dagre-6UL2VRFP-YwdsZ11r.js → dagre-6UL2VRFP-BcweuZHt.js} +7 -7
  62. package/dist/static/assets/{dagre-6UL2VRFP-YwdsZ11r.js.map → dagre-6UL2VRFP-BcweuZHt.js.map} +1 -1
  63. package/dist/static/assets/{diagram-PSM6KHXK-5KQCf3h2.js → diagram-PSM6KHXK-D4-QwLW1.js} +8 -8
  64. package/dist/static/assets/{diagram-PSM6KHXK-5KQCf3h2.js.map → diagram-PSM6KHXK-D4-QwLW1.js.map} +1 -1
  65. package/dist/static/assets/{diagram-QEK2KX5R-Mf24XxZL.js → diagram-QEK2KX5R-BVbuejJn.js} +7 -7
  66. package/dist/static/assets/{diagram-QEK2KX5R-Mf24XxZL.js.map → diagram-QEK2KX5R-BVbuejJn.js.map} +1 -1
  67. package/dist/static/assets/{diagram-S2PKOQOG-DyQjD4D5.js → diagram-S2PKOQOG-pB6N6Tq_.js} +7 -7
  68. package/dist/static/assets/{diagram-S2PKOQOG-DyQjD4D5.js.map → diagram-S2PKOQOG-pB6N6Tq_.js.map} +1 -1
  69. package/dist/static/assets/{erDiagram-Q2GNP2WA-CEzTKw1u.js → erDiagram-Q2GNP2WA-DLKmthuw.js} +5 -5
  70. package/dist/static/assets/{erDiagram-Q2GNP2WA-CEzTKw1u.js.map → erDiagram-Q2GNP2WA-DLKmthuw.js.map} +1 -1
  71. package/dist/static/assets/{flowDiagram-NV44I4VS-DT821XSz.js → flowDiagram-NV44I4VS-BsBhWukh.js} +6 -6
  72. package/dist/static/assets/{flowDiagram-NV44I4VS-DT821XSz.js.map → flowDiagram-NV44I4VS-BsBhWukh.js.map} +1 -1
  73. package/dist/static/assets/{ganttDiagram-JELNMOA3-DlmeVsGg.js → ganttDiagram-JELNMOA3-Debz-J-C.js} +3 -3
  74. package/dist/static/assets/{ganttDiagram-JELNMOA3-DlmeVsGg.js.map → ganttDiagram-JELNMOA3-Debz-J-C.js.map} +1 -1
  75. package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-yAfyBG_d.js → gitGraphDiagram-V2S2FVAM-BnAPFBGR.js} +8 -8
  76. package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-yAfyBG_d.js.map → gitGraphDiagram-V2S2FVAM-BnAPFBGR.js.map} +1 -1
  77. package/dist/static/assets/{graph-BYv8vyWe.js → graph-DbzWiBNK.js} +3 -3
  78. package/dist/static/assets/{graph-BYv8vyWe.js.map → graph-DbzWiBNK.js.map} +1 -1
  79. package/dist/static/assets/{index-DMbwqOm6.js → index-B-8J28g7.js} +987 -1049
  80. package/dist/static/assets/index-B-8J28g7.js.map +1 -0
  81. package/dist/static/assets/{index-BiNcBn_U.css → index-CD5wtC_i.css} +1 -1
  82. package/dist/static/assets/{infoDiagram-HS3SLOUP-DaadramQ.js → infoDiagram-HS3SLOUP-CZ5hWoxV.js} +6 -6
  83. package/dist/static/assets/{infoDiagram-HS3SLOUP-DaadramQ.js.map → infoDiagram-HS3SLOUP-CZ5hWoxV.js.map} +1 -1
  84. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-ftN8hxu3.js → journeyDiagram-XKPGCS4Q-CKN3oSxk.js} +5 -5
  85. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-ftN8hxu3.js.map → journeyDiagram-XKPGCS4Q-CKN3oSxk.js.map} +1 -1
  86. package/dist/static/assets/{kanban-definition-3W4ZIXB7-BIXETQ-C.js → kanban-definition-3W4ZIXB7-BQCMklfJ.js} +3 -3
  87. package/dist/static/assets/{kanban-definition-3W4ZIXB7-BIXETQ-C.js.map → kanban-definition-3W4ZIXB7-BQCMklfJ.js.map} +1 -1
  88. package/dist/static/assets/{layout-OTbrj0Ye.js → layout-C5B58szc.js} +5 -5
  89. package/dist/static/assets/{layout-OTbrj0Ye.js.map → layout-C5B58szc.js.map} +1 -1
  90. package/dist/static/assets/{linear-CVfOC669.js → linear-_32fut6G.js} +2 -2
  91. package/dist/static/assets/{linear-CVfOC669.js.map → linear-_32fut6G.js.map} +1 -1
  92. package/dist/static/assets/{mindmap-definition-VGOIOE7T-D2zv5uI9.js → mindmap-definition-VGOIOE7T-C_goMzjx.js} +4 -4
  93. package/dist/static/assets/{mindmap-definition-VGOIOE7T-D2zv5uI9.js.map → mindmap-definition-VGOIOE7T-C_goMzjx.js.map} +1 -1
  94. package/dist/static/assets/{pieDiagram-ADFJNKIX-DaUXTsv7.js → pieDiagram-ADFJNKIX-BQ2n0cOB.js} +8 -8
  95. package/dist/static/assets/{pieDiagram-ADFJNKIX-DaUXTsv7.js.map → pieDiagram-ADFJNKIX-BQ2n0cOB.js.map} +1 -1
  96. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-B7O2wPX9.js → quadrantDiagram-AYHSOK5B-BLg7_neg.js} +3 -3
  97. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-B7O2wPX9.js.map → quadrantDiagram-AYHSOK5B-BLg7_neg.js.map} +1 -1
  98. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-DpauVPY1.js → requirementDiagram-UZGBJVZJ-DwkJt0zi.js} +4 -4
  99. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-DpauVPY1.js.map → requirementDiagram-UZGBJVZJ-DwkJt0zi.js.map} +1 -1
  100. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-B3Hbfvad.js → sankeyDiagram-TZEHDZUN-DmxmatUB.js} +2 -2
  101. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-B3Hbfvad.js.map → sankeyDiagram-TZEHDZUN-DmxmatUB.js.map} +1 -1
  102. package/dist/static/assets/{sequenceDiagram-WL72ISMW-KdbWByWT.js → sequenceDiagram-WL72ISMW-KHU_eApU.js} +4 -4
  103. package/dist/static/assets/{sequenceDiagram-WL72ISMW-KdbWByWT.js.map → sequenceDiagram-WL72ISMW-KHU_eApU.js.map} +1 -1
  104. package/dist/static/assets/{stateDiagram-FKZM4ZOC-yDOCVezC.js → stateDiagram-FKZM4ZOC-B3DBCxAL.js} +9 -9
  105. package/dist/static/assets/{stateDiagram-FKZM4ZOC-yDOCVezC.js.map → stateDiagram-FKZM4ZOC-B3DBCxAL.js.map} +1 -1
  106. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-CpCJhvQO.js → stateDiagram-v2-4FDKWEC3-C-uIk7gh.js} +5 -5
  107. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-CpCJhvQO.js.map → stateDiagram-v2-4FDKWEC3-C-uIk7gh.js.map} +1 -1
  108. package/dist/static/assets/{timeline-definition-IT6M3QCI-CHxuEjhV.js → timeline-definition-IT6M3QCI-SysEcQCC.js} +3 -3
  109. package/dist/static/assets/{timeline-definition-IT6M3QCI-CHxuEjhV.js.map → timeline-definition-IT6M3QCI-SysEcQCC.js.map} +1 -1
  110. package/dist/static/assets/{treemap-GDKQZRPO-Bsqu3wIy.js → treemap-GDKQZRPO-d0AbKEc4.js} +5 -5
  111. package/dist/static/assets/{treemap-GDKQZRPO-Bsqu3wIy.js.map → treemap-GDKQZRPO-d0AbKEc4.js.map} +1 -1
  112. package/dist/static/assets/{xychartDiagram-PRI3JC2R-RZy33lFF.js → xychartDiagram-PRI3JC2R-CmSQMxUh.js} +3 -3
  113. package/dist/static/assets/{xychartDiagram-PRI3JC2R-RZy33lFF.js.map → xychartDiagram-PRI3JC2R-CmSQMxUh.js.map} +1 -1
  114. package/dist/static/index.html +2 -2
  115. package/dist/tools/fs.js +1 -1
  116. package/package.json +9 -7
  117. package/dist/agent-priming.js +0 -2051
  118. package/dist/apps/installed-file.js +0 -207
  119. package/dist/apps/runtime-port.js +0 -91
  120. package/dist/docs/dominds-agent-priming.md +0 -218
  121. package/dist/docs/dominds-agent-priming.zh.md +0 -196
  122. package/dist/docs/drive-logic-context-refactor-plan.zh.md +0 -338
  123. package/dist/docs/keep-going.md +0 -176
  124. package/dist/docs/keep-going.zh.md +0 -162
  125. package/dist/docs/kernel-app-architecture.md +0 -286
  126. package/dist/docs/kernel-app-architecture.zh.md +0 -285
  127. package/dist/docs/showing-by-doing.md +0 -208
  128. package/dist/docs/showing-by-doing.zh.md +0 -177
  129. package/dist/docs/team-mgmt-toolset.md +0 -482
  130. package/dist/docs/team-mgmt-toolset.zh.md +0 -426
  131. package/dist/llm/driver-entry.js +0 -28
  132. package/dist/llm/driver-v2/context-health.js +0 -121
  133. package/dist/llm/driver-v2/context.js +0 -56
  134. package/dist/llm/driver-v2/core.js +0 -1545
  135. package/dist/llm/driver-v2/index.js +0 -26
  136. package/dist/llm/driver-v2/orchestrator.js +0 -158
  137. package/dist/llm/driver-v2/policy.js +0 -129
  138. package/dist/llm/driver-v2/restore-dialog-hierarchy.js +0 -73
  139. package/dist/llm/driver-v2/round.js +0 -366
  140. package/dist/llm/driver-v2/runtime-utils.js +0 -365
  141. package/dist/llm/driver-v2/saying-events.js +0 -20
  142. package/dist/llm/driver-v2/subdialog-txn.js +0 -42
  143. package/dist/llm/driver-v2/supdialog-response.js +0 -400
  144. package/dist/llm/driver-v2/tellask-bridge.js +0 -1148
  145. package/dist/llm/driver-v2/types.js +0 -10
  146. package/dist/llm/driver-v2-ref-only/context-health.js +0 -121
  147. package/dist/llm/driver-v2-ref-only/context.js +0 -17
  148. package/dist/llm/driver-v2-ref-only/core.js +0 -1710
  149. package/dist/llm/driver-v2-ref-only/index.js +0 -26
  150. package/dist/llm/driver-v2-ref-only/orchestrator.js +0 -158
  151. package/dist/llm/driver-v2-ref-only/policy.js +0 -129
  152. package/dist/llm/driver-v2-ref-only/restore-dialog-hierarchy.js +0 -73
  153. package/dist/llm/driver-v2-ref-only/round.js +0 -366
  154. package/dist/llm/driver-v2-ref-only/runtime-utils.js +0 -473
  155. package/dist/llm/driver-v2-ref-only/saying-events.js +0 -18
  156. package/dist/llm/driver-v2-ref-only/subdialog-txn.js +0 -42
  157. package/dist/llm/driver-v2-ref-only/supdialog-response.js +0 -453
  158. package/dist/llm/driver-v2-ref-only/tellask-bridge.js +0 -1178
  159. package/dist/llm/driver-v2-ref-only/types.js +0 -10
  160. package/dist/llm/driver.js +0 -4093
  161. package/dist/minds/promptdocs.js +0 -263
  162. package/dist/server/prompts-routes.js +0 -545
  163. package/dist/shared/team-mgmt-manual.js +0 -120
  164. package/dist/shared/types/prompts.js +0 -2
  165. package/dist/shared/types/tellask.js +0 -8
  166. package/dist/showing-by-doing.js +0 -1091
  167. package/dist/snippets/README.en.md +0 -3
  168. package/dist/snippets/README.md +0 -4
  169. package/dist/static/assets/index-DMbwqOm6.js.map +0 -1
  170. package/dist/tellask.js +0 -439
  171. package/dist/tools/context-health.js +0 -177
  172. package/dist/tools/diag.js +0 -583
  173. package/dist/tools/prompts/memory/en/errors.md +0 -155
  174. package/dist/tools/prompts/memory/en/index.md +0 -47
  175. package/dist/tools/prompts/memory/en/principles.md +0 -87
  176. package/dist/tools/prompts/memory/en/scenarios.md +0 -174
  177. package/dist/tools/prompts/memory/en/tools.md +0 -129
  178. package/dist/tools/prompts/memory/zh/errors.md +0 -155
  179. package/dist/tools/prompts/memory/zh/index.md +0 -47
  180. package/dist/tools/prompts/memory/zh/principles.md +0 -89
  181. package/dist/tools/prompts/memory/zh/scenarios.md +0 -174
  182. package/dist/tools/prompts/memory/zh/tools.md +0 -129
  183. package/dist/tools/team-mgmt.js +0 -3487
  184. package/dist/utils/task-doc.js +0 -236
@@ -3,33 +3,27 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.materializeAppsResolution = materializeAppsResolution;
6
7
  exports.loadEnabledAppsSnapshot = loadEnabledAppsSnapshot;
7
8
  const promises_1 = __importDefault(require("node:fs/promises"));
8
9
  const node_path_1 = __importDefault(require("node:path"));
10
+ const app_lock_file_1 = require("./app-lock-file");
9
11
  const assigned_port_1 = require("./assigned-port");
12
+ const configuration_file_1 = require("./configuration-file");
10
13
  const manifest_1 = require("./manifest");
11
14
  const package_info_1 = require("./package-info");
12
15
  const resolution_file_1 = require("./resolution-file");
13
16
  const run_app_json_1 = require("./run-app-json");
14
- async function fileExists(filePathAbs) {
15
- try {
16
- await promises_1.default.access(filePathAbs);
17
- return true;
18
- }
19
- catch (err) {
20
- const isEnoent = typeof err === 'object' &&
21
- err !== null &&
22
- 'code' in err &&
23
- err.code === 'ENOENT';
24
- if (isEnoent)
25
- return false;
26
- throw err;
27
- }
17
+ function getRuntimePort(entry) {
18
+ if (entry.assignedPort !== null)
19
+ return entry.assignedPort;
20
+ const defaultPort = entry.installJson.frontend?.defaultPort;
21
+ return typeof defaultPort === 'number' && defaultPort > 0 ? defaultPort : null;
28
22
  }
29
23
  async function dirExists(dirPathAbs) {
30
24
  try {
31
- const st = await promises_1.default.stat(dirPathAbs);
32
- return st.isDirectory();
25
+ const stat = await promises_1.default.stat(dirPathAbs);
26
+ return stat.isDirectory();
33
27
  }
34
28
  catch (err) {
35
29
  const isEnoent = typeof err === 'object' &&
@@ -41,57 +35,29 @@ async function dirExists(dirPathAbs) {
41
35
  throw err;
42
36
  }
43
37
  }
44
- async function tryLoadRtwsAppManifestDeps(params) {
45
- const filePathAbs = node_path_1.default.resolve(params.rtwsRootAbs, '.minds', 'app.yaml');
46
- if (!(await fileExists(filePathAbs)))
47
- return [];
48
- const loaded = await (0, manifest_1.loadDomindsAppManifest)({
49
- packageRootAbs: params.rtwsRootAbs,
50
- manifestRelPath: '.minds/app.yaml',
51
- });
52
- if (loaded.kind === 'error') {
53
- throw new Error(`Failed to load rtws app manifest: ${loaded.errorText} (${loaded.filePathAbs})`);
54
- }
55
- return loaded.manifest.dependencies ?? [];
56
- }
57
- function indexOverlayApps(params) {
58
- const byId = new Map();
59
- const extras = [];
60
- for (const e of params.overlayApps) {
61
- if (byId.has(e.id)) {
62
- // Loud: duplicate IDs means non-deterministic overrides.
63
- throw new Error(`Invalid apps resolution overlay: duplicate app id '${e.id}'`);
64
- }
65
- byId.set(e.id, e);
66
- extras.push(e);
67
- }
68
- return { byId, extras };
69
- }
70
38
  function normalizeStrategy(raw) {
71
39
  const order = raw?.order ??
72
- resolution_file_1.DEFAULT_APPS_RESOLUTION_STRATEGY.order ??
40
+ configuration_file_1.DEFAULT_APPS_RESOLUTION_STRATEGY.order ??
73
41
  ['local'];
74
42
  const localRoots = raw?.localRoots ??
75
- resolution_file_1.DEFAULT_APPS_RESOLUTION_STRATEGY.localRoots ?? ['dominds-apps'];
43
+ configuration_file_1.DEFAULT_APPS_RESOLUTION_STRATEGY.localRoots ?? ['dominds-apps'];
76
44
  if (order.length === 0) {
77
- throw new Error(`Invalid ${resolution_file_1.APPS_RESOLUTION_REL_PATH}: resolutionStrategy.order must not be empty`);
45
+ throw new Error(`Invalid ${configuration_file_1.APPS_CONFIGURATION_REL_PATH}: resolutionStrategy.order must not be empty`);
78
46
  }
79
47
  if (localRoots.length === 0) {
80
- throw new Error(`Invalid ${resolution_file_1.APPS_RESOLUTION_REL_PATH}: resolutionStrategy.localRoots must not be empty`);
48
+ throw new Error(`Invalid ${configuration_file_1.APPS_CONFIGURATION_REL_PATH}: resolutionStrategy.localRoots must not be empty`);
81
49
  }
82
- const orderSet = new Set(order);
83
- if (orderSet.size !== order.length) {
84
- throw new Error(`Invalid ${resolution_file_1.APPS_RESOLUTION_REL_PATH}: resolutionStrategy.order has duplicates`);
50
+ if (new Set(order).size !== order.length) {
51
+ throw new Error(`Invalid ${configuration_file_1.APPS_CONFIGURATION_REL_PATH}: resolutionStrategy.order has duplicates`);
85
52
  }
86
- const localRootsSet = new Set(localRoots);
87
- if (localRootsSet.size !== localRoots.length) {
88
- throw new Error(`Invalid ${resolution_file_1.APPS_RESOLUTION_REL_PATH}: resolutionStrategy.localRoots has duplicates`);
53
+ if (new Set(localRoots).size !== localRoots.length) {
54
+ throw new Error(`Invalid ${configuration_file_1.APPS_CONFIGURATION_REL_PATH}: resolutionStrategy.localRoots has duplicates`);
89
55
  }
90
56
  return { order, localRoots };
91
57
  }
92
58
  function getResolutionHint(params) {
93
- const filePathAbs = node_path_1.default.resolve(params.rtwsRootAbs, resolution_file_1.APPS_RESOLUTION_REL_PATH);
94
- const action = params.hasResolutionFile ? 'Edit' : 'Create';
59
+ const filePathAbs = node_path_1.default.resolve(params.rtwsRootAbs, configuration_file_1.APPS_CONFIGURATION_REL_PATH);
60
+ const action = params.hasConfigurationFile ? 'Edit' : 'Create';
95
61
  return (`${action} ${filePathAbs} to configure 'resolutionStrategy'. ` +
96
62
  `Default local root is 'dominds-apps' (rtws-relative) and expects local apps at '<root>/<appId>/'.`);
97
63
  }
@@ -104,7 +70,7 @@ async function resolveLocalAppPackageRootAbs(params) {
104
70
  }
105
71
  return null;
106
72
  }
107
- async function resolveAppManifestDepsFromInstalledApp(params) {
73
+ async function loadManifestDepsFromResolvedApp(params) {
108
74
  const pkgInfo = await (0, package_info_1.readPackageInfo)({ packageRootAbs: params.packageRootAbs });
109
75
  const loaded = await (0, manifest_1.loadDomindsAppManifest)({
110
76
  packageRootAbs: params.packageRootAbs,
@@ -115,17 +81,75 @@ async function resolveAppManifestDepsFromInstalledApp(params) {
115
81
  }
116
82
  return loaded.manifest.dependencies ?? [];
117
83
  }
118
- async function resolveAppsFromRtwsHierarchy(params) {
119
- const issues = [];
120
- const pushIssue = (issue) => {
121
- issues.push(issue);
84
+ function makeLockedAppHint(entry) {
85
+ return {
86
+ packageName: entry.package.name,
87
+ version: entry.package.version,
122
88
  };
89
+ }
90
+ function buildNpxSpec(params) {
91
+ const packageName = params.lockedHint?.packageName ??
92
+ params.previousResolutionEntry?.installJson.package.name ??
93
+ params.appId;
94
+ const version = params.lockedHint?.version ?? null;
95
+ return version && version.trim() !== '' ? `${packageName}@${version}` : packageName;
96
+ }
97
+ async function probeAppByStrategy(params) {
98
+ for (const item of params.strategy.order) {
99
+ if (item === 'local') {
100
+ const packageRootAbs = await resolveLocalAppPackageRootAbs({
101
+ rtwsRootAbs: params.rtwsRootAbs,
102
+ appId: params.appId,
103
+ localRoots: params.strategy.localRoots,
104
+ });
105
+ if (!packageRootAbs)
106
+ continue;
107
+ const installJson = await (0, run_app_json_1.runDomindsAppJsonViaLocalPackage)({ packageRootAbs });
108
+ if (installJson.appId !== params.appId) {
109
+ throw new Error(`App id mismatch for local package '${packageRootAbs}': expected '${params.appId}', got '${installJson.appId}'`);
110
+ }
111
+ return { source: { kind: 'local', pathAbs: packageRootAbs }, installJson };
112
+ }
113
+ if (item === 'npx') {
114
+ const spec = buildNpxSpec({
115
+ appId: params.appId,
116
+ lockedHint: params.lockedHint,
117
+ previousResolutionEntry: params.previousResolutionEntry,
118
+ });
119
+ const installJson = await (0, run_app_json_1.runDomindsAppJsonViaNpx)({
120
+ spec,
121
+ cwdAbs: params.rtwsRootAbs,
122
+ });
123
+ if (installJson.appId !== params.appId) {
124
+ throw new Error(`App id mismatch for npx '${spec}': expected '${params.appId}', got '${installJson.appId}'`);
125
+ }
126
+ return { source: { kind: 'npx', spec }, installJson };
127
+ }
128
+ const exhaustive = item;
129
+ throw new Error(`Unreachable resolution strategy item: ${String(exhaustive)}`);
130
+ }
131
+ return null;
132
+ }
133
+ function makeResolutionEntry(params) {
134
+ return {
135
+ id: params.appId,
136
+ enabled: true,
137
+ source: params.probe.source,
138
+ assignedPort: params.cachedAssignedPort,
139
+ installJson: params.probe.installJson,
140
+ };
141
+ }
142
+ async function resolveGraph(params) {
143
+ const issues = [];
123
144
  const resolvedById = new Map();
124
145
  const depsByAppId = new Map();
146
+ const fatalApps = new Set();
125
147
  const requiredById = new Map();
126
148
  const requiredByParents = new Map();
127
- const missingRequired = new Set();
128
- const fatalApps = new Set();
149
+ const queue = [];
150
+ const pushIssue = (issue) => {
151
+ issues.push(issue);
152
+ };
129
153
  const addRequiredByParent = (depId, parentId) => {
130
154
  const existing = requiredByParents.get(depId);
131
155
  if (existing) {
@@ -140,24 +164,20 @@ async function resolveAppsFromRtwsHierarchy(params) {
140
164
  requiredById.set(id, required);
141
165
  return true;
142
166
  }
143
- if (prev === true)
167
+ if (prev === true || required === false)
144
168
  return false;
145
- if (required === true) {
146
- requiredById.set(id, true);
147
- return true;
148
- }
149
- return false;
169
+ requiredById.set(id, true);
170
+ return true;
150
171
  };
151
- const queue = [];
152
172
  const enqueue = (id, required, parentId) => {
153
173
  const changed = mergeRequiredFlag(id, required);
154
- if (parentId && required)
174
+ if (required && parentId)
155
175
  addRequiredByParent(id, parentId);
156
176
  if (changed)
157
177
  queue.push(id);
158
178
  };
159
179
  try {
160
- const rootDeps = await tryLoadRtwsAppManifestDeps({ rtwsRootAbs: params.rtwsRootAbs });
180
+ const rootDeps = await (0, manifest_1.loadRtwsDeclaredAppDependencies)({ rtwsRootAbs: params.rtwsRootAbs });
161
181
  for (const dep of rootDeps) {
162
182
  enqueue(dep.id, dep.optional !== true, 'rtws');
163
183
  }
@@ -174,111 +194,81 @@ async function resolveAppsFromRtwsHierarchy(params) {
174
194
  },
175
195
  });
176
196
  }
177
- // Also treat explicitly enabled overlay apps as roots so their own transitive dependencies
178
- // are resolved and missing-required issues can be surfaced.
179
- for (const e of params.overlay.extras) {
180
- if (!e.userEnabled)
181
- continue;
182
- enqueue(e.id, true, 'resolution_overlay');
183
- }
184
- const resolveMissingApp = async (appId) => {
185
- for (const item of params.strategy.order) {
186
- if (item === 'local') {
187
- const packageRootAbs = await resolveLocalAppPackageRootAbs({
188
- rtwsRootAbs: params.rtwsRootAbs,
189
- appId,
190
- localRoots: params.strategy.localRoots,
191
- });
192
- if (!packageRootAbs) {
193
- continue;
194
- }
195
- const installJson = await (0, run_app_json_1.runDomindsAppJsonViaLocalPackage)({ packageRootAbs });
196
- if (installJson.appId !== appId) {
197
- throw new Error(`App id mismatch for local package '${packageRootAbs}': expected '${appId}', got '${installJson.appId}'`);
198
- }
199
- const source = { kind: 'local', pathAbs: packageRootAbs };
200
- return {
201
- id: appId,
202
- enabled: true,
203
- userEnabled: true,
204
- source,
205
- assignedPort: null,
206
- installJson,
207
- };
208
- }
209
- if (item === 'npx') {
210
- throw new Error(`Apps resolution strategy 'npx' is not supported yet for missing app '${appId}'. ` +
211
- `Install it explicitly so it appears in ${resolution_file_1.APPS_RESOLUTION_REL_PATH}.`);
212
- }
213
- const _exhaustive = item;
214
- throw new Error(`Unreachable: unknown resolution strategy item: ${String(_exhaustive)}`);
215
- }
216
- return null;
217
- };
218
197
  while (queue.length > 0) {
219
198
  const appId = queue.shift();
220
199
  if (!appId)
221
200
  break;
222
- if (resolvedById.has(appId) || missingRequired.has(appId) || fatalApps.has(appId)) {
201
+ if (resolvedById.has(appId) || fatalApps.has(appId))
223
202
  continue;
224
- }
225
203
  const required = requiredById.get(appId) ?? true;
226
- const overlayEntry = params.overlay.byId.get(appId) ?? null;
227
- let entry = overlayEntry;
228
- if (!entry) {
229
- try {
230
- entry = await resolveMissingApp(appId);
231
- }
232
- catch (err) {
233
- if (required) {
234
- const roots = params.strategy.localRoots
235
- .map((r) => (node_path_1.default.isAbsolute(r) ? r : node_path_1.default.resolve(params.rtwsRootAbs, r)))
236
- .join(', ');
237
- pushIssue({
238
- kind: 'required_dependency_missing',
239
- severity: 'error',
240
- message: `Required app dependency '${appId}' failed to resolve.`,
241
- detail: {
242
- appId,
243
- searchedLocalRootsAbs: roots,
244
- hint: getResolutionHint({
245
- rtwsRootAbs: params.rtwsRootAbs,
246
- hasResolutionFile: params.hasResolutionFile,
247
- }),
248
- errorText: err instanceof Error ? err.message : String(err),
249
- requiredBy: [...(requiredByParents.get(appId) ?? new Set())].sort(),
250
- },
251
- });
252
- missingRequired.add(appId);
253
- }
254
- continue;
204
+ const explicitlyDisabled = params.configurationDisabledApps.has(appId);
205
+ const previousResolutionEntry = params.previousResolutionById.get(appId) ?? null;
206
+ let probe = null;
207
+ try {
208
+ probe = await probeAppByStrategy({
209
+ rtwsRootAbs: params.rtwsRootAbs,
210
+ appId,
211
+ strategy: params.strategy,
212
+ lockedHint: params.lockedHintsById.get(appId) ?? null,
213
+ previousResolutionEntry,
214
+ });
215
+ }
216
+ catch (err) {
217
+ if (required) {
218
+ const roots = params.strategy.localRoots
219
+ .map((root) => (node_path_1.default.isAbsolute(root) ? root : node_path_1.default.resolve(params.rtwsRootAbs, root)))
220
+ .join(', ');
221
+ pushIssue({
222
+ kind: explicitlyDisabled ? 'required_dependency_disabled' : 'required_dependency_missing',
223
+ severity: 'error',
224
+ message: explicitlyDisabled
225
+ ? `Required app dependency '${appId}' is disabled.`
226
+ : `Required app dependency '${appId}' failed to resolve.`,
227
+ detail: {
228
+ appId,
229
+ searchedLocalRootsAbs: roots,
230
+ hint: getResolutionHint({
231
+ rtwsRootAbs: params.rtwsRootAbs,
232
+ hasConfigurationFile: params.hasConfigurationFile,
233
+ }),
234
+ errorText: err instanceof Error ? err.message : String(err),
235
+ requiredBy: [...(requiredByParents.get(appId) ?? new Set())].sort(),
236
+ },
237
+ });
255
238
  }
239
+ continue;
256
240
  }
257
- if (!entry) {
241
+ if (!probe) {
258
242
  if (required) {
259
243
  const roots = params.strategy.localRoots
260
- .map((r) => (node_path_1.default.isAbsolute(r) ? r : node_path_1.default.resolve(params.rtwsRootAbs, r)))
244
+ .map((root) => (node_path_1.default.isAbsolute(root) ? root : node_path_1.default.resolve(params.rtwsRootAbs, root)))
261
245
  .join(', ');
262
246
  pushIssue({
263
- kind: 'required_dependency_missing',
247
+ kind: explicitlyDisabled ? 'required_dependency_disabled' : 'required_dependency_missing',
264
248
  severity: 'error',
265
- message: `Required app dependency '${appId}' is missing.`,
249
+ message: explicitlyDisabled
250
+ ? `Required app dependency '${appId}' is disabled.`
251
+ : `Required app dependency '${appId}' is missing.`,
266
252
  detail: {
267
253
  appId,
268
254
  searchedLocalRootsAbs: roots,
269
255
  hint: getResolutionHint({
270
256
  rtwsRootAbs: params.rtwsRootAbs,
271
- hasResolutionFile: params.hasResolutionFile,
257
+ hasConfigurationFile: params.hasConfigurationFile,
272
258
  }),
273
259
  requiredBy: [...(requiredByParents.get(appId) ?? new Set())].sort(),
274
260
  },
275
261
  });
276
- missingRequired.add(appId);
277
262
  }
278
263
  continue;
279
264
  }
265
+ const entry = makeResolutionEntry({
266
+ appId,
267
+ probe,
268
+ cachedAssignedPort: previousResolutionEntry?.assignedPort ?? null,
269
+ });
280
270
  resolvedById.set(appId, entry);
281
- if (!entry.userEnabled) {
271
+ if (explicitlyDisabled) {
282
272
  if (required) {
283
273
  pushIssue({
284
274
  kind: 'required_dependency_disabled',
@@ -286,12 +276,8 @@ async function resolveAppsFromRtwsHierarchy(params) {
286
276
  message: `Required app dependency '${appId}' is disabled.`,
287
277
  detail: {
288
278
  appId,
289
- resolutionFileRelPath: resolution_file_1.APPS_RESOLUTION_REL_PATH,
279
+ configurationFileRelPath: configuration_file_1.APPS_CONFIGURATION_REL_PATH,
290
280
  requiredBy: [...(requiredByParents.get(appId) ?? new Set())].sort(),
291
- hint: getResolutionHint({
292
- rtwsRootAbs: params.rtwsRootAbs,
293
- hasResolutionFile: params.hasResolutionFile,
294
- }),
295
281
  },
296
282
  });
297
283
  }
@@ -299,7 +285,7 @@ async function resolveAppsFromRtwsHierarchy(params) {
299
285
  }
300
286
  let manifestDeps;
301
287
  try {
302
- manifestDeps = await resolveAppManifestDepsFromInstalledApp({
288
+ manifestDeps = await loadManifestDepsFromResolvedApp({
303
289
  appId,
304
290
  packageRootAbs: entry.installJson.package.rootAbs,
305
291
  });
@@ -318,51 +304,48 @@ async function resolveAppsFromRtwsHierarchy(params) {
318
304
  fatalApps.add(appId);
319
305
  continue;
320
306
  }
321
- const edges = manifestDeps.map((d) => ({
322
- depId: d.id,
323
- required: d.optional !== true,
307
+ const edges = manifestDeps.map((dep) => ({
308
+ depId: dep.id,
309
+ required: dep.optional !== true,
324
310
  }));
325
311
  depsByAppId.set(appId, edges);
326
- for (const e of edges) {
327
- enqueue(e.depId, e.required, appId);
312
+ for (const edge of edges) {
313
+ enqueue(edge.depId, edge.required, appId);
328
314
  }
329
315
  }
330
316
  const effectiveEnabledById = new Map();
331
- for (const [id, entry] of resolvedById.entries()) {
332
- effectiveEnabledById.set(id, entry.userEnabled && !fatalApps.has(id));
317
+ for (const [appId] of resolvedById.entries()) {
318
+ effectiveEnabledById.set(appId, !params.configurationDisabledApps.has(appId) && !fatalApps.has(appId));
333
319
  }
334
- // Fixed-point disable propagation: if an enabled app has a required dependency that is missing
335
- // or effectively disabled, the app becomes effectively disabled.
336
320
  let changed = true;
337
321
  while (changed) {
338
322
  changed = false;
339
- for (const [appId, entry] of resolvedById.entries()) {
340
- if (!effectiveEnabledById.get(appId))
341
- continue;
342
- if (!entry.userEnabled)
323
+ for (const [appId] of resolvedById.entries()) {
324
+ if (!(effectiveEnabledById.get(appId) ?? false))
343
325
  continue;
344
326
  const edges = depsByAppId.get(appId) ?? [];
345
327
  for (const edge of edges) {
346
328
  if (!edge.required)
347
329
  continue;
348
- const depId = edge.depId;
349
- const depResolved = resolvedById.get(depId) ?? null;
350
- const depEnabled = depResolved ? (effectiveEnabledById.get(depId) ?? false) : false;
351
- const depMissing = !depResolved && missingRequired.has(depId);
352
- if (depMissing || !depEnabled) {
330
+ const depResolved = resolvedById.get(edge.depId) ?? null;
331
+ const depExplicitlyDisabled = params.configurationDisabledApps.has(edge.depId);
332
+ const depEffectiveEnabled = depResolved
333
+ ? (effectiveEnabledById.get(edge.depId) ?? false)
334
+ : false;
335
+ if (depExplicitlyDisabled || !depResolved || !depEffectiveEnabled) {
353
336
  effectiveEnabledById.set(appId, false);
354
337
  pushIssue({
355
338
  kind: 'app_effectively_disabled_due_to_required_dependency',
356
339
  severity: 'error',
357
- message: `App '${appId}' is effectively disabled due to missing/disabled required dependency '${depId}'.`,
340
+ message: `App '${appId}' is effectively disabled due to missing/disabled required dependency '${edge.depId}'.`,
358
341
  detail: {
359
342
  appId,
360
- dependencyId: depId,
361
- dependencyState: depMissing
362
- ? 'missing'
363
- : depResolved && depResolved.userEnabled === false
364
- ? 'disabled'
365
- : 'effectively_disabled',
343
+ dependencyId: edge.depId,
344
+ dependencyState: depExplicitlyDisabled
345
+ ? 'disabled'
346
+ : depResolved
347
+ ? 'effectively_disabled'
348
+ : 'missing',
366
349
  },
367
350
  });
368
351
  changed = true;
@@ -371,25 +354,22 @@ async function resolveAppsFromRtwsHierarchy(params) {
371
354
  }
372
355
  }
373
356
  }
374
- const assignedPortById = new Map();
375
- const resolvedEntriesForPort = [...resolvedById.values()];
357
+ const resolvedEntriesForPorts = [...resolvedById.values()];
376
358
  for (const [appId, entry] of resolvedById.entries()) {
377
- if (!effectiveEnabledById.get(appId))
359
+ if (!(effectiveEnabledById.get(appId) ?? false))
378
360
  continue;
379
361
  const assigned = await (0, assigned_port_1.resolveStableAssignedPortWithReason)({
380
362
  appId,
381
363
  installJson: entry.installJson,
382
- existingApps: resolvedEntriesForPort,
364
+ existingApps: resolvedEntriesForPorts,
383
365
  existingAssignedPort: entry.assignedPort,
384
366
  });
385
- assignedPortById.set(appId, assigned.assignedPort);
386
367
  if (assigned.assignedPort !== entry.assignedPort) {
387
368
  const nextEntry = { ...entry, assignedPort: assigned.assignedPort };
388
369
  resolvedById.set(appId, nextEntry);
389
- const idx = resolvedEntriesForPort.findIndex((a) => a.id === appId);
390
- if (idx >= 0) {
391
- resolvedEntriesForPort[idx] = nextEntry;
392
- }
370
+ const idx = resolvedEntriesForPorts.findIndex((item) => item.id === appId);
371
+ if (idx >= 0)
372
+ resolvedEntriesForPorts[idx] = nextEntry;
393
373
  }
394
374
  if (assigned.reason === 'reassigned_from_existing_conflict' ||
395
375
  assigned.reason === 'reassigned_from_existing_unbindable') {
@@ -407,78 +387,63 @@ async function resolveAppsFromRtwsHierarchy(params) {
407
387
  });
408
388
  }
409
389
  }
410
- const out = [];
390
+ const apps = [];
411
391
  for (const [appId, entry] of resolvedById.entries()) {
412
- if (!effectiveEnabledById.get(appId))
413
- continue;
414
- out.push(entry.enabled ? entry : { ...entry, enabled: true });
415
- }
416
- return { apps: out, issues, effectiveEnabledById, assignedPortById };
417
- }
418
- async function loadAppsResolutionOverlay(params) {
419
- const filePathAbs = node_path_1.default.resolve(params.rtwsRootAbs, resolution_file_1.APPS_RESOLUTION_REL_PATH);
420
- const hasResolutionFile = await fileExists(filePathAbs);
421
- if (!hasResolutionFile) {
422
- const emptyFile = { schemaVersion: 1, apps: [] };
423
- return {
424
- overlay: indexOverlayApps({ overlayApps: [] }),
425
- resolutionFile: emptyFile,
426
- strategy: normalizeStrategy(undefined),
427
- hasResolutionFile,
428
- };
429
- }
430
- const loaded = await (0, resolution_file_1.loadAppsResolutionFile)({ rtwsRootAbs: params.rtwsRootAbs });
431
- if (loaded.kind === 'error') {
432
- throw new Error(`Failed to load apps resolution file overlay: ${loaded.errorText} (${loaded.filePathAbs})`);
392
+ apps.push({ ...entry, enabled: effectiveEnabledById.get(appId) ?? false });
433
393
  }
434
394
  return {
435
- overlay: indexOverlayApps({ overlayApps: loaded.file.apps }),
436
- resolutionFile: loaded.file,
437
- strategy: normalizeStrategy(loaded.file.resolutionStrategy),
438
- hasResolutionFile,
395
+ resolutionFile: { schemaVersion: 1, apps },
396
+ issues,
439
397
  };
440
398
  }
441
- async function loadEffectiveAppsResolution(params) {
442
- const loaded = await loadAppsResolutionOverlay({ rtwsRootAbs: params.rtwsRootAbs });
443
- const resolved = await resolveAppsFromRtwsHierarchy({
399
+ async function materializeAppsResolution(params) {
400
+ const loadedConfig = await (0, configuration_file_1.loadAppsConfigurationFile)({ rtwsRootAbs: params.rtwsRootAbs });
401
+ if (loadedConfig.kind === 'error') {
402
+ throw new Error(`Failed to load apps configuration: ${loadedConfig.errorText} (${loadedConfig.filePathAbs})`);
403
+ }
404
+ const loadedResolution = await (0, resolution_file_1.loadAppsResolutionFile)({ rtwsRootAbs: params.rtwsRootAbs });
405
+ if (loadedResolution.kind === 'error') {
406
+ throw new Error(`Failed to load apps resolution snapshot: ${loadedResolution.errorText} (${loadedResolution.filePathAbs})`);
407
+ }
408
+ const loadedLock = await (0, app_lock_file_1.loadAppLockFile)({ rtwsRootAbs: params.rtwsRootAbs });
409
+ if (loadedLock.kind === 'error') {
410
+ throw new Error(`Failed to load app lock: ${loadedLock.errorText} (${loadedLock.filePathAbs})`);
411
+ }
412
+ const previousResolutionById = new Map();
413
+ for (const entry of loadedResolution.file.apps) {
414
+ previousResolutionById.set(entry.id, entry);
415
+ }
416
+ const lockedHintsById = new Map();
417
+ for (const entry of loadedLock.file.apps) {
418
+ lockedHintsById.set(entry.id, makeLockedAppHint(entry));
419
+ }
420
+ const resolved = await resolveGraph({
444
421
  rtwsRootAbs: params.rtwsRootAbs,
445
- overlay: loaded.overlay,
446
- strategy: loaded.strategy,
447
- hasResolutionFile: loaded.hasResolutionFile,
422
+ strategy: normalizeStrategy(loadedConfig.file.resolutionStrategy),
423
+ configurationDisabledApps: new Set(loadedConfig.file.disabledApps ?? []),
424
+ previousResolutionById,
425
+ lockedHintsById,
426
+ hasConfigurationFile: loadedConfig.exists,
448
427
  });
449
- if (loaded.hasResolutionFile) {
450
- const withEffectiveEnabled = (0, resolution_file_1.applyEffectiveEnabledToResolvedApps)({
451
- existing: loaded.resolutionFile,
452
- effectiveEnabledById: resolved.effectiveEnabledById,
453
- });
454
- const nextResolutionFile = (0, resolution_file_1.applyAssignedPortToResolvedApps)({
455
- existing: withEffectiveEnabled,
456
- assignedPortById: resolved.assignedPortById,
428
+ if (JSON.stringify(loadedResolution.file) !== JSON.stringify(resolved.resolutionFile)) {
429
+ await (0, resolution_file_1.writeAppsResolutionFileIfChanged)({
430
+ rtwsRootAbs: params.rtwsRootAbs,
431
+ file: resolved.resolutionFile,
457
432
  });
458
- if (nextResolutionFile !== loaded.resolutionFile) {
459
- await (0, resolution_file_1.writeAppsResolutionFileIfChanged)({
460
- rtwsRootAbs: params.rtwsRootAbs,
461
- file: nextResolutionFile,
462
- });
463
- }
464
433
  }
465
- return { apps: resolved.apps, issues: resolved.issues };
434
+ return resolved;
466
435
  }
467
436
  async function loadEnabledAppsSnapshot(params) {
468
- const loaded = await loadEffectiveAppsResolution({ rtwsRootAbs: params.rtwsRootAbs });
469
- const enabledApps = loaded.apps
470
- .filter((a) => a.enabled)
471
- .map((a) => ({
472
- // Note: installJson.frontend.defaultPort may be 0 (meaning "runtime decides"); do not pass 0 as runtimePort.
473
- id: a.id,
474
- runtimePort: a.assignedPort ??
475
- (a.installJson.frontend &&
476
- a.installJson.frontend.defaultPort &&
477
- a.installJson.frontend.defaultPort > 0
478
- ? a.installJson.frontend.defaultPort
479
- : null),
480
- installJson: a.installJson,
481
- source: a.source,
482
- }));
483
- return { enabledApps, issues: loaded.issues };
437
+ const resolved = await materializeAppsResolution({ rtwsRootAbs: params.rtwsRootAbs });
438
+ return {
439
+ enabledApps: resolved.resolutionFile.apps
440
+ .filter((app) => app.enabled)
441
+ .map((app) => ({
442
+ id: app.id,
443
+ runtimePort: getRuntimePort(app),
444
+ installJson: app.installJson,
445
+ source: app.source,
446
+ })),
447
+ issues: resolved.issues,
448
+ };
484
449
  }