omnius 1.0.18 → 1.0.20

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
@@ -15546,8 +15546,8 @@ function deleteCustomToolDefinition(name10, scope, repoRoot) {
15546
15546
  const dir = scope === "project" && repoRoot ? projectToolsDir(repoRoot) : globalToolsDir();
15547
15547
  const filePath = join24(dir, `${name10}.json`);
15548
15548
  if (existsSync19(filePath)) {
15549
- const { unlinkSync: unlinkSync25 } = __require("node:fs");
15550
- unlinkSync25(filePath);
15549
+ const { unlinkSync: unlinkSync26 } = __require("node:fs");
15550
+ unlinkSync26(filePath);
15551
15551
  return true;
15552
15552
  }
15553
15553
  return false;
@@ -25254,7 +25254,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
25254
25254
  bits2int_modN: "function"
25255
25255
  });
25256
25256
  ecdsaOpts = Object.assign({}, ecdsaOpts);
25257
- const randomBytes25 = ecdsaOpts.randomBytes || randomBytes7;
25257
+ const randomBytes26 = ecdsaOpts.randomBytes || randomBytes7;
25258
25258
  const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
25259
25259
  const { Fp, Fn } = Point;
25260
25260
  const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
@@ -25396,7 +25396,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
25396
25396
  throw new Error("invalid private key");
25397
25397
  const seedArgs = [int2octets(d2), int2octets(h1int)];
25398
25398
  if (extraEntropy != null && extraEntropy !== false) {
25399
- const e2 = extraEntropy === true ? randomBytes25(lengths.secretKey) : extraEntropy;
25399
+ const e2 = extraEntropy === true ? randomBytes26(lengths.secretKey) : extraEntropy;
25400
25400
  seedArgs.push(abytes(e2, void 0, "extraEntropy"));
25401
25401
  }
25402
25402
  const seed = concatBytes(...seedArgs);
@@ -61906,9 +61906,9 @@ var init_cookies = __esm({
61906
61906
 
61907
61907
  // ../node_modules/@libp2p/http-peer-id-auth/dist/src/utils.js
61908
61908
  function generateChallenge() {
61909
- const randomBytes25 = new Uint8Array(32);
61910
- crypto.getRandomValues(randomBytes25);
61911
- return toString2(randomBytes25, "base64urlpad");
61909
+ const randomBytes26 = new Uint8Array(32);
61910
+ crypto.getRandomValues(randomBytes26);
61911
+ return toString2(randomBytes26, "base64urlpad");
61912
61912
  }
61913
61913
  function encodeAuthParams(params) {
61914
61914
  const encodedParams = Object.entries(params).map(([key, value2]) => `${key}="${value2}"`).join(", ");
@@ -84452,7 +84452,7 @@ var require_mime_types = __commonJS({
84452
84452
  "../node_modules/mime-types/index.js"(exports) {
84453
84453
  "use strict";
84454
84454
  var db = require_mime_db();
84455
- var extname15 = __require("path").extname;
84455
+ var extname16 = __require("path").extname;
84456
84456
  var EXTRACT_TYPE_REGEXP = /^\s*([^;\s]*)(?:;|\s|$)/;
84457
84457
  var TEXT_TYPE_REGEXP = /^text\//i;
84458
84458
  exports.charset = charset;
@@ -84506,7 +84506,7 @@ var require_mime_types = __commonJS({
84506
84506
  if (!path11 || typeof path11 !== "string") {
84507
84507
  return false;
84508
84508
  }
84509
- var extension4 = extname15("x." + path11).toLowerCase().substr(1);
84509
+ var extension4 = extname16("x." + path11).toLowerCase().substr(1);
84510
84510
  if (!extension4) {
84511
84511
  return false;
84512
84512
  }
@@ -234104,7 +234104,7 @@ var require_websocket2 = __commonJS({
234104
234104
  var http6 = __require("http");
234105
234105
  var net5 = __require("net");
234106
234106
  var tls2 = __require("tls");
234107
- var { randomBytes: randomBytes25, createHash: createHash24 } = __require("crypto");
234107
+ var { randomBytes: randomBytes26, createHash: createHash24 } = __require("crypto");
234108
234108
  var { Duplex: Duplex3, Readable } = __require("stream");
234109
234109
  var { URL: URL3 } = __require("url");
234110
234110
  var PerMessageDeflate3 = require_permessage_deflate2();
@@ -234634,7 +234634,7 @@ var require_websocket2 = __commonJS({
234634
234634
  }
234635
234635
  }
234636
234636
  const defaultPort = isSecure ? 443 : 80;
234637
- const key = randomBytes25(16).toString("base64");
234637
+ const key = randomBytes26(16).toString("base64");
234638
234638
  const request = isSecure ? https4.request : http6.request;
234639
234639
  const protocolSet = /* @__PURE__ */ new Set();
234640
234640
  let perMessageDeflate;
@@ -255836,8 +255836,8 @@ var init_browser_action = __esm({
255836
255836
  const afterDom = await apiCall("/dom", "GET");
255837
255837
  const afterTitle = (afterDom.dom || "").match(/<title[^>]*>([^<]*)<\/title>/i)?.[1] || "";
255838
255838
  try {
255839
- const { unlinkSync: unlinkSync25 } = await import("node:fs");
255840
- unlinkSync25(imagePath);
255839
+ const { unlinkSync: unlinkSync26 } = await import("node:fs");
255840
+ unlinkSync26(imagePath);
255841
255841
  } catch {
255842
255842
  }
255843
255843
  return {
@@ -477005,7 +477005,7 @@ var require_path_browserify = __commonJS({
477005
477005
  return path11.slice(start2, end);
477006
477006
  }
477007
477007
  },
477008
- extname: function extname15(path11) {
477008
+ extname: function extname16(path11) {
477009
477009
  assertPath(path11);
477010
477010
  var startDot = -1;
477011
477011
  var startPart = 0;
@@ -507302,12 +507302,23 @@ function ensureGeneratedVoiceDir() {
507302
507302
  mkdirSync16(generatedVoiceDir(), { recursive: true });
507303
507303
  }
507304
507304
  function ttsOutputPath(args, backend) {
507305
- const output = typeof args["output"] === "string" ? args["output"] : typeof args["output_path"] === "string" ? args["output_path"] : "";
507306
- if (output.trim())
507307
- return resolvePath(output.trim());
507305
+ for (const key of ["output", "output_path", "path", "file_path", "file"]) {
507306
+ const output = args[key];
507307
+ if (typeof output === "string" && output.trim()) {
507308
+ return resolvePath(output.trim());
507309
+ }
507310
+ }
507308
507311
  ensureGeneratedVoiceDir();
507309
507312
  return join58(generatedVoiceDir(), `tts-${backend}-${Date.now()}-${Math.random().toString(36).slice(2, 7)}.wav`);
507310
507313
  }
507314
+ function ttsTextArg(args) {
507315
+ for (const key of ["text", "input", "prompt", "content", "message"]) {
507316
+ const value2 = args[key];
507317
+ if (typeof value2 === "string" && value2.trim())
507318
+ return value2.trim();
507319
+ }
507320
+ return "";
507321
+ }
507311
507322
  function listCloneRefs() {
507312
507323
  try {
507313
507324
  return readdirSync14(cloneRefsDir()).filter((file) => /\.(wav|mp3|flac|ogg|m4a)$/i.test(file) && existsSync40(join58(cloneRefsDir(), file))).sort((a2, b) => a2.localeCompare(b));
@@ -507348,6 +507359,12 @@ function supertonicInferScript() {
507348
507359
  function mlxVenvPy() {
507349
507360
  return process.platform === "win32" ? join58(voiceDir(), "mlx-venv", "Scripts", "python.exe") : join58(voiceDir(), "mlx-venv", "bin", "python3");
507350
507361
  }
507362
+ function piperVenvDir() {
507363
+ return join58(voiceDir(), "piper-venv");
507364
+ }
507365
+ function piperVenvBin() {
507366
+ return process.platform === "win32" ? join58(piperVenvDir(), "Scripts", "piper.exe") : join58(piperVenvDir(), "bin", "piper");
507367
+ }
507351
507368
  function ensureSupertonicInstalled() {
507352
507369
  const venvPy = supertonicVenvPy();
507353
507370
  if (!existsSync40(venvPy)) {
@@ -507385,6 +507402,25 @@ function ensureMlxInstalled() {
507385
507402
  }
507386
507403
  return venvPy;
507387
507404
  }
507405
+ function ensurePiperInstalled() {
507406
+ if (hasCommand3("piper"))
507407
+ return "piper";
507408
+ const bin = piperVenvBin();
507409
+ if (!existsSync40(bin)) {
507410
+ const py = findPython32();
507411
+ if (!py)
507412
+ throw new Error("python3 is required to set up Piper TTS.");
507413
+ mkdirSync16(voiceDir(), { recursive: true });
507414
+ execFileSync2(py, ["-m", "venv", piperVenvDir()], { stdio: "pipe", timeout: 18e4 });
507415
+ const venvPy = process.platform === "win32" ? join58(piperVenvDir(), "Scripts", "python.exe") : join58(piperVenvDir(), "bin", "python3");
507416
+ execFileSync2(venvPy, ["-m", "pip", "install", "--quiet", "--upgrade", "pip"], { stdio: "pipe", timeout: 12e4 });
507417
+ execFileSync2(venvPy, ["-m", "pip", "install", "--quiet", "piper-tts"], { stdio: "pipe", timeout: 6e5 });
507418
+ }
507419
+ if (!existsSync40(bin)) {
507420
+ throw new Error("Piper TTS installed but the piper executable was not found in the managed venv.");
507421
+ }
507422
+ return bin;
507423
+ }
507388
507424
  function saveCloneRefFromSample(sample, cloneName) {
507389
507425
  const source = resolvePath(sample);
507390
507426
  if (!existsSync40(source))
@@ -507552,7 +507588,7 @@ except Exception as exc:
507552
507588
  `;
507553
507589
  AudioPlaybackTool = class {
507554
507590
  name = "audio_playback";
507555
- description = "Play audio through speakers, synthesize text-to-speech, and manage TTS clone voices. Actions: 'play' to play an audio file (WAV/MP3/OGG — including recordings from memory episodes), 'speak' to synthesize and play text, 'synthesize' to save TTS to a WAV file, 'clone' to register a voice-clone sample, 'list_voices' to inspect available clone refs/backends, 'volume' to get or set system volume, 'list' to enumerate audio output devices. TTS backends are explicit: auto, luxtts, supertonic, mlx, onnx/piper, or espeak. Use generate_tts when the task is specifically to create a TTS file.";
507591
+ description = "Play audio through speakers, synthesize text-to-speech, and manage TTS clone voices. Actions: 'play' to play an audio file (WAV/MP3/OGG — including recordings from memory episodes), 'speak' to synthesize and play text, 'synthesize' to save TTS to a WAV file, 'clone' to register a voice-clone sample, 'list_voices' to inspect available clone refs/backends, 'volume' to get or set system volume, 'list' to enumerate audio output devices. TTS backends are explicit: auto, luxtts, supertonic, mlx, onnx/piper, or espeak. Neural TTS backends self-provision into ~/.omnius/voice on first use where supported. Use generate_tts when the task is specifically to create a TTS file; do not use shell speech commands or generate_audio for spoken TTS.";
507556
507592
  parameters = {
507557
507593
  type: "object",
507558
507594
  properties: {
@@ -507569,6 +507605,14 @@ except Exception as exc:
507569
507605
  type: "string",
507570
507606
  description: "Text to speak or synthesize"
507571
507607
  },
507608
+ input: {
507609
+ type: "string",
507610
+ description: "Alias for text."
507611
+ },
507612
+ prompt: {
507613
+ type: "string",
507614
+ description: "Alias for text."
507615
+ },
507572
507616
  backend: {
507573
507617
  type: "string",
507574
507618
  enum: ["auto", "luxtts", "supertonic", "mlx", "onnx", "piper", "espeak"],
@@ -507598,6 +507642,10 @@ except Exception as exc:
507598
507642
  type: "string",
507599
507643
  description: "Backend model id or raw ONNX/Piper model path. MLX default is mlx-community/Kokoro-82M-bf16."
507600
507644
  },
507645
+ strict_backend: {
507646
+ type: "boolean",
507647
+ description: "When true, fail instead of falling back if the requested TTS backend is unavailable. Defaults false."
507648
+ },
507601
507649
  volume: {
507602
507650
  type: "number",
507603
507651
  description: "Volume level 0-100 (for 'volume' action to SET volume)"
@@ -507693,7 +507741,7 @@ except Exception as exc:
507693
507741
  ` luxtts: ${existsSync40(join58(voiceDir(), "luxtts-venv", "bin", "python3")) ? "installed" : "not installed"}; clone refs: ${refs.length}`,
507694
507742
  ` supertonic: ${existsSync40(supertonicVenvPy()) ? "installed" : "not installed"}; voices include M1, M2, M3, M4 when package assets are available`,
507695
507743
  ` mlx: ${existsSync40(mlxVenvPy()) ? "installed" : "not installed"}; Apple Silicon only; default model mlx-community/Kokoro-82M-bf16`,
507696
- ` piper/onnx: ${hasCommand3("piper") ? "available" : "not found"}; pass model=<path.onnx> for raw ONNX voices`,
507744
+ ` piper/onnx: ${hasCommand3("piper") || existsSync40(piperVenvBin()) ? "available" : "not installed"}; first use installs piper-tts into ${piperVenvDir()}; pass model=<path.onnx> for raw ONNX voices`,
507697
507745
  ` espeak: ${hasCommand3("espeak-ng") ? "available" : "not found"}`,
507698
507746
  "",
507699
507747
  "Registered clone refs:",
@@ -507702,16 +507750,18 @@ except Exception as exc:
507702
507750
  return { success: true, output: lines.join("\n"), durationMs: performance.now() - start2 };
507703
507751
  }
507704
507752
  async synthesizeText(args, start2, speakDefault) {
507705
- const text = typeof args["text"] === "string" ? args["text"].trim() : "";
507753
+ const text = ttsTextArg(args);
507706
507754
  if (!text) {
507707
507755
  return { success: false, output: "", error: "Missing 'text' parameter. Provide text to synthesize.", durationMs: performance.now() - start2 };
507708
507756
  }
507709
507757
  const requestedBackend = normalizeTtsBackend(args["backend"]);
507758
+ const strictBackend = boolArg(args["strict_backend"] ?? args["strictBackend"], false);
507710
507759
  const playback = playbackArg(args, speakDefault);
507711
507760
  const outputPath2 = ttsOutputPath(args, requestedBackend);
507712
507761
  const device = typeof args["device"] === "string" ? args["device"] : "default";
507713
507762
  const tried = [];
507714
- const candidates = requestedBackend === "auto" ? ["luxtts", "supertonic", ...process.platform === "darwin" && process.arch === "arm64" ? ["mlx"] : [], "piper", "espeak"] : [requestedBackend];
507763
+ const autoCandidates = ["luxtts", "supertonic", ...process.platform === "darwin" && process.arch === "arm64" ? ["mlx"] : [], "piper", "espeak"];
507764
+ const candidates = requestedBackend === "auto" ? autoCandidates : strictBackend ? [requestedBackend] : [requestedBackend, ...autoCandidates.filter((backend) => backend !== requestedBackend)];
507715
507765
  let usedBackend = "";
507716
507766
  let voiceSummary = "";
507717
507767
  for (const backend of candidates) {
@@ -507734,7 +507784,7 @@ except Exception as exc:
507734
507784
  } catch (err) {
507735
507785
  const message2 = err instanceof Error ? err.message : String(err);
507736
507786
  tried.push(`${backend}: ${message2.slice(0, 300)}`);
507737
- if (requestedBackend !== "auto") {
507787
+ if (requestedBackend !== "auto" && strictBackend) {
507738
507788
  return { success: false, output: "", error: `${backend} TTS failed: ${message2}`, durationMs: performance.now() - start2 };
507739
507789
  }
507740
507790
  }
@@ -507754,11 +507804,13 @@ ${tried.map((line) => `- ${line}`).join("\n")}`,
507754
507804
  })() : " Playback: disabled";
507755
507805
  const size = Math.round(statSync18(outputPath2).size / 1024);
507756
507806
  const preview = text.length > 140 ? `${text.slice(0, 137)}...` : text;
507807
+ const fallbackLine = requestedBackend !== "auto" && usedBackend !== requestedBackend ? ` Fallback: requested ${requestedBackend}; ${tried[0] ?? "requested backend unavailable"}` : "";
507757
507808
  return {
507758
507809
  success: true,
507759
507810
  output: [
507760
507811
  `TTS generated: ${outputPath2}`,
507761
507812
  ` Backend: ${usedBackend}`,
507813
+ fallbackLine,
507762
507814
  voiceSummary ? ` Voice: ${voiceSummary}` : "",
507763
507815
  ` Size: ${size}KB`,
507764
507816
  playbackLine,
@@ -507783,8 +507835,9 @@ ${tried.map((line) => `- ${line}`).join("\n")}`,
507783
507835
  }
507784
507836
  const venvPy = join58(voiceDir(), "luxtts-venv", "bin", "python3");
507785
507837
  const repoDir = join58(voiceDir(), "LuxTTS");
507786
- if (!existsSync40(venvPy) || !existsSync40(repoDir))
507787
- throw new Error("LuxTTS is not installed. Run /voice model luxtts or set up the LuxTTS voice backend first.");
507838
+ if (!existsSync40(venvPy) || !existsSync40(repoDir)) {
507839
+ throw new Error("LuxTTS is not installed in the managed voice environment yet.");
507840
+ }
507788
507841
  const pyScript = [
507789
507842
  "import json, sys, wave",
507790
507843
  "import numpy as np, torch",
@@ -507842,8 +507895,7 @@ ${tried.map((line) => `- ${line}`).join("\n")}`,
507842
507895
  return `${voice} (${model})`;
507843
507896
  }
507844
507897
  synthesizePiper(text, outputPath2, args, requireModel) {
507845
- if (!hasCommand3("piper"))
507846
- throw new Error("piper command not found. Install Piper for ONNX TTS.");
507898
+ const piper = ensurePiperInstalled();
507847
507899
  const rawModel = typeof args["model"] === "string" ? args["model"] : typeof args["voice"] === "string" && /\.(onnx|onnx\.json)$/i.test(args["voice"]) ? args["voice"] : "";
507848
507900
  const argv = ["--output_file", outputPath2];
507849
507901
  let summary = "default piper voice";
@@ -507853,10 +507905,10 @@ ${tried.map((line) => `- ${line}`).join("\n")}`,
507853
507905
  throw new Error(`Piper/ONNX model file not found: ${rawModel}`);
507854
507906
  argv.unshift("--model", modelPath);
507855
507907
  summary = basename12(modelPath);
507856
- } else if (requireModel) {
507857
- throw new Error("Raw ONNX TTS requires model=<path.onnx> or voice=<path.onnx>.");
507908
+ } else {
507909
+ throw new Error(`${requireModel ? "Raw ONNX" : "Piper"} TTS requires model=<path.onnx> or voice=<path.onnx>.`);
507858
507910
  }
507859
- execFileSync2("piper", argv, { input: text, stdio: ["pipe", "pipe", "pipe"], timeout: 12e4 });
507911
+ execFileSync2(piper, argv, { input: text, stdio: ["pipe", "pipe", "pipe"], timeout: 12e4 });
507860
507912
  return summary;
507861
507913
  }
507862
507914
  synthesizeEspeak(text, outputPath2, args) {
@@ -507943,14 +507995,18 @@ ${devices.join("\n")}`,
507943
507995
  };
507944
507996
  TtsGenerateTool = class {
507945
507997
  name = "generate_tts";
507946
- description = "Generate text-to-speech audio as a WAV file, optionally playing it after synthesis. Supports explicit backends: auto, luxtts voice cloning, supertonic, mlx, onnx/piper, and espeak. Use clone_ref to select a registered LuxTTS voice, sample+clone_name to register a clone sample via audio_playback action=clone, and playback=false for silent file generation.";
507998
+ description = "Generate text-to-speech audio as a WAV file, optionally playing it after synthesis. Supports explicit backends: auto, luxtts voice cloning, supertonic, mlx, onnx/piper, and espeak. Neural TTS backends self-provision into ~/.omnius/voice on first use where supported. Use clone_ref to select a registered LuxTTS voice, sample+clone_name to register a clone sample via audio_playback action=clone, and playback=false for silent file generation. Use this tool for speech/TTS requests; do not use shell commands or generate_audio as a TTS fallback.";
507947
507999
  parameters = {
507948
508000
  type: "object",
507949
508001
  properties: {
507950
508002
  text: { type: "string", description: "Text to synthesize" },
508003
+ input: { type: "string", description: "Alias for text." },
508004
+ prompt: { type: "string", description: "Alias for text." },
507951
508005
  backend: { type: "string", enum: ["auto", "luxtts", "supertonic", "mlx", "onnx", "piper", "espeak"] },
507952
508006
  output: { type: "string", description: "Output WAV path. Defaults to ~/.omnius/voice/generated/tts-*.wav." },
508007
+ path: { type: "string", description: "Alias for output." },
507953
508008
  playback: { type: "boolean", description: "Whether to play after generating. Defaults false for generate_tts." },
508009
+ strict_backend: { type: "boolean", description: "When true, fail instead of falling back if the requested backend is unavailable. Defaults false." },
507954
508010
  voice: { type: "string", description: "Voice id/name, or raw Piper/ONNX path when backend=onnx/piper." },
507955
508011
  clone_ref: { type: "string", description: "LuxTTS clone reference path, filename, or registered clone name." },
507956
508012
  model: { type: "string", description: "Backend model id or raw ONNX/Piper model path." },
@@ -507958,7 +508014,7 @@ ${devices.join("\n")}`,
507958
508014
  speed: { type: "number", description: "Speech speed multiplier or backend-specific rate." },
507959
508015
  device: { type: "string", description: "Playback output device when playback=true." }
507960
508016
  },
507961
- required: ["text"]
508017
+ required: []
507962
508018
  };
507963
508019
  async execute(args) {
507964
508020
  const tool = new AudioPlaybackTool();
@@ -534492,7 +534548,7 @@ Respond with your assessment, then take action.`;
534492
534548
  } catch {
534493
534549
  }
534494
534550
  }
534495
- if (!this.options.disablePersistentMemory && !this.options.disableCodebaseMap && process.env["OMNIUS_DISABLE_CODEBASE_MAP"] !== "1" && this._episodeStore && this._workingDirectory) {
534551
+ if (!this.options.disablePersistentMemory && !this.options.disableCodebaseMap && !this.options.subAgent && !this.options.stateDir && process.env["OMNIUS_DISABLE_CODEBASE_MAP"] !== "1" && this._episodeStore && this._workingDirectory) {
534496
534552
  try {
534497
534553
  const memMod = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
534498
534554
  let commitSha = "no-commit";
@@ -542526,7 +542582,7 @@ ${result}`
542526
542582
  let resizedBase64 = null;
542527
542583
  try {
542528
542584
  const { execSync: execSync60 } = await import("node:child_process");
542529
- const { writeFileSync: writeFileSync71, readFileSync: readFileSync102, unlinkSync: unlinkSync25 } = await import("node:fs");
542585
+ const { writeFileSync: writeFileSync71, readFileSync: readFileSync102, unlinkSync: unlinkSync26 } = await import("node:fs");
542530
542586
  const { join: join142 } = await import("node:path");
542531
542587
  const { tmpdir: tmpdir23 } = await import("node:os");
542532
542588
  const tmpIn = join142(tmpdir23(), `omnius_img_in_${Date.now()}.png`);
@@ -542539,11 +542595,11 @@ ${result}`
542539
542595
  const resizedBuf = readFileSync102(tmpOut);
542540
542596
  resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
542541
542597
  try {
542542
- unlinkSync25(tmpIn);
542598
+ unlinkSync26(tmpIn);
542543
542599
  } catch {
542544
542600
  }
542545
542601
  try {
542546
- unlinkSync25(tmpOut);
542602
+ unlinkSync26(tmpOut);
542547
542603
  } catch {
542548
542604
  }
542549
542605
  } catch {
@@ -551061,7 +551117,7 @@ var require_websocket3 = __commonJS({
551061
551117
  var http6 = __require("http");
551062
551118
  var net5 = __require("net");
551063
551119
  var tls2 = __require("tls");
551064
- var { randomBytes: randomBytes25, createHash: createHash24 } = __require("crypto");
551120
+ var { randomBytes: randomBytes26, createHash: createHash24 } = __require("crypto");
551065
551121
  var { Duplex: Duplex3, Readable } = __require("stream");
551066
551122
  var { URL: URL3 } = __require("url");
551067
551123
  var PerMessageDeflate3 = require_permessage_deflate3();
@@ -551591,7 +551647,7 @@ var require_websocket3 = __commonJS({
551591
551647
  }
551592
551648
  }
551593
551649
  const defaultPort = isSecure ? 443 : 80;
551594
- const key = randomBytes25(16).toString("base64");
551650
+ const key = randomBytes26(16).toString("base64");
551595
551651
  const request = isSecure ? https4.request : http6.request;
551596
551652
  const protocolSet = /* @__PURE__ */ new Set();
551597
551653
  let perMessageDeflate;
@@ -579632,11 +579688,11 @@ async function handleSlashCommand(input, ctx3) {
579632
579688
  }
579633
579689
  if (action === "new") {
579634
579690
  try {
579635
- const { randomBytes: randomBytes25 } = await import("node:crypto");
579691
+ const { randomBytes: randomBytes26 } = await import("node:crypto");
579636
579692
  const { homedir: homedir48 } = await import("node:os");
579637
579693
  const { mkdirSync: mkdirSync76, writeFileSync: writeFileSync71 } = await import("node:fs");
579638
579694
  const { join: join142 } = await import("node:path");
579639
- const newKey = randomBytes25(16).toString("hex");
579695
+ const newKey = randomBytes26(16).toString("hex");
579640
579696
  process.env["OMNIUS_API_KEY"] = newKey;
579641
579697
  const dir = join142(homedir48(), ".omnius");
579642
579698
  mkdirSync76(dir, { recursive: true });
@@ -579893,8 +579949,8 @@ async function handleSlashCommand(input, ctx3) {
579893
579949
  }
579894
579950
  process.env["OMNIUS_ACCESS"] = val2;
579895
579951
  if (val2 === "any" && !process.env["OMNIUS_API_KEY"]) {
579896
- const { randomBytes: randomBytes25 } = await import("node:crypto");
579897
- const apiKey = randomBytes25(16).toString("hex");
579952
+ const { randomBytes: randomBytes26 } = await import("node:crypto");
579953
+ const apiKey = randomBytes26(16).toString("hex");
579898
579954
  process.env["OMNIUS_API_KEY"] = apiKey;
579899
579955
  renderInfo(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
579900
579956
  renderInfo(
@@ -580013,8 +580069,8 @@ async function handleSlashCommand(input, ctx3) {
580013
580069
  }
580014
580070
  process.env["OMNIUS_ACCESS"] = val;
580015
580071
  if (val === "any" && !process.env["OMNIUS_API_KEY"]) {
580016
- const { randomBytes: randomBytes25 } = await import("node:crypto");
580017
- const apiKey = randomBytes25(16).toString("hex");
580072
+ const { randomBytes: randomBytes26 } = await import("node:crypto");
580073
+ const apiKey = randomBytes26(16).toString("hex");
580018
580074
  process.env["OMNIUS_API_KEY"] = apiKey;
580019
580075
  renderInfo(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
580020
580076
  renderInfo(
@@ -590321,11 +590377,11 @@ var init_commands = __esm({
590321
590377
  process.env["OMNIUS_ACCESS"] = val;
590322
590378
  if (val === "any" && !process.env["OMNIUS_API_KEY"]) {
590323
590379
  try {
590324
- const { randomBytes: randomBytes25 } = await import("node:crypto");
590380
+ const { randomBytes: randomBytes26 } = await import("node:crypto");
590325
590381
  const { homedir: homedir48 } = await import("node:os");
590326
590382
  const { mkdirSync: mkdirSync76, writeFileSync: writeFileSync71 } = await import("node:fs");
590327
590383
  const { join: join142 } = await import("node:path");
590328
- const apiKey = randomBytes25(16).toString("hex");
590384
+ const apiKey = randomBytes26(16).toString("hex");
590329
590385
  process.env["OMNIUS_API_KEY"] = apiKey;
590330
590386
  const dir = join142(homedir48(), ".omnius");
590331
590387
  mkdirSync76(dir, { recursive: true });
@@ -596290,6 +596346,8 @@ var init_tool_policy = __esm({
596290
596346
  "glob_find",
596291
596347
  "list_directory",
596292
596348
  "code_sandbox",
596349
+ "full_sub_agent",
596350
+ "telegram_sandbox_handoff",
596293
596351
  "codebase_map",
596294
596352
  "diagnostic",
596295
596353
  "git_info",
@@ -596324,7 +596382,6 @@ var init_tool_policy = __esm({
596324
596382
  "generate_tts",
596325
596383
  "create_audio_file",
596326
596384
  "telegram_send_file",
596327
- "telegram_sandbox_handoff",
596328
596385
  "task_complete"
596329
596386
  ]);
596330
596387
  SAFE_GROUP_ADMIN_TOOLS = /* @__PURE__ */ new Set([
@@ -596341,24 +596398,26 @@ var init_tool_policy = __esm({
596341
596398
  "generate_tts",
596342
596399
  "create_audio_file",
596343
596400
  "telegram_send_file",
596344
- "telegram_sandbox_handoff",
596345
596401
  "task_complete"
596346
596402
  ]);
596347
596403
  }
596348
596404
  });
596349
596405
 
596350
596406
  // packages/cli/src/tui/telegram-creative-tools.ts
596407
+ import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes21 } from "node:crypto";
596351
596408
  import {
596352
596409
  existsSync as existsSync104,
596353
596410
  mkdirSync as mkdirSync59,
596354
596411
  readFileSync as readFileSync85,
596355
596412
  statSync as statSync35,
596413
+ unlinkSync as unlinkSync19,
596356
596414
  writeFileSync as writeFileSync55
596357
596415
  } from "node:fs";
596358
596416
  import { mkdir as mkdir17 } from "node:fs/promises";
596359
596417
  import {
596360
596418
  basename as basename22,
596361
596419
  dirname as dirname33,
596420
+ extname as extname14,
596362
596421
  isAbsolute as isAbsolute6,
596363
596422
  join as join119,
596364
596423
  relative as relative12,
@@ -596377,11 +596436,27 @@ function formatTelegramCreativeWorkspacePrompt(root) {
596377
596436
  "Public/group creative workspace is enabled.",
596378
596437
  `Workspace root: ${root}`,
596379
596438
  "Creative file tools are scoped to that folder only.",
596380
- "Allowed: create new files, read/list files in this workspace, and edit/patch files already created in this workspace.",
596381
- "Forbidden: delete files, access paths outside this workspace, mutate the project tree, run shell commands, or touch system state.",
596439
+ "Allowed: create and send non-executable creative artifacts in this workspace.",
596440
+ "At rest, artifacts are stored as random internal blobs with random header bytes; requested filenames are logical names restored only during Telegram upload.",
596441
+ "Forbidden: delete files, create scripts/executables, access paths outside this workspace, mutate the project tree, run shell/Python/code commands, or touch system state.",
596382
596442
  "When a user asks for an artifact to be sent, create it here and then call telegram_send_file. The bridge also auto-attaches recorded artifacts as a fallback. Refer to the attachment naturally; do not expose filesystem paths unless the admin explicitly asks."
596383
596443
  ].join("\n");
596384
596444
  }
596445
+ function publicCreativeArtifactPolicyError(path11) {
596446
+ const ext = extname14(path11).toLowerCase();
596447
+ if (PUBLIC_EXECUTABLE_ARTIFACT_EXTENSIONS.has(ext)) {
596448
+ return `Public Telegram creative work cannot create or send executable/script/code artifacts (${ext || "no extension"}). Use a non-executable artifact such as .md, .txt, .json, image, audio, or PDF.`;
596449
+ }
596450
+ return null;
596451
+ }
596452
+ function publicCreativeContentPolicyError(args) {
596453
+ const content = args["content"] ?? args["text"] ?? args["data"];
596454
+ if (typeof content !== "string") return null;
596455
+ if (/^\s*#!/.test(content)) {
596456
+ return "Public Telegram creative work cannot create executable scripts or shebang files.";
596457
+ }
596458
+ return null;
596459
+ }
596385
596460
  function collectGeneratedArtifactPathsFromText(text, root) {
596386
596461
  const rootAbs = resolve38(root);
596387
596462
  const paths = /* @__PURE__ */ new Set();
@@ -596389,7 +596464,7 @@ function collectGeneratedArtifactPathsFromText(text, root) {
596389
596464
  const value2 = match[1];
596390
596465
  if (!value2) continue;
596391
596466
  const guarded = guardPath(rootAbs, value2);
596392
- if (guarded.ok && existsSync104(guarded.path.abs) && safeStatFile(guarded.path.abs)) {
596467
+ if (guarded.ok && (isManifestArtifact(rootAbs, guarded.path.rel) || existsSync104(guarded.path.abs) && safeStatFile(guarded.path.abs))) {
596393
596468
  paths.add(guarded.path.abs);
596394
596469
  }
596395
596470
  }
@@ -596398,7 +596473,7 @@ function collectGeneratedArtifactPathsFromText(text, root) {
596398
596473
  const value2 = marker?.[1]?.trim().replace(/^["']|["']$/g, "");
596399
596474
  if (!value2) continue;
596400
596475
  const guarded = guardPath(rootAbs, value2);
596401
- if (guarded.ok && existsSync104(guarded.path.abs) && safeStatFile(guarded.path.abs)) {
596476
+ if (guarded.ok && (isManifestArtifact(rootAbs, guarded.path.rel) || existsSync104(guarded.path.abs) && safeStatFile(guarded.path.abs))) {
596402
596477
  paths.add(guarded.path.abs);
596403
596478
  }
596404
596479
  }
@@ -596408,11 +596483,7 @@ function buildTelegramCreativeTools(repoRoot, chatId, backendUrl, imageDefaults
596408
596483
  const root = telegramCreativeWorkspaceRoot(repoRoot, chatId);
596409
596484
  ensureManifest(root);
596410
596485
  return [
596411
- scopedTool(new FileReadTool(root), root, "read"),
596412
- scopedTool(new ListDirectoryTool(root), root, "list"),
596413
596486
  scopedTool(new FileWriteTool(root), root, "create"),
596414
- scopedTool(new FileEditTool(root), root, "edit"),
596415
- scopedTool(new FilePatchTool(root), root, "edit"),
596416
596487
  scopedTool(new StructuredFileTool(root), root, "create"),
596417
596488
  scopedTool(new ImageGenerateTool(root, backendUrl, imageDefaults), root, "generate"),
596418
596489
  scopedTool(new AudioGenerateTool(root, audioDefaults), root, "generate"),
@@ -596461,6 +596532,10 @@ function scopedTool(base3, root, mode) {
596461
596532
  if (pathKey) {
596462
596533
  const guarded = guardPath(rootAbs, String(next[pathKey]));
596463
596534
  if (!guarded.ok) return denied(guarded.error);
596535
+ const pathPolicyError = publicCreativeArtifactPolicyError(guarded.path.abs);
596536
+ if (pathPolicyError) return denied(pathPolicyError);
596537
+ const contentPolicyError = mode === "create" || mode === "edit" ? publicCreativeContentPolicyError(next) : null;
596538
+ if (contentPolicyError) return denied(contentPolicyError);
596464
596539
  if (mode === "edit" && !manifestHas(rootAbs, guarded.path.rel)) {
596465
596540
  return denied(`Public Telegram creative tools can only edit files created in this chat workspace: ${guarded.path.rel}`);
596466
596541
  }
@@ -596530,12 +596605,21 @@ function readManifest(root) {
596530
596605
  ensureManifest(root);
596531
596606
  try {
596532
596607
  const parsed = JSON.parse(readFileSync85(manifestPath(root), "utf8"));
596608
+ const objects = parsed.objects && typeof parsed.objects === "object" ? Object.fromEntries(
596609
+ Object.entries(parsed.objects).filter((entry) => {
596610
+ const value2 = entry[1];
596611
+ return Boolean(
596612
+ value2 && typeof value2.logicalRel === "string" && typeof value2.storedRel === "string" && typeof value2.originalName === "string" && typeof value2.prefixBytes === "number" && typeof value2.size === "number"
596613
+ );
596614
+ })
596615
+ ) : {};
596533
596616
  return {
596534
596617
  files: Array.isArray(parsed.files) ? parsed.files.filter((file) => typeof file === "string") : [],
596618
+ objects,
596535
596619
  updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
596536
596620
  };
596537
596621
  } catch {
596538
- return { files: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
596622
+ return { files: [], objects: {}, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
596539
596623
  }
596540
596624
  }
596541
596625
  function writeManifest(root, manifest) {
@@ -596544,18 +596628,114 @@ function writeManifest(root, manifest) {
596544
596628
  }
596545
596629
  function manifestHas(root, relPath) {
596546
596630
  const rel = relPath.replace(/\\/g, "/");
596547
- return readManifest(root).files.includes(rel);
596631
+ const manifest = readManifest(root);
596632
+ return manifest.files.includes(rel) || Boolean(manifest.objects?.[rel]);
596548
596633
  }
596549
596634
  function rememberCreated(root, absPath) {
596550
596635
  const guarded = guardPath(root, absPath);
596551
596636
  if (!guarded.ok || guarded.path.rel === ".") return;
596552
596637
  const manifest = readManifest(root);
596553
596638
  const rel = guarded.path.rel.replace(/\\/g, "/");
596639
+ if (publicCreativeArtifactPolicyError(guarded.path.abs)) return;
596640
+ if (existsSync104(guarded.path.abs) && safeStatFile(guarded.path.abs)) {
596641
+ const previous = manifest.objects?.[rel];
596642
+ if (previous) {
596643
+ const previousPath = resolve38(root, previous.storedRel);
596644
+ if (isInside(resolve38(root), previousPath) && existsSync104(previousPath)) {
596645
+ try {
596646
+ unlinkSync19(previousPath);
596647
+ } catch {
596648
+ }
596649
+ }
596650
+ }
596651
+ mkdirSync59(join119(root, OBJECTS_DIR), { recursive: true });
596652
+ const data = readFileSync85(guarded.path.abs);
596653
+ const prefix = randomBytes21(48);
596654
+ const key = randomBytes21(32);
596655
+ const iv = randomBytes21(12);
596656
+ const cipher = createCipheriv4("aes-256-gcm", key, iv);
596657
+ const encrypted = Buffer.concat([cipher.update(data), cipher.final()]);
596658
+ const tag = cipher.getAuthTag();
596659
+ const storedRel = join119(OBJECTS_DIR, `${Date.now()}-${randomBytes21(12).toString("hex")}.blob`).replace(/\\/g, "/");
596660
+ const storedAbs = join119(root, storedRel);
596661
+ writeFileSync55(storedAbs, Buffer.concat([prefix, encrypted]));
596662
+ try {
596663
+ unlinkSync19(guarded.path.abs);
596664
+ } catch {
596665
+ }
596666
+ manifest.objects = manifest.objects || {};
596667
+ manifest.objects[rel] = {
596668
+ logicalRel: rel,
596669
+ storedRel,
596670
+ originalName: basename22(guarded.path.abs),
596671
+ prefixBytes: prefix.length,
596672
+ encrypted: true,
596673
+ key: key.toString("base64"),
596674
+ iv: iv.toString("base64"),
596675
+ tag: tag.toString("base64"),
596676
+ size: data.length,
596677
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
596678
+ };
596679
+ }
596554
596680
  if (!manifest.files.includes(rel)) manifest.files.push(rel);
596555
596681
  manifest.files.sort();
596556
596682
  manifest.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
596557
596683
  writeManifest(root, manifest);
596558
596684
  }
596685
+ function isManifestArtifact(root, relPath) {
596686
+ return manifestHas(root, relPath);
596687
+ }
596688
+ function materializeTelegramCreativeArtifactForSend(root, rawPath) {
596689
+ const rootAbs = resolve38(root);
596690
+ const guarded = guardPath(rootAbs, rawPath);
596691
+ if (!guarded.ok) return { ok: false, error: guarded.error };
596692
+ const policyError = publicCreativeArtifactPolicyError(guarded.path.abs);
596693
+ if (policyError) return { ok: false, error: policyError };
596694
+ const manifest = readManifest(rootAbs);
596695
+ const rel = guarded.path.rel.replace(/\\/g, "/");
596696
+ const object = manifest.objects?.[rel];
596697
+ if (object) {
596698
+ const storedAbs = resolve38(rootAbs, object.storedRel);
596699
+ if (!isInside(rootAbs, storedAbs) || !existsSync104(storedAbs) || !safeStatFile(storedAbs)) {
596700
+ return { ok: false, error: `Scoped artifact storage is missing for ${rel}.` };
596701
+ }
596702
+ const blob = readFileSync85(storedAbs);
596703
+ if (blob.length < object.prefixBytes) {
596704
+ return { ok: false, error: `Scoped artifact storage is corrupt for ${rel}.` };
596705
+ }
596706
+ let payload = blob.subarray(object.prefixBytes);
596707
+ if (object.encrypted) {
596708
+ if (!object.key || !object.iv || !object.tag) {
596709
+ return { ok: false, error: `Scoped artifact encryption metadata is missing for ${rel}.` };
596710
+ }
596711
+ const decipher = createDecipheriv4(
596712
+ "aes-256-gcm",
596713
+ Buffer.from(object.key, "base64"),
596714
+ Buffer.from(object.iv, "base64")
596715
+ );
596716
+ decipher.setAuthTag(Buffer.from(object.tag, "base64"));
596717
+ payload = Buffer.concat([decipher.update(payload), decipher.final()]);
596718
+ }
596719
+ const stageDir = join119(rootAbs, SEND_DIR, `${Date.now()}-${randomBytes21(8).toString("hex")}`);
596720
+ mkdirSync59(stageDir, { recursive: true });
596721
+ const staged = join119(stageDir, object.originalName || basename22(rel));
596722
+ writeFileSync55(staged, payload);
596723
+ return {
596724
+ ok: true,
596725
+ path: staged,
596726
+ cleanup: () => {
596727
+ try {
596728
+ unlinkSync19(staged);
596729
+ } catch {
596730
+ }
596731
+ }
596732
+ };
596733
+ }
596734
+ if (existsSync104(guarded.path.abs) && safeStatFile(guarded.path.abs)) {
596735
+ return { ok: true, path: guarded.path.abs };
596736
+ }
596737
+ return { ok: false, error: `Scoped artifact not found in manifest: ${rawPath}` };
596738
+ }
596559
596739
  function safeStatFile(path11) {
596560
596740
  try {
596561
596741
  return statSync35(path11).isFile();
@@ -596573,15 +596753,75 @@ function denied(error) {
596573
596753
  mutatedFiles: []
596574
596754
  };
596575
596755
  }
596576
- var MANIFEST_FILE, PATH_KEYS, MEDIA_PATH_RE, CreativeAudioFileTool;
596756
+ var MANIFEST_FILE, OBJECTS_DIR, SEND_DIR, PATH_KEYS, MEDIA_PATH_RE, PUBLIC_EXECUTABLE_ARTIFACT_EXTENSIONS, CreativeAudioFileTool;
596577
596757
  var init_telegram_creative_tools = __esm({
596578
596758
  "packages/cli/src/tui/telegram-creative-tools.ts"() {
596579
596759
  "use strict";
596580
- init_typed_node_events();
596581
596760
  init_dist5();
596582
596761
  MANIFEST_FILE = ".omnius-creative-manifest.json";
596762
+ OBJECTS_DIR = ".objects";
596763
+ SEND_DIR = ".send";
596583
596764
  PATH_KEYS = ["path", "file", "file_path", "filename", "filepath", "filePath"];
596584
596765
  MEDIA_PATH_RE = /(?:^|[\s([])(\/[^\s<>"')\]]+\.[A-Za-z0-9]{1,12})(?:$|[\s),.\]])/g;
596766
+ PUBLIC_EXECUTABLE_ARTIFACT_EXTENSIONS = /* @__PURE__ */ new Set([
596767
+ ".sh",
596768
+ ".bash",
596769
+ ".zsh",
596770
+ ".fish",
596771
+ ".ksh",
596772
+ ".csh",
596773
+ ".py",
596774
+ ".pyw",
596775
+ ".pyc",
596776
+ ".pyo",
596777
+ ".ipynb",
596778
+ ".js",
596779
+ ".mjs",
596780
+ ".cjs",
596781
+ ".ts",
596782
+ ".tsx",
596783
+ ".jsx",
596784
+ ".rb",
596785
+ ".pl",
596786
+ ".pm",
596787
+ ".php",
596788
+ ".lua",
596789
+ ".r",
596790
+ ".jl",
596791
+ ".ps1",
596792
+ ".psm1",
596793
+ ".bat",
596794
+ ".cmd",
596795
+ ".com",
596796
+ ".exe",
596797
+ ".msi",
596798
+ ".jar",
596799
+ ".class",
596800
+ ".war",
596801
+ ".ear",
596802
+ ".go",
596803
+ ".rs",
596804
+ ".c",
596805
+ ".cc",
596806
+ ".cpp",
596807
+ ".cxx",
596808
+ ".h",
596809
+ ".hpp",
596810
+ ".java",
596811
+ ".kt",
596812
+ ".kts",
596813
+ ".scala",
596814
+ ".swift",
596815
+ ".cs",
596816
+ ".vb",
596817
+ ".fs",
596818
+ ".so",
596819
+ ".dylib",
596820
+ ".dll",
596821
+ ".app",
596822
+ ".appimage",
596823
+ ".desktop"
596824
+ ]);
596585
596825
  CreativeAudioFileTool = class {
596586
596826
  constructor(root) {
596587
596827
  this.root = root;
@@ -596593,6 +596833,8 @@ var init_telegram_creative_tools = __esm({
596593
596833
  type: "object",
596594
596834
  properties: {
596595
596835
  text: { type: "string", description: "Text to synthesize into speech" },
596836
+ input: { type: "string", description: "Alias for text" },
596837
+ prompt: { type: "string", description: "Alias for text" },
596596
596838
  path: { type: "string", description: "Output .wav path inside the creative workspace" },
596597
596839
  backend: { type: "string", enum: ["auto", "luxtts", "supertonic", "mlx", "onnx", "piper", "espeak"], description: "TTS backend. Defaults to auto." },
596598
596840
  voice: { type: "string", description: "Voice id/name for the selected TTS backend" },
@@ -596600,11 +596842,11 @@ var init_telegram_creative_tools = __esm({
596600
596842
  model: { type: "string", description: "Optional backend model id or raw Piper/ONNX path" },
596601
596843
  speed: { type: "number", description: "Speech speed multiplier or backend-specific rate" }
596602
596844
  },
596603
- required: ["text", "path"]
596845
+ required: []
596604
596846
  };
596605
596847
  async execute(args) {
596606
596848
  const start2 = performance.now();
596607
- const text = typeof args["text"] === "string" ? args["text"].trim() : "";
596849
+ const text = typeof args["text"] === "string" && args["text"].trim() ? args["text"].trim() : typeof args["input"] === "string" && args["input"].trim() ? args["input"].trim() : typeof args["prompt"] === "string" && args["prompt"].trim() ? args["prompt"].trim() : "";
596608
596850
  if (!text) return { success: false, output: "", error: "text is required", durationMs: performance.now() - start2 };
596609
596851
  const rawPath = typeof args["path"] === "string" && args["path"].trim() ? String(args["path"]) : `speech-${Date.now()}.wav`;
596610
596852
  const guarded = guardPath(this.root, rawPath);
@@ -596663,7 +596905,7 @@ __export(vision_ingress_exports, {
596663
596905
  runVisionIngress: () => runVisionIngress
596664
596906
  });
596665
596907
  import { execFileSync as execFileSync4 } from "node:child_process";
596666
- import { existsSync as existsSync105, readFileSync as readFileSync86, unlinkSync as unlinkSync19 } from "node:fs";
596908
+ import { existsSync as existsSync105, readFileSync as readFileSync86, unlinkSync as unlinkSync20 } from "node:fs";
596667
596909
  import { join as join120 } from "node:path";
596668
596910
  function isTesseractAvailable() {
596669
596911
  try {
@@ -596721,7 +596963,7 @@ function advancedOcr(imagePath) {
596721
596963
  const text = readFileSync86(txtFile, "utf-8").trim();
596722
596964
  if (text.length > 0) results.push(text);
596723
596965
  try {
596724
- unlinkSync19(txtFile);
596966
+ unlinkSync20(txtFile);
596725
596967
  } catch {
596726
596968
  }
596727
596969
  }
@@ -596806,7 +597048,7 @@ var init_vision_ingress = __esm({
596806
597048
  });
596807
597049
 
596808
597050
  // packages/cli/src/tui/telegram-bridge.ts
596809
- import { mkdirSync as mkdirSync60, existsSync as existsSync106, unlinkSync as unlinkSync20, readdirSync as readdirSync36, statSync as statSync36, readFileSync as readFileSync87, writeFileSync as writeFileSync57 } from "node:fs";
597051
+ import { mkdirSync as mkdirSync60, existsSync as existsSync106, unlinkSync as unlinkSync21, readdirSync as readdirSync36, statSync as statSync36, readFileSync as readFileSync87, writeFileSync as writeFileSync57 } from "node:fs";
596810
597052
  import { join as join121, resolve as resolve39, basename as basename23, relative as relative13, isAbsolute as isAbsolute7 } from "node:path";
596811
597053
  import { writeFile as writeFileAsync } from "node:fs/promises";
596812
597054
  import { createHash as createHash19, randomInt } from "node:crypto";
@@ -597122,7 +597364,8 @@ function telegramSyntheticHelpSignatures() {
597122
597364
  return [
597123
597365
  { signature: "/help", description: "Show Telegram command help" },
597124
597366
  { signature: "/start", description: "Show Telegram bridge status and authentication instructions" },
597125
- { signature: "/auth <code>", description: "Authenticate this Telegram user as bot admin using the TUI code" }
597367
+ { signature: "/auth <code>", description: "Authenticate this Telegram user as bot admin using the TUI code" },
597368
+ { signature: "/call", description: "Get the active voice call link when a call session is running" }
597126
597369
  ];
597127
597370
  }
597128
597371
  function telegramHelpCommandAllowed(cmd, scope) {
@@ -597626,7 +597869,8 @@ path and target. Do not search for Telegram bot tokens, environment secrets, or
597626
597869
  credentials; upload authorization is encapsulated by telegram_send_file.
597627
597870
 
597628
597871
  When asked to generate speech, narration, or TTS, use generate_tts or audio_playback.
597629
- Do not fall back to shell commands for speech synthesis while those tools are available.
597872
+ Those tools handle first-use backend setup where supported. Do not fall back to shell
597873
+ commands or generic audio generation for speech synthesis while those tools are available.
597630
597874
 
597631
597875
  Keep responses concise for Telegram but don't withhold information from the admin.
597632
597876
  `.trim();
@@ -599550,6 +599794,9 @@ ${mediaContext}` : ""}`
599550
599794
  runner.onEvent((event) => {
599551
599795
  if (subAgent.aborted) return;
599552
599796
  let suppressExternalEvent = false;
599797
+ if (!isAdminDM && event.type === "status") {
599798
+ suppressExternalEvent = true;
599799
+ }
599553
599800
  if (event.type === "tool_call" && event.toolName) {
599554
599801
  if (event.toolName === "task_complete") {
599555
599802
  subAgent.completionBoundarySeen = true;
@@ -599585,7 +599832,9 @@ ${mediaContext}` : ""}`
599585
599832
  }
599586
599833
  }
599587
599834
  } else if (event.type === "status" && event.content) {
599588
- this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `status: ${event.content}`);
599835
+ if (isAdminDM) {
599836
+ this.subAgentViewCallbacks?.onWrite(subAgent.viewId, `status: ${event.content}`);
599837
+ }
599589
599838
  } else if (event.type === "assistant_text" && event.content && event.source !== "task_complete_summary") {
599590
599839
  subAgent.assistantText = event.content;
599591
599840
  } else if (event.type === "stream_start") {
@@ -600056,10 +600305,27 @@ Scoped workspace: ${scopedRoot}`,
600056
600305
  ).map((tool) => adaptTool5(tool, todoSessionId));
600057
600306
  adaptedTools.push(...creativeTools);
600058
600307
  adaptedTools.push(adaptTool5(this.buildTelegramSendFileTool(context2, repoRoot, chatId, msg), todoSessionId));
600059
- adaptedTools.push(adaptTool5(this.buildTelegramSandboxHandoffTool(context2, repoRoot, `chat:${String(chatId ?? "unknown")}`, chatId), todoSessionId));
600308
+ adaptedTools = this.filterNonAdminTelegramTools(adaptedTools);
600060
600309
  }
600061
600310
  return [...adaptedTools, taskComplete];
600062
600311
  }
600312
+ filterNonAdminTelegramTools(tools) {
600313
+ const blocked = /* @__PURE__ */ new Set([
600314
+ "shell",
600315
+ "code_sandbox",
600316
+ "background_run",
600317
+ "task_output",
600318
+ "task_status",
600319
+ "task_stop",
600320
+ "full_sub_agent",
600321
+ "telegram_sandbox_handoff",
600322
+ "create_tool",
600323
+ "manage_tools",
600324
+ "aiwg_setup",
600325
+ "aiwg_workflow"
600326
+ ]);
600327
+ return tools.filter((tool) => !blocked.has(tool.name));
600328
+ }
600063
600329
  imageGenerationDefaultsForRepo(repoRoot) {
600064
600330
  const settings = resolveSettings(repoRoot);
600065
600331
  return {
@@ -600164,6 +600430,8 @@ Scoped workspace: ${scopedRoot}`,
600164
600430
  error: `Telegram file upload failed: ${err instanceof Error ? err.message : String(err)}`,
600165
600431
  durationMs: performance.now() - start2
600166
600432
  };
600433
+ } finally {
600434
+ file.cleanup?.();
600167
600435
  }
600168
600436
  }
600169
600437
  };
@@ -600217,10 +600485,12 @@ ${knownList}` : "Private-user telegram_send_file target must be this DM or a kno
600217
600485
  resolveTelegramFilePath(rawPath, repoRoot, scopedRoot) {
600218
600486
  const base3 = scopedRoot ? resolve39(scopedRoot) : resolve39(repoRoot);
600219
600487
  const trimmed = rawPath.trim().replace(/^["']|["']$/g, "");
600220
- const abs = isAbsolute7(trimmed) ? resolve39(trimmed) : resolve39(base3, trimmed);
600221
- if (scopedRoot && !isPathInside(base3, abs)) {
600222
- return { ok: false, error: `Public/group telegram_send_file can only send files inside ${base3}.` };
600488
+ if (scopedRoot) {
600489
+ const materialized = materializeTelegramCreativeArtifactForSend(base3, trimmed);
600490
+ if (!materialized.ok) return materialized;
600491
+ return materialized;
600223
600492
  }
600493
+ const abs = isAbsolute7(trimmed) ? resolve39(trimmed) : resolve39(base3, trimmed);
600224
600494
  if (!existsSync106(abs)) return { ok: false, error: `File does not exist: ${trimmed}` };
600225
600495
  if (!statSync36(abs).isFile()) return { ok: false, error: `Path is not a file: ${trimmed}` };
600226
600496
  return { ok: true, path: abs };
@@ -600381,7 +600651,7 @@ ${visionContext}]`;
600381
600651
  for (const [key, entry] of this.mediaCache) {
600382
600652
  if (now - entry.cachedAt > MEDIA_CACHE_TTL_MS) {
600383
600653
  try {
600384
- unlinkSync20(entry.localPath);
600654
+ unlinkSync21(entry.localPath);
600385
600655
  } catch {
600386
600656
  }
600387
600657
  this.mediaCache.delete(key);
@@ -600548,15 +600818,22 @@ Content-Type: ${contentType}\r
600548
600818
  const abs = resolve39(path11);
600549
600819
  if (!isPathInside(rootAbs, abs)) continue;
600550
600820
  if (!includeMentioned && alreadySentByText.has(abs)) continue;
600551
- if (!existsSync106(abs) || !statSync36(abs).isFile()) continue;
600552
- const kind = classifyMedia(abs) ?? "document";
600821
+ const materialized = materializeTelegramCreativeArtifactForSend(rootAbs, abs);
600822
+ if (!materialized.ok) continue;
600823
+ if (!existsSync106(materialized.path) || !statSync36(materialized.path).isFile()) {
600824
+ materialized.cleanup?.();
600825
+ continue;
600826
+ }
600827
+ const kind = classifyMedia(materialized.path) ?? "document";
600553
600828
  await this.sendMediaReference(msg.chatId, {
600554
- original: abs,
600555
- value: abs,
600829
+ original: materialized.path,
600830
+ value: materialized.path,
600556
600831
  kind,
600557
600832
  source: "file",
600558
600833
  audioAsVoice: kind === "voice"
600559
- }).catch(() => null);
600834
+ }).catch(() => null).finally(() => {
600835
+ materialized.cleanup?.();
600836
+ });
600560
600837
  }
600561
600838
  }
600562
600839
  async uploadTelegramFiles(method, fields, files) {
@@ -600998,7 +601275,7 @@ import {
600998
601275
  writeFileSync as writeFileSync58,
600999
601276
  renameSync as renameSync5,
601000
601277
  mkdirSync as mkdirSync61,
601001
- unlinkSync as unlinkSync21
601278
+ unlinkSync as unlinkSync22
601002
601279
  } from "node:fs";
601003
601280
  import { join as join122 } from "node:path";
601004
601281
  import { homedir as homedir36 } from "node:os";
@@ -601036,7 +601313,7 @@ function persistInFlight(j) {
601036
601313
  function deleteInFlightFile(id) {
601037
601314
  try {
601038
601315
  const p2 = inFlightPath(id);
601039
- if (existsSync107(p2)) unlinkSync21(p2);
601316
+ if (existsSync107(p2)) unlinkSync22(p2);
601040
601317
  } catch {
601041
601318
  }
601042
601319
  }
@@ -601257,7 +601534,7 @@ function drainCheckins(sessionId) {
601257
601534
  try {
601258
601535
  const raw = readFileSync88(fp, "utf-8");
601259
601536
  try {
601260
- unlinkSync21(fp);
601537
+ unlinkSync22(fp);
601261
601538
  } catch {
601262
601539
  }
601263
601540
  if (!raw.trim()) return [];
@@ -601295,7 +601572,7 @@ function listSessions2() {
601295
601572
  function deleteSession2(id) {
601296
601573
  try {
601297
601574
  const p2 = sessionPath(id);
601298
- if (existsSync107(p2)) unlinkSync21(p2);
601575
+ if (existsSync107(p2)) unlinkSync22(p2);
601299
601576
  } catch {
601300
601577
  }
601301
601578
  deleteInFlightFile(id);
@@ -602231,7 +602508,7 @@ var init_access_policy = __esm({
602231
602508
 
602232
602509
  // packages/cli/src/api/project-preferences.ts
602233
602510
  import { createHash as createHash20 } from "node:crypto";
602234
- import { existsSync as existsSync109, mkdirSync as mkdirSync63, readFileSync as readFileSync90, renameSync as renameSync7, writeFileSync as writeFileSync60, unlinkSync as unlinkSync22 } from "node:fs";
602511
+ import { existsSync as existsSync109, mkdirSync as mkdirSync63, readFileSync as readFileSync90, renameSync as renameSync7, writeFileSync as writeFileSync60, unlinkSync as unlinkSync23 } from "node:fs";
602235
602512
  import { homedir as homedir38 } from "node:os";
602236
602513
  import { join as join124, resolve as resolve41 } from "node:path";
602237
602514
  import { randomUUID as randomUUID15 } from "node:crypto";
@@ -602292,7 +602569,7 @@ function writeProjectPreferences(root, partial) {
602292
602569
  } catch {
602293
602570
  }
602294
602571
  try {
602295
- unlinkSync22(tmp);
602572
+ unlinkSync23(tmp);
602296
602573
  } catch {
602297
602574
  }
602298
602575
  throw err;
@@ -602303,7 +602580,7 @@ function deleteProjectPreferences(root) {
602303
602580
  try {
602304
602581
  const file = prefsPath(root);
602305
602582
  if (!existsSync109(file)) return false;
602306
- unlinkSync22(file);
602583
+ unlinkSync23(file);
602307
602584
  return true;
602308
602585
  } catch {
602309
602586
  return false;
@@ -604350,7 +604627,7 @@ __export(runtime_keys_exports, {
604350
604627
  import { existsSync as existsSync113, readFileSync as readFileSync93, writeFileSync as writeFileSync61, mkdirSync as mkdirSync66, chmodSync } from "node:fs";
604351
604628
  import { join as join127 } from "node:path";
604352
604629
  import { homedir as homedir40 } from "node:os";
604353
- import { randomBytes as randomBytes21 } from "node:crypto";
604630
+ import { randomBytes as randomBytes22 } from "node:crypto";
604354
604631
  function ensureDir2() {
604355
604632
  const dir = join127(homedir40(), ".omnius");
604356
604633
  if (!existsSync113(dir)) mkdirSync66(dir, { recursive: true });
@@ -604376,7 +604653,7 @@ function persistAll(records) {
604376
604653
  }
604377
604654
  function mintKey(args) {
604378
604655
  const records = loadAll();
604379
- const key = `omnius_${randomBytes21(32).toString("hex")}`;
604656
+ const key = `omnius_${randomBytes22(32).toString("hex")}`;
604380
604657
  const record = {
604381
604658
  key,
604382
604659
  scope: args.scope,
@@ -607684,11 +607961,11 @@ async function handleAimsIncidentPost(ctx3) {
607684
607961
  }));
607685
607962
  return true;
607686
607963
  }
607687
- const { randomBytes: randomBytes25 } = await import("node:crypto");
607964
+ const { randomBytes: randomBytes26 } = await import("node:crypto");
607688
607965
  const record = await withAimsLock("incidents.json", () => {
607689
607966
  const existing = readAimsFile("incidents.json", []);
607690
607967
  const rec = {
607691
- id: `INC-${Date.now()}-${randomBytes25(4).toString("hex")}`,
607968
+ id: `INC-${Date.now()}-${randomBytes26(4).toString("hex")}`,
607692
607969
  ts: (/* @__PURE__ */ new Date()).toISOString(),
607693
607970
  raised_by: user ?? "anonymous",
607694
607971
  status: "open",
@@ -616849,10 +617126,10 @@ var init_usage_tracker = __esm({
616849
617126
  });
616850
617127
 
616851
617128
  // packages/cli/src/api/profiles.ts
616852
- import { existsSync as existsSync118, readFileSync as readFileSync97, writeFileSync as writeFileSync64, mkdirSync as mkdirSync69, readdirSync as readdirSync40, unlinkSync as unlinkSync23 } from "node:fs";
617129
+ import { existsSync as existsSync118, readFileSync as readFileSync97, writeFileSync as writeFileSync64, mkdirSync as mkdirSync69, readdirSync as readdirSync40, unlinkSync as unlinkSync24 } from "node:fs";
616853
617130
  import { join as join132 } from "node:path";
616854
617131
  import { homedir as homedir43 } from "node:os";
616855
- import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes22, scryptSync as scryptSync3 } from "node:crypto";
617132
+ import { createCipheriv as createCipheriv5, createDecipheriv as createDecipheriv5, randomBytes as randomBytes23, scryptSync as scryptSync3 } from "node:crypto";
616856
617133
  function globalProfileDir() {
616857
617134
  return join132(homedir43(), ".omnius", "profiles");
616858
617135
  }
@@ -616930,16 +617207,16 @@ function deleteProfile(name10, scope = "global", projectDir2) {
616930
617207
  const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
616931
617208
  const filePath = join132(dir, `${sanitized}.json`);
616932
617209
  if (existsSync118(filePath)) {
616933
- unlinkSync23(filePath);
617210
+ unlinkSync24(filePath);
616934
617211
  return true;
616935
617212
  }
616936
617213
  return false;
616937
617214
  }
616938
617215
  function encryptProfile(profile, password) {
616939
- const salt = randomBytes22(32);
617216
+ const salt = randomBytes23(32);
616940
617217
  const key = scryptSync3(password, salt, 32);
616941
- const iv = randomBytes22(16);
616942
- const cipher = createCipheriv4("aes-256-gcm", key, iv);
617218
+ const iv = randomBytes23(16);
617219
+ const cipher = createCipheriv5("aes-256-gcm", key, iv);
616943
617220
  const plaintext = JSON.stringify(profile);
616944
617221
  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
616945
617222
  const tag = cipher.getAuthTag();
@@ -616958,7 +617235,7 @@ function decryptProfile(enc, password) {
616958
617235
  const salt = Buffer.from(enc.salt, "hex");
616959
617236
  const key = scryptSync3(password, salt, 32);
616960
617237
  const iv = Buffer.from(enc.iv, "hex");
616961
- const decipher = createDecipheriv4("aes-256-gcm", key, iv);
617238
+ const decipher = createDecipheriv5("aes-256-gcm", key, iv);
616962
617239
  decipher.setAuthTag(Buffer.from(enc.tag, "hex"));
616963
617240
  const decrypted = Buffer.concat([
616964
617241
  decipher.update(Buffer.from(enc.data, "hex")),
@@ -617590,8 +617867,8 @@ import { fileURLToPath as fileURLToPath17 } from "node:url";
617590
617867
  import { dirname as dirname37, join as join135, resolve as resolve43 } from "node:path";
617591
617868
  import { homedir as homedir45 } from "node:os";
617592
617869
  import { spawn as spawn29, execSync as execSync57 } from "node:child_process";
617593
- import { mkdirSync as mkdirSync71, writeFileSync as writeFileSync66, readFileSync as readFileSync98, readdirSync as readdirSync41, existsSync as existsSync120, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync24 } from "node:fs";
617594
- import { randomBytes as randomBytes23, randomUUID as randomUUID16 } from "node:crypto";
617870
+ import { mkdirSync as mkdirSync71, writeFileSync as writeFileSync66, readFileSync as readFileSync98, readdirSync as readdirSync41, existsSync as existsSync120, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync25 } from "node:fs";
617871
+ import { randomBytes as randomBytes24, randomUUID as randomUUID16 } from "node:crypto";
617595
617872
  import { createHash as createHash23 } from "node:crypto";
617596
617873
  function getVersion3() {
617597
617874
  try {
@@ -618340,13 +618617,13 @@ function pruneOldJobs() {
618340
618617
  const ts = ageRef ? Date.parse(ageRef) : NaN;
618341
618618
  if (Number.isFinite(ts) && ts < cutoffMs) {
618342
618619
  try {
618343
- unlinkSync24(path11);
618620
+ unlinkSync25(path11);
618344
618621
  } catch {
618345
618622
  }
618346
618623
  const outFile = path11.replace(/\.json$/, ".output");
618347
618624
  if (existsSync120(outFile)) {
618348
618625
  try {
618349
- unlinkSync24(outFile);
618626
+ unlinkSync25(outFile);
618350
618627
  } catch {
618351
618628
  }
618352
618629
  }
@@ -618356,7 +618633,7 @@ function pruneOldJobs() {
618356
618633
  }
618357
618634
  } catch {
618358
618635
  try {
618359
- unlinkSync24(path11);
618636
+ unlinkSync25(path11);
618360
618637
  pruned++;
618361
618638
  } catch {
618362
618639
  }
@@ -618648,7 +618925,7 @@ function atomicJobWrite(dir, id, job) {
618648
618925
  } catch {
618649
618926
  }
618650
618927
  try {
618651
- unlinkSync24(tmpPath);
618928
+ unlinkSync25(tmpPath);
618652
618929
  } catch {
618653
618930
  }
618654
618931
  }
@@ -619213,7 +619490,7 @@ ${messages2[firstSystemIdx].content}`
619213
619490
  messages2.unshift({ role: "system", content: SYSTEM_FACTUAL_FIRST });
619214
619491
  }
619215
619492
  }
619216
- const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
619493
+ const chatId = `chatcmpl-${randomBytes24(12).toString("hex")}`;
619217
619494
  const turnsLog = [];
619218
619495
  for (let turn = 1; turn <= maxTurns; turn++) {
619219
619496
  if (Date.now() > totalDeadline) {
@@ -619478,7 +619755,7 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
619478
619755
  "Cache-Control": "no-cache",
619479
619756
  "Connection": "keep-alive"
619480
619757
  });
619481
- const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
619758
+ const chatId = `chatcmpl-${randomBytes24(12).toString("hex")}`;
619482
619759
  let buffer2 = "";
619483
619760
  ollamaStream(
619484
619761
  targetUrl,
@@ -619520,7 +619797,7 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
619520
619797
  if (ollamaChunk.message.content) delta.content = ollamaChunk.message.content;
619521
619798
  if (ollamaChunk.message.tool_calls) {
619522
619799
  delta.tool_calls = ollamaChunk.message.tool_calls.map((tc, idx) => ({
619523
- id: tc.id || `call_${randomBytes23(8).toString("hex")}`,
619800
+ id: tc.id || `call_${randomBytes24(8).toString("hex")}`,
619524
619801
  type: "function",
619525
619802
  function: {
619526
619803
  name: tc?.function?.name ?? tc?.name ?? "",
@@ -619599,14 +619876,14 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
619599
619876
  if (ollamaResp.eval_count) metrics.totalTokensOut += ollamaResp.eval_count;
619600
619877
  if (ollamaResp.prompt_eval_count) metrics.totalTokensIn += ollamaResp.prompt_eval_count;
619601
619878
  trackTokens("local", ollamaResp.prompt_eval_count ?? 0, ollamaResp.eval_count ?? 0);
619602
- const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
619879
+ const chatId = `chatcmpl-${randomBytes24(12).toString("hex")}`;
619603
619880
  const responseMessage = {
619604
619881
  role: ollamaResp.message?.role ?? "assistant",
619605
619882
  content: ollamaResp.message?.content ?? ""
619606
619883
  };
619607
619884
  if (ollamaResp.message?.tool_calls && ollamaResp.message.tool_calls.length > 0) {
619608
619885
  responseMessage.tool_calls = ollamaResp.message.tool_calls.map((tc, idx) => ({
619609
- id: tc.id || `call_${randomBytes23(8).toString("hex")}`,
619886
+ id: tc.id || `call_${randomBytes24(8).toString("hex")}`,
619610
619887
  type: "function",
619611
619888
  function: {
619612
619889
  name: tc?.function?.name ?? tc?.name ?? "",
@@ -620391,7 +620668,7 @@ async function handleV1Run(req2, res) {
620391
620668
  return;
620392
620669
  }
620393
620670
  }
620394
- const id = `job-${randomBytes23(8).toString("hex")}`;
620671
+ const id = `job-${randomBytes24(8).toString("hex")}`;
620395
620672
  const dir = jobsDir();
620396
620673
  const workingDir = requestBody["working_directory"] || req2.headers["x-working-directory"];
620397
620674
  const isolate = requestBody["isolate"] === true;
@@ -621558,7 +621835,7 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
621558
621835
  return;
621559
621836
  }
621560
621837
  const { tmpdir: tmpdir23 } = await import("node:os");
621561
- const { writeFileSync: writeFileSync71, unlinkSync: unlinkSync25 } = await import("node:fs");
621838
+ const { writeFileSync: writeFileSync71, unlinkSync: unlinkSync26 } = await import("node:fs");
621562
621839
  const { join: pjoin } = await import("node:path");
621563
621840
  const tmpPath = pjoin(tmpdir23(), `omnius-clone-upload-${Date.now()}-${safeName2}`);
621564
621841
  writeFileSync71(tmpPath, buf);
@@ -621573,7 +621850,7 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
621573
621850
  });
621574
621851
  } finally {
621575
621852
  try {
621576
- unlinkSync25(tmpPath);
621853
+ unlinkSync26(tmpPath);
621577
621854
  } catch {
621578
621855
  }
621579
621856
  }
@@ -624026,8 +624303,8 @@ function startApiServer(options2 = {}) {
624026
624303
  const job = JSON.parse(readFileSync98(jobPath, "utf-8"));
624027
624304
  const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
624028
624305
  if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
624029
- const { unlinkSync: unlinkSync25 } = require4("node:fs");
624030
- unlinkSync25(jobPath);
624306
+ const { unlinkSync: unlinkSync26 } = require4("node:fs");
624307
+ unlinkSync26(jobPath);
624031
624308
  }
624032
624309
  } catch {
624033
624310
  }
@@ -625026,7 +625303,7 @@ var init_clipboard_media = __esm({
625026
625303
 
625027
625304
  // packages/cli/src/tui/interactive.ts
625028
625305
  import { cwd } from "node:process";
625029
- import { resolve as resolve44, join as join137, dirname as dirname38, extname as extname14, relative as relative14 } from "node:path";
625306
+ import { resolve as resolve44, join as join137, dirname as dirname38, extname as extname15, relative as relative14 } from "node:path";
625030
625307
  import { createRequire as createRequire8 } from "node:module";
625031
625308
  import { fileURLToPath as fileURLToPath18 } from "node:url";
625032
625309
  import {
@@ -632328,7 +632605,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
632328
632605
  const imgPath = resolve44(repoRoot, cleanPath);
632329
632606
  const imgBuffer = readFileSync100(imgPath);
632330
632607
  const base642 = imgBuffer.toString("base64");
632331
- const ext = extname14(cleanPath).toLowerCase();
632608
+ const ext = extname15(cleanPath).toLowerCase();
632332
632609
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
632333
632610
  const asciiContext = await renderAsciiPreviewForImage(
632334
632611
  imgPath,
@@ -633511,7 +633788,7 @@ __export(run_exports, {
633511
633788
  import { resolve as resolve45 } from "node:path";
633512
633789
  import { spawn as spawn30 } from "node:child_process";
633513
633790
  import { mkdirSync as mkdirSync74, writeFileSync as writeFileSync69, readFileSync as readFileSync101, readdirSync as readdirSync43, existsSync as existsSync122 } from "node:fs";
633514
- import { randomBytes as randomBytes24 } from "node:crypto";
633791
+ import { randomBytes as randomBytes25 } from "node:crypto";
633515
633792
  import { join as join138 } from "node:path";
633516
633793
  function jobsDir2(repoPath) {
633517
633794
  const root = resolve45(repoPath ?? process.cwd());
@@ -633609,7 +633886,7 @@ function extractSummary(captured) {
633609
633886
  return lines.slice(-3).join(" ").slice(0, 200);
633610
633887
  }
633611
633888
  async function runBackground(task, config, opts) {
633612
- const id = `job-${randomBytes24(3).toString("hex")}`;
633889
+ const id = `job-${randomBytes25(3).toString("hex")}`;
633613
633890
  const dir = jobsDir2(opts.repoPath);
633614
633891
  const repoRoot = resolve45(opts.repoPath ?? process.cwd());
633615
633892
  const job = {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "omnius",
9
- "version": "1.0.18",
9
+ "version": "1.0.20",
10
10
  "bundleDependencies": [
11
11
  "image-to-ascii"
12
12
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omnius",
3
- "version": "1.0.18",
3
+ "version": "1.0.20",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",