dominds 1.2.5 → 1.2.7

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 (149) hide show
  1. package/dist/agent-priming.js +2051 -0
  2. package/dist/apps/app-lock-file.js +228 -0
  3. package/dist/apps/assigned-port.js +124 -0
  4. package/dist/apps/enabled-apps.js +472 -7
  5. package/dist/apps/manifest.js +37 -0
  6. package/dist/apps/override-paths.js +19 -6
  7. package/dist/apps/problems.js +43 -0
  8. package/dist/apps/resolution-file.js +370 -0
  9. package/dist/apps/runtime.js +5 -17
  10. package/dist/apps/teammates.js +102 -1
  11. package/dist/cli/disable.js +10 -6
  12. package/dist/cli/enable.js +21 -19
  13. package/dist/cli/install.js +40 -18
  14. package/dist/cli/uninstall.js +6 -6
  15. package/dist/cli/update.js +38 -13
  16. package/dist/dialog.js +5 -0
  17. package/dist/docs/app-constitution.md +85 -18
  18. package/dist/docs/app-constitution.zh.md +86 -21
  19. package/dist/docs/dialog-system.md +1 -1
  20. package/dist/docs/dialog-system.zh.md +1 -1
  21. package/dist/docs/dominds-agent-priming.md +218 -0
  22. package/dist/docs/dominds-agent-priming.zh.md +196 -0
  23. package/dist/docs/drive-logic-context-refactor-plan.zh.md +338 -0
  24. package/dist/docs/keep-going.md +176 -0
  25. package/dist/docs/keep-going.zh.md +162 -0
  26. package/dist/docs/showing-by-doing.md +208 -0
  27. package/dist/docs/showing-by-doing.zh.md +177 -0
  28. package/dist/docs/team-mgmt-toolset.md +482 -0
  29. package/dist/docs/team-mgmt-toolset.zh.md +426 -0
  30. package/dist/llm/defaults.yaml +1 -1
  31. package/dist/llm/driver.js +4093 -0
  32. package/dist/llm/kernel-driver/drive.js +5 -2
  33. package/dist/llm/kernel-driver/flow.js +3 -0
  34. package/dist/minds/promptdocs.js +263 -0
  35. package/dist/problems.js +67 -16
  36. package/dist/server/api-routes.js +333 -0
  37. package/dist/server/prompts-routes.js +545 -0
  38. package/dist/server/server-core.js +4 -0
  39. package/dist/server/websocket-handler.js +17 -0
  40. package/dist/shared/team-mgmt-manual.js +120 -0
  41. package/dist/shared/types/prompts.js +2 -0
  42. package/dist/shared/types/tellask.js +8 -0
  43. package/dist/showing-by-doing.js +1091 -0
  44. package/dist/snippets/README.en.md +3 -0
  45. package/dist/snippets/README.md +4 -0
  46. package/dist/static/assets/{_basePickBy-CF9r08iy.js → _basePickBy-BMCtwrV7.js} +3 -3
  47. package/dist/static/assets/{_basePickBy-CF9r08iy.js.map → _basePickBy-BMCtwrV7.js.map} +1 -1
  48. package/dist/static/assets/{_baseUniq-CxKv0cd4.js → _baseUniq-BuyCgJiA.js} +2 -2
  49. package/dist/static/assets/{_baseUniq-CxKv0cd4.js.map → _baseUniq-BuyCgJiA.js.map} +1 -1
  50. package/dist/static/assets/{arc-C9JyvnlB.js → arc-BDuN8lwA.js} +2 -2
  51. package/dist/static/assets/{arc-C9JyvnlB.js.map → arc-BDuN8lwA.js.map} +1 -1
  52. package/dist/static/assets/{architectureDiagram-VXUJARFQ-CpcUgjHf.js → architectureDiagram-VXUJARFQ-C-ekqGAD.js} +7 -7
  53. package/dist/static/assets/{architectureDiagram-VXUJARFQ-CpcUgjHf.js.map → architectureDiagram-VXUJARFQ-C-ekqGAD.js.map} +1 -1
  54. package/dist/static/assets/{blockDiagram-VD42YOAC-BA9vtmm7.js → blockDiagram-VD42YOAC-CgQiNuuQ.js} +7 -7
  55. package/dist/static/assets/{blockDiagram-VD42YOAC-BA9vtmm7.js.map → blockDiagram-VD42YOAC-CgQiNuuQ.js.map} +1 -1
  56. package/dist/static/assets/{c4Diagram-YG6GDRKO-D49MGNdF.js → c4Diagram-YG6GDRKO-DONC39q-.js} +3 -3
  57. package/dist/static/assets/{c4Diagram-YG6GDRKO-D49MGNdF.js.map → c4Diagram-YG6GDRKO-DONC39q-.js.map} +1 -1
  58. package/dist/static/assets/{channel-B4KzL0Kg.js → channel-CJTFwXIG.js} +2 -2
  59. package/dist/static/assets/{channel-B4KzL0Kg.js.map → channel-CJTFwXIG.js.map} +1 -1
  60. package/dist/static/assets/{chunk-4BX2VUAB-0F-1ayl0.js → chunk-4BX2VUAB-NaIy4uLJ.js} +2 -2
  61. package/dist/static/assets/{chunk-4BX2VUAB-0F-1ayl0.js.map → chunk-4BX2VUAB-NaIy4uLJ.js.map} +1 -1
  62. package/dist/static/assets/{chunk-55IACEB6-Dnl2HDTZ.js → chunk-55IACEB6-JUKI_Ayx.js} +2 -2
  63. package/dist/static/assets/{chunk-55IACEB6-Dnl2HDTZ.js.map → chunk-55IACEB6-JUKI_Ayx.js.map} +1 -1
  64. package/dist/static/assets/{chunk-B4BG7PRW-Bhx5RbkQ.js → chunk-B4BG7PRW-dIswFJDn.js} +5 -5
  65. package/dist/static/assets/{chunk-B4BG7PRW-Bhx5RbkQ.js.map → chunk-B4BG7PRW-dIswFJDn.js.map} +1 -1
  66. package/dist/static/assets/{chunk-DI55MBZ5-EYd1wL3E.js → chunk-DI55MBZ5-DU2b_N30.js} +4 -4
  67. package/dist/static/assets/{chunk-DI55MBZ5-EYd1wL3E.js.map → chunk-DI55MBZ5-DU2b_N30.js.map} +1 -1
  68. package/dist/static/assets/{chunk-FMBD7UC4-DAjkhhUU.js → chunk-FMBD7UC4-BgExcScw.js} +2 -2
  69. package/dist/static/assets/{chunk-FMBD7UC4-DAjkhhUU.js.map → chunk-FMBD7UC4-BgExcScw.js.map} +1 -1
  70. package/dist/static/assets/{chunk-QN33PNHL-CK6TY7IE.js → chunk-QN33PNHL-bitxyqh7.js} +2 -2
  71. package/dist/static/assets/{chunk-QN33PNHL-CK6TY7IE.js.map → chunk-QN33PNHL-bitxyqh7.js.map} +1 -1
  72. package/dist/static/assets/{chunk-QZHKN3VN-CketngiE.js → chunk-QZHKN3VN-Cor8u7DT.js} +2 -2
  73. package/dist/static/assets/{chunk-QZHKN3VN-CketngiE.js.map → chunk-QZHKN3VN-Cor8u7DT.js.map} +1 -1
  74. package/dist/static/assets/{chunk-TZMSLE5B-Bcuvqo45.js → chunk-TZMSLE5B-Aceoxav_.js} +2 -2
  75. package/dist/static/assets/{chunk-TZMSLE5B-Bcuvqo45.js.map → chunk-TZMSLE5B-Aceoxav_.js.map} +1 -1
  76. package/dist/static/assets/{classDiagram-2ON5EDUG-CaP4T3r4.js → classDiagram-2ON5EDUG-D1Q6a8Hg.js} +6 -6
  77. package/dist/static/assets/{classDiagram-2ON5EDUG-CaP4T3r4.js.map → classDiagram-2ON5EDUG-D1Q6a8Hg.js.map} +1 -1
  78. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-CaP4T3r4.js → classDiagram-v2-WZHVMYZB-D1Q6a8Hg.js} +6 -6
  79. package/dist/static/assets/{classDiagram-v2-WZHVMYZB-CaP4T3r4.js.map → classDiagram-v2-WZHVMYZB-D1Q6a8Hg.js.map} +1 -1
  80. package/dist/static/assets/{clone-C-JULvnG.js → clone-MlWbv1V0.js} +2 -2
  81. package/dist/static/assets/{clone-C-JULvnG.js.map → clone-MlWbv1V0.js.map} +1 -1
  82. package/dist/static/assets/{cose-bilkent-S5V4N54A-vXCmi_eC.js → cose-bilkent-S5V4N54A-DWPCXSrn.js} +2 -2
  83. package/dist/static/assets/{cose-bilkent-S5V4N54A-vXCmi_eC.js.map → cose-bilkent-S5V4N54A-DWPCXSrn.js.map} +1 -1
  84. package/dist/static/assets/{dagre-6UL2VRFP-bhGzX6kO.js → dagre-6UL2VRFP-C8ptQ9V3.js} +7 -7
  85. package/dist/static/assets/{dagre-6UL2VRFP-bhGzX6kO.js.map → dagre-6UL2VRFP-C8ptQ9V3.js.map} +1 -1
  86. package/dist/static/assets/{diagram-PSM6KHXK-BUKfmfGk.js → diagram-PSM6KHXK-Bgf1FqkE.js} +8 -8
  87. package/dist/static/assets/{diagram-PSM6KHXK-BUKfmfGk.js.map → diagram-PSM6KHXK-Bgf1FqkE.js.map} +1 -1
  88. package/dist/static/assets/{diagram-QEK2KX5R-DYlq3uFq.js → diagram-QEK2KX5R-BZ5xzofU.js} +7 -7
  89. package/dist/static/assets/{diagram-QEK2KX5R-DYlq3uFq.js.map → diagram-QEK2KX5R-BZ5xzofU.js.map} +1 -1
  90. package/dist/static/assets/{diagram-S2PKOQOG-CjxkLHWG.js → diagram-S2PKOQOG-Dwp47T9I.js} +7 -7
  91. package/dist/static/assets/{diagram-S2PKOQOG-CjxkLHWG.js.map → diagram-S2PKOQOG-Dwp47T9I.js.map} +1 -1
  92. package/dist/static/assets/{erDiagram-Q2GNP2WA-S3hR85On.js → erDiagram-Q2GNP2WA-Cx4weIHl.js} +5 -5
  93. package/dist/static/assets/{erDiagram-Q2GNP2WA-S3hR85On.js.map → erDiagram-Q2GNP2WA-Cx4weIHl.js.map} +1 -1
  94. package/dist/static/assets/{flowDiagram-NV44I4VS-aBmNMuQ0.js → flowDiagram-NV44I4VS-vNUuIeRk.js} +6 -6
  95. package/dist/static/assets/{flowDiagram-NV44I4VS-aBmNMuQ0.js.map → flowDiagram-NV44I4VS-vNUuIeRk.js.map} +1 -1
  96. package/dist/static/assets/{ganttDiagram-JELNMOA3-DJxXaiW1.js → ganttDiagram-JELNMOA3-BEfozJAr.js} +3 -3
  97. package/dist/static/assets/{ganttDiagram-JELNMOA3-DJxXaiW1.js.map → ganttDiagram-JELNMOA3-BEfozJAr.js.map} +1 -1
  98. package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-DEOBCM0G.js → gitGraphDiagram-V2S2FVAM-eHxwc3d9.js} +8 -8
  99. package/dist/static/assets/{gitGraphDiagram-V2S2FVAM-DEOBCM0G.js.map → gitGraphDiagram-V2S2FVAM-eHxwc3d9.js.map} +1 -1
  100. package/dist/static/assets/{graph-DwrKSIE7.js → graph-C6a6uAok.js} +3 -3
  101. package/dist/static/assets/{graph-DwrKSIE7.js.map → graph-C6a6uAok.js.map} +1 -1
  102. package/dist/static/assets/{index-HWTRvE2k.js → index-D3TQbAKh.js} +383 -59
  103. package/dist/static/assets/index-D3TQbAKh.js.map +1 -0
  104. package/dist/static/assets/{infoDiagram-HS3SLOUP-BH9kVuYd.js → infoDiagram-HS3SLOUP-CX0NiId3.js} +6 -6
  105. package/dist/static/assets/{infoDiagram-HS3SLOUP-BH9kVuYd.js.map → infoDiagram-HS3SLOUP-CX0NiId3.js.map} +1 -1
  106. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Dap7AcjR.js → journeyDiagram-XKPGCS4Q-C1IepPZ-.js} +5 -5
  107. package/dist/static/assets/{journeyDiagram-XKPGCS4Q-Dap7AcjR.js.map → journeyDiagram-XKPGCS4Q-C1IepPZ-.js.map} +1 -1
  108. package/dist/static/assets/{kanban-definition-3W4ZIXB7-4NOl8MEj.js → kanban-definition-3W4ZIXB7-uMNX4Z1W.js} +3 -3
  109. package/dist/static/assets/{kanban-definition-3W4ZIXB7-4NOl8MEj.js.map → kanban-definition-3W4ZIXB7-uMNX4Z1W.js.map} +1 -1
  110. package/dist/static/assets/{layout-D6uIxu1E.js → layout-CpE3kk5z.js} +5 -5
  111. package/dist/static/assets/{layout-D6uIxu1E.js.map → layout-CpE3kk5z.js.map} +1 -1
  112. package/dist/static/assets/{linear-CvBOGQA2.js → linear-DV8laXr9.js} +2 -2
  113. package/dist/static/assets/{linear-CvBOGQA2.js.map → linear-DV8laXr9.js.map} +1 -1
  114. package/dist/static/assets/{mindmap-definition-VGOIOE7T-ugsrLNY5.js → mindmap-definition-VGOIOE7T-CKjgVM9S.js} +4 -4
  115. package/dist/static/assets/{mindmap-definition-VGOIOE7T-ugsrLNY5.js.map → mindmap-definition-VGOIOE7T-CKjgVM9S.js.map} +1 -1
  116. package/dist/static/assets/{pieDiagram-ADFJNKIX-CdVZjM8g.js → pieDiagram-ADFJNKIX-BBonlNyT.js} +8 -8
  117. package/dist/static/assets/{pieDiagram-ADFJNKIX-CdVZjM8g.js.map → pieDiagram-ADFJNKIX-BBonlNyT.js.map} +1 -1
  118. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-A6m5lZKd.js → quadrantDiagram-AYHSOK5B-BTI8HbBu.js} +3 -3
  119. package/dist/static/assets/{quadrantDiagram-AYHSOK5B-A6m5lZKd.js.map → quadrantDiagram-AYHSOK5B-BTI8HbBu.js.map} +1 -1
  120. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-Cac3zSJH.js → requirementDiagram-UZGBJVZJ-ZtSr9Q5R.js} +4 -4
  121. package/dist/static/assets/{requirementDiagram-UZGBJVZJ-Cac3zSJH.js.map → requirementDiagram-UZGBJVZJ-ZtSr9Q5R.js.map} +1 -1
  122. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DXDdUUl1.js → sankeyDiagram-TZEHDZUN-DibLVGzg.js} +2 -2
  123. package/dist/static/assets/{sankeyDiagram-TZEHDZUN-DXDdUUl1.js.map → sankeyDiagram-TZEHDZUN-DibLVGzg.js.map} +1 -1
  124. package/dist/static/assets/{sequenceDiagram-WL72ISMW-Domsjl5Y.js → sequenceDiagram-WL72ISMW-qXatfzVt.js} +4 -4
  125. package/dist/static/assets/{sequenceDiagram-WL72ISMW-Domsjl5Y.js.map → sequenceDiagram-WL72ISMW-qXatfzVt.js.map} +1 -1
  126. package/dist/static/assets/{stateDiagram-FKZM4ZOC-Bu0lRQK1.js → stateDiagram-FKZM4ZOC-7fgxCQHo.js} +9 -9
  127. package/dist/static/assets/{stateDiagram-FKZM4ZOC-Bu0lRQK1.js.map → stateDiagram-FKZM4ZOC-7fgxCQHo.js.map} +1 -1
  128. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-D0K-n3ic.js → stateDiagram-v2-4FDKWEC3-DcWlOAnF.js} +5 -5
  129. package/dist/static/assets/{stateDiagram-v2-4FDKWEC3-D0K-n3ic.js.map → stateDiagram-v2-4FDKWEC3-DcWlOAnF.js.map} +1 -1
  130. package/dist/static/assets/{timeline-definition-IT6M3QCI-BGvpddwR.js → timeline-definition-IT6M3QCI-iX2MRdpY.js} +3 -3
  131. package/dist/static/assets/{timeline-definition-IT6M3QCI-BGvpddwR.js.map → timeline-definition-IT6M3QCI-iX2MRdpY.js.map} +1 -1
  132. package/dist/static/assets/{treemap-GDKQZRPO-BoOzOm2j.js → treemap-GDKQZRPO-AVRnyXu1.js} +5 -5
  133. package/dist/static/assets/{treemap-GDKQZRPO-BoOzOm2j.js.map → treemap-GDKQZRPO-AVRnyXu1.js.map} +1 -1
  134. package/dist/static/assets/{xychartDiagram-PRI3JC2R-C_h3_ICR.js → xychartDiagram-PRI3JC2R-DVYEo5aJ.js} +3 -3
  135. package/dist/static/assets/{xychartDiagram-PRI3JC2R-C_h3_ICR.js.map → xychartDiagram-PRI3JC2R-DVYEo5aJ.js.map} +1 -1
  136. package/dist/static/index.html +1 -1
  137. package/dist/team.js +52 -48
  138. package/dist/tellask.js +439 -0
  139. package/dist/tools/context-health.js +177 -0
  140. package/dist/tools/diag.js +583 -0
  141. package/dist/tools/fs.js +194 -68
  142. package/dist/tools/prompts/memory/en/principles.md +13 -5
  143. package/dist/tools/prompts/memory/en/tools.md +11 -36
  144. package/dist/tools/prompts/memory/zh/principles.md +18 -8
  145. package/dist/tools/prompts/memory/zh/tools.md +11 -36
  146. package/dist/tools/team-mgmt.js +3487 -0
  147. package/dist/utils/task-doc.js +236 -0
  148. package/package.json +1 -1
  149. package/dist/static/assets/index-HWTRvE2k.js.map +0 -1
@@ -0,0 +1,228 @@
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.APP_LOCK_REL_PATH = void 0;
7
+ exports.parseAppLockFile = parseAppLockFile;
8
+ exports.loadAppLockFile = loadAppLockFile;
9
+ exports.upsertLockedApp = upsertLockedApp;
10
+ exports.writeAppLockFileIfChanged = writeAppLockFileIfChanged;
11
+ const promises_1 = __importDefault(require("node:fs/promises"));
12
+ const node_path_1 = __importDefault(require("node:path"));
13
+ const node_util_1 = require("node:util");
14
+ const yaml_1 = __importDefault(require("yaml"));
15
+ exports.APP_LOCK_REL_PATH = node_path_1.default.join('.minds', 'app-lock.yaml');
16
+ function isRecord(v) {
17
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
18
+ }
19
+ function asString(v) {
20
+ return typeof v === 'string' ? v : null;
21
+ }
22
+ function asNullableString(v) {
23
+ if (v === null)
24
+ return null;
25
+ return typeof v === 'string' ? v : null;
26
+ }
27
+ function parseSource(v, at) {
28
+ if (!isRecord(v))
29
+ return { ok: false, errorText: `Invalid ${at}: expected object` };
30
+ const kind = asString(v['kind']);
31
+ if (kind !== 'npx' && kind !== 'local') {
32
+ return { ok: false, errorText: `Invalid ${at}.kind: expected 'npx'|'local'` };
33
+ }
34
+ if (kind === 'npx') {
35
+ const keys = Object.keys(v);
36
+ for (const k of keys) {
37
+ if (k !== 'kind' && k !== 'spec') {
38
+ return { ok: false, errorText: `Invalid ${at}: unknown key '${k}'` };
39
+ }
40
+ }
41
+ const spec = asString(v['spec']);
42
+ if (!spec || spec.trim() === '') {
43
+ return { ok: false, errorText: `Invalid ${at}.spec: required` };
44
+ }
45
+ return { ok: true, source: { kind, spec } };
46
+ }
47
+ const keys = Object.keys(v);
48
+ for (const k of keys) {
49
+ if (k !== 'kind' && k !== 'pathAbs') {
50
+ return { ok: false, errorText: `Invalid ${at}: unknown key '${k}'` };
51
+ }
52
+ }
53
+ const pathAbs = asString(v['pathAbs']);
54
+ if (!pathAbs || pathAbs.trim() === '') {
55
+ return { ok: false, errorText: `Invalid ${at}.pathAbs: required` };
56
+ }
57
+ return { ok: true, source: { kind, pathAbs } };
58
+ }
59
+ function parseEntry(v, at) {
60
+ if (!isRecord(v))
61
+ return { ok: false, errorText: `Invalid ${at}: expected object` };
62
+ const keys = Object.keys(v);
63
+ for (const k of keys) {
64
+ if (k !== 'id' && k !== 'source' && k !== 'package') {
65
+ return { ok: false, errorText: `Invalid ${at}: unknown key '${k}'` };
66
+ }
67
+ }
68
+ const id = asString(v['id']);
69
+ if (!id || id.trim() === '')
70
+ return { ok: false, errorText: `Invalid ${at}.id: required` };
71
+ const sourceParsed = parseSource(v['source'], `${at}.source`);
72
+ if (!sourceParsed.ok)
73
+ return sourceParsed;
74
+ const pkg = v['package'];
75
+ if (!isRecord(pkg)) {
76
+ return { ok: false, errorText: `Invalid ${at}.package: expected object` };
77
+ }
78
+ const pkgKeys = Object.keys(pkg);
79
+ for (const k of pkgKeys) {
80
+ if (k !== 'name' && k !== 'version') {
81
+ return { ok: false, errorText: `Invalid ${at}.package: unknown key '${k}'` };
82
+ }
83
+ }
84
+ const name = asString(pkg['name']);
85
+ if (!name || name.trim() === '') {
86
+ return { ok: false, errorText: `Invalid ${at}.package.name: required` };
87
+ }
88
+ const versionRaw = pkg['version'] ?? null;
89
+ const version = asNullableString(versionRaw);
90
+ if (version === null) {
91
+ if (versionRaw !== null) {
92
+ return { ok: false, errorText: `Invalid ${at}.package.version: expected string|null` };
93
+ }
94
+ }
95
+ else if (version.trim() === '') {
96
+ return { ok: false, errorText: `Invalid ${at}.package.version: must not be empty` };
97
+ }
98
+ return {
99
+ ok: true,
100
+ entry: {
101
+ id,
102
+ source: sourceParsed.source,
103
+ package: { name, version },
104
+ },
105
+ };
106
+ }
107
+ function canonicalizeLockFile(file) {
108
+ const byId = new Map();
109
+ for (const e of file.apps) {
110
+ if (byId.has(e.id)) {
111
+ throw new Error(`Invalid ${exports.APP_LOCK_REL_PATH}: duplicate app id '${e.id}'`);
112
+ }
113
+ byId.set(e.id, e);
114
+ }
115
+ const apps = [...byId.values()].sort((a, b) => a.id.localeCompare(b.id));
116
+ return { schemaVersion: 1, apps };
117
+ }
118
+ function parseAppLockFile(parsed, filePathAbs) {
119
+ if (!isRecord(parsed)) {
120
+ return { ok: false, errorText: `Invalid app-lock.yaml: expected object (${filePathAbs})` };
121
+ }
122
+ const keys = Object.keys(parsed);
123
+ for (const k of keys) {
124
+ if (k !== 'schemaVersion' && k !== 'apps') {
125
+ return { ok: false, errorText: `Invalid app-lock.yaml: unknown key '${k}' (${filePathAbs})` };
126
+ }
127
+ }
128
+ const schemaVersion = parsed['schemaVersion'];
129
+ if (schemaVersion !== 1) {
130
+ return {
131
+ ok: false,
132
+ errorText: `Unsupported app-lock.yaml schemaVersion: ${String(schemaVersion)} (${filePathAbs})`,
133
+ };
134
+ }
135
+ const appsRaw = parsed['apps'];
136
+ if (!Array.isArray(appsRaw)) {
137
+ return {
138
+ ok: false,
139
+ errorText: `Invalid app-lock.yaml: apps must be an array (${filePathAbs})`,
140
+ };
141
+ }
142
+ const apps = [];
143
+ for (let i = 0; i < appsRaw.length; i += 1) {
144
+ const e = parseEntry(appsRaw[i], `apps[${i}]`);
145
+ if (!e.ok)
146
+ return { ok: false, errorText: `${e.errorText} (${filePathAbs})` };
147
+ apps.push(e.entry);
148
+ }
149
+ try {
150
+ return { ok: true, file: canonicalizeLockFile({ schemaVersion: 1, apps }) };
151
+ }
152
+ catch (err) {
153
+ return {
154
+ ok: false,
155
+ errorText: `${err instanceof Error ? err.message : String(err)} (${filePathAbs})`,
156
+ };
157
+ }
158
+ }
159
+ async function loadAppLockFile(params) {
160
+ const filePathAbs = node_path_1.default.resolve(params.rtwsRootAbs, exports.APP_LOCK_REL_PATH);
161
+ let raw;
162
+ try {
163
+ raw = await promises_1.default.readFile(filePathAbs, 'utf-8');
164
+ }
165
+ catch (err) {
166
+ const isEnoent = typeof err === 'object' &&
167
+ err !== null &&
168
+ 'code' in err &&
169
+ err.code === 'ENOENT';
170
+ if (isEnoent) {
171
+ return { kind: 'ok', filePathAbs, exists: false, file: { schemaVersion: 1, apps: [] } };
172
+ }
173
+ return {
174
+ kind: 'error',
175
+ filePathAbs,
176
+ errorText: err instanceof Error ? err.message : String(err),
177
+ };
178
+ }
179
+ let parsed;
180
+ try {
181
+ parsed = yaml_1.default.parse(raw);
182
+ }
183
+ catch (err) {
184
+ return {
185
+ kind: 'error',
186
+ filePathAbs,
187
+ errorText: `Failed to parse YAML: ${err instanceof Error ? err.message : String(err)}`,
188
+ };
189
+ }
190
+ const lockParsed = parseAppLockFile(parsed, filePathAbs);
191
+ if (!lockParsed.ok)
192
+ return { kind: 'error', filePathAbs, errorText: lockParsed.errorText };
193
+ return { kind: 'ok', filePathAbs, exists: true, file: lockParsed.file };
194
+ }
195
+ function upsertLockedApp(params) {
196
+ const existingEntry = params.existing.apps.find((a) => a.id === params.next.id) ?? null;
197
+ if (existingEntry && (0, node_util_1.isDeepStrictEqual)(existingEntry, params.next))
198
+ return params.existing;
199
+ const apps = [...params.existing.apps];
200
+ const idx = apps.findIndex((a) => a.id === params.next.id);
201
+ if (idx >= 0)
202
+ apps[idx] = params.next;
203
+ else
204
+ apps.push(params.next);
205
+ return canonicalizeLockFile({ schemaVersion: 1, apps });
206
+ }
207
+ async function writeAppLockFileIfChanged(params) {
208
+ const canonical = canonicalizeLockFile(params.file);
209
+ const loaded = await loadAppLockFile({ rtwsRootAbs: params.rtwsRootAbs });
210
+ if (loaded.kind === 'error') {
211
+ // Avoid overwriting user edits if the existing file is corrupt.
212
+ throw new Error(`Failed to read ${exports.APP_LOCK_REL_PATH}: ${loaded.errorText}`);
213
+ }
214
+ if (loaded.exists) {
215
+ const prevCanonical = canonicalizeLockFile(loaded.file);
216
+ if ((0, node_util_1.isDeepStrictEqual)(prevCanonical, canonical))
217
+ return;
218
+ }
219
+ else {
220
+ if (canonical.apps.length === 0)
221
+ return;
222
+ }
223
+ const mindsDirAbs = node_path_1.default.resolve(params.rtwsRootAbs, '.minds');
224
+ await promises_1.default.mkdir(mindsDirAbs, { recursive: true });
225
+ const filePathAbs = node_path_1.default.resolve(params.rtwsRootAbs, exports.APP_LOCK_REL_PATH);
226
+ const yamlText = yaml_1.default.stringify(canonical);
227
+ await promises_1.default.writeFile(filePathAbs, yamlText, 'utf-8');
228
+ }
@@ -0,0 +1,124 @@
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.resolveStableAssignedPort = resolveStableAssignedPort;
7
+ exports.resolveStableAssignedPortWithReason = resolveStableAssignedPortWithReason;
8
+ const node_net_1 = __importDefault(require("node:net"));
9
+ const STABLE_PORT_RANGE_START = 43000;
10
+ const STABLE_PORT_RANGE_END = 49999;
11
+ const PORT_MAX = 65535;
12
+ function isPositivePort(value) {
13
+ return (typeof value === 'number' &&
14
+ Number.isInteger(value) &&
15
+ value > 0 &&
16
+ value <= PORT_MAX &&
17
+ Number.isFinite(value));
18
+ }
19
+ function hashAppId(appId) {
20
+ // FNV-1a 32-bit hash for deterministic port probing order.
21
+ let hash = 0x811c9dc5;
22
+ for (let i = 0; i < appId.length; i += 1) {
23
+ hash ^= appId.charCodeAt(i);
24
+ hash = Math.imul(hash, 0x01000193);
25
+ }
26
+ return hash >>> 0;
27
+ }
28
+ function collectReservedPorts(existingApps, appId) {
29
+ const reserved = new Set();
30
+ for (const app of existingApps) {
31
+ if (app.id === appId)
32
+ continue;
33
+ if (isPositivePort(app.assignedPort)) {
34
+ reserved.add(app.assignedPort);
35
+ }
36
+ }
37
+ return reserved;
38
+ }
39
+ async function canBindPort(port) {
40
+ return await new Promise((resolve) => {
41
+ const server = node_net_1.default.createServer();
42
+ server.unref();
43
+ const finish = (ok) => {
44
+ server.removeAllListeners('error');
45
+ server.removeAllListeners('listening');
46
+ resolve(ok);
47
+ };
48
+ server.once('error', () => {
49
+ finish(false);
50
+ });
51
+ server.once('listening', () => {
52
+ server.close(() => finish(true));
53
+ });
54
+ server.listen({ host: '127.0.0.1', port, exclusive: true });
55
+ });
56
+ }
57
+ async function pickDeterministicAvailablePort(params) {
58
+ const rangeSize = STABLE_PORT_RANGE_END - STABLE_PORT_RANGE_START + 1;
59
+ if (rangeSize <= 0) {
60
+ throw new Error('Invalid stable app port range configuration');
61
+ }
62
+ const baseHash = hashAppId(params.appId);
63
+ for (let i = 0; i < rangeSize; i += 1) {
64
+ const candidate = STABLE_PORT_RANGE_START + ((baseHash + i) % rangeSize);
65
+ if (params.reservedPorts.has(candidate))
66
+ continue;
67
+ if (await canBindPort(candidate))
68
+ return candidate;
69
+ }
70
+ throw new Error(`Failed to allocate stable assignedPort for app '${params.appId}': no bindable port in ${STABLE_PORT_RANGE_START}-${STABLE_PORT_RANGE_END}`);
71
+ }
72
+ /**
73
+ * Resolve a stable non-zero assignedPort for an app frontend.
74
+ *
75
+ * - If the app has no frontend, returns null.
76
+ * - If an existing assignedPort exists, keeps it when still valid/bindable.
77
+ * - If existing assignedPort collides or is not bindable, reassigns deterministically.
78
+ * - Otherwise, tries installJson.frontend.defaultPort when it is bindable.
79
+ * - Falls back to a deterministic stable-range allocator.
80
+ */
81
+ async function resolveStableAssignedPort(params) {
82
+ const resolved = await resolveStableAssignedPortWithReason(params);
83
+ return resolved.assignedPort;
84
+ }
85
+ async function resolveStableAssignedPortWithReason(params) {
86
+ if (!params.installJson.frontend) {
87
+ return { assignedPort: null, reason: 'no_frontend' };
88
+ }
89
+ const reservedPorts = collectReservedPorts(params.existingApps, params.appId);
90
+ if (isPositivePort(params.existingAssignedPort)) {
91
+ if (reservedPorts.has(params.existingAssignedPort)) {
92
+ return {
93
+ assignedPort: await pickDeterministicAvailablePort({
94
+ appId: params.appId,
95
+ reservedPorts,
96
+ }),
97
+ reason: 'reassigned_from_existing_conflict',
98
+ };
99
+ }
100
+ if (!(await canBindPort(params.existingAssignedPort))) {
101
+ return {
102
+ assignedPort: await pickDeterministicAvailablePort({
103
+ appId: params.appId,
104
+ reservedPorts,
105
+ }),
106
+ reason: 'reassigned_from_existing_unbindable',
107
+ };
108
+ }
109
+ return { assignedPort: params.existingAssignedPort, reason: 'kept_existing' };
110
+ }
111
+ const defaultPort = params.installJson.frontend.defaultPort;
112
+ if (isPositivePort(defaultPort) &&
113
+ !reservedPorts.has(defaultPort) &&
114
+ (await canBindPort(defaultPort))) {
115
+ return { assignedPort: defaultPort, reason: 'selected_default' };
116
+ }
117
+ return {
118
+ assignedPort: await pickDeterministicAvailablePort({
119
+ appId: params.appId,
120
+ reservedPorts,
121
+ }),
122
+ reason: 'allocated_stable_range',
123
+ };
124
+ }