@liustack/modlens 3.12.1 → 3.13.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/dsh/index.js CHANGED
@@ -297,21 +297,47 @@ function abortableWait(promise, signal) {
297
297
  })
298
298
  }
299
299
 
300
+ /**
301
+ * Image blocks hide at two depths: top-level message content (pastes), and
302
+ * inside tool-result content (dsh's own read_image tool nests one there).
303
+ * The upstream adapter's rejection check recurses (issue #24), so the
304
+ * conversion must recurse the same way or a nested image wedges the session
305
+ * permanently — the durable log keeps the real block, and every later turn
306
+ * re-fails on it.
307
+ */
308
+ function contentHasImage(blocks) {
309
+ return (
310
+ Array.isArray(blocks) &&
311
+ blocks.some(
312
+ (b) => b?.type === 'image' || (b?.type === 'tool-result' && contentHasImage(b.content)),
313
+ )
314
+ )
315
+ }
316
+
317
+ async function convertBlocks(blocks, convertOne) {
318
+ const out = []
319
+ for (const block of blocks) {
320
+ if (block?.type === 'image') {
321
+ out.push(await convertOne(block))
322
+ } else if (block?.type === 'tool-result' && contentHasImage(block.content)) {
323
+ out.push({ ...block, content: await convertBlocks(block.content, convertOne) })
324
+ } else {
325
+ out.push(block)
326
+ }
327
+ }
328
+ return out
329
+ }
330
+
300
331
  async function convertImagesToEvidence(ctx, messages, signal, adapter) {
301
332
  const out = []
302
333
  for (const message of messages) {
303
- if (!Array.isArray(message.content) || !message.content.some((b) => b?.type === 'image')) {
334
+ if (!contentHasImage(message.content)) {
304
335
  out.push(message)
305
336
  continue
306
337
  }
307
- const content = []
308
- for (const block of message.content) {
309
- if (block?.type !== 'image') {
310
- content.push(block)
311
- continue
312
- }
313
- content.push(await abortableWait(cachedEvidence(ctx, adapter, block), signal))
314
- }
338
+ const content = await convertBlocks(message.content, (block) =>
339
+ abortableWait(cachedEvidence(ctx, adapter, block), signal),
340
+ )
315
341
  out.push({ ...message, content })
316
342
  }
317
343
  return out
@@ -331,28 +357,19 @@ function registerAutoRead(ctx) {
331
357
  if (decision.kind !== 'enter') {
332
358
  return decision
333
359
  }
334
- const hasImage = decision.messages.some(
335
- (message) =>
336
- Array.isArray(message.content) &&
337
- message.content.some((block) => block?.type === 'image'),
338
- )
339
- if (!hasImage) {
360
+ if (!decision.messages.some((message) => contentHasImage(message.content))) {
340
361
  return decision
341
362
  }
342
363
  const messages = []
343
364
  for (const message of decision.messages) {
344
- if (!Array.isArray(message.content)) {
365
+ if (!contentHasImage(message.content)) {
345
366
  messages.push(message)
346
367
  continue
347
368
  }
348
- const content = []
349
- for (const block of message.content) {
350
- if (block?.type !== 'image') {
351
- content.push(block)
352
- continue
353
- }
354
- content.push((await readImageBlock(ctx, block, payload.signal)).block)
355
- }
369
+ const content = await convertBlocks(
370
+ message.content,
371
+ async (block) => (await readImageBlock(ctx, block, payload.signal)).block,
372
+ )
356
373
  messages.push({ ...message, content })
357
374
  }
358
375
  return { kind: 'enter', messages }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liustack/modlens",
3
- "version": "3.12.1",
3
+ "version": "3.13.0",
4
4
  "description": "Plug-in vision for text-only LLMs, powered by the free Antigravity CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -53,7 +53,7 @@
53
53
  },
54
54
  "homepage": "https://github.com/liustack/modlens#readme",
55
55
  "engines": {
56
- "node": ">=22.13"
56
+ "node": ">=22.19"
57
57
  },
58
58
  "dependencies": {
59
59
  "commander": "^13.1.0",
@@ -20,12 +20,12 @@ powershell -ExecutionPolicy Bypass -File <skill-dir>\scripts\run.ps1 <args>
20
20
 
21
21
  It resolves a working runtime (PATH `modlens`, then `npx`, then `bunx`) and forwards your arguments unchanged. Exit 78 means no runtime: relay the `nextSteps` from its stderr JSON instead of retrying.
22
22
 
23
- If your harness forbids running scripts, reason through the same order by hand and run the first line that works (the pinned version is 3.12.1):
23
+ If your harness forbids running scripts, reason through the same order by hand and run the first line that works (the pinned version is 3.13.0):
24
24
 
25
- 1. A `modlens` on `PATH` whose major version is 3 and is at least 3.12.1: `modlens <args>`.
26
- 2. Otherwise, if `npx` exists: `npx --yes --package @liustack/modlens@3.12.1 modlens <args>`.
27
- 3. Otherwise, if `bunx` exists: `bunx --bun @liustack/modlens@3.12.1 <args>`.
28
- 4. Otherwise tell the user no JavaScript runtime was found and that installing Node 22.13+ (https://nodejs.org) or Bun (https://bun.sh) is the next step. Do not claim modlens itself failed.
25
+ 1. A `modlens` on `PATH` whose major version is 3 and is at least 3.13.0: `modlens <args>`.
26
+ 2. Otherwise, if `npx` exists: `npx --yes --package @liustack/modlens@3.13.0 modlens <args>`.
27
+ 3. Otherwise, if `bunx` exists: `bunx --bun @liustack/modlens@3.13.0 <args>`.
28
+ 4. Otherwise tell the user no JavaScript runtime was found and that installing Node 22.19+ (https://nodejs.org) or Bun (https://bun.sh) is the next step. Do not claim modlens itself failed.
29
29
 
30
30
  `references/runtime.md` documents the pin and the diagnostic fields.
31
31
 
@@ -8,7 +8,7 @@ shell syntax.
8
8
 
9
9
  ## Pinned version
10
10
 
11
- - Pinned CLI version: 3.12.1
11
+ - Pinned CLI version: 3.13.0
12
12
  - npm package: `@liustack/modlens`
13
13
  - CLI binary name: `modlens`
14
14
 
@@ -22,7 +22,7 @@ launcher/reference copies ever drift from `package.json`.
22
22
  Each call resolves a way to run the CLI, in this order:
23
23
 
24
24
  1. **A compatible `modlens` already on `PATH`** — run it directly, by name.
25
- 2. **`npx` present, and `node` meets the CLI's 22.13 floor** — `npx --yes --package @liustack/modlens@<pinned> modlens <args>`. An npx sitting on an older node is skipped: it would select a path known to fail at run time.
25
+ 2. **`npx` present, and `node` meets the CLI's 22.19 floor** — `npx --yes --package @liustack/modlens@<pinned> modlens <args>`. An npx sitting on an older node is skipped: it would select a path known to fail at run time.
26
26
  3. **`bunx` present** — `bunx --bun @liustack/modlens@<pinned> <args>`.
27
27
  4. **A native artifact** — reserved for phase B. None is published yet, so this
28
28
  branch reports `nativeArtifact.available: false` and moves on.
@@ -70,13 +70,13 @@ would have set.
70
70
  - `checked.pathCli` — `{ present, path, version, compatible }` for a `modlens`
71
71
  on `PATH`, with `compatible` applying the rule above.
72
72
  - `checked.npx` — `{ present, path, nodeMeetsFloor }`; `nodeMeetsFloor` is whether
73
- the local node satisfies the CLI's 22.13 floor, required for the npx path.
73
+ the local node satisfies the CLI's 22.19 floor, required for the npx path.
74
74
  - `checked.bunx` — `{ present, path }`.
75
75
  - `checked.node` — `{ present, version }`.
76
76
  - `nativeArtifact` — `{ available, note }`; `available` is `false` in phase A.
77
77
  - `selected` — the resolved path: `path`, `npx`, `bunx`, or `none`.
78
78
  - `nextSteps` — when `selected` is `none`, one or two plain-language actions for
79
- the user (install Node 22.13+, or Bun); empty otherwise.
79
+ the user (install Node 22.19+, or Bun); empty otherwise.
80
80
  - `cliDoctor` — when a CLI is resolvable, the CLI's own `doctor --json` report
81
81
  (provider, config, and harness diagnosis) is nested here; `null` otherwise.
82
82
 
@@ -87,8 +87,9 @@ first time (that is how those runners work); after that it is served from the
87
87
  local cache.
88
88
 
89
89
  One capability note for the bunx path: Bun cannot load `node:sqlite`, which
90
- OpenCode paste recovery needs, so on a machine where the launcher resolved to
91
- bunx, `recover-paste` for OpenCode requires installing Node 22.13+ instead.
90
+ OpenCode paste recovery needs (unflagged in Node since 22.13), so on a machine
91
+ where the launcher resolved to bunx, `recover-paste` for OpenCode requires a
92
+ real Node install — 22.19+, since that is the floor this launcher accepts.
92
93
 
93
94
  ## Delivery form: local CLI, long term
94
95
 
@@ -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.12.1'
27
+ $Pinned = '3.13.0'
28
28
  # -------------------------------------------------------------------------------
29
29
 
30
30
  $NativeNote = 'no native artifact is published for this tool yet; phase A ships npm launch paths only'
@@ -72,7 +72,7 @@ function Test-Compatible {
72
72
  # The npx path runs the CLI on this machine's node, so npx is only usable when
73
73
  # node itself meets the CLI's floor. An old node with a working npx used to be
74
74
  # selected anyway, a path known to fail at run time.
75
- $NodeFloor = '22.13.0'
75
+ $NodeFloor = '22.19.0'
76
76
  function Test-NodeMeetsFloor {
77
77
  if (-not (Get-Command node -ErrorAction SilentlyContinue)) { return $false }
78
78
  try { $nv = ((& node --version 2>$null) -replace '^v', '') } catch { return $false }
@@ -165,7 +165,7 @@ function Build-DiagnosisJson {
165
165
  $steps = @()
166
166
  if ($script:Selected -eq 'none') {
167
167
  $major = $Pinned.Split('.')[0]
168
- $first = "Install Node 22.13+ from https://nodejs.org so npx can run $Package@$Pinned, then re-run this launcher."
168
+ $first = "Install Node 22.19+ from https://nodejs.org so npx can run $Package@$Pinned, then re-run this launcher."
169
169
  if ($script:NpxPresent -and (-not $script:NodeFloorOk)) {
170
170
  $first = "npx is present but node $(if ($script:NodeVer) { $script:NodeVer } else { 'missing' }) is below the $NodeFloor floor this CLI needs. Upgrade Node at https://nodejs.org, then re-run this launcher."
171
171
  }
@@ -215,7 +215,7 @@ function Write-DiagnosisText {
215
215
  Write-Output ''
216
216
  Write-Output ("No runtime can launch {0} here. {1}" -f $Bin, $NativeNote)
217
217
  Write-Output 'Next steps:'
218
- Write-Output ' - Install Node 22.13+ from https://nodejs.org, then re-run this launcher.'
218
+ Write-Output ' - Install Node 22.19+ from https://nodejs.org, then re-run this launcher.'
219
219
  Write-Output (" - Or install Bun from https://bun.sh, or put a compatible {0} on PATH." -f $Bin)
220
220
  }
221
221
  }
@@ -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.12.1"
25
+ PINNED="3.13.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"
@@ -70,7 +70,7 @@ cli_version() {
70
70
  # The npx path runs the CLI on this machine's node, so npx is only usable when
71
71
  # node itself meets the CLI's floor. An old node with a working npx used to be
72
72
  # selected anyway, a path known to fail at run time.
73
- NODE_FLOOR="22.13.0"
73
+ NODE_FLOOR="22.19.0"
74
74
  node_meets_floor() {
75
75
  command -v node >/dev/null 2>&1 || return 1
76
76
  _nv="$(node --version 2>/dev/null | sed 's/^v//')"
@@ -189,7 +189,7 @@ compute_next_steps() {
189
189
  if [ "$G_NPX_PRESENT" = 1 ] && [ "$G_NODE_FLOOR_OK" = 0 ]; then
190
190
  _s1="npx is present but node ${G_NODE_VER:-missing} is below the $NODE_FLOOR floor this CLI needs. Upgrade Node at https://nodejs.org, then re-run this launcher."
191
191
  else
192
- _s1="Install Node 22.13+ from https://nodejs.org so npx can run $PKG@$PINNED, then re-run this launcher."
192
+ _s1="Install Node 22.19+ from https://nodejs.org so npx can run $PKG@$PINNED, then re-run this launcher."
193
193
  fi
194
194
  _s2="No JavaScript runtime? Install Bun from https://bun.sh to use bunx, or put a compatible $BIN (major ${PINNED%%.*}, at or above $PINNED) on PATH."
195
195
  G_NEXTSTEPS="$(printf '"%s", "%s"' "$(json_escape "$_s1")" "$(json_escape "$_s2")")"
@@ -255,7 +255,7 @@ emit_text() {
255
255
  if [ "$G_SEL" = "none" ]; then
256
256
  printf '\nNo runtime can launch %s here. %s\n' "$BIN" "$NATIVE_NOTE"
257
257
  printf 'Next steps:\n'
258
- printf ' - Install Node 22.13+ from https://nodejs.org, then re-run this launcher.\n'
258
+ printf ' - Install Node 22.19+ from https://nodejs.org, then re-run this launcher.\n'
259
259
  printf ' - Or install Bun from https://bun.sh, or put a compatible %s on PATH.\n' "$BIN"
260
260
  fi
261
261
  }