dsh-plugin-local-infer 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +4 -1
  2. package/docs/zh/README.md +4 -1
  3. package/dsh/client.js +627 -133
  4. package/package.json +11 -10
  5. package/packages/core/lib/adapter.d.ts +75 -4
  6. package/packages/core/lib/index.d.ts +2 -1
  7. package/packages/core/lib/index.js +1 -0
  8. package/packages/core/lib/launch-command.d.ts +13 -0
  9. package/packages/core/lib/launch-command.js +64 -0
  10. package/packages/core/lib/models.d.ts +2 -1
  11. package/packages/core/lib/models.js +10 -1
  12. package/packages/core/lib/status.d.ts +9 -1
  13. package/packages/core/lib/status.js +6 -1
  14. package/packages/providers/lib/acquire.d.ts +125 -0
  15. package/packages/providers/lib/acquire.js +325 -0
  16. package/packages/providers/lib/adapters.d.ts +42 -5
  17. package/packages/providers/lib/adapters.js +385 -57
  18. package/packages/providers/lib/deps.d.ts +4 -2
  19. package/packages/providers/lib/deps.js +16 -2
  20. package/packages/providers/lib/engines.d.ts +4 -3
  21. package/packages/providers/lib/engines.js +11 -3
  22. package/packages/providers/lib/guidelines.js +16 -0
  23. package/packages/providers/lib/index.d.ts +9 -3
  24. package/packages/providers/lib/index.js +8 -4
  25. package/packages/providers/lib/infernix.d.ts +170 -0
  26. package/packages/providers/lib/infernix.js +671 -0
  27. package/packages/providers/lib/model-defaults.d.ts +5 -3
  28. package/packages/providers/lib/model-defaults.js +27 -3
  29. package/packages/providers/lib/ninfer.d.ts +7 -0
  30. package/packages/providers/lib/ninfer.js +9 -2
  31. package/packages/providers/lib/platform.d.ts +31 -0
  32. package/packages/providers/lib/platform.js +58 -0
  33. package/packages/service/lib/index.d.ts +61 -18
  34. package/packages/service/lib/index.js +278 -42
  35. package/packages/service/lib/types.d.ts +44 -2
  36. package/packages/ui/lib/route.d.ts +83 -12
  37. package/packages/ui/lib/route.js +495 -55
  38. package/packages/ui/package.json +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-local-infer",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -22,6 +22,7 @@
22
22
  ],
23
23
  "license": "MIT",
24
24
  "type": "module",
25
+ "packageManager": "pnpm@12.11.2",
25
26
  "engines": {
26
27
  "node": "^22.19.0 || >=24.0.0"
27
28
  },
@@ -85,6 +86,14 @@
85
86
  "peerDependencies": {
86
87
  "@deepseek-ai/cordis": ">=4.0.5-alpha.2"
87
88
  },
89
+ "scripts": {
90
+ "build": "tsc -b",
91
+ "typecheck": "tsc -b",
92
+ "test": "vitest run",
93
+ "test:coverage": "vitest run --coverage",
94
+ "lint": "eslint .",
95
+ "clean": "tsc -b --clean"
96
+ },
88
97
  "devDependencies": {
89
98
  "@eslint/js": "^10.0.1",
90
99
  "@types/node": "^22.10.0",
@@ -94,13 +103,5 @@
94
103
  "typescript-eslint": "^8.71.2",
95
104
  "vite-tsconfig-paths": "^5.1.4",
96
105
  "vitest": "^5.0.4"
97
- },
98
- "scripts": {
99
- "build": "tsc -b",
100
- "typecheck": "tsc -b",
101
- "test": "vitest run",
102
- "test:coverage": "vitest run --coverage",
103
- "lint": "eslint .",
104
- "clean": "tsc -b --clean"
105
106
  }
106
- }
107
+ }
@@ -21,6 +21,7 @@ export interface LaunchPlan {
21
21
  env?: Record<string, string>;
22
22
  composeFile?: string;
23
23
  profile?: string;
24
+ composeArgs?: string;
24
25
  containerName?: string;
25
26
  modelId?: string;
26
27
  modelDirectory?: string;
@@ -32,12 +33,31 @@ export interface LaunchPlan {
32
33
  * specific engine: where the engine platform lives locally (the checkout and
33
34
  * build location) and the git repo that overrides the engine's default
34
35
  * upstream for this config. The deploy step consumes both: it clones the fork
35
- * (or the default upstream) into the engine directory.
36
+ * (or the default upstream) into the engine directory. `buildCommands`
37
+ * overrides the engine's local build command (the local build mode) and
38
+ * `dockerTag` overrides the docker image tag the docker deploy pulls (the
39
+ * docker build mode); each rides the platform map, so an engine switch keeps
40
+ * them.
36
41
  */
37
42
  export interface EnginePlatformConfig {
38
43
  engineId: string;
39
44
  engineDirectory?: string;
40
45
  engineFork?: string;
46
+ buildCommands?: string;
47
+ dockerTag?: string;
48
+ }
49
+ /**
50
+ * ProcessExitInfo is the one-shot answer to a spawned process's lifetime end:
51
+ * the exit code (null when a signal or a spawn failure ended it), the signal
52
+ * name (null when the process exited on its own), and the spawn error message
53
+ * when the child never ran (a missing binary). The host emits it exactly once
54
+ * per child, from the close event or the error event, so a crash or a pkill
55
+ * reaches the plugin's state through one seam instead of an uncaughtException.
56
+ */
57
+ export interface ProcessExitInfo {
58
+ code: number | null;
59
+ signal: string | null;
60
+ error?: string;
41
61
  }
42
62
  /**
43
63
  * ProcessHandle is the handle to a spawned engine process: its pid and a kill
@@ -46,12 +66,17 @@ export interface EnginePlatformConfig {
46
66
  * the host captures the child's stdout and stderr, is the accumulated output
47
67
  * the launch step surfaces in the card's Logs section and writes to the log
48
68
  * file. A host that does not capture streams (a container it cannot read)
49
- * omits it.
69
+ * omits it. `onExit`, when the host watches the child, registers a listener
70
+ * fired once with the ProcessExitInfo when the child ends (a crash, a signal
71
+ * like a pkill, or a clean stop); a listener registered after the child has
72
+ * already ended fires immediately. A host that cannot watch (a stub, or a
73
+ * container it cannot read) omits it.
50
74
  */
51
75
  export interface ProcessHandle {
52
76
  pid: number;
53
77
  kill(): void;
54
78
  logs?: string;
79
+ onExit?(listener: (exit: ProcessExitInfo) => void): void;
55
80
  }
56
81
  /**
57
82
  * FetchResult is the answer to a health poll: the HTTP status and whether it
@@ -71,6 +96,15 @@ export interface FetchResult {
71
96
  */
72
97
  export interface LifecycleHost {
73
98
  run(command: string): Promise<CommandOutcome>;
99
+ /**
100
+ * Optional: run a command line and stream each stdout/stderr chunk to
101
+ * onOutput while it runs, so the Get step can append build output to the
102
+ * card's Logs section as it lands. A host that cannot stream omits it,
103
+ * and the caller falls back to run. No overall timeout: a full CUDA
104
+ * build legitimately runs past any fixed cap, and the card prices a
105
+ * stalled step with its own output-idle watchdog.
106
+ */
107
+ runStream?(command: string, onOutput: (chunk: string) => void): Promise<CommandOutcome>;
74
108
  spawn(argv: readonly string[], env: Record<string, string>, cwd?: string): ProcessHandle;
75
109
  fetch(url: string): Promise<FetchResult>;
76
110
  debug?: DebugLogger;
@@ -84,6 +118,23 @@ export interface HealthCheckOptions {
84
118
  pollMs?: number;
85
119
  maxAttempts?: number;
86
120
  }
121
+ /**
122
+ * LaunchStep is the phase of a launch the card's Launch control prices: the
123
+ * system-dependency install (prereqs), the model and git checkout download
124
+ * (download), the source build or image pull (build), and the health poll that
125
+ * waits for the engine to come ready (launch). The service and the adapters
126
+ * report the step as each phase begins, so the card's button reads the phase
127
+ * that is actually running instead of a single "Launching..." for the whole
128
+ * rebuild. The card times out only the launch step; the rebuild steps (prereqs,
129
+ * download, build) run as long as they need to.
130
+ */
131
+ export type LaunchStep = 'prereqs' | 'download' | 'build' | 'launch';
132
+ /**
133
+ * LaunchProgress is the callback the launch flow calls as each phase begins.
134
+ * The route threads it from the streamed launch response through the service
135
+ * and the adapter's deploy step; a launch with no progress sink omits it.
136
+ */
137
+ export type LaunchProgress = (step: LaunchStep) => void;
87
138
  /**
88
139
  * HealthResult is the answer to a /health poll: whether the engine is up, the
89
140
  * HTTP status, and a detail string for the UI.
@@ -93,17 +144,37 @@ export interface HealthResult {
93
144
  status?: number;
94
145
  detail?: string;
95
146
  }
147
+ /**
148
+ * DeployOptions tunes a deploy run: `allowRunDeps` is the Play/Run trust gate
149
+ * (the card's "Allow one-click install (sudo)" checkbox). A local deploy that
150
+ * rebuilds the engine and leaves its binary out of the path links it into
151
+ * /usr/local/bin; the gate decides whether that sudo link runs (on) or is
152
+ * written to the card's Logs section for the user to run (off). `autoRebuild`
153
+ * is the card's "Auto Rebuild" checkbox: when false, the git sync (fetch,
154
+ * rebase, and the conditional rebuild) is skipped and the checkout launches
155
+ * as-is. Absent reads as true (the rebuild runs).
156
+ */
157
+ export interface DeployOptions {
158
+ allowRunDeps?: boolean;
159
+ autoRebuild?: boolean;
160
+ }
96
161
  /**
97
162
  * DeployResult reports whether a build-or-pull succeeded, with a detail for the
98
163
  * UI. `handle` is the spawned engine process when the deploy step started one
99
164
  * locally: the service reads its accumulated `logs` after the health poll, so
100
165
  * the launch result carries the engine's output for the card's Logs section and
101
- * the log file. A deploy that only pulls an image omits it.
166
+ * the log file, and attaches the handle's `onExit` listener to learn of a crash
167
+ * or a pkill. A deploy that starts no process (a compose up) omits it. `logs`
168
+ * is the deploy step's own captured output (the rebuild decision, the build
169
+ * command, and its output) the service prepends to the engine's output, so the
170
+ * card's Logs section shows the build a launch ran. A deploy that runs no
171
+ * rebuild (a docker pull, a compose up) omits it.
102
172
  */
103
173
  export interface DeployResult {
104
174
  ok: boolean;
105
175
  detail?: string;
106
176
  handle?: ProcessHandle;
177
+ logs?: string;
107
178
  }
108
179
  /**
109
180
  * EngineAdapter is the abstract base one subclass implements per engine. It
@@ -123,7 +194,7 @@ export declare abstract class EngineAdapter {
123
194
  abstract parameters(): readonly ParameterSpec[];
124
195
  abstract renderLaunch(config: Config, hw: HardwareProfile): LaunchPlan;
125
196
  abstract healthCheck(plan: LaunchPlan, options?: HealthCheckOptions): Promise<HealthResult>;
126
- abstract deploy(plan: LaunchPlan, platform?: EnginePlatformConfig): Promise<DeployResult>;
197
+ abstract deploy(plan: LaunchPlan, platform?: EnginePlatformConfig, onProgress?: LaunchProgress, options?: DeployOptions): Promise<DeployResult>;
127
198
  abstract stop(plan: LaunchPlan): Promise<void>;
128
199
  /**
129
200
  * Optional: the host deps this engine's deploy step needs for a build mode,
@@ -13,13 +13,14 @@ export { DEFAULT_OS_RESERVE_MIB, estimateVram, KV_PAGE_TOKENS, pageRoundUp, TIGH
13
13
  export type { EstimateContext, EstimateOptions, SpeculationTerms, VramBreakdown, VramContribution, VramEstimate, VramModel, VramVerdict, } from './estimator.ts';
14
14
  export { GPU_USAGE_BUSY_THRESHOLD, matchLaunchSignature, parseNvidiaSmiGpuUsage, resolveOsReserve, } from './reserve.ts';
15
15
  export { commandMatchesArgv, launchRecordFromPlan, reLinkRecord, } from './launch-record.ts';
16
+ export { formatLaunchCommand } from './launch-command.ts';
16
17
  export type { ProviderLaunchRecord, ReLinkInput, ReLinkOutcome, } from './launch-record.ts';
17
18
  export type { EngineLaunchSignature, GpuUsageProbe, ProcessLine, ReserveResolution, ReserveSource, } from './reserve.ts';
18
19
  export { computeProviderStatuses, isGpuBusy, } from './status.ts';
19
20
  export type { ProviderRef, ProviderStatus, ProviderStatusInput, RunningEngineRef, } from './status.ts';
20
21
  export { DEFAULT_LOG_PATH_TEMPLATE, LOG_FILE_NAME_TEMPLATE, LOG_TEMPLATE_ENGINE, LOG_TEMPLATE_HOME, LOG_TEMPLATE_MODEL, LOG_TEMPLATE_TIMESTAMP, formatLogTimestamp, resolveLogPath, slugifyModelName, } from './logs.ts';
21
22
  export { EngineAdapter } from './adapter.ts';
22
- export type { DeployResult, EnginePlatformConfig, FetchResult, HealthCheckOptions, HealthResult, LaunchPlan, LifecycleHost, ProcessHandle, } from './adapter.ts';
23
+ export type { DeployOptions, DeployResult, EnginePlatformConfig, FetchResult, HealthCheckOptions, HealthResult, LaunchPlan, LaunchProgress, LaunchStep, LifecycleHost, ProcessExitInfo, ProcessHandle, } from './adapter.ts';
23
24
  export { NOOP_DEBUG_LOGGER, createCommandDebugLogger, isHarnessLogDebug, } from './debug.ts';
24
25
  export type { CreateCommandDebugLoggerArgs, DebugLogger, } from './debug.ts';
25
26
  export { constraintId, evaluateGuidelines, modelGuidelines } from './guideline.ts';
@@ -9,6 +9,7 @@ export { detectHardware, parseNvidiaSmiGpu, } from "./hardware.js";
9
9
  export { DEFAULT_OS_RESERVE_MIB, estimateVram, KV_PAGE_TOKENS, pageRoundUp, TIGHT_HEADROOM_BYTES, } from "./estimator.js";
10
10
  export { GPU_USAGE_BUSY_THRESHOLD, matchLaunchSignature, parseNvidiaSmiGpuUsage, resolveOsReserve, } from "./reserve.js";
11
11
  export { commandMatchesArgv, launchRecordFromPlan, reLinkRecord, } from "./launch-record.js";
12
+ export { formatLaunchCommand } from "./launch-command.js";
12
13
  export { computeProviderStatuses, isGpuBusy, } from "./status.js";
13
14
  export { DEFAULT_LOG_PATH_TEMPLATE, LOG_FILE_NAME_TEMPLATE, LOG_TEMPLATE_ENGINE, LOG_TEMPLATE_HOME, LOG_TEMPLATE_MODEL, LOG_TEMPLATE_TIMESTAMP, formatLogTimestamp, resolveLogPath, slugifyModelName, } from "./logs.js";
14
15
  export { EngineAdapter } from "./adapter.js";
@@ -0,0 +1,13 @@
1
+ import type { LaunchPlan } from './adapter.ts';
2
+ /**
3
+ * formatLaunchCommand renders a launch plan as the shell command string the
4
+ * deploy step runs to start the engine: the quoted argv joined for a process
5
+ * or docker plan, or the `docker compose up` line for a compose plan. The
6
+ * card's Logs section shows the line above the engine's own output, so a
7
+ * user can read and copy the exact binary and arguments a launch started
8
+ * with. The Hyper-Qwen deploy runs this same string, so the printed line and
9
+ * the host command cannot drift. Returns undefined when the plan names no
10
+ * command (a non-compose plan with no argv).
11
+ */
12
+ export declare function formatLaunchCommand(plan: LaunchPlan): string | undefined;
13
+ //# sourceMappingURL=launch-command.d.ts.map
@@ -0,0 +1,64 @@
1
+ /**
2
+ * formatLaunchCommand renders a launch plan as the shell command string the
3
+ * deploy step runs to start the engine: the quoted argv joined for a process
4
+ * or docker plan, or the `docker compose up` line for a compose plan. The
5
+ * card's Logs section shows the line above the engine's own output, so a
6
+ * user can read and copy the exact binary and arguments a launch started
7
+ * with. The Hyper-Qwen deploy runs this same string, so the printed line and
8
+ * the host command cannot drift. Returns undefined when the plan names no
9
+ * command (a non-compose plan with no argv).
10
+ */
11
+ export function formatLaunchCommand(plan) {
12
+ if (plan.kind === 'compose') {
13
+ // The user's compose arguments (the card's docker-tag field) override the
14
+ // default profile: the flags the up step runs before the required `up -d`.
15
+ // An empty field reads as "use the default profile", so the up step falls
16
+ // back to the engine's own default.
17
+ const composeArgs = plan.composeArgs?.split(/\s+/).filter((token) => token !== '');
18
+ if (composeArgs !== undefined && composeArgs.length > 0) {
19
+ return [
20
+ 'docker',
21
+ 'compose',
22
+ '-f',
23
+ plan.composeFile ?? 'docker-compose.yml',
24
+ ...composeArgs,
25
+ 'up',
26
+ '-d',
27
+ ]
28
+ .map(quoteArg)
29
+ .join(' ');
30
+ }
31
+ // The compose defaults match the adapter's renderLaunch fallbacks, so a
32
+ // plan built from a bare config still spells a runnable command.
33
+ return [
34
+ 'docker',
35
+ 'compose',
36
+ '-f',
37
+ plan.composeFile ?? 'docker-compose.yml',
38
+ '--profile',
39
+ plan.profile ?? 'single',
40
+ 'up',
41
+ '--pull',
42
+ 'always',
43
+ '-d',
44
+ ]
45
+ .map(quoteArg)
46
+ .join(' ');
47
+ }
48
+ const argv = plan.argv;
49
+ if (argv === undefined || argv.length === 0)
50
+ return undefined;
51
+ return argv.map(quoteArg).join(' ');
52
+ }
53
+ /**
54
+ * quoteArg renders one argv token for display: a token made only of shell-
55
+ * safe characters rides bare, anything else lands in single quotes with
56
+ * embedded quotes escaped, so the printed line pastes back into a shell
57
+ * unchanged.
58
+ */
59
+ function quoteArg(token) {
60
+ if (token !== '' && /^[A-Za-z0-9@%+=:,./_-]+$/.test(token))
61
+ return token;
62
+ return `'${token.replaceAll("'", "'\\''")}'`;
63
+ }
64
+ //# sourceMappingURL=launch-command.js.map
@@ -67,7 +67,8 @@ export interface ModelDirectoryEntry {
67
67
  /**
68
68
  * modelEntriesForEngine filters a model directory listing down to the model
69
69
  * entries the engine's Model dropdown offers: NInfer takes `.ninfer`
70
- * artifacts, llama.cpp takes `.gguf` files, and Hyper-Qwen takes the repo
70
+ * artifacts, Infernix takes `.ninfer` artifacts and its own `.infernix`
71
+ * files, llama.cpp takes `.gguf` files, and Hyper-Qwen takes the repo
71
72
  * directories that hold a `.safetensors` weight file. Every other engine
72
73
  * (Strata) offers nothing, matching its empty default list. The result is
73
74
  * sorted, so the dropdown order is stable across summary fetches.
@@ -61,7 +61,8 @@ export function hfChatTemplateCommand(repo, directory) {
61
61
  /**
62
62
  * modelEntriesForEngine filters a model directory listing down to the model
63
63
  * entries the engine's Model dropdown offers: NInfer takes `.ninfer`
64
- * artifacts, llama.cpp takes `.gguf` files, and Hyper-Qwen takes the repo
64
+ * artifacts, Infernix takes `.ninfer` artifacts and its own `.infernix`
65
+ * files, llama.cpp takes `.gguf` files, and Hyper-Qwen takes the repo
65
66
  * directories that hold a `.safetensors` weight file. Every other engine
66
67
  * (Strata) offers nothing, matching its empty default list. The result is
67
68
  * sorted, so the dropdown order is stable across summary fetches.
@@ -74,6 +75,14 @@ export function modelEntriesForEngine(entries, engineId) {
74
75
  .filter((entry) => !entry.isDirectory && entry.name.endsWith('.ninfer'))
75
76
  .map((entry) => entry.name);
76
77
  break;
78
+ case 'infernix':
79
+ // Infernix loads NInfer artifacts unchanged plus its own `.infernix`
80
+ // files, so the dropdown offers both extensions.
81
+ names = entries
82
+ .filter((entry) => !entry.isDirectory &&
83
+ (entry.name.endsWith('.ninfer') || entry.name.endsWith('.infernix')))
84
+ .map((entry) => entry.name);
85
+ break;
77
86
  case 'llamacpp':
78
87
  names = entries
79
88
  .filter((entry) => !entry.isDirectory && entry.name.endsWith('.gguf'))
@@ -1,4 +1,5 @@
1
1
  import type { GpuUsageProbe } from './reserve.ts';
2
+ import type { Config } from './config.ts';
2
3
  /**
3
4
  * ProviderStatus is the running-state the plugin card paints each saved
4
5
  * provider's status dot: green while the engine is confirmed serving the
@@ -10,12 +11,19 @@ export type ProviderStatus = 'running' | 'stopped' | 'unsure';
10
11
  * ProviderRef is the identity side of one saved provider config: the stable
11
12
  * id the card renders and the engine and model it serves. The model is
12
13
  * optional because a config that names no model cannot be confirmed against
13
- * a running engine, and reads as unsure rather than a guess.
14
+ * a running engine, and reads as unsure rather than a guess. The config is
15
+ * optional and lets the detector price the provider's own launch signature
16
+ * (the engine binary the build mode runs, the port it binds) rather than the
17
+ * adapter's default-port signature; the port is the resolved bind port the
18
+ * detector read from that signature, and the resolver ties a running engine
19
+ * to the provider only when the ports agree.
14
20
  */
15
21
  export interface ProviderRef {
16
22
  id: string;
17
23
  engine: string;
18
24
  model?: string;
25
+ config?: Config;
26
+ port?: number;
19
27
  }
20
28
  /**
21
29
  * RunningEngineRef is one engine the detector confirmed live: the engine id,
@@ -28,7 +28,12 @@ export function isGpuBusy(usage) {
28
28
  export function computeProviderStatuses(input) {
29
29
  const statuses = {};
30
30
  for (const provider of input.providers) {
31
- const matches = input.running.filter((ref) => ref.engineId === provider.engine);
31
+ // A provider that names a port only counts an engine running on that
32
+ // port: two configs of one engine on different ports are distinct
33
+ // engines, and a match on the other port must not confirm (or deny) this
34
+ // config's model. An unnamed port keeps the engine-wide match.
35
+ const matches = input.running.filter((ref) => ref.engineId === provider.engine &&
36
+ (provider.port === undefined || ref.port === undefined || ref.port === provider.port));
32
37
  if (matches.length > 0) {
33
38
  // The engine is running. The question is which model it serves: the
34
39
  // detector's identified model, if it tied one, else unknown.
@@ -0,0 +1,125 @@
1
+ /**
2
+ * The per-engine acquisition data and the Get step. Each engine declares its
3
+ * git source (the upstream repo, the branch the rebase targets, and the build
4
+ * steps the checkout runs) as data here; the adapters' deploy steps and the
5
+ * /local-infer/get route both consume the same constants, so a build command
6
+ * has one home. The sync step clones a missing checkout, and a clean existing
7
+ * checkout is fetched and rebased onto the upstream branch; a checkout with
8
+ * local changes aborts, because a rebase would eat the user's work.
9
+ * @module dsh-plugin-local-infer/providers/acquire
10
+ */
11
+ import type { LifecycleHost } from '../../core/lib/index.js';
12
+ /**
13
+ * EngineSource is the per-engine acquisition data: the upstream git repo the
14
+ * clone step uses when no fork is provided, the branch the fetch/rebase step
15
+ * rebases onto, and the build steps run in the checkout after a clone or a
16
+ * rebase. A build step is a shell command line; the `{dir}` placeholder is
17
+ * replaced with the checkout directory before the step runs.
18
+ */
19
+ export interface EngineSource {
20
+ repo: string;
21
+ branch: string;
22
+ buildSteps: readonly string[];
23
+ }
24
+ /**
25
+ * The remote name a user-provided fork is added under, so the checkout's own
26
+ * origin (the upstream it was cloned from) survives the fork override.
27
+ */
28
+ export declare const FORK_REMOTE = "dsh-fork";
29
+ /**
30
+ * The per-engine git sources, keyed by engine id. NInfer and Infernix build
31
+ * through cmake (Infernix through its own preset); llama.cpp builds through
32
+ * the same cmake shape as NInfer; Hyper-Qwen is the compose-driven vLLM
33
+ * engine, so it carries no local build steps (the compose up pulls the
34
+ * image); Strata is the placeholder engine, and its repo and pull step land
35
+ * with the engine, the same way its docker image constant did.
36
+ */
37
+ export declare const ENGINE_SOURCES: Record<string, EngineSource>;
38
+ /**
39
+ * AcquireLog receives one line (or chunk) of Get output as it lands, so the
40
+ * route can stream it to the card's Logs section.
41
+ */
42
+ export type AcquireLog = (chunk: string) => void;
43
+ /**
44
+ * EngineStepResult reports one Get step (sync or build): whether it passed,
45
+ * whether it aborted on a rule (a dirty checkout), and a detail the Logs
46
+ * section shows when it did not pass.
47
+ */
48
+ export interface EngineStepResult {
49
+ ok: boolean;
50
+ aborted?: boolean;
51
+ detail?: string;
52
+ }
53
+ /**
54
+ * engineSource reads the registered acquisition data for an engine id, or
55
+ * undefined when none is registered.
56
+ */
57
+ export declare function engineSource(engineId: string): EngineSource | undefined;
58
+ /**
59
+ * engineBuildSteps reads the build steps an engine runs in its checkout, so
60
+ * the adapter's deploy step and the Get build step share one list.
61
+ */
62
+ export declare function engineBuildSteps(engineId: string): readonly string[];
63
+ /**
64
+ * syncEngineRepo brings the engine checkout to the listed source. A missing
65
+ * checkout is a fresh clone of the fork (or the engine's upstream repo when
66
+ * no fork is provided). An existing checkout with local changes aborts, so
67
+ * the user's work is never rebased away; a clean checkout fetches the listed
68
+ * fork (added as the named fork remote when provided, origin when not) and
69
+ * rebases onto its branch. Every command echoes into log as it runs.
70
+ */
71
+ export declare function syncEngineRepo(host: LifecycleHost, request: {
72
+ engineId: string;
73
+ directory: string;
74
+ fork?: string;
75
+ }, log: AcquireLog): Promise<EngineStepResult>;
76
+ /**
77
+ * SyncRebuildRequest names the checkout the conditional rebuild prices: the
78
+ * engine, its directory, the optional fork remote, the engine binary the
79
+ * symlink step links when a rebuild leaves it out of the path, and the
80
+ * Play/Run trust gate that decides whether that symlink runs (on) or is
81
+ * written to the logs (off).
82
+ */
83
+ export interface SyncRebuildRequest {
84
+ engineId: string;
85
+ directory: string;
86
+ fork?: string;
87
+ binary?: string;
88
+ allowRunDeps?: boolean;
89
+ }
90
+ /**
91
+ * SyncRebuildResult reports the conditional rebuild: whether it passed,
92
+ * whether a build actually ran (a fresh clone, or a rebase of a checkout that
93
+ * was behind), a detail for a failure, and the captured log text (the decision,
94
+ * the build command, and its output) the deploy step threads to the card's
95
+ * Logs section.
96
+ */
97
+ export interface SyncRebuildResult {
98
+ ok: boolean;
99
+ rebuilt: boolean;
100
+ detail?: string;
101
+ logs: string;
102
+ }
103
+ /**
104
+ * syncAndRebuildEngine brings the engine checkout to the listed source and
105
+ * rebuilds it only when it needs to. A missing checkout is a fresh clone of
106
+ * the fork (or the upstream repo) and always builds. An existing checkout is
107
+ * fetched and priced against the remote branch: when it is behind and clean,
108
+ * the primary branch is checked out, rebased onto the remote branch, and the
109
+ * working tree is cleaned (git clean -fxd) before the build; when it is not
110
+ * behind, or it carries local changes, the build is skipped so a launch does
111
+ * not rebuild a checkout that is current. The decision, the build command,
112
+ * and its output stream through log and are returned as the result's logs.
113
+ * After a rebuild, the engine binary is checked against the path; when a build
114
+ * that did not install it leaves it out, a symlink into /usr/local/bin is
115
+ * added (run when the trust gate is on, written to the logs when it is off).
116
+ */
117
+ export declare function syncAndRebuildEngine(host: LifecycleHost, request: SyncRebuildRequest, log: AcquireLog): Promise<SyncRebuildResult>;
118
+ /**
119
+ * buildEngineRepo runs the engine's build steps in the checkout, streaming
120
+ * each step's output through log. An engine with no build steps (the compose
121
+ * engines) passes through with a note; a failing step stops the build with
122
+ * the step's detail.
123
+ */
124
+ export declare function buildEngineRepo(host: LifecycleHost, engineId: string, directory: string, log: AcquireLog): Promise<EngineStepResult>;
125
+ //# sourceMappingURL=acquire.d.ts.map