@liustack/modlens 3.26.2 → 3.26.4
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/CHANGELOG.md +9 -0
- package/README.md +2 -2
- package/README.zh-CN.md +3 -3
- package/dist/main.js +2 -2
- package/docs/harness-setup.md +4 -3
- package/docs/harness-setup.zh-CN.md +3 -3
- package/docs/troubleshooting.md +2 -2
- package/docs/troubleshooting.zh-CN.md +2 -2
- package/dsh/client.js +30 -13
- package/dsh/index.js +8 -1
- package/package.json +1 -1
- package/skills/modlens/SKILL.md +4 -4
- package/skills/modlens/references/runtime.md +1 -1
- package/skills/modlens/scripts/run.ps1 +1 -1
- package/skills/modlens/scripts/run.sh +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.26.4 - 2026-09-24
|
|
4
|
+
|
|
5
|
+
- **dsh 0.1.7: the config card lives on the Plugins page ([#113](https://github.com/liustack/modlens/issues/113)).** dsh 0.1.7 removed `settings.register` and moved plugin configuration out of Settings onto the sidebar's Plugins page. The host half still called `register` without checking, so every boot logged `settings namespace skipped: TypeError`, and the card was gone because nothing rendered the old `settings.plugin.item` slot anymore. The host half now skips the namespace where the settings service has no `register`, and the browser half also registers the card in `plugins.bundle.config` under the package name, so on 0.1.7 the form shows on the `@liustack/modlens` page under Installed. There the page draws the title itself, so the card renders as the bare form, open from the start. Hosts before 0.1.7 keep the Settings card unchanged, and each host only declares one of the two slots, so the card never shows twice. Verified in the browser on dsh 0.1.7-rc.1. Thanks to @The-five-stooges.
|
|
6
|
+
|
|
7
|
+
## 3.26.3 - 2026-09-23
|
|
8
|
+
|
|
9
|
+
- **dsh: CJK evidence no longer turns into replacement characters ([#110](https://github.com/liustack/modlens/issues/110)).** The plugin's child-process runner appended each stdout chunk to a string, which decodes every chunk on its own, so a multi-byte character split across two pipe chunks came out as replacement characters (U+FFFD). The result still parsed as JSON, so both vision paths (the `modlens_read_image` tool and the paste conversion) could hand the model damaged transcription text with no error anywhere. Dense Chinese OCR output crosses the pipe's chunk size routinely. The runner now decodes stdout and stderr as one UTF-8 stream, the same fix the CLI's own children got earlier, and a regression test drives a fake CLI that cuts a character in half between two writes. Thanks to @nanami-0713.
|
|
10
|
+
- **dsh: one failed image no longer loses the rest of a multi-image paste ([#111](https://github.com/liustack/modlens/issues/111)).** Paste-to-path uploaded all images with `Promise.all`, so a single failure (a 413 on an oversized image, a network error) threw away the paths of the images that had already landed, and the native paste was gone too because the event had been taken. Each upload now settles on its own: the landed paths are inserted, each failure is logged, and a 404 or 403 on any of them still stands the client down as before. Thanks to @nanami-0713.
|
|
11
|
+
|
|
3
12
|
## 3.26.2 - 2026-09-19
|
|
4
13
|
|
|
5
14
|
- **dsh: `/modlens/paste` answers same-origin loopback only ([#107](https://github.com/liustack/modlens/issues/107)).** The paste route wrote to disk and disclosed the takeover verdict without the fence `/modlens/config` already had, so a page rebound onto loopback, or a cross-site page on the same machine, could plant a file in the paste store and, by repeating it, push the store over its ceiling and sweep away pastes a live session still had to read. Both branches now run the same `isTrustedRequest` check as the config route: a non-loopback Host, `Sec-Fetch-Site: cross-site`, or an Origin that does not match the Host is refused with 403 and nothing is written. The client treats that 403 like a 404 and stands down for the page, so a refused paste goes native at once instead of being taken and lost for the rest of the verdict window; the settings card does the same and does not mount. The refusal line is one shared constant, and both routes' tests assert it. A dsh opened over a LAN address loses paste-to-path and the settings card, which is the config route's existing behavior. Thanks to @nanami-0713 for the report.
|
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ Issues are welcome any time: [open one](https://github.com/liustack/modlens/issu
|
|
|
33
33
|
|
|
34
34
|
## Highlights
|
|
35
35
|
|
|
36
|
-
**🥇 The most capable vision plugin for DeepSeek Harness (dsh):** install it instantly with one command: `npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.
|
|
36
|
+
**🥇 The most capable vision plugin for DeepSeek Harness (dsh):** install it instantly with one command: `npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.4`. See the [setup guide](docs/harness-setup.md) for installation and update details. If the command line is not your thing but you still want to try DSH, check out <a href="https://github.com/liustack/aimanager"><b>AIManager</b></a>, the lightest desktop wrapper for DeepSeek Harness. It gets you started with zero code or configuration and installs every dependency for you with one click.
|
|
37
37
|
|
|
38
38
|
Pasting an image works two ways. **① Just paste.** On a text-only model the pasted image lands as a private temp file and its path enters the composer (the same interaction OpenCode and Pi ship), then the `modlens_read_image` tool takes it from there. **② Pick a `(modlens vision)` entry** in the model selector (it remembers your choice, so once is enough), then paste: the thumbnail stays visible in your message, closer to the Codex app feel, and the image is converted to structured evidence at request time, answered by the same underlying route. The plugin auto-discovers every provider route carrying eligible text-only DeepSeek, GLM, or MiMo Pro models and adds a wrapped entry per route. A stock install gets **`DeepSeek-V4-Flash (modlens vision)`** and **`DeepSeek-V4-Pro (modlens vision)`**, while extra routes like opencode-go or zai get their own. Native vision models in those families, including GLM-5.3-Flash, are excluded automatically. Which paste route applies is the host's per-model call: only a model its metadata positively confirms text-only is taken over, anything unconfirmed is left alone, so vision models keep their native paste ([details](docs/harness-setup.md)).
|
|
39
39
|
|
|
@@ -73,7 +73,7 @@ agy # sign in, then ex
|
|
|
73
73
|
|
|
74
74
|
The install also inventories vision reachable through your other local harness CLIs (Codex, OpenCode, Pi) and asks, per harness, whether modlens may reuse it. Granted logins join the engine pool as equals, and every reused read is labeled with whose quota it spent.
|
|
75
75
|
|
|
76
|
-
On DeepSeek Harness the command line is not the only way in. Settings → Plugins → Plugin config carries a ModLens card: switch the engine, tick which local CLIs `auto` mode may reuse, hit save and it takes effect.
|
|
76
|
+
On DeepSeek Harness the command line is not the only way in. Settings → Plugins → Plugin config carries a ModLens card (from dsh 0.1.7 on, open the sidebar's Plugins page and pick `@liustack/modlens` under Installed): switch the engine, tick which local CLIs `auto` mode may reuse, hit save and it takes effect.
|
|
77
77
|
|
|
78
78
|

|
|
79
79
|
|
package/README.zh-CN.md
CHANGED
|
@@ -33,7 +33,7 @@ DeepSeek 的主力对话模型和 GLM-5.3 本体仍是纯文本,无法读图
|
|
|
33
33
|
|
|
34
34
|
## 亮点
|
|
35
35
|
|
|
36
|
-
**🥇 全网最强的 DeepSeek Harness(dsh)外挂视觉识别插件:**一条命令即刻安装 `npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.
|
|
36
|
+
**🥇 全网最强的 DeepSeek Harness(dsh)外挂视觉识别插件:**一条命令即刻安装 `npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.4`。更多安装与更新细节参考 [配置手册](docs/harness-setup.zh-CN.md) 。如果用不惯命令行,也想想玩玩 DSH,推荐食用全网最轻量级的 DeepSeek Harness 桌面版封装 <a href="https://github.com/liustack/aimanager"><b> AIManager</b></a>,零代码零配置起手,一键帮你安装所有依赖环境。
|
|
37
37
|
|
|
38
38
|
DeepSeek Harness 粘贴识图有两种玩法。
|
|
39
39
|
|
|
@@ -80,12 +80,12 @@ agy # 浏览器完成
|
|
|
80
80
|
**DeepSeek Harness(dsh)用户不走 skill 流程**,本包就是原生 dsh 插件:
|
|
81
81
|
|
|
82
82
|
```sh
|
|
83
|
-
npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.
|
|
83
|
+
npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.4
|
|
84
84
|
```
|
|
85
85
|
|
|
86
86
|
装完即有 `modlens_read_image` 工具,选「(modlens vision)」模型变体即可直接粘贴识图。引擎配置同样在 `~/.modlens`,详见[宿主接入](docs/harness-setup.zh-CN.md)。
|
|
87
87
|
|
|
88
|
-
命令行不是唯一入口。dsh 设置页的「插件 → 插件配置」里有一张 ModLens
|
|
88
|
+
命令行不是唯一入口。dsh 设置页的「插件 → 插件配置」里有一张 ModLens 卡片(dsh 0.1.7 起改到侧栏的「插件」页,在「已安装」里点开 `@liustack/modlens`):切换引擎,勾选 auto 模式可以复用本机哪些 CLI,在网页上点几下保存就生效。
|
|
89
89
|
|
|
90
90
|

|
|
91
91
|
|
package/dist/main.js
CHANGED
|
@@ -5562,7 +5562,7 @@ function parsePositiveInt(raw, flag) {
|
|
|
5562
5562
|
}
|
|
5563
5563
|
return Number.parseInt(raw, 10);
|
|
5564
5564
|
}
|
|
5565
|
-
program.name("modlens").description("Plug-in vision for text-only LLMs: image in, structured JSON evidence out").version("3.26.
|
|
5565
|
+
program.name("modlens").description("Plug-in vision for text-only LLMs: image in, structured JSON evidence out").version("3.26.4");
|
|
5566
5566
|
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").option(
|
|
5567
5567
|
"--extra-body <json>",
|
|
5568
5568
|
`JSON merged into the API request body, e.g. '{"thinking":{"type":"disabled"}}'`
|
|
@@ -5673,7 +5673,7 @@ program.command("doctor").description(
|
|
|
5673
5673
|
configPath: CONFIG_PATH,
|
|
5674
5674
|
// Lets doctor name an installed skill copy that is older than
|
|
5675
5675
|
// the CLI reporting on it (issue #33).
|
|
5676
|
-
version: "3.26.
|
|
5676
|
+
version: "3.26.4"
|
|
5677
5677
|
});
|
|
5678
5678
|
const output = options.json ? JSON.stringify(report, null, 2) : renderDoctorReport(report);
|
|
5679
5679
|
process.stdout.write(`${output}
|
package/docs/harness-setup.md
CHANGED
|
@@ -55,7 +55,7 @@ OpenCode with DeepSeek: `opencode auth login`, pick DeepSeek and paste the key (
|
|
|
55
55
|
dsh is different from the other harnesses: modlens plugs in as a native tool, not a prompt-triggered skill. The package itself is a dsh bundle, so one command installs it into a profile:
|
|
56
56
|
|
|
57
57
|
```sh
|
|
58
|
-
npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.
|
|
58
|
+
npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.4
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
This registers a `modlens_read_image` tool whose schema reaches the model on every request (no trigger heuristics), runs the modlens CLI shipped inside the same package, and returns the structured evidence as the tool's canonical JSON output. Engines, reuse grants, and guard rules stay in `~/.modlens/config.json`, shared with every other harness. dsh is in developer preview and its plugin surface may change; the plugin keeps its touch small (raw tool registration, the llm adapter surface for the vision variants, the attachment reader, and one agent pre-step hook) and degrades loudly if any of them moves.
|
|
@@ -112,7 +112,8 @@ profile, the actual model ID rather than its display name, any `upstream` or
|
|
|
112
112
|
### Configuring the engine from the web UI
|
|
113
113
|
|
|
114
114
|
dsh web users have no terminal in front of them, so the engine settings have a
|
|
115
|
-
card in **Settings → Plugins → Plugin configuration
|
|
115
|
+
card in **Settings → Plugins → Plugin configuration** (from dsh 0.1.7 on, the
|
|
116
|
+
sidebar's **Plugins** page, under `@liustack/modlens` in **Installed**): which engine reads
|
|
116
117
|
images, its key, endpoint, model and proxy route, and which local sign-ins a read may
|
|
117
118
|
borrow. Expanding it probes this machine and lists the harnesses it actually
|
|
118
119
|
found, so the grants are a choice between real options rather than five names.
|
|
@@ -137,7 +138,7 @@ modlens ships often, and both install shapes freeze at whatever version they
|
|
|
137
138
|
got. On dsh, re-run the install with the version named:
|
|
138
139
|
|
|
139
140
|
```sh
|
|
140
|
-
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.
|
|
141
|
+
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.4
|
|
141
142
|
```
|
|
142
143
|
|
|
143
144
|
`npm view @liustack/modlens version` prints the current one, and this page is
|
|
@@ -55,7 +55,7 @@ OpenCode 接 DeepSeek:执行 `opencode auth login`,选择 DeepSeek 并粘贴
|
|
|
55
55
|
dsh 与其他 harness 不同:modlens 以原生工具的形式接入,而不是靠提示词触发的 skill。本包自身就是一个 dsh bundle,一条命令即可装进某个 profile:
|
|
56
56
|
|
|
57
57
|
```sh
|
|
58
|
-
npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.
|
|
58
|
+
npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@3.26.4
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
这会注册一个 `modlens_read_image` 工具,它的 schema 随每次请求抵达模型(不靠触发启发式),运行同一个包里自带的 modlens CLI,并把结构化证据作为工具的标准 JSON 输出返回。引擎、复用授权和 guard 规则仍在 `~/.modlens/config.json` 里,与其他所有 harness 共享。dsh 还在开发者预览阶段,插件接口可能变化。这个插件刻意保持很小的接触面(原生工具注册、视觉变体所用的 llm 适配层、附件读取器,以及一个 agent 执行前钩子),其中任何一处变动,它都会大声报错而不是无声退化。
|
|
@@ -105,7 +105,7 @@ npx -y @deepseek-ai/dsh --profile <name> --dump-config
|
|
|
105
105
|
|
|
106
106
|
### 在网页界面里配置引擎
|
|
107
107
|
|
|
108
|
-
dsh 的网页用户面前没有终端,所以引擎设置有一张卡片,在**设置 → 插件 →
|
|
108
|
+
dsh 的网页用户面前没有终端,所以引擎设置有一张卡片,在**设置 → 插件 → 插件配置**里(dsh 0.1.7 起改到侧栏的**插件**页,在**已安装**里点开 `@liustack/modlens`):用哪个引擎读图、它的密钥、地址、模型和代理方式,以及一次读取可以借用本机哪些已有登录。展开时会探测本机,只列出真正找到的 harness,让授权是在真实选项之间做选择,而不是面对五个名字。
|
|
109
109
|
|
|
110
110
|
这些值仍然住在 `~/.modlens/config.json`,与其他所有 harness 共享:卡片通过一条回环路由读写那个文件,所以在这里改一笔,和 `modlens config set` 改的是同一笔。卡片从不拿到已保存的密钥或代理地址,只知道密钥有没有,以及代理是继承、直连还是使用专属地址。密钥或代理输入框留空就不动已存的值。在插件配置行里设 `settingsCard: false` 可以连同路由一起去掉它。
|
|
111
111
|
|
|
@@ -116,7 +116,7 @@ dsh 的网页用户面前没有终端,所以引擎设置有一张卡片,在*
|
|
|
116
116
|
modlens 发布很频繁,而两种安装形态都会冻结在装进来的那个版本上。dsh 上重跑一遍安装即可,版本号要点名:
|
|
117
117
|
|
|
118
118
|
```sh
|
|
119
|
-
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.
|
|
119
|
+
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.4
|
|
120
120
|
```
|
|
121
121
|
|
|
122
122
|
`npm view @liustack/modlens version` 可以查到当前版本号,本页的版本号则由发布流程自动写入。
|
package/docs/troubleshooting.md
CHANGED
|
@@ -163,7 +163,7 @@ simply lands on an older one. Name the exact version instead, which pnpm treats
|
|
|
163
163
|
as a deliberate request rather than a resolution:
|
|
164
164
|
|
|
165
165
|
```sh
|
|
166
|
-
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.
|
|
166
|
+
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.4
|
|
167
167
|
```
|
|
168
168
|
|
|
169
169
|
`npm view @liustack/modlens version` prints the current one. pnpm 11 installs a named
|
|
@@ -178,7 +178,7 @@ file:
|
|
|
178
178
|
|
|
179
179
|
```yaml
|
|
180
180
|
minimumReleaseAgeExclude:
|
|
181
|
-
- '@liustack/modlens@3.26.
|
|
181
|
+
- '@liustack/modlens@3.26.4'
|
|
182
182
|
```
|
|
183
183
|
|
|
184
184
|
Or lift the gate for a single command, which lifts it for everything that
|
|
@@ -144,7 +144,7 @@ dsh profile 装到的是旧版 modlens。`dsh.bundle` 声明从 3.9.0 起才存
|
|
|
144
144
|
`@latest` 绕不开这一层,本页早先的说法是错的。冷静期先把候选版本过滤掉,dist-tag 才在剩下的里面解析,于是它直接落到了更旧的那个上。改成写死精确版本号,pnpm 会把它当作一次明确的指定,而不是一次解析:
|
|
145
145
|
|
|
146
146
|
```sh
|
|
147
|
-
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.
|
|
147
|
+
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.4
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
`npm view @liustack/modlens version` 可以查到当前版本号。pnpm 11 会装上被点名的版本,11.1.3 起还会把它作为一条已批准的例外写进该 profile 的 `pnpm-workspace.yaml`,其余所有包和 modlens 以后的版本仍然留在窗口后面。
|
|
@@ -153,7 +153,7 @@ npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modlens@3.26.2
|
|
|
153
153
|
|
|
154
154
|
```yaml
|
|
155
155
|
minimumReleaseAgeExclude:
|
|
156
|
-
- '@liustack/modlens@3.26.
|
|
156
|
+
- '@liustack/modlens@3.26.4'
|
|
157
157
|
```
|
|
158
158
|
|
|
159
159
|
或者只为这一条命令解除冷静期,注意它解除的是这条命令解析到的所有包,不只 modlens:
|
package/dsh/client.js
CHANGED
|
@@ -188,18 +188,16 @@ window.__ModuleLoader__.load({
|
|
|
188
188
|
// with it the host-side image admission a text-only model fails).
|
|
189
189
|
event.preventDefault()
|
|
190
190
|
event.stopImmediatePropagation()
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
console.error(`[modlens] paste-to-path: could not insert into the composer (${text})`)
|
|
191
|
+
// Settle each upload on its own: the paste is already taken, so one
|
|
192
|
+
// failed image must not take the ones that landed down with it (#111).
|
|
193
|
+
Promise.allSettled(files.map(uploadOne)).then((outcomes) => {
|
|
194
|
+
var paths = []
|
|
195
|
+
outcomes.forEach((outcome) => {
|
|
196
|
+
if (outcome.status === 'fulfilled') {
|
|
197
|
+
if (outcome.value.path) paths.push(outcome.value.path)
|
|
198
|
+
return
|
|
200
199
|
}
|
|
201
|
-
|
|
202
|
-
.catch((error) => {
|
|
200
|
+
var error = outcome.reason
|
|
203
201
|
// A 404 here means the route vanished AFTER a verdict confirmed it
|
|
204
202
|
// (plugin disposed mid-session), and a 403 that it refuses this
|
|
205
203
|
// page's origin: either way that race can cost this one paste —
|
|
@@ -211,6 +209,12 @@ window.__ModuleLoader__.load({
|
|
|
211
209
|
}
|
|
212
210
|
console.error(`[modlens] paste-to-path failed: ${error?.message ? error.message : error}`)
|
|
213
211
|
})
|
|
212
|
+
var text = paths.join(' ')
|
|
213
|
+
if (!text) return
|
|
214
|
+
if (!insertText(target, `${text} `)) {
|
|
215
|
+
console.error(`[modlens] paste-to-path: could not insert into the composer (${text})`)
|
|
216
|
+
}
|
|
217
|
+
})
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
// The settings card (issue #39). dsh renders a fixed set of plugin cards
|
|
@@ -502,7 +506,7 @@ window.__ModuleLoader__.load({
|
|
|
502
506
|
}),
|
|
503
507
|
)
|
|
504
508
|
|
|
505
|
-
return function ModlensCard() {
|
|
509
|
+
return function ModlensCard(props) {
|
|
506
510
|
// Subscribed, not sampled: the language is a live setting, and a card
|
|
507
511
|
// sitting open while the user switches has to follow. getSnapshot and
|
|
508
512
|
// subscribe are the pair dsh documents as useSyncExternalStore-safe.
|
|
@@ -515,11 +519,15 @@ window.__ModuleLoader__.load({
|
|
|
515
519
|
? react.useSyncExternalStore(subscribeLocale, readLocale)
|
|
516
520
|
: readLocale(),
|
|
517
521
|
)
|
|
522
|
+
// The 0.1.7 Plugins page draws the title and the crumb itself and
|
|
523
|
+
// passes view: 'page', so there the card is only its form, open from
|
|
524
|
+
// the start (#113). The Settings card before 0.1.7 keeps its header.
|
|
525
|
+
var page = props?.view === 'page'
|
|
518
526
|
var openState = react.useState(false)
|
|
519
527
|
var summaryState = react.useState(null)
|
|
520
528
|
var draftState = react.useState(null)
|
|
521
529
|
var noteState = react.useState('')
|
|
522
|
-
var open = openState[0]
|
|
530
|
+
var open = page || openState[0]
|
|
523
531
|
var summary = summaryState[0]
|
|
524
532
|
var draft = draftState[0]
|
|
525
533
|
var note = noteState[0]
|
|
@@ -1003,6 +1011,8 @@ window.__ModuleLoader__.load({
|
|
|
1003
1011
|
}
|
|
1004
1012
|
}
|
|
1005
1013
|
|
|
1014
|
+
if (page) return h('div', null, body)
|
|
1015
|
+
|
|
1006
1016
|
return h(
|
|
1007
1017
|
'div',
|
|
1008
1018
|
{
|
|
@@ -1123,6 +1133,13 @@ window.__ModuleLoader__.load({
|
|
|
1123
1133
|
ctx.slots.inject('settings.plugin.item', function* () {
|
|
1124
1134
|
yield ctx.slots.register({ name: 'settings.plugin.item', id: 'modlens', key: 'modlens', order: 30 }, Card)
|
|
1125
1135
|
})
|
|
1136
|
+
// dsh 0.1.7 moved plugin configuration to the Plugins page, which shows
|
|
1137
|
+
// a bundle's form from plugins.bundle.config keyed by its package name
|
|
1138
|
+
// (#113). slots.inject waits for a slot to be declared, so each host
|
|
1139
|
+
// mounts the card in the one place its settings UI declares.
|
|
1140
|
+
ctx.slots.inject('plugins.bundle.config', function* () {
|
|
1141
|
+
yield ctx.slots.register({ name: 'plugins.bundle.config', key: '@liustack/modlens' }, Card)
|
|
1142
|
+
})
|
|
1126
1143
|
}
|
|
1127
1144
|
|
|
1128
1145
|
function apply(ctx) {
|
package/dsh/index.js
CHANGED
|
@@ -203,9 +203,12 @@ export function apply(ctx, config = {}) {
|
|
|
203
203
|
// toJSON, the same stance the LlmAdapter takes: importing a dsh package for
|
|
204
204
|
// it would pin this plugin to one harness version. Harnesses without the
|
|
205
205
|
// settings service never run the closure, and their older settings page
|
|
206
|
-
// rendered every registered card anyway.
|
|
206
|
+
// rendered every registered card anyway. 0.1.7 keeps the service but drops
|
|
207
|
+
// runtime namespaces, since plugin cards moved to the Plugins page, which
|
|
208
|
+
// dispatches by package name instead (#113): nothing to register there.
|
|
207
209
|
if (config.settingsCard !== false && typeof ctx.inject === 'function') {
|
|
208
210
|
ctx.inject(['settings'], (scope) => {
|
|
211
|
+
if (typeof scope.settings.register !== 'function') return
|
|
209
212
|
try {
|
|
210
213
|
const passThrough = (value) => ({ ...(value ?? {}) })
|
|
211
214
|
passThrough.toJSON = () => ({
|
|
@@ -1525,6 +1528,10 @@ function run(command, args, signal) {
|
|
|
1525
1528
|
// this makes it behave as plain node for the spawned CLI (issue #25).
|
|
1526
1529
|
env: { ...process.env, ELECTRON_RUN_AS_NODE: '1' },
|
|
1527
1530
|
})
|
|
1531
|
+
// Decode as one stream, not chunk by chunk: a multi-byte character split
|
|
1532
|
+
// across two pipe chunks came out as replacement characters (issue #110).
|
|
1533
|
+
child.stdout.setEncoding('utf8')
|
|
1534
|
+
child.stderr.setEncoding('utf8')
|
|
1528
1535
|
let stdout = ''
|
|
1529
1536
|
let stderr = ''
|
|
1530
1537
|
child.stdout.on('data', (chunk) => {
|
package/package.json
CHANGED
package/skills/modlens/SKILL.md
CHANGED
|
@@ -20,11 +20,11 @@ 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.26.
|
|
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.26.4):
|
|
24
24
|
|
|
25
|
-
1. A `modlens` on `PATH` whose major version is 3 and is at least 3.26.
|
|
26
|
-
2. Otherwise, if `npx` exists: `npx --yes --package @liustack/modlens@3.26.
|
|
27
|
-
3. Otherwise, if `bunx` exists: `bunx --bun @liustack/modlens@3.26.
|
|
25
|
+
1. A `modlens` on `PATH` whose major version is 3 and is at least 3.26.4: `modlens <args>`.
|
|
26
|
+
2. Otherwise, if `npx` exists: `npx --yes --package @liustack/modlens@3.26.4 modlens <args>`.
|
|
27
|
+
3. Otherwise, if `bunx` exists: `bunx --bun @liustack/modlens@3.26.4 <args>`.
|
|
28
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.
|
|
@@ -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.26.
|
|
27
|
+
$Pinned = '3.26.4'
|
|
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.26.
|
|
25
|
+
PINNED="3.26.4"
|
|
26
26
|
# -------------------------------------------------------------------------------
|
|
27
27
|
|
|
28
28
|
NATIVE_NOTE="no native artifact is published for this tool yet; phase A ships npm launch paths only"
|