dsh-plugin-local-infer 0.1.2 → 0.1.4

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 (251) hide show
  1. package/README.md +32 -6
  2. package/cordis.patch.yml +7 -0
  3. package/docs/zh/README.md +24 -4
  4. package/dsh/client.js +4200 -4049
  5. package/package.json +33 -11
  6. package/packages/core/lib/adapter.d.ts +177 -11
  7. package/packages/core/lib/adapter.js +74 -1
  8. package/packages/core/lib/config.d.ts +1 -1
  9. package/packages/core/lib/config.js +1 -1
  10. package/packages/core/lib/debug.d.ts +1 -1
  11. package/packages/core/lib/debug.js +1 -1
  12. package/packages/core/lib/defaults.d.ts +1 -1
  13. package/packages/core/lib/defaults.js +1 -1
  14. package/packages/core/lib/deps.d.ts +48 -20
  15. package/packages/core/lib/deps.js +24 -8
  16. package/packages/core/lib/estimator.d.ts +1 -1
  17. package/packages/core/lib/estimator.js +1 -1
  18. package/packages/core/lib/guideline.d.ts +1 -1
  19. package/packages/core/lib/guideline.js +1 -1
  20. package/packages/core/lib/hardware.d.ts +1 -1
  21. package/packages/core/lib/hardware.js +1 -1
  22. package/packages/core/lib/hf-cache.d.ts +70 -0
  23. package/packages/core/lib/hf-cache.js +83 -0
  24. package/packages/core/lib/index.d.ts +16 -9
  25. package/packages/core/lib/index.js +10 -6
  26. package/packages/core/lib/infer-cache.d.ts +39 -0
  27. package/packages/core/lib/infer-cache.js +53 -0
  28. package/packages/core/lib/launch-command.d.ts +8 -4
  29. package/packages/core/lib/launch-command.js +13 -6
  30. package/packages/core/lib/launch-record.d.ts +1 -1
  31. package/packages/core/lib/launch-record.js +1 -1
  32. package/packages/core/lib/logs.d.ts +8 -1
  33. package/packages/core/lib/logs.js +12 -4
  34. package/packages/core/lib/models.d.ts +120 -14
  35. package/packages/core/lib/models.js +209 -17
  36. package/packages/core/lib/parameter.d.ts +31 -3
  37. package/packages/core/lib/parameter.js +1 -1
  38. package/packages/core/lib/progress.d.ts +54 -0
  39. package/packages/core/lib/progress.js +120 -0
  40. package/packages/core/lib/registrar.d.ts +25 -14
  41. package/packages/core/lib/registrar.js +30 -10
  42. package/packages/core/lib/reserve.d.ts +11 -3
  43. package/packages/core/lib/reserve.js +6 -4
  44. package/packages/core/lib/status.d.ts +12 -6
  45. package/packages/core/lib/status.js +21 -10
  46. package/packages/core/lib/sudo.d.ts +80 -0
  47. package/packages/core/lib/sudo.js +78 -0
  48. package/packages/core/package.json +1 -1
  49. package/packages/orchestrator/lib/config.d.ts +63 -0
  50. package/packages/orchestrator/lib/config.js +111 -0
  51. package/packages/orchestrator/lib/index.d.ts +51 -0
  52. package/packages/orchestrator/lib/index.js +73 -0
  53. package/packages/orchestrator/lib/route.d.ts +60 -0
  54. package/packages/orchestrator/lib/route.js +159 -0
  55. package/packages/orchestrator/locale/en.json +6 -0
  56. package/packages/orchestrator/package.json +39 -0
  57. package/packages/orchestrator/prompt.md +87 -0
  58. package/packages/providers/lib/acquire.d.ts +95 -15
  59. package/packages/providers/lib/acquire.js +239 -40
  60. package/packages/providers/lib/adapters.d.ts +155 -221
  61. package/packages/providers/lib/adapters.js +589 -935
  62. package/packages/providers/lib/debug.d.ts +1 -1
  63. package/packages/providers/lib/debug.js +1 -1
  64. package/packages/providers/lib/deps.d.ts +31 -212
  65. package/packages/providers/lib/deps.js +71 -205
  66. package/packages/providers/lib/engines/basalt/basalt.d.ts +130 -0
  67. package/packages/providers/lib/engines/basalt/basalt.js +304 -0
  68. package/packages/providers/lib/engines/basalt/basaltAdapter.d.ts +85 -0
  69. package/packages/providers/lib/engines/basalt/basaltAdapter.js +439 -0
  70. package/packages/providers/lib/engines/basalt/basaltLinux.d.ts +23 -0
  71. package/packages/providers/lib/engines/basalt/basaltLinux.js +47 -0
  72. package/packages/providers/lib/engines/basalt/basaltMacOS.d.ts +17 -0
  73. package/packages/providers/lib/engines/basalt/basaltMacOS.js +19 -0
  74. package/packages/providers/lib/engines/basalt/basaltWindows.d.ts +24 -0
  75. package/packages/providers/lib/engines/basalt/basaltWindows.js +49 -0
  76. package/packages/providers/lib/engines/engineOs.d.ts +24 -0
  77. package/packages/providers/lib/engines/engineOs.js +17 -0
  78. package/packages/providers/lib/{hyperqwen.d.ts → engines/hyperqwen/hyperqwen.d.ts} +2 -2
  79. package/packages/providers/lib/{hyperqwen.js → engines/hyperqwen/hyperqwen.js} +14 -2
  80. package/packages/providers/lib/engines/hyperqwen/hyperqwenAdapter.d.ts +38 -0
  81. package/packages/providers/lib/engines/hyperqwen/hyperqwenAdapter.js +115 -0
  82. package/packages/providers/lib/engines/hyperqwen/hyperqwenArch.d.ts +9 -0
  83. package/packages/providers/lib/engines/hyperqwen/hyperqwenArch.js +9 -0
  84. package/packages/providers/lib/engines/hyperqwen/hyperqwenDebian.d.ts +9 -0
  85. package/packages/providers/lib/engines/hyperqwen/hyperqwenDebian.js +9 -0
  86. package/packages/providers/lib/engines/hyperqwen/hyperqwenFedora.d.ts +9 -0
  87. package/packages/providers/lib/engines/hyperqwen/hyperqwenFedora.js +9 -0
  88. package/packages/providers/lib/engines/hyperqwen/hyperqwenLinux.d.ts +10 -0
  89. package/packages/providers/lib/engines/hyperqwen/hyperqwenLinux.js +14 -0
  90. package/packages/providers/lib/engines/hyperqwen/hyperqwenMacOS.d.ts +9 -0
  91. package/packages/providers/lib/engines/hyperqwen/hyperqwenMacOS.js +9 -0
  92. package/packages/providers/lib/engines/hyperqwen/hyperqwenWindows.d.ts +9 -0
  93. package/packages/providers/lib/engines/hyperqwen/hyperqwenWindows.js +9 -0
  94. package/packages/providers/lib/{infernix.d.ts → engines/infernix/infernix.d.ts} +7 -4
  95. package/packages/providers/lib/{infernix.js → engines/infernix/infernix.js} +53 -8
  96. package/packages/providers/lib/engines/infernix/infernixAdapter.d.ts +52 -0
  97. package/packages/providers/lib/engines/infernix/infernixAdapter.js +235 -0
  98. package/packages/providers/lib/engines/infernix/infernixArch.d.ts +9 -0
  99. package/packages/providers/lib/engines/infernix/infernixArch.js +9 -0
  100. package/packages/providers/lib/engines/infernix/infernixDebian.d.ts +9 -0
  101. package/packages/providers/lib/engines/infernix/infernixDebian.js +9 -0
  102. package/packages/providers/lib/engines/infernix/infernixFedora.d.ts +9 -0
  103. package/packages/providers/lib/engines/infernix/infernixFedora.js +9 -0
  104. package/packages/providers/lib/engines/infernix/infernixLinux.d.ts +17 -0
  105. package/packages/providers/lib/engines/infernix/infernixLinux.js +35 -0
  106. package/packages/providers/lib/engines/infernix/infernixMacOS.d.ts +16 -0
  107. package/packages/providers/lib/engines/infernix/infernixMacOS.js +18 -0
  108. package/packages/providers/lib/engines/infernix/infernixWindows.d.ts +16 -0
  109. package/packages/providers/lib/engines/infernix/infernixWindows.js +34 -0
  110. package/packages/providers/lib/{llamacpp.d.ts → engines/llamacpp/llamacpp.d.ts} +2 -2
  111. package/packages/providers/lib/{llamacpp.js → engines/llamacpp/llamacpp.js} +12 -2
  112. package/packages/providers/lib/engines/llamacpp/llamacppAdapter.d.ts +50 -0
  113. package/packages/providers/lib/engines/llamacpp/llamacppAdapter.js +274 -0
  114. package/packages/providers/lib/engines/llamacpp/llamacppArch.d.ts +9 -0
  115. package/packages/providers/lib/engines/llamacpp/llamacppArch.js +9 -0
  116. package/packages/providers/lib/engines/llamacpp/llamacppDebian.d.ts +9 -0
  117. package/packages/providers/lib/engines/llamacpp/llamacppDebian.js +9 -0
  118. package/packages/providers/lib/engines/llamacpp/llamacppFedora.d.ts +9 -0
  119. package/packages/providers/lib/engines/llamacpp/llamacppFedora.js +9 -0
  120. package/packages/providers/lib/engines/llamacpp/llamacppLinux.d.ts +17 -0
  121. package/packages/providers/lib/engines/llamacpp/llamacppLinux.js +28 -0
  122. package/packages/providers/lib/engines/llamacpp/llamacppMacOS.d.ts +15 -0
  123. package/packages/providers/lib/engines/llamacpp/llamacppMacOS.js +17 -0
  124. package/packages/providers/lib/engines/llamacpp/llamacppWindows.d.ts +15 -0
  125. package/packages/providers/lib/engines/llamacpp/llamacppWindows.js +26 -0
  126. package/packages/providers/lib/{ninfer.d.ts → engines/ninfer/ninfer.d.ts} +2 -2
  127. package/packages/providers/lib/{ninfer.js → engines/ninfer/ninfer.js} +25 -3
  128. package/packages/providers/lib/engines/ninfer/ninferAdapter.d.ts +81 -0
  129. package/packages/providers/lib/engines/ninfer/ninferAdapter.js +392 -0
  130. package/packages/providers/lib/engines/ninfer/ninferArch.d.ts +9 -0
  131. package/packages/providers/lib/engines/ninfer/ninferArch.js +9 -0
  132. package/packages/providers/lib/engines/ninfer/ninferDebian.d.ts +9 -0
  133. package/packages/providers/lib/engines/ninfer/ninferDebian.js +9 -0
  134. package/packages/providers/lib/engines/ninfer/ninferFedora.d.ts +9 -0
  135. package/packages/providers/lib/engines/ninfer/ninferFedora.js +9 -0
  136. package/packages/providers/lib/engines/ninfer/ninferLinux.d.ts +17 -0
  137. package/packages/providers/lib/engines/ninfer/ninferLinux.js +37 -0
  138. package/packages/providers/lib/engines/ninfer/ninferMacOS.d.ts +15 -0
  139. package/packages/providers/lib/engines/ninfer/ninferMacOS.js +17 -0
  140. package/packages/providers/lib/engines/ninfer/ninferWindows.d.ts +29 -0
  141. package/packages/providers/lib/engines/ninfer/ninferWindows.js +59 -0
  142. package/packages/providers/lib/engines/strata/strata.d.ts +1 -0
  143. package/packages/providers/lib/engines/strata/strata.js +264 -0
  144. package/packages/providers/lib/engines/strata/strataAdapter.d.ts +97 -0
  145. package/packages/providers/lib/engines/strata/strataAdapter.js +463 -0
  146. package/packages/providers/lib/engines/strata/strataArch.d.ts +9 -0
  147. package/packages/providers/lib/engines/strata/strataArch.js +9 -0
  148. package/packages/providers/lib/engines/strata/strataDebian.d.ts +9 -0
  149. package/packages/providers/lib/engines/strata/strataDebian.js +9 -0
  150. package/packages/providers/lib/engines/strata/strataFedora.d.ts +9 -0
  151. package/packages/providers/lib/engines/strata/strataFedora.js +9 -0
  152. package/packages/providers/lib/engines/strata/strataLinux.d.ts +21 -0
  153. package/packages/providers/lib/engines/strata/strataLinux.js +30 -0
  154. package/packages/providers/lib/engines/strata/strataMacOS.d.ts +16 -0
  155. package/packages/providers/lib/engines/strata/strataMacOS.js +17 -0
  156. package/packages/providers/lib/engines/strata/strataWindows.d.ts +27 -0
  157. package/packages/providers/lib/engines/strata/strataWindows.js +37 -0
  158. package/packages/providers/lib/engines.d.ts +8 -5
  159. package/packages/providers/lib/engines.js +22 -11
  160. package/packages/providers/lib/guidelines.d.ts +5 -4
  161. package/packages/providers/lib/guidelines.js +18 -5
  162. package/packages/providers/lib/index.d.ts +33 -24
  163. package/packages/providers/lib/index.js +46 -24
  164. package/packages/providers/lib/model-defaults.d.ts +10 -5
  165. package/packages/providers/lib/model-defaults.js +47 -5
  166. package/packages/providers/lib/platform.d.ts +8 -5
  167. package/packages/providers/lib/platform.js +27 -7
  168. package/packages/providers/lib/presets.d.ts +6 -4
  169. package/packages/providers/lib/presets.js +53 -5
  170. package/packages/providers/lib/systemDeps.d.ts +313 -0
  171. package/packages/providers/lib/systemDeps.js +284 -0
  172. package/packages/providers/lib/vram.d.ts +34 -8
  173. package/packages/providers/lib/vram.js +81 -8
  174. package/packages/providers/package.json +2 -2
  175. package/packages/service/lib/index.d.ts +187 -23
  176. package/packages/service/lib/index.js +667 -90
  177. package/packages/service/lib/launch-target.d.ts +19 -0
  178. package/packages/service/lib/launch-target.js +28 -0
  179. package/packages/service/lib/run-logs.d.ts +72 -0
  180. package/packages/service/lib/run-logs.js +125 -0
  181. package/packages/service/lib/types.d.ts +166 -8
  182. package/packages/service/lib/types.js +1 -1
  183. package/packages/service/package.json +2 -2
  184. package/packages/tool/lib/index.d.ts +1 -1
  185. package/packages/tool/lib/index.js +1 -1
  186. package/packages/tool/package.json +2 -2
  187. package/packages/ui/lib/config.d.ts +89 -0
  188. package/packages/ui/lib/config.js +251 -0
  189. package/packages/ui/lib/deps.d.ts +4 -4
  190. package/packages/ui/lib/deps.js +1 -1
  191. package/packages/ui/lib/form.d.ts +1 -1
  192. package/packages/ui/lib/form.js +1 -1
  193. package/packages/ui/lib/index.d.ts +7 -1
  194. package/packages/ui/lib/index.js +12 -2
  195. package/packages/ui/lib/meter.d.ts +1 -1
  196. package/packages/ui/lib/meter.js +1 -1
  197. package/packages/ui/lib/ops/engine.d.ts +216 -0
  198. package/packages/ui/lib/ops/engine.js +697 -0
  199. package/packages/ui/lib/ops/get-steps.d.ts +98 -0
  200. package/packages/ui/lib/ops/get-steps.js +359 -0
  201. package/packages/ui/lib/ops/hf.d.ts +42 -0
  202. package/packages/ui/lib/ops/hf.js +150 -0
  203. package/packages/ui/lib/ops/logs.d.ts +78 -0
  204. package/packages/ui/lib/ops/logs.js +119 -0
  205. package/packages/ui/lib/ops/model.d.ts +71 -0
  206. package/packages/ui/lib/ops/model.js +123 -0
  207. package/packages/ui/lib/request.d.ts +106 -0
  208. package/packages/ui/lib/request.js +80 -0
  209. package/packages/ui/lib/route.d.ts +106 -422
  210. package/packages/ui/lib/route.js +136 -1845
  211. package/packages/ui/lib/routes/chat-template.d.ts +1 -0
  212. package/packages/ui/lib/routes/chat-template.js +1 -0
  213. package/packages/ui/lib/routes/deps.d.ts +1 -0
  214. package/packages/ui/lib/routes/deps.js +1 -0
  215. package/packages/ui/lib/routes/download.d.ts +1 -0
  216. package/packages/ui/lib/routes/download.js +1 -0
  217. package/packages/ui/lib/routes/get.d.ts +1 -0
  218. package/packages/ui/lib/routes/get.js +106 -0
  219. package/packages/ui/lib/routes/install.d.ts +16 -0
  220. package/packages/ui/lib/routes/install.js +36 -0
  221. package/packages/ui/lib/routes/launch.d.ts +24 -0
  222. package/packages/ui/lib/routes/launch.js +74 -0
  223. package/packages/ui/lib/routes/logs.d.ts +57 -0
  224. package/packages/ui/lib/routes/logs.js +117 -0
  225. package/packages/ui/lib/routes/provider-delete.d.ts +15 -0
  226. package/packages/ui/lib/routes/provider-delete.js +37 -0
  227. package/packages/ui/lib/routes/register.d.ts +16 -0
  228. package/packages/ui/lib/routes/register.js +28 -0
  229. package/packages/ui/lib/routes/save.d.ts +18 -0
  230. package/packages/ui/lib/routes/save.js +159 -0
  231. package/packages/ui/lib/routes/stop.d.ts +19 -0
  232. package/packages/ui/lib/routes/stop.js +32 -0
  233. package/packages/ui/lib/routes/stream.d.ts +40 -0
  234. package/packages/ui/lib/routes/stream.js +68 -0
  235. package/packages/ui/lib/routes/summary.d.ts +15 -0
  236. package/packages/ui/lib/routes/summary.js +26 -0
  237. package/packages/ui/lib/routes/unregister.d.ts +14 -0
  238. package/packages/ui/lib/routes/unregister.js +26 -0
  239. package/packages/ui/lib/viewmodels/deps.d.ts +1 -0
  240. package/packages/ui/lib/viewmodels/deps.js +1 -0
  241. package/packages/ui/lib/viewmodels/depsHelpers.d.ts +1 -0
  242. package/packages/ui/lib/viewmodels/depsHelpers.js +94 -0
  243. package/packages/ui/lib/viewmodels/summary.d.ts +145 -0
  244. package/packages/ui/lib/viewmodels/summary.js +245 -0
  245. package/packages/ui/lib/viewmodels/summaryHelpers.d.ts +30 -0
  246. package/packages/ui/lib/viewmodels/summaryHelpers.js +42 -0
  247. package/packages/ui/lib/warnings.d.ts +1 -1
  248. package/packages/ui/lib/warnings.js +1 -1
  249. package/packages/ui/package.json +4 -4
  250. package/packages/providers/lib/strata.d.ts +0 -15
  251. package/packages/providers/lib/strata.js +0 -14
@@ -0,0 +1,251 @@
1
+ /**
2
+ * The stored-config persistence the routes and ops share. The values live in
3
+ * ~/.dsh/local-infer/config.json, shared with the CLI, so the browser never
4
+ * sees a secret it did not store. Every read sanitizes the file field by
5
+ * field, so a by-hand edit never poisons the deploy step or the re-link rule.
6
+ * @module dsh-plugin-local-infer/ui/config
7
+ */
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
9
+ import { homedir } from 'node:os';
10
+ import { dirname, join } from 'node:path';
11
+ // Relative, not the root package subpath: a self-referencing bare specifier
12
+ // only resolves when the package sits inside a node_modules tree, so a
13
+ // local-path or pnpm-linked install of this repo would fail the import.
14
+ import { DEFAULT_LOG_PATH_TEMPLATE } from '../../core/lib/index.js';
15
+ /**
16
+ * The config file the route owns. It sits under the dsh home so a web user and
17
+ * a CLI user share one file, the way modsearch shares ~/.modsearch.
18
+ */
19
+ export function localInferConfigPath() {
20
+ return join(homedir(), '.dsh', 'local-infer', 'config.json');
21
+ }
22
+ /**
23
+ * readConfig reads the stored engine, config, trust gate, and per-engine
24
+ * platform configs. A missing or broken file reads as the scaffold default
25
+ * (NInfer, empty config, gate off, no platform configs) so the card always has
26
+ * a form to draw. A platform entry that is not an object (or whose fields are
27
+ * not strings) is dropped, so a by-hand edit never poisons the deploy step.
28
+ */
29
+ export function readConfig() {
30
+ const path = localInferConfigPath();
31
+ if (!existsSync(path)) {
32
+ return {
33
+ engine: 'ninfer',
34
+ config: {},
35
+ allowRunDeps: false,
36
+ platform: {},
37
+ showHelp: true,
38
+ providers: [],
39
+ logPath: DEFAULT_LOG_PATH_TEMPLATE,
40
+ lastLogs: '',
41
+ };
42
+ }
43
+ try {
44
+ const parsed = JSON.parse(readFileSync(path, 'utf8'));
45
+ return {
46
+ engine: typeof parsed.engine === 'string' ? parsed.engine : 'ninfer',
47
+ config: parsed.config && typeof parsed.config === 'object' ? parsed.config : {},
48
+ allowRunDeps: typeof parsed.allowRunDeps === 'boolean' ? parsed.allowRunDeps : false,
49
+ platform: parsePlatformConfigs(parsed.platform),
50
+ // A file that predates the key (or carries a non-boolean) reads as
51
+ // descriptions visible, the default the card draws on first open.
52
+ showHelp: typeof parsed.showHelp === 'boolean' ? parsed.showHelp : true,
53
+ providers: parseProviders(parsed.providers),
54
+ // A file that predates the key reads as the plugin's default log dir,
55
+ // and the last-run logs start empty until a launch fills them.
56
+ logPath: typeof parsed.logPath === 'string' && parsed.logPath !== ''
57
+ ? parsed.logPath
58
+ : DEFAULT_LOG_PATH_TEMPLATE,
59
+ lastLogs: typeof parsed.lastLogs === 'string' ? parsed.lastLogs : '',
60
+ };
61
+ }
62
+ catch {
63
+ return {
64
+ engine: 'ninfer',
65
+ config: {},
66
+ allowRunDeps: false,
67
+ platform: {},
68
+ showHelp: true,
69
+ providers: [],
70
+ logPath: DEFAULT_LOG_PATH_TEMPLATE,
71
+ lastLogs: '',
72
+ };
73
+ }
74
+ }
75
+ /**
76
+ * parseProviders reads the stored provider list, keeping only entries with a
77
+ * non-blank string id. A non-object entry or an entry with no id is dropped,
78
+ * so a by-hand edit never poisons the card's provider list. The per-engine
79
+ * platform config is read through the same string-field rule the platform map
80
+ * uses, so a provider never carries a platform field it cannot price. A
81
+ * non-boolean autoRebuild is dropped by the same by-hand-edit rule, so only
82
+ * a stored true or false reaches the launch skip.
83
+ */
84
+ function parseProviders(raw) {
85
+ if (raw === null || typeof raw !== 'object' || !Array.isArray(raw)) {
86
+ return [];
87
+ }
88
+ const providers = [];
89
+ for (const entry of raw) {
90
+ if (entry === null || typeof entry !== 'object' || Array.isArray(entry))
91
+ continue;
92
+ const fields = entry;
93
+ if (typeof fields.id !== 'string' || fields.id.trim() === '')
94
+ continue;
95
+ const engine = typeof fields.engine === 'string' ? fields.engine : 'ninfer';
96
+ const config = fields.config && typeof fields.config === 'object' ? fields.config : {};
97
+ const platform = parseStoredPlatformConfig(fields.platform) ?? {};
98
+ const provider = { id: fields.id, engine, config, platform };
99
+ if (typeof fields.autoRebuild === 'boolean') {
100
+ provider.autoRebuild = fields.autoRebuild;
101
+ }
102
+ const launch = parseLaunchRecord(fields.launch);
103
+ if (launch !== undefined) {
104
+ provider.launch = launch;
105
+ }
106
+ providers.push(provider);
107
+ }
108
+ return providers;
109
+ }
110
+ /**
111
+ * parseLaunchRecord reads one stored launch record, keeping only the fields
112
+ * the re-link rule prices (the engine pid, the start time, the argv, the
113
+ * parent and previous pids, and the engine/model/port the detector ties the
114
+ * engine to). A record that is not an object, or that names no integer pid
115
+ * or engine id, is dropped, so a by-hand edit never poisons the re-link.
116
+ */
117
+ function parseLaunchRecord(raw) {
118
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
119
+ return undefined;
120
+ }
121
+ const fields = raw;
122
+ if (typeof fields.pid !== 'number' || !Number.isInteger(fields.pid)) {
123
+ return undefined;
124
+ }
125
+ if (typeof fields.startedAt !== 'string' || fields.startedAt === '') {
126
+ return undefined;
127
+ }
128
+ if (typeof fields.engineId !== 'string' || fields.engineId.trim() === '') {
129
+ return undefined;
130
+ }
131
+ const record = {
132
+ pid: fields.pid,
133
+ startedAt: fields.startedAt,
134
+ argv: Array.isArray(fields.argv)
135
+ ? fields.argv.filter((part) => typeof part === 'string')
136
+ : [],
137
+ previousPids: Array.isArray(fields.previousPids)
138
+ ? fields.previousPids.filter((part) => typeof part === 'number')
139
+ : [],
140
+ engineId: fields.engineId,
141
+ };
142
+ if (typeof fields.parentPid === 'number') {
143
+ record.parentPid = fields.parentPid;
144
+ }
145
+ if (typeof fields.modelId === 'string' && fields.modelId !== '') {
146
+ record.modelId = fields.modelId;
147
+ }
148
+ if (typeof fields.port === 'number') {
149
+ record.port = fields.port;
150
+ }
151
+ return record;
152
+ }
153
+ /**
154
+ * writeConfig persists the engine, config, trust gate, per-engine platform
155
+ * configs, and the help toggle, creating the directory tree on first write.
156
+ */
157
+ export function writeConfig(engine, config, allowRunDeps, platform, showHelp, providers, logPath, lastLogs) {
158
+ const path = localInferConfigPath();
159
+ mkdirSync(dirname(path), { recursive: true });
160
+ writeFileSync(path, JSON.stringify({
161
+ engine,
162
+ config,
163
+ allowRunDeps,
164
+ platform: platform ?? {},
165
+ showHelp: showHelp ?? true,
166
+ providers: providers ?? [],
167
+ logPath: logPath ?? DEFAULT_LOG_PATH_TEMPLATE,
168
+ lastLogs: lastLogs ?? '',
169
+ }, null, 2));
170
+ }
171
+ /**
172
+ * writeStored persists a read StoredConfig with a patch over one or more of
173
+ * its fields, leaving every unpatched field as the read returned it. The
174
+ * eight stored fields travel as one value through the ops, so a caller names
175
+ * only the field it changes (the providers list, the last-run logs) instead
176
+ * of re-passing every field the read returned.
177
+ */
178
+ export function writeStored(stored, patch = {}) {
179
+ const next = { ...stored, ...patch };
180
+ writeConfig(next.engine, next.config, next.allowRunDeps, next.platform, next.showHelp, next.providers, next.logPath, next.lastLogs);
181
+ }
182
+ /**
183
+ * parsePlatformConfigs reads the stored platform map, keeping only entries
184
+ * whose fields are strings. A non-object map or a non-object entry reads as
185
+ * absent, so the deploy step never sees a platform config it cannot price.
186
+ */
187
+ export function parsePlatformConfigs(raw) {
188
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
189
+ return {};
190
+ }
191
+ const platform = {};
192
+ for (const [engineId, entry] of Object.entries(raw)) {
193
+ if (entry === null || typeof entry !== 'object' || Array.isArray(entry)) {
194
+ continue;
195
+ }
196
+ const stored = {};
197
+ const fields = entry;
198
+ if (typeof fields.engineDirectory === 'string') {
199
+ stored.engineDirectory = fields.engineDirectory;
200
+ }
201
+ if (typeof fields.engineFork === 'string') {
202
+ stored.engineFork = fields.engineFork;
203
+ }
204
+ if (typeof fields.buildCommands === 'string') {
205
+ stored.buildCommands = fields.buildCommands;
206
+ }
207
+ if (typeof fields.dockerTag === 'string') {
208
+ stored.dockerTag = fields.dockerTag;
209
+ }
210
+ if (stored.engineDirectory !== undefined ||
211
+ stored.engineFork !== undefined ||
212
+ stored.buildCommands !== undefined ||
213
+ stored.dockerTag !== undefined) {
214
+ platform[engineId] = stored;
215
+ }
216
+ }
217
+ return platform;
218
+ }
219
+ /**
220
+ * parseStoredPlatformConfig reads one engine's platform config (the launch
221
+ * request's `platform` key), keeping only string fields. A non-object or an
222
+ * object with no string fields reads as absent, so the launch keeps the stored
223
+ * entry the save route synced.
224
+ */
225
+ export function parseStoredPlatformConfig(raw) {
226
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
227
+ return undefined;
228
+ }
229
+ const fields = raw;
230
+ const stored = {};
231
+ if (typeof fields.engineDirectory === 'string') {
232
+ stored.engineDirectory = fields.engineDirectory;
233
+ }
234
+ if (typeof fields.engineFork === 'string') {
235
+ stored.engineFork = fields.engineFork;
236
+ }
237
+ if (typeof fields.buildCommands === 'string') {
238
+ stored.buildCommands = fields.buildCommands;
239
+ }
240
+ if (typeof fields.dockerTag === 'string') {
241
+ stored.dockerTag = fields.dockerTag;
242
+ }
243
+ if (stored.engineDirectory === undefined &&
244
+ stored.engineFork === undefined &&
245
+ stored.buildCommands === undefined &&
246
+ stored.dockerTag === undefined) {
247
+ return undefined;
248
+ }
249
+ return stored;
250
+ }
251
+ //# sourceMappingURL=config.js.map
@@ -7,7 +7,7 @@
7
7
  * here.
8
8
  * @module dsh-plugin-local-infer/ui/deps
9
9
  */
10
- import type { DepCheck, DepStatus } from 'dsh-plugin-local-infer/core';
10
+ import type { BuildMode, DepCheck, DepStatus } from 'dsh-plugin-local-infer/core';
11
11
  /**
12
12
  * DepItemModel is one row of the panel's dep list: the dep id, the purpose
13
13
  * the user reads, the current status, and whether installing it needs sudo.
@@ -40,7 +40,7 @@ export interface ChatTemplateDepModel {
40
40
  */
41
41
  export interface DepsModel {
42
42
  engineId: string;
43
- buildMode: 'docker' | 'local';
43
+ buildMode: BuildMode;
44
44
  packageManager: string | null;
45
45
  deps: DepItemModel[];
46
46
  allSatisfied: boolean;
@@ -56,11 +56,11 @@ export interface DepsModel {
56
56
  */
57
57
  export declare function renderDeps(input: {
58
58
  engineId: string;
59
- buildMode: 'docker' | 'local';
59
+ buildMode: BuildMode;
60
60
  packageManager: string | null;
61
61
  checks: DepCheck[];
62
62
  installString: string;
63
63
  runAllowed: boolean;
64
64
  chatTemplate?: ChatTemplateDepModel;
65
65
  }): DepsModel;
66
- //# sourceMappingURL=deps.d.ts.map
66
+ //# sourceMappingURL=deps.d.ts.map
@@ -36,4 +36,4 @@ export function renderDeps(input) {
36
36
  }
37
37
  return model;
38
38
  }
39
- //# sourceMappingURL=deps.js.map
39
+ //# sourceMappingURL=deps.js.map
@@ -95,4 +95,4 @@ export declare function resolveValue(spec: ParameterSpec, config: Config): unkno
95
95
  * that message, which is how the form expresses cross-param gating.
96
96
  */
97
97
  export declare function renderForm(specs: readonly ParameterSpec[], config: Config, hw?: HardwareProfile): FormModel;
98
- //# sourceMappingURL=form.d.ts.map
98
+ //# sourceMappingURL=form.d.ts.map
@@ -98,4 +98,4 @@ export function renderForm(specs, config, hw) {
98
98
  }
99
99
  return { sections };
100
100
  }
101
- //# sourceMappingURL=form.js.map
101
+ //# sourceMappingURL=form.js.map
@@ -25,6 +25,12 @@ export { renderDeps } from './deps.ts';
25
25
  export type { ChatTemplateDepModel, DepItemModel, DepsModel } from './deps.ts';
26
26
  export { renderWarnings, toneFor } from './warnings.ts';
27
27
  export type { WarningBannerModel, WarningModel, WarningsModel, WarningTone, } from './warnings.ts';
28
+ export type { StoredPlatformConfig } from './config.ts';
29
+ export type { InstallResponse } from './viewmodels/depsHelpers.ts';
30
+ export type { ChatTemplateStatusModel, LocalInferSummary, ProviderSummaryEntry, } from './viewmodels/summary.ts';
31
+ export type { Config, CustomArg, RegisterResult } from 'dsh-plugin-local-infer/core';
32
+ export type { DownloadResult, LaunchResult } from 'dsh-plugin-local-infer/service';
33
+ export type { LogsStreamEvent } from './routes/logs.ts';
28
34
  /**
29
35
  * Mount the Web UI. The browser card (dsh/client.js) registers into the
30
36
  * Plugins page's `plugins.bundle.config` slot and talks to the settings route
@@ -38,4 +44,4 @@ declare const plugin: {
38
44
  apply: typeof apply;
39
45
  };
40
46
  export default plugin;
41
- //# sourceMappingURL=index.d.ts.map
47
+ //# sourceMappingURL=index.d.ts.map
@@ -9,6 +9,7 @@
9
9
  * from; Phase 8 wires them into one panel with the lifecycle controls.
10
10
  * @module dsh-plugin-local-infer/ui
11
11
  */
12
+ import { createNodeLifecycleHost } from '../../providers/lib/index.js';
12
13
  import { registerLocalInferRoute } from "./route.js";
13
14
  export const name = 'local-infer-ui';
14
15
  export const inject = ['localInfer'];
@@ -32,7 +33,16 @@ export function apply(ctx) {
32
33
  if (typeof ctx.inject === 'function') {
33
34
  ctx.inject(['webServer'], (scope) => {
34
35
  try {
35
- registerLocalInferRoute(scope, localInfer);
36
+ // The route host is built here (not the bare node default) so its
37
+ // sudo hook reaches the service: a guarded command whose credential
38
+ // probe found nothing announces through notifySudoNeeded, and the
39
+ // launch run's sudo observer (ops/engine.ts) turns it into the
40
+ // streamed sudo event and the Logs note. The same host drives the
41
+ // Get and launch routes' Get steps.
42
+ const host = createNodeLifecycleHost(undefined, {
43
+ notify: (command) => localInfer.notifySudoNeeded(command),
44
+ });
45
+ registerLocalInferRoute(scope, localInfer, host, host);
36
46
  }
37
47
  catch (error) {
38
48
  console.error(`[local-infer] settings route skipped: ${error}`);
@@ -42,4 +52,4 @@ export function apply(ctx) {
42
52
  }
43
53
  const plugin = { name, inject, apply };
44
54
  export default plugin;
45
- //# sourceMappingURL=index.js.map
55
+ //# sourceMappingURL=index.js.map
@@ -57,4 +57,4 @@ export interface MeterModel {
57
57
  * the dark segment's value came from.
58
58
  */
59
59
  export declare function renderMeter(breakdown: VramBreakdown, verdict: VramVerdict, vramGiB: number, source: 'measured' | 'estimated' | 'not-measured', reserveSource?: ReserveSource, unknownEngines?: UnknownEnginesModel | null): MeterModel;
60
- //# sourceMappingURL=meter.d.ts.map
60
+ //# sourceMappingURL=meter.d.ts.map
@@ -40,4 +40,4 @@ export function renderMeter(breakdown, verdict, vramGiB, source, reserveSource =
40
40
  unknownEngines,
41
41
  };
42
42
  }
43
- //# sourceMappingURL=meter.js.map
43
+ //# sourceMappingURL=meter.js.map
@@ -0,0 +1,216 @@
1
+ /**
2
+ * The engine lifecycle operations: launchEngine runs the shared Get-steps
3
+ * routine (idempotent) and then renders the plan the registered adapter
4
+ * produces and runs the service's launch entry point (deploy, then the health
5
+ * poll), preserving the Get-step logs in the persisted last-run logs;
6
+ * stopEngine stops the exact container or process the launch started (a
7
+ * re-adopted engine through the record's pid), and a failed stop persists a
8
+ * note to the last-run logs and the log file; getEngine is a thin wrapper
9
+ * over the shared Get-steps routine (deps, git sync, build, model download,
10
+ * chat-template download). The launch record (the engine pid, start time,
11
+ * launch arguments, and the DSH process pid that launched it) is what a DSH
12
+ * restart re-links a surviving engine to its config:
13
+ * relinkStoredProviders re-adopts surviving engines on mount and per summary
14
+ * read, handleEngineDeath settles the stored state the moment an engine dies
15
+ * outside the stop path, and persistLaunchLogs stores the captured output.
16
+ * The platform-config registry sync keeps the service registry in step with
17
+ * the stored config.
18
+ * @module dsh-plugin-local-infer/ui/ops/engine
19
+ */
20
+ import type { Config, LaunchStep, LifecycleHost } from 'dsh-plugin-local-infer/core';
21
+ import type { EngineDeathEvent, LaunchResult, LocalInferService } from 'dsh-plugin-local-infer/service';
22
+ import type { StoredConfig, StoredProviderConfig } from '../config.ts';
23
+ import type { GetRequest, LaunchRequest } from '../request.ts';
24
+ /**
25
+ * CANCELED_LINE names the shared "Canceled" run line; it lives with the other
26
+ * run-line constants in ops/logs.ts and is re-exported here for the launch
27
+ * persisters' import surface.
28
+ */
29
+ export { CANCELED_LINE } from './logs.ts';
30
+ /**
31
+ * GET_EVENT_PREFIX leads a Get run's event lines in the streamed and
32
+ * persisted run (the route's `get failed` line and getEngine's sudo CLI
33
+ * note), so both read alike and the `!!` marker has one home (routes/get.ts
34
+ * and getEngine both build it from here).
35
+ */
36
+ export declare const GET_EVENT_PREFIX = "!! ";
37
+ /**
38
+ * resolveAdapter picks the registered engine adapter an engine id routes to. A
39
+ * card that names an engine no adapter serves gets a 404, not a blank panel.
40
+ */
41
+ export declare function resolveAdapter(localInfer: LocalInferService, engineId: string): import("dsh-plugin-local-infer/core").EngineAdapter;
42
+ /**
43
+ * resolveStoredRequest resolves a route request's engine and config against
44
+ * the stored config: the request's fields win, and an absent field falls back
45
+ * to the stored value, the same rule every route applies. The Get route
46
+ * reads it for its run-log key before delegating to getEngine.
47
+ */
48
+ export declare function resolveStoredRequest(request: {
49
+ engine?: string;
50
+ config?: Config;
51
+ }): {
52
+ stored: StoredConfig;
53
+ engineId: string;
54
+ config: Config;
55
+ };
56
+ /**
57
+ * registerSudoObserver registers the run's sudo hook on the service under
58
+ * the run's key (the hub's own keying) and returns the disposer that removes
59
+ * only this hook: concurrent runs each keep their own slot, a re-launch
60
+ * under the same key takes the slot from the older run, and the first settle
61
+ * never clears another run's note routing. The service hands every guarded
62
+ * announcement to every registered hook (the shared CLI password wait can
63
+ * block any run, and the announce seam does not name the triggering run), so
64
+ * one wait notes every run in flight. launchEngine and getEngine share the
65
+ * helper so the sudo-note rule has one home: the hook appends noteLine to
66
+ * the run's own sink (the note rides the streamed run and the run text
67
+ * persisted when the step settles) and through persistProcessLog (so a run
68
+ * still hung on the prompt reads the note in the Logs section and the log
69
+ * file before it settles), then calls onSudo, the route's stream event; a
70
+ * Get passes none because its control keeps its throbber. The caller invokes
71
+ * the disposer in a finally so a failed run leaves no hook behind.
72
+ */
73
+ export declare function registerSudoObserver(localInfer: LocalInferService, runKey: string, noteLine: string, noteTo: (text: string) => void, onSudo?: () => void): () => void;
74
+ /**
75
+ * launchEngine runs the shared Get-steps routine (idempotent: deps, git sync,
76
+ * build, model download, chat-template download, each skipped when already
77
+ * satisfied) and then renders the plan the registered adapter produces for
78
+ * the config and the detected hardware, and runs the service's launch entry
79
+ * point (deploy, then the health poll). A git sync of an existing checkout
80
+ * that fails under the continueOnSyncFailure override (always on for a
81
+ * launch) keeps the Get run going with the checkout's current version and
82
+ * reports syncFailed on the result; the launch then threads autoRebuild:
83
+ * false into the deploy step, which skips its own git sync (it would hit the
84
+ * same rebase conflict) and launches the current version, while the Get
85
+ * error line persists in the last-run logs and the log file. The detail the
86
+ * launch returns names the broken step when the engine does not come up.
87
+ * The launch line (the
88
+ * engine binary and its arguments) leads the engine output in the run logs
89
+ * the card's Logs section and the log file carry, and the Get-step output the
90
+ * launch ran leads it, so a broken setup diagnoses against the exact steps
91
+ * and child process the launch started, and the Get logs are preserved, not
92
+ * wiped, by the launch's persistence. The launch step persists the
93
+ * launch record (the engine pid, start time, launch arguments, and the DSH
94
+ * process pid that launched it) on the request's provider entry, so a DSH
95
+ * restart can re-link a surviving engine to its config. The optional signal
96
+ * is the card's cancel: an abort interrupts the in-flight Get-step download
97
+ * child, and the persisted run carries a "Canceled" line. The optional
98
+ * onChunk is the hf download's raw stderr progress sink: the download runner
99
+ * hands each streamed chunk to it as it lands, so a launch that runs the Get
100
+ * steps streams the download progress the same way a Get does. The optional
101
+ * onSudo is the route's sudo-event writer: while the run is in flight, the
102
+ * service's sudo observer answers a guarded command waiting for a password on
103
+ * the launching CLI by landing the core CLI note in the run logs and the log
104
+ * file and calling onSudo; the observer is unregistered when the run settles,
105
+ * failed or not, so a failing run leaves none behind. The whole run brackets
106
+ * one live hub run under the runLogKey rule (the "--- Launching..." seed,
107
+ * the Get-steps sink, the command note, the deploy and engine output at
108
+ * settle, end in a finally), so the streaming logs route reads the launch.
109
+ */
110
+ export declare function launchEngine(localInfer: LocalInferService, request: LaunchRequest, onProgress?: (step: LaunchStep) => void, host?: LifecycleHost, signal?: AbortSignal, onChunk?: (chunk: string) => void, onSudo?: () => void): Promise<LaunchResult>;
111
+ /**
112
+ * RunLogWriter is the hub slice handleEngineDeath needs: the catch-up read,
113
+ * the append, and the settle. The LocalInfer service satisfies it, so the
114
+ * route's observer closure can hand the service itself to the note path.
115
+ */
116
+ export type RunLogWriter = Pick<LocalInferService, 'readRunLog' | 'appendRunLog' | 'endRun'>;
117
+ /**
118
+ * handleEngineDeath persists a provider entry's state when its engine process
119
+ * dies outside the plugin's stop path: a crash, a pkill of a plugin-launched
120
+ * child seen through the service's exit watch, or the poll-detected exit of a
121
+ * process adopted after a DSH restart. The entry whose launch record names the
122
+ * dead pid (or the dead engine-and-port, when the report carries no pid match)
123
+ * has its record cleared, so a restart never re-links a dead pid, and the exit
124
+ * line lands in the card's last-run logs beside the engine's own output. An
125
+ * event that matches no entry carrying a record (a stop the route already
126
+ * cleared, an engine the plugin never tracked) is a no-op, which keeps an
127
+ * expected stop quiet. With a run-log hub (the route's observer closure
128
+ * captures the service), the same note line also lands in the dead entry's
129
+ * live buffer: the snapshot is read first, and if the run was NOT already
130
+ * running, the append's lazy reopen is settled with endRun right after, so a
131
+ * late note streams without stranding the key as running.
132
+ */
133
+ export declare function handleEngineDeath(event: EngineDeathEvent, runLogs?: RunLogWriter): void;
134
+ /**
135
+ * persistLaunchLogs stores a launch's captured output as the last run and
136
+ * writes it to the configured log file. The Get-step output the launch ran
137
+ * (the optional runText) leads the persisted run, so the Logs section and the
138
+ * log file show the Get steps followed by the launch, not the launch wiping
139
+ * the Get logs. The stored last-run logs ride the shared capRunLogs tail rule
140
+ * (ops/logs.ts), the same cap the append paths and the live hub apply. The
141
+ * log file is only written when the run produced output and the log location
142
+ * is set; the last-run logs are always persisted (an empty string clears a
143
+ * stale run) so the card's Logs section shows the previous run after a
144
+ * reload.
145
+ */
146
+ export declare function persistLaunchLogs(result: LaunchResult, engineId: string, config: Config, runText?: string): void;
147
+ /**
148
+ * stopEngine renders the same plan and runs the service's stop entry point, so
149
+ * the stop step targets the exact container or process the launch started. The
150
+ * stop then clears the target entry's launch record (the engine pid and the
151
+ * previous-pid list with it), so a recycled pid cannot re-link an engine the
152
+ * user just stopped. An engine a DSH restart re-adopted carries no tracked
153
+ * child handle in the adapter, so the stop stamps the record's pid on the
154
+ * plan and the adapter signals it through the host; a stop that fails
155
+ * persists a note (the engine, the model, and the host's message) to the
156
+ * stored last-run logs and the log file, so the card's Logs section names the
157
+ * broken step, and re-throws, so the route answers 500 and the card's stop
158
+ * deadline settles the entry to the red Logs state.
159
+ */
160
+ export declare function stopEngine(localInfer: LocalInferService, request: LaunchRequest): Promise<void>;
161
+ /**
162
+ * relinkStoredProviders prices every stored provider launch record against the
163
+ * live process table through the service's re-link rule and returns the
164
+ * provider list the card should read: an adopted engine is re-marked plugin-
165
+ * launched and tied to its model by the service, and a liveness watcher starts
166
+ * on its port so a later pkill settles the stored state through the death
167
+ * observer without another summary read; a dead engine's record is cleared on
168
+ * disk here (the previous-pid list with it), so a recycled pid cannot re-link
169
+ * to a config whose engine is down. The route calls it on mount and the
170
+ * summary calls it per read, making re-attach independent of the card opening.
171
+ */
172
+ export declare function relinkStoredProviders(localInfer: LocalInferService, stored: StoredConfig): Promise<StoredProviderConfig[]>;
173
+ /**
174
+ * GetOutcome is the answer the Get step reports: ok with no detail, or a
175
+ * failure naming the broken step. The object literal union keeps the
176
+ * invariant the card reads: a detail only exists on a failure.
177
+ */
178
+ export type GetOutcome = {
179
+ ok: true;
180
+ } | {
181
+ ok: false;
182
+ detail?: string;
183
+ };
184
+ /**
185
+ * getEngine is the Get step: a thin wrapper over the shared Get-steps routine
186
+ * (the system dependencies, the git sync, the build, the model download, and
187
+ * the chat-template download), streaming every step through log as it lands,
188
+ * so the card appends it to the Logs section live. The dependency install
189
+ * only runs while the Play/Run trust gate is on; with the gate off the deps
190
+ * are re-checked and a missing one aborts the step with the copy/paste note.
191
+ * The optional signal is the card's cancel: an abort interrupts the in-flight
192
+ * hf download child (SIGINT, then SIGTERM). Resume is within-invocation only:
193
+ * the hf CLI (huggingface_hub 2.x) resumes a network blip via HTTP Range inside
194
+ * one `hf download` run, but a killed run re-downloads from zero on the re-run
195
+ * (each run writes a process-unique `.incomplete` temp blob and unlinks it on
196
+ * failure), so an orphaned partial blob lingers until `hf cache prune`. The
197
+ * optional onChunk is the hf download's raw stderr progress sink: the
198
+ * download runner hands each streamed chunk to it as it lands, separate from
199
+ * the log sink, so the route parses the tqdm lines into progress events. The
200
+ * run registers the same sudo observer a launch does: a guarded command
201
+ * waiting for the user's password on the launching CLI writes the core CLI
202
+ * note through log as a GET_EVENT_PREFIX line, the same marker the route's
203
+ * own failure line uses, so the note rides the streamed run and the run text
204
+ * the route persists, and through persistProcessLog so a run still hung on
205
+ * the prompt reads it before it settles. The Get control keeps its throbber,
206
+ * so the observer announces nothing beyond the note line.
207
+ */
208
+ export declare function getEngine(localInfer: LocalInferService, request: GetRequest, log: (chunk: string) => void, host?: LifecycleHost, signal?: AbortSignal, onChunk?: (chunk: string) => void): Promise<GetOutcome>;
209
+ /**
210
+ * syncPlatformConfigs re-syncs the service registry with the stored platform
211
+ * map: it registers (or re-registers) every engine that carries a config, and
212
+ * unregisters every engine that no longer does, so a launch always reads the
213
+ * platform config the user last saved.
214
+ */
215
+ export declare function syncPlatformConfigs(localInfer: LocalInferService, stored: StoredConfig): void;
216
+ //# sourceMappingURL=engine.d.ts.map