@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.
- package/assets/agents/review/code-reviewer/examples.md +1 -1
- package/assets/agents/review/code-reviewer/prompt.md +1 -1
- package/assets/agents/review/code-reviewer/verification.md +1 -1
- package/assets/skills/coding/knowledge-distillation/SKILL.md +248 -0
- package/assets/skills/coding/knowledge-distillation/manifest.json +10 -0
- package/assets/skills/coding/knowledge-distillation/references/knowledge-distillation-methods.md +122 -0
- package/assets/workflows/rd-bug-fix/WORKFLOW.json +1 -1
- package/assets/workflows/rd-code-review/WORKFLOW.json +1 -1
- package/assets/workflows/rd-docs-update/WORKFLOW.json +1 -1
- package/assets/workflows/rd-feature-implementation/WORKFLOW.json +1 -1
- package/assets/workflows/rd-refactor/WORKFLOW.json +1 -1
- package/assets/workflows/rd-release-readiness/WORKFLOW.json +1 -1
- package/assets/workflows/rd-security-boundary-review/WORKFLOW.json +2 -2
- package/assets/workflows/rd-test-generation/WORKFLOW.json +1 -1
- package/dist/config/index.js +242 -36
- package/dist/index.js +5045 -934
- package/dist/plugins/index.js +32 -32
- package/package.json +1 -1
- package/src/agents/index.ts +28 -49
- package/src/config/index.ts +2 -0
- package/src/config/paths.ts +30 -0
- package/src/config/settings.ts +52 -0
- package/src/config/store.ts +150 -0
- package/src/daemon/index.ts +376 -3
- package/src/evolution/index.ts +2356 -0
- package/src/hooks/index.ts +255 -238
- package/src/index.ts +4 -0
- package/src/pack/index.ts +13 -13
- package/src/plugins/capabilities.ts +40 -42
- package/src/plugins/index.ts +0 -1
- package/src/plugins/types.ts +4 -0
- package/src/protected-zones/index.ts +29 -11
- package/src/runtime-logs/index.ts +324 -0
- package/src/sync/orchestrator.ts +6 -0
- package/src/task/index.ts +3 -3
- package/src/team/index.ts +2398 -0
- package/src/team/mcp.ts +401 -0
- 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
|
+
}
|
package/src/sync/orchestrator.ts
CHANGED
|
@@ -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: "
|
|
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: "
|
|
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: "
|
|
356
|
+
policy: "advisory",
|
|
357
357
|
commands,
|
|
358
358
|
acceptanceResults,
|
|
359
359
|
antiCriteriaResults,
|