@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,401 @@
1
+ import { createInterface } from "node:readline";
2
+ import type { Readable, Writable } from "node:stream";
3
+ import { TeamMessageBroker, type TeamMessageBrokerOptions, type TeamMessageType } from "./index.ts";
4
+
5
+ export interface TeamsMcpServerOptions extends TeamMessageBrokerOptions {
6
+ defaultRunId?: string;
7
+ defaultFromRoleId?: string;
8
+ now?: Date;
9
+ }
10
+
11
+ export type JsonRpcId = string | number;
12
+
13
+ export interface JsonRpcResponse {
14
+ jsonrpc: "2.0";
15
+ id: JsonRpcId | null;
16
+ result?: Record<string, unknown>;
17
+ error?: {
18
+ code: number;
19
+ message: string;
20
+ data?: unknown;
21
+ };
22
+ }
23
+
24
+ export interface McpToolDefinition {
25
+ name: string;
26
+ title: string;
27
+ description: string;
28
+ inputSchema: Record<string, unknown>;
29
+ outputSchema?: Record<string, unknown>;
30
+ }
31
+
32
+ const PROTOCOL_VERSION = "2025-11-25";
33
+ const SUPPORTED_PROTOCOL_VERSIONS = new Set([PROTOCOL_VERSION, "2025-06-18"]);
34
+ const MESSAGE_TYPES = new Set<TeamMessageType>(["request", "result", "issue", "notice"]);
35
+
36
+ export function getTeamsMcpTools(): McpToolDefinition[] {
37
+ return [
38
+ {
39
+ name: "list_agents",
40
+ title: "List EvoDev Team Agents",
41
+ description: "List role agents in the current EvoDev team run.",
42
+ inputSchema: {
43
+ type: "object",
44
+ additionalProperties: false,
45
+ properties: {
46
+ runId: {
47
+ type: "string",
48
+ description: "Optional EvoDev team run id. Defaults to the latest run.",
49
+ },
50
+ },
51
+ },
52
+ outputSchema: {
53
+ type: "object",
54
+ additionalProperties: false,
55
+ properties: {
56
+ agents: { type: "array" },
57
+ },
58
+ required: ["agents"],
59
+ },
60
+ },
61
+ {
62
+ name: "send_message",
63
+ title: "Send EvoDev Team Message",
64
+ description: "Send a structured message to another EvoDev role agent.",
65
+ inputSchema: {
66
+ type: "object",
67
+ additionalProperties: false,
68
+ properties: {
69
+ runId: {
70
+ type: "string",
71
+ description: "Optional EvoDev team run id. Defaults to the latest run.",
72
+ },
73
+ toRoleId: {
74
+ type: "string",
75
+ description: "Target role id.",
76
+ },
77
+ message: {
78
+ type: "string",
79
+ description: "Message body to deliver.",
80
+ },
81
+ type: {
82
+ type: "string",
83
+ enum: ["request", "result", "issue", "notice"],
84
+ description: "Message type.",
85
+ },
86
+ fromRoleId: {
87
+ type: "string",
88
+ description: "Optional sender role id for audit context.",
89
+ },
90
+ },
91
+ required: ["toRoleId", "message"],
92
+ },
93
+ outputSchema: {
94
+ type: "object",
95
+ additionalProperties: true,
96
+ properties: {
97
+ ok: { type: "boolean" },
98
+ messageId: { type: "string" },
99
+ deliveredTo: { type: "string" },
100
+ cc: { type: "array" },
101
+ },
102
+ required: ["ok"],
103
+ },
104
+ },
105
+ {
106
+ name: "spawn_role",
107
+ title: "Spawn EvoDev Role Agent",
108
+ description: "Create or reuse one EvoDev role agent.",
109
+ inputSchema: {
110
+ type: "object",
111
+ additionalProperties: false,
112
+ properties: {
113
+ runId: {
114
+ type: "string",
115
+ description: "Optional EvoDev team run id. Defaults to the current team run.",
116
+ },
117
+ roleId: {
118
+ type: "string",
119
+ description: "Role id to create or reuse.",
120
+ },
121
+ reason: {
122
+ type: "string",
123
+ description: "Reason for lifecycle change.",
124
+ },
125
+ fromRoleId: {
126
+ type: "string",
127
+ description: "Optional sender role id for audit context.",
128
+ },
129
+ },
130
+ required: ["roleId"],
131
+ },
132
+ outputSchema: {
133
+ type: "object",
134
+ additionalProperties: true,
135
+ properties: {
136
+ ok: { type: "boolean" },
137
+ created: { type: "boolean" },
138
+ agent: { type: "object" },
139
+ error: { type: "string" },
140
+ message: { type: "string" },
141
+ },
142
+ required: ["ok"],
143
+ },
144
+ },
145
+ {
146
+ name: "stop_role",
147
+ title: "Stop EvoDev Role Agent",
148
+ description: "Stop one EvoDev role agent.",
149
+ inputSchema: {
150
+ type: "object",
151
+ additionalProperties: false,
152
+ properties: {
153
+ runId: {
154
+ type: "string",
155
+ description: "Optional EvoDev team run id. Defaults to the current team run.",
156
+ },
157
+ roleId: {
158
+ type: "string",
159
+ description: "Role id to stop.",
160
+ },
161
+ reason: {
162
+ type: "string",
163
+ description: "Reason for lifecycle change.",
164
+ },
165
+ fromRoleId: {
166
+ type: "string",
167
+ description: "Optional sender role id for audit context.",
168
+ },
169
+ },
170
+ required: ["roleId"],
171
+ },
172
+ outputSchema: {
173
+ type: "object",
174
+ additionalProperties: true,
175
+ properties: {
176
+ ok: { type: "boolean" },
177
+ stopped: { type: "boolean" },
178
+ agent: { type: "object" },
179
+ error: { type: "string" },
180
+ message: { type: "string" },
181
+ },
182
+ required: ["ok"],
183
+ },
184
+ },
185
+ ];
186
+ }
187
+
188
+ export async function handleTeamsMcpLine(
189
+ line: string,
190
+ options: TeamsMcpServerOptions = {},
191
+ ): Promise<JsonRpcResponse | null> {
192
+ try {
193
+ return await handleTeamsMcpMessage(JSON.parse(line), options);
194
+ } catch (error) {
195
+ return jsonRpcError(null, -32700, "Parse error", describeError(error));
196
+ }
197
+ }
198
+
199
+ export async function handleTeamsMcpMessage(
200
+ message: unknown,
201
+ options: TeamsMcpServerOptions = {},
202
+ ): Promise<JsonRpcResponse | null> {
203
+ const request = parseRequest(message);
204
+ if (request === null) return null;
205
+
206
+ try {
207
+ if (request.method === "initialize")
208
+ return jsonRpcResult(request.id, initializeResult(request));
209
+ if (request.method === "ping") return jsonRpcResult(request.id, {});
210
+ if (request.method === "tools/list") {
211
+ return jsonRpcResult(request.id, { tools: getTeamsMcpTools() });
212
+ }
213
+ if (request.method === "tools/call") {
214
+ return jsonRpcResult(request.id, await callTeamsTool(request.params, options));
215
+ }
216
+ return jsonRpcError(request.id, -32601, `Method not found: ${request.method}`);
217
+ } catch (error) {
218
+ return jsonRpcError(request.id, -32603, describeError(error));
219
+ }
220
+ }
221
+
222
+ export async function runTeamsMcpStdioServer(
223
+ options: TeamsMcpServerOptions & {
224
+ input?: Readable;
225
+ output?: Writable;
226
+ } = {},
227
+ ): Promise<void> {
228
+ const input = options.input ?? process.stdin;
229
+ const output = options.output ?? process.stdout;
230
+ const lines = createInterface({ input, crlfDelay: Number.POSITIVE_INFINITY });
231
+
232
+ for await (const line of lines) {
233
+ if (line.trim() === "") continue;
234
+ const response = await handleTeamsMcpLine(line, options);
235
+ if (response !== null) {
236
+ output.write(`${JSON.stringify(response)}\n`);
237
+ }
238
+ }
239
+ }
240
+
241
+ function initializeResult(request: ParsedRequest): Record<string, unknown> {
242
+ const params = isRecord(request.params) ? request.params : {};
243
+ const requestedVersion =
244
+ typeof params.protocolVersion === "string" ? params.protocolVersion : PROTOCOL_VERSION;
245
+ const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.has(requestedVersion)
246
+ ? requestedVersion
247
+ : PROTOCOL_VERSION;
248
+ return {
249
+ protocolVersion,
250
+ capabilities: {
251
+ tools: {
252
+ listChanged: false,
253
+ },
254
+ },
255
+ serverInfo: {
256
+ name: "evodev-teams",
257
+ version: "0.0.1-alpha",
258
+ },
259
+ instructions:
260
+ "Use list_agents to discover EvoDev role agents, spawn_role to create or reuse role agents in the current EvoDev team run, send_message to communicate through the EvoDev broker, and stop_role to stop roles. Role lifecycle is tracked by EvoDev Teams MCP/CLI (`evodev team ...`), not direct tmux orchestration.",
261
+ };
262
+ }
263
+
264
+ async function callTeamsTool(
265
+ params: unknown,
266
+ options: TeamsMcpServerOptions,
267
+ ): Promise<Record<string, unknown>> {
268
+ const input = expectRecord(params, "tools/call params");
269
+ const name = expectString(input.name, "tools/call params.name");
270
+ const args = input.arguments === undefined ? {} : expectRecord(input.arguments, "arguments");
271
+ const broker = new TeamMessageBroker(options);
272
+
273
+ if (name === "list_agents") {
274
+ const agents = await broker.listAgents({
275
+ runId: optionalString(args.runId) ?? options.defaultRunId,
276
+ });
277
+ return toolResult({ agents });
278
+ }
279
+
280
+ if (name === "send_message") {
281
+ const toRoleId = expectString(args.toRoleId, "arguments.toRoleId");
282
+ const message = expectString(args.message, "arguments.message");
283
+ const type = parseMessageType(args.type);
284
+ const fromRoleId = optionalString(args.fromRoleId) ?? options.defaultFromRoleId;
285
+ const result = await broker.send({
286
+ runId: optionalString(args.runId) ?? options.defaultRunId,
287
+ fromRoleId,
288
+ toRoleId,
289
+ message,
290
+ type,
291
+ now: options.now,
292
+ });
293
+ return result.ok ? toolResult({ ...result }) : toolResult({ ...result }, true);
294
+ }
295
+
296
+ if (name === "spawn_role") {
297
+ const roleId = expectString(args.roleId, "arguments.roleId");
298
+ const fromRoleId = optionalString(args.fromRoleId) ?? options.defaultFromRoleId;
299
+ const result = await broker.spawnRole({
300
+ runId: optionalString(args.runId) ?? options.defaultRunId,
301
+ fromRoleId,
302
+ roleId,
303
+ reason: optionalString(args.reason),
304
+ now: options.now,
305
+ });
306
+ return result.ok ? toolResult({ ...result }) : toolResult({ ...result }, true);
307
+ }
308
+
309
+ if (name === "stop_role") {
310
+ const roleId = expectString(args.roleId, "arguments.roleId");
311
+ const fromRoleId = optionalString(args.fromRoleId) ?? options.defaultFromRoleId;
312
+ const result = await broker.stopRole({
313
+ runId: optionalString(args.runId) ?? options.defaultRunId,
314
+ fromRoleId,
315
+ roleId,
316
+ reason: optionalString(args.reason),
317
+ now: options.now,
318
+ });
319
+ return result.ok ? toolResult({ ...result }) : toolResult({ ...result }, true);
320
+ }
321
+
322
+ throw new Error(`Unknown Teams MCP tool: ${name}`);
323
+ }
324
+
325
+ function toolResult(
326
+ structuredContent: Record<string, unknown>,
327
+ isError = false,
328
+ ): Record<string, unknown> {
329
+ return {
330
+ content: [
331
+ {
332
+ type: "text",
333
+ text: JSON.stringify(structuredContent, null, 2),
334
+ },
335
+ ],
336
+ structuredContent,
337
+ isError,
338
+ };
339
+ }
340
+
341
+ interface ParsedRequest {
342
+ id: JsonRpcId;
343
+ method: string;
344
+ params?: unknown;
345
+ }
346
+
347
+ function parseRequest(message: unknown): ParsedRequest | null {
348
+ if (!isRecord(message)) throw new Error("Invalid JSON-RPC message; expected object.");
349
+ if (message.jsonrpc !== "2.0") throw new Error("Invalid JSON-RPC version.");
350
+ if (message.id === undefined) return null;
351
+ if (typeof message.id !== "string" && typeof message.id !== "number") {
352
+ throw new Error("Invalid JSON-RPC id.");
353
+ }
354
+ const method = expectString(message.method, "method");
355
+ return { id: message.id, method, params: message.params };
356
+ }
357
+
358
+ function parseMessageType(value: unknown): TeamMessageType | undefined {
359
+ if (value === undefined) return undefined;
360
+ if (typeof value === "string" && MESSAGE_TYPES.has(value as TeamMessageType)) {
361
+ return value as TeamMessageType;
362
+ }
363
+ throw new Error("arguments.type must be request, result, issue, or notice.");
364
+ }
365
+
366
+ function jsonRpcResult(id: JsonRpcId, result: Record<string, unknown>): JsonRpcResponse {
367
+ return { jsonrpc: "2.0", id, result };
368
+ }
369
+
370
+ function jsonRpcError(
371
+ id: JsonRpcId | null,
372
+ code: number,
373
+ message: string,
374
+ data?: unknown,
375
+ ): JsonRpcResponse {
376
+ return { jsonrpc: "2.0", id, error: { code, message, data } };
377
+ }
378
+
379
+ function expectRecord(value: unknown, path: string): Record<string, unknown> {
380
+ if (!isRecord(value)) throw new Error(`Invalid ${path}; expected object.`);
381
+ return value;
382
+ }
383
+
384
+ function expectString(value: unknown, path: string): string {
385
+ if (typeof value !== "string" || value.length === 0) {
386
+ throw new Error(`Invalid ${path}; expected non-empty string.`);
387
+ }
388
+ return value;
389
+ }
390
+
391
+ function optionalString(value: unknown): string | undefined {
392
+ return typeof value === "string" && value.length > 0 ? value : undefined;
393
+ }
394
+
395
+ function isRecord(value: unknown): value is Record<string, unknown> {
396
+ return typeof value === "object" && value !== null && !Array.isArray(value);
397
+ }
398
+
399
+ function describeError(error: unknown): string {
400
+ return error instanceof Error ? error.message : String(error);
401
+ }
@@ -13,7 +13,7 @@ export interface WorkflowManifest {
13
13
  steps: WorkflowStep[];
14
14
  requiredEvidence: string[];
15
15
  verification: {
16
- policy: "fail-closed";
16
+ policy: "advisory";
17
17
  antiCriteria: string[];
18
18
  };
19
19
  privacy: {
@@ -41,7 +41,7 @@ export interface WorkflowPlan {
41
41
  steps: Array<WorkflowStep & { plannedOnly: true }>;
42
42
  requiredEvidence: string[];
43
43
  warnings: string[];
44
- blockers: string[];
44
+ advisories: string[];
45
45
  }
46
46
 
47
47
  export async function scanWorkflowManifests(workflowsDir: string): Promise<WorkflowManifest[]> {
@@ -84,10 +84,10 @@ export function planWorkflow(input: {
84
84
  }): WorkflowPlan {
85
85
  const mode = input.contract?.route.mode ?? null;
86
86
  const warnings: string[] = [];
87
- const blockers: string[] = [];
87
+ const advisories: string[] = [];
88
88
 
89
89
  if (mode !== null && !input.workflow.modes.includes(mode)) {
90
- blockers.push(`Workflow ${input.workflow.id} does not support task mode ${mode}.`);
90
+ advisories.push(`Workflow ${input.workflow.id} does not list task mode ${mode}.`);
91
91
  }
92
92
 
93
93
  return {
@@ -97,7 +97,7 @@ export function planWorkflow(input: {
97
97
  steps: input.workflow.steps.map((step) => ({ ...step, plannedOnly: true })),
98
98
  requiredEvidence: input.workflow.requiredEvidence,
99
99
  warnings,
100
- blockers,
100
+ advisories,
101
101
  };
102
102
  }
103
103
 
@@ -128,7 +128,7 @@ export function formatWorkflowPlan(plan: WorkflowPlan): string {
128
128
  "Required evidence:",
129
129
  ...plan.requiredEvidence.map((item) => ` - ${item}`),
130
130
  ...plan.warnings.map((warning) => `Warning: ${warning}`),
131
- ...plan.blockers.map((blocker) => `Blocker: ${blocker}`),
131
+ ...plan.advisories.map((advisory) => `Advisory: ${advisory}`),
132
132
  ].join("\n");
133
133
  }
134
134