termux-vision 1.7.0 → 1.8.0

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/lib/doctor.js CHANGED
@@ -1,88 +1,92 @@
1
- /**
2
- * Hardware, Memory, Vulkan, and Environment Diagnostic Doctor for Node.js.
3
- * Open-Source under Apache License 2.0.
4
- */
5
-
6
- 'use strict';
7
-
8
- const fs = require('fs');
9
- const os = require('os');
10
- const path = require('path');
11
- const { ModelCacheManager } = require('./cache');
12
-
13
- function runDoctor(probeVulkan = false) {
14
- const cache = new ModelCacheManager();
15
- const isAndroid = fs.existsSync('/system/build.prop') || Boolean(process.env.ANDROID_ROOT);
16
-
17
- let totalRamMb = null;
18
- let availableRamMb = null;
19
-
20
- try {
21
- if (fs.existsSync('/proc/meminfo')) {
22
- const content = fs.readFileSync('/proc/meminfo', 'utf-8');
23
- for (const line of content.split('\n')) {
24
- if (line.startsWith('MemTotal:')) {
25
- totalRamMb = Math.round(parseInt(line.split(/\s+/)[1], 10) / 1024);
26
- } else if (line.startsWith('MemAvailable:')) {
27
- availableRamMb = Math.round(parseInt(line.split(/\s+/)[1], 10) / 1024);
28
- }
29
- }
30
- }
31
- } catch (e) {}
32
-
33
- if (!totalRamMb) {
34
- totalRamMb = Math.round(os.totalmem() / (1024 * 1024));
35
- availableRamMb = Math.round(os.freemem() / (1024 * 1024));
36
- }
37
-
38
- const loaderDetected = fs.existsSync('/system/lib64/libvulkan.so') || fs.existsSync('/system/lib/libvulkan.so');
39
- const driverDetected = fs.existsSync('/vendor/lib64/hw/vulkan.adreno.so') || fs.existsSync('/vendor/lib64/hw/vulkan.mali.so');
40
-
41
- let vulkanStatus = 'unverified';
42
- let amevaRuntimeDetected = false;
43
- try {
44
- const avr = require('@ameva/runtime');
45
- amevaRuntimeDetected = true;
46
- if (probeVulkan) {
47
- vulkanStatus = (typeof avr.isAvailable === 'function' && avr.isAvailable()) ? 'driver_detected_experimental' : 'disabled';
48
- }
49
- } catch (err) {
50
- if (probeVulkan) {
51
- vulkanStatus = (loaderDetected && driverDetected) ? 'driver_detected_experimental' : 'disabled';
52
- }
53
- }
54
-
55
- const packageJson = require('../package.json');
56
- const installed = cache.listInstalled();
57
-
58
- return {
59
- schemaVersion: 1,
60
- clientVersion: packageJson.version,
61
- runtimeVersion: packageJson.version,
62
- platform: {
63
- system: os.type(),
64
- machine: os.arch(),
65
- nodeVersion: process.version,
66
- isAndroid: isAndroid
67
- },
68
- hardware: {
69
- cpuCores: os.cpus().length,
70
- totalRamMb: totalRamMb,
71
- availableRamMb: availableRamMb
72
- },
73
- vulkan: {
74
- loaderDetected: loaderDetected,
75
- driverDetected: driverDetected,
76
- status: vulkanStatus
77
- },
78
- vlmRuntime: {
79
- installedModelsCount: installed.length,
80
- cacheDir: cache.cacheRoot
81
- },
82
- recommendedPreset: 'Tier M (smolvlm-500m / 4-Threads CPU Reference)'
83
- };
84
- }
85
-
86
- module.exports = {
87
- runDoctor
88
- };
1
+ /**
2
+ * Copyright (c) 2026 Uno Kim / AMEVA Foundation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0 OR Commercial-License
4
+ */
5
+ /**
6
+ * Hardware, Memory, Vulkan, and Environment Diagnostic Doctor for Node.js.
7
+ * Open-Source under Apache License 2.0.
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ const fs = require('fs');
13
+ const os = require('os');
14
+ const path = require('path');
15
+ const { ModelCacheManager } = require('./cache');
16
+
17
+ function runDoctor(probeVulkan = false) {
18
+ const cache = new ModelCacheManager();
19
+ const isAndroid = fs.existsSync('/system/build.prop') || Boolean(process.env.ANDROID_ROOT);
20
+
21
+ let totalRamMb = null;
22
+ let availableRamMb = null;
23
+
24
+ try {
25
+ if (fs.existsSync('/proc/meminfo')) {
26
+ const content = fs.readFileSync('/proc/meminfo', 'utf-8');
27
+ for (const line of content.split('\n')) {
28
+ if (line.startsWith('MemTotal:')) {
29
+ totalRamMb = Math.round(parseInt(line.split(/\s+/)[1], 10) / 1024);
30
+ } else if (line.startsWith('MemAvailable:')) {
31
+ availableRamMb = Math.round(parseInt(line.split(/\s+/)[1], 10) / 1024);
32
+ }
33
+ }
34
+ }
35
+ } catch (e) {}
36
+
37
+ if (!totalRamMb) {
38
+ totalRamMb = Math.round(os.totalmem() / (1024 * 1024));
39
+ availableRamMb = Math.round(os.freemem() / (1024 * 1024));
40
+ }
41
+
42
+ const loaderDetected = fs.existsSync('/system/lib64/libvulkan.so') || fs.existsSync('/system/lib/libvulkan.so');
43
+ const driverDetected = fs.existsSync('/vendor/lib64/hw/vulkan.adreno.so') || fs.existsSync('/vendor/lib64/hw/vulkan.mali.so');
44
+
45
+ let vulkanStatus = 'unverified';
46
+ let amevaRuntimeDetected = false;
47
+ try {
48
+ const avr = require('@ameva/runtime');
49
+ amevaRuntimeDetected = true;
50
+ if (probeVulkan) {
51
+ vulkanStatus = (typeof avr.isAvailable === 'function' && avr.isAvailable()) ? 'driver_detected_experimental' : 'disabled';
52
+ }
53
+ } catch (err) {
54
+ if (probeVulkan) {
55
+ vulkanStatus = (loaderDetected && driverDetected) ? 'driver_detected_experimental' : 'disabled';
56
+ }
57
+ }
58
+
59
+ const packageJson = require('../package.json');
60
+ const installed = cache.listInstalled();
61
+
62
+ return {
63
+ schemaVersion: 1,
64
+ clientVersion: packageJson.version,
65
+ runtimeVersion: packageJson.version,
66
+ platform: {
67
+ system: os.type(),
68
+ machine: os.arch(),
69
+ nodeVersion: process.version,
70
+ isAndroid: isAndroid
71
+ },
72
+ hardware: {
73
+ cpuCores: os.cpus().length,
74
+ totalRamMb: totalRamMb,
75
+ availableRamMb: availableRamMb
76
+ },
77
+ vulkan: {
78
+ loaderDetected: loaderDetected,
79
+ driverDetected: driverDetected,
80
+ status: vulkanStatus
81
+ },
82
+ vlmRuntime: {
83
+ installedModelsCount: installed.length,
84
+ cacheDir: cache.cacheRoot
85
+ },
86
+ recommendedPreset: 'Tier M (smolvlm-500m / 4-Threads CPU Reference)'
87
+ };
88
+ }
89
+
90
+ module.exports = {
91
+ runDoctor
92
+ };
package/lib/errors.js CHANGED
@@ -1,121 +1,125 @@
1
- /**
2
- * Structured Exception Classes and Dynamic User Error Contracts for Node.js.
3
- * Open-Source under Apache License 2.0.
4
- */
5
-
6
- 'use strict';
7
-
8
- class TermuxVisionError extends Error {
9
- constructor(message) {
10
- super(message);
11
- this.name = this.constructor.name;
12
- }
13
- }
14
-
15
- class ModelNotFoundError extends TermuxVisionError {
16
- constructor(modelId, availableLocal = [], catalogModels = []) {
17
- let msg = `Model '${modelId}' was not found locally or on remote registry.`;
18
- if (availableLocal && availableLocal.length > 0) {
19
- msg += `\n\nCurrently installed local models (${availableLocal.length}):\n` +
20
- availableLocal.map(m => ` - ${m}`).join('\n') +
21
- `\n\nTo run with an installed model:\n termux-vision vlm <IMAGE> --model ${availableLocal[0]}`;
22
- } else if (catalogModels && catalogModels.length > 0) {
23
- msg += `\n\nNo models installed locally. Available catalog presets:\n` +
24
- catalogModels.map(m => ` - ${m}`).join('\n') +
25
- `\n\nInstall an official model:\n termux-vision model install ${catalogModels[0]}`;
26
- }
27
- super(msg);
28
- this.modelId = modelId;
29
- this.availableLocal = availableLocal;
30
- this.catalogModels = catalogModels;
31
- }
32
- }
33
-
34
- class NoInstalledModelsError extends ModelNotFoundError {
35
- constructor(catalogModels = []) {
36
- const catText = catalogModels.length > 0 ? catalogModels.map(m => ` - ${m}`).join('\n') : ' (none)';
37
- const msg =
38
- "No installed VLM models were found in local cache (~/.cache/termux-vision/models).\n\n" +
39
- "How to use VLM models:\n" +
40
- "1. Install an official catalog model:\n" +
41
- `${catText}\n` +
42
- " Example: termux-vision model install smolvlm-500m-q4\n\n" +
43
- "2. Use custom/external ('싸제') models:\n" +
44
- " - Place your text model GGUF and vision projector mmproj GGUF in:\n" +
45
- " ~/.cache/termux-vision/models/<custom_model_name>/\n" +
46
- " - Or pass direct file paths:\n" +
47
- " termux-vision vlm <IMAGE> --model /path/to/model.gguf --mmproj /path/to/mmproj.gguf\n" +
48
- " (Note: VLM inference requires both a language model .gguf and a vision projector mmproj-*.gguf)";
49
- super('all', [], catalogModels);
50
- this.message = msg;
51
- }
52
- }
53
-
54
- class ModelSelectionRequiredError extends ModelNotFoundError {
55
- constructor(installedModels = []) {
56
- const modelsText = installedModels.map(m => ` - ${m}`).join('\n');
57
- const exampleModel = installedModels[0] || 'MODEL_ID';
58
- const msg =
59
- `Multiple models are installed. Please specify one with --model:\n` +
60
- `${modelsText}\n\n` +
61
- `Example:\n` +
62
- ` termux-vision vlm <IMAGE> --model ${exampleModel} -p "Describe this image"`;
63
- super('multiple', installedModels, []);
64
- this.message = msg;
65
- }
66
- }
67
-
68
- class VulkanNotAvailableError extends TermuxVisionError {
69
- constructor(reason = '') {
70
- const detail = reason ? `\nFailure detail: ${reason}` : '';
71
- const msg =
72
- `Vulkan GPU acceleration is unavailable or failed on this device.${detail}\n\n` +
73
- `[Action Required] Explicit GPU mode cannot proceed. Please switch to CPU mode:\n` +
74
- ` CLI: --device cpu\n` +
75
- ` Node.js API: device: 'cpu'\n` +
76
- `Or use automatic detection: --device auto (device: 'auto')`;
77
- super(msg);
78
- this.reason = reason;
79
- }
80
- }
81
-
82
- class RuntimeNotFoundError extends TermuxVisionError {
83
- constructor(searchedPaths = []) {
84
- let searched = '';
85
- if (searchedPaths.length > 0) {
86
- searched = '\n\nSearched paths:\n' + searchedPaths.map(p => ` - ${p}`).join('\n');
87
- }
88
- const msg =
89
- `Required runtime engine 'llama-cli' was not found.${searched}\n\n` +
90
- `Please install the official termux-llamacpp native runtime:\n` +
91
- ` - Python: pip install termux-llamacpp\n` +
92
- ` - Node.js: npm install -g termux-llamacpp\n` +
93
- ` - Setup: termux-llama install (compiles native binary if needed)`;
94
- super(msg);
95
- this.searchedPaths = searchedPaths;
96
- }
97
- }
98
-
99
- class ModelDownloadError extends TermuxVisionError {
100
- constructor(source, reason = '', availableLocal = []) {
101
- let msg = `Failed to download model from '${source}': ${reason}`;
102
- if (availableLocal && availableLocal.length > 0) {
103
- msg += `\n\nInstalled local models available:\n` +
104
- availableLocal.map(m => ` - ${m}`).join('\n') +
105
- `\nRun with local model: termux-vision vlm <IMAGE> --model ${availableLocal[0]}`;
106
- }
107
- super(msg);
108
- this.source = source;
109
- this.reason = reason;
110
- }
111
- }
112
-
113
- module.exports = {
114
- TermuxVisionError,
115
- ModelNotFoundError,
116
- NoInstalledModelsError,
117
- ModelSelectionRequiredError,
118
- VulkanNotAvailableError,
119
- RuntimeNotFoundError,
120
- ModelDownloadError
121
- };
1
+ /**
2
+ * Copyright (c) 2026 Uno Kim / AMEVA Foundation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0 OR Commercial-License
4
+ */
5
+ /**
6
+ * Structured Exception Classes and Dynamic User Error Contracts for Node.js.
7
+ * Open-Source under Apache License 2.0.
8
+ */
9
+
10
+ 'use strict';
11
+
12
+ class TermuxVisionError extends Error {
13
+ constructor(message) {
14
+ super(message);
15
+ this.name = this.constructor.name;
16
+ }
17
+ }
18
+
19
+ class ModelNotFoundError extends TermuxVisionError {
20
+ constructor(modelId, availableLocal = [], catalogModels = []) {
21
+ let msg = `Model '${modelId}' was not found locally or on remote registry.`;
22
+ if (availableLocal && availableLocal.length > 0) {
23
+ msg += `\n\nCurrently installed local models (${availableLocal.length}):\n` +
24
+ availableLocal.map(m => ` - ${m}`).join('\n') +
25
+ `\n\nTo run with an installed model:\n termux-vision vlm <IMAGE> --model ${availableLocal[0]}`;
26
+ } else if (catalogModels && catalogModels.length > 0) {
27
+ msg += `\n\nNo models installed locally. Available catalog presets:\n` +
28
+ catalogModels.map(m => ` - ${m}`).join('\n') +
29
+ `\n\nInstall an official model:\n termux-vision model install ${catalogModels[0]}`;
30
+ }
31
+ super(msg);
32
+ this.modelId = modelId;
33
+ this.availableLocal = availableLocal;
34
+ this.catalogModels = catalogModels;
35
+ }
36
+ }
37
+
38
+ class NoInstalledModelsError extends ModelNotFoundError {
39
+ constructor(catalogModels = []) {
40
+ const catText = catalogModels.length > 0 ? catalogModels.map(m => ` - ${m}`).join('\n') : ' (none)';
41
+ const msg =
42
+ "No installed VLM models were found in local cache (~/.cache/termux-vision/models).\n\n" +
43
+ "How to use VLM models:\n" +
44
+ "1. Install an official catalog model:\n" +
45
+ `${catText}\n` +
46
+ " Example: termux-vision model install smolvlm-500m-q4\n\n" +
47
+ "2. Use custom/external ('싸제') models:\n" +
48
+ " - Place your text model GGUF and vision projector mmproj GGUF in:\n" +
49
+ " ~/.cache/termux-vision/models/<custom_model_name>/\n" +
50
+ " - Or pass direct file paths:\n" +
51
+ " termux-vision vlm <IMAGE> --model /path/to/model.gguf --mmproj /path/to/mmproj.gguf\n" +
52
+ " (Note: VLM inference requires both a language model .gguf and a vision projector mmproj-*.gguf)";
53
+ super('all', [], catalogModels);
54
+ this.message = msg;
55
+ }
56
+ }
57
+
58
+ class ModelSelectionRequiredError extends ModelNotFoundError {
59
+ constructor(installedModels = []) {
60
+ const modelsText = installedModels.map(m => ` - ${m}`).join('\n');
61
+ const exampleModel = installedModels[0] || 'MODEL_ID';
62
+ const msg =
63
+ `Multiple models are installed. Please specify one with --model:\n` +
64
+ `${modelsText}\n\n` +
65
+ `Example:\n` +
66
+ ` termux-vision vlm <IMAGE> --model ${exampleModel} -p "Describe this image"`;
67
+ super('multiple', installedModels, []);
68
+ this.message = msg;
69
+ }
70
+ }
71
+
72
+ class VulkanNotAvailableError extends TermuxVisionError {
73
+ constructor(reason = '') {
74
+ const detail = reason ? `\nFailure detail: ${reason}` : '';
75
+ const msg =
76
+ `Vulkan GPU acceleration is unavailable or failed on this device.${detail}\n\n` +
77
+ `[Action Required] Explicit GPU mode cannot proceed. Please switch to CPU mode:\n` +
78
+ ` CLI: --device cpu\n` +
79
+ ` Node.js API: device: 'cpu'\n` +
80
+ `Or use automatic detection: --device auto (device: 'auto')`;
81
+ super(msg);
82
+ this.reason = reason;
83
+ }
84
+ }
85
+
86
+ class RuntimeNotFoundError extends TermuxVisionError {
87
+ constructor(searchedPaths = []) {
88
+ let searched = '';
89
+ if (searchedPaths.length > 0) {
90
+ searched = '\n\nSearched paths:\n' + searchedPaths.map(p => ` - ${p}`).join('\n');
91
+ }
92
+ const msg =
93
+ `Required runtime engine 'llama-cli' was not found.${searched}\n\n` +
94
+ `Please install the official termux-llamacpp native runtime:\n` +
95
+ ` - Python: pip install termux-llamacpp\n` +
96
+ ` - Node.js: npm install -g termux-llamacpp\n` +
97
+ ` - Setup: termux-llama install (compiles native binary if needed)`;
98
+ super(msg);
99
+ this.searchedPaths = searchedPaths;
100
+ }
101
+ }
102
+
103
+ class ModelDownloadError extends TermuxVisionError {
104
+ constructor(source, reason = '', availableLocal = []) {
105
+ let msg = `Failed to download model from '${source}': ${reason}`;
106
+ if (availableLocal && availableLocal.length > 0) {
107
+ msg += `\n\nInstalled local models available:\n` +
108
+ availableLocal.map(m => ` - ${m}`).join('\n') +
109
+ `\nRun with local model: termux-vision vlm <IMAGE> --model ${availableLocal[0]}`;
110
+ }
111
+ super(msg);
112
+ this.source = source;
113
+ this.reason = reason;
114
+ }
115
+ }
116
+
117
+ module.exports = {
118
+ TermuxVisionError,
119
+ ModelNotFoundError,
120
+ NoInstalledModelsError,
121
+ ModelSelectionRequiredError,
122
+ VulkanNotAvailableError,
123
+ RuntimeNotFoundError,
124
+ ModelDownloadError
125
+ };
package/lib/vlm.js CHANGED
@@ -1,3 +1,7 @@
1
+ /**
2
+ * Copyright (c) 2026 Uno Kim / AMEVA Foundation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0 OR Commercial-License
4
+ */
1
5
  /**
2
6
  * Node.js VLM Engine & Supervised llama-cli Subprocess Bridge.
3
7
  * Open-Source under Apache License 2.0.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termux-vision",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "On-device computer vision & VLM multimodal inference framework utilizing device resources for Android Termux & ARM64",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -53,4 +53,4 @@
53
53
  "engines": {
54
54
  "node": ">=16.0.0"
55
55
  }
56
- }
56
+ }