mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-17 20:52:15 +03:00
Stage 7 of issue #10321 moves the optional ML and browser automation dependency closures out of the desktop bundle into checksummed, versioned packs installed on demand through the omniroute packs command. - scripts/build/optionalPackStaging.mjs stages pack members under .build/optional-packs, creates release tarballs, and emits optional-packs.index.json with per-member SHA-256 checksums. - scripts/packs provides manifest, install, remove, and verification helpers plus the packs CLI commands. - Runtime lookup includes installed pack node_modules directories, while LLMLingua and browser executors continue to degrade gracefully when packs are absent. The measured darwin-arm64 staging closure was about 534 MB of the 929 MB standalone node_modules tree (57%).
88 lines
3.6 KiB
TypeScript
88 lines
3.6 KiB
TypeScript
/**
|
|
* Optional runtime pack resolution (Stage 7 of the Electron efficiency roadmap,
|
|
* issue #10321).
|
|
*
|
|
* The desktop bundle ships WITHOUT the heavy optional ML/browser dependency
|
|
* closure; users install versioned packs (`omniroute packs install ml-runtime`)
|
|
* into `${DATA_DIR}/packs/<name>/node_modules`. `electron/main.js` prepends
|
|
* those directories to the spawned server's NODE_PATH, which is how dynamic
|
|
* imports (`await import("playwright")`, the LLMLingua worker) resolve pack
|
|
* members at runtime.
|
|
*
|
|
* This module is the runtime side and deliberately does NOT import the
|
|
* build-side manifest (`scripts/packs/optionalPackManifest.mjs`) — the
|
|
* standalone server must stay decoupled from build tooling. It embeds only the
|
|
* pack names and the index filename.
|
|
*
|
|
* Fail-open: every helper returns "absent" rather than throwing, so a missing
|
|
* or corrupt pack degrades the optional feature instead of the server.
|
|
*/
|
|
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import fs from "node:fs";
|
|
|
|
/** Pack names — must match OPTIONAL_PACKS in scripts/packs/optionalPackManifest.mjs. */
|
|
export const OPTIONAL_PACK_NAMES = ["ml-runtime", "browser-runtime"] as const;
|
|
|
|
export type OptionalPackName = (typeof OPTIONAL_PACK_NAMES)[number];
|
|
|
|
/** Index filename — must match PACK_INDEX_FILENAME in the manifest module. */
|
|
export const PACK_INDEX_FILENAME = "optional-packs.index.json";
|
|
|
|
/** Resolve DATA_DIR exactly like the rest of the runtime (modelStore.ts precedent). */
|
|
function resolveDataDir(override?: string): string {
|
|
return override || process.env.DATA_DIR || path.join(os.homedir(), ".omniroute");
|
|
}
|
|
|
|
/** `${DATA_DIR}/packs` — root of installed packs. */
|
|
export function packsRootDir(dataDirOverride?: string): string {
|
|
return path.join(resolveDataDir(dataDirOverride), "packs");
|
|
}
|
|
|
|
/** Install dir for one pack: `${DATA_DIR}/packs/<name>` (contains node_modules/). */
|
|
export function packInstallDir(name: string, dataDirOverride?: string): string {
|
|
return path.join(packsRootDir(dataDirOverride), name);
|
|
}
|
|
|
|
/** `node_modules` dir of an installed pack, whether or not it exists. */
|
|
export function packNodeModulesDir(name: string, dataDirOverride?: string): string {
|
|
return path.join(packInstallDir(name, dataDirOverride), "node_modules");
|
|
}
|
|
|
|
/**
|
|
* NODE_PATH entries for every INSTALLED pack (manifest order, deterministic).
|
|
* `electron/main.js` consumes this via its own plain-JS mirror — keep the
|
|
* semantics identical (existence check, no throw).
|
|
*/
|
|
export function installedPackNodePaths(dataDirOverride?: string): string[] {
|
|
const entries: string[] = [];
|
|
for (const name of OPTIONAL_PACK_NAMES) {
|
|
const dir = packNodeModulesDir(name, dataDirOverride);
|
|
try {
|
|
if (fs.statSync(dir).isDirectory()) entries.push(dir);
|
|
} catch {
|
|
// Not installed (or unreadable) — absent, not an error.
|
|
}
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
/**
|
|
* Probe a pack member by its path relative to a `node_modules` root, e.g.
|
|
* `@atjsh/llmlingua-2/package.json`. A single leading `node_modules` segment is
|
|
* accepted because existing filesystem probes express the same member from an
|
|
* install root. Checks every installed pack first, so an installed pack lights
|
|
* the feature up even though the bundle tree no longer carries the member.
|
|
*/
|
|
export function packMemberInstalled(memberRelPath: string, dataDirOverride?: string): boolean {
|
|
const segments = memberRelPath.split(/[\\/]/).filter(Boolean);
|
|
if (segments[0] === "node_modules") segments.shift();
|
|
if (segments.length === 0) return false;
|
|
|
|
for (const nodeModulesDir of installedPackNodePaths(dataDirOverride)) {
|
|
if (fs.existsSync(path.join(nodeModulesDir, ...segments))) return true;
|
|
}
|
|
return false;
|
|
}
|