@liustack/modlens 2.4.1 → 2.4.3

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
@@ -113,6 +113,15 @@ modlens -i <image-path-or-url> [options]
113
113
 
114
114
  Reach for `-m gemini-3.1-pro-high` on dense screenshots or tricky documents. Output contract: [skills/modlens/references/output-schema.md](skills/modlens/references/output-schema.md).
115
115
 
116
+ Two more subcommands: `modlens config <init|set|show>` manages providers and keys (details below), and `modlens recover-paste` rescues images pasted into Claude Code:
117
+
118
+ ```bash
119
+ modlens recover-paste # newest pasted image, path printed as JSON
120
+ modlens recover-paste --count 3 # the three newest
121
+ modlens recover-paste --session <id> # exact session (skills pass ${CLAUDE_SESSION_ID})
122
+ # --transcript <path> overrides everything; --cwd <dir> sets the project directory
123
+ ```
124
+
116
125
  ## Providers and config
117
126
 
118
127
  ModLens ships five vision providers. `antigravity-cli` stays the default: zero keys, pure free quota.
@@ -149,7 +158,7 @@ One catch: once text-only is declared, the Codex TUI **blocks Ctrl+V image paste
149
158
 
150
159
  No setup needed: drag the image file into the terminal, or type its path, and the skill takes over.
151
160
 
152
- Paste is trickier. If you run a text-only model behind `ANTHROPIC_BASE_URL`, Claude Code never writes pasted images to a regular temp file and has no modality switch, so a pasted image reaches the model as a pathless `[Unsupported Image]` placeholder (lenient gateways like DeepSeek's Anthropic endpoint) or breaks the request outright ([#62009](https://github.com/anthropics/claude-code/issues/62009)). But the bytes are not gone: Claude Code appends every user message, images included, to the local session transcript before the gateway ever sees it. That is what `modlens recover-paste` exploits: it pulls the most recent pasted images back out of the transcript and prints real file paths, ready for `modlens -i`. The skill runs this automatically when it spots the placeholder. Transcripts are per-session files. Skills can pass the exact session via `--session` (Claude Code substitutes `${CLAUDE_SESSION_ID}` into skill text since v2.1.9); without it, recovery picks the transcript holding the newest pasted image by message timestamp, so concurrent sessions in the same project do not confuse it either way. One honest caveat: the transcript layout is Claude Code internals with no compatibility promise; if recovery ever breaks, dragging the file still works everywhere.
161
+ Paste is trickier. If you run a text-only model behind `ANTHROPIC_BASE_URL`, Claude Code never writes pasted images to a regular temp file and has no modality switch, so a pasted image reaches the model as a pathless `[Unsupported Image]` placeholder (lenient gateways like DeepSeek's Anthropic endpoint) or breaks the request outright ([#62009](https://github.com/anthropics/claude-code/issues/62009)). But the bytes are not gone: Claude Code appends every user message, images included, to the local session transcript before the gateway ever sees it. That is what `modlens recover-paste` exploits: it pulls the most recent pasted images back out of the transcript and prints real file paths, ready for `modlens -i`. The skill runs this automatically when it spots the placeholder. Verified end to end in a real DeepSeek-gateway Claude Code session: paste an image, the model sees only the placeholder, recovers the file by session id, and answers with full image content. Transcripts are per-session files. Skills can pass the exact session via `--session` (Claude Code substitutes `${CLAUDE_SESSION_ID}` into skill text since v2.1.9); without it, recovery picks the transcript holding the newest pasted image by message timestamp, so concurrent sessions in the same project do not confuse it either way. One honest caveat: the transcript layout is Claude Code internals with no compatibility promise; if recovery ever breaks, dragging the file still works everywhere.
153
162
 
154
163
  ## Why a bridge instead of a multimodal model?
155
164
 
package/README.zh-CN.md CHANGED
@@ -113,6 +113,15 @@ modlens -i <图片路径或 URL> [选项]
113
113
 
114
114
  截图信息密集或文档难啃,换成 `-m gemini-3.1-pro-high`。输出契约见 [skills/modlens/references/output-schema.md](skills/modlens/references/output-schema.md)。
115
115
 
116
+ 另外两个子命令:`modlens config <init|set|show>` 管 provider 和 key(下文详述),`modlens recover-paste` 抢救粘贴进 Claude Code 的图片:
117
+
118
+ ```bash
119
+ modlens recover-paste # 捞最新一张,路径以 JSON 打印
120
+ modlens recover-paste --count 3 # 捞最近三张
121
+ modlens recover-paste --session <id> # 精确会话(skill 会传 ${CLAUDE_SESSION_ID})
122
+ # --transcript <path> 优先级最高,--cwd <dir> 指定项目目录
123
+ ```
124
+
116
125
  ## Provider 与配置
117
126
 
118
127
  ModLens 内置五个视觉 provider,默认还是 `antigravity-cli`:零 key,纯免费额度。
@@ -149,7 +158,7 @@ Codex 只认 Responses API,DeepSeek 官方端点原生支持。先照着[官
149
158
 
150
159
  不用任何配置:把图片文件拖进终端,或手打路径,skill 直接接手。
151
160
 
152
- 粘贴要多说两句。走 `ANTHROPIC_BASE_URL` 网关跑纯文本模型时,Claude Code 粘贴的图片从不写普通临时文件,也没有声明模型无视觉的开关,粘贴的图要么变成一个不带路径的 `[Unsupported Image]` 占位符到达模型(DeepSeek 的 Anthropic 兼容端点这类宽容网关),要么直接把请求搞挂([#62009](https://github.com/anthropics/claude-code/issues/62009))。但图片字节没有蒸发:Claude Code 在网关看到消息之前,就把每条用户消息(含图片)原样写进了本地会话记录。`modlens recover-paste` 干的就是这件事:从会话记录里把最近粘贴的图捞回来,落成真实文件路径,直接喂给 `modlens -i`。skill 看到占位符会自动跑这一步。会话记录本来就是一个会话一个文件。skill 可以通过 `--session` 传入精确会话(Claude Code 从 v2.1.9 起会把 `${CLAUDE_SESSION_ID}` 替换进 skill 文本),不传时按消息时间戳挑「持有最新粘贴图」的那份,两条路都不怕同项目并发多开。一句老实话:会话记录格式是 Claude Code 的内部实现,没有兼容承诺,哪天捞不动了,拖文件永远是保底。
161
+ 粘贴要多说两句。走 `ANTHROPIC_BASE_URL` 网关跑纯文本模型时,Claude Code 粘贴的图片从不写普通临时文件,也没有声明模型无视觉的开关,粘贴的图要么变成一个不带路径的 `[Unsupported Image]` 占位符到达模型(DeepSeek 的 Anthropic 兼容端点这类宽容网关),要么直接把请求搞挂([#62009](https://github.com/anthropics/claude-code/issues/62009))。但图片字节没有蒸发:Claude Code 在网关看到消息之前,就把每条用户消息(含图片)原样写进了本地会话记录。`modlens recover-paste` 干的就是这件事:从会话记录里把最近粘贴的图捞回来,落成真实文件路径,直接喂给 `modlens -i`。skill 看到占位符会自动跑这一步。已在真实的 DeepSeek 网关 Claude Code 会话里端到端验证:粘贴一张图,模型只看到占位符,按会话 ID 捞回文件,带着完整图片内容回答。会话记录本来就是一个会话一个文件。skill 可以通过 `--session` 传入精确会话(Claude Code 从 v2.1.9 起会把 `${CLAUDE_SESSION_ID}` 替换进 skill 文本),不传时按消息时间戳挑「持有最新粘贴图」的那份,两条路都不怕同项目并发多开。一句老实话:会话记录格式是 Claude Code 的内部实现,没有兼容承诺,哪天捞不动了,拖文件永远是保底。
153
162
 
154
163
  ## 为什么外挂,而不是换多模态模型?
155
164
 
package/dist/main.js CHANGED
@@ -982,7 +982,7 @@ function recoverPastedImages(options = {}) {
982
982
  return { transcript, images };
983
983
  }
984
984
  const program = new Command();
985
- program.name("modlens").description("Plug-in vision for text-only LLMs: image in, structured JSON evidence out").version("2.4.1");
985
+ program.name("modlens").description("Plug-in vision for text-only LLMs: image in, structured JSON evidence out").version("2.4.3");
986
986
  program.command("analyze", { isDefault: true }).description("Analyze an image into structured JSON evidence (default command)").requiredOption("-i, --input <path|url>", "Input image path or https URL").option("-o, --output <path>", "Write result JSON to a file").option("-m, --model <name>", "Provider model name").option("-p, --provider <name>", `Vision provider (${listProviders().join(", ")})`).option("--prompt <text>", "Extra focus for this image").option("--timeout <ms>", "Provider timeout in milliseconds", "180000").option("--provider-bin <path>", "Provider binary path (default: agy)").option("--workdir <path>", "Working directory for the provider").action(async (options) => {
987
987
  try {
988
988
  const timeoutMs = Number.parseInt(options.timeout, 10);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liustack/modlens",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "description": "Plug-in vision for text-only LLMs, powered by the free Antigravity CLI",
5
5
  "type": "module",
6
6
  "bin": {