dsh-continual-evolve 0.10.5 → 0.11.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/README.md +25 -31
- package/README.zh.md +18 -21
- package/lib/approval.d.ts +19 -6
- package/lib/approval.js +73 -12
- package/lib/audit-log.d.ts +19 -0
- package/lib/audit-log.js +52 -0
- package/lib/auto.js +1 -0
- package/lib/benchmark-command.d.ts +1 -1
- package/lib/benchmark-command.js +1 -1
- package/lib/command-util.d.ts +70 -0
- package/lib/command-util.js +123 -0
- package/lib/command.d.ts +7 -40
- package/lib/command.js +25 -459
- package/lib/copy.d.ts +4 -41
- package/lib/copy.js +0 -102
- package/lib/declines.d.ts +2 -0
- package/lib/declines.js +4 -0
- package/lib/evolve-event.js +2 -1
- package/lib/extraction-phase.d.ts +132 -0
- package/lib/extraction-phase.js +236 -0
- package/lib/index.d.ts +26 -42
- package/lib/index.js +24 -34
- package/lib/inject.d.ts +13 -119
- package/lib/inject.js +12 -260
- package/lib/injection-caps.d.ts +4 -0
- package/lib/injection-caps.js +4 -0
- package/lib/injection-directory.d.ts +29 -0
- package/lib/injection-directory.js +78 -0
- package/lib/injection-rank.d.ts +85 -0
- package/lib/injection-rank.js +161 -0
- package/lib/listener.d.ts +45 -0
- package/lib/listener.js +199 -0
- package/lib/maintenance-commands.d.ts +23 -0
- package/lib/maintenance-commands.js +136 -0
- package/lib/memory-agent.d.ts +7 -41
- package/lib/memory-agent.js +8 -276
- package/lib/memory-apply.d.ts +44 -0
- package/lib/memory-apply.js +202 -0
- package/lib/memory-manifest.d.ts +16 -0
- package/lib/memory-manifest.js +70 -0
- package/lib/mount-command.js +1 -1
- package/lib/notify.d.ts +9 -20
- package/lib/notify.js +0 -40
- package/lib/plan-command.d.ts +12 -0
- package/lib/plan-command.js +38 -0
- package/lib/prefix-cache.d.ts +2 -1
- package/lib/review-scheduler.d.ts +1 -1
- package/lib/review-scheduler.js +2 -10
- package/lib/runtime-commands.d.ts +14 -0
- package/lib/runtime-commands.js +115 -0
- package/lib/service.d.ts +16 -2
- package/lib/service.js +74 -1
- package/lib/store.d.ts +1 -2
- package/lib/store.js +2 -2
- package/lib/tool.d.ts +7 -0
- package/lib/tool.js +4 -4
- package/lib/turn-snapshot.d.ts +7 -1
- package/lib/turn-snapshot.js +14 -0
- package/lib/types.d.ts +10 -0
- package/lib/types.js +6 -0
- package/lib/wrapup-candidates.d.ts +127 -0
- package/lib/wrapup-candidates.js +161 -0
- package/lib/wrapup-command.d.ts +2 -1
- package/lib/wrapup-command.js +7 -4
- package/lib/wrapup-proposals.d.ts +101 -0
- package/lib/wrapup-proposals.js +281 -0
- package/lib/wrapup.d.ts +8 -212
- package/lib/wrapup.js +4 -438
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
[](https://github.com/ZK-Andy/dsh-continual-evolve/actions/workflows/ci.yml)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
[](package.json)
|
|
10
|
-
[]()
|
|
11
11
|
[]()
|
|
12
|
-
[]()
|
|
13
13
|
[]()
|
|
14
14
|
|
|
15
15
|
Continual self-evolution for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness): a versioned, auditable, rollback-safe harness state layer — prompt notes, memories, skills, subagent specs — refined from session trajectories.
|
|
@@ -22,7 +22,7 @@ Agents accumulate reusable experience (repeated failures, durable facts, reusabl
|
|
|
22
22
|
|
|
23
23
|
- **Three scopes** with merge semantics (global < project < local): **local** per-session staging, **project** per-workspace cross-session store, **global** cross-project — plus mechanical promotion guards so only portable, substantial, non-duplicate knowledge reaches global
|
|
24
24
|
- **Typed one-fact memories**: every memory entry carries a recall type (`user | feedback | project | reference`); pitfalls (`feedback`) must include Why + How to apply
|
|
25
|
-
- **
|
|
25
|
+
- **Moment-driven background memory agent**: a bounded ZCode-style loop wakes only at low-frequency moments (compaction, goal-blocked streaks, the session-close drain, manual wrapup), searches the frozen memory manifest, and proposes memory-only edits through a closed tool set; it cannot call agents, MCP, the network, or write source files. Successful turns never cost an LLM call — conversation writes own routine sedimentation
|
|
26
26
|
- **Memory recall, projection, and receipts**: `evolve_recall` reads back full memory content by query/kind/scope/type; every memory apply also materializes a readable `MEMORY.md` index plus one fact file per entry; each extraction lands a unified audit receipt (no-op/applied/declined with duration and turn stats) and only applied outcomes notify the session
|
|
27
27
|
- **Deterministic rollback**: inverse edits generated from applied results — no LLM re-guessing
|
|
28
28
|
- **Benchmark loop**: candidate refinements are evaluated against frozen cases by a separate scorer before acceptance (rubric encrypted at rest)
|
|
@@ -30,8 +30,8 @@ Agents accumulate reusable experience (repeated failures, durable facts, reusabl
|
|
|
30
30
|
|
|
31
31
|
## How it works
|
|
32
32
|
|
|
33
|
-
1. **Sediment** — the model creates entries via `evolve_add
|
|
34
|
-
2. **Capability-aware auxiliary calls** — the memory loop,
|
|
33
|
+
1. **Sediment** — the model creates entries via `evolve_add`; the automatic Memory Agent consumes incremental snapshots only at the four low-frequency moments (compaction, goal-blocked streak, session-close drain, manual wrapup).
|
|
34
|
+
2. **Capability-aware auxiliary calls** — the memory loop, planner, and wrapup resolve exact provider/model metadata through [`src/llm-text.ts`](src/llm-text.ts), use the lowest advertised enabled reasoning effort (falling back to a closing effort only when no enabled level exists), and forward the host session id for provider routing; models without reasoning metadata use their provider default.
|
|
35
35
|
3. **Guard** — code-enforced validation: edit schema, blast-radius/scope coherence, and the promotion policy (project-scoped markers, thin content, near-duplicate detection, credential screening keep the global store clean — secrets are rejected at every write sink, including mount materialization). Global creates that near-duplicate an existing entry are rejected at write time (≥0.8 similarity); moderate overlaps carry a `conflictHint` for later consolidation.
|
|
36
36
|
4. **Approve** — global and project writes require explicit human approval; the dialog shows the bounded structured edit diff and conflict warnings, while malformed/lost responses remain retryable rather than counting as rejection.
|
|
37
37
|
5. **Apply & inject** — memory batches preflight every persistent approval, recheck abort before writes, and compensate earlier scope writes if a later batch fails; every successful scope still passes through snapshot + audit. Prompt notes and delegation specs inject into the system prompt (capped, relevance-ranked, contradicted entries demoted, zero tokens when empty); memory CONTENT injects at session start under a hard character budget, frozen per session, with the when_to_save guide riding along; skills still appear as a relevance-ordered capped directory index.
|
|
@@ -86,14 +86,12 @@ Injection shape: prompt notes and delegation specs inject with content (≤6/kin
|
|
|
86
86
|
| `autoReview` | `false` | initial Memory Agent default when no `evolve/runtime.json` exists yet; the listener is always registered, so this is not a registration gate |
|
|
87
87
|
| `memoryMinUserWords` | `3` | ZCode-style minimum lexical words in one direct user text part; uses CJK-aware segmentation |
|
|
88
88
|
| `sessionCloseDrainMs` | `15000` | session-close bounded drain for in-flight extraction in ms (`0` aborts immediately) |
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `notifyOnAutoReview` | `true` | visible follow-up notice after an applied gate run |
|
|
89
|
+
| `maxReviewInputChars` | `40000` | trajectory slice handed to the extractor |
|
|
90
|
+
| `reviewBudgetTokens` | `4096` | output budget for the extraction loop |
|
|
91
|
+
| `notifyOnAutoReview` | `true` | visible follow-up receipt after an applied goal-blocked moment (compaction and session-close stay audit-only) |
|
|
93
92
|
| `requireGlobalApproval` | `true` | global and project edits ask for explicit approval |
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `goalBlockedWrapupTurns` | `3` | consecutive blocked-goal gate runs trigger one fate assessment (`0` disables) |
|
|
93
|
+
| `recordLanguage` | `auto` | authoring **and dialog** language: `auto` follows the DSH client preference, then the session's own user text, then `en`; `zh`/`en` pin it |
|
|
94
|
+
| `goalBlockedWrapupTurns` | `3` | consecutive blocked-goal idle probes trigger one memory extraction (`0` disables) |
|
|
97
95
|
| `promotionBlockPatterns` | POSIX paths, session ids, `~/.dsh` | content matching these is project-scoped and never promoted to global |
|
|
98
96
|
| `promotionMinChars` | `100` | whole promotions below this length stay local |
|
|
99
97
|
| `injectionDirectoryLines` | `15` | entry-directory lines per build before folding into a counter |
|
|
@@ -107,7 +105,7 @@ Injection shape: prompt notes and delegation specs inject with content (≤6/kin
|
|
|
107
105
|
| `logToFile` / `logLevel` / `logMaxBytes` | `true` / `1` / 5 MiB | plugin-owned JSONL file log with rotation |
|
|
108
106
|
| `autoRollbackOnReject` | `true` | deterministic rollback after a benchmark rejection |
|
|
109
107
|
| `autoCase` | `true` | failed evolution attempts are captured as draft regression cases (`auto_regression` benchmark) |
|
|
110
|
-
| `reviewModel` | agent's own | optional cheaper model for the dedicated memory agent
|
|
108
|
+
| `reviewModel` | agent's own | optional cheaper model for the dedicated memory agent (`"provider/model"`) |
|
|
111
109
|
| `plannerPrefixCache` | `auto` | Route A session-prefix input when cache evidence exists (`session` always, `off` legacy flat text) |
|
|
112
110
|
| `plannerPrefixMaxChars` | `12000` | session-prefix budget for Route A planning inputs (chars) |
|
|
113
111
|
| `historyRetain` | `{snapshots: 20, refinements: 500, reviews: 500, tokenUsage: 500}` | storage hygiene: snapshots per store, tail lines per store history, shared `reviews.jsonl` tail, and direct-call `token-usage.jsonl` tail |
|
|
@@ -118,32 +116,28 @@ Example profile patch:
|
|
|
118
116
|
- id: continual-evolve
|
|
119
117
|
config:
|
|
120
118
|
autoReview: true
|
|
121
|
-
reviewIntervalTurns: 6
|
|
122
119
|
```
|
|
123
120
|
|
|
124
121
|
The Memory Agent listener is registered even when `autoReview` is `false` —
|
|
125
122
|
`autoReview` only supplies the initial default, so an install works without
|
|
126
|
-
editing the profile. Use `/evolve resume` to enable
|
|
127
|
-
immediately, `/evolve pause` to suppress new
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
automatically: the generic review/planner, prompt/skill writes, and local-fate
|
|
132
|
-
phases are not reachable from this listener. The memory trigger follows ZCode's
|
|
123
|
+
editing the profile. Use `/evolve resume` to enable extraction moments
|
|
124
|
+
immediately, `/evolve pause` to suppress new model work, and `/evolve status`
|
|
125
|
+
to inspect the configured default plus the current runtime state. The runtime
|
|
126
|
+
switch is stored in `evolve/runtime.json`; manual `evolve_*` tools and
|
|
127
|
+
`/evolve` commands are not paused. The memory trigger follows ZCode's
|
|
133
128
|
lightweight eligibility: direct user text must contain at least
|
|
134
129
|
`memoryMinUserWords` lexical words (CJK-aware segmentation), while
|
|
135
|
-
empty/internal/direct-memory-write snapshots are skipped
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
before aborting.
|
|
130
|
+
empty/internal/direct-memory-write snapshots are skipped. Every extraction
|
|
131
|
+
writes a unified audit receipt (`noop`/`applied`/`declined` with duration and
|
|
132
|
+
turn/search stats) to `reviews.jsonl`; only an applied goal-blocked moment
|
|
133
|
+
queues a visible follow-up, and a closing session lets in-flight extraction
|
|
134
|
+
settle up to `sessionCloseDrainMs` before aborting.
|
|
141
135
|
|
|
142
136
|
## Development
|
|
143
137
|
|
|
144
138
|
```bash
|
|
145
139
|
pnpm install && pnpm build # deps + tsc -> lib/
|
|
146
|
-
pnpm test # vitest (
|
|
140
|
+
pnpm test # vitest (1020 tests)
|
|
147
141
|
pnpm test:coverage # v8 coverage, thresholds enforced in CI
|
|
148
142
|
pnpm coverage:gaps # locate uncovered lines per file (read-only)
|
|
149
143
|
pnpm lint # oxlint src test
|
|
@@ -152,11 +146,11 @@ pnpm lint # oxlint src test
|
|
|
152
146
|
Project layout:
|
|
153
147
|
|
|
154
148
|
```
|
|
155
|
-
├── src/ # engine, tools, commands, memory agent, recall, projection,
|
|
156
|
-
├── test/ # vitest suites (
|
|
149
|
+
├── src/ # engine, tools, commands, memory agent, recall, projection, benchmark, injection + token usage…
|
|
150
|
+
├── test/ # vitest suites (57 files)
|
|
157
151
|
├── lib/ # build output (tsc)
|
|
158
152
|
├── docs/
|
|
159
|
-
│ ├── design.md #
|
|
153
|
+
│ ├── design.md # the one-loop design narrative
|
|
160
154
|
│ ├── FAQ.md # real failure/fix records
|
|
161
155
|
│ ├── gap-analysis.md # vs prime-agent /refine + penguin-harness
|
|
162
156
|
│ ├── research/pi-dsh-competitor-gap-analysis.md # pi/dsh ecosystem competitors
|
package/README.zh.md
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
[](https://github.com/ZK-Andy/dsh-continual-evolve/actions/workflows/ci.yml)
|
|
8
8
|
[](LICENSE)
|
|
9
9
|
[](package.json)
|
|
10
|
-
[]()
|
|
11
11
|
[]()
|
|
12
|
-
[]()
|
|
13
13
|
[]()
|
|
14
14
|
|
|
15
15
|
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh`)的持续自进化插件:一套**版本化、可审计、可回滚**的 harness 状态层——提示词补充、记忆、技能、子代理规格——从会话轨迹中沉淀而来。
|
|
@@ -22,7 +22,7 @@ Agent 在每个会话里积累可复用经验(重复失败、持久事实、
|
|
|
22
22
|
|
|
23
23
|
- **三作用域**与合并语义(global < project < local):**local** 本会话暂存、**project** 本项目跨会话库、**global** 跨项目——配合机械化晋升守卫,只有可携带、有分量、非重复的知识才能进全局
|
|
24
24
|
- **类型化单条记忆**:每条 memory 带召回类型(`user | feedback | project | reference`);踩坑(`feedback`)必须含 Why + How to apply
|
|
25
|
-
-
|
|
25
|
+
- **时刻驱动的后台记忆 Agent**:有界 ZCode 式 loop 只在四个低频时刻醒来(压缩、goal 连续受阻、会话收尾 drain、手动 wrapup),检索冻结的 memory manifest,并经闭集工具提出纯 memory 编辑;不能调用 Agent、MCP、网络,也不能写源码。成功回合零 LLM 成本——日常沉淀由对话直写承担
|
|
26
26
|
- **记忆召回、投影与回执**:`evolve_recall` 按 query/kind/scope/type 精确读回记忆全文;每次 memory 落盘同时生成可读的 `MEMORY.md` 索引 + 单事实文件;每次提取留统一审计回执(no-op/applied/declined + 耗时与轮次统计),只有实际沉淀才通知会话
|
|
27
27
|
- **确定性回滚**:逆操作编辑由已应用结果生成——不靠 LLM 重新猜测
|
|
28
28
|
- **benchmark 闭环**:候选沉淀先经冻结用例 + 独立评分者评估再接受(rubric 加密落盘)
|
|
@@ -30,8 +30,8 @@ Agent 在每个会话里积累可复用经验(重复失败、持久事实、
|
|
|
30
30
|
|
|
31
31
|
## 工作原理
|
|
32
32
|
|
|
33
|
-
1. **沉淀**——模型经 `evolve_add`
|
|
34
|
-
2. **能力感知的辅助调用**——memory loop、
|
|
33
|
+
1. **沉淀**——模型经 `evolve_add` 创建条目;专用 Memory Agent 只在四个低频时刻消费增量 snapshot(压缩、goal 连续受阻、会话收尾 drain、手动 wrapup)。
|
|
34
|
+
2. **能力感知的辅助调用**——memory loop、planner、wrapup 通过 [`src/llm-text.ts`](src/llm-text.ts) 解析精确 provider/model 能力并使用模型公布的最低开启 reasoning effort,同时转发 host session id 供 provider 路由;只有没有开启档时才回退关闭档,没有 reasoning 元数据时使用 provider 默认行为。
|
|
35
35
|
3. **守卫**——代码强制校验:编辑 schema、blast-radius 与作用域一致性、晋升政策(项目专属标记 / 过薄内容 / 近似重复检测 / 凭据筛查保持全局库干净——密钥类内容在所有写入出口被拒,含 mount 物化)。全局 create 与既有条目高度相似(≥0.8)时写入即拒;中等重叠带 `conflictHint` 供后续合并。
|
|
36
36
|
4. **审批**——全局与项目写入需明确人工批准;弹窗展示有界结构化编辑 diff 与冲突提示,弹窗丢失/响应畸形会重试,不会被误记为拒绝。
|
|
37
37
|
5. **应用与注入**——memory 批次先完成所有持久化审批,写前重查 abort;后续 scope 失败时补偿回滚先前写入,成功 scope 仍保留快照与审计。prompt 补充与委派规格注入系统提示词(封顶、按相关性排序、被证伪条目降权、空 store 零 token);**memory 正文**在会话开场按硬预算注入(会话内冻结,when_to_save 指南随行);skill 仍以按相关性排序的目录索引出现。
|
|
@@ -67,14 +67,14 @@ dsh plugin add ZK-Andy/dsh-continual-evolve
|
|
|
67
67
|
| `/evolve mount · unmount <skillId>` | 把可执行技能热挂载为 live 插件 |
|
|
68
68
|
| `/evolve goal [objective · done · block]` | 回合驱动的自进化目标 |
|
|
69
69
|
| `/evolve benchmark …` | 用例生命周期、运行、接受决策 |
|
|
70
|
-
| `/evolve pause · resume · status` |
|
|
71
|
-
| `/evolve usage` | 每条目注入次数 + memory/
|
|
70
|
+
| `/evolve pause · resume · status` | 暂停/恢复自动提取(手动工具不受影响)、运行时状态 |
|
|
71
|
+
| `/evolve usage` | 每条目注入次数 + memory/planner/wrapup 直属调用的 provider 精确 token(不含 benchmark 宿主子代理) |
|
|
72
72
|
|
|
73
73
|
模型工具:`evolve_list / add / update / delete / rollback / recall`(`evolve_delete` 支持 `id` 或批量 `ids` 数组——一次 refinement、一次审批;`evolve_recall` 按 query/kind/scope/memoryType/limit 过滤,返回全文 + 版本 + 来源 + 过时信号)。记忆的读写都在对话里完成——模型手里有注入的记忆索引 + `evolve_recall`/`evolve_add`——因此不再有 `/evolve remember · forget · recall` 对应命令:直接在对话里说。
|
|
74
74
|
|
|
75
75
|
第三方消费:每次进化落地(门禁或手动)都会向 `reviews.jsonl` 追加结构化 `evolve_complete` 事件(shape 见 `src/evolve-event.ts`),与人类可读的审计记录并存。
|
|
76
76
|
|
|
77
|
-
`/evolve usage` 还会读取 `evolve/token-usage.jsonl`:插件直属 memory Agent、
|
|
77
|
+
`/evolve usage` 还会读取 `evolve/token-usage.jsonl`:插件直属 memory Agent、planner 与手动 wrapup 调用的 provider 精确 input/cache/output/total token。报告只覆盖保留尾部而非终身累计,单独显示 provider 未返回 usage 的调用,并明确排除宿主 benchmark 子代理、其 agent-loop 调用与逐条 memory 注入归因。
|
|
78
78
|
|
|
79
79
|
注入形态:prompt 补充与委派规格带内容注入(每 kind ≤6 条 × 180 字符,按相关性排序)。memory 以**正文**在会话开场注入:`evolve:memory-index` section(order 400)承载 when_to_save 指南 + 预算内的全部记忆正文,排序 `project > feedback > user > reference`,放不下的降级为 `[memory:type:id] 标题`钩子、其余折叠计数(硬上限 `memoryIndex.maxChars`,默认 6000 字符;未展示的用 `evolve_recall` 读)。该 section 每会话只算一次并逐字节复用,system prompt 因此稳定、prompt cache 持续命中——会话中途写入的记忆下个会话生效。skill 仍以按相关性排序的目录索引出现(15 行封顶 + 折叠计数行),memory 不再列入。每次 memory 落盘同时刷新 store 目录下的可读 `MEMORY.md` 索引 + 单事实文件。`memoryIndex.guide` 关闭且 store 为空时 = 零注入 token。
|
|
80
80
|
|
|
@@ -86,14 +86,12 @@ dsh plugin add ZK-Andy/dsh-continual-evolve
|
|
|
86
86
|
| `autoReview` | `false` | 没有 `evolve/runtime.json` 时 Memory Agent 的初始默认;监听器始终注册,因此它不是注册门 |
|
|
87
87
|
| `memoryMinUserWords` | `3` | ZCode 风格:单个直接用户文本至少包含的词数;使用 CJK 分词 |
|
|
88
88
|
| `sessionCloseDrainMs` | `15000` | 会话关闭时在途提取的有界 drain(毫秒,`0` 立即 abort) |
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
| `notifyOnAutoReview` | `true` | 门禁应用后发可见跟进通知 |
|
|
89
|
+
| `maxReviewInputChars` | `40000` | 交给提取器的轨迹切片 |
|
|
90
|
+
| `reviewBudgetTokens` | `4096` | 提取 loop 输出预算 |
|
|
91
|
+
| `notifyOnAutoReview` | `true` | goal 受阻时刻应用后发可见跟进回执(压缩与会话收尾只留审计) |
|
|
93
92
|
| `requireGlobalApproval` | `true` | 全局与项目写入需明确批准 |
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
-
| `goalBlockedWrapupTurns` | `3` | 连续阻塞目标的门禁轮数触发一次归宿评估(`0` 关闭) |
|
|
93
|
+
| `recordLanguage` | `auto` | 记录**与弹窗**语言:`auto` 依次跟随 DSH 客户端偏好 → 会话自身用户文本 → `en`;`zh`/`en` 固定 |
|
|
94
|
+
| `goalBlockedWrapupTurns` | `3` | 连续阻塞目标的 idle 探测轮数触发一次记忆提取(`0` 关闭) |
|
|
97
95
|
| `promotionBlockPatterns` | POSIX 路径、session id、`~/.dsh` | 内容命中即判定项目专属,永不晋升全局 |
|
|
98
96
|
| `promotionMinChars` | `100` | 低于此长度的整体晋升留在本地 |
|
|
99
97
|
| `injectionDirectoryLines` | `15` | 每次构建的目录行数上限,超出折叠为计数行 |
|
|
@@ -107,7 +105,7 @@ dsh plugin add ZK-Andy/dsh-continual-evolve
|
|
|
107
105
|
| `logToFile` / `logLevel` / `logMaxBytes` | `true` / `1` / 5 MiB | 插件自带 JSONL 文件日志带轮转 |
|
|
108
106
|
| `autoRollbackOnReject` | `true` | benchmark 拒绝后自动确定性回滚 |
|
|
109
107
|
| `autoCase` | `true` | 失败的进化尝试自动沉淀为 draft 回归用例(`auto_regression` 基准) |
|
|
110
|
-
| `reviewModel` | agent 自身 | 专用 memory Agent
|
|
108
|
+
| `reviewModel` | agent 自身 | 专用 memory Agent 可选更便宜的模型(`"provider/model"`) |
|
|
111
109
|
| `plannerPrefixCache` | `auto` | 有缓存证据时用会话前缀输入(`session` 总是前缀,`off` 保持旧扁平文本) |
|
|
112
110
|
| `plannerPrefixMaxChars` | `12000` | Route A 会话前缀预算(字符) |
|
|
113
111
|
| `historyRetain` | `{snapshots: 20, refinements: 500, reviews: 500, tokenUsage: 500}` | 存储卫生:每 store 快照数、每 store 历史尾行、共享 `reviews.jsonl` 尾行、直属调用 `token-usage.jsonl` 尾行 |
|
|
@@ -118,16 +116,15 @@ profile patch 示例:
|
|
|
118
116
|
- id: continual-evolve
|
|
119
117
|
config:
|
|
120
118
|
autoReview: true
|
|
121
|
-
reviewIntervalTurns: 6
|
|
122
119
|
```
|
|
123
120
|
|
|
124
|
-
即使 `autoReview` 为 `false`,Memory Agent 监听器也会注册——`autoReview` 只提供初始默认值,装完即用,无需改 profile。使用 `/evolve resume`
|
|
121
|
+
即使 `autoReview` 为 `false`,Memory Agent 监听器也会注册——`autoReview` 只提供初始默认值,装完即用,无需改 profile。使用 `/evolve resume` 立即开启提取时刻,使用 `/evolve pause` 抑制新的模型调用,使用 `/evolve status` 查看配置默认值与运行时状态。开关保存在 `evolve/runtime.json`;手动 `evolve_*` 工具和 `/evolve` 命令不受暂停影响。提取时刻驱动:压缩、goal 连续受阻(`goalBlockedWrapupTurns` 次 idle 探测)、会话收尾 drain(`sessionCloseDrainMs`)与手动 `/evolve wrapup`——成功回合零 LLM 成本。Memory 触发采用 ZCode 的轻量 eligibility:单个直接用户文本至少包含 `memoryMinUserWords` 个词(使用 CJK 分词);空增量、内部 Agent、直接 memory 写入会跳过。每次提取都在 `reviews.jsonl` 留统一审计回执(`noop`/`applied`/`declined` + 耗时与轮次/检索统计);只有 goal 受阻时刻的实际沉淀才排队前台回执,关闭的会话让在途提取在 `sessionCloseDrainMs` 内收尾再 abort。
|
|
125
122
|
|
|
126
123
|
## 开发
|
|
127
124
|
|
|
128
125
|
```bash
|
|
129
126
|
pnpm install && pnpm build # 依赖 + tsc -> lib/
|
|
130
|
-
pnpm test # vitest(
|
|
127
|
+
pnpm test # vitest(1020 例)
|
|
131
128
|
pnpm test:coverage # v8 覆盖率,CI 强制阈值
|
|
132
129
|
pnpm coverage:gaps # 定位各文件未覆盖行(只读)
|
|
133
130
|
pnpm lint # oxlint src test
|
|
@@ -136,11 +133,11 @@ pnpm lint # oxlint src test
|
|
|
136
133
|
目录结构:
|
|
137
134
|
|
|
138
135
|
```
|
|
139
|
-
├── src/ # 引擎、工具、命令、memory Agent
|
|
136
|
+
├── src/ # 引擎、工具、命令、memory Agent、召回、投影、benchmark、注入 + token 用量…
|
|
140
137
|
├── test/ # vitest 测试套件(59 个文件)
|
|
141
138
|
├── lib/ # 构建产物(tsc)
|
|
142
139
|
├── docs/
|
|
143
|
-
│ ├── design.md #
|
|
140
|
+
│ ├── design.md # 一条循环的设计叙事
|
|
144
141
|
│ ├── FAQ.md # 真实踩坑记录
|
|
145
142
|
│ ├── gap-analysis.md # 对照 prime-agent /refine + penguin-harness
|
|
146
143
|
│ ├── research/pi-dsh-competitor-gap-analysis.md # pi/dsh 生态竞品差距分析
|
package/lib/approval.d.ts
CHANGED
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { Context } from "@deepseek-ai/cordis";
|
|
8
8
|
import type { Agent } from "@deepseek-ai/dsh-agent";
|
|
9
|
-
import type
|
|
10
|
-
export type ScopeApprovalDecision
|
|
9
|
+
import { type RecordLanguagePreference } from "./record-language.js";
|
|
10
|
+
export { type ScopeApprovalDecision } from "./types.js";
|
|
11
|
+
import type { ScopeApprovalDecision } from "./types.js";
|
|
12
|
+
/** Labels the approval dialog offers for each decision (parser contract). */
|
|
13
|
+
export declare const APPROVE_LABELS: readonly ["批准", "Approve"];
|
|
14
|
+
export declare const DECLINE_LABELS: readonly ["拒绝", "Decline"];
|
|
11
15
|
export interface QuestionService {
|
|
12
16
|
ask(request: {
|
|
13
17
|
questions: {
|
|
@@ -24,6 +28,7 @@ export interface QuestionService {
|
|
|
24
28
|
answers?: {
|
|
25
29
|
id: string;
|
|
26
30
|
selected?: string[];
|
|
31
|
+
custom?: string;
|
|
27
32
|
}[];
|
|
28
33
|
}>;
|
|
29
34
|
}
|
|
@@ -41,20 +46,28 @@ export declare function questionServiceOf(ctx: Context): QuestionService | undef
|
|
|
41
46
|
* Copy follows the headline → details → impact shape in the resolved dialog
|
|
42
47
|
* language; labels stay literal per language for parser compatibility.
|
|
43
48
|
*
|
|
49
|
+
* Language resolution runs the full record-language chain — explicit config,
|
|
50
|
+
* then the durable client preference, then the session's own recent user text
|
|
51
|
+
* — because an approval dialog raised from a tool call DOES have a session
|
|
52
|
+
* behind it. Stopping at the durable tier gave a Chinese-speaking user English
|
|
53
|
+
* dialogs whenever the stored preference was unset (2026-10-01).
|
|
54
|
+
*
|
|
44
55
|
* @param ctx Cordis context carrying the userQuestions service.
|
|
45
56
|
* @param agent Agent prompting the question, if any.
|
|
46
57
|
* @param signal Abort signal for the question, if any.
|
|
47
58
|
* @param scope Target persistent scope.
|
|
48
59
|
* @param what Edit summary; truncated to 300 chars with "…" when longer.
|
|
49
|
-
* @param
|
|
50
|
-
*
|
|
60
|
+
* @param configured Plugin `recordLanguage` preference; `auto`/absent defers
|
|
61
|
+
* to the durable preference and the session's user text.
|
|
51
62
|
* @returns "approved" when the user picks the approval label, otherwise "declined".
|
|
52
63
|
* @throws When the service is missing or the answer is not unique/explicit.
|
|
53
64
|
*/
|
|
54
|
-
export declare function requestScopeApproval(ctx: Context, agent: Agent | undefined, signal: AbortSignal | undefined, scope: "project" | "global", what: string,
|
|
65
|
+
export declare function requestScopeApproval(ctx: Context, agent: Agent | undefined, signal: AbortSignal | undefined, scope: "project" | "global", what: string, configured?: RecordLanguagePreference): Promise<ScopeApprovalDecision>;
|
|
55
66
|
/**
|
|
56
67
|
* Ask the user to approve a global edit. Throws when the service is missing,
|
|
57
68
|
* the user declines, or the question cannot be answered.
|
|
69
|
+
*
|
|
70
|
+
* @param configured Plugin `recordLanguage` preference (see {@link requestScopeApproval}).
|
|
58
71
|
*/
|
|
59
|
-
export declare function requireGlobalApproval(ctx: Context, agent: Agent | undefined, signal: AbortSignal | undefined, what: string): Promise<void>;
|
|
72
|
+
export declare function requireGlobalApproval(ctx: Context, agent: Agent | undefined, signal: AbortSignal | undefined, what: string, configured?: RecordLanguagePreference): Promise<void>;
|
|
60
73
|
//# sourceMappingURL=approval.d.ts.map
|
package/lib/approval.js
CHANGED
|
@@ -1,4 +1,39 @@
|
|
|
1
|
-
import { approvalCopy
|
|
1
|
+
import { approvalCopy } from "./copy.js";
|
|
2
|
+
import { normalizeRecordLanguage, resolveRecordLanguage } from "./record-language.js";
|
|
3
|
+
import { recentUserText } from "./inject.js";
|
|
4
|
+
/** Labels the approval dialog offers for each decision (parser contract). */
|
|
5
|
+
export const APPROVE_LABELS = ["批准", "Approve"];
|
|
6
|
+
export const DECLINE_LABELS = ["拒绝", "Decline"];
|
|
7
|
+
/**
|
|
8
|
+
* Typed ("Other") answers accepted as an explicit decision once normalized.
|
|
9
|
+
* Deliberately exact: a substring rule would read "不批准" as approval, and a
|
|
10
|
+
* misread decision is far worse than asking the human to click the button.
|
|
11
|
+
*/
|
|
12
|
+
const TYPED_APPROVALS = new Set(["批准", "approve"]);
|
|
13
|
+
const TYPED_DECLINES = new Set(["拒绝", "decline"]);
|
|
14
|
+
/** Trim case/quotes/trailing punctuation and a trailing 吧/了 from a typed answer. */
|
|
15
|
+
function normalizeTypedAnswer(text) {
|
|
16
|
+
return text
|
|
17
|
+
.trim()
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/^[\s"'“”「」]+/, "")
|
|
20
|
+
.replace(/[\s"'“”「」。!!,,、]+$/, "")
|
|
21
|
+
.replace(/[吧了]$/, "");
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read a free-text answer as a decision, or `undefined` when it matches no
|
|
25
|
+
* label exactly. Never guesses.
|
|
26
|
+
*/
|
|
27
|
+
function typedDecision(custom) {
|
|
28
|
+
if (typeof custom !== "string")
|
|
29
|
+
return undefined;
|
|
30
|
+
const normalized = normalizeTypedAnswer(custom);
|
|
31
|
+
if (TYPED_APPROVALS.has(normalized))
|
|
32
|
+
return "approved";
|
|
33
|
+
if (TYPED_DECLINES.has(normalized))
|
|
34
|
+
return "declined";
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
2
37
|
/**
|
|
3
38
|
* Lazily resolve the userQuestions service from the context.
|
|
4
39
|
* Returns undefined when the service is not loaded — callers decide
|
|
@@ -15,22 +50,30 @@ export function questionServiceOf(ctx) {
|
|
|
15
50
|
* Copy follows the headline → details → impact shape in the resolved dialog
|
|
16
51
|
* language; labels stay literal per language for parser compatibility.
|
|
17
52
|
*
|
|
53
|
+
* Language resolution runs the full record-language chain — explicit config,
|
|
54
|
+
* then the durable client preference, then the session's own recent user text
|
|
55
|
+
* — because an approval dialog raised from a tool call DOES have a session
|
|
56
|
+
* behind it. Stopping at the durable tier gave a Chinese-speaking user English
|
|
57
|
+
* dialogs whenever the stored preference was unset (2026-10-01).
|
|
58
|
+
*
|
|
18
59
|
* @param ctx Cordis context carrying the userQuestions service.
|
|
19
60
|
* @param agent Agent prompting the question, if any.
|
|
20
61
|
* @param signal Abort signal for the question, if any.
|
|
21
62
|
* @param scope Target persistent scope.
|
|
22
63
|
* @param what Edit summary; truncated to 300 chars with "…" when longer.
|
|
23
|
-
* @param
|
|
24
|
-
*
|
|
64
|
+
* @param configured Plugin `recordLanguage` preference; `auto`/absent defers
|
|
65
|
+
* to the durable preference and the session's user text.
|
|
25
66
|
* @returns "approved" when the user picks the approval label, otherwise "declined".
|
|
26
67
|
* @throws When the service is missing or the answer is not unique/explicit.
|
|
27
68
|
*/
|
|
28
|
-
export async function requestScopeApproval(ctx, agent, signal, scope, what,
|
|
69
|
+
export async function requestScopeApproval(ctx, agent, signal, scope, what, configured) {
|
|
29
70
|
const userQuestions = questionServiceOf(ctx);
|
|
30
71
|
if (!userQuestions) {
|
|
31
72
|
throw new Error("global evolution edits require the userQuestions service (load @deepseek-ai/dsh-user-questions)");
|
|
32
73
|
}
|
|
33
|
-
const
|
|
74
|
+
const lang = normalizeRecordLanguage(configured) ??
|
|
75
|
+
resolveRecordLanguage({ ctx, trajectoryText: recentUserText(agent) });
|
|
76
|
+
const copy = approvalCopy(scope, what, lang);
|
|
34
77
|
const answer = await userQuestions.ask({
|
|
35
78
|
questions: [
|
|
36
79
|
{
|
|
@@ -46,20 +89,38 @@ export async function requestScopeApproval(ctx, agent, signal, scope, what, lang
|
|
|
46
89
|
if (matching.length !== 1 || !Array.isArray(matching[0]?.selected)) {
|
|
47
90
|
throw new Error("evolution approval returned no unique explicit decision");
|
|
48
91
|
}
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
92
|
+
const entry = matching[0];
|
|
93
|
+
const selected = [...new Set(entry.selected)];
|
|
94
|
+
if (selected.length === 0) {
|
|
95
|
+
// A typed "Other" answer counts only when it matches a dialog label
|
|
96
|
+
// exactly; anything fuzzier stays an error, so a lost or ambiguous
|
|
97
|
+
// reply is never recorded as a durable rejection.
|
|
98
|
+
const typed = typedDecision(entry.custom);
|
|
99
|
+
if (typed !== undefined) {
|
|
100
|
+
return typed;
|
|
101
|
+
}
|
|
102
|
+
throw new Error(`evolution approval needs one clicked option (${APPROVE_LABELS.join("/")} or ${DECLINE_LABELS.join("/")}) — a typed reply cannot serve as a decision`);
|
|
103
|
+
}
|
|
104
|
+
if (selected.length !== 1) {
|
|
53
105
|
throw new Error(`evolution approval returned an invalid decision: ${JSON.stringify(selected)}`);
|
|
54
106
|
}
|
|
55
|
-
|
|
107
|
+
const label = selected[0];
|
|
108
|
+
if (APPROVE_LABELS.includes(label)) {
|
|
109
|
+
return "approved";
|
|
110
|
+
}
|
|
111
|
+
if (DECLINE_LABELS.includes(label)) {
|
|
112
|
+
return "declined";
|
|
113
|
+
}
|
|
114
|
+
throw new Error(`evolution approval returned an unknown decision label: ${JSON.stringify(label)}`);
|
|
56
115
|
}
|
|
57
116
|
/**
|
|
58
117
|
* Ask the user to approve a global edit. Throws when the service is missing,
|
|
59
118
|
* the user declines, or the question cannot be answered.
|
|
119
|
+
*
|
|
120
|
+
* @param configured Plugin `recordLanguage` preference (see {@link requestScopeApproval}).
|
|
60
121
|
*/
|
|
61
|
-
export async function requireGlobalApproval(ctx, agent, signal, what) {
|
|
62
|
-
if ((await requestScopeApproval(ctx, agent, signal, "global", what)) !== "approved") {
|
|
122
|
+
export async function requireGlobalApproval(ctx, agent, signal, what, configured) {
|
|
123
|
+
if ((await requestScopeApproval(ctx, agent, signal, "global", what, configured)) !== "approved") {
|
|
63
124
|
throw new Error("global evolution edit rejected by the user");
|
|
64
125
|
}
|
|
65
126
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface ReviewAuditRow {
|
|
2
|
+
sessionId: string;
|
|
3
|
+
reason: string;
|
|
4
|
+
turnsSinceLastReview: number;
|
|
5
|
+
outcome: string;
|
|
6
|
+
rationale?: string;
|
|
7
|
+
[key: string]: unknown;
|
|
8
|
+
}
|
|
9
|
+
/** Resolve the shared audit trail path under `<baseDir>/evolve/`. */
|
|
10
|
+
export declare function reviewsAuditPath(baseDir: string): string;
|
|
11
|
+
/** Append one audit row and bound the trail at write time. Never throws. */
|
|
12
|
+
export declare function appendReviewRecord(baseDir: string, entry: ReviewAuditRow, retain: number | undefined, onError?: (cause: unknown) => void): void;
|
|
13
|
+
/**
|
|
14
|
+
* Boot-time diagnostic: the armed marker proves the listener was registered
|
|
15
|
+
* even when its runtime default is off, distinguishing "not registered"
|
|
16
|
+
* from "off". Never throws.
|
|
17
|
+
*/
|
|
18
|
+
export declare function writeArmedMarker(baseDir: string, rationale: string, onError?: (cause: unknown) => void): void;
|
|
19
|
+
//# sourceMappingURL=audit-log.d.ts.map
|
package/lib/audit-log.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shared `reviews.jsonl` audit trail: the only writer for extraction
|
|
3
|
+
* decisions, mechanical skips, and the boot armed marker. Writes are
|
|
4
|
+
* contained — a broken ledger must never break the extraction path that
|
|
5
|
+
* already made its decision.
|
|
6
|
+
*/
|
|
7
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { DEFAULT_REVIEWS_RETAIN, pruneJsonlFile } from "./store.js";
|
|
10
|
+
/** Resolve the shared audit trail path under `<baseDir>/evolve/`. */
|
|
11
|
+
export function reviewsAuditPath(baseDir) {
|
|
12
|
+
return join(baseDir, "evolve", "reviews.jsonl");
|
|
13
|
+
}
|
|
14
|
+
/** Append one audit row and bound the trail at write time. Never throws. */
|
|
15
|
+
export function appendReviewRecord(baseDir, entry, retain, onError) {
|
|
16
|
+
try {
|
|
17
|
+
mkdirSync(join(baseDir, "evolve"), { recursive: true });
|
|
18
|
+
appendFileSync(reviewsAuditPath(baseDir), `${JSON.stringify({ ...entry, timestamp: new Date().toISOString() })}\n`, "utf8");
|
|
19
|
+
}
|
|
20
|
+
catch (cause) {
|
|
21
|
+
onError?.(cause);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
pruneJsonlFile(reviewsAuditPath(baseDir), retain ?? DEFAULT_REVIEWS_RETAIN);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// ignored — the next record retries
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Boot-time diagnostic: the armed marker proves the listener was registered
|
|
33
|
+
* even when its runtime default is off, distinguishing "not registered"
|
|
34
|
+
* from "off". Never throws.
|
|
35
|
+
*/
|
|
36
|
+
export function writeArmedMarker(baseDir, rationale, onError) {
|
|
37
|
+
try {
|
|
38
|
+
mkdirSync(join(baseDir, "evolve"), { recursive: true });
|
|
39
|
+
appendFileSync(reviewsAuditPath(baseDir), `${JSON.stringify({
|
|
40
|
+
timestamp: new Date().toISOString(),
|
|
41
|
+
sessionId: "boot",
|
|
42
|
+
reason: "boot",
|
|
43
|
+
turnsSinceLastReview: 0,
|
|
44
|
+
outcome: "armed",
|
|
45
|
+
rationale,
|
|
46
|
+
})}\n`, "utf8");
|
|
47
|
+
}
|
|
48
|
+
catch (cause) {
|
|
49
|
+
onError?.(cause);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=audit-log.js.map
|
package/lib/auto.js
CHANGED
|
@@ -504,6 +504,7 @@ export async function runMemoryExtractionPhase(ctx, engine, agent, config, state
|
|
|
504
504
|
decisionCursor: memorySnapshot.cursor,
|
|
505
505
|
scopeDecisions: state.memoryDecisions,
|
|
506
506
|
onScopeDecision: (key, decision) => rememberMemoryDecision(state, key, decision),
|
|
507
|
+
...(config.recordLanguage !== undefined ? { recordLanguage: config.recordLanguage } : {}),
|
|
507
508
|
...(signal ? { signal } : {}),
|
|
508
509
|
});
|
|
509
510
|
for (const result of application.results) {
|
|
@@ -4,6 +4,6 @@
|
|
|
4
4
|
import type { Context } from "@deepseek-ai/cordis";
|
|
5
5
|
import type { CommandInvocation, CommandResult } from "@deepseek-ai/dsh-commands";
|
|
6
6
|
import type { EvolutionEngine } from "./service.js";
|
|
7
|
-
import type { CommandRuntimeOptions } from "./command.js";
|
|
7
|
+
import type { CommandRuntimeOptions } from "./command-util.js";
|
|
8
8
|
export declare function executeBenchmarkCommand(ctx: Context, engine: EvolutionEngine, invocation: CommandInvocation, rest: string[], runtime: CommandRuntimeOptions): Promise<CommandResult>;
|
|
9
9
|
//# sourceMappingURL=benchmark-command.d.ts.map
|
package/lib/benchmark-command.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatHarnessStateForPrompt } from "./render.js";
|
|
2
|
-
import { stripAngleBrackets } from "./command.js";
|
|
2
|
+
import { stripAngleBrackets } from "./command-util.js";
|
|
3
3
|
import { addCase, caseCheckProblems, createBenchmark, listBenchmarks, listCases, loadBenchmark, loadCaseMeta, loadScoreboard, rollbackRejectedCandidate, saveCaseMeta, saveScoreboard, transitionCaseStatus } from "./benchmark.js";
|
|
4
4
|
import { AUTO_CASE_BENCHMARK_ID, captureAutoCase } from "./autocase.js";
|
|
5
5
|
import { decide, decisionReport, entryFromCells, flagMaterialDrift } from "./score.js";
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared command-surface utilities: pure input parsing, entry lookup, and
|
|
3
|
+
* result rendering used by the `/evolve` router and every sub-command file.
|
|
4
|
+
* Lives below the interface layer so sub-command files can import it without
|
|
5
|
+
* cycling through command.ts.
|
|
6
|
+
*/
|
|
7
|
+
import type { HarnessEntry, HarnessState, HarnessScope, RefinementKind, RefinementResult } from "./types.js";
|
|
8
|
+
import type { CommandInvocation } from "@deepseek-ai/dsh-commands";
|
|
9
|
+
import type { PromotionPolicy } from "./promotion.js";
|
|
10
|
+
import type { RecordLanguagePreference } from "./record-language.js";
|
|
11
|
+
export interface CommandGateOptions {
|
|
12
|
+
requireGlobalApproval: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface CommandRuntimeOptions {
|
|
15
|
+
rubricKey: Buffer;
|
|
16
|
+
/** When a benchmark decision rejects a candidate, roll the refinement back automatically. */
|
|
17
|
+
autoRollbackOnReject: boolean;
|
|
18
|
+
/** P1: capture failed evolution attempts as draft cases in the auto-regression benchmark. */
|
|
19
|
+
autoCase: boolean;
|
|
20
|
+
/** Mechanical promotion guards for wrapup (2026-08-22 policy). */
|
|
21
|
+
promotionPolicy: PromotionPolicy;
|
|
22
|
+
/**
|
|
23
|
+
* Initial Memory Agent default from plugin config. The listener is always
|
|
24
|
+
* registered; this is not a registration gate.
|
|
25
|
+
*/
|
|
26
|
+
autoReview?: boolean;
|
|
27
|
+
/** Plugin `recordLanguage` preference for dialog copy (see `approval.ts`). */
|
|
28
|
+
recordLanguage?: RecordLanguagePreference;
|
|
29
|
+
}
|
|
30
|
+
/** Parse an optional leading scope token ("global" | "project") off the args. */
|
|
31
|
+
export declare function scopeArg(tokens: string[]): {
|
|
32
|
+
scope: HarnessScope;
|
|
33
|
+
rest: string[];
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The store id a scope reads/writes from the human command: live session id
|
|
37
|
+
* for local, derived project key for project, undefined for global. Throws
|
|
38
|
+
* for project when the session cwd is unavailable.
|
|
39
|
+
*/
|
|
40
|
+
export declare function storeIdForCommand(scope: HarnessScope, invocation: CommandInvocation): string | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Tokenize a command's raw input with shell-like quoting:
|
|
43
|
+
* - a `#` outside quotes starts a comment (rest of the line is dropped);
|
|
44
|
+
* - whitespace separates tokens;
|
|
45
|
+
* - double or single quotes group words into one token and are stripped.
|
|
46
|
+
*
|
|
47
|
+
* This lets users paste help-text examples verbatim, e.g.
|
|
48
|
+
* `/evolve benchmark add-case <bid> "<title>" "<statement>" "<rubric>"`.
|
|
49
|
+
*/
|
|
50
|
+
export declare function tokenizeEvolveInput(rawInput: string): string[];
|
|
51
|
+
/** Accept both `<id>` (help-text placeholder form) and bare `id`. */
|
|
52
|
+
export declare function stripAngleBrackets(value: string): string;
|
|
53
|
+
/**
|
|
54
|
+
* Locate an entry by id across every kind of a store. Ids are only unique
|
|
55
|
+
* within a kind, so the lookup scans all four and returns the first match
|
|
56
|
+
* (kind + entry) or undefined. Used by archive/unarchive, which take a bare
|
|
57
|
+
* id from the user.
|
|
58
|
+
*/
|
|
59
|
+
export declare function findEntryById(state: HarnessState, id: string): [RefinementKind, HarnessEntry] | undefined;
|
|
60
|
+
export declare function parsePositiveInt(value: string, what: string): number;
|
|
61
|
+
/** Structural stand-in for the host `CommandResult` (kind + text only). */
|
|
62
|
+
export interface CommandTextResult {
|
|
63
|
+
kind: "success" | "error";
|
|
64
|
+
text: string;
|
|
65
|
+
}
|
|
66
|
+
export declare function success(text: string): CommandTextResult;
|
|
67
|
+
export declare function error(text: string): CommandTextResult;
|
|
68
|
+
/** Human-readable one-refinement rendering shared by every apply path. */
|
|
69
|
+
export declare function renderResult(result: RefinementResult): string;
|
|
70
|
+
//# sourceMappingURL=command-util.d.ts.map
|