@sylphx/iris 0.2.1 → 0.3.1
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 +48 -226
- package/dist/doctor-cli.js +60 -58
- package/package.json +32 -16
- package/src/handlers/readImage.ts +7 -2
- package/src/schemas/readImage.ts +6 -0
package/README.md
CHANGED
|
@@ -1,268 +1,90 @@
|
|
|
1
|
-
<div align="center">
|
|
2
|
-
|
|
3
1
|
# Iris
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
### Image facts with pixel-level proof
|
|
4
|
+
|
|
5
|
+
Iris gives agents deterministic facts from screenshots, UI captures, forms,
|
|
6
|
+
diagrams, charts, and other images. It returns dimensions, metadata, OCR
|
|
7
|
+
regions, layout blocks, crops, and trust warnings without requiring a
|
|
8
|
+
generative vision model.
|
|
6
9
|
|
|
7
10
|
```bash
|
|
8
11
|
npx -y @sylphx/iris
|
|
9
12
|
```
|
|
10
13
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
### Image evidence for agents
|
|
15
|
-
|
|
16
|
-
Canonical package: **`@sylphx/iris`** · bin **`iris`**
|
|
17
|
-
|
|
18
|
-
**Iris** — **Rust-first** local image facts (`@sylphx/iris`) local image facts, not default VLM guesses. `sharp`/`exifr` are optional, not required for MCP.
|
|
19
|
-
|
|
20
|
-
<p align="center">
|
|
21
|
-
<img src="https://mark.sylphx.com/api/v1/banner?type=holo&theme=tokyonight&text=image+reader+mcp&desc=Evidence-first+image+reading+for+AI+agents+%E2%80%94+metadata%2C+OCR+text%2C+regions%2C+and+ci&height=200&animation=rise&credit=0" alt="image-reader-mcp — Sylphx Mark banner" width="100%" />
|
|
22
|
-
</p>
|
|
23
|
-
|
|
24
|
-
### Your agent looked at the image. **Did it see the truth?**
|
|
25
|
-
|
|
26
|
-
Evidence-first image reading for AI agents. One call turns any local image into an
|
|
27
|
-
**Agent Media Twin** — dimensions, metadata, optional OCR with bounding boxes, and
|
|
28
|
-
trust warnings you can cite without asking a vision LLM to guess.
|
|
29
|
-
|
|
30
|
-
[](https://www.npmjs.com/package/@sylphx/iris)
|
|
31
|
-
[](https://opensource.org/licenses/MIT)
|
|
32
|
-
[](https://github.com/SylphxAI/image-reader-mcp/actions/workflows/ci.yml)
|
|
33
|
-
[](https://www.typescriptlang.org/)
|
|
34
|
-
|
|
35
|
-
**Local-first** · **One smart `read_image` call** · **Evidence with bbox + provenance** · **23 tests**
|
|
36
|
-
|
|
37
|
-
SOTA family roadmap: [docs/roadmap/sota-family-roadmap.md](docs/roadmap/sota-family-roadmap.md).
|
|
38
|
-
|
|
39
|
-
[⭐ Star this repo](https://github.com/SylphxAI/image-reader-mcp) if agents should read images with facts, not vision-model guesses.
|
|
40
|
-
· [Quick start](#quick-start) · [See it work](#see-it-work) · [Why not vision LLM guess?](#why-not-vision-llm-guess)
|
|
41
|
-
|
|
42
|
-
This repository is product SSOT. Sibling agent tools live in separate repos.
|
|
43
|
-
Each instrument is an independent repository (marketplace + stars).
|
|
44
|
-
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
## See objects (L2, optional)
|
|
52
|
-
|
|
53
|
-
With a local Florence-class sidecar or Ollama, the same `read_image` can return **open-vocab objects** with pixel bboxes and scores:
|
|
54
|
-
|
|
55
|
-
```json
|
|
56
|
-
{ "path": "/abs/photo.jpg", "include_semantics": true, "semantics_prompt": "people and animals" }
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Objects are `scored_non_locator` evidence — deterministic L0/L1 facts (geometry/OCR/layout) stay authoritative and always on.
|
|
60
|
-
|
|
61
|
-
## Read images (not vague vision)
|
|
62
|
-
|
|
63
|
-
Iris is **local-first**: geometry + OCR + **layout blocks** + **agent_map** so a text-only agent can understand picture architecture without a vision model.
|
|
64
|
-
|
|
65
|
-
Spec: [docs/specs/agent-image-read-contract.md](docs/specs/agent-image-read-contract.md)
|
|
66
|
-
|
|
67
|
-
**Local-first frontier:** Rust decode, Tesseract native layout (no npm ML), optional Ollama VLM; cloud URL optional. Zero API key. Optional **L2 local semantics** (include_semantics) detects open-vocab objects (people/animals/things) with pixel bboxes via an official Florence-class sidecar (examples/florence-sidecar/) or Ollama -- never authority over OCR/layout locators.
|
|
68
|
-
|
|
69
|
-
## Product docs
|
|
70
|
-
|
|
71
|
-
| Doc | Purpose |
|
|
72
|
-
| --- | --- |
|
|
73
|
-
| [docs/POSITIONING.md](docs/POSITIONING.md) | Strategic positioning |
|
|
74
|
-
| [docs/COMPETITIVE.md](docs/COMPETITIVE.md) | Peer anchors and wedge |
|
|
75
|
-
| [docs/EVIDENCE_CONTRACT.md](docs/EVIDENCE_CONTRACT.md) | Evidence = result contract |
|
|
76
|
-
| [docs/TOOL_SURFACE.md](docs/TOOL_SURFACE.md) | Few clear tools policy |
|
|
77
|
-
| [docs/PRODUCT_INDEPENDENCE.md](docs/PRODUCT_INDEPENDENCE.md) | This repo is SSOT |
|
|
78
|
-
| [docs/IPPB.md](docs/IPPB.md) | Independent public product bar |
|
|
79
|
-
| [docs/PUBLISH.md](docs/PUBLISH.md) | npm/git publish status |
|
|
80
|
-
|
|
81
|
-
## The problem
|
|
82
|
-
|
|
83
|
-
Images are not filenames. They are pixels, EXIF, orientation, embedded GPS,
|
|
84
|
-
hidden metadata, and text that only exists if you OCR it with geometry.
|
|
85
|
-
|
|
86
|
-
Most agent stacks route images through a **vision LLM** and get a plausible
|
|
87
|
-
description. Dimensions get rounded. OCR text gets paraphrased. Metadata
|
|
88
|
-
disappears. Citations become "the model said so." Then the agent hallucinates —
|
|
89
|
-
confidently.
|
|
90
|
-
|
|
91
|
-
**Image Reader MCP is built for the moment your agent needs measurable facts about
|
|
92
|
-
an image, not a creative caption.**
|
|
93
|
-
|
|
94
|
-
## Why not vision LLM guess?
|
|
95
|
-
|
|
96
|
-
| Typical vision path | Image Reader MCP |
|
|
97
|
-
| --- | --- |
|
|
98
|
-
| "Describe this image" | Return filename, mime, dimensions, and structured metadata |
|
|
99
|
-
| Paraphrased OCR | Optional Tesseract lines with bounding boxes and confidence |
|
|
100
|
-
| GPS and EXIF leak into context | GPS redacted; trust warnings for suspicious metadata |
|
|
101
|
-
| No provenance | Agent Media Twin JSON with measurable, citeable fields |
|
|
102
|
-
| Cloud API by default | **Local-first** — Rust decode + optional Tesseract OCR; sharp/exifr only optional fallbacks |
|
|
103
|
-
| Ship and pray | **23** unit tests on schema, metadata, OCR hooks, safety limits, doctor, and release gate |
|
|
104
|
-
|
|
105
|
-
## See it work
|
|
106
|
-
|
|
107
|
-
### Install (30 seconds)
|
|
14
|
+
For Claude Code:
|
|
108
15
|
|
|
109
16
|
```bash
|
|
110
|
-
|
|
111
|
-
iris doctor
|
|
112
|
-
claude mcp add iris -- npx @sylphx/iris
|
|
17
|
+
claude mcp add iris -- npx -y @sylphx/iris
|
|
113
18
|
```
|
|
114
19
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
```
|
|
20
|
+
## The fastest useful workflow
|
|
119
21
|
|
|
120
22
|
```json
|
|
121
23
|
{
|
|
122
|
-
"path": "/absolute/path/to/
|
|
123
|
-
"include_metadata": true,
|
|
24
|
+
"path": "/absolute/path/to/screenshot.png",
|
|
124
25
|
"include_ocr": true
|
|
125
26
|
}
|
|
126
27
|
```
|
|
127
28
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
```json
|
|
132
|
-
{
|
|
133
|
-
"filename": "photo.jpg",
|
|
134
|
-
"mime": "image/jpeg",
|
|
135
|
-
"dimensions": { "width": 4032, "height": 3024 },
|
|
136
|
-
"orientation": 1,
|
|
137
|
-
"metadata": {
|
|
138
|
-
"Make": "ExampleCamera",
|
|
139
|
-
"Model": "Pro X",
|
|
140
|
-
"DateTimeOriginal": "2026-03-15T14:22:10"
|
|
141
|
-
},
|
|
142
|
-
"ocr": {
|
|
143
|
-
"available": true,
|
|
144
|
-
"lines": [
|
|
145
|
-
{
|
|
146
|
-
"text": "INVOICE #1042",
|
|
147
|
-
"bbox": { "x": 120, "y": 48, "width": 310, "height": 36 },
|
|
148
|
-
"confidence": 92
|
|
149
|
-
}
|
|
150
|
-
]
|
|
151
|
-
},
|
|
152
|
-
"trust_warnings": []
|
|
153
|
-
}
|
|
154
|
-
```
|
|
29
|
+
The result includes image dimensions, hash, OCR lines with bounding boxes,
|
|
30
|
+
layout blocks, a text map for agents, and explicit warnings or gaps.
|
|
155
31
|
|
|
156
|
-
|
|
32
|
+
## Jobs Iris is built for
|
|
157
33
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
| Tool | Use it when the agent needs to... |
|
|
34
|
+
| Ask your agent | Iris returns |
|
|
161
35
|
| --- | --- |
|
|
162
|
-
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
36
|
+
| “Read this screenshot.” | text regions and layout facts |
|
|
37
|
+
| “What changed between these UI captures?” | image diff evidence |
|
|
38
|
+
| “Extract this form.” | OCR lines and boxes |
|
|
39
|
+
| “Crop the important region.” | citeable pixel evidence |
|
|
40
|
+
| “Check the image metadata.” | format, dimensions, EXIF trust warnings |
|
|
167
41
|
|
|
168
|
-
|
|
42
|
+
## Tool surface
|
|
169
43
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
```json
|
|
178
|
-
{
|
|
179
|
-
"mcpServers": {
|
|
180
|
-
"iris": {
|
|
181
|
-
"command": "npx",
|
|
182
|
-
"args": ["@sylphx/iris"]
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Any MCP Client
|
|
189
|
-
|
|
190
|
-
```bash
|
|
191
|
-
npx @sylphx/iris
|
|
192
|
-
```
|
|
44
|
+
| Tool | Purpose |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `read_image` | Primary image facts and optional OCR |
|
|
47
|
+
| `image_probe` | Cheap metadata and geometry probe |
|
|
48
|
+
| `crop_region` | Extract a citeable pixel region |
|
|
49
|
+
| `compare_images` | Report pixel and layout differences between two images |
|
|
193
50
|
|
|
194
|
-
|
|
195
|
-
installed — no cloud credentials required by default.
|
|
51
|
+
## Predictable defaults
|
|
196
52
|
|
|
197
|
-
|
|
53
|
+
- `fast` returns deterministic metadata, geometry, and layout.
|
|
54
|
+
- `quality` explicitly enables OCR and local semantic helpers.
|
|
55
|
+
- Generative captions and object detection are opt-in and never authoritative.
|
|
56
|
+
- GPS metadata is redacted unless explicitly requested.
|
|
57
|
+
- Oversized or unsupported files fail with a structured error.
|
|
198
58
|
|
|
199
|
-
|
|
200
|
-
- **GPS redaction** — location metadata is stripped from agent-facing output unless explicitly opted in.
|
|
201
|
-
- **Size and format limits** — oversized or unsupported inputs return structured errors, not partial guesses.
|
|
202
|
-
- **Optional OCR** — Tesseract runs locally when installed; missing OCR is reported as `available: false`, not silent failure.
|
|
203
|
-
- **Trust warnings** — suspicious EXIF, orientation, or metadata anomalies surface in `trust_warnings` for agent verification.
|
|
59
|
+
## Why agents trust it
|
|
204
60
|
|
|
205
|
-
|
|
61
|
+
Every result keeps source path and hash, pixel locators, extraction route,
|
|
62
|
+
confidence or warnings, and known gaps. OCR and optional model output never
|
|
63
|
+
replace deterministic geometry.
|
|
206
64
|
|
|
207
|
-
|
|
65
|
+
## Companion MCP tools
|
|
208
66
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
67
|
+
| Product | Job |
|
|
68
|
+
| --- | --- |
|
|
69
|
+
| [Citra](https://github.com/SylphxAI/citra) | PDF answers with page-level proof |
|
|
70
|
+
| [Cue](https://github.com/SylphxAI/cue) | Video timelines and timestamp evidence |
|
|
71
|
+
| [Spine](https://github.com/SylphxAI/spine) | Repository architecture and impact |
|
|
72
|
+
| [Locus](https://github.com/SylphxAI/locus) | Exact code-chunk retrieval |
|
|
73
|
+
| [Lookout](https://github.com/SylphxAI/lookout) | Web research with source excerpts |
|
|
212
74
|
|
|
213
|
-
|
|
75
|
+
Each product is independent. Install only the tools your agent needs.
|
|
214
76
|
|
|
215
77
|
## Development
|
|
216
78
|
|
|
217
79
|
```bash
|
|
218
|
-
git clone https://github.com/SylphxAI/image-reader-mcp.git
|
|
219
|
-
cd image-reader-mcp
|
|
220
80
|
bun install
|
|
221
81
|
bun run build
|
|
222
82
|
bun test
|
|
223
|
-
|
|
224
|
-
bun run benchmark:
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
Useful checks:
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
bun run check
|
|
231
|
-
bun run typecheck
|
|
232
|
-
bun run validate
|
|
83
|
+
cargo test
|
|
84
|
+
bun run benchmark:public-proof
|
|
233
85
|
bun run benchmark:release-gate
|
|
234
86
|
```
|
|
235
87
|
|
|
236
|
-
Example `read_image` requests live in [`examples/`](examples/).
|
|
237
|
-
|
|
238
|
-
## Support
|
|
239
|
-
|
|
240
|
-
- [Issues](https://github.com/SylphxAI/image-reader-mcp/issues)
|
|
241
|
-
- [npm package](https://www.npmjs.com/package/@sylphx/iris)
|
|
242
|
-
- Portfolio orchestration: [smart-reader-mcp](https://github.com/SylphxAI/smart-reader-mcp)
|
|
243
|
-
|
|
244
|
-
## Help this reach more builders
|
|
245
|
-
|
|
246
|
-
If vision-model guesses have wasted your context, your citations, or your trust
|
|
247
|
-
in agent output, you are exactly who this project is for.
|
|
248
|
-
|
|
249
|
-
**[⭐ Star the repo](https://github.com/SylphxAI/image-reader-mcp)** — it is the
|
|
250
|
-
fastest way to help more agent builders find evidence-first image reading. Share
|
|
251
|
-
it in your MCP client setup, team wiki, or agent stack README.
|
|
252
|
-
|
|
253
|
-
### Discovery (in progress)
|
|
254
|
-
|
|
255
|
-
| Channel | Status |
|
|
256
|
-
| --- | --- |
|
|
257
|
-
| [Glama MCP directory](https://glama.ai/mcp/servers/SylphxAI/image-reader-mcp) | Listed — [claim server](https://glama.ai/mcp/servers/SylphxAI/image-reader-mcp/admin) for full discoverability |
|
|
258
|
-
| [Official MCP Registry](https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.SylphxAI/image-reader-mcp) | Listed — `io.github.SylphxAI/image-reader-mcp` @ v0.1.0 |
|
|
259
|
-
| [TensorBlock MCP Index PR #1113](https://github.com/TensorBlock/awesome-mcp-servers/pull/1113) | Open — multimedia/document processing listing |
|
|
260
|
-
| [MCP servers community issue #4500](https://github.com/modelcontextprotocol/servers/issues/4500) | Open — community server highlight |
|
|
261
|
-
| [mcp.so listing issue #3068](https://github.com/chatmcp/mcpso/issues/3068) | Open — directory submission request |
|
|
262
|
-
| [mcpservers.org submit](https://mcpservers.org/submit) | Not listed yet — free web-form submission |
|
|
263
|
-
|
|
264
|
-
Know another MCP directory? [Open an issue](https://github.com/SylphxAI/image-reader-mcp/issues/new) with the link.
|
|
265
|
-
|
|
266
88
|
## License
|
|
267
89
|
|
|
268
|
-
MIT
|
|
90
|
+
MIT
|
package/dist/doctor-cli.js
CHANGED
|
@@ -20,12 +20,14 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
20
20
|
}
|
|
21
21
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
22
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
if (mod && typeof mod === "object" || typeof mod === "function") {
|
|
24
|
+
for (let key of __getOwnPropNames(mod))
|
|
25
|
+
if (!__hasOwnProp.call(to, key))
|
|
26
|
+
__defProp(to, key, {
|
|
27
|
+
get: __accessProp.bind(mod, key),
|
|
28
|
+
enumerable: true
|
|
29
|
+
});
|
|
30
|
+
}
|
|
29
31
|
if (canCache)
|
|
30
32
|
cache.set(mod, to);
|
|
31
33
|
return to;
|
|
@@ -93,7 +95,7 @@ var init_is = __esm(() => {
|
|
|
93
95
|
});
|
|
94
96
|
|
|
95
97
|
// node_modules/detect-libc/lib/process.js
|
|
96
|
-
var require_process = __commonJS((exports, module)
|
|
98
|
+
var require_process = __commonJS(function(exports, module) {
|
|
97
99
|
var isLinux = () => process.platform === "linux";
|
|
98
100
|
var report = null;
|
|
99
101
|
var getReport = () => {
|
|
@@ -113,7 +115,7 @@ var require_process = __commonJS((exports, module) => {
|
|
|
113
115
|
});
|
|
114
116
|
|
|
115
117
|
// node_modules/detect-libc/lib/filesystem.js
|
|
116
|
-
var require_filesystem = __commonJS((exports, module)
|
|
118
|
+
var require_filesystem = __commonJS(function(exports, module) {
|
|
117
119
|
var fs = __require("fs");
|
|
118
120
|
var LDD_PATH = "/usr/bin/ldd";
|
|
119
121
|
var SELF_PATH = "/proc/self/exe";
|
|
@@ -147,7 +149,7 @@ var require_filesystem = __commonJS((exports, module) => {
|
|
|
147
149
|
});
|
|
148
150
|
|
|
149
151
|
// node_modules/detect-libc/lib/elf.js
|
|
150
|
-
var require_elf = __commonJS((exports, module)
|
|
152
|
+
var require_elf = __commonJS(function(exports, module) {
|
|
151
153
|
var interpreterPath = (elf) => {
|
|
152
154
|
if (elf.length < 64) {
|
|
153
155
|
return null;
|
|
@@ -181,7 +183,7 @@ var require_elf = __commonJS((exports, module) => {
|
|
|
181
183
|
});
|
|
182
184
|
|
|
183
185
|
// node_modules/detect-libc/lib/detect-libc.js
|
|
184
|
-
var require_detect_libc = __commonJS((exports, module)
|
|
186
|
+
var require_detect_libc = __commonJS(function(exports, module) {
|
|
185
187
|
var childProcess = __require("child_process");
|
|
186
188
|
var { isLinux, getReport } = require_process();
|
|
187
189
|
var { LDD_PATH, SELF_PATH, readFile, readFileSync } = require_filesystem();
|
|
@@ -427,7 +429,7 @@ var require_detect_libc = __commonJS((exports, module) => {
|
|
|
427
429
|
});
|
|
428
430
|
|
|
429
431
|
// node_modules/semver/internal/constants.js
|
|
430
|
-
var require_constants = __commonJS((exports, module)
|
|
432
|
+
var require_constants = __commonJS(function(exports, module) {
|
|
431
433
|
var SEMVER_SPEC_VERSION = "2.0.0";
|
|
432
434
|
var MAX_LENGTH = 256;
|
|
433
435
|
var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;
|
|
@@ -455,13 +457,13 @@ var require_constants = __commonJS((exports, module) => {
|
|
|
455
457
|
});
|
|
456
458
|
|
|
457
459
|
// node_modules/semver/internal/debug.js
|
|
458
|
-
var require_debug = __commonJS((exports, module)
|
|
460
|
+
var require_debug = __commonJS(function(exports, module) {
|
|
459
461
|
var debug = typeof process === "object" && process.env && process.env.NODE_DEBUG && /\bsemver\b/i.test(process.env.NODE_DEBUG) ? (...args) => console.error("SEMVER", ...args) : () => {};
|
|
460
462
|
module.exports = debug;
|
|
461
463
|
});
|
|
462
464
|
|
|
463
465
|
// node_modules/semver/internal/re.js
|
|
464
|
-
var require_re = __commonJS((exports, module)
|
|
466
|
+
var require_re = __commonJS(function(exports, module) {
|
|
465
467
|
var {
|
|
466
468
|
MAX_SAFE_COMPONENT_LENGTH,
|
|
467
469
|
MAX_SAFE_BUILD_LENGTH,
|
|
@@ -546,7 +548,7 @@ var require_re = __commonJS((exports, module) => {
|
|
|
546
548
|
});
|
|
547
549
|
|
|
548
550
|
// node_modules/semver/internal/parse-options.js
|
|
549
|
-
var require_parse_options = __commonJS((exports, module)
|
|
551
|
+
var require_parse_options = __commonJS(function(exports, module) {
|
|
550
552
|
var looseOption = Object.freeze({ loose: true });
|
|
551
553
|
var emptyOpts = Object.freeze({});
|
|
552
554
|
var parseOptions = (options) => {
|
|
@@ -562,7 +564,7 @@ var require_parse_options = __commonJS((exports, module) => {
|
|
|
562
564
|
});
|
|
563
565
|
|
|
564
566
|
// node_modules/semver/internal/identifiers.js
|
|
565
|
-
var require_identifiers = __commonJS((exports, module)
|
|
567
|
+
var require_identifiers = __commonJS(function(exports, module) {
|
|
566
568
|
var numeric = /^[0-9]+$/;
|
|
567
569
|
var compareIdentifiers = (a, b) => {
|
|
568
570
|
if (typeof a === "number" && typeof b === "number") {
|
|
@@ -584,7 +586,7 @@ var require_identifiers = __commonJS((exports, module) => {
|
|
|
584
586
|
});
|
|
585
587
|
|
|
586
588
|
// node_modules/semver/classes/semver.js
|
|
587
|
-
var require_semver = __commonJS((exports, module)
|
|
589
|
+
var require_semver = __commonJS(function(exports, module) {
|
|
588
590
|
var debug = require_debug();
|
|
589
591
|
var { MAX_LENGTH, MAX_SAFE_INTEGER } = require_constants();
|
|
590
592
|
var { safeRe: re, t } = require_re();
|
|
@@ -866,7 +868,7 @@ var require_semver = __commonJS((exports, module) => {
|
|
|
866
868
|
});
|
|
867
869
|
|
|
868
870
|
// node_modules/semver/functions/parse.js
|
|
869
|
-
var require_parse = __commonJS((exports, module)
|
|
871
|
+
var require_parse = __commonJS(function(exports, module) {
|
|
870
872
|
var SemVer = require_semver();
|
|
871
873
|
var parse = (version, options, throwErrors = false) => {
|
|
872
874
|
if (version instanceof SemVer) {
|
|
@@ -885,7 +887,7 @@ var require_parse = __commonJS((exports, module) => {
|
|
|
885
887
|
});
|
|
886
888
|
|
|
887
889
|
// node_modules/semver/functions/valid.js
|
|
888
|
-
var require_valid = __commonJS((exports, module)
|
|
890
|
+
var require_valid = __commonJS(function(exports, module) {
|
|
889
891
|
var parse = require_parse();
|
|
890
892
|
var valid = (version, options) => {
|
|
891
893
|
const v = parse(version, options);
|
|
@@ -895,7 +897,7 @@ var require_valid = __commonJS((exports, module) => {
|
|
|
895
897
|
});
|
|
896
898
|
|
|
897
899
|
// node_modules/semver/functions/clean.js
|
|
898
|
-
var require_clean = __commonJS((exports, module)
|
|
900
|
+
var require_clean = __commonJS(function(exports, module) {
|
|
899
901
|
var parse = require_parse();
|
|
900
902
|
var clean = (version, options) => {
|
|
901
903
|
const s = parse(version.trim().replace(/^[=v]+/, ""), options);
|
|
@@ -905,7 +907,7 @@ var require_clean = __commonJS((exports, module) => {
|
|
|
905
907
|
});
|
|
906
908
|
|
|
907
909
|
// node_modules/semver/functions/inc.js
|
|
908
|
-
var require_inc = __commonJS((exports, module)
|
|
910
|
+
var require_inc = __commonJS(function(exports, module) {
|
|
909
911
|
var SemVer = require_semver();
|
|
910
912
|
var inc = (version, release, options, identifier, identifierBase) => {
|
|
911
913
|
if (typeof options === "string") {
|
|
@@ -923,7 +925,7 @@ var require_inc = __commonJS((exports, module) => {
|
|
|
923
925
|
});
|
|
924
926
|
|
|
925
927
|
// node_modules/semver/functions/diff.js
|
|
926
|
-
var require_diff = __commonJS((exports, module)
|
|
928
|
+
var require_diff = __commonJS(function(exports, module) {
|
|
927
929
|
var parse = require_parse();
|
|
928
930
|
var diff = (version1, version2) => {
|
|
929
931
|
const v1 = parse(version1, null, true);
|
|
@@ -964,28 +966,28 @@ var require_diff = __commonJS((exports, module) => {
|
|
|
964
966
|
});
|
|
965
967
|
|
|
966
968
|
// node_modules/semver/functions/major.js
|
|
967
|
-
var require_major = __commonJS((exports, module)
|
|
969
|
+
var require_major = __commonJS(function(exports, module) {
|
|
968
970
|
var SemVer = require_semver();
|
|
969
971
|
var major = (a, loose) => new SemVer(a, loose).major;
|
|
970
972
|
module.exports = major;
|
|
971
973
|
});
|
|
972
974
|
|
|
973
975
|
// node_modules/semver/functions/minor.js
|
|
974
|
-
var require_minor = __commonJS((exports, module)
|
|
976
|
+
var require_minor = __commonJS(function(exports, module) {
|
|
975
977
|
var SemVer = require_semver();
|
|
976
978
|
var minor = (a, loose) => new SemVer(a, loose).minor;
|
|
977
979
|
module.exports = minor;
|
|
978
980
|
});
|
|
979
981
|
|
|
980
982
|
// node_modules/semver/functions/patch.js
|
|
981
|
-
var require_patch = __commonJS((exports, module)
|
|
983
|
+
var require_patch = __commonJS(function(exports, module) {
|
|
982
984
|
var SemVer = require_semver();
|
|
983
985
|
var patch = (a, loose) => new SemVer(a, loose).patch;
|
|
984
986
|
module.exports = patch;
|
|
985
987
|
});
|
|
986
988
|
|
|
987
989
|
// node_modules/semver/functions/prerelease.js
|
|
988
|
-
var require_prerelease = __commonJS((exports, module)
|
|
990
|
+
var require_prerelease = __commonJS(function(exports, module) {
|
|
989
991
|
var parse = require_parse();
|
|
990
992
|
var prerelease = (version, options) => {
|
|
991
993
|
const parsed = parse(version, options);
|
|
@@ -995,28 +997,28 @@ var require_prerelease = __commonJS((exports, module) => {
|
|
|
995
997
|
});
|
|
996
998
|
|
|
997
999
|
// node_modules/semver/functions/compare.js
|
|
998
|
-
var require_compare = __commonJS((exports, module)
|
|
1000
|
+
var require_compare = __commonJS(function(exports, module) {
|
|
999
1001
|
var SemVer = require_semver();
|
|
1000
1002
|
var compare = (a, b, loose) => new SemVer(a, loose).compare(new SemVer(b, loose));
|
|
1001
1003
|
module.exports = compare;
|
|
1002
1004
|
});
|
|
1003
1005
|
|
|
1004
1006
|
// node_modules/semver/functions/rcompare.js
|
|
1005
|
-
var require_rcompare = __commonJS((exports, module)
|
|
1007
|
+
var require_rcompare = __commonJS(function(exports, module) {
|
|
1006
1008
|
var compare = require_compare();
|
|
1007
1009
|
var rcompare = (a, b, loose) => compare(b, a, loose);
|
|
1008
1010
|
module.exports = rcompare;
|
|
1009
1011
|
});
|
|
1010
1012
|
|
|
1011
1013
|
// node_modules/semver/functions/compare-loose.js
|
|
1012
|
-
var require_compare_loose = __commonJS((exports, module)
|
|
1014
|
+
var require_compare_loose = __commonJS(function(exports, module) {
|
|
1013
1015
|
var compare = require_compare();
|
|
1014
1016
|
var compareLoose = (a, b) => compare(a, b, true);
|
|
1015
1017
|
module.exports = compareLoose;
|
|
1016
1018
|
});
|
|
1017
1019
|
|
|
1018
1020
|
// node_modules/semver/functions/compare-build.js
|
|
1019
|
-
var require_compare_build = __commonJS((exports, module)
|
|
1021
|
+
var require_compare_build = __commonJS(function(exports, module) {
|
|
1020
1022
|
var SemVer = require_semver();
|
|
1021
1023
|
var compareBuild = (a, b, loose) => {
|
|
1022
1024
|
const versionA = new SemVer(a, loose);
|
|
@@ -1027,63 +1029,63 @@ var require_compare_build = __commonJS((exports, module) => {
|
|
|
1027
1029
|
});
|
|
1028
1030
|
|
|
1029
1031
|
// node_modules/semver/functions/sort.js
|
|
1030
|
-
var require_sort = __commonJS((exports, module)
|
|
1032
|
+
var require_sort = __commonJS(function(exports, module) {
|
|
1031
1033
|
var compareBuild = require_compare_build();
|
|
1032
1034
|
var sort = (list, loose) => list.sort((a, b) => compareBuild(a, b, loose));
|
|
1033
1035
|
module.exports = sort;
|
|
1034
1036
|
});
|
|
1035
1037
|
|
|
1036
1038
|
// node_modules/semver/functions/rsort.js
|
|
1037
|
-
var require_rsort = __commonJS((exports, module)
|
|
1039
|
+
var require_rsort = __commonJS(function(exports, module) {
|
|
1038
1040
|
var compareBuild = require_compare_build();
|
|
1039
1041
|
var rsort = (list, loose) => list.sort((a, b) => compareBuild(b, a, loose));
|
|
1040
1042
|
module.exports = rsort;
|
|
1041
1043
|
});
|
|
1042
1044
|
|
|
1043
1045
|
// node_modules/semver/functions/gt.js
|
|
1044
|
-
var require_gt = __commonJS((exports, module)
|
|
1046
|
+
var require_gt = __commonJS(function(exports, module) {
|
|
1045
1047
|
var compare = require_compare();
|
|
1046
1048
|
var gt = (a, b, loose) => compare(a, b, loose) > 0;
|
|
1047
1049
|
module.exports = gt;
|
|
1048
1050
|
});
|
|
1049
1051
|
|
|
1050
1052
|
// node_modules/semver/functions/lt.js
|
|
1051
|
-
var require_lt = __commonJS((exports, module)
|
|
1053
|
+
var require_lt = __commonJS(function(exports, module) {
|
|
1052
1054
|
var compare = require_compare();
|
|
1053
1055
|
var lt = (a, b, loose) => compare(a, b, loose) < 0;
|
|
1054
1056
|
module.exports = lt;
|
|
1055
1057
|
});
|
|
1056
1058
|
|
|
1057
1059
|
// node_modules/semver/functions/eq.js
|
|
1058
|
-
var require_eq = __commonJS((exports, module)
|
|
1060
|
+
var require_eq = __commonJS(function(exports, module) {
|
|
1059
1061
|
var compare = require_compare();
|
|
1060
1062
|
var eq = (a, b, loose) => compare(a, b, loose) === 0;
|
|
1061
1063
|
module.exports = eq;
|
|
1062
1064
|
});
|
|
1063
1065
|
|
|
1064
1066
|
// node_modules/semver/functions/neq.js
|
|
1065
|
-
var require_neq = __commonJS((exports, module)
|
|
1067
|
+
var require_neq = __commonJS(function(exports, module) {
|
|
1066
1068
|
var compare = require_compare();
|
|
1067
1069
|
var neq = (a, b, loose) => compare(a, b, loose) !== 0;
|
|
1068
1070
|
module.exports = neq;
|
|
1069
1071
|
});
|
|
1070
1072
|
|
|
1071
1073
|
// node_modules/semver/functions/gte.js
|
|
1072
|
-
var require_gte = __commonJS((exports, module)
|
|
1074
|
+
var require_gte = __commonJS(function(exports, module) {
|
|
1073
1075
|
var compare = require_compare();
|
|
1074
1076
|
var gte = (a, b, loose) => compare(a, b, loose) >= 0;
|
|
1075
1077
|
module.exports = gte;
|
|
1076
1078
|
});
|
|
1077
1079
|
|
|
1078
1080
|
// node_modules/semver/functions/lte.js
|
|
1079
|
-
var require_lte = __commonJS((exports, module)
|
|
1081
|
+
var require_lte = __commonJS(function(exports, module) {
|
|
1080
1082
|
var compare = require_compare();
|
|
1081
1083
|
var lte = (a, b, loose) => compare(a, b, loose) <= 0;
|
|
1082
1084
|
module.exports = lte;
|
|
1083
1085
|
});
|
|
1084
1086
|
|
|
1085
1087
|
// node_modules/semver/functions/cmp.js
|
|
1086
|
-
var require_cmp = __commonJS((exports, module)
|
|
1088
|
+
var require_cmp = __commonJS(function(exports, module) {
|
|
1087
1089
|
var eq = require_eq();
|
|
1088
1090
|
var neq = require_neq();
|
|
1089
1091
|
var gt = require_gt();
|
|
@@ -1130,7 +1132,7 @@ var require_cmp = __commonJS((exports, module) => {
|
|
|
1130
1132
|
});
|
|
1131
1133
|
|
|
1132
1134
|
// node_modules/semver/functions/coerce.js
|
|
1133
|
-
var require_coerce = __commonJS((exports, module)
|
|
1135
|
+
var require_coerce = __commonJS(function(exports, module) {
|
|
1134
1136
|
var SemVer = require_semver();
|
|
1135
1137
|
var parse = require_parse();
|
|
1136
1138
|
var { safeRe: re, t } = require_re();
|
|
@@ -1173,7 +1175,7 @@ var require_coerce = __commonJS((exports, module) => {
|
|
|
1173
1175
|
});
|
|
1174
1176
|
|
|
1175
1177
|
// node_modules/semver/functions/truncate.js
|
|
1176
|
-
var require_truncate = __commonJS((exports, module)
|
|
1178
|
+
var require_truncate = __commonJS(function(exports, module) {
|
|
1177
1179
|
var parse = require_parse();
|
|
1178
1180
|
var constants = require_constants();
|
|
1179
1181
|
var SemVer = require_semver();
|
|
@@ -1211,7 +1213,7 @@ var require_truncate = __commonJS((exports, module) => {
|
|
|
1211
1213
|
});
|
|
1212
1214
|
|
|
1213
1215
|
// node_modules/semver/internal/lrucache.js
|
|
1214
|
-
var require_lrucache = __commonJS((exports, module)
|
|
1216
|
+
var require_lrucache = __commonJS(function(exports, module) {
|
|
1215
1217
|
class LRUCache {
|
|
1216
1218
|
constructor() {
|
|
1217
1219
|
this.max = 1000;
|
|
@@ -1246,7 +1248,7 @@ var require_lrucache = __commonJS((exports, module) => {
|
|
|
1246
1248
|
});
|
|
1247
1249
|
|
|
1248
1250
|
// node_modules/semver/classes/range.js
|
|
1249
|
-
var require_range = __commonJS((exports, module)
|
|
1251
|
+
var require_range = __commonJS(function(exports, module) {
|
|
1250
1252
|
var SPACE_CHARACTERS = /\s+/g;
|
|
1251
1253
|
|
|
1252
1254
|
class Range {
|
|
@@ -1628,7 +1630,7 @@ var require_range = __commonJS((exports, module) => {
|
|
|
1628
1630
|
});
|
|
1629
1631
|
|
|
1630
1632
|
// node_modules/semver/classes/comparator.js
|
|
1631
|
-
var require_comparator = __commonJS((exports, module)
|
|
1633
|
+
var require_comparator = __commonJS(function(exports, module) {
|
|
1632
1634
|
var ANY = Symbol("SemVer ANY");
|
|
1633
1635
|
|
|
1634
1636
|
class Comparator {
|
|
@@ -1739,7 +1741,7 @@ var require_comparator = __commonJS((exports, module) => {
|
|
|
1739
1741
|
});
|
|
1740
1742
|
|
|
1741
1743
|
// node_modules/semver/functions/satisfies.js
|
|
1742
|
-
var require_satisfies = __commonJS((exports, module)
|
|
1744
|
+
var require_satisfies = __commonJS(function(exports, module) {
|
|
1743
1745
|
var Range = require_range();
|
|
1744
1746
|
var satisfies = (version, range, options) => {
|
|
1745
1747
|
try {
|
|
@@ -1753,14 +1755,14 @@ var require_satisfies = __commonJS((exports, module) => {
|
|
|
1753
1755
|
});
|
|
1754
1756
|
|
|
1755
1757
|
// node_modules/semver/ranges/to-comparators.js
|
|
1756
|
-
var require_to_comparators = __commonJS((exports, module)
|
|
1758
|
+
var require_to_comparators = __commonJS(function(exports, module) {
|
|
1757
1759
|
var Range = require_range();
|
|
1758
1760
|
var toComparators = (range, options) => new Range(range, options).set.map((comp) => comp.map((c) => c.value).join(" ").trim().split(" "));
|
|
1759
1761
|
module.exports = toComparators;
|
|
1760
1762
|
});
|
|
1761
1763
|
|
|
1762
1764
|
// node_modules/semver/ranges/max-satisfying.js
|
|
1763
|
-
var require_max_satisfying = __commonJS((exports, module)
|
|
1765
|
+
var require_max_satisfying = __commonJS(function(exports, module) {
|
|
1764
1766
|
var SemVer = require_semver();
|
|
1765
1767
|
var Range = require_range();
|
|
1766
1768
|
var maxSatisfying = (versions, range, options) => {
|
|
@@ -1786,7 +1788,7 @@ var require_max_satisfying = __commonJS((exports, module) => {
|
|
|
1786
1788
|
});
|
|
1787
1789
|
|
|
1788
1790
|
// node_modules/semver/ranges/min-satisfying.js
|
|
1789
|
-
var require_min_satisfying = __commonJS((exports, module)
|
|
1791
|
+
var require_min_satisfying = __commonJS(function(exports, module) {
|
|
1790
1792
|
var SemVer = require_semver();
|
|
1791
1793
|
var Range = require_range();
|
|
1792
1794
|
var minSatisfying = (versions, range, options) => {
|
|
@@ -1812,7 +1814,7 @@ var require_min_satisfying = __commonJS((exports, module) => {
|
|
|
1812
1814
|
});
|
|
1813
1815
|
|
|
1814
1816
|
// node_modules/semver/ranges/min-version.js
|
|
1815
|
-
var require_min_version = __commonJS((exports, module)
|
|
1817
|
+
var require_min_version = __commonJS(function(exports, module) {
|
|
1816
1818
|
var SemVer = require_semver();
|
|
1817
1819
|
var Range = require_range();
|
|
1818
1820
|
var gt = require_gt();
|
|
@@ -1866,7 +1868,7 @@ var require_min_version = __commonJS((exports, module) => {
|
|
|
1866
1868
|
});
|
|
1867
1869
|
|
|
1868
1870
|
// node_modules/semver/ranges/valid.js
|
|
1869
|
-
var require_valid2 = __commonJS((exports, module)
|
|
1871
|
+
var require_valid2 = __commonJS(function(exports, module) {
|
|
1870
1872
|
var Range = require_range();
|
|
1871
1873
|
var validRange = (range, options) => {
|
|
1872
1874
|
try {
|
|
@@ -1879,7 +1881,7 @@ var require_valid2 = __commonJS((exports, module) => {
|
|
|
1879
1881
|
});
|
|
1880
1882
|
|
|
1881
1883
|
// node_modules/semver/ranges/outside.js
|
|
1882
|
-
var require_outside = __commonJS((exports, module)
|
|
1884
|
+
var require_outside = __commonJS(function(exports, module) {
|
|
1883
1885
|
var SemVer = require_semver();
|
|
1884
1886
|
var Comparator = require_comparator();
|
|
1885
1887
|
var { ANY } = Comparator;
|
|
@@ -1945,21 +1947,21 @@ var require_outside = __commonJS((exports, module) => {
|
|
|
1945
1947
|
});
|
|
1946
1948
|
|
|
1947
1949
|
// node_modules/semver/ranges/gtr.js
|
|
1948
|
-
var require_gtr = __commonJS((exports, module)
|
|
1950
|
+
var require_gtr = __commonJS(function(exports, module) {
|
|
1949
1951
|
var outside = require_outside();
|
|
1950
1952
|
var gtr = (version, range, options) => outside(version, range, ">", options);
|
|
1951
1953
|
module.exports = gtr;
|
|
1952
1954
|
});
|
|
1953
1955
|
|
|
1954
1956
|
// node_modules/semver/ranges/ltr.js
|
|
1955
|
-
var require_ltr = __commonJS((exports, module)
|
|
1957
|
+
var require_ltr = __commonJS(function(exports, module) {
|
|
1956
1958
|
var outside = require_outside();
|
|
1957
1959
|
var ltr = (version, range, options) => outside(version, range, "<", options);
|
|
1958
1960
|
module.exports = ltr;
|
|
1959
1961
|
});
|
|
1960
1962
|
|
|
1961
1963
|
// node_modules/semver/ranges/intersects.js
|
|
1962
|
-
var require_intersects = __commonJS((exports, module)
|
|
1964
|
+
var require_intersects = __commonJS(function(exports, module) {
|
|
1963
1965
|
var Range = require_range();
|
|
1964
1966
|
var intersects = (r1, r2, options) => {
|
|
1965
1967
|
r1 = new Range(r1, options);
|
|
@@ -1970,7 +1972,7 @@ var require_intersects = __commonJS((exports, module) => {
|
|
|
1970
1972
|
});
|
|
1971
1973
|
|
|
1972
1974
|
// node_modules/semver/ranges/simplify.js
|
|
1973
|
-
var require_simplify = __commonJS((exports, module)
|
|
1975
|
+
var require_simplify = __commonJS(function(exports, module) {
|
|
1974
1976
|
var satisfies = require_satisfies();
|
|
1975
1977
|
var compare = require_compare();
|
|
1976
1978
|
module.exports = (versions, range, options) => {
|
|
@@ -2017,7 +2019,7 @@ var require_simplify = __commonJS((exports, module) => {
|
|
|
2017
2019
|
});
|
|
2018
2020
|
|
|
2019
2021
|
// node_modules/semver/ranges/subset.js
|
|
2020
|
-
var require_subset = __commonJS((exports, module)
|
|
2022
|
+
var require_subset = __commonJS(function(exports, module) {
|
|
2021
2023
|
var Range = require_range();
|
|
2022
2024
|
var Comparator = require_comparator();
|
|
2023
2025
|
var { ANY } = Comparator;
|
|
@@ -2177,7 +2179,7 @@ var require_subset = __commonJS((exports, module) => {
|
|
|
2177
2179
|
});
|
|
2178
2180
|
|
|
2179
2181
|
// node_modules/semver/index.js
|
|
2180
|
-
var require_semver2 = __commonJS((exports, module)
|
|
2182
|
+
var require_semver2 = __commonJS(function(exports, module) {
|
|
2181
2183
|
var internalRe = require_re();
|
|
2182
2184
|
var constants = require_constants();
|
|
2183
2185
|
var SemVer = require_semver();
|
|
@@ -4508,7 +4510,7 @@ var init_operation = __esm(() => {
|
|
|
4508
4510
|
});
|
|
4509
4511
|
|
|
4510
4512
|
// node_modules/@img/colour/color.cjs
|
|
4511
|
-
var require_color = __commonJS((exports, module)
|
|
4513
|
+
var require_color = __commonJS(function(exports, module) {
|
|
4512
4514
|
var __defProp2 = Object.defineProperty;
|
|
4513
4515
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4514
4516
|
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
@@ -6084,7 +6086,7 @@ var require_color = __commonJS((exports, module) => {
|
|
|
6084
6086
|
});
|
|
6085
6087
|
|
|
6086
6088
|
// node_modules/@img/colour/index.cjs
|
|
6087
|
-
var require_colour = __commonJS((exports, module)
|
|
6089
|
+
var require_colour = __commonJS(function(exports, module) {
|
|
6088
6090
|
module.exports = require_color().default;
|
|
6089
6091
|
});
|
|
6090
6092
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sylphx/iris",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"mcpName": "io.github.SylphxAI/iris",
|
|
5
|
-
"description": "Iris
|
|
5
|
+
"description": "Iris — image facts with pixel-level proof. Local-first metadata, OCR boxes, layout, crops, and image diff evidence.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"iris": "./bin/iris"
|
|
@@ -24,22 +24,34 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
27
|
-
"url": "git+https://github.com/SylphxAI/
|
|
27
|
+
"url": "git+https://github.com/SylphxAI/iris.git"
|
|
28
28
|
},
|
|
29
|
-
"homepage": "https://github.
|
|
29
|
+
"homepage": "https://sylphxai.github.io/iris/",
|
|
30
30
|
"keywords": [
|
|
31
31
|
"mcp",
|
|
32
32
|
"model-context-protocol",
|
|
33
33
|
"image",
|
|
34
|
-
"
|
|
34
|
+
"image-analysis",
|
|
35
35
|
"ocr",
|
|
36
|
+
"computer-vision",
|
|
37
|
+
"screenshots",
|
|
38
|
+
"ui-testing",
|
|
39
|
+
"image-diff",
|
|
36
40
|
"metadata",
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
41
|
+
"exif",
|
|
42
|
+
"layout-analysis",
|
|
43
|
+
"crops",
|
|
44
|
+
"pixel-evidence",
|
|
45
|
+
"visual-evidence",
|
|
46
|
+
"local-first",
|
|
47
|
+
"rust",
|
|
48
|
+
"ai-agents",
|
|
49
|
+
"developer-tools",
|
|
50
|
+
"iris",
|
|
51
|
+
"sylphx"
|
|
40
52
|
],
|
|
41
53
|
"engines": {
|
|
42
|
-
"
|
|
54
|
+
"bun": ">=1.4.0"
|
|
43
55
|
},
|
|
44
56
|
"scripts": {
|
|
45
57
|
"build:rust": "cargo build --release -p image-reader-core -p image-reader-cli -p image-reader-mcp-server && bun scripts/stage-rust-mcp.ts",
|
|
@@ -63,7 +75,10 @@
|
|
|
63
75
|
"prepublishOnly": "bun run clean && bun run build && bun run build:rust",
|
|
64
76
|
"release": "bun run typecheck && bun run check && bun run build && bun test && changeset publish",
|
|
65
77
|
"benchmark:public-proof": "bun scripts/public-proof.ts",
|
|
66
|
-
"brand:pack-plan": "bun scripts/brand-pack-plan.ts"
|
|
78
|
+
"brand:pack-plan": "bun scripts/brand-pack-plan.ts",
|
|
79
|
+
"docs:dev": "vitepress dev docs",
|
|
80
|
+
"docs:build": "vitepress build docs",
|
|
81
|
+
"docs:preview": "vitepress preview docs"
|
|
67
82
|
},
|
|
68
83
|
"dependencies": {
|
|
69
84
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
@@ -75,16 +90,17 @@
|
|
|
75
90
|
"@changesets/cli": "^2.31.0",
|
|
76
91
|
"@types/node": "^25.9.1",
|
|
77
92
|
"bunup": "0.16.31",
|
|
78
|
-
"typescript": "^7.0.2"
|
|
93
|
+
"typescript": "^7.0.2",
|
|
94
|
+
"vitepress": "1.6.4"
|
|
79
95
|
},
|
|
80
|
-
"packageManager": "bun@1.
|
|
96
|
+
"packageManager": "bun@1.4.0",
|
|
81
97
|
"private": false,
|
|
82
98
|
"optionalDependencies": {
|
|
83
99
|
"sharp": "^0.35.0",
|
|
84
100
|
"exifr": "^7.1.3",
|
|
85
|
-
"@sylphx/iris-darwin-arm64": "0.
|
|
86
|
-
"@sylphx/iris-darwin-x64": "0.
|
|
87
|
-
"@sylphx/iris-linux-x64-gnu": "0.
|
|
88
|
-
"@sylphx/iris-linux-arm64-gnu": "0.
|
|
101
|
+
"@sylphx/iris-darwin-arm64": "0.3.0",
|
|
102
|
+
"@sylphx/iris-darwin-x64": "0.3.0",
|
|
103
|
+
"@sylphx/iris-linux-x64-gnu": "0.3.0",
|
|
104
|
+
"@sylphx/iris-linux-arm64-gnu": "0.3.0"
|
|
89
105
|
}
|
|
90
106
|
}
|
|
@@ -116,8 +116,9 @@ export const readImage = tool()
|
|
|
116
116
|
const fileStat = await stat(resolvedPath);
|
|
117
117
|
validateImageSafety({ fileSizeBytes: fileStat.size });
|
|
118
118
|
|
|
119
|
+
const profile = input.profile ?? 'fast';
|
|
119
120
|
const includeMetadata = input.include_metadata ?? true;
|
|
120
|
-
const includeOcr = input.include_ocr ??
|
|
121
|
+
const includeOcr = input.include_ocr ?? profile === 'quality';
|
|
121
122
|
const ocrLanguages = input.ocr_languages ?? ['eng'];
|
|
122
123
|
const useRustDecode = shouldUseRustDecodeEngine();
|
|
123
124
|
|
|
@@ -243,7 +244,11 @@ export const readImage = tool()
|
|
|
243
244
|
};
|
|
244
245
|
}
|
|
245
246
|
|
|
246
|
-
|
|
247
|
+
const intelligenceInput =
|
|
248
|
+
profile === 'quality' && input.include_semantics === undefined
|
|
249
|
+
? { ...input, include_semantics: true as const }
|
|
250
|
+
: input;
|
|
251
|
+
twin = await applyImageIntelligence(twin, resolvedPath, intelligenceInput, includeOcr);
|
|
247
252
|
|
|
248
253
|
if (input.region !== undefined) {
|
|
249
254
|
if (!useRustDecode) {
|
package/src/schemas/readImage.ts
CHANGED
|
@@ -20,6 +20,12 @@ export const imageDimensionsSchema = z.object({
|
|
|
20
20
|
|
|
21
21
|
export const readImageArgsSchema = z.object({
|
|
22
22
|
path: z.string().min(1).describe('Path to the local image file (absolute or relative to cwd).'),
|
|
23
|
+
profile: z
|
|
24
|
+
.enum(['fast', 'quality'])
|
|
25
|
+
.optional()
|
|
26
|
+
.describe(
|
|
27
|
+
'Predictable work profile. Fast is deterministic geometry; quality explicitly enables OCR and optional local semantics. '
|
|
28
|
+
),
|
|
23
29
|
include_metadata: z
|
|
24
30
|
.boolean()
|
|
25
31
|
.optional()
|