@liustack/modlens 3.7.0 → 3.9.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.
@@ -0,0 +1,33 @@
1
+ # Finding the image path in the chat
2
+
3
+ Harnesses rarely hand you a clean path. Identify which harness you are in, then follow its branch. Never mix branches across harnesses.
4
+
5
+ ## Codex
6
+
7
+ You see a text tag like `<image name=[Image #1] path="/tmp/xxxx.png">`:
8
+
9
+ - Extract the `path` value from the tag and run modlens on it. Pasted images live in a temp file Codex already created; a stripped image keeps its path tag next to the placeholder.
10
+ - Do NOT use `recover-paste` here: it detects Codex and refuses with this same guidance.
11
+
12
+ ## Claude Code with a `[Image: source: <path>]` line
13
+
14
+ Newer Claude Code builds write every pasted image to `~/.claude/image-cache/<session-id>/` and, in the terminal (`cli`) entrypoint, inject that line as a user message. Undocumented internal behavior (observed on 2.1.201 through 2.1.231; the VSCode and desktop entrypoints do not inject it), so treat it as a shortcut, not a guarantee.
15
+
16
+ - If the file at that path exists, run modlens on it directly and skip `recover-paste`. The file is Claude Code's own cache: read it, never delete or move it.
17
+ - If the path is gone (the cache is cleaned after a while) or there is no such line, fall through to the next branch.
18
+
19
+ ## Claude Code, Pi, or OpenCode (no usable path anywhere)
20
+
21
+ The image reads as `[Unsupported Image]`, a bare `[Image #1]`, or an attachment you simply cannot see. Whatever a gateway strips from the request, these harnesses persist user messages, image bytes included, in local session storage first: Claude Code and Pi in session JSONL files (`~/.claude/projects/`, `~/.pi/agent/sessions/`), OpenCode in a SQLite database (`~/.local/share/opencode/opencode.db`, read via node:sqlite, needs Node 22.5+; Bun cannot load node:sqlite, so a bunx-resolved launcher needs a real Node install for OpenCode recovery).
22
+
23
+ - Run `modlens recover-paste` from the project directory the conversation is happening in (`--count <n>` for several images). It detects which harness it is running inside and reads ONLY that harness's storage. In Claude Code it targets your exact session automatically via the injected `CLAUDE_CODE_SESSION_ID`; `--session <id>` is only needed to override.
24
+ - The output is JSON with real file paths, oldest to newest, so the LAST path is the most recent paste: analyze that one first. Entries carry `filename` when the harness stored one; match on it when the user's message mentions a name.
25
+ - Run every command yourself, never ask the user to run modlens or relay paths.
26
+ - When the analysis is done, delete the recovery output directory (each entry's `path` sits inside it): the files are private copies of the user's pastes, and nothing else cleans them up. Keep them only if the user asked.
27
+ - If the output's `detected` field is absent, detection failed and every store was scanned: check `harness` and `filename` match what you expect, force `--harness <claude-code|pi|opencode>` if not, and when in doubt ask the user for the file instead of describing the wrong image.
28
+ - Recovery is scoped to this project (the harness's own record of its working directory is checked), and recovered files are private to the user (0600).
29
+ - If recovery fails, ask the user to drag the image file into the terminal or type its path.
30
+
31
+ ## Any other harness, or nothing matches
32
+
33
+ No path tag and `recover-paste` reports no transcripts: do not guess. Ask the user for the image file path, or suggest dragging the file into the terminal.
@@ -0,0 +1,51 @@
1
+ # First run on this machine: inventory, ask, then configure
2
+
3
+ Run this flow when `~/.modlens/config.json` does not exist, or `modlens config show` prints an empty config (`{"providers":{}}` with no `reuse` decisions). That check makes the flow idempotent: a machine that has been through it is never re-onboarded, and an existing config is never overwritten without the user asking for a change. The user can also request it by name ("set up modlens").
4
+
5
+ ## 1. Inventory, spending nothing
6
+
7
+ ```bash
8
+ modlens doctor --json
9
+ ```
10
+
11
+ Read three things from the report: which providers are `ready`, the Reuse section (per-harness decisions plus discovered logins and vision models; the harness this conversation runs inside is itself the first reusable engine), and the guard state. Doctor spends no quota and makes no network calls.
12
+
13
+ ## 2. Tell the user what their machine already has
14
+
15
+ One line per finding, plain words, in the user's language. Name concrete things, not concepts:
16
+
17
+ - An engine is ready: "modlens is ready to go: <provider> is configured (via <env var / config file / existing login>)."
18
+ - Reusable vision found: "Your <harness> CLI is signed in and its model can read images. modlens can reuse it when needed, about <n> seconds per read, and it spends that account's quota."
19
+ - Nothing at all: "No vision engine is set up yet. The fastest free option is a Gemini API key (three minutes, no card); Antigravity CLI works with no sign-up at all."
20
+
21
+ Do not dump the raw doctor output on the user; summarize it. Do not describe options the machine does not have.
22
+
23
+ ## 3. Ask before touching anything
24
+
25
+ Consent rules:
26
+
27
+ - One question per decision, never a bundled yes. Reusing Codex and reusing pi credentials are two questions (or one question with independent options), not one.
28
+ - Each question names the harness, whose quota it spends, and the accounting promise. Example wording: "Allow modlens to reuse your signed-in Codex CLI for image reads? Every reused read is labeled in the result so you always see whose quota was spent."
29
+ - The do-nothing outcome must be safe and stated: "If you skip this, modlens just uses the engines you configure yourself."
30
+ - If the user offers an API key, take exactly that key; never go looking for keys they did not hand over.
31
+
32
+ ## 4. Apply only what was consented to
33
+
34
+ | The user agreed to | Run |
35
+ | :-- | :-- |
36
+ | Reusing a harness CLI | `modlens config set reuse.<claude\|codex\|opencode\|pi\|grok> true` (one per consent) |
37
+ | A Gemini key they handed over | `modlens config set gemini-api.apiKey <key>` |
38
+ | An OpenAI-compatible endpoint | `config set openai.baseUrl / openai.apiKey / openai.model` |
39
+ | Guard rules for their text-only model | `modlens config set guards.allowModels '["<pattern>"]'` (patterns: `references/configure.md`) |
40
+
41
+ A refusal is also an answer: record it with `modlens config set reuse.<harness> false` so the user is never asked again. Nothing decided at all: write nothing and stop.
42
+
43
+ ## 5. Close the loop
44
+
45
+ Run `modlens doctor` once more and report in one or two sentences: what was written (always and only `~/.modlens/config.json`), what the chain now looks like, and the undo (`modlens config set reuse.<harness> false`, or editing that file). If an engine is ready, offer to prove it on a real image.
46
+
47
+ ## Never
48
+
49
+ - Never set any `reuse.<harness>` to true without an explicit yes for that harness in this conversation.
50
+ - Never write, move, or read files outside `~/.modlens/` during onboarding (doctor's read-only probing is the one exception).
51
+ - Never present reusing another login as free: it spends the named account's quota, and the wording must say so.
@@ -8,7 +8,7 @@ shell syntax.
8
8
 
9
9
  ## Pinned version
10
10
 
11
- - Pinned CLI version: 3.7.0
11
+ - Pinned CLI version: 3.9.0
12
12
  - npm package: `@liustack/modlens`
13
13
  - CLI binary name: `modlens`
14
14
 
@@ -24,7 +24,7 @@ $ErrorActionPreference = 'Stop'
24
24
  # package.json version, and the release script rewrites it on every bump.
25
25
  $Package = '@liustack/modlens'
26
26
  $Bin = 'modlens'
27
- $Pinned = '3.7.0'
27
+ $Pinned = '3.9.0'
28
28
  # -------------------------------------------------------------------------------
29
29
 
30
30
  $NativeNote = 'no native artifact is published for this tool yet; phase A ships npm launch paths only'
@@ -22,7 +22,7 @@ set -eu
22
22
  # package.json version, and the release script rewrites it on every bump.
23
23
  PKG="@liustack/modlens"
24
24
  BIN="modlens"
25
- PINNED="3.7.0"
25
+ PINNED="3.9.0"
26
26
  # -------------------------------------------------------------------------------
27
27
 
28
28
  NATIVE_NOTE="no native artifact is published for this tool yet; phase A ships npm launch paths only"