omnius 1.0.430 → 1.0.432

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
@@ -1699,12 +1699,12 @@ var init_model_broker = __esm({
1699
1699
  // packages/execution/dist/broker-mediated-backend.js
1700
1700
  function wrapWithBroker(backend, options2) {
1701
1701
  const broker = getModelBroker();
1702
- const clamp10 = options2.clampNumCtx !== false;
1702
+ const clamp11 = options2.clampNumCtx !== false;
1703
1703
  const wrapped = Object.create(backend);
1704
1704
  wrapped.chatCompletion = async (request) => {
1705
1705
  const model = backend.model || request.model || "unknown";
1706
1706
  let effectiveRequest = request;
1707
- if (clamp10) {
1707
+ if (clamp11) {
1708
1708
  const trainCtx = await broker.getNctxTrain(model).catch(() => null);
1709
1709
  const requestedNumCtx = request.numCtx;
1710
1710
  if (trainCtx && trainCtx > 0) {
@@ -1738,7 +1738,7 @@ function wrapWithBroker(backend, options2) {
1738
1738
  wrapped.chatCompletionStream = async function* (request) {
1739
1739
  const model = backend.model || request.model || "unknown";
1740
1740
  let effectiveRequest = request;
1741
- if (clamp10) {
1741
+ if (clamp11) {
1742
1742
  const trainCtx = await broker.getNctxTrain(model).catch(() => null);
1743
1743
  const requestedNumCtx = request.numCtx;
1744
1744
  if (trainCtx && trainCtx > 0) {
@@ -37242,11 +37242,11 @@ function deleteCustomToolDefinition(name10, scope, repoRoot) {
37242
37242
  const dir = scope === "project" && repoRoot ? projectToolsDir(repoRoot) : globalToolsDir();
37243
37243
  const filePath = join35(dir, `${name10}.json`);
37244
37244
  if (existsSync33(filePath)) {
37245
- const { unlinkSync: unlinkSync37 } = __require("node:fs");
37246
- unlinkSync37(filePath);
37245
+ const { unlinkSync: unlinkSync38 } = __require("node:fs");
37246
+ unlinkSync38(filePath);
37247
37247
  const docsPath = toolDocsPath(name10, scope, repoRoot);
37248
37248
  if (existsSync33(docsPath))
37249
- unlinkSync37(docsPath);
37249
+ unlinkSync38(docsPath);
37250
37250
  if (scope === "project" && repoRoot)
37251
37251
  writeCustomToolRegistry(repoRoot);
37252
37252
  return true;
@@ -96067,13 +96067,13 @@ var require_singleton = __commonJS({
96067
96067
  Object.defineProperty(exports, "__esModule", { value: true });
96068
96068
  var injectable_1 = require_injectable();
96069
96069
  var dependency_container_1 = require_dependency_container();
96070
- function singleton() {
96070
+ function singleton2() {
96071
96071
  return function(target) {
96072
96072
  injectable_1.default()(target);
96073
96073
  dependency_container_1.instance.registerSingleton(target);
96074
96074
  };
96075
96075
  }
96076
- exports.default = singleton;
96076
+ exports.default = singleton2;
96077
96077
  }
96078
96078
  });
96079
96079
 
@@ -330392,7 +330392,7 @@ ${lanes.join("\n")}
330392
330392
  }
330393
330393
  return false;
330394
330394
  }
330395
- function createPropertyDescriptor(attributes, singleLine) {
330395
+ function createPropertyDescriptor(attributes, singleLine2) {
330396
330396
  const properties = [];
330397
330397
  tryAddPropertyAssignment(properties, "enumerable", asExpression(attributes.enumerable));
330398
330398
  tryAddPropertyAssignment(properties, "configurable", asExpression(attributes.configurable));
@@ -330401,7 +330401,7 @@ ${lanes.join("\n")}
330401
330401
  let isAccessor2 = tryAddPropertyAssignment(properties, "get", attributes.get);
330402
330402
  isAccessor2 = tryAddPropertyAssignment(properties, "set", attributes.set) || isAccessor2;
330403
330403
  Debug.assert(!(isData && isAccessor2), "A PropertyDescriptor may not be both an accessor descriptor and a data descriptor.");
330404
- return createObjectLiteralExpression(properties, !singleLine);
330404
+ return createObjectLiteralExpression(properties, !singleLine2);
330405
330405
  }
330406
330406
  function updateOuterExpression(outerExpression, expression) {
330407
330407
  switch (outerExpression.kind) {
@@ -343871,9 +343871,9 @@ ${lanes.join("\n")}
343871
343871
  }
343872
343872
  return;
343873
343873
  }
343874
- const singleLine = range.kind === 2 && singleLinePragmaRegEx.exec(text2);
343875
- if (singleLine) {
343876
- return addPragmaForMatch(pragmas, range, 2, singleLine);
343874
+ const singleLine2 = range.kind === 2 && singleLinePragmaRegEx.exec(text2);
343875
+ if (singleLine2) {
343876
+ return addPragmaForMatch(pragmas, range, 2, singleLine2);
343877
343877
  }
343878
343878
  if (range.kind === 3) {
343879
343879
  const multiLinePragmaRegEx = /@(\S+)(\s+(?:\S.*)?)?$/gm;
@@ -419394,7 +419394,7 @@ ${lanes.join("\n")}
419394
419394
  }
419395
419395
  function transformFunctionBody2(node) {
419396
419396
  let multiLine = false;
419397
- let singleLine = false;
419397
+ let singleLine2 = false;
419398
419398
  let statementsLocation;
419399
419399
  let closeBraceLocation;
419400
419400
  const prologue = [];
@@ -419436,7 +419436,7 @@ ${lanes.join("\n")}
419436
419436
  const equalsGreaterThanToken = node.equalsGreaterThanToken;
419437
419437
  if (!nodeIsSynthesized(equalsGreaterThanToken) && !nodeIsSynthesized(body)) {
419438
419438
  if (rangeEndIsOnSameLineAsRangeStart(equalsGreaterThanToken, body, currentSourceFile)) {
419439
- singleLine = true;
419439
+ singleLine2 = true;
419440
419440
  } else {
419441
419441
  multiLine = true;
419442
419442
  }
@@ -419465,7 +419465,7 @@ ${lanes.join("\n")}
419465
419465
  }
419466
419466
  const block = factory2.createBlock(setTextRange(factory2.createNodeArray(statements), statementsLocation), multiLine);
419467
419467
  setTextRange(block, node.body);
419468
- if (!multiLine && singleLine) {
419468
+ if (!multiLine && singleLine2) {
419469
419469
  setEmitFlags(
419470
419470
  block,
419471
419471
  1
@@ -554463,10 +554463,10 @@ function collectSnapshot(workingDir) {
554463
554463
  const freeRAM = freemem2();
554464
554464
  let load1 = 0, load5 = 0, load15 = 0;
554465
554465
  try {
554466
- const loadavg4 = __require("node:os").loadavg();
554467
- load1 = loadavg4[0];
554468
- load5 = loadavg4[1];
554469
- load15 = loadavg4[2];
554466
+ const loadavg5 = __require("node:os").loadavg();
554467
+ load1 = loadavg5[0];
554468
+ load5 = loadavg5[1];
554469
+ load15 = loadavg5[2];
554470
554470
  } catch {
554471
554471
  }
554472
554472
  let gpu = void 0;
@@ -564504,16 +564504,16 @@ function recommendMaxParallelFromVram(minFreeMB) {
564504
564504
  return 1;
564505
564505
  }
564506
564506
  async function getHardwareSnapshot() {
564507
- const { totalmem: totalmem10, freemem: freemem9, cpus: cpus6 } = await import("node:os");
564507
+ const { totalmem: totalmem11, freemem: freemem10, cpus: cpus7 } = await import("node:os");
564508
564508
  const gpus = await detectGpus();
564509
564509
  const diskPath = discoverSystemOllamaModelStore() ?? homedir33();
564510
564510
  const disk = snapshotDisk(diskPath);
564511
564511
  const network = snapshotNetwork();
564512
564512
  return {
564513
564513
  gpus,
564514
- cpuCores: cpus6().length,
564515
- ramTotalMB: Math.round(totalmem10() / (1024 * 1024)),
564516
- ramFreeMB: Math.round(freemem9() / (1024 * 1024)),
564514
+ cpuCores: cpus7().length,
564515
+ ramTotalMB: Math.round(totalmem11() / (1024 * 1024)),
564516
+ ramFreeMB: Math.round(freemem10() / (1024 * 1024)),
564517
564517
  disk,
564518
564518
  network,
564519
564519
  takenAtMs: Date.now()
@@ -578990,7 +578990,7 @@ ${context2 ?? ""}`;
578990
578990
  }
578991
578991
  }
578992
578992
  _applyTaskAffectFromResult(result, events) {
578993
- const clamp10 = (n2) => Math.max(0, Math.min(1, n2));
578993
+ const clamp11 = (n2) => Math.max(0, Math.min(1, n2));
578994
578994
  let uncertainty = this._taskAffectState.uncertainty * 0.94;
578995
578995
  let frustration = this._taskAffectState.frustration * 0.94;
578996
578996
  let confidence2 = this._taskAffectState.confidence * 0.94;
@@ -579023,11 +579023,11 @@ ${context2 ?? ""}`;
579023
579023
  }
579024
579024
  const level = frustration >= 0.72 || uncertainty >= 0.78 ? 4 : frustration >= 0.52 || uncertainty >= 0.58 ? 3 : frustration >= 0.32 || uncertainty >= 0.38 ? 2 : frustration >= 0.18 || uncertainty >= 0.22 ? 1 : 0;
579025
579025
  this._taskAffectState = {
579026
- uncertainty: clamp10(uncertainty),
579027
- frustration: clamp10(frustration),
579028
- confidence: clamp10(confidence2),
579029
- novelty: clamp10(novelty),
579030
- momentum: clamp10(momentum),
579026
+ uncertainty: clamp11(uncertainty),
579027
+ frustration: clamp11(frustration),
579028
+ confidence: clamp11(confidence2),
579029
+ novelty: clamp11(novelty),
579030
+ momentum: clamp11(momentum),
579031
579031
  adversaryLevel: level,
579032
579032
  lastUpdatedIso: (/* @__PURE__ */ new Date()).toISOString()
579033
579033
  };
@@ -593827,7 +593827,7 @@ ${result}`
593827
593827
  const buffer2 = Buffer.from(rawBase64, "base64");
593828
593828
  let resizedBase64 = null;
593829
593829
  try {
593830
- const { writeFileSync: writeFileSync95, readFileSync: readFileSync140, unlinkSync: unlinkSync37 } = await import("node:fs");
593830
+ const { writeFileSync: writeFileSync95, readFileSync: readFileSync140, unlinkSync: unlinkSync38 } = await import("node:fs");
593831
593831
  const { join: join188 } = await import("node:path");
593832
593832
  const { tmpdir: tmpdir26 } = await import("node:os");
593833
593833
  const tmpIn = join188(tmpdir26(), `omnius_img_in_${Date.now()}.png`);
@@ -593845,11 +593845,11 @@ ${result}`
593845
593845
  const resizedBuf = readFileSync140(tmpOut);
593846
593846
  resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
593847
593847
  try {
593848
- unlinkSync37(tmpIn);
593848
+ unlinkSync38(tmpIn);
593849
593849
  } catch {
593850
593850
  }
593851
593851
  try {
593852
- unlinkSync37(tmpOut);
593852
+ unlinkSync38(tmpOut);
593853
593853
  } catch {
593854
593854
  }
593855
593855
  } catch {
@@ -603393,6 +603393,10 @@ function defaultConsensusModel(primaryModel) {
603393
603393
  if (model === "large-v3" || model === "large") return "small";
603394
603394
  return "base";
603395
603395
  }
603396
+ function asrConsensusEnabled() {
603397
+ const consensusEnv = String(process.env["OMNIUS_ASR_CONSENSUS"] ?? "").trim().toLowerCase();
603398
+ return !(consensusEnv === "0" || consensusEnv === "off" || consensusEnv === "false");
603399
+ }
603396
603400
  async function ensureVenvForTranscribeCli() {
603397
603401
  const bin = process.platform === "win32" ? "Scripts" : "bin";
603398
603402
  const exe = process.platform === "win32" ? "python.exe" : "python3";
@@ -603895,8 +603899,19 @@ var init_listen = __esm({
603895
603899
  updateListenLiveState({ phase: "error", lastStatus: "no mic capture tool (arecord/sox/ffmpeg)" });
603896
603900
  return "No microphone capture tool found. Install arecord (Linux), sox (macOS), or ffmpeg.";
603897
603901
  }
603898
- let tc = await this.loadTranscribeCli();
603899
- if (!tc) {
603902
+ const preferWhisperFallback = asrConsensusEnabled();
603903
+ if (preferWhisperFallback) {
603904
+ this.emit(
603905
+ "info",
603906
+ "ASR consensus enabled — using live-whisper.py (CUDA when available)."
603907
+ );
603908
+ updateListenLiveState({
603909
+ backend: "openai-whisper",
603910
+ lastStatus: "starting consensus Whisper backend..."
603911
+ });
603912
+ }
603913
+ let tc = preferWhisperFallback ? null : await this.loadTranscribeCli();
603914
+ if (!preferWhisperFallback && !tc) {
603900
603915
  if (_bgInstallPromise) {
603901
603916
  this.emit("info", "Waiting for transcribe-cli install...");
603902
603917
  await _bgInstallPromise;
@@ -604174,13 +604189,14 @@ transcribe-cli error: ${transcribeCliError}` : "";
604174
604189
  * Caller is responsible for calling .stop() when done.
604175
604190
  */
604176
604191
  async createCallTranscriber() {
604177
- let tc = await this.loadTranscribeCli();
604178
- if (!tc && _bgInstallPromise) {
604192
+ const requireConsensus = asrConsensusEnabled();
604193
+ let tc = requireConsensus ? null : await this.loadTranscribeCli();
604194
+ if (!requireConsensus && !tc && _bgInstallPromise) {
604179
604195
  await _bgInstallPromise;
604180
604196
  this.transcribeCliAvailable = null;
604181
604197
  tc = await this.loadTranscribeCli();
604182
604198
  }
604183
- if (!tc) {
604199
+ if (!requireConsensus && !tc) {
604184
604200
  try {
604185
604201
  await ensureManagedTranscribeCliNode();
604186
604202
  this.transcribeCliAvailable = null;
@@ -604188,7 +604204,7 @@ transcribe-cli error: ${transcribeCliError}` : "";
604188
604204
  } catch {
604189
604205
  }
604190
604206
  }
604191
- if (tc?.TranscribeLive && await ensureVenvForTranscribeCli()) {
604207
+ if (!requireConsensus && tc?.TranscribeLive && await ensureVenvForTranscribeCli()) {
604192
604208
  try {
604193
604209
  const transcriber = new tc.TranscribeLive({
604194
604210
  model: this.config.model,
@@ -604326,13 +604342,36 @@ transcribe-cli error: ${transcribeCliError}` : "";
604326
604342
 
604327
604343
  // packages/cli/src/tui/camera-streamer.ts
604328
604344
  import { spawn as spawn30 } from "node:child_process";
604329
- import { existsSync as existsSync111, mkdirSync as mkdirSync69, statSync as statSync43 } from "node:fs";
604345
+ import { existsSync as existsSync111, mkdirSync as mkdirSync69, statSync as statSync43, unlinkSync as unlinkSync20 } from "node:fs";
604330
604346
  import { join as join127 } from "node:path";
604331
604347
  function streamFps() {
604332
604348
  const raw = Number(process.env["OMNIUS_LIVE_STREAM_FPS"] ?? "");
604333
604349
  if (Number.isFinite(raw) && raw > 0) return Math.max(1, Math.min(30, Math.round(raw)));
604334
604350
  return 8;
604335
604351
  }
604352
+ function parseResolution(value2) {
604353
+ const raw = String(value2 ?? "").trim().toLowerCase();
604354
+ if (!raw || raw === "native" || raw === "auto") return null;
604355
+ const alias = {
604356
+ "480p": "640x480",
604357
+ "720p": "1280x720",
604358
+ "1080p": "1920x1080",
604359
+ "1440p": "2560x1440",
604360
+ "4k": "3840x2160",
604361
+ "2160p": "3840x2160"
604362
+ };
604363
+ const normalized = alias[raw] ?? raw;
604364
+ const match = normalized.match(/^(\d{3,5})x(\d{3,5})$/);
604365
+ if (!match) return null;
604366
+ const width = Number(match[1]);
604367
+ const height = Number(match[2]);
604368
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) return null;
604369
+ return { label: `${width}x${height}`, width, height };
604370
+ }
604371
+ function scaleFilter(resolution) {
604372
+ if (!resolution) return null;
604373
+ return `scale=w='min(${resolution.width}\\,iw)':h='min(${resolution.height}\\,ih)':force_original_aspect_ratio=decrease`;
604374
+ }
604336
604375
  function rotateFilter(rotation) {
604337
604376
  switch ((rotation % 360 + 360) % 360) {
604338
604377
  case 90:
@@ -604352,7 +604391,7 @@ var MAX_ATTEMPT, FAST_EXIT_MS, RESTART_DELAY_MS, MAX_CONSECUTIVE_FAILURES, Camer
604352
604391
  var init_camera_streamer = __esm({
604353
604392
  "packages/cli/src/tui/camera-streamer.ts"() {
604354
604393
  "use strict";
604355
- MAX_ATTEMPT = 2;
604394
+ MAX_ATTEMPT = 4;
604356
604395
  FAST_EXIT_MS = 3e3;
604357
604396
  RESTART_DELAY_MS = 1500;
604358
604397
  MAX_CONSECUTIVE_FAILURES = 10;
@@ -604387,7 +604426,7 @@ var init_camera_streamer = __esm({
604387
604426
  * Only v4l2 device paths are streamable; other backends (OSC/WiFi cams)
604388
604427
  * keep the one-shot capture path.
604389
604428
  */
604390
- sync(sources, rotationFor) {
604429
+ sync(sources, rotationFor, resolutionFor) {
604391
604430
  const wanted = new Set(sources.filter((source) => source.startsWith("/dev/video")));
604392
604431
  for (const [source, stream] of this.streams) {
604393
604432
  if (!wanted.has(source)) {
@@ -604397,20 +604436,21 @@ var init_camera_streamer = __esm({
604397
604436
  }
604398
604437
  for (const source of wanted) {
604399
604438
  const rotation = rotationFor(source);
604439
+ const resolution = resolutionFor(source);
604400
604440
  const existing = this.streams.get(source);
604401
- if (existing && existing.rotation === rotation && !existing.stopped) continue;
604441
+ if (existing && existing.rotation === rotation && existing.resolution === resolution && !existing.stopped) continue;
604402
604442
  if (existing) {
604403
604443
  this.stopStream(existing);
604404
604444
  this.streams.delete(source);
604405
604445
  }
604406
- this.startStream(source, rotation);
604446
+ this.startStream(source, rotation, resolution);
604407
604447
  }
604408
604448
  }
604409
604449
  stopAll() {
604410
604450
  for (const stream of this.streams.values()) this.stopStream(stream);
604411
604451
  this.streams.clear();
604412
604452
  }
604413
- startStream(source, rotation) {
604453
+ startStream(source, rotation, resolution) {
604414
604454
  try {
604415
604455
  mkdirSync69(this.streamDir, { recursive: true });
604416
604456
  } catch {
@@ -604419,6 +604459,7 @@ var init_camera_streamer = __esm({
604419
604459
  source,
604420
604460
  framePath: join127(this.streamDir, `${slugForSource(source)}.jpg`),
604421
604461
  rotation,
604462
+ resolution,
604422
604463
  process: null,
604423
604464
  attempt: 0,
604424
604465
  consecutiveFailures: 0,
@@ -604433,13 +604474,17 @@ var init_camera_streamer = __esm({
604433
604474
  spawnStream(stream) {
604434
604475
  if (stream.stopped) return;
604435
604476
  const fps = streamFps();
604477
+ const resolution = parseResolution(stream.resolution);
604436
604478
  const filters = [`fps=${fps}`];
604479
+ const scale = scaleFilter(resolution);
604480
+ if (scale) filters.push(scale);
604437
604481
  const rotate = rotateFilter(stream.rotation);
604438
604482
  if (rotate) filters.push(rotate);
604439
604483
  const args = ["-hide_banner", "-loglevel", "error", "-f", "v4l2"];
604440
- if (stream.attempt === 0) args.push("-input_format", "mjpeg");
604484
+ if (stream.attempt === 0 || stream.attempt === 2) args.push("-input_format", "mjpeg");
604485
+ if (resolution && stream.attempt <= 1) args.push("-video_size", resolution.label);
604441
604486
  args.push("-i", stream.source, "-vf", filters.join(","), "-q:v", "6", "-f", "image2", "-update", "1");
604442
- if (stream.attempt <= 1) args.push("-atomic_writing", "1");
604487
+ if (stream.attempt <= 3) args.push("-atomic_writing", "1");
604443
604488
  args.push("-y", stream.framePath);
604444
604489
  const child = spawn30(process.env["OMNIUS_FFMPEG"] || "ffmpeg", args, {
604445
604490
  stdio: ["ignore", "ignore", "pipe"]
@@ -604482,12 +604527,24 @@ var init_camera_streamer = __esm({
604482
604527
  stream.restartTimer = null;
604483
604528
  }
604484
604529
  if (stream.process) {
604530
+ const child = stream.process;
604485
604531
  try {
604486
- stream.process.kill("SIGTERM");
604532
+ child.kill("SIGTERM");
604487
604533
  } catch {
604488
604534
  }
604535
+ const killTimer = setTimeout(() => {
604536
+ try {
604537
+ if (!child.killed) child.kill("SIGKILL");
604538
+ } catch {
604539
+ }
604540
+ }, 1500);
604541
+ killTimer.unref?.();
604489
604542
  stream.process = null;
604490
604543
  }
604544
+ try {
604545
+ if (existsSync111(stream.framePath)) unlinkSync20(stream.framePath);
604546
+ } catch {
604547
+ }
604491
604548
  }
604492
604549
  };
604493
604550
  }
@@ -604703,9 +604760,230 @@ var init_live_vlm = __esm({
604703
604760
  }
604704
604761
  });
604705
604762
 
604763
+ // packages/cli/src/tui/live-resource-arbiter.ts
604764
+ import { cpus as cpus3, freemem as freemem4, loadavg, totalmem as totalmem5 } from "node:os";
604765
+ function getLiveResourceArbiter() {
604766
+ if (!singleton) singleton = new LiveResourceArbiter();
604767
+ return singleton;
604768
+ }
604769
+ function formatLiveResourceBudgetLines(width = 100) {
604770
+ const snap = getLiveResourceArbiter().snapshot();
604771
+ const inner = Math.max(24, width - 2);
604772
+ const memoryColor = pressureColor(snap.memoryPressure, snap.target);
604773
+ const totalGB = snap.totalMemMB / 1024;
604774
+ const usedGB = snap.usedMemMB / 1024;
604775
+ const freeGB = snap.freeMemMB / 1024;
604776
+ const deferMs = Math.max(0, snap.deferUntil - Date.now());
604777
+ const status = deferMs > 0 ? colorText("deferring vision", 208) : colorText("vision allowed", 82);
604778
+ const leaseText = snap.leases.length > 0 ? snap.leases.slice(0, 3).map((lease) => `${lease.owner} p${lease.priority} ${Math.ceil(lease.expiresInMs / 1e3)}s`).join("; ") : "none";
604779
+ return [
604780
+ colorText(" resource budget", 45),
604781
+ `├─ memory: ${memoryColor(`${usedGB.toFixed(1)}/${totalGB.toFixed(1)}GB used`)} free=${freeGB.toFixed(1)}GB target<=${Math.round(snap.target * 100)}%`,
604782
+ `├─ pressure: ${pressureColor(snap.pressure, snap.target)(`${Math.round(snap.pressure * 100)}%`)} pid=${Math.round(snap.pid * 100)}% cpuLoad=${snap.cpuLoad1m.toFixed(2)} budget=${snap.budget} ${status}`,
604783
+ `└─ leases: ${truncateAnsi(leaseText, inner - 12)}`
604784
+ ];
604785
+ }
604786
+ function readBudget() {
604787
+ const raw = String(process.env["OMNIUS_LIVE_RESOURCE_BUDGET"] ?? "").trim().toLowerCase();
604788
+ if (raw === "low" || raw === "conserve" || raw === "conservative" || raw === "battery") return "conserve";
604789
+ if (raw === "high" || raw === "generous") return "high";
604790
+ if (raw === "aggressive" || raw === "max" || raw === "unlimited") return "aggressive";
604791
+ return "balanced";
604792
+ }
604793
+ function budgetTarget(budget) {
604794
+ const override = Number(process.env["OMNIUS_LIVE_RESOURCE_TARGET"] ?? "");
604795
+ if (Number.isFinite(override) && override > 0 && override < 1) return override;
604796
+ if (budget === "conserve") return 0.55;
604797
+ if (budget === "high") return 0.82;
604798
+ if (budget === "aggressive") return 0.92;
604799
+ return 0.7;
604800
+ }
604801
+ function numberEnv(name10, fallback) {
604802
+ const value2 = Number(process.env[name10] ?? "");
604803
+ return Number.isFinite(value2) ? value2 : fallback;
604804
+ }
604805
+ function clamp8(value2, min, max) {
604806
+ return Math.max(min, Math.min(max, value2));
604807
+ }
604808
+ function pressureColor(pressure, target) {
604809
+ if (pressure <= target) return (text2) => colorText(text2, 82);
604810
+ if (pressure <= target + 0.12) return (text2) => colorText(text2, 220);
604811
+ return (text2) => colorText(text2, 196);
604812
+ }
604813
+ function colorText(text2, color) {
604814
+ return `\x1B[38;5;${color}m${text2}\x1B[0m`;
604815
+ }
604816
+ function truncateAnsi(text2, max) {
604817
+ const plain = text2.replace(/\x1b\[[0-9;]*m/g, "");
604818
+ if (plain.length <= max) return text2;
604819
+ return `${plain.slice(0, Math.max(0, max - 3))}...`;
604820
+ }
604821
+ var LiveResourceArbiter, singleton;
604822
+ var init_live_resource_arbiter = __esm({
604823
+ "packages/cli/src/tui/live-resource-arbiter.ts"() {
604824
+ "use strict";
604825
+ LiveResourceArbiter = class {
604826
+ leases = /* @__PURE__ */ new Map();
604827
+ seq = 0;
604828
+ integral = 0;
604829
+ lastError = 0;
604830
+ lastAt = 0;
604831
+ pidDeferUntil = 0;
604832
+ lastPid = 0;
604833
+ lastPressure = 0;
604834
+ claim(args) {
604835
+ const now2 = Date.now();
604836
+ this.cleanup(now2);
604837
+ const id2 = `${now2}-${++this.seq}-${args.owner.replace(/[^a-z0-9_.:-]+/gi, "_")}`;
604838
+ const record = {
604839
+ id: id2,
604840
+ owner: args.owner,
604841
+ priority: clamp8(args.priority, 0, 100),
604842
+ reason: args.reason,
604843
+ suppress: args.suppress?.length ? args.suppress : ["vision"],
604844
+ createdAt: now2,
604845
+ expiresAt: now2 + Math.max(250, args.ttlMs)
604846
+ };
604847
+ this.leases.set(id2, record);
604848
+ return {
604849
+ id: id2,
604850
+ owner: record.owner,
604851
+ priority: record.priority,
604852
+ get expiresAt() {
604853
+ return record.expiresAt;
604854
+ },
604855
+ release: () => {
604856
+ this.leases.delete(id2);
604857
+ },
604858
+ extend: (ttlMs, reason) => {
604859
+ const current = this.leases.get(id2);
604860
+ if (!current) return;
604861
+ current.expiresAt = Math.max(current.expiresAt, Date.now() + Math.max(250, ttlMs));
604862
+ if (reason) current.reason = reason;
604863
+ }
604864
+ };
604865
+ }
604866
+ shouldDefer(kind, options2 = {}) {
604867
+ const now2 = Date.now();
604868
+ this.cleanup(now2);
604869
+ const budget = readBudget();
604870
+ if (String(process.env["OMNIUS_LIVE_RESOURCE_ARBITER"] ?? "").toLowerCase() === "off") {
604871
+ return this.decision(false, "", now2, 0, budget);
604872
+ }
604873
+ const minPriority = clamp8(options2.minPriority ?? 50, 0, 100);
604874
+ const token = kind.toLowerCase();
604875
+ let strongest = null;
604876
+ for (const lease of this.leases.values()) {
604877
+ if (lease.priority < minPriority) continue;
604878
+ if (!lease.suppress.some((entry) => entry === "*" || token.includes(entry.toLowerCase()))) continue;
604879
+ if (!strongest || lease.priority > strongest.priority || lease.expiresAt > strongest.expiresAt) strongest = lease;
604880
+ }
604881
+ if (strongest) {
604882
+ return this.decision(
604883
+ true,
604884
+ `live resource priority ${strongest.priority} from ${strongest.owner}: ${strongest.reason}`,
604885
+ strongest.expiresAt,
604886
+ strongest.priority,
604887
+ budget
604888
+ );
604889
+ }
604890
+ const pid = this.samplePid(now2, budget);
604891
+ if (pid.deferUntil > now2) {
604892
+ return this.decision(
604893
+ true,
604894
+ `resource PID pressure budget=${budget} pressure=${pid.pressure.toFixed(2)} target=${pid.target.toFixed(2)} output=${pid.output.toFixed(2)}`,
604895
+ pid.deferUntil,
604896
+ 45,
604897
+ budget
604898
+ );
604899
+ }
604900
+ return this.decision(false, "", now2, 0, budget);
604901
+ }
604902
+ snapshot(now2 = Date.now()) {
604903
+ this.cleanup(now2);
604904
+ const budget = readBudget();
604905
+ const pid = this.samplePid(now2, budget);
604906
+ const total = Math.max(1, totalmem5());
604907
+ const free = Math.max(0, freemem4());
604908
+ const cpuCount = Math.max(1, cpus3().length);
604909
+ const cpuLoad1m = loadavg()[0] ?? 0;
604910
+ return {
604911
+ budget,
604912
+ totalMemMB: Math.round(total / 1024 / 1024),
604913
+ freeMemMB: Math.round(free / 1024 / 1024),
604914
+ usedMemMB: Math.round((total - free) / 1024 / 1024),
604915
+ memoryPressure: clamp8(1 - free / total, 0, 1),
604916
+ cpuLoad1m,
604917
+ cpuPressure: clamp8(cpuLoad1m / cpuCount, 0, 2) / 2,
604918
+ pressure: pid.pressure,
604919
+ target: pid.target,
604920
+ pid: pid.output,
604921
+ deferUntil: pid.deferUntil,
604922
+ leases: [...this.leases.values()].sort((a2, b) => b.priority - a2.priority).map((lease) => ({
604923
+ owner: lease.owner,
604924
+ priority: lease.priority,
604925
+ reason: lease.reason,
604926
+ expiresInMs: Math.max(0, lease.expiresAt - now2)
604927
+ }))
604928
+ };
604929
+ }
604930
+ releaseOwnerPrefix(prefix) {
604931
+ for (const [id2, lease] of this.leases) {
604932
+ if (lease.owner.startsWith(prefix)) this.leases.delete(id2);
604933
+ }
604934
+ }
604935
+ decision(defer, reason, until, priority, budget) {
604936
+ return {
604937
+ defer,
604938
+ reason,
604939
+ until,
604940
+ priority,
604941
+ budget,
604942
+ pressure: this.lastPressure,
604943
+ pid: this.lastPid
604944
+ };
604945
+ }
604946
+ cleanup(now2) {
604947
+ for (const [id2, lease] of this.leases) {
604948
+ if (lease.expiresAt <= now2) this.leases.delete(id2);
604949
+ }
604950
+ }
604951
+ samplePid(now2, budget) {
604952
+ const target = budgetTarget(budget);
604953
+ const cpuCount = Math.max(1, cpus3().length);
604954
+ const cpuPressure = clamp8((loadavg()[0] ?? 0) / cpuCount, 0, 2) / 2;
604955
+ const total = Math.max(1, totalmem5());
604956
+ const free = Math.max(0, freemem4());
604957
+ const memoryPressure = clamp8(1 - free / total, 0, 1);
604958
+ const pressure = clamp8(Math.max(memoryPressure, cpuPressure * 0.65 + memoryPressure * 0.35), 0, 1);
604959
+ const dt = this.lastAt > 0 ? clamp8((now2 - this.lastAt) / 1e3, 0.1, 10) : 1;
604960
+ const error = pressure - target;
604961
+ this.integral = clamp8(this.integral + error * dt, -2, 2);
604962
+ const derivative = (error - this.lastError) / dt;
604963
+ const kp = numberEnv("OMNIUS_LIVE_PID_KP", 0.9);
604964
+ const ki = numberEnv("OMNIUS_LIVE_PID_KI", 0.18);
604965
+ const kd = numberEnv("OMNIUS_LIVE_PID_KD", 0.12);
604966
+ const output = clamp8(kp * error + ki * this.integral + kd * derivative, 0, 1);
604967
+ this.lastAt = now2;
604968
+ this.lastError = error;
604969
+ this.lastPressure = pressure;
604970
+ this.lastPid = output;
604971
+ if (output > 0.08) {
604972
+ const maxMs = numberEnv("OMNIUS_LIVE_PID_MAX_DEFER_MS", 3e4);
604973
+ this.pidDeferUntil = Math.max(this.pidDeferUntil, now2 + clamp8(750 + output * maxMs, 1e3, maxMs));
604974
+ } else if (pressure < target - 0.08) {
604975
+ this.pidDeferUntil = Math.min(this.pidDeferUntil, now2);
604976
+ }
604977
+ return { output, pressure, target, deferUntil: this.pidDeferUntil };
604978
+ }
604979
+ };
604980
+ singleton = null;
604981
+ }
604982
+ });
604983
+
604706
604984
  // packages/cli/src/tui/live-sensors.ts
604707
604985
  import { existsSync as existsSync113, mkdirSync as mkdirSync70, readFileSync as readFileSync91, writeFileSync as writeFileSync58 } from "node:fs";
604708
- import { arch as arch3, freemem as freemem4 } from "node:os";
604986
+ import { arch as arch3, freemem as freemem5 } from "node:os";
604709
604987
  import { basename as basename23, join as join128, relative as relative11 } from "node:path";
604710
604988
  function liveDir(repoRoot) {
604711
604989
  return join128(repoRoot, ".omnius", "live");
@@ -604857,6 +605135,52 @@ function describeCameraOrientation(orientation) {
604857
605135
  if (!orientation) return "upright/no correction (default)";
604858
605136
  return `${formatCameraRotation(orientation.rotation)} (${orientation.source}${orientation.confidence !== void 0 ? ` confidence=${orientation.confidence.toFixed(2)}` : ""}, updated=${nowIso3(orientation.updatedAt)})`;
604859
605137
  }
605138
+ function normalizeLiveCameraResolution(value2) {
605139
+ const raw = String(value2 ?? "").trim().toLowerCase();
605140
+ if (!raw || raw === "default" || raw === "1080" || raw === "1080p") return "1920x1080";
605141
+ if (raw === "native" || raw === "auto" || raw === "max") return "native";
605142
+ if (raw === "480" || raw === "480p" || raw === "vga") return "640x480";
605143
+ if (raw === "720" || raw === "720p" || raw === "hd") return "1280x720";
605144
+ if (raw === "1440" || raw === "1440p" || raw === "2k") return "2560x1440";
605145
+ if (raw === "2160" || raw === "2160p" || raw === "4k" || raw === "uhd") return "3840x2160";
605146
+ if (["640x480", "1280x720", "1920x1080", "2560x1440", "3840x2160"].includes(raw)) return raw;
605147
+ throw new Error(`Unsupported live camera resolution: ${String(value2)}. Use native, 480p, 720p, 1080p, 1440p, 4k, or WxH.`);
605148
+ }
605149
+ function formatLiveCameraResolution(value2) {
605150
+ const res = value2 ?? DEFAULT_CAMERA_RESOLUTION;
605151
+ if (res === "native") return "native";
605152
+ if (res === "640x480") return "480p (640x480)";
605153
+ if (res === "1280x720") return "720p (1280x720)";
605154
+ if (res === "1920x1080") return "1080p (1920x1080)";
605155
+ if (res === "2560x1440") return "1440p (2560x1440)";
605156
+ if (res === "3840x2160") return "4K (3840x2160)";
605157
+ return res;
605158
+ }
605159
+ function liveCameraResolutionSize(value2) {
605160
+ const res = value2 ?? DEFAULT_CAMERA_RESOLUTION;
605161
+ if (res === "native") return null;
605162
+ const [widthRaw, heightRaw] = res.split("x");
605163
+ const width = Number(widthRaw);
605164
+ const height = Number(heightRaw);
605165
+ return Number.isFinite(width) && Number.isFinite(height) ? { width, height } : null;
605166
+ }
605167
+ function sanitizeCameraStreams(value2) {
605168
+ if (typeof value2 !== "object" || value2 === null || Array.isArray(value2)) return {};
605169
+ const out = {};
605170
+ for (const [device, raw] of Object.entries(value2)) {
605171
+ if (!device || typeof raw !== "object" || raw === null || Array.isArray(raw)) continue;
605172
+ const entry = raw;
605173
+ try {
605174
+ out[device] = {
605175
+ enabled: entry["enabled"] !== false,
605176
+ resolution: normalizeLiveCameraResolution(entry["resolution"] ?? DEFAULT_CAMERA_RESOLUTION)
605177
+ };
605178
+ } catch {
605179
+ out[device] = { enabled: entry["enabled"] !== false, resolution: DEFAULT_CAMERA_RESOLUTION };
605180
+ }
605181
+ }
605182
+ return out;
605183
+ }
604860
605184
  function chooseCameraOrientationFromScores(scores) {
604861
605185
  const sorted = [...scores].filter((score) => Number.isFinite(score.score)).sort((a2, b) => b.score - a2.score);
604862
605186
  const best = sorted[0];
@@ -605616,6 +605940,13 @@ function formatLiveDashboardFromSnapshot(snapshot, opts = {}) {
605616
605940
  const horizontal = "─".repeat(Math.max(0, width - 2));
605617
605941
  const lines = [`╭${horizontal}╮`];
605618
605942
  lines.push(`│${truncateCell(` ${title}`, width - 2)}│`);
605943
+ lines.push(`├${horizontal}┤`);
605944
+ for (const budgetLine of formatLiveResourceBudgetLines(width - 2)) {
605945
+ lines.push(`│${truncateAnsiCell(budgetLine, width - 2)}│`);
605946
+ }
605947
+ const enabledStreams = Object.entries(snapshot.config.cameraStreams ?? {}).filter(([, stream]) => stream.enabled !== false);
605948
+ const selectedResolution = snapshot.config.selectedCamera ? formatLiveCameraResolution(snapshot.config.cameraStreams?.[snapshot.config.selectedCamera]?.resolution) : "none";
605949
+ lines.push(`│${truncateCell(` systems: camera-streams=${enabledStreams.length}/${snapshot.devices.video.length} selected-res=${selectedResolution} yolo=${snapshot.config.inferEnabled ? "on" : "off"} clip=${snapshot.config.clipEnabled ? "on" : "off"} asr=${snapshot.config.asrEnabled ? "on" : "off"} sounds=${snapshot.config.audioAnalysisEnabled ? "on" : "off"}`, width - 2)}│`);
605619
605950
  if (cameras.length === 0) {
605620
605951
  lines.push(`│${truncateCell(" no camera frames captured yet", width - 2)}│`);
605621
605952
  }
@@ -605942,6 +606273,7 @@ function loadLiveSensorConfig(repoRoot) {
605942
606273
  ...DEFAULT_CONFIG7,
605943
606274
  ...parsed,
605944
606275
  cameraOrientation: sanitizeCameraOrientation(parsed.cameraOrientation),
606276
+ cameraStreams: sanitizeCameraStreams(parsed.cameraStreams),
605945
606277
  videoIntervalMs: Math.max(MIN_VIDEO_INTERVAL_MS, Number(parsed.videoIntervalMs ?? DEFAULT_CONFIG7.videoIntervalMs)),
605946
606278
  audioIntervalMs: Math.max(MIN_AUDIO_INTERVAL_MS, Number(parsed.audioIntervalMs ?? DEFAULT_CONFIG7.audioIntervalMs))
605947
606279
  };
@@ -605981,7 +606313,9 @@ function formatLiveSensorContextFromSnapshot(snapshot, opts = {}) {
605981
606313
  lines.push(`Streams: video=${snapshot.config.videoEnabled ? "on" : "off"} infer=${snapshot.config.inferEnabled ? "on" : "off"} clip=${snapshot.config.clipEnabled ? "on" : "off"} audio=${snapshot.config.audioEnabled ? "on" : "off"} asr=${snapshot.config.asrEnabled ? "on" : "off"} sounds=${snapshot.config.audioAnalysisEnabled ? "on" : "off"} output-monitor=${snapshot.config.audioOutputEnabled ? "on" : "off"}`);
605982
606314
  if (snapshot.config.selectedCamera) {
605983
606315
  const orientation = snapshot.config.cameraOrientation?.[snapshot.config.selectedCamera];
606316
+ const stream = snapshot.config.cameraStreams?.[snapshot.config.selectedCamera];
605984
606317
  lines.push(`Selected camera: ${snapshot.config.selectedCamera}`);
606318
+ lines.push(`Selected camera stream: ${stream?.enabled !== false ? "enabled" : "disabled"} ${formatLiveCameraResolution(stream?.resolution)}`);
605985
606319
  lines.push(`Camera orientation correction: ${describeCameraOrientation(orientation)}`);
605986
606320
  }
605987
606321
  const cameraSnapshots = Object.values(snapshot.cameras ?? (snapshot.video ? { [snapshot.video.source]: snapshot.video } : {})).sort((a2, b) => {
@@ -606438,6 +606772,7 @@ function formatLiveStatus(snapshot) {
606438
606772
  const lines = [
606439
606773
  `Live streams: video=${cfg.videoEnabled ? "on" : "off"} infer=${cfg.inferEnabled ? "on" : "off"} clip=${cfg.clipEnabled ? "on" : "off"} audio=${cfg.audioEnabled ? "on" : "off"} asr=${cfg.asrEnabled ? "on" : "off"} sounds=${cfg.audioAnalysisEnabled ? "on" : "off"} output=${cfg.audioOutputEnabled ? "on" : "off"}`,
606440
606774
  `Camera: ${cfg.selectedCamera || "none"}`,
606775
+ `Camera stream: ${cfg.selectedCamera ? `${cfg.cameraStreams?.[cfg.selectedCamera]?.enabled !== false ? "enabled" : "disabled"} ${formatLiveCameraResolution(cfg.cameraStreams?.[cfg.selectedCamera]?.resolution)}` : "none"}`,
606441
606776
  `Camera orientation: ${cfg.selectedCamera ? describeCameraOrientation(cfg.cameraOrientation?.[cfg.selectedCamera]) : "none"}`,
606442
606777
  `Audio input: ${cfg.selectedAudioInput || "none"}`,
606443
606778
  `Audio output: ${cfg.selectedAudioOutput || "none"}`,
@@ -606451,7 +606786,7 @@ function formatLiveStatus(snapshot) {
606451
606786
  }
606452
606787
  return lines.join("\n");
606453
606788
  }
606454
- var MIN_VIDEO_INTERVAL_MS, LOW_LATENCY_VIDEO_INTERVAL_MS, MIN_AUDIO_INTERVAL_MS, LOW_LATENCY_AUDIO_INTERVAL_MS, AUDIO_ACTIVITY_INTERVAL_MS, AUDIO_ACTIVITY_SAMPLE_SEC, DEFAULT_CONFIG7, managers, DASHBOARD_ANSI_STICKY_PATTERN, _liveDashboardMaximizedCamera, LiveSensorManager;
606789
+ var MIN_VIDEO_INTERVAL_MS, LOW_LATENCY_VIDEO_INTERVAL_MS, MIN_AUDIO_INTERVAL_MS, LOW_LATENCY_AUDIO_INTERVAL_MS, AUDIO_ACTIVITY_INTERVAL_MS, AUDIO_ACTIVITY_SAMPLE_SEC, DEFAULT_CAMERA_RESOLUTION, DEFAULT_CONFIG7, managers, DASHBOARD_ANSI_STICKY_PATTERN, _liveDashboardMaximizedCamera, LiveSensorManager;
606455
606790
  var init_live_sensors = __esm({
606456
606791
  "packages/cli/src/tui/live-sensors.ts"() {
606457
606792
  "use strict";
@@ -606461,12 +606796,14 @@ var init_live_sensors = __esm({
606461
606796
  init_listen();
606462
606797
  init_camera_streamer();
606463
606798
  init_live_vlm();
606799
+ init_live_resource_arbiter();
606464
606800
  MIN_VIDEO_INTERVAL_MS = 250;
606465
606801
  LOW_LATENCY_VIDEO_INTERVAL_MS = 250;
606466
606802
  MIN_AUDIO_INTERVAL_MS = 1500;
606467
606803
  LOW_LATENCY_AUDIO_INTERVAL_MS = 2e3;
606468
606804
  AUDIO_ACTIVITY_INTERVAL_MS = 200;
606469
606805
  AUDIO_ACTIVITY_SAMPLE_SEC = 0.2;
606806
+ DEFAULT_CAMERA_RESOLUTION = "1920x1080";
606470
606807
  DEFAULT_CONFIG7 = {
606471
606808
  videoEnabled: false,
606472
606809
  audioEnabled: false,
@@ -606476,6 +606813,7 @@ var init_live_sensors = __esm({
606476
606813
  asrEnabled: false,
606477
606814
  audioAnalysisEnabled: false,
606478
606815
  cameraOrientation: {},
606816
+ cameraStreams: {},
606479
606817
  videoIntervalMs: 1e3,
606480
606818
  audioIntervalMs: 6e3
606481
606819
  };
@@ -606512,6 +606850,7 @@ var init_live_sensors = __esm({
606512
606850
  lastStreamPersistAt = 0;
606513
606851
  videoGeneration = 0;
606514
606852
  liveGpuYieldUntil = 0;
606853
+ resourceArbiter = getLiveResourceArbiter();
606515
606854
  videoInFlight = false;
606516
606855
  audioInFlight = false;
606517
606856
  audioActivityInFlight = false;
@@ -606656,12 +606995,85 @@ var init_live_sensors = __esm({
606656
606995
  if (!clean5 || ordered.includes(clean5)) return;
606657
606996
  const device = this.devices.video.find((entry) => entry.id === clean5);
606658
606997
  if (device && /metadata\/non-capture/i.test(device.detail ?? "")) return;
606998
+ if (!this.isCameraStreamEnabled(clean5)) return;
606659
606999
  ordered.push(clean5);
606660
607000
  };
606661
607001
  add3(this.config.selectedCamera);
606662
607002
  for (const device of this.devices.video) add3(device.id);
606663
- if (ordered.length === 0) add3(firstDeviceId(this.devices.video));
606664
- return ordered.slice(0, 4);
607003
+ const hasExplicitStreamConfig = Object.keys(this.config.cameraStreams ?? {}).length > 0;
607004
+ if (ordered.length === 0 && !hasExplicitStreamConfig) {
607005
+ const fallback = this.config.selectedCamera || firstDeviceId(this.devices.video);
607006
+ if (fallback) {
607007
+ this.config = {
607008
+ ...this.config,
607009
+ selectedCamera: fallback,
607010
+ cameraStreams: {
607011
+ ...this.config.cameraStreams ?? {},
607012
+ [fallback]: {
607013
+ enabled: true,
607014
+ resolution: this.config.cameraStreams?.[fallback]?.resolution ?? DEFAULT_CAMERA_RESOLUTION
607015
+ }
607016
+ }
607017
+ };
607018
+ add3(fallback);
607019
+ }
607020
+ }
607021
+ const maxStreams = Math.max(1, Math.min(8, Number(process.env["OMNIUS_LIVE_MAX_CAMERA_STREAMS"] ?? 4) || 4));
607022
+ return ordered.slice(0, maxStreams);
607023
+ }
607024
+ isCameraStreamEnabled(device = this.config.selectedCamera) {
607025
+ const target = device || this.config.selectedCamera;
607026
+ if (!target) return false;
607027
+ const configured = this.config.cameraStreams?.[target];
607028
+ if (configured) return configured.enabled !== false;
607029
+ return target === this.config.selectedCamera;
607030
+ }
607031
+ getCameraStreamResolution(device = this.config.selectedCamera) {
607032
+ const target = device || this.config.selectedCamera;
607033
+ return target ? this.config.cameraStreams?.[target]?.resolution ?? DEFAULT_CAMERA_RESOLUTION : DEFAULT_CAMERA_RESOLUTION;
607034
+ }
607035
+ setCameraStreamEnabled(device, enabled2) {
607036
+ const target = device || this.config.selectedCamera;
607037
+ if (!target) return null;
607038
+ const current = this.config.cameraStreams?.[target];
607039
+ const next = {
607040
+ enabled: enabled2,
607041
+ resolution: current?.resolution ?? DEFAULT_CAMERA_RESOLUTION
607042
+ };
607043
+ this.config = {
607044
+ ...this.config,
607045
+ selectedCamera: enabled2 ? target : this.config.selectedCamera,
607046
+ cameraStreams: {
607047
+ ...this.config.cameraStreams ?? {},
607048
+ [target]: next
607049
+ }
607050
+ };
607051
+ this.videoGeneration++;
607052
+ this.lastStreamFrameMtime.delete(target);
607053
+ this.persist();
607054
+ this.ensureLoops();
607055
+ return next;
607056
+ }
607057
+ setCameraStreamResolution(device, resolution) {
607058
+ const target = device || this.config.selectedCamera;
607059
+ if (!target) return null;
607060
+ const current = this.config.cameraStreams?.[target];
607061
+ const next = {
607062
+ enabled: current?.enabled ?? target === this.config.selectedCamera,
607063
+ resolution: normalizeLiveCameraResolution(resolution)
607064
+ };
607065
+ this.config = {
607066
+ ...this.config,
607067
+ cameraStreams: {
607068
+ ...this.config.cameraStreams ?? {},
607069
+ [target]: next
607070
+ }
607071
+ };
607072
+ this.videoGeneration++;
607073
+ this.lastStreamFrameMtime.delete(target);
607074
+ this.persist();
607075
+ this.ensureLoops();
607076
+ return next;
606665
607077
  }
606666
607078
  getCameraOrientation(device = this.config.selectedCamera) {
606667
607079
  return device ? this.config.cameraOrientation?.[device] : void 0;
@@ -606732,6 +607144,14 @@ var init_live_sensors = __esm({
606732
607144
  return isJetsonUnifiedMemoryHost() ? "yield" : "balanced";
606733
607145
  }
606734
607146
  async shouldYieldLiveGpuVideo(kind) {
607147
+ const resourceDecision = this.resourceArbiter.shouldDefer(`vision:${kind}`, { minPriority: 45 });
607148
+ if (resourceDecision.defer) {
607149
+ return {
607150
+ yield: true,
607151
+ reason: resourceDecision.reason,
607152
+ until: resourceDecision.until
607153
+ };
607154
+ }
606735
607155
  const policy = this.liveVideoGpuPolicy();
606736
607156
  if (policy === "aggressive") return { yield: false, reason: "" };
606737
607157
  if (policy === "yield") {
@@ -606755,7 +607175,7 @@ var init_live_sensors = __esm({
606755
607175
  };
606756
607176
  }
606757
607177
  } catch {
606758
- if (isJetsonUnifiedMemoryHost() || freemem4() < 6 * 1024 * 1024 * 1024) {
607178
+ if (isJetsonUnifiedMemoryHost() || freemem5() < 6 * 1024 * 1024 * 1024) {
606759
607179
  return { yield: true, reason: `live video ${kind} yielded: memory pressure unknown` };
606760
607180
  }
606761
607181
  }
@@ -606766,7 +607186,7 @@ var init_live_sensors = __esm({
606766
607186
  if (!decision2.yield) return false;
606767
607187
  const now2 = Date.now();
606768
607188
  if (now2 >= this.liveGpuYieldUntil) {
606769
- this.liveGpuYieldUntil = now2 + 15e3;
607189
+ this.liveGpuYieldUntil = Math.max(decision2.until ?? 0, now2 + 15e3);
606770
607190
  void this.liveVlm.unloadModel().catch(() => false);
606771
607191
  this.emitFeedbackThrottled(`live-video-gpu-yield:${kind}`, {
606772
607192
  kind: "status",
@@ -606774,6 +607194,8 @@ var init_live_sensors = __esm({
606774
607194
  observedAt: now2,
606775
607195
  message: `${decision2.reason}. Camera capture/ASCII preview stays active; GPU video inference is skipped. Set OMNIUS_LIVE_VIDEO_GPU_POLICY=aggressive to override.`
606776
607196
  }, 3e4);
607197
+ } else if (decision2.until) {
607198
+ this.liveGpuYieldUntil = Math.max(this.liveGpuYieldUntil, decision2.until);
606777
607199
  }
606778
607200
  return true;
606779
607201
  }
@@ -606798,10 +607220,12 @@ var init_live_sensors = __esm({
606798
607220
  }
606799
607221
  if (!framePath) {
606800
607222
  if (!this.isVideoWorkCurrent(generation)) return "Video context is disabled.";
607223
+ const captureSize = liveCameraResolutionSize(this.getCameraStreamResolution(target));
606801
607224
  const captured = await new CameraCaptureTool().execute({
606802
607225
  action: "capture",
606803
607226
  device: target,
606804
- rotate_degrees: 0
607227
+ rotate_degrees: 0,
607228
+ ...captureSize ? { width: captureSize.width, height: captureSize.height } : {}
606805
607229
  });
606806
607230
  if (!this.isVideoWorkCurrent(generation)) return "Video context is disabled.";
606807
607231
  if (!captured.success) {
@@ -606876,11 +607300,25 @@ var init_live_sensors = __esm({
606876
607300
  errors
606877
607301
  };
606878
607302
  if (!this.config.selectedCamera) this.config.selectedCamera = firstDeviceId(video);
607303
+ this.config.cameraStreams = this.reconcileCameraStreams(video);
606879
607304
  if (!this.config.selectedAudioInput) this.config.selectedAudioInput = preferredLiveAudioInputId(inputs.devices);
606880
607305
  if (!this.config.selectedAudioOutput) this.config.selectedAudioOutput = firstDeviceId(outputs.devices);
606881
607306
  this.persist();
606882
607307
  return this.devices;
606883
607308
  }
607309
+ reconcileCameraStreams(video) {
607310
+ const current = this.config.cameraStreams ?? {};
607311
+ const selected = this.config.selectedCamera || firstDeviceId(video);
607312
+ const next = {};
607313
+ for (const device of video) {
607314
+ if (!device.id || /metadata\/non-capture/i.test(device.detail ?? "")) continue;
607315
+ next[device.id] = {
607316
+ enabled: current[device.id]?.enabled ?? device.id === selected,
607317
+ resolution: current[device.id]?.resolution ?? DEFAULT_CAMERA_RESOLUTION
607318
+ };
607319
+ }
607320
+ return next;
607321
+ }
606884
607322
  configure(patch) {
606885
607323
  const wasVideoEnabled = this.config.videoEnabled;
606886
607324
  this.config = {
@@ -606889,6 +607327,17 @@ var init_live_sensors = __esm({
606889
607327
  videoIntervalMs: Math.max(MIN_VIDEO_INTERVAL_MS, Number(patch.videoIntervalMs ?? this.config.videoIntervalMs)),
606890
607328
  audioIntervalMs: Math.max(MIN_AUDIO_INTERVAL_MS, Number(patch.audioIntervalMs ?? this.config.audioIntervalMs))
606891
607329
  };
607330
+ this.config.cameraStreams = sanitizeCameraStreams(this.config.cameraStreams);
607331
+ if (patch.selectedCamera) {
607332
+ const selected = String(patch.selectedCamera);
607333
+ this.config.cameraStreams = {
607334
+ ...this.config.cameraStreams ?? {},
607335
+ [selected]: {
607336
+ enabled: true,
607337
+ resolution: this.config.cameraStreams?.[selected]?.resolution ?? DEFAULT_CAMERA_RESOLUTION
607338
+ }
607339
+ };
607340
+ }
606892
607341
  if (wasVideoEnabled && !this.config.videoEnabled) {
606893
607342
  this.videoGeneration++;
606894
607343
  this.lastStreamFrameMtime.clear();
@@ -606913,6 +607362,33 @@ var init_live_sensors = __esm({
606913
607362
  asrEnabled: false,
606914
607363
  audioAnalysisEnabled: false
606915
607364
  });
607365
+ this.cleanupLiveResources();
607366
+ }
607367
+ cleanupLiveResources() {
607368
+ this.clearLoopTimers();
607369
+ this.videoGeneration++;
607370
+ this.cameraStreamers?.stopAll();
607371
+ this.cameraStreamers = null;
607372
+ this.lastStreamFrameMtime.clear();
607373
+ this.lastVlmAt.clear();
607374
+ this.lastClipAt.clear();
607375
+ this.lastInferenceAt.clear();
607376
+ this.autoOrientationInFlight.clear();
607377
+ this.liveSpeechInFlight.clear();
607378
+ this.resourceArbiter.releaseOwnerPrefix("live-");
607379
+ void this.liveVlm.unloadModel().catch(() => false);
607380
+ this.snapshot = {
607381
+ version: 1,
607382
+ repoRoot: this.repoRoot,
607383
+ config: this.config,
607384
+ devices: this.devices,
607385
+ events: [],
607386
+ people: [],
607387
+ cameras: {}
607388
+ };
607389
+ this.persist();
607390
+ this.emitStatus();
607391
+ this.emitDashboard();
606916
607392
  }
606917
607393
  startRunMode(options2 = {}) {
606918
607394
  this.agentActionEnabled = Boolean(options2.agent);
@@ -607023,10 +607499,12 @@ var init_live_sensors = __esm({
607023
607499
  };
607024
607500
  }
607025
607501
  }
607502
+ const captureSize = liveCameraResolutionSize(this.getCameraStreamResolution(source));
607026
607503
  const result = await new CameraCaptureTool().execute({
607027
607504
  action: "capture",
607028
607505
  device: source,
607029
- rotate_degrees: rotation
607506
+ rotate_degrees: rotation,
607507
+ ...captureSize ? { width: captureSize.width, height: captureSize.height } : {}
607030
607508
  });
607031
607509
  if (!this.isVideoWorkCurrent(generation)) return { ok: false, message: "Video context is disabled." };
607032
607510
  if (!result.success) {
@@ -607431,6 +607909,8 @@ ${output}`).join("\n\n");
607431
607909
  async sampleAudioNow() {
607432
607910
  if (this.audioInFlight) return "Audio sampler is already running.";
607433
607911
  this.audioInFlight = true;
607912
+ let asrLease = null;
607913
+ let keepAsrLease = false;
607434
607914
  try {
607435
607915
  const input = this.resolveAudioInput();
607436
607916
  if (this.isLiveAudioMutedForTts()) {
@@ -607481,6 +607961,13 @@ ${output}`).join("\n\n");
607481
607961
  audioErrors.push(`No live input signal detected from selected input ${capture.device}; keeping the explicit selection.`);
607482
607962
  }
607483
607963
  if (this.config.asrEnabled) {
607964
+ asrLease = this.resourceArbiter.claim({
607965
+ owner: "live-asr",
607966
+ priority: 88,
607967
+ ttlMs: 18e3,
607968
+ reason: "live audio ASR capture/transcription",
607969
+ suppress: ["vision"]
607970
+ });
607484
607971
  try {
607485
607972
  const asr = await new TranscribeFileTool(this.repoRoot).execute({
607486
607973
  path: recordingPath,
@@ -607517,6 +608004,11 @@ ${output}`).join("\n\n");
607517
608004
  }
607518
608005
  if (transcript) {
607519
608006
  intake = await classifyLiveAudioIntake(transcript, this.intakeAgentConfig);
608007
+ keepAsrLease = true;
608008
+ asrLease?.extend(
608009
+ intake?.intendedForAgent ? 35e3 : 18e3,
608010
+ intake?.intendedForAgent ? "live ASR addressed Omnius; reserving compute for response inference" : "live ASR transcript accepted; briefly yielding vision"
608011
+ );
607520
608012
  }
607521
608013
  this.snapshot.audio = {
607522
608014
  updatedAt: Date.now(),
@@ -607584,6 +608076,7 @@ Sound analysis:
607584
608076
  ${analysis}` : ""
607585
608077
  ].filter(Boolean).join("\n");
607586
608078
  } finally {
608079
+ if (!keepAsrLease) asrLease?.release();
607587
608080
  this.audioInFlight = false;
607588
608081
  }
607589
608082
  }
@@ -607624,7 +608117,8 @@ ${analysis}` : ""
607624
608117
  }
607625
608118
  this.cameraStreamers.sync(
607626
608119
  this.activeVideoSources(),
607627
- (source) => this.getCameraOrientation(source)?.rotation ?? 0
608120
+ (source) => this.getCameraOrientation(source)?.rotation ?? 0,
608121
+ (source) => this.getCameraStreamResolution(source)
607628
608122
  );
607629
608123
  }
607630
608124
  previewTickIntervalMs() {
@@ -612426,6 +612920,8 @@ var init_command_registry = __esm({
612426
612920
  ["/live chat", "Start low-latency voicechat with live audio/video context and async agent review"],
612427
612921
  ["/livechat", "Alias for /live chat, used by the top live button"],
612428
612922
  ["/live camera <device>", "Select a camera and render an ASCII preview"],
612923
+ ["/live resolution [camera] 720p|1080p|1440p|4k|native", "Set per-camera live stream resolution (default 1080p)"],
612924
+ ["/live camera-on|camera-off [camera]", "Enable or disable an individual live camera stream"],
612429
612925
  ["/live rotate auto|cw|ccw|180|none [camera]", "Detect or set persistent camera orientation correction"],
612430
612926
  ["/live infer [now|on|off]", "Toggle or run camera object/location inference"],
612431
612927
  ["/live clip [on|off]", "Toggle CLIP visual-memory recognition on live frames"],
@@ -614314,7 +614810,7 @@ var init_syntax_highlight = __esm({
614314
614810
  });
614315
614811
 
614316
614812
  // packages/cli/src/tui/model-picker.ts
614317
- import { totalmem as totalmem5 } from "node:os";
614813
+ import { totalmem as totalmem6 } from "node:os";
614318
614814
  function isImageGenModel(name10, family) {
614319
614815
  return IMAGE_GEN_PATTERNS.some((p2) => p2.test(name10) || family && p2.test(family));
614320
614816
  }
@@ -614703,7 +615199,7 @@ async function queryModelContextSize(baseUrl2, modelName) {
614703
615199
  }
614704
615200
  }
614705
615201
  function estimateRealisticContext(kvBytesPerToken, archMax, modelSizeGB2) {
614706
- const totalMemGB = totalmem5() / 1024 ** 3;
615202
+ const totalMemGB = totalmem6() / 1024 ** 3;
614707
615203
  const usableBytes = totalMemGB * 0.7 * 1024 ** 3;
614708
615204
  const maxTokens = Math.floor(usableBytes / kvBytesPerToken);
614709
615205
  let numCtx = Math.max(2048, Math.floor(maxTokens / 1024) * 1024);
@@ -617275,6 +617771,7 @@ let micStream = null;
617275
617771
  let scriptProcessor = null;
617276
617772
  let micActive = false;
617277
617773
  let playbackQueue = [];
617774
+ let pendingTtsHeader = null;
617278
617775
  let isPlaying = false;
617279
617776
  let reconnectDelay = 1000;
617280
617777
  let reconnectTimer = null;
@@ -617334,10 +617831,14 @@ function connect() {
617334
617831
  waveState = 'speaking';
617335
617832
  } else if (msg.type === 'speaking_end') {
617336
617833
  waveState = micActive ? 'listening' : 'idle';
617834
+ } else if (msg.type === 'tts_header') {
617835
+ pendingTtsHeader = { sampleRate: msg.sampleRate || 22050 };
617337
617836
  }
617338
617837
  } catch {}
617339
617838
  } else {
617340
- playbackQueue.push(new Int16Array(evt.data));
617839
+ const sampleRate = (pendingTtsHeader && pendingTtsHeader.sampleRate) || 22050;
617840
+ pendingTtsHeader = null;
617841
+ playbackQueue.push({ pcm: new Int16Array(evt.data), sampleRate });
617341
617842
  if (!isPlaying) drainPlayback();
617342
617843
  }
617343
617844
  };
@@ -617356,15 +617857,17 @@ function escapeHtml(s) {
617356
617857
  }
617357
617858
 
617358
617859
  async function drainPlayback() {
617359
- if (!playbackCtx) playbackCtx = new AudioContext({ sampleRate: 22050 });
617860
+ if (!playbackCtx) playbackCtx = new AudioContext();
617360
617861
  isPlaying = true;
617361
617862
  while (playbackQueue.length > 0) {
617362
- const int16 = playbackQueue.shift();
617863
+ const frame = playbackQueue.shift();
617864
+ const int16 = frame.pcm || frame;
617865
+ const sampleRate = frame.sampleRate || 22050;
617363
617866
  const float32 = new Float32Array(int16.length);
617364
617867
  for (let i = 0; i < int16.length; i++) {
617365
617868
  float32[i] = int16[i] < 0 ? int16[i] / 0x8000 : int16[i] / 0x7FFF;
617366
617869
  }
617367
- const buf = playbackCtx.createBuffer(1, float32.length, 22050);
617870
+ const buf = playbackCtx.createBuffer(1, float32.length, sampleRate);
617368
617871
  buf.getChannelData(0).set(float32);
617369
617872
  const src = playbackCtx.createBufferSource();
617370
617873
  src.buffer = buf;
@@ -618013,11 +618516,15 @@ var init_voice_session = __esm({
618013
618516
  /**
618014
618517
  * Send TTS audio (PCM Int16 @ model sample rate) to all connected clients.
618015
618518
  */
618016
- sendAudioToClients(pcmInt16) {
618519
+ sendAudioToClients(pcmInt16, sampleRate = 22050) {
618017
618520
  this.ttsSpeaking = true;
618521
+ const header = JSON.stringify({ type: "tts_header", sampleRate, bytes: pcmInt16.length });
618018
618522
  for (const ws of this.wsClients.values()) {
618019
618523
  try {
618020
- if (ws.readyState === import_websocket5.default.OPEN) ws.send(pcmInt16);
618524
+ if (ws.readyState === import_websocket5.default.OPEN) {
618525
+ ws.send(header);
618526
+ ws.send(pcmInt16);
618527
+ }
618021
618528
  } catch {
618022
618529
  }
618023
618530
  }
@@ -618025,11 +618532,15 @@ var init_voice_session = __esm({
618025
618532
  /**
618026
618533
  * Send TTS audio to a specific client by clientId.
618027
618534
  */
618028
- sendAudioToClient(clientId, pcmInt16) {
618535
+ sendAudioToClient(clientId, pcmInt16, sampleRate = 22050) {
618536
+ this.ttsSpeaking = true;
618029
618537
  const ws = this.wsClients.get(clientId);
618030
618538
  if (ws) {
618031
618539
  try {
618032
- if (ws.readyState === import_websocket5.default.OPEN) ws.send(pcmInt16);
618540
+ if (ws.readyState === import_websocket5.default.OPEN) {
618541
+ ws.send(JSON.stringify({ type: "tts_header", sampleRate, bytes: pcmInt16.length }));
618542
+ ws.send(pcmInt16);
618543
+ }
618033
618544
  } catch {
618034
618545
  }
618035
618546
  }
@@ -618038,6 +618549,7 @@ var init_voice_session = __esm({
618038
618549
  * Send speaking state change to a specific client.
618039
618550
  */
618040
618551
  sendSpeakingStateToClient(clientId, speaking) {
618552
+ this.ttsSpeaking = speaking;
618041
618553
  const ws = this.wsClients.get(clientId);
618042
618554
  if (ws) {
618043
618555
  const msg = JSON.stringify({ type: speaking ? "speaking_start" : "speaking_end" });
@@ -619058,8 +619570,8 @@ import { spawn as spawn32, exec as exec3 } from "node:child_process";
619058
619570
  import { EventEmitter as EventEmitter8 } from "node:events";
619059
619571
  import { randomBytes as randomBytes22, timingSafeEqual } from "node:crypto";
619060
619572
  import { URL as URL2 } from "node:url";
619061
- import { loadavg, cpus as cpus3, totalmem as totalmem6, freemem as freemem5 } from "node:os";
619062
- import { existsSync as existsSync117, readFileSync as readFileSync95, writeFileSync as writeFileSync60, unlinkSync as unlinkSync20, mkdirSync as mkdirSync72, readdirSync as readdirSync38, statSync as statSync45, statfsSync as statfsSync7 } from "node:fs";
619573
+ import { loadavg as loadavg2, cpus as cpus4, totalmem as totalmem7, freemem as freemem6 } from "node:os";
619574
+ import { existsSync as existsSync117, readFileSync as readFileSync95, writeFileSync as writeFileSync60, unlinkSync as unlinkSync21, mkdirSync as mkdirSync72, readdirSync as readdirSync38, statSync as statSync45, statfsSync as statfsSync7 } from "node:fs";
619063
619575
  import { join as join132 } from "node:path";
619064
619576
  function cleanForwardHeaders(raw, targetHost) {
619065
619577
  const out = {};
@@ -619272,7 +619784,7 @@ function writeExposeState(stateDir, state) {
619272
619784
  }
619273
619785
  function removeExposeState(stateDir) {
619274
619786
  try {
619275
- unlinkSync20(join132(stateDir, STATE_FILE_NAME));
619787
+ unlinkSync21(join132(stateDir, STATE_FILE_NAME));
619276
619788
  } catch {
619277
619789
  }
619278
619790
  }
@@ -619316,10 +619828,10 @@ function parseRateLimitHeaders(headers) {
619316
619828
  };
619317
619829
  }
619318
619830
  async function collectSystemMetricsAsync() {
619319
- const [l1, l5, l15] = loadavg();
619320
- const cores = cpus3().length;
619321
- const totalMem = totalmem6();
619322
- const freeMem = freemem5();
619831
+ const [l1, l5, l15] = loadavg2();
619832
+ const cores = cpus4().length;
619833
+ const totalMem = totalmem7();
619834
+ const freeMem = freemem6();
619323
619835
  const usedMem = totalMem - freeMem;
619324
619836
  let disk = {
619325
619837
  path: process.cwd(),
@@ -619410,7 +619922,7 @@ function writeP2PExposeState(stateDir, state) {
619410
619922
  }
619411
619923
  function removeP2PExposeState(stateDir) {
619412
619924
  try {
619413
- unlinkSync20(join132(stateDir, P2P_STATE_FILE_NAME));
619925
+ unlinkSync21(join132(stateDir, P2P_STATE_FILE_NAME));
619414
619926
  } catch {
619415
619927
  }
619416
619928
  }
@@ -622545,7 +623057,7 @@ ${activitySummary}
622545
623057
  });
622546
623058
 
622547
623059
  // packages/cli/src/api/profiles.ts
622548
- import { existsSync as existsSync119, readFileSync as readFileSync97, writeFileSync as writeFileSync62, mkdirSync as mkdirSync74, readdirSync as readdirSync39, unlinkSync as unlinkSync21 } from "node:fs";
623060
+ import { existsSync as existsSync119, readFileSync as readFileSync97, writeFileSync as writeFileSync62, mkdirSync as mkdirSync74, readdirSync as readdirSync39, unlinkSync as unlinkSync22 } from "node:fs";
622549
623061
  import { join as join134 } from "node:path";
622550
623062
  import { homedir as homedir41 } from "node:os";
622551
623063
  import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes25, scryptSync as scryptSync3 } from "node:crypto";
@@ -622649,7 +623161,7 @@ function deleteProfile(name10, scope = "global", projectDir2) {
622649
623161
  const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
622650
623162
  const filePath = join134(dir, `${sanitized}.json`);
622651
623163
  if (existsSync119(filePath)) {
622652
- unlinkSync21(filePath);
623164
+ unlinkSync22(filePath);
622653
623165
  return true;
622654
623166
  }
622655
623167
  return false;
@@ -622927,7 +623439,7 @@ __export(omnius_directory_exports, {
622927
623439
  writeIndexMeta: () => writeIndexMeta,
622928
623440
  writeTaskHandoff: () => writeTaskHandoff2
622929
623441
  });
622930
- import { appendFileSync as appendFileSync13, cpSync as cpSync2, existsSync as existsSync120, mkdirSync as mkdirSync75, readFileSync as readFileSync98, writeFileSync as writeFileSync63, readdirSync as readdirSync40, statSync as statSync46, unlinkSync as unlinkSync22, openSync as openSync2, closeSync as closeSync2, renameSync as renameSync11, watch as fsWatch2 } from "node:fs";
623442
+ import { appendFileSync as appendFileSync13, cpSync as cpSync2, existsSync as existsSync120, mkdirSync as mkdirSync75, readFileSync as readFileSync98, writeFileSync as writeFileSync63, readdirSync as readdirSync40, statSync as statSync46, unlinkSync as unlinkSync23, openSync as openSync2, closeSync as closeSync2, renameSync as renameSync11, watch as fsWatch2 } from "node:fs";
622931
623443
  import { join as join135, relative as relative13, basename as basename25, dirname as dirname40, resolve as resolve57 } from "node:path";
622932
623444
  import { homedir as homedir42 } from "node:os";
622933
623445
  import { createHash as createHash37 } from "node:crypto";
@@ -623318,7 +623830,7 @@ function loadPendingTask(repoRoot) {
623318
623830
  if (!existsSync120(filePath)) return null;
623319
623831
  const data = JSON.parse(readFileSync98(filePath, "utf-8"));
623320
623832
  try {
623321
- unlinkSync22(filePath);
623833
+ unlinkSync23(filePath);
623322
623834
  } catch {
623323
623835
  }
623324
623836
  return data;
@@ -623337,7 +623849,7 @@ function writeTaskHandoff2(repoRoot, handoff) {
623337
623849
  } catch {
623338
623850
  writeFileSync63(filePath, JSON.stringify(handoff, null, 2) + "\n", "utf-8");
623339
623851
  try {
623340
- unlinkSync22(tempPath);
623852
+ unlinkSync23(tempPath);
623341
623853
  } catch {
623342
623854
  }
623343
623855
  }
@@ -623363,7 +623875,7 @@ function clearTaskHandoff(repoRoot) {
623363
623875
  const filePath = join135(repoRoot, OMNIUS_DIR, "context", HANDOFF_FILE);
623364
623876
  try {
623365
623877
  if (existsSync120(filePath)) {
623366
- unlinkSync22(filePath);
623878
+ unlinkSync23(filePath);
623367
623879
  }
623368
623880
  } catch {
623369
623881
  }
@@ -623437,13 +623949,13 @@ function acquireLock(lockPath) {
623437
623949
  const lockAge = Date.now() - lock.acquiredAt;
623438
623950
  if (lockAge > LOCK_TIMEOUT_MS) {
623439
623951
  try {
623440
- unlinkSync22(lockPath);
623952
+ unlinkSync23(lockPath);
623441
623953
  } catch {
623442
623954
  }
623443
623955
  }
623444
623956
  } catch {
623445
623957
  try {
623446
- unlinkSync22(lockPath);
623958
+ unlinkSync23(lockPath);
623447
623959
  } catch {
623448
623960
  }
623449
623961
  }
@@ -623461,7 +623973,7 @@ function releaseLock(lockPath) {
623461
623973
  const lockContent = readFileSync98(lockPath, "utf-8");
623462
623974
  const lock = JSON.parse(lockContent);
623463
623975
  if (lock.pid === process.pid) {
623464
- unlinkSync22(lockPath);
623976
+ unlinkSync23(lockPath);
623465
623977
  }
623466
623978
  }
623467
623979
  } catch {
@@ -623647,7 +624159,7 @@ function saveSessionContext(repoRoot, entry) {
623647
624159
  } catch {
623648
624160
  writeFileSync63(filePath, JSON.stringify(ctx3, null, 2) + "\n", "utf-8");
623649
624161
  try {
623650
- unlinkSync22(tempFilePath);
624162
+ unlinkSync23(tempFilePath);
623651
624163
  } catch {
623652
624164
  }
623653
624165
  }
@@ -624030,7 +624542,7 @@ function saveSessionHistory(repoRoot, sessionId, contentLines, meta) {
624030
624542
  if (index.length > 50) {
624031
624543
  const removed = index.shift();
624032
624544
  try {
624033
- unlinkSync22(join135(sessDir, `${removed.id}.jsonl`));
624545
+ unlinkSync23(join135(sessDir, `${removed.id}.jsonl`));
624034
624546
  } catch {
624035
624547
  }
624036
624548
  }
@@ -624060,7 +624572,7 @@ function deleteSession(repoRoot, sessionId) {
624060
624572
  const indexPath = join135(sessDir, SESSIONS_INDEX);
624061
624573
  try {
624062
624574
  const contentPath = join135(sessDir, `${sessionId}.jsonl`);
624063
- if (existsSync120(contentPath)) unlinkSync22(contentPath);
624575
+ if (existsSync120(contentPath)) unlinkSync23(contentPath);
624064
624576
  if (existsSync120(indexPath)) {
624065
624577
  let index = JSON.parse(readFileSync98(indexPath, "utf-8"));
624066
624578
  index = index.filter((s2) => s2.id !== sessionId);
@@ -624398,7 +624910,7 @@ function firstMeaningfulLine(transcript) {
624398
624910
  }
624399
624911
  return "";
624400
624912
  }
624401
- function clamp8(value2, max) {
624913
+ function clamp9(value2, max) {
624402
624914
  const v = value2.replace(/\s+/g, " ").trim();
624403
624915
  return v.length > max ? v.slice(0, max - 1).trimEnd() + "…" : v;
624404
624916
  }
@@ -624406,8 +624918,8 @@ function deterministicSummary(transcript) {
624406
624918
  const first2 = firstMeaningfulLine(transcript);
624407
624919
  if (!first2) return { title: "Untitled session", summary: "Empty session." };
624408
624920
  const cleaned = first2.replace(TUI_MARKER_PREFIX, "").replace(/^[>›$#\s]+/, "").trim();
624409
- const title = clamp8(cleaned, TITLE_MAX);
624410
- return { title: title || "Untitled session", summary: clamp8(cleaned || first2, SUMMARY_MAX) };
624921
+ const title = clamp9(cleaned, TITLE_MAX);
624922
+ return { title: title || "Untitled session", summary: clamp9(cleaned || first2, SUMMARY_MAX) };
624411
624923
  }
624412
624924
  function parseSummaryReply(content) {
624413
624925
  if (!content) return null;
@@ -624459,8 +624971,8 @@ async function generateSessionSummary(args) {
624459
624971
  const parsed = parseSummaryReply(content);
624460
624972
  if (!parsed) return fallback;
624461
624973
  return {
624462
- title: clamp8(parsed.title, TITLE_MAX) || fallback.title,
624463
- summary: clamp8(parsed.summary, SUMMARY_MAX) || fallback.summary
624974
+ title: clamp9(parsed.title, TITLE_MAX) || fallback.title,
624975
+ summary: clamp9(parsed.summary, SUMMARY_MAX) || fallback.summary
624464
624976
  };
624465
624977
  } catch {
624466
624978
  return fallback;
@@ -625490,7 +626002,7 @@ __export(system_metrics_exports, {
625490
626002
  getInstantSnapshot: () => getInstantSnapshot,
625491
626003
  instantaneousCpuPct: () => instantaneousCpuPct
625492
626004
  });
625493
- import { loadavg as loadavg2, cpus as cpus4, totalmem as totalmem7, freemem as freemem6, platform as platform4 } from "node:os";
626005
+ import { loadavg as loadavg3, cpus as cpus5, totalmem as totalmem8, freemem as freemem7, platform as platform4 } from "node:os";
625494
626006
  import { exec as exec4 } from "node:child_process";
625495
626007
  import { readFile as readFile24 } from "node:fs/promises";
625496
626008
  function formatRate(bytesPerSec) {
@@ -625659,7 +626171,7 @@ function getInstantSnapshot() {
625659
626171
  function readCpuTimes() {
625660
626172
  let idle = 0;
625661
626173
  let total = 0;
625662
- for (const cpu of cpus4()) {
626174
+ for (const cpu of cpus5()) {
625663
626175
  const t2 = cpu.times;
625664
626176
  idle += t2.idle;
625665
626177
  total += t2.user + t2.nice + t2.sys + t2.idle + t2.irq;
@@ -625678,13 +626190,13 @@ function instantaneousCpuPct() {
625678
626190
  return Math.max(0, Math.min(100, Math.round(usage * 100)));
625679
626191
  }
625680
626192
  function collectCpuRam() {
625681
- const cores = cpus4().length;
625682
- const cpuModel = cpus4()[0]?.model ?? "";
625683
- const totalMem = totalmem7();
625684
- const usedMem = totalMem - freemem6();
626193
+ const cores = cpus5().length;
626194
+ const cpuModel = cpus5()[0]?.model ?? "";
626195
+ const totalMem = totalmem8();
626196
+ const usedMem = totalMem - freemem7();
625685
626197
  let cpuUtil = instantaneousCpuPct();
625686
626198
  if (cpuUtil < 0) {
625687
- const [l1] = loadavg2();
626199
+ const [l1] = loadavg3();
625688
626200
  cpuUtil = Math.max(0, Math.min(100, Math.round(l1 / cores * 100)));
625689
626201
  }
625690
626202
  return {
@@ -633100,7 +633612,7 @@ import { spawn as spawn34, exec as exec5 } from "node:child_process";
633100
633612
  import { promisify as promisify7 } from "node:util";
633101
633613
  import { existsSync as existsSync126, writeFileSync as writeFileSync66, readFileSync as readFileSync104, appendFileSync as appendFileSync14, mkdirSync as mkdirSync78, chmodSync as chmodSync3 } from "node:fs";
633102
633614
  import { delimiter as pathDelimiter, join as join141 } from "node:path";
633103
- import { freemem as freemem7, homedir as homedir46, platform as platform5, totalmem as totalmem8 } from "node:os";
633615
+ import { freemem as freemem8, homedir as homedir46, platform as platform5, totalmem as totalmem9 } from "node:os";
633104
633616
  function wrapText2(value2, width) {
633105
633617
  const words = value2.split(/\s+/).filter(Boolean);
633106
633618
  const lines = [];
@@ -633213,8 +633725,8 @@ function parseRocmSmi(stdout) {
633213
633725
  return { total, free: Math.max(0, total - used), name: name10 ? `AMD ${name10}` : "AMD GPU" };
633214
633726
  }
633215
633727
  function detectSystemSpecs() {
633216
- let totalRamGB = totalmem8() / 1024 ** 3;
633217
- let availableRamGB = freemem7() / 1024 ** 3;
633728
+ let totalRamGB = totalmem9() / 1024 ** 3;
633729
+ let availableRamGB = freemem8() / 1024 ** 3;
633218
633730
  let gpuVramGB = 0;
633219
633731
  let availableVramGB = 0;
633220
633732
  const gpuName = "";
@@ -639995,7 +640507,7 @@ var init_audio_waveform = __esm({
639995
640507
  });
639996
640508
 
639997
640509
  // packages/cli/src/tui/neovim-mode.ts
639998
- import { existsSync as existsSync132, unlinkSync as unlinkSync24 } from "node:fs";
640510
+ import { existsSync as existsSync132, unlinkSync as unlinkSync25 } from "node:fs";
639999
640511
  import { tmpdir as tmpdir22 } from "node:os";
640000
640512
  import { join as join145 } from "node:path";
640001
640513
  function isNeovimActive() {
@@ -640044,7 +640556,7 @@ async function startNeovimMode(opts) {
640044
640556
  }
640045
640557
  const socketPath = join145(tmpdir22(), `omnius-nvim-${process.pid}-${Date.now()}.sock`);
640046
640558
  try {
640047
- if (existsSync132(socketPath)) unlinkSync24(socketPath);
640559
+ if (existsSync132(socketPath)) unlinkSync25(socketPath);
640048
640560
  } catch {
640049
640561
  }
640050
640562
  const ptyCols = opts.cols;
@@ -640433,7 +640945,7 @@ function doCleanup(state) {
640433
640945
  state.pty = null;
640434
640946
  }
640435
640947
  try {
640436
- if (existsSync132(state.socketPath)) unlinkSync24(state.socketPath);
640948
+ if (existsSync132(state.socketPath)) unlinkSync25(state.socketPath);
640437
640949
  } catch {
640438
640950
  }
640439
640951
  if (state.stdinHandler) {
@@ -640508,7 +641020,7 @@ __export(daemon_exports, {
640508
641020
  stopDaemon: () => stopDaemon
640509
641021
  });
640510
641022
  import { spawn as spawn35 } from "node:child_process";
640511
- import { existsSync as existsSync133, readFileSync as readFileSync108, writeFileSync as writeFileSync67, mkdirSync as mkdirSync79, unlinkSync as unlinkSync25, openSync as openSync3, closeSync as closeSync3 } from "node:fs";
641023
+ import { existsSync as existsSync133, readFileSync as readFileSync108, writeFileSync as writeFileSync67, mkdirSync as mkdirSync79, unlinkSync as unlinkSync26, openSync as openSync3, closeSync as closeSync3 } from "node:fs";
640512
641024
  import { join as join146 } from "node:path";
640513
641025
  import { homedir as homedir48 } from "node:os";
640514
641026
  import { fileURLToPath as fileURLToPath20 } from "node:url";
@@ -640584,7 +641096,7 @@ function getDaemonPid() {
640584
641096
  return pid;
640585
641097
  } catch {
640586
641098
  try {
640587
- unlinkSync25(PID_FILE2);
641099
+ unlinkSync26(PID_FILE2);
640588
641100
  } catch {
640589
641101
  }
640590
641102
  return null;
@@ -640700,13 +641212,13 @@ function stopDaemon() {
640700
641212
  }
640701
641213
  process.kill(pid, "SIGTERM");
640702
641214
  try {
640703
- unlinkSync25(PID_FILE2);
641215
+ unlinkSync26(PID_FILE2);
640704
641216
  } catch {
640705
641217
  }
640706
641218
  return true;
640707
641219
  } catch {
640708
641220
  try {
640709
- unlinkSync25(PID_FILE2);
641221
+ unlinkSync26(PID_FILE2);
640710
641222
  } catch {
640711
641223
  }
640712
641224
  return false;
@@ -640737,7 +641249,7 @@ async function forceKillDaemon(port) {
640737
641249
  } catch {
640738
641250
  }
640739
641251
  try {
640740
- unlinkSync25(PID_FILE2);
641252
+ unlinkSync26(PID_FILE2);
640741
641253
  } catch {
640742
641254
  }
640743
641255
  }
@@ -640792,7 +641304,7 @@ async function ensureDaemon() {
640792
641304
  } catch {
640793
641305
  }
640794
641306
  try {
640795
- unlinkSync25(PID_FILE2);
641307
+ unlinkSync26(PID_FILE2);
640796
641308
  } catch {
640797
641309
  }
640798
641310
  }
@@ -640809,7 +641321,7 @@ async function ensureDaemon() {
640809
641321
  } catch {
640810
641322
  }
640811
641323
  try {
640812
- unlinkSync25(PID_FILE2);
641324
+ unlinkSync26(PID_FILE2);
640813
641325
  } catch {
640814
641326
  }
640815
641327
  return false;
@@ -641272,7 +641784,7 @@ import {
641272
641784
  mkdirSync as mkdirSync80,
641273
641785
  chmodSync as chmodSync4,
641274
641786
  existsSync as existsSync136,
641275
- unlinkSync as unlinkSync26,
641787
+ unlinkSync as unlinkSync27,
641276
641788
  readdirSync as readdirSync44
641277
641789
  } from "node:fs";
641278
641790
  import { join as join149 } from "node:path";
@@ -641467,12 +641979,12 @@ function saveJobs(jobs) {
641467
641979
  const tmp = path12 + ".tmp";
641468
641980
  writeFileSync68(tmp, content, "utf-8");
641469
641981
  try {
641470
- unlinkSync26(path12);
641982
+ unlinkSync27(path12);
641471
641983
  } catch {
641472
641984
  }
641473
641985
  writeFileSync68(path12, content, "utf-8");
641474
641986
  try {
641475
- unlinkSync26(tmp);
641987
+ unlinkSync27(tmp);
641476
641988
  } catch {
641477
641989
  }
641478
641990
  secureFile(path12);
@@ -641821,7 +642333,7 @@ import {
641821
642333
  openSync as openSync5,
641822
642334
  closeSync as closeSync5,
641823
642335
  writeFileSync as writeFileSync69,
641824
- unlinkSync as unlinkSync27,
642336
+ unlinkSync as unlinkSync28,
641825
642337
  readFileSync as readFileSync110
641826
642338
  } from "node:fs";
641827
642339
  import { join as join150 } from "node:path";
@@ -641846,7 +642358,7 @@ function acquireTickLock() {
641846
642358
  if (age < 3e5) return false;
641847
642359
  }
641848
642360
  try {
641849
- unlinkSync27(lockPath);
642361
+ unlinkSync28(lockPath);
641850
642362
  } catch {
641851
642363
  }
641852
642364
  }
@@ -641863,7 +642375,7 @@ function acquireTickLock() {
641863
642375
  }
641864
642376
  function releaseTickLock() {
641865
642377
  try {
641866
- unlinkSync27(lockFilePath());
642378
+ unlinkSync28(lockFilePath());
641867
642379
  } catch {
641868
642380
  }
641869
642381
  }
@@ -643576,7 +644088,7 @@ import {
643576
644088
  mkdirSync as mkdirSync83,
643577
644089
  writeFileSync as writeFileSync71,
643578
644090
  readFileSync as readFileSync112,
643579
- unlinkSync as unlinkSync28,
644091
+ unlinkSync as unlinkSync29,
643580
644092
  readdirSync as readdirSync45,
643581
644093
  statSync as statSync52,
643582
644094
  copyFileSync as copyFileSync6,
@@ -645214,7 +645726,7 @@ except Exception as exc:
645214
645726
  const p2 = join152(luxttsCloneRefsDir(), filename);
645215
645727
  if (!existsSync139(p2)) return false;
645216
645728
  try {
645217
- unlinkSync28(p2);
645729
+ unlinkSync29(p2);
645218
645730
  const meta = this.loadCloneMeta();
645219
645731
  delete meta[filename];
645220
645732
  this.saveCloneMeta(meta);
@@ -645589,7 +646101,7 @@ except Exception as exc:
645589
646101
  }
645590
646102
  if (prefetchedWav) {
645591
646103
  try {
645592
- unlinkSync28(prefetchedWav.path);
646104
+ unlinkSync29(prefetchedWav.path);
645593
646105
  } catch {
645594
646106
  }
645595
646107
  }
@@ -645683,7 +646195,7 @@ except Exception as exc:
645683
646195
  this.writeStereoWav(stereo.left, stereo.right, sampleRate, wavPath);
645684
646196
  await this.playWav(wavPath);
645685
646197
  try {
645686
- unlinkSync28(wavPath);
646198
+ unlinkSync29(wavPath);
645687
646199
  } catch {
645688
646200
  }
645689
646201
  }
@@ -646229,7 +646741,7 @@ except Exception as exc:
646229
646741
  if (!wavPath) return null;
646230
646742
  try {
646231
646743
  const data = readFileSync112(wavPath);
646232
- unlinkSync28(wavPath);
646744
+ unlinkSync29(wavPath);
646233
646745
  return data;
646234
646746
  } catch {
646235
646747
  return null;
@@ -646413,7 +646925,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`
646413
646925
  }
646414
646926
  await this.playWav(wavPath);
646415
646927
  try {
646416
- unlinkSync28(wavPath);
646928
+ unlinkSync29(wavPath);
646417
646929
  } catch {
646418
646930
  }
646419
646931
  }
@@ -646457,7 +646969,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`
646457
646969
  if (!existsSync139(wavPath)) return null;
646458
646970
  try {
646459
646971
  const data = readFileSync112(wavPath);
646460
- unlinkSync28(wavPath);
646972
+ unlinkSync29(wavPath);
646461
646973
  return data;
646462
646974
  } catch {
646463
646975
  return null;
@@ -647413,7 +647925,7 @@ if __name__ == '__main__':
647413
647925
  await this.playWav(wavPath);
647414
647926
  await this.sleep(150);
647415
647927
  try {
647416
- unlinkSync28(wavPath);
647928
+ unlinkSync29(wavPath);
647417
647929
  } catch {
647418
647930
  }
647419
647931
  }
@@ -647453,7 +647965,7 @@ if __name__ == '__main__':
647453
647965
  if (!existsSync139(wavPath)) return null;
647454
647966
  try {
647455
647967
  const data = readFileSync112(wavPath);
647456
- unlinkSync28(wavPath);
647968
+ unlinkSync29(wavPath);
647457
647969
  return data;
647458
647970
  } catch {
647459
647971
  return null;
@@ -647780,7 +648292,7 @@ if __name__ == "__main__":
647780
648292
  await this.playWav(wavPath);
647781
648293
  await this.sleep(150);
647782
648294
  try {
647783
- unlinkSync28(wavPath);
648295
+ unlinkSync29(wavPath);
647784
648296
  } catch {
647785
648297
  }
647786
648298
  }
@@ -647829,7 +648341,7 @@ if __name__ == "__main__":
647829
648341
  if (!existsSync139(wavPath)) return null;
647830
648342
  try {
647831
648343
  const data = readFileSync112(wavPath);
647832
- unlinkSync28(wavPath);
648344
+ unlinkSync29(wavPath);
647833
648345
  return data;
647834
648346
  } catch {
647835
648347
  return null;
@@ -658674,6 +659186,134 @@ async function chooseLiveDevice(ctx3, title, devices, activeKey) {
658674
659186
  if (!result.confirmed || !result.key) return null;
658675
659187
  return devices.find((device) => device.id === result.key) ?? null;
658676
659188
  }
659189
+ function liveCameraStreamSummary(manager, deviceId) {
659190
+ return `${manager.isCameraStreamEnabled(deviceId) ? liveEnabled(true) : liveEnabled(false)} · ${formatLiveCameraResolution(manager.getCameraStreamResolution(deviceId))} · ${formatCameraRotation(manager.getCameraRotation(deviceId))}`;
659191
+ }
659192
+ async function chooseLiveCameraResolution(ctx3, manager, deviceId) {
659193
+ const current = manager.getCameraStreamResolution(deviceId);
659194
+ const choices = ["640x480", "1280x720", "1920x1080", "2560x1440", "3840x2160", "native"];
659195
+ const result = await tuiSelect({
659196
+ items: choices.map((resolution) => ({
659197
+ key: resolution,
659198
+ label: formatLiveCameraResolution(resolution),
659199
+ detail: resolution === "native" ? "use camera native format; highest burden" : resolution === "1920x1080" ? "default balanced stream size" : "downscaled camera stream"
659200
+ })),
659201
+ title: `Camera Resolution — ${deviceId}`,
659202
+ activeKey: current,
659203
+ rl: ctx3.rl,
659204
+ availableRows: ctx3.availableContentRows?.()
659205
+ });
659206
+ if (!result.confirmed || !result.key) return null;
659207
+ return normalizeLiveCameraResolution(result.key);
659208
+ }
659209
+ async function showLiveCameraMenu(ctx3, manager, device) {
659210
+ while (true) {
659211
+ const selected = manager.getConfig().selectedCamera === device.id;
659212
+ const enabled2 = manager.isCameraStreamEnabled(device.id);
659213
+ const resolution = manager.getCameraStreamResolution(device.id);
659214
+ const items = [
659215
+ { key: "hdr:camera", label: selectColors.dim(`─── Camera ${device.id} ───`) },
659216
+ {
659217
+ key: "info:camera",
659218
+ label: selectColors.dim(` ${device.label}${device.detail ? ` · ${device.detail}` : ""}`)
659219
+ },
659220
+ {
659221
+ key: "select",
659222
+ label: selected ? "Selected Camera" : "Select Camera",
659223
+ detail: "make this the primary live camera"
659224
+ },
659225
+ {
659226
+ key: "toggle",
659227
+ label: enabled2 ? "Disable This Camera Stream" : "Enable This Camera Stream",
659228
+ detail: "disabled cameras stay available but do not consume ffmpeg/vision resources"
659229
+ },
659230
+ {
659231
+ key: "resolution",
659232
+ label: "Set Stream Resolution",
659233
+ detail: formatLiveCameraResolution(resolution)
659234
+ },
659235
+ {
659236
+ key: "preview",
659237
+ label: "Preview Camera",
659238
+ detail: "capture frame + ASCII preview"
659239
+ },
659240
+ {
659241
+ key: "infer",
659242
+ label: "Infer Camera Now",
659243
+ detail: "run bounded vision inference on this camera"
659244
+ },
659245
+ {
659246
+ key: "auto-orient",
659247
+ label: "Auto-Orient Camera",
659248
+ detail: "detect persistent rotation correction"
659249
+ },
659250
+ {
659251
+ key: "cycle-rotation",
659252
+ label: "Cycle Rotation",
659253
+ detail: formatCameraRotation(manager.getCameraRotation(device.id))
659254
+ },
659255
+ { key: "rotate-0", label: "Rotation: Upright", detail: "0 degrees" },
659256
+ { key: "rotate-90", label: "Rotation: Clockwise", detail: "90 degrees" },
659257
+ { key: "rotate-180", label: "Rotation: 180", detail: "upside down correction" },
659258
+ { key: "rotate-270", label: "Rotation: Counter-clockwise", detail: "270 degrees" }
659259
+ ];
659260
+ const result = await tuiSelect({
659261
+ items,
659262
+ title: `Live Camera — ${device.id}`,
659263
+ activeKey: selected ? "select" : enabled2 ? "toggle" : void 0,
659264
+ rl: ctx3.rl,
659265
+ availableRows: ctx3.availableContentRows?.(),
659266
+ skipKeys: liveSkipKeys(items)
659267
+ });
659268
+ if (!result.confirmed || !result.key) return;
659269
+ switch (result.key) {
659270
+ case "select":
659271
+ manager.configure({ selectedCamera: device.id, videoEnabled: true });
659272
+ manager.setCameraStreamEnabled(device.id, true);
659273
+ renderInfo(`Selected camera ${device.id}.`);
659274
+ continue;
659275
+ case "toggle":
659276
+ manager.setCameraStreamEnabled(device.id, !enabled2);
659277
+ renderInfo(`${!enabled2 ? "Enabled" : "Disabled"} camera stream ${device.id}.`);
659278
+ continue;
659279
+ case "resolution": {
659280
+ const next = await chooseLiveCameraResolution(ctx3, manager, device.id);
659281
+ if (next) {
659282
+ manager.setCameraStreamResolution(device.id, next);
659283
+ renderInfo(`Camera ${device.id} stream resolution set to ${formatLiveCameraResolution(next)}.`);
659284
+ }
659285
+ continue;
659286
+ }
659287
+ case "preview":
659288
+ renderLivePreview(await manager.previewCamera(device.id));
659289
+ continue;
659290
+ case "infer":
659291
+ manager.setCameraStreamEnabled(device.id, true);
659292
+ renderInfo(await manager.sampleCameraNow(device.id, true, { forceInferenceNow: true }));
659293
+ continue;
659294
+ case "auto-orient":
659295
+ renderInfo("Detecting camera orientation...");
659296
+ renderInfo(await manager.autoOrientCamera(device.id));
659297
+ continue;
659298
+ case "cycle-rotation": {
659299
+ const orientation = manager.cycleCameraRotation(device.id);
659300
+ renderInfo(orientation ? `Camera rotation set to ${formatCameraRotation(orientation.rotation)} for ${device.id}.` : "No camera selected.");
659301
+ continue;
659302
+ }
659303
+ case "rotate-0":
659304
+ case "rotate-90":
659305
+ case "rotate-180":
659306
+ case "rotate-270": {
659307
+ const rotation = normalizeLiveCameraRotation(result.key.replace("rotate-", ""));
659308
+ const orientation = manager.setCameraRotation(device.id, rotation, "manual", `/live camera menu ${result.key}`);
659309
+ renderInfo(orientation ? `Camera rotation set to ${formatCameraRotation(orientation.rotation)} for ${device.id}.` : "No camera selected.");
659310
+ continue;
659311
+ }
659312
+ default:
659313
+ return;
659314
+ }
659315
+ }
659316
+ }
658677
659317
  async function handleLiveCommand(ctx3, arg) {
658678
659318
  const manager = getLiveSensorManager(ctx3.repoRoot);
658679
659319
  attachLiveSinks(ctx3, manager);
@@ -658745,6 +659385,40 @@ async function handleLiveCommand(ctx3, arg) {
658745
659385
  }
658746
659386
  return;
658747
659387
  }
659388
+ if (sub2 === "resolution" || sub2 === "res" || sub2 === "size") {
659389
+ await ensureLiveInventory(manager);
659390
+ const tokens = parts.slice(1);
659391
+ const rawResolution = tokens.pop();
659392
+ if (!rawResolution) {
659393
+ renderWarning("Usage: /live resolution [camera] 720p|1080p|1440p|4k|native");
659394
+ return;
659395
+ }
659396
+ const device = tokens.join(" ") || manager.getConfig().selectedCamera;
659397
+ if (!device) {
659398
+ renderWarning("No camera selected. Use /live camera <device> first.");
659399
+ return;
659400
+ }
659401
+ try {
659402
+ const resolution = normalizeLiveCameraResolution(rawResolution);
659403
+ manager.setCameraStreamResolution(device, resolution);
659404
+ renderInfo(`Camera ${device} stream resolution set to ${formatLiveCameraResolution(resolution)}.`);
659405
+ } catch (err) {
659406
+ renderWarning(err instanceof Error ? err.message : String(err));
659407
+ }
659408
+ return;
659409
+ }
659410
+ if (sub2 === "camera-on" || sub2 === "camera-off" || sub2 === "camera-enable" || sub2 === "camera-disable") {
659411
+ await ensureLiveInventory(manager);
659412
+ const device = value2 || manager.getConfig().selectedCamera;
659413
+ if (!device) {
659414
+ renderWarning("No camera selected. Use /live camera <device> first.");
659415
+ return;
659416
+ }
659417
+ const enabled2 = sub2 === "camera-on" || sub2 === "camera-enable";
659418
+ manager.setCameraStreamEnabled(device, enabled2);
659419
+ renderInfo(`${enabled2 ? "Enabled" : "Disabled"} camera stream ${device}.`);
659420
+ return;
659421
+ }
658748
659422
  if (sub2 === "video") {
658749
659423
  const cfg = manager.getConfig();
658750
659424
  manager.configure({ videoEnabled: setBool(value2, !cfg.videoEnabled) });
@@ -658870,6 +659544,11 @@ async function showLiveMenu(ctx3, manager) {
658870
659544
  label: "Select Camera",
658871
659545
  detail: `${devices.video.length} device(s)`
658872
659546
  },
659547
+ ...devices.video.map((device, index) => ({
659548
+ key: `camera-device:${index}`,
659549
+ label: `Camera: ${device.id}`,
659550
+ detail: `${liveCameraStreamSummary(manager, device.id)} — ${device.label}${device.detail ? ` — ${device.detail}` : ""}`
659551
+ })),
658873
659552
  {
658874
659553
  key: "preview-camera",
658875
659554
  label: "View Selected Camera",
@@ -658964,6 +659643,12 @@ async function showLiveMenu(ctx3, manager) {
658964
659643
  }
658965
659644
  });
658966
659645
  if (!result.confirmed || !result.key) return;
659646
+ if (result.key.startsWith("camera-device:")) {
659647
+ const index = Number(result.key.slice("camera-device:".length));
659648
+ const device = devices.video[index];
659649
+ if (device) await showLiveCameraMenu(ctx3, manager, device);
659650
+ continue;
659651
+ }
658967
659652
  switch (result.key) {
658968
659653
  case "toggle-video":
658969
659654
  manager.configure({ videoEnabled: !cfg.videoEnabled });
@@ -663817,15 +664502,15 @@ function refreshLocalGpuMetricsIfStale() {
663817
664502
  });
663818
664503
  }
663819
664504
  function getLocalSystemMetrics() {
663820
- const cpus6 = nodeOs.cpus();
664505
+ const cpus7 = nodeOs.cpus();
663821
664506
  const loads = nodeOs.loadavg();
663822
664507
  const totalMem = nodeOs.totalmem();
663823
664508
  const freeMem = nodeOs.freemem();
663824
664509
  const usedMem = totalMem - freeMem;
663825
664510
  const result = {
663826
- cpuModel: cpus6[0]?.model?.trim() ?? "unknown",
663827
- cpuCores: cpus6.length,
663828
- cpuUtil: Math.min(100, Math.round(loads[0] / cpus6.length * 100)),
664511
+ cpuModel: cpus7[0]?.model?.trim() ?? "unknown",
664512
+ cpuCores: cpus7.length,
664513
+ cpuUtil: Math.min(100, Math.round(loads[0] / cpus7.length * 100)),
663829
664514
  memTotalGB: Math.round(totalMem / (1024 * 1024 * 1024) * 10) / 10,
663830
664515
  memUsedGB: Math.round(usedMem / (1024 * 1024 * 1024) * 10) / 10,
663831
664516
  memUtil: Math.round(usedMem / totalMem * 100),
@@ -665690,7 +666375,7 @@ import {
665690
666375
  writeFileSync as writeFileSync74,
665691
666376
  renameSync as renameSync13,
665692
666377
  mkdirSync as mkdirSync86,
665693
- unlinkSync as unlinkSync29,
666378
+ unlinkSync as unlinkSync30,
665694
666379
  appendFileSync as appendFileSync16
665695
666380
  } from "node:fs";
665696
666381
  import { join as join156, resolve as resolve64 } from "node:path";
@@ -665729,7 +666414,7 @@ function persistInFlight(j) {
665729
666414
  function deleteInFlightFile(id2) {
665730
666415
  try {
665731
666416
  const p2 = inFlightPath(id2);
665732
- if (existsSync143(p2)) unlinkSync29(p2);
666417
+ if (existsSync143(p2)) unlinkSync30(p2);
665733
666418
  } catch {
665734
666419
  }
665735
666420
  }
@@ -666115,7 +666800,7 @@ function drainCheckins(sessionId) {
666115
666800
  try {
666116
666801
  const raw = readFileSync116(fp, "utf-8");
666117
666802
  try {
666118
- unlinkSync29(fp);
666803
+ unlinkSync30(fp);
666119
666804
  } catch {
666120
666805
  }
666121
666806
  if (!raw.trim()) return [];
@@ -666163,7 +666848,7 @@ function deleteSession2(id2) {
666163
666848
  try {
666164
666849
  const p2 = sessionPath(id2);
666165
666850
  if (existsSync143(p2)) {
666166
- unlinkSync29(p2);
666851
+ unlinkSync30(p2);
666167
666852
  removed = true;
666168
666853
  }
666169
666854
  } catch {
@@ -671795,7 +672480,7 @@ var init_bless_engine = __esm({
671795
672480
  });
671796
672481
 
671797
672482
  // packages/cli/src/tui/dmn-engine.ts
671798
- import { existsSync as existsSync150, readFileSync as readFileSync122, writeFileSync as writeFileSync79, mkdirSync as mkdirSync92, readdirSync as readdirSync53, unlinkSync as unlinkSync30 } from "node:fs";
672483
+ import { existsSync as existsSync150, readFileSync as readFileSync122, writeFileSync as writeFileSync79, mkdirSync as mkdirSync92, readdirSync as readdirSync53, unlinkSync as unlinkSync31 } from "node:fs";
671799
672484
  import { join as join163, basename as basename36 } from "node:path";
671800
672485
  import { exec as exec6 } from "node:child_process";
671801
672486
  import { promisify as promisify8 } from "node:util";
@@ -672732,7 +673417,7 @@ If decision is GO, selectedTask MUST be a fully-populated object (NEVER null)
672732
673417
  for (const file of files) {
672733
673418
  if (!keep.has(file)) {
672734
673419
  try {
672735
- unlinkSync30(join163(this.historyDir, file));
673420
+ unlinkSync31(join163(this.historyDir, file));
672736
673421
  } catch {
672737
673422
  }
672738
673423
  }
@@ -672810,7 +673495,7 @@ function appraiseEvent(event) {
672810
673495
  return null;
672811
673496
  }
672812
673497
  }
672813
- function clamp9(value2, min, max) {
673498
+ function clamp10(value2, min, max) {
672814
673499
  return Math.max(min, Math.min(max, value2));
672815
673500
  }
672816
673501
  var BASELINE_VALENCE, BASELINE_AROUSAL, DECAY_HALF_LIFE_MS, LABEL_UPDATE_INTERVAL_MS, DISTRESS_THRESHOLD, REFLECTION_COOLDOWN_MS, REFLECTION_MIN_EVENTS, LABEL_REGEN_THRESHOLD, EmotionEngine;
@@ -672949,8 +673634,8 @@ var init_emotion_engine = __esm({
672949
673634
  if (this.consecutiveFailures >= 2) {
672950
673635
  momentum = 1 + (this.consecutiveFailures - 1) * 0.25;
672951
673636
  }
672952
- this.state.valence = clamp9(this.state.valence + delta.valence * momentum, -1, 1);
672953
- this.state.arousal = clamp9(this.state.arousal + delta.arousal * momentum, 0, 1);
673637
+ this.state.valence = clamp10(this.state.valence + delta.valence * momentum, -1, 1);
673638
+ this.state.arousal = clamp10(this.state.arousal + delta.arousal * momentum, 0, 1);
672954
673639
  this.state.updatedAt = Date.now();
672955
673640
  const deterministicLabel = labelFromCoordinates(this.state.valence, this.state.arousal);
672956
673641
  this.state.label = deterministicLabel.label;
@@ -673216,6 +673901,147 @@ var init_emotion_engine = __esm({
673216
673901
  }
673217
673902
  });
673218
673903
 
673904
+ // packages/cli/src/tui/conversation-context.ts
673905
+ import { statfsSync as statfsSync8 } from "node:fs";
673906
+ function buildConversationRuntimeContext(now2 = /* @__PURE__ */ new Date(), repoRoot) {
673907
+ const date = new Intl.DateTimeFormat("en-US", {
673908
+ weekday: "long",
673909
+ year: "numeric",
673910
+ month: "long",
673911
+ day: "numeric"
673912
+ }).format(now2);
673913
+ const time = new Intl.DateTimeFormat("en-US", {
673914
+ hour: "numeric",
673915
+ minute: "2-digit",
673916
+ second: "2-digit",
673917
+ timeZoneName: "short"
673918
+ }).format(now2);
673919
+ const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || process.env["TZ"] || "system";
673920
+ let diskLine = "";
673921
+ if (repoRoot) {
673922
+ try {
673923
+ const stats = statfsSync8(repoRoot);
673924
+ const totalBytes = Number(stats.blocks) * Number(stats.bsize);
673925
+ const freeBytes = Number(stats.bavail) * Number(stats.bsize);
673926
+ const usedBytes = totalBytes - freeBytes;
673927
+ const totalGB = Math.round(totalBytes / 1024 ** 3);
673928
+ const freeGB = Math.round(freeBytes / 1024 ** 3);
673929
+ const usedGB = Math.round(usedBytes / 1024 ** 3);
673930
+ const usedPct = totalBytes > 0 ? Math.round(usedBytes / totalBytes * 100) : 0;
673931
+ diskLine = `Disk: disk_available_gb=${freeGB} disk_used_gb=${usedGB} disk_total_gb=${totalGB} disk_used_pct=${usedPct} path=${repoRoot}`;
673932
+ } catch {
673933
+ }
673934
+ }
673935
+ return [
673936
+ `Current date: ${date}`,
673937
+ `Current time: ${time}`,
673938
+ `Current ISO timestamp: ${now2.toISOString()}`,
673939
+ `Timezone: ${timezone}`,
673940
+ repoRoot ? `Working directory: ${repoRoot}` : "",
673941
+ diskLine
673942
+ ].filter(Boolean).join("\n");
673943
+ }
673944
+ function quoteConversationBlock(value2, maxChars = 2400) {
673945
+ const text2 = String(value2 ?? "").replace(/\r\n/g, "\n").trim();
673946
+ if (!text2) return "> (empty)";
673947
+ const clipped = text2.length > maxChars ? `${text2.slice(0, Math.max(0, maxChars - 1))}...` : text2;
673948
+ return clipped.split("\n").map((line) => `> ${line}`).join("\n");
673949
+ }
673950
+ function buildScopedConversationMessages(turns, options2) {
673951
+ const pinned = [];
673952
+ const dynamic = [];
673953
+ let latestContextFrame = null;
673954
+ for (const turn of turns) {
673955
+ if (options2.isPinnedSystemTurn(turn) && !pinned.some((p2) => p2.content === turn.content)) {
673956
+ pinned.push(turn);
673957
+ } else if (options2.isContextFrameTurn?.(turn)) {
673958
+ latestContextFrame = turn;
673959
+ } else {
673960
+ dynamic.push(turn);
673961
+ }
673962
+ }
673963
+ if (latestContextFrame) {
673964
+ if (options2.placeContextFrameBeforeLastUser !== false) {
673965
+ let lastUserIdx = -1;
673966
+ for (let i2 = dynamic.length - 1; i2 >= 0; i2--) {
673967
+ if (dynamic[i2].role === "user") {
673968
+ lastUserIdx = i2;
673969
+ break;
673970
+ }
673971
+ }
673972
+ if (lastUserIdx >= 0) dynamic.splice(lastUserIdx, 0, latestContextFrame);
673973
+ else dynamic.push(latestContextFrame);
673974
+ } else {
673975
+ dynamic.push(latestContextFrame);
673976
+ }
673977
+ }
673978
+ const available = Math.max(0, options2.maxMessages - pinned.length);
673979
+ let windowed = dynamic.slice(-available);
673980
+ if (latestContextFrame && available > 0 && !windowed.includes(latestContextFrame)) {
673981
+ windowed = [latestContextFrame, ...windowed.slice(-(available - 1))];
673982
+ }
673983
+ return [...pinned, ...windowed];
673984
+ }
673985
+ function buildVoiceSessionContext(args) {
673986
+ const maxTranscriptTurns = Math.max(1, args.maxTranscriptTurns ?? 8);
673987
+ const voiceLines = (args.voiceTranscript ?? []).slice(-maxTranscriptTurns).map((turn) => `${formatClock(turn.ts)} ${turn.role}: ${singleLine(turn.content, 360)}`);
673988
+ const relayLines = (args.relayTranscript ?? []).slice(-maxTranscriptTurns).map((turn) => {
673989
+ const dir = turn.dir === "toMain" ? "voice->main" : "main->voice";
673990
+ return `${formatClock(turn.ts)} ${dir}: ${singleLine(turn.content, 360)}`;
673991
+ });
673992
+ const taskLine = args.activeTask ? `active=${args.activeTask.active ? "yes" : "no"} tool_calls=${args.activeTask.toolCalls ?? 0} files_touched=${args.activeTask.filesTouched ?? 0}` : "active=unknown";
673993
+ const sections = [
673994
+ `## Runtime Context
673995
+
673996
+ ${buildConversationRuntimeContext(/* @__PURE__ */ new Date(), args.repoRoot)}`,
673997
+ [
673998
+ "## Voice/Live Session Contract",
673999
+ "",
674000
+ `surface=voicechat session_id=${args.sessionId} turn=${args.turnCount}`,
674001
+ `main_agent_task=${taskLine}`,
674002
+ "Latest user utterance remains the active request. Earlier ASR transcript turns are conversational history, not new instructions.",
674003
+ "ASR text can be noisy. Prefer consensus-filtered final turns, resolve pronouns from recent context, and ask for clarification rather than filling gaps.",
674004
+ "Live perception is evidence for the current reply, not a topic to narrate unless the user asks about it."
674005
+ ].join("\n")
674006
+ ];
674007
+ if (voiceLines.length > 0) {
674008
+ sections.push(`## Recent Voice Conversation
674009
+
674010
+ ${quoteConversationBlock(voiceLines.join("\n"))}`);
674011
+ }
674012
+ if (relayLines.length > 0) {
674013
+ sections.push(`## Main Agent Relay Stream
674014
+
674015
+ ${quoteConversationBlock(relayLines.join("\n"))}`);
674016
+ }
674017
+ if (args.liveContext?.trim()) {
674018
+ sections.push(`## Live Context Frame
674019
+
674020
+ ${args.liveContext.trim()}`);
674021
+ }
674022
+ return sections.join("\n\n");
674023
+ }
674024
+ function singleLine(value2, maxChars) {
674025
+ const clean5 = value2.replace(/\s+/g, " ").trim();
674026
+ return clean5.length > maxChars ? `${clean5.slice(0, Math.max(0, maxChars - 1))}...` : clean5;
674027
+ }
674028
+ function formatClock(ts) {
674029
+ try {
674030
+ return new Date(ts).toLocaleTimeString("en-US", {
674031
+ hour: "2-digit",
674032
+ minute: "2-digit",
674033
+ second: "2-digit"
674034
+ });
674035
+ } catch {
674036
+ return "unknown-time";
674037
+ }
674038
+ }
674039
+ var init_conversation_context = __esm({
674040
+ "packages/cli/src/tui/conversation-context.ts"() {
674041
+ "use strict";
674042
+ }
674043
+ });
674044
+
673219
674045
  // packages/cli/src/tui/telegram-format.ts
673220
674046
  function escapeHtml2(text2) {
673221
674047
  return String(text2 ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -674394,7 +675220,7 @@ import {
674394
675220
  mkdirSync as mkdirSync93,
674395
675221
  readFileSync as readFileSync123,
674396
675222
  statSync as statSync55,
674397
- unlinkSync as unlinkSync31,
675223
+ unlinkSync as unlinkSync32,
674398
675224
  writeFileSync as writeFileSync80
674399
675225
  } from "node:fs";
674400
675226
  import { mkdir as mkdir22 } from "node:fs/promises";
@@ -674647,7 +675473,7 @@ function scopedTool(base3, root, mode) {
674647
675473
  }
674648
675474
  } else if (restoredEditPath) {
674649
675475
  try {
674650
- unlinkSync31(restoredEditPath);
675476
+ unlinkSync32(restoredEditPath);
674651
675477
  } catch {
674652
675478
  }
674653
675479
  }
@@ -674792,7 +675618,7 @@ function rememberCreated(root, absPath) {
674792
675618
  const previousPath = resolve66(root, previous.storedRel);
674793
675619
  if (isInside(resolve66(root), previousPath) && existsSync151(previousPath)) {
674794
675620
  try {
674795
- unlinkSync31(previousPath);
675621
+ unlinkSync32(previousPath);
674796
675622
  } catch {
674797
675623
  }
674798
675624
  }
@@ -674812,7 +675638,7 @@ function rememberCreated(root, absPath) {
674812
675638
  const storedAbs = join164(root, storedRel);
674813
675639
  writeFileSync80(storedAbs, Buffer.concat([prefix, encrypted]));
674814
675640
  try {
674815
- unlinkSync31(guarded.path.abs);
675641
+ unlinkSync32(guarded.path.abs);
674816
675642
  } catch {
674817
675643
  }
674818
675644
  manifest.objects = manifest.objects || {};
@@ -674890,7 +675716,7 @@ function materializeTelegramCreativeArtifactForSend(root, rawPath) {
674890
675716
  path: staged,
674891
675717
  cleanup: () => {
674892
675718
  try {
674893
- unlinkSync31(staged);
675719
+ unlinkSync32(staged);
674894
675720
  } catch {
674895
675721
  }
674896
675722
  }
@@ -675827,7 +676653,7 @@ import {
675827
676653
  readdirSync as readdirSync54,
675828
676654
  readFileSync as readFileSync124,
675829
676655
  writeFileSync as writeFileSync81,
675830
- unlinkSync as unlinkSync32
676656
+ unlinkSync as unlinkSync33
675831
676657
  } from "node:fs";
675832
676658
  import { join as join165 } from "node:path";
675833
676659
  import { createHash as createHash39 } from "node:crypto";
@@ -676565,7 +677391,7 @@ function pruneTelegramChannelDaydreams(repoRoot, sessionKey, keep = DAYDREAM_ART
676565
677391
  let removed = 0;
676566
677392
  for (const file of toRemove) {
676567
677393
  try {
676568
- unlinkSync32(join165(dir, file));
677394
+ unlinkSync33(join165(dir, file));
676569
677395
  removed++;
676570
677396
  } catch {
676571
677397
  }
@@ -678332,7 +679158,7 @@ __export(vision_ingress_exports, {
678332
679158
  resolveVisionModel: () => resolveVisionModel,
678333
679159
  runVisionIngress: () => runVisionIngress
678334
679160
  });
678335
- import { existsSync as existsSync153, readFileSync as readFileSync125, unlinkSync as unlinkSync33 } from "node:fs";
679161
+ import { existsSync as existsSync153, readFileSync as readFileSync125, unlinkSync as unlinkSync34 } from "node:fs";
678336
679162
  import { join as join166 } from "node:path";
678337
679163
  async function isTesseractAvailable() {
678338
679164
  try {
@@ -678390,7 +679216,7 @@ async function advancedOcr(imagePath) {
678390
679216
  const text2 = readFileSync125(txtFile, "utf-8").trim();
678391
679217
  if (text2.length > 0) results.push(text2);
678392
679218
  try {
678393
- unlinkSync33(txtFile);
679219
+ unlinkSync34(txtFile);
678394
679220
  } catch {
678395
679221
  }
678396
679222
  }
@@ -678569,10 +679395,9 @@ var init_vision_ingress = __esm({
678569
679395
  import {
678570
679396
  mkdirSync as mkdirSync95,
678571
679397
  existsSync as existsSync154,
678572
- unlinkSync as unlinkSync34,
679398
+ unlinkSync as unlinkSync35,
678573
679399
  readdirSync as readdirSync55,
678574
679400
  statSync as statSync56,
678575
- statfsSync as statfsSync8,
678576
679401
  readFileSync as readFileSync126,
678577
679402
  writeFileSync as writeFileSync82,
678578
679403
  appendFileSync as appendFileSync18
@@ -679829,42 +680654,7 @@ function telegramMemoryTags(text2, mediaSummary) {
679829
680654
  return tokens.filter((token) => !/^\d+$/.test(token)).slice(0, 10);
679830
680655
  }
679831
680656
  function buildTelegramRuntimeContext(now2 = /* @__PURE__ */ new Date(), repoRoot) {
679832
- const date = new Intl.DateTimeFormat("en-US", {
679833
- weekday: "long",
679834
- year: "numeric",
679835
- month: "long",
679836
- day: "numeric"
679837
- }).format(now2);
679838
- const time = new Intl.DateTimeFormat("en-US", {
679839
- hour: "numeric",
679840
- minute: "2-digit",
679841
- second: "2-digit",
679842
- timeZoneName: "short"
679843
- }).format(now2);
679844
- const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || process.env["TZ"] || "system";
679845
- let diskLine = "";
679846
- if (repoRoot) {
679847
- try {
679848
- const stats = statfsSync8(repoRoot);
679849
- const totalBytes = stats.blocks * stats.bsize;
679850
- const freeBytes = stats.bavail * stats.bsize;
679851
- const usedBytes = totalBytes - freeBytes;
679852
- const totalGB = Math.round(totalBytes / 1024 ** 3);
679853
- const freeGB = Math.round(freeBytes / 1024 ** 3);
679854
- const usedGB = Math.round(usedBytes / 1024 ** 3);
679855
- const usedPct = totalBytes > 0 ? Math.round(usedBytes / totalBytes * 100) : 0;
679856
- diskLine = `Disk: disk_available_gb=${freeGB} disk_used_gb=${usedGB} disk_total_gb=${totalGB} disk_used_pct=${usedPct} path=${repoRoot}`;
679857
- } catch {
679858
- }
679859
- }
679860
- return [
679861
- `Current date: ${date}`,
679862
- `Current time: ${time}`,
679863
- `Current ISO timestamp: ${now2.toISOString()}`,
679864
- `Timezone: ${timezone}`,
679865
- repoRoot ? `Working directory: ${repoRoot}` : "",
679866
- diskLine
679867
- ].filter(Boolean).join("\n");
680657
+ return buildConversationRuntimeContext(now2, repoRoot);
679868
680658
  }
679869
680659
  function telegramSessionIdFromKey(sessionKey) {
679870
680660
  return `telegram-${createHash42("sha1").update(sessionKey).digest("hex").slice(0, 16)}`;
@@ -681026,6 +681816,7 @@ var TELEGRAM_TOOL_ACTION_GROUPS, TELEGRAM_TOOL_ACTION_GROUP, TELEGRAM_TOOL_MUTAT
681026
681816
  var init_telegram_bridge = __esm({
681027
681817
  "packages/cli/src/tui/telegram-bridge.ts"() {
681028
681818
  "use strict";
681819
+ init_conversation_context();
681029
681820
  init_telegram_format();
681030
681821
  init_async_process();
681031
681822
  init_dist8();
@@ -689657,7 +690448,7 @@ ${TELEGRAM_PUBLIC_ORCHESTRATOR_CONTRACT}`
689657
690448
  if (prior.pid !== process.pid) return;
689658
690449
  } catch {
689659
690450
  }
689660
- unlinkSync34(lockFile);
690451
+ unlinkSync35(lockFile);
689661
690452
  } catch {
689662
690453
  }
689663
690454
  }
@@ -696213,7 +697004,7 @@ ${text2}`.trim()
696213
697004
  for (const [key, entry] of this.mediaCache) {
696214
697005
  if (now2 - entry.cachedAt > MEDIA_CACHE_TTL_MS) {
696215
697006
  try {
696216
- unlinkSync34(entry.localPath);
697007
+ unlinkSync35(entry.localPath);
696217
697008
  } catch {
696218
697009
  }
696219
697010
  this.mediaCache.delete(key);
@@ -697648,43 +698439,22 @@ function isContextSnapshotTurn(turn) {
697648
698439
  return turn.role === "system" && turn.content.startsWith(CONTEXT_SNAPSHOT_PREFIX);
697649
698440
  }
697650
698441
  function isPinnedSystemTurn(turn) {
697651
- return turn.role === "system" && (turn.content === SYSTEM_PROMPT2 || turn.content.startsWith("Available tools (emit one-line JSON:"));
698442
+ return turn.role === "system" && (turn.content === SYSTEM_PROMPT2 || turn.content.startsWith("Available tools."));
697652
698443
  }
697653
698444
  function buildRealtimeVoiceMessages(turns, maxMessages = MAX_REALTIME_MODEL_MESSAGES) {
697654
- const pinned = [];
697655
- const dynamic = [];
697656
- let latestSnapshot = null;
697657
- for (const turn of turns) {
697658
- if (isPinnedSystemTurn(turn) && !pinned.some((p2) => p2.content === turn.content)) {
697659
- pinned.push(turn);
697660
- } else if (isContextSnapshotTurn(turn)) {
697661
- latestSnapshot = turn;
697662
- } else {
697663
- dynamic.push(turn);
697664
- }
697665
- }
697666
- if (latestSnapshot) {
697667
- let lastUserIdx = -1;
697668
- for (let i2 = dynamic.length - 1; i2 >= 0; i2--) {
697669
- if (dynamic[i2].role === "user") {
697670
- lastUserIdx = i2;
697671
- break;
697672
- }
697673
- }
697674
- if (lastUserIdx >= 0) dynamic.splice(lastUserIdx, 0, latestSnapshot);
697675
- else dynamic.push(latestSnapshot);
697676
- }
697677
- const available = Math.max(0, maxMessages - pinned.length);
697678
- let windowed = dynamic.slice(-available);
697679
- if (latestSnapshot && available > 0 && !windowed.includes(latestSnapshot)) {
697680
- windowed = [latestSnapshot, ...windowed.slice(-(available - 1))];
697681
- }
697682
- return [...pinned, ...windowed];
698445
+ return buildScopedConversationMessages(turns, {
698446
+ maxMessages,
698447
+ isPinnedSystemTurn,
698448
+ isContextFrameTurn: isContextSnapshotTurn,
698449
+ placeContextFrameBeforeLastUser: true
698450
+ });
697683
698451
  }
697684
698452
  var VAD_SILENCE_MS, MAX_SEGMENT_MS, SUMMARY_INJECTION_INTERVAL, MAX_CONTEXT_TURNS, MAX_REALTIME_MODEL_MESSAGES, CONTEXT_SNAPSHOT_PREFIX, CONTEXT_SNAPSHOT_SCOPE, MAX_VOICE_REPLY_CHARS, AGENT_ECHO_WINDOW_MS, AGENT_ECHO_SIMILARITY, SYSTEM_PROMPT2, MIN_SIGNAL_SCORE, NOISE_ONLY_RE, VoiceChatSession;
697685
698453
  var init_voicechat = __esm({
697686
698454
  "packages/cli/src/tui/voicechat.ts"() {
697687
698455
  "use strict";
698456
+ init_conversation_context();
698457
+ init_live_resource_arbiter();
697688
698458
  VAD_SILENCE_MS = 3e3;
697689
698459
  MAX_SEGMENT_MS = 6500;
697690
698460
  SUMMARY_INJECTION_INTERVAL = 4;
@@ -697699,6 +698469,7 @@ var init_voicechat = __esm({
697699
698469
 
697700
698470
  Rules:
697701
698471
  - ALWAYS answer the user's most recent message directly. The live context snapshot is background perception — never the topic. Do not describe cameras, feeds, or surroundings unless the user's latest message asks about them.
698472
+ - Treat this as one continuous conversation thread. Resolve pronouns from recent voice turns and main-agent relay context, but let the latest user utterance override earlier transcript noise.
697702
698473
  - Never repeat your previous answer. If you already described the scene, don't describe it again unless explicitly asked again — respond to what the user just said.
697703
698474
  - Live perception: each turn you may receive a read-only "[ACTIVE CONTEXT FRAME]" system message containing what the camera currently sees (objects, people, classifications, recent visual events) and what is currently heard (sound scene, recent sounds, transcripts). Treat it as your own live sight and hearing. When the user asks what you SEE, answer from the camera fields; when the user asks what you HEAR, answer from the audio/sound fields. If the snapshot is missing or stale, say you can't see/hear clearly right now — do not invent observations.
697704
698475
  - Never invent environment facts (cwd, OS, specs, repo state). If you need a precise fact from the main agent, request a tool by outputting on a single line EXACTLY one JSON object: {"tool": string, "args": object} and nothing else. Then wait for the tool result before answering.
@@ -697739,6 +698510,7 @@ Rules:
697739
698510
  lastSignalScore = null;
697740
698511
  listenPausedForResponse = false;
697741
698512
  lastAgentSpeech = null;
698513
+ liveResourceLease = null;
697742
698514
  // Abort control for inference
697743
698515
  abortController = null;
697744
698516
  // Callbacks
@@ -697790,9 +698562,45 @@ Rules:
697790
698562
  if (this._state === next) return;
697791
698563
  const prev = this._state;
697792
698564
  this._state = next;
698565
+ this.updateLiveResourceLease(next);
697793
698566
  this.onStateChange(next);
697794
698567
  this.emit("stateChange", { from: prev, to: next });
697795
698568
  }
698569
+ updateLiveResourceLease(state) {
698570
+ if (state === "CAPTURING") {
698571
+ this.holdLiveResources("asr-capture", 92, 1e4, "voicechat ASR capture");
698572
+ return;
698573
+ }
698574
+ if (state === "TRANSCRIBING") {
698575
+ this.holdLiveResources("asr-final", 94, 18e3, "voicechat final ASR/transcript handoff");
698576
+ return;
698577
+ }
698578
+ if (state === "THINKING") {
698579
+ this.holdLiveResources("voice-llm", 100, 6e4, "voicechat live LLM inference");
698580
+ return;
698581
+ }
698582
+ if (state === "SPEAKING") {
698583
+ this.holdLiveResources("tts", 84, 24e3, "voicechat TTS playback/echo guard");
698584
+ return;
698585
+ }
698586
+ if (state === "IDLE" || state === "LISTENING") {
698587
+ this.releaseLiveResources();
698588
+ }
698589
+ }
698590
+ holdLiveResources(owner, priority, ttlMs, reason) {
698591
+ this.liveResourceLease?.release();
698592
+ this.liveResourceLease = getLiveResourceArbiter().claim({
698593
+ owner: `voicechat:${owner}`,
698594
+ priority,
698595
+ ttlMs,
698596
+ reason,
698597
+ suppress: ["vision"]
698598
+ });
698599
+ }
698600
+ releaseLiveResources() {
698601
+ this.liveResourceLease?.release();
698602
+ this.liveResourceLease = null;
698603
+ }
697796
698604
  // ---------------------------------------------------------------------------
697797
698605
  // Start / Stop
697798
698606
  // ---------------------------------------------------------------------------
@@ -697902,6 +698710,7 @@ Rules:
697902
698710
  await this.listen.stop();
697903
698711
  } catch {
697904
698712
  }
698713
+ this.releaseLiveResources();
697905
698714
  this.setState("IDLE");
697906
698715
  if (this.verbose) this.onStatus("VoiceChat ended");
697907
698716
  this.emit("stopped");
@@ -697920,6 +698729,12 @@ Rules:
697920
698729
  this.emit("voiceEchoFiltered", echo);
697921
698730
  return;
697922
698731
  }
698732
+ this.holdLiveResources(
698733
+ isFinal ? "asr-final" : "asr-capture",
698734
+ isFinal ? 94 : 92,
698735
+ isFinal ? 18e3 : 1e4,
698736
+ isFinal ? "voicechat final ASR incoming" : "voicechat partial ASR incoming"
698737
+ );
697923
698738
  if (this._state === "LISTENING") {
697924
698739
  this.setState("CAPTURING");
697925
698740
  this.resetCaptureState();
@@ -698022,13 +698837,19 @@ Rules:
698022
698837
  const snap = await Promise.resolve(this.toolRelay.contextSnapshot());
698023
698838
  if (snap && snap.trim()) {
698024
698839
  this.dropTransientSystemTurns();
698840
+ const contextFrame = buildVoiceSessionContext({
698841
+ sessionId: "voicechat",
698842
+ turnCount: this.turnCount,
698843
+ voiceTranscript: this.voiceTranscript,
698844
+ relayTranscript: this.relayTranscript,
698845
+ liveContext: `${CONTEXT_SNAPSHOT_SCOPE}
698846
+
698847
+ ${snap.trim()}`
698848
+ });
698025
698849
  this.context.push({
698026
698850
  role: "system",
698027
698851
  content: `${CONTEXT_SNAPSHOT_PREFIX}
698028
- turn: ${this.turnCount}
698029
- ${CONTEXT_SNAPSHOT_SCOPE}
698030
-
698031
- ${snap.trim()}`
698852
+ ${contextFrame}`
698032
698853
  });
698033
698854
  this.trimContext();
698034
698855
  }
@@ -699834,7 +700655,7 @@ var init_access_policy = __esm({
699834
700655
 
699835
700656
  // packages/cli/src/api/project-preferences.ts
699836
700657
  import { createHash as createHash43 } from "node:crypto";
699837
- import { existsSync as existsSync156, mkdirSync as mkdirSync97, readFileSync as readFileSync128, renameSync as renameSync15, writeFileSync as writeFileSync84, unlinkSync as unlinkSync35 } from "node:fs";
700658
+ import { existsSync as existsSync156, mkdirSync as mkdirSync97, readFileSync as readFileSync128, renameSync as renameSync15, writeFileSync as writeFileSync84, unlinkSync as unlinkSync36 } from "node:fs";
699838
700659
  import { homedir as homedir57 } from "node:os";
699839
700660
  import { join as join169, resolve as resolve69 } from "node:path";
699840
700661
  import { randomUUID as randomUUID20 } from "node:crypto";
@@ -699895,7 +700716,7 @@ function writeProjectPreferences(root, partial) {
699895
700716
  } catch {
699896
700717
  }
699897
700718
  try {
699898
- unlinkSync35(tmp);
700719
+ unlinkSync36(tmp);
699899
700720
  } catch {
699900
700721
  }
699901
700722
  throw err;
@@ -699906,7 +700727,7 @@ function deleteProjectPreferences(root) {
699906
700727
  try {
699907
700728
  const file = prefsPath(root);
699908
700729
  if (!existsSync156(file)) return false;
699909
- unlinkSync35(file);
700730
+ unlinkSync36(file);
699910
700731
  return true;
699911
700732
  } catch {
699912
700733
  return false;
@@ -718857,7 +719678,7 @@ import {
718857
719678
  existsSync as existsSync168,
718858
719679
  watch as fsWatch4,
718859
719680
  renameSync as renameSync17,
718860
- unlinkSync as unlinkSync36,
719681
+ unlinkSync as unlinkSync37,
718861
719682
  statSync as statSync62,
718862
719683
  openSync as openSync6,
718863
719684
  readSync as readSync2,
@@ -720192,13 +721013,13 @@ function pruneOldJobs() {
720192
721013
  const ts = ageRef ? Date.parse(ageRef) : NaN;
720193
721014
  if (Number.isFinite(ts) && ts < cutoffMs) {
720194
721015
  try {
720195
- unlinkSync36(path12);
721016
+ unlinkSync37(path12);
720196
721017
  } catch {
720197
721018
  }
720198
721019
  const outFile = path12.replace(/\.json$/, ".output");
720199
721020
  if (existsSync168(outFile)) {
720200
721021
  try {
720201
- unlinkSync36(outFile);
721022
+ unlinkSync37(outFile);
720202
721023
  } catch {
720203
721024
  }
720204
721025
  }
@@ -720208,7 +721029,7 @@ function pruneOldJobs() {
720208
721029
  }
720209
721030
  } catch {
720210
721031
  try {
720211
- unlinkSync36(path12);
721032
+ unlinkSync37(path12);
720212
721033
  pruned++;
720213
721034
  } catch {
720214
721035
  }
@@ -720520,7 +721341,7 @@ function atomicJobWrite(dir, id2, job) {
720520
721341
  } catch {
720521
721342
  }
720522
721343
  try {
720523
- unlinkSync36(tmpPath);
721344
+ unlinkSync37(tmpPath);
720524
721345
  } catch {
720525
721346
  }
720526
721347
  }
@@ -724701,7 +725522,7 @@ async function handleRequest(req3, res, ollamaUrl, verbose, runtimeDefaults = {}
724701
725522
  return;
724702
725523
  }
724703
725524
  const { tmpdir: tmpdir26 } = await import("node:os");
724704
- const { writeFileSync: writeFileSync95, unlinkSync: unlinkSync37 } = await import("node:fs");
725525
+ const { writeFileSync: writeFileSync95, unlinkSync: unlinkSync38 } = await import("node:fs");
724705
725526
  const { join: pjoin } = await import("node:path");
724706
725527
  const tmpPath = pjoin(
724707
725528
  tmpdir26(),
@@ -724719,7 +725540,7 @@ async function handleRequest(req3, res, ollamaUrl, verbose, runtimeDefaults = {}
724719
725540
  });
724720
725541
  } finally {
724721
725542
  try {
724722
- unlinkSync37(tmpPath);
725543
+ unlinkSync38(tmpPath);
724723
725544
  } catch {
724724
725545
  }
724725
725546
  }
@@ -727962,8 +728783,8 @@ function startApiServer(options2 = {}) {
727962
728783
  job.startedAt ?? job.completedAt ?? 0
727963
728784
  ).getTime();
727964
728785
  if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
727965
- const { unlinkSync: unlinkSync37 } = require4("node:fs");
727966
- unlinkSync37(jobPath);
728786
+ const { unlinkSync: unlinkSync38 } = require4("node:fs");
728787
+ unlinkSync38(jobPath);
727967
728788
  }
727968
728789
  } catch {
727969
728790
  }
@@ -737112,6 +737933,32 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
737112
737933
  sharedTranscriber: null
737113
737934
  };
737114
737935
  const engine = getListenEngine();
737936
+ const callConsensusRequired = (() => {
737937
+ const env2 = String(process.env["OMNIUS_ASR_CONSENSUS"] ?? "").trim().toLowerCase();
737938
+ return !(env2 === "0" || env2 === "off" || env2 === "false");
737939
+ })();
737940
+ const recentCallFinals = [];
737941
+ const normalizeCallTranscript = (value2) => value2.toLowerCase().replace(/[^\p{L}\p{N}\s']/gu, " ").replace(/\s+/g, " ").trim();
737942
+ const isLikelyCallAsrHallucination = (normalized) => /^(thanks|thank you) for watching(?: this video)?$/.test(normalized) || /^thanks for watching and/.test(normalized) || /\bdon't forget to (like|subscribe)\b/.test(normalized);
737943
+ const shouldDropCallFinalTranscript = (text2, evt) => {
737944
+ if (callConsensusRequired && evt.consensus !== true) {
737945
+ return evt.consensus === false ? "consensus rejected" : "missing consensus metadata";
737946
+ }
737947
+ const normalized = normalizeCallTranscript(text2);
737948
+ if (!normalized) return "empty transcript";
737949
+ if (isLikelyCallAsrHallucination(normalized)) {
737950
+ return "known whisper outro hallucination";
737951
+ }
737952
+ const now2 = Date.now();
737953
+ while (recentCallFinals.length > 0 && now2 - recentCallFinals[0].ts > 15e3) {
737954
+ recentCallFinals.shift();
737955
+ }
737956
+ if (recentCallFinals.some((entry) => entry.normalized === normalized)) {
737957
+ return "duplicate final transcript";
737958
+ }
737959
+ recentCallFinals.push({ normalized, ts: now2 });
737960
+ return null;
737961
+ };
737115
737962
  voiceSession.onUserAudio = (pcmChunk, userId) => {
737116
737963
  if (callState.sharedTranscriber)
737117
737964
  callState.sharedTranscriber.write(pcmChunk);
@@ -737141,11 +737988,21 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
737141
737988
  voiceEngine.synthesizeToPCM(text2).then((result) => {
737142
737989
  if (result && session?.isActive) {
737143
737990
  const { pcm, sampleRate } = result;
737144
- session.sendSpeakingStateToClient(id2, true);
737145
- session.sendAudioToClient(id2, pcm);
737146
737991
  const durationMs = pcm.length / 2 / sampleRate * 1e3;
737992
+ const ttsLease = getLiveResourceArbiter().claim({
737993
+ owner: `call-tts:${id2}`,
737994
+ priority: 84,
737995
+ ttlMs: Math.min(45e3, durationMs + 3e3),
737996
+ reason: "cloud call TTS playback/echo guard",
737997
+ suppress: ["vision"]
737998
+ });
737999
+ session.sendSpeakingStateToClient(id2, true);
738000
+ session.sendAudioToClient(id2, pcm, sampleRate);
737147
738001
  setTimeout(
737148
- () => session.sendSpeakingStateToClient(id2, false),
738002
+ () => {
738003
+ session.sendSpeakingStateToClient(id2, false);
738004
+ ttsLease.release();
738005
+ },
737149
738006
  durationMs
737150
738007
  );
737151
738008
  }
@@ -737177,17 +738034,32 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
737177
738034
  (evt) => {
737178
738035
  if (!evt.text?.trim() || !voiceSession?.isActive) return;
737179
738036
  const text2 = evt.text.trim();
738037
+ if (!evt.isFinal) return;
738038
+ const dropReason = shouldDropCallFinalTranscript(text2, evt);
738039
+ if (dropReason) {
738040
+ writeContent(
738041
+ () => renderInfo(
738042
+ `[call/asr] dropped ${dropReason}: "${text2.slice(0, 80)}"`
738043
+ )
738044
+ );
738045
+ return;
738046
+ }
737180
738047
  writeContent(
737181
738048
  () => renderVoiceSessionTranscript("user", text2)
737182
738049
  );
737183
738050
  voiceSession?.sendTranscript("user", text2);
737184
- if (evt.isFinal) {
737185
- for (const [clientId, agent] of callSubAgents) {
737186
- agent.handleTranscript(text2);
737187
- }
737188
- if (callSubAgents.size === 0) {
737189
- rl.feed(text2 + "\n");
737190
- }
738051
+ getLiveResourceArbiter().claim({
738052
+ owner: "call-asr",
738053
+ priority: 92,
738054
+ ttlMs: 35e3,
738055
+ reason: "cloud call ASR accepted; reserving compute for call-agent inference",
738056
+ suppress: ["vision"]
738057
+ });
738058
+ for (const [clientId, agent] of callSubAgents) {
738059
+ agent.handleTranscript(text2);
738060
+ }
738061
+ if (callSubAgents.size === 0) {
738062
+ rl.feed(text2 + "\n");
737191
738063
  }
737192
738064
  }
737193
738065
  );
@@ -737249,10 +738121,20 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
737249
738121
  const session = voiceSession;
737250
738122
  voiceEngine.onPCMOutput = (pcm, sampleRate) => {
737251
738123
  if (session?.isActive) {
737252
- session.sendSpeakingState(true);
737253
- session.sendAudioToClients(pcm);
737254
738124
  const durationMs = pcm.length / 2 / sampleRate * 1e3;
737255
- setTimeout(() => session.sendSpeakingState(false), durationMs);
738125
+ const ttsLease = getLiveResourceArbiter().claim({
738126
+ owner: "call-broadcast-tts",
738127
+ priority: 84,
738128
+ ttlMs: Math.min(45e3, durationMs + 3e3),
738129
+ reason: "cloud call broadcast TTS playback/echo guard",
738130
+ suppress: ["vision"]
738131
+ });
738132
+ session.sendSpeakingState(true);
738133
+ session.sendAudioToClients(pcm, sampleRate);
738134
+ setTimeout(() => {
738135
+ session.sendSpeakingState(false);
738136
+ ttsLease.release();
738137
+ }, durationMs);
737256
738138
  }
737257
738139
  };
737258
738140
  }
@@ -739849,6 +740731,7 @@ var init_interactive = __esm({
739849
740731
  init_expose();
739850
740732
  init_p2p();
739851
740733
  init_call_agent();
740734
+ init_live_resource_arbiter();
739852
740735
  init_config();
739853
740736
  init_secret_redactor();
739854
740737
  init_profiles();