omnius 1.0.330 → 1.0.332

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.
package/dist/index.js CHANGED
@@ -279078,7 +279078,7 @@ if __name__ == "__main__":
279078
279078
  });
279079
279079
 
279080
279080
  // packages/execution/dist/tools/media-store-migrate.js
279081
- import { existsSync as existsSync41, readdirSync as readdirSync16, readFileSync as readFileSync30, statSync as statSync16, mkdirSync as mkdirSync22, copyFileSync, rmSync as rmSync5, statfsSync as statfsSync2 } from "node:fs";
279081
+ import { existsSync as existsSync41, readdirSync as readdirSync16, readFileSync as readFileSync30, statSync as statSync16, lstatSync, readlinkSync as readlinkSync2, symlinkSync, mkdirSync as mkdirSync22, copyFileSync, rmSync as rmSync5, statfsSync as statfsSync2 } from "node:fs";
279082
279082
  import { join as join50, dirname as dirname13, extname as extname6, resolve as resolvePath } from "node:path";
279083
279083
  function approxDirBytes(dir, budget = { nodes: 2e5 }) {
279084
279084
  let total = 0;
@@ -279209,19 +279209,41 @@ function freeBytesAt(path12) {
279209
279209
  return Number.MAX_SAFE_INTEGER;
279210
279210
  }
279211
279211
  }
279212
+ function treeSizeNoFollow(dir) {
279213
+ let entries;
279214
+ try {
279215
+ entries = readdirSync16(dir, { withFileTypes: true });
279216
+ } catch {
279217
+ return 0;
279218
+ }
279219
+ let total = 0;
279220
+ for (const ent of entries) {
279221
+ const p2 = join50(dir, ent.name);
279222
+ try {
279223
+ if (ent.isSymbolicLink())
279224
+ total += lstatSync(p2).size;
279225
+ else if (ent.isDirectory())
279226
+ total += treeSizeNoFollow(p2);
279227
+ else if (ent.isFile())
279228
+ total += statSync16(p2).size;
279229
+ } catch {
279230
+ }
279231
+ }
279232
+ return total;
279233
+ }
279212
279234
  function copyDirWithProgress(src2, dst, onFile) {
279213
279235
  mkdirSync22(dst, { recursive: true });
279214
279236
  for (const ent of readdirSync16(src2, { withFileTypes: true })) {
279215
279237
  const s2 = join50(src2, ent.name);
279216
279238
  const d2 = join50(dst, ent.name);
279217
- if (ent.isDirectory()) {
279218
- copyDirWithProgress(s2, d2, onFile);
279219
- } else if (ent.isSymbolicLink()) {
279239
+ if (ent.isSymbolicLink()) {
279220
279240
  try {
279221
- copyFileSync(s2, d2);
279222
- onFile(statSync16(d2).size, s2);
279241
+ symlinkSync(readlinkSync2(s2), d2);
279242
+ onFile(lstatSync(d2).size, s2);
279223
279243
  } catch {
279224
279244
  }
279245
+ } else if (ent.isDirectory()) {
279246
+ copyDirWithProgress(s2, d2, onFile);
279225
279247
  } else if (ent.isFile()) {
279226
279248
  copyFileSync(s2, d2);
279227
279249
  let size = 0;
@@ -279257,7 +279279,7 @@ function relocateMediaStore(args) {
279257
279279
  if (!dryRun && existsSync41(dst) && readdirSync16(dst).length > 0) {
279258
279280
  throw new Error(`Destination already has a non-empty "${name10}" folder: ${dst}. Choose an empty/new folder.`);
279259
279281
  }
279260
- const bytes = dirSizeBytes(src2);
279282
+ const bytes = treeSizeNoFollow(src2);
279261
279283
  present.push({ name: name10, src: src2, dst, bytes });
279262
279284
  bytesTotal += bytes;
279263
279285
  }
@@ -279289,8 +279311,8 @@ function relocateMediaStore(args) {
279289
279311
  emit2({ stage: "copy", bytesDone, bytesTotal, currentPath });
279290
279312
  });
279291
279313
  emit2({ stage: "verify", bytesDone, bytesTotal, message: `Verifying ${sub2.name}…` });
279292
- const copied = dirSizeBytes(sub2.dst);
279293
- if (copied < sub2.bytes * 0.99) {
279314
+ const copied = treeSizeNoFollow(sub2.dst);
279315
+ if (copied < sub2.bytes * 0.95) {
279294
279316
  throw new Error(`Verification failed for "${sub2.name}" (${formatBytes3(copied)} of ${formatBytes3(sub2.bytes)} copied). Source left intact at ${sub2.src}.`);
279295
279317
  }
279296
279318
  }
@@ -279320,9 +279342,15 @@ async function copyDirWithProgressAsync(src2, dst, onFile) {
279320
279342
  for (const ent of entries) {
279321
279343
  const s2 = join50(src2, ent.name);
279322
279344
  const d2 = join50(dst, ent.name);
279323
- if (ent.isDirectory()) {
279345
+ if (ent.isSymbolicLink()) {
279346
+ try {
279347
+ await fsp2.symlink(await fsp2.readlink(s2), d2);
279348
+ onFile((await fsp2.lstat(d2)).size, s2);
279349
+ } catch {
279350
+ }
279351
+ } else if (ent.isDirectory()) {
279324
279352
  await copyDirWithProgressAsync(s2, d2, onFile);
279325
- } else if (ent.isFile() || ent.isSymbolicLink()) {
279353
+ } else if (ent.isFile()) {
279326
279354
  try {
279327
279355
  await fsp2.copyFile(s2, d2);
279328
279356
  let size = 0;
@@ -279364,7 +279392,7 @@ async function relocateMediaStoreAsync(args) {
279364
279392
  if (!dryRun && existsSync41(dst) && readdirSync16(dst).length > 0) {
279365
279393
  throw new Error(`Destination already has a non-empty "${name10}" folder: ${dst}. Choose an empty/new folder.`);
279366
279394
  }
279367
- const bytes = dirSizeBytes(src2);
279395
+ const bytes = treeSizeNoFollow(src2);
279368
279396
  present.push({ name: name10, src: src2, dst, bytes });
279369
279397
  bytesTotal += bytes;
279370
279398
  }
@@ -279389,7 +279417,7 @@ async function relocateMediaStoreAsync(args) {
279389
279417
  emit2({ stage: "copy", bytesDone, bytesTotal, currentPath });
279390
279418
  });
279391
279419
  emit2({ stage: "verify", bytesDone, bytesTotal, message: `Verifying ${sub2.name}…` });
279392
- if (dirSizeBytes(sub2.dst) < sub2.bytes * 0.99) {
279420
+ if (treeSizeNoFollow(sub2.dst) < sub2.bytes * 0.95) {
279393
279421
  throw new Error(`Verification failed for "${sub2.name}". Source left intact at ${sub2.src}.`);
279394
279422
  }
279395
279423
  }
@@ -623226,8 +623254,11 @@ __export(daemon_exports, {
623226
623254
  ensureDaemon: () => ensureDaemon,
623227
623255
  forceKillDaemon: () => forceKillDaemon,
623228
623256
  getDaemonPid: () => getDaemonPid,
623257
+ getDaemonReportedVersion: () => getDaemonReportedVersion,
623229
623258
  getDaemonStatus: () => getDaemonStatus,
623259
+ getLocalCliVersion: () => getLocalCliVersion,
623230
623260
  isDaemonRunning: () => isDaemonRunning,
623261
+ restartDaemon: () => restartDaemon,
623231
623262
  startDaemon: () => startDaemon,
623232
623263
  stopDaemon: () => stopDaemon
623233
623264
  });
@@ -623257,6 +623288,48 @@ async function isDaemonRunning(port) {
623257
623288
  return false;
623258
623289
  }
623259
623290
  }
623291
+ function getLocalCliVersion() {
623292
+ try {
623293
+ const here = dirname42(fileURLToPath17(import.meta.url));
623294
+ for (const rel of ["../package.json", "../../package.json", "./package.json", "../../../package.json"]) {
623295
+ const p2 = join135(here, rel);
623296
+ if (existsSync123(p2)) {
623297
+ const v = JSON.parse(readFileSync100(p2, "utf8"))?.version;
623298
+ if (v) return String(v);
623299
+ }
623300
+ }
623301
+ } catch {
623302
+ }
623303
+ return "0.0.0";
623304
+ }
623305
+ async function getDaemonReportedVersion(port) {
623306
+ const p2 = port ?? getDaemonPort();
623307
+ try {
623308
+ const resp = await fetch(`http://127.0.0.1:${p2}/health`, { signal: AbortSignal.timeout(2e3) });
623309
+ if (!resp.ok) return null;
623310
+ const data = await resp.json();
623311
+ return data.version ?? null;
623312
+ } catch {
623313
+ return null;
623314
+ }
623315
+ }
623316
+ async function restartDaemon(port) {
623317
+ const p2 = port ?? getDaemonPort();
623318
+ try {
623319
+ const { spawnSync: spawnSync10 } = await import("node:child_process");
623320
+ const enabled2 = spawnSync10("systemctl", ["--user", "is-enabled", "omnius-daemon.service"], {
623321
+ stdio: "ignore",
623322
+ timeout: 5e3
623323
+ });
623324
+ if (enabled2.status === 0) {
623325
+ spawnSync10("systemctl", ["--user", "restart", "omnius-daemon.service"], { stdio: "ignore", timeout: 2e4 });
623326
+ return;
623327
+ }
623328
+ } catch {
623329
+ }
623330
+ await forceKillDaemon(p2);
623331
+ await startDaemon();
623332
+ }
623260
623333
  function getDaemonPid() {
623261
623334
  if (!existsSync123(PID_FILE2)) return null;
623262
623335
  try {
@@ -623451,6 +623524,20 @@ async function forceKillDaemon(port) {
623451
623524
  async function ensureDaemon() {
623452
623525
  const port = getDaemonPort();
623453
623526
  if (await isDaemonRunning(port)) {
623527
+ if (process.env["OMNIUS_NO_VERSION_GUARD"] !== "1") {
623528
+ const running = await getDaemonReportedVersion(port);
623529
+ const local = getLocalCliVersion();
623530
+ if (running && local !== "0.0.0" && running !== local) {
623531
+ await restartDaemon(port);
623532
+ for (let i2 = 0; i2 < 24; i2++) {
623533
+ await new Promise((r2) => setTimeout(r2, 500));
623534
+ if (await isDaemonRunning(port) && await getDaemonReportedVersion(port) === local) {
623535
+ return true;
623536
+ }
623537
+ }
623538
+ return await isDaemonRunning(port);
623539
+ }
623540
+ }
623454
623541
  return true;
623455
623542
  }
623456
623543
  const stalePid = getDaemonPid();
@@ -630946,7 +631033,7 @@ import {
630946
631033
  writeFileSync as writeFileSync66,
630947
631034
  mkdirSync as mkdirSync76,
630948
631035
  readdirSync as readdirSync44,
630949
- lstatSync,
631036
+ lstatSync as lstatSync2,
630950
631037
  statSync as statSync48,
630951
631038
  rmSync as rmSync10,
630952
631039
  appendFileSync as appendFileSync12,
@@ -639402,7 +639489,7 @@ function cacheCandidatePaths(root, model) {
639402
639489
  }
639403
639490
  function directorySizeBytes2(path12, seen = /* @__PURE__ */ new Set()) {
639404
639491
  try {
639405
- const stat8 = lstatSync(path12);
639492
+ const stat8 = lstatSync2(path12);
639406
639493
  if (stat8.isSymbolicLink()) return 0;
639407
639494
  if (stat8.isFile()) return stat8.size;
639408
639495
  if (!stat8.isDirectory()) return 0;
@@ -681018,6 +681105,54 @@ function handleRelocateStatus(ctx3) {
681018
681105
  });
681019
681106
  return true;
681020
681107
  }
681108
+ async function handleAvAnalyze(ctx3) {
681109
+ if (!requireRunScope(ctx3, "AV analysis")) return true;
681110
+ const body = await parseJsonBodyStrict(ctx3.req).catch(() => null);
681111
+ const raw = body?.path || body?.mediaUri;
681112
+ if (!raw) {
681113
+ sendProblem(ctx3.res, problemDetails({ type: P.invalidRequest, status: 400, title: "Missing media path", detail: "POST body must include {path} or {mediaUri}", instance: ctx3.requestId }));
681114
+ return true;
681115
+ }
681116
+ const filePath = raw.startsWith("file://") ? raw.slice(7) : raw;
681117
+ if (!existsSync149(filePath)) {
681118
+ sendProblem(ctx3.res, problemDetails({ type: P.notFound, status: 404, title: "Media not found", detail: filePath, instance: ctx3.requestId }));
681119
+ return true;
681120
+ }
681121
+ try {
681122
+ const registry4 = buildRegistry();
681123
+ const adapterStatus = {};
681124
+ let anyLive = false;
681125
+ for (const role of AV_ROLES) {
681126
+ const a2 = await registry4.selectForRole(role);
681127
+ adapterStatus[role] = a2 && !a2.meta.isMock ? "live" : "mock";
681128
+ if (adapterStatus[role] === "live") anyLive = true;
681129
+ }
681130
+ const episodeId = `rest-${basename37(filePath)}-${Date.now().toString(36)}`;
681131
+ const ingest = await ingestMedia(episodeId, `file://${filePath}`);
681132
+ const store2 = await analyzeEpisode({ episodeId, mediaUri: `file://${filePath}`, durationSec: ingest.source.durationSec, registry: registry4, windows: ingest.shots, roles: AV_ROLES });
681133
+ const world = store2.snapshot();
681134
+ const answer = composeAnswer(world, body?.question ?? "");
681135
+ const cap = getMediaCapability();
681136
+ sendJson2(ctx3.res, 200, {
681137
+ data: {
681138
+ episodeId,
681139
+ source: ingest.source,
681140
+ shots: ingest.shots,
681141
+ stack: cap.stack,
681142
+ adapters: adapterStatus,
681143
+ modelsLive: anyLive,
681144
+ note: anyLive ? void 0 : "No live AV models loaded yet — entity/event results are scaffold placeholders from mock adapters. They become real once the sidecar models finish downloading.",
681145
+ entities: world.entities,
681146
+ events: world.events,
681147
+ relations: world.relations,
681148
+ answer
681149
+ }
681150
+ });
681151
+ } catch (err) {
681152
+ sendProblem(ctx3.res, problemDetails({ type: P.internalError, status: 500, title: "AV analysis error", detail: err instanceof Error ? err.message : String(err), instance: ctx3.requestId }));
681153
+ }
681154
+ return true;
681155
+ }
681021
681156
  async function runGeneration(ctx3, kind, buildTool, buildArgs) {
681022
681157
  if (!requireRunScope(ctx3, `${kind} generation`)) return true;
681023
681158
  const body = await parseJsonBodyStrict(ctx3.req).catch(() => null);
@@ -681187,6 +681322,7 @@ async function tryRouteMedia(ctx3) {
681187
681322
  if (!pathname.startsWith("/v1/media")) return false;
681188
681323
  if (pathname === "/v1/media/models" && method === "GET") return handleListModels(ctx3);
681189
681324
  if (pathname === "/v1/media/store" && method === "GET") return handleStoreInfo(ctx3);
681325
+ if (pathname === "/v1/media/av/analyze" && method === "POST") return handleAvAnalyze(ctx3);
681190
681326
  if (pathname === "/v1/media/migrate" && method === "POST") return handleMigrate(ctx3);
681191
681327
  if (pathname === "/v1/media/relocate" && method === "POST") return handleRelocate(ctx3);
681192
681328
  if (pathname === "/v1/media/relocate/status" && method === "GET") return handleRelocateStatus(ctx3);
@@ -681265,7 +681401,7 @@ async function tryRouteMedia(ctx3) {
681265
681401
  }
681266
681402
  return false;
681267
681403
  }
681268
- var PROBLEM_BASE, P, MIME_BY_EXT, _relocateJob;
681404
+ var PROBLEM_BASE, P, MIME_BY_EXT, _relocateJob, AV_ROLES;
681269
681405
  var init_routes_media = __esm({
681270
681406
  "packages/cli/src/api/routes-media.ts"() {
681271
681407
  "use strict";
@@ -681296,6 +681432,7 @@ var init_routes_media = __esm({
681296
681432
  ".m4a": "audio/mp4"
681297
681433
  };
681298
681434
  _relocateJob = null;
681435
+ AV_ROLES = ["video_temporal", "grounding", "tracking", "audio_event", "cross_modal"];
681299
681436
  }
681300
681437
  });
681301
681438
 
@@ -696502,6 +696639,7 @@ function getOpenApiSpec() {
696502
696639
  "/v1/media/migrate": { post: { summary: "Dedup + migrate legacy per-group media caches into the unified store — body {dryRun?, roots?, maxDepth?}", tags: ["Media"], responses: { 200: { description: "Migration report (bytes reclaimed/migrated)" }, 403: { description: "Insufficient scope" } } } },
696503
696640
  "/v1/media/relocate": { post: { summary: "Relocate the whole media store (weights/venvs/gallery) to a chosen folder — body {newRoot, dryRun?}; streams media.relocate_progress and returns 202 + job_id", tags: ["Media"], responses: { 200: { description: "Dry-run plan" }, 202: { description: "Relocation started" }, 400: { description: "Missing newRoot" }, 409: { description: "Relocation already running" } } } },
696504
696641
  "/v1/media/relocate/status": { get: { summary: "Status of the in-flight (or last) media-store relocation job", tags: ["Media"], responses: { 200: { description: "Relocation job status + progress" } } } },
696642
+ "/v1/media/av/analyze": { post: { summary: "Analyze a media file into a grounded entity/event/evidence answer (AV entity-comprehension) — body {path|mediaUri, question?}; reports per-role live-vs-mock adapter status", tags: ["Media"], responses: { 200: { description: "Grounded answer + entity/event graph" }, 400: { description: "Missing media path" }, 404: { description: "Media not found" } } } },
696505
696643
  "/v1/media/image": { post: { summary: "Generate an image — body {prompt, model?, backend?, width?, height?, steps?, guidance?, seed?, aspect_ratio?}", tags: ["Media"], responses: { 200: { description: "Generated image path + gallery URL" }, 400: { description: "Missing prompt" }, 403: { description: "Insufficient scope" }, 502: { description: "Generation failed" } } } },
696506
696644
  "/v1/media/video": { post: { summary: "Generate a video — body {prompt, model?, backend?, num_frames?, fps?, width?, height?, steps?, guidance?, seed?}", tags: ["Media"], responses: { 200: { description: "Generated video path + gallery URL" }, 400: { description: "Missing prompt" }, 403: { description: "Insufficient scope" }, 502: { description: "Generation failed" } } } },
696507
696645
  "/v1/media/audio": { post: { summary: "Generate a sound effect — body {prompt, model?, backend?, duration?, seed?}", tags: ["Media"], responses: { 200: { description: "Generated audio path + gallery URL" }, 400: { description: "Missing prompt" }, 403: { description: "Insufficient scope" }, 502: { description: "Generation failed" } } } },
@@ -707162,6 +707300,39 @@ function startApiServer(options2 = {}) {
707162
707300
  log22(`
707163
707301
  omnius API server v${version4}
707164
707302
  `);
707303
+ if (process.env["OMNIUS_DAEMON"] === "1" && process.env["OMNIUS_NO_VERSION_GUARD"] !== "1") {
707304
+ const readDiskVersion = () => {
707305
+ try {
707306
+ const here = dirname50(fileURLToPath20(import.meta.url));
707307
+ for (const rel of ["../package.json", "../../package.json", "../../../package.json", "../../../../package.json"]) {
707308
+ const p2 = join169(here, rel);
707309
+ if (existsSync157(p2)) {
707310
+ const pkg = JSON.parse(readFileSync128(p2, "utf8"));
707311
+ if (pkg.name === "omnius" || pkg.name === "@omnius/cli" || pkg.name === "@omnius/monorepo") {
707312
+ return pkg.version ?? null;
707313
+ }
707314
+ }
707315
+ }
707316
+ } catch {
707317
+ }
707318
+ return null;
707319
+ };
707320
+ const bootVersion = readDiskVersion() ?? version4;
707321
+ const versionWatch = setInterval(() => {
707322
+ const disk = readDiskVersion();
707323
+ if (disk && disk !== bootVersion) {
707324
+ log22(` [daemon] version changed on disk ${bootVersion} -> ${disk}; restarting for the new version…
707325
+ `);
707326
+ try {
707327
+ server2.close(() => process.exit(0));
707328
+ } catch {
707329
+ process.exit(0);
707330
+ }
707331
+ setTimeout(() => process.exit(0), 3e3).unref();
707332
+ }
707333
+ }, 2e4);
707334
+ versionWatch.unref();
707335
+ }
707165
707336
  const proto = useTls ? "https" : "http";
707166
707337
  log22(` Listening on ${proto}://${host}:${port}
707167
707338
  `);
@@ -201,6 +201,7 @@ All generation is backed by the unified `~/.omnius` model store and shared venvs
201
201
  | `POST` | `/v1/media/migrate` | Dedup + migrate legacy per-group caches into the unified store |
202
202
  | `POST` | `/v1/media/relocate` | Relocate the whole media store (weights/venvs/gallery) to a chosen folder |
203
203
  | `GET` | `/v1/media/relocate/status` | Status + progress of the media-store relocation job |
204
+ | `POST` | `/v1/media/av/analyze` | Analyze a media file into a grounded entity/event answer (AV comprehension) |
204
205
  | `POST` | `/v1/media/image` | Generate an image |
205
206
  | `POST` | `/v1/media/video` | Generate a video |
206
207
  | `POST` | `/v1/media/audio` | Generate a sound effect |
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.330",
3
+ "version": "1.0.332",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.330",
9
+ "version": "1.0.332",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.330",
3
+ "version": "1.0.332",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",