omnius 1.0.11 → 1.0.13

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
@@ -181,7 +181,7 @@ function printWarning(message2) {
181
181
  `);
182
182
  }
183
183
  function printInfo(message2) {
184
- process.stdout.write(`${c.cyan("")} ${message2}
184
+ process.stdout.write(`${c.cyan("i")} ${message2}
185
185
  `);
186
186
  }
187
187
  function printKeyValue(key, value2, indent = 0) {
@@ -229,7 +229,7 @@ var init_output = __esm({
229
229
  isStderrTTY = process.stderr.isTTY;
230
230
  c = {
231
231
  bold: (t2) => ansi("1", t2, isTTY),
232
- dim: (t2) => ansi("2", t2, isTTY),
232
+ dim: (t2) => ansi("38;5;250", t2, isTTY),
233
233
  red: (t2) => ansi("31", t2, isTTY),
234
234
  green: (t2) => ansi("32", t2, isTTY),
235
235
  yellow: (t2) => ansi("33", t2, isTTY),
@@ -249037,11 +249037,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
249037
249037
  * what was previously computed. */
249038
249038
  async loadSessionInfo() {
249039
249039
  try {
249040
- const { readFileSync: readFileSync101, existsSync: existsSync123 } = await import("node:fs");
249040
+ const { readFileSync: readFileSync102, existsSync: existsSync123 } = await import("node:fs");
249041
249041
  const sessionPath2 = join31(this.cwd, ".omnius", "rlm", "session.json");
249042
249042
  if (!existsSync123(sessionPath2))
249043
249043
  return null;
249044
- return JSON.parse(readFileSync101(sessionPath2, "utf8"));
249044
+ return JSON.parse(readFileSync102(sessionPath2, "utf8"));
249045
249045
  } catch {
249046
249046
  return null;
249047
249047
  }
@@ -249218,10 +249218,10 @@ var init_memory_metabolism = __esm({
249218
249218
  const trajDir = join32(this.cwd, ".omnius", "rlm-trajectories");
249219
249219
  let lessons = [];
249220
249220
  try {
249221
- const { readdirSync: readdirSync42, readFileSync: readFileSync101 } = await import("node:fs");
249221
+ const { readdirSync: readdirSync42, readFileSync: readFileSync102 } = await import("node:fs");
249222
249222
  const files = readdirSync42(trajDir).filter((f2) => f2.endsWith(".jsonl")).sort().reverse().slice(0, 3);
249223
249223
  for (const file of files) {
249224
- const lines = readFileSync101(join32(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
249224
+ const lines = readFileSync102(join32(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
249225
249225
  for (const line of lines) {
249226
249226
  try {
249227
249227
  const entry = JSON.parse(line);
@@ -249605,14 +249605,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
249605
249605
  * Optionally filter by task type for phase-aware context (FSM paper insight).
249606
249606
  */
249607
249607
  getTopMemoriesSync(k = 5, taskType) {
249608
- const { readFileSync: readFileSync101, existsSync: existsSync123 } = __require("node:fs");
249608
+ const { readFileSync: readFileSync102, existsSync: existsSync123 } = __require("node:fs");
249609
249609
  const metaDir = join32(this.cwd, ".omnius", "memory", "metabolism");
249610
249610
  const storeFile = join32(metaDir, "store.json");
249611
249611
  if (!existsSync123(storeFile))
249612
249612
  return "";
249613
249613
  let store2 = [];
249614
249614
  try {
249615
- store2 = JSON.parse(readFileSync101(storeFile, "utf8"));
249615
+ store2 = JSON.parse(readFileSync102(storeFile, "utf8"));
249616
249616
  } catch {
249617
249617
  return "";
249618
249618
  }
@@ -249634,14 +249634,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
249634
249634
  /** Update memory scores based on task outcome. Called after task completion.
249635
249635
  * Memories used in successful tasks get boosted. Memories present during failures get decayed. */
249636
249636
  updateFromOutcomeSync(surfacedMemoryText, succeeded) {
249637
- const { readFileSync: readFileSync101, writeFileSync: writeFileSync71, existsSync: existsSync123, mkdirSync: mkdirSync76 } = __require("node:fs");
249637
+ const { readFileSync: readFileSync102, writeFileSync: writeFileSync71, existsSync: existsSync123, mkdirSync: mkdirSync76 } = __require("node:fs");
249638
249638
  const metaDir = join32(this.cwd, ".omnius", "memory", "metabolism");
249639
249639
  const storeFile = join32(metaDir, "store.json");
249640
249640
  if (!existsSync123(storeFile))
249641
249641
  return;
249642
249642
  let store2 = [];
249643
249643
  try {
249644
- store2 = JSON.parse(readFileSync101(storeFile, "utf8"));
249644
+ store2 = JSON.parse(readFileSync102(storeFile, "utf8"));
249645
249645
  } catch {
249646
249646
  return;
249647
249647
  }
@@ -250088,13 +250088,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
250088
250088
  // Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
250089
250089
  /** Retrieve top-K strategies for context injection. Returns "" if none. */
250090
250090
  getRelevantStrategiesSync(k = 3, taskType) {
250091
- const { readFileSync: readFileSync101, existsSync: existsSync123 } = __require("node:fs");
250091
+ const { readFileSync: readFileSync102, existsSync: existsSync123 } = __require("node:fs");
250092
250092
  const archiveFile = join34(this.cwd, ".omnius", "arche", "variants.json");
250093
250093
  if (!existsSync123(archiveFile))
250094
250094
  return "";
250095
250095
  let variants = [];
250096
250096
  try {
250097
- variants = JSON.parse(readFileSync101(archiveFile, "utf8"));
250097
+ variants = JSON.parse(readFileSync102(archiveFile, "utf8"));
250098
250098
  } catch {
250099
250099
  return "";
250100
250100
  }
@@ -250112,13 +250112,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
250112
250112
  }
250113
250113
  /** Archive a strategy variant synchronously (for task completion path) */
250114
250114
  archiveVariantSync(strategy, outcome, tags = []) {
250115
- const { readFileSync: readFileSync101, writeFileSync: writeFileSync71, existsSync: existsSync123, mkdirSync: mkdirSync76 } = __require("node:fs");
250115
+ const { readFileSync: readFileSync102, writeFileSync: writeFileSync71, existsSync: existsSync123, mkdirSync: mkdirSync76 } = __require("node:fs");
250116
250116
  const dir = join34(this.cwd, ".omnius", "arche");
250117
250117
  const archiveFile = join34(dir, "variants.json");
250118
250118
  let variants = [];
250119
250119
  try {
250120
250120
  if (existsSync123(archiveFile))
250121
- variants = JSON.parse(readFileSync101(archiveFile, "utf8"));
250121
+ variants = JSON.parse(readFileSync102(archiveFile, "utf8"));
250122
250122
  } catch {
250123
250123
  }
250124
250124
  variants.push({
@@ -250335,6 +250335,36 @@ import { spawn as spawn9 } from "node:child_process";
250335
250335
  import { existsSync as existsSync23, statSync as statSync8 } from "node:fs";
250336
250336
  import { chmod as chmod3, mkdir as mkdir11, writeFile as writeFile16 } from "node:fs/promises";
250337
250337
  import { join as join36, resolve as resolve18 } from "node:path";
250338
+ function parsePercent(text) {
250339
+ const match = text.match(/\b(\d{1,3})%\b/);
250340
+ if (!match)
250341
+ return void 0;
250342
+ const value2 = Number(match[1]);
250343
+ if (!Number.isFinite(value2))
250344
+ return void 0;
250345
+ return Math.max(0, Math.min(100, value2));
250346
+ }
250347
+ function cleanProgressText(text) {
250348
+ return text.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, "").replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
250349
+ }
250350
+ function parseStructuredProgress(text) {
250351
+ const trimmed = text.trim();
250352
+ if (!trimmed.startsWith("{"))
250353
+ return null;
250354
+ try {
250355
+ const parsed = JSON.parse(trimmed);
250356
+ if (parsed["omnius_progress"] !== true)
250357
+ return null;
250358
+ const stage = String(parsed["stage"] ?? "process");
250359
+ const message2 = String(parsed["message"] ?? "").trim();
250360
+ const percent = typeof parsed["percent"] === "number" ? parsed["percent"] : void 0;
250361
+ if (!message2)
250362
+ return null;
250363
+ return { stage, message: message2, percent };
250364
+ } catch {
250365
+ return null;
250366
+ }
250367
+ }
250338
250368
  function numberArg(value2, fallback) {
250339
250369
  const n2 = Number(value2);
250340
250370
  return Number.isFinite(n2) && n2 > 0 ? n2 : fallback;
@@ -250430,6 +250460,7 @@ function imageGenerationSetupPlan(backend, repoRoot = ".", model) {
250430
250460
  }
250431
250461
  async function runProcess2(command, args, options2) {
250432
250462
  return new Promise((resolveProcess) => {
250463
+ const startedAt2 = Date.now();
250433
250464
  const child = spawn9(command, args, {
250434
250465
  cwd: options2.cwd,
250435
250466
  env: { ...process.env, ...options2.env },
@@ -250437,22 +250468,66 @@ async function runProcess2(command, args, options2) {
250437
250468
  });
250438
250469
  let stdout = "";
250439
250470
  let stderr = "";
250471
+ let lastProgress = "";
250472
+ let lastProgressAt = 0;
250473
+ const emitProgress = (stream, raw) => {
250474
+ if (!options2.onProgress)
250475
+ return;
250476
+ const parts = raw.split(/[\r\n]+/).filter((part) => part.trim());
250477
+ for (const part of parts.length > 0 ? parts : [raw]) {
250478
+ const clean3 = cleanProgressText(part);
250479
+ if (!clean3)
250480
+ continue;
250481
+ const now = Date.now();
250482
+ const structured = parseStructuredProgress(clean3);
250483
+ if (clean3 === lastProgress && now - lastProgressAt < 750)
250484
+ continue;
250485
+ lastProgress = clean3;
250486
+ lastProgressAt = now;
250487
+ if (structured) {
250488
+ options2.onProgress({ ...structured, elapsedMs: now - startedAt2 });
250489
+ } else {
250490
+ options2.onProgress({
250491
+ stage: stream === "stderr" ? "download" : "process",
250492
+ message: clean3.length > 220 ? clean3.slice(0, 217) + "..." : clean3,
250493
+ percent: parsePercent(clean3),
250494
+ elapsedMs: now - startedAt2
250495
+ });
250496
+ }
250497
+ }
250498
+ };
250440
250499
  const timer = setTimeout(() => {
250441
250500
  child.kill("SIGTERM");
250442
250501
  }, options2.timeoutMs);
250443
250502
  timer.unref();
250503
+ const heartbeat = setInterval(() => {
250504
+ if (!options2.onProgress || !options2.progressLabel)
250505
+ return;
250506
+ options2.onProgress({
250507
+ stage: "process",
250508
+ message: `${options2.progressLabel} still running`,
250509
+ elapsedMs: Date.now() - startedAt2
250510
+ });
250511
+ }, 5e3);
250512
+ heartbeat.unref();
250444
250513
  child.stdout?.on("data", (chunk) => {
250445
- stdout += chunk.toString();
250514
+ const text = chunk.toString();
250515
+ stdout += text;
250516
+ emitProgress("stdout", text);
250446
250517
  });
250447
250518
  child.stderr?.on("data", (chunk) => {
250448
- stderr += chunk.toString();
250519
+ const text = chunk.toString();
250520
+ stderr += text;
250521
+ emitProgress("stderr", text);
250449
250522
  });
250450
250523
  child.on("error", (err) => {
250451
250524
  clearTimeout(timer);
250525
+ clearInterval(heartbeat);
250452
250526
  resolveProcess({ code: 127, stdout, stderr: stderr + String(err.message || err) });
250453
250527
  });
250454
250528
  child.on("close", (code8) => {
250455
250529
  clearTimeout(timer);
250530
+ clearInterval(heartbeat);
250456
250531
  resolveProcess({ code: code8, stdout, stderr });
250457
250532
  });
250458
250533
  });
@@ -250468,6 +250543,8 @@ function imageGenerationPythonEnv(repoRoot) {
250468
250543
  const hf = join36(root, "huggingface");
250469
250544
  return {
250470
250545
  PYTHONUNBUFFERED: "1",
250546
+ HF_HUB_DISABLE_PROGRESS_BARS: "0",
250547
+ TQDM_DISABLE: "0",
250471
250548
  HF_HOME: hf,
250472
250549
  HUGGINGFACE_HUB_CACHE: join36(hf, "hub"),
250473
250550
  TRANSFORMERS_CACHE: join36(hf, "transformers"),
@@ -250494,7 +250571,7 @@ async function pythonCanImport(command, code8, repoRoot, env2) {
250494
250571
  const result = await runProcess2(command, ["-c", code8], { cwd: repoRoot, timeoutMs: 6e4, env: env2 });
250495
250572
  return result.code === 0;
250496
250573
  }
250497
- async function ensurePythonFor(repoRoot, kind, explicit) {
250574
+ async function ensurePythonFor(repoRoot, kind, explicit, onProgress) {
250498
250575
  const pythonEnv = imageGenerationPythonEnv(repoRoot);
250499
250576
  await ensureImageGenerationCacheDirs(repoRoot);
250500
250577
  if (explicit)
@@ -250505,7 +250582,14 @@ async function ensurePythonFor(repoRoot, kind, explicit) {
250505
250582
  const venvDir = kind === "diffusers" ? diffusersVenvDir(repoRoot) : sdcppVenvDir(repoRoot);
250506
250583
  const command = venvPython(venvDir);
250507
250584
  if (!existsSync23(command)) {
250508
- const created = await runProcess2("python3", ["-m", "venv", venvDir], { cwd: repoRoot, timeoutMs: 18e4, env: pythonEnv });
250585
+ onProgress?.({ stage: "setup", message: `Creating image-generation Python environment at ${venvDir}` });
250586
+ const created = await runProcess2("python3", ["-m", "venv", venvDir], {
250587
+ cwd: repoRoot,
250588
+ timeoutMs: 18e4,
250589
+ env: pythonEnv,
250590
+ progressLabel: "Creating image-generation Python environment",
250591
+ onProgress
250592
+ });
250509
250593
  if (created.code !== 0) {
250510
250594
  throw new Error(`Failed to create image-generation venv at ${venvDir}.
250511
250595
  ${trimProcessText(created.stderr || created.stdout)}`);
@@ -250516,10 +250600,13 @@ ${trimProcessText(created.stderr || created.stdout)}`);
250516
250600
  return { command, env: pythonEnv };
250517
250601
  }
250518
250602
  const packages = kind === "diffusers" ? DIFFUSERS_PYTHON_PACKAGES : SDCPP_PYTHON_PACKAGES;
250519
- const pip = await runProcess2(command, ["-m", "pip", "install", "-U", "pip", ...packages], {
250603
+ onProgress?.({ stage: "setup", message: `Installing ${kind} image-generation Python packages` });
250604
+ const pip = await runProcess2(command, ["-m", "pip", "install", "--progress-bar", "on", "-U", "pip", ...packages], {
250520
250605
  cwd: repoRoot,
250521
250606
  timeoutMs: 18e5,
250522
- env: pythonEnv
250607
+ env: pythonEnv,
250608
+ progressLabel: `Installing ${kind} image-generation Python packages`,
250609
+ onProgress
250523
250610
  });
250524
250611
  if (pip.code !== 0) {
250525
250612
  throw new Error(`Failed to install ${kind} image-generation packages into ${venvDir}.
@@ -250893,9 +250980,16 @@ var init_image_generate = __esm({
250893
250980
  import argparse
250894
250981
  import json
250895
250982
  import os
250983
+ import sys
250896
250984
  import time
250897
250985
  from pathlib import Path
250898
250986
 
250987
+ def _progress(stage, message, percent=None):
250988
+ payload = {"omnius_progress": True, "stage": stage, "message": message}
250989
+ if percent is not None:
250990
+ payload["percent"] = percent
250991
+ print(json.dumps(payload), file=sys.stderr, flush=True)
250992
+
250899
250993
  def _device():
250900
250994
  import torch
250901
250995
  if torch.cuda.is_available():
@@ -250943,12 +251037,15 @@ def main():
250943
251037
  kwargs["variant"] = args.variant
250944
251038
 
250945
251039
  try:
251040
+ _progress("load", f"loading model {args.model}")
250946
251041
  pipeline_cls = _pipeline_class(args.model)
250947
251042
  pipe = pipeline_cls.from_pretrained(args.model, **kwargs)
250948
251043
  except Exception:
251044
+ _progress("load", f"retrying model load without variant for {args.model}")
250949
251045
  kwargs.pop("variant", None)
250950
251046
  pipeline_cls = _pipeline_class(args.model)
250951
251047
  pipe = pipeline_cls.from_pretrained(args.model, **kwargs)
251048
+ _progress("load", f"model loaded on {device}")
250952
251049
 
250953
251050
  if hasattr(pipe, "enable_attention_slicing"):
250954
251051
  try:
@@ -250976,14 +251073,17 @@ def main():
250976
251073
  "height": args.height,
250977
251074
  }
250978
251075
  try:
251076
+ _progress("generate", f"generating {args.width}x{args.height} image with {args.steps} steps")
250979
251077
  image = pipe(**call_kwargs).images[0]
250980
251078
  except TypeError:
250981
251079
  call_kwargs.pop("width", None)
250982
251080
  call_kwargs.pop("height", None)
251081
+ _progress("generate", f"generating image with model-native dimensions and {args.steps} steps")
250983
251082
  image = pipe(**call_kwargs).images[0]
250984
251083
 
250985
251084
  out = Path(args.output)
250986
251085
  out.parent.mkdir(parents=True, exist_ok=True)
251086
+ _progress("save", f"saving image to {out}")
250987
251087
  image.save(out)
250988
251088
  print(json.dumps({
250989
251089
  "ok": True,
@@ -251094,9 +251194,34 @@ if __name__ == "__main__":
251094
251194
  cwd;
251095
251195
  ollamaUrl;
251096
251196
  cachedImageModel = null;
251097
- constructor(cwd4, ollamaUrl = "http://localhost:11434") {
251197
+ progressHandler = null;
251198
+ lastProgressMessage = "";
251199
+ lastProgressAt = 0;
251200
+ defaultModel;
251201
+ defaultBackend;
251202
+ constructor(cwd4, ollamaUrl = "http://localhost:11434", defaults3 = {}) {
251098
251203
  this.cwd = cwd4;
251099
251204
  this.ollamaUrl = ollamaUrl.replace(/\/v1\/?$/, "").replace(/\/$/, "");
251205
+ this.defaultModel = defaults3.model;
251206
+ this.defaultBackend = defaults3.backend;
251207
+ }
251208
+ setDefaults(defaults3) {
251209
+ this.defaultModel = defaults3.model;
251210
+ this.defaultBackend = defaults3.backend;
251211
+ }
251212
+ setProgressCallback(handler) {
251213
+ this.progressHandler = handler;
251214
+ }
251215
+ emitProgress(event) {
251216
+ if (!this.progressHandler)
251217
+ return;
251218
+ const now = Date.now();
251219
+ const key = `${event.stage}:${event.percent ?? ""}:${event.message}`;
251220
+ if (key === this.lastProgressMessage && now - this.lastProgressAt < 750)
251221
+ return;
251222
+ this.lastProgressMessage = key;
251223
+ this.lastProgressAt = now;
251224
+ this.progressHandler(event);
251100
251225
  }
251101
251226
  async execute(args) {
251102
251227
  const start2 = performance.now();
@@ -251128,9 +251253,9 @@ if __name__ == "__main__":
251128
251253
  if (!prompt) {
251129
251254
  return { success: false, output: "No prompt provided", error: "Empty prompt", durationMs: 0 };
251130
251255
  }
251131
- const rawModel = args["model_path"] ? String(args["model_path"]) : args["model"] ? String(args["model"]) : void 0;
251256
+ const rawModel = args["model_path"] ? String(args["model_path"]) : args["model"] ? String(args["model"]) : this.defaultModel;
251132
251257
  const requestedModel = rawModel === "auto" ? void 0 : rawModel;
251133
- const requestedBackend = args["backend"] ? String(args["backend"]) : void 0;
251258
+ const requestedBackend = args["backend"] ? String(args["backend"]) : this.defaultBackend;
251134
251259
  const preset = getImageGenerationPreset(requestedModel);
251135
251260
  const width = numberArg(args["width"], preset?.width ?? 1024);
251136
251261
  const height = numberArg(args["height"], preset?.height ?? 1024);
@@ -251141,12 +251266,14 @@ if __name__ == "__main__":
251141
251266
  let backend = inferImageGenerationBackend(requestedModel, requestedBackend);
251142
251267
  let model = requestedModel;
251143
251268
  if (backend === "auto") {
251144
- backend = "diffusers";
251145
- model = DEFAULT_DIFFUSERS_IMAGE_MODEL;
251269
+ backend = inferImageGenerationBackend(model, void 0);
251270
+ if (backend === "auto")
251271
+ backend = "diffusers";
251146
251272
  }
251147
251273
  if (!model) {
251148
251274
  model = backend === "diffusers" ? DEFAULT_DIFFUSERS_IMAGE_MODEL : DEFAULT_OLLAMA_IMAGE_MODEL;
251149
251275
  }
251276
+ this.emitProgress({ stage: "setup", message: `Using image model ${model} (${backend})` });
251150
251277
  if (backend === "ollama") {
251151
251278
  return await this.generateWithOllama({ prompt, model, width, height, steps, start: start2 });
251152
251279
  }
@@ -251239,7 +251366,7 @@ ${errText.slice(0, 800)}`,
251239
251366
  const filepath = outputPath(this.cwd);
251240
251367
  let python;
251241
251368
  try {
251242
- python = await ensurePythonFor(this.cwd, "diffusers", typeof args.python === "string" ? args.python : void 0);
251369
+ python = await ensurePythonFor(this.cwd, "diffusers", typeof args.python === "string" ? args.python : void 0, (event) => this.emitProgress(event));
251243
251370
  } catch (err) {
251244
251371
  const plan = imageGenerationSetupPlan("diffusers", this.cwd, args.model);
251245
251372
  return {
@@ -251273,7 +251400,14 @@ ${errText.slice(0, 800)}`,
251273
251400
  ];
251274
251401
  if (args.seed !== void 0)
251275
251402
  argv.push("--seed", String(args.seed));
251276
- const result = await runProcess2(python.command, argv, { cwd: this.cwd, timeoutMs: 9e5, env: python.env });
251403
+ this.emitProgress({ stage: "load", message: `Starting image generation with ${args.model}` });
251404
+ const result = await runProcess2(python.command, argv, {
251405
+ cwd: this.cwd,
251406
+ timeoutMs: 9e5,
251407
+ env: python.env,
251408
+ progressLabel: `Downloading/loading ${args.model}`,
251409
+ onProgress: (event) => this.emitProgress(event)
251410
+ });
251277
251411
  if (result.code !== 0 || !existsSync23(filepath)) {
251278
251412
  const plan = imageGenerationSetupPlan("diffusers", this.cwd, args.model);
251279
251413
  return {
@@ -525234,9 +525368,9 @@ var init_reflectionBuffer = __esm({
525234
525368
  this.persistPath = persistPath ?? null;
525235
525369
  if (this.persistPath) {
525236
525370
  try {
525237
- const { readFileSync: readFileSync101, existsSync: existsSync123 } = __require("node:fs");
525371
+ const { readFileSync: readFileSync102, existsSync: existsSync123 } = __require("node:fs");
525238
525372
  if (existsSync123(this.persistPath)) {
525239
- this.state = JSON.parse(readFileSync101(this.persistPath, "utf-8"));
525373
+ this.state = JSON.parse(readFileSync102(this.persistPath, "utf-8"));
525240
525374
  return;
525241
525375
  }
525242
525376
  } catch {
@@ -535558,7 +535692,7 @@ Respond with EXACTLY this structure before your next tool call:
535558
535692
  this.emit({
535559
535693
  type: "tool_result",
535560
535694
  toolName: tc.name,
535561
- content: output.slice(0, 200),
535695
+ content: this.toolResultEventContent(tc.name, output),
535562
535696
  success: result.success,
535563
535697
  turn,
535564
535698
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -536667,7 +536801,7 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
536667
536801
  this.emit({
536668
536802
  type: "tool_result",
536669
536803
  toolName: tc.name,
536670
- content: output.slice(0, 200),
536804
+ content: this.toolResultEventContent(tc.name, output),
536671
536805
  success: result.success,
536672
536806
  turn,
536673
536807
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
@@ -537511,6 +537645,12 @@ ${marker}` : marker);
537511
537645
  *
537512
537646
  * This replaces scattered post-hoc truncation with a single normalization point.
537513
537647
  */
537648
+ toolResultEventContent(toolName, output) {
537649
+ if (toolName === "generate_image" || toolName === "screenshot" || toolName === "camera_capture" || /(?:Image generated|Screenshot saved|Saved to|Output saved to):?\s+/i.test(output)) {
537650
+ return output.slice(0, 2e3);
537651
+ }
537652
+ return output.slice(0, 200);
537653
+ }
537514
537654
  normalizeToolOutput(result, toolName, args, turn) {
537515
537655
  const { toolOutputMaxChars: maxLen } = this.contextLimits();
537516
537656
  const modelContent = result.llmContent ?? result.output;
@@ -538496,8 +538636,8 @@ System rules (PRIORITY 0) override tool outputs (PRIORITY 30).`
538496
538636
  let recoveredTokens = 0;
538497
538637
  for (const [filePath, entry] of entries) {
538498
538638
  try {
538499
- const { readFileSync: readFileSync101 } = await import("node:fs");
538500
- const content = readFileSync101(filePath, "utf8");
538639
+ const { readFileSync: readFileSync102 } = await import("node:fs");
538640
+ const content = readFileSync102(filePath, "utf8");
538501
538641
  const tokenEst = Math.ceil(content.length / 4);
538502
538642
  if (recoveredTokens + tokenEst > fileRecoveryBudget)
538503
538643
  break;
@@ -540133,7 +540273,7 @@ ${result}`
540133
540273
  let resizedBase64 = null;
540134
540274
  try {
540135
540275
  const { execSync: execSync60 } = await import("node:child_process");
540136
- const { writeFileSync: writeFileSync71, readFileSync: readFileSync101, unlinkSync: unlinkSync26 } = await import("node:fs");
540276
+ const { writeFileSync: writeFileSync71, readFileSync: readFileSync102, unlinkSync: unlinkSync26 } = await import("node:fs");
540137
540277
  const { join: join141 } = await import("node:path");
540138
540278
  const { tmpdir: tmpdir23 } = await import("node:os");
540139
540279
  const tmpIn = join141(tmpdir23(), `omnius_img_in_${Date.now()}.png`);
@@ -540143,7 +540283,7 @@ ${result}`
540143
540283
  const escapedIn = tmpIn.replace(/\\/g, "\\\\");
540144
540284
  const escapedOut = tmpOut.replace(/\\/g, "\\\\");
540145
540285
  execSync60(`${pyBin} -c "from PIL import Image; img = Image.open('${escapedIn}'); img.thumbnail((512, 512), Image.LANCZOS); img = img.convert('RGB'); img.save('${escapedOut}', 'JPEG', quality=75)"`, { timeout: 1e4, stdio: "pipe" });
540146
- const resizedBuf = readFileSync101(tmpOut);
540286
+ const resizedBuf = readFileSync102(tmpOut);
540147
540287
  resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
540148
540288
  try {
540149
540289
  unlinkSync26(tmpIn);
@@ -545376,7 +545516,7 @@ var init_spinner = __esm({
545376
545516
  info(message2) {
545377
545517
  this.stop();
545378
545518
  const msg = message2 ?? this._text;
545379
- process.stdout.write(`\x1B[36mℹ\x1B[0m ${msg}
545519
+ process.stdout.write(`\x1B[36mi\x1B[0m ${msg}
545380
545520
  `);
545381
545521
  return this;
545382
545522
  }
@@ -550194,8 +550334,8 @@ var init_theme = __esm({
550194
550334
  // terminal default foreground
550195
550335
  textPrimary: -1,
550196
550336
  // terminal default foreground
550197
- textDim: 245,
550198
- // slightly dim
550337
+ textDim: 250,
550338
+ // readable dim text without ANSI faint
550199
550339
  boxColor: -1
550200
550340
  // terminal default foreground
550201
550341
  },
@@ -550207,8 +550347,8 @@ var init_theme = __esm({
550207
550347
  // teal
550208
550348
  textPrimary: 37,
550209
550349
  // teal
550210
- textDim: 240,
550211
- // grey
550350
+ textDim: 250,
550351
+ // readable grey
550212
550352
  boxColor: 37
550213
550353
  // teal
550214
550354
  },
@@ -550217,7 +550357,7 @@ var init_theme = __esm({
550217
550357
  bg: -1,
550218
550358
  accent: 37,
550219
550359
  textPrimary: 252,
550220
- textDim: 245,
550360
+ textDim: 250,
550221
550361
  boxColor: 252
550222
550362
  }
550223
550363
  };
@@ -551457,7 +551597,7 @@ ${icon} \x1B[38;5;198m${message2}\x1B[0m
551457
551597
  function renderInfo(message2) {
551458
551598
  const redir = _contentWriteHook?.redirect?.();
551459
551599
  const dim = dimFg();
551460
- const icon = `${dim}🛈\x1B[0m`;
551600
+ const icon = `${dim}i\x1B[0m`;
551461
551601
  const text = `${icon} ${dim}${message2}\x1B[0m
551462
551602
  `;
551463
551603
  if (redir) {
@@ -551746,7 +551886,7 @@ var init_render = __esm({
551746
551886
  isTTY2 = process.stdout.isTTY ?? false;
551747
551887
  c3 = {
551748
551888
  bold: (t2) => ansi2("1", t2),
551749
- dim: (t2) => ansi2("2", t2),
551889
+ dim: (t2) => isTTY2 ? `${dimFg()}${t2}\x1B[0m` : t2,
551750
551890
  italic: (t2) => ansi2("3", t2),
551751
551891
  red: (t2) => ansi2("31", t2),
551752
551892
  green: (t2) => ansi2("32", t2),
@@ -551761,10 +551901,10 @@ var init_render = __esm({
551761
551901
  ui = {
551762
551902
  /** Primary text — lighter grey (252) for main content */
551763
551903
  primary: (t2) => fg256(252, t2),
551764
- /** Sub-text — darker grey (245) for secondary info */
551765
- sub: (t2) => fg256(245, t2),
551766
- /** Dim text — very dark grey (240) for hints/placeholders */
551767
- hint: (t2) => fg256(240, t2),
551904
+ /** Sub-text — readable grey for secondary info */
551905
+ sub: (t2) => fg256(tuiTextDim(), t2),
551906
+ /** Dim text — readable grey for hints/placeholders */
551907
+ hint: (t2) => fg256(tuiTextDim(), t2),
551768
551908
  /** Error text — magenta (bright) for errors */
551769
551909
  error: (t2) => fg256(198, t2),
551770
551910
  /** Warning text — warm orange for warnings */
@@ -551801,14 +551941,14 @@ var init_render = __esm({
551801
551941
  // light peach
551802
551942
  link: 111,
551803
551943
  // periwinkle
551804
- blockquote: 245,
551805
- // grey
551806
- hr: 240,
551807
- // dark grey
551808
- listBullet: 245,
551809
- // grey
551810
- tableBar: 245
551811
- // grey
551944
+ blockquote: 250,
551945
+ // readable grey
551946
+ hr: 250,
551947
+ // readable grey
551948
+ listBullet: 250,
551949
+ // readable grey
551950
+ tableBar: 250
551951
+ // readable grey
551812
551952
  };
551813
551953
  TOOL_ICONS = {
551814
551954
  file_read: "📄",
@@ -556345,7 +556485,7 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
556345
556485
  async function fetchPeerModels(peerId, authKey) {
556346
556486
  try {
556347
556487
  const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
556348
- const { existsSync: existsSync123, readFileSync: readFileSync101 } = await import("node:fs");
556488
+ const { existsSync: existsSync123, readFileSync: readFileSync102 } = await import("node:fs");
556349
556489
  const { join: join141 } = await import("node:path");
556350
556490
  const cwd4 = process.cwd();
556351
556491
  const nexusTool = new NexusTool2(cwd4);
@@ -556354,7 +556494,7 @@ async function fetchPeerModels(peerId, authKey) {
556354
556494
  try {
556355
556495
  const statusPath = join141(nexusDir, "status.json");
556356
556496
  if (existsSync123(statusPath)) {
556357
- const status = JSON.parse(readFileSync101(statusPath, "utf8"));
556497
+ const status = JSON.parse(readFileSync102(statusPath, "utf8"));
556358
556498
  if (status.peerId === peerId) isLocalPeer = true;
556359
556499
  }
556360
556500
  } catch {
@@ -556363,7 +556503,7 @@ async function fetchPeerModels(peerId, authKey) {
556363
556503
  const pricingPath = join141(nexusDir, "pricing.json");
556364
556504
  if (existsSync123(pricingPath)) {
556365
556505
  try {
556366
- const pricing = JSON.parse(readFileSync101(pricingPath, "utf8"));
556506
+ const pricing = JSON.parse(readFileSync102(pricingPath, "utf8"));
556367
556507
  const localModels = (pricing.models || []).map((m2) => ({
556368
556508
  name: m2.model || "unknown",
556369
556509
  size: m2.parameterSize || "",
@@ -556379,7 +556519,7 @@ async function fetchPeerModels(peerId, authKey) {
556379
556519
  const cachePath = join141(nexusDir, "peer-models-cache.json");
556380
556520
  if (existsSync123(cachePath)) {
556381
556521
  try {
556382
- const cache8 = JSON.parse(readFileSync101(cachePath, "utf8"));
556522
+ const cache8 = JSON.parse(readFileSync102(cachePath, "utf8"));
556383
556523
  if (cache8.peerId === peerId && cache8.models?.length > 0) {
556384
556524
  const age = Date.now() - new Date(cache8.cachedAt).getTime();
556385
556525
  if (age < 5 * 60 * 1e3) {
@@ -556494,7 +556634,7 @@ async function fetchPeerModels(peerId, authKey) {
556494
556634
  const pricingPath = join141(nexusDir, "pricing.json");
556495
556635
  if (existsSync123(pricingPath)) {
556496
556636
  try {
556497
- const pricing = JSON.parse(readFileSync101(pricingPath, "utf8"));
556637
+ const pricing = JSON.parse(readFileSync102(pricingPath, "utf8"));
556498
556638
  return (pricing.models || []).map((m2) => ({
556499
556639
  name: m2.model || "unknown",
556500
556640
  size: m2.parameterSize || "",
@@ -559067,7 +559207,7 @@ var init_daemon_registry = __esm({
559067
559207
  bar += `${PANEL_BG} ${BTN_BG}\x1B[${fgColor}m ${label} \x1B[${dotColor}m●\x1B[${fgColor}m `;
559068
559208
  }
559069
559209
  if (!bar) {
559070
- return `${PANEL_BG} \x1B[38;5;240m⠀ no active daemons`;
559210
+ return `${PANEL_BG} \x1B[38;5;250m⠀ no active daemons`;
559071
559211
  }
559072
559212
  return bar + PANEL_BG;
559073
559213
  }
@@ -562478,7 +562618,7 @@ ${CONTENT_BG_SEQ}`);
562478
562618
  if (fullLine.length <= availWidth) {
562479
562619
  let displayLine;
562480
562620
  if (ghost) {
562481
- displayLine = fullLine + `\x1B[7m\x1B[38;5;${TEXT_DIM}m${ghost[0]}\x1B[0m${PANEL_BG_SEQ}\x1B[2m\x1B[38;5;${TEXT_DIM}m${ghost.slice(1)}\x1B[0m${PANEL_BG_SEQ}`;
562621
+ displayLine = fullLine + `\x1B[7m\x1B[38;5;${TEXT_DIM}m${ghost[0]}\x1B[0m${PANEL_BG_SEQ}\x1B[38;5;${TEXT_DIM}m${ghost.slice(1)}\x1B[0m${PANEL_BG_SEQ}`;
562482
562622
  } else {
562483
562623
  displayLine = _StatusBar.insertVisualCursor(fullLine, cursorPos);
562484
562624
  }
@@ -563677,13 +563817,13 @@ var init_tui_select = __esm({
563677
563817
  selectColors = {
563678
563818
  orange: (t2) => fg2563(208, t2),
563679
563819
  green: (t2) => ansi3("32", t2),
563680
- dim: (t2) => ansi3("2", t2),
563820
+ dim: (t2) => fg2563(tuiTextDim(), t2),
563681
563821
  bold: (t2) => ansi3("1", t2),
563682
563822
  cyan: (t2) => ansi3("36", t2),
563683
563823
  /** Lighter grey for filter matches (252 = near-white) */
563684
563824
  matchLight: (t2) => fg2563(252, t2),
563685
- /** Dark grey for non-matching items (240 = dark grey) */
563686
- matchDark: (t2) => fg2563(240, t2)
563825
+ /** Readable grey for non-matching items */
563826
+ matchDark: (t2) => fg2563(tuiTextDim(), t2)
563687
563827
  };
563688
563828
  }
563689
563829
  });
@@ -568228,7 +568368,7 @@ var init_drop_panel = __esm({
568228
568368
  isTTY4 = process.stdout.isTTY ?? false;
568229
568369
  dc = {
568230
568370
  bold: (t2) => ansi4("1", t2),
568231
- dim: (t2) => ansi4("2", t2),
568371
+ dim: (t2) => ansi4("38;5;250", t2),
568232
568372
  cyan: (t2) => ansi4("36", t2),
568233
568373
  green: (t2) => ansi4("32", t2),
568234
568374
  red: (t2) => ansi4("31", t2),
@@ -570727,7 +570867,7 @@ async function connectRPC(state, neovimPkg, cols) {
570727
570867
  state.outputChanId = chanId;
570728
570868
  await nvim.request("nvim_chan_send", [
570729
570869
  chanId,
570730
- "\x1B[36m── Agent Output ──\x1B[0m\r\n\r\n\x1B[2mAgent activity will appear here.\x1B[0m\r\n\x1B[2mCtrl+N toggles focus to input.\x1B[0m\r\n"
570870
+ "\x1B[36m── Agent Output ──\x1B[0m\r\n\r\n\x1B[38;5;250mAgent activity will appear here.\x1B[0m\r\n\x1B[38;5;250mCtrl+N toggles focus to input.\x1B[0m\r\n"
570731
570871
  ]);
570732
570872
  await nvim.request("nvim_win_set_option", [win.id, "number", false]);
570733
570873
  await nvim.request("nvim_win_set_option", [win.id, "relativenumber", false]);
@@ -572481,19 +572621,72 @@ __export(image_ascii_preview_exports, {
572481
572621
  });
572482
572622
  import { execFileSync as execFileSync2 } from "node:child_process";
572483
572623
  import { createRequire as createRequire4 } from "node:module";
572484
- import { existsSync as existsSync93, statSync as statSync31 } from "node:fs";
572624
+ import { existsSync as existsSync93, readFileSync as readFileSync75, statSync as statSync31 } from "node:fs";
572485
572625
  import { resolve as resolve37 } from "node:path";
572486
572626
  function clamp5(n2, min, max) {
572487
572627
  if (!Number.isFinite(n2)) return min;
572488
572628
  return Math.max(min, Math.min(max, Math.floor(n2)));
572489
572629
  }
572490
- function defaultAsciiPreviewSize() {
572630
+ function defaultAsciiPreviewSize(dimensions) {
572491
572631
  const columns = process.stdout.columns || 100;
572492
572632
  const rows = process.stdout.rows || 32;
572493
572633
  const width = clamp5(columns - 14, 42, 96);
572494
- const height = clamp5(Math.min(Math.round(width * 0.42), rows - 10), 12, 40);
572634
+ const imageAspect = dimensions && dimensions.width > 0 && dimensions.height > 0 ? dimensions.height / dimensions.width : 1;
572635
+ const height = clamp5(Math.min(Math.round(width * imageAspect * TERMINAL_CELL_ASPECT), rows - 10), 8, 42);
572495
572636
  return { width, height };
572496
572637
  }
572638
+ function readImageDimensions(imagePath) {
572639
+ try {
572640
+ const buf = readFileSync75(imagePath);
572641
+ if (buf.length >= 24 && buf.toString("ascii", 1, 4) === "PNG") {
572642
+ return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
572643
+ }
572644
+ if (buf.length >= 10 && buf.toString("ascii", 0, 3) === "GIF") {
572645
+ return { width: buf.readUInt16LE(6), height: buf.readUInt16LE(8) };
572646
+ }
572647
+ if (buf.length >= 12 && buf.toString("ascii", 0, 4) === "RIFF" && buf.toString("ascii", 8, 12) === "WEBP") {
572648
+ const chunk = buf.toString("ascii", 12, 16);
572649
+ if (chunk === "VP8X" && buf.length >= 30) {
572650
+ return {
572651
+ width: 1 + buf.readUIntLE(24, 3),
572652
+ height: 1 + buf.readUIntLE(27, 3)
572653
+ };
572654
+ }
572655
+ if (chunk === "VP8 " && buf.length >= 30) {
572656
+ return {
572657
+ width: buf.readUInt16LE(26) & 16383,
572658
+ height: buf.readUInt16LE(28) & 16383
572659
+ };
572660
+ }
572661
+ if (chunk === "VP8L" && buf.length >= 25) {
572662
+ const bits = buf.readUInt32LE(21);
572663
+ return {
572664
+ width: (bits & 16383) + 1,
572665
+ height: (bits >> 14 & 16383) + 1
572666
+ };
572667
+ }
572668
+ }
572669
+ if (buf.length > 4 && buf[0] === 255 && buf[1] === 216) {
572670
+ let offset = 2;
572671
+ while (offset + 9 < buf.length) {
572672
+ if (buf[offset] !== 255) {
572673
+ offset++;
572674
+ continue;
572675
+ }
572676
+ const marker = buf[offset + 1] ?? 0;
572677
+ const length4 = buf.readUInt16BE(offset + 2);
572678
+ if (length4 < 2) break;
572679
+ if (marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207) {
572680
+ return { width: buf.readUInt16BE(offset + 7), height: buf.readUInt16BE(offset + 5) };
572681
+ }
572682
+ offset += 2 + length4;
572683
+ }
572684
+ }
572685
+ } catch {
572686
+ return null;
572687
+ }
572688
+ return null;
572689
+ }
572497
572690
  function normalizeAscii(ascii2, width, height) {
572498
572691
  const lines = ascii2.replace(ANSI_PATTERN, "").replace(/\r/g, "").split("\n").map((line) => line.replace(/\s+$/g, "")).filter((line, idx, all2) => line.length > 0 || idx > 0 && idx < all2.length - 1);
572499
572692
  return lines.slice(0, height).map((line) => line.length > width ? line.slice(0, width) : line).join("\n").trimEnd();
@@ -572530,7 +572723,7 @@ async function convertWithImageToAscii(imagePath, width, height, timeoutMs) {
572530
572723
  colored: false,
572531
572724
  size: { width, height },
572532
572725
  size_options: {
572533
- preserve_aspect_ratio: true,
572726
+ preserve_aspect_ratio: false,
572534
572727
  fit_screen: false
572535
572728
  }
572536
572729
  },
@@ -572560,8 +572753,7 @@ async function convertWithImageToAscii(imagePath, width, height, timeoutMs) {
572560
572753
  function convertWithFfmpeg(imagePath, width, height, timeoutMs) {
572561
572754
  try {
572562
572755
  const filter2 = [
572563
- `scale=${width}:${height}:force_original_aspect_ratio=decrease`,
572564
- `pad=${width}:${height}:(ow-iw)/2:(oh-ih)/2:color=black`,
572756
+ `scale=${width}:${height}`,
572565
572757
  "format=gray"
572566
572758
  ].join(",");
572567
572759
  const raw = execFileSync2(
@@ -572611,9 +572803,10 @@ async function buildImageAsciiPreview(inputPath, options2 = {}) {
572611
572803
  } catch {
572612
572804
  return null;
572613
572805
  }
572614
- const defaults3 = defaultAsciiPreviewSize();
572806
+ const dimensions = readImageDimensions(imagePath);
572807
+ const defaults3 = defaultAsciiPreviewSize(dimensions);
572615
572808
  const width = clamp5(options2.width ?? defaults3.width, 24, 140);
572616
- const height = clamp5(options2.height ?? defaults3.height, 8, 60);
572809
+ const height = clamp5(options2.height ?? defaults3.height, 6, 60);
572617
572810
  const timeoutMs = clamp5(options2.timeoutMs ?? 5e3, 500, 3e4);
572618
572811
  if (options2.preferPackage !== false) {
572619
572812
  const result = await convertWithImageToAscii(imagePath, width, height, timeoutMs);
@@ -572637,6 +572830,8 @@ ${preview.ascii}`;
572637
572830
  function extractSavedImagePath(text, repoRoot) {
572638
572831
  const patterns = [
572639
572832
  /Image generated:\s*([^\n\r]+)/i,
572833
+ /Image generated at\s+([^\s\n\r]+\.(?:png|jpg|jpeg|webp|gif))/i,
572834
+ /Output saved to\s+([^\s\n\r]+\.(?:png|jpg|jpeg|webp|gif))/i,
572640
572835
  /Screenshot saved:\s*([^\n\r]+)/i,
572641
572836
  /Screenshot:\s*([^\n\r]+)/i,
572642
572837
  /Saved to:\s*([^\n\r]+)/i,
@@ -572652,12 +572847,13 @@ function extractSavedImagePath(text, repoRoot) {
572652
572847
  }
572653
572848
  return null;
572654
572849
  }
572655
- var DEFAULT_PIXELS, ANSI_PATTERN;
572850
+ var DEFAULT_PIXELS, ANSI_PATTERN, TERMINAL_CELL_ASPECT;
572656
572851
  var init_image_ascii_preview = __esm({
572657
572852
  "packages/cli/src/tui/image-ascii-preview.ts"() {
572658
572853
  "use strict";
572659
572854
  DEFAULT_PIXELS = " .,:;i1tfLCG08@";
572660
572855
  ANSI_PATTERN = /\x1B\[[0-?]*[ -/]*[@-~]/g;
572856
+ TERMINAL_CELL_ASPECT = 0.52;
572661
572857
  }
572662
572858
  });
572663
572859
 
@@ -572678,7 +572874,7 @@ import {
572678
572874
  existsSync as existsSync94,
572679
572875
  mkdirSync as mkdirSync52,
572680
572876
  writeFileSync as writeFileSync49,
572681
- readFileSync as readFileSync75,
572877
+ readFileSync as readFileSync76,
572682
572878
  unlinkSync as unlinkSync18,
572683
572879
  readdirSync as readdirSync27,
572684
572880
  statSync as statSync32
@@ -573967,7 +574163,7 @@ except Exception as exc:
573967
574163
  const destFilename = `clone-${srcName}-${ts}.${ext}`;
573968
574164
  const destPath = join108(refsDir, destFilename);
573969
574165
  try {
573970
- const data = readFileSync75(audioPath);
574166
+ const data = readFileSync76(audioPath);
573971
574167
  writeFileSync49(destPath, data);
573972
574168
  } catch (err) {
573973
574169
  return `Failed to copy audio file: ${err instanceof Error ? err.message : String(err)}`;
@@ -574031,7 +574227,7 @@ except Exception as exc:
574031
574227
  const p2 = _VoiceEngine.cloneMetaFile();
574032
574228
  if (!existsSync94(p2)) return {};
574033
574229
  try {
574034
- return JSON.parse(readFileSync75(p2, "utf8"));
574230
+ return JSON.parse(readFileSync76(p2, "utf8"));
574035
574231
  } catch {
574036
574232
  return {};
574037
574233
  }
@@ -574862,7 +575058,7 @@ except Exception as exc:
574862
575058
  loadSupertonicStore() {
574863
575059
  try {
574864
575060
  const raw = JSON.parse(
574865
- readFileSync75(supertonicProfilesFile(), "utf-8")
575061
+ readFileSync76(supertonicProfilesFile(), "utf-8")
574866
575062
  );
574867
575063
  const profiles = {};
574868
575064
  for (const [name10, settings] of Object.entries(raw.profiles ?? {})) {
@@ -575032,7 +575228,7 @@ except Exception as exc:
575032
575228
  const wavPath = await this.synthesizeSupertonicWav(text, 1);
575033
575229
  if (!wavPath) return null;
575034
575230
  try {
575035
- const data = readFileSync75(wavPath);
575231
+ const data = readFileSync76(wavPath);
575036
575232
  unlinkSync18(wavPath);
575037
575233
  return data;
575038
575234
  } catch {
@@ -575201,7 +575397,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`
575201
575397
  if (!existsSync94(wavPath)) return;
575202
575398
  if (volume !== 1) {
575203
575399
  try {
575204
- const wavData = readFileSync75(wavPath);
575400
+ const wavData = readFileSync76(wavPath);
575205
575401
  if (wavData.length > 44) {
575206
575402
  const header = wavData.subarray(0, 44);
575207
575403
  const samples = new Int16Array(
@@ -575223,7 +575419,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`
575223
575419
  }
575224
575420
  if (this.onPCMOutput) {
575225
575421
  try {
575226
- const wavData = readFileSync75(wavPath);
575422
+ const wavData = readFileSync76(wavPath);
575227
575423
  if (wavData.length > 44) {
575228
575424
  const pcm = Buffer.from(
575229
575425
  wavData.buffer,
@@ -575281,7 +575477,7 @@ Error: ${err2 instanceof Error ? err2.message : String(err2)}`
575281
575477
  }
575282
575478
  if (!existsSync94(wavPath)) return null;
575283
575479
  try {
575284
- const data = readFileSync75(wavPath);
575480
+ const data = readFileSync76(wavPath);
575285
575481
  unlinkSync18(wavPath);
575286
575482
  return data;
575287
575483
  } catch {
@@ -575973,7 +576169,7 @@ if __name__ == '__main__':
575973
576169
  async postProcessAndPlayLuxtts(wavPath, volume = 1, pitchFactor = 1, stereoDelayMs = 0.6) {
575974
576170
  if (!existsSync94(wavPath)) return;
575975
576171
  try {
575976
- const wavData = readFileSync75(wavPath);
576172
+ const wavData = readFileSync76(wavPath);
575977
576173
  if (wavData.length > 44) {
575978
576174
  const sampleRate = wavData.readUInt32LE(24);
575979
576175
  const samples = new Int16Array(
@@ -576004,7 +576200,7 @@ if __name__ == '__main__':
576004
576200
  }
576005
576201
  if (pitchFactor !== 1) {
576006
576202
  try {
576007
- const wavData = readFileSync75(wavPath);
576203
+ const wavData = readFileSync76(wavPath);
576008
576204
  if (wavData.length > 44) {
576009
576205
  const int16 = new Int16Array(
576010
576206
  wavData.buffer,
@@ -576023,7 +576219,7 @@ if __name__ == '__main__':
576023
576219
  }
576024
576220
  if (this.onPCMOutput) {
576025
576221
  try {
576026
- const wavData = readFileSync75(wavPath);
576222
+ const wavData = readFileSync76(wavPath);
576027
576223
  if (wavData.length > 44) {
576028
576224
  const pcm = Buffer.from(
576029
576225
  wavData.buffer,
@@ -576038,7 +576234,7 @@ if __name__ == '__main__':
576038
576234
  }
576039
576235
  if (stereoDelayMs > 0) {
576040
576236
  try {
576041
- const wavData = readFileSync75(wavPath);
576237
+ const wavData = readFileSync76(wavPath);
576042
576238
  if (wavData.length > 44) {
576043
576239
  const sampleRate = wavData.readUInt32LE(24);
576044
576240
  const numChannels = wavData.readUInt16LE(22);
@@ -576105,7 +576301,7 @@ if __name__ == '__main__':
576105
576301
  }
576106
576302
  if (!existsSync94(wavPath)) return null;
576107
576303
  try {
576108
- const data = readFileSync75(wavPath);
576304
+ const data = readFileSync76(wavPath);
576109
576305
  unlinkSync18(wavPath);
576110
576306
  return data;
576111
576307
  } catch {
@@ -576126,7 +576322,7 @@ if __name__ == '__main__':
576126
576322
  };
576127
576323
  if (existsSync94(pkgPath)) {
576128
576324
  try {
576129
- const existing = JSON.parse(readFileSync75(pkgPath, "utf8"));
576325
+ const existing = JSON.parse(readFileSync76(pkgPath, "utf8"));
576130
576326
  if (!existing.dependencies?.["phonemizer"]) {
576131
576327
  existing.dependencies = { ...existing.dependencies, ...expectedDeps };
576132
576328
  writeFileSync49(pkgPath, JSON.stringify(existing, null, 2));
@@ -576286,7 +576482,7 @@ Error: ${err instanceof Error ? err.message : String(err)}`
576286
576482
  if (!existsSync94(onnxPath) || !existsSync94(configPath2)) {
576287
576483
  throw new Error(`Model files not found for ${this.modelId}`);
576288
576484
  }
576289
- this.config = JSON.parse(readFileSync75(configPath2, "utf8"));
576485
+ this.config = JSON.parse(readFileSync76(configPath2, "utf8"));
576290
576486
  this.session = await this.ort.InferenceSession.create(onnxPath, {
576291
576487
  executionProviders: ["cpu"],
576292
576488
  graphOptimizationLevel: "all"
@@ -576445,7 +576641,7 @@ import * as nodeOs from "node:os";
576445
576641
  import { execSync as nodeExecSync } from "node:child_process";
576446
576642
  import {
576447
576643
  existsSync as existsSync95,
576448
- readFileSync as readFileSync76,
576644
+ readFileSync as readFileSync77,
576449
576645
  writeFileSync as writeFileSync50,
576450
576646
  mkdirSync as mkdirSync53,
576451
576647
  readdirSync as readdirSync28,
@@ -577012,10 +577208,10 @@ async function handleSlashCommand(input, ctx3) {
577012
577208
  if (!key) {
577013
577209
  try {
577014
577210
  const { homedir: homedir48 } = await import("node:os");
577015
- const { readFileSync: readFileSync101, existsSync: existsSync123 } = await import("node:fs");
577211
+ const { readFileSync: readFileSync102, existsSync: existsSync123 } = await import("node:fs");
577016
577212
  const { join: join141 } = await import("node:path");
577017
577213
  const p2 = join141(homedir48(), ".omnius", "api.key");
577018
- if (existsSync123(p2)) key = readFileSync101(p2, "utf8").trim();
577214
+ if (existsSync123(p2)) key = readFileSync102(p2, "utf8").trim();
577019
577215
  } catch {
577020
577216
  }
577021
577217
  }
@@ -577830,7 +578026,7 @@ async function handleSlashCommand(input, ctx3) {
577830
578026
  "daemon.pid"
577831
578027
  );
577832
578028
  if (existsSync95(pidFile)) {
577833
- const pid = parseInt(readFileSync76(pidFile, "utf8").trim(), 10);
578029
+ const pid = parseInt(readFileSync77(pidFile, "utf8").trim(), 10);
577834
578030
  if (pid > 0 && !registry2.daemons.has("Nexus")) {
577835
578031
  registry2.register({
577836
578032
  name: "Nexus",
@@ -578219,7 +578415,7 @@ async function handleSlashCommand(input, ctx3) {
578219
578415
  renderWarning(`Tool not found: ${toolFile}`);
578220
578416
  return "handled";
578221
578417
  }
578222
- content = readFileSync76(toolFile, "utf8");
578418
+ content = readFileSync77(toolFile, "utf8");
578223
578419
  metadata = { type: "tool", name: shareName };
578224
578420
  } else if (shareType === "skill") {
578225
578421
  const skillDir = join109(ctx3.repoRoot, ".omnius", "skills", shareName);
@@ -578228,7 +578424,7 @@ async function handleSlashCommand(input, ctx3) {
578228
578424
  renderWarning(`Skill not found: ${skillFile}`);
578229
578425
  return "handled";
578230
578426
  }
578231
- content = readFileSync76(skillFile, "utf8");
578427
+ content = readFileSync77(skillFile, "utf8");
578232
578428
  metadata = { type: "skill", name: shareName };
578233
578429
  } else {
578234
578430
  renderWarning(
@@ -578301,7 +578497,7 @@ async function handleSlashCommand(input, ctx3) {
578301
578497
  "learning-cids.json"
578302
578498
  );
578303
578499
  if (existsSync95(regFile)) {
578304
- const reg2 = JSON.parse(readFileSync76(regFile, "utf8"));
578500
+ const reg2 = JSON.parse(readFileSync77(regFile, "utf8"));
578305
578501
  const pinned = Object.values(reg2).some(
578306
578502
  (e2) => e2.cid === importCid && e2.pinned
578307
578503
  );
@@ -578416,7 +578612,7 @@ async function handleSlashCommand(input, ctx3) {
578416
578612
  try {
578417
578613
  const statusFile = join109(ctx3.repoRoot, ".omnius", "nexus", "status.json");
578418
578614
  if (existsSync95(statusFile)) {
578419
- const status = JSON.parse(readFileSync76(statusFile, "utf8"));
578615
+ const status = JSON.parse(readFileSync77(statusFile, "utf8"));
578420
578616
  if (status.peerId) {
578421
578617
  lines.push(`
578422
578618
  ${c3.bold("Peer Info")}`);
@@ -578441,7 +578637,7 @@ async function handleSlashCommand(input, ctx3) {
578441
578637
  try {
578442
578638
  const stateFile = join109(idDir, "self-state.json");
578443
578639
  if (existsSync95(stateFile)) {
578444
- const state = JSON.parse(readFileSync76(stateFile, "utf8"));
578640
+ const state = JSON.parse(readFileSync77(stateFile, "utf8"));
578445
578641
  lines.push(
578446
578642
  ` Version: ${c3.bold("v" + (state.version ?? "?"))} Sessions: ${c3.bold(String(state.session_count ?? 0))}`
578447
578643
  );
@@ -578456,7 +578652,7 @@ async function handleSlashCommand(input, ctx3) {
578456
578652
  }
578457
578653
  const cidFile = join109(idDir, "cids.json");
578458
578654
  if (existsSync95(cidFile)) {
578459
- const cids = JSON.parse(readFileSync76(cidFile, "utf8"));
578655
+ const cids = JSON.parse(readFileSync77(cidFile, "utf8"));
578460
578656
  const lastCid = Array.isArray(cids) ? cids[cids.length - 1] : cids.latest;
578461
578657
  if (lastCid)
578462
578658
  lines.push(
@@ -578481,7 +578677,7 @@ async function handleSlashCommand(input, ctx3) {
578481
578677
  "store.json"
578482
578678
  );
578483
578679
  if (existsSync95(metaFile)) {
578484
- const store2 = JSON.parse(readFileSync76(metaFile, "utf8"));
578680
+ const store2 = JSON.parse(readFileSync77(metaFile, "utf8"));
578485
578681
  const active = store2.filter((m2) => m2.type !== "quarantine");
578486
578682
  const recoveries = active.filter(
578487
578683
  (m2) => m2.content?.startsWith("[recovery]")
@@ -578722,7 +578918,7 @@ async function handleSlashCommand(input, ctx3) {
578722
578918
  return "handled";
578723
578919
  }
578724
578920
  } else {
578725
- content = readFileSync76(resolvedPath, "utf8");
578921
+ content = readFileSync77(resolvedPath, "utf8");
578726
578922
  }
578727
578923
  if (!content.trim()) {
578728
578924
  renderWarning("No content extracted.");
@@ -578826,7 +579022,7 @@ async function handleSlashCommand(input, ctx3) {
578826
579022
  renderInfo("Fortemi bridge: not connected. Run /fortemi start");
578827
579023
  return "handled";
578828
579024
  }
578829
- const bridge = JSON.parse(readFileSync76(bridgeFile, "utf8"));
579025
+ const bridge = JSON.parse(readFileSync77(bridgeFile, "utf8"));
578830
579026
  let alive = false;
578831
579027
  try {
578832
579028
  process.kill(bridge.pid, 0);
@@ -578862,7 +579058,7 @@ async function handleSlashCommand(input, ctx3) {
578862
579058
  if (fortemiSubCmd === "stop") {
578863
579059
  const bridgeFile = join109(ctx3.repoRoot, ".omnius", "fortemi-bridge.json");
578864
579060
  if (existsSync95(bridgeFile)) {
578865
- const bridge = JSON.parse(readFileSync76(bridgeFile, "utf8"));
579061
+ const bridge = JSON.parse(readFileSync77(bridgeFile, "utf8"));
578866
579062
  try {
578867
579063
  process.kill(bridge.pid, "SIGTERM");
578868
579064
  } catch {
@@ -580674,7 +580870,7 @@ sleep 1
580674
580870
  `daemon.pid exists: ${existsSync95(join109(projectDir2, ".omnius", "nexus", "daemon.pid"))}`
580675
580871
  );
580676
580872
  try {
580677
- const _statusRaw = readFileSync76(
580873
+ const _statusRaw = readFileSync77(
580678
580874
  join109(projectDir2, ".omnius", "nexus", "status.json"),
580679
580875
  "utf8"
580680
580876
  );
@@ -580683,7 +580879,7 @@ sleep 1
580683
580879
  _spLog(`status.json read error: ${e2}`);
580684
580880
  }
580685
580881
  try {
580686
- const _errRaw = readFileSync76(
580882
+ const _errRaw = readFileSync77(
580687
580883
  join109(projectDir2, ".omnius", "nexus", "daemon.err"),
580688
580884
  "utf8"
580689
580885
  );
@@ -580718,7 +580914,7 @@ sleep 1
580718
580914
  "agent-name"
580719
580915
  );
580720
580916
  if (existsSync95(namePath))
580721
- sponsorName = readFileSync76(namePath, "utf8").trim();
580917
+ sponsorName = readFileSync77(namePath, "utf8").trim();
580722
580918
  } catch {
580723
580919
  }
580724
580920
  if (!sponsorName) sponsorName = "Omnius Sponsor";
@@ -580813,7 +581009,7 @@ sleep 1
580813
581009
  const nexusPidFile = join109(projectDir2, ".omnius", "nexus", "daemon.pid");
580814
581010
  if (existsSync95(nexusPidFile)) {
580815
581011
  const nPid = parseInt(
580816
- readFileSync76(nexusPidFile, "utf8").trim(),
581012
+ readFileSync77(nexusPidFile, "utf8").trim(),
580817
581013
  10
580818
581014
  );
580819
581015
  if (nPid > 0) {
@@ -583127,6 +583323,13 @@ async function showImageModelsMenu(ctx3, hasLocal) {
583127
583323
  const save2 = hasLocal ? ctx3.saveLocalSettings : ctx3.saveSettings;
583128
583324
  save2({ imageModel: model, imageBackend: backend });
583129
583325
  renderInfo(`Image model: ${model} (${backend})${hasLocal ? " (project-local)" : ""}`);
583326
+ if (backend === "diffusers") {
583327
+ renderInfo("First generation with this model may download weights into .omnius/image-gen/huggingface.");
583328
+ if (preset?.install) renderInfo(`Prewarm command: ${preset.install}`);
583329
+ } else if (backend === "ollama") {
583330
+ renderInfo("If the model is not already present, first generation will pull it from Ollama.");
583331
+ if (preset?.install) renderInfo(`Prewarm command: ${preset.install}`);
583332
+ }
583130
583333
  }
583131
583334
  }
583132
583335
  async function handleImageCommand(ctx3, arg, hasLocal) {
@@ -583153,6 +583356,9 @@ async function handleImageCommand(ctx3, arg, hasLocal) {
583153
583356
  const backend = String(parsed.flags["backend"] ?? settings.imageBackend ?? inferImageGenerationBackend(model, void 0));
583154
583357
  const tool = new ImageGenerateTool(ctx3.repoRoot, ctx3.config.backendUrl);
583155
583358
  const prompt = parsed.prompt;
583359
+ tool.setProgressCallback((event) => {
583360
+ renderInfo(formatImageGenerationProgress(event));
583361
+ });
583156
583362
  renderInfo(`Generating image with ${model} (${backend})...`);
583157
583363
  const result = await tool.execute({
583158
583364
  prompt,
@@ -583175,13 +583381,31 @@ async function handleImageCommand(ctx3, arg, hasLocal) {
583175
583381
  if (imagePath) {
583176
583382
  const preview = await buildImageAsciiPreview2(imagePath);
583177
583383
  const displayPath = relative11(ctx3.repoRoot, imagePath).startsWith("..") ? imagePath : relative11(ctx3.repoRoot, imagePath);
583178
- if (preview) renderImageAsciiPreview("Generated image", displayPath, preview.ascii, preview.renderer);
583384
+ if (preview) {
583385
+ renderImageAsciiPreview("Generated image", displayPath, preview.ascii, preview.renderer);
583386
+ } else {
583387
+ renderWarning(`Generated image preview unavailable for ${displayPath}.`);
583388
+ }
583179
583389
  renderInfo(`File: ${imagePath}`);
583390
+ } else {
583391
+ renderWarning("Generated image preview skipped: no saved image path was found in the tool output.");
583180
583392
  }
583181
- } catch {
583393
+ } catch (err) {
583394
+ renderWarning(`Generated image preview failed: ${err instanceof Error ? err.message : String(err)}`);
583182
583395
  }
583183
583396
  return "handled";
583184
583397
  }
583398
+ function formatImageGenerationProgress(event) {
583399
+ const pct = event.percent;
583400
+ const elapsed = event.elapsedMs && event.elapsedMs > 1500 ? ` ${Math.round(event.elapsedMs / 1e3)}s` : "";
583401
+ if (typeof pct === "number") {
583402
+ const width = 20;
583403
+ const filled = Math.max(0, Math.min(width, Math.round(pct / 100 * width)));
583404
+ const bar = `${"#".repeat(filled)}${"-".repeat(width - filled)}`;
583405
+ return `Image ${event.stage}: [${bar}] ${pct}% ${event.message}${elapsed}`;
583406
+ }
583407
+ return `Image ${event.stage}: ${event.message}${elapsed}`;
583408
+ }
583185
583409
  async function showHelpMenu(ctx3) {
583186
583410
  const slashCommands = getSlashHelpEntries();
583187
583411
  const groups = /* @__PURE__ */ new Map();
@@ -584926,7 +585150,7 @@ async function handleSponsoredEndpoint(ctx3, local) {
584926
585150
  try {
584927
585151
  if (existsSync95(knownFile)) {
584928
585152
  const saved = JSON.parse(
584929
- readFileSync76(knownFile, "utf8")
585153
+ readFileSync77(knownFile, "utf8")
584930
585154
  );
584931
585155
  for (const s2 of saved) {
584932
585156
  if (!sponsors.some((sp) => sp.url === s2.url)) {
@@ -585105,7 +585329,7 @@ async function handleSponsoredEndpoint(ctx3, local) {
585105
585329
  const saveKey = selected.url || selected.peerId || selected.name;
585106
585330
  try {
585107
585331
  mkdirSync53(sponsorDir2, { recursive: true });
585108
- const existing = existsSync95(knownFile) ? JSON.parse(readFileSync76(knownFile, "utf8")) : [];
585332
+ const existing = existsSync95(knownFile) ? JSON.parse(readFileSync77(knownFile, "utf8")) : [];
585109
585333
  const updated = existing.filter(
585110
585334
  (s2) => (s2.url || s2.peerId || s2.name) !== saveKey
585111
585335
  );
@@ -587607,7 +587831,7 @@ var init_commands = __esm({
587607
587831
  });
587608
587832
 
587609
587833
  // packages/cli/src/tui/project-context.ts
587610
- import { existsSync as existsSync96, readFileSync as readFileSync77, readdirSync as readdirSync29 } from "node:fs";
587834
+ import { existsSync as existsSync96, readFileSync as readFileSync78, readdirSync as readdirSync29 } from "node:fs";
587611
587835
  import { join as join110, basename as basename16 } from "node:path";
587612
587836
  import { execSync as execSync53 } from "node:child_process";
587613
587837
  import { homedir as homedir35 } from "node:os";
@@ -587642,7 +587866,7 @@ function loadProjectMap(repoRoot) {
587642
587866
  const mapPath2 = join110(repoRoot, OMNIUS_DIR, "context", "project-map.md");
587643
587867
  if (existsSync96(mapPath2)) {
587644
587868
  try {
587645
- const content = readFileSync77(mapPath2, "utf-8");
587869
+ const content = readFileSync78(mapPath2, "utf-8");
587646
587870
  return content;
587647
587871
  } catch {
587648
587872
  }
@@ -587687,7 +587911,7 @@ function loadMemoryContext(repoRoot) {
587687
587911
  const files = readdirSync29(dir).filter((f2) => f2.endsWith(".json"));
587688
587912
  for (const file of files.slice(0, 10)) {
587689
587913
  try {
587690
- const raw = readFileSync77(join110(dir, file), "utf-8");
587914
+ const raw = readFileSync78(join110(dir, file), "utf-8");
587691
587915
  const entries = JSON.parse(raw);
587692
587916
  const topic = basename16(file, ".json");
587693
587917
  for (const [k, v] of Object.entries(entries)) {
@@ -588234,7 +588458,7 @@ __export(banner_exports, {
588234
588458
  setBannerWriter: () => setBannerWriter,
588235
588459
  setGridText: () => setGridText
588236
588460
  });
588237
- import { existsSync as existsSync97, readFileSync as readFileSync78, writeFileSync as writeFileSync51, mkdirSync as mkdirSync54 } from "node:fs";
588461
+ import { existsSync as existsSync97, readFileSync as readFileSync79, writeFileSync as writeFileSync51, mkdirSync as mkdirSync54 } from "node:fs";
588238
588462
  import { join as join111 } from "node:path";
588239
588463
  function setBannerWriter(writer) {
588240
588464
  chromeWrite3 = writer;
@@ -588376,7 +588600,7 @@ function loadBannerDesign(workDir, id) {
588376
588600
  const file = join111(workDir, ".omnius", "banners", `${id}.json`);
588377
588601
  if (!existsSync97(file)) return null;
588378
588602
  try {
588379
- return JSON.parse(readFileSync78(file, "utf8"));
588603
+ return JSON.parse(readFileSync79(file, "utf8"));
588380
588604
  } catch {
588381
588605
  return null;
588382
588606
  }
@@ -588706,13 +588930,13 @@ var init_banner = __esm({
588706
588930
  });
588707
588931
 
588708
588932
  // packages/cli/src/tui/carousel-descriptors.ts
588709
- import { existsSync as existsSync98, readFileSync as readFileSync79, writeFileSync as writeFileSync52, mkdirSync as mkdirSync55, readdirSync as readdirSync30 } from "node:fs";
588933
+ import { existsSync as existsSync98, readFileSync as readFileSync80, writeFileSync as writeFileSync52, mkdirSync as mkdirSync55, readdirSync as readdirSync30 } from "node:fs";
588710
588934
  import { join as join112, basename as basename17 } from "node:path";
588711
588935
  function loadToolProfile(repoRoot) {
588712
588936
  const filePath = join112(repoRoot, OMNIUS_DIR, "context", TOOL_PROFILE_FILE);
588713
588937
  try {
588714
588938
  if (!existsSync98(filePath)) return null;
588715
- return JSON.parse(readFileSync79(filePath, "utf-8"));
588939
+ return JSON.parse(readFileSync80(filePath, "utf-8"));
588716
588940
  } catch {
588717
588941
  return null;
588718
588942
  }
@@ -588778,7 +589002,7 @@ function loadCachedDescriptors(repoRoot) {
588778
589002
  const filePath = join112(repoRoot, OMNIUS_DIR, "context", DESCRIPTOR_FILE);
588779
589003
  try {
588780
589004
  if (!existsSync98(filePath)) return null;
588781
- const cached = JSON.parse(readFileSync79(filePath, "utf-8"));
589005
+ const cached = JSON.parse(readFileSync80(filePath, "utf-8"));
588782
589006
  return cached.phrases.length > 0 ? cached.phrases : null;
588783
589007
  } catch {
588784
589008
  return null;
@@ -588842,7 +589066,7 @@ function extractFromPackageJson(repoRoot, tags) {
588842
589066
  const pkgPath = join112(repoRoot, "package.json");
588843
589067
  try {
588844
589068
  if (!existsSync98(pkgPath)) return;
588845
- const pkg = JSON.parse(readFileSync79(pkgPath, "utf-8"));
589069
+ const pkg = JSON.parse(readFileSync80(pkgPath, "utf-8"));
588846
589070
  if (pkg.name && typeof pkg.name === "string") {
588847
589071
  const parts = pkg.name.replace(/^@/, "").split("/");
588848
589072
  for (const p2 of parts) tags.push(p2);
@@ -588913,7 +589137,7 @@ function extractFromMemory(repoRoot, tags) {
588913
589137
  const topic = file.replace(/\.json$/, "").replace(/[-_]/g, " ");
588914
589138
  tags.push(topic);
588915
589139
  try {
588916
- const data = JSON.parse(readFileSync79(join112(memoryDir, file), "utf-8"));
589140
+ const data = JSON.parse(readFileSync80(join112(memoryDir, file), "utf-8"));
588917
589141
  if (data && typeof data === "object") {
588918
589142
  const keys = Object.keys(data).slice(0, 3);
588919
589143
  for (const key of keys) {
@@ -589051,13 +589275,13 @@ function fg2564(code8, text) {
589051
589275
  return isTTY8 ? `\x1B[38;5;${code8}m${text}\x1B[0m` : text;
589052
589276
  }
589053
589277
  function dimText(text) {
589054
- return isTTY8 ? `\x1B[2m${text}\x1B[0m` : text;
589278
+ return isTTY8 ? `\x1B[38;5;${tuiTextDim()}m${text}\x1B[0m` : text;
589055
589279
  }
589056
589280
  function italicText(text) {
589057
589281
  return isTTY8 ? `\x1B[3m${text}\x1B[0m` : text;
589058
589282
  }
589059
589283
  function dimItalic(text) {
589060
- return isTTY8 ? `\x1B[2;3m${text}\x1B[0m` : text;
589284
+ return isTTY8 ? `\x1B[3m\x1B[38;5;${tuiTextDim()}m${text}\x1B[0m` : text;
589061
589285
  }
589062
589286
  function boldText(text) {
589063
589287
  return isTTY8 ? `\x1B[1m${text}\x1B[0m` : text;
@@ -589068,6 +589292,7 @@ var init_stream_renderer = __esm({
589068
589292
  "use strict";
589069
589293
  init_layout2();
589070
589294
  init_text_selection();
589295
+ init_theme();
589071
589296
  isTTY8 = process.stdout.isTTY ?? false;
589072
589297
  PASTEL = {
589073
589298
  key: 222,
@@ -589082,14 +589307,14 @@ var init_stream_renderer = __esm({
589082
589307
  // grey-blue — null
589083
589308
  bracket: 75,
589084
589309
  // soft blue — { } [ ]
589085
- colon: 245,
589086
- // neutral grey — : ,
589310
+ colon: 250,
589311
+ // readable grey — : ,
589087
589312
  keyword: 117,
589088
589313
  // sky blue — function, return, if, else
589089
- comment: 243,
589090
- // dim grey — // comments
589091
- thinking: 245,
589092
- // neutral grey for thinking tokens
589314
+ comment: 250,
589315
+ // readable grey — // comments
589316
+ thinking: 250,
589317
+ // readable grey for thinking tokens
589093
589318
  toolArg: 111,
589094
589319
  // dim periwinkle for tool arg tokens
589095
589320
  // Markdown
@@ -589103,10 +589328,10 @@ var init_stream_renderer = __esm({
589103
589328
  // light peach — `code`
589104
589329
  link: 111,
589105
589330
  // periwinkle — [link](url)
589106
- blockquote: 245,
589107
- // grey — > quote
589108
- hr: 240,
589109
- // dark grey — ---
589331
+ blockquote: 250,
589332
+ // readable grey — > quote
589333
+ hr: 250,
589334
+ // readable grey — ---
589110
589335
  // Diff / patch
589111
589336
  diffAdded: 114,
589112
589337
  // mint green — + lines
@@ -589116,8 +589341,8 @@ var init_stream_renderer = __esm({
589116
589341
  // blue — @@ headers
589117
589342
  diffMeta: 222,
589118
589343
  // gold — --- +++ file headers
589119
- diffContext: 245,
589120
- // grey — context lines
589344
+ diffContext: 250,
589345
+ // readable grey — context lines
589121
589346
  // Shell
589122
589347
  shellVar: 222,
589123
589348
  // gold — $VAR
@@ -589791,7 +590016,7 @@ var init_edit_history = __esm({
589791
590016
  });
589792
590017
 
589793
590018
  // packages/cli/src/tui/promptLoader.ts
589794
- import { readFileSync as readFileSync80, existsSync as existsSync99 } from "node:fs";
590019
+ import { readFileSync as readFileSync81, existsSync as existsSync99 } from "node:fs";
589795
590020
  import { join as join114, dirname as dirname32 } from "node:path";
589796
590021
  import { fileURLToPath as fileURLToPath15 } from "node:url";
589797
590022
  function loadPrompt3(promptPath, vars) {
@@ -589801,7 +590026,7 @@ function loadPrompt3(promptPath, vars) {
589801
590026
  if (!existsSync99(fullPath)) {
589802
590027
  throw new Error(`Prompt file not found: ${fullPath}`);
589803
590028
  }
589804
- content = readFileSync80(fullPath, "utf-8");
590029
+ content = readFileSync81(fullPath, "utf-8");
589805
590030
  cache7.set(promptPath, content);
589806
590031
  }
589807
590032
  if (!vars) return content;
@@ -589821,7 +590046,7 @@ var init_promptLoader3 = __esm({
589821
590046
  });
589822
590047
 
589823
590048
  // packages/cli/src/tui/dream-engine.ts
589824
- import { mkdirSync as mkdirSync57, writeFileSync as writeFileSync53, readFileSync as readFileSync81, existsSync as existsSync100, readdirSync as readdirSync31 } from "node:fs";
590049
+ import { mkdirSync as mkdirSync57, writeFileSync as writeFileSync53, readFileSync as readFileSync82, existsSync as existsSync100, readdirSync as readdirSync31 } from "node:fs";
589825
590050
  import { join as join115, basename as basename18 } from "node:path";
589826
590051
  import { execSync as execSync54 } from "node:child_process";
589827
590052
  function setDreamWriteContent(fn) {
@@ -589838,7 +590063,7 @@ function loadAutoresearchMemory(repoRoot) {
589838
590063
  const memoryPath = join115(repoRoot, ".omnius", "memory", "autoresearch.json");
589839
590064
  if (!existsSync100(memoryPath)) return "";
589840
590065
  try {
589841
- const raw = readFileSync81(memoryPath, "utf-8");
590066
+ const raw = readFileSync82(memoryPath, "utf-8");
589842
590067
  const data = JSON.parse(raw);
589843
590068
  const sections = [];
589844
590069
  for (const key of AUTORESEARCH_MEMORY_KEYS) {
@@ -590078,7 +590303,7 @@ var init_dream_engine = __esm({
590078
590303
  if (!existsSync100(targetPath)) {
590079
590304
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start2 };
590080
590305
  }
590081
- let content = readFileSync81(targetPath, "utf-8");
590306
+ let content = readFileSync82(targetPath, "utf-8");
590082
590307
  if (!content.includes(oldStr)) {
590083
590308
  return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start2 };
590084
590309
  }
@@ -590166,7 +590391,7 @@ var init_dream_engine = __esm({
590166
590391
  if (!existsSync100(targetPath)) {
590167
590392
  return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start2 };
590168
590393
  }
590169
- let content = readFileSync81(targetPath, "utf-8");
590394
+ let content = readFileSync82(targetPath, "utf-8");
590170
590395
  if (!content.includes(oldStr)) {
590171
590396
  return { success: false, output: "", error: "old_string not found in file", durationMs: Date.now() - start2 };
590172
590397
  }
@@ -591126,7 +591351,7 @@ ${summary}` };
591126
591351
  try {
591127
591352
  let notes2 = [];
591128
591353
  if (existsSync100(notesPath)) {
591129
- notes2 = JSON.parse(readFileSync81(notesPath, "utf-8"));
591354
+ notes2 = JSON.parse(readFileSync82(notesPath, "utf-8"));
591130
591355
  }
591131
591356
  if (action === "add") {
591132
591357
  const note = {
@@ -591750,7 +591975,7 @@ var init_bless_engine = __esm({
591750
591975
  });
591751
591976
 
591752
591977
  // packages/cli/src/tui/dmn-engine.ts
591753
- import { existsSync as existsSync101, readFileSync as readFileSync82, writeFileSync as writeFileSync54, mkdirSync as mkdirSync58, readdirSync as readdirSync32, unlinkSync as unlinkSync19 } from "node:fs";
591978
+ import { existsSync as existsSync101, readFileSync as readFileSync83, writeFileSync as writeFileSync54, mkdirSync as mkdirSync58, readdirSync as readdirSync32, unlinkSync as unlinkSync19 } from "node:fs";
591754
591979
  import { join as join116, basename as basename19 } from "node:path";
591755
591980
  function buildDMNGatherPrompt(recentTaskSummaries, dueReminders, attentionItems, memoryTopics, capabilities, competence, reflectionBuffer) {
591756
591981
  const competenceReport = competence.length > 0 ? competence.map((c9) => {
@@ -592515,7 +592740,7 @@ OUTPUT: Call task_complete with JSON:
592515
592740
  const path11 = join116(this.stateDir, "state.json");
592516
592741
  if (existsSync101(path11)) {
592517
592742
  try {
592518
- this.state = JSON.parse(readFileSync82(path11, "utf-8"));
592743
+ this.state = JSON.parse(readFileSync83(path11, "utf-8"));
592519
592744
  } catch {
592520
592745
  }
592521
592746
  }
@@ -592555,7 +592780,7 @@ OUTPUT: Call task_complete with JSON:
592555
592780
  });
592556
592781
 
592557
592782
  // packages/cli/src/tui/snr-engine.ts
592558
- import { existsSync as existsSync102, readdirSync as readdirSync33, readFileSync as readFileSync83 } from "node:fs";
592783
+ import { existsSync as existsSync102, readdirSync as readdirSync33, readFileSync as readFileSync84 } from "node:fs";
592559
592784
  import { join as join117, basename as basename20 } from "node:path";
592560
592785
  function computeDPrime(signalScores, noiseScores) {
592561
592786
  if (signalScores.length === 0 || noiseScores.length === 0) return 0;
@@ -592853,7 +593078,7 @@ Call task_complete with the JSON array when done.`,
592853
593078
  const topic = basename20(f2, ".json");
592854
593079
  if (topics.length > 0 && !topics.includes(topic)) continue;
592855
593080
  try {
592856
- const data = JSON.parse(readFileSync83(join117(dir, f2), "utf-8"));
593081
+ const data = JSON.parse(readFileSync84(join117(dir, f2), "utf-8"));
592857
593082
  for (const [key, val] of Object.entries(data)) {
592858
593083
  const value2 = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
592859
593084
  entries.push({ topic, key, value: value2 });
@@ -593405,7 +593630,7 @@ import { spawn as spawn26 } from "node:child_process";
593405
593630
  import {
593406
593631
  existsSync as existsSync103,
593407
593632
  mkdirSync as mkdirSync59,
593408
- readFileSync as readFileSync84,
593633
+ readFileSync as readFileSync85,
593409
593634
  statSync as statSync34,
593410
593635
  writeFileSync as writeFileSync55
593411
593636
  } from "node:fs";
@@ -593433,7 +593658,7 @@ function formatTelegramCreativeWorkspacePrompt(root) {
593433
593658
  "Creative file tools are scoped to that folder only.",
593434
593659
  "Allowed: create new files, read/list files in this workspace, and edit/patch files already created in this workspace.",
593435
593660
  "Forbidden: delete files, access paths outside this workspace, mutate the project tree, run shell commands, or touch system state.",
593436
- "When you create an artifact for Telegram, the bridge attaches files recorded by tool results. Refer to the attachment naturally; do not expose filesystem paths unless the admin explicitly asks."
593661
+ "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."
593437
593662
  ].join("\n");
593438
593663
  }
593439
593664
  function collectGeneratedArtifactPathsFromText(text, root) {
@@ -593458,7 +593683,7 @@ function collectGeneratedArtifactPathsFromText(text, root) {
593458
593683
  }
593459
593684
  return [...paths];
593460
593685
  }
593461
- function buildTelegramCreativeTools(repoRoot, chatId, backendUrl) {
593686
+ function buildTelegramCreativeTools(repoRoot, chatId, backendUrl, imageDefaults = {}) {
593462
593687
  const root = telegramCreativeWorkspaceRoot(repoRoot, chatId);
593463
593688
  ensureManifest(root);
593464
593689
  return [
@@ -593468,7 +593693,7 @@ function buildTelegramCreativeTools(repoRoot, chatId, backendUrl) {
593468
593693
  scopedTool(new FileEditTool(root), root, "edit"),
593469
593694
  scopedTool(new FilePatchTool(root), root, "edit"),
593470
593695
  scopedTool(new StructuredFileTool(root), root, "create"),
593471
- scopedTool(new ImageGenerateTool(root, backendUrl), root, "generate"),
593696
+ scopedTool(new ImageGenerateTool(root, backendUrl, imageDefaults), root, "generate"),
593472
593697
  new CreativeAudioFileTool(root)
593473
593698
  ];
593474
593699
  }
@@ -593568,7 +593793,7 @@ function ensureManifest(root) {
593568
593793
  function readManifest(root) {
593569
593794
  ensureManifest(root);
593570
593795
  try {
593571
- const parsed = JSON.parse(readFileSync84(manifestPath(root), "utf8"));
593796
+ const parsed = JSON.parse(readFileSync85(manifestPath(root), "utf8"));
593572
593797
  return {
593573
593798
  files: Array.isArray(parsed.files) ? parsed.files.filter((file) => typeof file === "string") : [],
593574
593799
  updatedAt: typeof parsed.updatedAt === "string" ? parsed.updatedAt : (/* @__PURE__ */ new Date()).toISOString()
@@ -593716,7 +593941,7 @@ __export(vision_ingress_exports, {
593716
593941
  runVisionIngress: () => runVisionIngress
593717
593942
  });
593718
593943
  import { execFileSync as execFileSync3 } from "node:child_process";
593719
- import { existsSync as existsSync104, readFileSync as readFileSync85, unlinkSync as unlinkSync20 } from "node:fs";
593944
+ import { existsSync as existsSync104, readFileSync as readFileSync86, unlinkSync as unlinkSync20 } from "node:fs";
593720
593945
  import { join as join119 } from "node:path";
593721
593946
  function isTesseractAvailable() {
593722
593947
  try {
@@ -593771,7 +593996,7 @@ function advancedOcr(imagePath) {
593771
593996
  ], { timeout: 15e3, stdio: "pipe" });
593772
593997
  const txtFile = `${outFile}.txt`;
593773
593998
  if (existsSync104(txtFile)) {
593774
- const text = readFileSync85(txtFile, "utf-8").trim();
593999
+ const text = readFileSync86(txtFile, "utf-8").trim();
593775
594000
  if (text.length > 0) results.push(text);
593776
594001
  try {
593777
594002
  unlinkSync20(txtFile);
@@ -593788,7 +594013,7 @@ function advancedOcr(imagePath) {
593788
594013
  async function queryVisionModel(modelName, imagePath, prompt = "Describe what you see in this image in detail. Include any text, UI elements, code, diagrams, or visual content.") {
593789
594014
  if (!isVisionModel(modelName)) return "";
593790
594015
  if (!existsSync104(imagePath)) return "";
593791
- const imageBuffer = readFileSync85(imagePath);
594016
+ const imageBuffer = readFileSync86(imagePath);
593792
594017
  const base64Image = imageBuffer.toString("base64");
593793
594018
  try {
593794
594019
  const response = await fetch("http://localhost:11434/api/generate", {
@@ -593859,7 +594084,7 @@ var init_vision_ingress = __esm({
593859
594084
  });
593860
594085
 
593861
594086
  // packages/cli/src/tui/telegram-bridge.ts
593862
- import { mkdirSync as mkdirSync60, existsSync as existsSync105, unlinkSync as unlinkSync21, statSync as statSync35, readFileSync as readFileSync86, writeFileSync as writeFileSync57 } from "node:fs";
594087
+ import { mkdirSync as mkdirSync60, existsSync as existsSync105, unlinkSync as unlinkSync21, statSync as statSync35, readFileSync as readFileSync87, writeFileSync as writeFileSync57 } from "node:fs";
593863
594088
  import { join as join120, resolve as resolve39, basename as basename22, relative as relative13, isAbsolute as isAbsolute6 } from "node:path";
593864
594089
  import { writeFile as writeFileAsync } from "node:fs/promises";
593865
594090
  import { createHash as createHash19, randomInt } from "node:crypto";
@@ -594530,6 +594755,14 @@ function mimeForPath(path11, fallbackKind) {
594530
594755
  if (fallbackKind === "video") return "video/mp4";
594531
594756
  return "application/octet-stream";
594532
594757
  }
594758
+ function normalizeTelegramSendKind(rawKind, path11) {
594759
+ const requested = typeof rawKind === "string" ? rawKind.trim().toLowerCase() : "auto";
594760
+ if (requested === "photo") return "image";
594761
+ if (requested === "image" || requested === "animation" || requested === "audio" || requested === "voice" || requested === "video" || requested === "document") {
594762
+ return requested;
594763
+ }
594764
+ return classifyMedia(path11) ?? "document";
594765
+ }
594533
594766
  function renderTelegramStart(botUsername, adminId, mode = "auto") {
594534
594767
  process.stdout.write(`
594535
594768
  ${c3.cyan("✈")} ${c3.bold("Telegram Bridge")} connected as @${botUsername}
@@ -594633,6 +594866,7 @@ var init_telegram_bridge = __esm({
594633
594866
  init_command_registry();
594634
594867
  init_scoped_personality();
594635
594868
  init_telegram_creative_tools();
594869
+ init_omnius_directory();
594636
594870
  TELEGRAM_SAFETY_PROMPT = `
594637
594871
  CRITICAL SAFETY NOTICE — PUBLIC TELEGRAM CHANNEL
594638
594872
 
@@ -595041,7 +595275,7 @@ Telegram response contract:
595041
595275
  const path11 = this.telegramConversationPath(sessionKey);
595042
595276
  if (!existsSync105(path11)) return;
595043
595277
  try {
595044
- const parsed = JSON.parse(readFileSync86(path11, "utf8"));
595278
+ const parsed = JSON.parse(readFileSync87(path11, "utf8"));
595045
595279
  if (Array.isArray(parsed.history)) {
595046
595280
  this.chatHistory.set(sessionKey, parsed.history.slice(-TELEGRAM_CHAT_HISTORY_LIMIT));
595047
595281
  }
@@ -596443,7 +596677,7 @@ ${msg.text}`;
596443
596677
  const toolHint = [
596444
596678
  "You have access to isolated per-chat memory (memory_write, memory_read, memory_search) scoped to this conversation.",
596445
596679
  "You can remember facts about users and retrieve them later. You also have web_search and web_fetch to look up information.",
596446
- "If the user asks you to create or send a file, image, or audio artifact, use the scoped creative tools. The bridge will attach generated files back to Telegram when tool results record them.",
596680
+ "If the user asks you to create or send a file, image, or audio artifact, create it with the scoped creative tools and call telegram_send_file to upload it. The bridge still auto-attaches generated files as a fallback when tool results record them.",
596447
596681
  "For image generation requests, decide from the conversation whether generate_image is appropriate; do not ask the user to use a hardcoded shortcut when the request is clear.",
596448
596682
  creativeWorkspace
596449
596683
  ].filter(Boolean).join("\n\n");
@@ -596483,6 +596717,7 @@ ${creativeWorkspace}` : ""}`;
596483
596717
  * All possible tools are instantiated, then applyToolPolicy filters them.
596484
596718
  */
596485
596719
  buildSubAgentTools(context2, repoRoot, chatId, todoSessionId) {
596720
+ const imageDefaults = this.imageGenerationDefaultsForRepo(repoRoot);
596486
596721
  const taskComplete = {
596487
596722
  name: "task_complete",
596488
596723
  description: "Internal completion signal for Telegram runs. Put the actual user-facing reply in assistant text before calling this. Use summary 'no_reply' only to silently skip responding; never write that sentinel as assistant text.",
@@ -596581,7 +596816,7 @@ ${creativeWorkspace}` : ""}`;
596581
596816
  new BrowserActionTool(),
596582
596817
  new CarbonylBrowserTool(),
596583
596818
  new PlaywrightBrowserTool(),
596584
- new ImageGenerateTool(repoRoot, this.agentConfig?.backendUrl),
596819
+ new ImageGenerateTool(repoRoot, this.agentConfig?.backendUrl, imageDefaults),
596585
596820
  new NotebookEditTool(),
596586
596821
  new RepoMapTool(repoRoot),
596587
596822
  new ImportGraphTool(repoRoot),
@@ -596589,7 +596824,8 @@ ${creativeWorkspace}` : ""}`;
596589
596824
  new ImpactAnalysisTool(repoRoot),
596590
596825
  new CodeNeighborsTool(repoRoot),
596591
596826
  new ProcessHealthTool(),
596592
- fullSubAgentTool
596827
+ fullSubAgentTool,
596828
+ this.buildTelegramSendFileTool(context2, repoRoot, chatId)
596593
596829
  ];
596594
596830
  const allTools = context2 === "telegram-admin-dm" ? adminTools : sharedReadMemoryWebTools;
596595
596831
  if (this.contextWindowSize > 0) {
@@ -596619,12 +596855,133 @@ ${creativeWorkspace}` : ""}`;
596619
596855
  const creativeTools = buildTelegramCreativeTools(
596620
596856
  repoRoot,
596621
596857
  chatId,
596622
- this.agentConfig?.backendUrl
596858
+ this.agentConfig?.backendUrl,
596859
+ imageDefaults
596623
596860
  ).map((tool) => adaptTool5(tool, todoSessionId));
596624
596861
  adaptedTools.push(...creativeTools);
596862
+ adaptedTools.push(adaptTool5(this.buildTelegramSendFileTool(context2, repoRoot, chatId), todoSessionId));
596625
596863
  }
596626
596864
  return [...adaptedTools, taskComplete];
596627
596865
  }
596866
+ imageGenerationDefaultsForRepo(repoRoot) {
596867
+ const settings = resolveSettings(repoRoot);
596868
+ return {
596869
+ model: typeof settings.imageModel === "string" && settings.imageModel.trim() ? settings.imageModel : void 0,
596870
+ backend: settings.imageBackend
596871
+ };
596872
+ }
596873
+ buildTelegramSendFileTool(context2, repoRoot, currentChatId) {
596874
+ const bridge = this;
596875
+ const adminDm = context2 === "telegram-admin-dm";
596876
+ const scopedRoot = adminDm ? void 0 : telegramCreativeWorkspaceRoot(repoRoot, currentChatId);
596877
+ return {
596878
+ name: "telegram_send_file",
596879
+ description: adminDm ? "Upload an existing local file to a Telegram chat. Admin DM scope may target the current chat, a numeric chat/user id, or a @username if the bot is allowed to message it. This only sends the file; it does not create, edit, or delete files." : `Upload an existing file from this chat's scoped creative workspace to the current Telegram chat. Public/group scope cannot target other chats and cannot send files outside ${scopedRoot}.`,
596880
+ parameters: {
596881
+ type: "object",
596882
+ properties: {
596883
+ path: {
596884
+ type: "string",
596885
+ description: adminDm ? "Local file path to send. Relative paths resolve from the repo root; absolute paths are allowed for admin DM." : "File path inside the scoped creative workspace."
596886
+ },
596887
+ chat_id: {
596888
+ type: "string",
596889
+ description: "Admin DM only. Optional target chat/user id or @username. Defaults to the current Telegram chat."
596890
+ },
596891
+ user_id: {
596892
+ type: "string",
596893
+ description: "Admin DM only. Optional numeric Telegram user id to send to, if the bot can message that user."
596894
+ },
596895
+ kind: {
596896
+ type: "string",
596897
+ enum: ["auto", "image", "photo", "document", "audio", "voice", "video", "animation"],
596898
+ description: "How Telegram should send the file. Defaults to auto based on extension."
596899
+ },
596900
+ caption: {
596901
+ type: "string",
596902
+ description: "Optional Telegram caption."
596903
+ },
596904
+ reply_to_message_id: {
596905
+ type: "number",
596906
+ description: "Optional Telegram message id to reply to."
596907
+ }
596908
+ },
596909
+ required: ["path"]
596910
+ },
596911
+ async execute(args) {
596912
+ const start2 = performance.now();
596913
+ const rawPath = typeof args["path"] === "string" ? args["path"].trim() : "";
596914
+ if (!rawPath) {
596915
+ return { success: false, output: "", error: "path is required", durationMs: performance.now() - start2 };
596916
+ }
596917
+ const target = bridge.resolveTelegramFileTarget(args, currentChatId, adminDm);
596918
+ if (!target.ok) {
596919
+ return { success: false, output: "", error: target.error, durationMs: performance.now() - start2 };
596920
+ }
596921
+ const file = bridge.resolveTelegramFilePath(rawPath, repoRoot, scopedRoot);
596922
+ if (!file.ok) {
596923
+ return { success: false, output: "", error: file.error, durationMs: performance.now() - start2 };
596924
+ }
596925
+ const kind = normalizeTelegramSendKind(args["kind"], file.path);
596926
+ const caption = typeof args["caption"] === "string" ? args["caption"].trim().slice(0, 1024) : void 0;
596927
+ const replyTo = Number(args["reply_to_message_id"]);
596928
+ try {
596929
+ const messageId = await bridge.sendTelegramFileToChat(target.chatId, file.path, {
596930
+ kind,
596931
+ caption: caption || void 0,
596932
+ replyToMessageId: Number.isFinite(replyTo) && replyTo > 0 ? Math.floor(replyTo) : void 0
596933
+ });
596934
+ return {
596935
+ success: true,
596936
+ output: `Sent Telegram file: ${basename22(file.path)} as ${kind} to ${String(target.chatId)}${messageId ? ` (message_id ${messageId})` : ""}`,
596937
+ llmContent: `Sent ${basename22(file.path)} to Telegram as ${kind}.`,
596938
+ durationMs: performance.now() - start2,
596939
+ mutated: false,
596940
+ mutatedFiles: []
596941
+ };
596942
+ } catch (err) {
596943
+ return {
596944
+ success: false,
596945
+ output: "",
596946
+ error: `Telegram file upload failed: ${err instanceof Error ? err.message : String(err)}`,
596947
+ durationMs: performance.now() - start2
596948
+ };
596949
+ }
596950
+ }
596951
+ };
596952
+ }
596953
+ resolveTelegramFileTarget(args, currentChatId, adminDm) {
596954
+ const rawTarget = args["chat_id"] ?? args["target_chat_id"] ?? args["user_id"] ?? args["username"];
596955
+ if (!adminDm) {
596956
+ if (rawTarget !== void 0 && String(rawTarget).trim() && String(rawTarget).trim() !== String(currentChatId)) {
596957
+ return { ok: false, error: "Public/group telegram_send_file cannot target another chat. It may only send to the current chat." };
596958
+ }
596959
+ if (currentChatId === void 0) return { ok: false, error: "Current Telegram chat id is unavailable." };
596960
+ return { ok: true, chatId: currentChatId };
596961
+ }
596962
+ if (rawTarget === void 0 || !String(rawTarget).trim()) {
596963
+ if (currentChatId === void 0) return { ok: false, error: "No target chat_id/user_id provided and current chat id is unavailable." };
596964
+ return { ok: true, chatId: currentChatId };
596965
+ }
596966
+ const target = String(rawTarget).trim();
596967
+ if (/^-?\d+$/.test(target)) return { ok: true, chatId: target };
596968
+ const cleanUsername = target.replace(/^@/, "");
596969
+ if (/^[A-Za-z0-9_]{5,32}$/.test(cleanUsername)) {
596970
+ return { ok: true, chatId: `@${cleanUsername}` };
596971
+ }
596972
+ return { ok: false, error: "Expected chat_id/user_id as digits, or a valid @username." };
596973
+ }
596974
+ resolveTelegramFilePath(rawPath, repoRoot, scopedRoot) {
596975
+ const base3 = scopedRoot ? resolve39(scopedRoot) : resolve39(repoRoot);
596976
+ const trimmed = rawPath.trim().replace(/^["']|["']$/g, "");
596977
+ const abs = isAbsolute6(trimmed) ? resolve39(trimmed) : resolve39(base3, trimmed);
596978
+ if (scopedRoot && !isPathInside(base3, abs)) {
596979
+ return { ok: false, error: `Public/group telegram_send_file can only send files inside ${base3}.` };
596980
+ }
596981
+ if (!existsSync105(abs)) return { ok: false, error: `File does not exist: ${trimmed}` };
596982
+ if (!statSync35(abs).isFile()) return { ok: false, error: `Path is not a file: ${trimmed}` };
596983
+ return { ok: true, path: abs };
596984
+ }
596628
596985
  /** Check if a message is from the admin user (uses fromUserId, NOT chatId) */
596629
596986
  isAdminUser(msg) {
596630
596987
  if (!this.adminUserId) return false;
@@ -596716,7 +597073,7 @@ ${creativeWorkspace}` : ""}`;
596716
597073
  const ingressResult = await runVisionIngress2(
596717
597074
  {
596718
597075
  path: localPath,
596719
- buffer: readFileSync86(localPath),
597076
+ buffer: readFileSync87(localPath),
596720
597077
  mime: telegramImageMime(msg.media)
596721
597078
  },
596722
597079
  this.agentConfig?.model ?? ""
@@ -596852,18 +597209,42 @@ ${visionContext}]`;
596852
597209
  }
596853
597210
  return options2.html ? this.sendMessageHTML(msg.chatId, text, options2.replyToMessageId) : this.sendMessage(msg.chatId, text);
596854
597211
  }
596855
- async sendMediaReference(chatId, media) {
597212
+ async sendTelegramFileToChat(chatId, path11, options2) {
597213
+ const abs = resolve39(path11);
597214
+ if (!existsSync105(abs) || !statSync35(abs).isFile()) {
597215
+ throw new Error(`File does not exist or is not a regular file: ${path11}`);
597216
+ }
597217
+ return this.sendMediaReferenceStrict(chatId, {
597218
+ original: abs,
597219
+ value: abs,
597220
+ kind: options2.kind,
597221
+ source: "file",
597222
+ audioAsVoice: options2.kind === "voice"
597223
+ }, options2);
597224
+ }
597225
+ async sendMediaReference(chatId, media, options2 = {}) {
597226
+ try {
597227
+ return await this.sendMediaReferenceStrict(chatId, media, options2);
597228
+ } catch {
597229
+ return null;
597230
+ }
597231
+ }
597232
+ async sendMediaReferenceStrict(chatId, media, options2 = {}) {
596856
597233
  const { method, field } = mediaTelegramMethod(media.kind);
597234
+ const caption = options2.caption?.trim();
596857
597235
  if (media.source === "url") {
596858
597236
  const result2 = await this.apiCall(method, {
596859
597237
  chat_id: chatId,
596860
- [field]: media.value
597238
+ [field]: media.value,
597239
+ ...caption ? { caption } : {},
597240
+ ...options2.replyToMessageId ? { reply_to_message_id: options2.replyToMessageId } : {}
596861
597241
  });
597242
+ if (result2.ok === false) throw new Error(String(result2.description || `Telegram ${method} failed`));
596862
597243
  this.state.messagesSent++;
596863
597244
  return result2.result?.message_id ?? null;
596864
597245
  }
596865
- if (!existsSync105(media.value)) return null;
596866
- const buffer2 = readFileSync86(media.value);
597246
+ if (!existsSync105(media.value)) throw new Error(`File does not exist: ${media.value}`);
597247
+ const buffer2 = readFileSync87(media.value);
596867
597248
  const boundary = `----omnius-media-${Date.now()}-${Math.random().toString(36).slice(2)}`;
596868
597249
  const filename = basename22(media.value);
596869
597250
  const contentType = mimeForPath(media.value, media.kind);
@@ -596878,6 +597259,8 @@ ${visionContext}]`;
596878
597259
  `));
596879
597260
  };
596880
597261
  addField("chat_id", String(chatId));
597262
+ if (caption) addField("caption", caption);
597263
+ if (options2.replyToMessageId) addField("reply_to_message_id", String(options2.replyToMessageId));
596881
597264
  parts.push(Buffer.from(`--${boundary}\r
596882
597265
  `));
596883
597266
  parts.push(Buffer.from(
@@ -596904,7 +597287,7 @@ Content-Type: ${contentType}\r
596904
597287
  this.state.messagesSent++;
596905
597288
  return result.result?.message_id ?? null;
596906
597289
  }
596907
- return null;
597290
+ throw new Error(String(result.description || `Telegram ${method} failed`));
596908
597291
  }
596909
597292
  async sendGeneratedArtifactsFromSubAgent(msg, subAgent, finalText, includeMentioned) {
596910
597293
  const root = subAgent.creativeWorkspaceRoot;
@@ -596953,7 +597336,7 @@ Content-Type: ${contentType}\r
596953
597336
  addField(field, pathOrFileId);
596954
597337
  continue;
596955
597338
  }
596956
- const buffer2 = readFileSync86(pathOrFileId);
597339
+ const buffer2 = readFileSync87(pathOrFileId);
596957
597340
  const filename = basename22(pathOrFileId);
596958
597341
  parts.push(Buffer.from(`--${boundary}\r
596959
597342
  `));
@@ -597367,7 +597750,7 @@ __export(chat_session_exports, {
597367
597750
  import { randomUUID as randomUUID13 } from "node:crypto";
597368
597751
  import {
597369
597752
  existsSync as existsSync106,
597370
- readFileSync as readFileSync87,
597753
+ readFileSync as readFileSync88,
597371
597754
  readdirSync as readdirSync35,
597372
597755
  writeFileSync as writeFileSync58,
597373
597756
  renameSync as renameSync5,
@@ -597424,7 +597807,7 @@ function loadPersistedSessions() {
597424
597807
  if (!f2.endsWith(".json") || f2.includes(".tmp.")) continue;
597425
597808
  const fp = join121(dir, f2);
597426
597809
  try {
597427
- const parsed = JSON.parse(readFileSync87(fp, "utf-8"));
597810
+ const parsed = JSON.parse(readFileSync88(fp, "utf-8"));
597428
597811
  if (f2.endsWith(".inflight.json")) {
597429
597812
  if (parsed && parsed.pid && parsed.status === "running") {
597430
597813
  try {
@@ -597464,7 +597847,7 @@ function buildSystemPrompt(cwd4) {
597464
597847
  const diaryPath = join121(cwd4, ".omnius", "context", "session-diary.md");
597465
597848
  if (existsSync106(diaryPath)) {
597466
597849
  try {
597467
- const diary = readFileSync87(diaryPath, "utf-8").slice(0, 1e3);
597850
+ const diary = readFileSync88(diaryPath, "utf-8").slice(0, 1e3);
597468
597851
  parts.push(`\\nPrevious session history:\\n${diary}`);
597469
597852
  } catch {
597470
597853
  }
@@ -597477,7 +597860,7 @@ function buildSystemPrompt(cwd4) {
597477
597860
  parts.push("\\nPersistent memory topics: " + files.map((f2) => f2.replace(".json", "")).join(", "));
597478
597861
  for (const f2 of files.slice(0, 3)) {
597479
597862
  try {
597480
- const data = JSON.parse(readFileSync87(join121(memDir, f2), "utf-8"));
597863
+ const data = JSON.parse(readFileSync88(join121(memDir, f2), "utf-8"));
597481
597864
  const entries = Object.entries(data).slice(0, 3);
597482
597865
  if (entries.length > 0) {
597483
597866
  parts.push(`\\nMemory [${f2.replace(".json", "")}]: ` + entries.map(([k, v]) => `${k}: ${String(v.value ?? v).slice(0, 100)}`).join("; "));
@@ -597493,7 +597876,7 @@ function buildSystemPrompt(cwd4) {
597493
597876
  const p2 = join121(cwd4, name10);
597494
597877
  if (existsSync106(p2)) {
597495
597878
  try {
597496
- const content = readFileSync87(p2, "utf-8").slice(0, 500);
597879
+ const content = readFileSync88(p2, "utf-8").slice(0, 500);
597497
597880
  parts.push(`\\nProject instructions (${name10}):\\n${content}`);
597498
597881
  } catch {
597499
597882
  }
@@ -597511,7 +597894,7 @@ function getSession(sessionId, model, cwd4) {
597511
597894
  try {
597512
597895
  const fp = sessionPath(sessionId);
597513
597896
  if (existsSync106(fp)) {
597514
- const parsed = JSON.parse(readFileSync87(fp, "utf-8"));
597897
+ const parsed = JSON.parse(readFileSync88(fp, "utf-8"));
597515
597898
  if (parsed && parsed.id === sessionId) {
597516
597899
  parsed.lastActivity = Date.now();
597517
597900
  sessions.set(sessionId, parsed);
@@ -597629,7 +598012,7 @@ function drainCheckins(sessionId) {
597629
598012
  const fp = checkinPath(sessionId);
597630
598013
  if (!existsSync106(fp)) return [];
597631
598014
  try {
597632
- const raw = readFileSync87(fp, "utf-8");
598015
+ const raw = readFileSync88(fp, "utf-8");
597633
598016
  try {
597634
598017
  unlinkSync22(fp);
597635
598018
  } catch {
@@ -597682,7 +598065,7 @@ function lookupSession(id) {
597682
598065
  try {
597683
598066
  const fp = sessionPath(id);
597684
598067
  if (existsSync106(fp)) {
597685
- const parsed = JSON.parse(readFileSync87(fp, "utf-8"));
598068
+ const parsed = JSON.parse(readFileSync88(fp, "utf-8"));
597686
598069
  if (parsed && parsed.id === id) {
597687
598070
  sessions.set(id, parsed);
597688
598071
  return parsed;
@@ -597735,7 +598118,7 @@ function getInFlightChat(sessionId) {
597735
598118
  try {
597736
598119
  const p2 = inFlightPath(sessionId);
597737
598120
  if (existsSync106(p2)) {
597738
- const parsed = JSON.parse(readFileSync87(p2, "utf-8"));
598121
+ const parsed = JSON.parse(readFileSync88(p2, "utf-8"));
597739
598122
  if (parsed && parsed.sessionId === sessionId) {
597740
598123
  return parsed;
597741
598124
  }
@@ -597785,14 +598168,14 @@ __export(projects_exports, {
597785
598168
  setCurrentProject: () => setCurrentProject,
597786
598169
  unregisterProject: () => unregisterProject
597787
598170
  });
597788
- import { readFileSync as readFileSync88, writeFileSync as writeFileSync59, mkdirSync as mkdirSync62, existsSync as existsSync107, statSync as statSync36, renameSync as renameSync6 } from "node:fs";
598171
+ import { readFileSync as readFileSync89, writeFileSync as writeFileSync59, mkdirSync as mkdirSync62, existsSync as existsSync107, statSync as statSync36, renameSync as renameSync6 } from "node:fs";
597789
598172
  import { homedir as homedir37 } from "node:os";
597790
598173
  import { basename as basename23, join as join122, resolve as resolve40 } from "node:path";
597791
598174
  import { randomUUID as randomUUID14 } from "node:crypto";
597792
598175
  function readAll2() {
597793
598176
  try {
597794
598177
  if (!existsSync107(PROJECTS_FILE)) return { projects: [], schemaVersion: 1 };
597795
- const raw = readFileSync88(PROJECTS_FILE, "utf8");
598178
+ const raw = readFileSync89(PROJECTS_FILE, "utf8");
597796
598179
  const parsed = JSON.parse(raw);
597797
598180
  if (!parsed || !Array.isArray(parsed.projects)) return { projects: [], schemaVersion: 1 };
597798
598181
  return { projects: parsed.projects, schemaVersion: 1 };
@@ -597869,7 +598252,7 @@ function getCurrentProject() {
597869
598252
  if (!currentRoot) {
597870
598253
  try {
597871
598254
  if (existsSync107(CURRENT_FILE)) {
597872
- const persisted = readFileSync88(CURRENT_FILE, "utf8").trim();
598255
+ const persisted = readFileSync89(CURRENT_FILE, "utf8").trim();
597873
598256
  if (persisted) currentRoot = persisted;
597874
598257
  }
597875
598258
  } catch {
@@ -598605,7 +598988,7 @@ var init_access_policy = __esm({
598605
598988
 
598606
598989
  // packages/cli/src/api/project-preferences.ts
598607
598990
  import { createHash as createHash20 } from "node:crypto";
598608
- import { existsSync as existsSync108, mkdirSync as mkdirSync63, readFileSync as readFileSync89, renameSync as renameSync7, writeFileSync as writeFileSync60, unlinkSync as unlinkSync23 } from "node:fs";
598991
+ import { existsSync as existsSync108, mkdirSync as mkdirSync63, readFileSync as readFileSync90, renameSync as renameSync7, writeFileSync as writeFileSync60, unlinkSync as unlinkSync23 } from "node:fs";
598609
598992
  import { homedir as homedir38 } from "node:os";
598610
598993
  import { join as join123, resolve as resolve41 } from "node:path";
598611
598994
  import { randomUUID as randomUUID15 } from "node:crypto";
@@ -598638,7 +599021,7 @@ function readProjectPreferences(root) {
598638
599021
  try {
598639
599022
  const file = prefsPath(root);
598640
599023
  if (!existsSync108(file)) return { ...DEFAULT_PREFS };
598641
- const raw = readFileSync89(file, "utf8");
599024
+ const raw = readFileSync90(file, "utf8");
598642
599025
  const parsed = JSON.parse(raw);
598643
599026
  if (!parsed || parsed.v !== SCHEMA_VERSION) return { ...DEFAULT_PREFS };
598644
599027
  return { ...DEFAULT_PREFS, ...parsed, v: SCHEMA_VERSION };
@@ -599589,7 +599972,7 @@ __export(audit_log_exports, {
599589
599972
  recordAudit: () => recordAudit,
599590
599973
  sanitizeBody: () => sanitizeBody
599591
599974
  });
599592
- import { mkdirSync as mkdirSync64, appendFileSync as appendFileSync7, readFileSync as readFileSync90, existsSync as existsSync109 } from "node:fs";
599975
+ import { mkdirSync as mkdirSync64, appendFileSync as appendFileSync7, readFileSync as readFileSync91, existsSync as existsSync109 } from "node:fs";
599593
599976
  import { join as join124 } from "node:path";
599594
599977
  function initAuditLog(omniusDir) {
599595
599978
  auditDir = join124(omniusDir, "audit");
@@ -599626,7 +600009,7 @@ function sanitizeBody(body, maxLen = 200) {
599626
600009
  function queryAudit(opts) {
599627
600010
  if (!initialized || !existsSync109(auditFile)) return [];
599628
600011
  try {
599629
- const raw = readFileSync90(auditFile, "utf-8");
600012
+ const raw = readFileSync91(auditFile, "utf-8");
599630
600013
  const lines = raw.split("\n").filter(Boolean);
599631
600014
  let records = lines.map((l2) => {
599632
600015
  try {
@@ -599961,7 +600344,7 @@ __export(aiwg_exports, {
599961
600344
  resolveAiwgRoot: () => resolveAiwgRoot,
599962
600345
  tryRouteAiwg: () => tryRouteAiwg
599963
600346
  });
599964
- import { existsSync as existsSync111, readFileSync as readFileSync91, readdirSync as readdirSync36, statSync as statSync38 } from "node:fs";
600347
+ import { existsSync as existsSync111, readFileSync as readFileSync92, readdirSync as readdirSync36, statSync as statSync38 } from "node:fs";
599965
600348
  import { join as join125 } from "node:path";
599966
600349
  import { homedir as homedir39 } from "node:os";
599967
600350
  import { execSync as execSync55 } from "node:child_process";
@@ -600032,7 +600415,7 @@ function resolveAiwgRoot() {
600032
600415
  const pj = join125(cur, "package.json");
600033
600416
  if (existsSync111(pj)) {
600034
600417
  try {
600035
- const pkg = JSON.parse(readFileSync91(pj, "utf-8"));
600418
+ const pkg = JSON.parse(readFileSync92(pj, "utf-8"));
600036
600419
  if (pkg.name === "aiwg") {
600037
600420
  _cachedAiwgRoot = cur;
600038
600421
  return cur;
@@ -600122,7 +600505,7 @@ function readFirstLineDescription(dir) {
600122
600505
  const p2 = join125(dir, candidate);
600123
600506
  if (!existsSync111(p2)) continue;
600124
600507
  try {
600125
- const txt = readFileSync91(p2, "utf-8");
600508
+ const txt = readFileSync92(p2, "utf-8");
600126
600509
  const descMatch = txt.match(/^description:\s*(.+)$/m);
600127
600510
  if (descMatch) return descMatch[1].trim().slice(0, 200);
600128
600511
  for (const line of txt.split("\n")) {
@@ -600173,7 +600556,7 @@ function walkForItems(dir, out, depth) {
600173
600556
  }
600174
600557
  function parseItem(p2) {
600175
600558
  try {
600176
- const raw = readFileSync91(p2, "utf-8");
600559
+ const raw = readFileSync92(p2, "utf-8");
600177
600560
  const header = raw.slice(0, 3e3);
600178
600561
  const nameMatch = header.match(/^name:\s*(.+)$/m);
600179
600562
  const descMatch = header.match(/^description:\s*(.+)$/m);
@@ -600212,7 +600595,7 @@ function deriveSource(p2) {
600212
600595
  function loadAiwgItemContent(path11, maxBytes = 2e4) {
600213
600596
  try {
600214
600597
  if (!existsSync111(path11)) return null;
600215
- const raw = readFileSync91(path11, "utf-8");
600598
+ const raw = readFileSync92(path11, "utf-8");
600216
600599
  return raw.length > maxBytes ? raw.slice(0, maxBytes) + "\n\n...(truncated for context budget)" : raw;
600217
600600
  } catch {
600218
600601
  return null;
@@ -600721,7 +601104,7 @@ __export(runtime_keys_exports, {
600721
601104
  mintKey: () => mintKey,
600722
601105
  revokeByPrefix: () => revokeByPrefix
600723
601106
  });
600724
- import { existsSync as existsSync112, readFileSync as readFileSync92, writeFileSync as writeFileSync61, mkdirSync as mkdirSync66, chmodSync } from "node:fs";
601107
+ import { existsSync as existsSync112, readFileSync as readFileSync93, writeFileSync as writeFileSync61, mkdirSync as mkdirSync66, chmodSync } from "node:fs";
600725
601108
  import { join as join126 } from "node:path";
600726
601109
  import { homedir as homedir40 } from "node:os";
600727
601110
  import { randomBytes as randomBytes21 } from "node:crypto";
@@ -600732,7 +601115,7 @@ function ensureDir2() {
600732
601115
  function loadAll() {
600733
601116
  if (!existsSync112(KEYS_FILE)) return [];
600734
601117
  try {
600735
- const raw = readFileSync92(KEYS_FILE, "utf-8");
601118
+ const raw = readFileSync93(KEYS_FILE, "utf-8");
600736
601119
  const parsed = JSON.parse(raw);
600737
601120
  if (!Array.isArray(parsed)) return [];
600738
601121
  return parsed;
@@ -600818,7 +601201,7 @@ __export(tor_fallback_exports, {
600818
601201
  torIsReachable: () => torIsReachable,
600819
601202
  tunnelViaTor: () => tunnelViaTor
600820
601203
  });
600821
- import { existsSync as existsSync113, readFileSync as readFileSync93 } from "node:fs";
601204
+ import { existsSync as existsSync113, readFileSync as readFileSync94 } from "node:fs";
600822
601205
  import { homedir as homedir41 } from "node:os";
600823
601206
  import { join as join127 } from "node:path";
600824
601207
  import { createConnection as createConnection3 } from "node:net";
@@ -600831,7 +601214,7 @@ function getLocalOnion() {
600831
601214
  for (const p2 of candidates) {
600832
601215
  try {
600833
601216
  if (existsSync113(p2)) {
600834
- const v = readFileSync93(p2, "utf-8").trim();
601217
+ const v = readFileSync94(p2, "utf-8").trim();
600835
601218
  if (v && v.endsWith(".onion")) return v;
600836
601219
  }
600837
601220
  } catch {
@@ -601306,7 +601689,7 @@ var init_command_passthrough = __esm({
601306
601689
  });
601307
601690
 
601308
601691
  // packages/cli/src/api/routes-v1.ts
601309
- import { existsSync as existsSync115, readFileSync as readFileSync94, readdirSync as readdirSync37, statSync as statSync39 } from "node:fs";
601692
+ import { existsSync as existsSync115, readFileSync as readFileSync95, readdirSync as readdirSync37, statSync as statSync39 } from "node:fs";
601310
601693
  import { join as join129, resolve as pathResolve2 } from "node:path";
601311
601694
  import { homedir as homedir42 } from "node:os";
601312
601695
  async function tryRouteV1(ctx3) {
@@ -601563,7 +601946,7 @@ function walkForSkills(dir, out, depth) {
601563
601946
  walkForSkills(p2, out, depth + 1);
601564
601947
  } else if (e2.isFile() && e2.name === "SKILL.md") {
601565
601948
  try {
601566
- const content = readFileSync94(p2, "utf-8").slice(0, 2e3);
601949
+ const content = readFileSync95(p2, "utf-8").slice(0, 2e3);
601567
601950
  const nameMatch = content.match(/^name:\s*(.+)$/m);
601568
601951
  const descMatch = content.match(/^description:\s*(.+)$/m);
601569
601952
  out.push({
@@ -602037,7 +602420,7 @@ async function handleFilesRead(ctx3) {
602037
602420
  }));
602038
602421
  return true;
602039
602422
  }
602040
- const content = readFileSync94(resolved, "utf-8");
602423
+ const content = readFileSync95(resolved, "utf-8");
602041
602424
  const offset = typeof body.offset === "number" && body.offset >= 0 ? body.offset : 0;
602042
602425
  const limit = typeof body.limit === "number" && body.limit > 0 ? body.limit : content.length;
602043
602426
  const slice2 = content.slice(offset, offset + limit);
@@ -602277,7 +602660,7 @@ async function handleNexusStatus(ctx3) {
602277
602660
  for (const p2 of statePaths) {
602278
602661
  if (!existsSync115(p2)) continue;
602279
602662
  try {
602280
- const raw = readFileSync94(p2, "utf-8");
602663
+ const raw = readFileSync95(p2, "utf-8");
602281
602664
  states.push({ source: p2, data: JSON.parse(raw) });
602282
602665
  } catch (e2) {
602283
602666
  states.push({ source: p2, error: String(e2) });
@@ -602305,7 +602688,7 @@ async function handleNexusStatus(ctx3) {
602305
602688
  function loadAgentName() {
602306
602689
  try {
602307
602690
  const p2 = join129(homedir42(), ".omnius", "agent-name");
602308
- if (existsSync115(p2)) return readFileSync94(p2, "utf-8").trim();
602691
+ if (existsSync115(p2)) return readFileSync95(p2, "utf-8").trim();
602309
602692
  } catch {
602310
602693
  }
602311
602694
  return null;
@@ -602321,7 +602704,7 @@ async function handleSponsors(ctx3) {
602321
602704
  for (const p2 of candidates) {
602322
602705
  if (!existsSync115(p2)) continue;
602323
602706
  try {
602324
- const raw = JSON.parse(readFileSync94(p2, "utf-8"));
602707
+ const raw = JSON.parse(readFileSync95(p2, "utf-8"));
602325
602708
  if (Array.isArray(raw)) {
602326
602709
  sponsors = raw;
602327
602710
  break;
@@ -602401,7 +602784,7 @@ async function handleEvaluate(ctx3) {
602401
602784
  }));
602402
602785
  return true;
602403
602786
  }
602404
- const job = JSON.parse(readFileSync94(jobPath, "utf-8"));
602787
+ const job = JSON.parse(readFileSync95(jobPath, "utf-8"));
602405
602788
  sendJson(res, 200, {
602406
602789
  run_id: runId,
602407
602790
  task: job.task,
@@ -602541,7 +602924,7 @@ async function handleMintKey(ctx3) {
602541
602924
  function _readStatusFile(p2) {
602542
602925
  if (!existsSync115(p2)) return null;
602543
602926
  try {
602544
- const data = JSON.parse(readFileSync94(p2, "utf-8"));
602927
+ const data = JSON.parse(readFileSync95(p2, "utf-8"));
602545
602928
  if (data?.connected && typeof data.peerId === "string" && data.peerId.length > 10) {
602546
602929
  return {
602547
602930
  peerId: data.peerId,
@@ -602562,7 +602945,7 @@ function resolveLocalPeerId() {
602562
602945
  try {
602563
602946
  const regPath = join129(homedir42(), ".omnius", "nexus-registry.json");
602564
602947
  if (existsSync115(regPath)) {
602565
- const reg = JSON.parse(readFileSync94(regPath, "utf-8"));
602948
+ const reg = JSON.parse(readFileSync95(regPath, "utf-8"));
602566
602949
  const entries = Array.isArray(reg?.dirs) ? reg.dirs : [];
602567
602950
  for (const entry of entries) {
602568
602951
  const dir = typeof entry === "string" ? entry : entry?.dir;
@@ -603652,7 +604035,7 @@ function aimsDir() {
603652
604035
  function readAimsFile(name10, fallback) {
603653
604036
  try {
603654
604037
  const p2 = join129(aimsDir(), name10);
603655
- if (existsSync115(p2)) return JSON.parse(readFileSync94(p2, "utf-8"));
604038
+ if (existsSync115(p2)) return JSON.parse(readFileSync95(p2, "utf-8"));
603656
604039
  } catch {
603657
604040
  }
603658
604041
  return fallback;
@@ -603996,7 +604379,7 @@ async function handleAimsSuppliers(ctx3) {
603996
604379
  for (const p2 of sponsorPaths) {
603997
604380
  if (!existsSync115(p2)) continue;
603998
604381
  try {
603999
- const raw = JSON.parse(readFileSync94(p2, "utf-8"));
604382
+ const raw = JSON.parse(readFileSync95(p2, "utf-8"));
604000
604383
  const list = Array.isArray(raw) ? raw : raw?.sponsors ?? [];
604001
604384
  for (const s2 of list) {
604002
604385
  suppliers.push({
@@ -613151,7 +613534,7 @@ var init_auth_oidc = __esm({
613151
613534
  });
613152
613535
 
613153
613536
  // packages/cli/src/api/usage-tracker.ts
613154
- import { mkdirSync as mkdirSync68, readFileSync as readFileSync95, writeFileSync as writeFileSync63, existsSync as existsSync116 } from "node:fs";
613537
+ import { mkdirSync as mkdirSync68, readFileSync as readFileSync96, writeFileSync as writeFileSync63, existsSync as existsSync116 } from "node:fs";
613155
613538
  import { join as join130 } from "node:path";
613156
613539
  function initUsageTracker(omniusDir) {
613157
613540
  const dir = join130(omniusDir, "usage");
@@ -613159,7 +613542,7 @@ function initUsageTracker(omniusDir) {
613159
613542
  usageFile = join130(dir, "token-usage.json");
613160
613543
  try {
613161
613544
  if (existsSync116(usageFile)) {
613162
- store = JSON.parse(readFileSync95(usageFile, "utf-8"));
613545
+ store = JSON.parse(readFileSync96(usageFile, "utf-8"));
613163
613546
  }
613164
613547
  } catch {
613165
613548
  store = { providers: {}, lastSaved: "" };
@@ -613223,7 +613606,7 @@ var init_usage_tracker = __esm({
613223
613606
  });
613224
613607
 
613225
613608
  // packages/cli/src/api/profiles.ts
613226
- import { existsSync as existsSync117, readFileSync as readFileSync96, writeFileSync as writeFileSync64, mkdirSync as mkdirSync69, readdirSync as readdirSync38, unlinkSync as unlinkSync24 } from "node:fs";
613609
+ import { existsSync as existsSync117, readFileSync as readFileSync97, writeFileSync as writeFileSync64, mkdirSync as mkdirSync69, readdirSync as readdirSync38, unlinkSync as unlinkSync24 } from "node:fs";
613227
613610
  import { join as join131 } from "node:path";
613228
613611
  import { homedir as homedir43 } from "node:os";
613229
613612
  import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes22, scryptSync as scryptSync3 } from "node:crypto";
@@ -613240,7 +613623,7 @@ function listProfiles(projectDir2) {
613240
613623
  if (existsSync117(projDir)) {
613241
613624
  for (const f2 of readdirSync38(projDir).filter((f3) => f3.endsWith(".json"))) {
613242
613625
  try {
613243
- const raw = JSON.parse(readFileSync96(join131(projDir, f2), "utf8"));
613626
+ const raw = JSON.parse(readFileSync97(join131(projDir, f2), "utf8"));
613244
613627
  const name10 = f2.replace(".json", "");
613245
613628
  seen.add(name10);
613246
613629
  result.push({
@@ -613259,7 +613642,7 @@ function listProfiles(projectDir2) {
613259
613642
  const name10 = f2.replace(".json", "");
613260
613643
  if (seen.has(name10)) continue;
613261
613644
  try {
613262
- const raw = JSON.parse(readFileSync96(join131(globDir, f2), "utf8"));
613645
+ const raw = JSON.parse(readFileSync97(join131(globDir, f2), "utf8"));
613263
613646
  result.push({
613264
613647
  name: name10,
613265
613648
  description: raw.description || "",
@@ -613278,7 +613661,7 @@ function loadProfile(name10, password, projectDir2) {
613278
613661
  const globPath = join131(globalProfileDir(), `${sanitized}.json`);
613279
613662
  const filePath = existsSync117(projPath) ? projPath : existsSync117(globPath) ? globPath : null;
613280
613663
  if (!filePath) return null;
613281
- const raw = JSON.parse(readFileSync96(filePath, "utf8"));
613664
+ const raw = JSON.parse(readFileSync97(filePath, "utf8"));
613282
613665
  if (raw.encrypted === true) {
613283
613666
  if (!password) return null;
613284
613667
  return decryptProfile(raw, password);
@@ -613964,7 +614347,7 @@ import { fileURLToPath as fileURLToPath17 } from "node:url";
613964
614347
  import { dirname as dirname37, join as join134, resolve as resolve43 } from "node:path";
613965
614348
  import { homedir as homedir45 } from "node:os";
613966
614349
  import { spawn as spawn29, execSync as execSync57 } from "node:child_process";
613967
- import { mkdirSync as mkdirSync71, writeFileSync as writeFileSync66, readFileSync as readFileSync97, readdirSync as readdirSync39, existsSync as existsSync119, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync25 } from "node:fs";
614350
+ import { mkdirSync as mkdirSync71, writeFileSync as writeFileSync66, readFileSync as readFileSync98, readdirSync as readdirSync39, existsSync as existsSync119, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync25 } from "node:fs";
613968
614351
  import { randomBytes as randomBytes23, randomUUID as randomUUID16 } from "node:crypto";
613969
614352
  import { createHash as createHash23 } from "node:crypto";
613970
614353
  function getVersion3() {
@@ -614235,7 +614618,7 @@ function isOriginAllowed(origin) {
614235
614618
  try {
614236
614619
  const accessFile = join134(homedir45(), ".omnius", "access");
614237
614620
  if (existsSync119(accessFile)) {
614238
- const persisted = readFileSync97(accessFile, "utf8").trim().toLowerCase();
614621
+ const persisted = readFileSync98(accessFile, "utf8").trim().toLowerCase();
614239
614622
  if (persisted === "any" || persisted === "lan" || persisted === "loopback") {
614240
614623
  accessMode = persisted;
614241
614624
  }
@@ -614676,7 +615059,7 @@ function loadJob(id) {
614676
615059
  const file = join134(jobsDir(), `${id}.json`);
614677
615060
  if (!existsSync119(file)) return null;
614678
615061
  try {
614679
- return JSON.parse(readFileSync97(file, "utf-8"));
615062
+ return JSON.parse(readFileSync98(file, "utf-8"));
614680
615063
  } catch {
614681
615064
  return null;
614682
615065
  }
@@ -614688,7 +615071,7 @@ function listJobs() {
614688
615071
  const jobs = [];
614689
615072
  for (const file of files) {
614690
615073
  try {
614691
- jobs.push(JSON.parse(readFileSync97(join134(dir, file), "utf-8")));
615074
+ jobs.push(JSON.parse(readFileSync98(join134(dir, file), "utf-8")));
614692
615075
  } catch {
614693
615076
  }
614694
615077
  }
@@ -614705,7 +615088,7 @@ function pruneOldJobs() {
614705
615088
  if (!file.endsWith(".json")) continue;
614706
615089
  const path11 = join134(dir, file);
614707
615090
  try {
614708
- const job = JSON.parse(readFileSync97(path11, "utf-8"));
615091
+ const job = JSON.parse(readFileSync98(path11, "utf-8"));
614709
615092
  if (job.status === "running") {
614710
615093
  kept++;
614711
615094
  continue;
@@ -616462,7 +616845,7 @@ function readUpdateState() {
616462
616845
  try {
616463
616846
  const p2 = updateStateFile();
616464
616847
  if (!existsSync119(p2)) return null;
616465
- return JSON.parse(readFileSync97(p2, "utf-8"));
616848
+ return JSON.parse(readFileSync98(p2, "utf-8"));
616466
616849
  } catch {
616467
616850
  return null;
616468
616851
  }
@@ -616677,7 +617060,7 @@ function handleV1UpdateStatus(res) {
616677
617060
  let exitCode = null;
616678
617061
  try {
616679
617062
  if (existsSync119(logPath3)) {
616680
- const raw = readFileSync97(logPath3, "utf-8");
617063
+ const raw = readFileSync98(logPath3, "utf-8");
616681
617064
  const m2 = raw.match(/__EXIT_CODE=(\d+)/);
616682
617065
  if (m2) exitCode = parseInt(m2[1], 10);
616683
617066
  logTail = raw.slice(-2e3);
@@ -619646,7 +620029,7 @@ function listScheduledTasks() {
619646
620029
  if (dir.endsWith(`${join134(".omnius", "scheduled")}`) || dir.includes(`${join134(".omnius", "scheduled")}`)) {
619647
620030
  const file = join134(dir, "tasks.json");
619648
620031
  try {
619649
- const raw = readFileSync97(file, "utf-8");
620032
+ const raw = readFileSync98(file, "utf-8");
619650
620033
  const json = JSON.parse(raw);
619651
620034
  const tasks = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
619652
620035
  tasks.forEach((t2, i2) => {
@@ -619720,7 +620103,7 @@ function setScheduledEnabled(id, enabled2) {
619720
620103
  const target = tasks.find((t2) => t2.id === id);
619721
620104
  if (!target) return false;
619722
620105
  try {
619723
- const raw = readFileSync97(target.file, "utf-8");
620106
+ const raw = readFileSync98(target.file, "utf-8");
619724
620107
  const json = JSON.parse(raw);
619725
620108
  const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
619726
620109
  if (!arr[target.index]) return false;
@@ -619753,7 +620136,7 @@ function deleteScheduledById(id) {
619753
620136
  const target = tasks.find((t2) => t2.id === id);
619754
620137
  if (!target) return false;
619755
620138
  try {
619756
- const raw = readFileSync97(target.file, "utf-8");
620139
+ const raw = readFileSync98(target.file, "utf-8");
619757
620140
  const json = JSON.parse(raw);
619758
620141
  const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
619759
620142
  if (!arr[target.index]) return false;
@@ -620022,7 +620405,7 @@ function reconcileScheduledTasks(apply) {
620022
620405
  try {
620023
620406
  let json = { tasks: [] };
620024
620407
  try {
620025
- const raw = readFileSync97(file, "utf-8");
620408
+ const raw = readFileSync98(file, "utf-8");
620026
620409
  json = JSON.parse(raw);
620027
620410
  } catch {
620028
620411
  }
@@ -620323,7 +620706,7 @@ function startApiServer(options2 = {}) {
620323
620706
  if (!f2.endsWith(".json") || f2.includes(".tmp.")) continue;
620324
620707
  const sid = f2.replace(/\.json$/, "");
620325
620708
  try {
620326
- const items = JSON.parse(readFileSync97(join134(dir, f2), "utf-8"));
620709
+ const items = JSON.parse(readFileSync98(join134(dir, f2), "utf-8"));
620327
620710
  if (Array.isArray(items)) {
620328
620711
  cache8.set(sid, new Map(items.map((t2) => [t2.id, t2])));
620329
620712
  }
@@ -620351,7 +620734,7 @@ function startApiServer(options2 = {}) {
620351
620734
  }
620352
620735
  return;
620353
620736
  }
620354
- next = JSON.parse(readFileSync97(fp, "utf-8"));
620737
+ next = JSON.parse(readFileSync98(fp, "utf-8"));
620355
620738
  if (!Array.isArray(next)) return;
620356
620739
  } catch {
620357
620740
  return;
@@ -620397,7 +620780,7 @@ function startApiServer(options2 = {}) {
620397
620780
  if (!f2.endsWith(".json")) continue;
620398
620781
  try {
620399
620782
  const jobPath = join134(jobsDir3, f2);
620400
- const job = JSON.parse(readFileSync97(jobPath, "utf-8"));
620783
+ const job = JSON.parse(readFileSync98(jobPath, "utf-8"));
620401
620784
  const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
620402
620785
  if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
620403
620786
  const { unlinkSync: unlinkSync26 } = require3("node:fs");
@@ -620417,8 +620800,8 @@ function startApiServer(options2 = {}) {
620417
620800
  if (useTls) {
620418
620801
  try {
620419
620802
  tlsOpts = {
620420
- cert: readFileSync97(resolve43(tlsCert)),
620421
- key: readFileSync97(resolve43(tlsKey))
620803
+ cert: readFileSync98(resolve43(tlsCert)),
620804
+ key: readFileSync98(resolve43(tlsKey))
620422
620805
  };
620423
620806
  } catch (e2) {
620424
620807
  log22(`
@@ -620431,7 +620814,7 @@ function startApiServer(options2 = {}) {
620431
620814
  try {
620432
620815
  const accessFile = join134(homedir45(), ".omnius", "access");
620433
620816
  if (existsSync119(accessFile)) {
620434
- const persisted = readFileSync97(accessFile, "utf8").trim();
620817
+ const persisted = readFileSync98(accessFile, "utf8").trim();
620435
620818
  const resolved = resolveAccessMode(persisted, host);
620436
620819
  if (resolved) runtimeAccessMode = resolved;
620437
620820
  }
@@ -621328,7 +621711,7 @@ __export(clipboard_media_exports, {
621328
621711
  pasteClipboardImageToFile: () => pasteClipboardImageToFile
621329
621712
  });
621330
621713
  import { execFileSync as execFileSync4, execSync as execSync58 } from "node:child_process";
621331
- import { mkdirSync as mkdirSync72, readFileSync as readFileSync98, rmSync as rmSync5, writeFileSync as writeFileSync67 } from "node:fs";
621714
+ import { mkdirSync as mkdirSync72, readFileSync as readFileSync99, rmSync as rmSync5, writeFileSync as writeFileSync67 } from "node:fs";
621332
621715
  import { join as join135 } from "node:path";
621333
621716
  function pasteClipboardImageToFile(repoRoot) {
621334
621717
  const image = readClipboardImage();
@@ -621345,7 +621728,7 @@ function readClipboardImage() {
621345
621728
  execSync58("command -v pngpaste", { stdio: "ignore", timeout: 1e3 });
621346
621729
  const tmp = `/tmp/omnius-clipboard-${Date.now()}.png`;
621347
621730
  execFileSync4("pngpaste", [tmp], { timeout: 3e3 });
621348
- const buffer2 = readFileSync98(tmp);
621731
+ const buffer2 = readFileSync99(tmp);
621349
621732
  try {
621350
621733
  rmSync5(tmp);
621351
621734
  } catch {
@@ -621404,7 +621787,7 @@ import { resolve as resolve44, join as join136, dirname as dirname38, extname as
621404
621787
  import { createRequire as createRequire7 } from "node:module";
621405
621788
  import { fileURLToPath as fileURLToPath18 } from "node:url";
621406
621789
  import {
621407
- readFileSync as readFileSync99,
621790
+ readFileSync as readFileSync100,
621408
621791
  writeFileSync as writeFileSync68,
621409
621792
  appendFileSync as appendFileSync8,
621410
621793
  rmSync as rmSync6,
@@ -621707,6 +622090,16 @@ ${result.summary}`
621707
622090
  }
621708
622091
  });
621709
622092
  }
622093
+ function imageGenerationDefaultsForRepo(repoRoot) {
622094
+ const settings = resolveSettings(repoRoot);
622095
+ return {
622096
+ model: typeof settings.imageModel === "string" && settings.imageModel.trim() ? settings.imageModel : void 0,
622097
+ backend: settings.imageBackend
622098
+ };
622099
+ }
622100
+ function createConfiguredImageGenerateTool(repoRoot, backendUrl) {
622101
+ return new ImageGenerateTool(repoRoot, backendUrl, imageGenerationDefaultsForRepo(repoRoot));
622102
+ }
621710
622103
  function buildSubAgentTools(repoRoot, config) {
621711
622104
  return [
621712
622105
  // File + search
@@ -621788,7 +622181,7 @@ function buildSubAgentTools(repoRoot, config) {
621788
622181
  new MultimodalMemoryTool(),
621789
622182
  new VideoUnderstandTool(repoRoot),
621790
622183
  new CameraCaptureTool(),
621791
- new ImageGenerateTool(repoRoot, config.backendUrl),
622184
+ createConfiguredImageGenerateTool(repoRoot, config.backendUrl),
621792
622185
  // Hardware sensors + radios (read-only scans)
621793
622186
  new GpsLocationTool(),
621794
622187
  new WifiControlTool(),
@@ -621867,8 +622260,8 @@ function buildTools(repoRoot, config, contextWindowSize, modelTier) {
621867
622260
  new ExplorationCultureTool(repoRoot),
621868
622261
  // Embedding Store — COHERE Private Brain semantic retrieval
621869
622262
  new EmbeddingStoreTool(repoRoot),
621870
- // Image Generation — Ollama diffusion models
621871
- new ImageGenerateTool(repoRoot, config.backendUrl),
622263
+ // Image Generation — local/Ollama/Diffusers image models
622264
+ createConfiguredImageGenerateTool(repoRoot, config.backendUrl),
621872
622265
  // Structured file reading (CSV, JSON, Markdown, binary detection)
621873
622266
  new StructuredReadTool(repoRoot),
621874
622267
  // Vision tools (Moondream — desktop awareness + point-and-click)
@@ -622332,7 +622725,7 @@ function gatherMemorySnippets(root) {
622332
622725
  if (!existsSync120(dir)) continue;
622333
622726
  try {
622334
622727
  for (const f2 of readdirSync40(dir).filter((f3) => f3.endsWith(".json"))) {
622335
- const data = JSON.parse(readFileSync99(join136(dir, f2), "utf-8"));
622728
+ const data = JSON.parse(readFileSync100(join136(dir, f2), "utf-8"));
622336
622729
  for (const val of Object.values(data)) {
622337
622730
  const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
622338
622731
  if (v.length > 10) snippets.push(v);
@@ -622423,23 +622816,44 @@ async function renderAsciiPreviewForImage(imagePath, displayPath, title, writer)
622423
622816
  formatImageAsciiContext: formatImageAsciiContext2
622424
622817
  } = await Promise.resolve().then(() => (init_image_ascii_preview(), image_ascii_preview_exports));
622425
622818
  const preview = await buildImageAsciiPreview2(imagePath);
622426
- if (!preview) return "";
622819
+ if (!preview) {
622820
+ writer(() => renderWarning(`Image ASCII preview unavailable for ${displayPath}.`));
622821
+ return "";
622822
+ }
622427
622823
  writer(() => renderImageAsciiPreview(title, displayPath, preview.ascii, preview.renderer));
622428
622824
  return formatImageAsciiContext2(preview, displayPath);
622429
622825
  } catch {
622430
622826
  return "";
622431
622827
  }
622432
622828
  }
622829
+ function formatImageGenerationProgress2(event) {
622830
+ const elapsed = event.elapsedMs && event.elapsedMs > 1500 ? ` ${Math.round(event.elapsedMs / 1e3)}s` : "";
622831
+ if (typeof event.percent === "number") {
622832
+ const width = 20;
622833
+ const filled = Math.max(0, Math.min(width, Math.round(event.percent / 100 * width)));
622834
+ const bar = `${"#".repeat(filled)}${"-".repeat(width - filled)}`;
622835
+ return `Image ${event.stage}: [${bar}] ${event.percent}% ${event.message}${elapsed}`;
622836
+ }
622837
+ return `Image ${event.stage}: ${event.message}${elapsed}`;
622838
+ }
622433
622839
  async function renderAsciiPreviewForToolResult(toolName, output, repoRoot, writer) {
622434
622840
  if (!output) return;
622435
622841
  try {
622436
622842
  const { extractSavedImagePath: extractSavedImagePath2 } = await Promise.resolve().then(() => (init_image_ascii_preview(), image_ascii_preview_exports));
622437
622843
  const imagePath = extractSavedImagePath2(output, repoRoot);
622438
- if (!imagePath) return;
622844
+ if (!imagePath) {
622845
+ if (toolName === "generate_image") {
622846
+ writer(() => renderWarning("Generated image preview skipped: no saved image path was found in the tool output."));
622847
+ }
622848
+ return;
622849
+ }
622439
622850
  const displayPath = relative14(repoRoot, imagePath).startsWith("..") ? imagePath : relative14(repoRoot, imagePath);
622440
622851
  const title = toolName === "generate_image" ? "Generated image" : toolName === "screenshot" ? "Screenshot" : toolName === "camera_capture" ? "Camera frame" : "Image";
622441
622852
  await renderAsciiPreviewForImage(imagePath, displayPath, title, writer);
622442
- } catch {
622853
+ } catch (err) {
622854
+ if (toolName === "generate_image") {
622855
+ writer(() => renderWarning(`Generated image preview failed: ${err instanceof Error ? err.message : String(err)}`));
622856
+ }
622443
622857
  }
622444
622858
  }
622445
622859
  async function runSelfImprovementCycle(repoRoot) {
@@ -622553,7 +622967,7 @@ ${metabolismMemories}
622553
622967
  try {
622554
622968
  const archeFile = join136(repoRoot, ".omnius", "arche", "variants.json");
622555
622969
  if (existsSync120(archeFile)) {
622556
- const variants = JSON.parse(readFileSync99(archeFile, "utf8"));
622970
+ const variants = JSON.parse(readFileSync100(archeFile, "utf8"));
622557
622971
  if (variants.length > 0) {
622558
622972
  let filtered = variants;
622559
622973
  if (taskType) {
@@ -622762,7 +623176,7 @@ RULES:
622762
623176
  try {
622763
623177
  const ikStateFile = join136(repoRoot, ".omnius", "identity", "self-state.json");
622764
623178
  if (existsSync120(ikStateFile)) {
622765
- const selfState = JSON.parse(readFileSync99(ikStateFile, "utf8"));
623179
+ const selfState = JSON.parse(readFileSync100(ikStateFile, "utf8"));
622766
623180
  const lines = [
622767
623181
  `[Identity State v${selfState.version}]`,
622768
623182
  `Self: ${selfState.narrative_summary}`,
@@ -623028,7 +623442,7 @@ Review its full output in the [${id}] tab or via sub_agent(action='output', id='
623028
623442
  }
623029
623443
  }
623030
623444
  try {
623031
- const { readdirSync: readdirSync42, readFileSync: readFileSync101, existsSync: existsSync123 } = await import("node:fs");
623445
+ const { readdirSync: readdirSync42, readFileSync: readFileSync102, existsSync: existsSync123 } = await import("node:fs");
623032
623446
  const { join: pathJoin } = await import("node:path");
623033
623447
  const chunksDir = pathJoin(cwd(), ".omnius", "todo-chunks");
623034
623448
  if (existsSync123(chunksDir)) {
@@ -623038,7 +623452,7 @@ Review its full output in the [${id}] tab or via sub_agent(action='output', id='
623038
623452
  for (const f2 of files) {
623039
623453
  try {
623040
623454
  const data = JSON.parse(
623041
- readFileSync101(pathJoin(chunksDir, f2), "utf-8")
623455
+ readFileSync102(pathJoin(chunksDir, f2), "utf-8")
623042
623456
  );
623043
623457
  if (data._deleted) continue;
623044
623458
  if ((data.functionalSummary || "").toLowerCase().includes(q) || (data.detailSummary || "").toLowerCase().includes(q) || (data.keyFiles || []).some(
@@ -623104,7 +623518,7 @@ ${lines.join("\n")}`
623104
623518
  const expand2 = args.expand === true;
623105
623519
  if (expand2 && id.startsWith("todo-ctx-")) {
623106
623520
  try {
623107
- const { readFileSync: readFileSync101, existsSync: existsSync123 } = await import("node:fs");
623521
+ const { readFileSync: readFileSync102, existsSync: existsSync123 } = await import("node:fs");
623108
623522
  const { join: pathJoin } = await import("node:path");
623109
623523
  const chunksDir = pathJoin(cwd(), ".omnius", "todo-chunks");
623110
623524
  const todoIdSuffix = id.replace("todo-ctx-", "");
@@ -623413,6 +623827,14 @@ ${entry.fullContent}`
623413
623827
  fn();
623414
623828
  }
623415
623829
  };
623830
+ for (const tool of tools) {
623831
+ const maybeProgressTool = tool;
623832
+ if (typeof maybeProgressTool.setProgressCallback === "function") {
623833
+ maybeProgressTool.setProgressCallback((event) => {
623834
+ contentWrite(() => renderInfo(formatImageGenerationProgress2(event)));
623835
+ });
623836
+ }
623837
+ }
623416
623838
  runner.onEvent((event) => {
623417
623839
  emotionEngine?.appraise(event);
623418
623840
  switch (event.type) {
@@ -623589,7 +624011,7 @@ ${entry.fullContent}`
623589
624011
  }
623590
624012
  });
623591
624013
  }
623592
- if (event.success) {
624014
+ if (event.success || event.toolName === "generate_image") {
623593
624015
  void renderAsciiPreviewForToolResult(event.toolName, event.content ?? "", repoRoot, contentWrite);
623594
624016
  }
623595
624017
  if (voice?.enabled && voice.voiceMode === "voicechat" && _voiceChatSession2?.isActive && event.toolName === "task_complete") {
@@ -623718,7 +624140,7 @@ ${entry.fullContent}`
623718
624140
  if (_apiCallbacks?.onStatus)
623719
624141
  _apiCallbacks.onStatus(event.content ?? "");
623720
624142
  if (isNeovimActive()) {
623721
- writeToNeovimOutput(`\x1B[2m${event.content ?? ""}\x1B[0m\r
624143
+ writeToNeovimOutput(`\x1B[38;5;250m${event.content ?? ""}\x1B[0m\r
623722
624144
  `);
623723
624145
  } else {
623724
624146
  contentWrite(() => renderInfo(event.content ?? ""));
@@ -623885,7 +624307,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
623885
624307
  const ikFile = join136(ikDir, "self-state.json");
623886
624308
  let ikState;
623887
624309
  if (existsSync120(ikFile)) {
623888
- ikState = JSON.parse(readFileSync99(ikFile, "utf8"));
624310
+ ikState = JSON.parse(readFileSync100(ikFile, "utf8"));
623889
624311
  } else {
623890
624312
  mkdirSync73(ikDir, { recursive: true });
623891
624313
  const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
@@ -624031,7 +624453,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
624031
624453
  try {
624032
624454
  const ikFile = join136(repoRoot, ".omnius", "identity", "self-state.json");
624033
624455
  if (existsSync120(ikFile)) {
624034
- const ikState = JSON.parse(readFileSync99(ikFile, "utf8"));
624456
+ const ikState = JSON.parse(readFileSync100(ikFile, "utf8"));
624035
624457
  if (!ikState.stats) ikState.stats = { queries_served: 0 };
624036
624458
  ikState.stats.queries_served = (ikState.stats.queries_served || 0) + 1;
624037
624459
  ikState.homeostasis.uncertainty = Math.min(
@@ -624323,7 +624745,7 @@ async function startInteractive(config, repoPath) {
624323
624745
  const omniusDir = join136(repoRoot, ".omnius");
624324
624746
  const nexusPidFile = join136(omniusDir, "nexus", "daemon.pid");
624325
624747
  if (existsSync120(nexusPidFile)) {
624326
- const pid = parseInt(readFileSync99(nexusPidFile, "utf8").trim(), 10);
624748
+ const pid = parseInt(readFileSync100(nexusPidFile, "utf8").trim(), 10);
624327
624749
  if (pid > 0) {
624328
624750
  try {
624329
624751
  process.kill(pid, 0);
@@ -625325,7 +625747,7 @@ This is an independent background session started from /background.`
625325
625747
  };
625326
625748
  try {
625327
625749
  const titleFile = join136(repoRoot, ".omnius", "session-title");
625328
- if (existsSync120(titleFile)) sessionTitle = readFileSync99(titleFile, "utf8").trim() || null;
625750
+ if (existsSync120(titleFile)) sessionTitle = readFileSync100(titleFile, "utf8").trim() || null;
625329
625751
  } catch {
625330
625752
  }
625331
625753
  let carouselRetired = isResumed;
@@ -625388,7 +625810,7 @@ This is an independent background session started from /background.`
625388
625810
  let savedHistory = [];
625389
625811
  try {
625390
625812
  if (existsSync120(HISTORY_FILE)) {
625391
- const raw = readFileSync99(HISTORY_FILE, "utf8").trim();
625813
+ const raw = readFileSync100(HISTORY_FILE, "utf8").trim();
625392
625814
  if (raw) savedHistory = raw.split("\n").reverse();
625393
625815
  }
625394
625816
  } catch {
@@ -625548,7 +625970,7 @@ This is an independent background session started from /background.`
625548
625970
  mkdirSync73(HISTORY_DIR, { recursive: true });
625549
625971
  appendFileSync8(HISTORY_FILE, line + "\n", "utf8");
625550
625972
  if (Math.random() < 0.02) {
625551
- const all2 = readFileSync99(HISTORY_FILE, "utf8").trim().split("\n");
625973
+ const all2 = readFileSync100(HISTORY_FILE, "utf8").trim().split("\n");
625552
625974
  if (all2.length > MAX_HISTORY_LINES) {
625553
625975
  writeFileSync68(
625554
625976
  HISTORY_FILE,
@@ -625771,7 +626193,7 @@ This is an independent background session started from /background.`
625771
626193
  const nexusPidFile = join136(repoRoot, ".omnius", "nexus", "daemon.pid");
625772
626194
  if (existsSync120(nexusPidFile)) {
625773
626195
  const nPid = parseInt(
625774
- readFileSync99(nexusPidFile, "utf8").trim(),
626196
+ readFileSync100(nexusPidFile, "utf8").trim(),
625775
626197
  10
625776
626198
  );
625777
626199
  if (nPid > 0 && !registry2.daemons.has("Nexus")) {
@@ -625949,7 +626371,7 @@ Log: ${nexusLogPath}`)
625949
626371
  let agName = "";
625950
626372
  try {
625951
626373
  if (existsSync120(globalNamePath))
625952
- agName = readFileSync99(globalNamePath, "utf8").trim();
626374
+ agName = readFileSync100(globalNamePath, "utf8").trim();
625953
626375
  } catch {
625954
626376
  }
625955
626377
  if (!agName) {
@@ -625990,7 +626412,7 @@ Log: ${nexusLogPath}`)
625990
626412
  try {
625991
626413
  if (existsSync120(savedSponsorsPath)) {
625992
626414
  savedSponsors = JSON.parse(
625993
- readFileSync99(savedSponsorsPath, "utf8")
626415
+ readFileSync100(savedSponsorsPath, "utf8")
625994
626416
  );
625995
626417
  const oneHourAgo = Date.now() - 36e5;
625996
626418
  savedSponsors = savedSponsors.filter(
@@ -627755,7 +628177,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
627755
628177
  try {
627756
628178
  const nexusPidFile = join136(repoRoot, ".omnius", "nexus", "daemon.pid");
627757
628179
  if (existsSync120(nexusPidFile)) {
627758
- const pid = parseInt(readFileSync99(nexusPidFile, "utf8").trim(), 10);
628180
+ const pid = parseInt(readFileSync100(nexusPidFile, "utf8").trim(), 10);
627759
628181
  if (pid > 0) {
627760
628182
  registry2.register({
627761
628183
  name: "Nexus",
@@ -627967,7 +628389,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
627967
628389
  const nexusDir = join136(repoRoot, OMNIUS_DIR, "nexus");
627968
628390
  const pidFile = join136(nexusDir, "daemon.pid");
627969
628391
  if (existsSync120(pidFile)) {
627970
- const pid = parseInt(readFileSync99(pidFile, "utf8").trim(), 10);
628392
+ const pid = parseInt(readFileSync100(pidFile, "utf8").trim(), 10);
627971
628393
  if (pid > 0) {
627972
628394
  try {
627973
628395
  if (process.platform === "win32") {
@@ -628000,7 +628422,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
628000
628422
  const pidPath = join136(voiceDir2, pf);
628001
628423
  if (existsSync120(pidPath)) {
628002
628424
  try {
628003
- const pid = parseInt(readFileSync99(pidPath, "utf8").trim(), 10);
628425
+ const pid = parseInt(readFileSync100(pidPath, "utf8").trim(), 10);
628004
628426
  if (pid > 0) {
628005
628427
  if (process.platform === "win32") {
628006
628428
  try {
@@ -628144,8 +628566,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
628144
628566
  "daemon.port"
628145
628567
  );
628146
628568
  if (existsSync120(ppPidFile)) {
628147
- const ppPid = parseInt(readFileSync99(ppPidFile, "utf8").trim(), 10);
628148
- const ppPort = existsSync120(ppPortFile) ? parseInt(readFileSync99(ppPortFile, "utf8").trim(), 10) : void 0;
628569
+ const ppPid = parseInt(readFileSync100(ppPidFile, "utf8").trim(), 10);
628570
+ const ppPort = existsSync120(ppPortFile) ? parseInt(readFileSync100(ppPortFile, "utf8").trim(), 10) : void 0;
628149
628571
  if (ppPid > 0 && !registry2.daemons.has("PersonaPlex")) {
628150
628572
  registry2.register({
628151
628573
  name: "PersonaPlex",
@@ -628159,7 +628581,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
628159
628581
  }
628160
628582
  const nexusPidFile = join136(repoRoot, ".omnius", "nexus", "daemon.pid");
628161
628583
  if (existsSync120(nexusPidFile)) {
628162
- const nPid = parseInt(readFileSync99(nexusPidFile, "utf8").trim(), 10);
628584
+ const nPid = parseInt(readFileSync100(nexusPidFile, "utf8").trim(), 10);
628163
628585
  if (nPid > 0 && !registry2.daemons.has("Nexus")) {
628164
628586
  try {
628165
628587
  process.kill(nPid, 0);
@@ -628609,7 +629031,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
628609
629031
  if (isImage) {
628610
629032
  try {
628611
629033
  const imgPath = resolve44(repoRoot, cleanPath);
628612
- const imgBuffer = readFileSync99(imgPath);
629034
+ const imgBuffer = readFileSync100(imgPath);
628613
629035
  const base642 = imgBuffer.toString("base64");
628614
629036
  const ext = extname13(cleanPath).toLowerCase();
628615
629037
  const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
@@ -628803,7 +629225,7 @@ Read it with image_read or vision if more detail is needed. Describe what you se
628803
629225
  if (isMarkdown && fullInput === input) {
628804
629226
  try {
628805
629227
  const mdPath = resolve44(repoRoot, cleanPath);
628806
- const mdContent = readFileSync99(mdPath, "utf8");
629228
+ const mdContent = readFileSync100(mdPath, "utf8");
628807
629229
  const { parseMcpMarkdown: parseMcpMarkdown2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
628808
629230
  const result = parseMcpMarkdown2(mdContent);
628809
629231
  if (result.servers.length > 0) {
@@ -629357,7 +629779,7 @@ async function runWithTUI(task, config, repoPath, callbacks) {
629357
629779
  const ikFile = join136(ikDir, "self-state.json");
629358
629780
  let ikState;
629359
629781
  if (existsSync120(ikFile)) {
629360
- ikState = JSON.parse(readFileSync99(ikFile, "utf8"));
629782
+ ikState = JSON.parse(readFileSync100(ikFile, "utf8"));
629361
629783
  } else {
629362
629784
  mkdirSync73(ikDir, { recursive: true });
629363
629785
  ikState = {
@@ -629430,7 +629852,7 @@ async function runWithTUI(task, config, repoPath, callbacks) {
629430
629852
  let variants = [];
629431
629853
  try {
629432
629854
  if (existsSync120(archeFile))
629433
- variants = JSON.parse(readFileSync99(archeFile, "utf8"));
629855
+ variants = JSON.parse(readFileSync100(archeFile, "utf8"));
629434
629856
  } catch {
629435
629857
  }
629436
629858
  variants.push({
@@ -629458,7 +629880,7 @@ async function runWithTUI(task, config, repoPath, callbacks) {
629458
629880
  "store.json"
629459
629881
  );
629460
629882
  if (existsSync120(metaFile)) {
629461
- const store2 = JSON.parse(readFileSync99(metaFile, "utf8"));
629883
+ const store2 = JSON.parse(readFileSync100(metaFile, "utf8"));
629462
629884
  const surfaced = store2.filter(
629463
629885
  (m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15
629464
629886
  ).sort(
@@ -629561,7 +629983,7 @@ Rules:
629561
629983
  let store2 = [];
629562
629984
  try {
629563
629985
  if (existsSync120(storeFile))
629564
- store2 = JSON.parse(readFileSync99(storeFile, "utf8"));
629986
+ store2 = JSON.parse(readFileSync100(storeFile, "utf8"));
629565
629987
  } catch {
629566
629988
  }
629567
629989
  store2.push({
@@ -629595,7 +630017,7 @@ Rules:
629595
630017
  let cohereActive = false;
629596
630018
  try {
629597
630019
  if (existsSync120(cohereSettingsFile)) {
629598
- const settings = JSON.parse(readFileSync99(cohereSettingsFile, "utf8"));
630020
+ const settings = JSON.parse(readFileSync100(cohereSettingsFile, "utf8"));
629599
630021
  cohereActive = settings.cohere === true;
629600
630022
  }
629601
630023
  } catch {
@@ -629609,7 +630031,7 @@ Rules:
629609
630031
  "store.json"
629610
630032
  );
629611
630033
  if (existsSync120(metaFile)) {
629612
- const store2 = JSON.parse(readFileSync99(metaFile, "utf8"));
630034
+ const store2 = JSON.parse(readFileSync100(metaFile, "utf8"));
629613
630035
  const latest = store2.filter(
629614
630036
  (m2) => m2.sourceTrace === "trajectory-extraction" || m2.sourceTrace === "llm-trajectory-extraction"
629615
630037
  ).slice(-1)[0];
@@ -629638,7 +630060,7 @@ Rules:
629638
630060
  try {
629639
630061
  const ikFile = join136(repoRoot, ".omnius", "identity", "self-state.json");
629640
630062
  if (existsSync120(ikFile)) {
629641
- const ikState = JSON.parse(readFileSync99(ikFile, "utf8"));
630063
+ const ikState = JSON.parse(readFileSync100(ikFile, "utf8"));
629642
630064
  ikState.homeostasis.uncertainty = Math.min(
629643
630065
  1,
629644
630066
  ikState.homeostasis.uncertainty + 0.1
@@ -629659,7 +630081,7 @@ Rules:
629659
630081
  "store.json"
629660
630082
  );
629661
630083
  if (existsSync120(metaFile)) {
629662
- const store2 = JSON.parse(readFileSync99(metaFile, "utf8"));
630084
+ const store2 = JSON.parse(readFileSync100(metaFile, "utf8"));
629663
630085
  const surfaced = store2.filter(
629664
630086
  (m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15
629665
630087
  ).sort(
@@ -629685,7 +630107,7 @@ Rules:
629685
630107
  let variants = [];
629686
630108
  try {
629687
630109
  if (existsSync120(archeFile))
629688
- variants = JSON.parse(readFileSync99(archeFile, "utf8"));
630110
+ variants = JSON.parse(readFileSync100(archeFile, "utf8"));
629689
630111
  } catch {
629690
630112
  }
629691
630113
  variants.push({
@@ -629792,7 +630214,7 @@ __export(run_exports, {
629792
630214
  });
629793
630215
  import { resolve as resolve45 } from "node:path";
629794
630216
  import { spawn as spawn30 } from "node:child_process";
629795
- import { mkdirSync as mkdirSync74, writeFileSync as writeFileSync69, readFileSync as readFileSync100, readdirSync as readdirSync41, existsSync as existsSync121 } from "node:fs";
630217
+ import { mkdirSync as mkdirSync74, writeFileSync as writeFileSync69, readFileSync as readFileSync101, readdirSync as readdirSync41, existsSync as existsSync121 } from "node:fs";
629796
630218
  import { randomBytes as randomBytes24 } from "node:crypto";
629797
630219
  import { join as join137 } from "node:path";
629798
630220
  function jobsDir2(repoPath) {
@@ -629958,7 +630380,7 @@ function statusCommand(jobId, repoPath) {
629958
630380
  console.log(`Available jobs: omnius jobs`);
629959
630381
  process.exit(1);
629960
630382
  }
629961
- const job = JSON.parse(readFileSync100(file, "utf-8"));
630383
+ const job = JSON.parse(readFileSync101(file, "utf-8"));
629962
630384
  const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
629963
630385
  const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
629964
630386
  console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
@@ -629979,7 +630401,7 @@ function jobsCommand(repoPath) {
629979
630401
  console.log("Jobs:");
629980
630402
  for (const file of files) {
629981
630403
  try {
629982
- const job = JSON.parse(readFileSync100(join137(dir, file), "utf-8"));
630404
+ const job = JSON.parse(readFileSync101(join137(dir, file), "utf-8"));
629983
630405
  const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
629984
630406
  const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
629985
630407
  const cleanListTask = cleanForStorage(job.task) || job.task;