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,98 @@
1
+ /**
2
+ * The shared Get-steps routine both getEngine and launchEngine route through:
3
+ * it runs, in order, (1) the engine's system-dependency install for the host
4
+ * OS (gated by the Play/Run trust gate), (2) the git clone of the engine repo
5
+ * (or the fork) plus the fetch/rebase of a clean checkout, (3) the source
6
+ * build step (the compose engines carry no local build steps), (4) the hf
7
+ * download of the selected model when it is not already present, and (5) the
8
+ * hf download of any selected chat template when it is not already present.
9
+ * Every step streams through the log sink as it lands, and an already-
10
+ * satisfied step is skipped and logged as such, so a Launch that runs the
11
+ * routine before the deploy is idempotent. With an `onStep` reporter (a
12
+ * Launch's progress sink; a standalone Get passes none) each step announces
13
+ * its launch phase only when its work actually starts, so the card's button
14
+ * reads the phase that is running. A Launch can set
15
+ * `continueOnSyncFailure` on the request: when the git sync (rebase) of an
16
+ * existing checkout fails, the run keeps going with the checkout's current
17
+ * version and reports `syncFailed` on the result, so a broken rebase never
18
+ * halts the launch. A standalone Get omits the flag and keeps stopping on a
19
+ * sync failure.
20
+ * @module dsh-plugin-local-infer/ui/ops/get-steps
21
+ */
22
+ import type { Config, LaunchProgress, LifecycleHost } from 'dsh-plugin-local-infer/core';
23
+ import type { LocalInferService } from 'dsh-plugin-local-infer/service';
24
+ import type { StoredPlatformConfig } from '../config.ts';
25
+ /**
26
+ * GetStepsRequest names the run: the engine, the config the dep plan, build
27
+ * mode, model, and chat template read from, the platform entry the checkout
28
+ * directory and fork resolve against, the Play/Run trust gate that decides
29
+ * whether the dependency install runs, and the lifecycle host the git and
30
+ * build steps run through. `autoRebuild` false (the card's Auto Rebuild
31
+ * checkbox off) skips the sync and build steps, so a launch reads the
32
+ * checkout as-is, the same rule the adapter's deploy step applies. `signal`
33
+ * is the card's cancel: an abort interrupts the in-flight hf download child
34
+ * (SIGINT, then SIGTERM), resume is within-invocation only (the hf CLI resumes a network blip via
35
+ * HTTP Range inside one run); a killed run re-downloads from zero on the
36
+ * re-run, and the orphaned `.incomplete` blob lingers until `hf cache prune`.
37
+ * `onChunk` is the hf download's raw stderr progress sink: the download
38
+ * runner hands each streamed stdout and stderr chunk to it as it lands,
39
+ * separate from the log text sink the step lines stream through, so the
40
+ * caller parses the tqdm lines into progress events. `onStep` is the launch
41
+ * phase reporter (the card's button reader): a step announces its phase only
42
+ * when its work actually starts (the dep install, the sync/build, a model or
43
+ * template download), so a satisfied-and-skipped step announces nothing. A
44
+ * standalone Get passes none (its control keeps its throbber); a Launch
45
+ * threads its route progress sink here. `continueOnSyncFailure`
46
+ * (a Launch-only flag) keeps the run going when the git sync of an existing
47
+ * checkout fails: the run reports `syncFailed` on the result and the launch
48
+ * continues with the checkout's current version, so a broken rebase never
49
+ * halts it. A standalone Get omits it and stops on a sync failure.
50
+ */
51
+ export interface GetStepsRequest {
52
+ engineId: string;
53
+ config: Config;
54
+ platform?: StoredPlatformConfig;
55
+ allowRunDeps: boolean;
56
+ autoRebuild?: boolean;
57
+ continueOnSyncFailure?: boolean;
58
+ host: LifecycleHost;
59
+ signal?: AbortSignal;
60
+ onChunk?: (chunk: string) => void;
61
+ onStep?: LaunchProgress;
62
+ }
63
+ /**
64
+ * GetStepsResult reports the run: whether every step passed, a detail the
65
+ * Logs section shows when one did not, and the captured log text (every step
66
+ * line, in order) the caller persists or streams to the card. `syncFailed`
67
+ * marks a run that kept going after a non-fatal git sync failure (the
68
+ * `continueOnSyncFailure` override): `ok` stays true and the caller threads
69
+ * the flag into the launch so the deploy skips its own git sync and launches
70
+ * the checkout's current version.
71
+ */
72
+ export interface GetStepsResult {
73
+ ok: boolean;
74
+ logs: string;
75
+ detail?: string;
76
+ syncFailed?: boolean;
77
+ }
78
+ /**
79
+ * resolveEngineDirectory picks the checkout the Get step syncs: the Engine
80
+ * Directory override when it names a path, else the engine's default
81
+ * checkout home `~/.cache/dsh/infer/{engineId}` (one checkout per engine,
82
+ * never a subfolder of a model directory), so a Get with no override still
83
+ * has a real place to live.
84
+ */
85
+ export declare function resolveEngineDirectory(engineId: string, platform: StoredPlatformConfig | undefined): string;
86
+ /**
87
+ * runGetSteps is the shared Get-steps routine. It runs the five steps in
88
+ * order, streaming each through log and collecting the same text as the
89
+ * result's logs, so a caller can persist the run (a Get) or thread it into
90
+ * the launch's persisted logs (a Launch) without re-running the steps. A
91
+ * step that is already satisfied is skipped and logged as such; a failing
92
+ * step stops the run and names the broken step in the detail. A step that
93
+ * fails non-fatally (the git sync under the `continueOnSyncFailure`
94
+ * override) keeps the run going and threads `syncFailed` into the result, so
95
+ * the launch continues with the checkout's current version.
96
+ */
97
+ export declare function runGetSteps(localInfer: LocalInferService, request: GetStepsRequest, log: (chunk: string) => void): Promise<GetStepsResult>;
98
+ //# sourceMappingURL=get-steps.d.ts.map
@@ -0,0 +1,359 @@
1
+ /**
2
+ * The shared Get-steps routine both getEngine and launchEngine route through:
3
+ * it runs, in order, (1) the engine's system-dependency install for the host
4
+ * OS (gated by the Play/Run trust gate), (2) the git clone of the engine repo
5
+ * (or the fork) plus the fetch/rebase of a clean checkout, (3) the source
6
+ * build step (the compose engines carry no local build steps), (4) the hf
7
+ * download of the selected model when it is not already present, and (5) the
8
+ * hf download of any selected chat template when it is not already present.
9
+ * Every step streams through the log sink as it lands, and an already-
10
+ * satisfied step is skipped and logged as such, so a Launch that runs the
11
+ * routine before the deploy is idempotent. With an `onStep` reporter (a
12
+ * Launch's progress sink; a standalone Get passes none) each step announces
13
+ * its launch phase only when its work actually starts, so the card's button
14
+ * reads the phase that is running. A Launch can set
15
+ * `continueOnSyncFailure` on the request: when the git sync (rebase) of an
16
+ * existing checkout fails, the run keeps going with the checkout's current
17
+ * version and reports `syncFailed` on the result, so a broken rebase never
18
+ * halts the launch. A standalone Get omits the flag and keeps stopping on a
19
+ * sync failure.
20
+ * @module dsh-plugin-local-infer/ui/ops/get-steps
21
+ */
22
+ import { autoRebuildEnabled, chatTemplatePresent, checkDeps, commandLogLine, dshEngineCacheDirectory, modelArtifactPresent, resolveModelDirectory, } from '../../../core/lib/index.js';
23
+ import { buildEngineRepo, defaultModelFor, ENGINES, infernixGetDownloads, syncEngineRepo, } from '../../../providers/lib/index.js';
24
+ import { isHfRepoReference } from "../viewmodels/summaryHelpers.js";
25
+ import { resolveBuildMode } from "../viewmodels/deps.js";
26
+ /**
27
+ * resolveEngineDirectory picks the checkout the Get step syncs: the Engine
28
+ * Directory override when it names a path, else the engine's default
29
+ * checkout home `~/.cache/dsh/infer/{engineId}` (one checkout per engine,
30
+ * never a subfolder of a model directory), so a Get with no override still
31
+ * has a real place to live.
32
+ */
33
+ export function resolveEngineDirectory(engineId, platform) {
34
+ const override = platform?.engineDirectory;
35
+ if (override !== undefined && override.trim() !== '') {
36
+ return override;
37
+ }
38
+ return dshEngineCacheDirectory(engineId);
39
+ }
40
+ /**
41
+ * The marker a Get step reports when it fails non-fatally: the git sync of
42
+ * an existing checkout failed while the `continueOnSyncFailure` override is
43
+ * on, so the runner keeps going (skipping the build) and threads
44
+ * `syncFailed` into the result while the launch continues.
45
+ */
46
+ const SYNC_FAILED = { kind: 'syncFailed' };
47
+ /**
48
+ * downloadOptions builds the exactOptionalPropertyTypes-safe download options
49
+ * a Get step's hf download runs with: the hub-cache layout flag, the run's
50
+ * cancel signal, the onChunk progress sink, and the run's log sink (emit) so
51
+ * the service writes the `$ <hf command>` line into the same log text the step
52
+ * streams, ahead of the download's output. Each field is present only when the
53
+ * run carries it, so an absent field never writes `undefined`. The model and
54
+ * chat-template steps share it, so the option group (the directory layout, the
55
+ * cancel, the progress sink, the log sink) is built in one place.
56
+ */
57
+ function downloadOptions(ctx) {
58
+ return {
59
+ useHubCache: ctx.target.useHubCache,
60
+ onLog: ctx.emit,
61
+ ...(ctx.request.signal !== undefined ? { signal: ctx.request.signal } : {}),
62
+ ...(ctx.onChunk !== undefined ? { onChunk: ctx.onChunk } : {}),
63
+ };
64
+ }
65
+ /**
66
+ * runDepsStep is the Get step's system-dependency install: it runs the
67
+ * install while the Play/Run trust gate is on, and re-checks the deps with
68
+ * a copy/paste note when the gate is off, so a missing dependency aborts the
69
+ * run instead of a broken build.
70
+ */
71
+ async function runDepsStep(ctx) {
72
+ const { localInfer, request, engine, hardware, emit } = ctx;
73
+ const buildMode = resolveBuildMode(engine, request.config);
74
+ emit(`system dependencies (${buildMode})\n`);
75
+ if (request.allowRunDeps === true) {
76
+ // The prereqs phase runs only here: with the gate on the install actually
77
+ // runs, so the step announces it as it starts (the gate-off re-check
78
+ // below is not a prereqs phase and announces nothing).
79
+ request.onStep?.('prereqs');
80
+ // The install run's log sink is this step's emit, so the service writes
81
+ // each dependency install command's `$ <command>` line into the same run
82
+ // text (ahead of the per-dep results below) before the guarded runner
83
+ // spawns the child.
84
+ const install = await localInfer.runInstall(request.engineId, buildMode, hardware, {
85
+ onLog: emit,
86
+ });
87
+ for (const entry of install.results) {
88
+ emit(` ${entry.id}: ${entry.status}${entry.detail !== undefined ? ` (${entry.detail})` : ''}\n`);
89
+ }
90
+ if (!install.ok) {
91
+ emit('!! a system dependency install failed; copy the install string from the panel\n');
92
+ return { ok: false, detail: 'a system dependency install failed' };
93
+ }
94
+ return null;
95
+ }
96
+ const deps = await localInfer.deps(request.engineId, buildMode, hardware);
97
+ const checks = await checkDeps(deps, hardware);
98
+ let missing = false;
99
+ for (const check of checks) {
100
+ emit(` ${check.dep.id}: ${check.status}\n`);
101
+ if (check.status !== 'satisfied')
102
+ missing = true;
103
+ }
104
+ if (missing) {
105
+ emit('!! a system dependency is missing and one-click install is off; copy the install string from the panel\n');
106
+ return { ok: false, detail: 'a system dependency is missing' };
107
+ }
108
+ return null;
109
+ }
110
+ /**
111
+ * runSyncBuildStep is the Get step's git clone (or fork) of the engine repo,
112
+ * the fetch and rebase of a clean checkout, and the source build step (the
113
+ * compose engines carry no local build steps and pass through). A checkout
114
+ * with local changes aborts, so the user's work is never rebased away. The
115
+ * Auto Rebuild checkbox off skips both, so a launch reads the checkout as-is.
116
+ * Under the `continueOnSyncFailure` override, a failed sync of an existing
117
+ * checkout reports the SYNC_FAILED marker (the run keeps going with the
118
+ * checkout's current version and the build is skipped); a failed clone of a
119
+ * missing checkout stays fatal, since there is no current version to launch.
120
+ */
121
+ async function runSyncBuildStep(ctx) {
122
+ const { request, directory, emit } = ctx;
123
+ if (!autoRebuildEnabled(request.autoRebuild)) {
124
+ emit('engine sync and build: auto rebuild off, skipped\n');
125
+ return null;
126
+ }
127
+ // The sync and build actually run (the Auto Rebuild checkbox is not off),
128
+ // so the step announces its build phase as it starts; a skipped step
129
+ // announces nothing.
130
+ request.onStep?.('build');
131
+ // The distinct clone and build headers let the Logs-header step chips track
132
+ // the two sub-steps separately: the clone chip runs until the build header
133
+ // lands, and the build chip runs until the model header lands.
134
+ emit(`engine clone: ${request.engineId}\n`);
135
+ const fork = request.platform?.engineFork;
136
+ const sync = await syncEngineRepo(request.host, {
137
+ engineId: request.engineId,
138
+ directory,
139
+ ...(fork !== undefined && fork.trim() !== '' ? { fork } : {}),
140
+ }, emit);
141
+ if (!sync.ok) {
142
+ // A dirty checkout already alerted in the sync step; any other failure
143
+ // names its step here.
144
+ if (sync.aborted !== true && sync.detail !== undefined) {
145
+ emit(`!! ${sync.detail}\n`);
146
+ }
147
+ // The `continueOnSyncFailure` override (a Launch-only flag): when the git
148
+ // sync of an existing checkout fails, the run keeps going with the
149
+ // checkout's current version (the build is skipped, since the rebase
150
+ // failed and the checkout stays where it is) and reports the failure
151
+ // non-fatally, so a broken rebase never halts the launch. The sync result
152
+ // names the path it took: a fresh clone (cloned) means no prior checkout
153
+ // to launch, so a clone failure stays fatal; a rebase, fetch, or dirty
154
+ // checkout of an existing checkout (no clone) is non-fatal under the
155
+ // override. Reading the flag keeps the checkout-presence decision in the
156
+ // one place that probes it (the git rev-parse in the sync step).
157
+ if (request.continueOnSyncFailure === true && sync.cloned !== true) {
158
+ emit('!! engine sync failed; continuing with the current version\n');
159
+ return SYNC_FAILED;
160
+ }
161
+ return {
162
+ ok: false,
163
+ ...(sync.detail !== undefined ? { detail: sync.detail } : {}),
164
+ };
165
+ }
166
+ // The user's local build command (the card's Build commands field)
167
+ // overrides the engine's default build steps; absent runs the engine's
168
+ // acquisition steps. The host OS picks the engine's OS profile (the
169
+ // Windows vcpkg route and its pwsh.exe shell on a Windows host, the
170
+ // cmake route elsewhere).
171
+ emit(`engine build: ${request.engineId}\n`);
172
+ const build = await buildEngineRepo(request.host, request.engineId, directory, emit, request.platform?.buildCommands, ctx.hardware.os);
173
+ if (!build.ok) {
174
+ if (build.detail !== undefined) {
175
+ emit(`!! ${build.detail}\n`);
176
+ }
177
+ return {
178
+ ok: false,
179
+ ...(build.detail !== undefined ? { detail: build.detail } : {}),
180
+ };
181
+ }
182
+ return null;
183
+ }
184
+ /**
185
+ * runModelDownloadStep is the Get step's hf download of the selected model,
186
+ * skipped when the artifact is already present in the model directory (the
187
+ * hub cache under the cache layout; the single presence check the card's
188
+ * Model dropdown and the download route share), plus the Infernix extras a
189
+ * Get leaves ready to launch (the selected DFlash2 drafter and the PLE n-gram
190
+ * volume, pulled through the hf CLI into the model directory). A download
191
+ * failure aborts the run, so a launch never reads a missing model.
192
+ */
193
+ async function runModelDownloadStep(ctx) {
194
+ const { localInfer, request, target, emit } = ctx;
195
+ const modelId = typeof request.config.model === 'string' ? request.config.model : undefined;
196
+ if (modelId !== undefined) {
197
+ const entry = ctx.modelEntry;
198
+ if (entry === undefined) {
199
+ emit(`model download: ${modelId} has no registered default, skipped\n`);
200
+ }
201
+ else {
202
+ // The shared presence check resolves the deterministic hub-cache
203
+ // snapshot under the cache layout and joins the artifact onto the
204
+ // override under the flat layout (the target's base).
205
+ if (modelArtifactPresent(entry, target.baseDir, target.useHubCache)) {
206
+ emit(`model download: ${modelId} is already present, skipped\n`);
207
+ }
208
+ else {
209
+ // The download actually runs, so the step announces its download
210
+ // phase as it starts; an already-present artifact announces nothing.
211
+ request.onStep?.('download');
212
+ // The `$ <hf download ...>` line is written by the service's download
213
+ // exec site (through downloadOptions' onLog), so the command logs
214
+ // exactly once per run, from wherever the child actually spawns.
215
+ const download = await localInfer.downloadModel(entry, target.directory, downloadOptions(ctx));
216
+ if (!download.ok) {
217
+ emit(`!! ${download.detail ?? 'model download failed'}\n`);
218
+ return { ok: false, detail: download.detail ?? 'a model download failed' };
219
+ }
220
+ }
221
+ }
222
+ }
223
+ else {
224
+ emit('model download: no model selected, skipped\n');
225
+ }
226
+ if (request.engineId === 'infernix') {
227
+ const extras = infernixGetDownloads(request.config, target.directory, target.useHubCache);
228
+ if (extras.length > 0) {
229
+ // The extras actually download (even when the selected artifact was
230
+ // already present), so the step announces its download phase once here.
231
+ request.onStep?.('download');
232
+ }
233
+ for (const command of extras) {
234
+ emit(commandLogLine(command));
235
+ // The Infernix extra downloads stream through the host, so their tqdm
236
+ // lines reach the log sink and the onChunk progress sink together, the
237
+ // way the model and template downloads do. A caller that does not
238
+ // stream progress (onChunk absent) still lands the chunk in the log
239
+ // sink only.
240
+ const stream = request.host.runStream;
241
+ const outcome = stream !== undefined
242
+ ? await stream.call(request.host, command, (chunk) => {
243
+ emit(chunk);
244
+ ctx.onChunk?.(chunk);
245
+ }, {
246
+ ...(request.signal !== undefined ? { signal: request.signal } : {}),
247
+ })
248
+ : await request.host.run(command);
249
+ if (!outcome.ok) {
250
+ emit(`!! ${command} failed: ${outcome.detail ?? 'unknown'}\n`);
251
+ return { ok: false, detail: 'a model artifact download failed' };
252
+ }
253
+ // The plain-run fallback cannot stream, so the outcome's capped success
254
+ // output tail lands after the `$ <command>` line: the exec rule's
255
+ // append-results half, the way the streaming path already does.
256
+ if (stream === undefined &&
257
+ outcome.stdout !== undefined &&
258
+ outcome.stdout !== '') {
259
+ emit(outcome.stdout.endsWith('\n') ? outcome.stdout : `${outcome.stdout}\n`);
260
+ }
261
+ }
262
+ }
263
+ return null;
264
+ }
265
+ /**
266
+ * runChatTemplateStep is the Get step's hf download of the selected chat
267
+ * template (an HF repo reference the form's combo control offers), skipped
268
+ * when the template file is already present in the model directory.
269
+ */
270
+ async function runChatTemplateStep(ctx) {
271
+ const { localInfer, request, target, emit } = ctx;
272
+ const template = typeof request.config.chatTemplate === 'string' ? request.config.chatTemplate : '';
273
+ if (template !== '' && isHfRepoReference(template)) {
274
+ // Same shared presence check as the summary's template row: the cache
275
+ // layout resolves the deterministic snapshot, the flat layout joins onto
276
+ // the override.
277
+ if (chatTemplatePresent(template, target.baseDir, target.useHubCache)) {
278
+ emit(`chat template: ${template} is already present, skipped\n`);
279
+ }
280
+ else {
281
+ // The template download actually runs, so the step announces its
282
+ // download phase as it starts.
283
+ request.onStep?.('download');
284
+ // The `$ <hf chat-template ...>` line is written by the service's
285
+ // download exec site (through downloadOptions' onLog), logging once.
286
+ const download = await localInfer.downloadChatTemplate(template, target.directory, downloadOptions(ctx));
287
+ if (!download.ok) {
288
+ emit(`!! ${download.detail ?? 'chat template download failed'}\n`);
289
+ return { ok: false, detail: download.detail ?? 'a chat template download failed' };
290
+ }
291
+ }
292
+ }
293
+ return null;
294
+ }
295
+ /**
296
+ * runGetSteps is the shared Get-steps routine. It runs the five steps in
297
+ * order, streaming each through log and collecting the same text as the
298
+ * result's logs, so a caller can persist the run (a Get) or thread it into
299
+ * the launch's persisted logs (a Launch) without re-running the steps. A
300
+ * step that is already satisfied is skipped and logged as such; a failing
301
+ * step stops the run and names the broken step in the detail. A step that
302
+ * fails non-fatally (the git sync under the `continueOnSyncFailure`
303
+ * override) keeps the run going and threads `syncFailed` into the result, so
304
+ * the launch continues with the checkout's current version.
305
+ */
306
+ export async function runGetSteps(localInfer, request, log) {
307
+ const chunks = [];
308
+ const emit = (chunk) => {
309
+ chunks.push(chunk);
310
+ log(chunk);
311
+ };
312
+ // ENGINES is a known non-empty constant, so the fallback is always defined.
313
+ const engine = ENGINES.find((entry) => entry.id === request.engineId) ?? ENGINES[0];
314
+ // The shared resolution owns the layout rule: the hub-cache layout (no
315
+ // --local-dir, the models--{ns}--{name} dirs) applies only when the raw
316
+ // config names no model directory; a user override keeps the flat
317
+ // --local-dir target. The target's base is what the presence checks join
318
+ // onto, and its directory names the model directory the steps run: the
319
+ // override, the hub-cache snapshot holding a cached artifact (the hf
320
+ // download result), or the hub cache root when nothing is cached yet. The
321
+ // hub cache root comes from the service seam (created when absent), the
322
+ // same source the summary and the download routes read.
323
+ const selectedModelId = typeof request.config.model === 'string' ? request.config.model : undefined;
324
+ const modelEntry = selectedModelId === undefined ? undefined : defaultModelFor(request.engineId, selectedModelId);
325
+ const ctx = {
326
+ localInfer,
327
+ request,
328
+ engine,
329
+ directory: resolveEngineDirectory(request.engineId, request.platform),
330
+ target: resolveModelDirectory(request.config.modelDirectory, modelEntry, localInfer.defaultModelDirectory()),
331
+ ...(modelEntry !== undefined ? { modelEntry } : {}),
332
+ hardware: await localInfer.detectHardware(),
333
+ emit,
334
+ ...(request.onChunk !== undefined ? { onChunk: request.onChunk } : {}),
335
+ };
336
+ ctx.emit(`get ${request.engineId} in ${ctx.directory}\n`);
337
+ // A non-fatal sync failure (the `continueOnSyncFailure` override) keeps the
338
+ // run going through the remaining steps; the flag threads into the result
339
+ // so the launch skips the deploy's own git sync and launches the checkout's
340
+ // current version.
341
+ let syncFailed = false;
342
+ for (const step of [runDepsStep, runSyncBuildStep, runModelDownloadStep, runChatTemplateStep]) {
343
+ const failure = await step(ctx);
344
+ if (failure !== null) {
345
+ if ('kind' in failure) {
346
+ syncFailed = true;
347
+ continue;
348
+ }
349
+ return { ...failure, logs: chunks.join('') };
350
+ }
351
+ }
352
+ ctx.emit('get complete\n');
353
+ return {
354
+ ok: true,
355
+ logs: chunks.join(''),
356
+ ...(syncFailed ? { syncFailed: true } : {}),
357
+ };
358
+ }
359
+ //# sourceMappingURL=get-steps.js.map
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The hf CLI download operations: downloadFor runs the download for a default
3
+ * model, and chatTemplateDownloadFor pulls a selected chat template into the
4
+ * model directory. Both resolve the directory through resolveDownloadTarget
5
+ * (the request, the stored config, and the hub cache root in that order,
6
+ * through the shared override rule), so the hub-cache layout rule has one
7
+ * home across the download routes and the card.
8
+ * @module dsh-plugin-local-infer/ui/ops/hf
9
+ */
10
+ import type { DownloadResult, LocalInferService } from 'dsh-plugin-local-infer/service';
11
+ import type { ChatTemplateDownloadRequest, DownloadRequest } from '../request.ts';
12
+ /**
13
+ * downloadFor runs the hf CLI download for the request's default model: it
14
+ * resolves the entry through the providers' default list (a 404 when no
15
+ * entry names the pair), resolves the directory through
16
+ * resolveDownloadTarget, and runs the download through the service. The run
17
+ * brackets one live hub run under the runLogKey rule keyed on the entry's
18
+ * engine and model (a draft falls back to the engine id): the seed is the
19
+ * "Downloading..." separator, the hf CLI's streamed chunks append as they
20
+ * land, and the settled completion or failure line reaches the hub and the
21
+ * persisted run from one text before the run ends. The optional signal is
22
+ * the card's cancel (the download route's response-close abort, the Get and
23
+ * launch routes' rule): an abort interrupts the in-flight hf child (SIGINT,
24
+ * then SIGTERM) and the run carries the shared "Canceled" line, live and
25
+ * persisted.
26
+ */
27
+ export declare function downloadFor(localInfer: LocalInferService, request: DownloadRequest, signal?: AbortSignal): Promise<DownloadResult>;
28
+ /**
29
+ * chatTemplateDownloadFor runs the hf CLI download for the request's chat
30
+ * template: it resolves the template repo reference from the request or the
31
+ * stored config's chatTemplate (a 400 when neither names an HF repo
32
+ * reference), resolves the directory through resolveDownloadTarget, and
33
+ * runs the download through the service. The run brackets one live hub run
34
+ * under the "Downloading..." seed and the runLogKey rule (the stored entry
35
+ * matching the engine and model, else the engine id): the hf CLI's streamed
36
+ * chunks append as they land, and the run ends at settle. The optional
37
+ * signal is the card's cancel (the chat-template route's response-close
38
+ * abort, the Get and launch routes' rule): an abort interrupts the in-flight
39
+ * hf child and the live run carries the shared "Canceled" line.
40
+ */
41
+ export declare function chatTemplateDownloadFor(localInfer: LocalInferService, request: ChatTemplateDownloadRequest, signal?: AbortSignal): Promise<DownloadResult>;
42
+ //# sourceMappingURL=hf.d.ts.map
@@ -0,0 +1,150 @@
1
+ /**
2
+ * The hf CLI download operations: downloadFor runs the download for a default
3
+ * model, and chatTemplateDownloadFor pulls a selected chat template into the
4
+ * model directory. Both resolve the directory through resolveDownloadTarget
5
+ * (the request, the stored config, and the hub cache root in that order,
6
+ * through the shared override rule), so the hub-cache layout rule has one
7
+ * home across the download routes and the card.
8
+ * @module dsh-plugin-local-infer/ui/ops/hf
9
+ */
10
+ import { isModelDirectoryOverridden, modelDownloadTarget } from '../../../core/lib/index.js';
11
+ import { runLogKey } from '../../../service/lib/index.js';
12
+ import { defaultModelFor } from '../../../providers/lib/index.js';
13
+ import { readConfig } from "../config.js";
14
+ import { CANCELED_LINE, DOWNLOAD_RUN_SEED, persistProcessLog } from "./logs.js";
15
+ import { RouteError } from "../route.js";
16
+ import { isHfRepoReference } from "../viewmodels/summaryHelpers.js";
17
+ /**
18
+ * resolveDownloadTarget resolves the directory a download route targets: the
19
+ * request's directory, the stored config's model directory, and the hub
20
+ * cache root, in that order. The first named directory wins (the shared
21
+ * override predicate), then the shared modelDownloadTarget rule decides the
22
+ * layout: a named directory keeps the flat --local-dir target; only when
23
+ * neither names one does the hub-cache layout apply, based on the hub cache
24
+ * root (the service seam: the hf CLI's own download home, which resolves its
25
+ * own snapshot destination and creates the directory when absent), so a
26
+ * download never materializes a snapshot-directory or hub-root override into
27
+ * the config.
28
+ */
29
+ function resolveDownloadTarget(localInfer, requestDirectory, stored) {
30
+ const named = isModelDirectoryOverridden(requestDirectory)
31
+ ? requestDirectory
32
+ : stored.config.modelDirectory;
33
+ return modelDownloadTarget(named, localInfer.defaultModelDirectory());
34
+ }
35
+ /**
36
+ * downloadFor runs the hf CLI download for the request's default model: it
37
+ * resolves the entry through the providers' default list (a 404 when no
38
+ * entry names the pair), resolves the directory through
39
+ * resolveDownloadTarget, and runs the download through the service. The run
40
+ * brackets one live hub run under the runLogKey rule keyed on the entry's
41
+ * engine and model (a draft falls back to the engine id): the seed is the
42
+ * "Downloading..." separator, the hf CLI's streamed chunks append as they
43
+ * land, and the settled completion or failure line reaches the hub and the
44
+ * persisted run from one text before the run ends. The optional signal is
45
+ * the card's cancel (the download route's response-close abort, the Get and
46
+ * launch routes' rule): an abort interrupts the in-flight hf child (SIGINT,
47
+ * then SIGTERM) and the run carries the shared "Canceled" line, live and
48
+ * persisted.
49
+ */
50
+ export async function downloadFor(localInfer, request, signal) {
51
+ const stored = readConfig();
52
+ const engineId = request.engine ?? stored.engine;
53
+ const modelId = request.model ?? (typeof stored.config.model === 'string' ? stored.config.model : '');
54
+ const entry = defaultModelFor(engineId, modelId);
55
+ if (entry === undefined) {
56
+ throw new RouteError(404, `no default model is registered for "${engineId}/${modelId}"`);
57
+ }
58
+ const { baseDir, useHubCache } = resolveDownloadTarget(localInfer, request.directory, stored);
59
+ // The key rule prices the model this download fetches, so the run lands on
60
+ // the stored entry for that engine and model, not the draft's.
61
+ const runKey = runLogKey(stored.providers, engineId, undefined, {
62
+ ...stored.config,
63
+ ...(modelId === '' ? {} : { model: modelId }),
64
+ });
65
+ localInfer.beginRun(runKey, DOWNLOAD_RUN_SEED);
66
+ // The service writes the rendered hf command's `$ <command>` line through
67
+ // onLog before it spawns the child: it streams into the live hub right away
68
+ // and rides the persisted section below, so the command line reads exactly
69
+ // once per run in both readers, ahead of the CLI's output.
70
+ let commandLine = '';
71
+ try {
72
+ const result = await localInfer.downloadModel(entry, baseDir, {
73
+ useHubCache,
74
+ ...(signal !== undefined ? { signal } : {}),
75
+ onChunk: (chunk) => {
76
+ localInfer.appendRunLog(runKey, chunk);
77
+ },
78
+ onLog: (line) => {
79
+ commandLine += line;
80
+ localInfer.appendRunLog(runKey, line);
81
+ },
82
+ });
83
+ // The settle line reads the same in the live run and the persisted one:
84
+ // the "Downloading..." separator leads the stored run so the Logs
85
+ // section and the log file read the download as a fresh process section.
86
+ // A cancel appends the shared "Canceled" line, the Get and launch
87
+ // routes' mark, so the run reads as canceled wherever it is read.
88
+ const line = result.ok
89
+ ? 'download complete\n'
90
+ : `!! download failed${result.detail !== undefined ? `: ${result.detail}` : ''}\n`;
91
+ const settled = signal?.aborted === true ? `${line}${CANCELED_LINE}` : line;
92
+ localInfer.appendRunLog(runKey, settled);
93
+ persistProcessLog(`${DOWNLOAD_RUN_SEED}${commandLine}${settled}`);
94
+ return result;
95
+ }
96
+ finally {
97
+ localInfer.endRun(runKey);
98
+ }
99
+ }
100
+ /**
101
+ * chatTemplateDownloadFor runs the hf CLI download for the request's chat
102
+ * template: it resolves the template repo reference from the request or the
103
+ * stored config's chatTemplate (a 400 when neither names an HF repo
104
+ * reference), resolves the directory through resolveDownloadTarget, and
105
+ * runs the download through the service. The run brackets one live hub run
106
+ * under the "Downloading..." seed and the runLogKey rule (the stored entry
107
+ * matching the engine and model, else the engine id): the hf CLI's streamed
108
+ * chunks append as they land, and the run ends at settle. The optional
109
+ * signal is the card's cancel (the chat-template route's response-close
110
+ * abort, the Get and launch routes' rule): an abort interrupts the in-flight
111
+ * hf child and the live run carries the shared "Canceled" line.
112
+ */
113
+ export async function chatTemplateDownloadFor(localInfer, request, signal) {
114
+ const stored = readConfig();
115
+ let template = typeof request.template === 'string' ? request.template : '';
116
+ if (template.trim() === '') {
117
+ template = typeof stored.config.chatTemplate === 'string' ? stored.config.chatTemplate : '';
118
+ }
119
+ if (!isHfRepoReference(template)) {
120
+ throw new RouteError(400, `the chat template must be an HF repo reference, got "${template || '(none)'}"`);
121
+ }
122
+ const { baseDir, useHubCache } = resolveDownloadTarget(localInfer, request.directory, stored);
123
+ const runKey = runLogKey(stored.providers, request.engine ?? stored.engine, undefined, stored.config);
124
+ localInfer.beginRun(runKey, DOWNLOAD_RUN_SEED);
125
+ try {
126
+ const result = await localInfer.downloadChatTemplate(template, baseDir, {
127
+ useHubCache,
128
+ ...(signal !== undefined ? { signal } : {}),
129
+ onChunk: (chunk) => {
130
+ localInfer.appendRunLog(runKey, chunk);
131
+ },
132
+ // The service writes the rendered chat-template pull's `$ <command>`
133
+ // line through onLog before it spawns the child, so the live run reads
134
+ // the command ahead of the CLI's output, exactly once.
135
+ onLog: (line) => {
136
+ localInfer.appendRunLog(runKey, line);
137
+ },
138
+ });
139
+ // A cancel marks the live run canceled; the template pull's outcome
140
+ // rides the card's template cell, not the persisted run, so no persist.
141
+ if (signal?.aborted === true) {
142
+ localInfer.appendRunLog(runKey, CANCELED_LINE);
143
+ }
144
+ return result;
145
+ }
146
+ finally {
147
+ localInfer.endRun(runKey);
148
+ }
149
+ }
150
+ //# sourceMappingURL=hf.js.map