@evo-dev/core 0.0.1-alpha.2 → 0.0.1-alpha.4
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/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/config/index.js +181 -125
- package/dist/index.js +10971 -9455
- package/package.json +1 -1
- package/src/agents/index.ts +1 -1
- package/src/code-agent-traces/index.ts +3 -10
- package/src/config/settings.ts +14 -0
- package/src/config/store.ts +1 -1
- package/src/daemon/index.ts +1 -1
- package/src/evolution/candidates/index.ts +235 -0
- package/src/evolution/control/index.ts +19 -0
- package/src/evolution/evidence/analysis.ts +529 -0
- package/src/evolution/evidence/index.ts +3 -0
- package/src/evolution/evidence/session-memory/constants.ts +12 -0
- package/src/evolution/evidence/session-memory/index.ts +4 -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/segment.ts +192 -0
- package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
- package/src/evolution/evidence/session-memory/storage.ts +145 -0
- package/src/evolution/evidence/session-memory/types.ts +207 -0
- package/src/evolution/evidence/session-memory/updater.ts +184 -0
- package/src/evolution/formatters.ts +169 -0
- package/src/evolution/index.ts +12 -2827
- package/src/{knowledge → evolution/knowledge}/index.ts +7 -7
- package/src/evolution/paths.ts +41 -0
- package/src/evolution/processor/distillation.ts +436 -0
- package/src/evolution/processor/index.ts +3 -0
- package/src/evolution/processor/process.ts +306 -0
- package/src/evolution/schema.ts +522 -0
- package/src/evolution/shared.ts +677 -0
- package/src/evolution/triggers/classification.ts +102 -0
- package/src/evolution/triggers/index.ts +295 -0
- package/src/hooks/index.ts +56 -9
- package/src/index.ts +10 -2
- package/src/runtime-logs/index.ts +4 -12
- package/src/team/index.ts +576 -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/{learning → evolution/review}/index.ts +0 -0
package/dist/config/index.js
CHANGED
|
@@ -118,7 +118,39 @@ function expectString(value, path) {
|
|
|
118
118
|
}
|
|
119
119
|
// packages/core/src/config/settings.ts
|
|
120
120
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
121
|
-
|
|
121
|
+
// packages/core/src/utils/parsing.ts
|
|
122
|
+
function optionalBoolean(value, fallback) {
|
|
123
|
+
return typeof value === "boolean" ? value : fallback;
|
|
124
|
+
}
|
|
125
|
+
function positiveInteger(value, fallback) {
|
|
126
|
+
return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : fallback;
|
|
127
|
+
}
|
|
128
|
+
// packages/core/src/evolution/evidence/session-memory/policy.ts
|
|
129
|
+
function createDefaultSessionMemoryPolicy() {
|
|
130
|
+
return {
|
|
131
|
+
enabled: true,
|
|
132
|
+
storeRawSegments: true,
|
|
133
|
+
maxRawSegmentBytes: 200000,
|
|
134
|
+
retentionDays: 30,
|
|
135
|
+
minimumMessageTokensToInit: 1e4,
|
|
136
|
+
minimumTokensBetweenUpdate: 5000,
|
|
137
|
+
toolCallsBetweenUpdates: 9
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function parseSessionMemoryPolicy(value) {
|
|
141
|
+
const defaults = createDefaultSessionMemoryPolicy();
|
|
142
|
+
if (value === undefined)
|
|
143
|
+
return defaults;
|
|
144
|
+
return {
|
|
145
|
+
enabled: optionalBoolean(value.enabled, defaults.enabled),
|
|
146
|
+
storeRawSegments: optionalBoolean(value.storeRawSegments, defaults.storeRawSegments),
|
|
147
|
+
maxRawSegmentBytes: positiveInteger(value.maxRawSegmentBytes, defaults.maxRawSegmentBytes),
|
|
148
|
+
retentionDays: positiveInteger(value.retentionDays, defaults.retentionDays),
|
|
149
|
+
minimumMessageTokensToInit: positiveInteger(value.minimumMessageTokensToInit, defaults.minimumMessageTokensToInit),
|
|
150
|
+
minimumTokensBetweenUpdate: positiveInteger(value.minimumTokensBetweenUpdate, defaults.minimumTokensBetweenUpdate),
|
|
151
|
+
toolCallsBetweenUpdates: positiveInteger(value.toolCallsBetweenUpdates, defaults.toolCallsBetweenUpdates)
|
|
152
|
+
};
|
|
153
|
+
}
|
|
122
154
|
// packages/core/src/runtime-logs/index.ts
|
|
123
155
|
var SAFE_EXECUTION_METADATA_KEYS = new Set([
|
|
124
156
|
"phase",
|
|
@@ -143,7 +175,46 @@ var SAFE_REDACTION_LABELS = new Set([
|
|
|
143
175
|
"sensitive-text"
|
|
144
176
|
]);
|
|
145
177
|
|
|
146
|
-
// packages/core/src/
|
|
178
|
+
// packages/core/src/evolution/shared.ts
|
|
179
|
+
var PROCESS_LOCK_STALE_MS = 5 * 60 * 1000;
|
|
180
|
+
var FORBIDDEN_RAW_KEYS = new Set([
|
|
181
|
+
"commandhistory",
|
|
182
|
+
"commandoutput",
|
|
183
|
+
"credential",
|
|
184
|
+
"credentials",
|
|
185
|
+
"env",
|
|
186
|
+
"fullsource",
|
|
187
|
+
"memorybody",
|
|
188
|
+
"password",
|
|
189
|
+
"privatekey",
|
|
190
|
+
"prompt",
|
|
191
|
+
"promptbody",
|
|
192
|
+
"prompttext",
|
|
193
|
+
"rawcommand",
|
|
194
|
+
"rawcommandoutput",
|
|
195
|
+
"rawlog",
|
|
196
|
+
"rawlogs",
|
|
197
|
+
"rawoutput",
|
|
198
|
+
"rawpayload",
|
|
199
|
+
"rawprompt",
|
|
200
|
+
"secret",
|
|
201
|
+
"secretvalue",
|
|
202
|
+
"source",
|
|
203
|
+
"sourcebody",
|
|
204
|
+
"sourcecode",
|
|
205
|
+
"sourcecontent",
|
|
206
|
+
"sourcetext",
|
|
207
|
+
"stderr",
|
|
208
|
+
"stdout",
|
|
209
|
+
"token",
|
|
210
|
+
"transcript",
|
|
211
|
+
"transcriptbody",
|
|
212
|
+
"transcripttext"
|
|
213
|
+
]);
|
|
214
|
+
|
|
215
|
+
// packages/core/src/evolution/evidence/session-memory/constants.ts
|
|
216
|
+
var DEFAULT_MAX_RAW_EVENT_BYTES = 64 * 1024;
|
|
217
|
+
// packages/core/src/evolution/knowledge/index.ts
|
|
147
218
|
import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
148
219
|
import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
149
220
|
var RESERVED_OKF_FILENAMES = new Set(["index.md", "log.md"]);
|
|
@@ -192,19 +263,19 @@ var BEHAVIOR_CHANGE_KINDS = new Set([
|
|
|
192
263
|
"repo-asset-suggestion"
|
|
193
264
|
]);
|
|
194
265
|
function resolveOkfKnowledgePaths(homeDir) {
|
|
195
|
-
const
|
|
266
|
+
const paths2 = resolveEvoDevPaths(homeDir);
|
|
196
267
|
return {
|
|
197
|
-
knowledgeDir:
|
|
198
|
-
okfDir: join(
|
|
199
|
-
indexesDir: join(
|
|
200
|
-
tmpDir: join(
|
|
268
|
+
knowledgeDir: paths2.knowledgeDir,
|
|
269
|
+
okfDir: join(paths2.knowledgeDir, "okf"),
|
|
270
|
+
indexesDir: join(paths2.knowledgeDir, "indexes"),
|
|
271
|
+
tmpDir: join(paths2.knowledgeDir, "tmp")
|
|
201
272
|
};
|
|
202
273
|
}
|
|
203
274
|
async function ensureOkfKnowledgeBase(homeDir) {
|
|
204
|
-
const
|
|
205
|
-
await ensureLocalKnowledgeGitRepository(
|
|
206
|
-
await mkdir(
|
|
207
|
-
await mkdir(
|
|
275
|
+
const paths2 = resolveOkfKnowledgePaths(homeDir);
|
|
276
|
+
await ensureLocalKnowledgeGitRepository(paths2.knowledgeDir);
|
|
277
|
+
await mkdir(paths2.indexesDir, { recursive: true });
|
|
278
|
+
await mkdir(paths2.tmpDir, { recursive: true });
|
|
208
279
|
const directories = [
|
|
209
280
|
{
|
|
210
281
|
path: "",
|
|
@@ -234,13 +305,13 @@ async function ensureOkfKnowledgeBase(homeDir) {
|
|
|
234
305
|
{ path: "references", title: "References", description: "Cited references." }
|
|
235
306
|
];
|
|
236
307
|
for (const directory of directories) {
|
|
237
|
-
await ensureOkfDirectory(
|
|
308
|
+
await ensureOkfDirectory(paths2.okfDir, directory.path, directory.title, directory.description);
|
|
238
309
|
}
|
|
239
310
|
await rebuildOkfKnowledgeIndexes({ homeDir });
|
|
240
311
|
}
|
|
241
312
|
async function rebuildOkfKnowledgeIndexes(input) {
|
|
242
|
-
const
|
|
243
|
-
await mkdir(
|
|
313
|
+
const paths2 = resolveOkfKnowledgePaths(input.homeDir);
|
|
314
|
+
await mkdir(paths2.indexesDir, { recursive: true });
|
|
244
315
|
const concepts = (await listOkfKnowledgeConcepts({ homeDir: input.homeDir })).filter(isActiveOkfConcept);
|
|
245
316
|
const conceptSummaries = concepts.map((concept) => ({
|
|
246
317
|
id: concept.id,
|
|
@@ -257,34 +328,34 @@ async function rebuildOkfKnowledgeIndexes(input) {
|
|
|
257
328
|
pathScopes: concept.pathScopes
|
|
258
329
|
}));
|
|
259
330
|
const pathsWritten = [
|
|
260
|
-
join(
|
|
261
|
-
join(
|
|
262
|
-
join(
|
|
263
|
-
join(
|
|
264
|
-
join(
|
|
331
|
+
join(paths2.indexesDir, "index.json"),
|
|
332
|
+
join(paths2.indexesDir, "concepts.json"),
|
|
333
|
+
join(paths2.indexesDir, "repos.json"),
|
|
334
|
+
join(paths2.indexesDir, "roles.json"),
|
|
335
|
+
join(paths2.indexesDir, "workflows.json")
|
|
265
336
|
];
|
|
266
|
-
await
|
|
337
|
+
await writeJson2(pathsWritten[0], {
|
|
267
338
|
schemaVersion: 1,
|
|
268
339
|
kind: "okf-knowledge-index",
|
|
269
340
|
conceptCount: concepts.length,
|
|
270
341
|
updatedAt: new Date().toISOString()
|
|
271
342
|
}, { overwrite: true });
|
|
272
|
-
await
|
|
343
|
+
await writeJson2(pathsWritten[1], {
|
|
273
344
|
schemaVersion: 1,
|
|
274
345
|
kind: "okf-concepts-index",
|
|
275
346
|
concepts: conceptSummaries
|
|
276
347
|
}, { overwrite: true });
|
|
277
|
-
await
|
|
348
|
+
await writeJson2(pathsWritten[2], {
|
|
278
349
|
schemaVersion: 1,
|
|
279
350
|
kind: "okf-repos-index",
|
|
280
351
|
repos: groupConceptsByTag(concepts, "repoTags")
|
|
281
352
|
}, { overwrite: true });
|
|
282
|
-
await
|
|
353
|
+
await writeJson2(pathsWritten[3], {
|
|
283
354
|
schemaVersion: 1,
|
|
284
355
|
kind: "okf-roles-index",
|
|
285
356
|
roles: groupConceptsByTag(concepts, "roleTags")
|
|
286
357
|
}, { overwrite: true });
|
|
287
|
-
await
|
|
358
|
+
await writeJson2(pathsWritten[4], {
|
|
288
359
|
schemaVersion: 1,
|
|
289
360
|
kind: "okf-workflows-index",
|
|
290
361
|
workflows: groupConceptsByTag(concepts, "workflowTags")
|
|
@@ -293,7 +364,7 @@ async function rebuildOkfKnowledgeIndexes(input) {
|
|
|
293
364
|
}
|
|
294
365
|
async function listOkfKnowledgeConcepts(input) {
|
|
295
366
|
const okfDir = resolveOkfKnowledgePaths(input.homeDir).okfDir;
|
|
296
|
-
if (!await
|
|
367
|
+
if (!await pathExists2(okfDir))
|
|
297
368
|
return [];
|
|
298
369
|
const files = await listMarkdownFiles(okfDir);
|
|
299
370
|
const concepts = [];
|
|
@@ -310,7 +381,7 @@ async function listOkfKnowledgeConcepts(input) {
|
|
|
310
381
|
async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
|
|
311
382
|
await mkdir(knowledgeDir, { recursive: true });
|
|
312
383
|
const gitDir = join(knowledgeDir, ".git");
|
|
313
|
-
if (await
|
|
384
|
+
if (await pathExists2(gitDir))
|
|
314
385
|
return;
|
|
315
386
|
await mkdir(join(gitDir, "objects", "info"), { recursive: true });
|
|
316
387
|
await mkdir(join(gitDir, "objects", "pack"), { recursive: true });
|
|
@@ -336,7 +407,7 @@ async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
|
|
|
336
407
|
`));
|
|
337
408
|
}
|
|
338
409
|
async function writeTextIfMissing(path, value) {
|
|
339
|
-
if (await
|
|
410
|
+
if (await pathExists2(path))
|
|
340
411
|
return;
|
|
341
412
|
await mkdir(dirname(path), { recursive: true });
|
|
342
413
|
await writeFile(path, value, { encoding: "utf8", flag: "wx" });
|
|
@@ -349,7 +420,7 @@ async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
|
|
|
349
420
|
await mkdir(dir, { recursive: true });
|
|
350
421
|
const isRoot = dir === okfDir;
|
|
351
422
|
const indexPath = join(dir, "index.md");
|
|
352
|
-
if (!await
|
|
423
|
+
if (!await pathExists2(indexPath)) {
|
|
353
424
|
await writeFile(indexPath, isRoot ? [
|
|
354
425
|
"---",
|
|
355
426
|
`okf_version: ${yamlString("0.1")}`,
|
|
@@ -366,7 +437,7 @@ async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
|
|
|
366
437
|
`), "utf8");
|
|
367
438
|
}
|
|
368
439
|
const logPath = join(dir, "log.md");
|
|
369
|
-
if (!await
|
|
440
|
+
if (!await pathExists2(logPath)) {
|
|
370
441
|
await writeFile(logPath, [
|
|
371
442
|
"# Directory Update Log",
|
|
372
443
|
"",
|
|
@@ -473,13 +544,13 @@ function isLifecycleDateDue(value, now) {
|
|
|
473
544
|
}
|
|
474
545
|
function createDefaultOkfLifecycle(input) {
|
|
475
546
|
const createdAt = normalizeIsoDateString(input.createdAt) ?? "1970-01-01T00:00:00.000Z";
|
|
476
|
-
const
|
|
547
|
+
const policy2 = resolveOkfLifecyclePolicy(input);
|
|
477
548
|
return {
|
|
478
549
|
status: lifecycleStatusFromReviewState(input.reviewState),
|
|
479
550
|
createdAt,
|
|
480
551
|
lastVerifiedAt: createdAt,
|
|
481
|
-
reviewAfter: addDaysIso(createdAt,
|
|
482
|
-
staleAfter: addDaysIso(createdAt,
|
|
552
|
+
reviewAfter: addDaysIso(createdAt, policy2.reviewAfterDays),
|
|
553
|
+
staleAfter: addDaysIso(createdAt, policy2.staleAfterDays),
|
|
483
554
|
supersedes: [],
|
|
484
555
|
supersededBy: null,
|
|
485
556
|
revokedAt: null,
|
|
@@ -537,10 +608,10 @@ function isOkfLifecycleStatus(value) {
|
|
|
537
608
|
function normalizeIsoDateString(value) {
|
|
538
609
|
if (value === undefined || value === null || value === "" || value === "null")
|
|
539
610
|
return null;
|
|
540
|
-
const
|
|
541
|
-
if (!Number.isFinite(
|
|
611
|
+
const time2 = Date.parse(value);
|
|
612
|
+
if (!Number.isFinite(time2))
|
|
542
613
|
return null;
|
|
543
|
-
return new Date(
|
|
614
|
+
return new Date(time2).toISOString();
|
|
544
615
|
}
|
|
545
616
|
function addDaysIso(value, days) {
|
|
546
617
|
const date = new Date(value);
|
|
@@ -641,7 +712,7 @@ function parseYamlValue(value) {
|
|
|
641
712
|
return trimmed.replace(/^['"]|['"]$/gu, "");
|
|
642
713
|
}
|
|
643
714
|
async function listMarkdownFiles(root) {
|
|
644
|
-
if (!await
|
|
715
|
+
if (!await pathExists2(root))
|
|
645
716
|
return [];
|
|
646
717
|
const entries = await readdir(root, { withFileTypes: true });
|
|
647
718
|
const files = [];
|
|
@@ -694,13 +765,13 @@ function escapeRegExp(value) {
|
|
|
694
765
|
function todayIsoDate() {
|
|
695
766
|
return new Date().toISOString().slice(0, 10);
|
|
696
767
|
}
|
|
697
|
-
async function
|
|
768
|
+
async function writeJson2(path, value, options = {}) {
|
|
698
769
|
await mkdir(dirname(path), { recursive: true });
|
|
699
770
|
const flag = options.overwrite === true ? "w" : "wx";
|
|
700
771
|
await writeFile(path, `${JSON.stringify(value, null, 2)}
|
|
701
772
|
`, { encoding: "utf8", flag });
|
|
702
773
|
}
|
|
703
|
-
async function
|
|
774
|
+
async function pathExists2(path) {
|
|
704
775
|
try {
|
|
705
776
|
await stat(path);
|
|
706
777
|
return true;
|
|
@@ -711,43 +782,6 @@ async function pathExists(path) {
|
|
|
711
782
|
}
|
|
712
783
|
}
|
|
713
784
|
|
|
714
|
-
// packages/core/src/evolution/index.ts
|
|
715
|
-
var PROCESS_LOCK_STALE_MS = 5 * 60 * 1000;
|
|
716
|
-
var FORBIDDEN_RAW_KEYS = new Set([
|
|
717
|
-
"commandhistory",
|
|
718
|
-
"commandoutput",
|
|
719
|
-
"credential",
|
|
720
|
-
"credentials",
|
|
721
|
-
"env",
|
|
722
|
-
"fullsource",
|
|
723
|
-
"memorybody",
|
|
724
|
-
"password",
|
|
725
|
-
"privatekey",
|
|
726
|
-
"prompt",
|
|
727
|
-
"promptbody",
|
|
728
|
-
"prompttext",
|
|
729
|
-
"rawcommand",
|
|
730
|
-
"rawcommandoutput",
|
|
731
|
-
"rawlog",
|
|
732
|
-
"rawlogs",
|
|
733
|
-
"rawoutput",
|
|
734
|
-
"rawpayload",
|
|
735
|
-
"rawprompt",
|
|
736
|
-
"secret",
|
|
737
|
-
"secretvalue",
|
|
738
|
-
"source",
|
|
739
|
-
"sourcebody",
|
|
740
|
-
"sourcecode",
|
|
741
|
-
"sourcecontent",
|
|
742
|
-
"sourcetext",
|
|
743
|
-
"stderr",
|
|
744
|
-
"stdout",
|
|
745
|
-
"token",
|
|
746
|
-
"transcript",
|
|
747
|
-
"transcriptbody",
|
|
748
|
-
"transcripttext"
|
|
749
|
-
]);
|
|
750
|
-
|
|
751
785
|
// packages/core/src/task/index.ts
|
|
752
786
|
var FORBIDDEN_TASK_WRITE_SEGMENTS = new Set([".claude", ".codex"]);
|
|
753
787
|
var FORBIDDEN_PROJECT_ASSET_SEGMENTS = new Set(["packages", "src"]);
|
|
@@ -848,6 +882,23 @@ var TEAM_INTERNAL_WAKE_SIGNAL = [
|
|
|
848
882
|
"No user request is included in this message. Continue only from EvoDev team inbox messages injected by hooks."
|
|
849
883
|
].join(`
|
|
850
884
|
`);
|
|
885
|
+
var BUILT_IN_TEAM_DEFINITION = {
|
|
886
|
+
version: 1,
|
|
887
|
+
name: "builtin-minimal-team",
|
|
888
|
+
description: "Built-in minimal EvoDev team fallback.",
|
|
889
|
+
agents: {
|
|
890
|
+
executor: "builtin:executor",
|
|
891
|
+
reviewer: "builtin:reviewer",
|
|
892
|
+
tester: "builtin:tester"
|
|
893
|
+
},
|
|
894
|
+
body: [
|
|
895
|
+
"# Built-in Minimal Team",
|
|
896
|
+
"",
|
|
897
|
+
"Use role agents only when delegation improves correctness, coverage, safety, or latency.",
|
|
898
|
+
"Spawn roles on demand and send self-contained assignments through Teams MCP."
|
|
899
|
+
].join(`
|
|
900
|
+
`)
|
|
901
|
+
};
|
|
851
902
|
|
|
852
903
|
// packages/core/src/hooks/index.ts
|
|
853
904
|
var CANONICAL_HOOK_EVENT_TYPES = [
|
|
@@ -947,10 +998,10 @@ function parseHookSettings(value) {
|
|
|
947
998
|
if (!isRecord(value))
|
|
948
999
|
throw new Error("Invalid hooks settings; expected object.");
|
|
949
1000
|
const observability = isRecord(value.observability) ? value.observability : undefined;
|
|
950
|
-
|
|
951
|
-
|
|
1001
|
+
optionalBoolean2(observability?.metadataOnly, defaults.observability.metadataOnly, "hooks.observability.metadataOnly");
|
|
1002
|
+
optionalBoolean2(observability?.rawPayloadStorage, defaults.observability.rawPayloadStorage, "hooks.observability.rawPayloadStorage");
|
|
952
1003
|
return {
|
|
953
|
-
enabled:
|
|
1004
|
+
enabled: optionalBoolean2(value.enabled, defaults.enabled, "hooks.enabled"),
|
|
954
1005
|
targets: {
|
|
955
1006
|
claude: parseHookTargetSettings(value.targets, defaults.targets.claude, "claude"),
|
|
956
1007
|
codex: parseHookTargetSettings(value.targets, defaults.targets.codex, "codex")
|
|
@@ -958,7 +1009,7 @@ function parseHookSettings(value) {
|
|
|
958
1009
|
observability: {
|
|
959
1010
|
metadataOnly: true,
|
|
960
1011
|
rawPayloadStorage: false,
|
|
961
|
-
appendEvents:
|
|
1012
|
+
appendEvents: optionalBoolean2(observability?.appendEvents, defaults.observability.appendEvents, "hooks.observability.appendEvents")
|
|
962
1013
|
},
|
|
963
1014
|
learning: {
|
|
964
1015
|
emitCandidates: false,
|
|
@@ -972,14 +1023,14 @@ function parseHookTargetSettings(value, defaults, target) {
|
|
|
972
1023
|
const events = isRecord(targetSettings.events) ? targetSettings.events : {};
|
|
973
1024
|
const parsedEvents = { ...defaults.events };
|
|
974
1025
|
for (const eventType of CANONICAL_HOOK_EVENT_TYPES) {
|
|
975
|
-
parsedEvents[eventType] =
|
|
1026
|
+
parsedEvents[eventType] = optionalBoolean2(events[eventType], defaults.events[eventType], `hooks.targets.${target}.events.${eventType}`);
|
|
976
1027
|
}
|
|
977
1028
|
return {
|
|
978
|
-
enabled:
|
|
1029
|
+
enabled: optionalBoolean2(targetSettings.enabled, defaults.enabled, `hooks.targets.${target}.enabled`),
|
|
979
1030
|
events: parsedEvents
|
|
980
1031
|
};
|
|
981
1032
|
}
|
|
982
|
-
function
|
|
1033
|
+
function optionalBoolean2(value, fallback, path) {
|
|
983
1034
|
if (value === undefined)
|
|
984
1035
|
return fallback;
|
|
985
1036
|
if (typeof value !== "boolean")
|
|
@@ -1037,7 +1088,8 @@ function createDefaultMemorySettings() {
|
|
|
1037
1088
|
autoAccept: true,
|
|
1038
1089
|
runtimeInjection: true,
|
|
1039
1090
|
staleReview: true,
|
|
1040
|
-
lexicalIndex: true
|
|
1091
|
+
lexicalIndex: true,
|
|
1092
|
+
sessionMemory: createDefaultSessionMemoryPolicy()
|
|
1041
1093
|
};
|
|
1042
1094
|
}
|
|
1043
1095
|
function mergeSettings(existing, defaults = createDefaultSettings()) {
|
|
@@ -1085,11 +1137,11 @@ function mergeSettings(existing, defaults = createDefaultSettings()) {
|
|
|
1085
1137
|
return parseSettings(merged);
|
|
1086
1138
|
}
|
|
1087
1139
|
async function readRuntimeInjectionSettings(homeDir) {
|
|
1088
|
-
const
|
|
1140
|
+
const paths2 = resolveEvoDevPaths(homeDir);
|
|
1089
1141
|
try {
|
|
1090
|
-
return parseSettings(JSON.parse(await readFile2(
|
|
1142
|
+
return parseSettings(JSON.parse(await readFile2(paths2.settingsPath, "utf8"))).memory;
|
|
1091
1143
|
} catch (error) {
|
|
1092
|
-
if (
|
|
1144
|
+
if (isNotFoundError2(error))
|
|
1093
1145
|
return createDefaultMemorySettings();
|
|
1094
1146
|
throw error;
|
|
1095
1147
|
}
|
|
@@ -1137,7 +1189,8 @@ function parseMemorySettings(value, path) {
|
|
|
1137
1189
|
autoAccept: input.autoAccept === undefined ? defaults.autoAccept : expectBoolean(input.autoAccept, `${path}.autoAccept`),
|
|
1138
1190
|
runtimeInjection: input.runtimeInjection === undefined ? defaults.runtimeInjection : expectBoolean(input.runtimeInjection, `${path}.runtimeInjection`),
|
|
1139
1191
|
staleReview: input.staleReview === undefined ? defaults.staleReview : expectBoolean(input.staleReview, `${path}.staleReview`),
|
|
1140
|
-
lexicalIndex: input.lexicalIndex === undefined ? defaults.lexicalIndex : expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`)
|
|
1192
|
+
lexicalIndex: input.lexicalIndex === undefined ? defaults.lexicalIndex : expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`),
|
|
1193
|
+
sessionMemory: parseSessionMemoryPolicy(isPlainRecord(input.sessionMemory) ? input.sessionMemory : defaults.sessionMemory)
|
|
1141
1194
|
};
|
|
1142
1195
|
}
|
|
1143
1196
|
function parseTeamRuntimeSettings(value, path) {
|
|
@@ -1181,7 +1234,10 @@ function expectRecord2(value, path) {
|
|
|
1181
1234
|
}
|
|
1182
1235
|
return value;
|
|
1183
1236
|
}
|
|
1184
|
-
function
|
|
1237
|
+
function isPlainRecord(value) {
|
|
1238
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1239
|
+
}
|
|
1240
|
+
function isNotFoundError2(error) {
|
|
1185
1241
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1186
1242
|
}
|
|
1187
1243
|
function expectString2(value, path) {
|
|
@@ -1286,50 +1342,50 @@ function expectNonNegativeInteger(value, path) {
|
|
|
1286
1342
|
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
1287
1343
|
import { dirname as dirname2 } from "node:path";
|
|
1288
1344
|
function createCoreConfigStore(homeDir) {
|
|
1289
|
-
const
|
|
1345
|
+
const paths2 = resolveEvoDevPaths(homeDir);
|
|
1290
1346
|
return {
|
|
1291
|
-
paths,
|
|
1347
|
+
paths: paths2,
|
|
1292
1348
|
async ensureBaseDirs() {
|
|
1293
|
-
await mkdir2(
|
|
1294
|
-
await mkdir2(
|
|
1295
|
-
await mkdir2(
|
|
1296
|
-
await mkdir2(
|
|
1297
|
-
await mkdir2(
|
|
1298
|
-
await mkdir2(
|
|
1299
|
-
await mkdir2(
|
|
1349
|
+
await mkdir2(paths2.stateDir, { recursive: true });
|
|
1350
|
+
await mkdir2(paths2.logsDir, { recursive: true });
|
|
1351
|
+
await mkdir2(paths2.knowledgeDir, { recursive: true });
|
|
1352
|
+
await mkdir2(paths2.evosCasesDir, { recursive: true });
|
|
1353
|
+
await mkdir2(paths2.roleAgentsDir, { recursive: true });
|
|
1354
|
+
await mkdir2(paths2.teamsDir, { recursive: true });
|
|
1355
|
+
await mkdir2(paths2.runsDir, { recursive: true });
|
|
1300
1356
|
},
|
|
1301
1357
|
async ensureKnowledgeBase() {
|
|
1302
|
-
await ensureKnowledgeBaseFiles(
|
|
1358
|
+
await ensureKnowledgeBaseFiles(paths2);
|
|
1303
1359
|
},
|
|
1304
1360
|
async readSettings() {
|
|
1305
|
-
return readJsonFile(
|
|
1361
|
+
return readJsonFile(paths2.settingsPath, parseSettings);
|
|
1306
1362
|
},
|
|
1307
1363
|
async writeSettings(settings) {
|
|
1308
|
-
await
|
|
1364
|
+
await writeJsonFile2(paths2.settingsPath, parseSettings(settings));
|
|
1309
1365
|
},
|
|
1310
1366
|
async mergeAndWriteSettings(input) {
|
|
1311
|
-
const current = await readJsonFileOrDefault(
|
|
1367
|
+
const current = await readJsonFileOrDefault(paths2.settingsPath, parseSettings, createDefaultSettings());
|
|
1312
1368
|
const merged = mergeSettings(input, current);
|
|
1313
|
-
await
|
|
1369
|
+
await writeJsonFile2(paths2.settingsPath, merged);
|
|
1314
1370
|
return merged;
|
|
1315
1371
|
},
|
|
1316
1372
|
async readRegistry() {
|
|
1317
|
-
return readJsonFile(
|
|
1373
|
+
return readJsonFile(paths2.registryPath, parseRegistry);
|
|
1318
1374
|
},
|
|
1319
1375
|
async writeRegistry(registry) {
|
|
1320
|
-
await
|
|
1376
|
+
await writeJsonFile2(paths2.registryPath, parseRegistry(registry));
|
|
1321
1377
|
},
|
|
1322
1378
|
async readInstallState() {
|
|
1323
|
-
return readJsonFile(
|
|
1379
|
+
return readJsonFile(paths2.installStatePath, parseInstallState);
|
|
1324
1380
|
},
|
|
1325
1381
|
async writeInstallState(state) {
|
|
1326
|
-
await
|
|
1382
|
+
await writeJsonFile2(paths2.installStatePath, parseInstallState(state));
|
|
1327
1383
|
},
|
|
1328
1384
|
async readSyncState() {
|
|
1329
|
-
return readJsonFile(
|
|
1385
|
+
return readJsonFile(paths2.syncStatePath, parseSyncState);
|
|
1330
1386
|
},
|
|
1331
1387
|
async writeSyncState(state) {
|
|
1332
|
-
await
|
|
1388
|
+
await writeJsonFile2(paths2.syncStatePath, parseSyncState(state));
|
|
1333
1389
|
}
|
|
1334
1390
|
};
|
|
1335
1391
|
}
|
|
@@ -1343,11 +1399,11 @@ async function initializeCoreConfig(homeDir) {
|
|
|
1343
1399
|
await writeIfMissing(store.paths.syncStatePath, createDefaultSyncState());
|
|
1344
1400
|
return store;
|
|
1345
1401
|
}
|
|
1346
|
-
async function ensureKnowledgeBaseFiles(
|
|
1347
|
-
await mkdir2(
|
|
1348
|
-
await mkdir2(
|
|
1349
|
-
await ensureOkfKnowledgeBase(
|
|
1350
|
-
await writeTextIfMissing2(`${
|
|
1402
|
+
async function ensureKnowledgeBaseFiles(paths2) {
|
|
1403
|
+
await mkdir2(paths2.knowledgeDir, { recursive: true });
|
|
1404
|
+
await mkdir2(paths2.evosCasesDir, { recursive: true });
|
|
1405
|
+
await ensureOkfKnowledgeBase(paths2.homeDir);
|
|
1406
|
+
await writeTextIfMissing2(`${paths2.knowledgeDir}/README.md`, [
|
|
1351
1407
|
"# EvoDev Knowledge",
|
|
1352
1408
|
"",
|
|
1353
1409
|
"Local-private knowledge base for user-accepted facts, decisions, architecture notes, and reusable domain context.",
|
|
@@ -1356,13 +1412,13 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1356
1412
|
""
|
|
1357
1413
|
].join(`
|
|
1358
1414
|
`));
|
|
1359
|
-
await writeIndexIfMissingOrMigrate(
|
|
1415
|
+
await writeIndexIfMissingOrMigrate(paths2.knowledgeIndexPath, "knowledge-index", {
|
|
1360
1416
|
version: 1,
|
|
1361
1417
|
kind: "knowledge-index",
|
|
1362
1418
|
roleTags: [],
|
|
1363
1419
|
entries: []
|
|
1364
1420
|
});
|
|
1365
|
-
await writeTextIfMissing2(`${
|
|
1421
|
+
await writeTextIfMissing2(`${paths2.evosDir}/README.md`, [
|
|
1366
1422
|
"# EvoDev Evos",
|
|
1367
1423
|
"",
|
|
1368
1424
|
"Local-private evolution case library for reviewed improvement cases and reusable process changes.",
|
|
@@ -1371,20 +1427,20 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1371
1427
|
""
|
|
1372
1428
|
].join(`
|
|
1373
1429
|
`));
|
|
1374
|
-
await writeTextIfMissing2(`${
|
|
1430
|
+
await writeTextIfMissing2(`${paths2.evosCasesDir}/README.md`, [
|
|
1375
1431
|
"# Evolution Cases",
|
|
1376
1432
|
"",
|
|
1377
1433
|
"Store one reviewed evolution case per file. Do not store raw prompts, source dumps, secrets, transcripts, or raw command output here.",
|
|
1378
1434
|
""
|
|
1379
1435
|
].join(`
|
|
1380
1436
|
`));
|
|
1381
|
-
await writeIndexIfMissingOrMigrate(
|
|
1437
|
+
await writeIndexIfMissingOrMigrate(paths2.evosIndexPath, "evos-index", {
|
|
1382
1438
|
version: 1,
|
|
1383
1439
|
kind: "evos-index",
|
|
1384
1440
|
roleTags: [],
|
|
1385
1441
|
cases: []
|
|
1386
1442
|
});
|
|
1387
|
-
await writeTextIfMissing2(`${
|
|
1443
|
+
await writeTextIfMissing2(`${paths2.roleAgentsDir}/README.md`, [
|
|
1388
1444
|
"# Role Agents",
|
|
1389
1445
|
"",
|
|
1390
1446
|
"Local-private role agent registry for EvoDev-managed agent roles and user-reviewed role extensions.",
|
|
@@ -1393,13 +1449,13 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1393
1449
|
""
|
|
1394
1450
|
].join(`
|
|
1395
1451
|
`));
|
|
1396
|
-
await writeIndexIfMissingOrMigrate(
|
|
1452
|
+
await writeIndexIfMissingOrMigrate(paths2.roleAgentsIndexPath, "role-agent-index", {
|
|
1397
1453
|
version: 1,
|
|
1398
1454
|
kind: "role-agent-index",
|
|
1399
1455
|
roles: [],
|
|
1400
1456
|
projectExtensions: []
|
|
1401
1457
|
});
|
|
1402
|
-
await writeTextIfMissing2(`${
|
|
1458
|
+
await writeTextIfMissing2(`${paths2.teamsDir}/README.md`, [
|
|
1403
1459
|
"# Agent Teams",
|
|
1404
1460
|
"",
|
|
1405
1461
|
"Local-private EvoHub team registry for reviewed role-agent team definitions.",
|
|
@@ -1408,7 +1464,7 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1408
1464
|
""
|
|
1409
1465
|
].join(`
|
|
1410
1466
|
`));
|
|
1411
|
-
await writeIndexIfMissingOrMigrate(
|
|
1467
|
+
await writeIndexIfMissingOrMigrate(paths2.teamsIndexPath, "agent-team-index", {
|
|
1412
1468
|
version: 1,
|
|
1413
1469
|
kind: "agent-team-index",
|
|
1414
1470
|
teams: []
|
|
@@ -1451,7 +1507,7 @@ async function writeIfMissing(filePath, value) {
|
|
|
1451
1507
|
await readFile3(filePath, "utf8");
|
|
1452
1508
|
} catch (error) {
|
|
1453
1509
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1454
|
-
await
|
|
1510
|
+
await writeJsonFile2(filePath, value);
|
|
1455
1511
|
return;
|
|
1456
1512
|
}
|
|
1457
1513
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
@@ -1463,7 +1519,7 @@ async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
|
|
|
1463
1519
|
raw = await readFile3(filePath, "utf8");
|
|
1464
1520
|
} catch (error) {
|
|
1465
1521
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1466
|
-
await
|
|
1522
|
+
await writeJsonFile2(filePath, defaults);
|
|
1467
1523
|
return;
|
|
1468
1524
|
}
|
|
1469
1525
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
@@ -1479,7 +1535,7 @@ async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
|
|
|
1479
1535
|
const migrated = { ...defaults, ...existing };
|
|
1480
1536
|
if (Object.keys(defaults).every((key) => (key in existing)))
|
|
1481
1537
|
return;
|
|
1482
|
-
await
|
|
1538
|
+
await writeJsonFile2(filePath, migrated);
|
|
1483
1539
|
}
|
|
1484
1540
|
async function writeTextIfMissing2(filePath, value) {
|
|
1485
1541
|
try {
|
|
@@ -1493,7 +1549,7 @@ async function writeTextIfMissing2(filePath, value) {
|
|
|
1493
1549
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
1494
1550
|
}
|
|
1495
1551
|
}
|
|
1496
|
-
async function
|
|
1552
|
+
async function writeJsonFile2(filePath, value) {
|
|
1497
1553
|
await mkdir2(dirname2(filePath), { recursive: true });
|
|
1498
1554
|
await writeFile2(filePath, `${JSON.stringify(value, null, 2)}
|
|
1499
1555
|
`, "utf8");
|