@evo-dev/core 0.0.1-alpha.1 → 0.0.1-alpha.10
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/assets/skills/coding/knowledge-distillation/SKILL.md +117 -114
- package/assets/skills/coding/knowledge-distillation/references/knowledge-distillation-methods.md +11 -7
- package/assets/team/agents/code-reviewer.md +48 -0
- package/assets/team/agents/docs-maintainer.md +51 -0
- package/assets/team/agents/implementation-engineer.md +51 -0
- package/assets/team/agents/product-scope-analyst.md +58 -0
- package/assets/team/agents/release-engineer.md +55 -0
- package/assets/team/agents/security-boundary-reviewer.md +50 -0
- package/assets/team/agents/solution-architect.md +51 -0
- package/assets/team/agents/verification-engineer.md +51 -0
- package/assets/team/team.md +102 -0
- package/dist/config/index.js +925 -97
- package/dist/index.js +13107 -5618
- package/package.json +5 -1
- package/src/agents/index.ts +56 -264
- package/src/code-agent-traces/index.ts +520 -0
- package/src/config/index.ts +5 -0
- package/src/config/paths.ts +1 -1
- package/src/config/settings.ts +149 -0
- package/src/config/store.ts +2 -0
- package/src/daemon/index.ts +99 -50
- package/src/evolution/candidates/index.ts +564 -0
- package/src/evolution/control/index.ts +20 -0
- package/src/evolution/evidence/analysis.ts +533 -0
- package/src/evolution/evidence/index.ts +3 -0
- package/src/evolution/evidence/session-memory/analysis.ts +281 -0
- package/src/evolution/evidence/session-memory/constants.ts +9 -0
- package/src/evolution/evidence/session-memory/index.ts +7 -0
- package/src/evolution/evidence/session-memory/paths.ts +29 -0
- package/src/evolution/evidence/session-memory/policy.ts +39 -0
- package/src/evolution/evidence/session-memory/segment.ts +202 -0
- package/src/evolution/evidence/session-memory/sensitivity.ts +335 -0
- package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
- package/src/evolution/evidence/session-memory/storage.ts +379 -0
- package/src/evolution/evidence/session-memory/types.ts +221 -0
- package/src/evolution/evidence/session-memory/updater.ts +191 -0
- package/src/evolution/formatters.ts +169 -0
- package/src/evolution/index.ts +16 -2356
- package/src/evolution/knowledge/index.ts +5427 -0
- package/src/evolution/paths.ts +44 -0
- package/src/evolution/processor/distillation.ts +518 -0
- package/src/evolution/processor/index.ts +3 -0
- package/src/evolution/processor/process.ts +528 -0
- package/src/{learning → evolution/review}/index.ts +10 -14
- package/src/evolution/schema.ts +568 -0
- package/src/evolution/shared.ts +758 -0
- package/src/evolution/triggers/classification.ts +102 -0
- package/src/evolution/triggers/index.ts +295 -0
- package/src/hooks/index.ts +438 -179
- package/src/index.ts +12 -3
- package/src/projects/index.ts +453 -0
- package/src/runtime-logs/index.ts +490 -24
- package/src/team/index.ts +1429 -185
- package/src/team/mcp.ts +9 -5
- package/src/team/prompts.ts +141 -0
- package/src/utils/errors.ts +13 -0
- package/src/utils/fs.ts +40 -0
- package/src/utils/hash.ts +9 -0
- package/src/utils/ids.ts +12 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/parsing.ts +11 -0
- package/src/utils/text.ts +18 -0
- package/src/utils/time.ts +5 -0
- package/src/workflow/index.ts +3 -21
- package/src/project/index.ts +0 -507
- package/src/task/index.ts +0 -840
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { resolveEvoDevPaths } from "../config/paths.ts";
|
|
3
|
+
import type { EvolutionResolvedPaths } from "./schema.ts";
|
|
4
|
+
import { assertPathDescendant, sanitizeStorageId } from "./shared.ts";
|
|
5
|
+
|
|
6
|
+
export function resolveEvolutionPaths(input: {
|
|
7
|
+
homeDir: string;
|
|
8
|
+
projectKey: string;
|
|
9
|
+
runId: string;
|
|
10
|
+
}): EvolutionResolvedPaths {
|
|
11
|
+
const paths = resolveEvoDevPaths(input.homeDir);
|
|
12
|
+
const projectKey = sanitizeStorageId("projectKey", input.projectKey);
|
|
13
|
+
const runId = sanitizeStorageId("runId", input.runId);
|
|
14
|
+
const evolutionStateDir = join(paths.stateDir, "evolution");
|
|
15
|
+
const projectStateDir = join(evolutionStateDir, projectKey);
|
|
16
|
+
const runStateDir = join(evolutionStateDir, projectKey, runId);
|
|
17
|
+
const repoProposalsDir = join(runStateDir, "proposals");
|
|
18
|
+
const reviewCandidatesDir = join(runStateDir, "review-candidates");
|
|
19
|
+
const knowledgeProjectDir = join(paths.knowledgeDir, projectKey);
|
|
20
|
+
const evosCasesProjectDir = join(paths.evosCasesDir, projectKey);
|
|
21
|
+
assertPathDescendant(evolutionStateDir, runStateDir, "runStateDir");
|
|
22
|
+
assertPathDescendant(evolutionStateDir, projectStateDir, "projectStateDir");
|
|
23
|
+
assertPathDescendant(evolutionStateDir, reviewCandidatesDir, "reviewCandidatesDir");
|
|
24
|
+
assertPathDescendant(paths.knowledgeDir, knowledgeProjectDir, "knowledgeProjectDir");
|
|
25
|
+
assertPathDescendant(paths.evosCasesDir, evosCasesProjectDir, "evosCasesProjectDir");
|
|
26
|
+
return {
|
|
27
|
+
projectKey,
|
|
28
|
+
runId,
|
|
29
|
+
evolutionStateDir,
|
|
30
|
+
runStateDir,
|
|
31
|
+
evidenceWindowPath: join(runStateDir, "evidence-window.json"),
|
|
32
|
+
batchPath: join(runStateDir, "distillation-batch.json"),
|
|
33
|
+
triggersDir: join(runStateDir, "triggers"),
|
|
34
|
+
reviewCandidatesDir,
|
|
35
|
+
repoProposalsDir,
|
|
36
|
+
repoProposalsIndexPath: join(runStateDir, "proposals.index.json"),
|
|
37
|
+
knowledgeProjectDir,
|
|
38
|
+
knowledgeRecordsDir: join(knowledgeProjectDir, "records"),
|
|
39
|
+
knowledgeIndexPath: join(knowledgeProjectDir, "index.json"),
|
|
40
|
+
knowledgeReviewHistoryPath: join(projectStateDir, "knowledge-review-history.jsonl"),
|
|
41
|
+
evosCasesProjectDir,
|
|
42
|
+
evosIndexPath: paths.evosIndexPath,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
import { readFile, readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { resolveEvoDevPaths } from "../../config/paths.ts";
|
|
4
|
+
import {
|
|
5
|
+
createStableId,
|
|
6
|
+
normalizeTimestamp,
|
|
7
|
+
readJsonFiles,
|
|
8
|
+
writeJsonFile as writeJson,
|
|
9
|
+
} from "../../utils/index.ts";
|
|
10
|
+
import {
|
|
11
|
+
type OkfKnowledgePlan,
|
|
12
|
+
activateOkfKnowledgePlan,
|
|
13
|
+
createOkfKnowledgePlanFromDistillationBatch,
|
|
14
|
+
} from "../knowledge/index.ts";
|
|
15
|
+
import { resolveEvolutionPaths } from "../paths.ts";
|
|
16
|
+
import type {
|
|
17
|
+
EvolutionActivationResult,
|
|
18
|
+
EvolutionConfidence,
|
|
19
|
+
EvolutionDistillationBatch,
|
|
20
|
+
EvolutionEvidenceWindow,
|
|
21
|
+
EvolutionEvosCase,
|
|
22
|
+
EvolutionKnowledgeRecord,
|
|
23
|
+
EvolutionRepoProposal,
|
|
24
|
+
EvolutionWriteResult,
|
|
25
|
+
} from "../schema.ts";
|
|
26
|
+
import {
|
|
27
|
+
collectRoleIds,
|
|
28
|
+
createEvolutionEvosCase,
|
|
29
|
+
createEvolutionKnowledgeRecord,
|
|
30
|
+
createPrivacyFields,
|
|
31
|
+
hasConcreteRepoProposalChanges,
|
|
32
|
+
listDirectoryNames,
|
|
33
|
+
parseEvosCase,
|
|
34
|
+
parseKnowledgeRecord,
|
|
35
|
+
parseRepoProposal,
|
|
36
|
+
sanitizeText,
|
|
37
|
+
validateEvolutionDistillationBatch,
|
|
38
|
+
validateEvolutionEvidenceWindow,
|
|
39
|
+
validateEvolutionEvosCase,
|
|
40
|
+
validateEvolutionRepoProposal,
|
|
41
|
+
} from "../shared.ts";
|
|
42
|
+
import { chooseEvosTriggerKind, createTriggerSummary } from "../triggers/classification.ts";
|
|
43
|
+
|
|
44
|
+
export function createEvolutionDistillationBatch(input: {
|
|
45
|
+
evidenceWindow: EvolutionEvidenceWindow;
|
|
46
|
+
now?: string | Date;
|
|
47
|
+
warnings?: string[];
|
|
48
|
+
}): EvolutionDistillationBatch {
|
|
49
|
+
validateEvolutionEvidenceWindow(input.evidenceWindow);
|
|
50
|
+
const createdAt = normalizeTimestamp(input.now);
|
|
51
|
+
const roleIds = collectRoleIds(input.evidenceWindow);
|
|
52
|
+
const sourceRefs = input.evidenceWindow.sourceRefs.map((sourceRef) => sourceRef.id);
|
|
53
|
+
const failedSignals = input.evidenceWindow.events.filter(
|
|
54
|
+
(event) =>
|
|
55
|
+
event.kind === "error" ||
|
|
56
|
+
event.triggerReason === "stop-failure" ||
|
|
57
|
+
event.triggerReason === "tool-failure" ||
|
|
58
|
+
event.triggerReason === "permission-denied" ||
|
|
59
|
+
/fail|failed|failure|error|issue/i.test(event.summary),
|
|
60
|
+
);
|
|
61
|
+
const verificationSignals = input.evidenceWindow.events
|
|
62
|
+
.filter(
|
|
63
|
+
(event) => event.kind === "verification" || /test|lint|typecheck|build/i.test(event.summary),
|
|
64
|
+
)
|
|
65
|
+
.slice(0, 8)
|
|
66
|
+
.map((event) => event.summary);
|
|
67
|
+
const autoKnowledgeEligible =
|
|
68
|
+
input.evidenceWindow.events.length > 0 &&
|
|
69
|
+
failedSignals.length === 0 &&
|
|
70
|
+
verificationSignals.length > 0 &&
|
|
71
|
+
input.evidenceWindow.triggerPolicy.distillRecommended &&
|
|
72
|
+
input.evidenceWindow.triggerPolicy.evidenceSignals.failures === 0;
|
|
73
|
+
const confidence: EvolutionConfidence = autoKnowledgeEligible
|
|
74
|
+
? "high"
|
|
75
|
+
: failedSignals.length === 0
|
|
76
|
+
? "medium"
|
|
77
|
+
: "low";
|
|
78
|
+
|
|
79
|
+
const knowledgeRecords = !autoKnowledgeEligible
|
|
80
|
+
? []
|
|
81
|
+
: [
|
|
82
|
+
createEvolutionKnowledgeRecord({
|
|
83
|
+
id: createStableId("k", [input.evidenceWindow.id, "run-summary"]),
|
|
84
|
+
kind: "run-summary",
|
|
85
|
+
title: `Project run ${input.evidenceWindow.runId} evidence summary`,
|
|
86
|
+
projectKey: input.evidenceWindow.projectKey,
|
|
87
|
+
summary: createRunSummary(input.evidenceWindow, roleIds, failedSignals.length),
|
|
88
|
+
body: [
|
|
89
|
+
`Run ${input.evidenceWindow.runId} produced ${input.evidenceWindow.events.length} redacted metadata evidence event(s).`,
|
|
90
|
+
`Observed role(s): ${roleIds.length === 0 ? "none" : roleIds.join(", ")}.`,
|
|
91
|
+
"This record is derived from metadata-only evidence; active use depends on OKF plan review state.",
|
|
92
|
+
].join("\n"),
|
|
93
|
+
roleTags: roleIds,
|
|
94
|
+
tags: ["project-run", "auto-stored", "unreviewed"],
|
|
95
|
+
reviewState: "auto-stored/unreviewed",
|
|
96
|
+
authority: "contextual",
|
|
97
|
+
confidence,
|
|
98
|
+
provenance: createProvenance(input.evidenceWindow, createdAt, sourceRefs),
|
|
99
|
+
relations: {
|
|
100
|
+
relatedKnowledgeIds: [],
|
|
101
|
+
evosCaseIds: [createStableId("evo", [input.evidenceWindow.id, "case"])],
|
|
102
|
+
proposalIds: [],
|
|
103
|
+
supersedes: [],
|
|
104
|
+
},
|
|
105
|
+
privacy: createPrivacyFields(),
|
|
106
|
+
runtime: { canLoad: true, hardBlocking: false },
|
|
107
|
+
}),
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const evosCases =
|
|
111
|
+
input.evidenceWindow.events.length === 0
|
|
112
|
+
? []
|
|
113
|
+
: [
|
|
114
|
+
createEvolutionEvosCase({
|
|
115
|
+
id: createStableId("evo", [input.evidenceWindow.id, "case"]),
|
|
116
|
+
projectKey: input.evidenceWindow.projectKey,
|
|
117
|
+
title: `Run ${input.evidenceWindow.runId} evolution case`,
|
|
118
|
+
roleTags: roleIds,
|
|
119
|
+
tags: [
|
|
120
|
+
"project-run",
|
|
121
|
+
"evidence-window",
|
|
122
|
+
`trigger-${input.evidenceWindow.triggerPolicy.strongest}`,
|
|
123
|
+
],
|
|
124
|
+
reviewState: "auto-stored/unreviewed",
|
|
125
|
+
confidence,
|
|
126
|
+
trigger: {
|
|
127
|
+
kind: chooseEvosTriggerKind(input.evidenceWindow),
|
|
128
|
+
summary: createTriggerSummary(input.evidenceWindow),
|
|
129
|
+
},
|
|
130
|
+
intervention: {
|
|
131
|
+
summary: `Collected ${input.evidenceWindow.events.length} metadata event(s) and ${input.evidenceWindow.episodes.length} episode(s) from EvoDev execution logs.`,
|
|
132
|
+
roleIds,
|
|
133
|
+
},
|
|
134
|
+
result: {
|
|
135
|
+
summary:
|
|
136
|
+
failedSignals.length === 0
|
|
137
|
+
? "No failure signal was detected in the redacted evidence summaries."
|
|
138
|
+
: `${failedSignals.length} potential failure or issue signal(s) were detected.`,
|
|
139
|
+
verificationSignals,
|
|
140
|
+
},
|
|
141
|
+
expectedFutureBehavior:
|
|
142
|
+
"Future role agents should inspect accepted knowledge first and treat unreviewed cases as contextual evidence only.",
|
|
143
|
+
provenance: createProvenance(input.evidenceWindow, createdAt, sourceRefs),
|
|
144
|
+
privacy: createPrivacyFields(),
|
|
145
|
+
}),
|
|
146
|
+
];
|
|
147
|
+
|
|
148
|
+
// Failure metadata is evidence, not a repository change proposal. A proposal is only valid
|
|
149
|
+
// after another stage supplies concrete target files and proposed changes.
|
|
150
|
+
const repoProposals: EvolutionRepoProposal[] = [];
|
|
151
|
+
|
|
152
|
+
const batch: EvolutionDistillationBatch = {
|
|
153
|
+
schemaVersion: 1,
|
|
154
|
+
id: createStableId("batch", [input.evidenceWindow.id, createdAt]),
|
|
155
|
+
projectKey: input.evidenceWindow.projectKey,
|
|
156
|
+
runId: input.evidenceWindow.runId,
|
|
157
|
+
createdAt,
|
|
158
|
+
evidenceWindow: input.evidenceWindow,
|
|
159
|
+
knowledgeRecords,
|
|
160
|
+
evosCases,
|
|
161
|
+
repoProposals,
|
|
162
|
+
warnings: (input.warnings ?? []).map(sanitizeText),
|
|
163
|
+
};
|
|
164
|
+
validateEvolutionDistillationBatch(batch);
|
|
165
|
+
return batch;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export async function writeEvolutionDistillationBatch(input: {
|
|
169
|
+
homeDir: string;
|
|
170
|
+
batch: EvolutionDistillationBatch;
|
|
171
|
+
overwrite?: boolean;
|
|
172
|
+
}): Promise<EvolutionWriteResult> {
|
|
173
|
+
validateEvolutionDistillationBatch(input.batch);
|
|
174
|
+
const paths = resolveEvolutionPaths({
|
|
175
|
+
homeDir: input.homeDir,
|
|
176
|
+
projectKey: input.batch.projectKey,
|
|
177
|
+
runId: input.batch.runId,
|
|
178
|
+
});
|
|
179
|
+
const overwrite = input.overwrite === true;
|
|
180
|
+
await writeJson(paths.evidenceWindowPath, input.batch.evidenceWindow, { overwrite });
|
|
181
|
+
await writeJson(paths.batchPath, input.batch, { overwrite });
|
|
182
|
+
|
|
183
|
+
const knowledgePaths: string[] = [];
|
|
184
|
+
for (const record of input.batch.knowledgeRecords) {
|
|
185
|
+
const path = join(paths.knowledgeRecordsDir, `${record.id}.json`);
|
|
186
|
+
await writeJson(path, record, { overwrite });
|
|
187
|
+
knowledgePaths.push(path);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const evosCasePaths: string[] = [];
|
|
191
|
+
for (const evosCase of input.batch.evosCases) {
|
|
192
|
+
const path = join(paths.evosCasesProjectDir, `${evosCase.id}.json`);
|
|
193
|
+
await writeJson(path, evosCase, { overwrite });
|
|
194
|
+
evosCasePaths.push(path);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const repoProposalPaths: string[] = [];
|
|
198
|
+
for (const proposal of input.batch.repoProposals) {
|
|
199
|
+
const path = join(paths.repoProposalsDir, `${proposal.id}.json`);
|
|
200
|
+
await writeJson(path, proposal, { overwrite });
|
|
201
|
+
repoProposalPaths.push(path);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const allProjectKnowledgeRecords = await readJsonFiles(
|
|
205
|
+
paths.knowledgeRecordsDir,
|
|
206
|
+
parseKnowledgeRecord,
|
|
207
|
+
);
|
|
208
|
+
await writeJson(
|
|
209
|
+
paths.knowledgeIndexPath,
|
|
210
|
+
{
|
|
211
|
+
schemaVersion: 1,
|
|
212
|
+
projectKey: input.batch.projectKey,
|
|
213
|
+
updatedAt: input.batch.createdAt,
|
|
214
|
+
records: allProjectKnowledgeRecords.map((record) => ({
|
|
215
|
+
id: record.id,
|
|
216
|
+
kind: record.kind,
|
|
217
|
+
title: record.title,
|
|
218
|
+
reviewState: record.reviewState,
|
|
219
|
+
roleTags: record.roleTags,
|
|
220
|
+
})),
|
|
221
|
+
},
|
|
222
|
+
{ overwrite: true },
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
const evosCasesRootDir = resolveEvoDevPaths(input.homeDir).evosCasesDir;
|
|
226
|
+
const evosProjectKeys = await listDirectoryNames(evosCasesRootDir);
|
|
227
|
+
const evosProjects = await Promise.all(
|
|
228
|
+
evosProjectKeys.map(async (projectKey) => {
|
|
229
|
+
const cases = await readJsonFiles(join(evosCasesRootDir, projectKey), parseEvosCase);
|
|
230
|
+
return {
|
|
231
|
+
projectKey,
|
|
232
|
+
cases: cases.map((evosCase) => ({
|
|
233
|
+
id: evosCase.id,
|
|
234
|
+
title: evosCase.title,
|
|
235
|
+
reviewState: evosCase.reviewState,
|
|
236
|
+
})),
|
|
237
|
+
};
|
|
238
|
+
}),
|
|
239
|
+
);
|
|
240
|
+
await writeJson(
|
|
241
|
+
paths.evosIndexPath,
|
|
242
|
+
{
|
|
243
|
+
schemaVersion: 1,
|
|
244
|
+
updatedAt: input.batch.createdAt,
|
|
245
|
+
projects: evosProjects,
|
|
246
|
+
},
|
|
247
|
+
{ overwrite: true },
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
const allRunProposals = await readJsonFiles(paths.repoProposalsDir, parseRepoProposal);
|
|
251
|
+
await writeJson(
|
|
252
|
+
paths.repoProposalsIndexPath,
|
|
253
|
+
{
|
|
254
|
+
schemaVersion: 1,
|
|
255
|
+
projectKey: input.batch.projectKey,
|
|
256
|
+
runId: input.batch.runId,
|
|
257
|
+
updatedAt: input.batch.createdAt,
|
|
258
|
+
proposals: allRunProposals.map((proposal) => ({
|
|
259
|
+
id: proposal.id,
|
|
260
|
+
kind: proposal.kind,
|
|
261
|
+
title: proposal.title,
|
|
262
|
+
reviewState: proposal.reviewState,
|
|
263
|
+
})),
|
|
264
|
+
},
|
|
265
|
+
{ overwrite: true },
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
evidenceWindowPath: paths.evidenceWindowPath,
|
|
270
|
+
batchPath: paths.batchPath,
|
|
271
|
+
knowledgePaths,
|
|
272
|
+
evosCasePaths,
|
|
273
|
+
repoProposalPaths,
|
|
274
|
+
knowledgeIndexPath: paths.knowledgeIndexPath,
|
|
275
|
+
evosIndexPath: paths.evosIndexPath,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export async function writeEvolutionRepoProposal(input: {
|
|
280
|
+
homeDir: string;
|
|
281
|
+
proposal: EvolutionRepoProposal;
|
|
282
|
+
}): Promise<{ proposalPath: string; indexPath: string }> {
|
|
283
|
+
validateEvolutionRepoProposal(input.proposal);
|
|
284
|
+
if (!hasConcreteRepoProposalChanges(input.proposal)) {
|
|
285
|
+
throw new Error("Repo proposal must include a target repository and concrete file changes.");
|
|
286
|
+
}
|
|
287
|
+
const paths = resolveEvolutionPaths({
|
|
288
|
+
homeDir: input.homeDir,
|
|
289
|
+
projectKey: input.proposal.projectKey,
|
|
290
|
+
runId: input.proposal.provenance.runId,
|
|
291
|
+
});
|
|
292
|
+
const proposalPath = join(paths.repoProposalsDir, `${input.proposal.id}.json`);
|
|
293
|
+
await writeJson(proposalPath, input.proposal, { overwrite: false });
|
|
294
|
+
|
|
295
|
+
const allRunProposals = await readJsonFiles(paths.repoProposalsDir, parseRepoProposal);
|
|
296
|
+
await writeJson(
|
|
297
|
+
paths.repoProposalsIndexPath,
|
|
298
|
+
{
|
|
299
|
+
schemaVersion: 1,
|
|
300
|
+
projectKey: input.proposal.projectKey,
|
|
301
|
+
runId: input.proposal.provenance.runId,
|
|
302
|
+
updatedAt: input.proposal.provenance.createdAt,
|
|
303
|
+
proposals: allRunProposals.map((proposal) => ({
|
|
304
|
+
id: proposal.id,
|
|
305
|
+
kind: proposal.kind,
|
|
306
|
+
title: proposal.title,
|
|
307
|
+
reviewState: proposal.reviewState,
|
|
308
|
+
})),
|
|
309
|
+
},
|
|
310
|
+
{ overwrite: true },
|
|
311
|
+
);
|
|
312
|
+
return { proposalPath, indexPath: paths.repoProposalsIndexPath };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export async function activateEvolutionDistillationBatch(input: {
|
|
316
|
+
homeDir: string;
|
|
317
|
+
batch: EvolutionDistillationBatch;
|
|
318
|
+
overwrite?: boolean;
|
|
319
|
+
}): Promise<EvolutionActivationResult> {
|
|
320
|
+
validateEvolutionDistillationBatch(input.batch);
|
|
321
|
+
const paths = resolveEvolutionPaths({
|
|
322
|
+
homeDir: input.homeDir,
|
|
323
|
+
projectKey: input.batch.projectKey,
|
|
324
|
+
runId: input.batch.runId,
|
|
325
|
+
});
|
|
326
|
+
const overwrite = input.overwrite === true;
|
|
327
|
+
await writeJson(paths.evidenceWindowPath, input.batch.evidenceWindow, { overwrite });
|
|
328
|
+
await writeJson(paths.batchPath, input.batch, { overwrite });
|
|
329
|
+
|
|
330
|
+
const plan = createOkfKnowledgePlanFromDistillationBatch(input.batch, {
|
|
331
|
+
homeDir: input.homeDir,
|
|
332
|
+
});
|
|
333
|
+
const okf = await activateOkfKnowledgePlan({
|
|
334
|
+
homeDir: input.homeDir,
|
|
335
|
+
plan,
|
|
336
|
+
overwrite,
|
|
337
|
+
evidenceWindowPath: paths.evidenceWindowPath,
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
const evosCasePaths: string[] = [];
|
|
341
|
+
for (const evosCase of input.batch.evosCases) {
|
|
342
|
+
const matchingCandidate = plan.candidates.find((candidate) => candidate.id === evosCase.id);
|
|
343
|
+
if (
|
|
344
|
+
matchingCandidate === undefined ||
|
|
345
|
+
matchingCandidate.decision === "no_write" ||
|
|
346
|
+
matchingCandidate.decision === "skip"
|
|
347
|
+
) {
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
const persistedEvosCase =
|
|
351
|
+
matchingCandidate?.decision === "auto-accept"
|
|
352
|
+
? { ...evosCase, reviewState: "auto-accepted" as const }
|
|
353
|
+
: matchingCandidate?.decision === "needs-human"
|
|
354
|
+
? { ...evosCase, reviewState: "needs-human" as const }
|
|
355
|
+
: evosCase;
|
|
356
|
+
validateEvolutionEvosCase(persistedEvosCase);
|
|
357
|
+
const path = join(paths.evosCasesProjectDir, `${evosCase.id}.json`);
|
|
358
|
+
await writeJson(path, persistedEvosCase, { overwrite });
|
|
359
|
+
evosCasePaths.push(path);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const repoProposalPaths: string[] = [];
|
|
363
|
+
for (const proposal of input.batch.repoProposals) {
|
|
364
|
+
const path = join(paths.repoProposalsDir, `${proposal.id}.json`);
|
|
365
|
+
await writeJson(path, proposal, { overwrite });
|
|
366
|
+
repoProposalPaths.push(path);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
const evosCasesRootDir = resolveEvoDevPaths(input.homeDir).evosCasesDir;
|
|
370
|
+
const evosProjectKeys = await listDirectoryNames(evosCasesRootDir);
|
|
371
|
+
const evosProjects = await Promise.all(
|
|
372
|
+
evosProjectKeys.map(async (projectKey) => {
|
|
373
|
+
const cases = await readJsonFiles(join(evosCasesRootDir, projectKey), parseEvosCase);
|
|
374
|
+
return {
|
|
375
|
+
projectKey,
|
|
376
|
+
cases: cases.map((evosCase) => ({
|
|
377
|
+
id: evosCase.id,
|
|
378
|
+
title: evosCase.title,
|
|
379
|
+
reviewState: evosCase.reviewState,
|
|
380
|
+
})),
|
|
381
|
+
};
|
|
382
|
+
}),
|
|
383
|
+
);
|
|
384
|
+
await writeJson(
|
|
385
|
+
paths.evosIndexPath,
|
|
386
|
+
{
|
|
387
|
+
schemaVersion: 1,
|
|
388
|
+
updatedAt: input.batch.createdAt,
|
|
389
|
+
projects: evosProjects,
|
|
390
|
+
},
|
|
391
|
+
{ overwrite: true },
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
const allRunProposals = await readJsonFiles(paths.repoProposalsDir, parseRepoProposal);
|
|
395
|
+
await writeJson(
|
|
396
|
+
paths.repoProposalsIndexPath,
|
|
397
|
+
{
|
|
398
|
+
schemaVersion: 1,
|
|
399
|
+
projectKey: input.batch.projectKey,
|
|
400
|
+
runId: input.batch.runId,
|
|
401
|
+
updatedAt: input.batch.createdAt,
|
|
402
|
+
proposals: allRunProposals.map((proposal) => ({
|
|
403
|
+
id: proposal.id,
|
|
404
|
+
kind: proposal.kind,
|
|
405
|
+
title: proposal.title,
|
|
406
|
+
reviewState: proposal.reviewState,
|
|
407
|
+
})),
|
|
408
|
+
},
|
|
409
|
+
{ overwrite: true },
|
|
410
|
+
);
|
|
411
|
+
|
|
412
|
+
return {
|
|
413
|
+
evidenceWindowPath: paths.evidenceWindowPath,
|
|
414
|
+
batchPath: paths.batchPath,
|
|
415
|
+
okf,
|
|
416
|
+
evosCasePaths,
|
|
417
|
+
repoProposalPaths,
|
|
418
|
+
evosIndexPath: paths.evosIndexPath,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Persists the minimized evidence/batch audit records and activates a curator-produced plan.
|
|
424
|
+
* The plan is required to describe the exact evidence window so a model cannot redirect a write to
|
|
425
|
+
* another project or run. Raw segment or transcript content is never accepted by this boundary.
|
|
426
|
+
*/
|
|
427
|
+
export async function activateCuratedSessionKnowledgePlan(input: {
|
|
428
|
+
homeDir: string;
|
|
429
|
+
evidenceWindow: EvolutionEvidenceWindow;
|
|
430
|
+
plan: OkfKnowledgePlan;
|
|
431
|
+
now?: string | Date;
|
|
432
|
+
warnings?: string[];
|
|
433
|
+
overwrite?: boolean;
|
|
434
|
+
}): Promise<{ batch: EvolutionDistillationBatch; activation: EvolutionActivationResult }> {
|
|
435
|
+
validateEvolutionEvidenceWindow(input.evidenceWindow);
|
|
436
|
+
if (
|
|
437
|
+
input.plan.projectKey !== input.evidenceWindow.projectKey ||
|
|
438
|
+
input.plan.runId !== input.evidenceWindow.runId ||
|
|
439
|
+
input.plan.evidenceWindowId !== input.evidenceWindow.id
|
|
440
|
+
) {
|
|
441
|
+
throw new Error("Curated knowledge plan identity does not match its evidence window.");
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const createdAt = normalizeTimestamp(input.now ?? input.plan.createdAt);
|
|
445
|
+
const batch: EvolutionDistillationBatch = {
|
|
446
|
+
schemaVersion: 1,
|
|
447
|
+
id: createStableId("batch", [input.evidenceWindow.id, createdAt, "curated"]),
|
|
448
|
+
projectKey: input.evidenceWindow.projectKey,
|
|
449
|
+
runId: input.evidenceWindow.runId,
|
|
450
|
+
createdAt,
|
|
451
|
+
evidenceWindow: input.evidenceWindow,
|
|
452
|
+
knowledgeRecords: [],
|
|
453
|
+
evosCases: [],
|
|
454
|
+
repoProposals: [],
|
|
455
|
+
warnings: (input.warnings ?? []).map(sanitizeText),
|
|
456
|
+
};
|
|
457
|
+
validateEvolutionDistillationBatch(batch);
|
|
458
|
+
|
|
459
|
+
const paths = resolveEvolutionPaths({
|
|
460
|
+
homeDir: input.homeDir,
|
|
461
|
+
projectKey: batch.projectKey,
|
|
462
|
+
runId: batch.runId,
|
|
463
|
+
});
|
|
464
|
+
const overwrite = input.overwrite === true;
|
|
465
|
+
await writeJson(paths.evidenceWindowPath, batch.evidenceWindow, { overwrite });
|
|
466
|
+
await writeJson(paths.batchPath, batch, { overwrite });
|
|
467
|
+
const okf = await activateOkfKnowledgePlan({
|
|
468
|
+
homeDir: input.homeDir,
|
|
469
|
+
plan: input.plan,
|
|
470
|
+
overwrite,
|
|
471
|
+
evidenceWindowPath: paths.evidenceWindowPath,
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
return {
|
|
475
|
+
batch,
|
|
476
|
+
activation: {
|
|
477
|
+
evidenceWindowPath: paths.evidenceWindowPath,
|
|
478
|
+
batchPath: paths.batchPath,
|
|
479
|
+
okf,
|
|
480
|
+
evosCasePaths: [],
|
|
481
|
+
repoProposalPaths: [],
|
|
482
|
+
evosIndexPath: paths.evosIndexPath,
|
|
483
|
+
},
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function createRunSummary(
|
|
488
|
+
evidenceWindow: EvolutionEvidenceWindow,
|
|
489
|
+
roleIds: string[],
|
|
490
|
+
failedSignalCount: number,
|
|
491
|
+
): string {
|
|
492
|
+
const failureClause =
|
|
493
|
+
failedSignalCount === 0
|
|
494
|
+
? "No failure signal was detected in metadata summaries."
|
|
495
|
+
: `${failedSignalCount} potential failure or issue signal(s) were detected.`;
|
|
496
|
+
return sanitizeText(
|
|
497
|
+
`Run ${evidenceWindow.runId} produced ${evidenceWindow.events.length} redacted event(s) across ${roleIds.length} role(s). ${failureClause}`,
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function createProvenance(
|
|
502
|
+
evidenceWindow: EvolutionEvidenceWindow,
|
|
503
|
+
createdAt: string,
|
|
504
|
+
sourceRefs: string[],
|
|
505
|
+
): EvolutionKnowledgeRecord["provenance"] {
|
|
506
|
+
return {
|
|
507
|
+
runId: evidenceWindow.runId,
|
|
508
|
+
taskId: evidenceWindow.taskId,
|
|
509
|
+
evidenceWindowId: evidenceWindow.id,
|
|
510
|
+
sourceRefs,
|
|
511
|
+
createdAt,
|
|
512
|
+
createdBy: "evodev",
|
|
513
|
+
rawLogsStored: false,
|
|
514
|
+
rawPromptsStored: false,
|
|
515
|
+
sourceDumpsStored: false,
|
|
516
|
+
rawCommandOutputStored: false,
|
|
517
|
+
};
|
|
518
|
+
}
|