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/state.d.ts DELETED
@@ -1,26 +0,0 @@
1
- import type { HarnessScope, HarnessState } from "./types.js";
2
- export declare function stateFilePath(stateDir: string): string;
3
- /**
4
- * Load state from disk, degrading to empty on any unreadable or malformed
5
- * content. Called on every system-prompt build and before every apply, so it
6
- * must never throw for a bad file.
7
- */
8
- export declare function loadHarnessState(stateDir: string, scope?: HarnessScope): HarnessState;
9
- /**
10
- * Merge global, project, and local state into the view the model sees.
11
- * Precedence is global < project < local: a colliding project id is
12
- * prefixed `project:` so both remain addressable, and a colliding local id
13
- * is prefixed `local:` (local always wins — it is the session's live
14
- * staging copy). Called with two args the project layer is simply absent.
15
- */
16
- export declare function mergeHarnessStates(globalState: HarnessState, localState?: HarnessState | undefined, opts?: {
17
- projectState?: HarnessState | undefined;
18
- }): HarnessState;
19
- /**
20
- * Persist state atomically: write to a temp file, fsync-free but rename-based,
21
- * preserving the mode of an existing file (defaults to 0o600 for new files).
22
- */
23
- export declare function saveHarnessState(stateDir: string, state: HarnessState): string;
24
- /** True when an entry in `current` differs from the same entry in `baseline`. */
25
- export declare function entryChangedSince(baseline: HarnessState, current: HarnessState, kind: keyof HarnessState["entries"], id: string): boolean;
26
- //# sourceMappingURL=state.d.ts.map
package/lib/state.js DELETED
@@ -1,151 +0,0 @@
1
- /**
2
- * Persistence layer for harness state: atomic writes, corrupt-file degrade,
3
- * scope merge, and optimistic-concurrency primitives.
4
- *
5
- * Safety properties (code-enforced, not prompt-enforced):
6
- * - writes are atomic (temp file + rename) and preserve the file mode;
7
- * - an unreadable or non-object state file degrades to empty state so a
8
- * broken file can never take a session down; the next save rewrites it
9
- * cleanly;
10
- * - every entry read from disk is shape-normalized (scope, reference,
11
- * arguments, metadata) so a hand-edited file cannot smuggle garbage into
12
- * the system prompt renderer.
13
- */
14
- import { existsSync, mkdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
15
- import { readFileSync } from "node:fs";
16
- import { randomUUID } from "node:crypto";
17
- import { join } from "node:path";
18
- import { emptyHarnessState } from "./types.js";
19
- export function stateFilePath(stateDir) {
20
- return join(stateDir, "harness_state.json");
21
- }
22
- function normalizeScope(value, fallback) {
23
- return value === "global" || value === "project" || value === "local" ? value : fallback;
24
- }
25
- function objectRecord(value) {
26
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
27
- return undefined;
28
- }
29
- return value;
30
- }
31
- /**
32
- * Load state from disk, degrading to empty on any unreadable or malformed
33
- * content. Called on every system-prompt build and before every apply, so it
34
- * must never throw for a bad file.
35
- */
36
- export function loadHarnessState(stateDir, scope = "global") {
37
- const path = stateFilePath(stateDir);
38
- if (!existsSync(path)) {
39
- return emptyHarnessState();
40
- }
41
- let parsed;
42
- try {
43
- parsed = JSON.parse(readFileSync(path, "utf8"));
44
- }
45
- catch {
46
- return emptyHarnessState();
47
- }
48
- const root = objectRecord(parsed);
49
- if (!root) {
50
- return emptyHarnessState();
51
- }
52
- const state = emptyHarnessState();
53
- if (typeof root["schema"] === "number") {
54
- state.schema = root["schema"];
55
- }
56
- const entries = objectRecord(root["entries"]);
57
- if (entries) {
58
- for (const kind of Object.keys(state.entries)) {
59
- const records = objectRecord(entries[kind]);
60
- if (!records)
61
- continue;
62
- for (const [id, raw] of Object.entries(records)) {
63
- const entry = objectRecord(raw);
64
- if (!entry)
65
- continue;
66
- state.entries[kind][id] = {
67
- id: typeof entry["id"] === "string" ? entry["id"] : id,
68
- kind,
69
- title: typeof entry["title"] === "string" ? entry["title"] : id,
70
- content: typeof entry["content"] === "string" ? entry["content"] : "",
71
- path: typeof entry["path"] === "string" ? entry["path"] : "general",
72
- scope: normalizeScope(entry["scope"], scope),
73
- reference: objectRecord(entry["reference"]) ?? {},
74
- arguments: objectRecord(entry["arguments"]) ?? {},
75
- // skill_kind must survive persistence: /evolve mount and the
76
- // listing render branch on it (guidance vs executable).
77
- ...(entry["skill_kind"] === "guidance" || entry["skill_kind"] === "executable"
78
- ? { skill_kind: entry["skill_kind"] }
79
- : {}),
80
- metadata: objectRecord(entry["metadata"]) ?? {},
81
- source: "evolve",
82
- created_at: typeof entry["created_at"] === "string" ? entry["created_at"] : new Date(0).toISOString(),
83
- updated_at: typeof entry["updated_at"] === "string" ? entry["updated_at"] : new Date(0).toISOString(),
84
- version: typeof entry["version"] === "number" ? entry["version"] : 1,
85
- };
86
- }
87
- }
88
- }
89
- if (Array.isArray(root["refinements"])) {
90
- // Shape-check members like entries do: a hand-edited file must never
91
- // reach render/planner paths and crash them (review audit 2026-08-28
92
- // S6 — loadHarnessState promises "never throws on a bad file").
93
- state.refinements = root["refinements"].filter((item) => typeof item === "object" && item !== null && typeof item["id"] === "string");
94
- }
95
- return state;
96
- }
97
- /**
98
- * Merge global, project, and local state into the view the model sees.
99
- * Precedence is global < project < local: a colliding project id is
100
- * prefixed `project:` so both remain addressable, and a colliding local id
101
- * is prefixed `local:` (local always wins — it is the session's live
102
- * staging copy). Called with two args the project layer is simply absent.
103
- */
104
- export function mergeHarnessStates(globalState, localState, opts) {
105
- const merged = emptyHarnessState();
106
- merged.schema = Math.max(globalState.schema, opts?.projectState?.schema ?? 1, localState?.schema ?? 1);
107
- for (const kind of Object.keys(merged.entries)) {
108
- for (const [id, entry] of Object.entries(globalState.entries[kind])) {
109
- merged.entries[kind][id] = { ...entry, scope: "global" };
110
- }
111
- for (const [id, entry] of Object.entries(opts?.projectState?.entries[kind] ?? {})) {
112
- const scoped = { ...entry, scope: "project" };
113
- const mergedId = merged.entries[kind][id] ? `project:${id}` : id;
114
- merged.entries[kind][mergedId] = scoped;
115
- }
116
- for (const [id, entry] of Object.entries(localState?.entries[kind] ?? {})) {
117
- const scoped = { ...entry, scope: "local" };
118
- const mergedId = merged.entries[kind][id] ? `local:${id}` : id;
119
- merged.entries[kind][mergedId] = scoped;
120
- }
121
- }
122
- merged.refinements = [...globalState.refinements, ...(opts?.projectState?.refinements ?? []), ...(localState?.refinements ?? [])];
123
- return merged;
124
- }
125
- /**
126
- * Persist state atomically: write to a temp file, fsync-free but rename-based,
127
- * preserving the mode of an existing file (defaults to 0o600 for new files).
128
- */
129
- export function saveHarnessState(stateDir, state) {
130
- const path = stateFilePath(stateDir);
131
- const tempPath = `${path}.${process.pid}.${randomUUID()}.tmp`;
132
- mkdirSync(stateDir, { recursive: true });
133
- try {
134
- const mode = existsSync(path) ? statSync(path).mode & 0o777 : 0o600;
135
- writeFileSync(tempPath, `${JSON.stringify(state, null, 2)}\n`, { encoding: "utf8", mode });
136
- renameSync(tempPath, path);
137
- }
138
- finally {
139
- if (existsSync(tempPath)) {
140
- unlinkSync(tempPath);
141
- }
142
- }
143
- return path;
144
- }
145
- /** True when an entry in `current` differs from the same entry in `baseline`. */
146
- export function entryChangedSince(baseline, current, kind, id) {
147
- const before = baseline.entries[kind][id];
148
- const after = current.entries[kind][id];
149
- return JSON.stringify(before ?? null) !== JSON.stringify(after ?? null);
150
- }
151
- //# sourceMappingURL=state.js.map
package/lib/store.d.ts DELETED
@@ -1,62 +0,0 @@
1
- import type { HarnessScope, RefinementResult } from "./types.js";
2
- export declare const EVOLVE_DIR = "evolve";
3
- /**
4
- * Storage-hygiene defaults (#20): history used to grow append-only without
5
- * bound (dozens of full-state snapshot copies, unbounded JSONL). Retention
6
- * is count-based and generous — rollback only ever needs recent snapshots
7
- * and readers (`failures.ts` over reviews) need a working window, not the
8
- * full past. Tunable via the `historyRetain` plugin config.
9
- */
10
- export declare const DEFAULT_SNAPSHOT_RETAIN = 20;
11
- export declare const DEFAULT_REFINEMENTS_RETAIN = 500;
12
- export declare const DEFAULT_REVIEWS_RETAIN = 500;
13
- export declare const DEFAULT_TOKEN_USAGE_RETAIN = 500;
14
- /** Resolved retention set: how many snapshots / JSONL tail lines to keep. */
15
- export interface HistoryRetention {
16
- /** Full-state snapshots kept per store (oldest pruned first). */
17
- snapshots: number;
18
- /** Tail lines kept in each store's refinements.jsonl. */
19
- refinements: number;
20
- /** Tail lines kept in the shared reviews.jsonl audit trail. */
21
- reviews: number;
22
- /** Tail lines kept in the direct-call token-usage.jsonl ledger. */
23
- tokenUsage: number;
24
- }
25
- /** Defaults applied for absent / non-positive retention fields (fail loud never: clamp, don't throw). */
26
- export declare function resolveHistoryRetention(raw?: Partial<HistoryRetention>): HistoryRetention;
27
- export interface StorePaths {
28
- /** Directory holding harness_state.json. */
29
- stateDir: string;
30
- /** Directory holding snapshots for this store. */
31
- snapshotsDir: string;
32
- /** JSONL path for applied refinement results. */
33
- resultsPath: string;
34
- }
35
- /**
36
- * Resolve store paths for a scope. For `project` the `sessionId` parameter
37
- * carries the project key (see {@link resolveProjectKey} in project.ts) —
38
- * it is sanitized to a single path segment so an externally supplied key
39
- * can never traverse out of `evolve/projects/`.
40
- */
41
- export declare function storePaths(baseDir: string, scope: HarnessScope, sessionId?: string): StorePaths;
42
- /** Snapshot the current state file before a mutation, if one exists. */
43
- export declare function snapshotBefore(paths: StorePaths, refinementId: string): void;
44
- /** Append an applied result to the store's JSONL history. */
45
- export declare function appendResult(paths: StorePaths, result: RefinementResult): void;
46
- /**
47
- * Prune a store's snapshots to the newest `retain` files (by mtime, oldest
48
- * first). Best-effort: a missing directory or an unlink failure never breaks
49
- * the apply path — the next apply retries.
50
- */
51
- export declare function pruneSnapshots(snapshotsDir: string, retain: number): void;
52
- /**
53
- * Truncate a JSONL file to its last `retain` non-empty lines. No-op when the
54
- * file is missing or already within budget — the common case costs one
55
- * read and no write.
56
- */
57
- export declare function pruneJsonlFile(path: string, retain: number): void;
58
- /** Reviews audit-trail path shared by the gate, fate, and tool events. */
59
- export declare function reviewsPath(baseDir: string): string;
60
- /** Read the applied results history; malformed lines are skipped, never fatal. */
61
- export declare function loadResults(paths: StorePaths): RefinementResult[];
62
- //# sourceMappingURL=store.d.ts.map
package/lib/store.js DELETED
@@ -1,164 +0,0 @@
1
- /**
2
- * Store layout and snapshot discipline for the evolution plugin.
3
- *
4
- * Layout (self-contained under the DSH home; no dependency on session
5
- * persistence internals):
6
- *
7
- * <dshHome>/evolve/global/harness_state.json cross-project store
8
- * <dshHome>/evolve/global/refinements.jsonl applied results (rollback source)
9
- * <dshHome>/evolve/projects/<slug-hash>/... per-project store
10
- * <dshHome>/evolve/local/<sessionId>/... per-session staging store
11
- *
12
- * Snapshot discipline is code-enforced: before any mutating apply, the
13
- * pre-apply state is copied to `snapshots/<refinementId>.json`. The model has
14
- * no way to skip it — it runs inside the service, not in a prompt.
15
- */
16
- import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
17
- import { join } from "node:path";
18
- import { sanitizeProjectKey } from "./project.js";
19
- import { stateFilePath } from "./state.js";
20
- export const EVOLVE_DIR = "evolve";
21
- /**
22
- * Storage-hygiene defaults (#20): history used to grow append-only without
23
- * bound (dozens of full-state snapshot copies, unbounded JSONL). Retention
24
- * is count-based and generous — rollback only ever needs recent snapshots
25
- * and readers (`failures.ts` over reviews) need a working window, not the
26
- * full past. Tunable via the `historyRetain` plugin config.
27
- */
28
- export const DEFAULT_SNAPSHOT_RETAIN = 20;
29
- export const DEFAULT_REFINEMENTS_RETAIN = 500;
30
- export const DEFAULT_REVIEWS_RETAIN = 500;
31
- export const DEFAULT_TOKEN_USAGE_RETAIN = 500;
32
- /** Defaults applied for absent / non-positive retention fields (fail loud never: clamp, don't throw). */
33
- export function resolveHistoryRetention(raw) {
34
- const pick = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
35
- return {
36
- snapshots: pick(raw?.snapshots, DEFAULT_SNAPSHOT_RETAIN),
37
- refinements: pick(raw?.refinements, DEFAULT_REFINEMENTS_RETAIN),
38
- reviews: pick(raw?.reviews, DEFAULT_REVIEWS_RETAIN),
39
- tokenUsage: pick(raw?.tokenUsage, DEFAULT_TOKEN_USAGE_RETAIN),
40
- };
41
- }
42
- /**
43
- * Resolve store paths for a scope. For `project` the `sessionId` parameter
44
- * carries the project key (see {@link resolveProjectKey} in project.ts) —
45
- * it is sanitized to a single path segment so an externally supplied key
46
- * can never traverse out of `evolve/projects/`.
47
- */
48
- export function storePaths(baseDir, scope, sessionId) {
49
- const scopeDir = scope === "global" ? "global" : scope === "project" ? join("projects", sanitizeProjectKey(sessionId ?? "project")) : join("local", sessionId ?? "anonymous");
50
- const stateDir = join(baseDir, EVOLVE_DIR, scopeDir);
51
- return {
52
- stateDir,
53
- snapshotsDir: join(stateDir, "snapshots"),
54
- resultsPath: join(stateDir, "refinements.jsonl"),
55
- };
56
- }
57
- /** Snapshot the current state file before a mutation, if one exists. */
58
- export function snapshotBefore(paths, refinementId) {
59
- const statePath = stateFilePath(paths.stateDir);
60
- if (!existsSync(statePath)) {
61
- return;
62
- }
63
- mkdirSync(paths.snapshotsDir, { recursive: true });
64
- // 0600: the snapshot is a full copy of harness_state.json — same
65
- // permission discipline as the store itself (review audit 2026-08-28 S5).
66
- writeFileSync(join(paths.snapshotsDir, `${refinementId}.json`), readFileSync(statePath, "utf8"), { encoding: "utf8", mode: 0o600 });
67
- }
68
- /** Append an applied result to the store's JSONL history. */
69
- export function appendResult(paths, result) {
70
- mkdirSync(paths.stateDir, { recursive: true });
71
- writeFileSync(paths.resultsPath, `${JSON.stringify(result)}\n`, { encoding: "utf8", flag: "a" });
72
- }
73
- /**
74
- * Prune a store's snapshots to the newest `retain` files (by mtime, oldest
75
- * first). Best-effort: a missing directory or an unlink failure never breaks
76
- * the apply path — the next apply retries.
77
- */
78
- export function pruneSnapshots(snapshotsDir, retain) {
79
- const keep = Math.floor(retain);
80
- if (!(keep > 0) || !existsSync(snapshotsDir))
81
- return;
82
- let files;
83
- try {
84
- files = readdirSync(snapshotsDir).filter((f) => f.endsWith(".json"));
85
- }
86
- catch {
87
- return; // unreadable directory — leave it for the next attempt
88
- }
89
- if (files.length <= keep)
90
- return;
91
- const withTime = [];
92
- for (const file of files) {
93
- try {
94
- withTime.push({ file, mtime: statSync(join(snapshotsDir, file)).mtimeMs });
95
- }
96
- catch {
97
- // unstatable file — keep it rather than delete blindly
98
- }
99
- }
100
- withTime.sort((a, b) => a.mtime - b.mtime);
101
- for (const victim of withTime.slice(0, Math.max(0, withTime.length - keep))) {
102
- try {
103
- unlinkSync(join(snapshotsDir, victim.file));
104
- }
105
- catch {
106
- // one bad unlink must not stop the sweep or the apply path
107
- }
108
- }
109
- }
110
- /**
111
- * Truncate a JSONL file to its last `retain` non-empty lines. No-op when the
112
- * file is missing or already within budget — the common case costs one
113
- * read and no write.
114
- */
115
- export function pruneJsonlFile(path, retain) {
116
- const keep = Math.floor(retain);
117
- if (!(keep > 0) || !existsSync(path))
118
- return;
119
- let lines;
120
- try {
121
- lines = readFileSync(path, "utf8").split("\n").filter((l) => l.trim().length > 0);
122
- }
123
- catch {
124
- return; // unreadable file — leave it for the next attempt
125
- }
126
- if (lines.length <= keep)
127
- return;
128
- try {
129
- writeFileSync(path, `${lines.slice(-keep).join("\n")}\n`, "utf8");
130
- }
131
- catch {
132
- // truncation failure must not break the write path that called it
133
- }
134
- }
135
- /** Reviews audit-trail path shared by the gate, fate, and tool events. */
136
- export function reviewsPath(baseDir) {
137
- return join(baseDir, EVOLVE_DIR, "reviews.jsonl");
138
- }
139
- /** Read the applied results history; malformed lines are skipped, never fatal. */
140
- export function loadResults(paths) {
141
- if (!existsSync(paths.resultsPath)) {
142
- return [];
143
- }
144
- const results = [];
145
- for (const line of readFileSync(paths.resultsPath, "utf8").split("\n")) {
146
- const trimmed = line.trim();
147
- if (!trimmed)
148
- continue;
149
- try {
150
- const parsed = JSON.parse(trimmed);
151
- if (isResult(parsed)) {
152
- results.push(parsed);
153
- }
154
- }
155
- catch {
156
- // skip malformed line
157
- }
158
- }
159
- return results;
160
- }
161
- function isResult(data) {
162
- return typeof data === "object" && data !== null && "id" in data && "appliedEdits" in data;
163
- }
164
- //# sourceMappingURL=store.js.map
@@ -1,68 +0,0 @@
1
- import type { TokenUsage } from "@deepseek-ai/dsh-llm";
2
- import type { StreamTextObservation, StreamTextUsageObserver } from "./llm-text.js";
3
- export declare const TOKEN_USAGE_LEDGER_VERSION = 1;
4
- /** Plugin-owned direct call paths represented in the ledger. */
5
- export declare const TOKEN_USAGE_PHASES: readonly ["review", "memory", "planner", "wrapup", "fate"];
6
- export type TokenUsagePhase = (typeof TOKEN_USAGE_PHASES)[number];
7
- /** Whether the provider supplied a usage sample; missing is never treated as zero. */
8
- export type TokenUsageStatus = "reported" | "missing";
9
- /** How the exact full-call total was obtained. */
10
- export type TokenTotalSource = "provider" | "derived" | "unavailable";
11
- /** One retained direct-call observation. */
12
- export interface TokenUsageRecord {
13
- version: typeof TOKEN_USAGE_LEDGER_VERSION;
14
- timestamp: string;
15
- sessionId: string;
16
- phase: TokenUsagePhase;
17
- provider: string;
18
- model: string;
19
- outcome: StreamTextObservation["outcome"];
20
- usageStatus: TokenUsageStatus;
21
- /** Absent exactly when {@link usageStatus} is `missing`. */
22
- usage?: TokenUsage;
23
- totalSource: TokenTotalSource;
24
- }
25
- /** Caller-owned destination and failure hook; phase/provider/model are supplied by the call site. */
26
- export interface TokenUsageTarget {
27
- baseDir: string;
28
- sessionId: string;
29
- retain: number;
30
- onError?: (cause: unknown) => void;
31
- }
32
- /** Loaded retained window plus corrupt-line count for honest coverage reporting. */
33
- export interface LoadedTokenUsage {
34
- records: TokenUsageRecord[];
35
- corruptLines: number;
36
- }
37
- /** Aggregate provider-reported buckets over a retained ledger window. */
38
- export interface TokenUsageTotals {
39
- calls: number;
40
- reportedCalls: number;
41
- missingUsageCalls: number;
42
- uncachedInputTokens: number;
43
- cacheReadTokens: number;
44
- cacheWriteTokens: number;
45
- outputTokens: number;
46
- reasoningTokens: number;
47
- totalTokens: number;
48
- }
49
- /** Absolute path of the direct-call token ledger. */
50
- export declare function tokenUsagePath(baseDir: string): string;
51
- /** Exact full-call total, with the old-peer fallback only when `totalTokens` is absent. */
52
- export declare function exactTokenTotal(usage: TokenUsage): number;
53
- /** Build the observer attached to one `streamText` call. Errors are diagnostic-only. */
54
- export declare function createTokenUsageObserver(target: TokenUsageTarget, phase: TokenUsagePhase, provider: string, model: string): StreamTextUsageObserver;
55
- /**
56
- * Append one call and enforce the dedicated tail budget. Append + conditional
57
- * prune stay in one synchronous block, so concurrent async callers in one DSH
58
- * process cannot interleave the read/truncate/write. Multiple DSH processes
59
- * sharing one baseDir are outside the plugin's storage contract.
60
- */
61
- export declare function appendTokenUsage(target: TokenUsageTarget, record: TokenUsageRecord): void;
62
- /** Load valid records from the retained ledger; malformed lines never break `/evolve usage`. */
63
- export declare function loadTokenUsage(baseDir: string): LoadedTokenUsage;
64
- /** Sum exact provider-reported buckets without double-counting reasoning or cache fields. */
65
- export declare function aggregateTokenUsage(records: readonly TokenUsageRecord[]): TokenUsageTotals;
66
- /** Render the human-facing direct-call ledger section. */
67
- export declare function renderTokenUsageReport(ledger: LoadedTokenUsage, retain: number): string[];
68
- //# sourceMappingURL=token-usage.d.ts.map