clearai-dsh 0.1.2 → 0.1.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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to this project are recorded here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
4
 
5
+ ## [0.1.3] — 2026-09-15
6
+
7
+ ### Added
8
+
9
+ - **`npx clearai-dsh install` — one command, and the only prerequisite left is DSH's own.** The published package has always carried an install-side tool, but it only *diagnosed*: `doctor`, `root-yaml`, `seed`, `unseed`. The installer that could actually place the package lived in `tools/install-native.mjs`, which is not in the published files — so a stranger had nothing to run but `dsh plugin … add`, a command whose first word assumes a `dsh` that an `npx`-launched harness never puts on `PATH`. The new `install` verb resolves the CLI (a `dsh` on `PATH`, else `npx --yes @deepseek-ai/dsh`), installs into the profile, and then reads the composed config back to show that the `clearai-host` row really landed. `--dist` / `--tarball` / `--spec` point it at a local build instead of the registry, which is what the lifecycle check now exercises.
10
+
11
+ ### Changed
12
+
13
+ - **The install instructions no longer teach a mechanism we do not own.** They handed the reader a `corepack enable` line as the way to get pnpm. Corepack is a version *router*, not an install: its 186-byte shim fetches a pnpm on first use, and corepack 0.34 — the one Node 24 ships — launches pnpm by looking for `bin/pnpm.cjs`, which pnpm 11 and later no longer provide. It can therefore fetch a version it is unable to run, and its shims can shadow a pnpm that already worked. The docs now name the requirement (a `pnpm` on `PATH`, which is DSH's rather than ours) and leave the choice of how to satisfy it to the reader.
14
+ - `install` does not bootstrap a profile or hand-reconcile one. The CLI initializes a profile the first time it is used for one (`initialized profile web at …`), and a second implementation of the host's reconcile step is exactly the duplication this project rejects. Passing a shipped profile name to `--from-default-profile` is an error in the CLI (`profile "web" is shipped and cannot be a custom profile target`), so the verb does not offer that flag at all.
15
+ - `install` stops when `pnpm` is missing instead of degrading: pnpm is DSH's prerequisite, not this plugin's. The degraded, pnpm-less path stays in `tools/install-native.mjs`, where it exists for one-shot E2E homes and labels itself as degraded.
16
+ - **`doctor` asks the composed config through a `dsh` on `PATH` first**, falling back to `npx --no-install`. It previously always went through npx, so a machine that had the CLI on `PATH` could still be told the composition could not be determined.
17
+ - **The lifecycle check had a gate that could never open.** Its byte-for-byte comparison included `INVENTORY.txt` — the build's own file manifest, which is not in `files` and is therefore never present in a pnpm-installed copy — so that assertion was red on every run, and because the lifecycle check is not part of CI, nobody saw it. It also drove every compose query through `npx --no-install`, which returns an empty string when npx cannot run: two positive assertions failed while the negative one ("the row is gone") passed on that empty output. Both are fixed — the CLI is resolved from `PATH` first, and the comparison ignores the build manifest — and the check now exercises the shipped `install` verb too (28 checks).
18
+
5
19
  ## [0.1.2] — 2026-09-12
6
20
 
7
21
  ### Fixed
package/README.md CHANGED
@@ -22,6 +22,32 @@ A language model can produce a plausible answer in seconds. ClearAI is about wha
22
22
 
23
23
  ---
24
24
 
25
+ ## Install
26
+
27
+ One command, and it needs nothing but Node:
28
+
29
+ ```bash
30
+ npx clearai-dsh install
31
+ ```
32
+
33
+ It resolves the DSH CLI (from your `PATH`, or through `npx`), installs the plugin into your `web` profile, and reads the composed config back so you are not taking "success" on faith. Underneath it is the host's own install, so this is the same command: `dsh plugin --profile web add clearai-dsh`.
34
+
35
+ **Restart `dsh web` after that** (`npx @deepseek-ai/dsh web`). Both halves of the plugin are cached inside the running process, so refreshing the browser is not enough. Then open a session and pick **ClearAI** in the preset picker.
36
+
37
+ If it stops because **pnpm is not on your `PATH`**: DSH manages a profile by driving pnpm, so it needs one. Install it with `npm install -g pnpm`, or your system package manager. Prefer that to `corepack enable`, which installs a version *router* rather than pnpm, and the corepack shipped with current Node can fetch a pnpm it is unable to launch.
38
+
39
+ From a checkout (development, not the install path):
40
+
41
+ ```bash
42
+ npm test # kernel / host / brain / client / ontology suites
43
+ node tools/build-package.mjs # assemble dist/ from source
44
+ node tools/verify-package.mjs # rebuild and compare byte-for-byte
45
+ node tools/verify-clean-install.mjs # install into an empty DSH_HOME through the real CLI
46
+ node docs/diagrams/build.mjs # regenerate the loop diagram (needs google-chrome)
47
+ ```
48
+
49
+ `dist/` is generated and never committed. See [DSH integration](docs/dsh-integration.md).
50
+
25
51
  ## Why this is not just another agent loop
26
52
 
27
53
  Most agent loops track one thing: whether the task is done. The Epistemic Loop also tracks **how a conclusion came to be trusted**:
@@ -73,29 +99,6 @@ The plugin contributes three surfaces on top of stock DSH: a **deliverables** vi
73
99
 
74
100
  ![External brain](docs/shots/en/skills.png)
75
101
 
76
- ## Install
77
-
78
- Requires **Node ≥ 22** and **`pnpm` on `PATH`** — `dsh plugin …` is a pnpm forwarder, so without pnpm the profile cannot be managed at all:
79
-
80
- ```bash
81
- corepack enable --install-directory ~/.local/bin # if you do not have pnpm yet
82
- dsh plugin --profile web add clearai-dsh
83
- ```
84
-
85
- **Restart `dsh web` afterwards.** Both halves of the plugin are cached inside the running process, so refreshing the browser is not enough. Then open a session and pick **ClearAI** in the preset picker.
86
-
87
- From a checkout:
88
-
89
- ```bash
90
- npm test # kernel / host / brain / client / ontology suites
91
- node tools/build-package.mjs # assemble dist/ from source
92
- node tools/verify-package.mjs # rebuild and compare byte-for-byte
93
- node tools/verify-clean-install.mjs # install into an empty DSH_HOME through the real CLI
94
- node docs/diagrams/build.mjs # regenerate the loop diagram (needs google-chrome)
95
- ```
96
-
97
- `dist/` is generated and never committed. See [DSH integration](docs/dsh-integration.md).
98
-
99
102
  ## Where it lands in DSH
100
103
 
101
104
  ClearAI adds an epistemic layer on the DSH **composition surface** — one host package, one agent preset, one client module. The DSH engine is not modified.
package/README.zh-CN.md CHANGED
@@ -22,6 +22,32 @@ ClearAI 是一个**原生 DSH 插件**,把认识论循环带进 DeepSeek Harne
22
22
 
23
23
  ---
24
24
 
25
+ ## 安装
26
+
27
+ 一条命令,除了 Node 什么都不需要:
28
+
29
+ ```bash
30
+ npx clearai-dsh install
31
+ ```
32
+
33
+ 它会自己找到 DSH CLI(PATH 上有就用,没有就走 npx),把插件装进你的 `web` profile,再把组合读回来核一眼 —— 不用凭一句「成功」相信它。底下就是宿主自己的安装动作,所以两者等价:`dsh plugin --profile web add clearai-dsh`。
34
+
35
+ **装完要重启 `dsh web`**(`npx @deepseek-ai/dsh web`)。插件的两半都在运行中的进程里按模块 URL 缓存,只刷新浏览器不够。然后新建会话,在预设选择器里选 **ClearAI**。
36
+
37
+ 如果它因为 **PATH 上没有 pnpm** 而停下:DSH 管理 profile 就是靠 pnpm,所以需要一个。用 `npm install -g pnpm` 装,或用你的系统包管理器。**别用 `corepack enable` 抄近路**——它装的是一个版本**转发器**而不是 pnpm,而当前 Node 自带的那份 corepack 可能下载一个它自己启动不了的 pnpm。
38
+
39
+ 从仓库开发(这是开发路径,不是安装路径):
40
+
41
+ ```bash
42
+ npm test # 内核 / 宿主 / 外脑 / 客户端 / 本体 五份套件
43
+ node tools/build-package.mjs # 由源装配 dist/
44
+ node tools/verify-package.mjs # 现场重建并逐字节比对
45
+ node tools/verify-clean-install.mjs # 空 DSH_HOME + 真 CLI 装一遍(16 条断言)
46
+ node docs/diagrams/build.mjs # 重画循环主图(需 google-chrome)
47
+ ```
48
+
49
+ `dist/` 是生成物,不进版本库。见 [DSH 集成](docs/dsh-integration.zh-CN.md)。
50
+
25
51
  ## 为什么它不只是又一个 agent loop
26
52
 
27
53
  多数 agent loop 只跟踪一件事:任务做完没有。认识论循环还跟踪**一个结论凭什么被信任**:
@@ -73,29 +99,6 @@ ClearAI **不**声称实现递归自我改进。它提供的是自我改进系
73
99
 
74
100
  ![外脑](docs/shots/zh/skills.png)
75
101
 
76
- ## 安装
77
-
78
- 需要 **Node ≥ 22** 和 **`pnpm` 在 PATH 上** —— `dsh plugin …` 是 pnpm 的一层转发器,没有 pnpm 就管不了 profile:
79
-
80
- ```bash
81
- corepack enable --install-directory ~/.local/bin # 还没有 pnpm 就先装它
82
- dsh plugin --profile web add clearai-dsh
83
- ```
84
-
85
- **装完要重启 `dsh web`。** 插件的两半都在运行中的进程里按模块 URL 缓存,只刷新浏览器不够。然后新建会话,在预设选择器里选 **ClearAI**。
86
-
87
- 从仓库开发:
88
-
89
- ```bash
90
- npm test # 内核 / 宿主 / 外脑 / 客户端 / 本体 五份套件
91
- node tools/build-package.mjs # 由源装配 dist/
92
- node tools/verify-package.mjs # 现场重建并逐字节比对
93
- node tools/verify-clean-install.mjs # 空 DSH_HOME + 真 CLI 装一遍(16 条断言)
94
- node docs/diagrams/build.mjs # 重画循环主图(需 google-chrome)
95
- ```
96
-
97
- `dist/` 是生成物,不进版本库。见 [DSH 集成](docs/dsh-integration.zh-CN.md)。
98
-
99
102
  ## 它落在 DSH 的哪一层
100
103
 
101
104
  ClearAI 把认识论层加在 DSH 的**组合面**上——一个宿主包、一个 agent 预设、一个客户端模块,**DSH 引擎一行都没改**。
package/bin/clearai.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * clearai-dsh 的安装侧工具:**只做三件事,而且都不改别人的东西**。
3
+ * clearai-dsh 的安装侧工具。**只有一个动词会动 profile(`install`),而它动的方式是把活交给宿主**。
4
4
  *
5
5
  * 分包的三样东西落在三个平面:
6
6
  * · 宿主半(`lib/host.js`)—— 由包自带的 `cordis.patch.yml` 在 profile 层插一行,`dsh plugin add` 自动生效;
@@ -8,8 +8,11 @@
8
8
  * · agent 预设(`presets/clearai/`)—— **名册(roster)只从 root 目录扫**,包没法直接声明,
9
9
  * 所以要么把 root 指进包里,要么把它播种到用户根。这一件就是本工具存在的理由。
10
10
  *
11
- * 三种处理方式(按「原生程度」排序,默认只**打印**不改):
11
+ * 处理方式(前四个默认只**打印**不改;默认动词仍是 `doctor` —— 一个安装侧工具不该在
12
+ * 你没说要装的时候动你的部署):
12
13
  * doctor 看现状:包在哪、预设在哪、名册能不能看见它、探测到的 dsh / profile 是什么
14
+ * install 把包装进 profile —— `dsh plugin --profile <p> add <spec>` 的一层**前置解析**
15
+ * (读者不必知道 profile 叫什么、CLI 从哪来、包名怎么写),装完给读数与下一步
13
16
  * root-yaml 打印**可以直接粘进 profile 的 `cordis.patch.yml`** 的那一行(路径已算成绝对路径)
14
17
  * seed 把预设**播种**到用户根 `~/.dsh/.agent-presets/<id>`(带哈希记账:改过的不覆盖)
15
18
  * unseed 撤掉播种:只删「我们播的、且没被改过」的文件;用户 fork 的 id 一律不碰
@@ -19,10 +22,10 @@
19
22
  */
20
23
 
21
24
  import { createHash } from 'node:crypto'
22
- import { execFileSync } from 'node:child_process'
25
+ import { spawnSync } from 'node:child_process'
23
26
  import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs'
24
27
  import { homedir } from 'node:os'
25
- import { dirname, join, relative, resolve } from 'node:path'
28
+ import { delimiter, dirname, join, relative, resolve } from 'node:path'
26
29
  import { fileURLToPath } from 'node:url'
27
30
 
28
31
  const HERE = dirname(fileURLToPath(import.meta.url))
@@ -85,6 +88,44 @@ function rosterRoots() {
85
88
  return [join(DSH_HOME, '.agent-presets')]
86
89
  }
87
90
 
91
+ /**
92
+ * 在 PATH 上找一个可执行文件,找到就返回全路径。
93
+ *
94
+ * 为什么不用 `bash -lc 'command -v pnpm'`(tools/install-native.mjs 的写法):
95
+ * 这里要能在 Windows 上跑,而 `command -v` 是 shell 内建;另外**只查文件、不执行它** ——
96
+ * 执行一个 pnpm 可能是别的东西(比如 corepack 的转发器)在跑,那会引出网络与副作用。
97
+ */
98
+ function findOnPath(name) {
99
+ const exts = process.platform === 'win32' ? ['.cmd', '.exe', '.bat'] : ['']
100
+ for (const dir of (process.env.PATH ?? '').split(delimiter)) {
101
+ if (dir === '') continue
102
+ for (const ext of exts) {
103
+ const candidate = join(dir, `${name}${ext}`)
104
+ try {
105
+ if (statSync(candidate).isFile()) return candidate
106
+ } catch {
107
+ /* 这个目录里没有 */
108
+ }
109
+ }
110
+ }
111
+ return null
112
+ }
113
+
114
+ /**
115
+ * 问组合:宿主行到底有没有真的进组合。
116
+ *
117
+ * 优先用 PATH 上**真正的** `dsh`(以前一律走 `npx --no-install`,于是 PATH 上有 CLI 的机器
118
+ * 也会报「问不到」);没有 CLI 才退回 npx,且仍然 `--no-install` —— 诊断动作不该顺手下载东西。
119
+ */
120
+ function composeQuery(profileName, env) {
121
+ const onPath = findOnPath('dsh')
122
+ const args = ['--profile', profileName, '--dump-config']
123
+ const run = onPath === null
124
+ ? spawnSync('npx', ['--no-install', '@deepseek-ai/dsh', ...args], { encoding: 'utf8', env, timeout: 120000, stdio: ['ignore', 'pipe', 'ignore'] })
125
+ : spawnSync(onPath, args, { encoding: 'utf8', env, timeout: 120000, stdio: ['ignore', 'pipe', 'ignore'] })
126
+ return run.status === 0 ? String(run.stdout ?? '') : null
127
+ }
128
+
88
129
  function doctor() {
89
130
  const rows = []
90
131
  rows.push(`包目录 ${PKG_DIR}`)
@@ -103,13 +144,7 @@ function doctor() {
103
144
  * **包的补丁层**,不在 profile 的 cordis.patch.yml 里 —— 读文件的写法会误报「还没挂」)。
104
145
  * 事实在组合里;问不到就如实说问不到,不猜。
105
146
  */
106
- const composed = (() => {
107
- try {
108
- return execFileSync('npx', ['--no-install', '@deepseek-ai/dsh', '--profile', profile, '--dump-config'], { encoding: 'utf8', env: { ...process.env, DSH_HOME }, timeout: 120000, stdio: ['ignore', 'pipe', 'ignore'] })
109
- } catch {
110
- return null
111
- }
112
- })()
147
+ const composed = composeQuery(profile, { ...process.env, DSH_HOME })
113
148
  if (composed === null) {
114
149
  rows.push('组合 (问不到:dsh 不可用或超时 —— 下面两条无法判定)')
115
150
  } else {
@@ -125,6 +160,82 @@ function doctor() {
125
160
  console.log('\n提示:doctor 只读;它不会替你改 profile,也不会替你播种。')
126
161
  }
127
162
 
163
+ /**
164
+ * install —— 把包装进一个 profile。
165
+ *
166
+ * 真正干活的**永远是宿主的 CLI**(`dsh plugin --profile <p> add <spec>`):它自己会初始化
167
+ * profile、在 profile 目录里跑 pnpm、再对账 `dsh.profile.bundles`。这里只解析三件事 ——
168
+ * 装什么、装到哪、谁来跑 —— 于是读者不必先读过别的文档。
169
+ *
170
+ * 两条纪律:
171
+ * · **不偷偷降级**。没有 pnpm 就停下来把话说清楚:pnpm 是 DSH 的前置,不是本插件的。
172
+ * 在 profile 里手工摆文件等于把宿主的 reconcile 抄成第二份实现,而它一旦与宿主漂移,
173
+ * 坏的是用户的部署。(降级只保留在 `tools/install-native.mjs` —— 那是一次性 DSH_HOME 上的
174
+ * E2E 需要,而且它如实标注自己是降级。)
175
+ * · **装完给读数**。不靠一句「成功」交差:再问一次组合,看宿主行是不是真的进去了。
176
+ */
177
+ function install() {
178
+ const home = resolve(value('home', DSH_HOME))
179
+ const env = { ...process.env, DSH_HOME: home }
180
+ const profileDir = join(home, 'profiles', profile)
181
+ const manifest = JSON.parse(readFileSync(join(PKG_DIR, 'package.json'), 'utf8'))
182
+ const explicit = value('spec', null)
183
+ const dist = value('dist', null)
184
+ const tarball = value('tarball', null)
185
+ /**
186
+ * 缺省装 **registry 上的这一版**:profile 从此真正拥有它(能升级、能卸载),也不依赖
187
+ * npx 缓存还在。`--dist` / `--tarball` / `--spec` 是给开发与 E2E 用的另一条入口。
188
+ */
189
+ const spec = explicit ?? (tarball !== null ? resolve(tarball) : dist !== null ? `file:${resolve(dist)}` : `${manifest.name}@${manifest.version}`)
190
+ const source = explicit !== null ? '你给的 spec' : tarball !== null ? '本地 tarball' : dist !== null ? '本地目录' : 'registry'
191
+ /** PATH 上有 `dsh` 就用它;没有就用 npx 取官方 CLI(`--yes`:一键安装不该卡在一个确认提示上)。 */
192
+ const dshPath = findOnPath('dsh')
193
+ const route = dshPath === null ? 'npx --yes @deepseek-ai/dsh(PATH 上没有 dsh)' : dshPath
194
+ /**
195
+ * 子进程**继承 stdio**:安装进度、以及 CLI 那句 `initialized profile …` 都如实流到用户眼前;
196
+ * 失败时他看到的也是真实报错,而不是我截出来的尾巴。
197
+ */
198
+ const dsh = (args) => (dshPath === null ? spawnSync('npx', ['--yes', '@deepseek-ai/dsh', ...args], { env, stdio: 'inherit', timeout: 900000 }) : spawnSync(dshPath, args, { env, stdio: 'inherit', timeout: 900000 }))
199
+
200
+ console.log(`【安装】${manifest.name}@${manifest.version}`)
201
+ console.log(` 装什么 ${spec}(${source})`)
202
+ console.log(` 装到哪 ${profileDir}`)
203
+ console.log(` 谁来跑 ${route}`)
204
+
205
+ const pnpmPath = findOnPath('pnpm')
206
+ if (pnpmPath === null) {
207
+ console.error('\n✗ PATH 上没有 pnpm,而 DSH 管理一个 profile 就是靠它:`dsh plugin …` 把参数转发给 pnpm。')
208
+ console.error(' 装一个再来:npm install -g pnpm(或用系统包管理器,如 brew install pnpm)。')
209
+ console.error(' 别用 corepack enable 抄近路 —— 它装的是版本**转发器**而不是 pnpm,而当前 Node 自带的')
210
+ console.error(' 那份 corepack 可能下载一个它自己启动不了的 pnpm。')
211
+ console.error(' 这里刻意不手工改 profile:那等于把宿主的 reconcile 抄成第二份实现,与宿主漂移时坏的是你的部署。')
212
+ process.exit(1)
213
+ }
214
+
215
+ /**
216
+ * **刻意不做 profile bootstrap**:CLI 第一次用到某个 profile 时自己就会初始化它
217
+ * (实测输出 `dsh: initialized profile web at …`),那本来就是宿主的不变量,抄一遍只会
218
+ * 多一个会漂移的实现。顺带说:`--from-default-profile` 只接受**自定义目标**,把 shipped
219
+ * 名字传给它会被 CLI 直接拒 —— `profile "web" is shipped and cannot be a custom profile
220
+ * target`。所以这里连那个开关都不提供。
221
+ */
222
+ const added = dsh(['plugin', '--profile', profile, 'add', spec])
223
+ if (added.status !== 0) {
224
+ console.error('\n✗ 安装失败:见上面的输出。')
225
+ process.exit(1)
226
+ }
227
+
228
+ const composed = composeQuery(profile, env)
229
+ if (composed === null) {
230
+ console.log(' 宿主行 (问不到组合:CLI 不可用或超时 —— 装没装进去,从这里确认不了;用 doctor 再看)')
231
+ } else {
232
+ const inCompose = /^- id: clearai-host$/m.test(composed)
233
+ console.log(` 宿主行 ${inCompose ? '在组合里 ✓' : '**不在组合里** —— 装是装上了,但组合里没看到它(用 doctor 查)'}`)
234
+ }
235
+ console.log('\n 下一步 重启 dsh web(两半都在进程里按模块 URL 缓存,只刷新浏览器不够),然后在预设选择器里选 ClearAI。')
236
+ console.log(` 卸载 dsh plugin --profile ${profile} remove ${manifest.name}(同样可以冠 npx)`)
237
+ }
238
+
128
239
  function rootYaml() {
129
240
  const line = [
130
241
  '# ClearAI 预设的 root(由 clearai-dsh 的 bin 打印,路径已算成绝对路径)',
@@ -214,11 +325,16 @@ function unseed() {
214
325
  }
215
326
 
216
327
  if (command === 'doctor') doctor()
328
+ else if (command === 'install') install()
217
329
  else if (command === 'root-yaml') rootYaml()
218
330
  else if (command === 'seed') seed()
219
331
  else if (command === 'unseed') unseed()
220
332
  else if (command === 'version' || flag('version')) console.log(JSON.parse(readFileSync(join(PKG_DIR, 'package.json'), 'utf8')).version)
221
333
  else {
222
- console.error(`unknown command: ${command}\n用法:clearai-dsh [doctor|root-yaml|seed|unseed] [--profile web] [--root <dir>]`)
334
+ console.error(
335
+ `unknown command: ${command}\n` +
336
+ '用法:clearai-dsh [doctor|install|root-yaml|seed|unseed] [--profile web] [--home <dir>]\n' +
337
+ ' install 还可以:--dist <dir> | --tarball <tgz> | --spec <spec>',
338
+ )
223
339
  process.exit(2)
224
340
  }
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "clearai-dsh",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "ClearAI: The Epistemic Loop, native to DSH.",
5
5
  "type": "module",
6
6
  "private": false,
7
7
  "license": "Apache-2.0",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Clearailhc/clearai-dsh.git"
11
+ },
8
12
  "main": "./lib/host.js",
9
13
  "exports": {
10
14
  ".": "./lib/host.js",
@@ -13,7 +17,7 @@
13
17
  "./package.json": "./package.json"
14
18
  },
15
19
  "bin": {
16
- "clearai-dsh": "./bin/clearai.mjs"
20
+ "clearai-dsh": "bin/clearai.mjs"
17
21
  },
18
22
  "files": [
19
23
  "lib",