@evo-dev/core 0.0.1-alpha.4 → 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/index.js CHANGED
@@ -59,10 +59,10 @@ __export(exports_knowledge, {
59
59
  assertOkfKnowledgePlanContract: () => assertOkfKnowledgePlanContract,
60
60
  activateOkfKnowledgePlan: () => activateOkfKnowledgePlan
61
61
  });
62
- import { createHash as createHash2 } from "node:crypto";
62
+ import { createHash as createHash3 } from "node:crypto";
63
63
  import { existsSync, readFileSync, readdirSync } from "node:fs";
64
- import { mkdir as mkdir2, readFile as readFile3, readdir as readdir4, rename, rm, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
65
- import { dirname as dirname2, isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve as resolve2 } from "node:path";
64
+ import { mkdir as mkdir3, readFile as readFile3, readdir as readdir4, rename, rm as rm2, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
65
+ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join4, relative as relative2, resolve as resolve2 } from "node:path";
66
66
 
67
67
  // packages/core/src/config/paths.ts
68
68
  function resolveEvoDevPaths(homeDir = getHomeDir()) {
@@ -114,14 +114,19 @@ function stripTrailingSlash(path) {
114
114
  // packages/core/src/evolution/candidates/index.ts
115
115
  var exports_candidates = {};
116
116
  __export(exports_candidates, {
117
+ withEvolutionReviewDecisionLock: () => withEvolutionReviewDecisionLock,
118
+ updateEvolutionRepoProposalReviewState: () => updateEvolutionRepoProposalReviewState,
117
119
  updateEvolutionKnowledgeReviewState: () => updateEvolutionKnowledgeReviewState,
118
120
  readEvolutionReviewSnapshot: () => readEvolutionReviewSnapshot,
121
+ readEvolutionRepoProposalById: () => readEvolutionRepoProposalById,
119
122
  readEvolutionKnowledgeRecordById: () => readEvolutionKnowledgeRecordById,
123
+ listEvolutionKnowledgeReviewHistory: () => listEvolutionKnowledgeReviewHistory,
120
124
  listEvolutionKnowledgeRecords: () => listEvolutionKnowledgeRecords,
121
125
  listEvolutionEvosCases: () => listEvolutionEvosCases
122
126
  });
123
- import { readFile as readFile2, readdir as readdir3 } from "node:fs/promises";
124
- import { join as join3 } from "node:path";
127
+ import { createHash as createHash2 } from "node:crypto";
128
+ import { mkdir as mkdir2, readFile as readFile2, readdir as readdir3, rm, writeFile as writeFile2 } from "node:fs/promises";
129
+ import { dirname as dirname2, join as join3 } from "node:path";
125
130
 
126
131
  // packages/core/src/utils/errors.ts
127
132
  function isNotFoundError(error) {
@@ -223,6 +228,7 @@ import { readdir as readdir2 } from "node:fs/promises";
223
228
  import { isAbsolute, relative, resolve } from "node:path";
224
229
  var MAX_EVIDENCE_EVENTS = 200;
225
230
  var MAX_TEXT_LENGTH = 600;
231
+ var MAX_PROPOSED_CHANGE_LENGTH = 16 * 1024;
226
232
  var PROCESS_LOCK_STALE_MS = 5 * 60 * 1000;
227
233
  var REVIEW_STATES = [
228
234
  "auto-accepted",
@@ -524,7 +530,8 @@ function createEvolutionRepoProposal(input) {
524
530
  plannedFiles: input.plannedFiles.map((file) => ({
525
531
  relativePath: sanitizeRelativePath(file.relativePath),
526
532
  action: file.action,
527
- reason: sanitizeText(file.reason)
533
+ reason: sanitizeText(file.reason),
534
+ ...file.proposedChange === undefined ? {} : { proposedChange: sanitizeProposedChange(file.proposedChange) }
528
535
  }))
529
536
  };
530
537
  validateEvolutionRepoProposal(proposal);
@@ -555,6 +562,27 @@ function validateEvolutionRepoProposal(proposal) {
555
562
  "deferred",
556
563
  "applied"
557
564
  ]);
565
+ if (proposal.reviewStateChangedAt !== undefined && Number.isNaN(new Date(proposal.reviewStateChangedAt).getTime())) {
566
+ throw new Error("Repo proposal reviewStateChangedAt must be a valid timestamp.");
567
+ }
568
+ for (const file of proposal.plannedFiles) {
569
+ if (file.proposedChange !== undefined && file.proposedChange.trim() === "") {
570
+ throw new Error("Repo proposal proposedChange must not be empty.");
571
+ }
572
+ }
573
+ if (proposal.lastDecision !== undefined) {
574
+ assertEnum("lastDecision.state", proposal.lastDecision.state, [
575
+ "accepted",
576
+ "rejected",
577
+ "deferred"
578
+ ]);
579
+ if (proposal.lastDecision.reason !== null && (proposal.lastDecision.reason.trim() === "" || proposal.lastDecision.reason.length > 500)) {
580
+ throw new Error("Repo proposal decision reason must be 1-500 characters.");
581
+ }
582
+ if (Number.isNaN(new Date(proposal.lastDecision.decidedAt).getTime())) {
583
+ throw new Error("Repo proposal decision timestamp must be valid.");
584
+ }
585
+ }
558
586
  if (proposal.apply.autoApply !== false || proposal.apply.requiresExplicitCommand !== true) {
559
587
  throw new Error("Repo proposal must require explicit apply.");
560
588
  }
@@ -562,6 +590,9 @@ function validateEvolutionRepoProposal(proposal) {
562
590
  assertProvenance(proposal.provenance);
563
591
  assertNoForbiddenRawFields(proposal);
564
592
  }
593
+ function hasConcreteRepoProposalChanges(proposal) {
594
+ return proposal.targetRepoPath !== null && proposal.targetRepoPath.trim() !== "" && proposal.plannedFiles.length > 0 && proposal.plannedFiles.every((file) => file.proposedChange !== undefined && file.proposedChange.trim() !== "");
595
+ }
565
596
  function validateEvolutionReviewCandidate(candidate) {
566
597
  if (!isRecord(candidate))
567
598
  throw new Error("Review candidate must be an object.");
@@ -580,8 +611,14 @@ function validateEvolutionReviewCandidate(candidate) {
580
611
  assertString("reviewCandidate.targetStore", candidate.targetStore);
581
612
  assertString("reviewCandidate.targetPath", candidate.targetPath);
582
613
  assertString("reviewCandidate.stableKey", candidate.stableKey);
583
- if (candidate.reviewState !== "needs-human") {
584
- throw new Error("Review candidate reviewState must be needs-human.");
614
+ assertEnum("reviewCandidate.reviewState", candidate.reviewState, [
615
+ "needs-human",
616
+ "accepted",
617
+ "rejected",
618
+ "deferred"
619
+ ]);
620
+ if (candidate.reviewStateChangedAt !== undefined && Number.isNaN(new Date(candidate.reviewStateChangedAt).getTime())) {
621
+ throw new Error("Review candidate reviewStateChangedAt must be a valid timestamp.");
585
622
  }
586
623
  if (!Array.isArray(candidate.reasons))
587
624
  throw new Error("Review candidate reasons must be an array.");
@@ -769,6 +806,12 @@ function assertNoForbiddenRawFields(value, path = "") {
769
806
  function sanitizeText(value) {
770
807
  return value.replace(SENSITIVE_TEXT_REPLACE_PATTERN, "[redacted]").replace(/\s+/g, " ").trim().slice(0, MAX_TEXT_LENGTH);
771
808
  }
809
+ function sanitizeProposedChange(value) {
810
+ return value.replace(SENSITIVE_TEXT_REPLACE_PATTERN, "[redacted]").replaceAll(`\r
811
+ `, `
812
+ `).replaceAll("\r", `
813
+ `).trim().slice(0, MAX_PROPOSED_CHANGE_LENGTH);
814
+ }
772
815
  function sanitizeId(value) {
773
816
  return value.replace(/[^a-zA-Z0-9._/-]/g, "-").replace(/[\\/]+/g, "-").slice(0, 160) || "local";
774
817
  }
@@ -824,12 +867,14 @@ function resolveEvolutionPaths(input) {
824
867
  const projectKey = sanitizeStorageId2("projectKey", input.projectKey);
825
868
  const runId = sanitizeStorageId2("runId", input.runId);
826
869
  const evolutionStateDir = join2(paths.stateDir, "evolution");
870
+ const projectStateDir = join2(evolutionStateDir, projectKey);
827
871
  const runStateDir = join2(evolutionStateDir, projectKey, runId);
828
872
  const repoProposalsDir = join2(runStateDir, "proposals");
829
873
  const reviewCandidatesDir = join2(runStateDir, "review-candidates");
830
874
  const knowledgeProjectDir = join2(paths.knowledgeDir, projectKey);
831
875
  const evosCasesProjectDir = join2(paths.evosCasesDir, projectKey);
832
876
  assertPathDescendant(evolutionStateDir, runStateDir, "runStateDir");
877
+ assertPathDescendant(evolutionStateDir, projectStateDir, "projectStateDir");
833
878
  assertPathDescendant(evolutionStateDir, reviewCandidatesDir, "reviewCandidatesDir");
834
879
  assertPathDescendant(paths.knowledgeDir, knowledgeProjectDir, "knowledgeProjectDir");
835
880
  assertPathDescendant(paths.evosCasesDir, evosCasesProjectDir, "evosCasesProjectDir");
@@ -847,12 +892,40 @@ function resolveEvolutionPaths(input) {
847
892
  knowledgeProjectDir,
848
893
  knowledgeRecordsDir: join2(knowledgeProjectDir, "records"),
849
894
  knowledgeIndexPath: join2(knowledgeProjectDir, "index.json"),
895
+ knowledgeReviewHistoryPath: join2(projectStateDir, "knowledge-review-history.jsonl"),
850
896
  evosCasesProjectDir,
851
897
  evosIndexPath: paths.evosIndexPath
852
898
  };
853
899
  }
854
900
 
855
901
  // packages/core/src/evolution/candidates/index.ts
902
+ var REVIEW_LOCK_WAIT_MS = 2000;
903
+ var REVIEW_LOCK_RETRY_MS = 10;
904
+ async function withEvolutionReviewDecisionLock(input, operation) {
905
+ const paths = resolveEvoDevPaths(input.homeDir);
906
+ const key = createHash2("sha256").update(`${input.kind}\x00${input.itemId}`).digest("hex");
907
+ const lockPath = join3(paths.stateDir, "evolution", ".review-locks", `${key}.lock`);
908
+ const deadline = Date.now() + REVIEW_LOCK_WAIT_MS;
909
+ await mkdir2(dirname2(lockPath), { recursive: true });
910
+ while (true) {
911
+ try {
912
+ await writeFile2(lockPath, `${JSON.stringify({ version: 1, kind: input.kind, acquiredAt: new Date().toISOString(), pid: process.pid })}
913
+ `, { encoding: "utf8", flag: "wx" });
914
+ break;
915
+ } catch (error) {
916
+ if (!isAlreadyExistsError(error))
917
+ throw error;
918
+ if (Date.now() >= deadline)
919
+ throw new Error("Review decision lock is busy or stale.");
920
+ await sleep(REVIEW_LOCK_RETRY_MS);
921
+ }
922
+ }
923
+ try {
924
+ return await operation();
925
+ } finally {
926
+ await rm(lockPath, { force: true });
927
+ }
928
+ }
856
929
  async function readEvolutionReviewSnapshot(input) {
857
930
  const paths = resolveEvoDevPaths(input.homeDir);
858
931
  const projectKeys = input.projectKey === undefined ? await listEvolutionReviewProjectKeys(paths) : [sanitizeStorageId2("projectKey", input.projectKey)];
@@ -905,6 +978,32 @@ async function listEvolutionKnowledgeRecords(input) {
905
978
  projectKey: input.projectKey
906
979
  })).knowledgeRecords.sort((left, right) => left.id.localeCompare(right.id));
907
980
  }
981
+ async function listEvolutionKnowledgeReviewHistory(input) {
982
+ const paths = resolveEvoDevPaths(input.homeDir);
983
+ const projectKeys = input.projectKey === undefined ? await listDirectoryNames(join3(paths.stateDir, "evolution")) : [sanitizeStorageId2("projectKey", input.projectKey)];
984
+ const records = [];
985
+ for (const projectKey of projectKeys) {
986
+ const historyPath = resolveEvolutionPaths({
987
+ homeDir: input.homeDir,
988
+ projectKey,
989
+ runId: "review"
990
+ }).knowledgeReviewHistoryPath;
991
+ if (!await pathExists(historyPath))
992
+ continue;
993
+ for (const line of (await readFile2(historyPath, "utf8")).split(`
994
+ `)) {
995
+ if (line.trim() === "")
996
+ continue;
997
+ records.push(parseKnowledgeReviewHistoryRecord(JSON.parse(line)));
998
+ }
999
+ }
1000
+ return records.sort((left, right) => {
1001
+ const changedAt = left.changedAt.localeCompare(right.changedAt);
1002
+ if (changedAt !== 0)
1003
+ return changedAt;
1004
+ return left.knowledgeId.localeCompare(right.knowledgeId);
1005
+ });
1006
+ }
908
1007
  async function listEvolutionEvosCases(input) {
909
1008
  const paths = resolveEvoDevPaths(input.homeDir);
910
1009
  const projectKeys = input.projectKey === undefined ? await listDirectoryNames(paths.evosCasesDir) : [sanitizeStorageId2("projectKey", input.projectKey)];
@@ -955,44 +1054,186 @@ async function readEvolutionKnowledgeRecordById(input) {
955
1054
  return matches[0];
956
1055
  }
957
1056
  async function updateEvolutionKnowledgeReviewState(input) {
958
- const record = await readEvolutionKnowledgeRecordById(input);
959
- const next = {
960
- ...record,
961
- reviewState: input.reviewState,
962
- authority: input.reviewState === "accepted" ? "reviewed" : "contextual",
963
- runtime: {
964
- ...record.runtime,
965
- canLoad: input.reviewState === "accepted",
966
- hardBlocking: false
1057
+ return await withEvolutionReviewDecisionLock({ homeDir: input.homeDir, kind: "knowledge", itemId: input.knowledgeId }, async () => {
1058
+ const record = await readEvolutionKnowledgeRecordById(input);
1059
+ if (input.expectedReviewState !== undefined && record.reviewState !== input.expectedReviewState) {
1060
+ throw new Error("Knowledge review state changed before the decision was applied.");
967
1061
  }
968
- };
969
- validateEvolutionKnowledgeRecord(next);
970
- const paths = resolveEvolutionPaths({
1062
+ const paths = resolveEvolutionPaths({
1063
+ homeDir: input.homeDir,
1064
+ projectKey: record.projectKey,
1065
+ runId: "review"
1066
+ });
1067
+ const path = join3(paths.knowledgeRecordsDir, `${record.id}.json`);
1068
+ if (record.reviewState === input.reviewState)
1069
+ return { path, record, changed: false };
1070
+ const changedAt = normalizeTimestamp2(input.now);
1071
+ const next = {
1072
+ ...record,
1073
+ reviewState: input.reviewState,
1074
+ authority: input.reviewState === "accepted" ? "reviewed" : "contextual",
1075
+ runtime: {
1076
+ ...record.runtime,
1077
+ canLoad: false,
1078
+ hardBlocking: false
1079
+ }
1080
+ };
1081
+ validateEvolutionKnowledgeRecord(next);
1082
+ await writeJsonFile(path, next, { overwrite: true });
1083
+ const allProjectKnowledgeRecords = await readJsonFiles(paths.knowledgeRecordsDir, parseKnowledgeRecord);
1084
+ await writeJsonFile(paths.knowledgeIndexPath, {
1085
+ version: 1,
1086
+ kind: "evolution-knowledge-index",
1087
+ projectKey: next.projectKey,
1088
+ updatedAt: changedAt,
1089
+ records: allProjectKnowledgeRecords.map((item) => ({
1090
+ id: item.id,
1091
+ kind: item.kind,
1092
+ title: item.title,
1093
+ roleTags: item.roleTags,
1094
+ tags: item.tags,
1095
+ reviewState: item.reviewState,
1096
+ authority: item.authority,
1097
+ confidence: item.confidence,
1098
+ runtime: item.runtime
1099
+ }))
1100
+ }, { overwrite: true });
1101
+ const history = {
1102
+ version: 1,
1103
+ kind: "evolution-knowledge-review-state-changed",
1104
+ knowledgeId: next.id,
1105
+ projectKey: next.projectKey,
1106
+ roleTags: uniqueSorted(next.roleTags),
1107
+ artifactCreatedAt: next.provenance.createdAt,
1108
+ previousReviewState: record.reviewState,
1109
+ nextReviewState: next.reviewState,
1110
+ changedAt,
1111
+ metadataOnly: true
1112
+ };
1113
+ await mkdir2(dirname2(paths.knowledgeReviewHistoryPath), { recursive: true });
1114
+ await writeFile2(paths.knowledgeReviewHistoryPath, `${JSON.stringify(history)}
1115
+ `, {
1116
+ encoding: "utf8",
1117
+ flag: "a"
1118
+ });
1119
+ return { path, record: next, changed: true };
1120
+ });
1121
+ }
1122
+ async function readEvolutionRepoProposalById(input) {
1123
+ const matches = (await readEvolutionReviewSnapshot({
971
1124
  homeDir: input.homeDir,
972
- projectKey: next.projectKey,
973
- runId: "review"
1125
+ projectKey: input.projectKey
1126
+ })).repoProposals.filter((proposal) => proposal.id === input.proposalId);
1127
+ if (matches.length === 0)
1128
+ throw new Error(`Repo proposal not found: ${input.proposalId}`);
1129
+ if (matches.length > 1) {
1130
+ throw new Error(`Repo proposal id is ambiguous across runs: ${input.proposalId}`);
1131
+ }
1132
+ return matches[0];
1133
+ }
1134
+ async function updateEvolutionRepoProposalReviewState(input) {
1135
+ return await withEvolutionReviewDecisionLock({ homeDir: input.homeDir, kind: "repo-proposal", itemId: input.proposalId }, async () => {
1136
+ const record = await readEvolutionRepoProposalById(input);
1137
+ if (!hasConcreteRepoProposalChanges(record)) {
1138
+ throw new Error("Repo proposal has no concrete repository changes to review.");
1139
+ }
1140
+ const reason = input.reason?.trim();
1141
+ if (input.reviewState === "rejected" && reason === undefined) {
1142
+ throw new Error("Rejecting a repo proposal requires a reason.");
1143
+ }
1144
+ if (reason !== undefined && (reason === "" || reason.length > 500)) {
1145
+ throw new Error("Repo proposal review reason must be 1-500 characters.");
1146
+ }
1147
+ if (input.expectedReviewState !== undefined && record.reviewState !== input.expectedReviewState) {
1148
+ throw new Error("Repo proposal review state changed before the decision was applied.");
1149
+ }
1150
+ const paths = resolveEvolutionPaths({
1151
+ homeDir: input.homeDir,
1152
+ projectKey: record.projectKey,
1153
+ runId: record.provenance.runId
1154
+ });
1155
+ const path = join3(paths.repoProposalsDir, `${record.id}.json`);
1156
+ if (record.reviewState === input.reviewState)
1157
+ return { path, record, changed: false };
1158
+ const changedAt = normalizeTimestamp2(input.now);
1159
+ const next = {
1160
+ ...record,
1161
+ reviewState: input.reviewState,
1162
+ reviewStateChangedAt: changedAt,
1163
+ lastDecision: {
1164
+ state: input.reviewState,
1165
+ reason: reason === undefined ? null : sanitizeText(reason),
1166
+ decidedAt: changedAt
1167
+ }
1168
+ };
1169
+ validateEvolutionRepoProposal(next);
1170
+ await writeJsonFile(path, next, { overwrite: true });
1171
+ const allRunProposals = await readJsonFiles(paths.repoProposalsDir, parseRepoProposal);
1172
+ await writeJsonFile(paths.repoProposalsIndexPath, {
1173
+ schemaVersion: 1,
1174
+ projectKey: next.projectKey,
1175
+ runId: next.provenance.runId,
1176
+ updatedAt: changedAt,
1177
+ proposals: allRunProposals.map((proposal) => ({
1178
+ id: proposal.id,
1179
+ kind: proposal.kind,
1180
+ title: proposal.title,
1181
+ reviewState: proposal.reviewState
1182
+ }))
1183
+ }, { overwrite: true });
1184
+ return { path, record: next, changed: true };
974
1185
  });
975
- const path = join3(paths.knowledgeRecordsDir, `${next.id}.json`);
976
- await writeJsonFile(path, next, { overwrite: true });
977
- const allProjectKnowledgeRecords = await readJsonFiles(paths.knowledgeRecordsDir, parseKnowledgeRecord);
978
- await writeJsonFile(paths.knowledgeIndexPath, {
1186
+ }
1187
+ function parseKnowledgeReviewHistoryRecord(value) {
1188
+ if (!isRecord2(value))
1189
+ throw new Error("Knowledge review history record must be an object.");
1190
+ const allowedKeys = new Set([
1191
+ "version",
1192
+ "kind",
1193
+ "knowledgeId",
1194
+ "projectKey",
1195
+ "roleTags",
1196
+ "artifactCreatedAt",
1197
+ "previousReviewState",
1198
+ "nextReviewState",
1199
+ "changedAt",
1200
+ "metadataOnly"
1201
+ ]);
1202
+ if (Object.keys(value).some((key) => !allowedKeys.has(key))) {
1203
+ throw new Error("Knowledge review history record contains unsupported fields.");
1204
+ }
1205
+ if (value.version !== 1 || value.kind !== "evolution-knowledge-review-state-changed" || typeof value.knowledgeId !== "string" || typeof value.projectKey !== "string" || !Array.isArray(value.roleTags) || !value.roleTags.every((roleId) => typeof roleId === "string") || typeof value.artifactCreatedAt !== "string" || typeof value.previousReviewState !== "string" || !REVIEW_STATES.includes(value.previousReviewState) || typeof value.nextReviewState !== "string" || !REVIEW_STATES.includes(value.nextReviewState) || typeof value.changedAt !== "string" || value.metadataOnly !== true) {
1206
+ throw new Error("Invalid knowledge review history record.");
1207
+ }
1208
+ normalizeTimestamp2(value.artifactCreatedAt);
1209
+ normalizeTimestamp2(value.changedAt);
1210
+ return {
979
1211
  version: 1,
980
- kind: "evolution-knowledge-index",
981
- projectKey: next.projectKey,
982
- updatedAt: new Date().toISOString(),
983
- records: allProjectKnowledgeRecords.map((item) => ({
984
- id: item.id,
985
- kind: item.kind,
986
- title: item.title,
987
- roleTags: item.roleTags,
988
- tags: item.tags,
989
- reviewState: item.reviewState,
990
- authority: item.authority,
991
- confidence: item.confidence,
992
- runtime: item.runtime
993
- }))
994
- }, { overwrite: true });
995
- return { path, record: next };
1212
+ kind: "evolution-knowledge-review-state-changed",
1213
+ knowledgeId: sanitizeId(value.knowledgeId),
1214
+ projectKey: sanitizeStorageId2("projectKey", value.projectKey),
1215
+ roleTags: uniqueSorted(value.roleTags.map(sanitizeId)),
1216
+ artifactCreatedAt: value.artifactCreatedAt,
1217
+ previousReviewState: value.previousReviewState,
1218
+ nextReviewState: value.nextReviewState,
1219
+ changedAt: value.changedAt,
1220
+ metadataOnly: true
1221
+ };
1222
+ }
1223
+ function normalizeTimestamp2(value) {
1224
+ const date = value === undefined ? new Date : value instanceof Date ? value : new Date(value);
1225
+ if (Number.isNaN(date.getTime()))
1226
+ throw new Error("Invalid knowledge review history timestamp.");
1227
+ return date.toISOString();
1228
+ }
1229
+ function isAlreadyExistsError(error) {
1230
+ return error instanceof Error && "code" in error && error.code === "EEXIST";
1231
+ }
1232
+ async function sleep(milliseconds) {
1233
+ await new Promise((resolve2) => setTimeout(resolve2, milliseconds));
1234
+ }
1235
+ function isRecord2(value) {
1236
+ return typeof value === "object" && value !== null && !Array.isArray(value);
996
1237
  }
997
1238
 
998
1239
  // packages/core/src/evolution/knowledge/index.ts
@@ -1072,8 +1313,8 @@ function resolveOkfKnowledgePaths(homeDir) {
1072
1313
  async function ensureOkfKnowledgeBase(homeDir) {
1073
1314
  const paths = resolveOkfKnowledgePaths(homeDir);
1074
1315
  await ensureLocalKnowledgeGitRepository(paths.knowledgeDir);
1075
- await mkdir2(paths.indexesDir, { recursive: true });
1076
- await mkdir2(paths.tmpDir, { recursive: true });
1316
+ await mkdir3(paths.indexesDir, { recursive: true });
1317
+ await mkdir3(paths.tmpDir, { recursive: true });
1077
1318
  const directories = [
1078
1319
  {
1079
1320
  path: "",
@@ -1219,7 +1460,7 @@ function validateOkfKnowledgePlanContract(plan, _options = {}) {
1219
1460
  const add = (path, code, message, severity = "error") => {
1220
1461
  findings.push({ path, code, severity, message });
1221
1462
  };
1222
- if (!isRecord2(plan)) {
1463
+ if (!isRecord3(plan)) {
1223
1464
  add("$", "plan.object", "Plan must be an object.");
1224
1465
  return { ok: false, findings };
1225
1466
  }
@@ -1255,7 +1496,7 @@ function validateOkfKnowledgePlanContract(plan, _options = {}) {
1255
1496
  }
1256
1497
  if (Array.isArray(plan.droppedSignals)) {
1257
1498
  plan.droppedSignals.forEach((signal, index) => {
1258
- if (!isRecord2(signal))
1499
+ if (!isRecord3(signal))
1259
1500
  add(`droppedSignals[${index}]`, "signal.object", "Dropped signal must be an object.");
1260
1501
  if (!isNonEmptyString(signal?.evidenceRef)) {
1261
1502
  add(`droppedSignals[${index}].evidenceRef`, "signal.evidenceRef", "Dropped signal evidenceRef is required.");
@@ -1268,7 +1509,7 @@ function validateOkfKnowledgePlanContract(plan, _options = {}) {
1268
1509
  }
1269
1510
  if (Array.isArray(plan.conflicts)) {
1270
1511
  plan.conflicts.forEach((conflict, index) => {
1271
- if (!isRecord2(conflict))
1512
+ if (!isRecord3(conflict))
1272
1513
  add(`conflicts[${index}]`, "conflict.object", "Conflict must be an object.");
1273
1514
  if (!isNonEmptyString(conflict?.candidateId)) {
1274
1515
  add(`conflicts[${index}].candidateId`, "conflict.candidateId", "Conflict candidateId is required.");
@@ -1329,7 +1570,7 @@ function normalizePlanCandidate(value, path) {
1329
1570
  return candidate;
1330
1571
  }
1331
1572
  function validateCandidateContract(candidate, path, evalSetIds, add) {
1332
- if (!isRecord2(candidate)) {
1573
+ if (!isRecord3(candidate)) {
1333
1574
  add(path, "candidate.object", "Candidate must be an object.");
1334
1575
  return;
1335
1576
  }
@@ -1401,7 +1642,7 @@ function validateCandidateContract(candidate, path, evalSetIds, add) {
1401
1642
  if (!Array.isArray(candidate.evidenceRefs) || candidate.evidenceRefs.length === 0) {
1402
1643
  add(`${path}.evidenceRefs`, "candidate.active.evidenceRefs", "Active writes require evidenceRefs.");
1403
1644
  }
1404
- const verification = isRecord2(candidate.bodySections) && Array.isArray(candidate.bodySections.verification) ? candidate.bodySections.verification : [];
1645
+ const verification = isRecord3(candidate.bodySections) && Array.isArray(candidate.bodySections.verification) ? candidate.bodySections.verification : [];
1405
1646
  if (verification.length === 0 && !isNonEmptyString(candidate.verificationNotApplicableReason)) {
1406
1647
  add(`${path}.bodySections.verification`, "candidate.active.verification", "Active writes require verification or an explicit not-applicable reason.");
1407
1648
  }
@@ -1581,7 +1822,7 @@ function normalizeEvalSetDecision(value) {
1581
1822
  return normalized;
1582
1823
  }
1583
1824
  function assertRecordValue(value, path) {
1584
- if (!isRecord2(value))
1825
+ if (!isRecord3(value))
1585
1826
  throw new Error(`${path} must be an object.`);
1586
1827
  return value;
1587
1828
  }
@@ -1611,14 +1852,14 @@ function readScore(value, path) {
1611
1852
  }
1612
1853
  return value;
1613
1854
  }
1614
- function isRecord2(value) {
1855
+ function isRecord3(value) {
1615
1856
  return typeof value === "object" && value !== null && !Array.isArray(value);
1616
1857
  }
1617
1858
  function isNonEmptyString(value) {
1618
1859
  return typeof value === "string" && value.trim() !== "";
1619
1860
  }
1620
1861
  function validateEvidenceRefValue(evidenceRef, path, add) {
1621
- if (!isRecord2(evidenceRef)) {
1862
+ if (!isRecord3(evidenceRef)) {
1622
1863
  add(path, "evidenceRef.object", "Evidence ref must be an object.");
1623
1864
  return;
1624
1865
  }
@@ -1635,13 +1876,13 @@ function validateEvidenceRefValue(evidenceRef, path, add) {
1635
1876
  }
1636
1877
  }
1637
1878
  function validateEvalSetValue(evalSet, path, add) {
1638
- if (!isRecord2(evalSet)) {
1879
+ if (!isRecord3(evalSet)) {
1639
1880
  add(path, "evalSet.object", "Eval set must be an object.");
1640
1881
  return;
1641
1882
  }
1642
1883
  if (!isNonEmptyString(evalSet.id))
1643
1884
  add(`${path}.id`, "evalSet.id", "Eval set id is required.");
1644
- if (!isRecord2(evalSet.target)) {
1885
+ if (!isRecord3(evalSet.target)) {
1645
1886
  add(`${path}.target`, "evalSet.target", "Eval set target is required.");
1646
1887
  } else {
1647
1888
  if (!isNonEmptyString(evalSet.target.kind))
@@ -1657,7 +1898,7 @@ function validateEvalSetValue(evalSet, path, add) {
1657
1898
  } else {
1658
1899
  evalSet.cases.forEach((item, index) => {
1659
1900
  const casePath = `${path}.cases[${index}]`;
1660
- if (!isRecord2(item)) {
1901
+ if (!isRecord3(item)) {
1661
1902
  add(casePath, "evalSet.case.object", "Eval set case must be an object.");
1662
1903
  return;
1663
1904
  }
@@ -1670,7 +1911,7 @@ function validateEvalSetValue(evalSet, path, add) {
1670
1911
  }
1671
1912
  });
1672
1913
  }
1673
- if (!isRecord2(evalSet.privacy)) {
1914
+ if (!isRecord3(evalSet.privacy)) {
1674
1915
  add(`${path}.privacy`, "evalSet.privacy", "Eval set privacy is required.");
1675
1916
  } else {
1676
1917
  if (evalSet.privacy.usesRawPrompt !== false)
@@ -1702,7 +1943,7 @@ function validateOverlayUpdatesValue(value, path, add) {
1702
1943
  }
1703
1944
  value.forEach((item, index) => {
1704
1945
  const itemPath = `${path}[${index}]`;
1705
- if (!isRecord2(item)) {
1946
+ if (!isRecord3(item)) {
1706
1947
  add(itemPath, "overlayUpdate.object", "Overlay update must be an object.");
1707
1948
  return;
1708
1949
  }
@@ -1714,7 +1955,7 @@ function validateOverlayUpdatesValue(value, path, add) {
1714
1955
  });
1715
1956
  }
1716
1957
  function validateScoresValue(value, path, add) {
1717
- if (!isRecord2(value)) {
1958
+ if (!isRecord3(value)) {
1718
1959
  add(path, "scores.object", "Scores must be an object.");
1719
1960
  return;
1720
1961
  }
@@ -1733,7 +1974,7 @@ function validateScoresValue(value, path, add) {
1733
1974
  }
1734
1975
  }
1735
1976
  function validatePrivacyCheckValue(value, path, add) {
1736
- if (!isRecord2(value)) {
1977
+ if (!isRecord3(value)) {
1737
1978
  add(path, "privacy.object", "Privacy check must be an object.");
1738
1979
  return;
1739
1980
  }
@@ -1743,7 +1984,7 @@ function validatePrivacyCheckValue(value, path, add) {
1743
1984
  }
1744
1985
  }
1745
1986
  function validateBodySectionsValue(value, path, add) {
1746
- if (!isRecord2(value)) {
1987
+ if (!isRecord3(value)) {
1747
1988
  add(path, "bodySections.object", "Body sections must be an object.");
1748
1989
  return;
1749
1990
  }
@@ -1772,7 +2013,7 @@ function validateTargetPathValue(value, path, requireMarkdown, add) {
1772
2013
  }
1773
2014
  }
1774
2015
  function isBehaviorChangeCandidate(candidate) {
1775
- if (!isRecord2(candidate))
2016
+ if (!isRecord3(candidate))
1776
2017
  return false;
1777
2018
  const kind = typeof candidate.kind === "string" ? candidate.kind : "";
1778
2019
  const haystack = [
@@ -1892,10 +2133,10 @@ function decideOkfKnowledgeCandidate(candidate, context) {
1892
2133
  if (highRiskRequiresHuman) {
1893
2134
  return {
1894
2135
  ...sanitized,
1895
- decision: "needs-human",
2136
+ decision: "no_write",
1896
2137
  scores,
1897
- reviewState: "needs-human",
1898
- decisionReason: "Needs human review: high-risk domain requires review."
2138
+ reviewState: "auto-stored/unreviewed",
2139
+ decisionReason: "No write: high-risk knowledge is not eligible for automatic activation."
1899
2140
  };
1900
2141
  }
1901
2142
  if (conflict?.kind === "duplicate") {
@@ -1911,10 +2152,10 @@ function decideOkfKnowledgeCandidate(candidate, context) {
1911
2152
  if (reusable) {
1912
2153
  return {
1913
2154
  ...sanitized,
1914
- decision: "needs-human",
2155
+ decision: "no_write",
1915
2156
  scores,
1916
- reviewState: "needs-human",
1917
- decisionReason: conflict?.reason ?? explainNeedsHumanDecision(sanitized, scores, hasVerification, hasScopeTags)
2157
+ reviewState: "auto-stored/unreviewed",
2158
+ decisionReason: conflict?.reason ?? explainAutomaticNoWriteDecision(sanitized, scores, hasVerification, hasScopeTags)
1918
2159
  };
1919
2160
  }
1920
2161
  return {
@@ -1927,8 +2168,8 @@ function decideOkfKnowledgeCandidate(candidate, context) {
1927
2168
  }
1928
2169
  async function activateOkfKnowledgePlan(input) {
1929
2170
  const validation = validateOkfKnowledgePlanContract(input.plan);
1930
- const projectKey = isRecord2(input.plan) && isNonEmptyString(input.plan.projectKey) ? input.plan.projectKey : "unknown";
1931
- const runId = isRecord2(input.plan) && isNonEmptyString(input.plan.runId) ? input.plan.runId : "unknown";
2171
+ const projectKey = isRecord3(input.plan) && isNonEmptyString(input.plan.projectKey) ? input.plan.projectKey : "unknown";
2172
+ const runId = isRecord3(input.plan) && isNonEmptyString(input.plan.runId) ? input.plan.runId : "unknown";
1932
2173
  if (!validation.ok) {
1933
2174
  await writeFailedOkfKnowledgePlanArtifact({
1934
2175
  homeDir: input.homeDir,
@@ -1960,12 +2201,7 @@ async function activateOkfKnowledgePlan(input) {
1960
2201
  continue;
1961
2202
  }
1962
2203
  if (candidate.decision === "needs-human") {
1963
- await writeNeedsHumanKnowledgeCandidate({
1964
- homeDir: input.homeDir,
1965
- plan: input.plan,
1966
- candidate
1967
- });
1968
- needsHumanCandidates.push(candidate.id);
2204
+ skippedCandidates.push(candidate.id);
1969
2205
  continue;
1970
2206
  }
1971
2207
  if (candidate.targetStore !== "okf") {
@@ -1979,10 +2215,10 @@ async function activateOkfKnowledgePlan(input) {
1979
2215
  await appendOkfLog(paths.okfDir, `**Skip**: Candidate \`${candidate.id}\` matched existing [${candidate.title}](${toOkfLink(paths.okfDir, targetPath)}).`);
1980
2216
  continue;
1981
2217
  }
1982
- await mkdir2(dirname2(targetPath), { recursive: true });
1983
- await writeFile2(targetPath, renderOkfConcept(candidate, input.plan), "utf8");
2218
+ await mkdir3(dirname3(targetPath), { recursive: true });
2219
+ await writeFile3(targetPath, renderOkfConcept(candidate, input.plan), "utf8");
1984
2220
  conceptPaths.push(targetPath);
1985
- affectedDirectories.add(dirname2(targetPath));
2221
+ affectedDirectories.add(dirname3(targetPath));
1986
2222
  for (const update of candidate.overlayUpdates) {
1987
2223
  const overlayPath = resolveOkfTargetPath(paths.okfDir, update.targetPath);
1988
2224
  await ensureOverlayConcept({
@@ -1994,7 +2230,7 @@ async function activateOkfKnowledgePlan(input) {
1994
2230
  link: update.link
1995
2231
  });
1996
2232
  overlayPaths.push(overlayPath);
1997
- affectedDirectories.add(dirname2(overlayPath));
2233
+ affectedDirectories.add(dirname3(overlayPath));
1998
2234
  }
1999
2235
  }
2000
2236
  const indexPaths = await regenerateOkfDirectoryIndexes(paths.okfDir);
@@ -2008,8 +2244,8 @@ async function activateOkfKnowledgePlan(input) {
2008
2244
  skippedCandidates,
2009
2245
  needsHumanCandidates
2010
2246
  });
2011
- await rm(tmpRunDir, { recursive: true, force: true });
2012
- await rm(failedPlanPath, { force: true });
2247
+ await rm2(tmpRunDir, { recursive: true, force: true });
2248
+ await rm2(failedPlanPath, { force: true });
2013
2249
  return {
2014
2250
  planPath,
2015
2251
  failedPlanPath,
@@ -2032,8 +2268,8 @@ async function activateOkfKnowledgePlan(input) {
2032
2268
  error: error instanceof Error ? error.message : String(error),
2033
2269
  failureKind: "organizer"
2034
2270
  });
2035
- await rm(tmpRunDir, { recursive: true, force: true });
2036
- await writeJson(join4(dirname2(failedPlanPath), "organizer-report.json"), {
2271
+ await rm2(tmpRunDir, { recursive: true, force: true });
2272
+ await writeJson(join4(dirname3(failedPlanPath), "organizer-report.json"), {
2037
2273
  schemaVersion: 1,
2038
2274
  kind: "okf-organizer-report",
2039
2275
  projectKey: input.plan.projectKey,
@@ -2079,7 +2315,7 @@ async function writeFailedOkfKnowledgePlanArtifact(input) {
2079
2315
  async function readFailedOkfKnowledgePlanArtifact(input) {
2080
2316
  const path = resolveFailedPlanPath(input.homeDir, input.projectKey, input.runId);
2081
2317
  const value = JSON.parse(await readFile3(path, "utf8"));
2082
- if (isRecord2(value) && value.kind === "okf-knowledge-failed-plan") {
2318
+ if (isRecord3(value) && value.kind === "okf-knowledge-failed-plan") {
2083
2319
  const artifact = value;
2084
2320
  validateFailedPlanArtifact(artifact);
2085
2321
  return { path, artifact };
@@ -2113,12 +2349,12 @@ async function resumeFailedOkfKnowledgePlan(input) {
2113
2349
  }
2114
2350
  async function discardFailedOkfKnowledgePlan(input) {
2115
2351
  const path = resolveFailedPlanPath(input.homeDir, input.projectKey, input.runId);
2116
- await rm(path, { force: true });
2352
+ await rm2(path, { force: true });
2117
2353
  return { path };
2118
2354
  }
2119
2355
  async function rebuildOkfKnowledgeIndexes(input) {
2120
2356
  const paths = resolveOkfKnowledgePaths(input.homeDir);
2121
- await mkdir2(paths.indexesDir, { recursive: true });
2357
+ await mkdir3(paths.indexesDir, { recursive: true });
2122
2358
  const concepts = (await listOkfKnowledgeConcepts({ homeDir: input.homeDir })).filter(isActiveOkfConcept);
2123
2359
  const conceptSummaries = concepts.map((concept) => ({
2124
2360
  id: concept.id,
@@ -2703,7 +2939,7 @@ async function writeConceptLifecycleFrontmatter(input) {
2703
2939
  if (parsed === null)
2704
2940
  throw new Error(`OKF concept missing frontmatter: ${input.path}`);
2705
2941
  const frontmatter = upsertOkfLifecycleFrontmatter(parsed.frontmatter, input.reviewState, input.lifecycle);
2706
- await writeFile2(input.path, `---
2942
+ await writeFile3(input.path, `---
2707
2943
  ${frontmatter.trimEnd()}
2708
2944
  ---
2709
2945
  ${parsed.body}`, "utf8");
@@ -2749,7 +2985,7 @@ function upsertOkfLifecycleFrontmatter(frontmatter, reviewState, lifecycle) {
2749
2985
  }
2750
2986
  async function appendLifecycleLogs(input) {
2751
2987
  const directories = [
2752
- ...new Set(input.conceptPaths.flatMap((path) => ancestorDirectories(input.okfDir, dirname2(path))))
2988
+ ...new Set(input.conceptPaths.flatMap((path) => ancestorDirectories(input.okfDir, dirname3(path))))
2753
2989
  ];
2754
2990
  const logPaths = [];
2755
2991
  for (const directory of directories) {
@@ -2965,15 +3201,15 @@ function resolveFailedPlanPath(homeDir, projectKey, runId) {
2965
3201
  return path;
2966
3202
  }
2967
3203
  async function ensureLocalKnowledgeGitRepository(knowledgeDir) {
2968
- await mkdir2(knowledgeDir, { recursive: true });
3204
+ await mkdir3(knowledgeDir, { recursive: true });
2969
3205
  const gitDir = join4(knowledgeDir, ".git");
2970
3206
  if (await pathExists2(gitDir))
2971
3207
  return;
2972
- await mkdir2(join4(gitDir, "objects", "info"), { recursive: true });
2973
- await mkdir2(join4(gitDir, "objects", "pack"), { recursive: true });
2974
- await mkdir2(join4(gitDir, "refs", "heads"), { recursive: true });
2975
- await mkdir2(join4(gitDir, "refs", "tags"), { recursive: true });
2976
- await mkdir2(join4(gitDir, "info"), { recursive: true });
3208
+ await mkdir3(join4(gitDir, "objects", "info"), { recursive: true });
3209
+ await mkdir3(join4(gitDir, "objects", "pack"), { recursive: true });
3210
+ await mkdir3(join4(gitDir, "refs", "heads"), { recursive: true });
3211
+ await mkdir3(join4(gitDir, "refs", "tags"), { recursive: true });
3212
+ await mkdir3(join4(gitDir, "info"), { recursive: true });
2977
3213
  await writeTextIfMissing(join4(gitDir, "HEAD"), `ref: refs/heads/main
2978
3214
  `);
2979
3215
  await writeTextIfMissing(join4(gitDir, "config"), [
@@ -3016,8 +3252,8 @@ function assertPathDescendant2(root, candidate, field) {
3016
3252
  async function writeTextIfMissing(path, value) {
3017
3253
  if (await pathExists2(path))
3018
3254
  return;
3019
- await mkdir2(dirname2(path), { recursive: true });
3020
- await writeFile2(path, value, { encoding: "utf8", flag: "wx" });
3255
+ await mkdir3(dirname3(path), { recursive: true });
3256
+ await writeFile3(path, value, { encoding: "utf8", flag: "wx" });
3021
3257
  }
3022
3258
  function createCandidateFromEvosCase(evosCase) {
3023
3259
  const targetPath = `concepts/evos/${evosCase.id}.md`;
@@ -3078,49 +3314,6 @@ function createOverlayUpdates(projectKey, roleTags, workflowTags, sourceLink) {
3078
3314
  }))
3079
3315
  ];
3080
3316
  }
3081
- async function writeNeedsHumanKnowledgeCandidate(input) {
3082
- const root = join4(resolveEvoDevPaths(input.homeDir).stateDir, "evolution");
3083
- const targetDir = join4(root, sanitizePlanStorageId("projectKey", input.plan.projectKey), sanitizePlanStorageId("runId", input.plan.runId), "review-candidates");
3084
- const targetPath = join4(targetDir, `${sanitizePlanStorageId("candidateId", input.candidate.id)}.json`);
3085
- assertPathDescendant2(root, targetPath, "reviewCandidatePath");
3086
- const candidateSnapshot = sanitizeReviewQueueValue(input.candidate);
3087
- await writeJson(targetPath, {
3088
- schemaVersion: 1,
3089
- kind: "evolution-review-candidate",
3090
- id: input.candidate.id,
3091
- projectKey: input.plan.projectKey,
3092
- runId: input.plan.runId,
3093
- createdAt: input.plan.createdAt,
3094
- candidateKind: input.candidate.kind,
3095
- title: sanitizeOkfText(input.candidate.title),
3096
- targetStore: input.candidate.targetStore,
3097
- targetPath: sanitizeOkfText(input.candidate.targetPath),
3098
- stableKey: sanitizeOkfText(input.candidate.stableKey),
3099
- reviewState: "needs-human",
3100
- reasons: [sanitizeOkfText(input.candidate.decisionReason)],
3101
- candidate: candidateSnapshot,
3102
- provenance: {
3103
- runId: input.plan.runId,
3104
- evidenceWindowId: input.plan.evidenceWindowId,
3105
- evidenceRefs: input.candidate.evidenceRefs.map(sanitizeOkfText),
3106
- createdBy: "evodev",
3107
- rawLogsStored: false,
3108
- rawPromptsStored: false,
3109
- sourceDumpsStored: false,
3110
- rawCommandOutputStored: false
3111
- },
3112
- privacy: {
3113
- classification: "local-private",
3114
- rawPromptsStored: false,
3115
- rawLogsStored: false,
3116
- sourceDumpsStored: false,
3117
- rawCommandOutputStored: false,
3118
- secretsStored: false,
3119
- internalLinksStored: false
3120
- }
3121
- }, { overwrite: true });
3122
- return targetPath;
3123
- }
3124
3317
  function sanitizeOkfPlanCandidate(candidate) {
3125
3318
  return sanitizeReviewQueueValue(candidate);
3126
3319
  }
@@ -3143,9 +3336,9 @@ function hasUnsafeCandidateContent(candidate) {
3143
3336
  return FORBIDDEN_OKF_TEXT.test(content) || FORBIDDEN_OKF_FIELD.test(content) || PRIVATE_OR_INTERNAL_URL.test(content) || candidate.privacyCheck !== undefined && Object.values(candidate.privacyCheck).some((value) => value !== false);
3144
3337
  }
3145
3338
  function hasHighRiskHumanReviewSignal(candidate) {
3146
- if (!isRecord2(candidate))
3339
+ if (!isRecord3(candidate))
3147
3340
  return false;
3148
- const body = isRecord2(candidate.bodySections) ? candidate.bodySections : {};
3341
+ const body = isRecord3(candidate.bodySections) ? candidate.bodySections : {};
3149
3342
  const stringArray = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
3150
3343
  const stringValue = (value) => typeof value === "string" ? value : "";
3151
3344
  const values = [
@@ -3174,7 +3367,7 @@ function hasHighRiskHumanReviewSignal(candidate) {
3174
3367
  ];
3175
3368
  return HUMAN_REVIEW_DOMAIN_PATTERN.test(values.join(" "));
3176
3369
  }
3177
- function explainNeedsHumanDecision(candidate, scores, hasVerification, hasScopeTags) {
3370
+ function explainAutomaticNoWriteDecision(candidate, scores, hasVerification, hasScopeTags) {
3178
3371
  const reasons = [];
3179
3372
  if (candidate.targetStore !== "okf")
3180
3373
  reasons.push("target is not user-local OKF");
@@ -3194,7 +3387,7 @@ function explainNeedsHumanDecision(candidate, scores, hasVerification, hasScopeT
3194
3387
  reasons.push("stability is below auto-accept");
3195
3388
  if (scores.duplicationRisk > 2)
3196
3389
  reasons.push("duplication risk is above auto-accept");
3197
- return `Needs human review: ${reasons.join("; ") || "auto-accept gates were not all satisfied"}.`;
3390
+ return `No write: ${reasons.join("; ") || "auto-accept gates were not all satisfied"}.`;
3198
3391
  }
3199
3392
  function resolveCandidateReviewStateForWrite(candidate) {
3200
3393
  if (candidate.reviewState === "auto-accepted" || candidate.decision === "auto-accept") {
@@ -3259,19 +3452,19 @@ async function ensureOverlayConcept(input) {
3259
3452
  const root = segments[0] ?? "repos";
3260
3453
  const scopeId = segments[1] ?? input.projectKey;
3261
3454
  const type = root === "roles" ? "EvoDev Role Attention" : root === "workflows" ? "EvoDev Workflow Attention" : "EvoDev Repo Attention";
3262
- await ensureOkfDirectory(input.okfDir, dirname2(relativePath), scopeId, `Attention overlay for ${scopeId}.`);
3455
+ await ensureOkfDirectory(input.okfDir, dirname3(relativePath), scopeId, `Attention overlay for ${scopeId}.`);
3263
3456
  const exists = await pathExists2(input.overlayPath);
3264
3457
  const linkLine = `- [${input.candidate.title}](${input.link}) - ${input.candidate.description}`;
3265
3458
  if (exists) {
3266
3459
  const current = await readFile3(input.overlayPath, "utf8");
3267
3460
  if (current.includes(input.link))
3268
3461
  return;
3269
- await writeFile2(input.overlayPath, `${current.trimEnd()}
3462
+ await writeFile3(input.overlayPath, `${current.trimEnd()}
3270
3463
  ${linkLine}
3271
3464
  `, "utf8");
3272
3465
  return;
3273
3466
  }
3274
- await writeFile2(input.overlayPath, [
3467
+ await writeFile3(input.overlayPath, [
3275
3468
  "---",
3276
3469
  `type: ${yamlString(type)}`,
3277
3470
  `title: ${yamlString(`${scopeId} attention`)}`,
@@ -3416,11 +3609,11 @@ function renderOkfConcept(candidate, plan) {
3416
3609
  }
3417
3610
  async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
3418
3611
  const dir = relativeDir === "" || relativeDir === "." ? okfDir : resolveOkfTargetPath(okfDir, relativeDir);
3419
- await mkdir2(dir, { recursive: true });
3612
+ await mkdir3(dir, { recursive: true });
3420
3613
  const isRoot = dir === okfDir;
3421
3614
  const indexPath = join4(dir, "index.md");
3422
3615
  if (!await pathExists2(indexPath)) {
3423
- await writeFile2(indexPath, isRoot ? [
3616
+ await writeFile3(indexPath, isRoot ? [
3424
3617
  "---",
3425
3618
  `okf_version: ${yamlString("0.1")}`,
3426
3619
  `title: ${yamlString(title)}`,
@@ -3437,7 +3630,7 @@ async function ensureOkfDirectory(okfDir, relativeDir, title, description) {
3437
3630
  }
3438
3631
  const logPath = join4(dir, "log.md");
3439
3632
  if (!await pathExists2(logPath)) {
3440
- await writeFile2(logPath, [
3633
+ await writeFile3(logPath, [
3441
3634
  "# Directory Update Log",
3442
3635
  "",
3443
3636
  `## ${todayIsoDate()}`,
@@ -3488,7 +3681,7 @@ async function regenerateOkfDirectoryIndexes(okfDir) {
3488
3681
  ].join(`
3489
3682
  `);
3490
3683
  const indexPath = join4(directory, "index.md");
3491
- await writeFile2(indexPath, content, "utf8");
3684
+ await writeFile3(indexPath, content, "utf8");
3492
3685
  paths.push(indexPath);
3493
3686
  }
3494
3687
  return paths;
@@ -3510,7 +3703,7 @@ function ancestorDirectories(root, directory) {
3510
3703
  const directories = [directory];
3511
3704
  let current = directory;
3512
3705
  while (current !== root && current.startsWith(root)) {
3513
- current = dirname2(current);
3706
+ current = dirname3(current);
3514
3707
  directories.push(current);
3515
3708
  }
3516
3709
  return directories;
@@ -3519,20 +3712,20 @@ async function appendOkfLog(okfDir, entry) {
3519
3712
  await prependLogEntry(join4(okfDir, "log.md"), entry);
3520
3713
  }
3521
3714
  async function prependLogEntry(logPath, entry) {
3522
- await mkdir2(dirname2(logPath), { recursive: true });
3715
+ await mkdir3(dirname3(logPath), { recursive: true });
3523
3716
  const date = todayIsoDate();
3524
3717
  const existing = await pathExists2(logPath) ? await readFile3(logPath, "utf8") : `# Directory Update Log
3525
3718
  `;
3526
3719
  const line = `* ${entry}`;
3527
3720
  if (existing.includes(`## ${date}`)) {
3528
- await writeFile2(logPath, existing.replace(`## ${date}
3721
+ await writeFile3(logPath, existing.replace(`## ${date}
3529
3722
  `, `## ${date}
3530
3723
  ${line}
3531
3724
  `), "utf8");
3532
3725
  return;
3533
3726
  }
3534
3727
  const withoutTitle = existing.replace(/^# Directory Update Log\s*/u, "").trimStart();
3535
- await writeFile2(logPath, `${["# Directory Update Log", "", `## ${date}`, line, "", withoutTitle].join(`
3728
+ await writeFile3(logPath, `${["# Directory Update Log", "", `## ${date}`, line, "", withoutTitle].join(`
3536
3729
  `).trimEnd()}
3537
3730
  `, "utf8");
3538
3731
  }
@@ -3624,7 +3817,7 @@ function createKnowledgeContextRevision(items) {
3624
3817
  }))))}`;
3625
3818
  }
3626
3819
  function sha256Short2(value) {
3627
- return createHash2("sha256").update(value).digest("hex").slice(0, 16);
3820
+ return createHash3("sha256").update(value).digest("hex").slice(0, 16);
3628
3821
  }
3629
3822
  function stableJsonStringify(value) {
3630
3823
  if (value === null || typeof value !== "object")
@@ -3967,7 +4160,7 @@ function validateOkfKnowledgePlan(plan) {
3967
4160
  assertOkfKnowledgePlanContract(plan);
3968
4161
  }
3969
4162
  function validateFailedPlanArtifact(artifact) {
3970
- if (!isRecord2(artifact))
4163
+ if (!isRecord3(artifact))
3971
4164
  throw new Error("Failed plan artifact must be an object.");
3972
4165
  if (artifact.schemaVersion !== 1)
3973
4166
  throw new Error("Failed plan artifact schemaVersion must be 1.");
@@ -3987,7 +4180,7 @@ function validateFailedPlanArtifact(artifact) {
3987
4180
  if (!Array.isArray(artifact.findings))
3988
4181
  throw new Error("Failed plan artifact findings must be an array.");
3989
4182
  for (const finding of artifact.findings) {
3990
- if (!isRecord2(finding))
4183
+ if (!isRecord3(finding))
3991
4184
  throw new Error("Failed plan finding must be an object.");
3992
4185
  if (!isNonEmptyString(finding.path) || !isNonEmptyString(finding.code) || !isNonEmptyString(finding.message)) {
3993
4186
  throw new Error("Failed plan finding fields are required.");
@@ -4346,9 +4539,9 @@ function todayIsoDate() {
4346
4539
  return new Date().toISOString().slice(0, 10);
4347
4540
  }
4348
4541
  async function writeJson(path, value, options = {}) {
4349
- await mkdir2(dirname2(path), { recursive: true });
4542
+ await mkdir3(dirname3(path), { recursive: true });
4350
4543
  const flag = options.overwrite === true ? "w" : "wx";
4351
- await writeFile2(path, `${JSON.stringify(value, null, 2)}
4544
+ await writeFile3(path, `${JSON.stringify(value, null, 2)}
4352
4545
  `, { encoding: "utf8", flag });
4353
4546
  }
4354
4547
  async function pathExists2(path) {
@@ -4399,7 +4592,7 @@ function applyStrictestAgentPermissions(...permissions) {
4399
4592
  return merged;
4400
4593
  }
4401
4594
  function parseAgentProfile(value) {
4402
- if (!isRecord3(value))
4595
+ if (!isRecord4(value))
4403
4596
  throw new Error("Agent profile must be an object.");
4404
4597
  if (value.version !== 1)
4405
4598
  throw new Error("Agent profile version must be 1.");
@@ -4534,7 +4727,7 @@ function validateAgentOutput(schema, output) {
4534
4727
  if (schema === "design-options-v1")
4535
4728
  return validateRequiredObject(output, ["summary", "options", "recommendation", "evidenceRefs"]);
4536
4729
  const errors2 = [];
4537
- if (!isRecord3(output))
4730
+ if (!isRecord4(output))
4538
4731
  return { ok: false, errors: ["Output must be an object."] };
4539
4732
  if (typeof output.summary !== "string")
4540
4733
  errors2.push("summary is required.");
@@ -4707,7 +4900,7 @@ function collectPrivacyBoundaryAdvisories(contract, lenses, workflowId) {
4707
4900
  ] : [];
4708
4901
  }
4709
4902
  function validateRequiredObject(output, fields) {
4710
- if (!isRecord3(output))
4903
+ if (!isRecord4(output))
4711
4904
  return { ok: false, errors: ["Output must be an object."] };
4712
4905
  const errors2 = fields.filter((field) => output[field] === undefined).map((field) => `${field} is required.`);
4713
4906
  return { ok: errors2.length === 0, errors: errors2 };
@@ -4733,7 +4926,7 @@ function assertStringArray(value, path) {
4733
4926
  throw new Error(`${path} must be an array of non-empty strings.`);
4734
4927
  }
4735
4928
  }
4736
- function isRecord3(value) {
4929
+ function isRecord4(value) {
4737
4930
  return typeof value === "object" && value !== null && !Array.isArray(value);
4738
4931
  }
4739
4932
  // packages/core/src/assets/errors.ts
@@ -4948,8 +5141,8 @@ __export(exports_code_agent_traces, {
4948
5141
  listCodeAgentTraceRefs: () => listCodeAgentTraceRefs,
4949
5142
  createCodeAgentTraceRef: () => createCodeAgentTraceRef
4950
5143
  });
4951
- import { mkdir as mkdir4, readFile as readFile6, readdir as readdir6, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
4952
- import { dirname as dirname4, isAbsolute as isAbsolute4, join as join7, normalize, relative as relative5 } from "node:path";
5144
+ import { mkdir as mkdir5, readFile as readFile6, readdir as readdir6, stat as stat4, writeFile as writeFile4 } from "node:fs/promises";
5145
+ import { dirname as dirname5, isAbsolute as isAbsolute4, join as join7, normalize, relative as relative5 } from "node:path";
4953
5146
 
4954
5147
  // packages/core/src/runtime-logs/index.ts
4955
5148
  var exports_runtime_logs = {};
@@ -4967,8 +5160,8 @@ __export(exports_runtime_logs, {
4967
5160
  appendDebugLogEntry: () => appendDebugLogEntry,
4968
5161
  appendCliLogEntry: () => appendCliLogEntry
4969
5162
  });
4970
- import { appendFile, mkdir as mkdir3 } from "node:fs/promises";
4971
- import { dirname as dirname3, isAbsolute as isAbsolute3, join as join6, relative as relative4 } from "node:path";
5163
+ import { appendFile, mkdir as mkdir4 } from "node:fs/promises";
5164
+ import { dirname as dirname4, isAbsolute as isAbsolute3, join as join6, relative as relative4 } from "node:path";
4972
5165
  var MAX_LOG_STRING_LENGTH = 4096;
4973
5166
  var MAX_EVENT_STRING_LENGTH = 512;
4974
5167
  var MAX_DEBUG_ARRAY_LENGTH = 50;
@@ -5234,7 +5427,7 @@ function resolveProjectLogKey(homeDir, repoRoot) {
5234
5427
  return sanitizePersistentIdentifier(projectKey, "project");
5235
5428
  }
5236
5429
  function resolveTraceSessionKey(payload) {
5237
- const record = isRecord4(payload) ? payload : {};
5430
+ const record = isRecord5(payload) ? payload : {};
5238
5431
  const sessionId = optionalString3(record.session_id ?? record.sessionId);
5239
5432
  const cwd = optionalString3(record.cwd);
5240
5433
  const source = sessionId ?? cwd ?? "local";
@@ -5299,7 +5492,7 @@ function sanitizeEvoDevExecutionEventForAppend(event) {
5299
5492
  });
5300
5493
  }
5301
5494
  async function appendJsonLine(path, value) {
5302
- await mkdir3(dirname3(path), { recursive: true });
5495
+ await mkdir4(dirname4(path), { recursive: true });
5303
5496
  await appendFile(path, `${JSON.stringify(value)}
5304
5497
  `, "utf8");
5305
5498
  }
@@ -5380,7 +5573,7 @@ function sanitizeDebugValue(value, depth = 0) {
5380
5573
  }
5381
5574
  return items;
5382
5575
  }
5383
- if (isRecord4(value)) {
5576
+ if (isRecord5(value)) {
5384
5577
  const output = {};
5385
5578
  const entries = Object.entries(value).slice(0, MAX_DEBUG_OBJECT_KEYS);
5386
5579
  for (const [key, nestedValue] of entries) {
@@ -5416,7 +5609,7 @@ function describeError(error) {
5416
5609
  return truncateString(error.message);
5417
5610
  return truncateString(String(error));
5418
5611
  }
5419
- function isRecord4(value) {
5612
+ function isRecord5(value) {
5420
5613
  return typeof value === "object" && value !== null && !Array.isArray(value);
5421
5614
  }
5422
5615
 
@@ -5469,7 +5662,7 @@ function createCodeAgentTraceRef(input) {
5469
5662
  };
5470
5663
  }
5471
5664
  function parseCodeAgentTraceRef(value) {
5472
- if (!isRecord5(value))
5665
+ if (!isRecord6(value))
5473
5666
  throw new Error("Code Agent trace ref must be an object.");
5474
5667
  if (value.version !== 1)
5475
5668
  throw new Error("Code Agent trace ref version must be 1.");
@@ -5508,8 +5701,8 @@ async function writeCodeAgentTraceRef(input) {
5508
5701
  target: ref.target,
5509
5702
  sessionKey: ref.sessionKey
5510
5703
  });
5511
- await mkdir4(dirname4(path), { recursive: true });
5512
- await writeFile3(path, `${JSON.stringify(ref, null, 2)}
5704
+ await mkdir5(dirname5(path), { recursive: true });
5705
+ await writeFile4(path, `${JSON.stringify(ref, null, 2)}
5513
5706
  `, "utf8");
5514
5707
  return { ref, path };
5515
5708
  }
@@ -5756,7 +5949,7 @@ function stripTrailingSlash3(path) {
5756
5949
  function isNotFoundError2(error) {
5757
5950
  return error instanceof Error && (("code" in error) && error.code === "ENOENT" || error.message.includes("ENOENT"));
5758
5951
  }
5759
- function isRecord5(value) {
5952
+ function isRecord6(value) {
5760
5953
  return typeof value === "object" && value !== null && !Array.isArray(value);
5761
5954
  }
5762
5955
  // packages/core/src/config/errors.ts
@@ -5837,10 +6030,19 @@ import { readFile as readFile12 } from "node:fs/promises";
5837
6030
  // packages/core/src/evolution/evidence/session-memory/index.ts
5838
6031
  var exports_session_memory = {};
5839
6032
  __export(exports_session_memory, {
6033
+ writeSessionIndex: () => writeSessionIndex,
6034
+ writeJson: () => writeJson2,
5840
6035
  updateSessionMemoryFromHook: () => updateSessionMemoryFromHook,
5841
6036
  resolveSessionMemoryPaths: () => resolveSessionMemoryPaths,
6037
+ readSessionState: () => readSessionState,
6038
+ readSessionEvidenceSegment: () => readSessionEvidenceSegment,
6039
+ readSessionCursor: () => readSessionCursor,
6040
+ readLineRange: () => readLineRange,
5842
6041
  parseSessionMemoryPolicy: () => parseSessionMemoryPolicy,
5843
- createDefaultSessionMemoryPolicy: () => createDefaultSessionMemoryPolicy
6042
+ listSessionEvidenceSegments: () => listSessionEvidenceSegments,
6043
+ createDefaultSessionMemoryPolicy: () => createDefaultSessionMemoryPolicy,
6044
+ appendRawEvent: () => appendRawEvent,
6045
+ SessionMemoryEvidenceError: () => SessionMemoryEvidenceError
5844
6046
  });
5845
6047
 
5846
6048
  // packages/core/src/evolution/evidence/session-memory/paths.ts
@@ -5890,8 +6092,208 @@ function parseSessionMemoryPolicy(value) {
5890
6092
  toolCallsBetweenUpdates: positiveInteger(value.toolCallsBetweenUpdates, defaults.toolCallsBetweenUpdates)
5891
6093
  };
5892
6094
  }
6095
+ // packages/core/src/evolution/evidence/session-memory/storage.ts
6096
+ import { appendFile as appendFile2, mkdir as mkdir6, readFile as readFile7, readdir as readdir7, writeFile as writeFile5 } from "node:fs/promises";
6097
+ import { dirname as dirname6, join as join9 } from "node:path";
6098
+
6099
+ // packages/core/src/evolution/evidence/session-memory/constants.ts
6100
+ var DEFAULT_MAX_RAW_EVENT_BYTES = 64 * 1024;
6101
+ var SENSITIVE_TEXT_PATTERN2 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|\.env)\b/i;
6102
+ var EXPLICIT_MEMORY_PATTERN = /\b(remember|memorize|do not repeat|don't repeat|this is important|save this|learn this)\b/i;
6103
+ var FAILURE_PATTERN = /\b(fail|failed|failure|error|issue|exception|crash)\b/i;
6104
+ var VERIFICATION_PATTERN = /\b(test|lint|typecheck|build|verify|verification|passed|success)\b/i;
6105
+
6106
+ // packages/core/src/evolution/evidence/session-memory/storage.ts
6107
+ class SessionMemoryEvidenceError extends Error {
6108
+ code;
6109
+ constructor(code, message) {
6110
+ super(message);
6111
+ this.name = "SessionMemoryEvidenceError";
6112
+ this.code = code;
6113
+ }
6114
+ }
6115
+ async function listSessionEvidenceSegments(input) {
6116
+ const rootDir = join9(resolveEvoDevPaths(input.homeDir).stateDir, "session-memory");
6117
+ const projectDirs = input.projectKey === undefined ? await listDirectoryNames2(rootDir) : [input.projectKey];
6118
+ const segments = [];
6119
+ for (const projectKey of projectDirs) {
6120
+ const paths = resolveSessionMemoryPaths({
6121
+ homeDir: input.homeDir,
6122
+ projectKey,
6123
+ sessionKey: "list"
6124
+ });
6125
+ for (const sessionKey of await listDirectoryNames2(paths.projectDir)) {
6126
+ const sessionPaths = resolveSessionMemoryPaths({
6127
+ homeDir: input.homeDir,
6128
+ projectKey,
6129
+ sessionKey
6130
+ });
6131
+ for (const entry of await listJsonFiles(sessionPaths.segmentsDir)) {
6132
+ try {
6133
+ segments.push(parseSessionEvidenceSegment(JSON.parse(await readFile7(entry, "utf8"))));
6134
+ } catch {}
6135
+ }
6136
+ }
6137
+ }
6138
+ return segments.sort((left, right) => right.createdAt.localeCompare(left.createdAt));
6139
+ }
6140
+ async function readSessionEvidenceSegment(input) {
6141
+ const paths = resolveSessionMemoryPaths(input);
6142
+ try {
6143
+ const segment = parseSessionEvidenceSegment(JSON.parse(await readFile7(paths.segmentPath(input.segmentId), "utf8")));
6144
+ if (segment.id !== input.segmentId || segment.projectKey !== input.projectKey || segment.sessionKey !== input.sessionKey) {
6145
+ throw new SessionMemoryEvidenceError("invalid", "Session evidence identity does not match its storage path.");
6146
+ }
6147
+ return segment;
6148
+ } catch (error) {
6149
+ if (error instanceof SessionMemoryEvidenceError)
6150
+ throw error;
6151
+ if (isNotFoundError(error)) {
6152
+ throw new SessionMemoryEvidenceError("not-found", "Session evidence segment was not found.");
6153
+ }
6154
+ throw new SessionMemoryEvidenceError("invalid", "Session evidence segment is invalid.");
6155
+ }
6156
+ }
6157
+ async function readSessionState(path) {
6158
+ try {
6159
+ return JSON.parse(await readFile7(path, "utf8"));
6160
+ } catch (error) {
6161
+ if (isNotFoundError(error))
6162
+ return null;
6163
+ throw error;
6164
+ }
6165
+ }
6166
+ async function readSessionCursor(path, sessionKey, sourcePath, now) {
6167
+ try {
6168
+ return JSON.parse(await readFile7(path, "utf8"));
6169
+ } catch (error) {
6170
+ if (!isNotFoundError(error))
6171
+ throw error;
6172
+ return {
6173
+ schemaVersion: 1,
6174
+ kind: "session-memory-cursor",
6175
+ sessionKey,
6176
+ traceRefId: null,
6177
+ sourcePath,
6178
+ lastCapturedOffset: null,
6179
+ lastCapturedLine: null,
6180
+ lastCapturedEventId: null,
6181
+ updatedAt: now
6182
+ };
6183
+ }
6184
+ }
6185
+ async function appendRawEvent(path, event) {
6186
+ const existingLineCount = await countJsonlLines(path);
6187
+ await mkdir6(dirname6(path), { recursive: true });
6188
+ await appendFile2(path, `${JSON.stringify(event)}
6189
+ `, "utf8");
6190
+ return { lineNumber: existingLineCount + 1 };
6191
+ }
6192
+ async function readLineRange(path, fromLine, toLine) {
6193
+ const text2 = await readFile7(path, "utf8");
6194
+ const lines = text2.split(`
6195
+ `).filter((line) => line.trim() !== "");
6196
+ const selected = lines.slice(Math.max(0, fromLine - 1), toLine);
6197
+ let secretsDetected = false;
6198
+ for (const line of selected) {
6199
+ try {
6200
+ const parsed = JSON.parse(line);
6201
+ secretsDetected = secretsDetected || parsed.secretsDetected === true;
6202
+ } catch {
6203
+ secretsDetected = secretsDetected || SENSITIVE_TEXT_PATTERN2.test(line);
6204
+ }
6205
+ }
6206
+ return { content: selected.join(`
6207
+ `), truncated: false, secretsDetected };
6208
+ }
6209
+ async function writeSessionIndex(paths, state, segment, now) {
6210
+ const existing = await readSessionIndex(paths.indexPath);
6211
+ const segments = [
6212
+ ...existing.segments.filter((item) => item.id !== segment.id),
6213
+ {
6214
+ id: segment.id,
6215
+ reason: segment.reason,
6216
+ strength: segment.strength,
6217
+ createdAt: segment.createdAt,
6218
+ reviewState: segment.lifecycle.reviewState
6219
+ }
6220
+ ];
6221
+ await writeJson2(paths.indexPath, {
6222
+ schemaVersion: 1,
6223
+ kind: "session-memory-index",
6224
+ projectKey: state.projectKey,
6225
+ sessionKey: state.sessionKey,
6226
+ updatedAt: now,
6227
+ lastSegmentId: segment.id,
6228
+ segments
6229
+ });
6230
+ }
6231
+ async function writeJson2(path, value) {
6232
+ await mkdir6(dirname6(path), { recursive: true });
6233
+ await writeFile5(path, `${JSON.stringify(value, null, 2)}
6234
+ `, "utf8");
6235
+ }
6236
+ async function countJsonlLines(path) {
6237
+ try {
6238
+ const text2 = await readFile7(path, "utf8");
6239
+ return text2.split(`
6240
+ `).filter((line) => line.trim() !== "").length;
6241
+ } catch (error) {
6242
+ if (isNotFoundError(error))
6243
+ return 0;
6244
+ throw error;
6245
+ }
6246
+ }
6247
+ async function readSessionIndex(path) {
6248
+ try {
6249
+ const parsed = JSON.parse(await readFile7(path, "utf8"));
6250
+ if (!Array.isArray(parsed.segments))
6251
+ return { segments: [] };
6252
+ return {
6253
+ segments: parsed.segments.filter(isSessionIndexSegment)
6254
+ };
6255
+ } catch (error) {
6256
+ if (isNotFoundError(error))
6257
+ return { segments: [] };
6258
+ throw error;
6259
+ }
6260
+ }
6261
+ function isSessionIndexSegment(value) {
6262
+ if (typeof value !== "object" || value === null || Array.isArray(value))
6263
+ return false;
6264
+ const item = value;
6265
+ return typeof item.id === "string" && typeof item.reason === "string" && typeof item.strength === "string" && typeof item.createdAt === "string" && typeof item.reviewState === "string";
6266
+ }
6267
+ function parseSessionEvidenceSegment(value) {
6268
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
6269
+ throw new SessionMemoryEvidenceError("invalid", "Session evidence must be an object.");
6270
+ }
6271
+ const segment = value;
6272
+ if (segment.schemaVersion !== 1 || segment.kind !== "session-evidence-segment" || typeof segment.id !== "string" || typeof segment.projectKey !== "string" || typeof segment.sessionKey !== "string" || typeof segment.createdAt !== "string" || typeof segment.normalized !== "object" || segment.normalized === null || typeof segment.rawExcerpt !== "object" || segment.rawExcerpt === null) {
6273
+ throw new SessionMemoryEvidenceError("invalid", "Session evidence fields are invalid.");
6274
+ }
6275
+ return segment;
6276
+ }
6277
+ async function listDirectoryNames2(path) {
6278
+ try {
6279
+ return (await readdir7(path, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
6280
+ } catch (error) {
6281
+ if (isNotFoundError(error))
6282
+ return [];
6283
+ throw error;
6284
+ }
6285
+ }
6286
+ async function listJsonFiles(path) {
6287
+ try {
6288
+ return (await readdir7(path, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => join9(path, entry.name)).sort();
6289
+ } catch (error) {
6290
+ if (isNotFoundError(error))
6291
+ return [];
6292
+ throw error;
6293
+ }
6294
+ }
5893
6295
  // packages/core/src/evolution/evidence/session-memory/updater.ts
5894
- import { join as join10 } from "node:path";
6296
+ import { join as join11 } from "node:path";
5895
6297
 
5896
6298
  // packages/core/src/evolution/triggers/index.ts
5897
6299
  var exports_triggers = {};
@@ -5906,8 +6308,8 @@ __export(exports_triggers, {
5906
6308
  enqueueSegmentEvolutionTrigger: () => enqueueSegmentEvolutionTrigger,
5907
6309
  enqueueEvolutionTrigger: () => enqueueEvolutionTrigger
5908
6310
  });
5909
- import { readFile as readFile7 } from "node:fs/promises";
5910
- import { join as join9 } from "node:path";
6311
+ import { readFile as readFile8 } from "node:fs/promises";
6312
+ import { join as join10 } from "node:path";
5911
6313
 
5912
6314
  // packages/core/src/evolution/triggers/classification.ts
5913
6315
  function normalizeEvolutionEventType(value) {
@@ -6042,19 +6444,19 @@ async function enqueueEvolutionTrigger(input) {
6042
6444
  };
6043
6445
  validateEvolutionTriggerRecord(trigger);
6044
6446
  const paths = resolveEvolutionPaths({ homeDir: input.homeDir, projectKey, runId });
6045
- await writeJsonFile(join9(paths.triggersDir, `${trigger.id}.json`), trigger, { overwrite: false });
6447
+ await writeJsonFile(join10(paths.triggersDir, `${trigger.id}.json`), trigger, { overwrite: false });
6046
6448
  return trigger;
6047
6449
  }
6048
6450
  async function listEvolutionTriggers(input) {
6049
6451
  const paths = resolveEvoDevPaths(input.homeDir);
6050
- const evolutionStateDir = join9(paths.stateDir, "evolution");
6452
+ const evolutionStateDir = join10(paths.stateDir, "evolution");
6051
6453
  const projectKeys = input.projectKey === undefined ? await listDirectoryNames(evolutionStateDir) : [sanitizeStorageId2("projectKey", input.projectKey)];
6052
6454
  const triggers = [];
6053
6455
  for (const projectKey of projectKeys) {
6054
- const projectStateDir = join9(evolutionStateDir, projectKey);
6456
+ const projectStateDir = join10(evolutionStateDir, projectKey);
6055
6457
  const runIds = input.runId === undefined ? await listDirectoryNames(projectStateDir) : [sanitizeStorageId2("runId", input.runId)];
6056
6458
  for (const runId of runIds) {
6057
- const runTriggers = await readJsonFiles(join9(projectStateDir, runId, "triggers"), parseTrigger);
6459
+ const runTriggers = await readJsonFiles(join10(projectStateDir, runId, "triggers"), parseTrigger);
6058
6460
  triggers.push(...runTriggers.filter((trigger) => input.status === undefined || trigger.status === input.status));
6059
6461
  }
6060
6462
  }
@@ -6095,16 +6497,16 @@ async function enqueueSegmentEvolutionTrigger(input) {
6095
6497
  } catch (error) {
6096
6498
  if (!isFileExistsError(error))
6097
6499
  throw error;
6098
- return parseSegmentTrigger(JSON.parse(await readFile7(path, "utf8")));
6500
+ return parseSegmentTrigger(JSON.parse(await readFile8(path, "utf8")));
6099
6501
  }
6100
6502
  }
6101
6503
  async function listSegmentEvolutionTriggers(input) {
6102
6504
  const paths = resolveEvoDevPaths(input.homeDir);
6103
- const evolutionStateDir = join9(paths.stateDir, "evolution");
6505
+ const evolutionStateDir = join10(paths.stateDir, "evolution");
6104
6506
  const projectKeys = input.projectKey === undefined ? await listDirectoryNames(evolutionStateDir) : [sanitizeStorageId2("projectKey", input.projectKey)];
6105
6507
  const triggers = [];
6106
6508
  for (const projectKey of projectKeys) {
6107
- const projectSegmentsDir = join9(evolutionStateDir, projectKey, "segments");
6509
+ const projectSegmentsDir = join10(evolutionStateDir, projectKey, "segments");
6108
6510
  const projectTriggers = await readJsonFiles(projectSegmentsDir, parseSegmentTrigger);
6109
6511
  triggers.push(...projectTriggers.filter((trigger) => {
6110
6512
  if (input.status !== undefined && trigger.status !== input.status)
@@ -6141,7 +6543,7 @@ async function updateTriggers(homeDir, triggers, patch) {
6141
6543
  projectKey: next.projectKey,
6142
6544
  runId: next.runId
6143
6545
  });
6144
- await writeJsonFile(join9(paths.triggersDir, `${next.id}.json`), next, { overwrite: true });
6546
+ await writeJsonFile(join10(paths.triggersDir, `${next.id}.json`), next, { overwrite: true });
6145
6547
  }
6146
6548
  }
6147
6549
  async function updateSegmentTriggers(homeDir, triggers, patch) {
@@ -6160,128 +6562,7 @@ async function updateSegmentTriggers(homeDir, triggers, patch) {
6160
6562
  }
6161
6563
  function resolveSegmentEvolutionTriggerPath(homeDir, trigger) {
6162
6564
  const paths = resolveEvoDevPaths(homeDir);
6163
- return join9(paths.stateDir, "evolution", sanitizeStorageId2("projectKey", trigger.projectKey), "segments", `${sanitizeStorageId2("segmentTrigger", trigger.id)}.json`);
6164
- }
6165
-
6166
- // packages/core/src/evolution/evidence/session-memory/constants.ts
6167
- var DEFAULT_MAX_RAW_EVENT_BYTES = 64 * 1024;
6168
- var SENSITIVE_TEXT_PATTERN2 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|\.env)\b/i;
6169
- var EXPLICIT_MEMORY_PATTERN = /\b(remember|memorize|do not repeat|don't repeat|this is important|save this|learn this)\b/i;
6170
- var FAILURE_PATTERN = /\b(fail|failed|failure|error|issue|exception|crash)\b/i;
6171
- var VERIFICATION_PATTERN = /\b(test|lint|typecheck|build|verify|verification|passed|success)\b/i;
6172
-
6173
- // packages/core/src/evolution/evidence/session-memory/storage.ts
6174
- import { appendFile as appendFile2, mkdir as mkdir5, readFile as readFile8, writeFile as writeFile4 } from "node:fs/promises";
6175
- import { dirname as dirname5 } from "node:path";
6176
- async function readSessionState(path) {
6177
- try {
6178
- return JSON.parse(await readFile8(path, "utf8"));
6179
- } catch (error) {
6180
- if (isNotFoundError(error))
6181
- return null;
6182
- throw error;
6183
- }
6184
- }
6185
- async function readSessionCursor(path, sessionKey, sourcePath, now) {
6186
- try {
6187
- return JSON.parse(await readFile8(path, "utf8"));
6188
- } catch (error) {
6189
- if (!isNotFoundError(error))
6190
- throw error;
6191
- return {
6192
- schemaVersion: 1,
6193
- kind: "session-memory-cursor",
6194
- sessionKey,
6195
- traceRefId: null,
6196
- sourcePath,
6197
- lastCapturedOffset: null,
6198
- lastCapturedLine: null,
6199
- lastCapturedEventId: null,
6200
- updatedAt: now
6201
- };
6202
- }
6203
- }
6204
- async function appendRawEvent(path, event) {
6205
- const existingLineCount = await countJsonlLines(path);
6206
- await mkdir5(dirname5(path), { recursive: true });
6207
- await appendFile2(path, `${JSON.stringify(event)}
6208
- `, "utf8");
6209
- return { lineNumber: existingLineCount + 1 };
6210
- }
6211
- async function readLineRange(path, fromLine, toLine) {
6212
- const text2 = await readFile8(path, "utf8");
6213
- const lines = text2.split(`
6214
- `).filter((line) => line.trim() !== "");
6215
- const selected = lines.slice(Math.max(0, fromLine - 1), toLine);
6216
- let secretsDetected = false;
6217
- for (const line of selected) {
6218
- try {
6219
- const parsed = JSON.parse(line);
6220
- secretsDetected = secretsDetected || parsed.secretsDetected === true;
6221
- } catch {
6222
- secretsDetected = secretsDetected || SENSITIVE_TEXT_PATTERN2.test(line);
6223
- }
6224
- }
6225
- return { content: selected.join(`
6226
- `), truncated: false, secretsDetected };
6227
- }
6228
- async function writeSessionIndex(paths, state, segment, now) {
6229
- const existing = await readSessionIndex(paths.indexPath);
6230
- const segments = [
6231
- ...existing.segments.filter((item) => item.id !== segment.id),
6232
- {
6233
- id: segment.id,
6234
- reason: segment.reason,
6235
- strength: segment.strength,
6236
- createdAt: segment.createdAt,
6237
- reviewState: segment.lifecycle.reviewState
6238
- }
6239
- ];
6240
- await writeJson2(paths.indexPath, {
6241
- schemaVersion: 1,
6242
- kind: "session-memory-index",
6243
- projectKey: state.projectKey,
6244
- sessionKey: state.sessionKey,
6245
- updatedAt: now,
6246
- lastSegmentId: segment.id,
6247
- segments
6248
- });
6249
- }
6250
- async function writeJson2(path, value) {
6251
- await mkdir5(dirname5(path), { recursive: true });
6252
- await writeFile4(path, `${JSON.stringify(value, null, 2)}
6253
- `, "utf8");
6254
- }
6255
- async function countJsonlLines(path) {
6256
- try {
6257
- const text2 = await readFile8(path, "utf8");
6258
- return text2.split(`
6259
- `).filter((line) => line.trim() !== "").length;
6260
- } catch (error) {
6261
- if (isNotFoundError(error))
6262
- return 0;
6263
- throw error;
6264
- }
6265
- }
6266
- async function readSessionIndex(path) {
6267
- try {
6268
- const parsed = JSON.parse(await readFile8(path, "utf8"));
6269
- if (!Array.isArray(parsed.segments))
6270
- return { segments: [] };
6271
- return {
6272
- segments: parsed.segments.filter(isSessionIndexSegment)
6273
- };
6274
- } catch (error) {
6275
- if (isNotFoundError(error))
6276
- return { segments: [] };
6277
- throw error;
6278
- }
6279
- }
6280
- function isSessionIndexSegment(value) {
6281
- if (typeof value !== "object" || value === null || Array.isArray(value))
6282
- return false;
6283
- const item = value;
6284
- return typeof item.id === "string" && typeof item.reason === "string" && typeof item.strength === "string" && typeof item.createdAt === "string" && typeof item.reviewState === "string";
6565
+ return join10(paths.stateDir, "evolution", sanitizeStorageId2("projectKey", trigger.projectKey), "segments", `${sanitizeStorageId2("segmentTrigger", trigger.id)}.json`);
6285
6566
  }
6286
6567
 
6287
6568
  // packages/core/src/evolution/evidence/session-memory/segment.ts
@@ -6379,8 +6660,8 @@ async function createSegment(input) {
6379
6660
  externalUploadAllowed: false
6380
6661
  },
6381
6662
  lifecycle: {
6382
- status: "pending-review",
6383
- reviewState: "unreviewed",
6663
+ status: "captured",
6664
+ reviewState: "not-required",
6384
6665
  consumedByBatchIds: []
6385
6666
  }
6386
6667
  };
@@ -6690,7 +6971,7 @@ async function updateSessionMemoryFromHook(input) {
6690
6971
  await writeJson2(paths.cursorPath, cursor);
6691
6972
  stateWrites.push(paths.statePath, paths.cursorPath);
6692
6973
  if (queuedSegmentTriggerId !== null) {
6693
- stateWrites.push(join10(input.homeDir, ".evodev", "state", "evolution", projectKey, "segments", `${queuedSegmentTriggerId}.json`));
6974
+ stateWrites.push(join11(input.homeDir, ".evodev", "state", "evolution", projectKey, "segments", `${queuedSegmentTriggerId}.json`));
6694
6975
  }
6695
6976
  return {
6696
6977
  state,
@@ -6712,12 +6993,12 @@ function emptyResult() {
6712
6993
  };
6713
6994
  }
6714
6995
  // packages/core/src/hooks/index.ts
6715
- import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile7 } from "node:fs/promises";
6716
- import { dirname as dirname8, join as join13 } from "node:path";
6996
+ import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile8 } from "node:fs/promises";
6997
+ import { dirname as dirname9, join as join14 } from "node:path";
6717
6998
 
6718
6999
  // packages/core/src/task/index.ts
6719
- import { lstat, mkdir as mkdir6, readFile as readFile9, realpath, stat as stat5, writeFile as writeFile5 } from "node:fs/promises";
6720
- import { basename, dirname as dirname6, join as join11, resolve as resolve3 } from "node:path";
7000
+ import { lstat, mkdir as mkdir7, readFile as readFile9, realpath, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
7001
+ import { basename, dirname as dirname7, join as join12, resolve as resolve3 } from "node:path";
6721
7002
  var FORBIDDEN_TASK_PATHS = ["CLAUDE.md", "AGENTS.md", ".claude/**", ".codex/**"];
6722
7003
  var FORBIDDEN_TASK_WRITE_SEGMENTS = new Set([".claude", ".codex"]);
6723
7004
  var FORBIDDEN_PROJECT_ASSET_SEGMENTS = new Set(["packages", "src"]);
@@ -6917,8 +7198,8 @@ async function readTaskContract(path) {
6917
7198
  }
6918
7199
  async function writeTaskContract(path, contract, options = {}) {
6919
7200
  await assertTaskContractWritePathAllowed(path);
6920
- await mkdir6(dirname6(path), { recursive: true });
6921
- await writeFile5(path, `${JSON.stringify(contract, null, 2)}
7201
+ await mkdir7(dirname7(path), { recursive: true });
7202
+ await writeFile6(path, `${JSON.stringify(contract, null, 2)}
6922
7203
  `, {
6923
7204
  encoding: "utf8",
6924
7205
  flag: options.overwrite === true ? "w" : "wx"
@@ -6926,16 +7207,16 @@ async function writeTaskContract(path, contract, options = {}) {
6926
7207
  }
6927
7208
  async function resolveTaskContractOutputPath(input) {
6928
7209
  if (input.outputDir !== undefined) {
6929
- const outputPath = join11(input.outputDir, input.taskId, "contract.json");
7210
+ const outputPath = join12(input.outputDir, input.taskId, "contract.json");
6930
7211
  await assertTaskContractWritePathAllowed(outputPath);
6931
7212
  return outputPath;
6932
7213
  }
6933
7214
  if (input.projectDir !== undefined) {
6934
- const projectContextPath = join11(input.projectDir, ".evodev", "project.json");
7215
+ const projectContextPath = join12(input.projectDir, ".evodev", "project.json");
6935
7216
  if (!await pathExists4(projectContextPath)) {
6936
7217
  throw new Error("Project mode requires existing .evodev/project.json; use --output-dir instead.");
6937
7218
  }
6938
- const outputPath = join11(input.projectDir, ".evodev", "tasks", input.taskId, "contract.json");
7219
+ const outputPath = join12(input.projectDir, ".evodev", "tasks", input.taskId, "contract.json");
6939
7220
  await assertTaskContractWritePathAllowed(outputPath);
6940
7221
  return outputPath;
6941
7222
  }
@@ -7140,7 +7421,7 @@ function isVerificationReady(contract) {
7140
7421
  return contract.status !== "draft" && contract.route.mode !== null && contract.route.workflowId !== null && (contract.route.requiredVerification ?? []).length > 0;
7141
7422
  }
7142
7423
  function parseTaskContract(value) {
7143
- if (!isRecord6(value) || value.version !== 1 || typeof value.taskId !== "string") {
7424
+ if (!isRecord7(value) || value.version !== 1 || typeof value.taskId !== "string") {
7144
7425
  throw new Error("Invalid Task Contract JSON.");
7145
7426
  }
7146
7427
  return value;
@@ -7151,7 +7432,7 @@ function assertMetadataOnly(value) {
7151
7432
  assertMetadataOnly(item);
7152
7433
  return;
7153
7434
  }
7154
- if (!isRecord6(value)) {
7435
+ if (!isRecord7(value)) {
7155
7436
  if (typeof value === "string" && containsSensitiveText(value)) {
7156
7437
  throw new Error("Verification input contains sensitive content in metadata field.");
7157
7438
  }
@@ -7229,11 +7510,11 @@ async function resolveTaskWriteRealPath(path) {
7229
7510
  while (true) {
7230
7511
  try {
7231
7512
  await lstat(currentPath);
7232
- return join11(await realpath(currentPath), ...missingSegments.reverse());
7513
+ return join12(await realpath(currentPath), ...missingSegments.reverse());
7233
7514
  } catch (error) {
7234
7515
  if (!isMissingPathError(error))
7235
7516
  throw error;
7236
- const parentPath = dirname6(currentPath);
7517
+ const parentPath = dirname7(currentPath);
7237
7518
  if (parentPath === currentPath)
7238
7519
  return resolve3(path);
7239
7520
  missingSegments.push(basename(currentPath));
@@ -7275,14 +7556,14 @@ async function pathExists4(path) {
7275
7556
  function isMissingPathError(error) {
7276
7557
  return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
7277
7558
  }
7278
- function isRecord6(value) {
7559
+ function isRecord7(value) {
7279
7560
  return typeof value === "object" && value !== null && !Array.isArray(value);
7280
7561
  }
7281
7562
 
7282
7563
  // packages/core/src/team/index.ts
7283
7564
  import { spawn } from "node:child_process";
7284
- import { appendFile as appendFile3, cp, mkdir as mkdir7, readFile as readFile10, readdir as readdir7, stat as stat6, writeFile as writeFile6 } from "node:fs/promises";
7285
- import { basename as basename2, dirname as dirname7, extname, isAbsolute as isAbsolute5, join as join12, relative as relative6, resolve as resolve4 } from "node:path";
7565
+ import { appendFile as appendFile3, cp, mkdir as mkdir8, readFile as readFile10, readdir as readdir8, stat as stat6, writeFile as writeFile7 } from "node:fs/promises";
7566
+ import { basename as basename2, dirname as dirname8, extname, isAbsolute as isAbsolute5, join as join13, relative as relative6, resolve as resolve4 } from "node:path";
7286
7567
 
7287
7568
  // packages/core/src/team/prompts.ts
7288
7569
  var TEAM_ROLE_STARTUP_PROMPT_TEMPLATE = [
@@ -7483,8 +7764,8 @@ function createTeamRunStore(homeDir) {
7483
7764
  paths: paths2,
7484
7765
  async createRunDirs(runId) {
7485
7766
  await migrateLegacyRunDirIfNeeded(paths2, runId);
7486
- await mkdir7(paths2.runDir(runId), { recursive: true });
7487
- await mkdir7(paths2.agentsDir(runId), { recursive: true });
7767
+ await mkdir8(paths2.runDir(runId), { recursive: true });
7768
+ await mkdir8(paths2.agentsDir(runId), { recursive: true });
7488
7769
  },
7489
7770
  async writeRun(run) {
7490
7771
  await this.createRunDirs(run.runId);
@@ -7495,7 +7776,7 @@ function createTeamRunStore(homeDir) {
7495
7776
  return parseTeamRunRecord(JSON.parse(await readFile10(paths2.runPath(runId), "utf8")));
7496
7777
  },
7497
7778
  async writeLatestRunId(runId) {
7498
- await mkdir7(paths2.runsDir, { recursive: true });
7779
+ await mkdir8(paths2.runsDir, { recursive: true });
7499
7780
  await writeJson3(paths2.latestRunPath, { version: 1, runId });
7500
7781
  },
7501
7782
  async readLatestRunId() {
@@ -7529,8 +7810,8 @@ function createTeamRunStore(homeDir) {
7529
7810
  async readAgents(runId) {
7530
7811
  await migrateLegacyRunDirIfNeeded(paths2, runId);
7531
7812
  try {
7532
- const entries = await readdir7(paths2.agentsDir(runId));
7533
- const agents = await Promise.all(entries.filter((entry) => entry.endsWith(".json")).map((entry) => readFile10(join12(paths2.agentsDir(runId), entry), "utf8").then((raw) => parseTeamAgentRecord(JSON.parse(raw)))));
7813
+ const entries = await readdir8(paths2.agentsDir(runId));
7814
+ const agents = await Promise.all(entries.filter((entry) => entry.endsWith(".json")).map((entry) => readFile10(join13(paths2.agentsDir(runId), entry), "utf8").then((raw) => parseTeamAgentRecord(JSON.parse(raw)))));
7534
7815
  return agents.sort((left, right) => left.roleId.localeCompare(right.roleId));
7535
7816
  } catch {
7536
7817
  return [];
@@ -7585,7 +7866,7 @@ function createTeamRunStore(homeDir) {
7585
7866
  }
7586
7867
  function resolveTeamRunPaths(homeDir) {
7587
7868
  const paths2 = resolveEvoDevPaths(homeDir);
7588
- const legacyRunsDir = join12(paths2.rootDir, "runs");
7869
+ const legacyRunsDir = join13(paths2.rootDir, "runs");
7589
7870
  return {
7590
7871
  rootDir: paths2.rootDir,
7591
7872
  roleAgentsDir: paths2.roleAgentsDir,
@@ -7593,23 +7874,23 @@ function resolveTeamRunPaths(homeDir) {
7593
7874
  runsDir: paths2.runsDir,
7594
7875
  legacyRunsDir,
7595
7876
  latestRunPath: paths2.latestRunPath,
7596
- legacyLatestRunPath: join12(legacyRunsDir, "latest.json"),
7597
- runDir: (runId) => join12(paths2.runsDir, runId),
7598
- legacyRunDir: (runId) => join12(legacyRunsDir, runId),
7599
- runPath: (runId) => join12(paths2.runsDir, runId, "run.json"),
7600
- legacyRunPath: (runId) => join12(legacyRunsDir, runId, "run.json"),
7601
- tmuxPath: (runId) => join12(paths2.runsDir, runId, "tmux.json"),
7602
- legacyTmuxPath: (runId) => join12(legacyRunsDir, runId, "tmux.json"),
7603
- agentsDir: (runId) => join12(paths2.runsDir, runId, "agents"),
7604
- legacyAgentsDir: (runId) => join12(legacyRunsDir, runId, "agents"),
7605
- agentPath: (runId, roleId) => join12(paths2.runsDir, runId, "agents", `${roleId}.json`),
7606
- legacyAgentPath: (runId, roleId) => join12(legacyRunsDir, runId, "agents", `${roleId}.json`),
7607
- messagesPath: (runId) => join12(paths2.runsDir, runId, "messages.jsonl"),
7608
- legacyMessagesPath: (runId) => join12(legacyRunsDir, runId, "messages.jsonl"),
7609
- eventsPath: (runId) => join12(paths2.runsDir, runId, "events.jsonl"),
7610
- legacyEventsPath: (runId) => join12(legacyRunsDir, runId, "events.jsonl"),
7611
- statusPath: (runId) => join12(paths2.runsDir, runId, "status.json"),
7612
- messageListPath: (runId) => join12(paths2.runsDir, runId, "message-list.json")
7877
+ legacyLatestRunPath: join13(legacyRunsDir, "latest.json"),
7878
+ runDir: (runId) => join13(paths2.runsDir, runId),
7879
+ legacyRunDir: (runId) => join13(legacyRunsDir, runId),
7880
+ runPath: (runId) => join13(paths2.runsDir, runId, "run.json"),
7881
+ legacyRunPath: (runId) => join13(legacyRunsDir, runId, "run.json"),
7882
+ tmuxPath: (runId) => join13(paths2.runsDir, runId, "tmux.json"),
7883
+ legacyTmuxPath: (runId) => join13(legacyRunsDir, runId, "tmux.json"),
7884
+ agentsDir: (runId) => join13(paths2.runsDir, runId, "agents"),
7885
+ legacyAgentsDir: (runId) => join13(legacyRunsDir, runId, "agents"),
7886
+ agentPath: (runId, roleId) => join13(paths2.runsDir, runId, "agents", `${roleId}.json`),
7887
+ legacyAgentPath: (runId, roleId) => join13(legacyRunsDir, runId, "agents", `${roleId}.json`),
7888
+ messagesPath: (runId) => join13(paths2.runsDir, runId, "messages.jsonl"),
7889
+ legacyMessagesPath: (runId) => join13(legacyRunsDir, runId, "messages.jsonl"),
7890
+ eventsPath: (runId) => join13(paths2.runsDir, runId, "events.jsonl"),
7891
+ legacyEventsPath: (runId) => join13(legacyRunsDir, runId, "events.jsonl"),
7892
+ statusPath: (runId) => join13(paths2.runsDir, runId, "status.json"),
7893
+ messageListPath: (runId) => join13(paths2.runsDir, runId, "message-list.json")
7613
7894
  };
7614
7895
  }
7615
7896
  async function migrateLegacyRunDirIfNeeded(paths2, runId) {
@@ -7619,7 +7900,7 @@ async function migrateLegacyRunDirIfNeeded(paths2, runId) {
7619
7900
  const legacyDir = paths2.legacyRunDir(runId);
7620
7901
  if (!await pathExists5(legacyDir))
7621
7902
  return;
7622
- await mkdir7(dirname7(nextDir), { recursive: true });
7903
+ await mkdir8(dirname8(nextDir), { recursive: true });
7623
7904
  await cp(legacyDir, nextDir, { recursive: true, errorOnExist: false, force: false });
7624
7905
  }
7625
7906
  async function writeTeamStatusSnapshot(input) {
@@ -8149,7 +8430,7 @@ async function listTeamRuns(input = {}) {
8149
8430
  const entries = new Set;
8150
8431
  for (const runsDir of [store.paths.runsDir, store.paths.legacyRunsDir]) {
8151
8432
  try {
8152
- for (const entry of await readdir7(runsDir))
8433
+ for (const entry of await readdir8(runsDir))
8153
8434
  entries.add(entry);
8154
8435
  } catch (error) {
8155
8436
  if (!isNotFoundError3(error))
@@ -8481,7 +8762,7 @@ async function listTeamAgents(input = {}) {
8481
8762
  }));
8482
8763
  }
8483
8764
  async function resolveTeamOverlay(input) {
8484
- const repoTeamPath = join12(input.repoRoot, ".evodev", "team", "team.md");
8765
+ const repoTeamPath = join13(input.repoRoot, ".evodev", "team", "team.md");
8485
8766
  if (await pathExists5(repoTeamPath)) {
8486
8767
  return {
8487
8768
  source: "repo",
@@ -8508,7 +8789,7 @@ async function ensureDefaultTeamOverlay(input) {
8508
8789
  const paths2 = resolveEvoDevPaths(input.homeDir);
8509
8790
  const files = [];
8510
8791
  for (const asset of assets) {
8511
- const targetPath = asset.kind === "team" ? join12(paths2.rootDir, "team", "team.md") : join12(paths2.rootDir, "team", "agents", asset.name);
8792
+ const targetPath = asset.kind === "team" ? join13(paths2.rootDir, "team", "team.md") : join13(paths2.rootDir, "team", "agents", asset.name);
8512
8793
  const content = await readFile10(asset.sourcePath, "utf8");
8513
8794
  files.push({
8514
8795
  sourcePath: asset.sourcePath,
@@ -8542,7 +8823,7 @@ function resolveTeamAgentReference(input) {
8542
8823
  return {
8543
8824
  roleId: input.roleId,
8544
8825
  reference,
8545
- sourcePath: join12(resolveEvoDevPaths(input.homeDir).rootDir, "team", "agents", `${name}.md`),
8826
+ sourcePath: join13(resolveEvoDevPaths(input.homeDir).rootDir, "team", "agents", `${name}.md`),
8546
8827
  scope: "global"
8547
8828
  };
8548
8829
  }
@@ -8579,7 +8860,7 @@ async function readTeamAgentDefinition(input) {
8579
8860
  const reference = resolveTeamAgentReference(input);
8580
8861
  const markdown = await readTeamAgentMarkdown(reference);
8581
8862
  const parsed = parseMarkdownWithFrontmatter(markdown);
8582
- const evodev = isRecord7(parsed.frontmatter.evodev) ? parsed.frontmatter.evodev : {};
8863
+ const evodev = isRecord8(parsed.frontmatter.evodev) ? parsed.frontmatter.evodev : {};
8583
8864
  return {
8584
8865
  roleId: input.roleId,
8585
8866
  name: optionalString5(parsed.frontmatter.name) ?? defaultRoleName(input.roleId),
@@ -8662,7 +8943,7 @@ async function resolveTeamRole(input) {
8662
8943
  nativeAgent: null
8663
8944
  };
8664
8945
  }
8665
- const globalRolePath = join12(resolveEvoDevPaths(input.homeDir).roleAgentsDir, `${input.roleId}.json`);
8946
+ const globalRolePath = join13(resolveEvoDevPaths(input.homeDir).roleAgentsDir, `${input.roleId}.json`);
8666
8947
  const candidate = await readRoleCandidate(globalRolePath, "global");
8667
8948
  const nativeAgent = await resolveTeamRoleNativeAgentBinding({
8668
8949
  homeDir: input.homeDir,
@@ -8696,7 +8977,7 @@ async function resolveTeamRole(input) {
8696
8977
  };
8697
8978
  }
8698
8979
  function parseTeamRoleDefinition(value, defaults) {
8699
- const input = isRecord7(value) ? value : {};
8980
+ const input = isRecord8(value) ? value : {};
8700
8981
  const roleId = optionalString5(input.roleId) ?? defaults.roleId;
8701
8982
  assertSafeId(roleId, "roleId");
8702
8983
  const runtime = parseRuntime(input.runtime, defaults.defaultRuntime);
@@ -9220,12 +9501,12 @@ async function readTeamOverlayAgentSummaries(input) {
9220
9501
  })));
9221
9502
  }
9222
9503
  async function listDefaultTeamOverlayAssets(assetsRootDir) {
9223
- const teamPath = join12(assetsRootDir, "team", "team.md");
9224
- const agentsDir = join12(assetsRootDir, "team", "agents");
9504
+ const teamPath = join13(assetsRootDir, "team", "team.md");
9505
+ const agentsDir = join13(assetsRootDir, "team", "agents");
9225
9506
  await assertReadableFile(teamPath, "Default team asset");
9226
9507
  let entries;
9227
9508
  try {
9228
- entries = await readdir7(agentsDir, { withFileTypes: true });
9509
+ entries = await readdir8(agentsDir, { withFileTypes: true });
9229
9510
  } catch (error) {
9230
9511
  throw new Error(`Cannot read default team agents directory ${agentsDir}: ${describeError2(error)}`);
9231
9512
  }
@@ -9237,7 +9518,7 @@ async function listDefaultTeamOverlayAssets(assetsRootDir) {
9237
9518
  { kind: "team", sourcePath: teamPath, name: "team.md" },
9238
9519
  ...agentFiles.map((name) => ({
9239
9520
  kind: "agent",
9240
- sourcePath: join12(agentsDir, name),
9521
+ sourcePath: join13(agentsDir, name),
9241
9522
  name
9242
9523
  }))
9243
9524
  ];
@@ -9260,8 +9541,8 @@ async function writeTextFileIfMissing(path, content) {
9260
9541
  throw new Error(`Cannot inspect ${path}: ${describeError2(error)}`);
9261
9542
  }
9262
9543
  }
9263
- await mkdir7(dirname7(path), { recursive: true });
9264
- await writeFile6(path, content.endsWith(`
9544
+ await mkdir8(dirname8(path), { recursive: true });
9545
+ await writeFile7(path, content.endsWith(`
9265
9546
  `) ? content : `${content}
9266
9547
  `, "utf8");
9267
9548
  return true;
@@ -9269,7 +9550,7 @@ async function writeTextFileIfMissing(path, content) {
9269
9550
  function parseTeamDefinitionAgents(value) {
9270
9551
  if (value === undefined)
9271
9552
  return {};
9272
- if (!isRecord7(value))
9553
+ if (!isRecord8(value))
9273
9554
  throw new Error("team.md agents must be a role-id map.");
9274
9555
  const agents = {};
9275
9556
  for (const [roleId, reference] of Object.entries(value)) {
@@ -9335,7 +9616,7 @@ function parseSimpleYaml(content) {
9335
9616
  throw new Error(`Invalid YAML line: ${trimmed}`);
9336
9617
  const key = trimmed.slice(0, separator).trim();
9337
9618
  const rawValue = trimmed.slice(separator + 1).trim();
9338
- if (!isRecord7(parent))
9619
+ if (!isRecord8(parent))
9339
9620
  throw new Error(`Invalid YAML parent for key ${key}.`);
9340
9621
  if (rawValue === "") {
9341
9622
  const next = findNextYamlContentLine(lines, index + 1);
@@ -9397,10 +9678,10 @@ function appendPromptBlock(prompt, block) {
9397
9678
  ${block.trim()}`;
9398
9679
  }
9399
9680
  function resolveGlobalTeamMarkdownPath(homeDir) {
9400
- return join12(resolveEvoDevPaths(homeDir).rootDir, "team", "team.md");
9681
+ return join13(resolveEvoDevPaths(homeDir).rootDir, "team", "team.md");
9401
9682
  }
9402
9683
  function parseRolePermissions(value, main) {
9403
- const input = isRecord7(value) ? value : {};
9684
+ const input = isRecord8(value) ? value : {};
9404
9685
  return {
9405
9686
  writeMode: parseWriteMode(input.writeMode, "repo-write"),
9406
9687
  canUseTeamsMcp: optionalBoolean2(input.canUseTeamsMcp) ?? true,
@@ -9409,14 +9690,14 @@ function parseRolePermissions(value, main) {
9409
9690
  };
9410
9691
  }
9411
9692
  function parseRolePolicy(value, recordTranscript) {
9412
- const input = isRecord7(value) ? value : {};
9693
+ const input = isRecord8(value) ? value : {};
9413
9694
  return {
9414
9695
  roleInstancePolicy: "single-per-role",
9415
9696
  recordTranscript: optionalBoolean2(input.recordTranscript) ?? recordTranscript
9416
9697
  };
9417
9698
  }
9418
9699
  function parseTeamRunRecord(value) {
9419
- if (!isRecord7(value) || value.version !== 1)
9700
+ if (!isRecord8(value) || value.version !== 1)
9420
9701
  throw new Error("Invalid team run record.");
9421
9702
  const run = value;
9422
9703
  assertSafeId(run.runId, "runId");
@@ -9426,7 +9707,7 @@ function parseTeamRunRecord(value) {
9426
9707
  return run;
9427
9708
  }
9428
9709
  function parseTeamAgentRecord(value) {
9429
- if (!isRecord7(value) || value.version !== 1)
9710
+ if (!isRecord8(value) || value.version !== 1)
9430
9711
  throw new Error("Invalid team agent record.");
9431
9712
  const agent = value;
9432
9713
  assertSafeId(agent.agentId, "agentId");
@@ -9447,7 +9728,7 @@ function parseTeamAgentRecord(value) {
9447
9728
  ].includes(agent.status)) {
9448
9729
  throw new Error("Invalid agent status.");
9449
9730
  }
9450
- const nativeSessionValue = isRecord7(value.nativeSession) ? value.nativeSession : {};
9731
+ const nativeSessionValue = isRecord8(value.nativeSession) ? value.nativeSession : {};
9451
9732
  return {
9452
9733
  ...agent,
9453
9734
  nativeSession: {
@@ -9457,7 +9738,7 @@ function parseTeamAgentRecord(value) {
9457
9738
  };
9458
9739
  }
9459
9740
  function parseTeamMessageRecord(value) {
9460
- if (!isRecord7(value) || value.version !== 1)
9741
+ if (!isRecord8(value) || value.version !== 1)
9461
9742
  throw new Error("Invalid team message record.");
9462
9743
  const message = value;
9463
9744
  assertSafeId(message.messageId, "messageId");
@@ -9486,7 +9767,7 @@ function parseTeamPendingMessageRecord(value) {
9486
9767
  };
9487
9768
  }
9488
9769
  function parseTeamMessageListFile(value) {
9489
- if (!isRecord7(value) || value.version !== 1)
9770
+ if (!isRecord8(value) || value.version !== 1)
9490
9771
  throw new Error("Invalid team message list.");
9491
9772
  const messages = Array.isArray(value.messages) ? value.messages.map(parseTeamPendingMessageRecord) : [];
9492
9773
  return {
@@ -9496,7 +9777,7 @@ function parseTeamMessageListFile(value) {
9496
9777
  };
9497
9778
  }
9498
9779
  function parseTeamEventRecord(value) {
9499
- if (!isRecord7(value) || value.version !== 1)
9780
+ if (!isRecord8(value) || value.version !== 1)
9500
9781
  throw new Error("Invalid team event record.");
9501
9782
  const event = value;
9502
9783
  assertSafeId(event.eventId, "eventId");
@@ -9638,10 +9919,10 @@ async function resolveTeamRoleNativeAgentBinding(input) {
9638
9919
  return bindings.find((binding) => binding.roleId === input.roleId) ?? null;
9639
9920
  }
9640
9921
  function resolveGlobalTeamBindingPath(homeDir) {
9641
- return join12(resolveEvoDevPaths(homeDir).rootDir, "team", "roles.json");
9922
+ return join13(resolveEvoDevPaths(homeDir).rootDir, "team", "roles.json");
9642
9923
  }
9643
9924
  function resolveProjectTeamBindingPath(homeDir, projectKey) {
9644
- return join12(resolveEvoDevPaths(homeDir).rootDir, "projects", safeSlug(projectKey), "team.json");
9925
+ return join13(resolveEvoDevPaths(homeDir).rootDir, "projects", safeSlug(projectKey), "team.json");
9645
9926
  }
9646
9927
  function resolveTeamBindingWritePath(input) {
9647
9928
  if (input.scope === "global") {
@@ -9668,7 +9949,7 @@ async function readTeamBindingConfig(path) {
9668
9949
  }
9669
9950
  }
9670
9951
  function parseTeamBindingConfig(value) {
9671
- if (!isRecord7(value) || value.version !== 1)
9952
+ if (!isRecord8(value) || value.version !== 1)
9672
9953
  throw new Error("Invalid team binding config.");
9673
9954
  const updatedAt = optionalString5(value.updatedAt) ?? "unknown";
9674
9955
  const rolesValue = Array.isArray(value.roles) ? value.roles : [];
@@ -9679,7 +9960,7 @@ function parseTeamBindingConfig(value) {
9679
9960
  };
9680
9961
  }
9681
9962
  function parseTeamBindingRecord(value) {
9682
- if (!isRecord7(value) || value.version !== 1) {
9963
+ if (!isRecord8(value) || value.version !== 1) {
9683
9964
  throw new Error("Invalid team binding record.");
9684
9965
  }
9685
9966
  const roleId = optionalString5(value.roleId);
@@ -9724,12 +10005,12 @@ async function pathExists5(path) {
9724
10005
  }
9725
10006
  }
9726
10007
  async function writeJson3(path, value) {
9727
- await mkdir7(dirname7(path), { recursive: true });
9728
- await writeFile6(path, `${JSON.stringify(value, null, 2)}
10008
+ await mkdir8(dirname8(path), { recursive: true });
10009
+ await writeFile7(path, `${JSON.stringify(value, null, 2)}
9729
10010
  `, "utf8");
9730
10011
  }
9731
10012
  async function appendJsonLine2(path, value) {
9732
- await mkdir7(dirname7(path), { recursive: true });
10013
+ await mkdir8(dirname8(path), { recursive: true });
9733
10014
  await appendFile3(path, `${JSON.stringify(value)}
9734
10015
  `, "utf8");
9735
10016
  }
@@ -9767,7 +10048,7 @@ function optionalNullableString(value) {
9767
10048
  function optionalBoolean2(value) {
9768
10049
  return typeof value === "boolean" ? value : undefined;
9769
10050
  }
9770
- function isRecord7(value) {
10051
+ function isRecord8(value) {
9771
10052
  return typeof value === "object" && value !== null && !Array.isArray(value);
9772
10053
  }
9773
10054
  function describeError2(error) {
@@ -9871,9 +10152,9 @@ function parseHookSettings(value) {
9871
10152
  const defaults = createDefaultHookSettings();
9872
10153
  if (value === undefined || value === null)
9873
10154
  return defaults;
9874
- if (!isRecord8(value))
10155
+ if (!isRecord9(value))
9875
10156
  throw new Error("Invalid hooks settings; expected object.");
9876
- const observability = isRecord8(value.observability) ? value.observability : undefined;
10157
+ const observability = isRecord9(value.observability) ? value.observability : undefined;
9877
10158
  optionalBoolean3(observability?.metadataOnly, defaults.observability.metadataOnly, "hooks.observability.metadataOnly");
9878
10159
  optionalBoolean3(observability?.rawPayloadStorage, defaults.observability.rawPayloadStorage, "hooks.observability.rawPayloadStorage");
9879
10160
  return {
@@ -10004,11 +10285,11 @@ function formatHookEventDryRun(event) {
10004
10285
  `);
10005
10286
  }
10006
10287
  function resolveHookRuntimeSessionPaths(input) {
10007
- const sessionDir = join13(input.homeDir, ".evodev", "STATE", "hooks", "sessions", input.sessionKey);
10288
+ const sessionDir = join14(input.homeDir, ".evodev", "STATE", "hooks", "sessions", input.sessionKey);
10008
10289
  return {
10009
10290
  sessionDir,
10010
- bindingPath: join13(sessionDir, "binding.json"),
10011
- contractPath: join13(sessionDir, "contract.json")
10291
+ bindingPath: join14(sessionDir, "binding.json"),
10292
+ contractPath: join14(sessionDir, "contract.json")
10012
10293
  };
10013
10294
  }
10014
10295
  async function handleHookRuntime(input) {
@@ -10126,7 +10407,7 @@ async function recordEvolutionTriggerFromHook(input) {
10126
10407
  return { stateWrites: [], warnings: [] };
10127
10408
  return {
10128
10409
  stateWrites: [
10129
- join13(input.homeDir, ".evodev", "state", "evolution", trigger.projectKey, trigger.runId, "triggers", `${trigger.id}.json`)
10410
+ join14(input.homeDir, ".evodev", "state", "evolution", trigger.projectKey, trigger.runId, "triggers", `${trigger.id}.json`)
10130
10411
  ],
10131
10412
  warnings: []
10132
10413
  };
@@ -10445,7 +10726,7 @@ function hookOutput(eventName, output) {
10445
10726
  function appendAdditionalContext(output, eventName, context) {
10446
10727
  if (output === null)
10447
10728
  return hookOutput(eventName, { additionalContext: context });
10448
- const hookSpecificOutput = isRecord8(output.hookSpecificOutput) ? output.hookSpecificOutput : {};
10729
+ const hookSpecificOutput = isRecord9(output.hookSpecificOutput) ? output.hookSpecificOutput : {};
10449
10730
  const previous = typeof hookSpecificOutput.additionalContext === "string" ? hookSpecificOutput.additionalContext : "";
10450
10731
  return {
10451
10732
  ...output,
@@ -10594,8 +10875,8 @@ function resolveHookSessionKey(payload) {
10594
10875
  return `session-${sha256Short(source)}`;
10595
10876
  }
10596
10877
  async function writeJsonFile2(path, value) {
10597
- await mkdir8(dirname8(path), { recursive: true });
10598
- await writeFile7(path, `${JSON.stringify(value, null, 2)}
10878
+ await mkdir9(dirname9(path), { recursive: true });
10879
+ await writeFile8(path, `${JSON.stringify(value, null, 2)}
10599
10880
  `, "utf8");
10600
10881
  }
10601
10882
  function optionalPayloadString(value) {
@@ -10620,9 +10901,9 @@ function normalizeHookEventType(type, warnings) {
10620
10901
  throw new Error(`Unsupported hook event type: ${type}`);
10621
10902
  }
10622
10903
  function parseHookTargetSettings(value, defaults, target) {
10623
- const targets = isRecord8(value) ? value : {};
10624
- const targetSettings = isRecord8(targets[target]) ? targets[target] : {};
10625
- const events = isRecord8(targetSettings.events) ? targetSettings.events : {};
10904
+ const targets = isRecord9(value) ? value : {};
10905
+ const targetSettings = isRecord9(targets[target]) ? targets[target] : {};
10906
+ const events = isRecord9(targetSettings.events) ? targetSettings.events : {};
10626
10907
  const parsedEvents = { ...defaults.events };
10627
10908
  for (const eventType of CANONICAL_HOOK_EVENT_TYPES) {
10628
10909
  parsedEvents[eventType] = optionalBoolean3(events[eventType], defaults.events[eventType], `hooks.targets.${target}.events.${eventType}`);
@@ -10634,7 +10915,7 @@ function parseHookTargetSettings(value, defaults, target) {
10634
10915
  }
10635
10916
  function extractMetadata(type, payload, redactions) {
10636
10917
  const metadata = {};
10637
- const toolInput = isRecord8(payload.tool_input) ? payload.tool_input : isRecord8(payload.toolInput) ? payload.toolInput : {};
10918
+ const toolInput = isRecord9(payload.tool_input) ? payload.tool_input : isRecord9(payload.toolInput) ? payload.toolInput : {};
10638
10919
  const toolName = optionalSanitizedString(payload.tool_name ?? payload.toolName, redactions);
10639
10920
  if (toolName !== null)
10640
10921
  metadata.toolName = toolName;
@@ -10712,7 +10993,7 @@ function optionalNumber(value) {
10712
10993
  function formatMetadataValue(value) {
10713
10994
  return Array.isArray(value) ? value.join(",") : String(value);
10714
10995
  }
10715
- function isRecord8(value) {
10996
+ function isRecord9(value) {
10716
10997
  return typeof value === "object" && value !== null && !Array.isArray(value);
10717
10998
  }
10718
10999
 
@@ -11014,20 +11295,20 @@ function expectNonNegativeInteger(value, path) {
11014
11295
  return value;
11015
11296
  }
11016
11297
  // packages/core/src/config/store.ts
11017
- import { mkdir as mkdir9, readFile as readFile13, writeFile as writeFile8 } from "node:fs/promises";
11018
- import { dirname as dirname9 } from "node:path";
11298
+ import { mkdir as mkdir10, readFile as readFile13, writeFile as writeFile9 } from "node:fs/promises";
11299
+ import { dirname as dirname10 } from "node:path";
11019
11300
  function createCoreConfigStore(homeDir) {
11020
11301
  const paths2 = resolveEvoDevPaths(homeDir);
11021
11302
  return {
11022
11303
  paths: paths2,
11023
11304
  async ensureBaseDirs() {
11024
- await mkdir9(paths2.stateDir, { recursive: true });
11025
- await mkdir9(paths2.logsDir, { recursive: true });
11026
- await mkdir9(paths2.knowledgeDir, { recursive: true });
11027
- await mkdir9(paths2.evosCasesDir, { recursive: true });
11028
- await mkdir9(paths2.roleAgentsDir, { recursive: true });
11029
- await mkdir9(paths2.teamsDir, { recursive: true });
11030
- await mkdir9(paths2.runsDir, { recursive: true });
11305
+ await mkdir10(paths2.stateDir, { recursive: true });
11306
+ await mkdir10(paths2.logsDir, { recursive: true });
11307
+ await mkdir10(paths2.knowledgeDir, { recursive: true });
11308
+ await mkdir10(paths2.evosCasesDir, { recursive: true });
11309
+ await mkdir10(paths2.roleAgentsDir, { recursive: true });
11310
+ await mkdir10(paths2.teamsDir, { recursive: true });
11311
+ await mkdir10(paths2.runsDir, { recursive: true });
11031
11312
  },
11032
11313
  async ensureKnowledgeBase() {
11033
11314
  await ensureKnowledgeBaseFiles(paths2);
@@ -11075,8 +11356,8 @@ async function initializeCoreConfig(homeDir) {
11075
11356
  return store;
11076
11357
  }
11077
11358
  async function ensureKnowledgeBaseFiles(paths2) {
11078
- await mkdir9(paths2.knowledgeDir, { recursive: true });
11079
- await mkdir9(paths2.evosCasesDir, { recursive: true });
11359
+ await mkdir10(paths2.knowledgeDir, { recursive: true });
11360
+ await mkdir10(paths2.evosCasesDir, { recursive: true });
11080
11361
  await ensureOkfKnowledgeBase(paths2.homeDir);
11081
11362
  await writeTextIfMissing2(`${paths2.knowledgeDir}/README.md`, [
11082
11363
  "# EvoDev Knowledge",
@@ -11205,7 +11486,7 @@ async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
11205
11486
  } catch (error) {
11206
11487
  throw new EvoDevConfigError(`Invalid bootstrap index JSON (${describeFileError2(error)})`, filePath);
11207
11488
  }
11208
- if (!isRecord9(existing) || existing.kind !== kind)
11489
+ if (!isRecord10(existing) || existing.kind !== kind)
11209
11490
  return;
11210
11491
  const migrated = { ...defaults, ...existing };
11211
11492
  if (Object.keys(defaults).every((key) => (key in existing)))
@@ -11217,16 +11498,16 @@ async function writeTextIfMissing2(filePath, value) {
11217
11498
  await readFile13(filePath, "utf8");
11218
11499
  } catch (error) {
11219
11500
  if (isNodeError2(error) && error.code === "ENOENT") {
11220
- await mkdir9(dirname9(filePath), { recursive: true });
11221
- await writeFile8(filePath, value, "utf8");
11501
+ await mkdir10(dirname10(filePath), { recursive: true });
11502
+ await writeFile9(filePath, value, "utf8");
11222
11503
  return;
11223
11504
  }
11224
11505
  throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError2(error)})`, filePath);
11225
11506
  }
11226
11507
  }
11227
11508
  async function writeJsonFile3(filePath, value) {
11228
- await mkdir9(dirname9(filePath), { recursive: true });
11229
- await writeFile8(filePath, `${JSON.stringify(value, null, 2)}
11509
+ await mkdir10(dirname10(filePath), { recursive: true });
11510
+ await writeFile9(filePath, `${JSON.stringify(value, null, 2)}
11230
11511
  `, "utf8");
11231
11512
  }
11232
11513
  function describeFileError2(error) {
@@ -11238,14 +11519,14 @@ function describeFileError2(error) {
11238
11519
  function isNodeError2(error) {
11239
11520
  return error instanceof Error && "code" in error;
11240
11521
  }
11241
- function isRecord9(value) {
11522
+ function isRecord10(value) {
11242
11523
  return typeof value === "object" && value !== null && !Array.isArray(value);
11243
11524
  }
11244
11525
  // packages/core/src/daemon/index.ts
11245
11526
  import { randomBytes } from "node:crypto";
11246
- import { mkdir as mkdir12, readFile as readFile16, readdir as readdir10, rm as rm3, stat as stat9, writeFile as writeFile11 } from "node:fs/promises";
11527
+ import { mkdir as mkdir13, readFile as readFile16, readdir as readdir11, rm as rm4, stat as stat9, writeFile as writeFile12 } from "node:fs/promises";
11247
11528
  import { createServer } from "node:http";
11248
- import { dirname as dirname12, join as join18 } from "node:path";
11529
+ import { dirname as dirname13, join as join19 } from "node:path";
11249
11530
 
11250
11531
  // packages/core/src/evolution/control/index.ts
11251
11532
  var exports_control = {};
@@ -11386,6 +11667,7 @@ function formatEvolutionReviewSnapshot(snapshot) {
11386
11667
  // packages/core/src/evolution/processor/index.ts
11387
11668
  var exports_processor = {};
11388
11669
  __export(exports_processor, {
11670
+ writeEvolutionRepoProposal: () => writeEvolutionRepoProposal,
11389
11671
  writeEvolutionDistillationBatch: () => writeEvolutionDistillationBatch,
11390
11672
  processEvolutionTriggers: () => processEvolutionTriggers,
11391
11673
  createEvolutionDistillationBatch: () => createEvolutionDistillationBatch,
@@ -11394,8 +11676,8 @@ __export(exports_processor, {
11394
11676
  });
11395
11677
 
11396
11678
  // packages/core/src/evolution/evidence/analysis.ts
11397
- import { readFile as readFile14, readdir as readdir8 } from "node:fs/promises";
11398
- import { basename as basename3, join as join14 } from "node:path";
11679
+ import { readFile as readFile14, readdir as readdir9 } from "node:fs/promises";
11680
+ import { basename as basename3, join as join15 } from "node:path";
11399
11681
  async function analyzeEvolutionRun(input) {
11400
11682
  const projectKey = resolveEvolutionProjectKey(input);
11401
11683
  const runId = sanitizeId(input.runId);
@@ -11405,17 +11687,17 @@ async function analyzeEvolutionRun(input) {
11405
11687
  const linkedTraceRefIds = new Set;
11406
11688
  const events = [];
11407
11689
  const logsDir = resolveEvoDevPaths(input.homeDir).logsDir;
11408
- const projectRunAgentsDir = join14(logsDir, "teams", projectKey, runId, "agents");
11409
- const legacyProjectRunAgentsDir = join14(logsDir, projectKey, runId, "agents");
11410
- const agentDirs = await pathExists(projectRunAgentsDir) ? await readdir8(projectRunAgentsDir, { withFileTypes: true }) : [];
11411
- const legacyAgentDirs = await pathExists(legacyProjectRunAgentsDir) ? await readdir8(legacyProjectRunAgentsDir, { withFileTypes: true }) : [];
11690
+ const projectRunAgentsDir = join15(logsDir, "teams", projectKey, runId, "agents");
11691
+ const legacyProjectRunAgentsDir = join15(logsDir, projectKey, runId, "agents");
11692
+ const agentDirs = await pathExists(projectRunAgentsDir) ? await readdir9(projectRunAgentsDir, { withFileTypes: true }) : [];
11693
+ const legacyAgentDirs = await pathExists(legacyProjectRunAgentsDir) ? await readdir9(legacyProjectRunAgentsDir, { withFileTypes: true }) : [];
11412
11694
  if (agentDirs.length === 0 && legacyAgentDirs.length === 0) {
11413
11695
  warnings.push(`No agent execution event directory found: ${displayPath(input.homeDir, projectRunAgentsDir)}`);
11414
11696
  } else {
11415
11697
  const rolesWithExecutionEvents = new Set;
11416
11698
  for (const roleDir of agentDirs.filter((entry) => entry.isDirectory())) {
11417
11699
  const roleId = sanitizeId(roleDir.name);
11418
- const eventsPath = join14(projectRunAgentsDir, roleDir.name, "events.jsonl");
11700
+ const eventsPath = join15(projectRunAgentsDir, roleDir.name, "events.jsonl");
11419
11701
  if (!await pathExists(eventsPath))
11420
11702
  continue;
11421
11703
  rolesWithExecutionEvents.add(roleId);
@@ -11443,7 +11725,7 @@ async function analyzeEvolutionRun(input) {
11443
11725
  const roleId = sanitizeId(roleDir.name);
11444
11726
  if (rolesWithExecutionEvents.has(roleId))
11445
11727
  continue;
11446
- const tracePath = join14(legacyProjectRunAgentsDir, roleDir.name, "trace.log");
11728
+ const tracePath = join15(legacyProjectRunAgentsDir, roleDir.name, "trace.log");
11447
11729
  if (!await pathExists(tracePath))
11448
11730
  continue;
11449
11731
  const sourceRef = {
@@ -11807,7 +12089,7 @@ function resolveEvolutionProjectKey(input) {
11807
12089
  throw new Error("Missing project scope: pass --project <projectKey> or --project-dir <path>.");
11808
12090
  }
11809
12091
  // packages/core/src/evolution/processor/distillation.ts
11810
- import { join as join15 } from "node:path";
12092
+ import { join as join16 } from "node:path";
11811
12093
  function createEvolutionDistillationBatch(input) {
11812
12094
  validateEvolutionEvidenceWindow(input.evidenceWindow);
11813
12095
  const createdAt = normalizeTimestamp(input.now);
@@ -11839,7 +12121,7 @@ function createEvolutionDistillationBatch(input) {
11839
12121
  relations: {
11840
12122
  relatedKnowledgeIds: [],
11841
12123
  evosCaseIds: [createStableId("evo", [input.evidenceWindow.id, "case"])],
11842
- proposalIds: failedSignals.length === 0 ? [] : [createStableId("proposal", [input.evidenceWindow.id, "engineering-practice"])],
12124
+ proposalIds: [],
11843
12125
  supersedes: []
11844
12126
  },
11845
12127
  privacy: createPrivacyFields(),
@@ -11876,29 +12158,7 @@ function createEvolutionDistillationBatch(input) {
11876
12158
  privacy: createPrivacyFields()
11877
12159
  })
11878
12160
  ];
11879
- const repoProposals = failedSignals.length === 0 ? [] : [
11880
- createEvolutionRepoProposal({
11881
- id: createStableId("proposal", [input.evidenceWindow.id, "engineering-practice"]),
11882
- kind: "engineering-practice",
11883
- projectKey: input.evidenceWindow.projectKey,
11884
- title: `Review repeated failure signals for ${input.evidenceWindow.runId}`,
11885
- summary: "Failure or issue signals appeared in redacted run evidence; review whether repository rules, tests, skills, or role agents need improvement.",
11886
- rationale: "EvoDev stores this as a proposal only. It must not modify the user repository until an explicit apply command is implemented and invoked.",
11887
- roleTags: roleIds,
11888
- tags: ["proposal", "failure-signal"],
11889
- reviewState: "pending",
11890
- confidence: "low",
11891
- targetRepoPath: null,
11892
- plannedFiles: [],
11893
- apply: {
11894
- autoApply: false,
11895
- requiresExplicitCommand: true,
11896
- rollbackPlan: "No repository files are changed by this proposal."
11897
- },
11898
- provenance: createProvenance(input.evidenceWindow, createdAt, sourceRefs),
11899
- privacy: createPrivacyFields()
11900
- })
11901
- ];
12161
+ const repoProposals = [];
11902
12162
  const batch = {
11903
12163
  schemaVersion: 1,
11904
12164
  id: createStableId("batch", [input.evidenceWindow.id, createdAt]),
@@ -11926,19 +12186,19 @@ async function writeEvolutionDistillationBatch(input) {
11926
12186
  await writeJsonFile(paths2.batchPath, input.batch, { overwrite });
11927
12187
  const knowledgePaths = [];
11928
12188
  for (const record of input.batch.knowledgeRecords) {
11929
- const path = join15(paths2.knowledgeRecordsDir, `${record.id}.json`);
12189
+ const path = join16(paths2.knowledgeRecordsDir, `${record.id}.json`);
11930
12190
  await writeJsonFile(path, record, { overwrite });
11931
12191
  knowledgePaths.push(path);
11932
12192
  }
11933
12193
  const evosCasePaths = [];
11934
12194
  for (const evosCase of input.batch.evosCases) {
11935
- const path = join15(paths2.evosCasesProjectDir, `${evosCase.id}.json`);
12195
+ const path = join16(paths2.evosCasesProjectDir, `${evosCase.id}.json`);
11936
12196
  await writeJsonFile(path, evosCase, { overwrite });
11937
12197
  evosCasePaths.push(path);
11938
12198
  }
11939
12199
  const repoProposalPaths = [];
11940
12200
  for (const proposal of input.batch.repoProposals) {
11941
- const path = join15(paths2.repoProposalsDir, `${proposal.id}.json`);
12201
+ const path = join16(paths2.repoProposalsDir, `${proposal.id}.json`);
11942
12202
  await writeJsonFile(path, proposal, { overwrite });
11943
12203
  repoProposalPaths.push(path);
11944
12204
  }
@@ -11958,7 +12218,7 @@ async function writeEvolutionDistillationBatch(input) {
11958
12218
  const evosCasesRootDir = resolveEvoDevPaths(input.homeDir).evosCasesDir;
11959
12219
  const evosProjectKeys = await listDirectoryNames(evosCasesRootDir);
11960
12220
  const evosProjects = await Promise.all(evosProjectKeys.map(async (projectKey) => {
11961
- const cases = await readJsonFiles(join15(evosCasesRootDir, projectKey), parseEvosCase);
12221
+ const cases = await readJsonFiles(join16(evosCasesRootDir, projectKey), parseEvosCase);
11962
12222
  return {
11963
12223
  projectKey,
11964
12224
  cases: cases.map((evosCase) => ({
@@ -11996,6 +12256,33 @@ async function writeEvolutionDistillationBatch(input) {
11996
12256
  evosIndexPath: paths2.evosIndexPath
11997
12257
  };
11998
12258
  }
12259
+ async function writeEvolutionRepoProposal(input) {
12260
+ validateEvolutionRepoProposal(input.proposal);
12261
+ if (!hasConcreteRepoProposalChanges(input.proposal)) {
12262
+ throw new Error("Repo proposal must include a target repository and concrete file changes.");
12263
+ }
12264
+ const paths2 = resolveEvolutionPaths({
12265
+ homeDir: input.homeDir,
12266
+ projectKey: input.proposal.projectKey,
12267
+ runId: input.proposal.provenance.runId
12268
+ });
12269
+ const proposalPath = join16(paths2.repoProposalsDir, `${input.proposal.id}.json`);
12270
+ await writeJsonFile(proposalPath, input.proposal, { overwrite: false });
12271
+ const allRunProposals = await readJsonFiles(paths2.repoProposalsDir, parseRepoProposal);
12272
+ await writeJsonFile(paths2.repoProposalsIndexPath, {
12273
+ schemaVersion: 1,
12274
+ projectKey: input.proposal.projectKey,
12275
+ runId: input.proposal.provenance.runId,
12276
+ updatedAt: input.proposal.provenance.createdAt,
12277
+ proposals: allRunProposals.map((proposal) => ({
12278
+ id: proposal.id,
12279
+ kind: proposal.kind,
12280
+ title: proposal.title,
12281
+ reviewState: proposal.reviewState
12282
+ }))
12283
+ }, { overwrite: true });
12284
+ return { proposalPath, indexPath: paths2.repoProposalsIndexPath };
12285
+ }
11999
12286
  async function activateEvolutionDistillationBatch(input) {
12000
12287
  validateEvolutionDistillationBatch(input.batch);
12001
12288
  const paths2 = resolveEvolutionPaths({
@@ -12020,20 +12307,20 @@ async function activateEvolutionDistillationBatch(input) {
12020
12307
  const matchingCandidate = plan.candidates.find((candidate) => candidate.id === evosCase.id);
12021
12308
  const persistedEvosCase = matchingCandidate?.decision === "auto-accept" ? { ...evosCase, reviewState: "auto-accepted" } : matchingCandidate?.decision === "needs-human" ? { ...evosCase, reviewState: "needs-human" } : evosCase;
12022
12309
  validateEvolutionEvosCase(persistedEvosCase);
12023
- const path = join15(paths2.evosCasesProjectDir, `${evosCase.id}.json`);
12310
+ const path = join16(paths2.evosCasesProjectDir, `${evosCase.id}.json`);
12024
12311
  await writeJsonFile(path, persistedEvosCase, { overwrite });
12025
12312
  evosCasePaths.push(path);
12026
12313
  }
12027
12314
  const repoProposalPaths = [];
12028
12315
  for (const proposal of input.batch.repoProposals) {
12029
- const path = join15(paths2.repoProposalsDir, `${proposal.id}.json`);
12316
+ const path = join16(paths2.repoProposalsDir, `${proposal.id}.json`);
12030
12317
  await writeJsonFile(path, proposal, { overwrite });
12031
12318
  repoProposalPaths.push(path);
12032
12319
  }
12033
12320
  const evosCasesRootDir = resolveEvoDevPaths(input.homeDir).evosCasesDir;
12034
12321
  const evosProjectKeys = await listDirectoryNames(evosCasesRootDir);
12035
12322
  const evosProjects = await Promise.all(evosProjectKeys.map(async (projectKey) => {
12036
- const cases = await readJsonFiles(join15(evosCasesRootDir, projectKey), parseEvosCase);
12323
+ const cases = await readJsonFiles(join16(evosCasesRootDir, projectKey), parseEvosCase);
12037
12324
  return {
12038
12325
  projectKey,
12039
12326
  cases: cases.map((evosCase) => ({
@@ -12089,8 +12376,8 @@ function createProvenance(evidenceWindow, createdAt, sourceRefs) {
12089
12376
  };
12090
12377
  }
12091
12378
  // packages/core/src/evolution/processor/process.ts
12092
- import { mkdir as mkdir10, rm as rm2, stat as stat7, writeFile as writeFile9 } from "node:fs/promises";
12093
- import { dirname as dirname10, join as join16 } from "node:path";
12379
+ import { mkdir as mkdir11, rm as rm3, stat as stat7, writeFile as writeFile10 } from "node:fs/promises";
12380
+ import { dirname as dirname11, join as join17 } from "node:path";
12094
12381
  var PROCESS_LOCK_STALE_MS2 = 5 * 60 * 1000;
12095
12382
  async function processEvolutionTriggers(input) {
12096
12383
  const now = normalizeTimestamp(input.now);
@@ -12153,16 +12440,11 @@ async function processEvolutionTriggers(input) {
12153
12440
  attempts: (current) => current.attempts + 1
12154
12441
  });
12155
12442
  try {
12156
- await writeSegmentReviewCandidate({
12157
- homeDir: input.homeDir,
12158
- trigger,
12159
- now
12160
- });
12161
12443
  result.consumed += 1;
12162
12444
  await updateSegmentTriggers(input.homeDir, [trigger], {
12163
12445
  status: "consumed",
12164
12446
  updatedAt: now,
12165
- processedBatchId: createStableId("segment-review", [trigger.id]),
12447
+ processedBatchId: createStableId("segment-evidence", [trigger.id]),
12166
12448
  lastError: null
12167
12449
  });
12168
12450
  } catch (error) {
@@ -12254,10 +12536,10 @@ async function processEvolutionTriggers(input) {
12254
12536
  }
12255
12537
  async function acquireEvolutionProcessLock(homeDir, now) {
12256
12538
  const paths2 = resolveEvoDevPaths(homeDir);
12257
- const lockPath = join16(paths2.stateDir, "evolution", ".process.lock");
12258
- await mkdir10(dirname10(lockPath), { recursive: true });
12539
+ const lockPath = join17(paths2.stateDir, "evolution", ".process.lock");
12540
+ await mkdir11(dirname11(lockPath), { recursive: true });
12259
12541
  try {
12260
- await writeFile9(lockPath, `${JSON.stringify({
12542
+ await writeFile10(lockPath, `${JSON.stringify({
12261
12543
  schemaVersion: 1,
12262
12544
  kind: "evolution-process-lock",
12263
12545
  createdAt: now,
@@ -12270,70 +12552,18 @@ async function acquireEvolutionProcessLock(homeDir, now) {
12270
12552
  throw error;
12271
12553
  const current = await stat7(lockPath).catch(() => null);
12272
12554
  if (current !== null && Date.now() - current.mtimeMs > PROCESS_LOCK_STALE_MS2) {
12273
- await rm2(lockPath, { force: true });
12555
+ await rm3(lockPath, { force: true });
12274
12556
  return acquireEvolutionProcessLock(homeDir, now);
12275
12557
  }
12276
12558
  return null;
12277
12559
  }
12278
12560
  }
12279
12561
  async function releaseEvolutionProcessLock(lock) {
12280
- await rm2(lock.path, { force: true });
12281
- }
12282
- async function writeSegmentReviewCandidate(input) {
12283
- const runId = input.trigger.runId ?? `session-${input.trigger.sessionKey}`;
12284
- const paths2 = resolveEvolutionPaths({
12285
- homeDir: input.homeDir,
12286
- projectKey: input.trigger.projectKey,
12287
- runId
12288
- });
12289
- const candidate = {
12290
- schemaVersion: 1,
12291
- kind: "evolution-review-candidate",
12292
- id: createStableId("review", [input.trigger.id]),
12293
- projectKey: input.trigger.projectKey,
12294
- runId: paths2.runId,
12295
- createdAt: input.now,
12296
- candidateKind: "session-memory-segment",
12297
- title: sanitizeText(`Review session segment ${input.trigger.reason}`),
12298
- targetStore: "session-memory-segments",
12299
- targetPath: input.trigger.segmentPath,
12300
- stableKey: createStableId("segment-candidate", [
12301
- input.trigger.projectKey,
12302
- input.trigger.sessionKey,
12303
- input.trigger.segmentId
12304
- ]),
12305
- reviewState: "needs-human",
12306
- reasons: [input.trigger.reason, input.trigger.strength],
12307
- candidate: {
12308
- segmentId: input.trigger.segmentId,
12309
- sessionKey: input.trigger.sessionKey,
12310
- roleId: input.trigger.roleId,
12311
- summary: input.trigger.summary,
12312
- reviewAction: "Open the referenced local session segment for raw evidence before approving memory or OKF changes.",
12313
- directOkfWrite: false,
12314
- localOnly: true
12315
- },
12316
- provenance: {
12317
- runId: paths2.runId,
12318
- evidenceWindowId: input.trigger.segmentId,
12319
- evidenceRefs: [input.trigger.id, input.trigger.segmentId],
12320
- createdBy: "evodev",
12321
- rawLogsStored: false,
12322
- rawPromptsStored: false,
12323
- sourceDumpsStored: false,
12324
- rawCommandOutputStored: false
12325
- },
12326
- privacy: createPrivacyFields()
12327
- };
12328
- validateEvolutionReviewCandidate(candidate);
12329
- await writeJsonFile(join16(paths2.reviewCandidatesDir, `${candidate.id}.json`), candidate, {
12330
- overwrite: true
12331
- });
12332
- return candidate;
12562
+ await rm3(lock.path, { force: true });
12333
12563
  }
12334
12564
  // packages/core/src/observability/index.ts
12335
- import { mkdir as mkdir11, readFile as readFile15, readdir as readdir9, stat as stat8, writeFile as writeFile10 } from "node:fs/promises";
12336
- import { dirname as dirname11, join as join17 } from "node:path";
12565
+ import { mkdir as mkdir12, readFile as readFile15, readdir as readdir10, stat as stat8, writeFile as writeFile11 } from "node:fs/promises";
12566
+ import { dirname as dirname12, join as join18 } from "node:path";
12337
12567
  var EVENT_TYPE_TO_DIR = {
12338
12568
  "verification.completed": "verification",
12339
12569
  "workflow.step.planned": "workflows",
@@ -12395,14 +12625,14 @@ function validateObservabilityEvent(event) {
12395
12625
  assertNoForbiddenContent(event);
12396
12626
  }
12397
12627
  function resolveObservabilityStorePaths(homeDir, type) {
12398
- const rootDir = join17(homeDir, ".evodev", "OBSERVABILITY", EVENT_TYPE_TO_DIR[type]);
12399
- return { rootDir, eventsPath: join17(rootDir, "events.jsonl") };
12628
+ const rootDir = join18(homeDir, ".evodev", "OBSERVABILITY", EVENT_TYPE_TO_DIR[type]);
12629
+ return { rootDir, eventsPath: join18(rootDir, "events.jsonl") };
12400
12630
  }
12401
12631
  async function appendObservabilityEvent(homeDir, event) {
12402
12632
  validateObservabilityEvent(event);
12403
12633
  const paths2 = resolveObservabilityStorePaths(homeDir, event.type);
12404
- await mkdir11(dirname11(paths2.eventsPath), { recursive: true });
12405
- await writeFile10(paths2.eventsPath, `${JSON.stringify(event)}
12634
+ await mkdir12(dirname12(paths2.eventsPath), { recursive: true });
12635
+ await writeFile11(paths2.eventsPath, `${JSON.stringify(event)}
12406
12636
  `, { encoding: "utf8", flag: "a" });
12407
12637
  return paths2.eventsPath;
12408
12638
  }
@@ -12424,7 +12654,7 @@ async function listObservabilityEvents(homeDir, type) {
12424
12654
  return events.sort((left, right) => left.timestamp.localeCompare(right.timestamp));
12425
12655
  }
12426
12656
  async function dryRunObservabilityRetentionCleanup(homeDir) {
12427
- const root = join17(homeDir, ".evodev", "OBSERVABILITY");
12657
+ const root = join18(homeDir, ".evodev", "OBSERVABILITY");
12428
12658
  const candidates = [];
12429
12659
  if (!await pathExists6(root))
12430
12660
  return { candidates, totalBytes: 0 };
@@ -12495,10 +12725,10 @@ function assertNoForbiddenContent(value) {
12495
12725
  }
12496
12726
  }
12497
12727
  async function collectJsonlFiles(root) {
12498
- const entries = await readdir9(root, { withFileTypes: true });
12728
+ const entries = await readdir10(root, { withFileTypes: true });
12499
12729
  const files = [];
12500
12730
  for (const entry of entries) {
12501
- const path = join17(root, entry.name);
12731
+ const path = join18(root, entry.name);
12502
12732
  if (entry.isDirectory())
12503
12733
  files.push(...await collectJsonlFiles(path));
12504
12734
  if (entry.isFile() && entry.name.endsWith(".jsonl"))
@@ -12530,8 +12760,8 @@ function normalizeKey(key) {
12530
12760
  var DEFAULT_PORT = 37645;
12531
12761
  var SENSITIVE_TEXT_PATTERN6 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|raw log|raw output|raw source|raw prompt|transcript|stdout|stderr)\b/i;
12532
12762
  function resolveDaemonPaths(homeDir) {
12533
- const rootDir = join18(homeDir, ".evodev", "STATE", "daemon");
12534
- return { rootDir, lockPath: join18(rootDir, "lock.json"), tokenPath: join18(rootDir, "token") };
12763
+ const rootDir = join19(homeDir, ".evodev", "STATE", "daemon");
12764
+ return { rootDir, lockPath: join19(rootDir, "lock.json"), tokenPath: join19(rootDir, "token") };
12535
12765
  }
12536
12766
  function validateDaemonBindHost(host) {
12537
12767
  if (host === "127.0.0.1" || host === "localhost")
@@ -12571,14 +12801,14 @@ async function writeDaemonState(input) {
12571
12801
  tokenPath: plan.paths.tokenPath,
12572
12802
  versionText: input.versionText ?? "evodev 0.0.1-alpha"
12573
12803
  };
12574
- await mkdir12(dirname12(plan.paths.lockPath), { recursive: true });
12575
- await writeFile11(plan.paths.tokenPath, `${token}
12804
+ await mkdir13(dirname13(plan.paths.lockPath), { recursive: true });
12805
+ await writeFile12(plan.paths.tokenPath, `${token}
12576
12806
  `, {
12577
12807
  encoding: "utf8",
12578
12808
  flag: "wx",
12579
12809
  mode: 384
12580
12810
  });
12581
- await writeFile11(plan.paths.lockPath, `${JSON.stringify(lock, null, 2)}
12811
+ await writeFile12(plan.paths.lockPath, `${JSON.stringify(lock, null, 2)}
12582
12812
  `, {
12583
12813
  encoding: "utf8",
12584
12814
  flag: "wx",
@@ -12609,8 +12839,8 @@ async function cleanupDaemonState(homeDir, token) {
12609
12839
  const lock = await readDaemonLock(homeDir);
12610
12840
  if (lock === null || lock.component !== "evodev-daemon")
12611
12841
  throw new Error("Missing valid daemon lock.");
12612
- await rm3(paths2.lockPath, { force: true });
12613
- await rm3(paths2.tokenPath, { force: true });
12842
+ await rm4(paths2.lockPath, { force: true });
12843
+ await rm4(paths2.tokenPath, { force: true });
12614
12844
  return [paths2.lockPath, paths2.tokenPath];
12615
12845
  }
12616
12846
  async function handleDaemonRequest(input) {
@@ -12668,9 +12898,9 @@ async function handleDaemonRequest(input) {
12668
12898
  if (input.path === "/memory/candidates")
12669
12899
  return ok(await collectLearningCandidateSummaries(input.homeDir, warnings), warnings);
12670
12900
  if (input.path === "/projects")
12671
- return ok(await collectDirectorySummaries(join18(input.homeDir, ".evodev", "PROJECTS"), warnings), warnings);
12901
+ return ok(await collectDirectorySummaries(join19(input.homeDir, ".evodev", "PROJECTS"), warnings), warnings);
12672
12902
  if (input.path === "/packs")
12673
- return ok(await collectDirectorySummaries(join18(input.homeDir, ".evodev", "PACKS"), warnings), warnings);
12903
+ return ok(await collectDirectorySummaries(join19(input.homeDir, ".evodev", "PACKS"), warnings), warnings);
12674
12904
  if (input.path === "/runs")
12675
12905
  return ok(await collectTeamRuns(input.homeDir, warnings), warnings);
12676
12906
  if (input.path === "/evolution/triggers")
@@ -12788,7 +13018,7 @@ function isAllowedLocalOrigin(origin) {
12788
13018
  }
12789
13019
  }
12790
13020
  async function collectTaskSummaries(homeDir, warnings) {
12791
- const root = join18(homeDir, ".evodev", "STATE", "tasks");
13021
+ const root = join19(homeDir, ".evodev", "STATE", "tasks");
12792
13022
  if (!await pathExists7(root)) {
12793
13023
  warnings.push("Task store not found; returning empty tasks.");
12794
13024
  return [];
@@ -12826,7 +13056,7 @@ async function collectObservabilitySummaries(homeDir, warnings) {
12826
13056
  }
12827
13057
  }
12828
13058
  async function collectLearningCandidateSummaries(homeDir, warnings) {
12829
- const path = join18(homeDir, ".evodev", "STATE", "learning", "candidates.jsonl");
13059
+ const path = join19(homeDir, ".evodev", "STATE", "learning", "candidates.jsonl");
12830
13060
  if (!await pathExists7(path)) {
12831
13061
  warnings.push("Learning candidate store not found; returning empty candidates.");
12832
13062
  return [];
@@ -13063,7 +13293,7 @@ async function collectDirectorySummaries(root, warnings) {
13063
13293
  warnings.push(`Store not found: ${root}`);
13064
13294
  return [];
13065
13295
  }
13066
- const entries = await readdir10(root, { withFileTypes: true });
13296
+ const entries = await readdir11(root, { withFileTypes: true });
13067
13297
  return entries.filter((entry) => entry.isDirectory()).map((entry) => ({ id: entry.name, metadataOnly: true }));
13068
13298
  }
13069
13299
  function sanitizeMetadata(value) {
@@ -13114,13 +13344,13 @@ function optionalBodyBoolean(value) {
13114
13344
  return typeof value === "boolean" ? value : undefined;
13115
13345
  }
13116
13346
  function resolveDaemonEvolutionProcessErrorPath(homeDir) {
13117
- return join18(resolveDaemonPaths(homeDir).rootDir, "evolution-process-error.json");
13347
+ return join19(resolveDaemonPaths(homeDir).rootDir, "evolution-process-error.json");
13118
13348
  }
13119
13349
  async function recordDaemonEvolutionProcessError(homeDir, error) {
13120
13350
  try {
13121
13351
  const path = resolveDaemonEvolutionProcessErrorPath(homeDir);
13122
- await mkdir12(dirname12(path), { recursive: true });
13123
- await writeFile11(path, `${JSON.stringify({
13352
+ await mkdir13(dirname13(path), { recursive: true });
13353
+ await writeFile12(path, `${JSON.stringify({
13124
13354
  schemaVersion: 1,
13125
13355
  kind: "daemon-evolution-process-error",
13126
13356
  updatedAt: new Date().toISOString(),
@@ -13130,7 +13360,7 @@ async function recordDaemonEvolutionProcessError(homeDir, error) {
13130
13360
  } catch {}
13131
13361
  }
13132
13362
  async function clearDaemonEvolutionProcessError(homeDir) {
13133
- await rm3(resolveDaemonEvolutionProcessErrorPath(homeDir), { force: true }).catch(() => {
13363
+ await rm4(resolveDaemonEvolutionProcessErrorPath(homeDir), { force: true }).catch(() => {
13134
13364
  return;
13135
13365
  });
13136
13366
  }
@@ -13145,10 +13375,10 @@ function describeError3(error) {
13145
13375
  return error instanceof Error ? error.message : String(error);
13146
13376
  }
13147
13377
  async function collectNamedFiles(root, name) {
13148
- const entries = await readdir10(root, { withFileTypes: true });
13378
+ const entries = await readdir11(root, { withFileTypes: true });
13149
13379
  const files = [];
13150
13380
  for (const entry of entries) {
13151
- const path = join18(root, entry.name);
13381
+ const path = join19(root, entry.name);
13152
13382
  if (entry.isDirectory())
13153
13383
  files.push(...await collectNamedFiles(path, name));
13154
13384
  else if (entry.isFile() && entry.name === name)
@@ -13202,8 +13432,8 @@ __export(exports_review, {
13202
13432
  appendLearningReviewDecision: () => appendLearningReviewDecision,
13203
13433
  appendLearningCandidate: () => appendLearningCandidate
13204
13434
  });
13205
- import { mkdir as mkdir13, readFile as readFile17, stat as stat10, writeFile as writeFile12 } from "node:fs/promises";
13206
- import { dirname as dirname13, join as join19 } from "node:path";
13435
+ import { mkdir as mkdir14, readFile as readFile17, stat as stat10, writeFile as writeFile13 } from "node:fs/promises";
13436
+ import { dirname as dirname14, join as join20 } from "node:path";
13207
13437
  var LEARNING_CANDIDATE_KINDS = [
13208
13438
  "lesson",
13209
13439
  "anti-criteria",
@@ -13300,7 +13530,7 @@ function createLearningCandidate(input) {
13300
13530
  return candidate;
13301
13531
  }
13302
13532
  function validateLearningCandidate(candidate) {
13303
- if (!isRecord10(candidate))
13533
+ if (!isRecord11(candidate))
13304
13534
  throw new Error("Learning candidate must be an object.");
13305
13535
  if (candidate.version !== 1)
13306
13536
  throw new Error("Learning candidate version must be 1.");
@@ -13312,33 +13542,33 @@ function validateLearningCandidate(candidate) {
13312
13542
  if (candidate.routingInfluence !== false) {
13313
13543
  throw new Error("Learning candidate routingInfluence must be false in I5.");
13314
13544
  }
13315
- if (!isRecord10(candidate.scope))
13545
+ if (!isRecord11(candidate.scope))
13316
13546
  throw new Error("Learning candidate scope must be an object.");
13317
13547
  assertEnumValue("scope.level", candidate.scope.level, LEARNING_SCOPE_LEVELS);
13318
- if (!isRecord10(candidate.content)) {
13548
+ if (!isRecord11(candidate.content)) {
13319
13549
  throw new Error("Learning candidate content must be an object.");
13320
13550
  }
13321
13551
  assertStringField("content.summary", candidate.content.summary);
13322
13552
  assertStringField("content.howToApply", candidate.content.howToApply);
13323
13553
  assertStringArrayField("content.antiCriteriaImpact", candidate.content.antiCriteriaImpact);
13324
- if (!isRecord10(candidate.provenance)) {
13554
+ if (!isRecord11(candidate.provenance)) {
13325
13555
  throw new Error("Learning candidate provenance must be an object.");
13326
13556
  }
13327
13557
  assertEnumValue("provenance.sourceType", candidate.provenance.sourceType, LEARNING_SOURCE_TYPES);
13328
13558
  assertEnumValue("provenance.createdBy", candidate.provenance.createdBy, LEARNING_CREATED_BY_VALUES);
13329
13559
  assertStringField("provenance.createdAt", candidate.provenance.createdAt);
13330
13560
  assertStringArrayField("provenance.evidenceRefs", candidate.provenance.evidenceRefs);
13331
- if (!isRecord10(candidate.privacy)) {
13561
+ if (!isRecord11(candidate.privacy)) {
13332
13562
  throw new Error("Learning candidate privacy must be an object.");
13333
13563
  }
13334
13564
  assertEnumValue("privacy.classification", candidate.privacy.classification, ["local-private"]);
13335
- if (!isRecord10(candidate.review))
13565
+ if (!isRecord11(candidate.review))
13336
13566
  throw new Error("Learning candidate review must be an object.");
13337
13567
  assertEnumValue("review.decision", candidate.review.decision, LEARNING_REVIEW_DECISIONS);
13338
13568
  if (candidate.review.decision !== "pending") {
13339
13569
  throw new Error("Learning candidate review decision must be pending.");
13340
13570
  }
13341
- if (!isRecord10(candidate.retention)) {
13571
+ if (!isRecord11(candidate.retention)) {
13342
13572
  throw new Error("Learning candidate retention must be an object.");
13343
13573
  }
13344
13574
  assertEnumValue("confidence", candidate.confidence, LEARNING_CONFIDENCE_VALUES);
@@ -13354,7 +13584,7 @@ function validateLearningCandidate(candidate) {
13354
13584
  assertNoForbiddenContent2(candidate);
13355
13585
  }
13356
13586
  function validateLearningReviewDecisionRecord(record) {
13357
- if (!isRecord10(record))
13587
+ if (!isRecord11(record))
13358
13588
  throw new Error("Learning review decision must be an object.");
13359
13589
  if (record.version !== 1)
13360
13590
  throw new Error("Learning review decision version must be 1.");
@@ -13377,13 +13607,13 @@ function validateLearningReviewDecisionRecord(record) {
13377
13607
  assertNoForbiddenContent2(record);
13378
13608
  }
13379
13609
  function parseLearningCandidate(value) {
13380
- if (!isRecord10(value))
13610
+ if (!isRecord11(value))
13381
13611
  throw new Error("Invalid learning candidate JSON.");
13382
13612
  validateLearningCandidate(value);
13383
13613
  return value;
13384
13614
  }
13385
13615
  function parseLearningReviewDecisionRecord(value) {
13386
- if (!isRecord10(value))
13616
+ if (!isRecord11(value))
13387
13617
  throw new Error("Invalid learning review decision JSON.");
13388
13618
  validateLearningReviewDecisionRecord(value);
13389
13619
  return value;
@@ -13395,16 +13625,16 @@ async function readLearningReviewDecisions(path) {
13395
13625
  return parseJsonOrJsonlFile(path, parseLearningReviewDecisionRecord);
13396
13626
  }
13397
13627
  function resolveLearningCandidateQueuePath(homeDir) {
13398
- return join19(homeDir, ".evodev", "STATE", "learning", "candidates.jsonl");
13628
+ return join20(homeDir, ".evodev", "STATE", "learning", "candidates.jsonl");
13399
13629
  }
13400
13630
  function resolveLearningDecisionPath(homeDir) {
13401
- return join19(homeDir, ".evodev", "STATE", "learning", "review-decisions.jsonl");
13631
+ return join20(homeDir, ".evodev", "STATE", "learning", "review-decisions.jsonl");
13402
13632
  }
13403
13633
  async function appendLearningCandidate(homeDir, candidate) {
13404
13634
  validateLearningCandidate(candidate);
13405
13635
  const path = resolveLearningCandidateQueuePath(homeDir);
13406
- await mkdir13(dirname13(path), { recursive: true });
13407
- await writeFile12(path, `${JSON.stringify(candidate)}
13636
+ await mkdir14(dirname14(path), { recursive: true });
13637
+ await writeFile13(path, `${JSON.stringify(candidate)}
13408
13638
  `, { encoding: "utf8", flag: "a" });
13409
13639
  return path;
13410
13640
  }
@@ -13476,7 +13706,7 @@ function lintLearningCandidates(candidates2, options = {}) {
13476
13706
  validateLearningReviewDecisionRecord(decision);
13477
13707
  } catch (error) {
13478
13708
  findings.push({
13479
- candidateId: isRecord10(decision) && typeof decision.candidateId === "string" ? decision.candidateId : "unknown",
13709
+ candidateId: isRecord11(decision) && typeof decision.candidateId === "string" ? decision.candidateId : "unknown",
13480
13710
  severity: "error",
13481
13711
  field: "decision",
13482
13712
  message: error instanceof Error ? error.message : String(error)
@@ -13563,8 +13793,8 @@ function createLearningReviewDecisionRecord(input) {
13563
13793
  async function appendLearningReviewDecision(homeDir, record) {
13564
13794
  validateLearningReviewDecisionRecord(record);
13565
13795
  const path = resolveLearningDecisionPath(homeDir);
13566
- await mkdir13(dirname13(path), { recursive: true });
13567
- await writeFile12(path, `${JSON.stringify(record)}
13796
+ await mkdir14(dirname14(path), { recursive: true });
13797
+ await writeFile13(path, `${JSON.stringify(record)}
13568
13798
  `, { encoding: "utf8", flag: "a" });
13569
13799
  return path;
13570
13800
  }
@@ -13674,7 +13904,7 @@ function assertNoForbiddenContent2(value) {
13674
13904
  assertNoForbiddenContent2(item);
13675
13905
  return;
13676
13906
  }
13677
- if (!isRecord10(value))
13907
+ if (!isRecord11(value))
13678
13908
  return;
13679
13909
  for (const [key, child] of Object.entries(value)) {
13680
13910
  const normalizedKey = normalizeKey2(key);
@@ -13700,12 +13930,12 @@ function sanitizeNullableId(value) {
13700
13930
  function normalizeKey2(key) {
13701
13931
  return key.toLowerCase().replace(/[^a-z0-9]/g, "");
13702
13932
  }
13703
- function isRecord10(value) {
13933
+ function isRecord11(value) {
13704
13934
  return typeof value === "object" && value !== null && !Array.isArray(value);
13705
13935
  }
13706
13936
  // packages/core/src/pack/index.ts
13707
- import { readFile as readFile18, readdir as readdir11, stat as stat11 } from "node:fs/promises";
13708
- import { isAbsolute as isAbsolute6, join as join20, relative as relative7, sep } from "node:path";
13937
+ import { readFile as readFile18, readdir as readdir12, stat as stat11 } from "node:fs/promises";
13938
+ import { isAbsolute as isAbsolute6, join as join21, relative as relative7, sep } from "node:path";
13709
13939
 
13710
13940
  // packages/core/src/protected-zones/index.ts
13711
13941
  var SENSITIVE_DIRECTORY_SEGMENTS = new Set([
@@ -13849,7 +14079,7 @@ async function validatePack(packPath) {
13849
14079
  throw new Error("Only local pack directories are supported in I6.");
13850
14080
  }
13851
14081
  const packRoot = await resolvePackRoot(packPath);
13852
- const manifestPath = join20(packRoot, MANIFEST_FILE_NAME);
14082
+ const manifestPath = join21(packRoot, MANIFEST_FILE_NAME);
13853
14083
  const findings = [];
13854
14084
  let manifest;
13855
14085
  let assets = [];
@@ -13940,7 +14170,7 @@ async function planPackInstallDryRun(input) {
13940
14170
  };
13941
14171
  }
13942
14172
  function parsePackManifest(value) {
13943
- if (!isRecord11(value))
14173
+ if (!isRecord12(value))
13944
14174
  throw new Error("Pack manifest must be an object.");
13945
14175
  const manifest = value;
13946
14176
  validateManifestTopLevelFields(manifest);
@@ -13995,7 +14225,7 @@ function parsePackManifest(value) {
13995
14225
  userPath: requireString(customizations, "userPath"),
13996
14226
  projectPath: requireString(customizations, "projectPath")
13997
14227
  },
13998
- protectedZones: isRecord11(manifest.protectedZones) ? {
14228
+ protectedZones: isRecord12(manifest.protectedZones) ? {
13999
14229
  neverInclude: optionalStringArray(manifest.protectedZones, "neverInclude"),
14000
14230
  neverWrite: optionalStringArray(manifest.protectedZones, "neverWrite")
14001
14231
  } : undefined,
@@ -14103,7 +14333,7 @@ function manifestAssetRefs(manifest, packRoot, findings) {
14103
14333
  findings.push({ ...pathFinding, path: assetPath });
14104
14334
  continue;
14105
14335
  }
14106
- refs.push({ kind, path: assetPath, absolutePath: join20(packRoot, assetPath) });
14336
+ refs.push({ kind, path: assetPath, absolutePath: join21(packRoot, assetPath) });
14107
14337
  }
14108
14338
  }
14109
14339
  return refs;
@@ -14185,10 +14415,10 @@ function validateGuideReferences(manifest, assets, findings) {
14185
14415
  }
14186
14416
  }
14187
14417
  async function collectPackRelativePaths(packRoot, dir = packRoot) {
14188
- const entries = await readdir11(dir, { withFileTypes: true });
14418
+ const entries = await readdir12(dir, { withFileTypes: true });
14189
14419
  const paths3 = [];
14190
14420
  for (const entry of entries) {
14191
- const absolutePath = join20(dir, entry.name);
14421
+ const absolutePath = join21(dir, entry.name);
14192
14422
  const relativePath = normalizeRelativePath(relative7(packRoot, absolutePath));
14193
14423
  paths3.push(relativePath);
14194
14424
  if (entry.isDirectory()) {
@@ -14219,7 +14449,7 @@ function validatePackRelativePath(path, packRoot) {
14219
14449
  message: "Path must not escape pack root."
14220
14450
  };
14221
14451
  }
14222
- const absolute = join20(packRoot, normalized);
14452
+ const absolute = join21(packRoot, normalized);
14223
14453
  const rel = relative7(packRoot, absolute);
14224
14454
  if (rel === "" || rel.startsWith("..") || isAbsolute6(rel)) {
14225
14455
  return {
@@ -14266,7 +14496,7 @@ function parseAssets(value) {
14266
14496
  function parsePermissions(value) {
14267
14497
  if (value === undefined)
14268
14498
  return {};
14269
- if (!isRecord11(value))
14499
+ if (!isRecord12(value))
14270
14500
  throw new Error("Pack manifest permissions must be an object.");
14271
14501
  const permissions = {};
14272
14502
  const knownKeys = new Set(Object.keys(RISKY_PERMISSION_LABELS));
@@ -14304,7 +14534,7 @@ function requireBoolean(record, key) {
14304
14534
  }
14305
14535
  function requireRecord(record, key) {
14306
14536
  const value = record[key];
14307
- if (!isRecord11(value))
14537
+ if (!isRecord12(value))
14308
14538
  throw new Error(`Pack manifest missing object field: ${key}`);
14309
14539
  return value;
14310
14540
  }
@@ -14360,7 +14590,7 @@ function validateCompatibilityTargets(packId, targets) {
14360
14590
  function validateProtectedZoneDeclarations(value) {
14361
14591
  if (value === undefined)
14362
14592
  return;
14363
- if (!isRecord11(value))
14593
+ if (!isRecord12(value))
14364
14594
  throw new Error("Pack manifest protectedZones must be an object.");
14365
14595
  const knownFields = new Set(["neverInclude", "neverWrite"]);
14366
14596
  for (const key of Object.keys(value)) {
@@ -14373,7 +14603,7 @@ function validateProtectedZoneDeclarations(value) {
14373
14603
  function isRemotePackInput(packPath) {
14374
14604
  return /^[a-z][a-z0-9+.-]*:\/\//i.test(packPath);
14375
14605
  }
14376
- function isRecord11(value) {
14606
+ function isRecord12(value) {
14377
14607
  return typeof value === "object" && value !== null && !Array.isArray(value);
14378
14608
  }
14379
14609
  function normalizeRelativePath(path) {
@@ -14386,8 +14616,8 @@ function formatError(error) {
14386
14616
  return error instanceof Error ? error.message : String(error);
14387
14617
  }
14388
14618
  // packages/core/src/plugins/capabilities.ts
14389
- import { mkdir as mkdir14, readFile as readFile19, writeFile as writeFile13 } from "node:fs/promises";
14390
- import { dirname as dirname14, join as join21 } from "node:path";
14619
+ import { mkdir as mkdir15, readFile as readFile19, writeFile as writeFile14 } from "node:fs/promises";
14620
+ import { dirname as dirname15, join as join22 } from "node:path";
14391
14621
  function createUnknownNegotiatedCapabilities(pluginId) {
14392
14622
  return {
14393
14623
  pluginId,
@@ -14497,13 +14727,13 @@ async function createCodexCapabilityVerificationArtifact(input) {
14497
14727
  };
14498
14728
  }
14499
14729
  function resolveCodexCapabilityArtifactPath(homeDir) {
14500
- return join21(homeDir, ".evodev", "STATE", "plugins", "codex", "capability-verification.json");
14730
+ return join22(homeDir, ".evodev", "STATE", "plugins", "codex", "capability-verification.json");
14501
14731
  }
14502
14732
  async function writeCodexCapabilityVerificationArtifact(homeDir, artifact) {
14503
14733
  validateCodexCapabilityVerificationArtifact(artifact);
14504
14734
  const path = resolveCodexCapabilityArtifactPath(homeDir);
14505
- await mkdir14(dirname14(path), { recursive: true });
14506
- await writeFile13(path, `${JSON.stringify(artifact, null, 2)}
14735
+ await mkdir15(dirname15(path), { recursive: true });
14736
+ await writeFile14(path, `${JSON.stringify(artifact, null, 2)}
14507
14737
  `, { encoding: "utf8", flag: "wx" });
14508
14738
  return path;
14509
14739
  }
@@ -14635,8 +14865,8 @@ function getEnabledPluginIds(settings) {
14635
14865
  return Object.entries(settings.plugins).filter(([, pluginSettings]) => pluginSettings.enabled).map(([pluginId]) => pluginId).sort((left, right) => left.localeCompare(right));
14636
14866
  }
14637
14867
  // packages/core/src/project/index.ts
14638
- import { mkdir as mkdir15, readFile as readFile20, readdir as readdir12, stat as stat12, writeFile as writeFile14 } from "node:fs/promises";
14639
- import { basename as basename5, join as join22, relative as relative8 } from "node:path";
14868
+ import { mkdir as mkdir16, readFile as readFile20, readdir as readdir13, stat as stat12, writeFile as writeFile15 } from "node:fs/promises";
14869
+ import { basename as basename5, join as join23, relative as relative8 } from "node:path";
14640
14870
  var PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS = [
14641
14871
  ".evodev/project.json",
14642
14872
  ".evodev/profile.md",
@@ -14735,7 +14965,7 @@ async function createProjectContextPlan(projectDir) {
14735
14965
  sourceContentIncluded: false
14736
14966
  };
14737
14967
  const planFiles = await Promise.all(PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS.map(async (relativePath) => {
14738
- const absolutePath = join22(projectDir, relativePath);
14968
+ const absolutePath = join23(projectDir, relativePath);
14739
14969
  const exists = await pathExists9(absolutePath);
14740
14970
  return {
14741
14971
  relativePath,
@@ -14766,9 +14996,9 @@ ${plan.errors.join(`
14766
14996
  const writtenFiles = [];
14767
14997
  for (const relativePath of PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS) {
14768
14998
  const content = payloads[relativePath];
14769
- const absolutePath = join22(plan.projectDir, relativePath);
14770
- await mkdir15(join22(absolutePath, ".."), { recursive: true });
14771
- await writeFile14(absolutePath, content, { encoding: "utf8", flag: "wx" });
14999
+ const absolutePath = join23(plan.projectDir, relativePath);
15000
+ await mkdir16(join23(absolutePath, ".."), { recursive: true });
15001
+ await writeFile15(absolutePath, content, { encoding: "utf8", flag: "wx" });
14772
15002
  writtenFiles.push(relativePath);
14773
15003
  }
14774
15004
  return { writtenFiles };
@@ -14840,9 +15070,9 @@ function createProfileMarkdown(plan) {
14840
15070
  async function collectProjectFileMetadata(projectDir) {
14841
15071
  const files = [];
14842
15072
  async function visit(dir) {
14843
- const entries = await readdir12(dir, { withFileTypes: true });
15073
+ const entries = await readdir13(dir, { withFileTypes: true });
14844
15074
  for (const entry of entries) {
14845
- const absolutePath = join22(dir, entry.name);
15075
+ const absolutePath = join23(dir, entry.name);
14846
15076
  const relativePath = relative8(projectDir, absolutePath).replaceAll("\\", "/");
14847
15077
  if (shouldExcludePath(relativePath, entry.isDirectory())) {
14848
15078
  continue;
@@ -14862,7 +15092,7 @@ async function collectProjectFileMetadata(projectDir) {
14862
15092
  return files.sort((left, right) => left.path.localeCompare(right.path));
14863
15093
  }
14864
15094
  async function collectProjectCommands(projectDir) {
14865
- const packageJsonPath = join22(projectDir, "package.json");
15095
+ const packageJsonPath = join23(projectDir, "package.json");
14866
15096
  const warnings = [];
14867
15097
  if (!await pathExists9(packageJsonPath)) {
14868
15098
  return { version: 1, metadataOnly: true, rawCommandsIncluded: false, scripts: [], warnings };
@@ -14874,7 +15104,7 @@ async function collectProjectCommands(projectDir) {
14874
15104
  warnings.push(`package.json scripts skipped: ${describeError4(error)}`);
14875
15105
  return { version: 1, metadataOnly: true, rawCommandsIncluded: false, scripts: [], warnings };
14876
15106
  }
14877
- const scripts = isRecord12(parsed) && isRecord12(parsed.scripts) ? parsed.scripts : {};
15107
+ const scripts = isRecord13(parsed) && isRecord13(parsed.scripts) ? parsed.scripts : {};
14878
15108
  const summaries = [];
14879
15109
  for (const [name, value] of Object.entries(scripts).sort(([left], [right]) => left.localeCompare(right))) {
14880
15110
  if (typeof value !== "string") {
@@ -14984,14 +15214,14 @@ async function pathExists9(path) {
14984
15214
  throw error;
14985
15215
  }
14986
15216
  }
14987
- function isRecord12(value) {
15217
+ function isRecord13(value) {
14988
15218
  return typeof value === "object" && value !== null && !Array.isArray(value);
14989
15219
  }
14990
15220
  function describeError4(error) {
14991
15221
  return error instanceof Error ? error.message : String(error);
14992
15222
  }
14993
15223
  // packages/core/src/sync/orchestrator.ts
14994
- import { join as join23 } from "node:path";
15224
+ import { join as join24 } from "node:path";
14995
15225
  async function runSync(options) {
14996
15226
  const store = createCoreConfigStore(options.homeDir);
14997
15227
  const settings = await store.readSettings();
@@ -15134,8 +15364,8 @@ function filterAssetsForTarget(assets, targetPlugin) {
15134
15364
  }
15135
15365
  function resolveAssetScannerPaths(assetsRootDir) {
15136
15366
  return {
15137
- skillsDir: join23(assetsRootDir, "skills"),
15138
- agentsDir: join23(assetsRootDir, "agents")
15367
+ skillsDir: join24(assetsRootDir, "skills"),
15368
+ agentsDir: join24(assetsRootDir, "agents")
15139
15369
  };
15140
15370
  }
15141
15371
  async function readRegistryOrDefault(store) {
@@ -15363,7 +15593,7 @@ async function runTeamsMcpStdioServer(options = {}) {
15363
15593
  }
15364
15594
  }
15365
15595
  function initializeResult(request) {
15366
- const params = isRecord13(request.params) ? request.params : {};
15596
+ const params = isRecord14(request.params) ? request.params : {};
15367
15597
  const requestedVersion = typeof params.protocolVersion === "string" ? params.protocolVersion : PROTOCOL_VERSION;
15368
15598
  const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.has(requestedVersion) ? requestedVersion : PROTOCOL_VERSION;
15369
15599
  return {
@@ -15445,7 +15675,7 @@ function toolResult(structuredContent, isError = false) {
15445
15675
  };
15446
15676
  }
15447
15677
  function parseRequest(message) {
15448
- if (!isRecord13(message))
15678
+ if (!isRecord14(message))
15449
15679
  throw new Error("Invalid JSON-RPC message; expected object.");
15450
15680
  if (message.jsonrpc !== "2.0")
15451
15681
  throw new Error("Invalid JSON-RPC version.");
@@ -15472,7 +15702,7 @@ function jsonRpcError(id, code, message, data) {
15472
15702
  return { jsonrpc: "2.0", id, error: { code, message, data } };
15473
15703
  }
15474
15704
  function expectRecord5(value, path) {
15475
- if (!isRecord13(value))
15705
+ if (!isRecord14(value))
15476
15706
  throw new Error(`Invalid ${path}; expected object.`);
15477
15707
  return value;
15478
15708
  }
@@ -15485,28 +15715,28 @@ function expectString3(value, path) {
15485
15715
  function optionalString7(value) {
15486
15716
  return typeof value === "string" && value.length > 0 ? value : undefined;
15487
15717
  }
15488
- function isRecord13(value) {
15718
+ function isRecord14(value) {
15489
15719
  return typeof value === "object" && value !== null && !Array.isArray(value);
15490
15720
  }
15491
15721
  function describeError5(error) {
15492
15722
  return error instanceof Error ? error.message : String(error);
15493
15723
  }
15494
15724
  // packages/core/src/workflow/index.ts
15495
- import { readFile as readFile21, readdir as readdir13 } from "node:fs/promises";
15496
- import { join as join24 } from "node:path";
15725
+ import { readFile as readFile21, readdir as readdir14 } from "node:fs/promises";
15726
+ import { join as join25 } from "node:path";
15497
15727
  async function scanWorkflowManifests(workflowsDir) {
15498
15728
  const manifests = [];
15499
- const entries = await readdir13(workflowsDir, { withFileTypes: true });
15729
+ const entries = await readdir14(workflowsDir, { withFileTypes: true });
15500
15730
  for (const entry of entries) {
15501
15731
  if (!entry.isDirectory())
15502
15732
  continue;
15503
- const manifestPath = join24(workflowsDir, entry.name, "WORKFLOW.json");
15733
+ const manifestPath = join25(workflowsDir, entry.name, "WORKFLOW.json");
15504
15734
  manifests.push(parseWorkflowManifest(JSON.parse(await readFile21(manifestPath, "utf8"))));
15505
15735
  }
15506
15736
  return manifests.sort((left, right) => left.id.localeCompare(right.id));
15507
15737
  }
15508
15738
  function parseWorkflowManifest(value) {
15509
- if (!isRecord14(value))
15739
+ if (!isRecord15(value))
15510
15740
  throw new Error("Workflow manifest must be an object.");
15511
15741
  const manifest = value;
15512
15742
  if (typeof manifest.id !== "string" || typeof manifest.version !== "string") {
@@ -15563,24 +15793,29 @@ function formatWorkflowPlan(plan) {
15563
15793
  ].join(`
15564
15794
  `);
15565
15795
  }
15566
- function isRecord14(value) {
15796
+ function isRecord15(value) {
15567
15797
  return typeof value === "object" && value !== null && !Array.isArray(value);
15568
15798
  }
15569
15799
  export {
15570
15800
  writeTaskContract,
15801
+ writeSessionIndex,
15571
15802
  writeProjectContext,
15803
+ writeJson2 as writeJson,
15572
15804
  writeFailedOkfKnowledgePlanArtifact,
15805
+ writeEvolutionRepoProposal,
15573
15806
  writeEvolutionDistillationBatch,
15574
15807
  writeDaemonState,
15575
15808
  writeContextInjectionReceipt,
15576
15809
  writeCodexCapabilityVerificationArtifact,
15577
15810
  writeCodeAgentTraceRef,
15811
+ withEvolutionReviewDecisionLock,
15578
15812
  verifyTaskContract,
15579
15813
  validatePack,
15580
15814
  validateOkfKnowledgePlanContract,
15581
15815
  validateObservabilityEvent,
15582
15816
  validateLearningReviewDecisionRecord,
15583
15817
  validateLearningCandidate,
15818
+ validateEvolutionRepoProposal,
15584
15819
  validateEvolutionKnowledgeRecord,
15585
15820
  validateEvolutionEvidenceWindow,
15586
15821
  validateEvolutionDistillationBatch,
@@ -15591,6 +15826,7 @@ export {
15591
15826
  updateTeamAgentHookState,
15592
15827
  updateSessionMemoryFromHook,
15593
15828
  updateSegmentTriggers,
15829
+ updateEvolutionRepoProposalReviewState,
15594
15830
  updateEvolutionKnowledgeReviewState,
15595
15831
  unsetTeamRoleBinding,
15596
15832
  supersedeOkfKnowledgeConcept,
@@ -15607,6 +15843,7 @@ export {
15607
15843
  scanSkillAssets,
15608
15844
  scanAssets,
15609
15845
  scanAgentAssets,
15846
+ sanitizeProposedChange,
15610
15847
  runTeamsMcpStdioServer,
15611
15848
  runSync,
15612
15849
  runPluginConformance,
@@ -15647,14 +15884,19 @@ export {
15647
15884
  readTeamAgentSummary,
15648
15885
  readTeamAgentDefinition,
15649
15886
  readTaskContract,
15887
+ readSessionState,
15888
+ readSessionEvidenceSegment,
15889
+ readSessionCursor,
15650
15890
  readRuntimeInjectionSettings,
15651
15891
  readPendingTeamMessagesForRole,
15652
15892
  readOkfKnowledgeConcept,
15893
+ readLineRange,
15653
15894
  readLearningReviewDecisions,
15654
15895
  readLearningCandidates,
15655
15896
  readFailedOkfKnowledgePlanArtifact,
15656
15897
  readFailedOkfKnowledgePlan,
15657
15898
  readEvolutionReviewSnapshot,
15899
+ readEvolutionRepoProposalById,
15658
15900
  readEvolutionKnowledgeRecordById,
15659
15901
  readDaemonToken,
15660
15902
  readDaemonLock,
@@ -15700,12 +15942,14 @@ export {
15700
15942
  listTeamRuns,
15701
15943
  listTeamRoleBindings,
15702
15944
  listTeamAgents,
15945
+ listSessionEvidenceSegments,
15703
15946
  listSegmentEvolutionTriggers,
15704
15947
  listOkfKnowledgeConcepts,
15705
15948
  listObservabilityEvents,
15706
15949
  listLearningReviewDecisions,
15707
15950
  listLearningCandidates,
15708
15951
  listEvolutionTriggers,
15952
+ listEvolutionKnowledgeReviewHistory,
15709
15953
  listEvolutionKnowledgeRecords,
15710
15954
  listEvolutionEvosCases,
15711
15955
  listCodeAgentTraceRefs,
@@ -15717,6 +15961,7 @@ export {
15717
15961
  isActiveTeamAgentStatus,
15718
15962
  initializeCoreConfig,
15719
15963
  hasContextInjectionReceipt,
15964
+ hasConcreteRepoProposalChanges,
15720
15965
  handleTeamsMcpMessage,
15721
15966
  handleTeamsMcpLine,
15722
15967
  handleHookRuntime,
@@ -15784,6 +16029,7 @@ export {
15784
16029
  createLexicalKnowledgeDocumentFromEvosCase,
15785
16030
  createLearningReviewDecisionRecord,
15786
16031
  createLearningCandidate,
16032
+ createEvolutionRepoProposal,
15787
16033
  createEvolutionDistillationBatch,
15788
16034
  createEvoDevExecutionEvent,
15789
16035
  createDefaultTeamRuntimeSettings,
@@ -15810,6 +16056,7 @@ export {
15810
16056
  assertOkfKnowledgePlanContract,
15811
16057
  applyStrictestAgentPermissions,
15812
16058
  appendTraceLogEntry,
16059
+ appendRawEvent,
15813
16060
  appendObservabilityEvent,
15814
16061
  appendLearningReviewDecision,
15815
16062
  appendLearningCandidate,
@@ -15822,6 +16069,7 @@ export {
15822
16069
  TmuxRuntimeAdapter,
15823
16070
  TeamMessageBroker,
15824
16071
  TEAM_INTERNAL_WAKE_SIGNAL,
16072
+ SessionMemoryEvidenceError,
15825
16073
  PluginRegistryError,
15826
16074
  PluginRegistry,
15827
16075
  PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS,