dsh-continual-evolve 0.11.0 → 0.12.1
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 +42 -115
- package/README.zh.md +33 -93
- package/client/client.js +253 -0
- package/cordis.patch.yml +2 -2
- package/lib/card-routes.d.ts +32 -0
- package/lib/card-routes.js +92 -0
- package/lib/index.d.ts +65 -217
- package/lib/index.js +74 -234
- package/lib/known-workspaces.d.ts +22 -0
- package/lib/known-workspaces.js +42 -0
- package/lib/memory-guide.d.ts +13 -14
- package/lib/memory-guide.js +34 -21
- package/lib/memory-section.d.ts +77 -0
- package/lib/memory-section.js +189 -0
- package/lib/memory-snapshot.d.ts +54 -0
- package/lib/memory-snapshot.js +125 -0
- package/package.json +8 -17
- package/lib/apply.d.ts +0 -22
- package/lib/apply.js +0 -157
- package/lib/approval.d.ts +0 -73
- package/lib/approval.js +0 -127
- package/lib/audit-log.d.ts +0 -19
- package/lib/audit-log.js +0 -52
- package/lib/auto.d.ts +0 -236
- package/lib/auto.js +0 -773
- package/lib/autocase.d.ts +0 -38
- package/lib/autocase.js +0 -76
- package/lib/benchmark-command.d.ts +0 -9
- package/lib/benchmark-command.js +0 -357
- package/lib/benchmark.d.ts +0 -151
- package/lib/benchmark.js +0 -250
- package/lib/command-util.d.ts +0 -70
- package/lib/command-util.js +0 -123
- package/lib/command.d.ts +0 -13
- package/lib/command.js +0 -134
- package/lib/consolidate.d.ts +0 -90
- package/lib/consolidate.js +0 -180
- package/lib/copy.d.ts +0 -37
- package/lib/copy.js +0 -58
- package/lib/declines.d.ts +0 -103
- package/lib/declines.js +0 -179
- package/lib/evaluate.d.ts +0 -74
- package/lib/evaluate.js +0 -271
- package/lib/evolve-event.d.ts +0 -40
- package/lib/evolve-event.js +0 -60
- package/lib/extraction-phase.d.ts +0 -132
- package/lib/extraction-phase.js +0 -236
- package/lib/failures.d.ts +0 -42
- package/lib/failures.js +0 -171
- package/lib/fate.d.ts +0 -130
- package/lib/fate.js +0 -350
- package/lib/goal-command.d.ts +0 -7
- package/lib/goal-command.js +0 -37
- package/lib/goal.d.ts +0 -72
- package/lib/goal.js +0 -72
- package/lib/inject.d.ts +0 -90
- package/lib/inject.js +0 -164
- package/lib/injection-caps.d.ts +0 -4
- package/lib/injection-caps.js +0 -4
- package/lib/injection-directory.d.ts +0 -29
- package/lib/injection-directory.js +0 -78
- package/lib/injection-rank.d.ts +0 -85
- package/lib/injection-rank.js +0 -161
- package/lib/listener.d.ts +0 -45
- package/lib/listener.js +0 -199
- package/lib/llm-text.d.ts +0 -104
- package/lib/llm-text.js +0 -140
- package/lib/logfile.d.ts +0 -71
- package/lib/logfile.js +0 -159
- package/lib/maintenance-commands.d.ts +0 -23
- package/lib/maintenance-commands.js +0 -136
- package/lib/memory-agent.d.ts +0 -93
- package/lib/memory-agent.js +0 -300
- package/lib/memory-apply.d.ts +0 -44
- package/lib/memory-apply.js +0 -202
- package/lib/memory-benchmark.d.ts +0 -76
- package/lib/memory-benchmark.js +0 -170
- package/lib/memory-index.d.ts +0 -114
- package/lib/memory-index.js +0 -197
- package/lib/memory-manifest.d.ts +0 -16
- package/lib/memory-manifest.js +0 -70
- package/lib/message-source.d.ts +0 -23
- package/lib/message-source.js +0 -12
- package/lib/mount-command.d.ts +0 -10
- package/lib/mount-command.js +0 -48
- package/lib/mount.d.ts +0 -42
- package/lib/mount.js +0 -212
- package/lib/notify.d.ts +0 -48
- package/lib/notify.js +0 -57
- package/lib/plan-command.d.ts +0 -12
- package/lib/plan-command.js +0 -38
- package/lib/plan.d.ts +0 -16
- package/lib/plan.js +0 -126
- package/lib/planner.d.ts +0 -61
- package/lib/planner.js +0 -144
- package/lib/pool.d.ts +0 -7
- package/lib/pool.js +0 -25
- package/lib/prefix-cache.d.ts +0 -79
- package/lib/prefix-cache.js +0 -168
- package/lib/project.d.ts +0 -28
- package/lib/project.js +0 -66
- package/lib/projection.d.ts +0 -22
- package/lib/projection.js +0 -112
- package/lib/promotion.d.ts +0 -94
- package/lib/promotion.js +0 -171
- package/lib/recall.d.ts +0 -85
- package/lib/recall.js +0 -142
- package/lib/record-language.d.ts +0 -85
- package/lib/record-language.js +0 -152
- package/lib/render.d.ts +0 -13
- package/lib/render.js +0 -80
- package/lib/review-scheduler.d.ts +0 -38
- package/lib/review-scheduler.js +0 -183
- package/lib/review.d.ts +0 -60
- package/lib/review.js +0 -145
- package/lib/rollback.d.ts +0 -9
- package/lib/rollback.js +0 -68
- package/lib/rubric.d.ts +0 -29
- package/lib/rubric.js +0 -119
- package/lib/runtime-commands.d.ts +0 -14
- package/lib/runtime-commands.js +0 -115
- package/lib/runtime.d.ts +0 -24
- package/lib/runtime.js +0 -87
- package/lib/score.d.ts +0 -64
- package/lib/score.js +0 -191
- package/lib/search.d.ts +0 -83
- package/lib/search.js +0 -136
- package/lib/service.d.ts +0 -63
- package/lib/service.js +0 -253
- package/lib/skill-render.d.ts +0 -23
- package/lib/skill-render.js +0 -69
- package/lib/skill.d.ts +0 -15
- package/lib/skill.js +0 -80
- package/lib/skillquality.d.ts +0 -85
- package/lib/skillquality.js +0 -320
- package/lib/source.d.ts +0 -30
- package/lib/source.js +0 -43
- package/lib/state.d.ts +0 -26
- package/lib/state.js +0 -151
- package/lib/store.d.ts +0 -61
- package/lib/store.js +0 -164
- package/lib/token-usage.d.ts +0 -68
- package/lib/token-usage.js +0 -211
- package/lib/tool.d.ts +0 -34
- package/lib/tool.js +0 -320
- package/lib/turn-snapshot.d.ts +0 -78
- package/lib/turn-snapshot.js +0 -252
- package/lib/types.d.ts +0 -218
- package/lib/types.js +0 -133
- package/lib/usage.d.ts +0 -36
- package/lib/usage.js +0 -98
- package/lib/validate.d.ts +0 -28
- package/lib/validate.js +0 -181
- package/lib/wrapup-candidates.d.ts +0 -127
- package/lib/wrapup-candidates.js +0 -161
- package/lib/wrapup-command.d.ts +0 -10
- package/lib/wrapup-command.js +0 -243
- package/lib/wrapup-proposals.d.ts +0 -101
- package/lib/wrapup-proposals.js +0 -281
- package/lib/wrapup.d.ts +0 -56
- package/lib/wrapup.js +0 -105
package/lib/benchmark.js
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Benchmark store: file-backed case definitions and scoreboards under
|
|
3
|
-
* `<baseDir>/evolve/benchmarks/<bid>/`.
|
|
4
|
-
*
|
|
5
|
-
* Layout:
|
|
6
|
-
* benchmark.json title, runs (repeats per case), passThreshold
|
|
7
|
-
* cases/<cid>/statement.md public task text
|
|
8
|
-
* cases/<cid>/rubric.json encrypted scoring criteria (AES-256-GCM, see src/rubric.ts)
|
|
9
|
-
* scoreboard.json code-owned aggregates + acceptance history
|
|
10
|
-
*
|
|
11
|
-
* Rubric isolation is code-enforced: rubric plaintext never reaches the
|
|
12
|
-
* disk. Only the evaluation runner decrypts (into the child prompt); the
|
|
13
|
-
* optimizer can read the file and sees ciphertext only. Legacy files that
|
|
14
|
-
* predate encryption carry plaintext and are still readable.
|
|
15
|
-
*/
|
|
16
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
17
|
-
import { join } from "node:path";
|
|
18
|
-
import { encryptRubric, DEV_RUBRIC_KEY, deriveKey } from "./rubric.js";
|
|
19
|
-
/**
|
|
20
|
-
* Close the acceptance loop: when the code-owned decision rejects a
|
|
21
|
-
* candidate refinement, revert it deterministically. The rollback is the
|
|
22
|
-
* same engine path as `/evolve rollback` (inverse edits rebuilt from the
|
|
23
|
-
* applied result — no LLM re-guessing), so it snapshots, versions, and
|
|
24
|
-
* audits like any other mutation. Failures (e.g. the refinement belongs to
|
|
25
|
-
* another session's history) are reported, never thrown: the command shows
|
|
26
|
-
* the manual fallback instead.
|
|
27
|
-
*/
|
|
28
|
-
export function rollbackRejectedCandidate(engine, sessionId, candidateId) {
|
|
29
|
-
try {
|
|
30
|
-
const result = engine.rollback("local", sessionId, candidateId);
|
|
31
|
-
const applied = result.appliedEdits.filter((edit) => edit.applied).length;
|
|
32
|
-
return {
|
|
33
|
-
rolledBack: true,
|
|
34
|
-
message: `auto-rollback: reverted refinement ${candidateId} — ${applied} edits restored to the pre-refinement snapshot`,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
catch (cause) {
|
|
38
|
-
return {
|
|
39
|
-
rolledBack: false,
|
|
40
|
-
message: `auto-rollback failed: ${cause instanceof Error ? cause.message : String(cause)} — roll back manually with /evolve rollback <${candidateId}>`,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
export function benchmarkDir(baseDir, bid) {
|
|
45
|
-
return join(baseDir, "evolve", "benchmarks", bid);
|
|
46
|
-
}
|
|
47
|
-
export function sanitizeId(raw) {
|
|
48
|
-
const id = raw.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 40);
|
|
49
|
-
if (!id) {
|
|
50
|
-
throw new Error("benchmark id must be a non-empty slug");
|
|
51
|
-
}
|
|
52
|
-
return id;
|
|
53
|
-
}
|
|
54
|
-
export function createBenchmark(baseDir, opts) {
|
|
55
|
-
const id = sanitizeId(opts.title);
|
|
56
|
-
const dir = benchmarkDir(baseDir, id);
|
|
57
|
-
if (existsSync(dir)) {
|
|
58
|
-
throw new Error(`benchmark ${id} already exists`);
|
|
59
|
-
}
|
|
60
|
-
const definition = {
|
|
61
|
-
id,
|
|
62
|
-
title: opts.title.trim(),
|
|
63
|
-
description: opts.description?.trim() ?? "",
|
|
64
|
-
runs: opts.runs ?? 1,
|
|
65
|
-
passThreshold: opts.passThreshold ?? 60,
|
|
66
|
-
createdAt: new Date().toISOString(),
|
|
67
|
-
};
|
|
68
|
-
mkdirSync(dir, { recursive: true });
|
|
69
|
-
writeFileSync(join(dir, "benchmark.json"), `${JSON.stringify(definition, null, 2)}\n`, "utf8");
|
|
70
|
-
writeFileSync(join(dir, "scoreboard.json"), `${JSON.stringify({ candidates: [], decisions: [] }, null, 2)}\n`, "utf8");
|
|
71
|
-
return definition;
|
|
72
|
-
}
|
|
73
|
-
export function listBenchmarks(baseDir) {
|
|
74
|
-
const root = join(baseDir, "evolve", "benchmarks");
|
|
75
|
-
if (!existsSync(root))
|
|
76
|
-
return [];
|
|
77
|
-
return readdirSafe(root)
|
|
78
|
-
.map((id) => loadBenchmark(baseDir, id))
|
|
79
|
-
.filter((b) => b !== undefined);
|
|
80
|
-
}
|
|
81
|
-
export function loadBenchmark(baseDir, bid) {
|
|
82
|
-
const path = join(benchmarkDir(baseDir, bid), "benchmark.json");
|
|
83
|
-
if (!existsSync(path))
|
|
84
|
-
return undefined;
|
|
85
|
-
try {
|
|
86
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
export function addCase(baseDir, bid, title, statement, rubric, rubricKey) {
|
|
93
|
-
const definition = loadBenchmark(baseDir, bid);
|
|
94
|
-
if (!definition) {
|
|
95
|
-
throw new Error(`benchmark ${bid} not found`);
|
|
96
|
-
}
|
|
97
|
-
const id = sanitizeId(title);
|
|
98
|
-
const caseDir = join(benchmarkDir(baseDir, bid), "cases", id);
|
|
99
|
-
if (existsSync(caseDir)) {
|
|
100
|
-
throw new Error(`case ${id} already exists in ${bid}`);
|
|
101
|
-
}
|
|
102
|
-
mkdirSync(caseDir, { recursive: true });
|
|
103
|
-
writeFileSync(join(caseDir, "statement.md"), statement, "utf8");
|
|
104
|
-
// Rubric plaintext never touches the disk; callers pass a resolved key
|
|
105
|
-
// (config → env → per-installation key file → dev fallback, see
|
|
106
|
-
// resolveRubricKey) and the dev key here is only a defensive last resort.
|
|
107
|
-
const stored = rubricKey ? encryptRubric(rubric, rubricKey) : encryptRubric(rubric, deriveKey(DEV_RUBRIC_KEY));
|
|
108
|
-
writeFileSync(join(caseDir, "rubric.json"), `${JSON.stringify(stored, null, 2)}\n`, "utf8");
|
|
109
|
-
// A5: initialize case metadata for quality gate.
|
|
110
|
-
saveCaseMeta(baseDir, bid, id, defaultCaseMeta());
|
|
111
|
-
return { id, title: title.trim(), statement, rubric };
|
|
112
|
-
}
|
|
113
|
-
export function listCases(baseDir, bid) {
|
|
114
|
-
const casesDir = join(benchmarkDir(baseDir, bid), "cases");
|
|
115
|
-
if (!existsSync(casesDir))
|
|
116
|
-
return [];
|
|
117
|
-
return readdirSafe(casesDir)
|
|
118
|
-
.map((id) => {
|
|
119
|
-
const statementPath = join(casesDir, id, "statement.md");
|
|
120
|
-
const rubricPath = join(casesDir, id, "rubric.json");
|
|
121
|
-
if (!existsSync(statementPath) || !existsSync(rubricPath))
|
|
122
|
-
return undefined;
|
|
123
|
-
try {
|
|
124
|
-
const statement = readFileSync(statementPath, "utf8");
|
|
125
|
-
const rubric = JSON.parse(readFileSync(rubricPath, "utf8"));
|
|
126
|
-
const meta = loadCaseMeta(baseDir, bid, id);
|
|
127
|
-
return { id, title: id, statement, rubric, ...(meta ? { status: meta.status } : {}) };
|
|
128
|
-
}
|
|
129
|
-
catch {
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
132
|
-
})
|
|
133
|
-
.filter((c) => c !== undefined);
|
|
134
|
-
}
|
|
135
|
-
export function loadScoreboard(baseDir, bid) {
|
|
136
|
-
const path = join(benchmarkDir(baseDir, bid), "scoreboard.json");
|
|
137
|
-
if (!existsSync(path)) {
|
|
138
|
-
return { candidates: [], decisions: [] };
|
|
139
|
-
}
|
|
140
|
-
try {
|
|
141
|
-
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
142
|
-
return {
|
|
143
|
-
...(raw.reference ? { reference: raw.reference } : {}),
|
|
144
|
-
candidates: raw.candidates ?? [],
|
|
145
|
-
decisions: raw.decisions ?? [],
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
catch {
|
|
149
|
-
return { candidates: [], decisions: [] };
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
export function saveScoreboard(baseDir, bid, board) {
|
|
153
|
-
writeFileSync(join(benchmarkDir(baseDir, bid), "scoreboard.json"), `${JSON.stringify(board, null, 2)}\n`, "utf8");
|
|
154
|
-
}
|
|
155
|
-
// ── Case meta (gap A5: quality gate + calibration history) ────────────
|
|
156
|
-
export function loadCaseMeta(baseDir, bid, cid) {
|
|
157
|
-
const path = join(benchmarkDir(baseDir, bid), "cases", cid, "meta.json");
|
|
158
|
-
if (!existsSync(path))
|
|
159
|
-
return undefined;
|
|
160
|
-
try {
|
|
161
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
162
|
-
}
|
|
163
|
-
catch {
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
export function saveCaseMeta(baseDir, bid, cid, meta) {
|
|
168
|
-
const metaDir = join(benchmarkDir(baseDir, bid), "cases", cid);
|
|
169
|
-
mkdirSync(metaDir, { recursive: true });
|
|
170
|
-
writeFileSync(join(metaDir, "meta.json"), `${JSON.stringify(meta, null, 2)}\n`, "utf8");
|
|
171
|
-
}
|
|
172
|
-
/**
|
|
173
|
-
* Transition a case's lifecycle state. Throws on illegal transitions.
|
|
174
|
-
* draft → calibrating (start pilot)
|
|
175
|
-
* calibrating → draft (abandon calibration)
|
|
176
|
-
* calibrating → frozen (lock baseline)
|
|
177
|
-
*/
|
|
178
|
-
export function transitionCaseStatus(baseDir, bid, cid, to) {
|
|
179
|
-
const meta = loadCaseMeta(baseDir, bid, cid) ?? defaultCaseMeta();
|
|
180
|
-
const from = meta.status;
|
|
181
|
-
const valid = (from === "draft" && to === "calibrating") ||
|
|
182
|
-
(from === "calibrating" && to === "draft") ||
|
|
183
|
-
(from === "calibrating" && to === "frozen");
|
|
184
|
-
if (!valid) {
|
|
185
|
-
throw new Error(`illegal case status transition: ${from} → ${to}`);
|
|
186
|
-
}
|
|
187
|
-
meta.status = to;
|
|
188
|
-
saveCaseMeta(baseDir, bid, cid, meta);
|
|
189
|
-
return meta;
|
|
190
|
-
}
|
|
191
|
-
function defaultCaseMeta() {
|
|
192
|
-
return {
|
|
193
|
-
status: "draft",
|
|
194
|
-
capability: "",
|
|
195
|
-
distinguisher: "",
|
|
196
|
-
shortcuts: "",
|
|
197
|
-
calibrationHistory: [],
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
/**
|
|
201
|
-
* Quality-check a case: mechanical validation without LLM calls.
|
|
202
|
-
* Returns human-readable problems; empty array means the case passes.
|
|
203
|
-
*/
|
|
204
|
-
export function caseCheckProblems(baseDir, bid, cid) {
|
|
205
|
-
const problems = [];
|
|
206
|
-
const statementPath = join(benchmarkDir(baseDir, bid), "cases", cid, "statement.md");
|
|
207
|
-
if (!existsSync(statementPath)) {
|
|
208
|
-
problems.push("statement.md missing");
|
|
209
|
-
return problems;
|
|
210
|
-
}
|
|
211
|
-
const statement = readFileSync(statementPath, "utf8").trim();
|
|
212
|
-
if (statement.length < 20) {
|
|
213
|
-
problems.push(`statement too short (${statement.length} chars, minimum 20)`);
|
|
214
|
-
}
|
|
215
|
-
const rubricPath = join(benchmarkDir(baseDir, bid), "cases", cid, "rubric.json");
|
|
216
|
-
if (!existsSync(rubricPath)) {
|
|
217
|
-
problems.push("rubric.json missing");
|
|
218
|
-
return problems;
|
|
219
|
-
}
|
|
220
|
-
try {
|
|
221
|
-
const raw = readFileSync(rubricPath, "utf8");
|
|
222
|
-
JSON.parse(raw);
|
|
223
|
-
}
|
|
224
|
-
catch {
|
|
225
|
-
problems.push("rubric.json is not valid JSON");
|
|
226
|
-
}
|
|
227
|
-
const meta = loadCaseMeta(baseDir, bid, cid);
|
|
228
|
-
if (!meta) {
|
|
229
|
-
problems.push("meta.json missing (run /evolve benchmark casecheck to initialize)");
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
if (!meta.capability)
|
|
233
|
-
problems.push("capability contract is empty");
|
|
234
|
-
if (!meta.distinguisher)
|
|
235
|
-
problems.push("distinguisher is empty");
|
|
236
|
-
if (!meta.shortcuts)
|
|
237
|
-
problems.push("shortcuts annotation is empty");
|
|
238
|
-
}
|
|
239
|
-
return problems;
|
|
240
|
-
}
|
|
241
|
-
import { readdirSync } from "node:fs";
|
|
242
|
-
function readdirSafe(dir) {
|
|
243
|
-
try {
|
|
244
|
-
return readdirSync(dir);
|
|
245
|
-
}
|
|
246
|
-
catch {
|
|
247
|
-
return [];
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
//# sourceMappingURL=benchmark.js.map
|
package/lib/command-util.d.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
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
|
package/lib/command-util.js
DELETED
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { projectKeyOf } from "./project.js";
|
|
2
|
-
/** Parse an optional leading scope token ("global" | "project") off the args. */
|
|
3
|
-
export function scopeArg(tokens) {
|
|
4
|
-
if (tokens[0] === "global") {
|
|
5
|
-
return { scope: "global", rest: tokens.slice(1) };
|
|
6
|
-
}
|
|
7
|
-
if (tokens[0] === "project") {
|
|
8
|
-
return { scope: "project", rest: tokens.slice(1) };
|
|
9
|
-
}
|
|
10
|
-
return { scope: "local", rest: tokens };
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* The store id a scope reads/writes from the human command: live session id
|
|
14
|
-
* for local, derived project key for project, undefined for global. Throws
|
|
15
|
-
* for project when the session cwd is unavailable.
|
|
16
|
-
*/
|
|
17
|
-
export function storeIdForCommand(scope, invocation) {
|
|
18
|
-
if (scope === "local") {
|
|
19
|
-
return invocation.agent.id;
|
|
20
|
-
}
|
|
21
|
-
if (scope === "project") {
|
|
22
|
-
const key = projectKeyOf(invocation.agent);
|
|
23
|
-
if (!key) {
|
|
24
|
-
throw new Error("project scope needs the session cwd (unavailable here) — use local or global instead");
|
|
25
|
-
}
|
|
26
|
-
return key;
|
|
27
|
-
}
|
|
28
|
-
return undefined;
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Tokenize a command's raw input with shell-like quoting:
|
|
32
|
-
* - a `#` outside quotes starts a comment (rest of the line is dropped);
|
|
33
|
-
* - whitespace separates tokens;
|
|
34
|
-
* - double or single quotes group words into one token and are stripped.
|
|
35
|
-
*
|
|
36
|
-
* This lets users paste help-text examples verbatim, e.g.
|
|
37
|
-
* `/evolve benchmark add-case <bid> "<title>" "<statement>" "<rubric>"`.
|
|
38
|
-
*/
|
|
39
|
-
export function tokenizeEvolveInput(rawInput) {
|
|
40
|
-
const tokens = [];
|
|
41
|
-
let current = "";
|
|
42
|
-
let quote = null;
|
|
43
|
-
for (const char of rawInput) {
|
|
44
|
-
if (quote !== null) {
|
|
45
|
-
if (char === quote) {
|
|
46
|
-
quote = null;
|
|
47
|
-
}
|
|
48
|
-
else {
|
|
49
|
-
current += char;
|
|
50
|
-
}
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
if (char === '"' || char === "'") {
|
|
54
|
-
quote = char;
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
if (char === "#") {
|
|
58
|
-
break; // rest of the line is a comment
|
|
59
|
-
}
|
|
60
|
-
if (/\s/.test(char)) {
|
|
61
|
-
if (current.length > 0) {
|
|
62
|
-
tokens.push(current);
|
|
63
|
-
current = "";
|
|
64
|
-
}
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
current += char;
|
|
68
|
-
}
|
|
69
|
-
if (current.length > 0) {
|
|
70
|
-
tokens.push(current);
|
|
71
|
-
}
|
|
72
|
-
return tokens;
|
|
73
|
-
}
|
|
74
|
-
/** Accept both `<id>` (help-text placeholder form) and bare `id`. */
|
|
75
|
-
export function stripAngleBrackets(value) {
|
|
76
|
-
return value.replace(/^<|>$/g, "");
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Locate an entry by id across every kind of a store. Ids are only unique
|
|
80
|
-
* within a kind, so the lookup scans all four and returns the first match
|
|
81
|
-
* (kind + entry) or undefined. Used by archive/unarchive, which take a bare
|
|
82
|
-
* id from the user.
|
|
83
|
-
*/
|
|
84
|
-
export function findEntryById(state, id) {
|
|
85
|
-
for (const kind of Object.keys(state.entries)) {
|
|
86
|
-
const entry = state.entries[kind][id];
|
|
87
|
-
if (entry) {
|
|
88
|
-
return [kind, entry];
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return undefined;
|
|
92
|
-
}
|
|
93
|
-
export function parsePositiveInt(value, what) {
|
|
94
|
-
const n = Number(value);
|
|
95
|
-
if (!Number.isInteger(n) || n < 1) {
|
|
96
|
-
throw new Error(`${what} must be a positive integer, got "${value}"`);
|
|
97
|
-
}
|
|
98
|
-
return n;
|
|
99
|
-
}
|
|
100
|
-
export function success(text) {
|
|
101
|
-
return { kind: "success", text };
|
|
102
|
-
}
|
|
103
|
-
export function error(text) {
|
|
104
|
-
return { kind: "error", text };
|
|
105
|
-
}
|
|
106
|
-
/** Human-readable one-refinement rendering shared by every apply path. */
|
|
107
|
-
export function renderResult(result) {
|
|
108
|
-
const applied = result.appliedEdits.filter((e) => e.applied);
|
|
109
|
-
const failed = result.appliedEdits.filter((e) => !e.applied);
|
|
110
|
-
const lines = [
|
|
111
|
-
`refinement ${result.id}${result.rollbackOf ? ` (rollback of ${result.rollbackOf})` : ""}: ${applied.length} applied, ${failed.length} failed`,
|
|
112
|
-
`summary: ${result.summary}`,
|
|
113
|
-
];
|
|
114
|
-
for (const e of applied) {
|
|
115
|
-
lines.push(`- ${e.action} ${e.kind}:${e.id} (v${(e.after?.version ?? e.before?.version) ?? "?"})`);
|
|
116
|
-
}
|
|
117
|
-
for (const e of failed) {
|
|
118
|
-
lines.push(`- failed ${e.action} ${e.kind}:${e.id ?? "(computed)"} — ${e.error ?? "unknown error"}`);
|
|
119
|
-
}
|
|
120
|
-
lines.push(`expected outcome: ${result.expectedOutcome}`);
|
|
121
|
-
return lines.join("\n");
|
|
122
|
-
}
|
|
123
|
-
//# sourceMappingURL=command-util.js.map
|
package/lib/command.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The human-facing `/evolve` command router: parse the subcommand and hand
|
|
3
|
-
* off to its implementation file. Subcommand logic lives in the
|
|
4
|
-
* `*-command.ts` modules; this file owns only registration, help text, and
|
|
5
|
-
* the core inspect/rollback flows.
|
|
6
|
-
*/
|
|
7
|
-
import type { Context } from "@deepseek-ai/cordis";
|
|
8
|
-
import type { EvolutionEngine } from "./service.js";
|
|
9
|
-
import { findEntryById, stripAngleBrackets, tokenizeEvolveInput, type CommandGateOptions, type CommandRuntimeOptions } from "./command-util.js";
|
|
10
|
-
export { findEntryById, stripAngleBrackets, tokenizeEvolveInput };
|
|
11
|
-
export type { CommandGateOptions, CommandRuntimeOptions };
|
|
12
|
-
export declare function registerEvolveCommand(ctx: Context, engine: EvolutionEngine, opts: CommandGateOptions, runtime: CommandRuntimeOptions): void;
|
|
13
|
-
//# sourceMappingURL=command.d.ts.map
|
package/lib/command.js
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { formatHarnessStateForPrompt, historyForPrompt } from "./render.js";
|
|
2
|
-
import { findEntryById, renderResult, scopeArg, stripAngleBrackets, storeIdForCommand, success, error, tokenizeEvolveInput, } from "./command-util.js";
|
|
3
|
-
import { executePlanCommand } from "./plan-command.js";
|
|
4
|
-
import { executeArchiveCommand, executeConsolidateCommand, executeExportCommand, executeFailuresCommand, executeImportCommand, executeLogCommand, } from "./maintenance-commands.js";
|
|
5
|
-
import { executePauseResumeCommand, executeStatusCommand, executeUsageCommand } from "./runtime-commands.js";
|
|
6
|
-
import { executeGoalCommand } from "./goal-command.js";
|
|
7
|
-
import { executeMountCommand, executeUnmountCommand } from "./mount-command.js";
|
|
8
|
-
import { executeBenchmarkCommand } from "./benchmark-command.js";
|
|
9
|
-
import { executeWrapupCommand } from "./wrapup-command.js";
|
|
10
|
-
import { projectKeyOf } from "./project.js";
|
|
11
|
-
const USAGE_COMMON = `Usage:
|
|
12
|
-
/evolve show this help and the current local store
|
|
13
|
-
/evolve list [project|global] list entries (default local staging; "project" = this project's cross-session store, "global" = cross-project store)
|
|
14
|
-
/evolve history [global] show applied refinements (rollback ids)
|
|
15
|
-
/evolve rollback <id> [global] deterministically revert a refinement
|
|
16
|
-
/evolve plan [msg] run the LLM planner against the current store
|
|
17
|
-
/evolve wrapup assess this session's local entries: promote reusable ones
|
|
18
|
-
to the global store (approval required), archive one-offs
|
|
19
|
-
/evolve archive <id> [global] hide an entry from injection (data kept, restorable)
|
|
20
|
-
/evolve unarchive <id> [global] restore an archived entry
|
|
21
|
-
/evolve pause | resume pause/resume the automatic Memory Agent (manual tools and commands keep working)
|
|
22
|
-
/evolve status automatic Memory Agent state plus store entry counts
|
|
23
|
-
/evolve help all every subcommand, including the advanced ones below`;
|
|
24
|
-
const USAGE_ADVANCED = `Advanced:
|
|
25
|
-
/evolve consolidate [apply] [merge]
|
|
26
|
-
report (or apply) a batch archive of conflict-hinted
|
|
27
|
-
and stale zero-use global entries; "merge" folds
|
|
28
|
-
near-duplicate content into the surviving original
|
|
29
|
-
/evolve failures aggregated failure counts (gate + benchmark, by class)
|
|
30
|
-
/evolve log [tail N] show the recent plugin log (default 50 lines)
|
|
31
|
-
/evolve export [global] <path> backup a store to a JSON file
|
|
32
|
-
/evolve import [global] <path> restore a store from an export file
|
|
33
|
-
/evolve mount <skillId> hot-mount a skill entry as a live cordis plugin
|
|
34
|
-
/evolve mount list list hot-mounted plugins
|
|
35
|
-
/evolve unmount <id> remove a hot-mounted plugin
|
|
36
|
-
/evolve goal show the evolution goal (round-driven auto-review)
|
|
37
|
-
/evolve goal <objective> create/update the evolution goal
|
|
38
|
-
/evolve goal done complete the evolution goal
|
|
39
|
-
/evolve benchmark ... case lifecycle, runs, acceptance
|
|
40
|
-
/evolve usage injection counts + exact direct-call token usage (benchmark subagents excluded)`;
|
|
41
|
-
/** Default help (`/evolve`, `/evolve help`): the commands worth knowing. */
|
|
42
|
-
const USAGE = USAGE_COMMON;
|
|
43
|
-
export { findEntryById, stripAngleBrackets, tokenizeEvolveInput };
|
|
44
|
-
export function registerEvolveCommand(ctx, engine, opts, runtime) {
|
|
45
|
-
ctx.commands.register({
|
|
46
|
-
name: "evolve",
|
|
47
|
-
description: "自进化:检查并演进 harness 状态(记忆/技能/提示词/子代理) | Inspect and evolve the continual harness state (memories, skills, prompt notes, subagent specs)",
|
|
48
|
-
input: { hint: "[list [global] | history [global] | rollback <id> [global] | plan [msg] | help all]" },
|
|
49
|
-
handler: (invocation) => executeEvolveCommand(ctx, engine, invocation, opts, runtime),
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
async function executeEvolveCommand(ctx, engine, invocation, opts, runtime) {
|
|
53
|
-
const tokens = tokenizeEvolveInput(invocation.rawInput);
|
|
54
|
-
const sub = tokens[0] ?? "";
|
|
55
|
-
const rest = tokens.slice(1);
|
|
56
|
-
const sessionId = invocation.agent.id;
|
|
57
|
-
try {
|
|
58
|
-
switch (sub) {
|
|
59
|
-
case "":
|
|
60
|
-
case "help":
|
|
61
|
-
// Layered help (2026-10-01): the default listing stays short;
|
|
62
|
-
// `help all` expands the advanced half.
|
|
63
|
-
return success(`${rest[0] === "all" ? `${USAGE_COMMON}\n\n${USAGE_ADVANCED}` : USAGE_COMMON}\n\n${formatHarnessStateForPrompt(engine.load("local", sessionId))}`);
|
|
64
|
-
case "list": {
|
|
65
|
-
const { scope } = scopeArg(rest);
|
|
66
|
-
return success(formatHarnessStateForPrompt(engine.load(scope, storeIdForCommand(scope, invocation))));
|
|
67
|
-
}
|
|
68
|
-
case "history": {
|
|
69
|
-
const { scope } = scopeArg(rest);
|
|
70
|
-
const history = engine.history(scope, storeIdForCommand(scope, invocation));
|
|
71
|
-
return success(historyForPrompt(history) || "(no refinements yet)");
|
|
72
|
-
}
|
|
73
|
-
case "rollback": {
|
|
74
|
-
const { scope, rest: after } = scopeArg(rest);
|
|
75
|
-
const id = stripAngleBrackets(after[0] ?? "");
|
|
76
|
-
if (!id) {
|
|
77
|
-
return error(`rollback requires a refinement id.\n${USAGE}`);
|
|
78
|
-
}
|
|
79
|
-
const result = engine.rollback(scope, storeIdForCommand(scope, invocation), id);
|
|
80
|
-
return success(renderResult(result));
|
|
81
|
-
}
|
|
82
|
-
case "archive":
|
|
83
|
-
case "unarchive": {
|
|
84
|
-
return await executeArchiveCommand(ctx, engine, invocation, sub, scopeArg(rest), USAGE);
|
|
85
|
-
}
|
|
86
|
-
case "consolidate":
|
|
87
|
-
return executeConsolidateCommand(engine, rest);
|
|
88
|
-
case "failures":
|
|
89
|
-
return executeFailuresCommand(engine);
|
|
90
|
-
case "log":
|
|
91
|
-
return executeLogCommand(engine, rest, USAGE);
|
|
92
|
-
case "export": {
|
|
93
|
-
const parsed = scopeArg(rest);
|
|
94
|
-
return executeExportCommand(engine, invocation, parsed, USAGE);
|
|
95
|
-
}
|
|
96
|
-
case "import": {
|
|
97
|
-
const parsed = scopeArg(rest);
|
|
98
|
-
return executeImportCommand(engine, invocation, parsed, parsed.rest[0]);
|
|
99
|
-
}
|
|
100
|
-
case "plan": {
|
|
101
|
-
const { scope, rest: after } = scopeArg(rest);
|
|
102
|
-
return await executePlanCommand(ctx, engine, invocation, scope, after, opts, runtime);
|
|
103
|
-
}
|
|
104
|
-
case "wrapup": {
|
|
105
|
-
return await executeWrapupCommand(ctx, engine, invocation, runtime.promotionPolicy, runtime.recordLanguage);
|
|
106
|
-
}
|
|
107
|
-
case "pause":
|
|
108
|
-
case "resume":
|
|
109
|
-
return executePauseResumeCommand(engine, sub, runtime);
|
|
110
|
-
case "status":
|
|
111
|
-
return executeStatusCommand(engine, sessionId, projectKeyOf(invocation.agent), runtime);
|
|
112
|
-
case "usage":
|
|
113
|
-
return executeUsageCommand(engine, sessionId, projectKeyOf(invocation.agent));
|
|
114
|
-
case "goal": {
|
|
115
|
-
return executeGoalCommand(ctx, invocation, rest);
|
|
116
|
-
}
|
|
117
|
-
case "mount": {
|
|
118
|
-
return await executeMountCommand(ctx, engine, invocation, rest);
|
|
119
|
-
}
|
|
120
|
-
case "unmount": {
|
|
121
|
-
return await executeUnmountCommand(ctx, engine, rest);
|
|
122
|
-
}
|
|
123
|
-
case "benchmark": {
|
|
124
|
-
return await executeBenchmarkCommand(ctx, engine, invocation, rest, runtime);
|
|
125
|
-
}
|
|
126
|
-
default:
|
|
127
|
-
return error(`unknown subcommand: ${sub}\n${USAGE}`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
catch (cause) {
|
|
131
|
-
return error(cause instanceof Error ? cause.message : String(cause));
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
//# sourceMappingURL=command.js.map
|
package/lib/consolidate.d.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Global-store consolidation (R3): turn the two hygiene signals — R2's
|
|
3
|
-
* `conflictHint` stamps and usage v2's zero-injection staleness — into one
|
|
4
|
-
* deterministic, human-approved batch of archive edits (`/evolve consolidate`).
|
|
5
|
-
*
|
|
6
|
-
* Design (ADR implemented/feature/2026-08-24-consolidation-command.md):
|
|
7
|
-
* - pure functions only; the command layer owns loading, reporting, and the
|
|
8
|
-
* apply phase, and ALWAYS re-scans fresh state before applying (the report
|
|
9
|
-
* and the apply are two separate invocations — prefer under-archiving over
|
|
10
|
-
* mis-archiving when state moved in between);
|
|
11
|
-
* - archiving keeps data (ARCHIVED_AT_KEY stamp, restorable via
|
|
12
|
-
* `/evolve unarchive`) and preserves every existing metadata key including
|
|
13
|
-
* the conflictHint itself, so unarchived entries keep their trail;
|
|
14
|
-
* - no LLM call anywhere: code proposes, the human disposes.
|
|
15
|
-
*/
|
|
16
|
-
import type { HarnessState, RefinementEdit, RefinementKind } from "./types.js";
|
|
17
|
-
import { type UsageStore } from "./usage.js";
|
|
18
|
-
/** Zero-use entries at least this old are stale candidates (30d, matching the injection recency half-life scale). */
|
|
19
|
-
export declare const STALE_MIN_AGE_MS: number;
|
|
20
|
-
/** Parsed `<kind>:<id>:<score>` value of a {@link CONFLICT_HINT_KEY} stamp. */
|
|
21
|
-
export interface ConflictHint {
|
|
22
|
-
kind: RefinementKind;
|
|
23
|
-
id: string;
|
|
24
|
-
score: number;
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Parse one conflictHint metadata value. Returns undefined for anything that
|
|
28
|
-
* is not exactly `<kind>:<id>:<score>` with a known kind and a score in
|
|
29
|
-
* [0, 1] — foreign or legacy junk must never crash the scan.
|
|
30
|
-
*/
|
|
31
|
-
export declare function parseConflictHint(value: unknown): ConflictHint | undefined;
|
|
32
|
-
/** One planned archive with its human-readable justification. */
|
|
33
|
-
export interface ConsolidationCandidate {
|
|
34
|
-
kind: RefinementKind;
|
|
35
|
-
id: string;
|
|
36
|
-
title: string;
|
|
37
|
-
reason: string;
|
|
38
|
-
/**
|
|
39
|
-
* Merge tier (P1 反膨胀): set on conflict-pair candidates — the entry's
|
|
40
|
-
* content merges into this survivor (pointed-to original) before the
|
|
41
|
-
* entry itself archives, so nothing readable is lost by the archive. The
|
|
42
|
-
* plan only EMITS the merge when `mergeDuplicates` is on.
|
|
43
|
-
*/
|
|
44
|
-
mergeInto?: {
|
|
45
|
-
kind: RefinementKind;
|
|
46
|
-
id: string;
|
|
47
|
-
title: string;
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Entries stamped by the write-time conflict guard whose target still exists
|
|
52
|
-
* and is still active. The hinted (newer) entry is the archive candidate —
|
|
53
|
-
* the pointed-to original stays as the live copy.
|
|
54
|
-
*/
|
|
55
|
-
export declare function findConflictPairs(state: HarnessState): ConsolidationCandidate[];
|
|
56
|
-
/**
|
|
57
|
-
* Active global entries never injected in any session and untouched for at
|
|
58
|
-
* least `minAgeMs`: prime staleness candidates. Operates on whatever state
|
|
59
|
-
* it is handed (callers pass the global store).
|
|
60
|
-
*/
|
|
61
|
-
export declare function findStaleEntries(state: HarnessState, store: UsageStore, now: number, minAgeMs?: number): ConsolidationCandidate[];
|
|
62
|
-
/**
|
|
63
|
-
* Append a source entry's content to a survivor with an attributed divider,
|
|
64
|
-
* so the survivor's reader can see which part came from which entry.
|
|
65
|
-
*/
|
|
66
|
-
export declare function mergeContent(target: string, source: string, sourceRef: string, dateIso: string): string;
|
|
67
|
-
/**
|
|
68
|
-
* Merge both scans (conflict reason wins on overlap), deduped by kind:id,
|
|
69
|
-
* and build the batch archive edits. Each edit preserves the entry's full
|
|
70
|
-
* content and existing metadata — only ARCHIVED_AT_KEY is added — so
|
|
71
|
-
* `/evolve unarchive` restores everything intact.
|
|
72
|
-
*
|
|
73
|
-
* With `opts.mergeDuplicates`, conflict-pair candidates additionally merge
|
|
74
|
-
* their content INTO the pointed-to survivor (an attributed `mergeContent`
|
|
75
|
-
* section + a `mergedFrom` provenance stamp) before archiving — the #11
|
|
76
|
-
* candidate-c tier the 2026-08-28 ecosystem review promoted. Per-target
|
|
77
|
-
* accumulation composes multiple hints into one survivor (update edits
|
|
78
|
-
* replace content/metadata wholesale, so parallel merge edits would clobber
|
|
79
|
-
* each other).
|
|
80
|
-
*
|
|
81
|
-
* @param now Epoch ms used for the archivedAt stamp (injected for tests).
|
|
82
|
-
*/
|
|
83
|
-
export declare function planConsolidation(state: HarnessState, store: UsageStore, now?: number, opts?: {
|
|
84
|
-
minAgeMs?: number;
|
|
85
|
-
mergeDuplicates?: boolean;
|
|
86
|
-
}): {
|
|
87
|
-
candidates: ConsolidationCandidate[];
|
|
88
|
-
edits: RefinementEdit[];
|
|
89
|
-
};
|
|
90
|
-
//# sourceMappingURL=consolidate.d.ts.map
|