@evo-dev/core 0.0.1-alpha.3 → 0.0.1-alpha.5
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/dist/config/index.js +164 -125
- package/dist/index.js +8965 -7632
- 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 +505 -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 +5 -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 +266 -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 +16 -2827
- package/src/{knowledge → evolution/knowledge}/index.ts +16 -81
- package/src/evolution/paths.ts +44 -0
- package/src/evolution/processor/distillation.ts +445 -0
- package/src/evolution/processor/index.ts +3 -0
- package/src/evolution/processor/process.ts +235 -0
- package/src/evolution/schema.ts +544 -0
- package/src/evolution/shared.ts +737 -0
- package/src/evolution/triggers/classification.ts +102 -0
- package/src/evolution/triggers/index.ts +295 -0
- package/src/hooks/index.ts +54 -7
- package/src/index.ts +10 -2
- package/src/runtime-logs/index.ts +4 -12
- package/src/team/index.ts +1 -1
- 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,41 @@ 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
|
+
}
|
|
154
|
+
// packages/core/src/evolution/evidence/session-memory/constants.ts
|
|
155
|
+
var DEFAULT_MAX_RAW_EVENT_BYTES = 64 * 1024;
|
|
122
156
|
// packages/core/src/runtime-logs/index.ts
|
|
123
157
|
var SAFE_EXECUTION_METADATA_KEYS = new Set([
|
|
124
158
|
"phase",
|
|
@@ -143,7 +177,44 @@ var SAFE_REDACTION_LABELS = new Set([
|
|
|
143
177
|
"sensitive-text"
|
|
144
178
|
]);
|
|
145
179
|
|
|
146
|
-
// packages/core/src/
|
|
180
|
+
// packages/core/src/evolution/shared.ts
|
|
181
|
+
var MAX_PROPOSED_CHANGE_LENGTH = 16 * 1024;
|
|
182
|
+
var PROCESS_LOCK_STALE_MS = 5 * 60 * 1000;
|
|
183
|
+
var FORBIDDEN_RAW_KEYS = new Set([
|
|
184
|
+
"commandhistory",
|
|
185
|
+
"commandoutput",
|
|
186
|
+
"credential",
|
|
187
|
+
"credentials",
|
|
188
|
+
"env",
|
|
189
|
+
"fullsource",
|
|
190
|
+
"memorybody",
|
|
191
|
+
"password",
|
|
192
|
+
"privatekey",
|
|
193
|
+
"prompt",
|
|
194
|
+
"promptbody",
|
|
195
|
+
"prompttext",
|
|
196
|
+
"rawcommand",
|
|
197
|
+
"rawcommandoutput",
|
|
198
|
+
"rawlog",
|
|
199
|
+
"rawlogs",
|
|
200
|
+
"rawoutput",
|
|
201
|
+
"rawpayload",
|
|
202
|
+
"rawprompt",
|
|
203
|
+
"secret",
|
|
204
|
+
"secretvalue",
|
|
205
|
+
"source",
|
|
206
|
+
"sourcebody",
|
|
207
|
+
"sourcecode",
|
|
208
|
+
"sourcecontent",
|
|
209
|
+
"sourcetext",
|
|
210
|
+
"stderr",
|
|
211
|
+
"stdout",
|
|
212
|
+
"token",
|
|
213
|
+
"transcript",
|
|
214
|
+
"transcriptbody",
|
|
215
|
+
"transcripttext"
|
|
216
|
+
]);
|
|
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"]);
|
|
@@ -964,10 +998,10 @@ function parseHookSettings(value) {
|
|
|
964
998
|
if (!isRecord(value))
|
|
965
999
|
throw new Error("Invalid hooks settings; expected object.");
|
|
966
1000
|
const observability = isRecord(value.observability) ? value.observability : undefined;
|
|
967
|
-
|
|
968
|
-
|
|
1001
|
+
optionalBoolean2(observability?.metadataOnly, defaults.observability.metadataOnly, "hooks.observability.metadataOnly");
|
|
1002
|
+
optionalBoolean2(observability?.rawPayloadStorage, defaults.observability.rawPayloadStorage, "hooks.observability.rawPayloadStorage");
|
|
969
1003
|
return {
|
|
970
|
-
enabled:
|
|
1004
|
+
enabled: optionalBoolean2(value.enabled, defaults.enabled, "hooks.enabled"),
|
|
971
1005
|
targets: {
|
|
972
1006
|
claude: parseHookTargetSettings(value.targets, defaults.targets.claude, "claude"),
|
|
973
1007
|
codex: parseHookTargetSettings(value.targets, defaults.targets.codex, "codex")
|
|
@@ -975,7 +1009,7 @@ function parseHookSettings(value) {
|
|
|
975
1009
|
observability: {
|
|
976
1010
|
metadataOnly: true,
|
|
977
1011
|
rawPayloadStorage: false,
|
|
978
|
-
appendEvents:
|
|
1012
|
+
appendEvents: optionalBoolean2(observability?.appendEvents, defaults.observability.appendEvents, "hooks.observability.appendEvents")
|
|
979
1013
|
},
|
|
980
1014
|
learning: {
|
|
981
1015
|
emitCandidates: false,
|
|
@@ -989,14 +1023,14 @@ function parseHookTargetSettings(value, defaults, target) {
|
|
|
989
1023
|
const events = isRecord(targetSettings.events) ? targetSettings.events : {};
|
|
990
1024
|
const parsedEvents = { ...defaults.events };
|
|
991
1025
|
for (const eventType of CANONICAL_HOOK_EVENT_TYPES) {
|
|
992
|
-
parsedEvents[eventType] =
|
|
1026
|
+
parsedEvents[eventType] = optionalBoolean2(events[eventType], defaults.events[eventType], `hooks.targets.${target}.events.${eventType}`);
|
|
993
1027
|
}
|
|
994
1028
|
return {
|
|
995
|
-
enabled:
|
|
1029
|
+
enabled: optionalBoolean2(targetSettings.enabled, defaults.enabled, `hooks.targets.${target}.enabled`),
|
|
996
1030
|
events: parsedEvents
|
|
997
1031
|
};
|
|
998
1032
|
}
|
|
999
|
-
function
|
|
1033
|
+
function optionalBoolean2(value, fallback, path) {
|
|
1000
1034
|
if (value === undefined)
|
|
1001
1035
|
return fallback;
|
|
1002
1036
|
if (typeof value !== "boolean")
|
|
@@ -1054,7 +1088,8 @@ function createDefaultMemorySettings() {
|
|
|
1054
1088
|
autoAccept: true,
|
|
1055
1089
|
runtimeInjection: true,
|
|
1056
1090
|
staleReview: true,
|
|
1057
|
-
lexicalIndex: true
|
|
1091
|
+
lexicalIndex: true,
|
|
1092
|
+
sessionMemory: createDefaultSessionMemoryPolicy()
|
|
1058
1093
|
};
|
|
1059
1094
|
}
|
|
1060
1095
|
function mergeSettings(existing, defaults = createDefaultSettings()) {
|
|
@@ -1102,11 +1137,11 @@ function mergeSettings(existing, defaults = createDefaultSettings()) {
|
|
|
1102
1137
|
return parseSettings(merged);
|
|
1103
1138
|
}
|
|
1104
1139
|
async function readRuntimeInjectionSettings(homeDir) {
|
|
1105
|
-
const
|
|
1140
|
+
const paths2 = resolveEvoDevPaths(homeDir);
|
|
1106
1141
|
try {
|
|
1107
|
-
return parseSettings(JSON.parse(await readFile2(
|
|
1142
|
+
return parseSettings(JSON.parse(await readFile2(paths2.settingsPath, "utf8"))).memory;
|
|
1108
1143
|
} catch (error) {
|
|
1109
|
-
if (
|
|
1144
|
+
if (isNotFoundError2(error))
|
|
1110
1145
|
return createDefaultMemorySettings();
|
|
1111
1146
|
throw error;
|
|
1112
1147
|
}
|
|
@@ -1154,7 +1189,8 @@ function parseMemorySettings(value, path) {
|
|
|
1154
1189
|
autoAccept: input.autoAccept === undefined ? defaults.autoAccept : expectBoolean(input.autoAccept, `${path}.autoAccept`),
|
|
1155
1190
|
runtimeInjection: input.runtimeInjection === undefined ? defaults.runtimeInjection : expectBoolean(input.runtimeInjection, `${path}.runtimeInjection`),
|
|
1156
1191
|
staleReview: input.staleReview === undefined ? defaults.staleReview : expectBoolean(input.staleReview, `${path}.staleReview`),
|
|
1157
|
-
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)
|
|
1158
1194
|
};
|
|
1159
1195
|
}
|
|
1160
1196
|
function parseTeamRuntimeSettings(value, path) {
|
|
@@ -1198,7 +1234,10 @@ function expectRecord2(value, path) {
|
|
|
1198
1234
|
}
|
|
1199
1235
|
return value;
|
|
1200
1236
|
}
|
|
1201
|
-
function
|
|
1237
|
+
function isPlainRecord(value) {
|
|
1238
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1239
|
+
}
|
|
1240
|
+
function isNotFoundError2(error) {
|
|
1202
1241
|
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
1203
1242
|
}
|
|
1204
1243
|
function expectString2(value, path) {
|
|
@@ -1303,50 +1342,50 @@ function expectNonNegativeInteger(value, path) {
|
|
|
1303
1342
|
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
1304
1343
|
import { dirname as dirname2 } from "node:path";
|
|
1305
1344
|
function createCoreConfigStore(homeDir) {
|
|
1306
|
-
const
|
|
1345
|
+
const paths2 = resolveEvoDevPaths(homeDir);
|
|
1307
1346
|
return {
|
|
1308
|
-
paths,
|
|
1347
|
+
paths: paths2,
|
|
1309
1348
|
async ensureBaseDirs() {
|
|
1310
|
-
await mkdir2(
|
|
1311
|
-
await mkdir2(
|
|
1312
|
-
await mkdir2(
|
|
1313
|
-
await mkdir2(
|
|
1314
|
-
await mkdir2(
|
|
1315
|
-
await mkdir2(
|
|
1316
|
-
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 });
|
|
1317
1356
|
},
|
|
1318
1357
|
async ensureKnowledgeBase() {
|
|
1319
|
-
await ensureKnowledgeBaseFiles(
|
|
1358
|
+
await ensureKnowledgeBaseFiles(paths2);
|
|
1320
1359
|
},
|
|
1321
1360
|
async readSettings() {
|
|
1322
|
-
return readJsonFile(
|
|
1361
|
+
return readJsonFile(paths2.settingsPath, parseSettings);
|
|
1323
1362
|
},
|
|
1324
1363
|
async writeSettings(settings) {
|
|
1325
|
-
await
|
|
1364
|
+
await writeJsonFile2(paths2.settingsPath, parseSettings(settings));
|
|
1326
1365
|
},
|
|
1327
1366
|
async mergeAndWriteSettings(input) {
|
|
1328
|
-
const current = await readJsonFileOrDefault(
|
|
1367
|
+
const current = await readJsonFileOrDefault(paths2.settingsPath, parseSettings, createDefaultSettings());
|
|
1329
1368
|
const merged = mergeSettings(input, current);
|
|
1330
|
-
await
|
|
1369
|
+
await writeJsonFile2(paths2.settingsPath, merged);
|
|
1331
1370
|
return merged;
|
|
1332
1371
|
},
|
|
1333
1372
|
async readRegistry() {
|
|
1334
|
-
return readJsonFile(
|
|
1373
|
+
return readJsonFile(paths2.registryPath, parseRegistry);
|
|
1335
1374
|
},
|
|
1336
1375
|
async writeRegistry(registry) {
|
|
1337
|
-
await
|
|
1376
|
+
await writeJsonFile2(paths2.registryPath, parseRegistry(registry));
|
|
1338
1377
|
},
|
|
1339
1378
|
async readInstallState() {
|
|
1340
|
-
return readJsonFile(
|
|
1379
|
+
return readJsonFile(paths2.installStatePath, parseInstallState);
|
|
1341
1380
|
},
|
|
1342
1381
|
async writeInstallState(state) {
|
|
1343
|
-
await
|
|
1382
|
+
await writeJsonFile2(paths2.installStatePath, parseInstallState(state));
|
|
1344
1383
|
},
|
|
1345
1384
|
async readSyncState() {
|
|
1346
|
-
return readJsonFile(
|
|
1385
|
+
return readJsonFile(paths2.syncStatePath, parseSyncState);
|
|
1347
1386
|
},
|
|
1348
1387
|
async writeSyncState(state) {
|
|
1349
|
-
await
|
|
1388
|
+
await writeJsonFile2(paths2.syncStatePath, parseSyncState(state));
|
|
1350
1389
|
}
|
|
1351
1390
|
};
|
|
1352
1391
|
}
|
|
@@ -1360,11 +1399,11 @@ async function initializeCoreConfig(homeDir) {
|
|
|
1360
1399
|
await writeIfMissing(store.paths.syncStatePath, createDefaultSyncState());
|
|
1361
1400
|
return store;
|
|
1362
1401
|
}
|
|
1363
|
-
async function ensureKnowledgeBaseFiles(
|
|
1364
|
-
await mkdir2(
|
|
1365
|
-
await mkdir2(
|
|
1366
|
-
await ensureOkfKnowledgeBase(
|
|
1367
|
-
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`, [
|
|
1368
1407
|
"# EvoDev Knowledge",
|
|
1369
1408
|
"",
|
|
1370
1409
|
"Local-private knowledge base for user-accepted facts, decisions, architecture notes, and reusable domain context.",
|
|
@@ -1373,13 +1412,13 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1373
1412
|
""
|
|
1374
1413
|
].join(`
|
|
1375
1414
|
`));
|
|
1376
|
-
await writeIndexIfMissingOrMigrate(
|
|
1415
|
+
await writeIndexIfMissingOrMigrate(paths2.knowledgeIndexPath, "knowledge-index", {
|
|
1377
1416
|
version: 1,
|
|
1378
1417
|
kind: "knowledge-index",
|
|
1379
1418
|
roleTags: [],
|
|
1380
1419
|
entries: []
|
|
1381
1420
|
});
|
|
1382
|
-
await writeTextIfMissing2(`${
|
|
1421
|
+
await writeTextIfMissing2(`${paths2.evosDir}/README.md`, [
|
|
1383
1422
|
"# EvoDev Evos",
|
|
1384
1423
|
"",
|
|
1385
1424
|
"Local-private evolution case library for reviewed improvement cases and reusable process changes.",
|
|
@@ -1388,20 +1427,20 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1388
1427
|
""
|
|
1389
1428
|
].join(`
|
|
1390
1429
|
`));
|
|
1391
|
-
await writeTextIfMissing2(`${
|
|
1430
|
+
await writeTextIfMissing2(`${paths2.evosCasesDir}/README.md`, [
|
|
1392
1431
|
"# Evolution Cases",
|
|
1393
1432
|
"",
|
|
1394
1433
|
"Store one reviewed evolution case per file. Do not store raw prompts, source dumps, secrets, transcripts, or raw command output here.",
|
|
1395
1434
|
""
|
|
1396
1435
|
].join(`
|
|
1397
1436
|
`));
|
|
1398
|
-
await writeIndexIfMissingOrMigrate(
|
|
1437
|
+
await writeIndexIfMissingOrMigrate(paths2.evosIndexPath, "evos-index", {
|
|
1399
1438
|
version: 1,
|
|
1400
1439
|
kind: "evos-index",
|
|
1401
1440
|
roleTags: [],
|
|
1402
1441
|
cases: []
|
|
1403
1442
|
});
|
|
1404
|
-
await writeTextIfMissing2(`${
|
|
1443
|
+
await writeTextIfMissing2(`${paths2.roleAgentsDir}/README.md`, [
|
|
1405
1444
|
"# Role Agents",
|
|
1406
1445
|
"",
|
|
1407
1446
|
"Local-private role agent registry for EvoDev-managed agent roles and user-reviewed role extensions.",
|
|
@@ -1410,13 +1449,13 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1410
1449
|
""
|
|
1411
1450
|
].join(`
|
|
1412
1451
|
`));
|
|
1413
|
-
await writeIndexIfMissingOrMigrate(
|
|
1452
|
+
await writeIndexIfMissingOrMigrate(paths2.roleAgentsIndexPath, "role-agent-index", {
|
|
1414
1453
|
version: 1,
|
|
1415
1454
|
kind: "role-agent-index",
|
|
1416
1455
|
roles: [],
|
|
1417
1456
|
projectExtensions: []
|
|
1418
1457
|
});
|
|
1419
|
-
await writeTextIfMissing2(`${
|
|
1458
|
+
await writeTextIfMissing2(`${paths2.teamsDir}/README.md`, [
|
|
1420
1459
|
"# Agent Teams",
|
|
1421
1460
|
"",
|
|
1422
1461
|
"Local-private EvoHub team registry for reviewed role-agent team definitions.",
|
|
@@ -1425,7 +1464,7 @@ async function ensureKnowledgeBaseFiles(paths) {
|
|
|
1425
1464
|
""
|
|
1426
1465
|
].join(`
|
|
1427
1466
|
`));
|
|
1428
|
-
await writeIndexIfMissingOrMigrate(
|
|
1467
|
+
await writeIndexIfMissingOrMigrate(paths2.teamsIndexPath, "agent-team-index", {
|
|
1429
1468
|
version: 1,
|
|
1430
1469
|
kind: "agent-team-index",
|
|
1431
1470
|
teams: []
|
|
@@ -1468,7 +1507,7 @@ async function writeIfMissing(filePath, value) {
|
|
|
1468
1507
|
await readFile3(filePath, "utf8");
|
|
1469
1508
|
} catch (error) {
|
|
1470
1509
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1471
|
-
await
|
|
1510
|
+
await writeJsonFile2(filePath, value);
|
|
1472
1511
|
return;
|
|
1473
1512
|
}
|
|
1474
1513
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
@@ -1480,7 +1519,7 @@ async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
|
|
|
1480
1519
|
raw = await readFile3(filePath, "utf8");
|
|
1481
1520
|
} catch (error) {
|
|
1482
1521
|
if (isNodeError(error) && error.code === "ENOENT") {
|
|
1483
|
-
await
|
|
1522
|
+
await writeJsonFile2(filePath, defaults);
|
|
1484
1523
|
return;
|
|
1485
1524
|
}
|
|
1486
1525
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
@@ -1496,7 +1535,7 @@ async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
|
|
|
1496
1535
|
const migrated = { ...defaults, ...existing };
|
|
1497
1536
|
if (Object.keys(defaults).every((key) => (key in existing)))
|
|
1498
1537
|
return;
|
|
1499
|
-
await
|
|
1538
|
+
await writeJsonFile2(filePath, migrated);
|
|
1500
1539
|
}
|
|
1501
1540
|
async function writeTextIfMissing2(filePath, value) {
|
|
1502
1541
|
try {
|
|
@@ -1510,7 +1549,7 @@ async function writeTextIfMissing2(filePath, value) {
|
|
|
1510
1549
|
throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
|
|
1511
1550
|
}
|
|
1512
1551
|
}
|
|
1513
|
-
async function
|
|
1552
|
+
async function writeJsonFile2(filePath, value) {
|
|
1514
1553
|
await mkdir2(dirname2(filePath), { recursive: true });
|
|
1515
1554
|
await writeFile2(filePath, `${JSON.stringify(value, null, 2)}
|
|
1516
1555
|
`, "utf8");
|