@evo-dev/core 0.0.1-alpha.1 → 0.0.1-alpha.11

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 (66) hide show
  1. package/assets/skills/coding/knowledge-distillation/SKILL.md +117 -114
  2. package/assets/skills/coding/knowledge-distillation/references/knowledge-distillation-methods.md +11 -7
  3. package/assets/team/agents/code-reviewer.md +48 -0
  4. package/assets/team/agents/docs-maintainer.md +51 -0
  5. package/assets/team/agents/implementation-engineer.md +51 -0
  6. package/assets/team/agents/product-scope-analyst.md +58 -0
  7. package/assets/team/agents/release-engineer.md +55 -0
  8. package/assets/team/agents/security-boundary-reviewer.md +50 -0
  9. package/assets/team/agents/solution-architect.md +51 -0
  10. package/assets/team/agents/verification-engineer.md +51 -0
  11. package/assets/team/team.md +102 -0
  12. package/dist/config/index.js +925 -97
  13. package/dist/index.js +13107 -5618
  14. package/package.json +5 -1
  15. package/src/agents/index.ts +56 -264
  16. package/src/code-agent-traces/index.ts +520 -0
  17. package/src/config/index.ts +5 -0
  18. package/src/config/paths.ts +1 -1
  19. package/src/config/settings.ts +149 -0
  20. package/src/config/store.ts +2 -0
  21. package/src/daemon/index.ts +99 -50
  22. package/src/evolution/candidates/index.ts +564 -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 +281 -0
  27. package/src/evolution/evidence/session-memory/constants.ts +9 -0
  28. package/src/evolution/evidence/session-memory/index.ts +7 -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/segment.ts +202 -0
  32. package/src/evolution/evidence/session-memory/sensitivity.ts +335 -0
  33. package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
  34. package/src/evolution/evidence/session-memory/storage.ts +379 -0
  35. package/src/evolution/evidence/session-memory/types.ts +221 -0
  36. package/src/evolution/evidence/session-memory/updater.ts +191 -0
  37. package/src/evolution/formatters.ts +169 -0
  38. package/src/evolution/index.ts +16 -2356
  39. package/src/evolution/knowledge/index.ts +5427 -0
  40. package/src/evolution/paths.ts +44 -0
  41. package/src/evolution/processor/distillation.ts +518 -0
  42. package/src/evolution/processor/index.ts +3 -0
  43. package/src/evolution/processor/process.ts +528 -0
  44. package/src/{learning → evolution/review}/index.ts +10 -14
  45. package/src/evolution/schema.ts +568 -0
  46. package/src/evolution/shared.ts +758 -0
  47. package/src/evolution/triggers/classification.ts +102 -0
  48. package/src/evolution/triggers/index.ts +295 -0
  49. package/src/hooks/index.ts +438 -179
  50. package/src/index.ts +12 -3
  51. package/src/projects/index.ts +453 -0
  52. package/src/runtime-logs/index.ts +490 -24
  53. package/src/team/index.ts +1429 -185
  54. package/src/team/mcp.ts +9 -5
  55. package/src/team/prompts.ts +141 -0
  56. package/src/utils/errors.ts +13 -0
  57. package/src/utils/fs.ts +40 -0
  58. package/src/utils/hash.ts +9 -0
  59. package/src/utils/ids.ts +12 -0
  60. package/src/utils/index.ts +7 -0
  61. package/src/utils/parsing.ts +11 -0
  62. package/src/utils/text.ts +18 -0
  63. package/src/utils/time.ts +5 -0
  64. package/src/workflow/index.ts +3 -21
  65. package/src/project/index.ts +0 -507
  66. package/src/task/index.ts +0 -840
@@ -1,507 +0,0 @@
1
- import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
2
- import { basename, join, relative } from "node:path";
3
-
4
- export const PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS = [
5
- ".evodev/project.json",
6
- ".evodev/profile.md",
7
- ".evodev/index.json",
8
- ".evodev/commands.json",
9
- ".evodev/privacy.json",
10
- ".evodev/decisions/README.md",
11
- ] as const;
12
-
13
- export type ProjectContextAllowedRelativePath =
14
- (typeof PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS)[number];
15
-
16
- export type ProjectContextPlanAction = "create" | "error";
17
-
18
- export interface ProjectContextPlanEntry {
19
- relativePath: ProjectContextAllowedRelativePath;
20
- absolutePath: string;
21
- action: ProjectContextPlanAction;
22
- reason: string;
23
- }
24
-
25
- export interface ProjectContextPlan {
26
- projectDir: string;
27
- projectId: string;
28
- files: ProjectContextPlanEntry[];
29
- index: ProjectIndex;
30
- commands: ProjectCommands;
31
- privacy: ProjectPrivacy;
32
- warnings: string[];
33
- errors: string[];
34
- }
35
-
36
- export interface ProjectProfile {
37
- version: 1;
38
- projectId: string;
39
- displayName: string;
40
- root: {
41
- pathPolicy: "local-only";
42
- };
43
- privacy: {
44
- classification: "local-private";
45
- metadataOnly: true;
46
- sourceContentIncluded: false;
47
- rawCommandsIncluded: false;
48
- };
49
- }
50
-
51
- export interface ProjectIndex {
52
- version: 1;
53
- mode: "metadata-only";
54
- projectId: string;
55
- generatedAt: null;
56
- rootName: string;
57
- files: ProjectFileMetadata[];
58
- docs: {
59
- entrypoints: string[];
60
- };
61
- commands: {
62
- scripts: ProjectScriptSummary[];
63
- testCommandCandidates: string[];
64
- };
65
- exclusions: string[];
66
- sourceContentIncluded: false;
67
- }
68
-
69
- export interface ProjectFileMetadata {
70
- path: string;
71
- kind: "file" | "directory";
72
- sizeBytes?: number;
73
- }
74
-
75
- export interface ProjectCommands {
76
- version: 1;
77
- metadataOnly: true;
78
- rawCommandsIncluded: false;
79
- scripts: ProjectScriptSummary[];
80
- warnings: string[];
81
- }
82
-
83
- export interface ProjectScriptSummary {
84
- name: string;
85
- commandClass: ProjectCommandClass;
86
- summary: string;
87
- rawCommandStored: false;
88
- redacted: boolean;
89
- warning?: string;
90
- }
91
-
92
- export type ProjectCommandClass =
93
- | "build"
94
- | "format"
95
- | "install"
96
- | "lint"
97
- | "other"
98
- | "release"
99
- | "test"
100
- | "typecheck";
101
-
102
- export interface ProjectPrivacy {
103
- version: 1;
104
- classification: "local-private";
105
- metadataOnly: true;
106
- sourceContentIndex: false;
107
- promptHistoryIndex: false;
108
- shellHistoryIndex: false;
109
- rawCommandOutputIndex: false;
110
- externalUpload: false;
111
- excludedGlobs: string[];
112
- protectedPatterns: string[];
113
- }
114
-
115
- export interface WriteProjectContextResult {
116
- writtenFiles: ProjectContextAllowedRelativePath[];
117
- }
118
-
119
- const EXCLUDED_DIRECTORY_NAMES = new Set([
120
- ".git",
121
- ".claude",
122
- ".codex",
123
- "backups",
124
- "build",
125
- "coverage",
126
- "dist",
127
- "node_modules",
128
- ]);
129
-
130
- const EXCLUDED_FILE_PREFIXES = [".env"];
131
- const EXCLUDED_FILE_PARTS = [
132
- "api-key",
133
- "api_key",
134
- "apikey",
135
- "credential",
136
- "credentials",
137
- "internal",
138
- "internal-link",
139
- "password",
140
- "passwords",
141
- "passwd",
142
- "private",
143
- "private-url",
144
- "secret",
145
- "token",
146
- ];
147
- const EXCLUDED_FILE_EXTENSIONS = [".key", ".pem", ".p12", ".pfx"];
148
- const DOC_ENTRYPOINTS = new Set(["README.md"]);
149
- const DEFAULT_EXCLUDED_GLOBS = [
150
- ".git/**",
151
- "node_modules/**",
152
- "dist/**",
153
- "build/**",
154
- "coverage/**",
155
- ".env*",
156
- "**/*secret*",
157
- "**/*token*",
158
- "**/*password*",
159
- "**/*passwd*",
160
- "**/*api-key*",
161
- "**/*api_key*",
162
- "**/*apikey*",
163
- "**/*credential*",
164
- "**/*private*",
165
- "**/*internal*",
166
- "**/*.key",
167
- "**/*.pem",
168
- ".claude/**",
169
- ".codex/**",
170
- ".evodev/backups/**",
171
- ];
172
- const PROTECTED_PATTERNS = [
173
- "secret",
174
- "token",
175
- "password",
176
- "passwd",
177
- "api-key",
178
- "credential",
179
- "private",
180
- "private-url",
181
- "internal",
182
- "internal-link",
183
- ];
184
-
185
- export async function createProjectContextPlan(projectDir: string): Promise<ProjectContextPlan> {
186
- const projectDirStat = await stat(projectDir);
187
- if (!projectDirStat.isDirectory()) {
188
- throw new Error(`Project dir is not a directory: ${projectDir}`);
189
- }
190
-
191
- const projectId = createProjectId(projectDir);
192
- const privacy = createProjectPrivacy();
193
- const files = await collectProjectFileMetadata(projectDir);
194
- const commands = await collectProjectCommands(projectDir);
195
- const docs = files
196
- .filter((file) => file.kind === "file" && DOC_ENTRYPOINTS.has(basename(file.path)))
197
- .map((file) => file.path)
198
- .sort();
199
- const index: ProjectIndex = {
200
- version: 1,
201
- mode: "metadata-only",
202
- projectId,
203
- generatedAt: null,
204
- rootName: basename(projectDir),
205
- files,
206
- docs: { entrypoints: docs },
207
- commands: {
208
- scripts: commands.scripts,
209
- testCommandCandidates: commands.scripts
210
- .filter((script) => script.commandClass === "test")
211
- .map((script) => script.name),
212
- },
213
- exclusions: privacy.excludedGlobs,
214
- sourceContentIncluded: false,
215
- };
216
- const planFiles = await Promise.all(
217
- PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS.map(async (relativePath) => {
218
- const absolutePath = join(projectDir, relativePath);
219
- const exists = await pathExists(absolutePath);
220
- return {
221
- relativePath,
222
- absolutePath,
223
- action: exists ? "error" : "create",
224
- reason: exists
225
- ? "Target already exists; I1 does not overwrite."
226
- : "Allowed project context file.",
227
- } satisfies ProjectContextPlanEntry;
228
- }),
229
- );
230
- const errors = planFiles
231
- .filter((file) => file.action === "error")
232
- .map((file) => `${file.relativePath}: ${file.reason}`);
233
-
234
- return {
235
- projectDir,
236
- projectId,
237
- files: planFiles,
238
- index,
239
- commands,
240
- privacy,
241
- warnings: commands.warnings,
242
- errors,
243
- };
244
- }
245
-
246
- export async function writeProjectContext(
247
- plan: ProjectContextPlan,
248
- ): Promise<WriteProjectContextResult> {
249
- if (plan.errors.length > 0) {
250
- throw new Error(`Cannot write project context:\n${plan.errors.join("\n")}`);
251
- }
252
-
253
- const payloads = createProjectContextPayloads(plan);
254
- const writtenFiles: ProjectContextAllowedRelativePath[] = [];
255
-
256
- for (const relativePath of PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS) {
257
- const content = payloads[relativePath];
258
- const absolutePath = join(plan.projectDir, relativePath);
259
- await mkdir(join(absolutePath, ".."), { recursive: true });
260
- await writeFile(absolutePath, content, { encoding: "utf8", flag: "wx" });
261
- writtenFiles.push(relativePath);
262
- }
263
-
264
- return { writtenFiles };
265
- }
266
-
267
- export function formatProjectContextPlan(
268
- plan: ProjectContextPlan,
269
- mode: "dry-run" | "write",
270
- ): string {
271
- return [
272
- "EvoDev project init",
273
- "",
274
- `Mode: ${mode}`,
275
- `Project: ${plan.projectDir}`,
276
- `Project id: ${plan.projectId}`,
277
- "",
278
- "Plan:",
279
- ...plan.files.map((file) => ` - ${file.action}: ${file.relativePath} (${file.reason})`),
280
- "",
281
- "Metadata-only index summary:",
282
- ` - files: ${plan.index.files.filter((file) => file.kind === "file").length}`,
283
- ` - directories: ${plan.index.files.filter((file) => file.kind === "directory").length}`,
284
- ` - docs: ${plan.index.docs.entrypoints.length}`,
285
- ` - package scripts: ${plan.commands.scripts.length}`,
286
- ...plan.warnings.map((warning) => `Warning: ${warning}`),
287
- ...plan.errors.map((error) => `Error: ${error}`),
288
- ].join("\n");
289
- }
290
-
291
- function createProjectContextPayloads(
292
- plan: ProjectContextPlan,
293
- ): Record<ProjectContextAllowedRelativePath, string> {
294
- const profile: ProjectProfile = {
295
- version: 1,
296
- projectId: plan.projectId,
297
- displayName: basename(plan.projectDir),
298
- root: { pathPolicy: "local-only" },
299
- privacy: {
300
- classification: "local-private",
301
- metadataOnly: true,
302
- sourceContentIncluded: false,
303
- rawCommandsIncluded: false,
304
- },
305
- };
306
-
307
- return {
308
- ".evodev/project.json": `${JSON.stringify(profile, null, 2)}\n`,
309
- ".evodev/profile.md": createProfileMarkdown(plan),
310
- ".evodev/index.json": `${JSON.stringify(plan.index, null, 2)}\n`,
311
- ".evodev/commands.json": `${JSON.stringify(plan.commands, null, 2)}\n`,
312
- ".evodev/privacy.json": `${JSON.stringify(plan.privacy, null, 2)}\n`,
313
- ".evodev/decisions/README.md": "# Project Decisions\n\nRecord project decisions here.\n",
314
- };
315
- }
316
-
317
- function createProfileMarkdown(plan: ProjectContextPlan): string {
318
- return [
319
- `# ${basename(plan.projectDir)} Project Context`,
320
- "",
321
- "This project context was generated as metadata-only local state.",
322
- "",
323
- `- Project id: ${plan.projectId}`,
324
- "- Source content included: false",
325
- "- Raw package script commands included: false",
326
- "- External upload: false",
327
- "",
328
- ].join("\n");
329
- }
330
-
331
- async function collectProjectFileMetadata(projectDir: string): Promise<ProjectFileMetadata[]> {
332
- const files: ProjectFileMetadata[] = [];
333
-
334
- async function visit(dir: string): Promise<void> {
335
- const entries = await readdir(dir, { withFileTypes: true });
336
-
337
- for (const entry of entries) {
338
- const absolutePath = join(dir, entry.name);
339
- const relativePath = relative(projectDir, absolutePath).replaceAll("\\", "/");
340
- if (shouldExcludePath(relativePath, entry.isDirectory())) {
341
- continue;
342
- }
343
-
344
- if (entry.isDirectory()) {
345
- files.push({ path: relativePath, kind: "directory" });
346
- await visit(absolutePath);
347
- continue;
348
- }
349
-
350
- if (entry.isFile()) {
351
- const fileStat = await stat(absolutePath);
352
- files.push({ path: relativePath, kind: "file", sizeBytes: fileStat.size });
353
- }
354
- }
355
- }
356
-
357
- await visit(projectDir);
358
- return files.sort((left, right) => left.path.localeCompare(right.path));
359
- }
360
-
361
- async function collectProjectCommands(projectDir: string): Promise<ProjectCommands> {
362
- const packageJsonPath = join(projectDir, "package.json");
363
- const warnings: string[] = [];
364
-
365
- if (!(await pathExists(packageJsonPath))) {
366
- return { version: 1, metadataOnly: true, rawCommandsIncluded: false, scripts: [], warnings };
367
- }
368
-
369
- let parsed: unknown;
370
- try {
371
- parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
372
- } catch (error) {
373
- warnings.push(`package.json scripts skipped: ${describeError(error)}`);
374
- return { version: 1, metadataOnly: true, rawCommandsIncluded: false, scripts: [], warnings };
375
- }
376
-
377
- const scripts = isRecord(parsed) && isRecord(parsed.scripts) ? parsed.scripts : {};
378
- const summaries: ProjectScriptSummary[] = [];
379
-
380
- for (const [name, value] of Object.entries(scripts).sort(([left], [right]) =>
381
- left.localeCompare(right),
382
- )) {
383
- if (typeof value !== "string") {
384
- continue;
385
- }
386
-
387
- const commandClass = classifyScript(name, value);
388
- const sensitiveReason = detectSensitiveScript(`${name} ${value}`);
389
- if (sensitiveReason !== null) {
390
- const safeName = `redacted-${commandClass}-script`;
391
- const warning = `Protected ${commandClass} script name/command omitted because it matched protected pattern: ${sensitiveReason}.`;
392
- warnings.push(warning);
393
- summaries.push({
394
- name: safeName,
395
- commandClass,
396
- summary: `Protected ${commandClass} script name/command omitted.`,
397
- rawCommandStored: false,
398
- redacted: true,
399
- warning,
400
- });
401
- continue;
402
- }
403
-
404
- summaries.push({
405
- name,
406
- commandClass,
407
- summary: `Safe ${commandClass} script command summary only.`,
408
- rawCommandStored: false,
409
- redacted: false,
410
- });
411
- }
412
-
413
- return {
414
- version: 1,
415
- metadataOnly: true,
416
- rawCommandsIncluded: false,
417
- scripts: summaries,
418
- warnings,
419
- };
420
- }
421
-
422
- function classifyScript(name: string, command: string): ProjectCommandClass {
423
- const text = `${name} ${command}`.toLowerCase();
424
- if (text.includes("typecheck") || text.includes("tsc")) return "typecheck";
425
- if (text.includes("lint") || text.includes("biome") || text.includes("eslint")) return "lint";
426
- if (text.includes("test")) return "test";
427
- if (text.includes("build")) return "build";
428
- if (text.includes("format") || text.includes("prettier")) return "format";
429
- if (text.includes("install")) return "install";
430
- if (text.includes("release") || text.includes("publish") || text.includes("pack"))
431
- return "release";
432
- return "other";
433
- }
434
-
435
- function detectSensitiveScript(command: string): string | null {
436
- const lower = command.toLowerCase();
437
- if (
438
- /(^|[^a-z0-9])(secret|token|password|passwd|api[_-]?key|apikey|credential|credentials|private|internal|private-url|internal-link)([^a-z0-9]|$)/.test(
439
- lower,
440
- )
441
- )
442
- return "protected-name-or-command";
443
- if (/https?:\/\//i.test(command)) return "url";
444
- if (/\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i.test(command)) return "email-or-internal-id";
445
- return null;
446
- }
447
-
448
- function createProjectPrivacy(): ProjectPrivacy {
449
- return {
450
- version: 1,
451
- classification: "local-private",
452
- metadataOnly: true,
453
- sourceContentIndex: false,
454
- promptHistoryIndex: false,
455
- shellHistoryIndex: false,
456
- rawCommandOutputIndex: false,
457
- externalUpload: false,
458
- excludedGlobs: DEFAULT_EXCLUDED_GLOBS,
459
- protectedPatterns: PROTECTED_PATTERNS,
460
- };
461
- }
462
-
463
- function createProjectId(projectDir: string): string {
464
- return (
465
- basename(projectDir)
466
- .toLowerCase()
467
- .replace(/[^a-z0-9._-]+/g, "-")
468
- .replace(/^-+|-+$/g, "") || "project"
469
- );
470
- }
471
-
472
- function shouldExcludePath(relativePath: string, isDirectory: boolean): boolean {
473
- const segments = relativePath.split("/");
474
- const name = segments.at(-1) ?? relativePath;
475
- const lowerName = name.toLowerCase();
476
-
477
- if (isDirectory && EXCLUDED_DIRECTORY_NAMES.has(name)) return true;
478
- if (segments.includes(".evodev") && !relativePath.startsWith(".evodev/decisions")) return true;
479
- if (EXCLUDED_FILE_PREFIXES.some((prefix) => name.startsWith(prefix))) return true;
480
- if (EXCLUDED_FILE_PARTS.some((part) => lowerName.includes(part))) return true;
481
- if (EXCLUDED_FILE_EXTENSIONS.some((extension) => lowerName.endsWith(extension))) return true;
482
- return false;
483
- }
484
-
485
- async function pathExists(path: string): Promise<boolean> {
486
- try {
487
- await stat(path);
488
- return true;
489
- } catch (error) {
490
- if (
491
- error instanceof Error &&
492
- "code" in error &&
493
- (error as NodeJS.ErrnoException).code === "ENOENT"
494
- ) {
495
- return false;
496
- }
497
- throw error;
498
- }
499
- }
500
-
501
- function isRecord(value: unknown): value is Record<string, unknown> {
502
- return typeof value === "object" && value !== null && !Array.isArray(value);
503
- }
504
-
505
- function describeError(error: unknown): string {
506
- return error instanceof Error ? error.message : String(error);
507
- }