omnius 1.0.412 → 1.0.413

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
@@ -41412,7 +41412,7 @@ ${content}`
41412
41412
  // packages/execution/dist/tools/transcribe-tool.js
41413
41413
  import { existsSync as existsSync38, mkdirSync as mkdirSync22, writeFileSync as writeFileSync21, readFileSync as readFileSync30, unlinkSync as unlinkSync5, readdirSync as readdirSync14 } from "node:fs";
41414
41414
  import { join as join40, basename as basename7, extname as extname4, resolve as resolve21 } from "node:path";
41415
- import { homedir as homedir11 } from "node:os";
41415
+ import { homedir as homedir11, tmpdir as tmpdir5 } from "node:os";
41416
41416
  function transcriptionPythonEnv(extra = {}) {
41417
41417
  const env2 = { ...process.env, ...extra };
41418
41418
  applyMediaCudaDeviceFilterToEnv(env2, "asr");
@@ -41639,6 +41639,11 @@ var init_transcribe_tool = __esm({
41639
41639
  diarize: {
41640
41640
  type: "boolean",
41641
41641
  description: "Enable speaker diarization (identify who said what). Default: false"
41642
+ },
41643
+ backend: {
41644
+ type: "string",
41645
+ description: "ASR backend preference. auto tries fast transcribe-cli first; managed-whisper uses Omnius' isolated Whisper venv directly.",
41646
+ enum: ["auto", "managed-whisper", "transcribe-cli"]
41642
41647
  }
41643
41648
  },
41644
41649
  required: ["path"]
@@ -41652,6 +41657,7 @@ var init_transcribe_tool = __esm({
41652
41657
  const filePath = resolve21(this.workingDir, String(args["path"] ?? ""));
41653
41658
  let model = String(args["model"] ?? "base");
41654
41659
  const diarize = Boolean(args["diarize"] ?? false);
41660
+ const backend = String(args["backend"] ?? "auto").toLowerCase();
41655
41661
  if (!existsSync38(filePath)) {
41656
41662
  return {
41657
41663
  success: false,
@@ -41703,8 +41709,21 @@ var init_transcribe_tool = __esm({
41703
41709
  } catch (err) {
41704
41710
  failures.push(`managed ASR runtime bootstrap: ${err instanceof Error ? err.message : String(err)}`);
41705
41711
  }
41712
+ if (backend === "managed-whisper") {
41713
+ const managed2 = await this.execViaManagedWhisper(filePath, model, start2);
41714
+ if (managed2.success)
41715
+ return managed2;
41716
+ if (managed2.error)
41717
+ failures.push(managed2.error);
41718
+ return {
41719
+ success: false,
41720
+ output: "",
41721
+ error: `Managed Whisper ASR failed. ${failures.join(" | ").slice(0, 1200)}`,
41722
+ durationMs: performance.now() - start2
41723
+ };
41724
+ }
41706
41725
  const tc = await loadTranscribeCli() ?? await ensureManagedTranscribeCliRuntime();
41707
- if (tc) {
41726
+ if (tc && backend !== "managed-whisper") {
41708
41727
  try {
41709
41728
  const result = await withProcessEnv(transcriptionPythonEnv(), () => tc.transcribe(filePath, {
41710
41729
  model,
@@ -41894,8 +41913,14 @@ var init_transcribe_tool = __esm({
41894
41913
  }
41895
41914
  }
41896
41915
  async execViaManagedWhisper(filePath, model, start2) {
41897
- const scriptPath2 = join40(this.workingDir, ".omnius", "tmp", `managed-whisper-${Date.now()}.py`);
41898
- mkdirSync22(join40(this.workingDir, ".omnius", "tmp"), { recursive: true });
41916
+ let scriptDir = join40(this.workingDir, ".omnius", "tmp");
41917
+ try {
41918
+ mkdirSync22(scriptDir, { recursive: true });
41919
+ } catch {
41920
+ scriptDir = join40(tmpdir5(), "omnius-asr");
41921
+ mkdirSync22(scriptDir, { recursive: true });
41922
+ }
41923
+ const scriptPath2 = join40(scriptDir, `managed-whisper-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.py`);
41899
41924
  const script = `
41900
41925
  import json, os, warnings
41901
41926
  warnings.filterwarnings("ignore")
@@ -41904,13 +41929,15 @@ audio_file = ${JSON.stringify(filePath)}
41904
41929
  model_name = ${JSON.stringify(model)}
41905
41930
  try:
41906
41931
  import whisper
41907
- device = "cpu"
41908
- try:
41909
- import torch
41910
- if torch.cuda.is_available():
41911
- device = "cuda"
41912
- except Exception:
41913
- pass
41932
+ device = os.environ.get("OMNIUS_ASR_DEVICE", "cpu").strip().lower() or "cpu"
41933
+ if device == "auto":
41934
+ device = "cpu"
41935
+ try:
41936
+ import torch
41937
+ if torch.cuda.is_available():
41938
+ device = "cuda"
41939
+ except Exception:
41940
+ pass
41914
41941
  m = whisper.load_model(model_name, device=device)
41915
41942
  result = m.transcribe(audio_file, fp16=(device == "cuda"), condition_on_previous_text=False)
41916
41943
  segments = []
@@ -42491,7 +42518,7 @@ var init_structured_file = __esm({
42491
42518
  import { spawn as spawn7 } from "node:child_process";
42492
42519
  import { writeFile as writeFile9, mkdtemp, rm as rm2, readdir as readdir4, stat as stat4 } from "node:fs/promises";
42493
42520
  import { join as join41 } from "node:path";
42494
- import { tmpdir as tmpdir5 } from "node:os";
42521
+ import { tmpdir as tmpdir6 } from "node:os";
42495
42522
  function runProcess(cmd, args, options2) {
42496
42523
  return new Promise((resolve76) => {
42497
42524
  const proc = spawn7(cmd, args, {
@@ -42689,7 +42716,7 @@ ${result.filesCreated.join("\n")}`);
42689
42716
  // Subprocess mode — temp directory + separate process
42690
42717
  // -------------------------------------------------------------------------
42691
42718
  async #runSubprocess(code8, langConfig, timeoutMs, stdin) {
42692
- const sandboxDir = await mkdtemp(join41(tmpdir5(), "omnius-sandbox-"));
42719
+ const sandboxDir = await mkdtemp(join41(tmpdir6(), "omnius-sandbox-"));
42693
42720
  try {
42694
42721
  const scriptFile = join41(sandboxDir, `_sandbox_script${langConfig.ext}`);
42695
42722
  await writeFile9(scriptFile, code8, "utf-8");
@@ -42716,7 +42743,7 @@ ${result.filesCreated.join("\n")}`);
42716
42743
  bash: "bash:5"
42717
42744
  };
42718
42745
  const image = images[language] ?? "node:22-slim";
42719
- const sandboxDir = await mkdtemp(join41(tmpdir5(), "omnius-docker-sandbox-"));
42746
+ const sandboxDir = await mkdtemp(join41(tmpdir6(), "omnius-docker-sandbox-"));
42720
42747
  try {
42721
42748
  const scriptFile = `_sandbox_script${langConfig.ext}`;
42722
42749
  await writeFile9(join41(sandboxDir, scriptFile), code8, "utf-8");
@@ -274241,7 +274268,7 @@ New: ${newNarrative.slice(0, 200)}...`,
274241
274268
  import { spawn as spawn9 } from "node:child_process";
274242
274269
  import { createServer as createServer2 } from "node:net";
274243
274270
  import { join as join44 } from "node:path";
274244
- import { tmpdir as tmpdir6 } from "node:os";
274271
+ import { tmpdir as tmpdir7 } from "node:os";
274245
274272
  import { randomBytes as randomBytes11 } from "node:crypto";
274246
274273
  import { unlinkSync as unlinkSync6 } from "node:fs";
274247
274274
  var ReplTool;
@@ -274313,7 +274340,7 @@ var init_repl = __esm({
274313
274340
  if (!this.proc || this.proc.killed || this.proc.exitCode !== null) {
274314
274341
  await this.startProcess();
274315
274342
  }
274316
- const tempFile = join44(tmpdir6(), `omnius-repl-ctx-${randomBytes11(6).toString("hex")}.txt`);
274343
+ const tempFile = join44(tmpdir7(), `omnius-repl-ctx-${randomBytes11(6).toString("hex")}.txt`);
274317
274344
  const { writeFileSync: writeFs, unlinkSync: unlinkFs } = await import("node:fs");
274318
274345
  writeFs(tempFile, content, "utf8");
274319
274346
  const result = await this.executeCode(`with open(${JSON.stringify(tempFile)}, "r") as _f:
@@ -274540,7 +274567,7 @@ print("__OMNIUS_REPL_READY__")
274540
274567
  if (this.ipcServer)
274541
274568
  return;
274542
274569
  const sockId = randomBytes11(8).toString("hex");
274543
- this.ipcPath = join44(tmpdir6(), `omnius-repl-ipc-${sockId}.sock`);
274570
+ this.ipcPath = join44(tmpdir7(), `omnius-repl-ipc-${sockId}.sock`);
274544
274571
  return new Promise((resolve76, reject) => {
274545
274572
  this.ipcServer = createServer2((conn) => {
274546
274573
  let buffer2 = new Uint8Array(0);
@@ -287719,7 +287746,7 @@ ${parts.join("\n\n")}`,
287719
287746
  // packages/execution/dist/tools/desktop-click.js
287720
287747
  import { readFileSync as readFileSync35 } from "node:fs";
287721
287748
  import { execSync as execSync16 } from "node:child_process";
287722
- import { tmpdir as tmpdir7 } from "node:os";
287749
+ import { tmpdir as tmpdir8 } from "node:os";
287723
287750
  import { join as join57 } from "node:path";
287724
287751
  function getImageDimensions2(filePath) {
287725
287752
  try {
@@ -287936,7 +287963,7 @@ Button: ${button}, Type: ${clickType}`,
287936
287963
  durationMs: performance.now() - start2
287937
287964
  };
287938
287965
  }
287939
- const screenshotPath = join57(tmpdir7(), `omnius-desktop-click-${Date.now()}.png`);
287966
+ const screenshotPath = join57(tmpdir8(), `omnius-desktop-click-${Date.now()}.png`);
287940
287967
  const screenshotBackend = captureDesktopScreenshot(screenshotPath);
287941
287968
  const dims = getImageDimensions2(screenshotPath);
287942
287969
  if (!dims) {
@@ -288103,7 +288130,7 @@ Screenshot: ${screenshotPath}`,
288103
288130
  if (delayMs > 0) {
288104
288131
  await new Promise((r2) => setTimeout(r2, delayMs));
288105
288132
  }
288106
- const screenshotPath = join57(tmpdir7(), `omnius-desktop-describe-${Date.now()}.png`);
288133
+ const screenshotPath = join57(tmpdir8(), `omnius-desktop-describe-${Date.now()}.png`);
288107
288134
  const screenshotBackend = captureDesktopScreenshot(screenshotPath);
288108
288135
  const dims = getImageDimensions2(screenshotPath);
288109
288136
  const imageBuffer = readFileSync35(screenshotPath);
@@ -289307,7 +289334,7 @@ Language: ${language}
289307
289334
  import { existsSync as existsSync50, statSync as statSync21, readFileSync as readFileSync37, unlinkSync as unlinkSync8 } from "node:fs";
289308
289335
  import { resolve as resolve29, basename as basename10, join as join59 } from "node:path";
289309
289336
  import { execSync as execSync18 } from "node:child_process";
289310
- import { tmpdir as tmpdir8 } from "node:os";
289337
+ import { tmpdir as tmpdir9 } from "node:os";
289311
289338
  var PdfToTextTool;
289312
289339
  var init_pdf_to_text = __esm({
289313
289340
  "packages/execution/dist/tools/pdf-to-text.js"() {
@@ -289459,7 +289486,7 @@ ${text2}`,
289459
289486
  if (!ocrCheck.available || !tesCheck.available || !gsCheck.available) {
289460
289487
  return null;
289461
289488
  }
289462
- const tmpPdf = join59(tmpdir8(), `omnius-ocr-${Date.now()}.pdf`);
289489
+ const tmpPdf = join59(tmpdir9(), `omnius-ocr-${Date.now()}.pdf`);
289463
289490
  try {
289464
289491
  const ocrCmd = `ocrmypdf -l ${language} --skip-text ${JSON.stringify(inputPath)} ${JSON.stringify(tmpPdf)}`;
289465
289492
  execSync18(ocrCmd, { stdio: "pipe", timeout: 6e5 });
@@ -289493,7 +289520,7 @@ import { existsSync as existsSync51, mkdirSync as mkdirSync28, statSync as statS
289493
289520
  import { resolve as resolve30, basename as basename11, dirname as dirname16, join as join60 } from "node:path";
289494
289521
  import { execSync as execSync19 } from "node:child_process";
289495
289522
  import { fileURLToPath as fileURLToPath6 } from "node:url";
289496
- import { homedir as homedir13, tmpdir as tmpdir9 } from "node:os";
289523
+ import { homedir as homedir13, tmpdir as tmpdir10 } from "node:os";
289497
289524
  function findOcrScript() {
289498
289525
  const thisDir = dirname16(fileURLToPath6(import.meta.url));
289499
289526
  const devPath3 = resolve30(thisDir, "../../scripts/ocr-advanced.py");
@@ -289726,7 +289753,7 @@ var init_ocr_image_advanced = __esm({
289726
289753
  cmdParts.push("--output-dir", JSON.stringify(resolve30(this.workingDir, outputDir2)));
289727
289754
  let debugDir;
289728
289755
  if (debug) {
289729
- debugDir = join60(tmpdir9(), `omnius-ocr-debug-${Date.now()}`);
289756
+ debugDir = join60(tmpdir10(), `omnius-ocr-debug-${Date.now()}`);
289730
289757
  cmdParts.push("--debug-dir", debugDir);
289731
289758
  }
289732
289759
  try {
@@ -543195,7 +543222,7 @@ var init_process_health = __esm({
543195
543222
  // packages/execution/dist/tools/camera-capture.js
543196
543223
  import { accessSync, constants, readFileSync as readFileSync44, writeFileSync as writeFileSync28, unlinkSync as unlinkSync11, existsSync as existsSync60, mkdirSync as mkdirSync34, readdirSync as readdirSync21, renameSync as renameSync7 } from "node:fs";
543197
543224
  import { join as join75 } from "node:path";
543198
- import { tmpdir as tmpdir10 } from "node:os";
543225
+ import { tmpdir as tmpdir11 } from "node:os";
543199
543226
  function normalizeCameraRotationDegrees(value2) {
543200
543227
  if (value2 === void 0 || value2 === null || value2 === "")
543201
543228
  return 0;
@@ -543693,7 +543720,7 @@ ${formatRouterPlan(plan)}`,
543693
543720
  const height = args["height"] || 720;
543694
543721
  const outputPath3 = args["output_path"];
543695
543722
  const rotation = normalizeCameraRotationDegrees(args["rotate_degrees"] ?? args["rotation_degrees"] ?? args["rotate"]);
543696
- const captureDir = join75(tmpdir10(), "omnius-camera");
543723
+ const captureDir = join75(tmpdir11(), "omnius-camera");
543697
543724
  if (!existsSync60(captureDir))
543698
543725
  mkdirSync34(captureDir, { recursive: true });
543699
543726
  const tempFile = outputPath3 || join75(captureDir, `capture-${Date.now()}.jpg`);
@@ -544075,7 +544102,7 @@ Auto-installed camera dependencies: ${[
544075
544102
  } catch (err) {
544076
544103
  return { success: false, output: "", error: `QooCam OSC error: ${err instanceof Error ? err.message : String(err)}`, durationMs: performance.now() - start2 };
544077
544104
  }
544078
- const captureDir = join75(tmpdir10(), "omnius-camera");
544105
+ const captureDir = join75(tmpdir11(), "omnius-camera");
544079
544106
  if (!existsSync60(captureDir))
544080
544107
  mkdirSync34(captureDir, { recursive: true });
544081
544108
  const tempFile = outputPath3 || join75(captureDir, `qoocam-${Date.now()}.jpg`);
@@ -544225,7 +544252,7 @@ Saved to: ${outputPath3}`;
544225
544252
  import { execSync as execSync26 } from "node:child_process";
544226
544253
  import { readFileSync as readFileSync45, unlinkSync as unlinkSync12, existsSync as existsSync61, mkdirSync as mkdirSync35, statSync as statSync25 } from "node:fs";
544227
544254
  import { join as join76 } from "node:path";
544228
- import { tmpdir as tmpdir11 } from "node:os";
544255
+ import { tmpdir as tmpdir12 } from "node:os";
544229
544256
  var AudioCaptureTool;
544230
544257
  var init_audio_capture = __esm({
544231
544258
  "packages/execution/dist/tools/audio-capture.js"() {
@@ -544331,7 +544358,7 @@ ${devices.join("\n")}`,
544331
544358
  const channels = args["channels"] || 1;
544332
544359
  const format3 = args["format"] || "wav";
544333
544360
  const outputPath3 = args["output_path"];
544334
- const captureDir = join76(tmpdir11(), "omnius-audio");
544361
+ const captureDir = join76(tmpdir12(), "omnius-audio");
544335
544362
  if (!existsSync61(captureDir))
544336
544363
  mkdirSync35(captureDir, { recursive: true });
544337
544364
  const ext = format3 === "mp3" ? "mp3" : "wav";
@@ -544418,7 +544445,7 @@ Saved to: ${tempFile}`,
544418
544445
  }
544419
544446
  checkLevel(args, start2) {
544420
544447
  const device = args["device"] || "default";
544421
- const tempFile = join76(tmpdir11(), `omnius-level-${Date.now()}.raw`);
544448
+ const tempFile = join76(tmpdir12(), `omnius-level-${Date.now()}.raw`);
544422
544449
  try {
544423
544450
  execSync26(`arecord -D ${device} -f S16_LE -r 16000 -c 1 -d 1 -t raw -q ${tempFile}`, { timeout: 5e3, stdio: "pipe" });
544424
544451
  if (!existsSync61(tempFile)) {
@@ -544476,7 +544503,7 @@ Saved to: ${tempFile}`,
544476
544503
  import { execFileSync as execFileSync2, execSync as execSync27, spawn as spawn18 } from "node:child_process";
544477
544504
  import { copyFileSync as copyFileSync4, existsSync as existsSync62, statSync as statSync26, writeFileSync as writeFileSync29, mkdirSync as mkdirSync36, readdirSync as readdirSync22, writeSync, rmSync as rmSync7 } from "node:fs";
544478
544505
  import { basename as basename15, dirname as dirname21, extname as extname12, isAbsolute as isAbsolute4, join as join77, resolve as resolve39 } from "node:path";
544479
- import { homedir as homedir17, tmpdir as tmpdir12 } from "node:os";
544506
+ import { homedir as homedir17, tmpdir as tmpdir13 } from "node:os";
544480
544507
  function ttsPythonEnv(extra = {}) {
544481
544508
  const env2 = { ...process.env, ...extra };
544482
544509
  applyMediaCudaDeviceFilterToEnv(env2, "tts");
@@ -545357,7 +545384,7 @@ function ensureLuxttsDaemon() {
545357
545384
  }, 12e4);
545358
545385
  const daemon = spawn18(venvPy, [inferScript], {
545359
545386
  stdio: ["pipe", "pipe", "pipe"],
545360
- cwd: tmpdir12(),
545387
+ cwd: tmpdir13(),
545361
545388
  env: ttsPythonEnv({ LUXTTS_REPO_PATH: repoDir })
545362
545389
  });
545363
545390
  _luxttsDaemon = daemon;
@@ -545414,7 +545441,7 @@ function luxttsSynthesize(text2, cloneRef, outputPath3, speed = 1) {
545414
545441
  return;
545415
545442
  }
545416
545443
  const id2 = `tts-${++_luxttsRequestId}`;
545417
- const outPath = outputPath3 || join77(tmpdir12(), `omnius-luxtts-${Date.now()}.wav`);
545444
+ const outPath = outputPath3 || join77(tmpdir13(), `omnius-luxtts-${Date.now()}.wav`);
545418
545445
  const timeout2 = setTimeout(() => {
545419
545446
  _luxttsPending.delete(id2);
545420
545447
  reject(new Error("LuxTTS synthesis timeout"));
@@ -545557,7 +545584,7 @@ function ensureMisottsDaemon() {
545557
545584
  }, 12e4);
545558
545585
  const daemon = spawn18(venvPy, [inferScript], {
545559
545586
  stdio: ["pipe", "pipe", "pipe"],
545560
- cwd: tmpdir12(),
545587
+ cwd: tmpdir13(),
545561
545588
  env: ttsPythonEnv({ MISO_TTS_REPO_PATH: repoDir, NO_TORCH_COMPILE: "1" })
545562
545589
  });
545563
545590
  _misottsDaemon = daemon;
@@ -545614,7 +545641,7 @@ function misottsSynthesize(text2, cloneRef, outputPath3, maxAudioLengthMs = 3e4)
545614
545641
  return;
545615
545642
  }
545616
545643
  const id2 = `tts-${++_misottsRequestId}`;
545617
- const outPath = outputPath3 || join77(tmpdir12(), `omnius-misotts-${Date.now()}.wav`);
545644
+ const outPath = outputPath3 || join77(tmpdir13(), `omnius-misotts-${Date.now()}.wav`);
545618
545645
  const timeout2 = setTimeout(() => {
545619
545646
  _misottsPending.delete(id2);
545620
545647
  reject(new Error("MisoTTS synthesis timeout"));
@@ -546272,7 +546299,7 @@ ${tried.map((line) => `- ${line}`).join("\n")}`,
546272
546299
  ], {
546273
546300
  stdio: "pipe",
546274
546301
  timeout: 18e4,
546275
- cwd: tmpdir12()
546302
+ cwd: tmpdir13()
546276
546303
  });
546277
546304
  return `${voice} (${model})`;
546278
546305
  }
@@ -547069,7 +547096,7 @@ ${info}`, durationMs: performance.now() - start2 };
547069
547096
  import { execSync as execSync30 } from "node:child_process";
547070
547097
  import { readFileSync as readFileSync46, unlinkSync as unlinkSync13, existsSync as existsSync63, mkdirSync as mkdirSync37, statSync as statSync27 } from "node:fs";
547071
547098
  import { join as join78 } from "node:path";
547072
- import { tmpdir as tmpdir13 } from "node:os";
547099
+ import { tmpdir as tmpdir14 } from "node:os";
547073
547100
  var SdrScanTool;
547074
547101
  var init_sdr_scan = __esm({
547075
547102
  "packages/execution/dist/tools/sdr-scan.js"() {
@@ -547240,7 +547267,7 @@ Tools installed but rtl_test failed — device may be in use by another process.
547240
547267
  if (!await this.ensureSdrTools()) {
547241
547268
  return { success: false, output: "", error: "rtl-sdr tools not installed. Connect an RTL-SDR dongle and retry (will prompt for install).", durationMs: performance.now() - start2 };
547242
547269
  }
547243
- const captureDir = join78(tmpdir13(), "omnius-sdr");
547270
+ const captureDir = join78(tmpdir14(), "omnius-sdr");
547244
547271
  if (!existsSync63(captureDir))
547245
547272
  mkdirSync37(captureDir, { recursive: true });
547246
547273
  const outFile = join78(captureDir, `scan-${Date.now()}.csv`);
@@ -547324,7 +547351,7 @@ ${output.slice(0, 2e3)}`,
547324
547351
  } catch {
547325
547352
  return { success: false, output: "", error: "rtl_fm not installed. Run: sudo apt install rtl-sdr", durationMs: performance.now() - start2 };
547326
547353
  }
547327
- const captureDir = join78(tmpdir13(), "omnius-sdr");
547354
+ const captureDir = join78(tmpdir14(), "omnius-sdr");
547328
547355
  if (!existsSync63(captureDir))
547329
547356
  mkdirSync37(captureDir, { recursive: true });
547330
547357
  const outFile = join78(captureDir, `fm-${Date.now()}.wav`);
@@ -547781,7 +547808,7 @@ ${result.trim()}`, durationMs: performance.now() - start2 };
547781
547808
  // packages/execution/dist/tools/audio-analyze.js
547782
547809
  import { existsSync as existsSync65, mkdirSync as mkdirSync38, writeFileSync as writeFileSync30 } from "node:fs";
547783
547810
  import { basename as basename16, isAbsolute as isAbsolute5, join as join79, resolve as resolve40 } from "node:path";
547784
- import { homedir as homedir18, tmpdir as tmpdir14 } from "node:os";
547811
+ import { homedir as homedir18, tmpdir as tmpdir15 } from "node:os";
547785
547812
  import { fileURLToPath as fileURLToPath9 } from "node:url";
547786
547813
  function audioAnalysisPythonEnv(extra = {}) {
547787
547814
  const env2 = { ...process.env, ...extra };
@@ -548212,7 +548239,7 @@ except Exception as e:
548212
548239
  const contextDir = join79(homedir18(), ".omnius", "audio-context");
548213
548240
  if (!existsSync65(contextDir))
548214
548241
  mkdirSync38(contextDir, { recursive: true });
548215
- const audioFile = join79(tmpdir14(), `omnius-listen-${Date.now()}.wav`);
548242
+ const audioFile = join79(tmpdir15(), `omnius-listen-${Date.now()}.wav`);
548216
548243
  try {
548217
548244
  await execFileText("arecord", ["-D", "default", "-f", "S16_LE", "-r", "16000", "-c", "1", "-d", String(Math.min(duration, 60)), "-q", audioFile], {
548218
548245
  timeout: (duration + 10) * 1e3
@@ -548353,7 +548380,7 @@ ${e2.stderr ? String(e2.stderr) : ""}`.trim();
548353
548380
  return file;
548354
548381
  }
548355
548382
  const duration = args["duration"] || 5;
548356
- const outFile = join79(tmpdir14(), `omnius-analyze-${Date.now()}.wav`);
548383
+ const outFile = join79(tmpdir15(), `omnius-analyze-${Date.now()}.wav`);
548357
548384
  try {
548358
548385
  await execFileText("arecord", ["-D", "default", "-f", "S16_LE", "-r", "16000", "-c", "1", "-d", String(duration), "-q", outFile], {
548359
548386
  timeout: (duration + 10) * 1e3
@@ -548382,7 +548409,7 @@ ${e2.stderr ? String(e2.stderr) : ""}`.trim();
548382
548409
  }
548383
548410
  /** Run a Python script in the venv and parse JSON output */
548384
548411
  async runPythonScript(script, start2, label) {
548385
- const scriptFile = join79(tmpdir14(), `omnius-audio-${Date.now()}.py`);
548412
+ const scriptFile = join79(tmpdir15(), `omnius-audio-${Date.now()}.py`);
548386
548413
  writeFileSync30(scriptFile, script);
548387
548414
  try {
548388
548415
  const output = await execFileText(VENV_PYTHON, [scriptFile], {
@@ -548418,7 +548445,7 @@ ${output}`, durationMs: performance.now() - start2 };
548418
548445
  import { execSync as execSync33, spawnSync as spawnSync6 } from "node:child_process";
548419
548446
  import { existsSync as existsSync66, readFileSync as readFileSync47, writeFileSync as writeFileSync31, mkdirSync as mkdirSync39 } from "node:fs";
548420
548447
  import { join as join80 } from "node:path";
548421
- import { tmpdir as tmpdir15, homedir as homedir19 } from "node:os";
548448
+ import { tmpdir as tmpdir16, homedir as homedir19 } from "node:os";
548422
548449
  var GPS_USB_IDS, GpsLocationTool;
548423
548450
  var init_gps_location = __esm({
548424
548451
  "packages/execution/dist/tools/gps-location.js"() {
@@ -548543,7 +548570,7 @@ var init_gps_location = __esm({
548543
548570
  /** Run a Python GPS script using pyserial+pynmea2 and return JSON result */
548544
548571
  async runGpsPython(script, timeoutMs = 3e4) {
548545
548572
  await this.ensureGpsVenv();
548546
- const scriptFile = join80(tmpdir15(), `omnius-gps-${Date.now()}.py`);
548573
+ const scriptFile = join80(tmpdir16(), `omnius-gps-${Date.now()}.py`);
548547
548574
  writeFileSync31(scriptFile, script);
548548
548575
  try {
548549
548576
  const output = execSync33(`${this.GPS_PYTHON} ${scriptFile}`, {
@@ -549015,7 +549042,7 @@ Drift: ${drift != null ? drift + "ms" : "unknown"}`,
549015
549042
  // =========================================================================
549016
549043
  async recordTrack(args, start2) {
549017
549044
  const duration = args["duration"] || 60;
549018
- const outputPath3 = args["output_path"] || join80(tmpdir15(), `omnius-gps-track-${Date.now()}.gpx`);
549045
+ const outputPath3 = args["output_path"] || join80(tmpdir16(), `omnius-gps-track-${Date.now()}.gpx`);
549019
549046
  if (!await this.ensureGpsd(args)) {
549020
549047
  return { success: false, output: "", error: "gpsd required for track recording. Connect a GPS device.", durationMs: performance.now() - start2 };
549021
549048
  }
@@ -549248,7 +549275,7 @@ def _omnius_normalized_features(features):
549248
549275
  import { execFile as execFile6 } from "node:child_process";
549249
549276
  import { existsSync as existsSync67, mkdirSync as mkdirSync40, writeFileSync as writeFileSync32, readFileSync as readFileSync48 } from "node:fs";
549250
549277
  import { join as join81 } from "node:path";
549251
- import { homedir as homedir20, tmpdir as tmpdir16 } from "node:os";
549278
+ import { homedir as homedir20, tmpdir as tmpdir17 } from "node:os";
549252
549279
  function visualMemoryPythonEnv(extra = {}) {
549253
549280
  const env2 = { ...process.env, ...extra };
549254
549281
  applyMediaCudaDeviceFilterToEnv(env2, "vision");
@@ -550020,7 +550047,7 @@ ${objects.join("\n") || " (none taught)"}`,
550020
550047
  }
550021
550048
  }
550022
550049
  async runVisionPython(script, timeoutMs = 6e4) {
550023
- const scriptFile = join81(tmpdir16(), `omnius-vmem-${Date.now()}.py`);
550050
+ const scriptFile = join81(tmpdir17(), `omnius-vmem-${Date.now()}.py`);
550024
550051
  writeFileSync32(scriptFile, script);
550025
550052
  try {
550026
550053
  const { stdout: output } = await execFileText2(VENV_PY, [scriptFile], {
@@ -550053,7 +550080,7 @@ ${objects.join("\n") || " (none taught)"}`,
550053
550080
  import { execSync as execSync34 } from "node:child_process";
550054
550081
  import { appendFileSync as appendFileSync5, existsSync as existsSync68, mkdirSync as mkdirSync41, writeFileSync as writeFileSync33, readFileSync as readFileSync49, readdirSync as readdirSync23 } from "node:fs";
550055
550082
  import { join as join82 } from "node:path";
550056
- import { homedir as homedir21, tmpdir as tmpdir17 } from "node:os";
550083
+ import { homedir as homedir21, tmpdir as tmpdir18 } from "node:os";
550057
550084
  import { randomUUID as randomUUID15 } from "node:crypto";
550058
550085
  var MM_DIR, MM_INDEX, MultimodalMemoryTool;
550059
550086
  var init_multimodal_memory = __esm({
@@ -550172,7 +550199,7 @@ with torch.no_grad():
550172
550199
  features = _omnius_normalized_features(model.get_image_features(**inputs))
550173
550200
  print(json.dumps(features[0].cpu().numpy().tolist()))
550174
550201
  `;
550175
- const scriptFile = join82(tmpdir17(), `mm-clip-${Date.now()}.py`);
550202
+ const scriptFile = join82(tmpdir18(), `mm-clip-${Date.now()}.py`);
550176
550203
  writeFileSync33(scriptFile, clipScript);
550177
550204
  const clipOutput = execSync34(`${venvPy} ${scriptFile}`, { encoding: "utf8", timeout: 12e4, env: { ...process.env, PYTHONUNBUFFERED: "1" } });
550178
550205
  const embedding = JSON.parse(clipOutput.trim().split("\n").pop());
@@ -550194,7 +550221,7 @@ faces = app.get(img) if img is not None else []
550194
550221
  result = [{"confidence": float(f.det_score), "age": int(f.age) if hasattr(f, 'age') else None} for f in faces]
550195
550222
  print(json.dumps(result))
550196
550223
  `;
550197
- const scriptFile = join82(tmpdir17(), `mm-face-${Date.now()}.py`);
550224
+ const scriptFile = join82(tmpdir18(), `mm-face-${Date.now()}.py`);
550198
550225
  writeFileSync33(scriptFile, faceScript);
550199
550226
  const faceOutput = execSync34(`${venvPy} ${scriptFile}`, { encoding: "utf8", timeout: 6e4, env: { ...process.env, PYTHONUNBUFFERED: "1" } });
550200
550227
  const faces = JSON.parse(faceOutput.trim().split("\n").pop());
@@ -550246,7 +550273,7 @@ with open(model.class_map_path().numpy().decode()) as f:
550246
550273
  top=scores.numpy().mean(axis=0).argsort()[-1]
550247
550274
  print(classes[top])
550248
550275
  `;
550249
- const scriptFile = join82(tmpdir17(), `mm-yamnet-${Date.now()}.py`);
550276
+ const scriptFile = join82(tmpdir18(), `mm-yamnet-${Date.now()}.py`);
550250
550277
  writeFileSync33(scriptFile, classifyScript);
550251
550278
  const soundClass = execSync34(`${mlVenvPy} ${scriptFile}`, { encoding: "utf8", timeout: 12e4 }).trim().split("\n").pop();
550252
550279
  episode.audio.soundClass = soundClass;
@@ -550342,7 +550369,7 @@ if faces:
550342
550369
  else:
550343
550370
  print(json.dumps({"enrolled": False, "reason": "no face detected"}))
550344
550371
  `;
550345
- const scriptFile = join82(tmpdir17(), `mm-enroll-${Date.now()}.py`);
550372
+ const scriptFile = join82(tmpdir18(), `mm-enroll-${Date.now()}.py`);
550346
550373
  writeFileSync33(scriptFile, enrollScript);
550347
550374
  const enrollOutput = execSync34(`${venvPy} ${scriptFile}`, { encoding: "utf8", timeout: 6e4, env: { ...process.env, PYTHONUNBUFFERED: "1" } });
550348
550375
  const enrollResult = JSON.parse(enrollOutput.trim().split("\n").pop());
@@ -550397,7 +550424,7 @@ with torch.no_grad():
550397
550424
  features = _omnius_normalized_features(model.get_text_features(**inputs))
550398
550425
  print(json.dumps(features[0].cpu().numpy().tolist()))
550399
550426
  `;
550400
- const scriptFile = join82(tmpdir17(), `mm-clipq-${Date.now()}.py`);
550427
+ const scriptFile = join82(tmpdir18(), `mm-clipq-${Date.now()}.py`);
550401
550428
  writeFileSync33(scriptFile, clipTextScript);
550402
550429
  const output = execSync34(`${venvPy} ${scriptFile}`, { encoding: "utf8", timeout: 6e4, env: { ...process.env, PYTHONUNBUFFERED: "1" } });
550403
550430
  queryClipEmbedding = JSON.parse(output.trim().split("\n").pop());
@@ -550679,7 +550706,7 @@ ${lines.join("\n")}`,
550679
550706
  import { execSync as execSync35, spawnSync as spawnSync7 } from "node:child_process";
550680
550707
  import { existsSync as existsSync69, mkdirSync as mkdirSync42, writeFileSync as writeFileSync34, readFileSync as readFileSync50, unlinkSync as unlinkSync14 } from "node:fs";
550681
550708
  import { dirname as dirname22, join as join83, resolve as resolve41 } from "node:path";
550682
- import { tmpdir as tmpdir18, homedir as homedir22 } from "node:os";
550709
+ import { tmpdir as tmpdir19, homedir as homedir22 } from "node:os";
550683
550710
  import { fileURLToPath as fileURLToPath10 } from "node:url";
550684
550711
  function asrPythonEnv(extra = {}) {
550685
550712
  const env2 = { ...process.env, ...extra };
@@ -550794,7 +550821,7 @@ var init_asr_listen = __esm({
550794
550821
  listenAndTranscribe(args, start2) {
550795
550822
  const duration = args["duration"] || 8;
550796
550823
  const device = args["device"] || "default";
550797
- const captureDir = join83(tmpdir18(), "omnius-asr");
550824
+ const captureDir = join83(tmpdir19(), "omnius-asr");
550798
550825
  if (!existsSync69(captureDir))
550799
550826
  mkdirSync42(captureDir, { recursive: true });
550800
550827
  const audioFile = join83(captureDir, `listen-${Date.now()}.wav`);
@@ -550941,7 +550968,7 @@ except Exception:
550941
550968
 
550942
550969
  print(json.dumps({"ok": False, "error": "No whisper backend available"}))
550943
550970
  `;
550944
- const scriptFile = join83(tmpdir18(), `omnius-asr-whisper-${Date.now()}.py`);
550971
+ const scriptFile = join83(tmpdir19(), `omnius-asr-whisper-${Date.now()}.py`);
550945
550972
  writeFileSync34(scriptFile, whisperScript);
550946
550973
  const pyPaths = [
550947
550974
  join83(homedir22(), ".omnius", "venv", "bin", "python3"),
@@ -555719,7 +555746,7 @@ var init_visual_trigger = __esm({
555719
555746
 
555720
555747
  // packages/execution/dist/tools/live-media-loop.js
555721
555748
  import { existsSync as existsSync78, mkdirSync as mkdirSync47, readFileSync as readFileSync57, rmSync as rmSync10, writeFileSync as writeFileSync39 } from "node:fs";
555722
- import { homedir as homedir28, tmpdir as tmpdir19 } from "node:os";
555749
+ import { homedir as homedir28, tmpdir as tmpdir20 } from "node:os";
555723
555750
  import { basename as basename19, isAbsolute as isAbsolute8, join as join92, resolve as resolve46 } from "node:path";
555724
555751
  function buildYolo26BootstrapPlan(model = DEFAULT_YOLO26_MODEL) {
555725
555752
  return {
@@ -556038,8 +556065,8 @@ async function ensureRuntime(autoBootstrap) {
556038
556065
  }
556039
556066
  }
556040
556067
  async function exportYolo26Model(python, model, options2, yoloeClasses = []) {
556041
- const cfgPath = join92(tmpdir19(), `omnius-yolo26-export-${Date.now()}.json`);
556042
- const scriptPath2 = join92(tmpdir19(), `omnius-yolo26-export-${Date.now()}.py`);
556068
+ const cfgPath = join92(tmpdir20(), `omnius-yolo26-export-${Date.now()}.json`);
556069
+ const scriptPath2 = join92(tmpdir20(), `omnius-yolo26-export-${Date.now()}.py`);
556043
556070
  writeFileSync39(cfgPath, JSON.stringify({ model, options: options2, yoloeClasses }, null, 2), "utf8");
556044
556071
  writeFileSync39(scriptPath2, String.raw`
556045
556072
  import json, sys
@@ -556615,8 +556642,8 @@ var init_live_media_loop = __esm({
556615
556642
  return { success: false, output: "", error: runtime.error, durationMs: performance.now() - start2 };
556616
556643
  const outDir = join92(this.workingDir, ".omnius", "live-media", `run-${Date.now().toString(36)}`);
556617
556644
  mkdirSync47(outDir, { recursive: true });
556618
- const cfgPath = join92(tmpdir19(), `omnius-live-media-${Date.now()}.json`);
556619
- const scriptPath2 = join92(tmpdir19(), `omnius-live-media-${Date.now()}.py`);
556645
+ const cfgPath = join92(tmpdir20(), `omnius-live-media-${Date.now()}.json`);
556646
+ const scriptPath2 = join92(tmpdir20(), `omnius-live-media-${Date.now()}.py`);
556620
556647
  writeFileSync39(cfgPath, JSON.stringify({
556621
556648
  source_kind: sourceKind(args),
556622
556649
  source: src2,
@@ -593747,9 +593774,9 @@ ${result}`
593747
593774
  try {
593748
593775
  const { writeFileSync: writeFileSync95, readFileSync: readFileSync137, unlinkSync: unlinkSync37 } = await import("node:fs");
593749
593776
  const { join: join186 } = await import("node:path");
593750
- const { tmpdir: tmpdir25 } = await import("node:os");
593751
- const tmpIn = join186(tmpdir25(), `omnius_img_in_${Date.now()}.png`);
593752
- const tmpOut = join186(tmpdir25(), `omnius_img_out_${Date.now()}.jpg`);
593777
+ const { tmpdir: tmpdir26 } = await import("node:os");
593778
+ const tmpIn = join186(tmpdir26(), `omnius_img_in_${Date.now()}.png`);
593779
+ const tmpOut = join186(tmpdir26(), `omnius_img_out_${Date.now()}.jpg`);
593753
593780
  writeFileSync95(tmpIn, buffer2);
593754
593781
  const pyBin = process.platform === "win32" ? "python" : "python3";
593755
593782
  const resizeScript = [
@@ -595284,7 +595311,7 @@ var init_constraint_learner = __esm({
595284
595311
  import { existsSync as existsSync102, statSync as statSync39, openSync, readSync, closeSync, unlinkSync as unlinkSync18, writeFileSync as writeFileSync49 } from "node:fs";
595285
595312
  import { watch as fsWatch } from "node:fs";
595286
595313
  import { join as join113 } from "node:path";
595287
- import { tmpdir as tmpdir20 } from "node:os";
595314
+ import { tmpdir as tmpdir21 } from "node:os";
595288
595315
  import { randomBytes as randomBytes21 } from "node:crypto";
595289
595316
  var NexusAgenticBackend;
595290
595317
  var init_nexusBackend = __esm({
@@ -595486,7 +595513,7 @@ ${suffix}` } : m2);
595486
595513
  * Falls back to unary + word-split if streaming setup fails.
595487
595514
  */
595488
595515
  async *chatCompletionStream(request) {
595489
- const streamFile = join113(tmpdir20(), `nexus-stream-${randomBytes21(6).toString("hex")}.jsonl`);
595516
+ const streamFile = join113(tmpdir21(), `nexus-stream-${randomBytes21(6).toString("hex")}.jsonl`);
595490
595517
  writeFileSync49(streamFile, "", "utf8");
595491
595518
  const effectiveThink = this.effectiveThink(request);
595492
595519
  const daemonArgs = {
@@ -603069,7 +603096,7 @@ function liveDashboardPreviewWidthForSources(sourceCount, termWidth = process.st
603069
603096
  function formatCameraPane(camera, paneWidth, paneHeight, now2) {
603070
603097
  const contentWidth = Math.max(10, paneWidth - 2);
603071
603098
  const age = Math.max(0, Math.round((now2 - camera.updatedAt) / 1e3));
603072
- const title = `${compactSourceId(camera.source)} ${age}s${cameraPaneBadge(camera)}`;
603099
+ const title = `↺ ${compactSourceId(camera.source)} ${age}s${cameraPaneBadge(camera)} ↻`;
603073
603100
  const topTitle = ` ${title} `;
603074
603101
  const left = Math.max(0, Math.floor((contentWidth - topTitle.length) / 2));
603075
603102
  const right = Math.max(0, contentWidth - topTitle.length - left);
@@ -603080,6 +603107,30 @@ function formatCameraPane(camera, paneWidth, paneHeight, now2) {
603080
603107
  const body = fitDashboardPane(previewLines, contentWidth, paneHeight, fallback);
603081
603108
  return [top, ...body.map((line) => `│${truncateAnsiCell(line, contentWidth)}│`), bottom];
603082
603109
  }
603110
+ function liveDashboardRotationActionFromClick(snapshot, lineText, col) {
603111
+ const plain = stripDashboardAnsi(lineText);
603112
+ const idx = Math.max(0, col - 1);
603113
+ const clicked = plain[idx];
603114
+ if (clicked !== "↺" && clicked !== "↻") return null;
603115
+ const direction = clicked === "↺" ? "ccw" : "cw";
603116
+ const cameras = Object.values(snapshot.cameras ?? (snapshot.video ? { [snapshot.video.source]: snapshot.video } : {}));
603117
+ if (cameras.length === 0) return null;
603118
+ const leftPositions = [];
603119
+ for (let i2 = 0; i2 < plain.length; i2++) {
603120
+ if (plain[i2] === "↺") leftPositions.push(i2);
603121
+ }
603122
+ for (let i2 = 0; i2 < leftPositions.length; i2++) {
603123
+ const left = leftPositions[i2];
603124
+ const nextLeft = leftPositions[i2 + 1] ?? plain.length;
603125
+ const right = plain.indexOf("↻", left + 1);
603126
+ if (right < 0 || right >= nextLeft) continue;
603127
+ if (idx !== left && idx !== right) continue;
603128
+ const segment = plain.slice(left, right + 1);
603129
+ const camera = cameras.find((entry) => segment.includes(compactSourceId(entry.source)));
603130
+ if (camera) return { source: camera.source, direction };
603131
+ }
603132
+ return null;
603133
+ }
603083
603134
  function pushDashboardWrapped(lines, value2, width) {
603084
603135
  const contentWidth = Math.max(10, width - 2);
603085
603136
  const words = stripDashboardAnsi(value2).replace(/\s+/g, " ").trim().split(" ").filter(Boolean);
@@ -604346,12 +604397,15 @@ var init_live_sensors = __esm({
604346
604397
  autoOrientationInFlight = /* @__PURE__ */ new Set();
604347
604398
  lastFeedbackAt = /* @__PURE__ */ new Map();
604348
604399
  lastClipAt = /* @__PURE__ */ new Map();
604400
+ lastInferenceAt = /* @__PURE__ */ new Map();
604349
604401
  nextVideoSourceIndex = 0;
604350
604402
  liveSpeechSink = null;
604351
604403
  liveSpeechEnabled = false;
604352
604404
  lastLiveSpeechAt = 0;
604353
604405
  lastLiveSpeechByKey = /* @__PURE__ */ new Map();
604354
604406
  liveSpeechInFlight = /* @__PURE__ */ new Set();
604407
+ liveSpeechMutedUntil = 0;
604408
+ liveTtsSpeaking = null;
604355
604409
  intakeAgentConfig;
604356
604410
  setStatusSink(sink) {
604357
604411
  this.statusSink = sink ?? null;
@@ -604369,6 +604423,15 @@ var init_live_sensors = __esm({
604369
604423
  setLiveSpeechEnabled(enabled2) {
604370
604424
  this.liveSpeechEnabled = enabled2;
604371
604425
  }
604426
+ setLiveTtsSpeakingSource(source) {
604427
+ this.liveTtsSpeaking = source ?? null;
604428
+ }
604429
+ muteLiveAudioFor(ms) {
604430
+ this.liveSpeechMutedUntil = Math.max(this.liveSpeechMutedUntil, Date.now() + Math.max(0, ms));
604431
+ }
604432
+ isLiveAudioMutedForTts() {
604433
+ return Date.now() < this.liveSpeechMutedUntil || Boolean(this.liveTtsSpeaking?.());
604434
+ }
604372
604435
  setAudioIntakeAgentConfig(config) {
604373
604436
  this.intakeAgentConfig = config && config.backendUrl && config.model ? { backendUrl: config.backendUrl, model: config.model, apiKey: config.apiKey } : void 0;
604374
604437
  }
@@ -604439,6 +604502,12 @@ var init_live_sensors = __esm({
604439
604502
  const next = current === 0 ? 90 : current === 90 ? 180 : current === 180 ? 270 : 0;
604440
604503
  return this.setCameraRotation(device, next, "manual", "manual cycle from /live menu");
604441
604504
  }
604505
+ rotateCameraRelative(device, direction) {
604506
+ const current = this.getCameraRotation(device);
604507
+ const delta = direction === "cw" ? 90 : 270;
604508
+ const next = (current + delta) % 360;
604509
+ return this.setCameraRotation(device, next, "manual", `manual ${direction === "cw" ? "clockwise" : "counter-clockwise"} dashboard override`);
604510
+ }
604442
604511
  async autoOrientCamera(device = this.config.selectedCamera, options2 = {}) {
604443
604512
  const target = device || this.config.selectedCamera || firstDeviceId(this.devices.video);
604444
604513
  if (!target) return "No camera selected. Use /live camera <device> or select a camera in /live.";
@@ -604594,7 +604663,7 @@ var init_live_sensors = __esm({
604594
604663
  }, 6e4);
604595
604664
  });
604596
604665
  }
604597
- void this.sampleVideoNow(true, { mode: "all" }).catch((err) => {
604666
+ void this.sampleVideoNow(true, { mode: "all", forceInferenceNow: true }).catch((err) => {
604598
604667
  this.emitFeedback({
604599
604668
  kind: "error",
604600
604669
  title: "Live video sample failed",
@@ -604781,13 +604850,17 @@ var init_live_sensors = __esm({
604781
604850
  return message2;
604782
604851
  }
604783
604852
  }
604784
- async sampleSingleVideoNow(source, forceInfer, previewWidth) {
604853
+ async sampleSingleVideoNow(source, forceInfer, previewWidth, options2 = {}) {
604785
604854
  const preview = await this.previewCamera(source, { emit: false, previewWidth });
604786
604855
  let inference = "";
604787
604856
  let clipSummary = "";
604788
604857
  const orientation = this.getCameraOrientation(source);
604789
604858
  const sampledAt = Date.now();
604790
- if (forceInfer && source) {
604859
+ const inferenceThrottleMs = Math.max(0, Number(options2.inferThrottleMs ?? 2500));
604860
+ const lastInferenceAt = this.lastInferenceAt.get(source) ?? 0;
604861
+ const shouldInfer = Boolean(forceInfer && source && (options2.forceInferenceNow || sampledAt - lastInferenceAt >= inferenceThrottleMs));
604862
+ if (shouldInfer) {
604863
+ this.lastInferenceAt.set(source, sampledAt);
604791
604864
  const loop = new LiveMediaLoopTool(this.repoRoot);
604792
604865
  const inferFromCapturedFrame = preview.ok && Boolean(preview.framePath);
604793
604866
  const result = await loop.execute({
@@ -604900,6 +604973,15 @@ ${inference}` : "", clipSummary ? `
604900
604973
  CLIP visual memory:
604901
604974
  ${clipSummary}` : ""].filter(Boolean).join("\n");
604902
604975
  }
604976
+ async sampleCameraNow(source, forceInfer = this.config.inferEnabled || this.config.clipEnabled, options2 = {}) {
604977
+ const previewWidth = liveDashboardPreviewWidthForSources(this.activeVideoSources().length);
604978
+ const result = await this.sampleSingleVideoNow(source, forceInfer, previewWidth, {
604979
+ forceInferenceNow: options2.forceInferenceNow,
604980
+ inferThrottleMs: options2.forceInferenceNow ? 0 : 2500
604981
+ });
604982
+ this.emitDashboard();
604983
+ return result;
604984
+ }
604903
604985
  async sampleVideoNow(forceInfer = this.config.inferEnabled, options2 = {}) {
604904
604986
  if (this.videoInFlight) return "Video sampler is already running.";
604905
604987
  this.videoInFlight = true;
@@ -604911,7 +604993,7 @@ ${clipSummary}` : ""].filter(Boolean).join("\n");
604911
604993
  const outputs = [];
604912
604994
  const previewWidth = liveDashboardPreviewWidthForSources(allSources.length);
604913
604995
  for (const source of sources) {
604914
- outputs.push(await this.sampleSingleVideoNow(source, forceInfer, previewWidth));
604996
+ outputs.push(await this.sampleSingleVideoNow(source, forceInfer, previewWidth, options2));
604915
604997
  }
604916
604998
  this.emitDashboard();
604917
604999
  return outputs.map((output, index) => `## Camera ${sources[index]}
@@ -604927,6 +605009,20 @@ ${output}`).join("\n\n");
604927
605009
  const preferredInput = preferredLiveAudioInputId(this.devices.audioInputs, this.config.selectedAudioInput) || "default";
604928
605010
  const input = this.config.selectedAudioInput && !isAudioOutputMonitorId(this.config.selectedAudioInput) ? this.config.selectedAudioInput : preferredInput;
604929
605011
  if (input !== this.config.selectedAudioInput) this.config.selectedAudioInput = input;
605012
+ if (this.isLiveAudioMutedForTts()) {
605013
+ const now2 = Date.now();
605014
+ this.snapshot.audio = {
605015
+ updatedAt: now2,
605016
+ input,
605017
+ output: this.config.selectedAudioOutput,
605018
+ transcript: "",
605019
+ analysis: "",
605020
+ error: "Live audio capture muted during Omnius TTS playback to prevent echo."
605021
+ };
605022
+ this.persist();
605023
+ this.emitDashboard();
605024
+ return "Live audio capture muted during Omnius TTS playback to prevent echo.";
605025
+ }
604930
605026
  const outputDir2 = liveDir(this.repoRoot);
604931
605027
  ensureLiveDir(this.repoRoot);
604932
605028
  const recordingPath = join124(outputDir2, `audio-${Date.now()}.wav`);
@@ -604963,7 +605059,11 @@ ${output}`).join("\n\n");
604963
605059
  }
604964
605060
  if (this.config.asrEnabled) {
604965
605061
  try {
604966
- const asr = await new TranscribeFileTool(this.repoRoot).execute({ path: recordingPath, model: "tiny" });
605062
+ const asr = await new TranscribeFileTool(this.repoRoot).execute({
605063
+ path: recordingPath,
605064
+ model: "tiny",
605065
+ backend: "managed-whisper"
605066
+ });
604967
605067
  if (asr.success) {
604968
605068
  transcript = cleanPreview(typeof asr.llmContent === "string" ? asr.llmContent : "", 1600);
604969
605069
  asrBackend = extractAsrBackend(asr.output) ?? "whisper";
@@ -606316,7 +606416,7 @@ var init_listen = __esm({
606316
606416
  let caughtUncaught = null;
606317
606417
  const uncaughtHandler = (err) => {
606318
606418
  const msg = err?.message || String(err);
606319
- if (msg.includes("live_worker") || msg.includes("numpy") || msg.includes("Traceback")) {
606419
+ if (msg.includes("live_worker") || msg.includes("numpy") || msg.includes("transcribe_cli") || msg.includes("ModuleNotFoundError") || msg.includes("Traceback")) {
606320
606420
  caughtUncaught = err;
606321
606421
  } else {
606322
606422
  throw err;
@@ -625268,6 +625368,7 @@ var init_status_bar = __esm({
625268
625368
  * repaint, including selection updates and scroll events.
625269
625369
  */
625270
625370
  _dynamicBlocks = /* @__PURE__ */ new Map();
625371
+ _dynamicBlockClickHandlers = /* @__PURE__ */ new Map();
625271
625372
  /** Sentinel marker — used both for scrollback storage and reflow detection. */
625272
625373
  DYNAMIC_BLOCK_MARK_PREFIX = "DYNBLOCK:";
625273
625374
  DYNAMIC_BLOCK_MARK_SUFFIX = "";
@@ -625414,9 +625515,13 @@ var init_status_bar = __esm({
625414
625515
  this.invalidateRowCountCache();
625415
625516
  return `${this.DYNAMIC_BLOCK_MARK_PREFIX}${id2}${this.DYNAMIC_BLOCK_MARK_SUFFIX}`;
625416
625517
  }
625518
+ registerDynamicBlockClickHandler(id2, handler) {
625519
+ this._dynamicBlockClickHandlers.set(id2, handler);
625520
+ }
625417
625521
  /** Unregister a dynamic block. Existing sentinels in scrollback become inert (rendered as empty). */
625418
625522
  unregisterDynamicBlock(id2) {
625419
625523
  this._dynamicBlocks.delete(id2);
625524
+ this._dynamicBlockClickHandlers.delete(id2);
625420
625525
  this._dynamicBlockVersion++;
625421
625526
  this.invalidateRowCountCache();
625422
625527
  }
@@ -627119,9 +627224,23 @@ var init_status_bar = __esm({
627119
627224
  * other body rows are left alone so text selection still works. Returns true
627120
627225
  * when the click was consumed.
627121
627226
  */
627122
- handleContentBlockClick(screenRow) {
627227
+ handleContentBlockClick(screenRow, col) {
627123
627228
  const hit = this.hitTestContentBlock(screenRow);
627124
- if (!hit || !isCollapsibleBlock(hit.id)) return false;
627229
+ if (!hit) return false;
627230
+ const handler = this._dynamicBlockClickHandlers.get(hit.id);
627231
+ if (handler?.({
627232
+ id: hit.id,
627233
+ offset: hit.offset,
627234
+ col,
627235
+ row: screenRow,
627236
+ lineText: hit.lineText
627237
+ })) {
627238
+ if (this.active && !isOverlayActive() && !this._suspendContentLayer) {
627239
+ this.repaintContent();
627240
+ }
627241
+ return true;
627242
+ }
627243
+ if (!isCollapsibleBlock(hit.id)) return false;
627125
627244
  const plain = stripAnsi(hit.lineText);
627126
627245
  if (plain.includes(READ_MORE_LABEL) || plain.includes(READ_LESS_LABEL)) {
627127
627246
  toggleMore(hit.id);
@@ -627145,7 +627264,7 @@ var init_status_bar = __esm({
627145
627264
  if (!this.active) return;
627146
627265
  const w = termCols();
627147
627266
  if (type === "press" && row >= this.scrollRegionTop) {
627148
- if (this.handleContentBlockClick(row)) return;
627267
+ if (this.handleContentBlockClick(row, col)) return;
627149
627268
  }
627150
627269
  if (type === "press" && this._suggestions.length > 0) {
627151
627270
  if (this.suggestClickAt(row)) return;
@@ -638356,7 +638475,7 @@ var init_audio_waveform = __esm({
638356
638475
 
638357
638476
  // packages/cli/src/tui/neovim-mode.ts
638358
638477
  import { existsSync as existsSync129, unlinkSync as unlinkSync24 } from "node:fs";
638359
- import { tmpdir as tmpdir21 } from "node:os";
638478
+ import { tmpdir as tmpdir22 } from "node:os";
638360
638479
  import { join as join143 } from "node:path";
638361
638480
  function isNeovimActive() {
638362
638481
  return _state2 !== null && !_state2.cleanedUp;
@@ -638402,7 +638521,7 @@ async function startNeovimMode(opts) {
638402
638521
  );
638403
638522
  } catch {
638404
638523
  }
638405
- const socketPath = join143(tmpdir21(), `omnius-nvim-${process.pid}-${Date.now()}.sock`);
638524
+ const socketPath = join143(tmpdir22(), `omnius-nvim-${process.pid}-${Date.now()}.sock`);
638406
638525
  try {
638407
638526
  if (existsSync129(socketPath)) unlinkSync24(socketPath);
638408
638527
  } catch {
@@ -641943,7 +642062,7 @@ import {
641943
642062
  rmSync as rmSync11
641944
642063
  } from "node:fs";
641945
642064
  import { join as join150, dirname as dirname45, resolve as resolve61 } from "node:path";
641946
- import { homedir as homedir50, tmpdir as tmpdir22, platform as platform6 } from "node:os";
642065
+ import { homedir as homedir50, tmpdir as tmpdir23, platform as platform6 } from "node:os";
641947
642066
  import {
641948
642067
  spawn as nodeSpawn
641949
642068
  } from "node:child_process";
@@ -643639,6 +643758,9 @@ except Exception as exc:
643639
643758
  await this.sleep(100);
643640
643759
  }
643641
643760
  }
643761
+ isSpeaking() {
643762
+ return this.speaking || this.speakQueue.length > 0 || Boolean(this.currentPlayback);
643763
+ }
643642
643764
  enqueueSpeech(text2, volume, pitchFactor, speedFactor = 1, stereoDelayMs = 0.6, emotion) {
643643
643765
  if (!this.enabled || !this.ready) return;
643644
643766
  text2 = sanitizeForTTS(text2);
@@ -644036,7 +644158,7 @@ except Exception as exc:
644036
644158
  }
644037
644159
  this.onPCMOutput(Buffer.from(int16.buffer), sampleRate);
644038
644160
  }
644039
- const wavPath = join150(tmpdir22(), `omnius-voice-${Date.now()}.wav`);
644161
+ const wavPath = join150(tmpdir23(), `omnius-voice-${Date.now()}.wav`);
644040
644162
  this.writeStereoWav(stereo.left, stereo.right, sampleRate, wavPath);
644041
644163
  await this.playWav(wavPath);
644042
644164
  try {
@@ -644549,7 +644671,7 @@ except Exception as exc:
644549
644671
  const cleaned = injectExpressionTags ? applySupertonicExpressionTags(baseText, settings.expression, emotion) : baseText;
644550
644672
  if (!cleaned) return null;
644551
644673
  const wavPath = join150(
644552
- tmpdir22(),
644674
+ tmpdir23(),
644553
644675
  `omnius-supertonic3-${Date.now()}-${Math.random().toString(36).slice(2, 6)}.wav`
644554
644676
  );
644555
644677
  try {
@@ -644620,7 +644742,7 @@ except Exception as exc:
644620
644742
  return new Promise((resolve76, reject) => {
644621
644743
  const proc = nodeSpawn("sh", ["-c", command], {
644622
644744
  stdio: ["ignore", "pipe", "pipe"],
644623
- cwd: tmpdir22(),
644745
+ cwd: tmpdir23(),
644624
644746
  env: voicePythonEnv()
644625
644747
  });
644626
644748
  let stdout = "";
@@ -644707,7 +644829,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`
644707
644829
  const mlxModelId = model.mlxModelId ?? "mlx-community/Kokoro-82M-bf16";
644708
644830
  const mlxVoice = model.mlxVoice ?? "af_heart";
644709
644831
  const mlxLangCode = model.mlxLangCode ?? "a";
644710
- const wavPath = join150(tmpdir22(), `omnius-mlx-${Date.now()}.wav`);
644832
+ const wavPath = join150(tmpdir23(), `omnius-mlx-${Date.now()}.wav`);
644711
644833
  const pyScript = [
644712
644834
  "import sys, json",
644713
644835
  "from mlx_audio.tts import generate as tts_gen",
@@ -644788,7 +644910,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`
644788
644910
  const mlxModelId = model.mlxModelId ?? "mlx-community/Kokoro-82M-bf16";
644789
644911
  const mlxVoice = model.mlxVoice ?? "af_heart";
644790
644912
  const mlxLangCode = model.mlxLangCode ?? "a";
644791
- const wavPath = join150(tmpdir22(), `omnius-mlx-buf-${Date.now()}.wav`);
644913
+ const wavPath = join150(tmpdir23(), `omnius-mlx-buf-${Date.now()}.wav`);
644792
644914
  const pyScript = [
644793
644915
  "import sys, json",
644794
644916
  "from mlx_audio.tts import generate as tts_gen",
@@ -645564,7 +645686,7 @@ if __name__ == '__main__':
645564
645686
  const env2 = voicePythonEnv({ LUXTTS_REPO_PATH: luxttsRepoDir2() });
645565
645687
  const daemon = nodeSpawn(venvPy, [luxttsInferScript2()], {
645566
645688
  stdio: ["pipe", "pipe", "pipe"],
645567
- cwd: tmpdir22(),
645689
+ cwd: tmpdir23(),
645568
645690
  env: env2
645569
645691
  });
645570
645692
  this._luxttsDaemon = daemon;
@@ -645654,7 +645776,7 @@ if __name__ == '__main__':
645654
645776
  const ready = await this.ensureLuxttsDaemon();
645655
645777
  if (!ready) return null;
645656
645778
  const wavPath = join150(
645657
- tmpdir22(),
645779
+ tmpdir23(),
645658
645780
  `omnius-luxtts-${Date.now()}-${Math.random().toString(36).slice(2, 6)}.wav`
645659
645781
  );
645660
645782
  try {
@@ -645795,7 +645917,7 @@ if __name__ == '__main__':
645795
645917
  if (!cleaned) return null;
645796
645918
  const ready = await this.ensureLuxttsDaemon();
645797
645919
  if (!ready) return null;
645798
- const wavPath = join150(tmpdir22(), `omnius-luxtts-buf-${Date.now()}.wav`);
645920
+ const wavPath = join150(tmpdir23(), `omnius-luxtts-buf-${Date.now()}.wav`);
645799
645921
  try {
645800
645922
  await this.luxttsRequest({
645801
645923
  action: "synthesize",
@@ -645929,7 +646051,7 @@ if __name__ == "__main__":
645929
646051
  });
645930
646052
  const daemon = nodeSpawn(venvPy, [misottsInferScript2()], {
645931
646053
  stdio: ["pipe", "pipe", "pipe"],
645932
- cwd: tmpdir22(),
646054
+ cwd: tmpdir23(),
645933
646055
  env: env2
645934
646056
  });
645935
646057
  this._misottsDaemon = daemon;
@@ -646013,7 +646135,7 @@ if __name__ == "__main__":
646013
646135
  const ready = await this.ensureMisottsDaemon();
646014
646136
  if (!ready) return null;
646015
646137
  const wavPath = join150(
646016
- tmpdir22(),
646138
+ tmpdir23(),
646017
646139
  `omnius-misotts-${Date.now()}-${Math.random().toString(36).slice(2, 6)}.wav`
646018
646140
  );
646019
646141
  try {
@@ -646163,7 +646285,7 @@ if __name__ == "__main__":
646163
646285
  if (!cleaned) return null;
646164
646286
  const ready = await this.ensureMisottsDaemon();
646165
646287
  if (!ready) return null;
646166
- const wavPath = join150(tmpdir22(), `omnius-misotts-buf-${Date.now()}.wav`);
646288
+ const wavPath = join150(tmpdir23(), `omnius-misotts-buf-${Date.now()}.wav`);
646167
646289
  try {
646168
646290
  const settings = this.getMisottsSettings();
646169
646291
  const cloneName = this.misottsCloneRef.split("/").pop() ?? "";
@@ -656904,6 +657026,15 @@ function renderLiveDashboard(ctx3, manager) {
656904
657026
  id2,
656905
657027
  (width) => formatLiveDashboardFromSnapshot(manager.getSnapshot(), { width })
656906
657028
  );
657029
+ host.registerDynamicBlockClickHandler?.(id2, ({ col, lineText }) => {
657030
+ const action = liveDashboardRotationActionFromClick(manager.getSnapshot(), lineText, col);
657031
+ if (!action) return false;
657032
+ manager.rotateCameraRelative(action.source, action.direction);
657033
+ void manager.sampleCameraNow(action.source, true, { forceInferenceNow: true }).catch((err) => {
657034
+ renderWarning(`Camera refresh failed after manual rotation: ${err instanceof Error ? err.message : String(err)}`);
657035
+ });
657036
+ return true;
657037
+ });
656907
657038
  host.appendDynamicBlock(id2);
656908
657039
  return;
656909
657040
  }
@@ -656934,7 +657065,7 @@ ${feedback.message}`);
656934
657065
  renderInfo(`[live ${stamp}] ${feedback.title}
656935
657066
  ${feedback.message}`);
656936
657067
  }
656937
- function attachLiveSinks(ctx3, manager, agentEnabled = false) {
657068
+ function attachLiveSinks(ctx3, manager, agentEnabled = false, speechEnabledOverride) {
656938
657069
  manager.setStatusSink(ctx3.setLiveMediaStatus);
656939
657070
  manager.setFeedbackSink((feedback) => renderLiveFeedback(ctx3, manager, feedback));
656940
657071
  manager.setAudioIntakeAgentConfig({
@@ -656942,10 +657073,13 @@ function attachLiveSinks(ctx3, manager, agentEnabled = false) {
656942
657073
  model: ctx3.config.model,
656943
657074
  apiKey: ctx3.config.apiKey
656944
657075
  });
656945
- const speechEnabled = agentEnabled && Boolean(ctx3.voiceSpeak);
657076
+ const speechEnabled = Boolean(speechEnabledOverride ?? agentEnabled) && Boolean(ctx3.voiceSpeak);
656946
657077
  manager.setLiveSpeechEnabled(speechEnabled);
657078
+ manager.setLiveTtsSpeakingSource(ctx3.voiceIsSpeaking);
656947
657079
  manager.setLiveSpeechSink(speechEnabled ? (text2) => {
656948
657080
  if (ctx3.voiceIsEnabled && !ctx3.voiceIsEnabled()) return;
657081
+ const estimatedSpeechMs = Math.max(1500, Math.min(15e3, text2.length * 85));
657082
+ manager.muteLiveAudioFor(estimatedSpeechMs + 1e3);
656949
657083
  ctx3.voiceSpeak?.(text2);
656950
657084
  } : void 0);
656951
657085
  if (agentEnabled && ctx3.startBackgroundPrompt) {
@@ -656958,17 +657092,17 @@ function attachLiveSinks(ctx3, manager, agentEnabled = false) {
656958
657092
  }
656959
657093
  }
656960
657094
  async function startLiveVoicechat(ctx3, manager) {
656961
- const agentEnabled = Boolean(ctx3.startBackgroundPrompt);
656962
- attachLiveSinks(ctx3, manager, agentEnabled);
657095
+ const speechEnabled = Boolean(ctx3.voiceSpeak);
657096
+ attachLiveSinks(ctx3, manager, false, speechEnabled);
656963
657097
  await ensureLiveInventory(manager);
656964
657098
  if (!ctx3.voiceChatStart) {
656965
- renderInfo(manager.startRunMode({ agent: agentEnabled, lowLatency: true, speech: false }));
657099
+ renderInfo(manager.startRunMode({ agent: false, lowLatency: true, speech: false }));
656966
657100
  renderWarning("Voice chat is not available in this context; live audio/video feedback remains active.");
656967
657101
  return;
656968
657102
  }
656969
657103
  ctx3.voiceSetMode?.("voicechat");
656970
657104
  if (ctx3.isVoiceChatActive?.()) {
656971
- renderInfo(manager.startRunMode({ agent: agentEnabled, lowLatency: true, speech: Boolean(ctx3.voiceSpeak) }));
657105
+ renderInfo(manager.startRunMode({ agent: false, lowLatency: true, speech: speechEnabled }));
656972
657106
  renderInfo("Voice chat is already active. Live audio/video feedback remains attached.");
656973
657107
  return;
656974
657108
  }
@@ -656979,7 +657113,7 @@ async function startLiveVoicechat(ctx3, manager) {
656979
657113
  try {
656980
657114
  renderInfo("Starting live voicechat with audio/video context...");
656981
657115
  await ctx3.voiceChatStart();
656982
- renderInfo(manager.startRunMode({ agent: agentEnabled, lowLatency: true, speech: Boolean(ctx3.voiceSpeak) }));
657116
+ renderInfo(manager.startRunMode({ agent: false, lowLatency: true, speech: speechEnabled }));
656983
657117
  renderInfo("Live voicechat active: low-latency audio/video context is updating while voice conversation continues.");
656984
657118
  } catch (err) {
656985
657119
  renderError(`Live voicechat failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -695342,15 +695476,15 @@ Content-Type: ${mimeForPath(pathOrFileId, field === "photo" ? "image" : "video")
695342
695476
  let filename = "response.wav";
695343
695477
  let mimeType = "audio/wav";
695344
695478
  try {
695345
- const { tmpdir: tmpdir25 } = await import("node:os");
695479
+ const { tmpdir: tmpdir26 } = await import("node:os");
695346
695480
  const { join: joinPath } = await import("node:path");
695347
695481
  const {
695348
695482
  writeFileSync: writeFs,
695349
695483
  readFileSync: readFs,
695350
695484
  unlinkSync: unlinkFs
695351
695485
  } = await import("node:fs");
695352
- const tmpWav = joinPath(tmpdir25(), `omnius-tg-voice-${Date.now()}.wav`);
695353
- const tmpOgg = joinPath(tmpdir25(), `omnius-tg-voice-${Date.now()}.ogg`);
695486
+ const tmpWav = joinPath(tmpdir26(), `omnius-tg-voice-${Date.now()}.wav`);
695487
+ const tmpOgg = joinPath(tmpdir26(), `omnius-tg-voice-${Date.now()}.ogg`);
695354
695488
  writeFs(tmpWav, wavBuffer);
695355
695489
  await execFileText4(
695356
695490
  "ffmpeg",
@@ -700370,7 +700504,7 @@ __export(graphical_sudo_exports, {
700370
700504
  import { spawn as spawn35 } from "node:child_process";
700371
700505
  import { existsSync as existsSync161, mkdirSync as mkdirSync102, writeFileSync as writeFileSync87, chmodSync as chmodSync6 } from "node:fs";
700372
700506
  import { join as join174 } from "node:path";
700373
- import { tmpdir as tmpdir23 } from "node:os";
700507
+ import { tmpdir as tmpdir24 } from "node:os";
700374
700508
  function detectSudoHelper() {
700375
700509
  if (process.platform === "win32") return null;
700376
700510
  if (process.platform === "darwin") return "osascript";
@@ -700391,7 +700525,7 @@ function which2(cmd) {
700391
700525
  return null;
700392
700526
  }
700393
700527
  function ensureAskpassShim(helper, description) {
700394
- const shimDir = join174(tmpdir23(), "omnius-askpass");
700528
+ const shimDir = join174(tmpdir24(), "omnius-askpass");
700395
700529
  mkdirSync102(shimDir, { recursive: true });
700396
700530
  const shim = join174(shimDir, `${helper}.sh`);
700397
700531
  let body;
@@ -722734,11 +722868,11 @@ async function handleRequest(req3, res, ollamaUrl, verbose, runtimeDefaults = {}
722734
722868
  });
722735
722869
  return;
722736
722870
  }
722737
- const { tmpdir: tmpdir25 } = await import("node:os");
722871
+ const { tmpdir: tmpdir26 } = await import("node:os");
722738
722872
  const { writeFileSync: writeFileSync95, unlinkSync: unlinkSync37 } = await import("node:fs");
722739
722873
  const { join: pjoin } = await import("node:path");
722740
722874
  const tmpPath = pjoin(
722741
- tmpdir25(),
722875
+ tmpdir26(),
722742
722876
  `omnius-clone-upload-${Date.now()}-${safeName3}`
722743
722877
  );
722744
722878
  writeFileSync95(tmpPath, buf);
@@ -734213,6 +734347,9 @@ The user pasted a clipboard image saved at ${relPath}. Use the OCR, vision analy
734213
734347
  voiceIsEnabled() {
734214
734348
  return voiceEngine.enabled;
734215
734349
  },
734350
+ voiceIsSpeaking() {
734351
+ return voiceEngine.isSpeaking();
734352
+ },
734216
734353
  voiceGetModel() {
734217
734354
  return voiceEngine.modelId ?? "unknown";
734218
734355
  },
@@ -735092,6 +735229,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
735092
735229
  liveDynamicBlockHost: {
735093
735230
  registerDynamicBlock: (id2, render2) => statusBar.registerDynamicBlock(id2, render2),
735094
735231
  appendDynamicBlock: (id2) => statusBar.appendDynamicBlock(id2),
735232
+ registerDynamicBlockClickHandler: (id2, handler) => statusBar.registerDynamicBlockClickHandler(id2, handler),
735095
735233
  refreshDynamicBlocks: () => statusBar.refreshDynamicBlocks()
735096
735234
  },
735097
735235
  // Voice call session — standalone cloudflared tunnel for /call
@@ -738774,7 +738912,7 @@ __export(eval_exports, {
738774
738912
  evalCommand: () => evalCommand,
738775
738913
  expectedStatusesForEvalTask: () => expectedStatusesForEvalTask
738776
738914
  });
738777
- import { tmpdir as tmpdir24 } from "node:os";
738915
+ import { tmpdir as tmpdir25 } from "node:os";
738778
738916
  import { mkdirSync as mkdirSync110, writeFileSync as writeFileSync94 } from "node:fs";
738779
738917
  import { join as join184 } from "node:path";
738780
738918
  function expectedStatusesForEvalTask(task, live) {
@@ -738918,7 +739056,7 @@ async function evalCommand(opts, config) {
738918
739056
  process.exit(failed > 0 ? 1 : 0);
738919
739057
  }
738920
739058
  function createTempEvalRepo() {
738921
- const dir = join184(tmpdir24(), `omnius-eval-${Date.now()}`);
739059
+ const dir = join184(tmpdir25(), `omnius-eval-${Date.now()}`);
738922
739060
  mkdirSync110(dir, { recursive: true });
738923
739061
  mkdirSync110(join184(dir, "src"), { recursive: true });
738924
739062
  mkdirSync110(join184(dir, "tests"), { recursive: true });
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.412",
3
+ "version": "1.0.413",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.412",
9
+ "version": "1.0.413",
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.412",
3
+ "version": "1.0.413",
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",