dominds 1.25.13 → 1.25.15

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 (119) hide show
  1. package/dist/dialog-display-state.d.ts +4 -2
  2. package/dist/dialog-display-state.js +26 -6
  3. package/dist/llm/kernel-driver/drive.js +15 -0
  4. package/dist/llm/kernel-driver/flow.js +3 -0
  5. package/dist/llm/kernel-driver/sideDialog.js +1 -9
  6. package/dist/mcp/supervisor.js +2 -4
  7. package/dist/minds/system-prompt.js +4 -4
  8. package/dist/runtime/driver-messages.d.ts +5 -0
  9. package/dist/runtime/driver-messages.js +103 -59
  10. package/dist/server/api-routes.js +5 -8
  11. package/dist/server/dominds-self-update.js +584 -106
  12. package/dist/server/websocket-handler.js +5 -15
  13. package/dist/tools/app-reminders.js +6 -6
  14. package/dist/tools/cmd-runner-protocol.d.ts +1 -0
  15. package/dist/tools/cmd-runner-protocol.js +8 -1
  16. package/dist/tools/cmd-runner.js +33 -6
  17. package/dist/tools/mcp.js +2 -8
  18. package/dist/tools/os.js +27 -22
  19. package/dist/tools/pending-tellask-reminder.js +10 -10
  20. package/dist/tools/process-kill.d.ts +4 -0
  21. package/dist/tools/process-kill.js +48 -0
  22. package/dist/tools/prompts/os/en/tools.md +2 -2
  23. package/dist/tools/prompts/os/zh/tools.md +2 -2
  24. package/package.json +4 -4
  25. package/webapp/dist/assets/{_basePickBy-B1-brAPU.js → _basePickBy-bB-pfQPi.js} +3 -3
  26. package/webapp/dist/assets/{_basePickBy-B1-brAPU.js.map → _basePickBy-bB-pfQPi.js.map} +1 -1
  27. package/webapp/dist/assets/{_baseUniq-BuB0jmKD.js → _baseUniq-CGrWBZre.js} +2 -2
  28. package/webapp/dist/assets/{_baseUniq-BuB0jmKD.js.map → _baseUniq-CGrWBZre.js.map} +1 -1
  29. package/webapp/dist/assets/{arc-CvsBvjnB.js → arc-I9vbIaKk.js} +2 -2
  30. package/webapp/dist/assets/{arc-CvsBvjnB.js.map → arc-I9vbIaKk.js.map} +1 -1
  31. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-B-xGuLbb.js → architectureDiagram-2XIMDMQ5-CrwjTxLz.js} +7 -7
  32. package/webapp/dist/assets/{architectureDiagram-2XIMDMQ5-B-xGuLbb.js.map → architectureDiagram-2XIMDMQ5-CrwjTxLz.js.map} +1 -1
  33. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-Bu53fwsa.js → blockDiagram-WCTKOSBZ-DTm0qfvP.js} +7 -7
  34. package/webapp/dist/assets/{blockDiagram-WCTKOSBZ-Bu53fwsa.js.map → blockDiagram-WCTKOSBZ-DTm0qfvP.js.map} +1 -1
  35. package/webapp/dist/assets/{c4Diagram-IC4MRINW-D9-FJ4LB.js → c4Diagram-IC4MRINW-DwRQtzZF.js} +3 -3
  36. package/webapp/dist/assets/{c4Diagram-IC4MRINW-D9-FJ4LB.js.map → c4Diagram-IC4MRINW-DwRQtzZF.js.map} +1 -1
  37. package/webapp/dist/assets/{channel-D1VPurpu.js → channel-BHLOwBnI.js} +2 -2
  38. package/webapp/dist/assets/{channel-D1VPurpu.js.map → channel-BHLOwBnI.js.map} +1 -1
  39. package/webapp/dist/assets/{chunk-4BX2VUAB-DB14wcWS.js → chunk-4BX2VUAB-C-uXnDVV.js} +2 -2
  40. package/webapp/dist/assets/{chunk-4BX2VUAB-DB14wcWS.js.map → chunk-4BX2VUAB-C-uXnDVV.js.map} +1 -1
  41. package/webapp/dist/assets/{chunk-55IACEB6-C5KCE85A.js → chunk-55IACEB6-Dq9BI2N6.js} +2 -2
  42. package/webapp/dist/assets/{chunk-55IACEB6-C5KCE85A.js.map → chunk-55IACEB6-Dq9BI2N6.js.map} +1 -1
  43. package/webapp/dist/assets/{chunk-FMBD7UC4-Bb6zm0iH.js → chunk-FMBD7UC4-DR9kFZOV.js} +2 -2
  44. package/webapp/dist/assets/{chunk-FMBD7UC4-Bb6zm0iH.js.map → chunk-FMBD7UC4-DR9kFZOV.js.map} +1 -1
  45. package/webapp/dist/assets/{chunk-JSJVCQXG-CJPrv6fM.js → chunk-JSJVCQXG-xnc6SVE5.js} +2 -2
  46. package/webapp/dist/assets/{chunk-JSJVCQXG-CJPrv6fM.js.map → chunk-JSJVCQXG-xnc6SVE5.js.map} +1 -1
  47. package/webapp/dist/assets/{chunk-KX2RTZJC-8J1Swk7E.js → chunk-KX2RTZJC-rUxlh4aS.js} +2 -2
  48. package/webapp/dist/assets/{chunk-KX2RTZJC-8J1Swk7E.js.map → chunk-KX2RTZJC-rUxlh4aS.js.map} +1 -1
  49. package/webapp/dist/assets/{chunk-NQ4KR5QH-DySHY4x9.js → chunk-NQ4KR5QH-BGU4PhTQ.js} +4 -4
  50. package/webapp/dist/assets/{chunk-NQ4KR5QH-DySHY4x9.js.map → chunk-NQ4KR5QH-BGU4PhTQ.js.map} +1 -1
  51. package/webapp/dist/assets/{chunk-QZHKN3VN-CTO5Z-4P.js → chunk-QZHKN3VN-CAlu4xE7.js} +2 -2
  52. package/webapp/dist/assets/{chunk-QZHKN3VN-CTO5Z-4P.js.map → chunk-QZHKN3VN-CAlu4xE7.js.map} +1 -1
  53. package/webapp/dist/assets/{chunk-WL4C6EOR-Ci_Ec8Ax.js → chunk-WL4C6EOR-zZXRkBBY.js} +6 -6
  54. package/webapp/dist/assets/{chunk-WL4C6EOR-Ci_Ec8Ax.js.map → chunk-WL4C6EOR-zZXRkBBY.js.map} +1 -1
  55. package/webapp/dist/assets/{classDiagram-VBA2DB6C-CxAxBvv7.js → classDiagram-VBA2DB6C-DI1CfOtL.js} +7 -7
  56. package/webapp/dist/assets/{classDiagram-VBA2DB6C-CxAxBvv7.js.map → classDiagram-VBA2DB6C-DI1CfOtL.js.map} +1 -1
  57. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-CxAxBvv7.js → classDiagram-v2-RAHNMMFH-DI1CfOtL.js} +7 -7
  58. package/webapp/dist/assets/{classDiagram-v2-RAHNMMFH-CxAxBvv7.js.map → classDiagram-v2-RAHNMMFH-DI1CfOtL.js.map} +1 -1
  59. package/webapp/dist/assets/{clone-ePiNaiNY.js → clone-quTqCNPA.js} +2 -2
  60. package/webapp/dist/assets/{clone-ePiNaiNY.js.map → clone-quTqCNPA.js.map} +1 -1
  61. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-j-Ex-Sef.js → cose-bilkent-S5V4N54A-BY28yO7Y.js} +2 -2
  62. package/webapp/dist/assets/{cose-bilkent-S5V4N54A-j-Ex-Sef.js.map → cose-bilkent-S5V4N54A-BY28yO7Y.js.map} +1 -1
  63. package/webapp/dist/assets/{dagre-KLK3FWXG-ihZ2wOCM.js → dagre-KLK3FWXG-DLyZ54D-.js} +7 -7
  64. package/webapp/dist/assets/{dagre-KLK3FWXG-ihZ2wOCM.js.map → dagre-KLK3FWXG-DLyZ54D-.js.map} +1 -1
  65. package/webapp/dist/assets/{diagram-E7M64L7V-Cp4GQGS7.js → diagram-E7M64L7V-CD-HWZAJ.js} +8 -8
  66. package/webapp/dist/assets/{diagram-E7M64L7V-Cp4GQGS7.js.map → diagram-E7M64L7V-CD-HWZAJ.js.map} +1 -1
  67. package/webapp/dist/assets/{diagram-IFDJBPK2-B70cgyS5.js → diagram-IFDJBPK2-BHOQ9HH2.js} +7 -7
  68. package/webapp/dist/assets/{diagram-IFDJBPK2-B70cgyS5.js.map → diagram-IFDJBPK2-BHOQ9HH2.js.map} +1 -1
  69. package/webapp/dist/assets/{diagram-P4PSJMXO-DMOv7eKE.js → diagram-P4PSJMXO-OEPgBDcD.js} +7 -7
  70. package/webapp/dist/assets/{diagram-P4PSJMXO-DMOv7eKE.js.map → diagram-P4PSJMXO-OEPgBDcD.js.map} +1 -1
  71. package/webapp/dist/assets/{erDiagram-INFDFZHY-BKpXWjIc.js → erDiagram-INFDFZHY-Dcgo204J.js} +5 -5
  72. package/webapp/dist/assets/{erDiagram-INFDFZHY-BKpXWjIc.js.map → erDiagram-INFDFZHY-Dcgo204J.js.map} +1 -1
  73. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-DgrItj0h.js → flowDiagram-PKNHOUZH-CWLo3Lkf.js} +7 -7
  74. package/webapp/dist/assets/{flowDiagram-PKNHOUZH-DgrItj0h.js.map → flowDiagram-PKNHOUZH-CWLo3Lkf.js.map} +1 -1
  75. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-7-8hlYsT.js → ganttDiagram-A5KZAMGK-DWXL4ZD6.js} +3 -3
  76. package/webapp/dist/assets/{ganttDiagram-A5KZAMGK-7-8hlYsT.js.map → ganttDiagram-A5KZAMGK-DWXL4ZD6.js.map} +1 -1
  77. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-cPSaCUUk.js → gitGraphDiagram-K3NZZRJ6-7iLQbTrH.js} +8 -8
  78. package/webapp/dist/assets/{gitGraphDiagram-K3NZZRJ6-cPSaCUUk.js.map → gitGraphDiagram-K3NZZRJ6-7iLQbTrH.js.map} +1 -1
  79. package/webapp/dist/assets/{graph-CAlg3tEk.js → graph-Bq1MLNWN.js} +3 -3
  80. package/webapp/dist/assets/{graph-CAlg3tEk.js.map → graph-Bq1MLNWN.js.map} +1 -1
  81. package/webapp/dist/assets/{index-DLTS_eOh.js → index-r4An5YoX.js} +245 -60
  82. package/webapp/dist/assets/{index-DLTS_eOh.js.map → index-r4An5YoX.js.map} +1 -1
  83. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-CHJHvxMC.js → infoDiagram-LFFYTUFH-CoF5OE3_.js} +6 -6
  84. package/webapp/dist/assets/{infoDiagram-LFFYTUFH-CHJHvxMC.js.map → infoDiagram-LFFYTUFH-CoF5OE3_.js.map} +1 -1
  85. package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-S8N-XZ8E.js → ishikawaDiagram-PHBUUO56-iKggfQhA.js} +2 -2
  86. package/webapp/dist/assets/{ishikawaDiagram-PHBUUO56-S8N-XZ8E.js.map → ishikawaDiagram-PHBUUO56-iKggfQhA.js.map} +1 -1
  87. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-ChHNpMtH.js → journeyDiagram-4ABVD52K-NYDQ7_xv.js} +5 -5
  88. package/webapp/dist/assets/{journeyDiagram-4ABVD52K-ChHNpMtH.js.map → journeyDiagram-4ABVD52K-NYDQ7_xv.js.map} +1 -1
  89. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-Cqxd99wZ.js → kanban-definition-K7BYSVSG-YWCnJwk0.js} +3 -3
  90. package/webapp/dist/assets/{kanban-definition-K7BYSVSG-Cqxd99wZ.js.map → kanban-definition-K7BYSVSG-YWCnJwk0.js.map} +1 -1
  91. package/webapp/dist/assets/{layout-uOLcVthp.js → layout-CE6gccWy.js} +5 -5
  92. package/webapp/dist/assets/{layout-uOLcVthp.js.map → layout-CE6gccWy.js.map} +1 -1
  93. package/webapp/dist/assets/{linear-Ga_f4H_w.js → linear-12arIJK-.js} +2 -2
  94. package/webapp/dist/assets/{linear-Ga_f4H_w.js.map → linear-12arIJK-.js.map} +1 -1
  95. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-TSH7wOlZ.js → mindmap-definition-YRQLILUH-D_5iNhfP.js} +4 -4
  96. package/webapp/dist/assets/{mindmap-definition-YRQLILUH-TSH7wOlZ.js.map → mindmap-definition-YRQLILUH-D_5iNhfP.js.map} +1 -1
  97. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-DPXszqns.js → pieDiagram-SKSYHLDU-DCbLQaXM.js} +8 -8
  98. package/webapp/dist/assets/{pieDiagram-SKSYHLDU-DPXszqns.js.map → pieDiagram-SKSYHLDU-DCbLQaXM.js.map} +1 -1
  99. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-BgA_GVhR.js → quadrantDiagram-337W2JSQ-CVRDOyty.js} +3 -3
  100. package/webapp/dist/assets/{quadrantDiagram-337W2JSQ-BgA_GVhR.js.map → quadrantDiagram-337W2JSQ-CVRDOyty.js.map} +1 -1
  101. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-CM-47daj.js → requirementDiagram-Z7DCOOCP-iBpmayOS.js} +4 -4
  102. package/webapp/dist/assets/{requirementDiagram-Z7DCOOCP-CM-47daj.js.map → requirementDiagram-Z7DCOOCP-iBpmayOS.js.map} +1 -1
  103. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-CxDCwHAj.js → sankeyDiagram-WA2Y5GQK-DqzWCtib.js} +2 -2
  104. package/webapp/dist/assets/{sankeyDiagram-WA2Y5GQK-CxDCwHAj.js.map → sankeyDiagram-WA2Y5GQK-DqzWCtib.js.map} +1 -1
  105. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-1UJP6Fff.js → sequenceDiagram-2WXFIKYE-DHzt-u2j.js} +4 -4
  106. package/webapp/dist/assets/{sequenceDiagram-2WXFIKYE-1UJP6Fff.js.map → sequenceDiagram-2WXFIKYE-DHzt-u2j.js.map} +1 -1
  107. package/webapp/dist/assets/{stateDiagram-RAJIS63D-B2aqr0KQ.js → stateDiagram-RAJIS63D-D14FagfU.js} +9 -9
  108. package/webapp/dist/assets/{stateDiagram-RAJIS63D-B2aqr0KQ.js.map → stateDiagram-RAJIS63D-D14FagfU.js.map} +1 -1
  109. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-DvmkevVb.js → stateDiagram-v2-FVOUBMTO-CZRolF-A.js} +5 -5
  110. package/webapp/dist/assets/{stateDiagram-v2-FVOUBMTO-DvmkevVb.js.map → stateDiagram-v2-FVOUBMTO-CZRolF-A.js.map} +1 -1
  111. package/webapp/dist/assets/{timeline-definition-YZTLITO2-CaOrqzT1.js → timeline-definition-YZTLITO2-L4O4kc8p.js} +3 -3
  112. package/webapp/dist/assets/{timeline-definition-YZTLITO2-CaOrqzT1.js.map → timeline-definition-YZTLITO2-L4O4kc8p.js.map} +1 -1
  113. package/webapp/dist/assets/{treemap-KZPCXAKY-CWs_8GJm.js → treemap-KZPCXAKY-CvHKWhtl.js} +5 -5
  114. package/webapp/dist/assets/{treemap-KZPCXAKY-CWs_8GJm.js.map → treemap-KZPCXAKY-CvHKWhtl.js.map} +1 -1
  115. package/webapp/dist/assets/{vennDiagram-LZ73GAT5-BuBxFDz6.js → vennDiagram-LZ73GAT5-8sPBS5jq.js} +2 -2
  116. package/webapp/dist/assets/{vennDiagram-LZ73GAT5-BuBxFDz6.js.map → vennDiagram-LZ73GAT5-8sPBS5jq.js.map} +1 -1
  117. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-ChjL-_2b.js → xychartDiagram-JWTSCODW-CqLmOgCw.js} +3 -3
  118. package/webapp/dist/assets/{xychartDiagram-JWTSCODW-ChjL-_2b.js.map → xychartDiagram-JWTSCODW-CqLmOgCw.js.map} +1 -1
  119. package/webapp/dist/index.html +1 -1
@@ -21,7 +21,7 @@ const LATEST_VERSION_CHECK_TIMEOUT_MS = 60000;
21
21
  const RESTART_PORT_RELEASE_TIMEOUT_MS = 15000;
22
22
  const RESTART_PORT_PROBE_INTERVAL_MS = 150;
23
23
  const RESTART_EXIT_GRACE_MS = 1000;
24
- const RESTART_FORCE_KILL_AFTER_MS = 3000;
24
+ const RESTART_FORCE_KILL_AFTER_MS = 30000;
25
25
  const COMMAND_OUTPUT_LOG_LIMIT = 2000;
26
26
  const PROXY_URL_ENV_KEYS = new Set([
27
27
  'HTTP_PROXY',
@@ -32,12 +32,14 @@ const PROXY_URL_ENV_KEYS = new Set([
32
32
  'npm_config_https_proxy',
33
33
  ]);
34
34
  const IDLE_RESTART_STATE = { kind: 'idle' };
35
+ const PROCESS_START_CWD = process.cwd();
35
36
  let runtimeConfig = null;
36
37
  let latestObservation = { kind: 'unknown' };
37
38
  let backgroundCheckTimer = null;
38
39
  let installPromise = null;
39
40
  let restartPromise = null;
40
41
  let restartState = IDLE_RESTART_STATE;
42
+ let installFailureObservation = null;
41
43
  let broadcastStatusUpdate = null;
42
44
  function normalizeVersionString(value) {
43
45
  return value.trim().replace(/^v/i, '');
@@ -76,9 +78,9 @@ function detectRunKind(mode) {
76
78
  return 'disabled';
77
79
  const scriptPath = (process.argv[1] ?? '').replace(/\\/g, '/');
78
80
  if (scriptPath.includes('/_npx/') && scriptPath.includes('/node_modules/dominds/')) {
79
- return 'npx_latest';
81
+ return 'npx';
80
82
  }
81
- return 'npm_global';
83
+ return 'global';
82
84
  }
83
85
  function hasInteractiveConsole() {
84
86
  return Boolean(process.stdin.isTTY || process.stdout.isTTY || process.stderr.isTTY);
@@ -93,6 +95,94 @@ function getRestartPortProbeHost(host) {
93
95
  return '::1';
94
96
  return host;
95
97
  }
98
+ function normalizeComparablePath(value) {
99
+ const normalized = path_1.default.normalize(value);
100
+ return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
101
+ }
102
+ async function getComparableRealPath(absPath) {
103
+ try {
104
+ return normalizeComparablePath(await promises_1.default.realpath(absPath));
105
+ }
106
+ catch (error) {
107
+ const code = getStringErrorProp(error, 'code');
108
+ if (code === 'ENOENT')
109
+ return normalizeComparablePath(path_1.default.resolve(absPath));
110
+ throw error;
111
+ }
112
+ }
113
+ function getCurrentProcessEntrypoint() {
114
+ const entrypoint = process.argv[1];
115
+ if (typeof entrypoint !== 'string' || entrypoint.trim() === '') {
116
+ throw new Error('Cannot restart Dominds because the current process entrypoint is unavailable');
117
+ }
118
+ return entrypoint;
119
+ }
120
+ function buildCurrentProcessRestartArgs() {
121
+ getCurrentProcessEntrypoint();
122
+ return [...process.execArgv, ...process.argv.slice(1)];
123
+ }
124
+ function buildCurrentDomindsCliArgs() {
125
+ return process.argv.slice(2);
126
+ }
127
+ function getNpxWorkspaceDirAbs() {
128
+ const entrypoint = getCurrentProcessEntrypoint().replace(/\\/g, '/');
129
+ const marker = '/node_modules/dominds/';
130
+ const markerIndex = entrypoint.indexOf(marker);
131
+ if (markerIndex < 0)
132
+ return null;
133
+ const nodeModulesPrefix = entrypoint.slice(0, markerIndex);
134
+ const nodeModulesSuffix = '/node_modules';
135
+ if (!nodeModulesPrefix.endsWith(nodeModulesSuffix))
136
+ return null;
137
+ const workspaceDir = nodeModulesPrefix.slice(0, -nodeModulesSuffix.length);
138
+ if (workspaceDir.trim() === '')
139
+ return null;
140
+ return path_1.default.resolve(PROCESS_START_CWD, workspaceDir);
141
+ }
142
+ function parseNpxDomindsPackageSpec(spec) {
143
+ if (spec === 'dominds@latest')
144
+ return { kind: 'latest' };
145
+ if (spec === 'dominds')
146
+ return { kind: 'versionless' };
147
+ if (spec.startsWith('dominds@'))
148
+ return { kind: 'fixed', spec };
149
+ return null;
150
+ }
151
+ async function readNpxDomindsSpec() {
152
+ const workspaceDir = getNpxWorkspaceDirAbs();
153
+ if (workspaceDir === null)
154
+ return null;
155
+ const packageJsonPath = path_1.default.join(workspaceDir, 'package.json');
156
+ const raw = await promises_1.default.readFile(packageJsonPath, 'utf8');
157
+ const parsed = JSON.parse(raw);
158
+ if (!isRecord(parsed))
159
+ throw new Error(`Invalid npx package metadata at ${packageJsonPath}`);
160
+ const npxValue = parsed['_npx'];
161
+ const packagesValue = isRecord(npxValue) ? npxValue['packages'] : undefined;
162
+ if (!Array.isArray(packagesValue))
163
+ return null;
164
+ for (const packageSpec of packagesValue) {
165
+ if (typeof packageSpec !== 'string')
166
+ continue;
167
+ const parsedSpec = parseNpxDomindsPackageSpec(packageSpec.trim());
168
+ if (parsedSpec !== null)
169
+ return parsedSpec;
170
+ }
171
+ return null;
172
+ }
173
+ async function buildNpxLatestRestartLaunchSpec() {
174
+ const npm = await resolveNpmCommandSpec();
175
+ return {
176
+ command: npm.command,
177
+ args: [...npm.args, 'exec', '-y', '--', 'dominds@latest', ...buildCurrentDomindsCliArgs()],
178
+ };
179
+ }
180
+ function buildCurrentProcessRestartLaunchSpec() {
181
+ return {
182
+ command: process.execPath,
183
+ args: buildCurrentProcessRestartArgs(),
184
+ };
185
+ }
96
186
  function truncateCommandOutput(value) {
97
187
  const raw = typeof value === 'string' ? value.trim() : '';
98
188
  if (raw.length <= COMMAND_OUTPUT_LOG_LIMIT)
@@ -136,7 +226,7 @@ function redactProxyUrl(proxyUrl) {
136
226
  return proxyUrl.replace(/\/\/[^@/]+@/g, '//***@');
137
227
  }
138
228
  }
139
- function buildNpmCommandEnv() {
229
+ function buildPackageManagerCommandEnv() {
140
230
  const env = { ...process.env };
141
231
  const httpProxy = getEnvValue(env, 'HTTP_PROXY', 'http_proxy');
142
232
  const httpsProxy = getEnvValue(env, 'HTTPS_PROXY', 'https_proxy');
@@ -195,7 +285,7 @@ async function resolveNpmCommandSpec() {
195
285
  return {
196
286
  command: process.execPath,
197
287
  args: [candidate],
198
- display: `${process.execPath} ${candidate}`,
288
+ display: process.execPath + ' ' + candidate,
199
289
  };
200
290
  }
201
291
  catch {
@@ -203,10 +293,55 @@ async function resolveNpmCommandSpec() {
203
293
  }
204
294
  }
205
295
  if (process.platform === 'win32') {
206
- throw new Error(`Cannot find bundled npm CLI at ${candidates.join(', ')}. Dominds self-update avoids npm.cmd so the Windows console title is not hijacked.`);
296
+ throw new Error('Cannot find bundled npm CLI at ' +
297
+ candidates.join(', ') +
298
+ '. Dominds self-update avoids npm.cmd so the Windows console title is not hijacked.');
207
299
  }
208
300
  return { command: 'npm', args: [], display: 'npm' };
209
301
  }
302
+ async function resolveCorepackPnpmCommandSpec() {
303
+ const nodeDir = path_1.default.dirname(process.execPath);
304
+ const candidates = process.platform === 'win32'
305
+ ? [path_1.default.join(nodeDir, 'node_modules', 'corepack', 'dist', 'corepack.js')]
306
+ : [
307
+ path_1.default.join(nodeDir, '..', 'lib', 'node_modules', 'corepack', 'dist', 'corepack.js'),
308
+ path_1.default.join(nodeDir, '..', 'share', 'nodejs', 'corepack', 'dist', 'corepack.js'),
309
+ ];
310
+ for (const candidate of candidates) {
311
+ try {
312
+ await promises_1.default.access(candidate);
313
+ return {
314
+ command: process.execPath,
315
+ args: [candidate, 'pnpm'],
316
+ display: process.execPath + ' ' + candidate + ' pnpm',
317
+ };
318
+ }
319
+ catch {
320
+ continue;
321
+ }
322
+ }
323
+ return null;
324
+ }
325
+ async function resolvePnpmCommandSpec() {
326
+ const userAgent = process.env.npm_config_user_agent;
327
+ if (typeof userAgent === 'string' && userAgent.startsWith('pnpm/')) {
328
+ const npmExecpath = process.env.npm_execpath;
329
+ if (typeof npmExecpath === 'string' && npmExecpath.trim() !== '') {
330
+ return {
331
+ command: process.execPath,
332
+ args: [npmExecpath],
333
+ display: process.execPath + ' ' + npmExecpath,
334
+ };
335
+ }
336
+ }
337
+ const corepackPnpm = await resolveCorepackPnpmCommandSpec();
338
+ if (corepackPnpm !== null)
339
+ return corepackPnpm;
340
+ if (process.platform === 'win32') {
341
+ throw new Error('Cannot resolve pnpm CLI without pnpm npm_execpath or bundled Corepack on Windows');
342
+ }
343
+ return { command: 'pnpm', args: [], display: 'pnpm' };
344
+ }
210
345
  function getStringOrNumberErrorProp(error, key) {
211
346
  const value = getErrorProp(error, key);
212
347
  return typeof value === 'string' || typeof value === 'number' ? value : null;
@@ -244,36 +379,13 @@ function createCommandFailureError(params) {
244
379
  error.domindsProxyEnvSummary = params.proxyEnvSummary;
245
380
  return error;
246
381
  }
247
- async function runNpmCommand(args, params) {
248
- const env = buildNpmCommandEnv();
382
+ async function runPackageManagerCommand(commandSpec, args, params) {
383
+ const env = buildPackageManagerCommandEnv();
249
384
  const startedAtMs = Date.now();
250
- let npm;
251
- try {
252
- npm = await resolveNpmCommandSpec();
253
- }
254
- catch (error) {
255
- const fallbackCmd = ['npm', ...args].join(' ');
256
- throw createCommandFailureError({
257
- cmd: fallbackCmd,
258
- durationMs: Date.now() - startedAtMs,
259
- timeoutMs: params.timeoutMs,
260
- timedOut: false,
261
- outputExceeded: false,
262
- capturedOutputChars: 0,
263
- maxBuffer: params.maxBuffer,
264
- code: null,
265
- signal: null,
266
- killed: null,
267
- stdout: '',
268
- stderr: '',
269
- proxyEnvSummary: summarizeNpmProxyEnv(env),
270
- cause: error,
271
- });
272
- }
273
- const cmd = [npm.display, ...args].join(' ');
385
+ const cmd = [commandSpec.display, ...args].join(' ');
274
386
  return await new Promise((resolve, reject) => {
275
- const child = (0, child_process_1.spawn)(npm.command, [...npm.args, ...args], {
276
- cwd: process.cwd(),
387
+ const child = (0, child_process_1.spawn)(commandSpec.command, [...commandSpec.args, ...args], {
388
+ cwd: PROCESS_START_CWD,
277
389
  env,
278
390
  stdio: ['ignore', 'pipe', 'pipe'],
279
391
  windowsHide: true,
@@ -361,6 +473,56 @@ async function runNpmCommand(args, params) {
361
473
  });
362
474
  });
363
475
  }
476
+ async function runCurrentDomindsVersionProbe() {
477
+ const startedAtMs = Date.now();
478
+ const timeoutMs = 15000;
479
+ return await new Promise((resolve, reject) => {
480
+ const child = (0, child_process_1.spawn)(process.execPath, [getCurrentProcessEntrypoint(), '--version'], {
481
+ cwd: PROCESS_START_CWD,
482
+ env: process.env,
483
+ stdio: ['ignore', 'pipe', 'pipe'],
484
+ windowsHide: true,
485
+ shell: false,
486
+ });
487
+ let stdout = '';
488
+ let stderr = '';
489
+ let settled = false;
490
+ let timedOut = false;
491
+ const finish = (fn) => {
492
+ if (settled)
493
+ return;
494
+ settled = true;
495
+ fn();
496
+ };
497
+ const timer = setTimeout(() => {
498
+ timedOut = true;
499
+ child.kill('SIGTERM');
500
+ }, timeoutMs);
501
+ child.stdout?.on('data', (chunk) => {
502
+ stdout += chunk.toString('utf8');
503
+ });
504
+ child.stderr?.on('data', (chunk) => {
505
+ stderr += chunk.toString('utf8');
506
+ });
507
+ child.once('error', (error) => {
508
+ clearTimeout(timer);
509
+ finish(() => reject(error));
510
+ });
511
+ child.once('close', (code, signal) => {
512
+ clearTimeout(timer);
513
+ finish(() => {
514
+ if (code === 0) {
515
+ resolve({ stdout, stderr });
516
+ return;
517
+ }
518
+ const detail = timedOut
519
+ ? `timed out after ${String(Date.now() - startedAtMs)}ms`
520
+ : `exited with code=${String(code)} signal=${String(signal)}`;
521
+ reject(new Error(`current Dominds entrypoint --version probe ${detail}; stdout=${truncateCommandOutput(stdout)} stderr=${truncateCommandOutput(stderr)}`));
522
+ });
523
+ });
524
+ });
525
+ }
364
526
  function getErrorProp(error, key) {
365
527
  if (typeof error !== 'object' || error === null)
366
528
  return undefined;
@@ -475,7 +637,7 @@ function formatCommandFailureForUi(diagnostics) {
475
637
  async function queryLatestVersion() {
476
638
  const checkedAt = (0, time_1.formatUnifiedTimestamp)(new Date());
477
639
  try {
478
- const { stdout } = await runNpmCommand(['view', 'dominds', 'version', '--json'], {
640
+ const { stdout } = await runPackageManagerCommand(await resolveNpmCommandSpec(), ['view', 'dominds', 'version', '--json'], {
479
641
  maxBuffer: 1024 * 1024,
480
642
  timeoutMs: LATEST_VERSION_CHECK_TIMEOUT_MS,
481
643
  });
@@ -520,20 +682,225 @@ async function queryLatestVersion() {
520
682
  };
521
683
  }
522
684
  }
523
- async function resolveGlobalDomindsCommandAbs() {
524
- const { stdout } = await runNpmCommand(['prefix', '-g'], {
685
+ async function findRunningDomindsPackageRootAbs() {
686
+ const scriptPath = process.argv[1];
687
+ if (typeof scriptPath !== 'string' || scriptPath.trim() === '')
688
+ return null;
689
+ const scriptPathAbs = path_1.default.isAbsolute(scriptPath)
690
+ ? scriptPath
691
+ : path_1.default.resolve(PROCESS_START_CWD, scriptPath);
692
+ let currentDir = path_1.default.dirname(scriptPathAbs);
693
+ for (let depth = 0; depth < 8; depth++) {
694
+ const packageJsonPath = path_1.default.join(currentDir, 'package.json');
695
+ try {
696
+ const raw = await promises_1.default.readFile(packageJsonPath, 'utf8');
697
+ const parsed = JSON.parse(raw);
698
+ if (isRecord(parsed) && parsed.name === 'dominds')
699
+ return currentDir;
700
+ }
701
+ catch (error) {
702
+ const code = getStringErrorProp(error, 'code');
703
+ if (code !== 'ENOENT')
704
+ throw error;
705
+ }
706
+ const parentDir = path_1.default.dirname(currentDir);
707
+ if (parentDir === currentDir)
708
+ return null;
709
+ currentDir = parentDir;
710
+ }
711
+ return null;
712
+ }
713
+ async function readPackageVersionFromPackageJson(packageJsonPath) {
714
+ try {
715
+ const raw = await promises_1.default.readFile(packageJsonPath, 'utf8');
716
+ const parsed = JSON.parse(raw);
717
+ if (!isRecord(parsed) || typeof parsed.version !== 'string' || parsed.version.trim() === '') {
718
+ throw new Error(`Invalid Dominds package metadata at ${packageJsonPath}`);
719
+ }
720
+ return parsed.version.trim();
721
+ }
722
+ catch (error) {
723
+ const code = getStringErrorProp(error, 'code');
724
+ if (code === 'ENOENT')
725
+ return null;
726
+ throw error;
727
+ }
728
+ }
729
+ async function readCurrentDomindsPackageRootAbs() {
730
+ const runningPackageRoot = await findRunningDomindsPackageRootAbs();
731
+ if (runningPackageRoot === null) {
732
+ throw new Error('Cannot find package.json for the current Dominds process entrypoint');
733
+ }
734
+ return runningPackageRoot;
735
+ }
736
+ async function readCurrentDomindsPackageVersion() {
737
+ const runningPackageRoot = await readCurrentDomindsPackageRootAbs();
738
+ const packageJsonPath = path_1.default.join(runningPackageRoot, 'package.json');
739
+ const version = await readPackageVersionFromPackageJson(packageJsonPath);
740
+ if (version === null) {
741
+ throw new Error(`Cannot read current Dominds package metadata at ${packageJsonPath}`);
742
+ }
743
+ return version;
744
+ }
745
+ function parsePackageManagerRoot(stdout) {
746
+ const lines = stdout
747
+ .split(/\r?\n/u)
748
+ .map((line) => line.trim())
749
+ .filter((line) => line !== '');
750
+ const npmRoot = lines[lines.length - 1];
751
+ if (npmRoot === undefined) {
752
+ throw new Error('package manager root -g returned empty stdout');
753
+ }
754
+ return npmRoot;
755
+ }
756
+ async function readSymlinkTargetAbs(absPath) {
757
+ try {
758
+ const stat = await promises_1.default.lstat(absPath);
759
+ if (!stat.isSymbolicLink())
760
+ return null;
761
+ const target = await promises_1.default.readlink(absPath);
762
+ return path_1.default.isAbsolute(target) ? target : path_1.default.resolve(path_1.default.dirname(absPath), target);
763
+ }
764
+ catch (error) {
765
+ const code = getStringErrorProp(error, 'code');
766
+ if (code === 'ENOENT')
767
+ return null;
768
+ throw error;
769
+ }
770
+ }
771
+ function isSameOrInsidePath(childAbs, parentAbs) {
772
+ const childComparable = normalizeComparablePath(path_1.default.resolve(childAbs));
773
+ const parentComparable = normalizeComparablePath(path_1.default.resolve(parentAbs));
774
+ if (childComparable === parentComparable)
775
+ return true;
776
+ const relative = path_1.default.relative(parentComparable, childComparable);
777
+ return relative !== '' && !relative.startsWith('..') && !path_1.default.isAbsolute(relative);
778
+ }
779
+ async function readGlobalRootAbs(commandSpec) {
780
+ const rootResult = await runPackageManagerCommand(commandSpec, ['root', '-g'], {
525
781
  maxBuffer: 1024 * 1024,
526
782
  timeoutMs: 15000,
527
783
  });
528
- const prefix = stdout.trim();
529
- if (prefix === '') {
530
- throw new Error('npm prefix -g returned empty output');
784
+ return path_1.default.resolve(PROCESS_START_CWD, parsePackageManagerRoot(rootResult.stdout));
785
+ }
786
+ async function verifyGlobalInstallTargetsCurrentPackage() {
787
+ let currentPackageRootAbs = null;
788
+ const checkedTargets = [];
789
+ try {
790
+ currentPackageRootAbs = await readCurrentDomindsPackageRootAbs();
791
+ const currentComparable = await getComparableRealPath(currentPackageRootAbs);
792
+ const managers = ['npm', 'pnpm'];
793
+ for (const manager of managers) {
794
+ try {
795
+ const commandSpec = manager === 'pnpm' ? await resolvePnpmCommandSpec() : await resolveNpmCommandSpec();
796
+ const managerGlobalRootAbs = await readGlobalRootAbs(commandSpec);
797
+ const managerPackageRootAbs = path_1.default.join(managerGlobalRootAbs, 'dominds');
798
+ checkedTargets.push(manager + ':' + managerPackageRootAbs);
799
+ const symlinkTargetAbs = await readSymlinkTargetAbs(managerPackageRootAbs);
800
+ if (symlinkTargetAbs !== null &&
801
+ !isSameOrInsidePath(symlinkTargetAbs, managerGlobalRootAbs)) {
802
+ checkedTargets.push(manager + ':linked:' + symlinkTargetAbs);
803
+ continue;
804
+ }
805
+ const managerComparable = await getComparableRealPath(managerPackageRootAbs);
806
+ if (currentComparable === managerComparable) {
807
+ return {
808
+ kind: 'ok',
809
+ manager,
810
+ currentPackageRootAbs,
811
+ managerPackageRootAbs,
812
+ };
813
+ }
814
+ }
815
+ catch (error) {
816
+ checkedTargets.push(manager + ':error:' + formatErrorForUi(error));
817
+ }
818
+ }
819
+ return {
820
+ kind: 'unsupported',
821
+ currentPackageRootAbs,
822
+ checkedTargets,
823
+ message: 'Automatic global update is disabled because neither npm nor pnpm global install target safely matches the current Dominds process at ' +
824
+ currentPackageRootAbs +
825
+ '. Checked: ' +
826
+ checkedTargets.join('; ') +
827
+ '.',
828
+ };
829
+ }
830
+ catch (error) {
831
+ return {
832
+ kind: 'unsupported',
833
+ currentPackageRootAbs,
834
+ checkedTargets,
835
+ message: 'Automatic global update is disabled because the global install target could not be verified: ' +
836
+ formatErrorForUi(error),
837
+ };
838
+ }
839
+ }
840
+ function buildGlobalInstallArgs(manager) {
841
+ return manager === 'pnpm' ? ['add', '-g', 'dominds@latest'] : ['i', '-g', 'dominds@latest'];
842
+ }
843
+ async function buildGlobalInstallCommandSpec(manager) {
844
+ return manager === 'pnpm' ? await resolvePnpmCommandSpec() : await resolveNpmCommandSpec();
845
+ }
846
+ function parseDomindsVersionProbe(stdout, stderr) {
847
+ const combined = `${stdout}\n${stderr}`;
848
+ const match = /dominds\s+v([^\s]+)/i.exec(combined) ??
849
+ /\bv(\d+(?:\.\d+){1,3}(?:[-+][^\s]+)?)\b/i.exec(combined);
850
+ if (match === null)
851
+ return null;
852
+ return match[1].trim();
853
+ }
854
+ function formatErrorForUi(error) {
855
+ const diagnostics = extractCommandFailureDiagnostics(error);
856
+ if (diagnostics.cmd !== null || diagnostics.stdout !== '' || diagnostics.stderr !== '') {
857
+ return formatCommandFailureForUi(diagnostics);
858
+ }
859
+ return error instanceof Error ? error.message : String(error);
860
+ }
861
+ async function verifyInstalledDominds(targetVersion) {
862
+ let packageVersion = null;
863
+ let probeVersion = null;
864
+ try {
865
+ packageVersion = await readCurrentDomindsPackageVersion();
866
+ const probe = await runCurrentDomindsVersionProbe();
867
+ probeVersion = parseDomindsVersionProbe(probe.stdout, probe.stderr);
868
+ if (probeVersion === null) {
869
+ return {
870
+ kind: 'failed',
871
+ message: `Current Dominds entrypoint did not report a parseable version; stdout=${truncateCommandOutput(probe.stdout)} stderr=${truncateCommandOutput(probe.stderr)}`,
872
+ packageVersion,
873
+ probeVersion,
874
+ };
875
+ }
876
+ const packageProbeComparison = compareVersions(packageVersion, probeVersion);
877
+ const versionsMatch = packageProbeComparison !== null
878
+ ? packageProbeComparison === 0
879
+ : packageVersion === probeVersion;
880
+ const packageTargetComparison = compareVersions(packageVersion, targetVersion);
881
+ const probeTargetComparison = compareVersions(probeVersion, targetVersion);
882
+ const packageAtLeastTarget = packageTargetComparison !== null
883
+ ? packageTargetComparison >= 0
884
+ : packageVersion === targetVersion;
885
+ const probeAtLeastTarget = probeTargetComparison !== null ? probeTargetComparison >= 0 : probeVersion === targetVersion;
886
+ if (!versionsMatch || !packageAtLeastTarget || !probeAtLeastTarget) {
887
+ return {
888
+ kind: 'failed',
889
+ message: `Current Dominds entrypoint version verification failed; target=${targetVersion} package=${packageVersion} probe=${probeVersion}`,
890
+ packageVersion,
891
+ probeVersion,
892
+ };
893
+ }
894
+ return { kind: 'ok', packageVersion, probeVersion };
895
+ }
896
+ catch (error) {
897
+ return {
898
+ kind: 'failed',
899
+ message: error instanceof Error ? error.message : String(error),
900
+ packageVersion,
901
+ probeVersion,
902
+ };
531
903
  }
532
- const commandAbs = process.platform === 'win32'
533
- ? path_1.default.join(prefix, 'dominds.cmd')
534
- : path_1.default.join(prefix, 'bin', 'dominds');
535
- await promises_1.default.access(commandAbs);
536
- return commandAbs;
537
904
  }
538
905
  function clearBackgroundCheckTimer() {
539
906
  if (backgroundCheckTimer === null)
@@ -593,6 +960,7 @@ async function checkLatestDomindsVersionNow() {
593
960
  if (restartState.kind === 'restart_required' || restartState.kind === 'restarting') {
594
961
  return await getDomindsSelfUpdateStatus();
595
962
  }
963
+ installFailureObservation = null;
596
964
  latestObservation = await queryLatestVersion();
597
965
  publishStatusUpdateSoon();
598
966
  scheduleBackgroundCheck(BACKGROUND_CHECK_INTERVAL_MS);
@@ -630,6 +998,7 @@ function configureDomindsSelfUpdate(params) {
630
998
  };
631
999
  latestObservation = { kind: 'unknown' };
632
1000
  restartState = IDLE_RESTART_STATE;
1001
+ installFailureObservation = null;
633
1002
  clearBackgroundCheckTimer();
634
1003
  if (params.mode === 'production') {
635
1004
  scheduleBackgroundCheck(BACKGROUND_CHECK_INTERVAL_MS);
@@ -669,8 +1038,8 @@ async function getDomindsSelfUpdateStatus() {
669
1038
  runKind,
670
1039
  action: 'restart',
671
1040
  busy: 'idle',
672
- reason: 'restart_required',
673
- message: 'Latest Dominds is installed and waiting for restart',
1041
+ reason: restartState.reason,
1042
+ message: restartState.installReport ?? 'Latest Dominds is installed and waiting for restart',
674
1043
  targetVersion: restartState.installedVersion,
675
1044
  });
676
1045
  }
@@ -704,6 +1073,21 @@ async function getDomindsSelfUpdateStatus() {
704
1073
  targetVersion: latestObservation.kind === 'ok' ? latestObservation.latestVersion : null,
705
1074
  });
706
1075
  }
1076
+ if (installFailureObservation !== null) {
1077
+ return buildStatus({
1078
+ currentVersion: runningVersion,
1079
+ installedVersion: runningVersion,
1080
+ latestVersion: latestObservation.kind === 'ok' ? latestObservation.latestVersion : null,
1081
+ checkedAt: installFailureObservation.failedAt,
1082
+ mode: cfg.mode,
1083
+ runKind,
1084
+ action: latestObservation.kind === 'ok' ? 'install' : 'none',
1085
+ busy: 'idle',
1086
+ reason: 'install_failed',
1087
+ message: installFailureObservation.errorText,
1088
+ targetVersion: latestObservation.kind === 'ok' ? latestObservation.latestVersion : null,
1089
+ });
1090
+ }
707
1091
  if (restartPromise !== null) {
708
1092
  return buildStatus({
709
1093
  currentVersion: runningVersion,
@@ -766,7 +1150,27 @@ async function getDomindsSelfUpdateStatus() {
766
1150
  targetVersion: null,
767
1151
  });
768
1152
  }
769
- if (runKind === 'npx_latest') {
1153
+ if (runKind === 'npx') {
1154
+ const npxSpec = await readNpxDomindsSpec();
1155
+ if (npxSpec?.kind === 'latest') {
1156
+ return buildStatus({
1157
+ currentVersion: runningVersion,
1158
+ installedVersion: runningVersion,
1159
+ latestVersion: latestObservation.latestVersion,
1160
+ checkedAt: latestObservation.checkedAt,
1161
+ mode: cfg.mode,
1162
+ runKind,
1163
+ action: 'restart',
1164
+ busy: 'idle',
1165
+ reason: 'restart_required',
1166
+ message: 'Restart to relaunch Dominds via npx dominds@latest',
1167
+ targetVersion: latestObservation.latestVersion,
1168
+ });
1169
+ }
1170
+ const reason = npxSpec?.kind === 'fixed' ? 'npx_fixed_version_unsupported' : 'npx_versionless_unsupported';
1171
+ const message = npxSpec?.kind === 'fixed'
1172
+ ? `A newer Dominds version is available, but this npx session was launched with ${npxSpec.spec}; use dominds@latest to enable automatic restart updates.`
1173
+ : 'A newer Dominds version is available, but this npx session was launched without a verified dominds@latest spec; use dominds@latest to enable automatic restart updates.';
770
1174
  return buildStatus({
771
1175
  currentVersion: runningVersion,
772
1176
  installedVersion: runningVersion,
@@ -774,10 +1178,26 @@ async function getDomindsSelfUpdateStatus() {
774
1178
  checkedAt: latestObservation.checkedAt,
775
1179
  mode: cfg.mode,
776
1180
  runKind,
777
- action: 'restart',
1181
+ action: 'none',
778
1182
  busy: 'idle',
779
- reason: 'restart_available_via_npx',
780
- message: 'Restart to relaunch Dominds via npx latest',
1183
+ reason,
1184
+ message,
1185
+ targetVersion: latestObservation.latestVersion,
1186
+ });
1187
+ }
1188
+ const globalTargetVerification = await verifyGlobalInstallTargetsCurrentPackage();
1189
+ if (globalTargetVerification.kind === 'unsupported') {
1190
+ return buildStatus({
1191
+ currentVersion: runningVersion,
1192
+ installedVersion: runningVersion,
1193
+ latestVersion: latestObservation.latestVersion,
1194
+ checkedAt: latestObservation.checkedAt,
1195
+ mode: cfg.mode,
1196
+ runKind,
1197
+ action: 'none',
1198
+ busy: 'idle',
1199
+ reason: 'global_install_target_unsupported',
1200
+ message: globalTargetVerification.message,
781
1201
  targetVersion: latestObservation.latestVersion,
782
1202
  });
783
1203
  }
@@ -801,7 +1221,7 @@ async function installLatestDominds() {
801
1221
  throw new Error('Dominds self-update install is disabled in development mode');
802
1222
  }
803
1223
  const runKind = detectRunKind(cfg.mode);
804
- if (runKind !== 'npm_global') {
1224
+ if (runKind !== 'global') {
805
1225
  throw new Error(`Install action is not supported for runKind=${runKind}`);
806
1226
  }
807
1227
  if (restartState.kind === 'restart_required') {
@@ -814,49 +1234,100 @@ async function installLatestDominds() {
814
1234
  return await getDomindsSelfUpdateStatus();
815
1235
  }
816
1236
  installPromise = (async () => {
1237
+ installFailureObservation = null;
817
1238
  const runningVersion = getRunningVersion();
1239
+ const previouslyKnownLatest = latestObservation.kind === 'ok' ? latestObservation : null;
818
1240
  const latest = await queryLatestVersion();
819
- latestObservation = latest;
820
- if (latest.kind === 'error') {
1241
+ let targetVersion;
1242
+ if (latest.kind === 'ok') {
1243
+ latestObservation = latest;
1244
+ targetVersion = latest.latestVersion;
1245
+ }
1246
+ else if (previouslyKnownLatest === null) {
1247
+ latestObservation = latest;
821
1248
  throw new Error(latest.errorText);
822
1249
  }
823
- const comparison = compareVersions(runningVersion, latest.latestVersion);
824
- const hasUpdate = comparison !== null ? comparison < 0 : runningVersion !== latest.latestVersion;
1250
+ else {
1251
+ targetVersion = previouslyKnownLatest.latestVersion;
1252
+ log.warn('Dominds install latest-version refresh failed; continuing with previously known update target', undefined, {
1253
+ previousLatestVersion: previouslyKnownLatest.latestVersion,
1254
+ previousCheckedAt: previouslyKnownLatest.checkedAt,
1255
+ refreshErrorText: latest.errorText,
1256
+ refreshCheckedAt: latest.checkedAt,
1257
+ });
1258
+ }
1259
+ const comparison = compareVersions(runningVersion, targetVersion);
1260
+ const hasUpdate = comparison !== null ? comparison < 0 : runningVersion !== targetVersion;
825
1261
  if (!hasUpdate) {
826
1262
  throw new Error('No installable Dominds update is currently available');
827
1263
  }
828
- await runNpmCommand(['i', '-g', 'dominds@latest'], {
829
- maxBuffer: 20 * 1024 * 1024,
830
- timeoutMs: 10 * 60 * 1000,
831
- });
832
- const globalCommandAbs = await resolveGlobalDomindsCommandAbs();
1264
+ const globalTargetVerification = await verifyGlobalInstallTargetsCurrentPackage();
1265
+ if (globalTargetVerification.kind === 'unsupported') {
1266
+ throw new Error(globalTargetVerification.message);
1267
+ }
1268
+ let installCommandError = null;
1269
+ try {
1270
+ await runPackageManagerCommand(await buildGlobalInstallCommandSpec(globalTargetVerification.manager), buildGlobalInstallArgs(globalTargetVerification.manager), {
1271
+ maxBuffer: 20 * 1024 * 1024,
1272
+ timeoutMs: 10 * 60 * 1000,
1273
+ });
1274
+ }
1275
+ catch (error) {
1276
+ installCommandError = error;
1277
+ log.warn('Dominds install command failed; verifying installed files before reporting failure', error, {
1278
+ currentVersion: runningVersion,
1279
+ targetVersion,
1280
+ });
1281
+ }
1282
+ const installedVerification = await verifyInstalledDominds(targetVersion);
1283
+ if (installedVerification.kind === 'failed') {
1284
+ if (installCommandError !== null) {
1285
+ throw new Error(`npm install failed and installed Dominds verification failed. npm: ${formatErrorForUi(installCommandError)} verification: ${installedVerification.message}`);
1286
+ }
1287
+ throw new Error(installedVerification.message);
1288
+ }
1289
+ if (installCommandError !== null) {
1290
+ log.warn('Dominds install command failed but installed files passed verification', installCommandError, {
1291
+ targetVersion,
1292
+ packageVersion: installedVerification.packageVersion,
1293
+ probeVersion: installedVerification.probeVersion,
1294
+ });
1295
+ }
1296
+ const installReport = installCommandError === null
1297
+ ? null
1298
+ : `Dominds install command reported failure, but the current entrypoint version probe confirmed v${installedVerification.probeVersion}. Restart is available.`;
833
1299
  restartState = {
834
1300
  kind: 'restart_required',
835
- installedVersion: latest.latestVersion,
836
- globalCommandAbs,
1301
+ installedVersion: installedVerification.probeVersion,
1302
+ installReport,
1303
+ reason: installCommandError === null
1304
+ ? 'restart_required'
1305
+ : 'install_verified_after_command_failure',
837
1306
  };
1307
+ installFailureObservation = null;
838
1308
  return await getDomindsSelfUpdateStatus();
839
1309
  })()
840
1310
  .catch((error) => {
841
1311
  const latestVersion = latestObservation.kind === 'ok' ? latestObservation.latestVersion : null;
842
1312
  const checkedAt = latestObservation.kind === 'unknown' ? null : latestObservation.checkedAt;
1313
+ installFailureObservation = {
1314
+ errorText: formatErrorForUi(error),
1315
+ failedAt: (0, time_1.formatUnifiedTimestamp)(new Date()),
1316
+ };
843
1317
  log.error('Dominds version install failed', error, {
844
1318
  runKind,
845
1319
  currentVersion: getRunningVersion(),
846
1320
  latestVersion,
847
1321
  checkedAt,
848
1322
  });
849
- throw error;
1323
+ return getDomindsSelfUpdateStatus();
850
1324
  })
851
1325
  .finally(() => {
852
1326
  installPromise = null;
853
1327
  publishStatusUpdateSoon();
854
1328
  });
855
1329
  publishStatusUpdateSoon();
856
- return await installPromise;
857
- }
858
- function buildRestartArgs(cfg) {
859
- return ['webui', '-p', String(cfg.port), '-h', cfg.host, '--mode', 'prod', '--nobrowser'];
1330
+ return await getDomindsSelfUpdateStatus();
860
1331
  }
861
1332
  function spawnDetachedRestartHelper(params) {
862
1333
  const stdioMode = getRestartHelperStdio();
@@ -876,7 +1347,7 @@ function spawnDetachedRestartHelper(params) {
876
1347
  "const net = require('net');",
877
1348
  "const { spawn } = require('child_process');",
878
1349
  'const payload = JSON.parse(process.argv[1]);',
879
- 'const detached = payload.stdioMode !== "inherit" || process.platform === "win32";',
1350
+ 'const detached = payload.stdioMode !== "inherit";',
880
1351
  'function isPortBusy() {',
881
1352
  ' return new Promise((resolve) => {',
882
1353
  ' const socket = net.createConnection({ host: payload.host, port: payload.port });',
@@ -915,13 +1386,18 @@ function spawnDetachedRestartHelper(params) {
915
1386
  ' throw error;',
916
1387
  ' }',
917
1388
  '}',
918
- 'async function waitForRestartReadiness(timeoutMs) {',
1389
+ 'async function waitForRetiringProcessExit(timeoutMs) {',
919
1390
  ' const deadline = Date.now() + timeoutMs;',
1391
+ ' while (Date.now() < deadline) {',
1392
+ ' if (!isRetiringProcessAlive()) return true;',
1393
+ ' await new Promise((resolve) => setTimeout(resolve, payload.probeIntervalMs));',
1394
+ ' }',
1395
+ ' return false;',
1396
+ '}',
1397
+ 'async function waitForPortReleaseUntil(deadline) {',
920
1398
  ' let consecutiveReady = 0;',
921
1399
  ' while (Date.now() < deadline) {',
922
- ' const processAlive = isRetiringProcessAlive();',
923
- ' const portBusy = await isPortBusy();',
924
- ' if (!processAlive && !portBusy) {',
1400
+ ' if (!(await isPortBusy())) {',
925
1401
  ' consecutiveReady += 1;',
926
1402
  ' if (consecutiveReady >= 2) return true;',
927
1403
  ' } else {',
@@ -933,7 +1409,7 @@ function spawnDetachedRestartHelper(params) {
933
1409
  '}',
934
1410
  'function runBestEffortKiller(command, args) {',
935
1411
  ' return new Promise((resolve) => {',
936
- ' const killer = spawn(command, args, { stdio: payload.stdioMode });',
1412
+ ' const killer = spawn(command, args, { stdio: payload.stdioMode, windowsHide: payload.stdioMode !== "inherit" });',
937
1413
  " killer.once('error', () => resolve());",
938
1414
  " killer.once('exit', () => resolve());",
939
1415
  ' });',
@@ -953,16 +1429,26 @@ function spawnDetachedRestartHelper(params) {
953
1429
  '}',
954
1430
  '(async () => {',
955
1431
  ' try {',
956
- ' const readyGracefully = await waitForRestartReadiness(payload.forceKillAfterMs);',
957
- ' if (!readyGracefully) {',
1432
+ ' const forceKillDeadline = Date.now() + payload.forceKillAfterMs;',
1433
+ ' const exitedGracefully = await waitForRetiringProcessExit(payload.forceKillAfterMs);',
1434
+ ' if (!exitedGracefully) {',
958
1435
  ' await forceKillRetiringProcess();',
959
- ' const readyAfterKill = await waitForRestartReadiness(payload.portReleaseTimeoutMs);',
960
- ' if (!readyAfterKill) {',
961
- ' throw new Error(`Dominds restart target is still not ready after force-killing pid ${String(payload.retiringPid)}; port=${String(payload.host)}:${String(payload.port)}`);',
1436
+ ' const exitedAfterKill = await waitForRetiringProcessExit(payload.portReleaseTimeoutMs);',
1437
+ ' if (!exitedAfterKill) {',
1438
+ ' throw new Error(`Dominds retiring process is still alive after force-killing pid ${String(payload.retiringPid)}`);',
962
1439
  ' }',
963
1440
  ' }',
964
- " const child = spawn(payload.command, payload.args, { cwd: payload.cwd, env: process.env, detached, stdio: payload.stdioMode, shell: process.platform === 'win32' });",
1441
+ ' const portReleaseDeadline = Math.max(forceKillDeadline, Date.now() + payload.portReleaseTimeoutMs);',
1442
+ ' const portReleased = await waitForPortReleaseUntil(portReleaseDeadline);',
1443
+ ' if (!portReleased) {',
1444
+ ' throw new Error(`Dominds restart port is still busy after retiring pid ${String(payload.retiringPid)} exited; port=${String(payload.host)}:${String(payload.port)}`);',
1445
+ ' }',
1446
+ ' const child = spawn(payload.command, payload.args, { cwd: payload.cwd, env: process.env, detached, stdio: payload.stdioMode, shell: false, windowsHide: payload.stdioMode !== "inherit" });',
965
1447
  ' if (detached) child.unref();',
1448
+ ' await new Promise((resolve, reject) => {',
1449
+ " child.once('error', reject);",
1450
+ " child.once('spawn', resolve);",
1451
+ ' });',
966
1452
  ' process.exit(0);',
967
1453
  ' } catch (error) {',
968
1454
  ' console.error(error instanceof Error ? error.message : String(error));',
@@ -973,10 +1459,11 @@ function spawnDetachedRestartHelper(params) {
973
1459
  const helper = (0, child_process_1.spawn)(process.execPath, ['-e', helperScript, helperPayload], {
974
1460
  cwd: params.cwd,
975
1461
  env: process.env,
976
- detached: stdioMode !== 'inherit' || process.platform === 'win32',
1462
+ detached: stdioMode !== 'inherit',
977
1463
  stdio: stdioMode,
1464
+ windowsHide: stdioMode !== 'inherit',
978
1465
  });
979
- if (stdioMode !== 'inherit' || process.platform === 'win32') {
1466
+ if (stdioMode !== 'inherit') {
980
1467
  helper.unref();
981
1468
  }
982
1469
  }
@@ -1023,50 +1510,41 @@ async function restartDomindsIntoLatest() {
1023
1510
  throw new Error('No restartable Dominds update is currently available');
1024
1511
  }
1025
1512
  const runKind = detectRunKind(cfg.mode);
1026
- const args = buildRestartArgs(cfg);
1027
- let command;
1513
+ let launchSpec;
1028
1514
  const previousRestartRequiredState = restartState.kind === 'restart_required' ? restartState : null;
1029
- if (runKind === 'npx_latest') {
1030
- command = 'npx';
1031
- args.unshift('dominds@latest');
1032
- args.unshift('-y');
1515
+ if (previousRestartRequiredState !== null) {
1516
+ launchSpec = buildCurrentProcessRestartLaunchSpec();
1033
1517
  }
1034
- else if (previousRestartRequiredState !== null) {
1035
- command = previousRestartRequiredState.globalCommandAbs;
1518
+ else if (runKind === 'npx') {
1519
+ const npxSpec = await readNpxDomindsSpec();
1520
+ if (npxSpec?.kind !== 'latest') {
1521
+ throw new Error('Dominds npx restart requires launching Dominds with dominds@latest');
1522
+ }
1523
+ launchSpec = await buildNpxLatestRestartLaunchSpec();
1036
1524
  }
1037
1525
  else {
1038
- throw new Error('Dominds restart requires a completed install or an npx latest session');
1526
+ throw new Error('Dominds restart requires a completed install or a restartable session');
1039
1527
  }
1040
1528
  restartState = { kind: 'restarting', targetVersion: status.targetVersion };
1041
1529
  publishStatusUpdateSoon();
1042
1530
  try {
1043
1531
  spawnDetachedRestartHelper({
1044
- command,
1045
- args,
1046
- cwd: process.cwd(),
1532
+ command: launchSpec.command,
1533
+ args: launchSpec.args,
1534
+ cwd: PROCESS_START_CWD,
1047
1535
  host: cfg.host,
1048
1536
  port: cfg.port,
1049
1537
  });
1050
1538
  setImmediate(() => {
1051
1539
  void stopAndExitForRestart().catch((error) => {
1052
1540
  log.error('Failed to stop Dominds server during restart', error);
1053
- if (runKind === 'npm_global' && previousRestartRequiredState !== null) {
1054
- restartState = previousRestartRequiredState;
1055
- publishStatusUpdateSoon();
1056
- return;
1057
- }
1058
- restartState = IDLE_RESTART_STATE;
1541
+ restartState = previousRestartRequiredState ?? IDLE_RESTART_STATE;
1059
1542
  publishStatusUpdateSoon();
1060
1543
  });
1061
1544
  });
1062
1545
  }
1063
1546
  catch (error) {
1064
- if (previousRestartRequiredState !== null) {
1065
- restartState = previousRestartRequiredState;
1066
- }
1067
- else {
1068
- restartState = IDLE_RESTART_STATE;
1069
- }
1547
+ restartState = previousRestartRequiredState ?? IDLE_RESTART_STATE;
1070
1548
  publishStatusUpdateSoon();
1071
1549
  throw error;
1072
1550
  }