omnius 1.0.9 → 1.0.11

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/README.md CHANGED
@@ -278,7 +278,7 @@ The agent uses tools autonomously in a loop — reading errors, fixing code, and
278
278
 
279
279
  - **61 autonomous tools** — file I/O, shell, grep, web search/fetch/crawl, memory (read/write/search), sub-agents, background tasks, image/OCR/PDF, git, diagnostics, vision, desktop automation, browser automation, temporal agency (scheduler/reminders/agenda), structured files, code sandbox, transcription, skills, opencode delegation, cron agents, nexus P2P networking + x402 micropayments, **COHERE cognitive stack** (persistent REPL, recursive LLM calls, memory metabolism, identity kernel, reflection, exploration)
280
280
  - **Moondream vision** — see and interact with the desktop via Moondream VLM (caption, query, detect, point-and-click)
281
- - **Image generation with TUI previews** — `/image <prompt>` and the `generate_image` tool create PNGs under `.omnius/images/`, support explicit `--model` selection, and render generated, pasted, screenshot, and camera-capture images as auto-sized ASCII previews via `image-to-ascii`
281
+ - **Image generation with TUI previews** — `/image <prompt>` and the `generate_image` tool create PNGs under `.omnius/images/`, support explicit `--model` selection, and render generated, pasted, screenshot, and camera-capture images as auto-sized ASCII previews via the bundled `image-to-ascii` renderer
282
282
  - **Desktop automation** — vision-guided clicking: describe a UI element in natural language, the agent finds and clicks it
283
283
  - **Auto-install desktop deps** — screenshot, mouse, OCR, and image tools auto-install missing system packages (scrot, xdotool, tesseract, imagemagick) on first use
284
284
  - **Hardware-rated model lists** — first-run setup, `/models`, `/score`, and `/image list` score model fit against detected RAM/VRAM/GPU so text and image model choices are visible before you switch or generate
@@ -3294,7 +3294,7 @@ omnius
3294
3294
 
3295
3295
  The TUI features an animated multilingual phrase carousel, live metrics bar with pastel-colored labels (token in/out, context window usage, human expert speed ratio, cost), rotating tips, syntax-highlighted tool output, and dynamic terminal-width cropping.
3296
3296
 
3297
- Image surfaces are first-class in the terminal. `/image` generations, generated-image tool results, pasted image context, screenshots, and camera captures are converted through `image-to-ascii` and sized to the current terminal before being printed into the main scrollback. Each generated image also includes the saved file path below the preview.
3297
+ Image surfaces are first-class in the terminal. `/image` generations, generated-image tool results, pasted image context, screenshots, and camera captures are converted through Omnius' bundled `image-to-ascii` renderer and sized to the current terminal before being printed into the main scrollback. The bundled renderer preserves the upstream `require("image-to-ascii")` API without installing the legacy `lwip` native dependency chain that fails on modern Node releases. Each generated image also includes the saved file path below the preview, and preview renderer failures are surfaced in the scrollback instead of disappearing silently.
3298
3298
 
3299
3299
  ### Slash Commands
3300
3300
 
package/dist/index.js CHANGED
@@ -572498,22 +572498,29 @@ function normalizeAscii(ascii2, width, height) {
572498
572498
  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
572499
  return lines.slice(0, height).map((line) => line.length > width ? line.slice(0, width) : line).join("\n").trimEnd();
572500
572500
  }
572501
+ function previewFailure(message2, width) {
572502
+ const clean3 = message2.replace(/\s+/g, " ").trim();
572503
+ const text = `[image-to-ascii preview failed: ${clean3 || "unknown error"}]`;
572504
+ return text.length > width ? `${text.slice(0, Math.max(0, width - 1))}]` : text;
572505
+ }
572501
572506
  async function convertWithImageToAscii(imagePath, width, height, timeoutMs) {
572502
572507
  let imageToAscii;
572503
572508
  try {
572504
572509
  const require4 = createRequire4(import.meta.url);
572505
572510
  const mod2 = require4("image-to-ascii");
572506
572511
  imageToAscii = typeof mod2 === "function" ? mod2 : mod2.default;
572507
- if (typeof imageToAscii !== "function") return null;
572508
- } catch {
572509
- return null;
572512
+ if (typeof imageToAscii !== "function") {
572513
+ return { ascii: null, error: "module did not export a function" };
572514
+ }
572515
+ } catch (err) {
572516
+ return { ascii: null, error: err instanceof Error ? err.message : String(err) };
572510
572517
  }
572511
572518
  return new Promise((resolvePreview) => {
572512
572519
  let settled = false;
572513
572520
  const timer = setTimeout(() => {
572514
572521
  if (!settled) {
572515
572522
  settled = true;
572516
- resolvePreview(null);
572523
+ resolvePreview({ ascii: null, error: `timed out after ${timeoutMs}ms` });
572517
572524
  }
572518
572525
  }, timeoutMs).unref();
572519
572526
  try {
@@ -572532,18 +572539,20 @@ async function convertWithImageToAscii(imagePath, width, height, timeoutMs) {
572532
572539
  settled = true;
572533
572540
  clearTimeout(timer);
572534
572541
  if (err || !converted) {
572535
- resolvePreview(null);
572542
+ resolvePreview({ ascii: null, error: err?.message || "empty renderer output" });
572536
572543
  return;
572537
572544
  }
572538
572545
  const normalized = normalizeAscii(converted, width, height);
572539
- resolvePreview(normalized || null);
572546
+ resolvePreview(
572547
+ normalized ? { ascii: normalized } : { ascii: null, error: "empty normalized renderer output" }
572548
+ );
572540
572549
  }
572541
572550
  );
572542
- } catch {
572551
+ } catch (err) {
572543
572552
  if (!settled) {
572544
572553
  settled = true;
572545
572554
  clearTimeout(timer);
572546
- resolvePreview(null);
572555
+ resolvePreview({ ascii: null, error: err instanceof Error ? err.message : String(err) });
572547
572556
  }
572548
572557
  }
572549
572558
  });
@@ -572607,8 +572616,15 @@ async function buildImageAsciiPreview(inputPath, options2 = {}) {
572607
572616
  const height = clamp5(options2.height ?? defaults3.height, 8, 60);
572608
572617
  const timeoutMs = clamp5(options2.timeoutMs ?? 5e3, 500, 3e4);
572609
572618
  if (options2.preferPackage !== false) {
572610
- const ascii2 = await convertWithImageToAscii(imagePath, width, height, timeoutMs);
572611
- if (ascii2) return { path: imagePath, ascii: ascii2, renderer: "image-to-ascii", width, height };
572619
+ const result = await convertWithImageToAscii(imagePath, width, height, timeoutMs);
572620
+ if (result.ascii) return { path: imagePath, ascii: result.ascii, renderer: "image-to-ascii", width, height };
572621
+ return {
572622
+ path: imagePath,
572623
+ ascii: previewFailure(result.error || "renderer unavailable", width),
572624
+ renderer: "image-to-ascii",
572625
+ width,
572626
+ height
572627
+ };
572612
572628
  }
572613
572629
  const fallback = convertWithFfmpeg(imagePath, width, height, timeoutMs);
572614
572630
  if (fallback) return { path: imagePath, ascii: fallback, renderer: "ffmpeg", width, height };
@@ -47,6 +47,16 @@ function log(msg) {
47
47
  function warn(msg) {
48
48
  process.stdout.write(" [daemon] " + msg + "\n");
49
49
  }
50
+ function quietInstall() {
51
+ var level = String(process.env.npm_config_loglevel || "").toLowerCase();
52
+ return process.env.OMNIUS_QUIET_INSTALL === "1" || level === "silent";
53
+ }
54
+ function progress(step, total, msg) {
55
+ if (quietInstall()) return;
56
+ var width = 18;
57
+ var filled = Math.max(0, Math.min(width, Math.round((step / total) * width)));
58
+ process.stdout.write(" [" + "#".repeat(filled) + ".".repeat(width - filled) + "] " + step + "/" + total + " " + msg + "\n");
59
+ }
50
60
 
51
61
  function runQuiet(cmd, opts) {
52
62
  try {
@@ -669,10 +679,12 @@ function repairBrokenWrappers() {
669
679
 
670
680
  function main() {
671
681
  // Always do the nexus cleanup first, regardless of opt-out.
682
+ progress(1, 5, "Cleaning stale Nexus runtime state");
672
683
  cleanNexus();
673
684
 
674
685
  // Auto-repair stale Omnius model wrappers BEFORE restarting the daemon, so the
675
686
  // freshly-restarted daemon picks up the rebuilt models on first inference.
687
+ progress(2, 5, "Checking local model wrappers");
676
688
  try { repairBrokenWrappers(); } catch (e) {
677
689
  warn("wrapper auto-repair crashed (non-fatal): " + (e && e.message));
678
690
  }
@@ -688,6 +700,7 @@ function main() {
688
700
  // restart can't reach it, so we have to clean up explicitly. Without this,
689
701
  // the new service-managed daemon fails to bind port 11435 and the user
690
702
  // ends up running stale in-memory code from the previous version.
703
+ progress(3, 5, "Clearing daemon port");
691
704
  forceKillPortHolder(PORT, function (killedCount) {
692
705
  if (killedCount > 0) {
693
706
  log("Killed " + killedCount + " stale daemon process(es) holding port " + PORT + ".");
@@ -718,6 +731,7 @@ function runMainAfterKill() {
718
731
  // idempotent and ensures the unit file matches the current bundle.
719
732
  }
720
733
 
734
+ progress(4, 5, "Installing daemon service");
721
735
  log("Installing Omnius API daemon service for port " + PORT + " ...");
722
736
  log(" node: " + nodeBin);
723
737
  log(" omnius script: " + omniusScript);
@@ -748,6 +762,7 @@ function runMainAfterKill() {
748
762
  }
749
763
 
750
764
  // Wait up to 15s for /health to come up, but don't fail npm install.
765
+ progress(5, 5, "Verifying daemon health");
751
766
  waitForHealth(15000, function (healthy) {
752
767
  if (healthy) {
753
768
  log("Omnius API daemon is live: http://127.0.0.1:" + PORT + "/health");
@@ -29,12 +29,34 @@ var HOME = os.homedir();
29
29
  var SERVICE_LABEL = "omnius-daemon";
30
30
  var LAUNCHD_LABEL = "ai.omnius.daemon";
31
31
  var WIN_TASK_NAME = "OmniusDaemon";
32
+ var BANNER = [
33
+ "",
34
+ "░░ ░░░ ░░░░ ░░ ░░░ ░░ ░░ ░░░░ ░░░ ░░",
35
+ "▒ ▒▒▒▒ ▒▒ ▒▒ ▒▒ ▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒ ▒▒ ▒▒▒▒▒▒▒",
36
+ "▓ ▓▓▓▓ ▓▓ ▓▓ ▓ ▓ ▓▓▓▓▓ ▓▓▓▓▓ ▓▓▓▓ ▓▓▓ ▓▓",
37
+ "█ ████ ██ █ █ ██ ██ █████ █████ ████ ████████ █",
38
+ "██ ███ ████ ██ ███ ██ ███ ████ ██",
39
+ ""
40
+ ].join("\n");
41
+
42
+ function quietInstall() {
43
+ var level = String(process.env.npm_config_loglevel || "").toLowerCase();
44
+ return process.env.OMNIUS_QUIET_INSTALL === "1" || level === "silent";
45
+ }
32
46
 
33
47
  function runQuiet(cmd) {
34
48
  try { cp.execSync(cmd, { stdio: "pipe", timeout: 8000 }); return true; } catch (e) { return false; }
35
49
  }
36
50
 
37
51
  function log(msg) { process.stdout.write(" [preinstall] " + msg + "\n"); }
52
+ function progress(step, total, msg) {
53
+ if (quietInstall()) return;
54
+ var width = 18;
55
+ var filled = Math.max(0, Math.min(width, Math.round((step / total) * width)));
56
+ process.stdout.write(" [" + "#".repeat(filled) + ".".repeat(width - filled) + "] " + step + "/" + total + " " + msg + "\n");
57
+ }
58
+
59
+ if (!quietInstall()) process.stdout.write(BANNER + "\n");
38
60
 
39
61
  function stopServiceManager() {
40
62
  // Stop via the registered service manager if one exists. This is
@@ -65,8 +87,10 @@ function killPidFile(pidFile) {
65
87
  return false;
66
88
  }
67
89
 
90
+ progress(1, 3, "Preparing Omnius service handoff");
68
91
  stopServiceManager();
69
92
  killPidFile(path.join(HOME, ".omnius", "daemon.pid"));
93
+ progress(2, 3, "Stopped old daemon handles");
70
94
 
71
95
  // Final: lsof-based sweep for any process still holding 11435.
72
96
  try {
@@ -88,5 +112,5 @@ try {
88
112
  } catch (e) {}
89
113
 
90
114
  // 1.5s grace so SIGTERM handlers can flush state.
115
+ progress(3, 3, "Install handoff ready");
91
116
  setTimeout(function () { process.exit(0); }, 1500);
92
-
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ var imageToAscii = require("../index.cjs");
5
+
6
+ var source = process.argv[2];
7
+ if (!source) {
8
+ process.stderr.write("Usage: image-to-ascii <image-path-or-url>\n");
9
+ process.exit(2);
10
+ }
11
+
12
+ imageToAscii(source, { colored: false }, function (err, converted) {
13
+ if (err) {
14
+ process.stderr.write((err && err.message ? err.message : String(err)) + "\n");
15
+ process.exit(1);
16
+ }
17
+ process.stdout.write(String(converted || "") + "\n");
18
+ });
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+
3
+ var childProcess = require("node:child_process");
4
+ var crypto = require("node:crypto");
5
+ var fs = require("node:fs");
6
+ var os = require("node:os");
7
+ var path = require("node:path");
8
+
9
+ var DEFAULT_PIXELS = " .,:;i1tfLCG08@";
10
+
11
+ function isObject(value) {
12
+ return value !== null && typeof value === "object" && !Buffer.isBuffer(value);
13
+ }
14
+
15
+ function clamp(value, min, max) {
16
+ var n = Number(value);
17
+ if (!Number.isFinite(n)) return min;
18
+ n = Math.floor(n);
19
+ return Math.max(min, Math.min(max, n));
20
+ }
21
+
22
+ function percentOrNumber(value, basis, fallback) {
23
+ if (typeof value === "number" && Number.isFinite(value)) return value;
24
+ if (typeof value === "string") {
25
+ var trimmed = value.trim();
26
+ if (trimmed.endsWith("%")) {
27
+ var pct = Number(trimmed.slice(0, -1));
28
+ if (Number.isFinite(pct)) return Math.max(1, Math.floor((basis * pct) / 100));
29
+ }
30
+ var parsed = Number(trimmed);
31
+ if (Number.isFinite(parsed)) return parsed;
32
+ }
33
+ return fallback;
34
+ }
35
+
36
+ function resolveSize(options) {
37
+ var size = isObject(options.size) ? options.size : {};
38
+ var sizeOptions = isObject(options.size_options) ? options.size_options : {};
39
+ var screen = isObject(sizeOptions.screen_size) ? sizeOptions.screen_size : {};
40
+ var screenWidth = clamp(screen.width || process.stdout.columns || 80, 20, 240);
41
+ var screenHeight = clamp(screen.height || process.stdout.rows || 32, 8, 120);
42
+ var width = percentOrNumber(size.width, screenWidth, Math.min(80, screenWidth));
43
+ var height = percentOrNumber(size.height, screenHeight, Math.max(8, Math.round(width * 0.42)));
44
+ return {
45
+ width: clamp(width, 8, 240),
46
+ height: clamp(height, 4, 120)
47
+ };
48
+ }
49
+
50
+ function normalizeOptions(options) {
51
+ if (!isObject(options)) options = {};
52
+ var pixels = options.pixels;
53
+ if (Array.isArray(pixels)) pixels = pixels.join("");
54
+ if (typeof pixels !== "string" || pixels.length < 2) pixels = DEFAULT_PIXELS;
55
+ if (options.reverse === true) pixels = pixels.split("").reverse().join("");
56
+ return {
57
+ pixels: pixels,
58
+ colored: options.colored === true,
59
+ concat: options.concat !== false,
60
+ stringify: options.stringify !== false,
61
+ timeoutMs: clamp(options.timeoutMs || options.timeout || 5000, 500, 60000),
62
+ preserveAspectRatio: !options.size_options || options.size_options.preserve_aspect_ratio !== false,
63
+ size: resolveSize(options),
64
+ stringifyFn: typeof options.stringify_fn === "function" ? options.stringify_fn : null
65
+ };
66
+ }
67
+
68
+ function tempFilePath(ext) {
69
+ var suffix = ext || ".img";
70
+ if (!suffix.startsWith(".")) suffix = "." + suffix;
71
+ return path.join(os.tmpdir(), "omnius-image-to-ascii-" + crypto.randomUUID() + suffix);
72
+ }
73
+
74
+ function extensionFromUrl(url) {
75
+ try {
76
+ var parsed = new URL(url);
77
+ var ext = path.extname(parsed.pathname || "");
78
+ return ext || ".img";
79
+ } catch (e) {
80
+ return ".img";
81
+ }
82
+ }
83
+
84
+ function sourceToFile(source, callback) {
85
+ if (Buffer.isBuffer(source)) {
86
+ var bufPath = tempFilePath(".img");
87
+ fs.writeFile(bufPath, source, function (err) {
88
+ callback(err, bufPath, true);
89
+ });
90
+ return;
91
+ }
92
+
93
+ if (typeof source !== "string" || source.trim().length === 0) {
94
+ callback(new Error("image-to-ascii source must be a file path, URL, or Buffer"));
95
+ return;
96
+ }
97
+
98
+ if (/^https?:\/\//i.test(source)) {
99
+ if (typeof fetch !== "function") {
100
+ callback(new Error("image-to-ascii URL input requires Node fetch support"));
101
+ return;
102
+ }
103
+ fetch(source).then(function (res) {
104
+ if (!res.ok) throw new Error("image-to-ascii failed to fetch image: HTTP " + res.status);
105
+ return res.arrayBuffer();
106
+ }).then(function (arrayBuffer) {
107
+ var urlPath = tempFilePath(extensionFromUrl(source));
108
+ fs.writeFile(urlPath, Buffer.from(arrayBuffer), function (err) {
109
+ callback(err, urlPath, true);
110
+ });
111
+ }).catch(function (err) {
112
+ callback(err);
113
+ });
114
+ return;
115
+ }
116
+
117
+ callback(null, source, false);
118
+ }
119
+
120
+ function buildFilter(width, height, preserveAspectRatio) {
121
+ if (preserveAspectRatio) {
122
+ return [
123
+ "scale=" + width + ":" + height + ":force_original_aspect_ratio=decrease",
124
+ "pad=" + width + ":" + height + ":(ow-iw)/2:(oh-ih)/2:color=black",
125
+ "format=gray"
126
+ ].join(",");
127
+ }
128
+ return "scale=" + width + ":" + height + ",format=gray";
129
+ }
130
+
131
+ function matrixFromRaw(raw, width, height) {
132
+ var matrix = [];
133
+ for (var y = 0; y < height; y++) {
134
+ var row = [];
135
+ for (var x = 0; x < width; x++) {
136
+ var value = raw[y * width + x] || 0;
137
+ row.push({ r: value, g: value, b: value, a: 255, value: value });
138
+ }
139
+ matrix.push(row);
140
+ }
141
+ return matrix;
142
+ }
143
+
144
+ function stringifyMatrix(matrix, options) {
145
+ var lines = [];
146
+ var pixels = options.pixels;
147
+ var maxIdx = pixels.length - 1;
148
+ for (var y = 0; y < matrix.length; y++) {
149
+ var line = "";
150
+ for (var x = 0; x < matrix[y].length; x++) {
151
+ var value = matrix[y][x].value || 0;
152
+ var idx = Math.round((value / 255) * maxIdx);
153
+ var ch = pixels[idx] || " ";
154
+ if (options.colored) {
155
+ line += "\x1b[38;2;" + value + ";" + value + ";" + value + "m" + ch + "\x1b[0m";
156
+ } else {
157
+ line += ch;
158
+ }
159
+ }
160
+ lines.push(line.replace(/\s+$/g, ""));
161
+ }
162
+ return options.concat ? lines.join("\n") : lines;
163
+ }
164
+
165
+ function renderFile(filePath, options, callback) {
166
+ var width = options.size.width;
167
+ var height = options.size.height;
168
+ var args = [
169
+ "-hide_banner",
170
+ "-loglevel",
171
+ "error",
172
+ "-i",
173
+ filePath,
174
+ "-vf",
175
+ buildFilter(width, height, options.preserveAspectRatio),
176
+ "-frames:v",
177
+ "1",
178
+ "-f",
179
+ "rawvideo",
180
+ "-pix_fmt",
181
+ "gray",
182
+ "-"
183
+ ];
184
+
185
+ childProcess.execFile("ffmpeg", args, {
186
+ encoding: "buffer",
187
+ maxBuffer: width * height + 4096,
188
+ timeout: options.timeoutMs
189
+ }, function (err, stdout, stderr) {
190
+ if (err) {
191
+ var detail = stderr && stderr.length ? String(stderr).trim() : err.message;
192
+ callback(new Error("image-to-ascii failed via ffmpeg: " + detail));
193
+ return;
194
+ }
195
+ if (!stdout || stdout.length < width * height) {
196
+ callback(new Error("image-to-ascii decoded too few pixels for " + width + "x" + height));
197
+ return;
198
+ }
199
+ var matrix = matrixFromRaw(stdout, width, height);
200
+ if (!options.stringify) {
201
+ callback(null, matrix);
202
+ return;
203
+ }
204
+ if (options.stringifyFn) {
205
+ try {
206
+ callback(null, options.stringifyFn(matrix, options));
207
+ } catch (stringifyErr) {
208
+ callback(stringifyErr);
209
+ }
210
+ return;
211
+ }
212
+ callback(null, stringifyMatrix(matrix, options));
213
+ });
214
+ }
215
+
216
+ function imageToAscii(source, options, callback) {
217
+ if (typeof options === "function") {
218
+ callback = options;
219
+ options = {};
220
+ }
221
+ if (typeof callback !== "function") {
222
+ return new Promise(function (resolve, reject) {
223
+ imageToAscii(source, options || {}, function (err, converted) {
224
+ if (err) reject(err);
225
+ else resolve(converted);
226
+ });
227
+ });
228
+ }
229
+
230
+ var normalized = normalizeOptions(options || {});
231
+ sourceToFile(source, function (sourceErr, filePath, cleanup) {
232
+ if (sourceErr) {
233
+ callback(sourceErr);
234
+ return;
235
+ }
236
+ renderFile(filePath, normalized, function (renderErr, converted) {
237
+ if (cleanup) {
238
+ fs.unlink(filePath, function () {});
239
+ }
240
+ callback(renderErr, converted);
241
+ });
242
+ });
243
+ }
244
+
245
+ imageToAscii.defaults = {
246
+ size_options: {
247
+ px_size: { width: 1 }
248
+ },
249
+ stringify: true,
250
+ concat: true,
251
+ size: {
252
+ height: "100%"
253
+ }
254
+ };
255
+
256
+ module.exports = imageToAscii;
257
+ module.exports.default = imageToAscii;
@@ -0,0 +1,48 @@
1
+ declare namespace imageToAscii {
2
+ interface Size {
3
+ width?: number | string;
4
+ height?: number | string;
5
+ }
6
+
7
+ interface SizeOptions {
8
+ screen_size?: {
9
+ width?: number;
10
+ height?: number;
11
+ };
12
+ preserve_aspect_ratio?: boolean;
13
+ fit_screen?: boolean;
14
+ px_size?: {
15
+ width?: number;
16
+ height?: number;
17
+ };
18
+ }
19
+
20
+ interface Options {
21
+ pxWidth?: number;
22
+ size?: Size;
23
+ size_options?: SizeOptions;
24
+ stringify?: boolean;
25
+ concat?: boolean;
26
+ pixels?: string | string[];
27
+ reverse?: boolean;
28
+ colored?: boolean;
29
+ bg?: boolean;
30
+ fg?: boolean;
31
+ white_bg?: boolean;
32
+ px_background?: { r: number; g: number; b: number };
33
+ image_type?: string;
34
+ timeout?: number;
35
+ timeoutMs?: number;
36
+ stringify_fn?: (pixels: unknown, options: Options) => unknown;
37
+ }
38
+
39
+ type Callback = (err: Error | null, converted?: unknown) => void;
40
+ }
41
+
42
+ declare function imageToAscii(
43
+ source: string | Buffer,
44
+ options: imageToAscii.Options | imageToAscii.Callback,
45
+ callback?: imageToAscii.Callback,
46
+ ): void | Promise<unknown>;
47
+
48
+ export = imageToAscii;
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "image-to-ascii",
3
+ "version": "3.3.0-omnius.1",
4
+ "description": "Omnius bundled image-to-ascii compatibility renderer without the legacy lwip native dependency chain.",
5
+ "main": "index.cjs",
6
+ "types": "index.d.ts",
7
+ "bin": {
8
+ "image-to-ascii": "bin/image-to-ascii.cjs"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "types": "./index.d.ts",
13
+ "require": "./index.cjs",
14
+ "default": "./index.cjs"
15
+ }
16
+ },
17
+ "license": "MIT",
18
+ "engines": {
19
+ "node": ">=22.0.0"
20
+ },
21
+ "dependencies": {}
22
+ }