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

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 (38) 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 +248 -0
  5. package/assets/skills/coding/knowledge-distillation/manifest.json +10 -0
  6. package/assets/skills/coding/knowledge-distillation/references/knowledge-distillation-methods.md +122 -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 +242 -36
  16. package/dist/index.js +5045 -934
  17. package/dist/plugins/index.js +32 -32
  18. package/package.json +1 -1
  19. package/src/agents/index.ts +28 -49
  20. package/src/config/index.ts +2 -0
  21. package/src/config/paths.ts +30 -0
  22. package/src/config/settings.ts +52 -0
  23. package/src/config/store.ts +150 -0
  24. package/src/daemon/index.ts +376 -3
  25. package/src/evolution/index.ts +2356 -0
  26. package/src/hooks/index.ts +255 -238
  27. package/src/index.ts +4 -0
  28. package/src/pack/index.ts +13 -13
  29. package/src/plugins/capabilities.ts +40 -42
  30. package/src/plugins/index.ts +0 -1
  31. package/src/plugins/types.ts +4 -0
  32. package/src/protected-zones/index.ts +29 -11
  33. package/src/runtime-logs/index.ts +324 -0
  34. package/src/sync/orchestrator.ts +6 -0
  35. package/src/task/index.ts +3 -3
  36. package/src/team/index.ts +2398 -0
  37. package/src/team/mcp.ts +401 -0
  38. package/src/workflow/index.ts +6 -6
@@ -0,0 +1,324 @@
1
+ import { createHash } from "node:crypto";
2
+ import { appendFile, mkdir } from "node:fs/promises";
3
+ import { dirname, isAbsolute, join, relative } from "node:path";
4
+ import { resolveEvoDevPaths } from "../config/paths.ts";
5
+
6
+ export type EvoDevLogPhase = "started" | "completed" | "failed";
7
+
8
+ export interface CliLogEntryV1 {
9
+ version: 1;
10
+ kind: "cli";
11
+ timestamp: string;
12
+ date: string;
13
+ phase: EvoDevLogPhase;
14
+ command: string | null;
15
+ argv: string[];
16
+ cwd: string | null;
17
+ pid: number;
18
+ exitCode: number | null;
19
+ durationMs: number | null;
20
+ error: string | null;
21
+ }
22
+
23
+ export interface TraceLogEntryV1 {
24
+ version: 1;
25
+ kind: "trace";
26
+ timestamp: string;
27
+ date: string;
28
+ phase: EvoDevLogPhase;
29
+ sessionKey: string;
30
+ target: string;
31
+ runtime: {
32
+ surface: "cli" | "plugin";
33
+ argv: string[];
34
+ runtimeFile: string | null;
35
+ };
36
+ input: {
37
+ stdinBytes: number | null;
38
+ payload: unknown;
39
+ } | null;
40
+ event: {
41
+ eventId: string;
42
+ type: string;
43
+ summary: string;
44
+ metadata: unknown;
45
+ decision: unknown;
46
+ } | null;
47
+ result: {
48
+ enabled: boolean;
49
+ summary: string;
50
+ stateWrites: string[];
51
+ warnings: string[];
52
+ formattedResponse: string | null;
53
+ durationMs: number | null;
54
+ } | null;
55
+ error: string | null;
56
+ team: TraceLogTeamContext | null;
57
+ }
58
+
59
+ export interface TraceLogTeamContext {
60
+ runId: string;
61
+ roleId: string;
62
+ projectKey: string;
63
+ }
64
+
65
+ export interface CliLogInput {
66
+ phase: EvoDevLogPhase;
67
+ argv: string[];
68
+ timestamp?: Date | string;
69
+ cwd?: string | null;
70
+ pid?: number;
71
+ exitCode?: number | null;
72
+ durationMs?: number | null;
73
+ error?: unknown;
74
+ }
75
+
76
+ export interface TraceLogInput {
77
+ phase: EvoDevLogPhase;
78
+ target: string;
79
+ runtime: TraceLogEntryV1["runtime"];
80
+ sessionKey?: string;
81
+ payload?: Record<string, unknown> | null;
82
+ stdinBytes?: number | null;
83
+ event?: TraceLogEntryV1["event"] | null;
84
+ result?: TraceLogEntryV1["result"] | null;
85
+ timestamp?: Date | string;
86
+ error?: unknown;
87
+ team?: TraceLogTeamContext | null;
88
+ }
89
+
90
+ export interface EvoDevLogPaths {
91
+ logsDir: string;
92
+ cliDir: string;
93
+ cliLogPath: string;
94
+ traceRootDir: string;
95
+ traceDateDir: string;
96
+ traceSessionDir: string | null;
97
+ traceLogPath: string | null;
98
+ projectRunDir: string | null;
99
+ projectRunAgentsDir: string | null;
100
+ agentLogDir: string | null;
101
+ agentTraceLogPath: string | null;
102
+ }
103
+
104
+ const MAX_LOG_STRING_LENGTH = 4096;
105
+ export function createCliLogEntry(input: CliLogInput): CliLogEntryV1 {
106
+ const timestamp = normalizeTimestamp(input.timestamp);
107
+ return {
108
+ version: 1,
109
+ kind: "cli",
110
+ timestamp,
111
+ date: formatLocalDateKey(timestamp),
112
+ phase: input.phase,
113
+ command: input.argv[0] ?? null,
114
+ argv: input.argv.map((arg) => truncateString(arg)),
115
+ cwd: input.cwd === undefined ? process.cwd() : input.cwd,
116
+ pid: input.pid ?? process.pid,
117
+ exitCode: input.exitCode ?? null,
118
+ durationMs: input.durationMs ?? null,
119
+ error: input.error === undefined ? null : describeError(input.error),
120
+ };
121
+ }
122
+
123
+ export function createTraceLogEntry(input: TraceLogInput): TraceLogEntryV1 {
124
+ const timestamp = normalizeTimestamp(input.timestamp);
125
+ const payload = input.payload ?? null;
126
+ const sessionKey = input.sessionKey ?? resolveTraceSessionKey(payload);
127
+ return {
128
+ version: 1,
129
+ kind: "trace",
130
+ timestamp,
131
+ date: formatLocalDateKey(timestamp),
132
+ phase: input.phase,
133
+ sessionKey,
134
+ target: truncateString(input.target),
135
+ runtime: {
136
+ surface: input.runtime.surface,
137
+ argv: input.runtime.argv.map((arg) => truncateString(arg)),
138
+ runtimeFile:
139
+ input.runtime.runtimeFile === null ? null : truncateString(input.runtime.runtimeFile),
140
+ },
141
+ input:
142
+ payload === null
143
+ ? null
144
+ : {
145
+ stdinBytes: input.stdinBytes ?? null,
146
+ payload,
147
+ },
148
+ event: input.event === undefined ? null : input.event,
149
+ result: input.result === undefined ? null : input.result,
150
+ error: input.error === undefined ? null : describeError(input.error),
151
+ team:
152
+ input.team === undefined || input.team === null
153
+ ? null
154
+ : {
155
+ runId: sanitizePathSegment(input.team.runId),
156
+ roleId: sanitizePathSegment(input.team.roleId),
157
+ projectKey: sanitizePathSegment(input.team.projectKey),
158
+ },
159
+ };
160
+ }
161
+
162
+ export function resolveEvoDevLogPaths(input: {
163
+ homeDir: string;
164
+ timestamp?: Date | string;
165
+ sessionKey?: string | null;
166
+ team?: TraceLogTeamContext | null;
167
+ }): EvoDevLogPaths {
168
+ const paths = resolveEvoDevPaths(input.homeDir);
169
+ const date = formatLocalDateKey(normalizeTimestamp(input.timestamp));
170
+ const cliDir = join(paths.logsDir, "cli");
171
+ const traceRootDir = join(paths.logsDir, "trace");
172
+ const traceDateDir = join(traceRootDir, date);
173
+ const traceSessionDir =
174
+ input.sessionKey === undefined || input.sessionKey === null
175
+ ? null
176
+ : join(traceDateDir, sanitizePathSegment(input.sessionKey));
177
+ const projectRunDir =
178
+ input.team === undefined || input.team === null
179
+ ? null
180
+ : join(
181
+ paths.logsDir,
182
+ sanitizePathSegment(input.team.projectKey),
183
+ sanitizePathSegment(input.team.runId),
184
+ );
185
+ const projectRunAgentsDir = projectRunDir === null ? null : join(projectRunDir, "agents");
186
+ const agentLogDir =
187
+ projectRunAgentsDir === null || input.team === undefined || input.team === null
188
+ ? null
189
+ : join(projectRunAgentsDir, sanitizePathSegment(input.team.roleId));
190
+
191
+ return {
192
+ logsDir: paths.logsDir,
193
+ cliDir,
194
+ cliLogPath: join(cliDir, `${date}.log`),
195
+ traceRootDir,
196
+ traceDateDir,
197
+ traceSessionDir,
198
+ traceLogPath: traceSessionDir === null ? null : join(traceSessionDir, "trace.log"),
199
+ projectRunDir,
200
+ projectRunAgentsDir,
201
+ agentLogDir,
202
+ agentTraceLogPath: agentLogDir === null ? null : join(agentLogDir, "trace.log"),
203
+ };
204
+ }
205
+
206
+ export async function appendCliLogEntry(homeDir: string, entry: CliLogEntryV1): Promise<string> {
207
+ const path = resolveEvoDevLogPaths({ homeDir, timestamp: entry.timestamp }).cliLogPath;
208
+ await appendJsonLine(path, entry);
209
+ return path;
210
+ }
211
+
212
+ export async function appendTraceLogEntry(
213
+ homeDir: string,
214
+ entry: TraceLogEntryV1,
215
+ ): Promise<string> {
216
+ const path = resolveEvoDevLogPaths({
217
+ homeDir,
218
+ timestamp: entry.timestamp,
219
+ sessionKey: entry.sessionKey,
220
+ }).traceLogPath;
221
+ if (path === null) throw new Error("Cannot resolve trace log path without a session key.");
222
+ await appendJsonLine(path, entry);
223
+ const agentTraceLogPath = resolveEvoDevLogPaths({
224
+ homeDir,
225
+ timestamp: entry.timestamp,
226
+ sessionKey: entry.sessionKey,
227
+ team: entry.team,
228
+ }).agentTraceLogPath;
229
+ if (agentTraceLogPath !== null) {
230
+ await appendJsonLine(agentTraceLogPath, entry);
231
+ }
232
+ return path;
233
+ }
234
+
235
+ export function resolveTraceTeamContext(input: {
236
+ homeDir: string;
237
+ environment?: Record<string, string | undefined>;
238
+ payload?: Record<string, unknown> | null;
239
+ }): TraceLogTeamContext | null {
240
+ const environment = input.environment ?? {};
241
+ const runId = optionalString(environment.EVODEV_TEAM_RUN_ID);
242
+ const roleId = optionalString(environment.EVODEV_TEAM_ROLE_ID);
243
+ if (runId === null || roleId === null) return null;
244
+ const repoRoot =
245
+ optionalString(environment.EVODEV_TEAM_REPO_ROOT) ??
246
+ optionalString(input.payload?.cwd) ??
247
+ input.homeDir;
248
+ return {
249
+ runId: sanitizePathSegment(runId),
250
+ roleId: sanitizePathSegment(roleId),
251
+ projectKey: resolveProjectLogKey(input.homeDir, repoRoot),
252
+ };
253
+ }
254
+
255
+ export function resolveProjectLogKey(homeDir: string, repoRoot: string): string {
256
+ const trimmedHome = stripTrailingSlash(homeDir);
257
+ const trimmedRepo = stripTrailingSlash(repoRoot);
258
+ const relativePath = relative(trimmedHome, trimmedRepo);
259
+ const source =
260
+ relativePath !== "" && !relativePath.startsWith("..") && !isAbsolute(relativePath)
261
+ ? relativePath
262
+ : trimmedRepo.replace(/^[/\\]+/, "");
263
+ return (
264
+ source
265
+ .split(/[/\\]+/)
266
+ .filter(Boolean)
267
+ .map((part) => sanitizePathSegment(part))
268
+ .join("-") || "project-local"
269
+ );
270
+ }
271
+
272
+ export function resolveTraceSessionKey(payload: unknown): string {
273
+ const record = isRecord(payload) ? payload : {};
274
+ const sessionId = optionalString(record.session_id ?? record.sessionId);
275
+ const cwd = optionalString(record.cwd);
276
+ const source = sessionId ?? cwd ?? "local";
277
+ return `session-${createHash("sha256").update(source).digest("hex").slice(0, 16)}`;
278
+ }
279
+
280
+ async function appendJsonLine(path: string, value: unknown): Promise<void> {
281
+ await mkdir(dirname(path), { recursive: true });
282
+ await appendFile(path, `${JSON.stringify(value)}\n`, "utf8");
283
+ }
284
+
285
+ function normalizeTimestamp(value?: Date | string): string {
286
+ if (value instanceof Date) return value.toISOString();
287
+ if (typeof value === "string" && value.trim() !== "") return new Date(value).toISOString();
288
+ return new Date().toISOString();
289
+ }
290
+
291
+ function formatLocalDateKey(timestamp: string): string {
292
+ const date = new Date(timestamp);
293
+ const year = date.getFullYear();
294
+ const month = String(date.getMonth() + 1).padStart(2, "0");
295
+ const day = String(date.getDate()).padStart(2, "0");
296
+ return `${year}-${month}-${day}`;
297
+ }
298
+
299
+ function truncateString(value: string): string {
300
+ if (value.length <= MAX_LOG_STRING_LENGTH) return value;
301
+ return `${value.slice(0, MAX_LOG_STRING_LENGTH)}...[truncated:${value.length - MAX_LOG_STRING_LENGTH}]`;
302
+ }
303
+
304
+ function sanitizePathSegment(value: string): string {
305
+ return value.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || "session-local";
306
+ }
307
+
308
+ function stripTrailingSlash(path: string): string {
309
+ if (path === "/" || /^[A-Za-z]:[\\/]?$/.test(path)) return path;
310
+ return path.replace(/[/\\]+$/, "");
311
+ }
312
+
313
+ function optionalString(value: unknown): string | null {
314
+ return typeof value === "string" && value.length > 0 ? value : null;
315
+ }
316
+
317
+ function describeError(error: unknown): string {
318
+ if (error instanceof Error) return truncateString(error.message);
319
+ return truncateString(String(error));
320
+ }
321
+
322
+ function isRecord(value: unknown): value is Record<string, unknown> {
323
+ return typeof value === "object" && value !== null && !Array.isArray(value);
324
+ }
@@ -25,6 +25,7 @@ export interface SyncOrchestratorOptions {
25
25
  assetsRootDir: string;
26
26
  pluginRegistry: PluginRegistry;
27
27
  dryRun?: boolean;
28
+ force?: boolean;
28
29
  targetPlugins?: PluginId[];
29
30
  includeSkills?: boolean;
30
31
  includeAgents?: boolean;
@@ -49,6 +50,7 @@ export async function runSync(options: SyncOrchestratorOptions): Promise<SyncRun
49
50
  assets,
50
51
  plugins,
51
52
  dryRun: options.dryRun ?? false,
53
+ force: options.force ?? false,
52
54
  includeSkills: options.includeSkills,
53
55
  includeAgents: options.includeAgents,
54
56
  });
@@ -77,6 +79,7 @@ export interface BuildSyncPlansInput {
77
79
  assets: AssetScanResult;
78
80
  plugins: CodeAgentPlugin[];
79
81
  dryRun: boolean;
82
+ force: boolean;
80
83
  includeSkills?: boolean;
81
84
  includeAgents?: boolean;
82
85
  }
@@ -94,6 +97,7 @@ export function buildSyncPlans(input: BuildSyncPlansInput): SyncPlan[] {
94
97
  skills: filterAssetsForTarget(skills, plugin.id),
95
98
  agents: filterAssetsForTarget(agents, plugin.id),
96
99
  dryRun: input.dryRun,
100
+ force: input.force,
97
101
  }));
98
102
  }
99
103
 
@@ -116,11 +120,13 @@ async function executeSyncPlans(
116
120
  targetPlugin: plan.targetPlugin,
117
121
  skills: plan.skills,
118
122
  dryRun: plan.dryRun,
123
+ force: plan.force,
119
124
  }),
120
125
  plugin.syncAgents({
121
126
  targetPlugin: plan.targetPlugin,
122
127
  agents: plan.agents,
123
128
  dryRun: plan.dryRun,
129
+ force: plan.force,
124
130
  }),
125
131
  ]);
126
132
 
package/src/task/index.ts CHANGED
@@ -56,7 +56,7 @@ export interface TaskContract {
56
56
  requiredVerification: string[];
57
57
  };
58
58
  verification: {
59
- policy: "fail-closed";
59
+ policy: "advisory";
60
60
  commands: VerificationCommandResult[];
61
61
  acceptanceResults: VerificationCriterionResult[];
62
62
  antiCriteriaResults: VerificationCriterionResult[];
@@ -261,7 +261,7 @@ export function createTaskContract(input: TaskInitInput): TaskContract {
261
261
  requiredVerification: uniqueSanitizedIds(input.requiredVerification ?? []),
262
262
  },
263
263
  verification: {
264
- policy: "fail-closed",
264
+ policy: "advisory",
265
265
  commands: [],
266
266
  acceptanceResults: [],
267
267
  antiCriteriaResults: [],
@@ -353,7 +353,7 @@ export function verifyTaskContract(
353
353
  criterion.status,
354
354
  })),
355
355
  verification: {
356
- policy: "fail-closed",
356
+ policy: "advisory",
357
357
  commands,
358
358
  acceptanceResults,
359
359
  antiCriteriaResults,