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

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 (85) 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 +251 -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/team/agents/code-reviewer.md +48 -0
  8. package/assets/team/agents/docs-maintainer.md +51 -0
  9. package/assets/team/agents/implementation-engineer.md +51 -0
  10. package/assets/team/agents/product-scope-analyst.md +58 -0
  11. package/assets/team/agents/release-engineer.md +55 -0
  12. package/assets/team/agents/security-boundary-reviewer.md +50 -0
  13. package/assets/team/agents/solution-architect.md +51 -0
  14. package/assets/team/agents/verification-engineer.md +51 -0
  15. package/assets/team/team.md +102 -0
  16. package/assets/workflows/rd-bug-fix/WORKFLOW.json +1 -1
  17. package/assets/workflows/rd-code-review/WORKFLOW.json +1 -1
  18. package/assets/workflows/rd-docs-update/WORKFLOW.json +1 -1
  19. package/assets/workflows/rd-feature-implementation/WORKFLOW.json +1 -1
  20. package/assets/workflows/rd-refactor/WORKFLOW.json +1 -1
  21. package/assets/workflows/rd-release-readiness/WORKFLOW.json +1 -1
  22. package/assets/workflows/rd-security-boundary-review/WORKFLOW.json +2 -2
  23. package/assets/workflows/rd-test-generation/WORKFLOW.json +1 -1
  24. package/dist/config/index.js +1115 -81
  25. package/dist/index.js +13796 -2196
  26. package/dist/plugins/index.js +32 -32
  27. package/package.json +5 -1
  28. package/src/agents/index.ts +63 -292
  29. package/src/code-agent-traces/index.ts +520 -0
  30. package/src/config/index.ts +7 -0
  31. package/src/config/paths.ts +30 -0
  32. package/src/config/settings.ts +201 -0
  33. package/src/config/store.ts +152 -0
  34. package/src/daemon/index.ts +462 -40
  35. package/src/evolution/candidates/index.ts +564 -0
  36. package/src/evolution/control/index.ts +20 -0
  37. package/src/evolution/evidence/analysis.ts +533 -0
  38. package/src/evolution/evidence/index.ts +3 -0
  39. package/src/evolution/evidence/session-memory/analysis.ts +281 -0
  40. package/src/evolution/evidence/session-memory/constants.ts +9 -0
  41. package/src/evolution/evidence/session-memory/index.ts +7 -0
  42. package/src/evolution/evidence/session-memory/paths.ts +29 -0
  43. package/src/evolution/evidence/session-memory/policy.ts +39 -0
  44. package/src/evolution/evidence/session-memory/segment.ts +202 -0
  45. package/src/evolution/evidence/session-memory/sensitivity.ts +335 -0
  46. package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
  47. package/src/evolution/evidence/session-memory/storage.ts +379 -0
  48. package/src/evolution/evidence/session-memory/types.ts +221 -0
  49. package/src/evolution/evidence/session-memory/updater.ts +191 -0
  50. package/src/evolution/formatters.ts +169 -0
  51. package/src/evolution/index.ts +16 -0
  52. package/src/evolution/knowledge/index.ts +5427 -0
  53. package/src/evolution/paths.ts +44 -0
  54. package/src/evolution/processor/distillation.ts +518 -0
  55. package/src/evolution/processor/index.ts +3 -0
  56. package/src/evolution/processor/process.ts +528 -0
  57. package/src/{learning → evolution/review}/index.ts +10 -14
  58. package/src/evolution/schema.ts +568 -0
  59. package/src/evolution/shared.ts +758 -0
  60. package/src/evolution/triggers/classification.ts +102 -0
  61. package/src/evolution/triggers/index.ts +295 -0
  62. package/src/hooks/index.ts +652 -376
  63. package/src/index.ts +16 -3
  64. package/src/pack/index.ts +13 -13
  65. package/src/plugins/capabilities.ts +40 -42
  66. package/src/plugins/index.ts +0 -1
  67. package/src/plugins/types.ts +4 -0
  68. package/src/projects/index.ts +453 -0
  69. package/src/protected-zones/index.ts +29 -11
  70. package/src/runtime-logs/index.ts +790 -0
  71. package/src/sync/orchestrator.ts +6 -0
  72. package/src/team/index.ts +3642 -0
  73. package/src/team/mcp.ts +405 -0
  74. package/src/team/prompts.ts +141 -0
  75. package/src/utils/errors.ts +13 -0
  76. package/src/utils/fs.ts +40 -0
  77. package/src/utils/hash.ts +9 -0
  78. package/src/utils/ids.ts +12 -0
  79. package/src/utils/index.ts +7 -0
  80. package/src/utils/parsing.ts +11 -0
  81. package/src/utils/text.ts +18 -0
  82. package/src/utils/time.ts +5 -0
  83. package/src/workflow/index.ts +6 -24
  84. package/src/project/index.ts +0 -507
  85. package/src/task/index.ts +0 -840
@@ -9,37 +9,28 @@ function createUnknownNegotiatedCapabilities(pluginId) {
9
9
  hooks: "unsupported",
10
10
  canPlanWrites: false,
11
11
  warnings: [],
12
- blockers: [`Plugin ${pluginId} capabilities are unknown and unsupported.`]
12
+ advisories: [`Plugin ${pluginId} capabilities are unknown and unsupported.`]
13
13
  };
14
14
  }
15
15
  function isCapabilityUsable(state) {
16
16
  return state === "enabled";
17
17
  }
18
- function assertNoUnverifiedWrites(negotiation) {
19
- if (!negotiation.canPlanWrites) {
20
- throw new Error(`Plugin ${negotiation.pluginId} has no verified enabled write capabilities.`);
21
- }
22
- }
23
18
  function negotiatePluginCapabilities(input) {
24
19
  if (input.pluginId === "codex") {
25
- const declaredSupport = [
26
- input.declared.skills.supported ? "skills" : null,
27
- input.declared.agents.supported ? "agents" : null,
28
- input.declared.hooks.supported ? "hooks" : null
29
- ].filter(Boolean);
30
- const blockers = ["Codex capabilities are unverified; writes are unsupported in I10."];
20
+ const advisories = [];
31
21
  const warnings = [
32
- input.verified ? "Codex readonly verification artifact exists; sync remains no-write until formats are verified." : null,
33
- declaredSupport.length > 0 ? `Codex declares ${declaredSupport.join(", ")} support, but declared support alone cannot authorize writes.` : null
22
+ input.verified ? "Codex metadata-only verification artifact exists; implemented Codex skill/agent distribution remains governed by adapter tests." : null,
23
+ input.declared.skills.supported ? "Codex skills are distributed through the EvoDev Codex plugin bundle, not direct user-directory skill sync." : null,
24
+ input.declared.agents.supported ? "Codex agents can sync to user-level TOML files with no-overwrite semantics." : null
34
25
  ].filter((warning) => warning !== null);
35
26
  return {
36
27
  pluginId: input.pluginId,
37
- skills: input.declared.skills.supported ? "unverified" : "unsupported",
38
- agents: input.declared.agents.supported ? "unverified" : "unsupported",
39
- hooks: input.declared.hooks.supported ? "unverified" : "unsupported",
40
- canPlanWrites: false,
28
+ skills: resolveNonCodexCapabilityState(input.declared.skills.supported, input.enabled),
29
+ agents: resolveNonCodexCapabilityState(input.declared.agents.supported, input.enabled),
30
+ hooks: resolveNonCodexCapabilityState(input.declared.hooks.supported, input.enabled),
31
+ canPlanWrites: input.enabled && input.declared.agents.supported,
41
32
  warnings,
42
- blockers
33
+ advisories
43
34
  };
44
35
  }
45
36
  return {
@@ -49,9 +40,9 @@ function negotiatePluginCapabilities(input) {
49
40
  hooks: resolveNonCodexCapabilityState(input.declared.hooks.supported, input.enabled),
50
41
  canPlanWrites: input.enabled && input.declared.skills.supported && input.declared.agents.supported,
51
42
  warnings: input.enabled ? [] : [
52
- `Plugin ${input.pluginId} has declared capabilities but is not enabled; writes are not authorized.`
43
+ `Plugin ${input.pluginId} has declared capabilities but is not enabled for write planning.`
53
44
  ],
54
- blockers: []
45
+ advisories: []
55
46
  };
56
47
  }
57
48
  function resolveNonCodexCapabilityState(supported, enabled) {
@@ -63,7 +54,9 @@ async function createCodexCapabilityVerificationArtifact(input) {
63
54
  const timestamp = input.createdAt ?? new Date().toISOString();
64
55
  const detectionMessage = sanitizeText(input.detection.message);
65
56
  const diagnostics = [
66
- "Codex remains no-write until concrete user-level paths and formats are verified."
57
+ "Codex skills are packaged in the EvoDev Codex plugin payload.",
58
+ "Codex agents sync to user-level TOML files under ~/.codex/agents.",
59
+ "Codex hooks are supplied by the EvoDev Codex plugin manifest and enabled through Codex plugin hooks."
67
60
  ];
68
61
  return {
69
62
  version: 1,
@@ -80,7 +73,11 @@ async function createCodexCapabilityVerificationArtifact(input) {
80
73
  externalUpload: false,
81
74
  networkUsed: false,
82
75
  toolSummary: { tool: "codex", detectionStatus: input.detection.status, version: null },
83
- capabilities: { skills: "unverified", agents: "unverified", hooks: "unverified" },
76
+ capabilities: {
77
+ skills: "plugin-bundled",
78
+ agents: "user-level-toml-sync",
79
+ hooks: "plugin-manifest-hooks"
80
+ },
84
81
  writeBoundary: {
85
82
  writesAllowed: false,
86
83
  allowedPaths: [],
@@ -98,7 +95,7 @@ async function createCodexCapabilityVerificationArtifact(input) {
98
95
  secretsStored: false,
99
96
  externalUpload: false
100
97
  },
101
- blockers: ["Codex asset capabilities are unverified and unsupported for writes in I10."],
98
+ advisories: [],
102
99
  diagnostics,
103
100
  evidenceRefs: [],
104
101
  evidence: {
@@ -106,7 +103,8 @@ async function createCodexCapabilityVerificationArtifact(input) {
106
103
  detectionMessage,
107
104
  writesAllowed: false,
108
105
  notes: [
109
- "Metadata-only readonly artifact; no Codex paths, formats, hooks, or writes verified."
106
+ "Metadata-only verification artifact; it does not probe or write Code Agent directories.",
107
+ "Implemented Codex asset distribution is covered by adapter tests: plugin-bundled skills and user-level TOML agents."
110
108
  ]
111
109
  }
112
110
  };
@@ -149,12 +147,12 @@ function formatCodexCapabilityVerificationArtifact(artifact, path) {
149
147
  `Status: ${artifact.status}`,
150
148
  `Artifact: ${path ?? "dry-run only"}`,
151
149
  `Verified at: ${artifact.verifiedAt}`,
152
- "Capabilities: skills=unverified agents=unverified hooks=unverified",
153
- "Writes allowed: false",
150
+ `Capabilities: skills=${artifact.capabilities.skills} agents=${artifact.capabilities.agents} hooks=${artifact.capabilities.hooks}`,
151
+ "Verification writes allowed: false",
154
152
  "Allowed paths: none",
155
- "User-level write paths verified: false",
153
+ "User-level agent sync path: ~/.codex/agents",
156
154
  "Project writes allowed: false",
157
- "No-overwrite verified: false",
155
+ "No-overwrite policy: skip existing files unless force refresh is requested",
158
156
  `External upload: ${artifact.externalUpload}`,
159
157
  `Detection: ${artifact.evidence.detectionStatus}`,
160
158
  ...artifact.evidence.notes.map((note) => `Note: ${note}`)
@@ -171,8 +169,11 @@ async function runPluginConformance(plugin) {
171
169
  }
172
170
  if (plugin.id === "codex") {
173
171
  const capabilities = await plugin.getCapabilities();
174
- if (capabilities.skills.supported || capabilities.agents.supported || capabilities.hooks.supported) {
175
- findings.push("Codex must not declare verified runtime support in I10.");
172
+ if (!capabilities.skills.supported || !capabilities.agents.supported) {
173
+ findings.push("Codex must declare plugin-bundled skills and user-level TOML agents.");
174
+ }
175
+ if (!capabilities.hooks.supported || capabilities.hooks.events.length === 0) {
176
+ findings.push("Codex must declare plugin-manifest hook support.");
176
177
  }
177
178
  }
178
179
  return { ok: findings.length === 0, findings };
@@ -259,7 +260,6 @@ export {
259
260
  createUnknownNegotiatedCapabilities,
260
261
  createPluginRegistry,
261
262
  createCodexCapabilityVerificationArtifact,
262
- assertNoUnverifiedWrites,
263
263
  PluginRegistryError,
264
264
  PluginRegistry
265
265
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evo-dev/core",
3
- "version": "0.0.1-alpha",
3
+ "version": "0.0.1-alpha.10",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,18 +10,22 @@
10
10
  "exports": {
11
11
  ".": {
12
12
  "types": "./src/index.ts",
13
+ "bun": "./src/index.ts",
13
14
  "import": "./dist/index.js"
14
15
  },
15
16
  "./assets": {
16
17
  "types": "./src/assets/index.ts",
18
+ "bun": "./src/assets/index.ts",
17
19
  "import": "./dist/assets/index.js"
18
20
  },
19
21
  "./config": {
20
22
  "types": "./src/config/index.ts",
23
+ "bun": "./src/config/index.ts",
21
24
  "import": "./dist/config/index.js"
22
25
  },
23
26
  "./plugins": {
24
27
  "types": "./src/plugins/index.ts",
28
+ "bun": "./src/plugins/index.ts",
25
29
  "import": "./dist/plugins/index.js"
26
30
  }
27
31
  },
@@ -1,20 +1,16 @@
1
1
  import { readFile } from "node:fs/promises";
2
- import type { TaskContract, TaskExecutionMode } from "../task/index.ts";
2
+ import {
3
+ type ScopedKnowledgeContextPack,
4
+ createScopedKnowledgeContextPack,
5
+ formatScopedKnowledgePromptBlock,
6
+ } from "../evolution/knowledge/index.ts";
3
7
 
4
8
  export type AgentPersistence = "named" | "dynamic";
5
- export type AgentLens =
6
- | "review"
7
- | "qa"
8
- | "security"
9
- | "release"
10
- | "architecture"
11
- | "migration"
12
- | "test";
13
9
  export type AgentOutputSchemaId =
14
10
  | "review-findings-v1"
15
11
  | "verification-summary-v1"
16
12
  | "design-options-v1";
17
- export type AgentFindingSeverity = "blocker" | "high" | "medium" | "low" | "info";
13
+ export type AgentFindingSeverity = "critical" | "high" | "medium" | "low" | "info";
18
14
 
19
15
  export interface AgentPermissions {
20
16
  canReadMetadata: boolean;
@@ -56,34 +52,6 @@ export interface AgentProfile {
56
52
  };
57
53
  }
58
54
 
59
- export interface AgentPlannedInvocation {
60
- profile: AgentProfile;
61
- lens: AgentLens;
62
- reason: string;
63
- plannedOnly: true;
64
- }
65
-
66
- export interface AgentMergePlan {
67
- strategy: "none" | "single-output" | "dedupe-preserve-conflicts-fail-closed";
68
- outputSchema: AgentOutputSchemaId | null;
69
- dedupeBy: string[];
70
- conflictPolicy: string[];
71
- failClosedCategories: string[];
72
- }
73
-
74
- export interface AgentComposeDryRunPlan {
75
- ok: boolean;
76
- taskId: string;
77
- mode: TaskExecutionMode | null;
78
- workflowId: string | null;
79
- agents: AgentPlannedInvocation[];
80
- permissions: AgentPermissions;
81
- mergePlan: AgentMergePlan;
82
- warnings: string[];
83
- blockers: string[];
84
- rationale: string;
85
- }
86
-
87
55
  export interface AgentContextDryRunBundle {
88
56
  profile: AgentProfile;
89
57
  context: {
@@ -93,7 +61,16 @@ export interface AgentContextDryRunBundle {
93
61
  provenance: string[];
94
62
  };
95
63
  warnings: string[];
96
- blockers: string[];
64
+ advisories: string[];
65
+ }
66
+
67
+ export interface AgentLoadedContextBundle {
68
+ profile: AgentProfile;
69
+ contextPack: ScopedKnowledgeContextPack | null;
70
+ promptBlock: string | null;
71
+ warnings: string[];
72
+ advisories: string[];
73
+ rawContentStored: false;
97
74
  }
98
75
 
99
76
  export interface ReviewFindingOutput {
@@ -124,17 +101,6 @@ const DEFAULT_AGENT_PERMISSIONS: AgentPermissions = {
124
101
  };
125
102
  const FORBIDDEN_INPUTS = ["rawPrompts", "secrets", "rawCommandLogs", "sourceCorpus"];
126
103
  const SAFE_AGENT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
127
- const PRIVACY_BLOCKER_PATTERN =
128
- /raw prompt|rawprompt|source corpus|sourcecorpus|secret|\.env|raw command|raw log|internal url|private url|network|write files|run commands|spawn agents|write memory/i;
129
- const LENS_TO_EXPERTISE: Record<AgentLens, string[]> = {
130
- review: ["code-review"],
131
- qa: ["qa", "verification"],
132
- security: ["security", "privacy"],
133
- release: ["release", "packaging"],
134
- architecture: ["architecture"],
135
- migration: ["migration", "impact-analysis"],
136
- test: ["testing"],
137
- };
138
104
 
139
105
  export function createDefaultAgentPermissions(): AgentPermissions {
140
106
  return { ...DEFAULT_AGENT_PERMISSIONS };
@@ -170,16 +136,6 @@ export function parseAgentProfile(value: unknown): AgentProfile {
170
136
  throw new Error("Agent profile must be metadata-only and must not store raw prompts/source.");
171
137
  }
172
138
  const permissions = normalizeAgentPermissions(profile.permissions);
173
- if (
174
- permissions.canWriteFiles ||
175
- permissions.canRunCommands ||
176
- permissions.canUseNetwork ||
177
- permissions.canSpawnAgents ||
178
- permissions.canWriteMemory ||
179
- permissions.canReadSourceContent
180
- ) {
181
- throw new Error("Agent profile requests permissions outside I8 dry-run boundaries.");
182
- }
183
139
  if (!SAFE_AGENT_ID_PATTERN.test(profile.id)) throw new Error("Agent profile id is unsafe.");
184
140
  assertStringArray(profile.traits?.expertise, "profile.traits.expertise");
185
141
  assertStringArray(profile.traits?.stance, "profile.traits.stance");
@@ -188,11 +144,6 @@ export function parseAgentProfile(value: unknown): AgentProfile {
188
144
  assertStringArray(profile.inputs?.required, "profile.inputs.required");
189
145
  assertStringArray(profile.inputs?.optional, "profile.inputs.optional");
190
146
  assertStringArray(profile.inputs?.forbidden, "profile.inputs.forbidden");
191
- if (!FORBIDDEN_INPUTS.every((item) => profile.inputs.forbidden.includes(item))) {
192
- throw new Error(
193
- "Agent profile must forbid raw prompts, secrets, raw command logs, and source corpus.",
194
- );
195
- }
196
147
  if (!isKnownOutputSchema(profile.output?.schema))
197
148
  throw new Error("Agent profile output schema is unsupported.");
198
149
  assertStringArray(profile.output.requiredFields, "profile.output.requiredFields");
@@ -203,73 +154,6 @@ export async function readAgentProfile(path: string): Promise<AgentProfile> {
203
154
  return parseAgentProfile(JSON.parse(await readFile(path, "utf8")));
204
155
  }
205
156
 
206
- export function composeAgentDryRun(input: {
207
- contract: TaskContract;
208
- workflowId?: string;
209
- lenses?: AgentLens[];
210
- }): AgentComposeDryRunPlan {
211
- const mode = input.contract.route.mode;
212
- const workflowId = input.workflowId ?? input.contract.route.workflowId;
213
- const warnings: string[] = [];
214
- const blockers: string[] = [];
215
- const permissions = createDefaultAgentPermissions();
216
- const requestedLenses = dedupeLenses(input.lenses ?? []);
217
- const privacyBlockers = collectPrivacyBoundaryBlockers(
218
- input.contract,
219
- requestedLenses,
220
- workflowId,
221
- );
222
- blockers.push(...privacyBlockers);
223
-
224
- if (mode === "minimal") {
225
- return {
226
- ok: blockers.length === 0,
227
- taskId: input.contract.taskId,
228
- mode,
229
- workflowId,
230
- agents: [],
231
- permissions,
232
- mergePlan: createMergePlan([]),
233
- warnings,
234
- blockers,
235
- rationale: "Minimal mode does not force dynamic agents by default.",
236
- };
237
- }
238
-
239
- const selectedLenses = selectLenses(
240
- mode,
241
- requestedLenses,
242
- workflowId,
243
- input.contract.route.requiredReview,
244
- );
245
- const agents = selectedLenses.map((lens) => ({
246
- profile: createDynamicProfile(lens, input.contract, permissions),
247
- lens,
248
- reason: createLensReason(lens, mode, workflowId),
249
- plannedOnly: true as const,
250
- }));
251
-
252
- if (mode === "standard" && agents.length > 1) {
253
- blockers.push("Standard mode allows at most one optional reviewer/triager in I8 dry-run.");
254
- }
255
-
256
- return {
257
- ok: blockers.length === 0,
258
- taskId: input.contract.taskId,
259
- mode,
260
- workflowId,
261
- agents,
262
- permissions,
263
- mergePlan: createMergePlan(agents),
264
- warnings,
265
- blockers,
266
- rationale:
267
- agents.length === 0
268
- ? "No dynamic agents selected; deterministic verification may be sufficient."
269
- : `Selected ${agents.length} planned-only agent(s) based on mode/workflow/lenses.`,
270
- };
271
- }
272
-
273
157
  export function loadAgentContextDryRun(profile: AgentProfile): AgentContextDryRunBundle {
274
158
  const parsed = parseAgentProfile(profile);
275
159
  return {
@@ -288,10 +172,52 @@ export function loadAgentContextDryRun(profile: AgentProfile): AgentContextDryRu
288
172
  provenance: [`agent-profile:${parsed.id}`],
289
173
  },
290
174
  warnings: [],
291
- blockers: [],
175
+ advisories: [],
176
+ };
177
+ }
178
+
179
+ export async function loadAgentContext(input: {
180
+ homeDir: string;
181
+ profile: AgentProfile;
182
+ projectKey?: string;
183
+ roleId?: string;
184
+ workflowId?: string;
185
+ paths?: string[];
186
+ queryText?: string;
187
+ limit?: number;
188
+ }): Promise<AgentLoadedContextBundle> {
189
+ const parsed = parseAgentProfile(input.profile);
190
+ const pack = await createScopedKnowledgeContextPack({
191
+ homeDir: input.homeDir,
192
+ projectKey: input.projectKey,
193
+ roleId: input.roleId ?? parsed.id,
194
+ workflowId: input.workflowId,
195
+ paths: input.paths,
196
+ queryText: input.queryText,
197
+ limit: input.limit,
198
+ });
199
+ return {
200
+ profile: parsed,
201
+ contextPack: pack,
202
+ promptBlock: pack === null ? null : formatScopedKnowledgePromptBlock(pack),
203
+ warnings: pack?.warnings ?? [],
204
+ advisories: [],
205
+ rawContentStored: false,
292
206
  };
293
207
  }
294
208
 
209
+ export function formatAgentLoadedContextPromptBlock(bundle: AgentLoadedContextBundle): string {
210
+ if (bundle.promptBlock !== null) return bundle.promptBlock;
211
+ return [
212
+ "EvoDev Scoped Knowledge Context",
213
+ `Agent: ${bundle.profile.id}`,
214
+ "Raw content stored: false",
215
+ "",
216
+ "Applicable items:",
217
+ "- none",
218
+ ].join("\n");
219
+ }
220
+
295
221
  export function validateAgentOutput(
296
222
  schema: AgentOutputSchemaId,
297
223
  output: unknown,
@@ -341,47 +267,6 @@ export function mergeReviewFindings(outputs: ReviewFindingOutput[]): {
341
267
  return { acceptedFindings: [...byKey.values()], unresolvedConflicts: conflicts };
342
268
  }
343
269
 
344
- export function formatAgentComposeDryRun(plan: AgentComposeDryRunPlan): string {
345
- return [
346
- "EvoDev agent compose dry-run",
347
- "",
348
- `Task: ${plan.taskId}`,
349
- `Mode: ${plan.mode ?? "not routed"}`,
350
- `Workflow: ${plan.workflowId ?? "none"}`,
351
- `Rationale: ${plan.rationale}`,
352
- "No-write/no-spawn: true",
353
- "Privacy: local-private, metadata-only, raw prompts/source/secrets/logs forbidden",
354
- "Agents:",
355
- ...(plan.agents.length === 0
356
- ? [" - none"]
357
- : plan.agents.map(
358
- (agent) =>
359
- ` - ${agent.profile.id} [${agent.lens}] traits=${agent.profile.traits.expertise.join(",")} schema=${agent.profile.output.schema} plannedOnly=${agent.plannedOnly}`,
360
- )),
361
- "Inputs:",
362
- ...(plan.agents.length === 0
363
- ? [" - none"]
364
- : [
365
- ` - required: ${plan.agents[0].profile.inputs.required.join(",")}`,
366
- ` - optional: ${plan.agents[0].profile.inputs.optional.join(",")}`,
367
- ` - forbidden: ${plan.agents[0].profile.inputs.forbidden.join(",")}`,
368
- ]),
369
- "Permissions:",
370
- ...Object.entries(plan.permissions).map(([key, value]) => ` - ${key}: ${value}`),
371
- "Merge plan:",
372
- ` - strategy: ${plan.mergePlan.strategy}`,
373
- ` - outputSchema: ${plan.mergePlan.outputSchema ?? "none"}`,
374
- "Warnings:",
375
- ...(plan.warnings.length === 0
376
- ? [" - none"]
377
- : plan.warnings.map((warning) => ` - ${warning}`)),
378
- "Blockers:",
379
- ...(plan.blockers.length === 0
380
- ? [" - none"]
381
- : plan.blockers.map((blocker) => ` - ${blocker}`)),
382
- ].join("\n");
383
- }
384
-
385
270
  export function formatAgentContextDryRun(bundle: AgentContextDryRunBundle): string {
386
271
  return [
387
272
  "EvoDev agent load-context dry-run",
@@ -394,123 +279,13 @@ export function formatAgentContextDryRun(bundle: AgentContextDryRunBundle): stri
394
279
  ...bundle.context.forbiddenSections.map((section) => ` - ${section}`),
395
280
  "Permissions:",
396
281
  ...Object.entries(bundle.profile.permissions).map(([key, value]) => ` - ${key}: ${value}`),
397
- "Blockers:",
398
- ...(bundle.blockers.length === 0
282
+ "Advisories:",
283
+ ...(bundle.advisories.length === 0
399
284
  ? [" - none"]
400
- : bundle.blockers.map((blocker) => ` - ${blocker}`)),
285
+ : bundle.advisories.map((advisory) => ` - ${advisory}`)),
401
286
  ].join("\n");
402
287
  }
403
288
 
404
- function createDynamicProfile(
405
- lens: AgentLens,
406
- contract: TaskContract,
407
- permissions: AgentPermissions,
408
- ): AgentProfile {
409
- return {
410
- version: 1,
411
- id: `dynamic-${lens}-${contract.taskId}`.slice(0, 100),
412
- name: `Dynamic ${lens} reviewer`,
413
- persistence: "dynamic",
414
- description: `Task-scoped ${lens} profile for metadata-only dry-run planning.`,
415
- traits: {
416
- expertise: LENS_TO_EXPERTISE[lens],
417
- stance: ["skeptical-reviewer"],
418
- approach: ["evidence-first", "fail-closed"],
419
- domain: ["software-rd"],
420
- },
421
- inputs: {
422
- required: ["taskContract", "scope", "evidenceSummary"],
423
- optional: ["workflowPlan"],
424
- forbidden: FORBIDDEN_INPUTS,
425
- },
426
- permissions,
427
- output: {
428
- schema: "review-findings-v1",
429
- requiredFields: ["summary", "findings", "confidence", "evidenceRefs"],
430
- },
431
- privacy: {
432
- classification: "local-private",
433
- metadataOnly: true,
434
- rawPromptStored: false,
435
- sourceContentStored: false,
436
- },
437
- };
438
- }
439
-
440
- function selectLenses(
441
- mode: TaskExecutionMode | null,
442
- requested: AgentLens[],
443
- workflowId: string | null,
444
- requiredReview: string[],
445
- ): AgentLens[] {
446
- if (requested.length > 0) return mode === "standard" ? requested.slice(0, 1) : requested;
447
- if (mode === "standard") return requiredReview.length > 0 ? ["review"] : [];
448
- if (mode === "rigorous") {
449
- if (workflowId?.includes("security")) return ["security", "review"];
450
- if (workflowId?.includes("release")) return ["release", "security"];
451
- if (workflowId?.includes("migration")) return ["migration", "architecture"];
452
- if (workflowId?.includes("architecture")) return ["architecture", "review"];
453
- return requiredReview.length > 0 ? ["review", "qa"] : [];
454
- }
455
- return [];
456
- }
457
-
458
- function createMergePlan(agents: AgentPlannedInvocation[]): AgentMergePlan {
459
- if (agents.length === 0)
460
- return {
461
- strategy: "none",
462
- outputSchema: null,
463
- dedupeBy: [],
464
- conflictPolicy: [],
465
- failClosedCategories: [],
466
- };
467
- if (agents.length === 1)
468
- return {
469
- strategy: "single-output",
470
- outputSchema: agents[0].profile.output.schema,
471
- dedupeBy: [],
472
- conflictPolicy: [],
473
- failClosedCategories: [],
474
- };
475
- return {
476
- strategy: "dedupe-preserve-conflicts-fail-closed",
477
- outputSchema: "review-findings-v1",
478
- dedupeBy: ["category", "path", "line", "title"],
479
- conflictPolicy: ["preserve dissent", "keep higher severity unless evidence refutes"],
480
- failClosedCategories: ["security", "privacy", "release"],
481
- };
482
- }
483
-
484
- function createLensReason(
485
- lens: AgentLens,
486
- mode: TaskExecutionMode | null,
487
- workflowId: string | null,
488
- ): string {
489
- return `${lens} lens selected for ${mode ?? "unrouted"} mode${workflowId ? ` and workflow ${workflowId}` : ""}.`;
490
- }
491
-
492
- function collectPrivacyBoundaryBlockers(
493
- contract: TaskContract,
494
- lenses: AgentLens[],
495
- workflowId: string | null,
496
- ): string[] {
497
- const text = [
498
- contract.source.summary,
499
- contract.currentState.summary,
500
- contract.targetState.summary,
501
- contract.route.rationale,
502
- workflowId ?? "",
503
- ...contract.scope.allowedOperations,
504
- ...contract.scope.requiresUserConfirmation,
505
- ...lenses,
506
- ].join(" ");
507
- return PRIVACY_BLOCKER_PATTERN.test(text)
508
- ? [
509
- "Agent planning refuses privacy/risky context requiring raw data, writes, commands, network, spawning, or memory.",
510
- ]
511
- : [];
512
- }
513
-
514
289
  function validateRequiredObject(
515
290
  output: unknown,
516
291
  fields: string[],
@@ -534,12 +309,8 @@ function isKnownOutputSchema(value: unknown): value is AgentOutputSchemaId {
534
309
  );
535
310
  }
536
311
 
537
- function dedupeLenses(lenses: AgentLens[]): AgentLens[] {
538
- return [...new Set(lenses)];
539
- }
540
-
541
312
  function severityRank(severity: AgentFindingSeverity): number {
542
- return { info: 0, low: 1, medium: 2, high: 3, blocker: 4 }[severity];
313
+ return { info: 0, low: 1, medium: 2, high: 3, critical: 4 }[severity];
543
314
  }
544
315
 
545
316
  function assertString(value: unknown, path: string): void {