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.
- package/README.md +35 -122
- package/README.zh.md +26 -97
- package/cordis.patch.yml +2 -2
- package/lib/index.d.ts +44 -241
- package/lib/index.js +30 -253
- package/lib/memory-guide.d.ts +13 -14
- package/lib/memory-guide.js +32 -21
- package/lib/memory-section.d.ts +77 -0
- package/lib/memory-section.js +189 -0
- package/package.json +2 -17
- package/lib/apply.d.ts +0 -22
- package/lib/apply.js +0 -157
- package/lib/approval.d.ts +0 -72
- package/lib/approval.js +0 -127
- package/lib/auto.d.ts +0 -236
- package/lib/auto.js +0 -773
- package/lib/autocase.d.ts +0 -38
- package/lib/autocase.js +0 -76
- package/lib/benchmark-command.d.ts +0 -9
- package/lib/benchmark-command.js +0 -357
- package/lib/benchmark.d.ts +0 -151
- package/lib/benchmark.js +0 -250
- package/lib/command.d.ts +0 -49
- package/lib/command.js +0 -568
- package/lib/consolidate.d.ts +0 -90
- package/lib/consolidate.js +0 -180
- package/lib/copy.d.ts +0 -74
- package/lib/copy.js +0 -160
- package/lib/declines.d.ts +0 -101
- package/lib/declines.js +0 -175
- package/lib/evaluate.d.ts +0 -74
- package/lib/evaluate.js +0 -271
- package/lib/evolve-event.d.ts +0 -40
- package/lib/evolve-event.js +0 -59
- package/lib/failures.d.ts +0 -42
- package/lib/failures.js +0 -171
- package/lib/fate.d.ts +0 -130
- package/lib/fate.js +0 -350
- package/lib/goal-command.d.ts +0 -7
- package/lib/goal-command.js +0 -37
- package/lib/goal.d.ts +0 -72
- package/lib/goal.js +0 -72
- package/lib/inject.d.ts +0 -196
- package/lib/inject.js +0 -412
- package/lib/llm-text.d.ts +0 -104
- package/lib/llm-text.js +0 -140
- package/lib/logfile.d.ts +0 -71
- package/lib/logfile.js +0 -159
- package/lib/memory-agent.d.ts +0 -129
- package/lib/memory-agent.js +0 -568
- package/lib/memory-benchmark.d.ts +0 -76
- package/lib/memory-benchmark.js +0 -170
- package/lib/memory-index.d.ts +0 -114
- package/lib/memory-index.js +0 -197
- package/lib/message-source.d.ts +0 -23
- package/lib/message-source.js +0 -12
- package/lib/mount-command.d.ts +0 -10
- package/lib/mount-command.js +0 -48
- package/lib/mount.d.ts +0 -42
- package/lib/mount.js +0 -212
- package/lib/notify.d.ts +0 -59
- package/lib/notify.js +0 -97
- package/lib/plan.d.ts +0 -16
- package/lib/plan.js +0 -126
- package/lib/planner.d.ts +0 -61
- package/lib/planner.js +0 -144
- package/lib/pool.d.ts +0 -7
- package/lib/pool.js +0 -25
- package/lib/prefix-cache.d.ts +0 -78
- package/lib/prefix-cache.js +0 -168
- package/lib/project.d.ts +0 -28
- package/lib/project.js +0 -66
- package/lib/projection.d.ts +0 -22
- package/lib/projection.js +0 -112
- package/lib/promotion.d.ts +0 -94
- package/lib/promotion.js +0 -171
- package/lib/recall.d.ts +0 -85
- package/lib/recall.js +0 -142
- package/lib/record-language.d.ts +0 -85
- package/lib/record-language.js +0 -152
- package/lib/render.d.ts +0 -13
- package/lib/render.js +0 -80
- package/lib/review-scheduler.d.ts +0 -38
- package/lib/review-scheduler.js +0 -191
- package/lib/review.d.ts +0 -60
- package/lib/review.js +0 -145
- package/lib/rollback.d.ts +0 -9
- package/lib/rollback.js +0 -68
- package/lib/rubric.d.ts +0 -29
- package/lib/rubric.js +0 -119
- package/lib/runtime.d.ts +0 -24
- package/lib/runtime.js +0 -87
- package/lib/score.d.ts +0 -64
- package/lib/score.js +0 -191
- package/lib/search.d.ts +0 -83
- package/lib/search.js +0 -136
- package/lib/service.d.ts +0 -49
- package/lib/service.js +0 -180
- package/lib/skill-render.d.ts +0 -23
- package/lib/skill-render.js +0 -69
- package/lib/skill.d.ts +0 -15
- package/lib/skill.js +0 -80
- package/lib/skillquality.d.ts +0 -85
- package/lib/skillquality.js +0 -320
- package/lib/source.d.ts +0 -30
- package/lib/source.js +0 -43
- package/lib/state.d.ts +0 -26
- package/lib/state.js +0 -151
- package/lib/store.d.ts +0 -62
- package/lib/store.js +0 -164
- package/lib/token-usage.d.ts +0 -68
- package/lib/token-usage.js +0 -211
- package/lib/tool.d.ts +0 -34
- package/lib/tool.js +0 -320
- package/lib/turn-snapshot.d.ts +0 -72
- package/lib/turn-snapshot.js +0 -238
- package/lib/types.d.ts +0 -208
- package/lib/types.js +0 -127
- package/lib/usage.d.ts +0 -36
- package/lib/usage.js +0 -98
- package/lib/validate.d.ts +0 -28
- package/lib/validate.js +0 -181
- package/lib/wrapup-command.d.ts +0 -10
- package/lib/wrapup-command.js +0 -243
- package/lib/wrapup.d.ts +0 -260
- package/lib/wrapup.js +0 -539
package/lib/consolidate.js
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { ARCHIVED_AT_KEY, CONFLICT_HINT_KEY, MERGED_FROM_KEY, isArchived } from "./types.js";
|
|
2
|
-
import { getUsageCount } from "./usage.js";
|
|
3
|
-
/** Zero-use entries at least this old are stale candidates (30d, matching the injection recency half-life scale). */
|
|
4
|
-
export const STALE_MIN_AGE_MS = 30 * 24 * 60 * 60 * 1000;
|
|
5
|
-
const KINDS = ["prompt", "memory", "skill", "subagent"];
|
|
6
|
-
/**
|
|
7
|
-
* Parse one conflictHint metadata value. Returns undefined for anything that
|
|
8
|
-
* is not exactly `<kind>:<id>:<score>` with a known kind and a score in
|
|
9
|
-
* [0, 1] — foreign or legacy junk must never crash the scan.
|
|
10
|
-
*/
|
|
11
|
-
export function parseConflictHint(value) {
|
|
12
|
-
if (typeof value !== "string") {
|
|
13
|
-
return undefined;
|
|
14
|
-
}
|
|
15
|
-
const parts = value.split(":");
|
|
16
|
-
if (parts.length !== 3) {
|
|
17
|
-
return undefined;
|
|
18
|
-
}
|
|
19
|
-
const [kind, id, rawScore] = parts;
|
|
20
|
-
if (!kind || !id || !rawScore || !KINDS.includes(kind)) {
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
23
|
-
const score = Number(rawScore);
|
|
24
|
-
if (!Number.isFinite(score) || score < 0 || score > 1) {
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
return { kind: kind, id, score };
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Entries stamped by the write-time conflict guard whose target still exists
|
|
31
|
-
* and is still active. The hinted (newer) entry is the archive candidate —
|
|
32
|
-
* the pointed-to original stays as the live copy.
|
|
33
|
-
*/
|
|
34
|
-
export function findConflictPairs(state) {
|
|
35
|
-
const candidates = [];
|
|
36
|
-
for (const kind of KINDS) {
|
|
37
|
-
for (const entry of Object.values(state.entries[kind])) {
|
|
38
|
-
if (isArchived(entry))
|
|
39
|
-
continue;
|
|
40
|
-
const hint = parseConflictHint(entry.metadata[CONFLICT_HINT_KEY]);
|
|
41
|
-
if (!hint || hint.kind !== kind)
|
|
42
|
-
continue;
|
|
43
|
-
const target = state.entries[hint.kind]?.[hint.id];
|
|
44
|
-
if (!target || isArchived(target))
|
|
45
|
-
continue;
|
|
46
|
-
candidates.push({
|
|
47
|
-
kind,
|
|
48
|
-
id: entry.id,
|
|
49
|
-
title: entry.title,
|
|
50
|
-
reason: `near-duplicate of ${hint.id} 「${target.title}」 (${Math.round(hint.score * 100)}%) — keep the original`,
|
|
51
|
-
mergeInto: { kind: hint.kind, id: hint.id, title: target.title },
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return candidates;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Active global entries never injected in any session and untouched for at
|
|
59
|
-
* least `minAgeMs`: prime staleness candidates. Operates on whatever state
|
|
60
|
-
* it is handed (callers pass the global store).
|
|
61
|
-
*/
|
|
62
|
-
export function findStaleEntries(state, store, now, minAgeMs = STALE_MIN_AGE_MS) {
|
|
63
|
-
const candidates = [];
|
|
64
|
-
for (const kind of KINDS) {
|
|
65
|
-
for (const entry of Object.values(state.entries[kind])) {
|
|
66
|
-
if (isArchived(entry))
|
|
67
|
-
continue;
|
|
68
|
-
if (getUsageCount(store, kind, entry.id) !== 0)
|
|
69
|
-
continue;
|
|
70
|
-
const updatedAt = Date.parse(entry.updated_at);
|
|
71
|
-
if (Number.isNaN(updatedAt) || now - updatedAt < minAgeMs)
|
|
72
|
-
continue;
|
|
73
|
-
candidates.push({
|
|
74
|
-
kind,
|
|
75
|
-
id: entry.id,
|
|
76
|
-
title: entry.title,
|
|
77
|
-
reason: `0 injections since ${entry.updated_at.slice(0, 10)} (stale)`,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return candidates;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Append a source entry's content to a survivor with an attributed divider,
|
|
85
|
-
* so the survivor's reader can see which part came from which entry.
|
|
86
|
-
*/
|
|
87
|
-
export function mergeContent(target, source, sourceRef, dateIso) {
|
|
88
|
-
const body = source.trim();
|
|
89
|
-
if (body.length === 0) {
|
|
90
|
-
return target;
|
|
91
|
-
}
|
|
92
|
-
return `${target.trimEnd()}\n\n---\n[Merged from ${sourceRef} on ${dateIso.slice(0, 10)} — near-duplicate consolidated]\n${body}`;
|
|
93
|
-
}
|
|
94
|
-
/** Existing `<kind>:<id>` strings of a target's {@link MERGED_FROM_KEY} trail. */
|
|
95
|
-
function existingMergedFrom(metadata) {
|
|
96
|
-
const value = metadata[MERGED_FROM_KEY];
|
|
97
|
-
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Merge both scans (conflict reason wins on overlap), deduped by kind:id,
|
|
101
|
-
* and build the batch archive edits. Each edit preserves the entry's full
|
|
102
|
-
* content and existing metadata — only ARCHIVED_AT_KEY is added — so
|
|
103
|
-
* `/evolve unarchive` restores everything intact.
|
|
104
|
-
*
|
|
105
|
-
* With `opts.mergeDuplicates`, conflict-pair candidates additionally merge
|
|
106
|
-
* their content INTO the pointed-to survivor (an attributed `mergeContent`
|
|
107
|
-
* section + a `mergedFrom` provenance stamp) before archiving — the #11
|
|
108
|
-
* candidate-c tier the 2026-08-28 ecosystem review promoted. Per-target
|
|
109
|
-
* accumulation composes multiple hints into one survivor (update edits
|
|
110
|
-
* replace content/metadata wholesale, so parallel merge edits would clobber
|
|
111
|
-
* each other).
|
|
112
|
-
*
|
|
113
|
-
* @param now Epoch ms used for the archivedAt stamp (injected for tests).
|
|
114
|
-
*/
|
|
115
|
-
export function planConsolidation(state, store, now = Date.now(), opts) {
|
|
116
|
-
const byKey = new Map();
|
|
117
|
-
for (const candidate of [...findConflictPairs(state), ...findStaleEntries(state, store, now, opts?.minAgeMs)]) {
|
|
118
|
-
const key = `${candidate.kind}:${candidate.id}`;
|
|
119
|
-
if (!byKey.has(key)) {
|
|
120
|
-
byKey.set(key, candidate);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
const candidates = [...byKey.values()];
|
|
124
|
-
const dateIso = new Date(now).toISOString();
|
|
125
|
-
// A merge survivor must not itself be an archive candidate in the same
|
|
126
|
-
// batch: its archive edit is built from the ORIGINAL state snapshot, so it
|
|
127
|
-
// would overwrite the merge edit's content/mergedFrom wholesale and then
|
|
128
|
-
// archive the survivor (review audit 2026-08-28 S2). Survivors stay live;
|
|
129
|
-
// their merge lands, the source archives.
|
|
130
|
-
const mergeTargets = new Set(candidates.filter((candidate) => candidate.mergeInto).map((candidate) => `${candidate.mergeInto.kind}:${candidate.mergeInto.id}`));
|
|
131
|
-
const archiveCandidates = candidates.filter((candidate) => !mergeTargets.has(`${candidate.kind}:${candidate.id}`));
|
|
132
|
-
const edits = archiveCandidates.map((candidate) => {
|
|
133
|
-
const entry = state.entries[candidate.kind][candidate.id];
|
|
134
|
-
const metadata = { ...entry?.metadata, [ARCHIVED_AT_KEY]: dateIso };
|
|
135
|
-
return {
|
|
136
|
-
action: "update",
|
|
137
|
-
kind: candidate.kind,
|
|
138
|
-
id: candidate.id,
|
|
139
|
-
title: candidate.title,
|
|
140
|
-
content: entry?.content ?? "",
|
|
141
|
-
metadata,
|
|
142
|
-
};
|
|
143
|
-
});
|
|
144
|
-
if (opts?.mergeDuplicates) {
|
|
145
|
-
const merges = new Map();
|
|
146
|
-
for (const candidate of candidates) {
|
|
147
|
-
if (!candidate.mergeInto)
|
|
148
|
-
continue;
|
|
149
|
-
const source = state.entries[candidate.kind][candidate.id];
|
|
150
|
-
const target = state.entries[candidate.mergeInto.kind]?.[candidate.mergeInto.id];
|
|
151
|
-
if (!source || !target)
|
|
152
|
-
continue;
|
|
153
|
-
const key = `${candidate.mergeInto.kind}:${candidate.mergeInto.id}`;
|
|
154
|
-
const acc = merges.get(key) ??
|
|
155
|
-
{
|
|
156
|
-
kind: candidate.mergeInto.kind,
|
|
157
|
-
id: candidate.mergeInto.id,
|
|
158
|
-
title: target.title,
|
|
159
|
-
content: target.content,
|
|
160
|
-
mergedFrom: existingMergedFrom(target.metadata),
|
|
161
|
-
metadata: target.metadata,
|
|
162
|
-
};
|
|
163
|
-
acc.content = mergeContent(acc.content, source.content ?? "", `${candidate.kind}:${candidate.id}`, dateIso);
|
|
164
|
-
acc.mergedFrom.push(`${candidate.kind}:${candidate.id}`);
|
|
165
|
-
merges.set(key, acc);
|
|
166
|
-
}
|
|
167
|
-
for (const acc of merges.values()) {
|
|
168
|
-
edits.unshift({
|
|
169
|
-
action: "update",
|
|
170
|
-
kind: acc.kind,
|
|
171
|
-
id: acc.id,
|
|
172
|
-
title: acc.title,
|
|
173
|
-
content: acc.content,
|
|
174
|
-
metadata: { ...acc.metadata, [MERGED_FROM_KEY]: acc.mergedFrom },
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
return { candidates, edits };
|
|
179
|
-
}
|
|
180
|
-
//# sourceMappingURL=consolidate.js.map
|
package/lib/copy.d.ts
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Backend user-visible copy for the four evolution confirmation dialogs,
|
|
3
|
-
* in both shipped languages. Labels stay literal per language (the parsers
|
|
4
|
-
* match them); guidance lives in `description`.
|
|
5
|
-
*
|
|
6
|
-
* Language is never hardcoded at a call site: every builder takes an
|
|
7
|
-
* explicit `lang`, and dialog entry points resolve it per call
|
|
8
|
-
* (explicit config upstream, else the durable DSH client preference,
|
|
9
|
-
* else `en`) when the caller does not supply one.
|
|
10
|
-
*/
|
|
11
|
-
import { type RecordLanguage } from "./record-language.js";
|
|
12
|
-
export interface ConfirmOption {
|
|
13
|
-
label: string;
|
|
14
|
-
description: string;
|
|
15
|
-
}
|
|
16
|
-
export interface ConfirmCopy {
|
|
17
|
-
question: string;
|
|
18
|
-
options: ConfirmOption[];
|
|
19
|
-
}
|
|
20
|
-
/** Maximum edit-summary chars carried into a dialog; longer text truncates. */
|
|
21
|
-
export declare const COPY_WHAT_MAX_CHARS = 300;
|
|
22
|
-
/**
|
|
23
|
-
* Persistent-scope write approval (`approve-global-evolve`).
|
|
24
|
-
*
|
|
25
|
-
* @param scope Target persistent scope.
|
|
26
|
-
* @param what Edit summary shown in the dialog body.
|
|
27
|
-
* @param lang Dialog language.
|
|
28
|
-
*/
|
|
29
|
-
export declare function approvalCopy(scope: "project" | "global", what: string, lang: RecordLanguage): ConfirmCopy;
|
|
30
|
-
export interface FateConsultSections {
|
|
31
|
-
promotable: string[];
|
|
32
|
-
splits: string[];
|
|
33
|
-
reviewArchives: string[];
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Local-fate homing consult (`evolve-fate-consult`).
|
|
37
|
-
*
|
|
38
|
-
* @param sections Pre-rendered per-item lines per group.
|
|
39
|
-
* @param lang Dialog language.
|
|
40
|
-
*/
|
|
41
|
-
export declare function fateConsultCopy(sections: FateConsultSections, lang: RecordLanguage): ConfirmCopy;
|
|
42
|
-
/**
|
|
43
|
-
* Single-entry wrap-up archive confirm (`evolve-wrapup-archive-review`).
|
|
44
|
-
*
|
|
45
|
-
* @param title Entry title shown in the headline.
|
|
46
|
-
* @param lang Dialog language.
|
|
47
|
-
*/
|
|
48
|
-
export declare function wrapupArchiveCopy(title: string, lang: RecordLanguage): ConfirmCopy;
|
|
49
|
-
/**
|
|
50
|
-
* Skill solidification consult (`evolve-skill-consult`).
|
|
51
|
-
*
|
|
52
|
-
* @param description Pre-rendered per-edit lines.
|
|
53
|
-
* @param lang Dialog language.
|
|
54
|
-
*/
|
|
55
|
-
export declare function skillConsultCopy(description: string, lang: RecordLanguage): ConfirmCopy;
|
|
56
|
-
/**
|
|
57
|
-
* One skill-edit line inside the solidification consult.
|
|
58
|
-
*
|
|
59
|
-
* @param action Edit action (`create` etc.).
|
|
60
|
-
* @param title Entry title or id fallback.
|
|
61
|
-
* @param skillKind `guidance` skills are SKILL.md documents.
|
|
62
|
-
* @param lang Dialog language.
|
|
63
|
-
*/
|
|
64
|
-
export declare function skillEditLine(action: string, title: string, skillKind: string | undefined, lang: RecordLanguage): string;
|
|
65
|
-
/**
|
|
66
|
-
* Resolve the dialog language for a call site that holds no explicit
|
|
67
|
-
* choice: durable client preference first, `en` otherwise. (Dialogs carry
|
|
68
|
-
* no trajectory text, so there is no detection tier here.)
|
|
69
|
-
*
|
|
70
|
-
* @param ctx Host context for the durable-preference read.
|
|
71
|
-
* @returns The dialog language.
|
|
72
|
-
*/
|
|
73
|
-
export declare function resolveDialogLanguage(ctx: unknown): RecordLanguage;
|
|
74
|
-
//# sourceMappingURL=copy.d.ts.map
|
package/lib/copy.js
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Backend user-visible copy for the four evolution confirmation dialogs,
|
|
3
|
-
* in both shipped languages. Labels stay literal per language (the parsers
|
|
4
|
-
* match them); guidance lives in `description`.
|
|
5
|
-
*
|
|
6
|
-
* Language is never hardcoded at a call site: every builder takes an
|
|
7
|
-
* explicit `lang`, and dialog entry points resolve it per call
|
|
8
|
-
* (explicit config upstream, else the durable DSH client preference,
|
|
9
|
-
* else `en`) when the caller does not supply one.
|
|
10
|
-
*/
|
|
11
|
-
import { resolveRecordLanguage } from "./record-language.js";
|
|
12
|
-
/** Maximum edit-summary chars carried into a dialog; longer text truncates. */
|
|
13
|
-
export const COPY_WHAT_MAX_CHARS = 300;
|
|
14
|
-
function compactWhat(what) {
|
|
15
|
-
return what.length > COPY_WHAT_MAX_CHARS ? `${what.slice(0, COPY_WHAT_MAX_CHARS)}…` : what;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Persistent-scope write approval (`approve-global-evolve`).
|
|
19
|
-
*
|
|
20
|
-
* @param scope Target persistent scope.
|
|
21
|
-
* @param what Edit summary shown in the dialog body.
|
|
22
|
-
* @param lang Dialog language.
|
|
23
|
-
*/
|
|
24
|
-
export function approvalCopy(scope, what, lang) {
|
|
25
|
-
const body = compactWhat(what);
|
|
26
|
-
if (lang === "zh") {
|
|
27
|
-
const storeLabel = scope === "project" ? "本项目跨会话 store" : "跨会话全局 store";
|
|
28
|
-
return {
|
|
29
|
-
question: `写入${storeLabel}?\n${body}\n${scope === "project" ? "影响:仅本项目会话可见,可回滚。" : "影响:所有会话可见,可回滚。"}`,
|
|
30
|
-
options: [
|
|
31
|
-
{ label: "批准", description: scope === "project" ? "写入,仅本项目会话可见" : "写入,所有会话可见" },
|
|
32
|
-
{ label: "拒绝", description: "不写入,本次跳过" },
|
|
33
|
-
],
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
const storeLabel = scope === "project" ? "project cross-session store" : "global cross-session store";
|
|
37
|
-
return {
|
|
38
|
-
question: `Write to the ${storeLabel}?\n${body}\n${scope === "project" ? "Impact: visible to this project's sessions only, reversible." : "Impact: visible to all sessions, reversible."}`,
|
|
39
|
-
options: [
|
|
40
|
-
{ label: "Approve", description: scope === "project" ? "Write, visible to this project only" : "Write, visible to all sessions" },
|
|
41
|
-
{ label: "Decline", description: "Skip this write" },
|
|
42
|
-
],
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Local-fate homing consult (`evolve-fate-consult`).
|
|
47
|
-
*
|
|
48
|
-
* @param sections Pre-rendered per-item lines per group.
|
|
49
|
-
* @param lang Dialog language.
|
|
50
|
-
*/
|
|
51
|
-
export function fateConsultCopy(sections, lang) {
|
|
52
|
-
if (lang === "zh") {
|
|
53
|
-
const lines = ["自进化门禁:本会话 local 条目需要归宿处理"];
|
|
54
|
-
if (sections.promotable.length > 0 || sections.splits.length > 0) {
|
|
55
|
-
lines.push("【提升到全局(写入全局 store)】", ...sections.promotable, ...sections.splits);
|
|
56
|
-
}
|
|
57
|
-
if (sections.reviewArchives.length > 0) {
|
|
58
|
-
lines.push("【归档(本地隐藏,可恢复)】", ...sections.reviewArchives);
|
|
59
|
-
}
|
|
60
|
-
lines.push("提升写入后所有会话可见,归档隐藏但可恢复。是否执行?");
|
|
61
|
-
return {
|
|
62
|
-
question: lines.join("\n"),
|
|
63
|
-
options: [
|
|
64
|
-
{ label: "执行", description: "提升写全局,归档隐藏本地(均可恢复)" },
|
|
65
|
-
{ label: "不执行", description: "全部保留,10 回合内不再打扰" },
|
|
66
|
-
],
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
const lines = ["Evolution gate: this session's local entries need homing"];
|
|
70
|
-
if (sections.promotable.length > 0 || sections.splits.length > 0) {
|
|
71
|
-
lines.push("[Promote to global (write to the global store)]", ...sections.promotable, ...sections.splits);
|
|
72
|
-
}
|
|
73
|
-
if (sections.reviewArchives.length > 0) {
|
|
74
|
-
lines.push("[Archive (hidden locally, restorable)]", ...sections.reviewArchives);
|
|
75
|
-
}
|
|
76
|
-
lines.push("Promotions become visible to all sessions; archives hide but stay restorable. Proceed?");
|
|
77
|
-
return {
|
|
78
|
-
question: lines.join("\n"),
|
|
79
|
-
options: [
|
|
80
|
-
{ label: "Proceed", description: "Promote to global, archive locally (all reversible)" },
|
|
81
|
-
{ label: "Skip", description: "Keep everything, cooldown 10 turns" },
|
|
82
|
-
],
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
/**
|
|
86
|
-
* Single-entry wrap-up archive confirm (`evolve-wrapup-archive-review`).
|
|
87
|
-
*
|
|
88
|
-
* @param title Entry title shown in the headline.
|
|
89
|
-
* @param lang Dialog language.
|
|
90
|
-
*/
|
|
91
|
-
export function wrapupArchiveCopy(title, lang) {
|
|
92
|
-
if (lang === "zh") {
|
|
93
|
-
return {
|
|
94
|
-
question: `wrapup 确认归档:条目「${title}」\n未被全局覆盖且源自真实对话。归档后不再注入,数据保留、可恢复。`,
|
|
95
|
-
options: [
|
|
96
|
-
{ label: "归档", description: "隐藏但可恢复" },
|
|
97
|
-
{ label: "保留", description: "继续注入" },
|
|
98
|
-
],
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
return {
|
|
102
|
-
question: `Wrap-up archive confirm: entry "${title}"\nNot covered globally and distilled from real conversation. Archiving stops injection; data stays restorable.`,
|
|
103
|
-
options: [
|
|
104
|
-
{ label: "Archive", description: "Hide but restorable" },
|
|
105
|
-
{ label: "Keep", description: "Keep injecting" },
|
|
106
|
-
],
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Skill solidification consult (`evolve-skill-consult`).
|
|
111
|
-
*
|
|
112
|
-
* @param description Pre-rendered per-edit lines.
|
|
113
|
-
* @param lang Dialog language.
|
|
114
|
-
*/
|
|
115
|
-
export function skillConsultCopy(description, lang) {
|
|
116
|
-
if (lang === "zh") {
|
|
117
|
-
return {
|
|
118
|
-
question: `发现可复用的流程,建议固化为技能\n${description}\n\n固化后以后同类任务自动复用,可回滚。是否固化?`,
|
|
119
|
-
options: [
|
|
120
|
-
{ label: "固化", description: "生成技能,以后复用" },
|
|
121
|
-
{ label: "不固化", description: "本次跳过,10 回合内不再打扰" },
|
|
122
|
-
],
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
return {
|
|
126
|
-
question: `Reusable workflow found, suggest solidifying as a skill\n${description}\n\nSolidified skills are reused by similar tasks later, reversible. Solidify?`,
|
|
127
|
-
options: [
|
|
128
|
-
{ label: "Solidify", description: "Create the skill for reuse" },
|
|
129
|
-
{ label: "Skip", description: "Skip this time, cooldown 10 turns" },
|
|
130
|
-
],
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* One skill-edit line inside the solidification consult.
|
|
135
|
-
*
|
|
136
|
-
* @param action Edit action (`create` etc.).
|
|
137
|
-
* @param title Entry title or id fallback.
|
|
138
|
-
* @param skillKind `guidance` skills are SKILL.md documents.
|
|
139
|
-
* @param lang Dialog language.
|
|
140
|
-
*/
|
|
141
|
-
export function skillEditLine(action, title, skillKind, lang) {
|
|
142
|
-
if (lang === "zh") {
|
|
143
|
-
const form = skillKind === "guidance" ? "guidance 技能(SKILL.md 文档)" : "可执行技能";
|
|
144
|
-
return `- ${action}「${title}」(${form})`;
|
|
145
|
-
}
|
|
146
|
-
const form = skillKind === "guidance" ? "guidance skill (SKILL.md document)" : "executable skill";
|
|
147
|
-
return `- ${action} "${title}" (${form})`;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Resolve the dialog language for a call site that holds no explicit
|
|
151
|
-
* choice: durable client preference first, `en` otherwise. (Dialogs carry
|
|
152
|
-
* no trajectory text, so there is no detection tier here.)
|
|
153
|
-
*
|
|
154
|
-
* @param ctx Host context for the durable-preference read.
|
|
155
|
-
* @returns The dialog language.
|
|
156
|
-
*/
|
|
157
|
-
export function resolveDialogLanguage(ctx) {
|
|
158
|
-
return resolveRecordLanguage({ ctx });
|
|
159
|
-
}
|
|
160
|
-
//# sourceMappingURL=copy.js.map
|
package/lib/declines.d.ts
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/** Cap on remembered declines; oldest-first pruning keeps the file small. */
|
|
2
|
-
export declare const MAX_DECLINED_MEMORY_LEDGER = 50;
|
|
3
|
-
/** Cap on stored content tokens per entry; enough for coverage, never prose. */
|
|
4
|
-
export declare const MAX_DECLINED_ENTRY_TOKENS = 128;
|
|
5
|
-
/** Minimum coverage of an entry's tokens by the checkpoint to pre-suppress. */
|
|
6
|
-
export declare const DECLINED_PRECHECK_COVERAGE = 0.85;
|
|
7
|
-
/** Minimum overlapping tokens; tiny entries must never match vacuously. */
|
|
8
|
-
export declare const DECLINED_PRECHECK_MIN_TOKENS = 5;
|
|
9
|
-
/** One declined project/global batch, keyed by its content fingerprint. */
|
|
10
|
-
export interface DeclinedMemoryBatch {
|
|
11
|
-
/** Persistent scope that was declined. Local never asks, so never lands here. */
|
|
12
|
-
scope: "project" | "global";
|
|
13
|
-
/** sha256-16 over the normalized batch (same cut as evaluate.ts/project.ts). */
|
|
14
|
-
fingerprint: string;
|
|
15
|
-
/** First edit title (audit readability only, never matched on). */
|
|
16
|
-
title: string;
|
|
17
|
-
/** Deduplicated content tokens for checkpoint containment checks. */
|
|
18
|
-
tokens: string[];
|
|
19
|
-
/** ISO timestamp of the human rejection. */
|
|
20
|
-
declinedAt: string;
|
|
21
|
-
}
|
|
22
|
-
/** Minimal edit shape needed for fingerprinting (avoids importing the agent). */
|
|
23
|
-
export interface FingerprintableEdit {
|
|
24
|
-
action: string;
|
|
25
|
-
id?: string;
|
|
26
|
-
title?: string;
|
|
27
|
-
content?: string;
|
|
28
|
-
}
|
|
29
|
-
/** Full path of the decline ledger file. */
|
|
30
|
-
export declare function declinedMemoryPath(baseDir: string): string;
|
|
31
|
-
/**
|
|
32
|
-
* Fingerprint one scope batch. Normalization is whitespace-only on purpose:
|
|
33
|
-
* case folding could conflate distinct facts (e.g. env var names), and a
|
|
34
|
-
* missed match only costs one more popup (fail-closed).
|
|
35
|
-
*
|
|
36
|
-
* @param scope - persistent scope the batch targets.
|
|
37
|
-
* @param edits - the scope batch in proposal order (order is significant).
|
|
38
|
-
* @returns 16-char hex fingerprint.
|
|
39
|
-
*/
|
|
40
|
-
export declare function fingerprintMemoryBatch(scope: "project" | "global", edits: readonly FingerprintableEdit[]): string;
|
|
41
|
-
/**
|
|
42
|
-
* Load the decline ledger. Missing or malformed files read as empty so a
|
|
43
|
-
* broken ledger degrades to the status quo (ask anyway), never to a crash
|
|
44
|
-
* on the approval path.
|
|
45
|
-
*
|
|
46
|
-
* @param baseDir - engine base directory.
|
|
47
|
-
* @returns validated ledger entries (possibly empty).
|
|
48
|
-
*/
|
|
49
|
-
export declare function loadDeclinedMemory(baseDir: string): DeclinedMemoryBatch[];
|
|
50
|
-
/**
|
|
51
|
-
* Whether this exact batch was declined before.
|
|
52
|
-
*
|
|
53
|
-
* @param entries - loaded ledger.
|
|
54
|
-
* @param scope - persistent scope of the pending batch.
|
|
55
|
-
* @param fingerprint - fingerprint of the pending batch.
|
|
56
|
-
*/
|
|
57
|
-
export declare function isDeclinedRepeat(entries: readonly DeclinedMemoryBatch[], scope: "project" | "global", fingerprint: string): boolean;
|
|
58
|
-
/**
|
|
59
|
-
* Record one human decline, pruning oldest-first past the cap. The batch
|
|
60
|
-
* edits supply fingerprint material, match tokens, and the secret screen:
|
|
61
|
-
* a secret-shaped decline is still declined, but never lands in the ledger
|
|
62
|
-
* (it was never engine-screened, so it must not be persisted anywhere).
|
|
63
|
-
*
|
|
64
|
-
* @param baseDir - engine base directory.
|
|
65
|
-
* @param scope - persistent scope that was declined.
|
|
66
|
-
* @param edits - the declined scope batch in proposal order.
|
|
67
|
-
* @param title - first edit title, kept for audit readability.
|
|
68
|
-
* @returns the ledger file path, or undefined when skipped by the secret screen.
|
|
69
|
-
* @throws On filesystem write failure; callers on the approval path should
|
|
70
|
-
* contain it (suppression is an optimization, never load-bearing).
|
|
71
|
-
*/
|
|
72
|
-
export declare function recordDeclinedMemory(baseDir: string, scope: "project" | "global", edits: readonly FingerprintableEdit[], title: string): string | undefined;
|
|
73
|
-
/**
|
|
74
|
-
* Deduplicated content tokens of one batch, capped. Shared CJK-aware
|
|
75
|
-
* tokenizer with the manifest ranking, so both sides of the containment
|
|
76
|
-
* check speak the same token language.
|
|
77
|
-
*
|
|
78
|
-
* @param edits - batch edits.
|
|
79
|
-
* @returns at most MAX_DECLINED_ENTRY_TOKENS distinct tokens.
|
|
80
|
-
*/
|
|
81
|
-
export declare function declinedContentTokens(edits: readonly FingerprintableEdit[]): string[];
|
|
82
|
-
/** One checkpoint containment hit: which entry matched and how strongly. */
|
|
83
|
-
export interface DeclinedCheckpointHit {
|
|
84
|
-
/** Ledger entry whose content the checkpoint re-covers. */
|
|
85
|
-
entry: DeclinedMemoryBatch;
|
|
86
|
-
/** Fraction of the entry's tokens present in the checkpoint. */
|
|
87
|
-
coverage: number;
|
|
88
|
-
/** Overlapping token count. */
|
|
89
|
-
hits: number;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Match a pending checkpoint against declined content (entry ⊆ checkpoint).
|
|
93
|
-
* Conservative by design: high coverage plus an absolute token floor, so
|
|
94
|
-
* tiny or vague declines can never suppress anything.
|
|
95
|
-
*
|
|
96
|
-
* @param entries - loaded ledger.
|
|
97
|
-
* @param checkpointTokens - tokens of the pending checkpoint trajectory.
|
|
98
|
-
* @returns the strongest hit, or undefined when nothing clears the floor.
|
|
99
|
-
*/
|
|
100
|
-
export declare function matchDeclinedCheckpoint(entries: readonly DeclinedMemoryBatch[], checkpointTokens: readonly string[]): DeclinedCheckpointHit | undefined;
|
|
101
|
-
//# sourceMappingURL=declines.d.ts.map
|