dsh-continual-evolve 0.10.6 → 0.12.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.
Files changed (126) hide show
  1. package/README.md +35 -122
  2. package/README.zh.md +26 -97
  3. package/cordis.patch.yml +2 -2
  4. package/lib/index.d.ts +44 -241
  5. package/lib/index.js +30 -253
  6. package/lib/memory-guide.d.ts +13 -14
  7. package/lib/memory-guide.js +32 -21
  8. package/lib/memory-section.d.ts +77 -0
  9. package/lib/memory-section.js +189 -0
  10. package/package.json +2 -17
  11. package/lib/apply.d.ts +0 -22
  12. package/lib/apply.js +0 -157
  13. package/lib/approval.d.ts +0 -72
  14. package/lib/approval.js +0 -127
  15. package/lib/auto.d.ts +0 -236
  16. package/lib/auto.js +0 -773
  17. package/lib/autocase.d.ts +0 -38
  18. package/lib/autocase.js +0 -76
  19. package/lib/benchmark-command.d.ts +0 -9
  20. package/lib/benchmark-command.js +0 -357
  21. package/lib/benchmark.d.ts +0 -151
  22. package/lib/benchmark.js +0 -250
  23. package/lib/command.d.ts +0 -49
  24. package/lib/command.js +0 -568
  25. package/lib/consolidate.d.ts +0 -90
  26. package/lib/consolidate.js +0 -180
  27. package/lib/copy.d.ts +0 -74
  28. package/lib/copy.js +0 -160
  29. package/lib/declines.d.ts +0 -101
  30. package/lib/declines.js +0 -175
  31. package/lib/evaluate.d.ts +0 -74
  32. package/lib/evaluate.js +0 -271
  33. package/lib/evolve-event.d.ts +0 -40
  34. package/lib/evolve-event.js +0 -59
  35. package/lib/failures.d.ts +0 -42
  36. package/lib/failures.js +0 -171
  37. package/lib/fate.d.ts +0 -130
  38. package/lib/fate.js +0 -350
  39. package/lib/goal-command.d.ts +0 -7
  40. package/lib/goal-command.js +0 -37
  41. package/lib/goal.d.ts +0 -72
  42. package/lib/goal.js +0 -72
  43. package/lib/inject.d.ts +0 -196
  44. package/lib/inject.js +0 -412
  45. package/lib/llm-text.d.ts +0 -104
  46. package/lib/llm-text.js +0 -140
  47. package/lib/logfile.d.ts +0 -71
  48. package/lib/logfile.js +0 -159
  49. package/lib/memory-agent.d.ts +0 -129
  50. package/lib/memory-agent.js +0 -568
  51. package/lib/memory-benchmark.d.ts +0 -76
  52. package/lib/memory-benchmark.js +0 -170
  53. package/lib/memory-index.d.ts +0 -114
  54. package/lib/memory-index.js +0 -197
  55. package/lib/message-source.d.ts +0 -23
  56. package/lib/message-source.js +0 -12
  57. package/lib/mount-command.d.ts +0 -10
  58. package/lib/mount-command.js +0 -48
  59. package/lib/mount.d.ts +0 -42
  60. package/lib/mount.js +0 -212
  61. package/lib/notify.d.ts +0 -59
  62. package/lib/notify.js +0 -97
  63. package/lib/plan.d.ts +0 -16
  64. package/lib/plan.js +0 -126
  65. package/lib/planner.d.ts +0 -61
  66. package/lib/planner.js +0 -144
  67. package/lib/pool.d.ts +0 -7
  68. package/lib/pool.js +0 -25
  69. package/lib/prefix-cache.d.ts +0 -78
  70. package/lib/prefix-cache.js +0 -168
  71. package/lib/project.d.ts +0 -28
  72. package/lib/project.js +0 -66
  73. package/lib/projection.d.ts +0 -22
  74. package/lib/projection.js +0 -112
  75. package/lib/promotion.d.ts +0 -94
  76. package/lib/promotion.js +0 -171
  77. package/lib/recall.d.ts +0 -85
  78. package/lib/recall.js +0 -142
  79. package/lib/record-language.d.ts +0 -85
  80. package/lib/record-language.js +0 -152
  81. package/lib/render.d.ts +0 -13
  82. package/lib/render.js +0 -80
  83. package/lib/review-scheduler.d.ts +0 -38
  84. package/lib/review-scheduler.js +0 -191
  85. package/lib/review.d.ts +0 -60
  86. package/lib/review.js +0 -145
  87. package/lib/rollback.d.ts +0 -9
  88. package/lib/rollback.js +0 -68
  89. package/lib/rubric.d.ts +0 -29
  90. package/lib/rubric.js +0 -119
  91. package/lib/runtime.d.ts +0 -24
  92. package/lib/runtime.js +0 -87
  93. package/lib/score.d.ts +0 -64
  94. package/lib/score.js +0 -191
  95. package/lib/search.d.ts +0 -83
  96. package/lib/search.js +0 -136
  97. package/lib/service.d.ts +0 -49
  98. package/lib/service.js +0 -180
  99. package/lib/skill-render.d.ts +0 -23
  100. package/lib/skill-render.js +0 -69
  101. package/lib/skill.d.ts +0 -15
  102. package/lib/skill.js +0 -80
  103. package/lib/skillquality.d.ts +0 -85
  104. package/lib/skillquality.js +0 -320
  105. package/lib/source.d.ts +0 -30
  106. package/lib/source.js +0 -43
  107. package/lib/state.d.ts +0 -26
  108. package/lib/state.js +0 -151
  109. package/lib/store.d.ts +0 -62
  110. package/lib/store.js +0 -164
  111. package/lib/token-usage.d.ts +0 -68
  112. package/lib/token-usage.js +0 -211
  113. package/lib/tool.d.ts +0 -34
  114. package/lib/tool.js +0 -320
  115. package/lib/turn-snapshot.d.ts +0 -72
  116. package/lib/turn-snapshot.js +0 -238
  117. package/lib/types.d.ts +0 -208
  118. package/lib/types.js +0 -127
  119. package/lib/usage.d.ts +0 -36
  120. package/lib/usage.js +0 -98
  121. package/lib/validate.d.ts +0 -28
  122. package/lib/validate.js +0 -181
  123. package/lib/wrapup-command.d.ts +0 -10
  124. package/lib/wrapup-command.js +0 -243
  125. package/lib/wrapup.d.ts +0 -260
  126. package/lib/wrapup.js +0 -539
package/lib/review.js DELETED
@@ -1,145 +0,0 @@
1
- import { extractJsonObject } from "./plan.js";
2
- import { formatHarnessStateForPrompt, historyForPrompt } from "./render.js";
3
- import { sessionEventsOf } from "./inject.js";
4
- import { buildPrefixMessages, detectPlannerRoute, resolvePrefixCache } from "./prefix-cache.js";
5
- import { asLlmSessionId, streamText } from "./llm-text.js";
6
- import { createTokenUsageObserver } from "./token-usage.js";
7
- import { recordLanguageInstruction, resolveRecordLanguage } from "./record-language.js";
8
- export const AUTO_REVIEW_SYSTEM_PROMPT = `You are the automatic /evolve review gate.
9
-
10
- Decide whether this checkpoint should continue the non-memory /evolve path.
11
- A dedicated memory extraction agent has already processed the same snapshot
12
- with a frozen memory manifest, so do NOT approve solely to create, update,
13
- archive, or delete a memory entry. Decline with a rationale that the memory
14
- phase owns that evidence. For the remaining kinds, approve ONLY when the
15
- trajectory shows repeated evidence: the same failure, tactic, delegation
16
- role, or behavioral policy recurs at least twice across turns. A single
17
- one-off interaction defaults to decline no matter how useful it looks for
18
- future turns — one data point is never enough to generalize. When approving,
19
- cite the repeated spans in the instructions so the planner can ground its
20
- edits.
21
-
22
- The current harness state below includes GLOBAL entries (scope=global) plus
23
- this session's local entries (scope=local). When a topic is already covered
24
- by a global entry, do NOT approve a local duplicate of it — decline and say
25
- in the rationale that the topic is already covered globally.
26
-
27
- Reject one-off noise, unsupported hypotheses, transient tool outputs, and
28
- requests that carry no reusable content.
29
-
30
- Stale local entries (superseded, long-unused, obsolete facts) are a valid
31
- refine target: approve with instructions naming the entry ids, and tell the
32
- planner to archive them (archive hides from injection, data stays restorable)
33
- rather than delete.
34
-
35
- Skill-related trajectories (the evidence concerns creating or improving a
36
- skill entry) are judged against the DSH skill quality standard (skill-audit
37
- dimensions: frontmatter routing, the 7 structural features, paragraph
38
- skeleton, no duplication of the official 11 skills or covered skills).
39
- Approve only when the trajectory shows a REAL trigger scenario and the
40
- resulting skill would meet the standard; otherwise decline and say in the
41
- rationale what must improve — drafting follows skill-creator, and the
42
- planner receives the standard as its <skill_quality_standard> block.
43
-
44
- Repeated multi-step workflows (session start/end routines, recurring
45
- wrap-up or handoff procedures) are a valid refine target: approve with
46
- instructions telling the planner to propose a guidance skill (kind=skill,
47
- skill_kind=guidance — a SKILL.md document, no python reference). Only
48
- propose when the same workflow recurs in the trajectory — never for
49
- one-off flows. Auto-created skills are always offered to the user for a
50
- decision before they land; the gate never writes a skill silently.
51
-
52
- Return JSON only:
53
- {
54
- "shouldRefine": true|false,
55
- "rationale": "short reason",
56
- "instructions": "optional concise instructions for /evolve if shouldRefine is true"
57
- }`;
58
- /** Parse the gate's JSON reply. */
59
- export function parseAutoRefineReview(text) {
60
- const value = extractJsonObject(text);
61
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
62
- throw new Error("auto-refine review JSON must be an object");
63
- }
64
- const record = value;
65
- const review = {
66
- shouldRefine: record["shouldRefine"] === true,
67
- rationale: typeof record["rationale"] === "string" ? record["rationale"] : "No rationale provided.",
68
- };
69
- if (typeof record["instructions"] === "string" && record["instructions"].length > 0) {
70
- review.instructions = record["instructions"];
71
- }
72
- return review;
73
- }
74
- /** Serialize surface events to bounded role-prefixed text. */
75
- export function serializeSurface(events, maxChars) {
76
- const lines = [];
77
- for (const raw of events) {
78
- if (typeof raw !== "object" || raw === null)
79
- continue;
80
- const event = raw;
81
- const role = event.type === "user/message" ? "user" : event.type === "assistant/message" ? "assistant" : null;
82
- if (role === null)
83
- continue;
84
- const content = event.data?.content;
85
- if (!Array.isArray(content))
86
- continue;
87
- const text = content
88
- .filter((block) => typeof block === "object" && block !== null && block.type === "text")
89
- .map((block) => block.text ?? "")
90
- .filter(Boolean)
91
- .join(" ");
92
- if (text.length > 0) {
93
- lines.push(`${role}: ${text}`);
94
- }
95
- }
96
- const joined = lines.join("\n");
97
- return joined.length <= maxChars ? joined : joined.slice(-maxChars);
98
- }
99
- export async function reviewAutoRefine(ctx, options) {
100
- const { agent, state, history } = options;
101
- const provider = options.overrideProvider ?? agent.options.provider;
102
- const model = options.overrideModel ?? agent.options.model;
103
- if (!provider || !model) {
104
- throw new Error("evolve: no provider/model route for the review gate");
105
- }
106
- if (!options.trajectory || options.trajectory.length === 0) {
107
- throw new Error("evolve: review gate has no trajectory to judge");
108
- }
109
- // Route A carries the judged conversation as a session-derived message
110
- // prefix and drops the flat block; an empty prefix falls back to B.
111
- const events = options.trajectoryEvents ?? sessionEventsOf(agent);
112
- const routing = resolvePrefixCache(options.prefixCache);
113
- const route = detectPlannerRoute(events, routing.mode);
114
- let prefixMessages = [];
115
- if (route === "A") {
116
- prefixMessages = buildPrefixMessages(events, {
117
- ...(provider ? { provider } : {}),
118
- ...(model ? { model } : {}),
119
- maxChars: routing.maxChars,
120
- });
121
- }
122
- const conversationBlock = prefixMessages.length > 0 ? "" : `<conversation>\n${options.trajectory}\n</conversation>`;
123
- const userPrompt = [
124
- `<trigger>\n${options.context.reason}; ${options.context.turnsSinceLastReview} turns since the last review\n</trigger>`,
125
- `<current_harness_state>\n${formatHarnessStateForPrompt(state)}\n</current_harness_state>`,
126
- `<refinement_history>\n${historyForPrompt(history)}\n</refinement_history>`,
127
- conversationBlock,
128
- "Return shouldRefine=true only when the trajectory shows repeated evidence (>=2 occurrences) useful to this session's future turns. A single one-off interaction defaults to shouldRefine=false. Prefer local edits; do not ask for global refinement here.",
129
- ]
130
- .filter(Boolean)
131
- .join("\n\n");
132
- const text = await streamText(ctx, {
133
- provider,
134
- model,
135
- sessionId: asLlmSessionId(agent.id),
136
- system: `${AUTO_REVIEW_SYSTEM_PROMPT}\n\n${recordLanguageInstruction(options.language ?? resolveRecordLanguage({ ctx, trajectoryText: options.trajectory }))}`,
137
- prompt: userPrompt,
138
- maxTokens: options.budgetTokens ?? 8000,
139
- signal: options.signal,
140
- ...(prefixMessages.length > 0 ? { prefixMessages } : {}),
141
- ...(options.tokenUsage ? { onUsage: createTokenUsageObserver(options.tokenUsage, "review", provider, model) } : {}),
142
- });
143
- return parseAutoRefineReview(text);
144
- }
145
- //# sourceMappingURL=review.js.map
package/lib/rollback.d.ts DELETED
@@ -1,9 +0,0 @@
1
- /**
2
- * Deterministic rollback: rebuild the inverse edit list from the applied
3
- * result, in reverse order. Rollback is pure data transformation — no LLM
4
- * is asked to "guess" the previous state.
5
- */
6
- import type { RefinementProposal, RefinementResult } from "./types.js";
7
- /** Build the inverse proposal for an applied refinement. */
8
- export declare function rollbackProposal(target: RefinementResult): RefinementProposal;
9
- //# sourceMappingURL=rollback.d.ts.map
package/lib/rollback.js DELETED
@@ -1,68 +0,0 @@
1
- /** Build the inverse proposal for an applied refinement. */
2
- export function rollbackProposal(target) {
3
- const edits = [];
4
- for (const edit of [...target.appliedEdits].reverse()) {
5
- if (!edit.applied)
6
- continue;
7
- const inverse = inverseEdit(edit, target.id);
8
- if (inverse) {
9
- edits.push(inverse);
10
- }
11
- }
12
- return {
13
- summary: `Rollback refinement ${target.id}`,
14
- rationale: `Restores harness state to the snapshot recorded before refinement ${target.id}.`,
15
- expectedOutcome: "Faulty refinement edits are reverted.",
16
- edits,
17
- };
18
- }
19
- function inverseEdit(edit, refinementId) {
20
- if (edit.before && edit.after) {
21
- // Forward action was an update: restore the before snapshot.
22
- // skill_kind rides along (review audit 2026-08-28 B4): without it a
23
- // rollback could flip the skill form or fail validation on re-apply.
24
- return {
25
- action: "update",
26
- kind: edit.kind,
27
- id: edit.id,
28
- title: edit.before.title,
29
- content: edit.before.content,
30
- path: edit.before.path,
31
- reference: edit.before.reference,
32
- arguments: edit.before.arguments,
33
- ...(edit.before.skill_kind !== undefined ? { skill_kind: edit.before.skill_kind } : {}),
34
- metadata: edit.before.metadata,
35
- reason: `Rollback ${refinementId}`,
36
- };
37
- }
38
- if (edit.before) {
39
- // Forward action was a delete: re-create the entry from the snapshot.
40
- // skill_kind is required for the re-created skill to pass the same
41
- // contract validation as the original create (B4: a deleted guidance
42
- // skill was previously unrecoverable via rollback).
43
- return {
44
- action: "create",
45
- kind: edit.kind,
46
- id: edit.id,
47
- title: edit.before.title,
48
- content: edit.before.content,
49
- path: edit.before.path,
50
- reference: edit.before.reference,
51
- arguments: edit.before.arguments,
52
- ...(edit.before.skill_kind !== undefined ? { skill_kind: edit.before.skill_kind } : {}),
53
- metadata: edit.before.metadata,
54
- reason: `Rollback ${refinementId}`,
55
- };
56
- }
57
- if (edit.after) {
58
- // Forward action was a create: delete the created entry.
59
- return {
60
- action: "delete",
61
- kind: edit.kind,
62
- id: edit.id,
63
- reason: `Rollback ${refinementId}`,
64
- };
65
- }
66
- return undefined;
67
- }
68
- //# sourceMappingURL=rollback.js.map
package/lib/rubric.d.ts DELETED
@@ -1,29 +0,0 @@
1
- /** The development fallback key — reachable only when the local key file is unusable. */
2
- export declare const DEV_RUBRIC_KEY = "dsh-continual-evolve-dev-key";
3
- /** Name of the per-installation key file under `<baseDir>/evolve/`. */
4
- export declare const RUBRIC_KEY_FILE_NAME = "rubric.key";
5
- /** Full path of the per-installation rubric key file. */
6
- export declare function rubricKeyFilePath(baseDir: string): string;
7
- export interface RubricCipher {
8
- iv: string;
9
- tag: string;
10
- data: string;
11
- }
12
- export declare const RUBRIC_PREFIX = "v1:";
13
- /** Derive a 32-byte AES-256 key from any passphrase. */
14
- export declare function deriveKey(passphrase: string): Buffer;
15
- /** Resolve the effective rubric key with the documented precedence. */
16
- export declare function resolveRubricKey(baseDir: string, configKey: string | undefined, env?: NodeJS.ProcessEnv, warn?: (message: string) => void): Buffer;
17
- /** Encrypt rubric plaintext into the `v1:` envelope (never written raw). */
18
- export declare function encryptRubric(plaintext: string, key: Buffer): string;
19
- /**
20
- * Decrypt a `v1:` envelope. Legacy plaintext (no prefix) passes through
21
- * unchanged so pre-ACL benchmark files keep working. Throws on tampered
22
- * data, a wrong key, or a malformed envelope.
23
- */
24
- export declare function decryptRubric(payload: string, key: Buffer): string;
25
- /** True when a stored rubric is an encrypted envelope rather than legacy plaintext. */
26
- export declare function isEncryptedRubric(payload: string): boolean;
27
- /** Shape helper for tests and callers that inspect envelopes. */
28
- export declare function parseEnvelope(payload: string): RubricCipher | undefined;
29
- //# sourceMappingURL=rubric.d.ts.map
package/lib/rubric.js DELETED
@@ -1,119 +0,0 @@
1
- /**
2
- * Rubric ACL: rubric plaintext never touches the disk. The evaluation runner
3
- * is the ONLY consumer that decrypts — the optimizer (planner) and the model
4
- * (with its bash tools) can read benchmark files and see ciphertext only, so
5
- * rubric isolation is enforced by code, not by prompt construction.
6
- *
7
- * Format: `v1:<base64(iv) | base64(tag) | base64(ciphertext)>` — each part is
8
- * URL-safe base64 without padding, joined by `|`. A value without the `v1:`
9
- * prefix is treated as legacy plaintext (pre-ACL files) and passes through.
10
- *
11
- * Key resolution (first match wins):
12
- * 1. plugin config `rubricKey`
13
- * 2. environment `DSH_EVOLVE_RUBRIC_KEY`
14
- * 3. a per-installation local key file at `<baseDir>/evolve/rubric.key`
15
- * (auto-generated with 0600 permissions on first use — every install
16
- * gets its own random key, so no user setup is needed and no publicly
17
- * known key protects anyone's rubrics)
18
- * 4. a fixed development key as a last-resort fallback when the key file
19
- * can neither be read nor written (warns; only reachable in
20
- * pathological environments, since the plugin's stores live under the
21
- * same directory)
22
- * The key string is derived to 32 bytes with SHA-256, so any passphrase works.
23
- */
24
- import { createCipheriv, createDecipheriv, createHash, randomBytes } from "node:crypto";
25
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
26
- import { dirname, join } from "node:path";
27
- /** The development fallback key — reachable only when the local key file is unusable. */
28
- export const DEV_RUBRIC_KEY = "dsh-continual-evolve-dev-key";
29
- /** Name of the per-installation key file under `<baseDir>/evolve/`. */
30
- export const RUBRIC_KEY_FILE_NAME = "rubric.key";
31
- /** Full path of the per-installation rubric key file. */
32
- export function rubricKeyFilePath(baseDir) {
33
- return join(baseDir, "evolve", RUBRIC_KEY_FILE_NAME);
34
- }
35
- export const RUBRIC_PREFIX = "v1:";
36
- /** Derive a 32-byte AES-256 key from any passphrase. */
37
- export function deriveKey(passphrase) {
38
- return createHash("sha256").update(passphrase, "utf8").digest();
39
- }
40
- /** Resolve the effective rubric key with the documented precedence. */
41
- export function resolveRubricKey(baseDir, configKey, env = process.env, warn) {
42
- if (configKey && configKey.length > 0) {
43
- return deriveKey(configKey);
44
- }
45
- const envKey = env["DSH_EVOLVE_RUBRIC_KEY"];
46
- if (envKey && envKey.length > 0) {
47
- return deriveKey(envKey);
48
- }
49
- return loadOrCreateLocalKey(baseDir, warn);
50
- }
51
- /**
52
- * Load the per-installation key file, generating a fresh random key (0600)
53
- * on first use. Falls back to the development key with a warning when the
54
- * file can neither be read nor written.
55
- */
56
- function loadOrCreateLocalKey(baseDir, warn) {
57
- const path = rubricKeyFilePath(baseDir);
58
- try {
59
- if (existsSync(path)) {
60
- const content = readFileSync(path, "utf8").trim();
61
- if (content.length > 0) {
62
- return deriveKey(content);
63
- }
64
- }
65
- const key = randomBytes(32).toString("hex");
66
- mkdirSync(dirname(path), { recursive: true });
67
- writeFileSync(path, `${key}\n`, { encoding: "utf8", mode: 0o600 });
68
- return deriveKey(key);
69
- }
70
- catch (cause) {
71
- warn?.(`rubric encryption: cannot read/write the local key file (${path}): ${cause instanceof Error ? cause.message : String(cause)} — using the development key`);
72
- return deriveKey(DEV_RUBRIC_KEY);
73
- }
74
- }
75
- /** Encrypt rubric plaintext into the `v1:` envelope (never written raw). */
76
- export function encryptRubric(plaintext, key) {
77
- const iv = randomBytes(12);
78
- const cipher = createCipheriv("aes-256-gcm", key, iv);
79
- const data = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
80
- const tag = cipher.getAuthTag();
81
- return `${RUBRIC_PREFIX}${[iv, tag, data].map((part) => part.toString("base64url")).join("|")}`;
82
- }
83
- /**
84
- * Decrypt a `v1:` envelope. Legacy plaintext (no prefix) passes through
85
- * unchanged so pre-ACL benchmark files keep working. Throws on tampered
86
- * data, a wrong key, or a malformed envelope.
87
- */
88
- export function decryptRubric(payload, key) {
89
- if (!payload.startsWith(RUBRIC_PREFIX)) {
90
- return payload; // legacy plaintext file
91
- }
92
- const raw = payload.slice(RUBRIC_PREFIX.length);
93
- const parts = raw.split("|");
94
- if (parts.length !== 3) {
95
- throw new Error("rubric: malformed encrypted envelope");
96
- }
97
- const [ivText, tagText, dataText] = parts;
98
- const iv = Buffer.from(ivText, "base64url");
99
- const tag = Buffer.from(tagText, "base64url");
100
- const data = Buffer.from(dataText, "base64url");
101
- const decipher = createDecipheriv("aes-256-gcm", key, iv);
102
- decipher.setAuthTag(tag);
103
- return Buffer.concat([decipher.update(data), decipher.final()]).toString("utf8");
104
- }
105
- /** True when a stored rubric is an encrypted envelope rather than legacy plaintext. */
106
- export function isEncryptedRubric(payload) {
107
- return payload.startsWith(RUBRIC_PREFIX);
108
- }
109
- /** Shape helper for tests and callers that inspect envelopes. */
110
- export function parseEnvelope(payload) {
111
- if (!isEncryptedRubric(payload))
112
- return undefined;
113
- const parts = payload.slice(RUBRIC_PREFIX.length).split("|");
114
- if (parts.length !== 3)
115
- return undefined;
116
- const [iv, tag, data] = parts;
117
- return { iv, tag, data };
118
- }
119
- //# sourceMappingURL=rubric.js.map
package/lib/runtime.d.ts DELETED
@@ -1,24 +0,0 @@
1
- /** On-disk runtime gate state. Version 2 adds an explicit enable bit. */
2
- export interface GateRuntime {
3
- version: 2;
4
- /** Whether the human has enabled automatic review. */
5
- enabled: boolean;
6
- /** Whether the human has explicitly paused automatic review. */
7
- paused: boolean;
8
- /** ISO timestamp of the last pause/resume write. */
9
- updatedAt: string;
10
- }
11
- /** Full path of the runtime switch file. */
12
- export declare function runtimePath(baseDir: string): string;
13
- /**
14
- * Load the runtime switch. Missing, malformed, or legacy content uses the
15
- * supplied configured default and never throws; this is a trigger-path read.
16
- */
17
- export declare function loadGateRuntime(baseDir: string, defaultEnabled?: boolean): GateRuntime;
18
- /** Persist the runtime switch atomically (temp file + rename). */
19
- export declare function saveGateRuntime(baseDir: string, paused: boolean, enabled?: boolean): string;
20
- /** True while the human paused the automatic review gate. */
21
- export declare function isGatePaused(baseDir: string): boolean;
22
- /** Effective automatic-review state, including the explicit enable bit. */
23
- export declare function isGateEnabled(baseDir: string, defaultEnabled?: boolean): boolean;
24
- //# sourceMappingURL=runtime.d.ts.map
package/lib/runtime.js DELETED
@@ -1,87 +0,0 @@
1
- /**
2
- * Runtime gate switch: a small human-owned file that enables or pauses the
3
- * automatic review listener without editing the profile or restarting DSH.
4
- *
5
- * - file: `<baseDir>/evolve/runtime.json` (`{version: 2, enabled, paused, updatedAt}`)
6
- * - the file is consulted at every trigger and before scheduler execution;
7
- * - `/evolve pause` sets `paused`, `/evolve resume` sets `enabled=true` and
8
- * clears the pause, while manual tools and commands remain independent;
9
- * - a missing or malformed file uses the caller's configured default. A
10
- * legacy v1 `{paused}` file is readable and preserves its pause state.
11
- */
12
- import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
13
- import { randomUUID } from "node:crypto";
14
- import { join } from "node:path";
15
- import { EVOLVE_DIR } from "./store.js";
16
- const RUNTIME_FILE = "runtime.json";
17
- /** Full path of the runtime switch file. */
18
- export function runtimePath(baseDir) {
19
- return join(baseDir, EVOLVE_DIR, RUNTIME_FILE);
20
- }
21
- function state(enabled, paused) {
22
- return { version: 2, enabled, paused, updatedAt: new Date(0).toISOString() };
23
- }
24
- /**
25
- * Load the runtime switch. Missing, malformed, or legacy content uses the
26
- * supplied configured default and never throws; this is a trigger-path read.
27
- */
28
- export function loadGateRuntime(baseDir, defaultEnabled = false) {
29
- const path = runtimePath(baseDir);
30
- if (!existsSync(path))
31
- return state(defaultEnabled, false);
32
- try {
33
- const raw = JSON.parse(readFileSync(path, "utf8"));
34
- if (typeof raw !== "object" || raw === null || Array.isArray(raw))
35
- return state(defaultEnabled, false);
36
- const record = raw;
37
- const paused = record["paused"] === true;
38
- // v1 had no enable bit. Its only meaningful state was pause, so retain
39
- // the configured default when it is not paused.
40
- const enabled = typeof record["enabled"] === "boolean" ? record["enabled"] : defaultEnabled;
41
- return {
42
- version: 2,
43
- enabled,
44
- paused,
45
- updatedAt: typeof record["updatedAt"] === "string" ? record["updatedAt"] : new Date(0).toISOString(),
46
- };
47
- }
48
- catch {
49
- return state(defaultEnabled, false);
50
- }
51
- }
52
- /** Persist the runtime switch atomically (temp file + rename). */
53
- export function saveGateRuntime(baseDir, paused, enabled = true) {
54
- const path = runtimePath(baseDir);
55
- mkdirSync(join(baseDir, EVOLVE_DIR), { recursive: true });
56
- const tempPath = `${path}.${process.pid}.${randomUUID()}.tmp`;
57
- const payload = { version: 2, enabled, paused, updatedAt: new Date().toISOString() };
58
- writeFileSync(tempPath, `${JSON.stringify(payload, null, 2)}\n`, "utf8");
59
- try {
60
- renameSync(tempPath, path);
61
- }
62
- finally {
63
- if (existsSync(tempPath))
64
- unlinkSync(tempPath);
65
- }
66
- return path;
67
- }
68
- /** True while the human paused the automatic review gate. */
69
- export function isGatePaused(baseDir) {
70
- try {
71
- return loadGateRuntime(baseDir).paused;
72
- }
73
- catch {
74
- return false;
75
- }
76
- }
77
- /** Effective automatic-review state, including the explicit enable bit. */
78
- export function isGateEnabled(baseDir, defaultEnabled = false) {
79
- try {
80
- const current = loadGateRuntime(baseDir, defaultEnabled);
81
- return current.enabled && !current.paused;
82
- }
83
- catch {
84
- return defaultEnabled;
85
- }
86
- }
87
- //# sourceMappingURL=runtime.js.map
package/lib/score.d.ts DELETED
@@ -1,64 +0,0 @@
1
- /**
2
- * Code-owned scoring: aggregation and acceptance decisions. The model only
3
- * produces per-cell raw scores; every average and every accept/reject call
4
- * happens here, in deterministic code.
5
- */
6
- import type { CellScore, EvaluationEntry } from "./benchmark.js";
7
- export interface AggregateOptions {
8
- /** A cell is "passed" if its raw score is at least this threshold. */
9
- passThreshold: number;
10
- /** Per-case regression tolerance: candidate may drop below reference by at most this much. */
11
- regressionTolerance: number;
12
- /**
13
- * Failure-cell protocol (gap A2): a round with more failed cells than
14
- * this is rejected outright — failed cells are NEVER averaged in as
15
- * zeros. Default 0 (any failure rejects the round).
16
- */
17
- maxFailedCells: number;
18
- }
19
- export declare const DEFAULT_AGGREGATE: AggregateOptions;
20
- export interface AggregateResult extends Record<string, number | null> {
21
- overall: number | null;
22
- /** Count of failed cells (excluded from every mean). */
23
- failed: number;
24
- /** Total cells considered (ok + failed). */
25
- total: number;
26
- /** Gap C3: total wall-clock duration of all cells in milliseconds. */
27
- totalDurationMs: number;
28
- }
29
- /**
30
- * Aggregate raw cells into code-owned per-case means + overall mean.
31
- * Failure-cell protocol (gap A2): failed cells are EXCLUDED from means and
32
- * counted separately — a crashed unit can never silently drag the mean down
33
- * like a zero. A case whose cells all failed reports null (no mean).
34
- */
35
- export declare function aggregate(cells: readonly CellScore[]): AggregateResult;
36
- export declare function entryFromCells(label: string, cells: readonly CellScore[], refinementId?: string): EvaluationEntry;
37
- export interface Decision {
38
- accepted: boolean;
39
- reasons: string[];
40
- }
41
- /** Human-readable decision report with per-case before → after deltas. */
42
- export declare function decisionReport(reference: EvaluationEntry, candidate: EvaluationEntry, decision: Decision): string[];
43
- /**
44
- * Gap A3 (version_changed semantics): detect cells whose case material
45
- * changed between the reference and candidate evaluation runs. A candidate
46
- * cell whose `caseHash` differs from the reference cell of the SAME case
47
- * means the statement/rubric was edited between the two runs — its score is
48
- * not comparable to the baseline and must not count toward the decision.
49
- *
50
- * The check is conservative: cells without a hash on either side (pre-A3
51
- * data) and cells already failed are left untouched. Mismatched cells are
52
- * returned re-marked as `failed` with a reason in notes, so aggregation
53
- * excludes them and the acceptance rule can reject the round.
54
- */
55
- export declare function flagMaterialDrift(reference: EvaluationEntry, candidateCells: readonly CellScore[]): CellScore[];
56
- /**
57
- * Non-regressive acceptance rule (Self-Harness style):
58
- * the candidate is accepted iff its overall mean is STRICTLY higher than the
59
- * reference, no case regresses by more than `regressionTolerance` points,
60
- * and neither side has more failed cells than `maxFailedCells` (failure-cell
61
- * protocol, gap A2 — a partial/invalid round is never accepted).
62
- */
63
- export declare function decide(reference: EvaluationEntry, candidate: EvaluationEntry, opts: AggregateOptions): Decision;
64
- //# sourceMappingURL=score.d.ts.map