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

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 (41) 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 +249 -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/workflows/rd-bug-fix/WORKFLOW.json +1 -1
  8. package/assets/workflows/rd-code-review/WORKFLOW.json +1 -1
  9. package/assets/workflows/rd-docs-update/WORKFLOW.json +1 -1
  10. package/assets/workflows/rd-feature-implementation/WORKFLOW.json +1 -1
  11. package/assets/workflows/rd-refactor/WORKFLOW.json +1 -1
  12. package/assets/workflows/rd-release-readiness/WORKFLOW.json +1 -1
  13. package/assets/workflows/rd-security-boundary-review/WORKFLOW.json +2 -2
  14. package/assets/workflows/rd-test-generation/WORKFLOW.json +1 -1
  15. package/dist/config/index.js +968 -39
  16. package/dist/index.js +10914 -1476
  17. package/dist/plugins/index.js +32 -32
  18. package/package.json +5 -1
  19. package/src/agents/index.ts +84 -49
  20. package/src/code-agent-traces/index.ts +521 -0
  21. package/src/config/index.ts +5 -0
  22. package/src/config/paths.ts +30 -0
  23. package/src/config/settings.ts +130 -0
  24. package/src/config/store.ts +152 -0
  25. package/src/daemon/index.ts +465 -3
  26. package/src/evolution/index.ts +2827 -0
  27. package/src/hooks/index.ts +543 -247
  28. package/src/index.ts +6 -0
  29. package/src/knowledge/index.ts +4784 -0
  30. package/src/pack/index.ts +13 -13
  31. package/src/plugins/capabilities.ts +40 -42
  32. package/src/plugins/index.ts +0 -1
  33. package/src/plugins/types.ts +4 -0
  34. package/src/protected-zones/index.ts +29 -11
  35. package/src/runtime-logs/index.ts +798 -0
  36. package/src/sync/orchestrator.ts +6 -0
  37. package/src/task/index.ts +3 -3
  38. package/src/team/index.ts +3069 -0
  39. package/src/team/mcp.ts +405 -0
  40. package/src/team/prompts.ts +141 -0
  41. package/src/workflow/index.ts +6 -6
@@ -1,5 +1,7 @@
1
+ import { readFile } from "node:fs/promises";
1
2
  import { type HookSettings, createDefaultHookSettings, parseHookSettings } from "../hooks/index.ts";
2
3
  import { EvoDevConfigError, describeType } from "./errors.ts";
4
+ import { resolveEvoDevPaths } from "./paths.ts";
3
5
 
4
6
  export interface PluginSettings {
5
7
  enabled: boolean;
@@ -7,6 +9,13 @@ export interface PluginSettings {
7
9
  autoSyncAgents?: boolean;
8
10
  }
9
11
 
12
+ export interface MemorySettings {
13
+ autoAccept: boolean;
14
+ runtimeInjection: boolean;
15
+ staleReview: boolean;
16
+ lexicalIndex: boolean;
17
+ }
18
+
10
19
  export interface EvoDevSettings {
11
20
  version: 1;
12
21
  platform: {
@@ -28,6 +37,8 @@ export interface EvoDevSettings {
28
37
  lastRunAt: string | null;
29
38
  };
30
39
  hooks: HookSettings;
40
+ teamRuntime: TeamRuntimeSettings;
41
+ memory: MemorySettings;
31
42
  }
32
43
 
33
44
  export type SettingsInput = Partial<{
@@ -43,8 +54,18 @@ export type SettingsInput = Partial<{
43
54
  }>;
44
55
  doctor: Partial<EvoDevSettings["doctor"]>;
45
56
  hooks: unknown;
57
+ teamRuntime: Partial<TeamRuntimeSettings>;
58
+ memory: Partial<MemorySettings>;
46
59
  }>;
47
60
 
61
+ export interface TeamRuntimeSettings {
62
+ defaultRuntime: "codex" | "claude";
63
+ defaultModel: string | null;
64
+ defaultThinkingLevel: string | null;
65
+ recordTranscript: boolean;
66
+ displayMode: "normal" | "development";
67
+ }
68
+
48
69
  export function createDefaultSettings(os: string = process.platform): EvoDevSettings {
49
70
  return {
50
71
  version: 1,
@@ -73,6 +94,27 @@ export function createDefaultSettings(os: string = process.platform): EvoDevSett
73
94
  lastRunAt: null,
74
95
  },
75
96
  hooks: createDefaultHookSettings(),
97
+ teamRuntime: createDefaultTeamRuntimeSettings(),
98
+ memory: createDefaultMemorySettings(),
99
+ };
100
+ }
101
+
102
+ export function createDefaultTeamRuntimeSettings(): TeamRuntimeSettings {
103
+ return {
104
+ defaultRuntime: "codex",
105
+ defaultModel: null,
106
+ defaultThinkingLevel: null,
107
+ recordTranscript: false,
108
+ displayMode: "normal",
109
+ };
110
+ }
111
+
112
+ export function createDefaultMemorySettings(): MemorySettings {
113
+ return {
114
+ autoAccept: true,
115
+ runtimeInjection: true,
116
+ staleReview: true,
117
+ lexicalIndex: true,
76
118
  };
77
119
  }
78
120
 
@@ -112,11 +154,29 @@ export function mergeSettings(
112
154
  ...existing.doctor,
113
155
  },
114
156
  hooks: existing.hooks ?? defaults.hooks,
157
+ teamRuntime: {
158
+ ...defaults.teamRuntime,
159
+ ...existing.teamRuntime,
160
+ },
161
+ memory: {
162
+ ...defaults.memory,
163
+ ...existing.memory,
164
+ },
115
165
  };
116
166
 
117
167
  return parseSettings(merged);
118
168
  }
119
169
 
170
+ export async function readRuntimeInjectionSettings(homeDir?: string): Promise<MemorySettings> {
171
+ const paths = resolveEvoDevPaths(homeDir);
172
+ try {
173
+ return parseSettings(JSON.parse(await readFile(paths.settingsPath, "utf8"))).memory;
174
+ } catch (error) {
175
+ if (isNotFoundError(error)) return createDefaultMemorySettings();
176
+ throw error;
177
+ }
178
+ }
179
+
120
180
  export function parseSettings(value: unknown): EvoDevSettings {
121
181
  const root = expectRecord(value, "settings");
122
182
  const version = root.version;
@@ -157,11 +217,75 @@ export function parseSettings(value: unknown): EvoDevSettings {
157
217
  lastRunAt: expectNullableString(doctor.lastRunAt, "settings.doctor.lastRunAt"),
158
218
  },
159
219
  hooks: parseHookSettings(root.hooks),
220
+ teamRuntime: parseTeamRuntimeSettings(
221
+ root.teamRuntime ?? createDefaultTeamRuntimeSettings(),
222
+ "settings.teamRuntime",
223
+ ),
224
+ memory: parseMemorySettings(root.memory ?? createDefaultMemorySettings(), "settings.memory"),
160
225
  };
161
226
 
162
227
  return parsed;
163
228
  }
164
229
 
230
+ function parseMemorySettings(value: unknown, path: string): MemorySettings {
231
+ const input = expectRecord(value, path);
232
+ const defaults = createDefaultMemorySettings();
233
+ return {
234
+ autoAccept:
235
+ input.autoAccept === undefined
236
+ ? defaults.autoAccept
237
+ : expectBoolean(input.autoAccept, `${path}.autoAccept`),
238
+ runtimeInjection:
239
+ input.runtimeInjection === undefined
240
+ ? defaults.runtimeInjection
241
+ : expectBoolean(input.runtimeInjection, `${path}.runtimeInjection`),
242
+ staleReview:
243
+ input.staleReview === undefined
244
+ ? defaults.staleReview
245
+ : expectBoolean(input.staleReview, `${path}.staleReview`),
246
+ lexicalIndex:
247
+ input.lexicalIndex === undefined
248
+ ? defaults.lexicalIndex
249
+ : expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`),
250
+ };
251
+ }
252
+
253
+ function parseTeamRuntimeSettings(value: unknown, path: string): TeamRuntimeSettings {
254
+ const input = expectRecord(value, path);
255
+ const defaults = createDefaultTeamRuntimeSettings();
256
+ const defaultRuntime = input.defaultRuntime ?? defaults.defaultRuntime;
257
+ if (defaultRuntime !== "codex" && defaultRuntime !== "claude") {
258
+ throw new EvoDevConfigError(`Invalid ${path}.defaultRuntime; expected codex or claude`);
259
+ }
260
+
261
+ return {
262
+ defaultRuntime,
263
+ defaultModel:
264
+ input.defaultModel === undefined
265
+ ? defaults.defaultModel
266
+ : expectNullableString(input.defaultModel, `${path}.defaultModel`),
267
+ defaultThinkingLevel:
268
+ input.defaultThinkingLevel === undefined
269
+ ? defaults.defaultThinkingLevel
270
+ : expectNullableString(input.defaultThinkingLevel, `${path}.defaultThinkingLevel`),
271
+ recordTranscript:
272
+ input.recordTranscript === undefined
273
+ ? defaults.recordTranscript
274
+ : expectBoolean(input.recordTranscript, `${path}.recordTranscript`),
275
+ displayMode: parseTeamRuntimeDisplayMode(input.displayMode, defaults.displayMode, path),
276
+ };
277
+ }
278
+
279
+ function parseTeamRuntimeDisplayMode(
280
+ value: unknown,
281
+ fallback: TeamRuntimeSettings["displayMode"],
282
+ path: string,
283
+ ): TeamRuntimeSettings["displayMode"] {
284
+ if (value === undefined) return fallback;
285
+ if (value === "normal" || value === "development") return value;
286
+ throw new EvoDevConfigError(`Invalid ${path}.displayMode; expected normal or development`);
287
+ }
288
+
165
289
  function parsePluginSettings(value: unknown, path: string): PluginSettings {
166
290
  const input = expectRecord(value, path);
167
291
  const parsed: PluginSettings = {
@@ -187,6 +311,12 @@ function expectRecord(value: unknown, path: string): Record<string, unknown> {
187
311
  return value as Record<string, unknown>;
188
312
  }
189
313
 
314
+ function isNotFoundError(error: unknown): boolean {
315
+ return (
316
+ error instanceof Error && "code" in error && (error as NodeJS.ErrnoException).code === "ENOENT"
317
+ );
318
+ }
319
+
190
320
  function expectString(value: unknown, path: string): string {
191
321
  if (typeof value !== "string" || value.length === 0) {
192
322
  throw new EvoDevConfigError(`Invalid ${path}; expected non-empty string`);
@@ -1,5 +1,6 @@
1
1
  import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import { dirname } from "node:path";
3
+ import { ensureOkfKnowledgeBase } from "../knowledge/index.ts";
3
4
  import { EvoDevConfigError } from "./errors.ts";
4
5
  import { type EvoDevPaths, resolveEvoDevPaths } from "./paths.ts";
5
6
  import { type EvoDevRegistry, createDefaultRegistry, parseRegistry } from "./registry.ts";
@@ -22,6 +23,7 @@ import {
22
23
  export interface CoreConfigStore {
23
24
  readonly paths: EvoDevPaths;
24
25
  ensureBaseDirs(): Promise<void>;
26
+ ensureKnowledgeBase(): Promise<void>;
25
27
  readSettings(): Promise<EvoDevSettings>;
26
28
  writeSettings(settings: EvoDevSettings): Promise<void>;
27
29
  mergeAndWriteSettings(input: SettingsInput): Promise<EvoDevSettings>;
@@ -40,6 +42,15 @@ export function createCoreConfigStore(homeDir?: string): CoreConfigStore {
40
42
  paths,
41
43
  async ensureBaseDirs() {
42
44
  await mkdir(paths.stateDir, { recursive: true });
45
+ await mkdir(paths.logsDir, { recursive: true });
46
+ await mkdir(paths.knowledgeDir, { recursive: true });
47
+ await mkdir(paths.evosCasesDir, { recursive: true });
48
+ await mkdir(paths.roleAgentsDir, { recursive: true });
49
+ await mkdir(paths.teamsDir, { recursive: true });
50
+ await mkdir(paths.runsDir, { recursive: true });
51
+ },
52
+ async ensureKnowledgeBase() {
53
+ await ensureKnowledgeBaseFiles(paths);
43
54
  },
44
55
  async readSettings() {
45
56
  return readJsonFile(paths.settingsPath, parseSettings);
@@ -81,6 +92,7 @@ export function createCoreConfigStore(homeDir?: string): CoreConfigStore {
81
92
  export async function initializeCoreConfig(homeDir?: string): Promise<CoreConfigStore> {
82
93
  const store = createCoreConfigStore(homeDir);
83
94
  await store.ensureBaseDirs();
95
+ await store.ensureKnowledgeBase();
84
96
  await writeIfMissing(store.paths.settingsPath, createDefaultSettings());
85
97
  await writeIfMissing(store.paths.registryPath, createDefaultRegistry());
86
98
  await writeIfMissing(store.paths.installStatePath, createDefaultInstallState());
@@ -88,6 +100,88 @@ export async function initializeCoreConfig(homeDir?: string): Promise<CoreConfig
88
100
  return store;
89
101
  }
90
102
 
103
+ export async function ensureKnowledgeBaseFiles(paths: EvoDevPaths): Promise<void> {
104
+ await mkdir(paths.knowledgeDir, { recursive: true });
105
+ await mkdir(paths.evosCasesDir, { recursive: true });
106
+ await ensureOkfKnowledgeBase(paths.homeDir);
107
+ await writeTextIfMissing(
108
+ `${paths.knowledgeDir}/README.md`,
109
+ [
110
+ "# EvoDev Knowledge",
111
+ "",
112
+ "Local-private knowledge base for user-accepted facts, decisions, architecture notes, and reusable domain context.",
113
+ "",
114
+ "EvoDev must not populate this directory from source code, prompts, command output, logs, or transcripts without an explicit consent flow.",
115
+ "",
116
+ ].join("\n"),
117
+ );
118
+ await writeIndexIfMissingOrMigrate(paths.knowledgeIndexPath, "knowledge-index", {
119
+ version: 1,
120
+ kind: "knowledge-index",
121
+ roleTags: [],
122
+ entries: [],
123
+ });
124
+ await writeTextIfMissing(
125
+ `${paths.evosDir}/README.md`,
126
+ [
127
+ "# EvoDev Evos",
128
+ "",
129
+ "Local-private evolution case library for reviewed improvement cases and reusable process changes.",
130
+ "",
131
+ "Cases start empty. Future automation may propose candidates, but accepted evos require explicit review before they can influence workflows or routing.",
132
+ "",
133
+ ].join("\n"),
134
+ );
135
+ await writeTextIfMissing(
136
+ `${paths.evosCasesDir}/README.md`,
137
+ [
138
+ "# Evolution Cases",
139
+ "",
140
+ "Store one reviewed evolution case per file. Do not store raw prompts, source dumps, secrets, transcripts, or raw command output here.",
141
+ "",
142
+ ].join("\n"),
143
+ );
144
+ await writeIndexIfMissingOrMigrate(paths.evosIndexPath, "evos-index", {
145
+ version: 1,
146
+ kind: "evos-index",
147
+ roleTags: [],
148
+ cases: [],
149
+ });
150
+ await writeTextIfMissing(
151
+ `${paths.roleAgentsDir}/README.md`,
152
+ [
153
+ "# Role Agents",
154
+ "",
155
+ "Local-private role agent registry for EvoDev-managed agent roles and user-reviewed role extensions.",
156
+ "",
157
+ "Repository-specific role agents should be proposed first and written into a user repository only after explicit project opt-in.",
158
+ "",
159
+ ].join("\n"),
160
+ );
161
+ await writeIndexIfMissingOrMigrate(paths.roleAgentsIndexPath, "role-agent-index", {
162
+ version: 1,
163
+ kind: "role-agent-index",
164
+ roles: [],
165
+ projectExtensions: [],
166
+ });
167
+ await writeTextIfMissing(
168
+ `${paths.teamsDir}/README.md`,
169
+ [
170
+ "# Agent Teams",
171
+ "",
172
+ "Local-private EvoHub team registry for reviewed role-agent team definitions.",
173
+ "",
174
+ "Teams may reference role agents and role-tagged knowledge, but they must not contain raw source, prompts, transcripts, secrets, or raw command output.",
175
+ "",
176
+ ].join("\n"),
177
+ );
178
+ await writeIndexIfMissingOrMigrate(paths.teamsIndexPath, "agent-team-index", {
179
+ version: 1,
180
+ kind: "agent-team-index",
181
+ teams: [],
182
+ });
183
+ }
184
+
91
185
  async function readJsonFile<T>(filePath: string, parse: (value: unknown) => T): Promise<T> {
92
186
  let raw: string;
93
187
 
@@ -148,6 +242,60 @@ async function writeIfMissing(filePath: string, value: unknown): Promise<void> {
148
242
  }
149
243
  }
150
244
 
245
+ async function writeIndexIfMissingOrMigrate(
246
+ filePath: string,
247
+ kind: string,
248
+ defaults: Record<string, unknown>,
249
+ ): Promise<void> {
250
+ let raw: string;
251
+ try {
252
+ raw = await readFile(filePath, "utf8");
253
+ } catch (error) {
254
+ if (isNodeError(error) && error.code === "ENOENT") {
255
+ await writeJsonFile(filePath, defaults);
256
+ return;
257
+ }
258
+
259
+ throw new EvoDevConfigError(
260
+ `Cannot inspect config file (${describeFileError(error)})`,
261
+ filePath,
262
+ );
263
+ }
264
+
265
+ let existing: unknown;
266
+ try {
267
+ existing = JSON.parse(raw);
268
+ } catch (error) {
269
+ throw new EvoDevConfigError(
270
+ `Invalid bootstrap index JSON (${describeFileError(error)})`,
271
+ filePath,
272
+ );
273
+ }
274
+
275
+ if (!isRecord(existing) || existing.kind !== kind) return;
276
+
277
+ const migrated = { ...defaults, ...existing };
278
+ if (Object.keys(defaults).every((key) => key in existing)) return;
279
+ await writeJsonFile(filePath, migrated);
280
+ }
281
+
282
+ async function writeTextIfMissing(filePath: string, value: string): Promise<void> {
283
+ try {
284
+ await readFile(filePath, "utf8");
285
+ } catch (error) {
286
+ if (isNodeError(error) && error.code === "ENOENT") {
287
+ await mkdir(dirname(filePath), { recursive: true });
288
+ await writeFile(filePath, value, "utf8");
289
+ return;
290
+ }
291
+
292
+ throw new EvoDevConfigError(
293
+ `Cannot inspect config file (${describeFileError(error)})`,
294
+ filePath,
295
+ );
296
+ }
297
+ }
298
+
151
299
  async function writeJsonFile(filePath: string, value: unknown): Promise<void> {
152
300
  await mkdir(dirname(filePath), { recursive: true });
153
301
  await writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
@@ -164,3 +312,7 @@ function describeFileError(error: unknown): string {
164
312
  function isNodeError(error: unknown): error is NodeJS.ErrnoException {
165
313
  return error instanceof Error && "code" in error;
166
314
  }
315
+
316
+ function isRecord(value: unknown): value is Record<string, unknown> {
317
+ return typeof value === "object" && value !== null && !Array.isArray(value);
318
+ }