@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.
Files changed (79) hide show
  1. package/assets/skills/coding/knowledge-distillation/SKILL.md +5 -3
  2. package/assets/team/agents/code-reviewer.md +48 -0
  3. package/assets/team/agents/docs-maintainer.md +51 -0
  4. package/assets/team/agents/implementation-engineer.md +51 -0
  5. package/assets/team/agents/product-scope-analyst.md +58 -0
  6. package/assets/team/agents/release-engineer.md +55 -0
  7. package/assets/team/agents/security-boundary-reviewer.md +50 -0
  8. package/assets/team/agents/solution-architect.md +51 -0
  9. package/assets/team/agents/verification-engineer.md +51 -0
  10. package/assets/team/team.md +102 -0
  11. package/dist/assets/index.js +5 -5
  12. package/dist/config/index.js +793 -241
  13. package/dist/index.js +20840 -12908
  14. package/dist/plugins/index.js +13 -13
  15. package/package.json +1 -1
  16. package/src/agents/index.ts +1 -265
  17. package/src/code-agent-traces/index.ts +11 -12
  18. package/src/config/index.ts +2 -0
  19. package/src/config/settings.ts +116 -7
  20. package/src/config/store.ts +1 -1
  21. package/src/daemon/index.ts +1 -41
  22. package/src/evolution/candidates/index.ts +730 -0
  23. package/src/evolution/control/index.ts +20 -0
  24. package/src/evolution/evidence/analysis.ts +533 -0
  25. package/src/evolution/evidence/index.ts +3 -0
  26. package/src/evolution/evidence/session-memory/analysis.ts +287 -0
  27. package/src/evolution/evidence/session-memory/constants.ts +9 -0
  28. package/src/evolution/evidence/session-memory/index.ts +9 -0
  29. package/src/evolution/evidence/session-memory/paths.ts +29 -0
  30. package/src/evolution/evidence/session-memory/policy.ts +39 -0
  31. package/src/evolution/evidence/session-memory/retention.ts +643 -0
  32. package/src/evolution/evidence/session-memory/segment.ts +216 -0
  33. package/src/evolution/evidence/session-memory/semantic-packet.ts +408 -0
  34. package/src/evolution/evidence/session-memory/sensitivity.ts +335 -0
  35. package/src/evolution/evidence/session-memory/state-machine.ts +249 -0
  36. package/src/evolution/evidence/session-memory/storage.ts +744 -0
  37. package/src/evolution/evidence/session-memory/types.ts +296 -0
  38. package/src/evolution/evidence/session-memory/updater.ts +199 -0
  39. package/src/evolution/formatters.ts +169 -0
  40. package/src/evolution/imports/apply.ts +435 -0
  41. package/src/evolution/imports/diff.ts +472 -0
  42. package/src/evolution/imports/index.ts +7 -0
  43. package/src/evolution/imports/materialize.ts +640 -0
  44. package/src/evolution/imports/paths.ts +129 -0
  45. package/src/evolution/imports/stage.ts +414 -0
  46. package/src/evolution/imports/storage.ts +952 -0
  47. package/src/evolution/imports/types.ts +226 -0
  48. package/src/evolution/index.ts +19 -2827
  49. package/src/evolution/knowledge/change-store.ts +558 -0
  50. package/src/evolution/knowledge/changes.ts +459 -0
  51. package/src/evolution/knowledge/freshness.ts +69 -0
  52. package/src/{knowledge → evolution/knowledge}/index.ts +1532 -206
  53. package/src/evolution/knowledge/review.ts +446 -0
  54. package/src/evolution/knowledge/support.ts +135 -0
  55. package/src/evolution/paths.ts +44 -0
  56. package/src/evolution/processor/distillation.ts +518 -0
  57. package/src/evolution/processor/index.ts +3 -0
  58. package/src/evolution/processor/process.ts +594 -0
  59. package/src/{learning → evolution/review}/index.ts +10 -14
  60. package/src/evolution/schema.ts +639 -0
  61. package/src/evolution/shared.ts +1053 -0
  62. package/src/evolution/triggers/classification.ts +102 -0
  63. package/src/evolution/triggers/index.ts +295 -0
  64. package/src/hooks/index.ts +281 -197
  65. package/src/index.ts +15 -4
  66. package/src/projects/index.ts +934 -0
  67. package/src/runtime-logs/index.ts +100 -13
  68. package/src/team/index.ts +582 -3
  69. package/src/utils/errors.ts +13 -0
  70. package/src/utils/fs.ts +40 -0
  71. package/src/utils/hash.ts +9 -0
  72. package/src/utils/ids.ts +12 -0
  73. package/src/utils/index.ts +7 -0
  74. package/src/utils/parsing.ts +11 -0
  75. package/src/utils/text.ts +18 -0
  76. package/src/utils/time.ts +5 -0
  77. package/src/workflow/index.ts +3 -21
  78. package/src/project/index.ts +0 -507
  79. package/src/task/index.ts +0 -840
@@ -117,9 +117,164 @@ function expectString(value, path) {
117
117
  return value;
118
118
  }
119
119
  // packages/core/src/config/settings.ts
120
- import { readFile as readFile2 } from "node:fs/promises";
120
+ import { readFile as readFile3 } from "node:fs/promises";
121
+
122
+ // packages/core/src/utils/errors.ts
123
+ function isNotFoundError(error) {
124
+ return error instanceof Error && (("code" in error) && error.code === "ENOENT" || error.message.includes("ENOENT"));
125
+ }
126
+ // packages/core/src/utils/hash.ts
127
+ import { createHash } from "node:crypto";
128
+ function sha256Hex(value) {
129
+ return createHash("sha256").update(value).digest("hex");
130
+ }
131
+ function sha256Short(value, length = 16) {
132
+ return sha256Hex(value).slice(0, length);
133
+ }
134
+ // packages/core/src/utils/ids.ts
135
+ function sanitizeStorageId(value, fallbackPrefix) {
136
+ const sanitized = value.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120);
137
+ return sanitized === "" || sanitized === "." || sanitized === ".." ? `${fallbackPrefix}-local` : sanitized;
138
+ }
139
+ // packages/core/src/utils/parsing.ts
140
+ function optionalBoolean(value, fallback) {
141
+ return typeof value === "boolean" ? value : fallback;
142
+ }
143
+ function positiveInteger(value, fallback) {
144
+ return typeof value === "number" && Number.isInteger(value) && value > 0 ? value : fallback;
145
+ }
146
+ // packages/core/src/evolution/evidence/session-memory/sensitivity.ts
147
+ var SESSION_MEMORY_CREDENTIAL_REDACTION = "[credential-redacted]";
148
+ var CREDENTIAL_FIELD_KEYS = new Set([
149
+ "accesstoken",
150
+ "apikey",
151
+ "auth",
152
+ "authtoken",
153
+ "authorization",
154
+ "clientsecret",
155
+ "cookie",
156
+ "credential",
157
+ "credentials",
158
+ "idtoken",
159
+ "password",
160
+ "passwd",
161
+ "privatekey",
162
+ "proxyauthorization",
163
+ "refreshtoken",
164
+ "secret",
165
+ "secretvalue",
166
+ "sessiontoken",
167
+ "setcookie",
168
+ "signingkey",
169
+ "token"
170
+ ]);
171
+ var CREDENTIAL_KEY_PATTERN = String.raw`(?:access[_-]?token|api[_-]?key|auth(?:orization)?|client[_-]?secret|cookie|credential(?:s)?|id[_-]?token|password|passwd|private[_-]?key|proxy[_-]?authorization|refresh[_-]?token|secret(?:[_-]?value)?|session[_-]?token|set[_-]?cookie|signing[_-]?key|token)`;
172
+ var CREDENTIAL_SHAPE_PATTERNS = [
173
+ /-----BEGIN [A-Z0-9 ]*PRIVATE KEY-----/i,
174
+ /\bAKIA[0-9A-Z]{16}\b/,
175
+ /\bgh[pousr]_[A-Za-z0-9]{20,}\b/,
176
+ /\bxox[baprs]-[A-Za-z0-9-]{16,}\b/,
177
+ /\bBearer\s+[A-Za-z0-9._~+/=-]+/i,
178
+ /\bBasic\s+[A-Za-z0-9+/]+={0,2}/i,
179
+ new RegExp(String.raw`(?:^|[^A-Za-z0-9_])["']?${CREDENTIAL_KEY_PATTERN}["']?\s*[:=]\s*["']?[A-Za-z0-9][A-Za-z0-9._~+/=-]*`, "i"),
180
+ new RegExp(String.raw`(?:^|[^A-Za-z0-9_])["']?${CREDENTIAL_KEY_PATTERN}["']?\s*[:=]\s*["'](?!\[credential-redacted\]["'])[^"'\r\n]+["']`, "i")
181
+ ];
182
+ var PRIVATE_KEY_BLOCK_PATTERN = /-----BEGIN ([A-Z0-9 ]*PRIVATE KEY)-----[\s\S]*?-----END \1-----/giu;
183
+ var AUTHORIZATION_HEADER_PATTERN = /(^|[\r\n])(\s*(?:authorization|proxy-authorization)\s*:\s*)(?:Bearer|Basic)\s+[^\r\n]+/gimu;
184
+ var COOKIE_HEADER_PATTERN = /(^|[\r\n])(\s*(?:cookie|set-cookie)\s*:\s*)[^\r\n]+/gimu;
185
+ var BEARER_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]+/giu;
186
+ var BASIC_PATTERN = /\bBasic\s+[A-Za-z0-9+/]+={0,2}/giu;
187
+ var AWS_ACCESS_KEY_PATTERN = /\bAKIA[0-9A-Z]{16}\b/gu;
188
+ var GITHUB_TOKEN_PATTERN = /\bgh[pousr]_[A-Za-z0-9]{20,}\b/gu;
189
+ var SLACK_TOKEN_PATTERN = /\bxox[baprs]-[A-Za-z0-9-]{16,}\b/gu;
190
+ var QUOTED_SERIALIZED_CREDENTIAL_PATTERN = new RegExp(String.raw`(^|[^A-Za-z0-9_])(["']?${CREDENTIAL_KEY_PATTERN}["']?\s*[:=]\s*)(["'])([^"'\r\n]+)(\3)`, "gimu");
191
+ var SERIALIZED_CREDENTIAL_PATTERN = new RegExp(String.raw`(^|[^A-Za-z0-9_])(["']?${CREDENTIAL_KEY_PATTERN}["']?\s*[:=]\s*)(["']?)([A-Za-z0-9][A-Za-z0-9._~+/=-]*)(\3)`, "gimu");
192
+ var URL_USERINFO_PATTERN = /(https?:\/\/)[^@\s/"']+@/giu;
193
+ var URL_CREDENTIAL_PARAMETER_PATTERN = new RegExp(String.raw`([?&#]["']?${CREDENTIAL_KEY_PATTERN}["']?=)[^&#\s"'<>]+`, "giu");
194
+ function redactSessionMemoryCredentialText(value) {
195
+ let redacted = value.replace(PRIVATE_KEY_BLOCK_PATTERN, SESSION_MEMORY_CREDENTIAL_REDACTION).replace(AUTHORIZATION_HEADER_PATTERN, (_, boundary, prefix) => {
196
+ return `${boundary}${prefix}${SESSION_MEMORY_CREDENTIAL_REDACTION}`;
197
+ }).replace(COOKIE_HEADER_PATTERN, (_, boundary, prefix) => {
198
+ return `${boundary}${prefix}${SESSION_MEMORY_CREDENTIAL_REDACTION}`;
199
+ }).replace(BEARER_PATTERN, `Bearer ${SESSION_MEMORY_CREDENTIAL_REDACTION}`).replace(BASIC_PATTERN, `Basic ${SESSION_MEMORY_CREDENTIAL_REDACTION}`).replace(AWS_ACCESS_KEY_PATTERN, SESSION_MEMORY_CREDENTIAL_REDACTION).replace(GITHUB_TOKEN_PATTERN, SESSION_MEMORY_CREDENTIAL_REDACTION).replace(SLACK_TOKEN_PATTERN, SESSION_MEMORY_CREDENTIAL_REDACTION).replace(QUOTED_SERIALIZED_CREDENTIAL_PATTERN, (_, boundary, prefix, quote) => `${boundary}${prefix}${quote}${SESSION_MEMORY_CREDENTIAL_REDACTION}${quote}`).replace(SERIALIZED_CREDENTIAL_PATTERN, (_, boundary, prefix, quote, credentialValue) => {
200
+ const trailingPunctuation = quote === "" ? credentialValue.match(/[.,;!?]+$/u)?.[0] ?? "" : "";
201
+ return `${boundary}${prefix}${quote}${SESSION_MEMORY_CREDENTIAL_REDACTION}${quote}${trailingPunctuation}`;
202
+ }).replace(URL_CREDENTIAL_PARAMETER_PATTERN, (_, prefix) => `${prefix}${SESSION_MEMORY_CREDENTIAL_REDACTION}`).replace(URL_USERINFO_PATTERN, (_, protocol) => protocol);
203
+ if (redacted === "")
204
+ redacted = value;
205
+ return { value: redacted, redacted: redacted !== value };
206
+ }
207
+
208
+ // packages/core/src/evolution/shared.ts
209
+ var MAX_PROPOSED_CHANGE_LENGTH = 16 * 1024;
210
+ var PROCESS_LOCK_STALE_MS = 5 * 60 * 1000;
211
+ var FORBIDDEN_RAW_KEYS = new Set([
212
+ "commandhistory",
213
+ "commandoutput",
214
+ "credential",
215
+ "credentials",
216
+ "env",
217
+ "fullsource",
218
+ "memorybody",
219
+ "password",
220
+ "privatekey",
221
+ "prompt",
222
+ "promptbody",
223
+ "prompttext",
224
+ "rawcommand",
225
+ "rawcommandoutput",
226
+ "rawlog",
227
+ "rawlogs",
228
+ "rawoutput",
229
+ "rawpayload",
230
+ "rawprompt",
231
+ "secret",
232
+ "secretvalue",
233
+ "source",
234
+ "sourcebody",
235
+ "sourcecode",
236
+ "sourcecontent",
237
+ "sourcetext",
238
+ "stderr",
239
+ "stdout",
240
+ "token",
241
+ "transcript",
242
+ "transcriptbody",
243
+ "transcripttext"
244
+ ]);
245
+ // packages/core/src/evolution/evidence/session-memory/policy.ts
246
+ function createDefaultSessionMemoryPolicy() {
247
+ return {
248
+ enabled: true,
249
+ storeRawSegments: true,
250
+ maxRawSegmentBytes: 200000,
251
+ retentionDays: 30,
252
+ minimumMessageTokensToInit: 1e4,
253
+ minimumTokensBetweenUpdate: 5000,
254
+ toolCallsBetweenUpdates: 9
255
+ };
256
+ }
257
+ function parseSessionMemoryPolicy(value) {
258
+ const defaults = createDefaultSessionMemoryPolicy();
259
+ if (value === undefined)
260
+ return defaults;
261
+ return {
262
+ enabled: optionalBoolean(value.enabled, defaults.enabled),
263
+ storeRawSegments: optionalBoolean(value.storeRawSegments, defaults.storeRawSegments),
264
+ maxRawSegmentBytes: positiveInteger(value.maxRawSegmentBytes, defaults.maxRawSegmentBytes),
265
+ retentionDays: positiveInteger(value.retentionDays, defaults.retentionDays),
266
+ minimumMessageTokensToInit: positiveInteger(value.minimumMessageTokensToInit, defaults.minimumMessageTokensToInit),
267
+ minimumTokensBetweenUpdate: positiveInteger(value.minimumTokensBetweenUpdate, defaults.minimumTokensBetweenUpdate),
268
+ toolCallsBetweenUpdates: positiveInteger(value.toolCallsBetweenUpdates, defaults.toolCallsBetweenUpdates)
269
+ };
270
+ }
271
+ // packages/core/src/projects/index.ts
272
+ import { lstat, readFile, readdir, realpath, stat } from "node:fs/promises";
273
+ import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute2, join as join2, parse } from "node:path";
121
274
 
122
275
  // packages/core/src/runtime-logs/index.ts
276
+ import { lstatSync, readFileSync, realpathSync } from "node:fs";
277
+ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
123
278
  var SAFE_EXECUTION_METADATA_KEYS = new Set([
124
279
  "phase",
125
280
  "runtimeSurface",
@@ -135,6 +290,7 @@ var SAFE_EXECUTION_METADATA_KEYS = new Set([
135
290
  "redactionLabels",
136
291
  "normalizedEventType"
137
292
  ]);
293
+ var SENSITIVE_EVENT_TEXT_PATTERN = /https?:\/\/\S+|(^|[^a-z0-9])(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|stdout|stderr|transcript|formattedresponse|additionalcontext)([^a-z0-9]|$)|raw[\s_-]?(payload|prompt|output|source)|source[\s_-]?dump/i;
138
294
  var SAFE_REDACTION_LABELS = new Set([
139
295
  "raw-command",
140
296
  "raw-command-output",
@@ -142,26 +298,341 @@ var SAFE_REDACTION_LABELS = new Set([
142
298
  "sensitive-command",
143
299
  "sensitive-text"
144
300
  ]);
301
+ function resolveProjectLogIdentity(homeDir, repoRoot) {
302
+ const identityHomeDir = realpathDirectoryOrFallback(homeDir);
303
+ const workspaceRoot = realpathDirectoryOrFallback(repoRoot);
304
+ const workspaceKey = resolvePathProjectLogKey(identityHomeDir, workspaceRoot);
305
+ const gitCommonDir = resolveGitCommonDir(workspaceRoot);
306
+ if (gitCommonDir === null) {
307
+ return {
308
+ projectKey: workspaceKey,
309
+ workspaceKey,
310
+ projectRoot: workspaceRoot,
311
+ workspaceRoot,
312
+ gitCommonDir: null,
313
+ linkedWorktree: false
314
+ };
315
+ }
316
+ const commonDirOwnsWorktree = basename(gitCommonDir) === ".git";
317
+ const projectIdentityPath = commonDirOwnsWorktree ? dirname(gitCommonDir) : gitCommonDir;
318
+ const projectRoot = commonDirOwnsWorktree ? projectIdentityPath : workspaceRoot;
319
+ return {
320
+ projectKey: resolvePathProjectLogKey(identityHomeDir, projectIdentityPath),
321
+ workspaceKey,
322
+ projectRoot,
323
+ workspaceRoot,
324
+ gitCommonDir,
325
+ linkedWorktree: workspaceKey !== resolvePathProjectLogKey(identityHomeDir, projectIdentityPath)
326
+ };
327
+ }
328
+ function resolvePathProjectLogKey(homeDir, repoRoot) {
329
+ const trimmedHome = stripTrailingSlash2(homeDir);
330
+ const trimmedRepo = stripTrailingSlash2(repoRoot);
331
+ const relativePath = relative(trimmedHome, trimmedRepo);
332
+ const source = relativePath !== "" && !relativePath.startsWith("..") && !isAbsolute(relativePath) ? relativePath : trimmedRepo.replace(/^[/\\]+/, "");
333
+ const projectKey = source.split(/[/\\]+/).filter(Boolean).map((part) => sanitizePathSegment(part)).join("-") || "project-local";
334
+ return sanitizePersistentIdentifier(projectKey, "project");
335
+ }
336
+ function realpathDirectoryOrFallback(path) {
337
+ try {
338
+ return realpathSync(path);
339
+ } catch {
340
+ if (!isAbsolute(path))
341
+ return stripTrailingSlash2(path);
342
+ const missingSegments = [];
343
+ let current = stripTrailingSlash2(path);
344
+ for (;; ) {
345
+ const parent = dirname(current);
346
+ if (parent === current)
347
+ return stripTrailingSlash2(path);
348
+ missingSegments.unshift(basename(current));
349
+ current = parent;
350
+ try {
351
+ return join(realpathSync(current), ...missingSegments);
352
+ } catch {}
353
+ }
354
+ }
355
+ }
356
+ function resolveGitCommonDir(workspaceRoot) {
357
+ const markerPath = join(workspaceRoot, ".git");
358
+ let gitDir;
359
+ try {
360
+ const marker = lstatSync(markerPath);
361
+ if (marker.isDirectory()) {
362
+ gitDir = realpathSync(markerPath);
363
+ } else if (marker.isFile()) {
364
+ const value = readFileSync(markerPath, "utf8").trim();
365
+ const match = value.match(/^gitdir:\s*(.+)$/u);
366
+ if (match?.[1] === undefined || match[1].includes("\x00"))
367
+ return null;
368
+ gitDir = realpathSync(isAbsolute(match[1]) ? match[1] : resolve(workspaceRoot, match[1]));
369
+ } else {
370
+ return null;
371
+ }
372
+ } catch {
373
+ return null;
374
+ }
375
+ try {
376
+ const commonDirValue = readFileSync(join(gitDir, "commondir"), "utf8").trim();
377
+ if (commonDirValue === "" || commonDirValue.includes("\x00"))
378
+ return gitDir;
379
+ return realpathSync(isAbsolute(commonDirValue) ? commonDirValue : resolve(gitDir, commonDirValue));
380
+ } catch {
381
+ return gitDir;
382
+ }
383
+ }
384
+ function sanitizePathSegment(value) {
385
+ return value.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || "session-local";
386
+ }
387
+ function sanitizePersistentIdentifier(value, prefix) {
388
+ const pathSafe = value.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 120) || `${prefix}-local`;
389
+ if (!SENSITIVE_EVENT_TEXT_PATTERN.test(value) && !SENSITIVE_EVENT_TEXT_PATTERN.test(pathSafe)) {
390
+ return pathSafe;
391
+ }
392
+ return `${prefix}-${sha256Short(value)}`;
393
+ }
394
+ function stripTrailingSlash2(path) {
395
+ if (path === "/" || /^[A-Za-z]:[\\/]?$/.test(path))
396
+ return path;
397
+ return path.replace(/[/\\]+$/, "");
398
+ }
145
399
 
146
- // packages/core/src/knowledge/index.ts
147
- import { mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
148
- import { dirname, isAbsolute, join, relative, resolve } from "node:path";
400
+ // packages/core/src/projects/index.ts
401
+ class ProjectRegistrationError extends Error {
402
+ code;
403
+ constructor(code, message) {
404
+ super(message);
405
+ this.name = "ProjectRegistrationError";
406
+ this.code = code;
407
+ }
408
+ }
409
+ function resolveProjectRegistryPaths(homeDir) {
410
+ const paths = resolveEvoDevPaths(homeDir);
411
+ const discoveredDir = join2(paths.stateDir, "projects", "discovered");
412
+ const registeredDir = join2(paths.rootDir, "projects");
413
+ const workspaceDir = join2(paths.stateDir, "projects", "workspaces");
414
+ const aliasDir = join2(paths.stateDir, "projects", "aliases");
415
+ return {
416
+ discoveredDir,
417
+ registeredDir,
418
+ workspaceDir,
419
+ aliasDir,
420
+ discoveredPath: (projectKey) => join2(discoveredDir, `${projectKey}.json`),
421
+ registeredPath: (projectKey) => join2(registeredDir, projectKey, "workspace.json"),
422
+ workspacePath: (workspaceKey) => join2(workspaceDir, `${workspaceKey}.json`),
423
+ aliasPath: (aliasProjectKey) => join2(aliasDir, `${aliasProjectKey}.json`)
424
+ };
425
+ }
426
+ async function resolveProjectWorkspaceFromCwd(input) {
427
+ if (!isAbsolute2(input.cwd))
428
+ return null;
429
+ let cwd;
430
+ try {
431
+ const info = await stat(input.cwd);
432
+ if (!info.isDirectory())
433
+ return null;
434
+ cwd = await realpath(input.cwd);
435
+ } catch (error) {
436
+ if (isNotFoundError(error))
437
+ return null;
438
+ throw error;
439
+ }
440
+ const gitRoot = await findNearestGitRoot(cwd);
441
+ const workspaceRoot = gitRoot ?? cwd;
442
+ const identity = resolveProjectLogIdentity(input.homeDir, workspaceRoot);
443
+ return {
444
+ projectKey: sanitizeStorageId(identity.projectKey, "project"),
445
+ workspaceKey: sanitizeStorageId(identity.workspaceKey, "workspace"),
446
+ displayName: basename2(identity.projectRoot) || parse(identity.projectRoot).root,
447
+ projectRoot: identity.projectRoot,
448
+ workspaceRoot,
449
+ workspaceKind: gitRoot === null ? "directory" : "git",
450
+ gitCommonDir: identity.gitCommonDir,
451
+ linkedWorktree: identity.linkedWorktree,
452
+ cwd
453
+ };
454
+ }
455
+ async function listProjectAliases(input) {
456
+ const paths = resolveProjectRegistryPaths(input.homeDir);
457
+ const aliases = {};
458
+ for (const path of await listJsonFilePaths(paths.aliasDir)) {
459
+ const record = await readProjectAlias(path);
460
+ if (record !== null)
461
+ aliases[record.aliasProjectKey] = record.canonicalProjectKey;
462
+ }
463
+ for (const path of await listJsonFilePaths(paths.discoveredDir)) {
464
+ const record = await readDiscoveredProject(path);
465
+ if (record !== null) {
466
+ await collectAvailableProjectAlias(input.homeDir, record, aliases);
467
+ }
468
+ }
469
+ for (const projectKey of await listDirectoryNames2(paths.registeredDir)) {
470
+ const record = await readRegisteredProject(join2(paths.registeredDir, projectKey, "workspace.json"));
471
+ if (record !== null) {
472
+ await collectAvailableProjectAlias(input.homeDir, record, aliases);
473
+ }
474
+ }
475
+ return normalizeProjectAliases(aliases);
476
+ }
477
+ function canonicalizeProjectKey(projectKey, aliases) {
478
+ let current = projectKey;
479
+ const seen = new Set;
480
+ while (!seen.has(current)) {
481
+ seen.add(current);
482
+ const next = aliases[current];
483
+ if (next === undefined || next === current)
484
+ return current;
485
+ current = next;
486
+ }
487
+ return projectKey;
488
+ }
489
+ async function listEquivalentProjectKeys(input) {
490
+ const aliases = await listProjectAliases({ homeDir: input.homeDir });
491
+ const canonical = canonicalizeProjectKey(input.projectKey, aliases);
492
+ return [
493
+ ...new Set([
494
+ canonical,
495
+ input.projectKey,
496
+ ...Object.keys(aliases).filter((alias) => canonicalizeProjectKey(alias, aliases) === canonical)
497
+ ])
498
+ ].sort();
499
+ }
500
+ async function collectAvailableProjectAlias(homeDir, record, aliases) {
501
+ const workspace = await resolveProjectWorkspaceFromCwd({
502
+ homeDir,
503
+ cwd: record.workspaceRoot
504
+ }).catch(() => null);
505
+ if (workspace === null)
506
+ return;
507
+ if (record.projectKey !== workspace.projectKey) {
508
+ aliases[record.projectKey] = workspace.projectKey;
509
+ }
510
+ if (workspace.workspaceKey !== workspace.projectKey) {
511
+ aliases[workspace.workspaceKey] = workspace.projectKey;
512
+ }
513
+ }
514
+ function normalizeProjectAliases(aliases) {
515
+ return Object.fromEntries(Object.keys(aliases).sort().flatMap((alias) => {
516
+ const canonical = canonicalizeProjectKey(alias, aliases);
517
+ return canonical === alias ? [] : [[alias, canonical]];
518
+ }));
519
+ }
520
+ async function findNearestGitRoot(cwd) {
521
+ let current = cwd;
522
+ for (;; ) {
523
+ try {
524
+ const marker = await lstat(join2(current, ".git"));
525
+ if (marker.isDirectory() || marker.isFile())
526
+ return current;
527
+ } catch (error) {
528
+ if (!isNotFoundError(error))
529
+ throw error;
530
+ }
531
+ const parent = dirname2(current);
532
+ if (parent === current)
533
+ return null;
534
+ current = parent;
535
+ }
536
+ }
537
+ async function readDiscoveredProject(path) {
538
+ try {
539
+ return parseDiscoveredProject(JSON.parse(await readFile(path, "utf8")));
540
+ } catch (error) {
541
+ if (isNotFoundError(error) || error instanceof ProjectRegistrationError)
542
+ return null;
543
+ throw error;
544
+ }
545
+ }
546
+ async function readRegisteredProject(path) {
547
+ try {
548
+ return parseRegisteredProject(JSON.parse(await readFile(path, "utf8")));
549
+ } catch (error) {
550
+ if (isNotFoundError(error) || error instanceof ProjectRegistrationError)
551
+ return null;
552
+ throw error;
553
+ }
554
+ }
555
+ async function readProjectAlias(path) {
556
+ try {
557
+ return parseProjectAlias(JSON.parse(await readFile(path, "utf8")));
558
+ } catch (error) {
559
+ if (isNotFoundError(error) || error instanceof ProjectRegistrationError)
560
+ return null;
561
+ throw error;
562
+ }
563
+ }
564
+ function parseDiscoveredProject(value) {
565
+ const record = requireRecord(value);
566
+ if (record.schemaVersion !== 1 || record.kind !== "discovered-project" || !isProjectKey(record.projectKey) || !isNonEmptyString(record.displayName) || !isAbsoluteString(record.workspaceRoot) || !isAbsoluteString(record.lastCwd) || !isWorkspaceKind(record.workspaceKind) || !isDiscoveryTargetArray(record.sourceTargets) || !(record.lastSessionKey === null || isNonEmptyString(record.lastSessionKey)) || !isNonEmptyString(record.firstSeenAt) || !isNonEmptyString(record.lastSeenAt) || record.localOnly !== true || record.sourceContentStored !== false) {
567
+ throw new ProjectRegistrationError("invalid", "Discovered project record is invalid.");
568
+ }
569
+ return record;
570
+ }
571
+ function parseRegisteredProject(value) {
572
+ const record = requireRecord(value);
573
+ if (record.schemaVersion !== 1 || record.kind !== "registered-project" || !isProjectKey(record.projectKey) || !isNonEmptyString(record.displayName) || !isAbsoluteString(record.workspaceRoot) || !isWorkspaceKind(record.workspaceKind) || !isNonEmptyString(record.registeredAt) || !isNonEmptyString(record.lastSeenAt) || record.localOnly !== true || record.sourceContentStored !== false) {
574
+ throw new ProjectRegistrationError("invalid", "Registered project record is invalid.");
575
+ }
576
+ return record;
577
+ }
578
+ function parseProjectAlias(value) {
579
+ const record = requireRecord(value);
580
+ if (record.schemaVersion !== 1 || record.kind !== "project-alias" || !isProjectKey(record.aliasProjectKey) || !isProjectKey(record.canonicalProjectKey) || record.aliasProjectKey === record.canonicalProjectKey || !isAbsoluteString(record.workspaceRoot) || !isNonEmptyString(record.createdAt) || !isNonEmptyString(record.updatedAt) || record.localOnly !== true || record.sourceContentStored !== false) {
581
+ throw new ProjectRegistrationError("invalid", "Project alias record is invalid.");
582
+ }
583
+ return record;
584
+ }
585
+ async function listJsonFilePaths(path) {
586
+ try {
587
+ return (await readdir(path, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => join2(path, entry.name)).sort();
588
+ } catch (error) {
589
+ if (isNotFoundError(error))
590
+ return [];
591
+ throw error;
592
+ }
593
+ }
594
+ async function listDirectoryNames2(path) {
595
+ try {
596
+ return (await readdir(path, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
597
+ } catch (error) {
598
+ if (isNotFoundError(error))
599
+ return [];
600
+ throw error;
601
+ }
602
+ }
603
+ function isProjectKey(value) {
604
+ return typeof value === "string" && value !== "." && value !== ".." && /^[A-Za-z0-9._-]{1,120}$/.test(value);
605
+ }
606
+ function isNonEmptyString(value) {
607
+ return typeof value === "string" && value.trim() !== "";
608
+ }
609
+ function isAbsoluteString(value) {
610
+ return isNonEmptyString(value) && isAbsolute2(value);
611
+ }
612
+ function isWorkspaceKind(value) {
613
+ return value === "git" || value === "directory";
614
+ }
615
+ function isDiscoveryTargetArray(value) {
616
+ return Array.isArray(value) && value.length > 0 && value.every((item) => item === "claude" || item === "codex");
617
+ }
618
+ function requireRecord(value) {
619
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
620
+ throw new ProjectRegistrationError("invalid", "Project record must be an object.");
621
+ }
622
+ return value;
623
+ }
624
+
625
+ // packages/core/src/evolution/evidence/session-memory/constants.ts
626
+ var DEFAULT_MAX_RAW_EVENT_BYTES = 64 * 1024;
627
+ // packages/core/src/evolution/knowledge/index.ts
628
+ import { mkdir, readFile as readFile2, readdir as readdir2, rename, rm, stat as stat2, writeFile } from "node:fs/promises";
629
+ import { dirname as dirname3, isAbsolute as isAbsolute3, join as join3, relative as relative2, resolve as resolve2 } from "node:path";
630
+
631
+ // packages/core/src/evolution/knowledge/change-store.ts
632
+ var KNOWLEDGE_CHANGE_LOCK_STALE_MS = 5 * 60 * 1000;
633
+
634
+ // packages/core/src/evolution/knowledge/index.ts
149
635
  var RESERVED_OKF_FILENAMES = new Set(["index.md", "log.md"]);
150
- var FORBIDDEN_OKF_TEXT = /\b(secret|token|password|passwd|api[_-]?key|apikey|credential|credentials|secret[\s_-]*token(?:[\s_-]*repro)?|raw[\s_-]*(?:log|logs|output|source|prompt)(?:[\s_-]*repro)?|shell[\s_-]*history|command[\s_-]*history)\b/i;
151
- var PRIVATE_OR_INTERNAL_URL = /https?:\/\/\S*(?:internal|private|corp|localhost|127\.0\.0\.1)\S*/i;
152
- var OKF_PRIVACY_FLAG_KEYS = [
153
- "rawPromptsStored",
154
- "rawLogsStored",
155
- "sourceDumpsStored",
156
- "rawCommandOutputStored",
157
- "secretsStored",
158
- "internalLinksStored"
159
- ];
160
- var OKF_QUERY_PRIVACY_FLAG_KEYS = [
161
- ...OKF_PRIVACY_FLAG_KEYS,
162
- "rawOutputStored",
163
- "sourceContentStored"
164
- ];
165
636
  var ACTIVE_OKF_REVIEW_STATES = ["accepted", "auto-accepted"];
166
637
  var OKF_REVIEW_STATES = [
167
638
  "auto-accepted",
@@ -192,19 +663,19 @@ var BEHAVIOR_CHANGE_KINDS = new Set([
192
663
  "repo-asset-suggestion"
193
664
  ]);
194
665
  function resolveOkfKnowledgePaths(homeDir) {
195
- const paths = resolveEvoDevPaths(homeDir);
666
+ const paths2 = resolveEvoDevPaths(homeDir);
196
667
  return {
197
- knowledgeDir: paths.knowledgeDir,
198
- okfDir: join(paths.knowledgeDir, "okf"),
199
- indexesDir: join(paths.knowledgeDir, "indexes"),
200
- tmpDir: join(paths.knowledgeDir, "tmp")
668
+ knowledgeDir: paths2.knowledgeDir,
669
+ okfDir: join3(paths2.knowledgeDir, "okf"),
670
+ indexesDir: join3(paths2.knowledgeDir, "indexes"),
671
+ tmpDir: join3(paths2.knowledgeDir, "tmp")
201
672
  };
202
673
  }
203
674
  async function ensureOkfKnowledgeBase(homeDir) {
204
- const paths = resolveOkfKnowledgePaths(homeDir);
205
- await ensureLocalKnowledgeGitRepository(paths.knowledgeDir);
206
- await mkdir(paths.indexesDir, { recursive: true });
207
- await mkdir(paths.tmpDir, { recursive: true });
675
+ const paths2 = resolveOkfKnowledgePaths(homeDir);
676
+ await ensureLocalKnowledgeGitRepository(paths2.knowledgeDir);
677
+ await mkdir(paths2.indexesDir, { recursive: true });
678
+ await mkdir(paths2.tmpDir, { recursive: true });
208
679
  const directories = [
209
680
  {
210
681
  path: "",
@@ -234,13 +705,47 @@ async function ensureOkfKnowledgeBase(homeDir) {
234
705
  { path: "references", title: "References", description: "Cited references." }
235
706
  ];
236
707
  for (const directory of directories) {
237
- await ensureOkfDirectory(paths.okfDir, directory.path, directory.title, directory.description);
708
+ await ensureOkfDirectory(paths2.okfDir, directory.path, directory.title, directory.description);
238
709
  }
239
710
  await rebuildOkfKnowledgeIndexes({ homeDir });
240
711
  }
712
+ function normalizeKnowledgeSupportRef(value, path) {
713
+ const input = assertRecordValue(value, path);
714
+ const kind = readRequiredString(input.kind, `${path}.kind`);
715
+ if (kind !== "user-declaration" && kind !== "repo-policy" && kind !== "state-observation" && kind !== "verified-outcome" && kind !== "semantic-inference") {
716
+ throw new Error(`${path}.kind is invalid.`);
717
+ }
718
+ const observedAt = readRequiredString(input.observedAt, `${path}.observedAt`);
719
+ if (!Number.isFinite(Date.parse(observedAt)))
720
+ throw new Error(`${path}.observedAt is invalid.`);
721
+ const subjectFingerprint = input.subjectFingerprint === null ? null : sanitizeOkfText(readRequiredString(input.subjectFingerprint, `${path}.subjectFingerprint`));
722
+ return {
723
+ id: sanitizeOkfText(readRequiredString(input.id, `${path}.id`)),
724
+ kind,
725
+ sourceRefId: sanitizeOkfText(readRequiredString(input.sourceRefId, `${path}.sourceRefId`)),
726
+ subjectFingerprint,
727
+ observedAt: new Date(observedAt).toISOString()
728
+ };
729
+ }
730
+ function assertRecordValue(value, path) {
731
+ if (!isRecord(value))
732
+ throw new Error(`${path} must be an object.`);
733
+ return value;
734
+ }
735
+ function readRequiredString(value, path) {
736
+ if (!isNonEmptyString2(value))
737
+ throw new Error(`${path} must be a non-empty string.`);
738
+ return value;
739
+ }
740
+ function isRecord(value) {
741
+ return typeof value === "object" && value !== null && !Array.isArray(value);
742
+ }
743
+ function isNonEmptyString2(value) {
744
+ return typeof value === "string" && value.trim() !== "";
745
+ }
241
746
  async function rebuildOkfKnowledgeIndexes(input) {
242
- const paths = resolveOkfKnowledgePaths(input.homeDir);
243
- await mkdir(paths.indexesDir, { recursive: true });
747
+ const paths2 = resolveOkfKnowledgePaths(input.homeDir);
748
+ await mkdir(paths2.indexesDir, { recursive: true });
244
749
  const concepts = (await listOkfKnowledgeConcepts({ homeDir: input.homeDir })).filter(isActiveOkfConcept);
245
750
  const conceptSummaries = concepts.map((concept) => ({
246
751
  id: concept.id,
@@ -257,34 +762,34 @@ async function rebuildOkfKnowledgeIndexes(input) {
257
762
  pathScopes: concept.pathScopes
258
763
  }));
259
764
  const pathsWritten = [
260
- join(paths.indexesDir, "index.json"),
261
- join(paths.indexesDir, "concepts.json"),
262
- join(paths.indexesDir, "repos.json"),
263
- join(paths.indexesDir, "roles.json"),
264
- join(paths.indexesDir, "workflows.json")
765
+ join3(paths2.indexesDir, "index.json"),
766
+ join3(paths2.indexesDir, "concepts.json"),
767
+ join3(paths2.indexesDir, "repos.json"),
768
+ join3(paths2.indexesDir, "roles.json"),
769
+ join3(paths2.indexesDir, "workflows.json")
265
770
  ];
266
- await writeJson(pathsWritten[0], {
771
+ await writeJson2(pathsWritten[0], {
267
772
  schemaVersion: 1,
268
773
  kind: "okf-knowledge-index",
269
774
  conceptCount: concepts.length,
270
775
  updatedAt: new Date().toISOString()
271
776
  }, { overwrite: true });
272
- await writeJson(pathsWritten[1], {
777
+ await writeJson2(pathsWritten[1], {
273
778
  schemaVersion: 1,
274
779
  kind: "okf-concepts-index",
275
780
  concepts: conceptSummaries
276
781
  }, { overwrite: true });
277
- await writeJson(pathsWritten[2], {
782
+ await writeJson2(pathsWritten[2], {
278
783
  schemaVersion: 1,
279
784
  kind: "okf-repos-index",
280
785
  repos: groupConceptsByTag(concepts, "repoTags")
281
786
  }, { overwrite: true });
282
- await writeJson(pathsWritten[3], {
787
+ await writeJson2(pathsWritten[3], {
283
788
  schemaVersion: 1,
284
789
  kind: "okf-roles-index",
285
790
  roles: groupConceptsByTag(concepts, "roleTags")
286
791
  }, { overwrite: true });
287
- await writeJson(pathsWritten[4], {
792
+ await writeJson2(pathsWritten[4], {
288
793
  schemaVersion: 1,
289
794
  kind: "okf-workflows-index",
290
795
  workflows: groupConceptsByTag(concepts, "workflowTags")
@@ -293,33 +798,37 @@ async function rebuildOkfKnowledgeIndexes(input) {
293
798
  }
294
799
  async function listOkfKnowledgeConcepts(input) {
295
800
  const okfDir = resolveOkfKnowledgePaths(input.homeDir).okfDir;
296
- if (!await pathExists(okfDir))
801
+ if (!await pathExists2(okfDir))
297
802
  return [];
803
+ const equivalentProjectKeys = input.projectKey === undefined ? undefined : await listEquivalentProjectKeys({
804
+ homeDir: input.homeDir,
805
+ projectKey: input.projectKey
806
+ });
298
807
  const files = await listMarkdownFiles(okfDir);
299
808
  const concepts = [];
300
809
  for (const file of files) {
301
810
  if (RESERVED_OKF_FILENAMES.has(file.name))
302
811
  continue;
303
- const content = await readFile(file.path, "utf8");
812
+ const content = await readFile2(file.path, "utf8");
304
813
  const parsed = parseOkfConceptFile(okfDir, file.path, content);
305
814
  if (parsed !== null)
306
815
  concepts.push(parsed);
307
816
  }
308
- return concepts.filter((concept) => matchesConceptFilters(concept, input)).sort((left, right) => left.id.localeCompare(right.id));
817
+ return concepts.filter((concept) => matchesConceptFilters(concept, input, equivalentProjectKeys)).sort((left, right) => left.id.localeCompare(right.id));
309
818
  }
310
819
  async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
311
820
  await mkdir(knowledgeDir, { recursive: true });
312
- const gitDir = join(knowledgeDir, ".git");
313
- if (await pathExists(gitDir))
821
+ const gitDir = join3(knowledgeDir, ".git");
822
+ if (await pathExists2(gitDir))
314
823
  return;
315
- await mkdir(join(gitDir, "objects", "info"), { recursive: true });
316
- await mkdir(join(gitDir, "objects", "pack"), { recursive: true });
317
- await mkdir(join(gitDir, "refs", "heads"), { recursive: true });
318
- await mkdir(join(gitDir, "refs", "tags"), { recursive: true });
319
- await mkdir(join(gitDir, "info"), { recursive: true });
320
- await writeTextIfMissing(join(gitDir, "HEAD"), `ref: refs/heads/main
824
+ await mkdir(join3(gitDir, "objects", "info"), { recursive: true });
825
+ await mkdir(join3(gitDir, "objects", "pack"), { recursive: true });
826
+ await mkdir(join3(gitDir, "refs", "heads"), { recursive: true });
827
+ await mkdir(join3(gitDir, "refs", "tags"), { recursive: true });
828
+ await mkdir(join3(gitDir, "info"), { recursive: true });
829
+ await writeTextIfMissing(join3(gitDir, "HEAD"), `ref: refs/heads/main
321
830
  `);
322
- await writeTextIfMissing(join(gitDir, "config"), [
831
+ await writeTextIfMissing(join3(gitDir, "config"), [
323
832
  "[core]",
324
833
  "\trepositoryformatversion = 0",
325
834
  "\tfilemode = true",
@@ -328,7 +837,7 @@ async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
328
837
  ""
329
838
  ].join(`
330
839
  `));
331
- await writeTextIfMissing(join(gitDir, "info", "exclude"), [
840
+ await writeTextIfMissing(join3(gitDir, "info", "exclude"), [
332
841
  "# EvoDev user-local knowledge git repository.",
333
842
  "# No remote is configured by default.",
334
843
  ""
@@ -336,20 +845,20 @@ async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
336
845
  `));
337
846
  }
338
847
  async function writeTextIfMissing(path, value) {
339
- if (await pathExists(path))
848
+ if (await pathExists2(path))
340
849
  return;
341
- await mkdir(dirname(path), { recursive: true });
850
+ await mkdir(dirname3(path), { recursive: true });
342
851
  await writeFile(path, value, { encoding: "utf8", flag: "wx" });
343
852
  }
344
853
  function sanitizeOkfText(value) {
345
- return value.replace(new RegExp(PRIVATE_OR_INTERNAL_URL.source, "gi"), "[redacted]").replace(new RegExp(FORBIDDEN_OKF_TEXT.source, "gi"), "[redacted]").replace(/\s+/gu, " ").trim().slice(0, 800);
854
+ return redactSessionMemoryCredentialText(value).value.replace(/\s+/gu, " ").trim().slice(0, 800);
346
855
  }
347
856
  async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
348
857
  const dir = relativeDir === "" || relativeDir === "." ? okfDir : resolveOkfTargetPath(okfDir, relativeDir);
349
858
  await mkdir(dir, { recursive: true });
350
859
  const isRoot = dir === okfDir;
351
- const indexPath = join(dir, "index.md");
352
- if (!await pathExists(indexPath)) {
860
+ const indexPath = join3(dir, "index.md");
861
+ if (!await pathExists2(indexPath)) {
353
862
  await writeFile(indexPath, isRoot ? [
354
863
  "---",
355
864
  `okf_version: ${yamlString("0.1")}`,
@@ -365,8 +874,8 @@ async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
365
874
  `) : [`# ${title}`, "", description, ""].join(`
366
875
  `), "utf8");
367
876
  }
368
- const logPath = join(dir, "log.md");
369
- if (!await pathExists(logPath)) {
877
+ const logPath = join3(dir, "log.md");
878
+ if (!await pathExists2(logPath)) {
370
879
  await writeFile(logPath, [
371
880
  "# Directory Update Log",
372
881
  "",
@@ -411,6 +920,8 @@ function parseOkfConceptFile(okfDir, filePath, content) {
411
920
  reviewState,
412
921
  lifecycle: lifecycleParsed.lifecycle,
413
922
  lifecyclePersisted: lifecycleParsed.persisted,
923
+ verificationSnapshot: parseOkfVerificationSnapshot(frontmatter),
924
+ supportRef: parseOkfKnowledgeSupportRef(frontmatter),
414
925
  title,
415
926
  description,
416
927
  tags,
@@ -421,8 +932,40 @@ function parseOkfConceptFile(okfDir, filePath, content) {
421
932
  body: parsed.body
422
933
  };
423
934
  }
424
- function matchesConceptFilters(concept, input) {
425
- if (input.projectKey !== undefined && concept.repoTags.length > 0 && !concept.repoTags.includes(sanitizeSlug(input.projectKey)) && !concept.tags.includes(`repo:${sanitizeSlug(input.projectKey)}`)) {
935
+ function parseOkfKnowledgeSupportRef(frontmatter) {
936
+ const block = extractNestedYamlBlock(frontmatter, "evodev", "supportRef");
937
+ if (block === null)
938
+ return null;
939
+ try {
940
+ return normalizeKnowledgeSupportRef({
941
+ id: readIndentedYamlScalar(block, "id"),
942
+ kind: readIndentedYamlScalar(block, "kind"),
943
+ sourceRefId: readIndentedYamlScalar(block, "sourceRefId"),
944
+ subjectFingerprint: readNullableLifecycleString(readIndentedYamlScalar(block, "subjectFingerprint")),
945
+ observedAt: readIndentedYamlScalar(block, "observedAt")
946
+ }, "evodev.supportRef");
947
+ } catch {
948
+ return null;
949
+ }
950
+ }
951
+ function parseOkfVerificationSnapshot(frontmatter) {
952
+ const block = extractNestedYamlBlock(frontmatter, "evodev", "verificationSnapshot");
953
+ if (block === null)
954
+ return null;
955
+ const schemaVersion = readIndentedYamlScalar(block, "schemaVersion");
956
+ const verifiedAt = normalizeIsoDateString(readIndentedYamlScalar(block, "verifiedAt"));
957
+ if (schemaVersion !== "1" || verifiedAt === null)
958
+ return null;
959
+ return {
960
+ schemaVersion: 1,
961
+ verifiedAt,
962
+ evidenceRefs: readYamlList(block, "evidenceRefs"),
963
+ repository: null
964
+ };
965
+ }
966
+ function matchesConceptFilters(concept, input, equivalentProjectKeys) {
967
+ const projectKeys = (equivalentProjectKeys ?? []).map(sanitizeSlug);
968
+ if (input.projectKey !== undefined && concept.repoTags.length > 0 && ![sanitizeSlug(input.projectKey), ...projectKeys].some((projectKey) => concept.repoTags.includes(projectKey) || concept.tags.includes(`repo:${projectKey}`))) {
426
969
  return false;
427
970
  }
428
971
  if (input.roleId !== undefined && concept.roleTags.length > 0 && !concept.roleTags.includes(sanitizeSlug(input.roleId)) && !concept.tags.includes(`role:${sanitizeSlug(input.roleId)}`)) {
@@ -473,13 +1016,13 @@ function isLifecycleDateDue(value, now) {
473
1016
  }
474
1017
  function createDefaultOkfLifecycle(input) {
475
1018
  const createdAt = normalizeIsoDateString(input.createdAt) ?? "1970-01-01T00:00:00.000Z";
476
- const policy = resolveOkfLifecyclePolicy(input);
1019
+ const policy2 = resolveOkfLifecyclePolicy(input);
477
1020
  return {
478
1021
  status: lifecycleStatusFromReviewState(input.reviewState),
479
1022
  createdAt,
480
1023
  lastVerifiedAt: createdAt,
481
- reviewAfter: addDaysIso(createdAt, policy.reviewAfterDays),
482
- staleAfter: addDaysIso(createdAt, policy.staleAfterDays),
1024
+ reviewAfter: addDaysIso(createdAt, policy2.reviewAfterDays),
1025
+ staleAfter: addDaysIso(createdAt, policy2.staleAfterDays),
483
1026
  supersedes: [],
484
1027
  supersededBy: null,
485
1028
  revokedAt: null,
@@ -537,10 +1080,10 @@ function isOkfLifecycleStatus(value) {
537
1080
  function normalizeIsoDateString(value) {
538
1081
  if (value === undefined || value === null || value === "" || value === "null")
539
1082
  return null;
540
- const time = Date.parse(value);
541
- if (!Number.isFinite(time))
1083
+ const time2 = Date.parse(value);
1084
+ if (!Number.isFinite(time2))
542
1085
  return null;
543
- return new Date(time).toISOString();
1086
+ return new Date(time2).toISOString();
544
1087
  }
545
1088
  function addDaysIso(value, days) {
546
1089
  const date = new Date(value);
@@ -641,12 +1184,12 @@ function parseYamlValue(value) {
641
1184
  return trimmed.replace(/^['"]|['"]$/gu, "");
642
1185
  }
643
1186
  async function listMarkdownFiles(root) {
644
- if (!await pathExists(root))
1187
+ if (!await pathExists2(root))
645
1188
  return [];
646
- const entries = await readdir(root, { withFileTypes: true });
1189
+ const entries = await readdir2(root, { withFileTypes: true });
647
1190
  const files = [];
648
1191
  for (const entry of entries) {
649
- const path = join(root, entry.name);
1192
+ const path = join3(root, entry.name);
650
1193
  if (entry.isDirectory()) {
651
1194
  files.push(...await listMarkdownFiles(path));
652
1195
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
@@ -672,14 +1215,14 @@ function resolveOkfTargetPath(okfDir, targetPath) {
672
1215
  if (clean.split("/").some((segment) => segment === ".." || segment === "." || segment === "")) {
673
1216
  throw new Error(`Unsafe OKF target path: ${targetPath}`);
674
1217
  }
675
- const resolved = join(okfDir, clean);
676
- const rel = relative(okfDir, resolved);
1218
+ const resolved = join3(okfDir, clean);
1219
+ const rel = relative2(okfDir, resolved);
677
1220
  if (rel.startsWith("..") || rel === "")
678
1221
  throw new Error(`Unsafe OKF target path: ${targetPath}`);
679
1222
  return resolved;
680
1223
  }
681
1224
  function toOkfRelativePath(okfDir, path) {
682
- return relative(okfDir, path).replace(/\\/gu, "/");
1225
+ return relative2(okfDir, path).replace(/\\/gu, "/");
683
1226
  }
684
1227
  function sanitizeSlug(value) {
685
1228
  const slug = value.trim().toLowerCase().replace(/[^a-z0-9._/-]+/gu, "-").replace(/\/+/gu, "/").replace(/^-+|-+$/gu, "");
@@ -694,15 +1237,15 @@ function escapeRegExp(value) {
694
1237
  function todayIsoDate() {
695
1238
  return new Date().toISOString().slice(0, 10);
696
1239
  }
697
- async function writeJson(path, value, options = {}) {
698
- await mkdir(dirname(path), { recursive: true });
1240
+ async function writeJson2(path, value, options = {}) {
1241
+ await mkdir(dirname3(path), { recursive: true });
699
1242
  const flag = options.overwrite === true ? "w" : "wx";
700
1243
  await writeFile(path, `${JSON.stringify(value, null, 2)}
701
1244
  `, { encoding: "utf8", flag });
702
1245
  }
703
- async function pathExists(path) {
1246
+ async function pathExists2(path) {
704
1247
  try {
705
- await stat(path);
1248
+ await stat2(path);
706
1249
  return true;
707
1250
  } catch (error) {
708
1251
  if (error instanceof Error && "code" in error && error.code === "ENOENT")
@@ -711,79 +1254,6 @@ async function pathExists(path) {
711
1254
  }
712
1255
  }
713
1256
 
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
- // packages/core/src/task/index.ts
752
- var FORBIDDEN_TASK_WRITE_SEGMENTS = new Set([".claude", ".codex"]);
753
- var FORBIDDEN_PROJECT_ASSET_SEGMENTS = new Set(["packages", "src"]);
754
- var FORBIDDEN_TASK_WRITE_FILES = new Set(["agents.md", "claude.md", "package.json", "readme.md"]);
755
- var FORBIDDEN_RAW_KEYS2 = new Set([
756
- "rawoutput",
757
- "raw_output",
758
- "stdout",
759
- "stderr",
760
- "source",
761
- "sourcecontent",
762
- "source_content",
763
- "sourcetext",
764
- "source_text",
765
- "prompt",
766
- "prompttext",
767
- "prompt_text",
768
- "transcript",
769
- "transcripttext",
770
- "transcript_text",
771
- "secret",
772
- "secretvalue",
773
- "secret_value"
774
- ]);
775
- var ALLOWED_VERIFICATION_KEYS = new Set([
776
- "acceptanceResults",
777
- "antiCriteriaResults",
778
- "commands",
779
- "evidence",
780
- "exitCode",
781
- "id",
782
- "status",
783
- "summary",
784
- "type"
785
- ]);
786
-
787
1257
  // packages/core/src/team/prompts.ts
788
1258
  var TEAM_ROLE_STARTUP_PROMPT_TEMPLATE = [
789
1259
  "You are an EvoDev managed role agent.",
@@ -848,6 +1318,23 @@ var TEAM_INTERNAL_WAKE_SIGNAL = [
848
1318
  "No user request is included in this message. Continue only from EvoDev team inbox messages injected by hooks."
849
1319
  ].join(`
850
1320
  `);
1321
+ var BUILT_IN_TEAM_DEFINITION = {
1322
+ version: 1,
1323
+ name: "builtin-minimal-team",
1324
+ description: "Built-in minimal EvoDev team fallback.",
1325
+ agents: {
1326
+ executor: "builtin:executor",
1327
+ reviewer: "builtin:reviewer",
1328
+ tester: "builtin:tester"
1329
+ },
1330
+ body: [
1331
+ "# Built-in Minimal Team",
1332
+ "",
1333
+ "Use role agents only when delegation improves correctness, coverage, safety, or latency.",
1334
+ "Spawn roles on demand and send self-contained assignments through Teams MCP."
1335
+ ].join(`
1336
+ `)
1337
+ };
851
1338
 
852
1339
  // packages/core/src/hooks/index.ts
853
1340
  var CANONICAL_HOOK_EVENT_TYPES = [
@@ -916,6 +1403,12 @@ var CODEX_STOP_EVENTS_WITHOUT_ADDITIONAL_CONTEXT = new Set([
916
1403
  "Stop",
917
1404
  "SubagentStop"
918
1405
  ]);
1406
+ var COMPLETION_EVENTS_WITHOUT_DEVELOPMENT_DIAGNOSTICS = new Set([
1407
+ "Stop",
1408
+ "SubagentStop",
1409
+ "TaskCompleted",
1410
+ "TeammateIdle"
1411
+ ]);
919
1412
  function createDefaultHookSettings() {
920
1413
  return {
921
1414
  enabled: true,
@@ -944,13 +1437,13 @@ function parseHookSettings(value) {
944
1437
  const defaults = createDefaultHookSettings();
945
1438
  if (value === undefined || value === null)
946
1439
  return defaults;
947
- if (!isRecord(value))
1440
+ if (!isRecord2(value))
948
1441
  throw new Error("Invalid hooks settings; expected object.");
949
- const observability = isRecord(value.observability) ? value.observability : undefined;
950
- optionalBoolean(observability?.metadataOnly, defaults.observability.metadataOnly, "hooks.observability.metadataOnly");
951
- optionalBoolean(observability?.rawPayloadStorage, defaults.observability.rawPayloadStorage, "hooks.observability.rawPayloadStorage");
1442
+ const observability = isRecord2(value.observability) ? value.observability : undefined;
1443
+ optionalBoolean2(observability?.metadataOnly, defaults.observability.metadataOnly, "hooks.observability.metadataOnly");
1444
+ optionalBoolean2(observability?.rawPayloadStorage, defaults.observability.rawPayloadStorage, "hooks.observability.rawPayloadStorage");
952
1445
  return {
953
- enabled: optionalBoolean(value.enabled, defaults.enabled, "hooks.enabled"),
1446
+ enabled: optionalBoolean2(value.enabled, defaults.enabled, "hooks.enabled"),
954
1447
  targets: {
955
1448
  claude: parseHookTargetSettings(value.targets, defaults.targets.claude, "claude"),
956
1449
  codex: parseHookTargetSettings(value.targets, defaults.targets.codex, "codex")
@@ -958,7 +1451,7 @@ function parseHookSettings(value) {
958
1451
  observability: {
959
1452
  metadataOnly: true,
960
1453
  rawPayloadStorage: false,
961
- appendEvents: optionalBoolean(observability?.appendEvents, defaults.observability.appendEvents, "hooks.observability.appendEvents")
1454
+ appendEvents: optionalBoolean2(observability?.appendEvents, defaults.observability.appendEvents, "hooks.observability.appendEvents")
962
1455
  },
963
1456
  learning: {
964
1457
  emitCandidates: false,
@@ -967,26 +1460,26 @@ function parseHookSettings(value) {
967
1460
  };
968
1461
  }
969
1462
  function parseHookTargetSettings(value, defaults, target) {
970
- const targets = isRecord(value) ? value : {};
971
- const targetSettings = isRecord(targets[target]) ? targets[target] : {};
972
- const events = isRecord(targetSettings.events) ? targetSettings.events : {};
1463
+ const targets = isRecord2(value) ? value : {};
1464
+ const targetSettings = isRecord2(targets[target]) ? targets[target] : {};
1465
+ const events = isRecord2(targetSettings.events) ? targetSettings.events : {};
973
1466
  const parsedEvents = { ...defaults.events };
974
1467
  for (const eventType of CANONICAL_HOOK_EVENT_TYPES) {
975
- parsedEvents[eventType] = optionalBoolean(events[eventType], defaults.events[eventType], `hooks.targets.${target}.events.${eventType}`);
1468
+ parsedEvents[eventType] = optionalBoolean2(events[eventType], defaults.events[eventType], `hooks.targets.${target}.events.${eventType}`);
976
1469
  }
977
1470
  return {
978
- enabled: optionalBoolean(targetSettings.enabled, defaults.enabled, `hooks.targets.${target}.enabled`),
1471
+ enabled: optionalBoolean2(targetSettings.enabled, defaults.enabled, `hooks.targets.${target}.enabled`),
979
1472
  events: parsedEvents
980
1473
  };
981
1474
  }
982
- function optionalBoolean(value, fallback, path) {
1475
+ function optionalBoolean2(value, fallback, path) {
983
1476
  if (value === undefined)
984
1477
  return fallback;
985
1478
  if (typeof value !== "boolean")
986
1479
  throw new Error(`Invalid ${path}; expected boolean.`);
987
1480
  return value;
988
1481
  }
989
- function isRecord(value) {
1482
+ function isRecord2(value) {
990
1483
  return typeof value === "object" && value !== null && !Array.isArray(value);
991
1484
  }
992
1485
 
@@ -1020,7 +1513,8 @@ function createDefaultSettings(os = process.platform) {
1020
1513
  },
1021
1514
  hooks: createDefaultHookSettings(),
1022
1515
  teamRuntime: createDefaultTeamRuntimeSettings(),
1023
- memory: createDefaultMemorySettings()
1516
+ memory: createDefaultMemorySettings(),
1517
+ evolution: createDefaultEvolutionSettings()
1024
1518
  };
1025
1519
  }
1026
1520
  function createDefaultTeamRuntimeSettings() {
@@ -1034,10 +1528,23 @@ function createDefaultTeamRuntimeSettings() {
1034
1528
  }
1035
1529
  function createDefaultMemorySettings() {
1036
1530
  return {
1037
- autoAccept: true,
1531
+ reviewKnowledgeUpdates: true,
1038
1532
  runtimeInjection: true,
1039
1533
  staleReview: true,
1040
- lexicalIndex: true
1534
+ lexicalIndex: true,
1535
+ sessionMemory: createDefaultSessionMemoryPolicy()
1536
+ };
1537
+ }
1538
+ function createDefaultEvolutionSettings() {
1539
+ return {
1540
+ schedule: {
1541
+ dailyTime: "02:00"
1542
+ },
1543
+ automation: {
1544
+ knowledge: true,
1545
+ semanticKnowledge: false,
1546
+ recommendations: false
1547
+ }
1041
1548
  };
1042
1549
  }
1043
1550
  function mergeSettings(existing, defaults = createDefaultSettings()) {
@@ -1080,16 +1587,28 @@ function mergeSettings(existing, defaults = createDefaultSettings()) {
1080
1587
  memory: {
1081
1588
  ...defaults.memory,
1082
1589
  ...existing.memory
1590
+ },
1591
+ evolution: {
1592
+ ...defaults.evolution,
1593
+ ...existing.evolution,
1594
+ schedule: {
1595
+ ...defaults.evolution.schedule,
1596
+ ...existing.evolution?.schedule
1597
+ },
1598
+ automation: {
1599
+ ...defaults.evolution.automation,
1600
+ ...existing.evolution?.automation
1601
+ }
1083
1602
  }
1084
1603
  };
1085
1604
  return parseSettings(merged);
1086
1605
  }
1087
1606
  async function readRuntimeInjectionSettings(homeDir) {
1088
- const paths = resolveEvoDevPaths(homeDir);
1607
+ const paths2 = resolveEvoDevPaths(homeDir);
1089
1608
  try {
1090
- return parseSettings(JSON.parse(await readFile2(paths.settingsPath, "utf8"))).memory;
1609
+ return parseSettings(JSON.parse(await readFile3(paths2.settingsPath, "utf8"))).memory;
1091
1610
  } catch (error) {
1092
- if (isNotFoundError(error))
1611
+ if (isNotFoundError2(error))
1093
1612
  return createDefaultMemorySettings();
1094
1613
  throw error;
1095
1614
  }
@@ -1126,18 +1645,47 @@ function parseSettings(value) {
1126
1645
  },
1127
1646
  hooks: parseHookSettings(root.hooks),
1128
1647
  teamRuntime: parseTeamRuntimeSettings(root.teamRuntime ?? createDefaultTeamRuntimeSettings(), "settings.teamRuntime"),
1129
- memory: parseMemorySettings(root.memory ?? createDefaultMemorySettings(), "settings.memory")
1648
+ memory: parseMemorySettings(root.memory ?? createDefaultMemorySettings(), "settings.memory"),
1649
+ evolution: parseEvolutionSettings(root.evolution ?? createDefaultEvolutionSettings(), "settings.evolution")
1130
1650
  };
1131
1651
  return parsed;
1132
1652
  }
1653
+ function parseEvolutionSettings(value, path) {
1654
+ const input = expectRecord2(value, path);
1655
+ const defaults = createDefaultEvolutionSettings();
1656
+ const schedule = expectRecord2(input.schedule ?? defaults.schedule, `${path}.schedule`);
1657
+ const automation = expectRecord2(input.automation ?? defaults.automation, `${path}.automation`);
1658
+ return {
1659
+ schedule: {
1660
+ dailyTime: parseDailyTime(schedule.dailyTime ?? defaults.schedule.dailyTime, `${path}.schedule.dailyTime`)
1661
+ },
1662
+ automation: {
1663
+ knowledge: automation.knowledge === undefined ? defaults.automation.knowledge : expectBoolean(automation.knowledge, `${path}.automation.knowledge`),
1664
+ semanticKnowledge: automation.semanticKnowledge === undefined ? defaults.automation.semanticKnowledge : expectBoolean(automation.semanticKnowledge, `${path}.automation.semanticKnowledge`),
1665
+ recommendations: automation.recommendations === undefined ? defaults.automation.recommendations : expectBoolean(automation.recommendations, `${path}.automation.recommendations`)
1666
+ }
1667
+ };
1668
+ }
1669
+ function parseDailyTime(value, path) {
1670
+ const dailyTime = expectString2(value, path);
1671
+ const match = /^(\d{2}):(\d{2})$/u.exec(dailyTime);
1672
+ if (match === null || Number(match[1]) > 23 || Number(match[2]) > 59) {
1673
+ throw new EvoDevConfigError(`Invalid ${path}; expected a 24-hour HH:MM time`);
1674
+ }
1675
+ return dailyTime;
1676
+ }
1133
1677
  function parseMemorySettings(value, path) {
1134
1678
  const input = expectRecord2(value, path);
1135
1679
  const defaults = createDefaultMemorySettings();
1680
+ if (input.autoAccept !== undefined) {
1681
+ expectBoolean(input.autoAccept, `${path}.autoAccept`);
1682
+ }
1136
1683
  return {
1137
- autoAccept: input.autoAccept === undefined ? defaults.autoAccept : expectBoolean(input.autoAccept, `${path}.autoAccept`),
1684
+ reviewKnowledgeUpdates: input.reviewKnowledgeUpdates === undefined ? defaults.reviewKnowledgeUpdates : expectBoolean(input.reviewKnowledgeUpdates, `${path}.reviewKnowledgeUpdates`),
1138
1685
  runtimeInjection: input.runtimeInjection === undefined ? defaults.runtimeInjection : expectBoolean(input.runtimeInjection, `${path}.runtimeInjection`),
1139
1686
  staleReview: input.staleReview === undefined ? defaults.staleReview : expectBoolean(input.staleReview, `${path}.staleReview`),
1140
- lexicalIndex: input.lexicalIndex === undefined ? defaults.lexicalIndex : expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`)
1687
+ lexicalIndex: input.lexicalIndex === undefined ? defaults.lexicalIndex : expectBoolean(input.lexicalIndex, `${path}.lexicalIndex`),
1688
+ sessionMemory: parseSessionMemoryPolicy(isPlainRecord(input.sessionMemory) ? input.sessionMemory : defaults.sessionMemory)
1141
1689
  };
1142
1690
  }
1143
1691
  function parseTeamRuntimeSettings(value, path) {
@@ -1181,7 +1729,10 @@ function expectRecord2(value, path) {
1181
1729
  }
1182
1730
  return value;
1183
1731
  }
1184
- function isNotFoundError(error) {
1732
+ function isPlainRecord(value) {
1733
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1734
+ }
1735
+ function isNotFoundError2(error) {
1185
1736
  return error instanceof Error && "code" in error && error.code === "ENOENT";
1186
1737
  }
1187
1738
  function expectString2(value, path) {
@@ -1283,53 +1834,53 @@ function expectNonNegativeInteger(value, path) {
1283
1834
  return value;
1284
1835
  }
1285
1836
  // packages/core/src/config/store.ts
1286
- import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
1287
- import { dirname as dirname2 } from "node:path";
1837
+ import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "node:fs/promises";
1838
+ import { dirname as dirname4 } from "node:path";
1288
1839
  function createCoreConfigStore(homeDir) {
1289
- const paths = resolveEvoDevPaths(homeDir);
1840
+ const paths2 = resolveEvoDevPaths(homeDir);
1290
1841
  return {
1291
- paths,
1842
+ paths: paths2,
1292
1843
  async ensureBaseDirs() {
1293
- await mkdir2(paths.stateDir, { recursive: true });
1294
- await mkdir2(paths.logsDir, { recursive: true });
1295
- await mkdir2(paths.knowledgeDir, { recursive: true });
1296
- await mkdir2(paths.evosCasesDir, { recursive: true });
1297
- await mkdir2(paths.roleAgentsDir, { recursive: true });
1298
- await mkdir2(paths.teamsDir, { recursive: true });
1299
- await mkdir2(paths.runsDir, { recursive: true });
1844
+ await mkdir2(paths2.stateDir, { recursive: true });
1845
+ await mkdir2(paths2.logsDir, { recursive: true });
1846
+ await mkdir2(paths2.knowledgeDir, { recursive: true });
1847
+ await mkdir2(paths2.evosCasesDir, { recursive: true });
1848
+ await mkdir2(paths2.roleAgentsDir, { recursive: true });
1849
+ await mkdir2(paths2.teamsDir, { recursive: true });
1850
+ await mkdir2(paths2.runsDir, { recursive: true });
1300
1851
  },
1301
1852
  async ensureKnowledgeBase() {
1302
- await ensureKnowledgeBaseFiles(paths);
1853
+ await ensureKnowledgeBaseFiles(paths2);
1303
1854
  },
1304
1855
  async readSettings() {
1305
- return readJsonFile(paths.settingsPath, parseSettings);
1856
+ return readJsonFile(paths2.settingsPath, parseSettings);
1306
1857
  },
1307
1858
  async writeSettings(settings) {
1308
- await writeJsonFile(paths.settingsPath, parseSettings(settings));
1859
+ await writeJsonFile2(paths2.settingsPath, parseSettings(settings));
1309
1860
  },
1310
1861
  async mergeAndWriteSettings(input) {
1311
- const current = await readJsonFileOrDefault(paths.settingsPath, parseSettings, createDefaultSettings());
1862
+ const current = await readJsonFileOrDefault(paths2.settingsPath, parseSettings, createDefaultSettings());
1312
1863
  const merged = mergeSettings(input, current);
1313
- await writeJsonFile(paths.settingsPath, merged);
1864
+ await writeJsonFile2(paths2.settingsPath, merged);
1314
1865
  return merged;
1315
1866
  },
1316
1867
  async readRegistry() {
1317
- return readJsonFile(paths.registryPath, parseRegistry);
1868
+ return readJsonFile(paths2.registryPath, parseRegistry);
1318
1869
  },
1319
1870
  async writeRegistry(registry) {
1320
- await writeJsonFile(paths.registryPath, parseRegistry(registry));
1871
+ await writeJsonFile2(paths2.registryPath, parseRegistry(registry));
1321
1872
  },
1322
1873
  async readInstallState() {
1323
- return readJsonFile(paths.installStatePath, parseInstallState);
1874
+ return readJsonFile(paths2.installStatePath, parseInstallState);
1324
1875
  },
1325
1876
  async writeInstallState(state) {
1326
- await writeJsonFile(paths.installStatePath, parseInstallState(state));
1877
+ await writeJsonFile2(paths2.installStatePath, parseInstallState(state));
1327
1878
  },
1328
1879
  async readSyncState() {
1329
- return readJsonFile(paths.syncStatePath, parseSyncState);
1880
+ return readJsonFile(paths2.syncStatePath, parseSyncState);
1330
1881
  },
1331
1882
  async writeSyncState(state) {
1332
- await writeJsonFile(paths.syncStatePath, parseSyncState(state));
1883
+ await writeJsonFile2(paths2.syncStatePath, parseSyncState(state));
1333
1884
  }
1334
1885
  };
1335
1886
  }
@@ -1343,11 +1894,11 @@ async function initializeCoreConfig(homeDir) {
1343
1894
  await writeIfMissing(store.paths.syncStatePath, createDefaultSyncState());
1344
1895
  return store;
1345
1896
  }
1346
- async function ensureKnowledgeBaseFiles(paths) {
1347
- await mkdir2(paths.knowledgeDir, { recursive: true });
1348
- await mkdir2(paths.evosCasesDir, { recursive: true });
1349
- await ensureOkfKnowledgeBase(paths.homeDir);
1350
- await writeTextIfMissing2(`${paths.knowledgeDir}/README.md`, [
1897
+ async function ensureKnowledgeBaseFiles(paths2) {
1898
+ await mkdir2(paths2.knowledgeDir, { recursive: true });
1899
+ await mkdir2(paths2.evosCasesDir, { recursive: true });
1900
+ await ensureOkfKnowledgeBase(paths2.homeDir);
1901
+ await writeTextIfMissing2(`${paths2.knowledgeDir}/README.md`, [
1351
1902
  "# EvoDev Knowledge",
1352
1903
  "",
1353
1904
  "Local-private knowledge base for user-accepted facts, decisions, architecture notes, and reusable domain context.",
@@ -1356,13 +1907,13 @@ async function ensureKnowledgeBaseFiles(paths) {
1356
1907
  ""
1357
1908
  ].join(`
1358
1909
  `));
1359
- await writeIndexIfMissingOrMigrate(paths.knowledgeIndexPath, "knowledge-index", {
1910
+ await writeIndexIfMissingOrMigrate(paths2.knowledgeIndexPath, "knowledge-index", {
1360
1911
  version: 1,
1361
1912
  kind: "knowledge-index",
1362
1913
  roleTags: [],
1363
1914
  entries: []
1364
1915
  });
1365
- await writeTextIfMissing2(`${paths.evosDir}/README.md`, [
1916
+ await writeTextIfMissing2(`${paths2.evosDir}/README.md`, [
1366
1917
  "# EvoDev Evos",
1367
1918
  "",
1368
1919
  "Local-private evolution case library for reviewed improvement cases and reusable process changes.",
@@ -1371,20 +1922,20 @@ async function ensureKnowledgeBaseFiles(paths) {
1371
1922
  ""
1372
1923
  ].join(`
1373
1924
  `));
1374
- await writeTextIfMissing2(`${paths.evosCasesDir}/README.md`, [
1925
+ await writeTextIfMissing2(`${paths2.evosCasesDir}/README.md`, [
1375
1926
  "# Evolution Cases",
1376
1927
  "",
1377
1928
  "Store one reviewed evolution case per file. Do not store raw prompts, source dumps, secrets, transcripts, or raw command output here.",
1378
1929
  ""
1379
1930
  ].join(`
1380
1931
  `));
1381
- await writeIndexIfMissingOrMigrate(paths.evosIndexPath, "evos-index", {
1932
+ await writeIndexIfMissingOrMigrate(paths2.evosIndexPath, "evos-index", {
1382
1933
  version: 1,
1383
1934
  kind: "evos-index",
1384
1935
  roleTags: [],
1385
1936
  cases: []
1386
1937
  });
1387
- await writeTextIfMissing2(`${paths.roleAgentsDir}/README.md`, [
1938
+ await writeTextIfMissing2(`${paths2.roleAgentsDir}/README.md`, [
1388
1939
  "# Role Agents",
1389
1940
  "",
1390
1941
  "Local-private role agent registry for EvoDev-managed agent roles and user-reviewed role extensions.",
@@ -1393,13 +1944,13 @@ async function ensureKnowledgeBaseFiles(paths) {
1393
1944
  ""
1394
1945
  ].join(`
1395
1946
  `));
1396
- await writeIndexIfMissingOrMigrate(paths.roleAgentsIndexPath, "role-agent-index", {
1947
+ await writeIndexIfMissingOrMigrate(paths2.roleAgentsIndexPath, "role-agent-index", {
1397
1948
  version: 1,
1398
1949
  kind: "role-agent-index",
1399
1950
  roles: [],
1400
1951
  projectExtensions: []
1401
1952
  });
1402
- await writeTextIfMissing2(`${paths.teamsDir}/README.md`, [
1953
+ await writeTextIfMissing2(`${paths2.teamsDir}/README.md`, [
1403
1954
  "# Agent Teams",
1404
1955
  "",
1405
1956
  "Local-private EvoHub team registry for reviewed role-agent team definitions.",
@@ -1408,16 +1959,16 @@ async function ensureKnowledgeBaseFiles(paths) {
1408
1959
  ""
1409
1960
  ].join(`
1410
1961
  `));
1411
- await writeIndexIfMissingOrMigrate(paths.teamsIndexPath, "agent-team-index", {
1962
+ await writeIndexIfMissingOrMigrate(paths2.teamsIndexPath, "agent-team-index", {
1412
1963
  version: 1,
1413
1964
  kind: "agent-team-index",
1414
1965
  teams: []
1415
1966
  });
1416
1967
  }
1417
- async function readJsonFile(filePath, parse) {
1968
+ async function readJsonFile(filePath, parse2) {
1418
1969
  let raw;
1419
1970
  try {
1420
- raw = await readFile3(filePath, "utf8");
1971
+ raw = await readFile4(filePath, "utf8");
1421
1972
  } catch (error) {
1422
1973
  throw new EvoDevConfigError(`Cannot read config file (${describeFileError(error)})`, filePath);
1423
1974
  }
@@ -1428,7 +1979,7 @@ async function readJsonFile(filePath, parse) {
1428
1979
  throw new EvoDevConfigError(`Invalid JSON (${describeFileError(error)})`, filePath);
1429
1980
  }
1430
1981
  try {
1431
- return parse(json);
1982
+ return parse2(json);
1432
1983
  } catch (error) {
1433
1984
  if (error instanceof EvoDevConfigError) {
1434
1985
  throw new EvoDevConfigError(error.message, filePath);
@@ -1436,9 +1987,9 @@ async function readJsonFile(filePath, parse) {
1436
1987
  throw error;
1437
1988
  }
1438
1989
  }
1439
- async function readJsonFileOrDefault(filePath, parse, fallback) {
1990
+ async function readJsonFileOrDefault(filePath, parse2, fallback) {
1440
1991
  try {
1441
- return await readJsonFile(filePath, parse);
1992
+ return await readJsonFile(filePath, parse2);
1442
1993
  } catch (error) {
1443
1994
  if (error instanceof EvoDevConfigError && error.message.includes("ENOENT")) {
1444
1995
  return fallback;
@@ -1448,10 +1999,10 @@ async function readJsonFileOrDefault(filePath, parse, fallback) {
1448
1999
  }
1449
2000
  async function writeIfMissing(filePath, value) {
1450
2001
  try {
1451
- await readFile3(filePath, "utf8");
2002
+ await readFile4(filePath, "utf8");
1452
2003
  } catch (error) {
1453
2004
  if (isNodeError(error) && error.code === "ENOENT") {
1454
- await writeJsonFile(filePath, value);
2005
+ await writeJsonFile2(filePath, value);
1455
2006
  return;
1456
2007
  }
1457
2008
  throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
@@ -1460,10 +2011,10 @@ async function writeIfMissing(filePath, value) {
1460
2011
  async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
1461
2012
  let raw;
1462
2013
  try {
1463
- raw = await readFile3(filePath, "utf8");
2014
+ raw = await readFile4(filePath, "utf8");
1464
2015
  } catch (error) {
1465
2016
  if (isNodeError(error) && error.code === "ENOENT") {
1466
- await writeJsonFile(filePath, defaults);
2017
+ await writeJsonFile2(filePath, defaults);
1467
2018
  return;
1468
2019
  }
1469
2020
  throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
@@ -1474,27 +2025,27 @@ async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
1474
2025
  } catch (error) {
1475
2026
  throw new EvoDevConfigError(`Invalid bootstrap index JSON (${describeFileError(error)})`, filePath);
1476
2027
  }
1477
- if (!isRecord2(existing) || existing.kind !== kind)
2028
+ if (!isRecord3(existing) || existing.kind !== kind)
1478
2029
  return;
1479
2030
  const migrated = { ...defaults, ...existing };
1480
2031
  if (Object.keys(defaults).every((key) => (key in existing)))
1481
2032
  return;
1482
- await writeJsonFile(filePath, migrated);
2033
+ await writeJsonFile2(filePath, migrated);
1483
2034
  }
1484
2035
  async function writeTextIfMissing2(filePath, value) {
1485
2036
  try {
1486
- await readFile3(filePath, "utf8");
2037
+ await readFile4(filePath, "utf8");
1487
2038
  } catch (error) {
1488
2039
  if (isNodeError(error) && error.code === "ENOENT") {
1489
- await mkdir2(dirname2(filePath), { recursive: true });
2040
+ await mkdir2(dirname4(filePath), { recursive: true });
1490
2041
  await writeFile2(filePath, value, "utf8");
1491
2042
  return;
1492
2043
  }
1493
2044
  throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError(error)})`, filePath);
1494
2045
  }
1495
2046
  }
1496
- async function writeJsonFile(filePath, value) {
1497
- await mkdir2(dirname2(filePath), { recursive: true });
2047
+ async function writeJsonFile2(filePath, value) {
2048
+ await mkdir2(dirname4(filePath), { recursive: true });
1498
2049
  await writeFile2(filePath, `${JSON.stringify(value, null, 2)}
1499
2050
  `, "utf8");
1500
2051
  }
@@ -1507,24 +2058,25 @@ function describeFileError(error) {
1507
2058
  function isNodeError(error) {
1508
2059
  return error instanceof Error && "code" in error;
1509
2060
  }
1510
- function isRecord2(value) {
2061
+ function isRecord3(value) {
1511
2062
  return typeof value === "object" && value !== null && !Array.isArray(value);
1512
2063
  }
1513
2064
  export {
1514
- resolveEvoDevPaths,
1515
- readRuntimeInjectionSettings,
1516
- parseSyncState,
1517
- parseSettings,
1518
- parseRegistry,
1519
- parseInstallState,
1520
- mergeSettings,
1521
- initializeCoreConfig,
1522
- createDefaultTeamRuntimeSettings,
1523
- createDefaultSyncState,
1524
- createDefaultSettings,
1525
- createDefaultRegistry,
1526
- createDefaultMemorySettings,
1527
- createDefaultInstallState,
2065
+ EvoDevConfigError,
1528
2066
  createCoreConfigStore,
1529
- EvoDevConfigError
2067
+ createDefaultEvolutionSettings,
2068
+ createDefaultInstallState,
2069
+ createDefaultMemorySettings,
2070
+ createDefaultRegistry,
2071
+ createDefaultSettings,
2072
+ createDefaultSyncState,
2073
+ createDefaultTeamRuntimeSettings,
2074
+ initializeCoreConfig,
2075
+ mergeSettings,
2076
+ parseInstallState,
2077
+ parseRegistry,
2078
+ parseSettings,
2079
+ parseSyncState,
2080
+ readRuntimeInjectionSettings,
2081
+ resolveEvoDevPaths
1530
2082
  };