clearai-dsh 0.1.5 → 0.1.6
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 +36 -1
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/bin/clearai.mjs +17 -0
- package/lib/client.js +142 -105
- package/lib/fold.js +183 -51
- package/lib/host.js +36 -8
- package/package.json +1 -1
- package/presets/clearai/agent.cordis.yml +1 -1
- package/presets/clearai/plugins/clearai-kernel.js +351 -46
- package/presets/clearai/plugins/ontology.js +23 -8
- package/presets/clearai/plugins/prompts.js +3 -3
- package/presets/clearai/preset.yml +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -2,15 +2,48 @@
|
|
|
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.6] — 2026-09-16
|
|
6
|
+
|
|
7
|
+
**机制不许再说自己没有的话。** 一轮「按真值表逐条核对文档 vs 代码」的清点,把三处
|
|
8
|
+
「文档写了、代码没有」补上了生产者;同时修掉四处在真跑里现形的缺陷——其中一个控件
|
|
9
|
+
**点了报成功、账上一字未改**,还有一把**只有方向、没有口径**的尺子。
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **A control that reported success and did nothing.** The inbox rendered the same `fork_adopt` gate twice: once by the worldline block (with each branch's reading) and again by the generic list, because `needs === 'click'` implied "give it a 裁决 button". The second button sent `fork: null`, so the fold's `forks.find(id === null)` matched nothing and the state did not change — while the host route answered `200 {ok:true}`. One criterion now drives both renderings, and the generic layer only offers what it can actually land: 采纳 for a skill candidate, 用提问卡决定 for a gate the worldline block cannot render, a sentence-prompt for word gates.
|
|
14
|
+
- **The ruler had a direction but no scale.** Two worldlines' `done_criteria` were byte-identical and each told the *branch* to publish its own 计分口径 — so two mutually invisible executors measured in different units (炉次 vs 等效炉次) and `min` compared the two conventions as if they were one quantity. `decide_by.metric` must now read `量 = 口径` (`decide_by_scale_required`), and the *sharing* is guaranteed by the existing "each branch's criteria must contain the metric verbatim" check — no new field, no new gate, refused at registration instead of after the work.
|
|
15
|
+
- **The declared evidence path was never told to the doer.** `ForkPlan` declares each branch's `artifacts`, and delivery requires those paths to exist inside the executor's worktree — but the executor's brief carried only criteria, approach and workspace. A fresh agent therefore wrote to `products/reports/` and delivery failed on the declaration, leaving "copy the file into the declared path" as the only way through: a copy in a place where the evidence was not produced. The brief now carries the declared paths, and the refusal names the two honest ways out instead of inviting the copy.
|
|
16
|
+
- **The delivery-point commit could be swallowed by an exploration snapshot.** A snapshot committed the tree, so the delivery commit became empty, `commitLedger` skipped it silently (its rule is "nothing changed → no commit") and the delivery point disappeared from the ledger. The delivery point is a *named* event ("what the workspace looked like when this step was delivered"): only it passes `allowEmpty`.
|
|
17
|
+
- **Receiving no verdict never escalated.** A lost or unavailable independent verdict failed closed forever: the model could re-deliver, fail closed, and repeat — the same action, no new fact — without ever reaching a person. It now shares the block counter with a failed admission, so repeating it blocks the plan and lands in the inbox door that already exists.
|
|
18
|
+
- **`retracted` had no producer** — the state was declared in the ontology, absent from it in code, and drawn in the panel. Refuting evidence now only *marks* a promoted fact (`refuted`, derived) and raises an inbox item; a human decides **撤回** or **维持原事实**, and both land as one `fact/reviewed` (retraction is terminal, the record is kept). "No decision" and "decided to keep" have to stay distinguishable, or the gate holds continuation forever.
|
|
19
|
+
- **Platform junk no longer enters the ledger.** `.DS_Store` is nobody's content, is binary, and changes whenever a directory is browsed — two worldlines' copies always differ, so a merge conflicts over something unrelated to the delivery (a person clicked adopt and the model spent a round aligning `.DS_Store` bytes). `LEDGER_JUNK` now goes into the same `info/exclude` (exclusion is per repository, so every worktree benefits), and files already tracked are unstaged with `git rm --cached` — index only, the file in the workspace is untouched.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **`untouchedLevels`.** A level measures how much a conclusion depends on trusting the doer; the compensation ladder (independent evaluator → human release) is the mechanism. "One level at a time" is an economic order, not a permission — and a reason for skipping cannot be falsified, so requiring one would be a field nobody can check. What is mechanical: the levels a hypothesis never used are derived and shown.
|
|
24
|
+
- **`confirm_provisional`.** A provisional adoption could only be acknowledged by talking, while an open gate holds continuation — so the system waited for an action that could never arrive. Approval is a decision and now has a button.
|
|
25
|
+
- **`VoidPlanStep`-style exits for the two gates that had none**, and two new human-gate verbs `retract_fact` / `keep_fact` (the whitelist is enumerated verbatim, and every gate is now checkable for both outcomes).
|
|
26
|
+
- **Exploration snapshots** (`git/snapshot`): work written between deliveries is recorded, so exploration output is recoverable without asking anyone to declare it.
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **The truth table tells the truth about itself.** Every `implemented` row must point at symbols that exist (`source.code` is now falsifiable and caught a dead identifier), every non-implemented row must name a destination, and the counts are 57 mechanisms: implemented 51 / partial 1 / design-only 1 / removed 4.
|
|
31
|
+
- **`verification-loop`'s state table is a landing-point record**, not a design target: each of the nine names says where it lives today (a fact / something `derive()` computes / deliberately unrepresentable), and a machine check goes red if a row is added without one. §6 now says what carries each rule and admits that rule 1 is a reading, not a gate.
|
|
32
|
+
- **Observation provenance declares only what has a producer** (`self`, `scout`); the type may not promise an origin nothing writes.
|
|
33
|
+
- Docs, counts and suites aligned: 13 suites, 1267 assertions, `verify-package` 31/0.
|
|
34
|
+
|
|
5
35
|
## [0.1.5] — 2026-09-16
|
|
6
36
|
|
|
37
|
+
**卡片读不出自己的名字。** 预设卡片显示成 `clearai` + 「暂无描述」,而不是 ClearAI 与它的说明 ——
|
|
38
|
+
根因不在界面,在文件:元数据根本没被读进去,而名册对读失败**静默降级**。
|
|
39
|
+
|
|
7
40
|
### Fixed
|
|
8
41
|
|
|
9
42
|
- **The preset card still read `clearai` with an empty description.** 0.1.2, 0.1.3 and 0.1.4 all shipped `preset.yml` with the description as a plain YAML scalar containing `English: state` — a colon followed by a space cannot appear in a plain scalar, so the file did not parse at all. DSH's preset roster treats *every* metadata read failure as "no metadata", silently, so the picker fell back to the directory id plus 「暂无描述」 and nothing on either side reported an error. The description is now a block scalar, and `verify-package` parses `preset.yml` with the host's own `yaml` library and requires a non-empty `name` and `description` — this can no longer ship silently.
|
|
10
43
|
|
|
11
44
|
## [0.1.4] — 2026-09-16
|
|
12
45
|
|
|
13
|
-
|
|
46
|
+
**子任务的交付链修好了。** 侦察与世界线执行者的结论此前只进账本、模型读不到
|
|
14
47
|
(账本里也有过「派出去就再也没人收」的挂空)。现在四类子任务(侦察 / 世界线执行者 /
|
|
15
48
|
评估者 / 横评仲裁)统一走原生 `subagents.start()` 的一次性句柄:账本只认本进程攥着的
|
|
16
49
|
`run.result`,结论正文由**收集那一刻的工具返回**交给模型,全文另落
|
|
@@ -64,6 +97,8 @@ All notable changes to this project are recorded here. The format follows [Keep
|
|
|
64
97
|
|
|
65
98
|
## [0.1.3] — 2026-09-15
|
|
66
99
|
|
|
100
|
+
**一条命令的安装路径,以及一条从没被走通的发布路径。**
|
|
101
|
+
|
|
67
102
|
### Added
|
|
68
103
|
|
|
69
104
|
- **`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.
|
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ If it stops because **pnpm is not on your `PATH`**: DSH manages a profile by dri
|
|
|
39
39
|
From a checkout (development, not the install path):
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
npm test #
|
|
42
|
+
npm test # 13 suites — the list lives in test/run.sh
|
|
43
43
|
node tools/build-package.mjs # assemble dist/ from source
|
|
44
44
|
node tools/verify-package.mjs # rebuild and compare byte-for-byte
|
|
45
45
|
node tools/verify-clean-install.mjs # install into an empty DSH_HOME through the real CLI
|
package/README.zh-CN.md
CHANGED
|
@@ -39,7 +39,7 @@ npx clearai-dsh install
|
|
|
39
39
|
从仓库开发(这是开发路径,不是安装路径):
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
npm test #
|
|
42
|
+
npm test # 13 份套件 —— 清单在 test/run.sh
|
|
43
43
|
node tools/build-package.mjs # 由源装配 dist/
|
|
44
44
|
node tools/verify-package.mjs # 现场重建并逐字节比对
|
|
45
45
|
node tools/verify-clean-install.mjs # 空 DSH_HOME + 真 CLI 装一遍(16 条断言)
|
package/bin/clearai.mjs
CHANGED
|
@@ -136,6 +136,23 @@ function doctor() {
|
|
|
136
136
|
const dir = join(root, PRESET_ID)
|
|
137
137
|
const present = existsSync(join(dir, 'agent.cordis.yml'))
|
|
138
138
|
rows.push(`用户根 ${dir} ${present ? '✓ 名册看得见' : '✗ 还没有(用 seed 播种,或把 root-yaml 那一行粘进 profile)'}`)
|
|
139
|
+
/**
|
|
140
|
+
* 用户根里那份**会不会被包的 root 遮住**。
|
|
141
|
+
*
|
|
142
|
+
* 名册按 root 顺序先到先得(自带 root → 配置 root → 用户根),所以包一装,用户根里
|
|
143
|
+
* 同 id 的那份副本就**再也读不到**——它会安静地烂在那里,还会把「部署出去的那份」的
|
|
144
|
+
* 自检引到你手改过的旧副本上。判据只取事实:两份 `preset.yml` 的字节是否一致。
|
|
145
|
+
*/
|
|
146
|
+
const mine = join(PRESET_SRC, 'preset.yml')
|
|
147
|
+
const theirs = join(dir, 'preset.yml')
|
|
148
|
+
if (!present || !existsSync(mine) || !existsSync(theirs)) continue
|
|
149
|
+
let same = false
|
|
150
|
+
try {
|
|
151
|
+
same = readFileSync(mine).equals(readFileSync(theirs))
|
|
152
|
+
} catch {
|
|
153
|
+
same = false
|
|
154
|
+
}
|
|
155
|
+
if (!same) rows.push(` ⚠️ 影子副本 ${theirs} 与包里的那份**不一致**,而它被包的 root 遮住、永远不会被读到(自检却会优先读它)。删掉它,或用它来承载你自己的改动并换一个 id。`)
|
|
139
156
|
}
|
|
140
157
|
const profileDir = join(DSH_HOME, 'profiles', profile)
|
|
141
158
|
rows.push(`profile ${profileDir}${existsSync(profileDir) ? '' : '(不存在:先跑一次 dsh --profile ' + profile + ')'}`)
|