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.
Files changed (161) hide show
  1. package/README.md +42 -115
  2. package/README.zh.md +33 -93
  3. package/client/client.js +253 -0
  4. package/cordis.patch.yml +2 -2
  5. package/lib/card-routes.d.ts +32 -0
  6. package/lib/card-routes.js +92 -0
  7. package/lib/index.d.ts +65 -217
  8. package/lib/index.js +74 -234
  9. package/lib/known-workspaces.d.ts +22 -0
  10. package/lib/known-workspaces.js +42 -0
  11. package/lib/memory-guide.d.ts +13 -14
  12. package/lib/memory-guide.js +34 -21
  13. package/lib/memory-section.d.ts +77 -0
  14. package/lib/memory-section.js +189 -0
  15. package/lib/memory-snapshot.d.ts +54 -0
  16. package/lib/memory-snapshot.js +125 -0
  17. package/package.json +8 -17
  18. package/lib/apply.d.ts +0 -22
  19. package/lib/apply.js +0 -157
  20. package/lib/approval.d.ts +0 -73
  21. package/lib/approval.js +0 -127
  22. package/lib/audit-log.d.ts +0 -19
  23. package/lib/audit-log.js +0 -52
  24. package/lib/auto.d.ts +0 -236
  25. package/lib/auto.js +0 -773
  26. package/lib/autocase.d.ts +0 -38
  27. package/lib/autocase.js +0 -76
  28. package/lib/benchmark-command.d.ts +0 -9
  29. package/lib/benchmark-command.js +0 -357
  30. package/lib/benchmark.d.ts +0 -151
  31. package/lib/benchmark.js +0 -250
  32. package/lib/command-util.d.ts +0 -70
  33. package/lib/command-util.js +0 -123
  34. package/lib/command.d.ts +0 -13
  35. package/lib/command.js +0 -134
  36. package/lib/consolidate.d.ts +0 -90
  37. package/lib/consolidate.js +0 -180
  38. package/lib/copy.d.ts +0 -37
  39. package/lib/copy.js +0 -58
  40. package/lib/declines.d.ts +0 -103
  41. package/lib/declines.js +0 -179
  42. package/lib/evaluate.d.ts +0 -74
  43. package/lib/evaluate.js +0 -271
  44. package/lib/evolve-event.d.ts +0 -40
  45. package/lib/evolve-event.js +0 -60
  46. package/lib/extraction-phase.d.ts +0 -132
  47. package/lib/extraction-phase.js +0 -236
  48. package/lib/failures.d.ts +0 -42
  49. package/lib/failures.js +0 -171
  50. package/lib/fate.d.ts +0 -130
  51. package/lib/fate.js +0 -350
  52. package/lib/goal-command.d.ts +0 -7
  53. package/lib/goal-command.js +0 -37
  54. package/lib/goal.d.ts +0 -72
  55. package/lib/goal.js +0 -72
  56. package/lib/inject.d.ts +0 -90
  57. package/lib/inject.js +0 -164
  58. package/lib/injection-caps.d.ts +0 -4
  59. package/lib/injection-caps.js +0 -4
  60. package/lib/injection-directory.d.ts +0 -29
  61. package/lib/injection-directory.js +0 -78
  62. package/lib/injection-rank.d.ts +0 -85
  63. package/lib/injection-rank.js +0 -161
  64. package/lib/listener.d.ts +0 -45
  65. package/lib/listener.js +0 -199
  66. package/lib/llm-text.d.ts +0 -104
  67. package/lib/llm-text.js +0 -140
  68. package/lib/logfile.d.ts +0 -71
  69. package/lib/logfile.js +0 -159
  70. package/lib/maintenance-commands.d.ts +0 -23
  71. package/lib/maintenance-commands.js +0 -136
  72. package/lib/memory-agent.d.ts +0 -93
  73. package/lib/memory-agent.js +0 -300
  74. package/lib/memory-apply.d.ts +0 -44
  75. package/lib/memory-apply.js +0 -202
  76. package/lib/memory-benchmark.d.ts +0 -76
  77. package/lib/memory-benchmark.js +0 -170
  78. package/lib/memory-index.d.ts +0 -114
  79. package/lib/memory-index.js +0 -197
  80. package/lib/memory-manifest.d.ts +0 -16
  81. package/lib/memory-manifest.js +0 -70
  82. package/lib/message-source.d.ts +0 -23
  83. package/lib/message-source.js +0 -12
  84. package/lib/mount-command.d.ts +0 -10
  85. package/lib/mount-command.js +0 -48
  86. package/lib/mount.d.ts +0 -42
  87. package/lib/mount.js +0 -212
  88. package/lib/notify.d.ts +0 -48
  89. package/lib/notify.js +0 -57
  90. package/lib/plan-command.d.ts +0 -12
  91. package/lib/plan-command.js +0 -38
  92. package/lib/plan.d.ts +0 -16
  93. package/lib/plan.js +0 -126
  94. package/lib/planner.d.ts +0 -61
  95. package/lib/planner.js +0 -144
  96. package/lib/pool.d.ts +0 -7
  97. package/lib/pool.js +0 -25
  98. package/lib/prefix-cache.d.ts +0 -79
  99. package/lib/prefix-cache.js +0 -168
  100. package/lib/project.d.ts +0 -28
  101. package/lib/project.js +0 -66
  102. package/lib/projection.d.ts +0 -22
  103. package/lib/projection.js +0 -112
  104. package/lib/promotion.d.ts +0 -94
  105. package/lib/promotion.js +0 -171
  106. package/lib/recall.d.ts +0 -85
  107. package/lib/recall.js +0 -142
  108. package/lib/record-language.d.ts +0 -85
  109. package/lib/record-language.js +0 -152
  110. package/lib/render.d.ts +0 -13
  111. package/lib/render.js +0 -80
  112. package/lib/review-scheduler.d.ts +0 -38
  113. package/lib/review-scheduler.js +0 -183
  114. package/lib/review.d.ts +0 -60
  115. package/lib/review.js +0 -145
  116. package/lib/rollback.d.ts +0 -9
  117. package/lib/rollback.js +0 -68
  118. package/lib/rubric.d.ts +0 -29
  119. package/lib/rubric.js +0 -119
  120. package/lib/runtime-commands.d.ts +0 -14
  121. package/lib/runtime-commands.js +0 -115
  122. package/lib/runtime.d.ts +0 -24
  123. package/lib/runtime.js +0 -87
  124. package/lib/score.d.ts +0 -64
  125. package/lib/score.js +0 -191
  126. package/lib/search.d.ts +0 -83
  127. package/lib/search.js +0 -136
  128. package/lib/service.d.ts +0 -63
  129. package/lib/service.js +0 -253
  130. package/lib/skill-render.d.ts +0 -23
  131. package/lib/skill-render.js +0 -69
  132. package/lib/skill.d.ts +0 -15
  133. package/lib/skill.js +0 -80
  134. package/lib/skillquality.d.ts +0 -85
  135. package/lib/skillquality.js +0 -320
  136. package/lib/source.d.ts +0 -30
  137. package/lib/source.js +0 -43
  138. package/lib/state.d.ts +0 -26
  139. package/lib/state.js +0 -151
  140. package/lib/store.d.ts +0 -61
  141. package/lib/store.js +0 -164
  142. package/lib/token-usage.d.ts +0 -68
  143. package/lib/token-usage.js +0 -211
  144. package/lib/tool.d.ts +0 -34
  145. package/lib/tool.js +0 -320
  146. package/lib/turn-snapshot.d.ts +0 -78
  147. package/lib/turn-snapshot.js +0 -252
  148. package/lib/types.d.ts +0 -218
  149. package/lib/types.js +0 -133
  150. package/lib/usage.d.ts +0 -36
  151. package/lib/usage.js +0 -98
  152. package/lib/validate.d.ts +0 -28
  153. package/lib/validate.js +0 -181
  154. package/lib/wrapup-candidates.d.ts +0 -127
  155. package/lib/wrapup-candidates.js +0 -161
  156. package/lib/wrapup-command.d.ts +0 -10
  157. package/lib/wrapup-command.js +0 -243
  158. package/lib/wrapup-proposals.d.ts +0 -101
  159. package/lib/wrapup-proposals.js +0 -281
  160. package/lib/wrapup.d.ts +0 -56
  161. 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
@@ -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
@@ -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
@@ -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