@evo-dev/core 0.0.1-alpha.2 → 0.0.1-alpha.20
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/skills/coding/knowledge-distillation/SKILL.md +5 -3
- package/assets/team/agents/code-reviewer.md +48 -0
- package/assets/team/agents/docs-maintainer.md +51 -0
- package/assets/team/agents/implementation-engineer.md +51 -0
- package/assets/team/agents/product-scope-analyst.md +58 -0
- package/assets/team/agents/release-engineer.md +55 -0
- package/assets/team/agents/security-boundary-reviewer.md +50 -0
- package/assets/team/agents/solution-architect.md +51 -0
- package/assets/team/agents/verification-engineer.md +51 -0
- package/assets/team/team.md +102 -0
- package/dist/assets/index.js +5 -5
- package/dist/config/index.js +793 -241
- package/dist/index.js +20840 -12908
- package/dist/plugins/index.js +13 -13
- package/package.json +1 -1
- package/src/agents/index.ts +1 -265
- package/src/code-agent-traces/index.ts +11 -12
- package/src/config/index.ts +2 -0
- package/src/config/settings.ts +116 -7
- package/src/config/store.ts +1 -1
- package/src/daemon/index.ts +1 -41
- package/src/evolution/candidates/index.ts +730 -0
- package/src/evolution/control/index.ts +20 -0
- package/src/evolution/evidence/analysis.ts +533 -0
- package/src/evolution/evidence/index.ts +3 -0
- package/src/evolution/evidence/session-memory/analysis.ts +287 -0
- package/src/evolution/evidence/session-memory/constants.ts +9 -0
- package/src/evolution/evidence/session-memory/index.ts +9 -0
- package/src/evolution/evidence/session-memory/paths.ts +29 -0
- package/src/evolution/evidence/session-memory/policy.ts +39 -0
- package/src/evolution/evidence/session-memory/retention.ts +643 -0
- package/src/evolution/evidence/session-memory/segment.ts +216 -0
- package/src/evolution/evidence/session-memory/semantic-packet.ts +408 -0
- package/src/evolution/evidence/session-memory/sensitivity.ts +335 -0
- package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
- package/src/evolution/evidence/session-memory/storage.ts +744 -0
- package/src/evolution/evidence/session-memory/types.ts +296 -0
- package/src/evolution/evidence/session-memory/updater.ts +199 -0
- package/src/evolution/formatters.ts +169 -0
- package/src/evolution/imports/apply.ts +435 -0
- package/src/evolution/imports/diff.ts +472 -0
- package/src/evolution/imports/index.ts +7 -0
- package/src/evolution/imports/materialize.ts +640 -0
- package/src/evolution/imports/paths.ts +129 -0
- package/src/evolution/imports/stage.ts +414 -0
- package/src/evolution/imports/storage.ts +952 -0
- package/src/evolution/imports/types.ts +226 -0
- package/src/evolution/index.ts +19 -2827
- package/src/evolution/knowledge/change-store.ts +558 -0
- package/src/evolution/knowledge/changes.ts +459 -0
- package/src/evolution/knowledge/freshness.ts +69 -0
- package/src/{knowledge → evolution/knowledge}/index.ts +1532 -206
- package/src/evolution/knowledge/review.ts +446 -0
- package/src/evolution/knowledge/support.ts +135 -0
- package/src/evolution/paths.ts +44 -0
- package/src/evolution/processor/distillation.ts +518 -0
- package/src/evolution/processor/index.ts +3 -0
- package/src/evolution/processor/process.ts +594 -0
- package/src/{learning → evolution/review}/index.ts +10 -14
- package/src/evolution/schema.ts +639 -0
- package/src/evolution/shared.ts +1053 -0
- package/src/evolution/triggers/classification.ts +102 -0
- package/src/evolution/triggers/index.ts +295 -0
- package/src/hooks/index.ts +281 -197
- package/src/index.ts +15 -4
- package/src/projects/index.ts +934 -0
- package/src/runtime-logs/index.ts +100 -13
- package/src/team/index.ts +582 -3
- package/src/utils/errors.ts +13 -0
- package/src/utils/fs.ts +40 -0
- package/src/utils/hash.ts +9 -0
- package/src/utils/ids.ts +12 -0
- package/src/utils/index.ts +7 -0
- package/src/utils/parsing.ts +11 -0
- package/src/utils/text.ts +18 -0
- package/src/utils/time.ts +5 -0
- package/src/workflow/index.ts +3 -21
- package/src/project/index.ts +0 -507
- package/src/task/index.ts +0 -840
package/dist/plugins/index.js
CHANGED
|
@@ -248,18 +248,18 @@ function getEnabledPluginIds(settings) {
|
|
|
248
248
|
return Object.entries(settings.plugins).filter(([, pluginSettings]) => pluginSettings.enabled).map(([pluginId]) => pluginId).sort((left, right) => left.localeCompare(right));
|
|
249
249
|
}
|
|
250
250
|
export {
|
|
251
|
-
|
|
252
|
-
validateCodexCapabilityVerificationArtifact,
|
|
253
|
-
runPluginConformance,
|
|
254
|
-
resolveCodexCapabilityArtifactPath,
|
|
255
|
-
readCodexCapabilityVerificationArtifact,
|
|
256
|
-
negotiatePluginCapabilities,
|
|
257
|
-
isCapabilityUsable,
|
|
258
|
-
getEnabledPluginIds,
|
|
259
|
-
formatCodexCapabilityVerificationArtifact,
|
|
260
|
-
createUnknownNegotiatedCapabilities,
|
|
261
|
-
createPluginRegistry,
|
|
262
|
-
createCodexCapabilityVerificationArtifact,
|
|
251
|
+
PluginRegistry,
|
|
263
252
|
PluginRegistryError,
|
|
264
|
-
|
|
253
|
+
createCodexCapabilityVerificationArtifact,
|
|
254
|
+
createPluginRegistry,
|
|
255
|
+
createUnknownNegotiatedCapabilities,
|
|
256
|
+
formatCodexCapabilityVerificationArtifact,
|
|
257
|
+
getEnabledPluginIds,
|
|
258
|
+
isCapabilityUsable,
|
|
259
|
+
negotiatePluginCapabilities,
|
|
260
|
+
readCodexCapabilityVerificationArtifact,
|
|
261
|
+
resolveCodexCapabilityArtifactPath,
|
|
262
|
+
runPluginConformance,
|
|
263
|
+
validateCodexCapabilityVerificationArtifact,
|
|
264
|
+
writeCodexCapabilityVerificationArtifact
|
|
265
265
|
};
|
package/package.json
CHANGED
package/src/agents/index.ts
CHANGED
|
@@ -3,18 +3,9 @@ import {
|
|
|
3
3
|
type ScopedKnowledgeContextPack,
|
|
4
4
|
createScopedKnowledgeContextPack,
|
|
5
5
|
formatScopedKnowledgePromptBlock,
|
|
6
|
-
} from "../knowledge/index.ts";
|
|
7
|
-
import type { TaskContract, TaskExecutionMode } from "../task/index.ts";
|
|
6
|
+
} from "../evolution/knowledge/index.ts";
|
|
8
7
|
|
|
9
8
|
export type AgentPersistence = "named" | "dynamic";
|
|
10
|
-
export type AgentLens =
|
|
11
|
-
| "review"
|
|
12
|
-
| "qa"
|
|
13
|
-
| "security"
|
|
14
|
-
| "release"
|
|
15
|
-
| "architecture"
|
|
16
|
-
| "migration"
|
|
17
|
-
| "test";
|
|
18
9
|
export type AgentOutputSchemaId =
|
|
19
10
|
| "review-findings-v1"
|
|
20
11
|
| "verification-summary-v1"
|
|
@@ -61,34 +52,6 @@ export interface AgentProfile {
|
|
|
61
52
|
};
|
|
62
53
|
}
|
|
63
54
|
|
|
64
|
-
export interface AgentPlannedInvocation {
|
|
65
|
-
profile: AgentProfile;
|
|
66
|
-
lens: AgentLens;
|
|
67
|
-
reason: string;
|
|
68
|
-
plannedOnly: true;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface AgentMergePlan {
|
|
72
|
-
strategy: "none" | "single-output" | "dedupe-preserve-conflicts";
|
|
73
|
-
outputSchema: AgentOutputSchemaId | null;
|
|
74
|
-
dedupeBy: string[];
|
|
75
|
-
conflictPolicy: string[];
|
|
76
|
-
advisoryCategories: string[];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface AgentComposeDryRunPlan {
|
|
80
|
-
ok: boolean;
|
|
81
|
-
taskId: string;
|
|
82
|
-
mode: TaskExecutionMode | null;
|
|
83
|
-
workflowId: string | null;
|
|
84
|
-
agents: AgentPlannedInvocation[];
|
|
85
|
-
permissions: AgentPermissions;
|
|
86
|
-
mergePlan: AgentMergePlan;
|
|
87
|
-
warnings: string[];
|
|
88
|
-
advisories: string[];
|
|
89
|
-
rationale: string;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
55
|
export interface AgentContextDryRunBundle {
|
|
93
56
|
profile: AgentProfile;
|
|
94
57
|
context: {
|
|
@@ -138,17 +101,6 @@ const DEFAULT_AGENT_PERMISSIONS: AgentPermissions = {
|
|
|
138
101
|
};
|
|
139
102
|
const FORBIDDEN_INPUTS = ["rawPrompts", "secrets", "rawCommandLogs", "sourceCorpus"];
|
|
140
103
|
const SAFE_AGENT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
|
|
141
|
-
const PRIVACY_ADVISORY_PATTERN =
|
|
142
|
-
/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;
|
|
143
|
-
const LENS_TO_EXPERTISE: Record<AgentLens, string[]> = {
|
|
144
|
-
review: ["code-review"],
|
|
145
|
-
qa: ["qa", "verification"],
|
|
146
|
-
security: ["security", "privacy"],
|
|
147
|
-
release: ["release", "packaging"],
|
|
148
|
-
architecture: ["architecture"],
|
|
149
|
-
migration: ["migration", "impact-analysis"],
|
|
150
|
-
test: ["testing"],
|
|
151
|
-
};
|
|
152
104
|
|
|
153
105
|
export function createDefaultAgentPermissions(): AgentPermissions {
|
|
154
106
|
return { ...DEFAULT_AGENT_PERMISSIONS };
|
|
@@ -202,67 +154,6 @@ export async function readAgentProfile(path: string): Promise<AgentProfile> {
|
|
|
202
154
|
return parseAgentProfile(JSON.parse(await readFile(path, "utf8")));
|
|
203
155
|
}
|
|
204
156
|
|
|
205
|
-
export function composeAgentDryRun(input: {
|
|
206
|
-
contract: TaskContract;
|
|
207
|
-
workflowId?: string;
|
|
208
|
-
lenses?: AgentLens[];
|
|
209
|
-
}): AgentComposeDryRunPlan {
|
|
210
|
-
const mode = input.contract.route.mode;
|
|
211
|
-
const workflowId = input.workflowId ?? input.contract.route.workflowId;
|
|
212
|
-
const warnings: string[] = [];
|
|
213
|
-
const permissions = createDefaultAgentPermissions();
|
|
214
|
-
const requestedLenses = dedupeLenses(input.lenses ?? []);
|
|
215
|
-
const advisories = collectPrivacyBoundaryAdvisories(input.contract, requestedLenses, workflowId);
|
|
216
|
-
|
|
217
|
-
if (mode === "minimal") {
|
|
218
|
-
return {
|
|
219
|
-
ok: advisories.length === 0,
|
|
220
|
-
taskId: input.contract.taskId,
|
|
221
|
-
mode,
|
|
222
|
-
workflowId,
|
|
223
|
-
agents: [],
|
|
224
|
-
permissions,
|
|
225
|
-
mergePlan: createMergePlan([]),
|
|
226
|
-
warnings,
|
|
227
|
-
advisories,
|
|
228
|
-
rationale: "Minimal mode does not force dynamic agents by default.",
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
const selectedLenses = selectLenses(
|
|
233
|
-
mode,
|
|
234
|
-
requestedLenses,
|
|
235
|
-
workflowId,
|
|
236
|
-
input.contract.route.requiredReview,
|
|
237
|
-
);
|
|
238
|
-
const agents = selectedLenses.map((lens) => ({
|
|
239
|
-
profile: createDynamicProfile(lens, input.contract, permissions),
|
|
240
|
-
lens,
|
|
241
|
-
reason: createLensReason(lens, mode, workflowId),
|
|
242
|
-
plannedOnly: true as const,
|
|
243
|
-
}));
|
|
244
|
-
|
|
245
|
-
if (mode === "standard" && agents.length > 1) {
|
|
246
|
-
warnings.push("Standard mode advisory selected more than one reviewer/triager.");
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
return {
|
|
250
|
-
ok: advisories.length === 0,
|
|
251
|
-
taskId: input.contract.taskId,
|
|
252
|
-
mode,
|
|
253
|
-
workflowId,
|
|
254
|
-
agents,
|
|
255
|
-
permissions,
|
|
256
|
-
mergePlan: createMergePlan(agents),
|
|
257
|
-
warnings,
|
|
258
|
-
advisories,
|
|
259
|
-
rationale:
|
|
260
|
-
agents.length === 0
|
|
261
|
-
? "No dynamic agents selected; deterministic verification may be sufficient."
|
|
262
|
-
: `Selected ${agents.length} planned-only agent(s) based on mode/workflow/lenses.`,
|
|
263
|
-
};
|
|
264
|
-
}
|
|
265
|
-
|
|
266
157
|
export function loadAgentContextDryRun(profile: AgentProfile): AgentContextDryRunBundle {
|
|
267
158
|
const parsed = parseAgentProfile(profile);
|
|
268
159
|
return {
|
|
@@ -376,47 +267,6 @@ export function mergeReviewFindings(outputs: ReviewFindingOutput[]): {
|
|
|
376
267
|
return { acceptedFindings: [...byKey.values()], unresolvedConflicts: conflicts };
|
|
377
268
|
}
|
|
378
269
|
|
|
379
|
-
export function formatAgentComposeDryRun(plan: AgentComposeDryRunPlan): string {
|
|
380
|
-
return [
|
|
381
|
-
"EvoDev agent compose dry-run",
|
|
382
|
-
"",
|
|
383
|
-
`Task: ${plan.taskId}`,
|
|
384
|
-
`Mode: ${plan.mode ?? "not routed"}`,
|
|
385
|
-
`Workflow: ${plan.workflowId ?? "none"}`,
|
|
386
|
-
`Rationale: ${plan.rationale}`,
|
|
387
|
-
"No-write/no-spawn: true",
|
|
388
|
-
"Privacy: local-private, metadata-only, raw prompts/source/secrets/logs forbidden",
|
|
389
|
-
"Agents:",
|
|
390
|
-
...(plan.agents.length === 0
|
|
391
|
-
? [" - none"]
|
|
392
|
-
: plan.agents.map(
|
|
393
|
-
(agent) =>
|
|
394
|
-
` - ${agent.profile.id} [${agent.lens}] traits=${agent.profile.traits.expertise.join(",")} schema=${agent.profile.output.schema} plannedOnly=${agent.plannedOnly}`,
|
|
395
|
-
)),
|
|
396
|
-
"Inputs:",
|
|
397
|
-
...(plan.agents.length === 0
|
|
398
|
-
? [" - none"]
|
|
399
|
-
: [
|
|
400
|
-
` - required: ${plan.agents[0].profile.inputs.required.join(",")}`,
|
|
401
|
-
` - optional: ${plan.agents[0].profile.inputs.optional.join(",")}`,
|
|
402
|
-
` - forbidden: ${plan.agents[0].profile.inputs.forbidden.join(",")}`,
|
|
403
|
-
]),
|
|
404
|
-
"Permissions:",
|
|
405
|
-
...Object.entries(plan.permissions).map(([key, value]) => ` - ${key}: ${value}`),
|
|
406
|
-
"Merge plan:",
|
|
407
|
-
` - strategy: ${plan.mergePlan.strategy}`,
|
|
408
|
-
` - outputSchema: ${plan.mergePlan.outputSchema ?? "none"}`,
|
|
409
|
-
"Warnings:",
|
|
410
|
-
...(plan.warnings.length === 0
|
|
411
|
-
? [" - none"]
|
|
412
|
-
: plan.warnings.map((warning) => ` - ${warning}`)),
|
|
413
|
-
"Advisories:",
|
|
414
|
-
...(plan.advisories.length === 0
|
|
415
|
-
? [" - none"]
|
|
416
|
-
: plan.advisories.map((advisory) => ` - ${advisory}`)),
|
|
417
|
-
].join("\n");
|
|
418
|
-
}
|
|
419
|
-
|
|
420
270
|
export function formatAgentContextDryRun(bundle: AgentContextDryRunBundle): string {
|
|
421
271
|
return [
|
|
422
272
|
"EvoDev agent load-context dry-run",
|
|
@@ -436,116 +286,6 @@ export function formatAgentContextDryRun(bundle: AgentContextDryRunBundle): stri
|
|
|
436
286
|
].join("\n");
|
|
437
287
|
}
|
|
438
288
|
|
|
439
|
-
function createDynamicProfile(
|
|
440
|
-
lens: AgentLens,
|
|
441
|
-
contract: TaskContract,
|
|
442
|
-
permissions: AgentPermissions,
|
|
443
|
-
): AgentProfile {
|
|
444
|
-
return {
|
|
445
|
-
version: 1,
|
|
446
|
-
id: `dynamic-${lens}-${contract.taskId}`.slice(0, 100),
|
|
447
|
-
name: `Dynamic ${lens} reviewer`,
|
|
448
|
-
persistence: "dynamic",
|
|
449
|
-
description: `Task-scoped ${lens} profile for metadata-only dry-run planning.`,
|
|
450
|
-
traits: {
|
|
451
|
-
expertise: LENS_TO_EXPERTISE[lens],
|
|
452
|
-
stance: ["skeptical-reviewer"],
|
|
453
|
-
approach: ["evidence-first", "advisory"],
|
|
454
|
-
domain: ["software-rd"],
|
|
455
|
-
},
|
|
456
|
-
inputs: {
|
|
457
|
-
required: ["taskContract", "scope", "evidenceSummary"],
|
|
458
|
-
optional: ["workflowPlan"],
|
|
459
|
-
forbidden: FORBIDDEN_INPUTS,
|
|
460
|
-
},
|
|
461
|
-
permissions,
|
|
462
|
-
output: {
|
|
463
|
-
schema: "review-findings-v1",
|
|
464
|
-
requiredFields: ["summary", "findings", "confidence", "evidenceRefs"],
|
|
465
|
-
},
|
|
466
|
-
privacy: {
|
|
467
|
-
classification: "local-private",
|
|
468
|
-
metadataOnly: true,
|
|
469
|
-
rawPromptStored: false,
|
|
470
|
-
sourceContentStored: false,
|
|
471
|
-
},
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
function selectLenses(
|
|
476
|
-
mode: TaskExecutionMode | null,
|
|
477
|
-
requested: AgentLens[],
|
|
478
|
-
workflowId: string | null,
|
|
479
|
-
requiredReview: string[],
|
|
480
|
-
): AgentLens[] {
|
|
481
|
-
if (requested.length > 0) return mode === "standard" ? requested.slice(0, 1) : requested;
|
|
482
|
-
if (mode === "standard") return requiredReview.length > 0 ? ["review"] : [];
|
|
483
|
-
if (mode === "rigorous") {
|
|
484
|
-
if (workflowId?.includes("security")) return ["security", "review"];
|
|
485
|
-
if (workflowId?.includes("release")) return ["release", "security"];
|
|
486
|
-
if (workflowId?.includes("migration")) return ["migration", "architecture"];
|
|
487
|
-
if (workflowId?.includes("architecture")) return ["architecture", "review"];
|
|
488
|
-
return requiredReview.length > 0 ? ["review", "qa"] : [];
|
|
489
|
-
}
|
|
490
|
-
return [];
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
function createMergePlan(agents: AgentPlannedInvocation[]): AgentMergePlan {
|
|
494
|
-
if (agents.length === 0)
|
|
495
|
-
return {
|
|
496
|
-
strategy: "none",
|
|
497
|
-
outputSchema: null,
|
|
498
|
-
dedupeBy: [],
|
|
499
|
-
conflictPolicy: [],
|
|
500
|
-
advisoryCategories: [],
|
|
501
|
-
};
|
|
502
|
-
if (agents.length === 1)
|
|
503
|
-
return {
|
|
504
|
-
strategy: "single-output",
|
|
505
|
-
outputSchema: agents[0].profile.output.schema,
|
|
506
|
-
dedupeBy: [],
|
|
507
|
-
conflictPolicy: [],
|
|
508
|
-
advisoryCategories: [],
|
|
509
|
-
};
|
|
510
|
-
return {
|
|
511
|
-
strategy: "dedupe-preserve-conflicts",
|
|
512
|
-
outputSchema: "review-findings-v1",
|
|
513
|
-
dedupeBy: ["category", "path", "line", "title"],
|
|
514
|
-
conflictPolicy: ["preserve dissent", "keep higher severity unless evidence refutes"],
|
|
515
|
-
advisoryCategories: ["security", "privacy", "release"],
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
function createLensReason(
|
|
520
|
-
lens: AgentLens,
|
|
521
|
-
mode: TaskExecutionMode | null,
|
|
522
|
-
workflowId: string | null,
|
|
523
|
-
): string {
|
|
524
|
-
return `${lens} lens selected for ${mode ?? "unrouted"} mode${workflowId ? ` and workflow ${workflowId}` : ""}.`;
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
function collectPrivacyBoundaryAdvisories(
|
|
528
|
-
contract: TaskContract,
|
|
529
|
-
lenses: AgentLens[],
|
|
530
|
-
workflowId: string | null,
|
|
531
|
-
): string[] {
|
|
532
|
-
const text = [
|
|
533
|
-
contract.source.summary,
|
|
534
|
-
contract.currentState.summary,
|
|
535
|
-
contract.targetState.summary,
|
|
536
|
-
contract.route.rationale,
|
|
537
|
-
workflowId ?? "",
|
|
538
|
-
...contract.scope.allowedOperations,
|
|
539
|
-
...contract.scope.requiresUserConfirmation,
|
|
540
|
-
...lenses,
|
|
541
|
-
].join(" ");
|
|
542
|
-
return PRIVACY_ADVISORY_PATTERN.test(text)
|
|
543
|
-
? [
|
|
544
|
-
"Agent planning detected privacy/risky context requiring raw data, writes, commands, network, spawning, or memory.",
|
|
545
|
-
]
|
|
546
|
-
: [];
|
|
547
|
-
}
|
|
548
|
-
|
|
549
289
|
function validateRequiredObject(
|
|
550
290
|
output: unknown,
|
|
551
291
|
fields: string[],
|
|
@@ -569,10 +309,6 @@ function isKnownOutputSchema(value: unknown): value is AgentOutputSchemaId {
|
|
|
569
309
|
);
|
|
570
310
|
}
|
|
571
311
|
|
|
572
|
-
function dedupeLenses(lenses: AgentLens[]): AgentLens[] {
|
|
573
|
-
return [...new Set(lenses)];
|
|
574
|
-
}
|
|
575
|
-
|
|
576
312
|
function severityRank(severity: AgentFindingSeverity): number {
|
|
577
313
|
return { info: 0, low: 1, medium: 2, high: 3, critical: 4 }[severity];
|
|
578
314
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
3
2
|
import { dirname, isAbsolute, join, normalize, relative } from "node:path";
|
|
4
3
|
import { resolveEvoDevPaths } from "../config/paths.ts";
|
|
4
|
+
import { resolveProjectWorkspaceFromCwd } from "../projects/index.ts";
|
|
5
5
|
import { resolveTraceSessionKey, resolveTraceTeamContext } from "../runtime-logs/index.ts";
|
|
6
|
+
import { normalizeTimestamp, sha256Short } from "../utils/index.ts";
|
|
6
7
|
|
|
7
8
|
export type CodeAgentTraceTarget = "claude" | "codex";
|
|
8
9
|
export type CodeAgentTraceRefSource =
|
|
@@ -264,6 +265,11 @@ export async function recordCodeAgentTraceRefFromHook(
|
|
|
264
265
|
payload: input.payload,
|
|
265
266
|
environment,
|
|
266
267
|
});
|
|
268
|
+
const cwd = optionalString(input.payload.cwd);
|
|
269
|
+
const workspace =
|
|
270
|
+
team === null && cwd !== null
|
|
271
|
+
? await resolveProjectWorkspaceFromCwd({ homeDir: input.homeDir, cwd })
|
|
272
|
+
: null;
|
|
267
273
|
const source =
|
|
268
274
|
sessionIdFromPayload !== null || tracePathFromPayload !== null ? "hook-payload" : "environment";
|
|
269
275
|
|
|
@@ -271,10 +277,10 @@ export async function recordCodeAgentTraceRefFromHook(
|
|
|
271
277
|
target: input.target,
|
|
272
278
|
sessionKey: resolveTraceSessionKey(input.payload),
|
|
273
279
|
nativeSessionId,
|
|
274
|
-
projectKey: team?.projectKey ?? null,
|
|
280
|
+
projectKey: team?.projectKey ?? workspace?.projectKey ?? null,
|
|
275
281
|
runId: team?.runId ?? null,
|
|
276
282
|
roleId: team?.roleId ?? null,
|
|
277
|
-
cwd
|
|
283
|
+
cwd,
|
|
278
284
|
discoveredAt: input.now,
|
|
279
285
|
source,
|
|
280
286
|
tracePath: normalizedPath,
|
|
@@ -440,7 +446,7 @@ function hasRawTraversalSegment(path: string): boolean {
|
|
|
440
446
|
|
|
441
447
|
function hashOptionalIdentifier(value: string | null): string | null {
|
|
442
448
|
if (value === null || value.trim() === "") return null;
|
|
443
|
-
return `sha256-${
|
|
449
|
+
return `sha256-${sha256Short(value)}`;
|
|
444
450
|
}
|
|
445
451
|
|
|
446
452
|
function sanitizeHashMetadata(value: string | null): string | null {
|
|
@@ -454,8 +460,7 @@ function sanitizePersistentIdentifier(value: string, prefix: string): string {
|
|
|
454
460
|
if (!SENSITIVE_IDENTIFIER_PATTERN.test(value) && !SENSITIVE_IDENTIFIER_PATTERN.test(pathSafe)) {
|
|
455
461
|
return pathSafe;
|
|
456
462
|
}
|
|
457
|
-
|
|
458
|
-
return `${prefix}-${hash}`;
|
|
463
|
+
return `${prefix}-${sha256Short(value)}`;
|
|
459
464
|
}
|
|
460
465
|
|
|
461
466
|
function sanitizeNotes(notes: string[]): string[] {
|
|
@@ -471,12 +476,6 @@ function sanitizeNote(note: string): string {
|
|
|
471
476
|
return truncated;
|
|
472
477
|
}
|
|
473
478
|
|
|
474
|
-
function normalizeTimestamp(value?: Date | string): string {
|
|
475
|
-
if (value instanceof Date) return value.toISOString();
|
|
476
|
-
if (typeof value === "string" && value.trim() !== "") return new Date(value).toISOString();
|
|
477
|
-
return new Date().toISOString();
|
|
478
|
-
}
|
|
479
|
-
|
|
480
479
|
function optionalString(value: unknown): string | null {
|
|
481
480
|
return typeof value === "string" && value.trim() !== "" ? value : null;
|
|
482
481
|
}
|
package/src/config/index.ts
CHANGED
|
@@ -8,11 +8,13 @@ export {
|
|
|
8
8
|
} from "./registry.ts";
|
|
9
9
|
export {
|
|
10
10
|
type EvoDevSettings,
|
|
11
|
+
type EvolutionSettings,
|
|
11
12
|
type MemorySettings,
|
|
12
13
|
type PluginSettings,
|
|
13
14
|
type SettingsInput,
|
|
14
15
|
type TeamRuntimeSettings,
|
|
15
16
|
createDefaultMemorySettings,
|
|
17
|
+
createDefaultEvolutionSettings,
|
|
16
18
|
createDefaultTeamRuntimeSettings,
|
|
17
19
|
createDefaultSettings,
|
|
18
20
|
mergeSettings,
|
package/src/config/settings.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
+
import {
|
|
3
|
+
type SessionMemoryPolicySnapshot,
|
|
4
|
+
createDefaultSessionMemoryPolicy,
|
|
5
|
+
parseSessionMemoryPolicy,
|
|
6
|
+
} from "../evolution/evidence/session-memory/index.ts";
|
|
2
7
|
import { type HookSettings, createDefaultHookSettings, parseHookSettings } from "../hooks/index.ts";
|
|
3
8
|
import { EvoDevConfigError, describeType } from "./errors.ts";
|
|
4
9
|
import { resolveEvoDevPaths } from "./paths.ts";
|
|
@@ -10,10 +15,30 @@ export interface PluginSettings {
|
|
|
10
15
|
}
|
|
11
16
|
|
|
12
17
|
export interface MemorySettings {
|
|
13
|
-
|
|
18
|
+
reviewKnowledgeUpdates: boolean;
|
|
14
19
|
runtimeInjection: boolean;
|
|
15
20
|
staleReview: boolean;
|
|
16
21
|
lexicalIndex: boolean;
|
|
22
|
+
sessionMemory: SessionMemoryPolicySnapshot;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type LegacyMemorySettingsInput = Partial<MemorySettings> & {
|
|
26
|
+
/**
|
|
27
|
+
* Deprecated compatibility input. This flag was never connected to OKF activation and is
|
|
28
|
+
* intentionally omitted from canonical settings output.
|
|
29
|
+
*/
|
|
30
|
+
autoAccept?: boolean;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export interface EvolutionSettings {
|
|
34
|
+
schedule: {
|
|
35
|
+
dailyTime: string;
|
|
36
|
+
};
|
|
37
|
+
automation: {
|
|
38
|
+
knowledge: boolean;
|
|
39
|
+
semanticKnowledge: boolean;
|
|
40
|
+
recommendations: boolean;
|
|
41
|
+
};
|
|
17
42
|
}
|
|
18
43
|
|
|
19
44
|
export interface EvoDevSettings {
|
|
@@ -39,6 +64,7 @@ export interface EvoDevSettings {
|
|
|
39
64
|
hooks: HookSettings;
|
|
40
65
|
teamRuntime: TeamRuntimeSettings;
|
|
41
66
|
memory: MemorySettings;
|
|
67
|
+
evolution: EvolutionSettings;
|
|
42
68
|
}
|
|
43
69
|
|
|
44
70
|
export type SettingsInput = Partial<{
|
|
@@ -55,7 +81,11 @@ export type SettingsInput = Partial<{
|
|
|
55
81
|
doctor: Partial<EvoDevSettings["doctor"]>;
|
|
56
82
|
hooks: unknown;
|
|
57
83
|
teamRuntime: Partial<TeamRuntimeSettings>;
|
|
58
|
-
memory:
|
|
84
|
+
memory: LegacyMemorySettingsInput;
|
|
85
|
+
evolution: Partial<{
|
|
86
|
+
schedule: Partial<EvolutionSettings["schedule"]>;
|
|
87
|
+
automation: Partial<EvolutionSettings["automation"]>;
|
|
88
|
+
}>;
|
|
59
89
|
}>;
|
|
60
90
|
|
|
61
91
|
export interface TeamRuntimeSettings {
|
|
@@ -96,6 +126,7 @@ export function createDefaultSettings(os: string = process.platform): EvoDevSett
|
|
|
96
126
|
hooks: createDefaultHookSettings(),
|
|
97
127
|
teamRuntime: createDefaultTeamRuntimeSettings(),
|
|
98
128
|
memory: createDefaultMemorySettings(),
|
|
129
|
+
evolution: createDefaultEvolutionSettings(),
|
|
99
130
|
};
|
|
100
131
|
}
|
|
101
132
|
|
|
@@ -111,10 +142,24 @@ export function createDefaultTeamRuntimeSettings(): TeamRuntimeSettings {
|
|
|
111
142
|
|
|
112
143
|
export function createDefaultMemorySettings(): MemorySettings {
|
|
113
144
|
return {
|
|
114
|
-
|
|
145
|
+
reviewKnowledgeUpdates: true,
|
|
115
146
|
runtimeInjection: true,
|
|
116
147
|
staleReview: true,
|
|
117
148
|
lexicalIndex: true,
|
|
149
|
+
sessionMemory: createDefaultSessionMemoryPolicy(),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function createDefaultEvolutionSettings(): EvolutionSettings {
|
|
154
|
+
return {
|
|
155
|
+
schedule: {
|
|
156
|
+
dailyTime: "02:00",
|
|
157
|
+
},
|
|
158
|
+
automation: {
|
|
159
|
+
knowledge: true,
|
|
160
|
+
semanticKnowledge: false,
|
|
161
|
+
recommendations: false,
|
|
162
|
+
},
|
|
118
163
|
};
|
|
119
164
|
}
|
|
120
165
|
|
|
@@ -162,6 +207,18 @@ export function mergeSettings(
|
|
|
162
207
|
...defaults.memory,
|
|
163
208
|
...existing.memory,
|
|
164
209
|
},
|
|
210
|
+
evolution: {
|
|
211
|
+
...defaults.evolution,
|
|
212
|
+
...existing.evolution,
|
|
213
|
+
schedule: {
|
|
214
|
+
...defaults.evolution.schedule,
|
|
215
|
+
...existing.evolution?.schedule,
|
|
216
|
+
},
|
|
217
|
+
automation: {
|
|
218
|
+
...defaults.evolution.automation,
|
|
219
|
+
...existing.evolution?.automation,
|
|
220
|
+
},
|
|
221
|
+
},
|
|
165
222
|
};
|
|
166
223
|
|
|
167
224
|
return parseSettings(merged);
|
|
@@ -222,19 +279,64 @@ export function parseSettings(value: unknown): EvoDevSettings {
|
|
|
222
279
|
"settings.teamRuntime",
|
|
223
280
|
),
|
|
224
281
|
memory: parseMemorySettings(root.memory ?? createDefaultMemorySettings(), "settings.memory"),
|
|
282
|
+
evolution: parseEvolutionSettings(
|
|
283
|
+
root.evolution ?? createDefaultEvolutionSettings(),
|
|
284
|
+
"settings.evolution",
|
|
285
|
+
),
|
|
225
286
|
};
|
|
226
287
|
|
|
227
288
|
return parsed;
|
|
228
289
|
}
|
|
229
290
|
|
|
291
|
+
function parseEvolutionSettings(value: unknown, path: string): EvolutionSettings {
|
|
292
|
+
const input = expectRecord(value, path);
|
|
293
|
+
const defaults = createDefaultEvolutionSettings();
|
|
294
|
+
const schedule = expectRecord(input.schedule ?? defaults.schedule, `${path}.schedule`);
|
|
295
|
+
const automation = expectRecord(input.automation ?? defaults.automation, `${path}.automation`);
|
|
296
|
+
return {
|
|
297
|
+
schedule: {
|
|
298
|
+
dailyTime: parseDailyTime(
|
|
299
|
+
schedule.dailyTime ?? defaults.schedule.dailyTime,
|
|
300
|
+
`${path}.schedule.dailyTime`,
|
|
301
|
+
),
|
|
302
|
+
},
|
|
303
|
+
automation: {
|
|
304
|
+
knowledge:
|
|
305
|
+
automation.knowledge === undefined
|
|
306
|
+
? defaults.automation.knowledge
|
|
307
|
+
: expectBoolean(automation.knowledge, `${path}.automation.knowledge`),
|
|
308
|
+
semanticKnowledge:
|
|
309
|
+
automation.semanticKnowledge === undefined
|
|
310
|
+
? defaults.automation.semanticKnowledge
|
|
311
|
+
: expectBoolean(automation.semanticKnowledge, `${path}.automation.semanticKnowledge`),
|
|
312
|
+
recommendations:
|
|
313
|
+
automation.recommendations === undefined
|
|
314
|
+
? defaults.automation.recommendations
|
|
315
|
+
: expectBoolean(automation.recommendations, `${path}.automation.recommendations`),
|
|
316
|
+
},
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function parseDailyTime(value: unknown, path: string): string {
|
|
321
|
+
const dailyTime = expectString(value, path);
|
|
322
|
+
const match = /^(\d{2}):(\d{2})$/u.exec(dailyTime);
|
|
323
|
+
if (match === null || Number(match[1]) > 23 || Number(match[2]) > 59) {
|
|
324
|
+
throw new EvoDevConfigError(`Invalid ${path}; expected a 24-hour HH:MM time`);
|
|
325
|
+
}
|
|
326
|
+
return dailyTime;
|
|
327
|
+
}
|
|
328
|
+
|
|
230
329
|
function parseMemorySettings(value: unknown, path: string): MemorySettings {
|
|
231
330
|
const input = expectRecord(value, path);
|
|
232
331
|
const defaults = createDefaultMemorySettings();
|
|
332
|
+
if (input.autoAccept !== undefined) {
|
|
333
|
+
expectBoolean(input.autoAccept, `${path}.autoAccept`);
|
|
334
|
+
}
|
|
233
335
|
return {
|
|
234
|
-
|
|
235
|
-
input.
|
|
236
|
-
? defaults.
|
|
237
|
-
: expectBoolean(input.
|
|
336
|
+
reviewKnowledgeUpdates:
|
|
337
|
+
input.reviewKnowledgeUpdates === undefined
|
|
338
|
+
? defaults.reviewKnowledgeUpdates
|
|
339
|
+
: expectBoolean(input.reviewKnowledgeUpdates, `${path}.reviewKnowledgeUpdates`),
|
|
238
340
|
runtimeInjection:
|
|
239
341
|
input.runtimeInjection === undefined
|
|
240
342
|
? defaults.runtimeInjection
|
|
@@ -247,6 +349,9 @@ function parseMemorySettings(value: unknown, path: string): MemorySettings {
|
|
|
247
349
|
input.lexicalIndex === undefined
|
|
248
350
|
? defaults.lexicalIndex
|
|
249
351
|
: expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`),
|
|
352
|
+
sessionMemory: parseSessionMemoryPolicy(
|
|
353
|
+
isPlainRecord(input.sessionMemory) ? input.sessionMemory : defaults.sessionMemory,
|
|
354
|
+
),
|
|
250
355
|
};
|
|
251
356
|
}
|
|
252
357
|
|
|
@@ -311,6 +416,10 @@ function expectRecord(value: unknown, path: string): Record<string, unknown> {
|
|
|
311
416
|
return value as Record<string, unknown>;
|
|
312
417
|
}
|
|
313
418
|
|
|
419
|
+
function isPlainRecord(value: unknown): value is Record<string, unknown> {
|
|
420
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
421
|
+
}
|
|
422
|
+
|
|
314
423
|
function isNotFoundError(error: unknown): boolean {
|
|
315
424
|
return (
|
|
316
425
|
error instanceof Error && "code" in error && (error as NodeJS.ErrnoException).code === "ENOENT"
|
package/src/config/store.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
-
import { ensureOkfKnowledgeBase } from "../knowledge/index.ts";
|
|
3
|
+
import { ensureOkfKnowledgeBase } from "../evolution/knowledge/index.ts";
|
|
4
4
|
import { EvoDevConfigError } from "./errors.ts";
|
|
5
5
|
import { type EvoDevPaths, resolveEvoDevPaths } from "./paths.ts";
|
|
6
6
|
import { type EvoDevRegistry, createDefaultRegistry, parseRegistry } from "./registry.ts";
|