@evo-dev/core 0.0.1-alpha → 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.
Files changed (85) hide show
  1. package/assets/agents/review/code-reviewer/examples.md +1 -1
  2. package/assets/agents/review/code-reviewer/prompt.md +1 -1
  3. package/assets/agents/review/code-reviewer/verification.md +1 -1
  4. package/assets/skills/coding/knowledge-distillation/SKILL.md +251 -0
  5. package/assets/skills/coding/knowledge-distillation/manifest.json +10 -0
  6. package/assets/skills/coding/knowledge-distillation/references/knowledge-distillation-methods.md +126 -0
  7. package/assets/team/agents/code-reviewer.md +48 -0
  8. package/assets/team/agents/docs-maintainer.md +51 -0
  9. package/assets/team/agents/implementation-engineer.md +51 -0
  10. package/assets/team/agents/product-scope-analyst.md +58 -0
  11. package/assets/team/agents/release-engineer.md +55 -0
  12. package/assets/team/agents/security-boundary-reviewer.md +50 -0
  13. package/assets/team/agents/solution-architect.md +51 -0
  14. package/assets/team/agents/verification-engineer.md +51 -0
  15. package/assets/team/team.md +102 -0
  16. package/assets/workflows/rd-bug-fix/WORKFLOW.json +1 -1
  17. package/assets/workflows/rd-code-review/WORKFLOW.json +1 -1
  18. package/assets/workflows/rd-docs-update/WORKFLOW.json +1 -1
  19. package/assets/workflows/rd-feature-implementation/WORKFLOW.json +1 -1
  20. package/assets/workflows/rd-refactor/WORKFLOW.json +1 -1
  21. package/assets/workflows/rd-release-readiness/WORKFLOW.json +1 -1
  22. package/assets/workflows/rd-security-boundary-review/WORKFLOW.json +2 -2
  23. package/assets/workflows/rd-test-generation/WORKFLOW.json +1 -1
  24. package/dist/config/index.js +1115 -81
  25. package/dist/index.js +13796 -2196
  26. package/dist/plugins/index.js +32 -32
  27. package/package.json +5 -1
  28. package/src/agents/index.ts +63 -292
  29. package/src/code-agent-traces/index.ts +520 -0
  30. package/src/config/index.ts +7 -0
  31. package/src/config/paths.ts +30 -0
  32. package/src/config/settings.ts +201 -0
  33. package/src/config/store.ts +152 -0
  34. package/src/daemon/index.ts +462 -40
  35. package/src/evolution/candidates/index.ts +564 -0
  36. package/src/evolution/control/index.ts +20 -0
  37. package/src/evolution/evidence/analysis.ts +533 -0
  38. package/src/evolution/evidence/index.ts +3 -0
  39. package/src/evolution/evidence/session-memory/analysis.ts +281 -0
  40. package/src/evolution/evidence/session-memory/constants.ts +9 -0
  41. package/src/evolution/evidence/session-memory/index.ts +7 -0
  42. package/src/evolution/evidence/session-memory/paths.ts +29 -0
  43. package/src/evolution/evidence/session-memory/policy.ts +39 -0
  44. package/src/evolution/evidence/session-memory/segment.ts +202 -0
  45. package/src/evolution/evidence/session-memory/sensitivity.ts +335 -0
  46. package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
  47. package/src/evolution/evidence/session-memory/storage.ts +379 -0
  48. package/src/evolution/evidence/session-memory/types.ts +221 -0
  49. package/src/evolution/evidence/session-memory/updater.ts +191 -0
  50. package/src/evolution/formatters.ts +169 -0
  51. package/src/evolution/index.ts +16 -0
  52. package/src/evolution/knowledge/index.ts +5427 -0
  53. package/src/evolution/paths.ts +44 -0
  54. package/src/evolution/processor/distillation.ts +518 -0
  55. package/src/evolution/processor/index.ts +3 -0
  56. package/src/evolution/processor/process.ts +528 -0
  57. package/src/{learning → evolution/review}/index.ts +10 -14
  58. package/src/evolution/schema.ts +568 -0
  59. package/src/evolution/shared.ts +758 -0
  60. package/src/evolution/triggers/classification.ts +102 -0
  61. package/src/evolution/triggers/index.ts +295 -0
  62. package/src/hooks/index.ts +652 -376
  63. package/src/index.ts +16 -3
  64. package/src/pack/index.ts +13 -13
  65. package/src/plugins/capabilities.ts +40 -42
  66. package/src/plugins/index.ts +0 -1
  67. package/src/plugins/types.ts +4 -0
  68. package/src/projects/index.ts +453 -0
  69. package/src/protected-zones/index.ts +29 -11
  70. package/src/runtime-logs/index.ts +790 -0
  71. package/src/sync/orchestrator.ts +6 -0
  72. package/src/team/index.ts +3642 -0
  73. package/src/team/mcp.ts +405 -0
  74. package/src/team/prompts.ts +141 -0
  75. package/src/utils/errors.ts +13 -0
  76. package/src/utils/fs.ts +40 -0
  77. package/src/utils/hash.ts +9 -0
  78. package/src/utils/ids.ts +12 -0
  79. package/src/utils/index.ts +7 -0
  80. package/src/utils/parsing.ts +11 -0
  81. package/src/utils/text.ts +18 -0
  82. package/src/utils/time.ts +5 -0
  83. package/src/workflow/index.ts +6 -24
  84. package/src/project/index.ts +0 -507
  85. package/src/task/index.ts +0 -840
@@ -0,0 +1,102 @@
1
+ import type {
2
+ EvolutionEvidenceEvent,
3
+ EvolutionEvidenceEventKind,
4
+ EvolutionEvidenceWindow,
5
+ EvolutionEvosCase,
6
+ EvolutionNormalizedEventType,
7
+ EvolutionTriggerPolicy,
8
+ EvolutionTriggerReason,
9
+ EvolutionTriggerStrength,
10
+ } from "../schema.ts";
11
+ import { NORMALIZED_EVENT_TYPES, sanitizeText } from "../shared.ts";
12
+
13
+ export function normalizeEvolutionEventType(
14
+ value: string | null | undefined,
15
+ ): EvolutionNormalizedEventType {
16
+ if (value === "AgentStop") return "SubagentStop";
17
+ if (typeof value === "string" && (NORMALIZED_EVENT_TYPES as readonly string[]).includes(value)) {
18
+ return value as EvolutionNormalizedEventType;
19
+ }
20
+ return "unknown";
21
+ }
22
+
23
+ export function decideEvolutionTrigger(input: {
24
+ eventType: EvolutionNormalizedEventType;
25
+ summary: string;
26
+ kind: EvolutionEvidenceEventKind;
27
+ }): { strength: EvolutionTriggerStrength; reason: EvolutionTriggerReason } {
28
+ if (input.eventType === "TaskCompleted") return { strength: "strong", reason: "task-completed" };
29
+ if (input.eventType === "StopFailure") return { strength: "strong", reason: "stop-failure" };
30
+ if (input.eventType === "PostToolUseFailure")
31
+ return { strength: "strong", reason: "tool-failure" };
32
+ if (input.eventType === "PermissionDenied")
33
+ return { strength: "strong", reason: "permission-denied" };
34
+ if (input.eventType === "Stop") return { strength: "conditional", reason: "turn-completed" };
35
+ if (input.eventType === "SessionEnd") return { strength: "conditional", reason: "session-ended" };
36
+ if (input.eventType === "SubagentStop")
37
+ return { strength: "conditional", reason: "role-completed" };
38
+ if (input.kind === "error" || /fail|failed|failure|error|issue/i.test(input.summary)) {
39
+ return { strength: "strong", reason: "failure-signal" };
40
+ }
41
+ return { strength: "none", reason: "none" };
42
+ }
43
+
44
+ export function createTriggerPolicy(events: EvolutionEvidenceEvent[]): EvolutionTriggerPolicy {
45
+ const failures = events.filter((event) => event.kind === "error").length;
46
+ const verifications = events.filter((event) => event.kind === "verification").length;
47
+ const roleLifecycle = events.filter((event) => event.kind === "subagent").length;
48
+ const skillCalls = events.filter((event) => event.kind === "skill-call").length;
49
+ const strongest = strongestTrigger(events);
50
+ const reasons = uniqueTriggerReasons(
51
+ events.flatMap((event) => (event.triggerReason === "none" ? [] : [event.triggerReason])),
52
+ );
53
+ const hasSignal = failures > 0 || verifications > 0 || roleLifecycle > 0 || skillCalls > 0;
54
+ return {
55
+ strongest: strongest.strength,
56
+ reasons,
57
+ distillRecommended:
58
+ strongest.strength === "strong" || (strongest.strength === "conditional" && hasSignal),
59
+ evidenceSignals: { failures, verifications, roleLifecycle, skillCalls },
60
+ };
61
+ }
62
+
63
+ export function strongestTrigger(events: EvolutionEvidenceEvent[]): {
64
+ strength: EvolutionTriggerStrength;
65
+ reason: EvolutionTriggerReason;
66
+ } {
67
+ const strong = events.find((event) => event.triggerStrength === "strong");
68
+ if (strong !== undefined) return { strength: "strong", reason: strong.triggerReason };
69
+ const conditional = events.find((event) => event.triggerStrength === "conditional");
70
+ if (conditional !== undefined) {
71
+ return { strength: "conditional", reason: conditional.triggerReason };
72
+ }
73
+ return { strength: "none", reason: "none" };
74
+ }
75
+
76
+ export function uniqueTriggerReasons(values: EvolutionTriggerReason[]): EvolutionTriggerReason[] {
77
+ return [...new Set(values)].filter((reason) => reason !== "none");
78
+ }
79
+
80
+ export function chooseEvosTriggerKind(
81
+ evidenceWindow: EvolutionEvidenceWindow,
82
+ ): EvolutionEvosCase["trigger"]["kind"] {
83
+ if (evidenceWindow.triggerPolicy.reasons.includes("task-completed")) return "task-completion";
84
+ if (evidenceWindow.triggerPolicy.reasons.includes("turn-completed")) return "session-completion";
85
+ if (evidenceWindow.triggerPolicy.reasons.includes("session-ended")) return "session-completion";
86
+ return "manual";
87
+ }
88
+
89
+ export function createTriggerSummary(evidenceWindow: EvolutionEvidenceWindow): string {
90
+ const reasons = evidenceWindow.triggerPolicy.reasons.join(", ") || "manual";
91
+ return sanitizeText(
92
+ `Evolution distillation used ${evidenceWindow.triggerPolicy.strongest} trigger evidence: ${reasons}.`,
93
+ );
94
+ }
95
+
96
+ export function createTriggerDecisionSummary(
97
+ eventType: EvolutionNormalizedEventType,
98
+ strength: EvolutionTriggerStrength,
99
+ reason: EvolutionTriggerReason,
100
+ ): string {
101
+ return `Hook event ${eventType} classified as ${strength} evolution trigger (${reason}).`;
102
+ }
@@ -0,0 +1,295 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { resolveEvoDevPaths } from "../../config/paths.ts";
4
+ import {
5
+ createStableId,
6
+ isFileExistsError,
7
+ normalizeTimestamp,
8
+ readJsonFiles,
9
+ writeJsonFile as writeJson,
10
+ } from "../../utils/index.ts";
11
+ import { resolveEvolutionPaths } from "../paths.ts";
12
+ import type {
13
+ EvolutionTriggerDecision,
14
+ EvolutionTriggerInput,
15
+ EvolutionTriggerListInput,
16
+ EvolutionTriggerRecord,
17
+ EvolutionTriggerStatus,
18
+ SegmentEvolutionTriggerInput,
19
+ SegmentEvolutionTriggerListInput,
20
+ SegmentEvolutionTriggerRecord,
21
+ } from "../schema.ts";
22
+ import {
23
+ createPrivacyFields,
24
+ listDirectoryNames,
25
+ parseSegmentTrigger,
26
+ parseTrigger,
27
+ sanitizeId,
28
+ sanitizeStorageId,
29
+ sanitizeText,
30
+ validateEvolutionTriggerRecord,
31
+ validateSegmentEvolutionTriggerRecord,
32
+ } from "../shared.ts";
33
+ import {
34
+ createTriggerDecisionSummary,
35
+ decideEvolutionTrigger,
36
+ normalizeEvolutionEventType,
37
+ } from "./classification.ts";
38
+
39
+ export function resolveEvolutionTriggerDecision(input: {
40
+ eventType: string;
41
+ summary?: string | null;
42
+ }): EvolutionTriggerDecision {
43
+ const eventType = normalizeEvolutionEventType(input.eventType);
44
+ const trigger = decideEvolutionTrigger({
45
+ eventType,
46
+ summary: input.summary ?? "",
47
+ kind: "trace",
48
+ });
49
+ return {
50
+ eventType,
51
+ strength: trigger.strength,
52
+ reason: trigger.reason,
53
+ shouldQueue: trigger.strength !== "none",
54
+ summary: createTriggerDecisionSummary(eventType, trigger.strength, trigger.reason),
55
+ };
56
+ }
57
+
58
+ export async function enqueueEvolutionTrigger(
59
+ input: EvolutionTriggerInput,
60
+ ): Promise<EvolutionTriggerRecord | null> {
61
+ const decision = resolveEvolutionTriggerDecision({
62
+ eventType: input.eventType,
63
+ summary: input.summary,
64
+ });
65
+ if (!decision.shouldQueue) return null;
66
+
67
+ const now = normalizeTimestamp(input.now);
68
+ const projectKey = sanitizeId(input.projectKey);
69
+ const runId = sanitizeId(input.runId);
70
+ const id = createStableId("trigger", [
71
+ projectKey,
72
+ runId,
73
+ input.roleId ?? "",
74
+ input.eventId ?? "",
75
+ decision.eventType,
76
+ now,
77
+ ]);
78
+ const trigger: EvolutionTriggerRecord = {
79
+ schemaVersion: 1,
80
+ id,
81
+ kind: "evolution-trigger",
82
+ projectKey,
83
+ runId,
84
+ roleId: input.roleId === undefined || input.roleId === null ? null : sanitizeId(input.roleId),
85
+ taskId: input.taskId === undefined || input.taskId === null ? null : sanitizeId(input.taskId),
86
+ eventType: decision.eventType,
87
+ eventId:
88
+ input.eventId === undefined || input.eventId === null ? null : sanitizeId(input.eventId),
89
+ evidenceRef:
90
+ input.evidenceRef === undefined || input.evidenceRef === null
91
+ ? null
92
+ : sanitizeText(input.evidenceRef),
93
+ summary: sanitizeText(input.summary ?? decision.summary),
94
+ triggerStrength: decision.strength,
95
+ triggerReason: decision.reason,
96
+ status: "pending",
97
+ attempts: 0,
98
+ createdAt: now,
99
+ updatedAt: now,
100
+ processedBatchId: null,
101
+ lastError: null,
102
+ rawContentStored: false,
103
+ privacy: createPrivacyFields(input.summary ?? decision.summary),
104
+ };
105
+ validateEvolutionTriggerRecord(trigger);
106
+ const paths = resolveEvolutionPaths({ homeDir: input.homeDir, projectKey, runId });
107
+ await writeJson(join(paths.triggersDir, `${trigger.id}.json`), trigger, { overwrite: false });
108
+ return trigger;
109
+ }
110
+
111
+ export async function listEvolutionTriggers(
112
+ input: EvolutionTriggerListInput,
113
+ ): Promise<EvolutionTriggerRecord[]> {
114
+ const paths = resolveEvoDevPaths(input.homeDir);
115
+ const evolutionStateDir = join(paths.stateDir, "evolution");
116
+ const projectKeys =
117
+ input.projectKey === undefined
118
+ ? await listDirectoryNames(evolutionStateDir)
119
+ : [sanitizeStorageId("projectKey", input.projectKey)];
120
+ const triggers: EvolutionTriggerRecord[] = [];
121
+ for (const projectKey of projectKeys) {
122
+ const projectStateDir = join(evolutionStateDir, projectKey);
123
+ const runIds =
124
+ input.runId === undefined
125
+ ? await listDirectoryNames(projectStateDir)
126
+ : [sanitizeStorageId("runId", input.runId)];
127
+ for (const runId of runIds) {
128
+ const runTriggers = await readJsonFiles(
129
+ join(projectStateDir, runId, "triggers"),
130
+ parseTrigger,
131
+ );
132
+ triggers.push(
133
+ ...runTriggers.filter(
134
+ (trigger) => input.status === undefined || trigger.status === input.status,
135
+ ),
136
+ );
137
+ }
138
+ }
139
+ return triggers.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
140
+ }
141
+
142
+ export async function enqueueSegmentEvolutionTrigger(
143
+ input: SegmentEvolutionTriggerInput,
144
+ ): Promise<SegmentEvolutionTriggerRecord> {
145
+ const now = normalizeTimestamp(input.now);
146
+ const projectKey = sanitizeId(input.projectKey);
147
+ const sessionKey = sanitizeId(input.sessionKey);
148
+ const segmentId = sanitizeId(input.segmentId);
149
+ const id = createStableId("segment-trigger", [projectKey, sessionKey, segmentId]);
150
+ const trigger: SegmentEvolutionTriggerRecord = {
151
+ schemaVersion: 1,
152
+ id,
153
+ kind: "segment-evolution-trigger",
154
+ projectKey,
155
+ sessionKey,
156
+ runId: input.runId === undefined || input.runId === null ? null : sanitizeId(input.runId),
157
+ roleId: input.roleId === undefined || input.roleId === null ? null : sanitizeId(input.roleId),
158
+ segmentId,
159
+ segmentPath: sanitizeText(input.segmentPath),
160
+ strength: input.strength,
161
+ reason: input.reason,
162
+ summary: sanitizeText(input.summary),
163
+ status: "pending",
164
+ attempts: 0,
165
+ createdAt: now,
166
+ updatedAt: now,
167
+ processedBatchId: null,
168
+ lastError: null,
169
+ rawContentStored: false,
170
+ };
171
+ validateSegmentEvolutionTriggerRecord(trigger);
172
+ const path = resolveSegmentEvolutionTriggerPath(input.homeDir, trigger);
173
+ try {
174
+ await writeJson(path, trigger, { overwrite: false });
175
+ return trigger;
176
+ } catch (error) {
177
+ if (!isFileExistsError(error)) throw error;
178
+ return parseSegmentTrigger(JSON.parse(await readFile(path, "utf8")) as unknown);
179
+ }
180
+ }
181
+
182
+ export async function listSegmentEvolutionTriggers(
183
+ input: SegmentEvolutionTriggerListInput,
184
+ ): Promise<SegmentEvolutionTriggerRecord[]> {
185
+ const paths = resolveEvoDevPaths(input.homeDir);
186
+ const evolutionStateDir = join(paths.stateDir, "evolution");
187
+ const projectKeys =
188
+ input.projectKey === undefined
189
+ ? await listDirectoryNames(evolutionStateDir)
190
+ : [sanitizeStorageId("projectKey", input.projectKey)];
191
+ const triggers: SegmentEvolutionTriggerRecord[] = [];
192
+ for (const projectKey of projectKeys) {
193
+ const projectSegmentsDir = join(evolutionStateDir, projectKey, "segments");
194
+ const projectTriggers = await readJsonFiles(projectSegmentsDir, parseSegmentTrigger);
195
+ triggers.push(
196
+ ...projectTriggers.filter((trigger) => {
197
+ if (input.status !== undefined && trigger.status !== input.status) return false;
198
+ if (
199
+ input.runId !== undefined &&
200
+ trigger.runId !== sanitizeStorageId("runId", input.runId)
201
+ ) {
202
+ return false;
203
+ }
204
+ return true;
205
+ }),
206
+ );
207
+ }
208
+ return triggers.sort((left, right) => left.createdAt.localeCompare(right.createdAt));
209
+ }
210
+
211
+ export function groupTriggersByRun(triggers: EvolutionTriggerRecord[]): EvolutionTriggerRecord[][] {
212
+ const groups = new Map<string, EvolutionTriggerRecord[]>();
213
+ for (const trigger of triggers) {
214
+ const key = `${trigger.projectKey}\0${trigger.runId}`;
215
+ groups.set(key, [...(groups.get(key) ?? []), trigger]);
216
+ }
217
+ return [...groups.values()];
218
+ }
219
+
220
+ export async function updateTriggers(
221
+ homeDir: string,
222
+ triggers: EvolutionTriggerRecord[],
223
+ patch: {
224
+ status: EvolutionTriggerStatus;
225
+ updatedAt: string;
226
+ attempts?: ((trigger: EvolutionTriggerRecord) => number) | number;
227
+ processedBatchId?: string | null;
228
+ lastError?: string | null;
229
+ },
230
+ ): Promise<void> {
231
+ for (const trigger of triggers) {
232
+ const next: EvolutionTriggerRecord = {
233
+ ...trigger,
234
+ status: patch.status,
235
+ updatedAt: patch.updatedAt,
236
+ attempts:
237
+ typeof patch.attempts === "function"
238
+ ? patch.attempts(trigger)
239
+ : (patch.attempts ?? trigger.attempts),
240
+ processedBatchId:
241
+ patch.processedBatchId === undefined ? trigger.processedBatchId : patch.processedBatchId,
242
+ lastError: patch.lastError === undefined ? trigger.lastError : patch.lastError,
243
+ };
244
+ validateEvolutionTriggerRecord(next);
245
+ const paths = resolveEvolutionPaths({
246
+ homeDir,
247
+ projectKey: next.projectKey,
248
+ runId: next.runId,
249
+ });
250
+ await writeJson(join(paths.triggersDir, `${next.id}.json`), next, { overwrite: true });
251
+ }
252
+ }
253
+
254
+ export async function updateSegmentTriggers(
255
+ homeDir: string,
256
+ triggers: SegmentEvolutionTriggerRecord[],
257
+ patch: {
258
+ status: EvolutionTriggerStatus;
259
+ updatedAt: string;
260
+ attempts?: ((trigger: SegmentEvolutionTriggerRecord) => number) | number;
261
+ processedBatchId?: string | null;
262
+ lastError?: string | null;
263
+ },
264
+ ): Promise<void> {
265
+ for (const trigger of triggers) {
266
+ const next: SegmentEvolutionTriggerRecord = {
267
+ ...trigger,
268
+ status: patch.status,
269
+ updatedAt: patch.updatedAt,
270
+ attempts:
271
+ typeof patch.attempts === "function"
272
+ ? patch.attempts(trigger)
273
+ : (patch.attempts ?? trigger.attempts),
274
+ processedBatchId:
275
+ patch.processedBatchId === undefined ? trigger.processedBatchId : patch.processedBatchId,
276
+ lastError: patch.lastError === undefined ? trigger.lastError : patch.lastError,
277
+ };
278
+ validateSegmentEvolutionTriggerRecord(next);
279
+ await writeJson(resolveSegmentEvolutionTriggerPath(homeDir, next), next, { overwrite: true });
280
+ }
281
+ }
282
+
283
+ export function resolveSegmentEvolutionTriggerPath(
284
+ homeDir: string,
285
+ trigger: Pick<SegmentEvolutionTriggerRecord, "projectKey" | "id">,
286
+ ): string {
287
+ const paths = resolveEvoDevPaths(homeDir);
288
+ return join(
289
+ paths.stateDir,
290
+ "evolution",
291
+ sanitizeStorageId("projectKey", trigger.projectKey),
292
+ "segments",
293
+ `${sanitizeStorageId("segmentTrigger", trigger.id)}.json`,
294
+ );
295
+ }