@evo-dev/core 0.0.1-alpha.2 → 0.0.1-alpha.20

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 (79) hide show
  1. package/assets/skills/coding/knowledge-distillation/SKILL.md +5 -3
  2. package/assets/team/agents/code-reviewer.md +48 -0
  3. package/assets/team/agents/docs-maintainer.md +51 -0
  4. package/assets/team/agents/implementation-engineer.md +51 -0
  5. package/assets/team/agents/product-scope-analyst.md +58 -0
  6. package/assets/team/agents/release-engineer.md +55 -0
  7. package/assets/team/agents/security-boundary-reviewer.md +50 -0
  8. package/assets/team/agents/solution-architect.md +51 -0
  9. package/assets/team/agents/verification-engineer.md +51 -0
  10. package/assets/team/team.md +102 -0
  11. package/dist/assets/index.js +5 -5
  12. package/dist/config/index.js +793 -241
  13. package/dist/index.js +20840 -12908
  14. package/dist/plugins/index.js +13 -13
  15. package/package.json +1 -1
  16. package/src/agents/index.ts +1 -265
  17. package/src/code-agent-traces/index.ts +11 -12
  18. package/src/config/index.ts +2 -0
  19. package/src/config/settings.ts +116 -7
  20. package/src/config/store.ts +1 -1
  21. package/src/daemon/index.ts +1 -41
  22. package/src/evolution/candidates/index.ts +730 -0
  23. package/src/evolution/control/index.ts +20 -0
  24. package/src/evolution/evidence/analysis.ts +533 -0
  25. package/src/evolution/evidence/index.ts +3 -0
  26. package/src/evolution/evidence/session-memory/analysis.ts +287 -0
  27. package/src/evolution/evidence/session-memory/constants.ts +9 -0
  28. package/src/evolution/evidence/session-memory/index.ts +9 -0
  29. package/src/evolution/evidence/session-memory/paths.ts +29 -0
  30. package/src/evolution/evidence/session-memory/policy.ts +39 -0
  31. package/src/evolution/evidence/session-memory/retention.ts +643 -0
  32. package/src/evolution/evidence/session-memory/segment.ts +216 -0
  33. package/src/evolution/evidence/session-memory/semantic-packet.ts +408 -0
  34. package/src/evolution/evidence/session-memory/sensitivity.ts +335 -0
  35. package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
  36. package/src/evolution/evidence/session-memory/storage.ts +744 -0
  37. package/src/evolution/evidence/session-memory/types.ts +296 -0
  38. package/src/evolution/evidence/session-memory/updater.ts +199 -0
  39. package/src/evolution/formatters.ts +169 -0
  40. package/src/evolution/imports/apply.ts +435 -0
  41. package/src/evolution/imports/diff.ts +472 -0
  42. package/src/evolution/imports/index.ts +7 -0
  43. package/src/evolution/imports/materialize.ts +640 -0
  44. package/src/evolution/imports/paths.ts +129 -0
  45. package/src/evolution/imports/stage.ts +414 -0
  46. package/src/evolution/imports/storage.ts +952 -0
  47. package/src/evolution/imports/types.ts +226 -0
  48. package/src/evolution/index.ts +19 -2827
  49. package/src/evolution/knowledge/change-store.ts +558 -0
  50. package/src/evolution/knowledge/changes.ts +459 -0
  51. package/src/evolution/knowledge/freshness.ts +69 -0
  52. package/src/{knowledge → evolution/knowledge}/index.ts +1532 -206
  53. package/src/evolution/knowledge/review.ts +446 -0
  54. package/src/evolution/knowledge/support.ts +135 -0
  55. package/src/evolution/paths.ts +44 -0
  56. package/src/evolution/processor/distillation.ts +518 -0
  57. package/src/evolution/processor/index.ts +3 -0
  58. package/src/evolution/processor/process.ts +594 -0
  59. package/src/{learning → evolution/review}/index.ts +10 -14
  60. package/src/evolution/schema.ts +639 -0
  61. package/src/evolution/shared.ts +1053 -0
  62. package/src/evolution/triggers/classification.ts +102 -0
  63. package/src/evolution/triggers/index.ts +295 -0
  64. package/src/hooks/index.ts +281 -197
  65. package/src/index.ts +15 -4
  66. package/src/projects/index.ts +934 -0
  67. package/src/runtime-logs/index.ts +100 -13
  68. package/src/team/index.ts +582 -3
  69. package/src/utils/errors.ts +13 -0
  70. package/src/utils/fs.ts +40 -0
  71. package/src/utils/hash.ts +9 -0
  72. package/src/utils/ids.ts +12 -0
  73. package/src/utils/index.ts +7 -0
  74. package/src/utils/parsing.ts +11 -0
  75. package/src/utils/text.ts +18 -0
  76. package/src/utils/time.ts +5 -0
  77. package/src/workflow/index.ts +3 -21
  78. package/src/project/index.ts +0 -507
  79. package/src/task/index.ts +0 -840
@@ -0,0 +1,287 @@
1
+ import { createStableId, normalizeTimestamp } from "../../../utils/index.ts";
2
+ import type {
3
+ EvolutionEpisode,
4
+ EvolutionEvidenceEvent,
5
+ EvolutionEvidenceEventKind,
6
+ EvolutionEvidenceWindow,
7
+ EvolutionTriggerReason,
8
+ EvolutionTriggerStrength,
9
+ } from "../../schema.ts";
10
+ import {
11
+ MAX_EVIDENCE_EVENTS,
12
+ createPrivacyFields,
13
+ displayPath,
14
+ sanitizeId,
15
+ sanitizeOptionalId,
16
+ sanitizeText,
17
+ validateEvolutionEvidenceWindow,
18
+ } from "../../shared.ts";
19
+ import {
20
+ createTriggerPolicy,
21
+ decideEvolutionTrigger,
22
+ normalizeEvolutionEventType,
23
+ strongestTrigger,
24
+ } from "../../triggers/classification.ts";
25
+ import { resolveSessionMemoryPaths } from "./paths.ts";
26
+ import { redactSessionMemoryCredentialText } from "./sensitivity.ts";
27
+ import type {
28
+ SessionEvidenceSegmentV1,
29
+ SessionMemorySegmentReason,
30
+ SessionMemorySignal,
31
+ SessionMemorySignalStrength,
32
+ } from "./types.ts";
33
+
34
+ export type SessionSegmentDistillationSkipReason =
35
+ | "sensitive-segment"
36
+ | "segment-deleted"
37
+ | "segment-raw-expired"
38
+ | "segment-ignored"
39
+ | "segment-rejected"
40
+ | "no-distillation-signal";
41
+
42
+ export interface SessionSegmentEvidenceAnalysis {
43
+ evidenceWindow: EvolutionEvidenceWindow | null;
44
+ skipReason: SessionSegmentDistillationSkipReason | null;
45
+ warnings: string[];
46
+ }
47
+
48
+ /**
49
+ * Converts a stored Session Memory segment into the metadata-only evidence contract consumed by
50
+ * the existing distillation and OKF activation pipeline. Raw excerpts are deliberately excluded.
51
+ */
52
+ export function analyzeSessionEvidenceSegment(input: {
53
+ homeDir: string;
54
+ segment: SessionEvidenceSegmentV1;
55
+ now?: string | Date;
56
+ }): SessionSegmentEvidenceAnalysis {
57
+ const { segment } = input;
58
+ if (segment.lifecycle.status === "deleted") return skipped("segment-deleted");
59
+ if (segment.lifecycle.status === "raw-expired") return skipped("segment-raw-expired");
60
+ if (segment.lifecycle.status === "ignored") return skipped("segment-ignored");
61
+ if (segment.lifecycle.reviewState === "rejected") return skipped("segment-rejected");
62
+
63
+ const roleId = resolveSegmentRoleId(segment);
64
+ const sourceRefId = "source-session-segment";
65
+ const episodeId = "episode-session-0001";
66
+ const signals = segment.signals.slice(0, MAX_EVIDENCE_EVENTS);
67
+ const events = signals.map((signal, index) =>
68
+ createSegmentEvidenceEvent({
69
+ signal,
70
+ segmentReason: segment.reason,
71
+ segmentStrength: segment.strength,
72
+ roleId,
73
+ sourceRefId,
74
+ episodeId,
75
+ sequence: index + 1,
76
+ }),
77
+ );
78
+ if (!isSegmentEligibleForDistillation(segment, events)) {
79
+ return skipped("no-distillation-signal");
80
+ }
81
+
82
+ const strongest = strongestTrigger(events);
83
+ const episode: EvolutionEpisode = {
84
+ id: episodeId,
85
+ kind: "session",
86
+ status: events.some((event) => event.kind === "error") ? "failed" : "closed",
87
+ roleId,
88
+ taskId: null,
89
+ startedAt: events[0]?.occurredAt ?? segment.createdAt,
90
+ endedAt: events.at(-1)?.occurredAt ?? segment.createdAt,
91
+ eventIds: events.map((event) => event.id),
92
+ triggerStrength: strongest.strength,
93
+ triggerReason: strongest.reason,
94
+ summary: `Session Memory segment ${segment.reason} contains ${events.length} normalized metadata signal(s).`,
95
+ rawContentStored: false,
96
+ };
97
+ const paths = resolveSessionMemoryPaths({
98
+ homeDir: input.homeDir,
99
+ projectKey: segment.projectKey,
100
+ sessionKey: segment.sessionKey,
101
+ });
102
+ const evidenceWindow: EvolutionEvidenceWindow = {
103
+ schemaVersion: 1,
104
+ id: createStableId("segment-evidence", [segment.id]),
105
+ kind: "evidence-window",
106
+ projectKey: sanitizeId(segment.projectKey),
107
+ // A segment needs its own run namespace so multiple segments from one native/team session do
108
+ // not overwrite one another's evidence window, plan, or distillation batch.
109
+ runId: createStableId("segment-run", [segment.projectKey, segment.sessionKey, segment.id]),
110
+ taskId: null,
111
+ createdAt: normalizeTimestamp(input.now),
112
+ sourceRefs: [
113
+ {
114
+ id: sourceRefId,
115
+ kind: "session-memory-segment",
116
+ path: displayPath(input.homeDir, paths.segmentPath(segment.id)),
117
+ roleId,
118
+ rawContentStored: false,
119
+ externalContentCopied: false,
120
+ },
121
+ ],
122
+ events,
123
+ episodes: [episode],
124
+ triggerPolicy: createTriggerPolicy(events),
125
+ privacy: createPrivacyFields({ events, episodes: [episode] }),
126
+ };
127
+ validateEvolutionEvidenceWindow(evidenceWindow);
128
+ return {
129
+ evidenceWindow,
130
+ skipReason: null,
131
+ warnings:
132
+ segment.signals.length > MAX_EVIDENCE_EVENTS
133
+ ? [
134
+ `Session segment metadata signals were truncated from ${segment.signals.length} to ${MAX_EVIDENCE_EVENTS}.`,
135
+ ]
136
+ : [],
137
+ };
138
+ }
139
+
140
+ function skipped(skipReason: SessionSegmentDistillationSkipReason): SessionSegmentEvidenceAnalysis {
141
+ return { evidenceWindow: null, skipReason, warnings: [] };
142
+ }
143
+
144
+ function resolveSegmentRoleId(segment: SessionEvidenceSegmentV1): string | null {
145
+ const explicitRoleId = sanitizeOptionalId(segment.roleId);
146
+ if (explicitRoleId !== null) return explicitRoleId;
147
+ // Ordinary non-team sessions still need a bounded role scope for OKF policy. The configured Code
148
+ // Agent target is a real session attribute; unknown targets remain unscoped and cannot auto-accept.
149
+ return segment.target === "unknown" ? null : sanitizeId(segment.target);
150
+ }
151
+
152
+ function createSegmentEvidenceEvent(input: {
153
+ signal: SessionMemorySignal;
154
+ segmentReason: SessionMemorySegmentReason;
155
+ segmentStrength: SessionMemorySignalStrength;
156
+ roleId: string | null;
157
+ sourceRefId: string;
158
+ episodeId: string;
159
+ sequence: number;
160
+ }): EvolutionEvidenceEvent {
161
+ const eventType = normalizeEvolutionEventType(input.signal.eventType);
162
+ const summary =
163
+ sanitizeText(redactSessionMemoryCredentialText(input.signal.summary).value) ||
164
+ "Session metadata signal observed.";
165
+ const kind = classifySegmentSignal(input.signal, summary);
166
+ const baseTrigger = decideEvolutionTrigger({ eventType, summary, kind });
167
+ const segmentTrigger =
168
+ input.signal.reason === "observed"
169
+ ? null
170
+ : classifySegmentTrigger(input.segmentReason, input.segmentStrength);
171
+ const trigger = segmentTrigger ?? baseTrigger;
172
+ return {
173
+ id: `event-${String(input.sequence).padStart(4, "0")}`,
174
+ kind,
175
+ eventType,
176
+ hookEventId: sanitizeOptionalId(input.signal.eventId),
177
+ occurredAt: input.signal.occurredAt,
178
+ summary,
179
+ roleId: input.roleId,
180
+ taskId: null,
181
+ evidenceRef: `${input.sourceRefId}#signal-${input.sequence}`,
182
+ episodeIds: [input.episodeId],
183
+ triggerStrength: trigger.strength,
184
+ triggerReason: trigger.reason,
185
+ rawContentStored: false,
186
+ };
187
+ }
188
+
189
+ function classifySegmentSignal(
190
+ signal: SessionMemorySignal,
191
+ summary: string,
192
+ ): EvolutionEvidenceEventKind {
193
+ const eventType = normalizeEvolutionEventType(signal.eventType);
194
+ if (
195
+ eventType === "StopFailure" ||
196
+ eventType === "PostToolUseFailure" ||
197
+ eventType === "PermissionDenied" ||
198
+ signal.reason === "failure-signal" ||
199
+ signal.reason === "permission-denied"
200
+ ) {
201
+ return "error";
202
+ }
203
+ if (
204
+ signal.reason === "verification-after-fix" ||
205
+ /verify|test|lint|typecheck|build/i.test(summary)
206
+ ) {
207
+ return "verification";
208
+ }
209
+ if (
210
+ signal.reason === "user-interruption" ||
211
+ signal.reason === "intent-refinement" ||
212
+ signal.reason === "explicit-memory-intent"
213
+ ) {
214
+ return "user-feedback";
215
+ }
216
+ if (
217
+ eventType === "PreToolUse" ||
218
+ eventType === "PostToolUse" ||
219
+ eventType === "PermissionRequest" ||
220
+ eventType === "PostToolBatch"
221
+ ) {
222
+ return "tool-call";
223
+ }
224
+ if (eventType === "SubagentStart" || eventType === "SubagentStop") return "subagent";
225
+ if (/skill/i.test(summary)) return "skill-call";
226
+ if (/review/i.test(summary)) return "review";
227
+ if (
228
+ eventType === "SessionStart" ||
229
+ eventType === "SessionEnd" ||
230
+ eventType === "UserPromptSubmit" ||
231
+ eventType === "Stop" ||
232
+ eventType === "TaskCreated" ||
233
+ eventType === "TaskCompleted"
234
+ ) {
235
+ return "run-state";
236
+ }
237
+ return "trace";
238
+ }
239
+
240
+ function classifySegmentTrigger(
241
+ reason: SessionMemorySegmentReason,
242
+ strength: SessionMemorySignalStrength,
243
+ ): { strength: EvolutionTriggerStrength; reason: EvolutionTriggerReason } {
244
+ if (reason === "failure-signal") return { strength: "strong", reason: "failure-signal" };
245
+ if (reason === "permission-denied") return { strength: "strong", reason: "permission-denied" };
246
+ if (reason === "historical-import") {
247
+ return { strength: "strong", reason: "explicit-command" };
248
+ }
249
+ if (reason === "session-memory-init") return { strength: "none", reason: "none" };
250
+ return {
251
+ strength: strength === "strong" ? "strong" : "conditional",
252
+ reason: "explicit-command",
253
+ };
254
+ }
255
+
256
+ function isSegmentEligibleForDistillation(
257
+ segment: SessionEvidenceSegmentV1,
258
+ events: EvolutionEvidenceEvent[],
259
+ ): boolean {
260
+ if (events.length === 0) return false;
261
+ if (
262
+ segment.reason === "user-interruption" ||
263
+ segment.reason === "failure-signal" ||
264
+ segment.reason === "permission-denied" ||
265
+ segment.reason === "verification-after-fix" ||
266
+ segment.reason === "explicit-memory-intent" ||
267
+ segment.reason === "historical-import"
268
+ ) {
269
+ return true;
270
+ }
271
+
272
+ const hasOutcomeSignal =
273
+ segment.normalized.decisions.length > 0 ||
274
+ segment.normalized.failures.length > 0 ||
275
+ segment.normalized.verifications.length > 0 ||
276
+ events.some((event) => event.kind === "error" || event.kind === "verification");
277
+ if (segment.reason === "session-memory-threshold") return hasOutcomeSignal;
278
+ if (segment.reason !== "intent-refinement") return false;
279
+ return (
280
+ hasOutcomeSignal ||
281
+ segment.signals.some(
282
+ (signal) =>
283
+ signal.reason === "explicit-memory-intent" ||
284
+ ["TaskCompleted", "Stop", "SessionEnd", "SubagentStop"].includes(signal.eventType),
285
+ )
286
+ );
287
+ }
@@ -0,0 +1,9 @@
1
+ export const DEFAULT_MAX_RAW_EVENT_BYTES = 64 * 1024;
2
+
3
+ export const EXPLICIT_MEMORY_PATTERN =
4
+ /\b(remember|memorize|do not repeat|don't repeat|this is important|save this|learn this)\b/i;
5
+
6
+ export const FAILURE_PATTERN = /\b(fail|failed|failure|error|issue|exception|crash)\b/i;
7
+
8
+ export const VERIFICATION_PATTERN =
9
+ /\b(test|lint|typecheck|build|verify|verification|passed|success)\b/i;
@@ -0,0 +1,9 @@
1
+ export * from "./analysis.ts";
2
+ export * from "./paths.ts";
3
+ export * from "./policy.ts";
4
+ export * from "./sensitivity.ts";
5
+ export * from "./semantic-packet.ts";
6
+ export * from "./retention.ts";
7
+ export * from "./storage.ts";
8
+ export * from "./types.ts";
9
+ export * from "./updater.ts";
@@ -0,0 +1,29 @@
1
+ import { join } from "node:path";
2
+ import { resolveEvoDevPaths } from "../../../config/paths.ts";
3
+ import { sanitizeStorageId } from "../../../utils/index.ts";
4
+ import type { SessionMemoryPaths } from "./types.ts";
5
+
6
+ export function resolveSessionMemoryPaths(input: {
7
+ homeDir: string;
8
+ projectKey: string;
9
+ sessionKey: string;
10
+ }): SessionMemoryPaths {
11
+ const rootDir = join(resolveEvoDevPaths(input.homeDir).stateDir, "session-memory");
12
+ const projectKey = sanitizeStorageId(input.projectKey, "project");
13
+ const sessionKey = sanitizeStorageId(input.sessionKey, "session");
14
+ const projectDir = join(rootDir, projectKey);
15
+ const sessionDir = join(projectDir, sessionKey);
16
+ const segmentsDir = join(sessionDir, "segments");
17
+ return {
18
+ rootDir,
19
+ projectDir,
20
+ sessionDir,
21
+ statePath: join(sessionDir, "state.json"),
22
+ cursorPath: join(sessionDir, "cursor.json"),
23
+ eventsPath: join(sessionDir, "events.jsonl"),
24
+ segmentsDir,
25
+ segmentPath: (segmentId: string) =>
26
+ join(segmentsDir, `${sanitizeStorageId(segmentId, "segment")}.json`),
27
+ indexPath: join(sessionDir, "index.json"),
28
+ };
29
+ }
@@ -0,0 +1,39 @@
1
+ import { optionalBoolean, positiveInteger } from "../../../utils/index.ts";
2
+ import type { SessionMemoryPolicySnapshot } from "./types.ts";
3
+
4
+ export function createDefaultSessionMemoryPolicy(): SessionMemoryPolicySnapshot {
5
+ return {
6
+ enabled: true,
7
+ storeRawSegments: true,
8
+ maxRawSegmentBytes: 200_000,
9
+ retentionDays: 30,
10
+ minimumMessageTokensToInit: 10_000,
11
+ minimumTokensBetweenUpdate: 5_000,
12
+ toolCallsBetweenUpdates: 9,
13
+ };
14
+ }
15
+
16
+ export function parseSessionMemoryPolicy(
17
+ value: Partial<SessionMemoryPolicySnapshot> | undefined,
18
+ ): SessionMemoryPolicySnapshot {
19
+ const defaults = createDefaultSessionMemoryPolicy();
20
+ if (value === undefined) return defaults;
21
+ return {
22
+ enabled: optionalBoolean(value.enabled, defaults.enabled),
23
+ storeRawSegments: optionalBoolean(value.storeRawSegments, defaults.storeRawSegments),
24
+ maxRawSegmentBytes: positiveInteger(value.maxRawSegmentBytes, defaults.maxRawSegmentBytes),
25
+ retentionDays: positiveInteger(value.retentionDays, defaults.retentionDays),
26
+ minimumMessageTokensToInit: positiveInteger(
27
+ value.minimumMessageTokensToInit,
28
+ defaults.minimumMessageTokensToInit,
29
+ ),
30
+ minimumTokensBetweenUpdate: positiveInteger(
31
+ value.minimumTokensBetweenUpdate,
32
+ defaults.minimumTokensBetweenUpdate,
33
+ ),
34
+ toolCallsBetweenUpdates: positiveInteger(
35
+ value.toolCallsBetweenUpdates,
36
+ defaults.toolCallsBetweenUpdates,
37
+ ),
38
+ };
39
+ }