@miller-tech/uap 2.36.1 → 2.39.0

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 (101) hide show
  1. package/config/model-profiles/qwen38.json +3 -3
  2. package/config/model-registry.json +96 -6
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/bin/cli.js +57 -0
  5. package/dist/bin/cli.js.map +1 -1
  6. package/dist/cli/deliver.d.ts +46 -0
  7. package/dist/cli/deliver.d.ts.map +1 -1
  8. package/dist/cli/deliver.js +155 -36
  9. package/dist/cli/deliver.js.map +1 -1
  10. package/dist/cli/models.d.ts +11 -1
  11. package/dist/cli/models.d.ts.map +1 -1
  12. package/dist/cli/models.js +164 -3
  13. package/dist/cli/models.js.map +1 -1
  14. package/dist/cli/workflow.d.ts +36 -0
  15. package/dist/cli/workflow.d.ts.map +1 -0
  16. package/dist/cli/workflow.js +246 -0
  17. package/dist/cli/workflow.js.map +1 -0
  18. package/dist/delivery/run-state.d.ts +1 -1
  19. package/dist/delivery/run-state.d.ts.map +1 -1
  20. package/dist/delivery/run-state.js +1 -1
  21. package/dist/delivery/run-state.js.map +1 -1
  22. package/dist/delivery/team-solve-deliver.d.ts +83 -0
  23. package/dist/delivery/team-solve-deliver.d.ts.map +1 -0
  24. package/dist/delivery/team-solve-deliver.js +191 -0
  25. package/dist/delivery/team-solve-deliver.js.map +1 -0
  26. package/dist/inference/model-files.d.ts +111 -0
  27. package/dist/inference/model-files.d.ts.map +1 -0
  28. package/dist/inference/model-files.js +172 -0
  29. package/dist/inference/model-files.js.map +1 -0
  30. package/dist/placement/registry.d.ts +650 -0
  31. package/dist/placement/registry.d.ts.map +1 -1
  32. package/dist/placement/registry.js +21 -0
  33. package/dist/placement/registry.js.map +1 -1
  34. package/dist/workflow/loader.d.ts +34 -0
  35. package/dist/workflow/loader.d.ts.map +1 -0
  36. package/dist/workflow/loader.js +232 -0
  37. package/dist/workflow/loader.js.map +1 -0
  38. package/dist/workflow/runner.d.ts +90 -0
  39. package/dist/workflow/runner.d.ts.map +1 -0
  40. package/dist/workflow/runner.js +416 -0
  41. package/dist/workflow/runner.js.map +1 -0
  42. package/dist/workflow/types.d.ts +400 -0
  43. package/dist/workflow/types.d.ts.map +1 -0
  44. package/dist/workflow/types.js +147 -0
  45. package/dist/workflow/types.js.map +1 -0
  46. package/docs/INDEX.md +1 -0
  47. package/docs/architecture/adr/0013-declarative-workflow-layer.md +99 -0
  48. package/docs/architecture/adr/0014-loop-steps-and-team-solve-deliver.md +142 -0
  49. package/docs/benchmarks/LCB_DROID_SMOKE.md +111 -0
  50. package/docs/guides/DELIVER.md +3 -1
  51. package/docs/guides/WORKFLOWS.md +179 -0
  52. package/docs/plans/model-performance-proof-options.md +39 -0
  53. package/docs/reference/CLI.md +33 -0
  54. package/docs/reference/CONFIGURATION.md +1 -0
  55. package/docs/reference/FEATURES.md +18 -0
  56. package/examples/auto-coordinator-example.js +127 -0
  57. package/examples/demo-order-solid.ts +19 -0
  58. package/examples/order-processing-strategy-pattern.ts +186 -0
  59. package/examples/order-processor-refactored.ts +473 -0
  60. package/examples/order-solid-refactor.ts +830 -0
  61. package/examples/refactored-order-processing.ts +106 -0
  62. package/examples/run-order-processing.ts +48 -0
  63. package/examples/solid-order-processing.ts +324 -0
  64. package/examples/strategy-pattern-example.ts +100 -0
  65. package/examples/workflows/team-solve/README.md +85 -0
  66. package/examples/workflows/team-solve/check-samples.sh +50 -0
  67. package/examples/workflows/team-solve/sample/task.md +22 -0
  68. package/examples/workflows/team-solve/sample/tests/1.in +2 -0
  69. package/examples/workflows/team-solve/sample/tests/1.out +1 -0
  70. package/examples/workflows/team-solve/sample/tests/2.in +2 -0
  71. package/examples/workflows/team-solve/sample/tests/2.out +1 -0
  72. package/examples/workflows/team-solve/sample/tests/3.in +2 -0
  73. package/examples/workflows/team-solve/sample/tests/3.out +1 -0
  74. package/examples/workflows/team-solve/sample/tests/4.in +2 -0
  75. package/examples/workflows/team-solve/sample/tests/4.out +1 -0
  76. package/examples/workflows/team-solve/sample/tests/5.in +1 -0
  77. package/examples/workflows/team-solve/sample/tests/5.out +1 -0
  78. package/examples/workflows/team-solve/steps/ideate-a.md +26 -0
  79. package/examples/workflows/team-solve/steps/ideate-b.md +28 -0
  80. package/examples/workflows/team-solve/steps/plan.md +20 -0
  81. package/examples/workflows/team-solve/steps/repair.md +25 -0
  82. package/examples/workflows/team-solve/steps/review.md +29 -0
  83. package/examples/workflows/team-solve/steps/solve.md +26 -0
  84. package/examples/workflows/team-solve/workflow.yaml +78 -0
  85. package/examples/workflows/team-solve-deliver/README.md +84 -0
  86. package/examples/workflows/team-solve-deliver/steps/ideate-a.md +25 -0
  87. package/examples/workflows/team-solve-deliver/steps/ideate-b.md +28 -0
  88. package/examples/workflows/team-solve-deliver/steps/plan.md +25 -0
  89. package/examples/workflows/team-solve-deliver/steps/repair.md +20 -0
  90. package/examples/workflows/team-solve-deliver/steps/review.md +31 -0
  91. package/examples/workflows/team-solve-deliver/steps/solve.md +28 -0
  92. package/examples/workflows/team-solve-deliver/steps/verify.md +9 -0
  93. package/examples/workflows/team-solve-deliver/workflow.yaml +74 -0
  94. package/package.json +2 -1
  95. package/src/policies/enforcers/__pycache__/_common.cpython-311.pyc +0 -0
  96. package/src/policies/enforcers/__pycache__/expert_review_required.cpython-311.pyc +0 -0
  97. package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-311.pyc +0 -0
  98. package/templates/hooks/__pycache__/deliver_autoroute.cpython-311.pyc +0 -0
  99. package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-311.pyc +0 -0
  100. package/tools/agents/scripts/anthropic_proxy.py +181 -15
  101. package/tools/agents/tests/test_signature_quality.py +51 -0
@@ -0,0 +1,191 @@
1
+ /**
2
+ * team-solve-deliver — the wrapper that runs the bundled team-solve-deliver
3
+ * workflow around a mission's dispatch (ADR 0014). Extracted from deliver.ts's
4
+ * dispatch block so the aggregation is unit-testable and every closure capture
5
+ * is an explicit dep — the same treatment the epic/phased/orchestrated cores
6
+ * got when their closures grew risky.
7
+ *
8
+ * The roles: plan → parallel ideations → solve (loop) → fresh review → repair
9
+ * (loop) → verify (loop, gates-only). The caller injects the mission's own
10
+ * machinery as the seams: solve = the mission dispatch with the team's
11
+ * approach enriching the instruction, repair = a bounded convergence loop
12
+ * seeded with the reviewer's brief, verify = the tiered ladder with no
13
+ * executor turns.
14
+ */
15
+ import { mkdirSync } from 'fs';
16
+ import { join, relative } from 'path';
17
+ /** The exact step ids the rail assignment and seam mapping below are keyed to. */
18
+ export const TEAM_SOLVE_DELIVER_STEPS = [
19
+ 'plan',
20
+ 'ideate-a',
21
+ 'ideate-b',
22
+ 'solve',
23
+ 'review',
24
+ 'repair',
25
+ 'verify',
26
+ ];
27
+ /** Roles that ride the JUDGE rail (cool, deterministic, distinct when
28
+ * configured): planning and review. Everything else rides the generator. */
29
+ const JUDGE_RAIL_STEPS = new Set(['plan', 'review']);
30
+ /**
31
+ * Fail-closed on shape drift: the rail assignment (which ids get the judge)
32
+ * and the seam mapping (which loop step is solve/repair/verify) are keyed to
33
+ * TEAM_SOLVE_DELIVER_STEPS. A project override that renames or adds steps
34
+ * must NOT silently ride the wrong rail — refuse loudly instead.
35
+ */
36
+ export function assertTeamSolveDeliverShape(loaded) {
37
+ const ids = loaded.def.steps.map((s) => s.id).join(',');
38
+ const expected = TEAM_SOLVE_DELIVER_STEPS.join(',');
39
+ if (ids !== expected) {
40
+ throw new Error(`team-solve-deliver workflow shape drifted: expected steps [${expected}], got [${ids}] — ` +
41
+ 'the judge-rail assignment and loop-seam mapping are keyed to these ids; ' +
42
+ 'fix the overriding workflow or the drift in src/delivery/team-solve-deliver.ts');
43
+ }
44
+ }
45
+ /**
46
+ * One line of loop outcome for the workflow ledger — sized for the reviewer's
47
+ * dependency summary. Honest about what it carries: gate status, turns, the
48
+ * changed-tree flag, and a feedback tail. It does NOT carry a file list (the
49
+ * reviewer's prompt is written to match — see steps/review.md).
50
+ */
51
+ export function loopOutcome(r) {
52
+ const head = r.success
53
+ ? `gates GREEN after ${r.turns} turn(s)${r.alreadyDelivered ? ' (baseline already green)' : ''}`
54
+ : `NOT delivered after ${r.turns} turn(s) — best ${Math.round(r.bestScore * 100)}% of gates`;
55
+ const changed = r.changedTree ? '; tree changed' : '';
56
+ return `${head}${changed}${r.finalFeedback ? `; ${r.finalFeedback.slice(0, 150)}` : ''}`;
57
+ }
58
+ /**
59
+ * Aggregate the workflow run + the two loop results into the mission's
60
+ * DeliveryResult. PURE. The final verdict is the verify pass AND the
61
+ * workflow's own status: a failed role step means no repair brief or no
62
+ * verdict — not delivered. Histories concatenate; the last loop-bearing
63
+ * result carries the best score; `wf.failed` lists steps that did not
64
+ * complete (skip-cascaded descendants included — phrased honestly).
65
+ */
66
+ export function aggregateTeamSolveResult(input) {
67
+ const inner = input.repairResult ?? input.solveResult;
68
+ if (!inner) {
69
+ return {
70
+ success: false,
71
+ alreadyDelivered: false,
72
+ turns: 0,
73
+ bestScore: 0,
74
+ bestTurn: 0,
75
+ history: [],
76
+ finalFeedback: `team-solve roles failed before the solve loop (not completed: ${input.wf.failed.join(', ')})`,
77
+ finalOutput: '',
78
+ totalDurationMs: 0,
79
+ };
80
+ }
81
+ const { solveResult, repairResult } = input;
82
+ return {
83
+ success: input.wf.status === 'succeeded' && input.verifyPassed,
84
+ alreadyDelivered: solveResult?.alreadyDelivered === true && input.wf.status === 'succeeded',
85
+ turns: (solveResult?.turns ?? 0) + (repairResult?.turns ?? 0),
86
+ bestScore: inner.bestScore,
87
+ bestTurn: inner.bestTurn,
88
+ history: [...(solveResult?.history ?? []), ...(repairResult?.history ?? [])],
89
+ finalFeedback: input.wf.status === 'succeeded'
90
+ ? `${input.verifySummary}; role ledger: ${relative(input.projectRoot, input.ledgerDir)}`
91
+ : `team-solve workflow ${input.wf.status}${input.wf.failed.length ? ` (not completed: ${input.wf.failed.join(', ')})` : ''}`,
92
+ finalOutput: inner.finalOutput,
93
+ totalDurationMs: (solveResult?.totalDurationMs ?? 0) + (repairResult?.totalDurationMs ?? 0),
94
+ changedTree: solveResult?.changedTree || repairResult?.changedTree || undefined,
95
+ stopped: solveResult?.stopped || repairResult?.stopped || undefined,
96
+ stallReason: repairResult?.stallReason ?? solveResult?.stallReason,
97
+ };
98
+ }
99
+ /**
100
+ * Run the team-solve-deliver workflow around the mission dispatch. Falls back
101
+ * to the plain dispatch (with a visible warning) when the workflow is not
102
+ * installed — AUTO engagement must never make deliver worse than its default
103
+ * posture.
104
+ */
105
+ export async function runTeamSolveDeliver(deps) {
106
+ let loaded;
107
+ try {
108
+ loaded = deps.loadWorkflow();
109
+ assertTeamSolveDeliverShape(loaded);
110
+ }
111
+ catch (e) {
112
+ deps.log(`⚠ team-solve engaged but the workflow is unusable (${e instanceof Error ? e.message : String(e)}) — running the standard dispatch`);
113
+ return deps.dispatch();
114
+ }
115
+ const ledgerDir = join(deps.runsDir(), deps.newRunId());
116
+ mkdirSync(ledgerDir, { recursive: true });
117
+ // Surface the RESOLVED source: project `.uap/workflows/` shadows the
118
+ // bundled copy (first hit wins), and an operator must be able to see which
119
+ // one ran — the ledger dir alone does not say.
120
+ deps.log(`🧠 team-solve: roles direct the convergence loop (source: ${relative(deps.projectRoot, loaded.dir) || loaded.dir}; ledger: ${relative(deps.projectRoot, ledgerDir)})`);
121
+ let solveResult;
122
+ let repairResult;
123
+ let verifyPassed = false;
124
+ let verifySummary = 'gates not run';
125
+ const wf = await deps.runWorkflow({
126
+ loaded,
127
+ runDir: ledgerDir,
128
+ mission: deps.getInstruction(),
129
+ // Pins are advisory here: the executor rails below own each role's model.
130
+ resolveModel: deps.resolveModel,
131
+ completeStep: (step, prompt) => JUDGE_RAIL_STEPS.has(step.id) ? deps.judgeExecutor(prompt) : deps.generatorExecutor(prompt),
132
+ runLoop: async ({ stepId, prompt, turns, verifyOnly }) => {
133
+ // verifyOnly FIRST: a gates-only verdict must never run executor turns,
134
+ // whatever the step id says (the engine-level contract).
135
+ if (verifyOnly) {
136
+ const gates = await deps.runGates();
137
+ verifyPassed = gates.passed;
138
+ verifySummary = gates.passed
139
+ ? `${gates.count} gates green (verify-only pass)`
140
+ : `gates red: ${gates.feedback.slice(0, 240)}`;
141
+ return { success: gates.passed, summary: verifySummary, turns: 0 };
142
+ }
143
+ if (stepId === 'solve') {
144
+ if (turns !== undefined) {
145
+ deps.log('⚠ solve turns: bound ignored — the mission turn budget governs the solve dispatch');
146
+ }
147
+ // The team's approach (planner + both ideators, assembled by the
148
+ // workflow engine) enriches the mission; the posture chain runs
149
+ // UNCHANGED beneath it.
150
+ const prior = deps.getInstruction();
151
+ deps.setInstruction(`${prior}\n\nTEAM-SOLVE APPROACH (the team's plan + chosen proposal — steer by it; the gates decide):\n${prompt}`);
152
+ try {
153
+ solveResult = await deps.dispatch();
154
+ }
155
+ finally {
156
+ deps.setInstruction(prior);
157
+ }
158
+ return { success: solveResult.success, summary: loopOutcome(solveResult), turns: solveResult.turns };
159
+ }
160
+ if (stepId === 'repair') {
161
+ // Bounded convergence loop seeded with the reviewer's brief: fresh
162
+ // checkpoint state (a repair-scoped checkpoint must not replay into
163
+ // the original mission's resume — the CI-reconverge precedent), the
164
+ // SAME gate ladder + acceptance spec. A declared turns: bound caps
165
+ // this pass. When the reviewer says NO REPAIR NEEDED, the loop's own
166
+ // baseline check is the green confirmation — zero turns, untouched.
167
+ const repairConfig = {
168
+ ...deps.loopConfig,
169
+ resumeFrom: undefined,
170
+ onCheckpoint: undefined,
171
+ ...(turns !== undefined ? { maxTurns: turns } : {}),
172
+ };
173
+ const repairLoop = deps.buildRepairLoop(repairConfig);
174
+ repairResult = await repairLoop.deliver(prompt);
175
+ return { success: repairResult.success, summary: loopOutcome(repairResult), turns: repairResult.turns };
176
+ }
177
+ throw new Error(`team-solve-deliver: unexpected loop step "${stepId}"`);
178
+ },
179
+ log: deps.log,
180
+ });
181
+ return aggregateTeamSolveResult({
182
+ wf,
183
+ solveResult,
184
+ repairResult,
185
+ verifyPassed,
186
+ verifySummary,
187
+ projectRoot: deps.projectRoot,
188
+ ledgerDir,
189
+ });
190
+ }
191
+ //# sourceMappingURL=team-solve-deliver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-solve-deliver.js","sourceRoot":"","sources":["../../src/delivery/team-solve-deliver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ /** One declared model file: where it must live, and how to recognize it. */
2
+ export interface ModelFileManifest {
3
+ /** Absolute destination path on this machine. */
4
+ path: string;
5
+ /** Hugging Face repo id (e.g. "jakeatx/Qwen3.8-27B-ATX-IQ4_XS-M-GGUF"). */
6
+ repo?: string;
7
+ /** Filename inside the repo; defaults to the destination basename. */
8
+ file?: string;
9
+ /** Repo revision to fetch from; defaults to main. Pin it when the file was
10
+ * removed from main (unsloth deleted Qwen3.8-27B-Q4_K_M.gguf 2026-08-19). */
11
+ rev?: string;
12
+ /** Expected size in bytes (truncation detector). */
13
+ bytes?: number;
14
+ /** Expected sha256, lowercase hex. Verified after download and on demand. */
15
+ sha256?: string;
16
+ }
17
+ /** Result of checking one manifest entry without repairing it. */
18
+ export type FileState = {
19
+ status: 'ok';
20
+ path: string;
21
+ bytes: number;
22
+ note?: string;
23
+ } | {
24
+ status: 'unchecked';
25
+ path: string;
26
+ bytes: number;
27
+ note: 'no expected size or sha256 recorded' | string;
28
+ } | {
29
+ status: 'missing';
30
+ path: string;
31
+ } | {
32
+ status: 'size-mismatch';
33
+ path: string;
34
+ bytes: number;
35
+ expectedBytes: number;
36
+ } | {
37
+ status: 'sha-mismatch';
38
+ path: string;
39
+ bytes: number;
40
+ expectedSha256: string;
41
+ };
42
+ /** curl runner, injectable so tests never touch the network. */
43
+ export type RunCurl = (args: string[]) => Promise<{
44
+ code: number;
45
+ stderr: string;
46
+ }>;
47
+ export declare const defaultRunCurl: RunCurl;
48
+ /** Filename inside the repo for a manifest entry. */
49
+ export declare function manifestRepoFile(entry: ModelFileManifest): string;
50
+ /** Hugging Face resolve URL for a manifest entry. */
51
+ export declare function hfResolveUrl(entry: ModelFileManifest): string;
52
+ /** sha256 of a file, streamed — the only full-read check we ever do. */
53
+ export declare function sha256File(path: string): Promise<string>;
54
+ /**
55
+ * Check one declared file. Cheap by default (stat only); with `verifySha`
56
+ * also hashes (minutes for tens of GiB — opt-in, never a unit preflight).
57
+ */
58
+ export declare function fileState(entry: ModelFileManifest, opts?: {
59
+ verifySha?: boolean;
60
+ }): Promise<FileState>;
61
+ /** A download may only ever target a path inside the operator's home. */
62
+ export declare function downloadTargetSafe(path: string): boolean;
63
+ /** Whether a missing file can be repaired (a source is recorded). */
64
+ export declare function isRepairable(entry: ModelFileManifest): boolean;
65
+ /**
66
+ * Download (or resume) one declared file into place.
67
+ * - downloads to `<path>.part` with curl -C -, then verifies and renames;
68
+ * - an existing file that already matches `bytes` is left untouched;
69
+ * - refuses targets outside $HOME (repo-supplied manifests are not trusted
70
+ * with the rest of the filesystem).
71
+ */
72
+ export declare function downloadModelFile(entry: ModelFileManifest, opts?: {
73
+ runCurl?: RunCurl;
74
+ }): Promise<{
75
+ ok: true;
76
+ bytes: number;
77
+ } | {
78
+ ok: false;
79
+ error: string;
80
+ }>;
81
+ /** What `ensure` did, in one printable summary. */
82
+ export interface EnsureResult {
83
+ /** Manifest entries inspected. */
84
+ checked: number;
85
+ /** Entries already present and (if recorded) sized right. */
86
+ present: number;
87
+ /** Entries missing or truncated, whether or not a repair was attempted. */
88
+ broken: Array<{
89
+ entry: ModelFileManifest;
90
+ state: FileState;
91
+ }>;
92
+ /** Entries repaired by download this run. */
93
+ repaired: ModelFileManifest[];
94
+ /** Repairs attempted and failed (last error kept). */
95
+ failed: Array<{
96
+ entry: ModelFileManifest;
97
+ error: string;
98
+ }>;
99
+ }
100
+ /**
101
+ * Verify every declared file; repair what is missing or truncated.
102
+ * `dryRun` reports without downloading; `download: false` forces that too.
103
+ * Returns a structured result — the CLI decides how loud to be.
104
+ */
105
+ export declare function ensureFiles(entries: ModelFileManifest[], opts?: {
106
+ dryRun?: boolean;
107
+ download?: boolean;
108
+ verifySha?: boolean;
109
+ runCurl?: RunCurl;
110
+ }): Promise<EnsureResult>;
111
+ //# sourceMappingURL=model-files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-files.d.ts","sourceRoot":"","sources":["../../src/inference/model-files.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Model file integrity + recovery for the local inference engines.
3
+ *
4
+ * The placement registry (config/model-registry.json) declares, per config,
5
+ * the weight files the engine needs on disk together with their source and
6
+ * integrity facts. This module answers the operational failure the units
7
+ * kept hitting one way or another: a file deleted or truncated after
8
+ * installation ("accidentally deleted"), which used to kill the server at
9
+ * start with nothing but an ERROR line.
10
+ *
11
+ * Two checks, deliberately split by cost:
12
+ * - presence + size: a stat() call, run on every ensure (unit preflight
13
+ * budget: milliseconds, no hashing of a 15 GiB GGUF at boot);
14
+ * - sha256: a full read, run only after a download or with --verify.
15
+ *
16
+ * Downloads are curl, resumable (-C - against the .part file), never
17
+ * huggingface-cli (broken on this box: deprecated shim + typer/click
18
+ * TypeError — see the strata bench log of 2026-10-28), and land only inside
19
+ * $HOME: a repo-supplied manifest must not let a cloned repo write outside
20
+ * the operator's home. A file with no recorded repo is check-only — a
21
+ * deletion is reported, not guessed at.
22
+ */
23
+ import { execFile } from 'child_process';
24
+ import { createHash } from 'crypto';
25
+ import { createReadStream, existsSync, mkdirSync, renameSync, statSync } from 'fs';
26
+ import { homedir } from 'os';
27
+ import { basename, dirname, isAbsolute, resolve } from 'path';
28
+ export const defaultRunCurl = (args) => new Promise((resolvePromise) => {
29
+ execFile('curl', args, { maxBuffer: 1 << 20, timeout: 0 }, (err, _stdout, stderr) => {
30
+ resolvePromise({ code: err && typeof err.code === 'number' ? err.code : 0, stderr: String(stderr ?? '') });
31
+ });
32
+ });
33
+ /** Filename inside the repo for a manifest entry. */
34
+ export function manifestRepoFile(entry) {
35
+ return entry.file ?? basename(entry.path);
36
+ }
37
+ /** Hugging Face resolve URL for a manifest entry. */
38
+ export function hfResolveUrl(entry) {
39
+ if (!entry.repo)
40
+ throw new Error(`no repo recorded for ${entry.path}`);
41
+ const rev = entry.rev ?? 'main';
42
+ return `https://huggingface.co/${entry.repo}/resolve/${rev}/${encodeURIComponent(manifestRepoFile(entry))}`;
43
+ }
44
+ /** sha256 of a file, streamed — the only full-read check we ever do. */
45
+ export function sha256File(path) {
46
+ return new Promise((resolvePromise, rejectPromise) => {
47
+ const hash = createHash('sha256');
48
+ const stream = createReadStream(path);
49
+ stream.on('data', (chunk) => hash.update(chunk));
50
+ stream.on('error', rejectPromise);
51
+ stream.on('end', () => resolvePromise(hash.digest('hex')));
52
+ });
53
+ }
54
+ /**
55
+ * Check one declared file. Cheap by default (stat only); with `verifySha`
56
+ * also hashes (minutes for tens of GiB — opt-in, never a unit preflight).
57
+ */
58
+ export async function fileState(entry, opts = {}) {
59
+ if (!existsSync(entry.path))
60
+ return { status: 'missing', path: entry.path };
61
+ const bytes = statSync(entry.path).size;
62
+ if (entry.bytes !== undefined && bytes !== entry.bytes) {
63
+ return { status: 'size-mismatch', path: entry.path, bytes, expectedBytes: entry.bytes };
64
+ }
65
+ if (opts.verifySha === true && entry.sha256) {
66
+ const got = await sha256File(entry.path);
67
+ if (got !== entry.sha256) {
68
+ return { status: 'sha-mismatch', path: entry.path, bytes, expectedSha256: entry.sha256 };
69
+ }
70
+ return { status: 'ok', path: entry.path, bytes };
71
+ }
72
+ if (entry.bytes === undefined && !entry.sha256) {
73
+ return {
74
+ status: 'unchecked',
75
+ path: entry.path,
76
+ bytes,
77
+ note: 'no expected size or sha256 recorded',
78
+ };
79
+ }
80
+ return { status: 'ok', path: entry.path, bytes };
81
+ }
82
+ /** A download may only ever target a path inside the operator's home. */
83
+ export function downloadTargetSafe(path) {
84
+ if (!isAbsolute(path))
85
+ return false;
86
+ const home = homedir();
87
+ const target = resolve(path);
88
+ return target === home || target.startsWith(`${home}/`);
89
+ }
90
+ /** Whether a missing file can be repaired (a source is recorded). */
91
+ export function isRepairable(entry) {
92
+ return typeof entry.repo === 'string' && entry.repo.length > 0;
93
+ }
94
+ /**
95
+ * Download (or resume) one declared file into place.
96
+ * - downloads to `<path>.part` with curl -C -, then verifies and renames;
97
+ * - an existing file that already matches `bytes` is left untouched;
98
+ * - refuses targets outside $HOME (repo-supplied manifests are not trusted
99
+ * with the rest of the filesystem).
100
+ */
101
+ export async function downloadModelFile(entry, opts = {}) {
102
+ if (!isRepairable(entry))
103
+ return { ok: false, error: `no repo recorded for ${entry.path}` };
104
+ if (!downloadTargetSafe(entry.path)) {
105
+ return { ok: false, error: `refusing to download outside $HOME: ${entry.path}` };
106
+ }
107
+ if (existsSync(entry.path)) {
108
+ const bytes = statSync(entry.path).size;
109
+ if (entry.bytes === undefined || bytes === entry.bytes) {
110
+ return { ok: true, bytes };
111
+ }
112
+ }
113
+ const runCurl = opts.runCurl ?? defaultRunCurl;
114
+ const part = `${entry.path}.part`;
115
+ const url = hfResolveUrl(entry);
116
+ mkdirSync(dirname(entry.path), { recursive: true });
117
+ const authArgs = process.env.HF_TOKEN
118
+ ? ['-H', `Authorization: Bearer ${process.env.HF_TOKEN}`]
119
+ : [];
120
+ const baseArgs = ['-fL', '-sS', '--retry', '3', '--retry-delay', '2', ...authArgs, '-o', part, url];
121
+ // -C - resumes a leftover .part; curl exit 33 means "cannot resume" (no
122
+ // ranges, or the .part is already complete) — retry once from scratch.
123
+ const resumed = await runCurl(['-C', '-', ...baseArgs]);
124
+ if (resumed.code !== 0) {
125
+ const fresh = await runCurl(baseArgs);
126
+ if (fresh.code !== 0) {
127
+ return { ok: false, error: `curl exit ${resumed.code}/${fresh.code} for ${url}: ${fresh.stderr.slice(0, 200)}` };
128
+ }
129
+ }
130
+ if (!existsSync(part))
131
+ return { ok: false, error: `curl left no .part file for ${url}` };
132
+ const partBytes = statSync(part).size;
133
+ if (entry.bytes !== undefined && partBytes !== entry.bytes) {
134
+ return { ok: false, error: `downloaded ${partBytes} bytes, expected ${entry.bytes} (${url}); .part kept for resume` };
135
+ }
136
+ if (entry.sha256) {
137
+ const got = await sha256File(part);
138
+ if (got !== entry.sha256) {
139
+ return { ok: false, error: `sha256 mismatch after download (${url}); .part kept for resume` };
140
+ }
141
+ }
142
+ renameSync(part, entry.path);
143
+ return { ok: true, bytes: statSync(entry.path).size };
144
+ }
145
+ /**
146
+ * Verify every declared file; repair what is missing or truncated.
147
+ * `dryRun` reports without downloading; `download: false` forces that too.
148
+ * Returns a structured result — the CLI decides how loud to be.
149
+ */
150
+ export async function ensureFiles(entries, opts = {}) {
151
+ const out = { checked: 0, present: 0, broken: [], repaired: [], failed: [] };
152
+ for (const entry of entries) {
153
+ out.checked += 1;
154
+ const state = await fileState(entry, { verifySha: opts.verifySha === true });
155
+ if (state.status === 'ok' || state.status === 'unchecked') {
156
+ out.present += 1;
157
+ continue;
158
+ }
159
+ out.broken.push({ entry, state });
160
+ if (opts.dryRun === true || opts.download === false)
161
+ continue;
162
+ if (!isRepairable(entry))
163
+ continue;
164
+ const res = await downloadModelFile(entry, { runCurl: opts.runCurl });
165
+ if (res.ok)
166
+ out.repaired.push(entry);
167
+ else
168
+ out.failed.push({ entry, error: res.error });
169
+ }
170
+ return out;
171
+ }
172
+ //# sourceMappingURL=model-files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-files.js","sourceRoot":"","sources":["../../src/inference/model-files.ts"],"names":[],"mappings":"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"}